JavaScript で ePub を生成するライブラリ (というか EeePub を JavaScript で写経してみた)

http://github.com/tily/js-eeepub

JavaScriptePub を読むだけじゃなくて作成できたら面白いだろうなと思って、勉強も兼ねて jugyo さんの EeePubJavaScript に移植してみた。

不完全なところが色々あるし、もっと便利にできそうな気がするんだけど、だいぶ飽きてきたんで一旦 github で公開してみる。

zip.jsxmlbuilder.js に依存している。あと、JSSpec でスペックを書いてみた。スペックに書いてるまんまだけど、こんな感じで使う。

var easy = new EeePub.Easy({
    title:'sample',
    creator:'tily',
    identifiers:'http://example.com/book/foo',
    uid:'http://example.com/book/foo',
})
easy.sections.push(['1. foo', [
    '<?xml version="1.0" encoding="UTF-8"?>', "\n",
    '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">', "\n",
    '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja">', "\n",
    '  <head>', "\n",
    '    <title>foo</title>', "\n",
    '  </head>', "\n",
    '  <body>', "\n",
    '    <p>', "\n",
    '    foo foo foo foo foo foo', "\n",
    '    </p>', "\n",
    '  </body>', "\n",
    '</html>', "\n"
].join('')])
easy.sections.push(['2. bar', [
    '<?xml version="1.0" encoding="UTF-8"?>', "\n",
    '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">', "\n",
    '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja">', "\n",
    '  <head>', "\n",
    '    <title>bar</title>', "\n",
    '  </head>', "\n",
    '  <body>', "\n",
    '    <p>', "\n",
    '    bar bar bar bar bar bar', "\n",
    '    </p>', "\n",
    '  </body>', "\n",
    '</html>', "\n"
].join('')])
console.log(easy.save())

こんな感じのが出力される。

