Generating epub.

This commit is contained in:
Vahagn Khachatryan
2018-12-17 18:24:51 +00:00
parent c579ee72c9
commit 040bb0b6dc
4 changed files with 405 additions and 34 deletions

View File

@@ -1,38 +1,297 @@
var isNode=new Function("try {return this===global;}catch(e){return false;}");
if (isNode()){
var JSZip = require('jszip');
const { TextDecoder } = require('string_decoder');
var generatedBufferType = 'uint8array'
} else {
var generatedBufferType = 'uint8array'
}
class EpubXhtml{
constructor(filename) {
let name = filename.split('.')
name[name.length-1] = 'xhtml'
this.filename = name.join('.')
this.mime = 'application/xhtml+xml'
}
convert(content){
// var blob = new Blob([content],{type:'text/plain'});
// var reader = new FileReader();
// reader.onload = function(evt){callback(evt.target.result);};
// reader.readAsText(blob, encoding);
let cnt = `<?xml version="1.0" encoding="utf-8" standalone="no"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:epub="http://www.idpf.org/2007/ops">
<head>
<title></title>
</head>
<body>
${new TextDecoder("utf-8").write(content)}
</body>
</html>
`
return cnt
}
}
class EpubOpf{
constructor(filename, meta) {
this.filename = filename
this.meta = meta
}
generate(){
let m = this.meta
let cnt = `<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://www.idpf.org/2007/opf"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:dcterms="http://purl.org/dc/terms/"
unique-identifier="pub-id"
version="3.0">
<metadata>
<meta property="dcterms:modified">2013-03-22T12:24:00Z</meta>
<dc:rights>Please read the legal notice included in this e-book and/or check the copyright status in your country.</dc:rights>
<dc:identifier id="pub-id">${m.metadata.book_id}</dc:identifier>
<dc:title>${m.metadata.title}</dc:title>
<dc:language>${m.metadata.language}</dc:language>\n`
if (m.metadata.publisher){
cnt += ` <dc:publisher>${m.metadata.publisher}</dc:publisher>\n`
}
if (m.metadata.cover_image){
cnt += ` <meta content="cover-image" name="${m.metadata.cover_image}"/>\n`
}
// <dc:creator opf:file-as="Greatness, Georgia's" opf:role="aut">Lauren Baratz-Logsted</dc:creator>
cnt +=' </metadata>\n <manifest>\n'
for (let id in m.manifest){
let f = m.manifest[id]
if (f.hasOwnProperty('property')){
cnt += ` <item id="${f.id}" media-type="${f.mime}" href="${f.filename}" properties="${f.property}"/>\n`
}else{
cnt += ` <item id="${f.id}" media-type="${f.mime}" href="${f.filename}"/>\n`
}
}
cnt += ` </manifest>\n <spine toc="${m.getId(m.ncx().filename)}">\n`
for (let i in m.spine){
cnt += ` <itemref idref="${m.spine[i]}" />\n`
}
cnt += ' </spine>\n <guide>\n'
cnt += ` <reference href="${m.nav().filename}" title="Table of Contents" type="toc"/>\n`
cnt += ' </guide>\n</package>\n'
return cnt
}
}
class EpubNcx{
constructor(filename, meta) {
this.filename = filename
this.meta = meta
this.mime = 'application/x-dtbncx+xml'
}
generate(){
let m = this.meta
let cnt = `<?xml version="1.0" encoding="UTF-8"?>
<ncx xmlns="http://www.daisy.org/z3986/2005/ncx/" xml:lang="en" version="2005-1">
<head>
<meta name="dtb:uid" content="${m.metadata.book_id}"/>
<meta name="dtb:depth" content="2"/>
<meta name="dtb:totalPageCount" content="0"/>
<meta name="dtb:maxPageNumber" content="0"/>
</head>
<docTitle>
<text>${m.metadata.title}</text>
</docTitle>
<navMap>
`
for (let i in this.meta.toc){
let toc_item = this.meta.toc[i]
cnt +=
` <navPoint class="chapter" id="navpoint-${i}" playOrder="${i}">\n`
+` <navLabel><text>${toc_item.label}</text></navLabel>\n`
+` <content src="${toc_item.filename}"/>\n`
+' </navPoint>\n'
}
cnt += ' </navMap>\n</ncx>\n'
return cnt
}
}
class EpubNav{
constructor(filename, meta) {
this.filename = filename
this.meta = meta
this.mime = 'application/xhtml+xml'
}
generate(){
let m = this.meta
let cnt = `<?xml version="1.0" encoding="utf-8" standalone="no"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:epub="http://www.idpf.org/2007/ops">
<head>
<title>${m.metadata.title}</title>
</head>
<body>
<h1>${m.metadata.title}</h1>
<nav epub:type="toc" id="toc">
<h2>Table Of Content</h2>
<ol>
`
for (let i in this.meta.toc){
let toc_item = this.meta.toc[i]
cnt += ` <li><a href="${toc_item.filename}">${toc_item.label}</a></li>\n`
}
cnt += ' </ol>\n </nav>\n</body>\n</html>\n'
return cnt
}
}
class EpubMeta{
constructor() {
this.zip = new JSZip();
this.metadata = {
book_id: 'book_id',
title: 'title',
language: 'en',
author: 'author',
publisher: 'publisher',
cover_image: 'cover.img'
}
this.manifest = {}
this.spine = []
this.guide = []
this.toc = []
this.override = {}
this.addManifest(this.ncx().filename, this.ncx().mime)
this.addManifest(this.nav().filename, this.nav().mime, 'nav')
this.manifest[this.nav().filename].property = 'nav' //TODO
}
addBookId(book_id){
this.metadata.book_id = book_id
}
addTitle(title){
this.metadata.title = title
}
addAuthor(author){
this.metadata.author = author
}
addPublisher(publisher){
this.metadata.publisher = publisher
}
addLanguage(lang){
this.metadata.language = lang
}
addMetaData(){
}
addManifest(filename, mime){
let key = filename
if (mime.startsWith('text/html')){
let o = new EpubXhtml(filename)
this.override[key] = o
filename = o.filename
mime = o.mime
}
let id = 'id_' + filename.replace(/[^a-z0-9]/gi, '_').toLowerCase()
this.manifest[key] =
{
filename : filename,
mime : mime,
id : id
}
}
getId(filename){
return this.manifest[filename].id
}
addSpine(filename){
this.spine.push(this.manifest[filename].id)
}
addCover(filename){
this.manifest[filename].property = 'cover-image'
}
addToc(filename, label, depth){
if (filename in this.override){
filename = this.override[filename].filename
}
this.toc.push({
filename: filename,
label: label,
depth: depth
})
}
opf(){
return new EpubOpf("content.opf", this)
}
ncx(){
return new EpubNcx("content.ncx", this)
}
nav(){
return new EpubNav("content.xhtml", this)
}
}
class EpubWriter{
constructor(book_id) {
this.zip = new JSZip();
this.filename = "test";
this.meta = new EpubMeta();
this.override = {}
this.createEpubStruct();
// this.image
// this.book_id = book_id;
// this.raw_book = [];
// this.chapter_list = [];
}
createEpubStruct(){
this.zip.file("mimetype", "application/epub+zip", {compression: "STORE"});
this.zip.file("META-INF/container.xml", `
<?xml version='1.0' encoding='utf-8'?>
<container xmlns="urn:oasis:names:tc:opendocument:xmlns:container" version="1.0">
<rootfiles>
<rootfile media-type="application/oebps-package+xml" full-path="EPUB/content.opf"/>
</rootfiles>
</container>
`);
this.zip.file("META-INF/container.xml",
`<?xml version='1.0' encoding='utf-8'?>
<container xmlns="urn:oasis:names:tc:opendocument:xmlns:container" version="1.0">
<rootfiles>
<rootfile media-type="application/oebps-package+xml" full-path="EPUB/content.opf"/>
</rootfiles>
</container>
` );
}
addFile(name, content){
console.log(`epub ${name}: ${content}`)
this.zip.file("EPUB/"+name, content)
addFile(filename, content){
console.log(`epub ${filename}: ${content}`)
if (filename in this.meta.override){
let o = this.meta.override[filename]
filename = o.filename
content = o.convert(content)
}
this.zip.file("EPUB/"+filename, content)
}
generateAsync(){
this.addFile(this.meta.ncx().filename, this.meta.ncx().generate())
this.addFile(this.meta.nav().filename, this.meta.nav().generate())
this.addFile(this.meta.opf().filename, this.meta.opf().generate())
return this.zip.generateAsync({
type: 'blob',
compression: "DEFLATE"})
type: generatedBufferType,
compression: "DEFLATE"})
}
}
}
if (isNode()){
module.exports = EpubWriter
}

View File

@@ -39,9 +39,10 @@ function extractBookId(url){
class Book{
constructor(book_id, epub) {
this.book_id = book_id;
this.raw_book = {};
this.chapter_list = [];
this.book_id = book_id
this.raw_book = {}
this.chapter_list = []
this.chapter_info = {}
this.book_files = {}
this.book_info = null
this.book_toc = null
@@ -116,7 +117,8 @@ class Book{
renderProgress(`${chapter}`)
return this.downloadJson(chapter)
.then((json) => {
return this.extractChapterAssets(json)
this.chapter_info[chapter] = json
return this.extractChapterAssets(json)
})
},{concurrency: 10}))