diff --git a/.vscode/launch.json b/.vscode/launch.json
index 653bdc3..2ea791c 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -37,7 +37,8 @@
"name": "Launch Node.JS",
"type": "node",
"request": "launch",
- "program": "${file}"
+ "program": "${workspaceFolder}/test/app.js"
+ // "program": "${file}"
}
]
}
\ No newline at end of file
diff --git a/src/epub.js b/src/epub.js
index 7c26892..e1415ea 100644
--- a/src/epub.js
+++ b/src/epub.js
@@ -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 = `
+
+
+
+
+
+
+${new TextDecoder("utf-8").write(content)}
+
+
+`
+ return cnt
+ }
+}
+
+class EpubOpf{
+ constructor(filename, meta) {
+ this.filename = filename
+ this.meta = meta
+ }
+
+ generate(){
+ let m = this.meta
+ let cnt = `
+
+
+ 2013-03-22T12:24:00Z
+ Please read the legal notice included in this e-book and/or check the copyright status in your country.
+ ${m.metadata.book_id}
+ ${m.metadata.title}
+ ${m.metadata.language}\n`
+
+ if (m.metadata.publisher){
+ cnt += ` ${m.metadata.publisher}\n`
+ }
+ if (m.metadata.cover_image){
+ cnt += ` \n`
+ }
+ // Lauren Baratz-Logsted
+
+ cnt +=' \n \n'
+
+ for (let id in m.manifest){
+ let f = m.manifest[id]
+ if (f.hasOwnProperty('property')){
+ cnt += ` \n`
+ }else{
+ cnt += ` \n`
+ }
+ }
+ cnt += ` \n \n`
+ for (let i in m.spine){
+ cnt += ` \n`
+ }
+ cnt += ' \n \n'
+ cnt += ` \n`
+ cnt += ' \n\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 = `
+
+
+
+
+
+
+
+
+ ${m.metadata.title}
+
+
+`
+ for (let i in this.meta.toc){
+ let toc_item = this.meta.toc[i]
+ cnt +=
+ ` \n`
+ +` ${toc_item.label}\n`
+ +` \n`
+ +' \n'
+ }
+
+ cnt += ' \n\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 = `
+
+
+
+ ${m.metadata.title}
+
+
+ ${m.metadata.title}
+ \n\n\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", `
-
-
-
-
-
-
- `);
+ this.zip.file("META-INF/container.xml",
+`
+
+
+
+
+
+` );
}
- 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"})
}
-}
\ No newline at end of file
+}
+
+if (isNode()){
+ module.exports = EpubWriter
+}
diff --git a/src/sidebar.js b/src/sidebar.js
index ebdf53a..2daec42 100644
--- a/src/sidebar.js
+++ b/src/sidebar.js
@@ -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}))
diff --git a/test/app.js b/test/app.js
index 98f7681..fafc7e6 100644
--- a/test/app.js
+++ b/test/app.js
@@ -1,6 +1,8 @@
-var fs = require("fs");
-var JSZip = require('jszip');
+let fs = require("fs");
+let JSZip = require('jszip');
+let EpubWriter = require('../src/epub')
let zip = new JSZip()
+let epub = new EpubWriter()
new JSZip.external.Promise((resolve, reject)=>{
fs.readFile('test/mythical_man_month__the__essays_on_software_engineering__anniversary_edition.zip',
@@ -18,15 +20,122 @@ new JSZip.external.Promise((resolve, reject)=>{
})
})
.then((zip)=>{
- console.log(zip)
- zip.folder('EPUB').forEach((fileName, _)=>{
- console.log(`${fileName}`)
+ return loadBookInfo(zip)
+ .then((book_info)=>{
+ createEbook(epub, book_info)
+ return copyContent(epub, zip)
+ })
+ .then(()=>{
+ return epub.generateAsync()
+ })
+ .then((file)=>{
+ fs.writeFile('ttttest.epub', file, (err) => {
+ if (err)
+ return console.log(err);
+ })
})
})
.catch((reason)=>{
console.log(`Error: ${reason}`)
})
+function copyContent(epub, zip)
+{
+ let jobs = []
+ zip.folder('EPUB').forEach((fileName, zipObj)=>{
+ console.log(`${fileName}`)
+ jobs.push(
+ zipObj.async('uint8array')
+ .then((buffer)=>{
+ epub.addFile(fileName, buffer)
+ })
+ )
+ })
+ return Promise.all(jobs)
+}
+function loadBookInfo(zip)
+{
+ let book_json = zip.file('EPUB/book.json')
+ if (!book_json){
+ book_json = zip.file('META-INF/book.json')
+ }
+ return book_json.async('string')
+ .then((blob)=>{
+ return JSON.parse(blob)
+ })
+}
-console.log('test')
\ No newline at end of file
+function createEbook(epub, book_info)
+{
+ console.log(`${book_info}`)
+
+ // OPF file info.
+ fillManifest(epub, book_info)
+ fillSpine(epub, book_info)
+ fillGuide(epub, book_info)
+ fillMetadata(epub, book_info)
+
+ // NCX and NAV files.
+ fillToc(epub, book_info)
+}
+
+function fillMetadata(epub, book_info)
+{
+ epub.meta.addTitle(book_info.book_info.title)
+ epub.meta.addLanguage(book_info.book_info.language)
+ epub.meta.addBookId(book_info.book_info.isbn)
+ for (let i in book_info.book_info.authors){
+ let author = book_info.book_info.authors[i]
+ epub.meta.addAuthor(author)
+ }
+ for (let i in book_info.book_info.publishers){
+ let publisher = book_info.book_info.publishers[i]
+ epub.meta.addPublisher(publisher.name)
+ }
+ // # The metadata element or deprecated dc-metadata element contains
+ // # at least one identifier element, at least one title element,
+ // # and at least one language element drawn from the Dublin Core tag
+ // # set.
+ // epub.set_title('Test Title')
+ // epub.set_language('en')
+ // epub.set_direction('ltr')
+ // # epub.set_cover(file_name, content, create_page=True):
+ // # epub.add_author(author, file_as=None, role=None, uid='creator'):
+ // # epub.add_metadata(namespace, name, value, others=None):
+ // # epub.set_unique_metadata(namespace, name, value, others=None):
+
+}
+
+function fillManifest(epub, book_info)
+{
+ for (let key in book_info.book_files){
+ let f = book_info.book_files[key]
+ epub.meta.addManifest(f.filename, f.mime)
+ }
+
+ let f = book_info.book_files[book_info.book_info.cover]
+ epub.meta.addCover(f.filename)
+}
+
+function fillToc(epub, book_info)
+{
+ for (let i in book_info.book_toc){
+ let toc_item = book_info.book_toc[i]
+ epub.meta.addToc(
+ toc_item.filename,
+ toc_item.label,
+ toc_item.depth)
+ }
+}
+
+function fillSpine(epub, book_info)
+{
+ for (let i in book_info.book_info.chapters){
+ let s = book_info.book_info.chapters[i].split('/')
+ epub.meta.addSpine(s[s.length-1])
+ }
+}
+
+function fillGuide(epub, book_info)
+{}
\ No newline at end of file