diff --git a/client/components/Search/BookInfoDialog/BookInfoDialog.vue b/client/components/Search/BookInfoDialog/BookInfoDialog.vue index b7bed34..6dfc51d 100644 --- a/client/components/Search/BookInfoDialog/BookInfoDialog.vue +++ b/client/components/Search/BookInfoDialog/BookInfoDialog.vue @@ -239,7 +239,6 @@ class BookInfoDialog { parseBookInfo() { const bookInfo = this.bookInfo; - const parser = new Fb2Parser(); //cover if (bookInfo.cover) @@ -247,16 +246,10 @@ class BookInfoDialog { //fb2 if (bookInfo.fb2) { - this.fb2 = parser.bookInfoList(bookInfo.fb2, { - valueToString(value, nodePath, origVTS) {//eslint-disable-line no-unused-vars - if (nodePath == 'documentInfo/historyHtml' && value) - return value.replace(/

/g, `

`); + const parser = new Fb2Parser(bookInfo.fb2); - return origVTS(value, nodePath); - }, - }); - - const infoObj = parser.bookInfo(bookInfo.fb2); + const infoObj = parser.bookInfo(); +console.log(JSON.stringify(infoObj, null, 2)); if (infoObj.titleInfo) { let ann = infoObj.titleInfo.annotationHtml; if (ann) { @@ -264,6 +257,15 @@ class BookInfoDialog { this.annotation = ann; } } + + this.fb2 = parser.bookInfoList(infoObj, { + valueToString(value, nodePath, origVTS) {//eslint-disable-line no-unused-vars + if (nodePath == 'documentInfo/historyHtml' && value) + return value.replace(/

/g, `

`); + + return origVTS(value, nodePath); + }, + }); } //book diff --git a/server/core/WebWorker.js b/server/core/WebWorker.js index c862b0d..b1d715c 100644 --- a/server/core/WebWorker.js +++ b/server/core/WebWorker.js @@ -369,7 +369,7 @@ class WebWorker { const link = `${this.config.filesPathStatic}/${hash}`; const bookFile = `${this.config.filesDir}/${hash}`; - const bookFileDesc = `${bookFile}.json`; + const bookFileDesc = `${bookFile}.d.json`; if (!await fs.pathExists(bookFile) || !await fs.pathExists(bookFileDesc)) { if (!await fs.pathExists(bookFile) && extractedFile) { @@ -435,7 +435,7 @@ class WebWorker { if (rows.length) {//хеш найден по bookPath const hash = rows[0].hash; const bookFile = `${this.config.filesDir}/${hash}`; - const bookFileDesc = `${bookFile}.json`; + const bookFileDesc = `${bookFile}.d.json`; if (await fs.pathExists(bookFile) && await fs.pathExists(bookFileDesc)) { link = `${this.config.filesPathStatic}/${hash}`; @@ -467,9 +467,9 @@ class WebWorker { let bookInfo = await this.getBookLink(bookId); const hash = path.basename(bookInfo.link); const bookFile = `${this.config.filesDir}/${hash}`; - const bookFileInfo = `${bookFile}.info`; + const bookFileInfo = `${bookFile}.i.json`; - const restoreBookInfo = async() => { + const restoreBookInfo = async(info) => { const result = {}; const rows = await db.select({table: 'book', where: `@@id(${db.esc(bookId)})`}); @@ -478,10 +478,12 @@ class WebWorker { result.book = book; result.cover = ''; result.fb2 = false; + let parser = null; if (book.ext == 'fb2') { const {fb2, cover, coverExt} = await this.fb2Helper.getDescAndCover(bookFile); - result.fb2 = fb2; + parser = fb2; + result.fb2 = fb2.rawNodes; if (cover) { result.cover = `${this.config.filesPathStatic}/${hash}${coverExt}`; @@ -489,12 +491,16 @@ class WebWorker { } } - return result; + Object.assign(info ,result); + await fs.writeFile(bookFileInfo, JSON.stringify(info)); + + if (this.config.branch === 'development') { + await fs.writeFile(`${bookFile}.dev`, `${JSON.stringify(info, null, 2)}\n\n${parser ? parser.toString({format: true}) : ''}`); + } }; if (!await fs.pathExists(bookFileInfo)) { - Object.assign(bookInfo, await restoreBookInfo()); - await fs.writeFile(bookFileInfo, JSON.stringify(bookInfo, null, 2)); + await restoreBookInfo(bookInfo); } else { await utils.touchFile(bookFileInfo); const info = await fs.readFile(bookFileInfo, 'utf-8'); @@ -506,8 +512,7 @@ class WebWorker { coverFile = `${this.config.publicFilesDir}${tmpInfo.cover}`; if (coverFile && !await fs.pathExists(coverFile)) { - Object.assign(bookInfo, await restoreBookInfo()); - await fs.writeFile(bookFileInfo, JSON.stringify(bookInfo, null, 2)); + await restoreBookInfo(bookInfo); } else { bookInfo = tmpInfo; } diff --git a/server/core/fb2/Fb2Helper.js b/server/core/fb2/Fb2Helper.js index e70e30d..5a3383b 100644 --- a/server/core/fb2/Fb2Helper.js +++ b/server/core/fb2/Fb2Helper.js @@ -63,12 +63,11 @@ class Fb2Helper { pickNode: route => route.indexOf('fictionbook/body') !== 0, }); - const desc = parser.$$('description').toObject(); - const coverImage = parser.inspector(desc).$('description/title-info/coverpage/image'); + const coverImage = parser.$$('/description/title-info/coverpage/image'); let cover = null; let coverExt = ''; - if (coverImage) { + if (coverImage.count) { const coverAttrs = coverImage.attrs(); const href = coverAttrs[`${parser.xlinkNS}:href`]; let coverType = coverAttrs['content-type']; @@ -79,24 +78,21 @@ class Fb2Helper { const binaryId = (href[0] == '#' ? href.substring(1) : href); //найдем нужный image - parser.$$('binary').eachSelf(node => { + for (const node of parser.$$array('/binary')) { let attrs = node.attrs(); if (!attrs) return; - attrs = Object.fromEntries(attrs); if (attrs.id === binaryId) { - const textNode = new Fb2Parser(node.value); - const base64 = textNode.$self('*TEXT').value; - + const base64 = node.text(); cover = (base64 ? Buffer.from(base64, 'base64') : null); } - }); + } } } parser.remove('binary'); - return {fb2: parser.toObject(), cover, coverExt}; + return {fb2: parser, cover, coverExt}; } } diff --git a/server/core/fb2/Fb2Parser.js b/server/core/fb2/Fb2Parser.js index 70e2815..4a23075 100644 --- a/server/core/fb2/Fb2Parser.js +++ b/server/core/fb2/Fb2Parser.js @@ -3,7 +3,7 @@ const XmlParser = require('../xml/XmlParser'); class Fb2Parser extends XmlParser { get xlinkNS() { if (!this._xlinkNS) { - const rootAttrs = this.$self().attrs(); + const rootAttrs = this.selectFirstSelf().attrs(); let ns = 'l'; for (const [key, value] of rootAttrs) { if (value == 'http://www.w3.org/1999/xlink') { @@ -18,27 +18,24 @@ class Fb2Parser extends XmlParser { return this._xlinkNS; } - bookInfo(fb2Object) { + bookInfo() { const result = {}; - if (!fb2Object) - fb2Object = this.toObject(); - - const desc = this.inspector(fb2Object).$('fictionbook/description'); + const desc = this.$$('/description/'); if (!desc) return result; const parseAuthors = (node, tagName) => { const authors = []; - for (const a of node.$$(tagName)) { + for (const a of node.$$array(tagName)) { let names = []; - names.push(a.text('last-name')); - names.push(a.text('first-name')); - names.push(a.text('middle-name')); + names.push(a.text('/last-name')); + names.push(a.text('/first-name')); + names.push(a.text('/middle-name')); names = names.filter(n => n); if (!names.length) - names.push(a.text('nickname')); + names.push(a.text('/nickname')); authors.push(names.join(' ')); } @@ -48,7 +45,7 @@ class Fb2Parser extends XmlParser { const parseSequence = (node, tagName) => { const sequence = []; - for (const s of node.$$(tagName)) { + for (const s of node.$$array(tagName)) { const seqAttrs = s.attrs() || {}; const name = seqAttrs['name'] || null; const num = seqAttrs['number'] || null; @@ -64,7 +61,7 @@ class Fb2Parser extends XmlParser { const info = {}; info.genre = []; - for (const g of titleInfo.$$('genre')) + for (const g of titleInfo.$$array('genre')) info.genre.push(g.text()); info.author = parseAuthors(titleInfo, 'author'); @@ -77,7 +74,7 @@ class Fb2Parser extends XmlParser { info.annotationHtml = null; if (info.annotation) { //annotation как кусок xml - info.annotationXml = (new XmlParser()).fromObject(info.annotation).toString({noHeader: true}); + info.annotationXml = titleInfo.$$('annotation/').toString({noHeader: true}); //annotation как html info.annotationHtml = this.toHtml(info.annotationXml); @@ -97,19 +94,19 @@ class Fb2Parser extends XmlParser { } //title-info - const titleInfo = desc.$('title-info'); + const titleInfo = desc.$$('title-info/'); if (titleInfo) { result.titleInfo = parseTitleInfo(titleInfo); } //src-title-info - const srcTitleInfo = desc.$('src-title-info'); + const srcTitleInfo = desc.$$('src-title-info/'); if (srcTitleInfo) { result.srcTitleInfo = parseTitleInfo(srcTitleInfo); } //document-info - const documentInfo = desc.$('document-info'); + const documentInfo = desc.$$('document-info/'); if (documentInfo) { const info = {}; @@ -118,7 +115,7 @@ class Fb2Parser extends XmlParser { info.date = documentInfo.text('date'); info.srcUrl = []; - for (const url of documentInfo.$$('src-url')) + for (const url of documentInfo.$$array('src-url')) info.srcUrl.push(url.text()); info.srcOcr = documentInfo.text('src-ocr'); @@ -131,7 +128,7 @@ class Fb2Parser extends XmlParser { info.historyHtml = null; if (info.history) { //history как кусок xml - info.historyXml = (new XmlParser()).fromObject(info.history).toString({noHeader: true}); + info.historyXml = documentInfo.$$('history/').toString({noHeader: true}); //history как html info.historyHtml = this.toHtml(info.historyXml); @@ -143,7 +140,7 @@ class Fb2Parser extends XmlParser { } //publish-info - const publishInfo = desc.$('publish-info'); + const publishInfo = desc.$$('publish-info/'); if (publishInfo) { const info = {}; @@ -160,7 +157,7 @@ class Fb2Parser extends XmlParser { return result; } - bookInfoList(fb2Object, options = {}) { + bookInfoList(bookInfo, options = {}) { let { correctMapping = false, valueToString = false, @@ -236,7 +233,7 @@ class Fb2Parser extends XmlParser { ]; mapping = correctMapping(mapping); - const bookInfo = this.bookInfo(fb2Object); + bookInfo = (bookInfo ? bookInfo : this.bookInfo()); //заполняем mapping let result = []; diff --git a/server/core/xml/XmlParser.js b/server/core/xml/XmlParser.js index 4d07ac5..2c073c6 100644 --- a/server/core/xml/XmlParser.js +++ b/server/core/xml/XmlParser.js @@ -817,7 +817,7 @@ class XmlParser extends NodeBase { if (raw.length && !s.last) { if (s.index < raw.length) { raw = raw[s.index]; - if (raw[0] === NODE) + if (raw[0] === NODE && raw[3]) raw = raw[3]; else { raw = []; diff --git a/server/index.js b/server/index.js index 15e387f..9e2e8aa 100644 --- a/server/index.js +++ b/server/index.js @@ -191,7 +191,7 @@ function initStatic(app, config) { if (path.extname(req.path) == '') { const bookFile = `${config.publicFilesDir}${req.path}`; - const bookFileDesc = `${bookFile}.json`; + const bookFileDesc = `${bookFile}.d.json`; let downFileName = ''; //восстановим из json-файла описания