注意:ここで紹介する方法よりも、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を使う方が簡単で、できあがりも高品質です。