AuthorPage.js 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. const BasePage = require('./BasePage');
  2. const utils = require('../utils');
  3. class AuthorPage extends BasePage {
  4. constructor(config) {
  5. super(config);
  6. this.id = 'author';
  7. this.title = 'Авторы';
  8. }
  9. sortBooks(bookList) {
  10. //схлопывание серий
  11. const books = [];
  12. const seriesMap = new Map();
  13. for (const book of bookList) {
  14. if (book.series) {
  15. let seriesIndex = seriesMap.get(book.series);
  16. if (seriesIndex === undefined) {
  17. seriesIndex = books.length;
  18. books.push({
  19. type: 'series',
  20. book,
  21. bookCount: 0,
  22. });
  23. seriesMap.set(book.series, seriesIndex);
  24. }
  25. books[seriesIndex].bookCount++;
  26. } else {
  27. books.push({
  28. type: 'book',
  29. book
  30. });
  31. }
  32. }
  33. //сортировка
  34. books.sort((a, b) => {
  35. if (a.type == 'series') {
  36. return (b.type == 'series' ? a.book.series.localeCompare(b.book.series) : -1);
  37. } else {
  38. return (b.type == 'book' ? a.book.title.localeCompare(b.book.title) : 1);
  39. }
  40. });
  41. return books;
  42. }
  43. sortSeriesBooks(seriesBooks) {
  44. seriesBooks.sort((a, b) => {
  45. const dserno = (a.serno || Number.MAX_VALUE) - (b.serno || Number.MAX_VALUE);
  46. const dtitle = a.title.localeCompare(b.title);
  47. const dext = a.ext.localeCompare(b.ext);
  48. return (dserno ? dserno : (dtitle ? dtitle : dext));
  49. });
  50. return seriesBooks;
  51. }
  52. async body(req) {
  53. const result = {};
  54. const query = {
  55. author: req.query.author || '',
  56. series: req.query.series || '',
  57. genre: req.query.genre || '',
  58. del: 0,
  59. all: req.query.all || '',
  60. depth: 0,
  61. };
  62. query.depth = query.author.length + 1;
  63. if (query.author == '___others') {
  64. query.author = '';
  65. query.depth = 1;
  66. query.others = true;
  67. }
  68. const entry = [];
  69. if (query.series) {
  70. //книги по серии
  71. const bookList = await this.webWorker.getSeriesBookList(query.series);
  72. if (bookList.books) {
  73. let books = bookList.books;
  74. const booksAll = this.filterBooks(books, {del: 0});
  75. const filtered = (query.all ? booksAll : this.filterBooks(books, query));
  76. const sorted = this.sortSeriesBooks(filtered);
  77. if (booksAll.length > filtered.length) {
  78. entry.push(
  79. this.makeEntry({
  80. id: 'all_series_books',
  81. title: '[Все книги серии]',
  82. link: this.navLink({
  83. href: `/${this.id}?author=${encodeURIComponent(query.author)}` +
  84. `&series=${encodeURIComponent(query.series)}&all=1`}),
  85. })
  86. );
  87. }
  88. for (const book of sorted) {
  89. const title = `${book.serno ? `${book.serno}. `: ''}${book.title || 'Без названия'} (${book.ext})`;
  90. entry.push(
  91. this.makeEntry({
  92. id: book._uid,
  93. title,
  94. link: this.acqLink({href: `/book?uid=${encodeURIComponent(book._uid)}`}),
  95. content: {
  96. '*ATTRS': {type: 'text'},
  97. '*TEXT': this.bookAuthor(book.author),
  98. },
  99. })
  100. );
  101. }
  102. }
  103. } else if (query.author && query.author[0] == '=') {
  104. //книги по автору
  105. const bookList = await this.webWorker.getAuthorBookList(0, query.author.substring(1));
  106. if (bookList.books) {
  107. let books = bookList.books;
  108. books = this.sortBooks(this.filterBooks(books, query));
  109. for (const b of books) {
  110. if (b.type == 'series') {
  111. entry.push(
  112. this.makeEntry({
  113. id: b.book._uid,
  114. title: `Серия: ${b.book.series}`,
  115. link: this.navLink({
  116. href: `/${this.id}?author=${encodeURIComponent(query.author)}` +
  117. `&series=${encodeURIComponent(b.book.series)}&genre=${encodeURIComponent(query.genre)}`}),
  118. content: {
  119. '*ATTRS': {type: 'text'},
  120. '*TEXT': `${b.bookCount} книг${utils.wordEnding(b.bookCount, 8)} по автору${(query.genre ? ' (в выбранном жанре)' : '')}`,
  121. },
  122. })
  123. );
  124. } else {
  125. const title = `${b.book.title || 'Без названия'} (${b.book.ext})`;
  126. entry.push(
  127. this.makeEntry({
  128. id: b.book._uid,
  129. title,
  130. link: this.acqLink({href: `/book?uid=${encodeURIComponent(b.book._uid)}`}),
  131. content: {
  132. '*ATTRS': {type: 'text'},
  133. '*TEXT': this.bookAuthor(b.book.author),
  134. },
  135. })
  136. );
  137. }
  138. }
  139. }
  140. } else {
  141. if (query.depth == 1 && !query.genre && !query.others) {
  142. entry.push(
  143. this.makeEntry({
  144. id: 'select_genre',
  145. title: '[Выбрать жанр]',
  146. link: this.navLink({href: `/genre?from=${this.id}`}),
  147. })
  148. );
  149. }
  150. //навигация по каталогу
  151. const queryRes = await this.opdsQuery('author', query, '[Остальные авторы]');
  152. for (const rec of queryRes) {
  153. const e = {
  154. id: rec.id,
  155. title: this.bookAuthor(rec.title),
  156. link: this.navLink({href: `/${this.id}?author=${rec.q}&genre=${encodeURIComponent(query.genre)}`}),
  157. };
  158. let countStr = '';
  159. if (rec.count)
  160. countStr = `${rec.count} автор${utils.wordEnding(rec.count, 0)}${(query.genre ? ' (в выбранном жанре)' : '')}`;
  161. if (!countStr && rec.bookCount && !query.genre)
  162. countStr = `${rec.bookCount} книг${utils.wordEnding(rec.bookCount, 8)}`;
  163. if (countStr) {
  164. e.content = {
  165. '*ATTRS': {type: 'text'},
  166. '*TEXT': countStr,
  167. };
  168. }
  169. entry.push(this.makeEntry(e));
  170. }
  171. }
  172. result.entry = entry;
  173. return this.makeBody(result, req);
  174. }
  175. }
  176. module.exports = AuthorPage;