注意:ここで紹介する方法よりも、calibreを使う方が簡単で、できあがりも高品質です。
「たった600円でオライリー本をiPadやKindleで読む。すてき。」という記事がすてきです。100冊買っても6万円って。でも、作業がちょっと面倒です。
iPadな人は、「perl – O’ReillyのiPhoneアプリ本からepubをぶっこぬく」にあるスクリプトを使えば、処理の大部分を自動化できます。
Kindleな人は、もう一手間かかるのですが、やはりスクリプトを書いて自動化しておきましょう。(参考:Kindle形式で目次を表示する。epubとの違い。・Kindle用の目次を生成するスクリプトを書いた。)
以下の作業を一つのスクリプトにまとめます。
- toc.ncxからのネームスペースの削除
- toc.htmlの生成と登録
- iPad用のepubの生成
- Kindle用のmobiの生成
準備
perl, zip, unzip, kindlegenにPATHを通しておいてください。Windowsの人は、Cygwinを使うといいでしょう(デフォルトではzipは入らないかもしれないので、インストール時に選択してください)。
使い方
perl ipa2mobi.pl ipaファイル名
ipa2mobi.plのコード
#!/usr/bin/perl -w #------------------------------------------------------------------ print "Step 1: http://blog.livedoor.jp/dankogai/archives/51484907.html\n"; use strict; use warnings; use File::Basename; use File::Path; sub clean{ File::Path::rmtree('Payload'); } my $src = shift; #die "usage:$0 src.ipa [dst.epub]" unless -f $src; die "usage:$0 src.ipa" unless -f $src; #my $dst = shift; my $dst = basename($src); #if (!$dst){ # $dst = basename($src); $dst =~ s/\w+$/epub/; #} system qw/unzip -q/, $src, qw/-x iTunes*/; die $! if $!; my $app = <Payload/*.app/book>; clean and die "No book found in the archive" unless $app; chdir $app; my $updir = '../../..'; #system qw/zip -q0X/, "$updir/$dst", 'mimetype'; #system qw/zip -qXr9D/, "$updir/$dst", qw/ META-INF OEBPS/; #chdir $updir; #clean; #system qw{open -a /Applications/iTunes.app}, $dst; #------------------------------------------------------------------ print "Step 2: Modify toc.ncx\n"; chdir 'OEBPS'; rename 'toc.ncx', 'toc.bak'; open(IN, 'toc.bak'); open(NCX, '> toc.ncx'); while (<IN>) { $_ =~ s|<(/{0,1})ncx:|<$1|g; print(NCX $_); } close(IN); close(NCX); unlink 'toc.bak'; #------------------------------------------------------------------ print "Step 3: Create toc.html\n"; use XML::LibXML; if (! -f 'toc.html') { sub processNavPoint() { my $node=shift; my $depth=shift; if ($depth==0) { print HTML '<h1>'; } printf(HTML "<a href='%s'>%s</a>", $node->findvalue('content/@src'), $node->findvalue('navLabel/text')); if ($depth==0) { print HTML "</h1>\n"; } my @navPoints=$node->findnodes('navPoint'); if ($#navPoints!=-1) { print HTML "<ul>\n"; foreach my $navPoint (@navPoints) { print HTML '<li>'; &processNavPoint($navPoint,$depth+1); print HTML "</li>\n"; } print HTML "</ul>\n"; } } open(HTML, '> toc.html'); binmode(HTML, ":utf8"); print HTML <<EOF; <?xml version="1.0" encoding="UTF-8" standalone="no"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html> <head> <title>Table of Contents</title> </head> <body> EOF my $parser = XML::LibXML->new(); my $toc = $parser->parse_file('toc.ncx'); &processNavPoint($toc->findnodes('/ncx/navMap/navPoint'),0); print HTML '</body></html>'; close(HTML); #------------------------------------------------------------------ print "Step 4: Modify content.opf\n"; rename 'content.opf', 'content.bak'; open(IN, 'content.bak'); open(OPF, '> content.opf'); while (<IN>) { print(OPF $_); if (/<item id="cover"/) { print(OPF ' <item id="toc" href="toc.html" media-type="text/html"/>'."\n"); } elsif (/<itemref idref="cover"/) { print(OPF ' <itemref idref="toc" linear="no"/>'."\n"); } elsif (/<reference href="cover.html"/) { print(OPF ' <reference href="toc.html" type="toc" title="Table of Contents"/>'."\n"); } } close(IN); close(OPF); unlink 'content.bak'; } # end of if (! -f 'toc.html') #------------------------------------------------------------------ print "Step 5: Create ePub\n"; chdir '..'; system qw/zip -q0X/, "$updir/$dst", 'mimetype'; system qw/zip -qXr9D/, "$updir/$dst", qw/ META-INF OEBPS/; chdir $updir; clean; #------------------------------------------------------------------ print "Step 6: Create mobi\n"; system qw/kindlegen/, "$dst";
問題
目次の位置が本の最後になってしまいます(ジャンプすればいいのですが)- perlの作法、よく知りません。
って書いておけば、誰かがきれいなスクリプトに直してくれるはず。
ゆっくり読みたいときは目に優しいKindleが、開発中にリファレンスとして使いたいときは描画の速いiPadがいいと思います。iPhoneで読むのは大変だと思います。
オライリーとしては、情報弱者を食い物にするのと情報強者にサービスするののバランスを調整することで、利益が最大になればいいのでしょう。
追記:toc.htmlがすでに存在しているときには、step 3, 4を飛ばすようにしました。
追記:目次が最後になってしまう問題が解決しました(コメントに感謝)。
追記:ここで紹介する方法よりも、calibreを使う方が簡単で、できあがりも高品質です。
すでに目次がある場合、上書きしてしまいますね
syou6162さん
オライリーのiPhone本で、
実際にtoc.htmlがあるものがあるのでしょうか。
私が試しに買った3冊には無かったのですが。
あるなら直した方がいいですね。
[ガジェット]Kindle用の目次を生成するスクリプトを書いた。
オライリーのiPhoneアプリからepubを抜き出し、それをさらにKindle形式に変換。epubを抜き出すところまでは、dankogai先生がスクリプ…
直しました。
目次の位置が最後になってしまう件ですが、”Step 4: Modify content.opf”のwhileループに以下を追加すれば、表紙の次に目次がくるようになりました。
elsif (/’.”\n”);
}
前の投稿の表示がおかしくなったため、エスケープしたものを再度投稿します。申し訳ありません。
elsif (/<itemref idref="cover"/) {
print(OPF ‘ <itemref idref="toc" linear="no"/>’."\n");
}
Anonymousさん
掲載したスクリプトを修正しました。
ありがとうございます。