EPUBファイルの目次を抽出

EPUBファイルの目次を抽出

最近、ファイルの TOC を印刷するコマンドを実行しましたpdf

mutool show file.pdf outline

epub上記のフォーマットと同様に、使い方が簡単で、優れた結果が得られるコマンドをフォーマットに使用したいと思いますpdf

そういうのってあるんですか?

答え1

.epubファイルは、 XHTML と CSS およびその他のファイル (画像、さまざまなメタデータ ファイル、および目次を含む.zipXML ファイルなど) を含むファイルです。toc.ncx

次のスクリプトはstdoutにunzip -p抽出するために使用しtoc.ncx、それをパイプでxml2コマンドを実行して、sed各章の見出しのテキストのみを抽出します。

コマンドラインでは 1 つ以上のファイル名引数を受け取ります。

#! /bin/sh

# This script needs InfoZIP's unzip program
# and the xml2 tool from http://ofb.net/~egnor/xml2/
# and sed, of course.

for f in "$@" ; do
    echo "$f:"
    unzip -p "$f" toc.ncx | 
        xml2 | 
        sed -n -e 's:^/ncx/navMap/navPoint/navLabel/text=:  :p'
    echo
done

これは、epub のファイル名の後に を出力し:、次の行の各章のタイトルを 2 つのスペースでインデントします。例:

book.epub:
  Chapter One
  Chapter Two
  Chapter Three
  Chapter Four
  Chapter Five

book2.epub:
  Chapter One
  Chapter Two
  Chapter Three
  Chapter Four
  Chapter Five

epub ファイルに が含まれていない場合toc.ncx、その特定の書籍に対して次のような出力が表示されます。

book3.epub:
caution: filename not matched:  toc.ncx
error: Extra content at the end of the document

最初のエラー行は からのものでunzip、2 番目の行は からのものですxml2。 また、不適切にフォーマットされたファイルxml2など、検出されたその他のエラーについても警告します。toc.ncx

エラー メッセージは stderr にありますが、本のファイル名は stdout にあることに注意してください。

xml2Debian、Ubuntu、その他の Debian 派生版、そしておそらく他のほとんどの Linux ディストリビューション向けにパッケージ化済みで提供されています。

このような単純なタスク (つまりsed、、、、などで使用するために XML を行指向形式に変換するだけの場合) では、よりも の方がシンプルで使いやすくなっています。awkcutgrepxml2xmlstarlet

ちなみに、epub のタイトルも印刷したい場合は、sedスクリプトを次のように変更します。

sed -n -e 's:^/ncx/navMap/navPoint/navLabel/text=:  :p
           s!^/ncx/docTitle/text=!  Title: !p'

またはスクリプトに置き換えますawk:

awk -F= '/(navLabel|docTitle)\/text/ {print $2}'

答え2

@cas の回答は、場合によっては機能しますが、epub バージョン 2.0 で、toc.ncxzip コンテナの最上位に NCX ドキュメントの名前が付けられていることを前提としています。1 つのフォルダにある 223 個の epub のうち、この前提を満たすのは 5 個だけです。これらの epub には、古いリーダー システムとの互換性のためだけに が含まれています。 はtoc.ncx必須のファイルではありませんMETA-INF/content.xml。必須のファイルは です。これには、epub の他のすべての要素へのポインタが含まれます。これにより、bash によるスクリプト作成が少し複雑になりますが、可能です。以下は、(content.xml によってポイントされる) opf ファイルからタイトルと著者を取得するスクリプトです。

#! /bin/sh

for f in "$@" ; do
    echo -n "$f""   "
    opf=$(unzip -p "$f" META-INF/container.xml | 
        xml2 | 
        sed -n -e 's:^/container/rootfiles/rootfile/@full-path=::p')
    unzip -p "$f" "$opf" |
        xml2 |
        sed -n -e 's!^/package/metadata/dc:title=!  !p' | tr  '
' ' '
    unzip -p "$f" "$opf" |
        xml2 |
        sed -n -e 's!^/package/metadata/dc:creator=!    !p' | tr  '
' ' '
    echo
done

はい、opf結果の順序を保証するために 2 回解析します。これにより、スプレッドシートのインポートに適した、タブで区切られた 3 列のファイル (2 つの感嘆符の間にある sed 行のタブ) が生成されます。

ncx ファイルを見つけるためにもう 1 歩進むと、少しトリッキーになります。xml2 を使用して各タグと属性ごとに 1 行を生成すると、ここでは不利になります。属性が に等しいhref属性の値が必要です。少しずるをして、元の項目がすべて 1 行にあることを期待し、grep を使用してそのフラグメントだけを抽出し、それを xml2 で処理して href 値を取得します。media-typeapplication/x-dtbncx+xml

これは相対 URL なので、opf エントリからパス部分も抽出する必要があります。すべてをまとめると、次のようになります。

#! /bin/sh

for f in "$@" ; do
    echo "$f""  "
    opf=$(unzip -p "$f" META-INF/container.xml | 
        xml2 | 
        sed -n -e 's:^/container/rootfiles/rootfile/@full-path=::p')
    ncx=$(unzip -p "$f" "$opf" |
        grep application/x-dtbncx+xml| 
        xml2 |
        sed -n -e 's!^/item/@href=!!p')
    opf_filename=${opf##*/}
    opf_path=${opf%$opf_filename}
    unzip -p "$f" ${opf_path}${ncx} |
        xml2 |
        sed -n -e 's:^/ncx/navMap/navPoint/navLabel/text=:  :p
                   s!^/ncx/docTitle/text=!Title: !p'
done

これはまだ仮定に基づいていますが、最も有力なのは、これらが epub2 互換ファイルであり、したがってどこかに ncx ファイルが含まれているというものです。epub3 ドキュメントは、異なる HTML ベースのナビゲーション形式を使用します。それでも、テスト ファイル 223 個すべてに TOC が表示されます (ただし、ncx にタイトルがないものもあります)。

関連情報