フリー小説をKindleの縦書きファイルへ変換する(3)※青空文庫

  1. はじめに
  2. 1話ごとのテキストを、一括でダウンロード
  3. Powershellで、1つのファイル(EPUB)を生成(小説家になろう 版)
    1. 青空文庫 版
  4. Kindle PreviewerでMOBIファイルへ変換し、USB接続でKindleへ転送

Powershellで、1つのファイル(EPUB)を生成

以下のPowerShellを使えば、実行するだけで、epubファイルが生成されます。
青空文庫のHTMLは、ダウンロードしたHTMLは、目次が外れてしまうのと、縦書きにならないのが難点です。
このPowerShellは、目次と縦書きを実現します。

例えば、15少年漂流記(ちょっとなまえちがうけど)を例に変換してみましょう。
www.aozora.gr.jp

ファイルのダウンロード

青空文庫は、基本的に1つのファイルになっているようです。
なので、ダウンロードは1回ですみました。

XHTMLファイルをダウンロードする

実行する際のファイル構成

実行する際の注意点

  • 検証済環境:Windows10、PowerShell Ver. 5.1.19041.2364
  • html2epub.ps1の文字コード=Shift-JIS
  • 作業フォルダは英数字のフォルダで作業してください
  • あたり前ですが、ZIPファイルは解凍してください。ZIPファイルのままでは、powershellは実行できません。
html2epub.ps1

下記のテキストをテキストエディタにコピー&ペーストして
「html2epub.ps1」と言うファイル名で保存します。

###########################################################
# Title:  青空文庫のHTMLに目次を追加してepubファイルにする
# Created:2023/03/15

# Usage:
# > Powershell 実行方法
# > PowerShell -ExecutionPolicy RemoteSigned -file .\html2epub.ps1 "title" xxx.html

# File Tree:
#  book.epub = zip
#   ├ META-INF
#   │  └ container.xml
#   ├ OEBPS
#   │  ├ book.html
#   │  ├ content.opf
#   │  └ toc.ncx
#   └ mimetype
###########################################################
$outFile   = 'book\OEBPS\book.html'  # 結合後のファイル名