data:application/zip;base64,UEsDBAoAAAAAANwG5TzeiCCNNQEAADUBAAAOAAAAc2VjdGlvbl8wLmh0bWw8P3htbCB2ZXJzaW9uPSIxLjAiIGVuY29kaW5nPSJVVEYtOCI/Pgo8IURPQ1RZUEUgaHRtbCBQVUJMSUMgIi0vL1czQy8vRFREIFhIVE1MIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9UUi94aHRtbDExL0RURC94aHRtbDExLmR0ZCI+CjxodG1sIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hodG1sIiB4bWw6bGFuZz0iamEiPgogIDxoZWFkPgogICAgPHRpdGxlPmZvbzwvdGl0bGU+CiAgPC9oZWFkPgogIDxib2R5PgogICAgPHA+CiAgICBmb28gZm9vIGZvbyBmb28gZm9vIGZvbwogICAgPC9wPgogIDwvYm9keT4KPC9odG1sPgpQSwMECgAAAAAA3AblPOsjb3w1AQAANQEAAA4AAABzZWN0aW9uXzEuaHRtbDw/eG1sIHZlcnNpb249IjEuMCIgZW5jb2Rpbmc9IlVURi04Ij8+CjwhRE9DVFlQRSBodG1sIFBVQkxJQyAiLS8vVzNDLy9EVEQgWEhUTUwgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL1RSL3hodG1sMTEvRFREL3hodG1sMTEuZHRkIj4KPGh0bWwgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGh0bWwiIHhtbDpsYW5nPSJqYSI+CiAgPGhlYWQ+CiAgICA8dGl0bGU+YmFyPC90aXRsZT4KICA8L2hlYWQ+CiAgPGJvZHk+CiAgICA8cD4KICAgIGJhciBiYXIgYmFyIGJhciBiYXIgYmFyCiAgICA8L3A+CiAgPC9ib2R5Pgo8L2h0bWw+ClBLAwQKAAAAAADcBuU8sk72IY0CAACNAgAABwAAAHRvYy5uY3g8P3htbCB2ZXJzaW9uPSIxLjAiIGVuY29kaW5nPSJVVEYtOCI/Pgo8bmN4IHhtbG5zPSJodHRwOi8vd3d3LmRhaXN5Lm9yZy96Mzk4Ni8yMDA1L25jeC8iIHZlcnNpb249IjIwMDUtMSI+PGRvY1RpdGxlPjx0ZXh0PnNhbXBsZTwvdGV4dD48L2RvY1RpdGxlPjxoZWFkPjxtZXRhIG5hbWU9ImR0Yjp1aWQiIGNvbnRlbnQ9Imh0dHA6Ly9leGFtcGxlLmNvbS9ib29rL2ZvbyI+PC9tZXRhPjxtZXRhIG5hbWU9ImR0YjpkZXB0aCIgY29udGVudD0iMSI+PC9tZXRhPjxtZXRhIG5hbWU9ImR0Yjp0b3RhbFBhZ2VDb3VudCIgY29udGVudD0iMCI+PC9tZXRhPjxtZXRhIG5hbWU9ImR0YjptYXhQYWdlTnVtYmVyIiBjb250ZW50PSIwIj48L21ldGE+PC9oZWFkPjxuYXZNYXA+PG5hdlBvaW50IGlkPSJuYXZQb2ludC0xIiBwbGF5T3JkZXI9IjEiPjxuYXZMYWJlbD48dGV4dD4xLiBmb288L3RleHQ+PC9uYXZMYWJlbD48Y29udGVudCBzcmM9InNlY3Rpb25fMC5odG1sIj48L2NvbnRlbnQ+PC9uYXZQb2ludD48bmF2UG9pbnQgaWQ9Im5hdlBvaW50LTIiIHBsYXlPcmRlcj0iMiI+PG5hdkxhYmVsPjx0ZXh0PjIuIGJhcjwvdGV4dD48L25hdkxhYmVsPjxjb250ZW50IHNyYz0ic2VjdGlvbl8xLmh0bWwiPjwvY29udGVudD48L25hdlBvaW50PjwvbmF2TWFwPjwvbmN4PlBLAwQKAAAAAADcBuU8ArTT+24DAABuAwAACwAAAGNvbnRlbnQub3BmPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHBhY2thZ2UgeG1sbnM9Imh0dHA6Ly93d3cuaWRwZi5vcmcvMjAwNy9vcGYiIHVuaXF1ZS1pZGVudGlmaWVyPSJCb29rSWQiIHZlcnNpb249IjIuMCI+PG1ldGFkYXRhIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6ZGN0ZXJtcz0iaHR0cDovL3B1cmwub3JnL2RjL3Rlcm1zLyIgeG1sbnM6eHNpPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgeG1sbnM6b3BmPSJodHRwOi8vd3d3LmlkcGYub3JnLzIwMDcvb3BmIj48ZGM6aWRlbnRpZmllciBpZD0iQm9va0lkIj5odHRwOi8vZXhhbXBsZS5jb20vYm9vay9mb288L2RjOmlkZW50aWZpZXI+PGRjOnRpdGxlPnNhbXBsZTwvZGM6dGl0bGU+PGRjOmxhbmd1YWdlPmVuPC9kYzpsYW5ndWFnZT48ZGM6Y3JlYXRvcj50aWx5PC9kYzpjcmVhdG9yPjwvbWV0YWRhdGE+PG1hbmlmZXN0PjxpdGVtIGlkPSJzZWN0aW9uXzAuaHRtbCIgaHJlZj0ic2VjdGlvbl8wLmh0bWwiIG1lZGlhLXR5cGU9ImFwcGxpY2F0aW9uL3hodG1sK3htbCI+PC9pdGVtPjxpdGVtIGlkPSJzZWN0aW9uXzEuaHRtbCIgaHJlZj0ic2VjdGlvbl8xLmh0bWwiIG1lZGlhLXR5cGU9ImFwcGxpY2F0aW9uL3hodG1sK3htbCI+PC9pdGVtPjxpdGVtIGlkPSJuY3giIGhyZWY9InRvYy5uY3giIG1lZGlhLXR5cGU9ImFwcGxpY2F0aW9uL3gtZHRibmN4K3htbCI+PC9pdGVtPjwvbWFuaWZlc3Q+PHNwaW5lIHRvYz0ibmN4Ij48aXRlbXJlZiBpZHJlZj0ic2VjdGlvbl8wLmh0bWwiPjwvaXRlbXJlZj48aXRlbXJlZiBpZHJlZj0ic2VjdGlvbl8xLmh0bWwiPjwvaXRlbXJlZj48L3NwaW5lPjwvcGFja2FnZT5QSwMECgAAAAAA3AblPG9hqywUAAAAFAAAAAgAAABtaW1ldHlwZWFwcGxpY2F0aW9uL2VwdWIremlwUEsDBAoAAAAAANwG5TwAAAAAAAAAAAAAAAAJAAAATUVUQS1JTkYvUEsDBAoAAAAAANwG5Ty6T6vP8wAAAPMAAAAWAAAATUVUQS1JTkYvY29udGFpbmVyLnhtbDw/eG1sIHZlcnNpb249IjEuMCIgZW5jb2Rpbmc9IlVURi04Ij8+Cjxjb250YWluZXIgeG1sbnM9InVybjpvYXNpczpuYW1lczp0YzpvcGVuZG9jdW1lbnQ6eG1sbnM6Y29udGFpbmVyIiB2ZXJzaW9uPSIxLjAiPjxyb290ZmlsZXM+PHJvb3RmaWxlIGZ1bGwtcGF0aD0iY29udGVudC5vcGYiIG1lZGlhLXR5cGU9ImFwcGxpY2F0aW9uL29lYnBzLXBhY2thZ2UreG1sIj48L3Jvb3RmaWxlPjwvcm9vdGZpbGVzPjwvY29udGFpbmVyPlBLAQIXAwoAAAAAANwG5TzeiCCNNQEAADUBAAAOAAAAAAAAAAAAAACkgQAAAABzZWN0aW9uXzAuaHRtbFBLAQIXAwoAAAAAANwG5TzrI298NQEAADUBAAAOAAAAAAAAAAAAAACkgWEBAABzZWN0aW9uXzEuaHRtbFBLAQIXAwoAAAAAANwG5TyyTvYhjQIAAI0CAAAHAAAAAAAAAAAAAACkgcICAAB0b2MubmN4UEsBAhcDCgAAAAAA3AblPAK00/tuAwAAbgMAAAsAAAAAAAAAAAAAAKSBdAUAAGNvbnRlbnQub3BmUEsBAhcDCgAAAAAA3AblPG9hqywUAAAAFAAAAAgAAAAAAAAAAAAAAKSBCwkAAG1pbWV0eXBlUEsBAhcDCgAAAAAA3AblPAAAAAAAAAAAAAAAAAkAAAAAAAAAAAAQAO1BRQkAAE1FVEEtSU5GL1BLAQIXAwoAAAAAANwG5Ty6T6vP8wAAAPMAAAAWAAAAAAAAAAAAAACkgWwJAABNRVRBLUlORi9jb250YWluZXIueG1sUEsFBgAAAAAHAAcAlwEAAJMKAAAAAA==

FirefoxRhino (jgate) で動くことを確認しています。生成された ePub ファイルについては ibis readerEPUBReader で読めることを確認している。スペックは E4X を使っているので Firefox でしか動かない。

これを使って「あとで読みたい」と思ったページを ePub にしたり LDR のピンを ePub にするやつとか作りたいな。というかその前にまともに ePub を読めるモバイル端末が欲しい。