BookPage.js 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. const path = require('path');
  2. const _ = require('lodash');
  3. const dayjs = require('dayjs');
  4. const BasePage = require('./BasePage');
  5. const Fb2Parser = require('../fb2/Fb2Parser');
  6. class BookPage extends BasePage {
  7. constructor(config) {
  8. super(config);
  9. this.id = 'book';
  10. this.title = 'Книга';
  11. }
  12. formatSize(size) {
  13. size = size/1024;
  14. let unit = 'KB';
  15. if (size > 1024) {
  16. size = size/1024;
  17. unit = 'MB';
  18. }
  19. return `${size.toFixed(1)} ${unit}`;
  20. }
  21. inpxInfo(bookRec) {
  22. const mapping = [
  23. {name: 'fileInfo', label: 'Информация о файле', value: [
  24. {name: 'folder', label: 'Папка'},
  25. {name: 'file', label: 'Файл'},
  26. {name: 'size', label: 'Размер'},
  27. {name: 'date', label: 'Добавлен'},
  28. {name: 'del', label: 'Удален'},
  29. {name: 'libid', label: 'LibId'},
  30. {name: 'insno', label: 'InsideNo'},
  31. ]},
  32. {name: 'titleInfo', label: 'Общая информация', value: [
  33. {name: 'author', label: 'Автор(ы)'},
  34. {name: 'title', label: 'Название'},
  35. {name: 'series', label: 'Серия'},
  36. {name: 'genre', label: 'Жанр'},
  37. {name: 'librate', label: 'Оценка'},
  38. {name: 'lang', label: 'Язык книги'},
  39. {name: 'keywords', label: 'Ключевые слова'},
  40. ]},
  41. ];
  42. const valueToString = (value, nodePath, b) => {//eslint-disable-line no-unused-vars
  43. if (nodePath == 'fileInfo/file')
  44. return `${value}.${b.ext}`;
  45. if (nodePath == 'fileInfo/size')
  46. return `${this.formatSize(value)} (${value.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1 ')} Bytes)`;
  47. if (nodePath == 'fileInfo/date')
  48. return dayjs(value, 'YYYY-MM-DD').format('DD.MM.YYYY');
  49. if (nodePath == 'fileInfo/del')
  50. return (value ? 'Да' : null);
  51. if (nodePath == 'fileInfo/insno')
  52. return (value ? value : null);
  53. if (nodePath == 'titleInfo/author')
  54. return value.split(',').join(', ');
  55. if (nodePath == 'titleInfo/librate' && !value)
  56. return null;
  57. if (typeof(value) === 'string') {
  58. return value;
  59. }
  60. return (value.toString ? value.toString() : '');
  61. };
  62. let result = [];
  63. const book = _.cloneDeep(bookRec);
  64. book.series = [book.series, book.serno].filter(v => v).join(' #');
  65. for (const item of mapping) {
  66. const itemOut = {name: item.name, label: item.label, value: []};
  67. for (const subItem of item.value) {
  68. const subItemOut = {
  69. name: subItem.name,
  70. label: subItem.label,
  71. value: valueToString(book[subItem.name], `${item.name}/${subItem.name}`, book)
  72. };
  73. if (subItemOut.value)
  74. itemOut.value.push(subItemOut);
  75. }
  76. if (itemOut.value.length)
  77. result.push(itemOut);
  78. }
  79. return result;
  80. }
  81. htmlInfo(title, infoList) {
  82. let info = '';
  83. for (const part of infoList) {
  84. if (part.value.length)
  85. info += `<h3>${part.label}</h3>`;
  86. for (const rec of part.value)
  87. info += `<p>${rec.label}: ${rec.value}</p>`;
  88. }
  89. if (info)
  90. info = `<h2>${title}</h2>${info}`;
  91. return info;
  92. }
  93. async body(req) {
  94. const result = {};
  95. result.link = this.baseLinks(req, true);
  96. const bookUid = req.query.uid;
  97. const entry = [];
  98. if (bookUid) {
  99. const {bookInfo} = await this.webWorker.getBookInfo(bookUid);
  100. if (bookInfo) {
  101. const {genreMap} = await this.getGenres();
  102. //format
  103. const ext = bookInfo.book.ext;
  104. let fileFormat = `${ext}+zip`;
  105. let downHref = bookInfo.link;
  106. if (ext === 'mobi') {
  107. fileFormat = 'x-mobipocket-ebook';
  108. } else if (ext == 'epub') {
  109. //
  110. } else {
  111. downHref = `${bookInfo.link}/zip`;
  112. }
  113. //entry
  114. const e = this.makeEntry({
  115. id: bookUid,
  116. title: bookInfo.book.title || 'Без названия',
  117. });
  118. //author bookInfo
  119. if (bookInfo.book.author) {
  120. e.author = bookInfo.book.author.split(',').map(a => ({name: a}));
  121. }
  122. e['dc:language'] = bookInfo.book.lang;
  123. e['dc:format'] = fileFormat;
  124. //genre
  125. const genre = bookInfo.book.genre.split(',');
  126. for (const g of genre) {
  127. const genreName = genreMap.get(g);
  128. if (genreName) {
  129. if (!e.category)
  130. e.category = [];
  131. e.category.push({
  132. '*ATTRS': {term: genreName, label: genreName},
  133. });
  134. }
  135. }
  136. let content = '';
  137. let ann = '';
  138. let info = '';
  139. //fb2 info
  140. if (bookInfo.fb2) {
  141. const parser = new Fb2Parser(bookInfo.fb2);
  142. const infoObj = parser.bookInfo();
  143. if (infoObj.titleInfo) {
  144. //author fb2Info
  145. if (!e.author && infoObj.titleInfo.author.length) {
  146. e.author = infoObj.titleInfo.author.map(a => ({name: a}));
  147. }
  148. ann = infoObj.titleInfo.annotationHtml || '';
  149. const infoList = parser.bookInfoList(infoObj);
  150. info += this.htmlInfo('Fb2 инфо', infoList);
  151. }
  152. }
  153. //content
  154. info += this.htmlInfo('Inpx инфо', this.inpxInfo(bookInfo.book));
  155. content = `${ann}${info}`;
  156. if (content) {
  157. e.content = {
  158. '*ATTRS': {type: 'text/html'},
  159. '*TEXT': this.escape(content),
  160. };
  161. }
  162. //links
  163. e.link = [ this.downLink({href: downHref, type: `application/${fileFormat}`}) ];
  164. if (bookInfo.cover) {
  165. let coverType = 'image/jpeg';
  166. if (path.extname(bookInfo.cover) == '.png')
  167. coverType = 'image/png';
  168. e.link.push(this.imgLink({href: bookInfo.cover, type: coverType}));
  169. e.link.push(this.imgLink({href: bookInfo.cover, type: coverType, thumb: true}));
  170. }
  171. entry.push(e);
  172. }
  173. }
  174. result.entry = entry;
  175. return this.makeBody(result, req);
  176. }
  177. }
  178. module.exports = BookPage;