if([string]::IsNullorEmpty($Args[0])){
  Write-Host "Usage: PowerShell -ExecutionPolicy RemoteSigned -file .\html2epub.ps1 `"title`""
  Write-Host "" 
  exit
}
$htmlTitle = $Args[0]
Write-Host "Titile  :" $htmlTitle
$uuid = "html2epub-" + ( Get-Date -Format "yyyyMMdd-HHmmss" )
$htmlStyle = "<style type=`"text/css`">
    <!--
        body, h1, p {
            writing-mode: vertical-rl;
            text-orientation: upright;
            -webkit-writing-mode:vertical-rl;
            -epub-writing-mode:vertical-rl;
            -moz-writing-mode:vertical-rl;
            -o-writing-mode:vertical-rl;
        }
    -->
</style>"

$opfBody = "<?xml version=`"1.0`" encoding=`"utf-8`"?>
<package version=`"2.0`" unique-identifier=`"BookId`" xmlns=`"http://www.idpf.org/2007/opf`">
  <metadata xmlns:dc=`"http://purl.org/dc/elements/1.1/`" xmlns:opf=`"http://www.idpf.org/2007/opf`">
    <meta content=`"horizontal-rl`" name=`"primary-writing-mode`"/>
    <dc:identifier id=`"BookId`" opf:scheme=`"UUID`">urn:uuid:" + $uuid + "</dc:identifier>
    <dc:language>ja</dc:language>
    <dc:title>" + $htmlTitle + "</dc:title>
    <dc:date opf:event=`"modification`" xmlns:opf=`"http://www.idpf.org/2007/opf`">" + ( Get-Date -UFormat "%Y-%m-%d" ) + "</dc:date>
  </metadata>
  <manifest>
    <item id=`"book.html`" href=`"book.html`" media-type=`"application/xhtml+xml`"/>
    <item id=`"ncx`" href=`"toc.ncx`" media-type=`"application/x-dtbncx+xml`"/>
  </manifest>
  <spine toc=`"ncx`">
    <itemref idref=`"book.html`"/>
  </spine>
</package>"

$containerBody = "<?xml version=`"1.0`" encoding=`"UTF-8`"?>
<container version=`"1.0`" xmlns=`"urn:oasis:names:tc:opendocument:xmlns:container`">
    <rootfiles>
        <rootfile full-path=`"OEBPS/content.opf`" media-type=`"application/oebps-package+xml`"/>
   </rootfiles>
</container>"

$ncxBody = "<?xml version=`"1.0`" encoding=`"utf-8`"?>
<!DOCTYPE ncx PUBLIC `"-//NISO//DTD ncx 2005-1//EN`"
   `"http://www.daisy.org/z3986/2005/ncx-2005-1.dtd`">
<ncx xmlns=`"http://www.daisy.org/z3986/2005/ncx/`" version=`"2005-1`">
  <head>
    <meta name=`"dtb:uid`" content=`"urn:uuid:" + $uuid + "`" />
    <meta name=`"dtb:depth`" content=`"0`" />
    <meta name=`"dtb:totalPageCount`" content=`"0`" />
    <meta name=`"dtb:maxPageNumber`" content=`"0`" />
  </head>
<docTitle>
  <text>" + $htmlTitle + "</text>
</docTitle>
<navMap>
<navPoint id=`"navPoint-1`" playOrder=`"1`">
  <navLabel>
    <text>目次へ</text>
  </navLabel>
  <content src=`"book.html`" />
</navPoint>
</navMap>
</ncx>"

$mimetype = "application/epub+zip"

# ---------------------------------------------------------
# 結合後のファイルがあった場合は削除
Write-Host "Delete  : book dir, book.epub, book.zip"

If(Test-Path "book"){
  Remove-Item -Path "book" -Recurse
}
If(Test-Path "book.epub"){
  Remove-Item -Path "book.epub"
}
If(Test-Path "book.zip"){
  Remove-Item -Path "book.zip"
}

# フォルダ&ファイルの生成
New-Item "book"          -ItemType Directory > $null
New-Item "book\META-INF" -ItemType Directory > $null
New-Item "book\OEBPS"    -ItemType Directory > $null
Write-Output $containerBody | Out-File -FilePath "book\META-INF\container.xml"  -Append -Encoding UTF8
Write-Output $mimetype      | Out-File -FilePath "book\mimetype"                -Append -Encoding UTF8
Write-Output $opfBody       | Out-File -FilePath "book\OEBPS\content.opf"       -Append -Encoding UTF8
Write-Output $ncxBody       | Out-File -FilePath "book\OEBPS\toc.ncx"           -Append -Encoding UTF8

# ---------------------------------------------------------
# 目次の生成
$orgHtml = $Args[1]
Write-Host "SrcHtml :" $orgHtml
$xmlDoc = [xml](Get-Content $orgHtml -Encoding Default)
# $xmlNav = [Xml.Xpath.XPathNavigator]$xmlDoc.CreateNavigator()

$val = 0  # カウンター
$agenda = $xmlDoc.html.body.div.div|
  foreach {
    if( $null -ne $_ ){
      if( $_['h3'] -ne $null){
        "&nbsp;&nbsp;<a href=`"#" + $_['h3'].a.id + "`">" + $_['h3'].a.InnerXML + "</a><br />`n"
      }
      if( $_['h4'] -ne $null){
        "&nbsp;&nbsp;&nbsp;&nbsp;<a href=`"#" + $_['h4'].a.id + "`">" + $_['h4'].a.InnerXML + "</a><br />`n"
      }
      $val = $val + 1
      Write-Host -NoNewline ("`r" + "Progress: ${val}")
    }
  }
Write-Host ""
$agendaAll = "<h1 style=`"page-break-before:always`">目次</h1>`n" + $agenda
#Write-Host $agendaAll

#$Navi.Select("//h4")
#$Navi.Select("//h4") | select Name

# ---------------------------------------------------------
# 本文へ目次を挿入
[string]$srcStr = "<div class=`"main_text`"><br />"
[string]$destStr = $agendaAll + $srcStr
(Get-Content $orgHtml -Encoding Default) | foreach { $_ -replace $srcStr,$destStr } | Set-Content $outFile -Encoding Default

# CSSを挿入
[string]$srcCssStr = "</head>"
[string]$desCsstStr = $htmlStyle + $srcStr
(Get-Content $outFile -Encoding Default) | foreach { $_ -replace $srcCssStr,$desCsstStr } | Set-Content $outFile -Encoding Default

# ---------------------------------------------------------
# ZIP圧縮 & 拡張子変更
Compress-Archive -Path "book" -DestinationPath "book.zip"
Rename-Item -Path "book.zip" -NewName "book.epub"
Write-Host "Created : book.epub"

実行例

PowerShell -ExecutionPolicy RemoteSigned -file .\html2epub.ps1 "無人島に生きる十六人" .\42767_15618.html

実行例
  • book.epubファイルができていたら成功です。

以上