iTunes向けオライリー本からepubを取り出すスクリプトApp2Epub.js
先日、Kindle用にmobiファイルを生成するスクリプトを作りましたが、
その過程で、epubファイルも生成されたりします。
で、たぶんepubファイルがほしいだけの人もいるんじゃないかと思って、
toc.ncxをいじらずにそのまま引き抜くスクリプトを作ってみました。
こっちのほうがもしかして需要があるかもしれません。
Windows用。
目次作成について
そういえば、先のApp2EpubAndMobi.jsには、目次作成機能はないです。
id:shunsuk様が目次作成スクリプトをrubyで作成されたようですので、もしかしたらボチボチやるかも。
やらないかも。
今回の収穫
先のApp2EpubAndMobi.jsを少し手直しすればいいかと思ったら、うまく動かない。
最後の最後、一時フォルダの削除に失敗するんですね。
コメントアウトしただけなのに…
で、いろいろやっていくうちに、
Windows Scripting Hostでは、どうやらGarbageCollectionが起きた時に初めてShell.Applicationの不要なフォルダロックが解除される
ような気がしてきました。
つまり
GCかからないうちは、Shell.Applicationがフォルダをつかんだままになっていて、そのフォルダを削除できない
と。
で、強制GCかけたら、ビンゴでした。
これはわからない。
フォルダ削除できない時点でGC走るなんて芸当はもちろんやるはずないですよね。
というわけで、
先のApp2EpubAndMobi.jsにもこの点反映させています(他の些末なバグの解消もこっそりしている)。
今回のスクリプトさらし
恥ずかしながら、さらすの巻。
if (WScript.Arguments.Length <= 0) { WScript.Echo('ファイルを指定してください。'); WScript.Quit(); } // extractZipHere(Zipファイル名) var extractZipHere = function(fileInput) { var fso = new ActiveXObject('Scripting.FileSystemObject'); var folderParent = fso.GetParentFolderName(fileInput); var folderExtract = fso.BuildPath(folderParent, fso.GetTempName()); if (!fso.FolderExists(folderExtract)) { fso.CreateFolder(folderExtract); } var shell = new ActiveXObject('Shell.Application'); shell.NameSpace(folderExtract).CopyHere(shell.NameSpace(fileInput).Items()); return folderExtract; } // createZip(作成先のZipファイル名、元のフォルダ名) var createZip = function(fileZip, folderSrc) { var fso = new ActiveXObject('Scripting.FileSystemObject'); var shell = new ActiveXObject('Shell.Application'); fso.CreateTextFile(fileZip); var ofileZip = fso.OpenTextFile(fileZip, 2); // 2 : for Write ofileZip.Write('PK' + String.fromCharCode(5,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)); ofileZip.Close(); var ofolderZip = shell.NameSpace(fileZip); var ofolderSrc = shell.NameSpace(folderSrc); var scount = ofolderSrc.Items().count; ofolderZip.CopyHere(ofolderSrc.Items()); while (ofolderZip.items().count != scount ) { WScript.Sleep(100); } } //必要なオブジェクトの生成 var shell = new ActiveXObject('Shell.Application'); var wshell = new ActiveXObject('WScript.Shell'); var fso = new ActiveXObject('Scripting.FileSystemObject'); //指定されたファイルが.ipaファイルか確認 var fileOriginal = WScript.Arguments.Item(0); if (fso.GetExtensionName(fileOriginal) != 'ipa') { WScript.Echo('iPhoneアプリをドラッグ&ドロップしてください。'); WScript.Quit(); } //スクリプトフォルダを取得 var folderScript = String(WScript.ScriptFullName).replace(WScript.ScriptName, ''); //オリジナルファイルを一時フォルダにコピー var folderTmp = fso.GetSpecialFolder(2); var fileInput = fso.BuildPath(folderTmp, fso.GetTempName() + '.zip' ); fso.CopyFile(fileOriginal, fileInput); //zipファイルを展開 var folderExtract = extractZipHere(fileInput); //appフォルダなどの取得 var folderPayload = fso.BuildPath(folderExtract, 'Payload'); //PayLoadフォルダ内の.appファイルのファイル名を取得する(1個しかないはず…) var fileApp = shell.NameSpace(folderPayload).Items().Item(0).Name; var folderApp = fso.BuildPath(folderPayload, fileApp); var folderBook = fso.BuildPath(folderApp, 'book'); var folderOEBPS = fso.BuildPath(folderBook, 'OEBPS'); //.appフォルダ内をZipに固めて.epubファイルにリネーム var fileZip = fso.BuildPath(folderScript, fso.GetBaseName(fileApp) + '.zip'); createZip(fileZip, folderBook); var fileEpub = fso.BuildPath(folderScript, fso.GetBaseName(fileApp) + '.epub'); if (fso.FileExists(fileEpub)) { fso.DeleteFile(fileEpub); } fso.MoveFile(fileZip, fileEpub); //アトシマツ 一時ファイルを削除 this.CollectGarbage(); //Shell.Applicationがフォルダを離さないことがあるので念のためGC fso.DeleteFile(fileInput); fso.DeleteFolder(folderExtract); WScript.Echo('終了しました。');
↑CollectGarbage()しないと、削除できないんですフォルダ。
先のスクリプトではうまくGCが動いて、Shell.Applicationがフォルダを開放していたようなんです。
非常に絶妙なタイミングでうまく動いていたんだなぁ。