diff --git a/client/components/Search/BookInfoDialog/BookInfoDialog.vue b/client/components/Search/BookInfoDialog/BookInfoDialog.vue index 1c88f49..a66c857 100644 --- a/client/components/Search/BookInfoDialog/BookInfoDialog.vue +++ b/client/components/Search/BookInfoDialog/BookInfoDialog.vue @@ -16,7 +16,6 @@
-{{ annotation }}
@@ -62,6 +61,7 @@ class BookInfoDialog {
//info props
coverSrc = '';
annotation = '';
+ info = [];
created() {
this.commit = this.$store.commit;
@@ -78,24 +78,25 @@ class BookInfoDialog {
//defaults
this.coverSrc = '';
this.annotation = '';
+ this.info = [];
//cover
if (bookInfo.cover)
this.coverSrc = bookInfo.cover;
//fb2
- if (bookInfo.fb2 && bookInfo.fb2.fictionbook && bookInfo.fb2.fictionbook.description) {
- const desc = parser.inspector(bookInfo.fb2.fictionbook.description);
-
- //annotation
- const annObj = desc.v('title-info/annotation');
- if (annObj) {
- this.annotation = parser.fromObject(annObj).toString({noHeader: true, format: true});
- this.annotation = parser.toHtml(this.annotation);
- this.annotation = this.annotation.replace(//g, `
`); + if (bookInfo.fb2) { + this.info = parser.bookInfoList(bookInfo.fb2); + + const infoObj = parser.bookInfo(bookInfo.fb2); + if (infoObj) { + let ann = infoObj.titleInfo.annotationHtml; + if (ann) { + ann = ann.replace(/
/g, `
`); + this.annotation = ann; + } } } - } okClick() { diff --git a/server/core/fb2/Fb2Helper.js b/server/core/fb2/Fb2Helper.js index 709844c..e70e30d 100644 --- a/server/core/fb2/Fb2Helper.js +++ b/server/core/fb2/Fb2Helper.js @@ -70,7 +70,7 @@ class Fb2Helper { let coverExt = ''; if (coverImage) { const coverAttrs = coverImage.attrs(); - const href = coverAttrs['l:href']; + const href = coverAttrs[`${parser.xlinkNS}:href`]; let coverType = coverAttrs['content-type']; coverType = (coverType == 'image/jpg' || coverType == 'application/octet-stream' ? 'image/jpeg' : coverType); coverExt = (coverType == 'image/png' ? '.png' : '.jpg'); diff --git a/server/core/fb2/Fb2Parser.js b/server/core/fb2/Fb2Parser.js index 13806bf..f8cdd6a 100644 --- a/server/core/fb2/Fb2Parser.js +++ b/server/core/fb2/Fb2Parser.js @@ -1,15 +1,159 @@ const XmlParser = require('../xml/XmlParser'); class Fb2Parser extends XmlParser { + get xlinkNS() { + if (!this._xlinkNS) { + const rootAttrs = this.$self().attrs(); + let ns = 'l'; + for (const [key, value] of rootAttrs) { + if (value == 'http://www.w3.org/1999/xlink') { + ns = key.split(':')[1] || ns; + break; + } + } + + this._xlinkNS = ns; + } + + return this._xlinkNS; + } + bookInfo(fb2Object) { + const result = {}; + if (!fb2Object) fb2Object = this.toObject(); - //const result = {}; + const desc = this.inspector(fb2Object).$('fictionbook/description'); + if (!desc) + return result; + + //title-info + const titleInfo = desc.$('title-info'); + if (titleInfo) { + const info = {}; + + info.genre = []; + for (const g of titleInfo.$$('genre')) + info.genre.push(g.text()); + + const parseAuthors = (tagName) => { + const authors = []; + for (const a of titleInfo.$$(tagName)) { + let names = []; + 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')); + + authors.push(names.join(' ')); + } + + return authors; + } + + info.author = parseAuthors('author'); + + info.bookTitle = titleInfo.text('book-title'); + + info.annotation = null; + info.annotationHtml = null; + const node = titleInfo.$('annotation') && titleInfo.$('annotation').value; + + if (node) { + //annotation как кусок xml + info.annotation = (new XmlParser()).fromObject(node).toString({noHeader: true}); + + //annotation как html + info.annotationHtml = this.toHtml(info.annotation); + } + + info.keywords = titleInfo.text('keywords'); + info.date = titleInfo.text('date'); + info.coverpage = titleInfo.$('coverpage') && titleInfo.$('coverpage').value; + info.lang = titleInfo.text('lang'); + info.srcLang = titleInfo.text('src-lang'); + + info.translator = parseAuthors('translator'); + + const seqAttrs = titleInfo.attrs('sequence') || new Map(); + info.sequenceName = seqAttrs.get('name') || null; + info.sequenceNum = seqAttrs.get('number') || null; + info.sequenceLang = seqAttrs.get('xml:lang') || null; + + result.titleInfo = info; + } + + return result; } - bookInfoList(fb2Object) { + bookInfoList(fb2Object, options = {}) { + let { + correctMapping = false, + valueToString = false, + } = options; + + if (!correctMapping) + correctMapping = mapping => mapping; + + if (!valueToString) { + valueToString = (value, nodePath) => {//eslint-disable-line no-unused-vars + if (typeof(value) === 'string') { + return value; + } else if (Array.isArray(value)) { + return value.join(', '); + } else if (typeof(value) === 'object') { + return JSON.stringify(value); + } + + return value; + }; + } + + let mapping = [ + {name: 'titleInfo', label: 'Общая информация', value: [ + {name: 'author', label: 'Автор(ы)'}, + {name: 'bookTitle', label: 'Название'}, + {name: 'sequenceName', label: 'Серия'}, + {name: 'sequenceNum', label: 'Номер в серии'}, + {name: 'genre', label: 'Жанр'}, + + {name: 'date', label: 'Дата'}, + {name: 'lang', label: 'Язык книги'}, + {name: 'srcLang', label: 'Язык оригинала'}, + {name: 'translator', label: 'Переводчик(и)'}, + {name: 'keywords', label: 'Ключевые слова'}, + ]}, + ]; + + mapping = correctMapping(mapping); + const bookInfo = this.bookInfo(fb2Object); + + //заполняем mapping + let result = []; + for (const item of mapping) { + const itemOut = {name: item.name, label: item.label, value: []}; + const info = bookInfo[item.name]; + if (!info) + continue; + + for (const subItem of item.value) { + if (info[subItem.name] !== null) + itemOut.value.push({ + name: subItem.name, + label: subItem.label, + value: valueToString(info[subItem.name]) + }); + } + + if (itemOut.value.length) + result.push(itemOut); + } + + return result; } toHtml(xmlString) { diff --git a/server/core/xml/ObjectInspector.js b/server/core/xml/ObjectInspector.js index 616228d..0adc188 100644 --- a/server/core/xml/ObjectInspector.js +++ b/server/core/xml/ObjectInspector.js @@ -56,7 +56,7 @@ class ObjectInspector { } if (raw === null) - return null; + return []; raw = (Array.isArray(raw) ? raw : [raw]);