diff --git a/src/sources/multisrc/readwn/ReadwnGenerator.js b/src/sources/multisrc/readwn/ReadwnGenerator.js
index 885bbe679..029e0663c 100644
--- a/src/sources/multisrc/readwn/ReadwnGenerator.js
+++ b/src/sources/multisrc/readwn/ReadwnGenerator.js
@@ -4,18 +4,198 @@ const ReadwnScraper = new MultiSrcScraper(
68,
'https://www.wuxiap.com/',
'Readwn.com',
+ {
+ label: 'Genre / Category',
+ values: [
+ { label: 'All', value: 'all' },
+ { label: 'Action', value: 'action' },
+ { label: 'Adventure', value: 'adventure' },
+ { label: 'Chinese', value: 'chinese' },
+ { label: 'Comedy', value: 'comedy' },
+ { label: 'Contemporary Romance', value: 'contemporary-romance' },
+ { label: 'Drama', value: 'drama' },
+ { label: 'Eastern Fantasy', value: 'eastern-fantasy' },
+ { label: 'Ecchi', value: 'ecchi' },
+ { label: 'Erciyuan', value: 'erciyuan' },
+ { label: 'Faloo', value: 'faloo' },
+ { label: 'Fan-Fiction', value: 'fan-fiction' },
+ { label: 'Fantasy', value: 'fantasy' },
+ { label: 'Fantasy Romance', value: 'fantasy-romance' },
+ { label: 'Game', value: 'game' },
+ { label: 'Gender Bender', value: 'gender-bender' },
+ { label: 'Harem', value: 'harem' },
+ { label: 'Hentai', value: 'hentai' },
+ { label: 'Historical', value: 'historical' },
+ { label: 'Horror', value: 'horror' },
+ { label: 'Isekai', value: 'isekai' },
+ { label: 'Japanese', value: 'japanese' },
+ { label: 'Josei', value: 'josei' },
+ { label: 'Korean', value: 'korean' },
+ { label: 'Lolicon', value: 'lolicon' },
+ { label: 'Magic', value: 'magic' },
+ { label: 'Magical Realism', value: 'magical-realism' },
+ { label: 'Martial Arts', value: 'martial-arts' },
+ { label: 'Mecha', value: 'mecha' },
+ { label: 'Military', value: 'military' },
+ { label: 'Mystery', value: 'mystery' },
+ { label: 'Official Circles', value: 'official_circles' },
+ { label: 'Psychological', value: 'psychological' },
+ { label: 'Romance', value: 'romance' },
+ { label: 'School Life', value: 'school-life' },
+ { label: 'Sci-fi', value: 'sci-fi' },
+ { label: 'Science Fiction', value: 'science_fiction' },
+ { label: 'Seinen', value: 'seinen' },
+ { label: 'Shoujo', value: 'shoujo' },
+ { label: 'Shoujo Ai', value: 'shoujo-ai' },
+ { label: 'Shounen', value: 'shounen' },
+ { label: 'Shounen Ai', value: 'shounen-ai' },
+ { label: 'Slice of Life', value: 'slice-of-life' },
+ { label: 'Sports', value: 'sports' },
+ { label: 'Supernatural', value: 'supernatural' },
+ { label: 'Suspense Thriller', value: 'suspense_thriller' },
+ { label: 'Tragedy', value: 'tragedy' },
+ { label: 'Travel Through Time', value: 'travel_through_time' },
+ { label: 'Two-dimensional', value: 'two-dimensional' },
+ { label: 'Urban', value: 'urban' },
+ { label: 'Urban Life', value: 'urban-life' },
+ { label: 'Video Games', value: 'video-games' },
+ { label: 'Virtual Reality', value: 'virtual-reality' },
+ { label: 'Wuxia', value: 'wuxia' },
+ { label: 'Wuxia Xianxia', value: 'wuxia_xianxia' },
+ { label: 'Xianxia', value: 'xianxia' },
+ { label: 'Xuanhuan', value: 'xuanhuan' },
+ { label: 'Yaoi', value: 'yaoi' },
+ { label: 'Yuri', value: 'yuri' },
+ ],
+ },
);
const NovelmtScraper = new MultiSrcScraper(
99,
'https://www.wuxiapub.com/',
'Novelmt.com',
+ {
+ label: 'Genre / Category',
+ values: [
+ { label: 'All', value: 'all' },
+ { label: 'Action', value: 'action' },
+ { label: 'Adult', value: 'adult' },
+ { label: 'Adventure', value: 'adventure' },
+ { label: 'Billionaire', value: 'billionaire' },
+ { label: 'CEO', value: 'ceo' },
+ { label: 'Chinese', value: 'chinese' },
+ { label: 'Comedy', value: 'comedy' },
+ { label: 'Contemporary Romance', value: 'contemporary-romance' },
+ { label: 'Drama', value: 'drama' },
+ { label: 'Eastern Fantasy', value: 'eastern-fantasy' },
+ { label: 'Ecchi', value: 'ecchi' },
+ { label: 'Erciyuan', value: 'erciyuan' },
+ { label: 'Faloo', value: 'faloo' },
+ { label: 'Fan-Fiction', value: 'fan-fiction' },
+ { label: 'Fantasy', value: 'fantasy' },
+ { label: 'Fantasy Romance', value: 'fantasy-romance' },
+ { label: 'Farming', value: 'farming' },
+ { label: 'Game', value: 'game' },
+ { label: 'Games', value: 'games' },
+ { label: 'Gay Romance', value: 'gay-romance' },
+ { label: 'Gender Bender', value: 'gender-bender' },
+ { label: 'Harem', value: 'harem' },
+ { label: 'Historical', value: 'historical' },
+ { label: 'Historical Romance', value: 'historical-romance' },
+ { label: 'Horror', value: 'horror' },
+ { label: 'Isekai', value: 'isekai' },
+ { label: 'Japanese', value: 'japanese' },
+ { label: 'Josei', value: 'josei' },
+ { label: 'Korean', value: 'korean' },
+ { label: 'Lolicon', value: 'lolicon' },
+ { label: 'Magic', value: 'magic' },
+ { label: 'Magical Realism', value: 'magical-realism' },
+ { label: 'Martial Arts', value: 'martial-arts' },
+ { label: 'Mature', value: 'mature' },
+ { label: 'Mecha', value: 'mecha' },
+ { label: 'Military', value: 'military' },
+ { label: 'Modern Life', value: 'modern-life' },
+ { label: 'Modern Romance', value: 'modern-romance' },
+ { label: 'Mystery', value: 'mystery' },
+ { label: 'Psychological', value: 'psychological' },
+ { label: 'Romance', value: 'romance' },
+ { label: 'Romantic', value: 'romantic' },
+ { label: 'School Life', value: 'school-life' },
+ { label: 'Sci-fi', value: 'sci-fi' },
+ { label: 'Seinen', value: 'seinen' },
+ { label: 'Shoujo', value: 'shoujo' },
+ { label: 'Shoujo Ai', value: 'shoujo-ai' },
+ { label: 'Shounen', value: 'shounen' },
+ { label: 'Shounen Ai', value: 'shounen-ai' },
+ { label: 'Slice of Life', value: 'slice-of-life' },
+ { label: 'Smut', value: 'smut' },
+ { label: 'Sports', value: 'sports' },
+ { label: 'Supernatural', value: 'supernatural' },
+ { label: 'Tragedy', value: 'tragedy' },
+ { label: 'Two-dimensional', value: 'two-dimensional' },
+ { label: 'Urban', value: 'urban' },
+ { label: 'Urban Life', value: 'urban-life' },
+ { label: 'Video Games', value: 'video-games' },
+ { label: 'Virtual Reality', value: 'virtual-reality' },
+ { label: 'Wuxia', value: 'wuxia' },
+ { label: 'Xianxia', value: 'xianxia' },
+ { label: 'Xuanhuan', value: 'xuanhuan' },
+ { label: 'Yaoi', value: 'yaoi' },
+ { label: 'Yuri', value: 'yuri' },
+ ],
+ },
);
const LtnovelScraper = new MultiSrcScraper(
100,
'https://www.ltnovel.com/',
'Ltnovel.com',
+ {
+ label: 'Genre / Category',
+ values: [
+ { label: 'All', value: 'all' },
+ { label: 'Action', value: 'action' },
+ { label: 'Adult', value: 'adult' },
+ { label: 'Adventure', value: 'adventure' },
+ { label: 'Comedy', value: 'comedy' },
+ { label: 'Contemporary Romance', value: 'contemporary-romance' },
+ { label: 'Drama', value: 'drama' },
+ { label: 'Eastern Fantasy', value: 'eastern-fantasy' },
+ { label: 'Ecchi', value: 'ecchi' },
+ { label: 'Fantasy', value: 'fantasy' },
+ { label: 'Fantasy Romance', value: 'fantasy-romance' },
+ { label: 'Game', value: 'game' },
+ { label: 'Gender Bender', value: 'gender-bender' },
+ { label: 'Harem', value: 'harem' },
+ { label: 'Historical', value: 'historical' },
+ { label: 'Horror', value: 'horror' },
+ { label: 'Josei', value: 'josei' },
+ { label: 'Lolicon', value: 'lolicon' },
+ { label: 'Magical Realism', value: 'magical-realism' },
+ { label: 'Martial Arts', value: 'martial-arts' },
+ { label: 'Mature', value: 'mature' },
+ { label: 'Mecha', value: 'mecha' },
+ { label: 'Mystery', value: 'mystery' },
+ { label: 'Psychological', value: 'psychological' },
+ { label: 'Romance', value: 'romance' },
+ { label: 'School Life', value: 'school-life' },
+ { label: 'Sci-fi', value: 'sci-fi' },
+ { label: 'Seinen', value: 'seinen' },
+ { label: 'Shoujo', value: 'shoujo' },
+ { label: 'Shounen', value: 'shounen' },
+ { label: 'Shounen Ai', value: 'shounen-ai' },
+ { label: 'Slice of Life', value: 'slice-of-life' },
+ { label: 'Smut', value: 'smut' },
+ { label: 'Sports', value: 'sports' },
+ { label: 'Supernatural', value: 'supernatural' },
+ { label: 'Tragedy', value: 'tragedy' },
+ { label: 'Video Games', value: 'video-games' },
+ { label: 'Wuxia', value: 'wuxia' },
+ { label: 'Xianxia', value: 'xianxia' },
+ { label: 'Xuanhuan', value: 'xuanhuan' },
+ { label: 'Yaoi', value: 'yaoi' },
+ ],
+ },
);
export { ReadwnScraper, NovelmtScraper, LtnovelScraper };
diff --git a/src/sources/multisrc/readwn/ReadwnScraper.js b/src/sources/multisrc/readwn/ReadwnScraper.js
index be6856034..96b504627 100644
--- a/src/sources/multisrc/readwn/ReadwnScraper.js
+++ b/src/sources/multisrc/readwn/ReadwnScraper.js
@@ -1,22 +1,54 @@
+import { FilterInputs } from '../../types/filterTypes';
import * as cheerio from 'cheerio';
import QueryString from 'qs';
class ReadwnScraper {
- constructor(sourceId, baseUrl, sourceName) {
+ constructor(sourceId, baseUrl, sourceName, genres) {
this.sourceId = sourceId;
this.baseUrl = baseUrl;
this.sourceName = sourceName;
+ this.filters = [
+ {
+ key: 'sort',
+ label: 'Sort By',
+ values: [
+ { label: 'New', value: 'newstime' },
+ { label: 'Popular', value: 'onclick' },
+ { label: 'Updates', value: 'lastdotime' },
+ ],
+ inputType: FilterInputs.Picker,
+ },
+ {
+ key: 'status',
+ label: 'Status',
+ values: [
+ { label: 'All', value: 'all' },
+ { label: 'Completed', value: 'Completed' },
+ { label: 'Ongoing', value: 'Ongoing' },
+ ],
+ inputType: FilterInputs.Picker,
+ },
+ {
+ key: 'genres',
+ label: genres.label,
+ values: genres.values,
+ inputType: FilterInputs.Picker,
+ },
+ ];
}
- async popularNovels(page, options) {
+ async popularNovels(page, { showLatestNovels, filters }) {
const baseUrl = this.baseUrl;
const sourceId = this.sourceId;
const pageNo = page - 1;
- const url = `${baseUrl}list/all/${
- options?.showLatestNovels ? 'all-lastdotime' : 'all-onclick'
- }-${pageNo}.html`;
+ let url = baseUrl + 'list/';
+ url += (filters?.genres || 'all') + '/';
+ url += (filters?.status || 'all') + '-';
+ url +=
+ (showLatestNovels ? 'lastdotime' : filters?.sort || 'newstime') + '-';
+ url += pageNo + '.html';
const result = await fetch(url);
const body = await result.text();
diff --git a/src/sources/multisrc/rulate/RulateGenerator.js b/src/sources/multisrc/rulate/RulateGenerator.js
index 32c2eedfd..af60f7177 100644
--- a/src/sources/multisrc/rulate/RulateGenerator.js
+++ b/src/sources/multisrc/rulate/RulateGenerator.js
@@ -14,7 +14,7 @@ const RulateScraper = new MultiSrcScraper(
{ label: 'Арт', value: '1' },
{ label: 'Боевик', value: '2' },
{ label: 'Боевые искусства', value: '3' },
- { label: 'Гарем', value: '5' },
+ { label: 'Гаремник', value: '5' },
{ label: 'Героическое фэнтези', value: '7' },
{ label: 'Детектив', value: '8' },
{ label: 'Дзёсэй', value: '9' },
@@ -65,8 +65,6 @@ const RulateScraper = new MultiSrcScraper(
values: [
{ label: '12+', value: '3316' },
{ label: '16+', value: '83' },
- { label: '18+', value: '1749' },
- { label: '21+', value: '3191' },
{ label: 'Абсурд', value: '7973' },
{ label: 'Авантюристы', value: '222' },
{ label: 'Автомат', value: '5272' },
@@ -108,7 +106,6 @@ const RulateScraper = new MultiSrcScraper(
{ label: 'Америка', value: '4082' },
{ label: 'Амнезия', value: '2207' },
{ label: 'Аморальный герой', value: '18' },
- { label: 'Анальный секс', value: '1942' },
{ label: 'Анбу', value: '8129' },
{ label: 'Ангелы', value: '857' },
{ label: 'Ангелы и демоны', value: '1327' },
@@ -139,19 +136,17 @@ const RulateScraper = new MultiSrcScraper(
{ label: 'Басейн', value: '6847' },
{ label: 'Баскетбол', value: '7933' },
{ label: 'Бастарды', value: '76' },
- { label: 'Бдсм', value: '444' },
{ label: 'Бедность', value: '1207' },
{ label: 'Без культивации', value: '668' },
{ label: 'Без любовной линий', value: '2225' },
{ label: 'Без перерождений', value: '262' },
{ label: 'Без попаданца', value: '8065' },
{ label: 'Без системы', value: '747' },
- { label: 'Без цензуры', value: '7525' },
{ label: 'Без юмора', value: '763' },
{ label: 'Бездна', value: '1026' },
{ label: 'Безжалостное домашнее животное', value: '1245' },
{ label: 'Безжалостные персонажи', value: '2986' },
- { label: 'Беззаботные персонажи ', value: '3123' },
+ { label: 'Беззаботные персонажи', value: '3123' },
{ label: 'Безответная любовь', value: '7815' },
{ label: 'Безработный', value: '2202' },
{ label: 'Безумие', value: '37' },
@@ -186,10 +181,7 @@ const RulateScraper = new MultiSrcScraper(
{ label: 'Богоубийца', value: '1253' },
{ label: 'Богохульство', value: '95' },
{ label: 'Боевая академия', value: '2108' },
- { label: 'Боевик', value: '529' },
- { label: 'Боевые искусства', value: '2090' },
{ label: 'Большая грудь', value: '4717' },
- { label: 'Большой член', value: '5299' },
{ label: 'Борос', value: '6533' },
{ label: 'Борьба', value: '1925' },
{ label: 'Борьба за власть', value: '8072' },
@@ -209,7 +201,6 @@ const RulateScraper = new MultiSrcScraper(
{ label: 'Бэтмен', value: '4668' },
{ label: 'В первый раз', value: '6212' },
{ label: 'В этот же мир', value: '49' },
- { label: 'Вагинальный секс', value: '4742' },
{ label: 'Ваканда', value: '8331' },
{ label: 'Валькирии', value: '4047' },
{ label: 'Вампиры', value: '2206' },
@@ -278,7 +269,6 @@ const RulateScraper = new MultiSrcScraper(
{ label: 'Гений', value: '1650' },
{ label: 'Гермиона грейнджер', value: '4280' },
{ label: 'Герои', value: '185' },
- { label: 'Героическое фэнтези', value: '1148' },
{ label: 'Гигаполис', value: '8393' },
{ label: 'Гильгамеш', value: '6031' },
{ label: 'Гильдии', value: '900' },
@@ -312,7 +302,6 @@ const RulateScraper = new MultiSrcScraper(
{ label: 'Главный герой сильный с самого начала', value: '88' },
{ label: 'Главный герой скрывает свою силу', value: '1059' },
{ label: 'Главный герой эгоист', value: '8326' },
- { label: 'Глотание спермы', value: '4491' },
{ label: 'Гномы', value: '1870' },
{ label: 'Гоблины', value: '2029' },
{ label: 'Годзилла', value: '6990' },
@@ -321,7 +310,6 @@ const RulateScraper = new MultiSrcScraper(
{ label: 'Головоломка', value: '1697' },
{ label: 'Горничные', value: '8091' },
{ label: 'Гробница', value: '388' },
- { label: 'Групповой секс', value: '1314' },
{ label: 'Дазай осаму', value: '4112' },
{ label: 'Даньмэй', value: '3411' },
{ label: 'Даосизм', value: '258' },
@@ -337,7 +325,6 @@ const RulateScraper = new MultiSrcScraper(
{ label: 'Демон лорд', value: '153' },
{ label: 'Демонология', value: '2024' },
{ label: 'Демоны', value: '1406' },
- { label: 'Детектив', value: '1265' },
{ label: 'Дети', value: '580' },
{ label: 'Джарвис', value: '933' },
{ label: 'Джедай', value: '4442' },
@@ -365,12 +352,10 @@ const RulateScraper = new MultiSrcScraper(
{ label: 'Драко малфой', value: '46' },
{ label: 'Драконы', value: '282' },
{ label: 'Драконы оборотни', value: '8082' },
- { label: 'Драма', value: '611' },
{ label: 'Древние времена', value: '7781' },
{ label: 'Древний египет', value: '7614' },
{ label: 'Древний китай', value: '473' },
{ label: 'Древний мир', value: '4' },
- { label: 'Дрочка', value: '4565' },
{ label: 'Другая вселенная', value: '39' },
{ label: 'Другие планеты', value: '2371' },
{ label: 'Другой мир', value: '2248' },
@@ -393,10 +378,8 @@ const RulateScraper = new MultiSrcScraper(
{ label: 'Женское доминирование', value: '4622' },
{ label: 'Женщина в теле мужчины', value: '2748' },
{ label: 'Женщина кошка', value: '7513' },
- { label: 'Жесткий секс', value: '2238' },
- { label: 'Жестокие персонажи ', value: '3153' },
+ { label: 'Жестокие персонажи', value: '3153' },
{ label: 'Жестокий мир', value: '1532' },
- { label: 'Жестокое обращение с детьми', value: '84' },
{ label: 'Жестокость', value: '7880' },
{ label: 'Животные', value: '7488' },
{ label: 'Животные компаньоны', value: '2061' },
@@ -426,13 +409,11 @@ const RulateScraper = new MultiSrcScraper(
{ label: 'Змей', value: '5721' },
{ label: 'Знаменитости', value: '1341' },
{ label: 'Знание медицины', value: '1411' },
- { label: 'Золотой дождь', value: '1828' },
{ label: 'Золушка', value: '2980' },
{ label: 'Зомби', value: '1743' },
{ label: 'Зомби апокалипсис', value: '912' },
{ label: 'Зона 51', value: '3051' },
{ label: 'Зооморфы', value: '375' },
- { label: 'Зоофилия', value: '1165' },
{ label: 'Зорро', value: '6736' },
{ label: 'Зрелые женщины', value: '1458' },
{ label: 'Игра', value: '663' },
@@ -444,7 +425,6 @@ const RulateScraper = new MultiSrcScraper(
{ label: 'Изменение характера', value: '1113' },
{ label: 'Изменения внешности', value: '259' },
{ label: 'Изменения личности', value: '1080' },
- { label: 'Изнасилование', value: '1283' },
{ label: 'Изобретения', value: '126' },
{ label: 'Изуку мидория', value: '6967' },
{ label: 'Император', value: '867' },
@@ -461,7 +441,6 @@ const RulateScraper = new MultiSrcScraper(
{ label: 'Интимные сцены', value: '3450' },
{ label: 'Интрига', value: '317' },
{ label: 'Интриги и заговоры', value: '1009' },
- { label: 'Инцест', value: '1934' },
{ label: 'Иные миры', value: '35' },
{ label: 'Исекай', value: '2979' },
{ label: 'Искусственный интеллект', value: '1900' },
@@ -480,7 +459,6 @@ const RulateScraper = new MultiSrcScraper(
{ label: 'Кафе', value: '3934' },
{ label: 'Кацуки бакуго', value: '7696' },
{ label: 'Квесты', value: '1707' },
- { label: 'Киберпанк', value: '1614' },
{ label: 'Киберспорт', value: '1984' },
{ label: 'Кино', value: '7126' },
{ label: 'Китай', value: '3762' },
@@ -490,17 +468,14 @@ const RulateScraper = new MultiSrcScraper(
{ label: 'Книги', value: '1068' },
{ label: 'Книжный червь', value: '521' },
{ label: 'Колдовство', value: '2681' },
- { label: 'Колледж', value: '5058' },
+ { label: 'колледж', value: '5058' },
{ label: 'Коллекционер', value: '2588' },
{ label: 'Кольцо', value: '1628' },
- { label: 'Комедия', value: '1430' },
{ label: 'Коммунисты', value: '1042' },
{ label: 'Коноха', value: '2827' },
{ label: 'Контракт', value: '4304' },
{ label: 'Контроль разума', value: '485' },
{ label: 'Конфеты', value: '341' },
- { label: 'Кончил внутрь', value: '4589' },
- { label: 'Копрофилия', value: '2568' },
{ label: 'Корейцы', value: '6535' },
{ label: 'Корея', value: '2443' },
{ label: 'Королевская власть', value: '55' },
@@ -515,19 +490,16 @@ const RulateScraper = new MultiSrcScraper(
{ label: 'Кража навыков', value: '1159' },
{ label: 'Красивая главная героиня', value: '186' },
{ label: 'Красивые женщины', value: '66' },
- { label: 'Красивые персонажи ', value: '5787' },
+ { label: 'Красивые персонажи', value: '5787' },
{ label: 'Красивый главный герой', value: '895' },
{ label: 'Крафт', value: '1599' },
- { label: 'Кровь и расчлененка', value: '7752' },
{ label: 'Кроссовер', value: '75' },
- { label: 'Ксенофилия', value: '2265' },
{ label: 'Ктулху', value: '920' },
{ label: 'Кузнец', value: '853' },
{ label: 'Кукла', value: '3085' },
{ label: 'Кулинария', value: '2230' },
{ label: 'Культивация', value: '1901' },
{ label: 'Культивирование', value: '1860' },
- { label: 'Кунилингус', value: '4651' },
{ label: 'Курама', value: '5709' },
{ label: 'Курилин', value: '6134' },
{ label: 'Кушина узумаки', value: '5222' },
@@ -538,7 +510,6 @@ const RulateScraper = new MultiSrcScraper(
{ label: 'Леон золдик', value: '7469' },
{ label: 'Лес', value: '6645' },
{ label: 'Лечебная магия', value: '562' },
- { label: 'Литрпг', value: '505' },
{ label: 'Локи', value: '1725' },
{ label: 'Лоли', value: '1576' },
{ label: 'Лопата', value: '4989' },
@@ -587,7 +558,6 @@ const RulateScraper = new MultiSrcScraper(
{ label: 'Марс', value: '4013' },
{ label: 'Марти стью', value: '594' },
{ label: 'Мастер на все руки', value: '3189' },
- { label: 'Мастурбация', value: '3078' },
{ label: 'Матриархат', value: '7197' },
{ label: 'Мать и сестры', value: '7946' },
{ label: 'Мафия', value: '353' },
@@ -596,13 +566,11 @@ const RulateScraper = new MultiSrcScraper(
{ label: 'Медицина', value: '441' },
{ label: 'Медленная романтика', value: '8383' },
{ label: 'Медленное развитие истории', value: '7462' },
- { label: 'Межрасовый секс', value: '3489' },
{ label: 'Мелиодас', value: '7224' },
{ label: 'Мелодрама', value: '1507' },
{ label: 'Менеджмент', value: '368' },
{ label: 'Мерлин', value: '3977' },
{ label: 'Месть', value: '1218' },
- { label: 'Меха', value: '2303' },
{ label: 'Меч', value: '48' },
{ label: 'Мечники', value: '969' },
{ label: 'Мечта', value: '527' },
@@ -614,12 +582,10 @@ const RulateScraper = new MultiSrcScraper(
{ label: 'Мимик', value: '5706' },
{ label: 'Мина ашидо', value: '7695' },
{ label: 'Минато намикадзе', value: '5223' },
- { label: 'Минет', value: '3289' },
{ label: 'Мир будущего', value: '1770' },
{ label: 'Мир земли', value: '8394' },
{ label: 'Мир меча и магии', value: '1271' },
{ label: 'Мистер пропер', value: '565' },
- { label: 'Мистика', value: '510' },
{ label: 'Мифические существа', value: '1878' },
{ label: 'Мифы и легенды', value: '4463' },
{ label: 'Младшая сестра', value: '1523' },
@@ -638,7 +604,7 @@ const RulateScraper = new MultiSrcScraper(
{ label: 'Мортал комбат', value: '5861' },
{ label: 'Мошенник', value: '959' },
{ label: 'Мрачный мир', value: '1' },
- { label: 'Мужчина протагонист', value: '31' },
+ { label: 'Мужчина в женском теле', value: '8405' },
{ label: 'Музыка', value: '1183' },
{ label: 'Мультивселенная', value: '7410' },
{ label: 'Мурим', value: '7342' },
@@ -653,12 +619,10 @@ const RulateScraper = new MultiSrcScraper(
{ label: 'Наивный главный герой', value: '159' },
{ label: 'Наложница', value: '4867' },
{ label: 'Наноботы', value: '2332' },
- { label: 'Наркотики', value: '1436' },
{ label: 'Наруто', value: '7177' },
{ label: 'Наруто и хината', value: '5766' },
{ label: 'Насилие и жестокость', value: '1440' },
{ label: 'Наука', value: '2150' },
- { label: 'Научная фантастика', value: '2244' },
{ label: 'Национализм', value: '5556' },
{ label: 'Нацу', value: '5826' },
{ label: 'Нацуки субару', value: '6656' },
@@ -674,7 +638,6 @@ const RulateScraper = new MultiSrcScraper(
{ label: 'Некромаг', value: '7441' },
{ label: 'Некромант', value: '1914' },
{ label: 'Некромантия', value: '754' },
- { label: 'Некрофилия', value: '1285' },
{ label: 'Ненормативная лексика', value: '160' },
{ label: 'Необычные герои', value: '67' },
{ label: 'Нет людей', value: '7486' },
@@ -687,7 +650,6 @@ const RulateScraper = new MultiSrcScraper(
{ label: 'Ниндзюцу', value: '2354' },
{ label: 'Ниндзя', value: '1330' },
{ label: 'Новелла', value: '2105' },
- { label: 'Нудизм', value: '2233' },
{ label: 'Нэко', value: '147' },
{ label: 'Оби ван кеноби', value: '6830' },
{ label: 'Обито учиха', value: '2814' },
@@ -699,8 +661,6 @@ const RulateScraper = new MultiSrcScraper(
{ label: 'Один в поле воин', value: '6498' },
{ label: 'Онлайн игра', value: '1565' },
{ label: 'Ооками теппей', value: '849' },
- { label: 'Оральный секс', value: '605' },
- { label: 'Оргия', value: '974' },
{ label: 'Оригинальные персонажи', value: '7741' },
{ label: 'Орки', value: '1597' },
{ label: 'Оружие', value: '125' },
@@ -719,7 +679,6 @@ const RulateScraper = new MultiSrcScraper(
{ label: 'Ояш', value: '8048' },
{ label: 'Падчерица', value: '7023' },
{ label: 'Падший ангел', value: '184' },
- { label: 'Пайзури', value: '3560' },
{ label: 'Палач', value: '852' },
{ label: 'Палочка', value: '2682' },
{ label: 'Пандорум', value: '4360' },
@@ -768,7 +727,6 @@ const RulateScraper = new MultiSrcScraper(
{ label: 'Повествование от первого лица', value: '1054' },
{ label: 'Повествование от разных лиц', value: '600' },
{ label: 'Повествование от третьего лица', value: '2116' },
- { label: 'Повседневность', value: '802' },
{ label: 'Подавитель', value: '497' },
{ label: 'Подземелье', value: '798' },
{ label: 'Подростки', value: '636' },
@@ -788,9 +746,7 @@ const RulateScraper = new MultiSrcScraper(
{ label: 'Попаданец в другой мир', value: '685' },
{ label: 'Попаданец в игру', value: '6466' },
{ label: 'Попадание в книгу', value: '6957' },
- { label: 'Порно', value: '4023' },
{ label: 'Постапокалипсис', value: '1079' },
- { label: 'Потеря девственности', value: '5879' },
{ label: 'Похищение', value: '7452' },
{ label: 'Поэзия', value: '1120' },
{ label: 'Правитель', value: '2261' },
@@ -804,7 +760,6 @@ const RulateScraper = new MultiSrcScraper(
{ label: 'Призыв', value: '332' },
{ label: 'Призыв в другой мир', value: '781' },
{ label: 'Призыв существ', value: '412' },
- { label: 'Приключения', value: '964' },
{ label: 'Приложение на телефоне', value: '5345' },
{ label: 'Принудительный брак', value: '2954' },
{ label: 'Принуждение', value: '1442' },
@@ -818,14 +773,13 @@ const RulateScraper = new MultiSrcScraper(
{ label: 'Проклятия', value: '1347' },
{ label: 'Проработанный мир', value: '1711' },
{ label: 'Пророчество', value: '7762' },
+ { label: 'Против наркотиков', value: '8406' },
{ label: 'Псайкеры', value: '3659' },
{ label: 'Псионика', value: '5216' },
{ label: 'Психбольница', value: '6969' },
{ label: 'Психические расстройства', value: '2445' },
{ label: 'Психологические травмы', value: '3418' },
- { label: 'Психология', value: '17' },
{ label: 'Публичный дом', value: '7860' },
- { label: 'Публичный секс', value: '6647' },
{ label: 'Путешествие в другой мир', value: '10' },
{ label: 'Пух', value: '4286' },
{ label: 'Пушечное мясо', value: '7234' },
@@ -839,7 +793,6 @@ const RulateScraper = new MultiSrcScraper(
{ label: 'Развитие персонажа', value: '1780' },
{ label: 'Развитие поселения', value: '7203' },
{ label: 'Развитие технологий', value: '1875' },
- { label: 'Разврат', value: '1924' },
{ label: 'Раздвоение личности', value: '2062' },
{ label: 'Разные расы', value: '1188' },
{ label: 'Разорванная помолвка', value: '2057' },
@@ -848,7 +801,6 @@ const RulateScraper = new MultiSrcScraper(
{ label: 'Ранобэ', value: '1764' },
{ label: 'Расизм', value: '3554' },
{ label: 'Растение', value: '407' },
- { label: 'Расчленение', value: '7125' },
{ label: 'Реализм', value: '1180' },
{ label: 'Ребенок', value: '2881' },
{ label: 'Ревность', value: '293' },
@@ -871,7 +823,6 @@ const RulateScraper = new MultiSrcScraper(
{ label: 'Роботы', value: '467' },
{ label: 'Рок ли', value: '7002' },
{ label: 'Рокси', value: '7380' },
- { label: 'Романтика', value: '1025' },
{ label: 'Рон уизли', value: '4279' },
{ label: 'Ророноа зоро', value: '1590' },
{ label: 'Росомаха', value: '1035' },
@@ -887,7 +838,6 @@ const RulateScraper = new MultiSrcScraper(
{ label: 'Сайян', value: '6802' },
{ label: 'Сакура', value: '2515' },
{ label: 'Самец', value: '1592' },
- { label: 'Самоубийство', value: '4312' },
{ label: 'Самураи', value: '576' },
{ label: 'Санса старк', value: '3925' },
{ label: 'Сарказм', value: '4658' },
@@ -896,31 +846,16 @@ const RulateScraper = new MultiSrcScraper(
{ label: 'Сборник', value: '7367' },
{ label: 'Свадьба', value: '1524' },
{ label: 'Сверхсила', value: '1055' },
- { label: 'Сверхъестественное', value: '1074' },
- { label: 'Свингеры', value: '514' },
{ label: 'Свинцовые книги', value: '5322' },
{ label: 'Связывание', value: '4506' },
{ label: 'Священик', value: '61' },
{ label: 'Северус снейп', value: '5783' },
{ label: 'Сёдзе', value: '2219' },
- { label: 'Секс', value: '2472' },
- { label: 'Секс без проникновения', value: '151' },
- { label: 'Секс игрушки', value: '1124' },
- { label: 'Секс по принуждению', value: '8335' },
- { label: 'Секс по согласию', value: '7307' },
- { label: 'Секс рабыня', value: '7174' },
- { label: 'Секс с близнецами', value: '7457' },
- { label: 'Секс с монстрами', value: '6073' },
- { label: 'Секс с учителем', value: '2570' },
- { label: 'Секса будет много', value: '7265' },
- { label: 'Сексуальные и психологические отклонения', value: '888' },
{ label: 'Секты', value: '1234' },
- { label: 'Селфцест', value: '7498' },
{ label: 'Сельское хозяйство', value: '787' },
{ label: 'Семейный конфликт', value: '935' },
{ label: 'Семья', value: '728' },
{ label: 'Сенджу', value: '6069' },
- { label: 'Сёнэн', value: '2058' },
{ label: 'Серийный убийца', value: '261' },
{ label: 'Сестра', value: '2342' },
{ label: 'Сила глаза', value: '1019' },
@@ -933,13 +868,11 @@ const RulateScraper = new MultiSrcScraper(
{ label: 'Сирота', value: '297' },
{ label: 'Система', value: '251' },
{ label: 'Система уровней', value: '2174' },
- { label: 'Сиськи', value: '16' },
{ label: 'Ситх', value: '1618' },
{ label: 'Сказка', value: '3570' },
{ label: 'Скайрим', value: '4032' },
{ label: 'Скайуокер', value: '6828' },
{ label: 'Сквиб', value: '4101' },
- { label: 'Сквирт', value: '4526' },
{ label: 'Скелет', value: '1315' },
{ label: 'Скрытые способности', value: '3417' },
{ label: 'Скульптор', value: '1178' },
@@ -974,7 +907,6 @@ const RulateScraper = new MultiSrcScraper(
{ label: 'Спокойная главная героиня', value: '236' },
{ label: 'Спокойный главный герой', value: '1656' },
{ label: 'Спор', value: '3484' },
- { label: 'Спорт', value: '1387' },
{ label: 'Спортивное тело', value: '8317' },
{ label: 'Способность кражи', value: '7784' },
{ label: 'Сражения', value: '23' },
@@ -988,7 +920,6 @@ const RulateScraper = new MultiSrcScraper(
{ label: 'Стимпанк', value: '1894' },
{ label: 'Стихи', value: '1309' },
{ label: 'Стратегия', value: '569' },
- { label: 'Стриптиз', value: '6914' },
{ label: 'Строительство', value: '921' },
{ label: 'Студент', value: '1464' },
{ label: 'Студентка', value: '7518' },
@@ -1005,11 +936,9 @@ const RulateScraper = new MultiSrcScraper(
{ label: 'Сценарий', value: '7489' },
{ label: 'Счастливый конец', value: '3293' },
{ label: 'Сын', value: '3297' },
- { label: 'Сэйнэн', value: '345' },
{ label: 'Сэм винчестер', value: '7461' },
{ label: 'Сюаньхуа', value: '2560' },
{ label: 'Сюжетные повороты', value: '7202' },
- { label: 'Сянься', value: '1126' },
{ label: 'Таблетки для развития', value: '589' },
{ label: 'Таинственное прошлое', value: '769' },
{ label: 'Тайная личность', value: '8096' },
@@ -1018,7 +947,6 @@ const RulateScraper = new MultiSrcScraper(
{ label: 'Тайные отношения', value: '7450' },
{ label: 'Тайцы', value: '6413' },
{ label: 'Танки', value: '1787' },
- { label: 'Твинцест', value: '2450' },
{ label: 'Творчество', value: '20' },
{ label: 'Тейлор эберт', value: '3526' },
{ label: 'Телекинез', value: '2203' },
@@ -1029,7 +957,6 @@ const RulateScraper = new MultiSrcScraper(
{ label: 'Темное фэнтези', value: '1675' },
{ label: 'Темные эльфы', value: '7198' },
{ label: 'Тенсейган', value: '4367' },
- { label: 'Тентакли', value: '3236' },
{ label: 'Тетя', value: '4194' },
{ label: 'Техномагия', value: '508' },
{ label: 'Тиран', value: '1174' },
@@ -1042,14 +969,12 @@ const RulateScraper = new MultiSrcScraper(
{ label: 'Тор и локи', value: '2645' },
{ label: 'Торговля', value: '1637' },
{ label: 'Травничество', value: '221' },
- { label: 'Трагедия', value: '470' },
{ label: 'Трагическое прошлое', value: '644' },
{ label: 'Трактир', value: '1918' },
{ label: 'Трансмиграция', value: '1071' },
{ label: 'Трансформация', value: '156' },
{ label: 'Трансформеры', value: '4616' },
{ label: 'Тревор филипс', value: '5427' },
- { label: 'Триллер', value: '1676' },
{ label: 'Тройняшки', value: '7169' },
{ label: 'Троли', value: '4250' },
{ label: 'Трудолюбивый главный герой', value: '248' },
@@ -1062,7 +987,6 @@ const RulateScraper = new MultiSrcScraper(
{ label: 'Убийцы драконов', value: '1484' },
{ label: 'Увечья', value: '3266' },
{ label: 'Удача', value: '6575' },
- { label: 'Ужасы', value: '1747' },
{ label: 'Узумаки', value: '7579' },
{ label: 'Укротитель', value: '367' },
{ label: 'Умения', value: '531' },
@@ -1078,7 +1002,6 @@ const RulateScraper = new MultiSrcScraper(
{ label: 'Усопп', value: '6737' },
{ label: 'Устроенный брак', value: '2223' },
{ label: 'Усыновление', value: '395' },
- { label: 'Уся', value: '1172' },
{ label: 'Утопия', value: '4677' },
{ label: 'Уход за детьми', value: '7609' },
{ label: 'Учеба в университете', value: '2797' },
@@ -1089,9 +1012,7 @@ const RulateScraper = new MultiSrcScraper(
{ label: 'Фамильяры', value: '1471' },
{ label: 'Фанатичная любовь', value: '6721' },
{ label: 'Фанаты', value: '7739' },
- { label: 'Фантастика', value: '286' },
{ label: 'Фантастический мир', value: '2414' },
- { label: 'Фанфик', value: '767' },
{ label: 'Фармацевт', value: '1706' },
{ label: 'Фашисты', value: '3118' },
{ label: 'Феи', value: '7185' },
@@ -1101,11 +1022,9 @@ const RulateScraper = new MultiSrcScraper(
{ label: 'Фенрир', value: '2740' },
{ label: 'Феодализм', value: '280' },
{ label: 'Ферма', value: '285' },
- { label: 'Фетиш', value: '2398' },
{ label: 'Фехтовальщик', value: '4685' },
{ label: 'Филиппины', value: '128' },
{ label: 'Философия', value: '1859' },
- { label: 'Фистинг', value: '4206' },
{ label: 'Флафф', value: '5048' },
{ label: 'Флер делакур', value: '5191' },
{ label: 'Флэш', value: '4667' },
@@ -1114,7 +1033,6 @@ const RulateScraper = new MultiSrcScraper(
{ label: 'Фугаку', value: '6161' },
{ label: 'Фурри', value: '6631' },
{ label: 'Футбол', value: '1121' },
- { label: 'Фэнтези', value: '174' },
{ label: 'Фэнтезийный мир', value: '1556' },
{ label: 'Хакер', value: '475' },
{ label: 'Халк', value: '1196' },
@@ -1123,7 +1041,6 @@ const RulateScraper = new MultiSrcScraper(
{ label: 'Хаос', value: '3117' },
{ label: 'Харизматичный главный герой', value: '2350' },
{ label: 'Хатаке какаши', value: '2820' },
- { label: 'Хентай', value: '1682' },
{ label: 'Хиддлстон', value: '5903' },
{ label: 'Химавари', value: '2583' },
{ label: 'Хината', value: '2513' },
@@ -1161,21 +1078,15 @@ const RulateScraper = new MultiSrcScraper(
{ label: 'Эволюция', value: '2040' },
{ label: 'Экзорцизм', value: '676' },
{ label: 'Экономика', value: '121' },
- { label: 'Эксгибиционизм', value: '1643' },
{ label: 'Экспансия', value: '110' },
{ label: 'Эксперименты над людьми', value: '7408' },
- { label: 'Экшен', value: '2859' },
{ label: 'Элементальная магия', value: '1264' },
- { label: 'Элементы бдсм', value: '1323' },
{ label: 'Эльфы', value: '1362' },
{ label: 'Эротика', value: '2053' },
- { label: 'Этти', value: '1317' },
{ label: 'Юмор', value: '7360' },
{ label: 'Яды', value: '201' },
{ label: 'Якудза', value: '4599' },
{ label: 'Яндере', value: '7111' },
- { label: 'Bl', value: '8282' },
- { label: 'Gl', value: '8284' },
{ label: 'Rpg', value: '90' },
{ label: 'Star wars', value: '1985' },
{ label: 'Time skip', value: '824' },
@@ -1224,7 +1135,7 @@ const ErolateScraper = new MultiSrcScraper(
{ label: 'Приключения', value: '38' },
{ label: 'Публичный секс', value: '33' },
{ label: 'Романтика', value: '25' },
- { label: 'С изображениями ', value: '36' },
+ { label: 'С изображениями', value: '36' },
{ label: 'Сверхъестественное', value: '34' },
{ label: 'Смат', value: '37' },
{ label: 'Тентакли', value: '26' },
@@ -1267,6 +1178,7 @@ const ErolateScraper = new MultiSrcScraper(
{ label: 'Бесстрашные персонажи', value: '339' },
{ label: 'Библиотека', value: '265' },
{ label: 'Бистиалити', value: '391' },
+ { label: 'Битва за трон', value: '404' },
{ label: 'Близнецы', value: '198' },
{ label: 'Блондинка', value: '91' },
{ label: 'Богатые персонажи', value: '248' },
@@ -1297,12 +1209,15 @@ const ErolateScraper = new MultiSrcScraper(
{ label: 'Вирус', value: '203' },
{ label: 'Внучка', value: '189' },
{ label: 'Война', value: '387' },
+ { label: 'Воспоминания из прошлого', value: '405' },
+ { label: 'Враги становятся любовниками', value: '410' },
{ label: 'Время', value: '81' },
{ label: 'Второй шанс', value: '244' },
{ label: 'Вуайеризм', value: '62' },
{ label: 'Выживание', value: '135' },
{ label: 'Гарем', value: '107' },
{ label: 'Гарри поттер', value: '97' },
+ { label: 'Гвен', value: '402' },
{ label: 'Гг имба', value: '87' },
{ label: 'Генетические модификации', value: '314' },
{ label: 'Гипноз', value: '143' },
@@ -1361,6 +1276,7 @@ const ErolateScraper = new MultiSrcScraper(
{ label: 'Золотой дождь', value: '146' },
{ label: 'Зомби апокалипсис', value: '241' },
{ label: 'Зоофилия', value: '144' },
+ { label: 'Зрелые женщины', value: '398' },
{ label: 'Игровые элементы', value: '385' },
{ label: 'Извращения', value: '192' },
{ label: 'Измена', value: '71' },
@@ -1376,6 +1292,7 @@ const ErolateScraper = new MultiSrcScraper(
{ label: 'Интроверт', value: '38' },
{ label: 'Инфекция', value: '207' },
{ label: 'Инцест', value: '35' },
+ { label: 'Исторический роман', value: '406' },
{ label: 'Камера', value: '92' },
{ label: 'Колледж', value: '82' },
{ label: 'Комикс', value: '286' },
@@ -1393,7 +1310,9 @@ const ErolateScraper = new MultiSrcScraper(
{ label: 'Кулинария', value: '362' },
{ label: 'Культвация', value: '86' },
{ label: 'Кунилингус', value: '152' },
+ { label: 'Кушина', value: '399' },
{ label: 'Лактация', value: '11' },
+ { label: 'Лесби', value: '408' },
{ label: 'Лишение девственности', value: '212' },
{ label: 'Лоли', value: '218' },
{ label: 'Лунатизм', value: '279' },
@@ -1428,6 +1347,7 @@ const ErolateScraper = new MultiSrcScraper(
{ label: 'Минет', value: '52' },
{ label: 'Мистика', value: '250' },
{ label: 'Младшая сестра', value: '154' },
+ { label: 'Много спермы', value: '409' },
{ label: 'Модель', value: '324' },
{ label: 'Монстры', value: '333' },
{ label: 'Мошеничество', value: '44' },
@@ -1435,6 +1355,7 @@ const ErolateScraper = new MultiSrcScraper(
{ label: 'Мужчина протагонист', value: '108' },
{ label: 'Музыка', value: '331' },
{ label: 'Мэри съюха', value: '309' },
+ { label: 'Наруко', value: '400' },
{ label: 'Наруто', value: '46' },
{ label: 'Насилие', value: '128' },
{ label: 'Насилие и жестокость', value: '193' },
@@ -1495,6 +1416,7 @@ const ErolateScraper = new MultiSrcScraper(
{ label: 'Постапокалипсис', value: '332' },
{ label: 'Потеря девственности', value: '142' },
{ label: 'Похищение', value: '161' },
+ { label: 'Преданные любовный интерес', value: '407' },
{ label: 'Приключения', value: '134' },
{ label: 'Принуждение', value: '66' },
{ label: 'Психология', value: '238' },
@@ -1506,6 +1428,7 @@ const ErolateScraper = new MultiSrcScraper(
{ label: 'Разврат', value: '64' },
{ label: 'Райзен', value: '95' },
{ label: 'Раса инопланетных космических лесбиянок', value: '294' },
+ { label: 'Религия', value: '403' },
{ label: 'Рестленг', value: '84' },
{ label: 'Риас гремори', value: '389' },
{ label: 'Романтика', value: '178' },
@@ -1618,6 +1541,7 @@ const ErolateScraper = new MultiSrcScraper(
{ label: 'Юмор', value: '105' },
{ label: 'Яндере', value: '155' },
{ label: 'Bl', value: '125' },
+ { label: 'Dc', value: '411' },
{ label: 'Gl', value: '96' },
{ label: 'Harry potter', value: '190' },
{ label: 'Harry potter', value: '168' },
@@ -1625,6 +1549,7 @@ const ErolateScraper = new MultiSrcScraper(
{ label: 'Marvel', value: '194' },
{ label: 'Marvel', value: '174' },
{ label: 'Milf', value: '167' },
+ { label: 'Mj', value: '401' },
],
inputType: FilterInputs.Checkbox,
},
diff --git a/src/sources/multisrc/rulate/RulateScraper.js b/src/sources/multisrc/rulate/RulateScraper.js
index 914519cc8..300ee7d3c 100644
--- a/src/sources/multisrc/rulate/RulateScraper.js
+++ b/src/sources/multisrc/rulate/RulateScraper.js
@@ -81,11 +81,11 @@ class RulateScraper {
async popularNovels(page, { showLatestNovels, filters }) {
const baseUrl = this.baseUrl;
const sourceId = this.sourceId;
- let url = baseUrl + '/search?t=&cat=2';
- url += '&sort=' + showLatestNovels ? '4' : filters?.sort || '6';
- url += '&type=' + filters?.type || '0';
- url += '&atmosphere=' + filters?.atmosphere || '0';
- url += '&adult=' + filters?.adult || '0';
+ let url = baseUrl + '/search?t=&cat=0';
+ url += '&type=' + (filters?.type || '0');
+ url += '&sort=' + (showLatestNovels ? '4' : filters?.sort || '6');
+ url += '&atmosphere=' + (filters?.atmosphere || '0');
+ url += '&adult=' + (filters?.adult || '0');
if (filters?.genres?.length) {
url += filters.genres.map(i => `&genres[]=${i}`).join('');
@@ -145,45 +145,51 @@ class RulateScraper {
novelUrl,
};
- novel.novelName = loadedCheerio('div[class="container"] > div > div > h1')
+ novel.novelName = loadedCheerio(
+ 'div[class="container"] > div > div > h1, div.span8:nth-child(1) > h1:nth-child(2)',
+ )
.text()
.trim();
novel.novelCover =
this.baseUrl + loadedCheerio('div[class="images"] > div img').attr('src');
- novel.summary = loadedCheerio('#Info > div:nth-child(3)').html();
+ novel.summary = loadedCheerio(
+ '#Info > div:nth-child(3), .book-description',
+ ).html();
let genre = [];
if (novel?.summary) {
novel.summary = htmlToText(novel.summary);
}
- loadedCheerio('div[class="span5"] > p').each(function () {
- switch (loadedCheerio(this).find('strong').text()) {
- case 'Автор:':
- novel.author = loadedCheerio(this).find('em > a').text().trim();
- break;
- case 'Выпуск:':
- novel.status =
- loadedCheerio(this).find('em').text().trim() === 'продолжается'
- ? Status.ONGOING
- : Status.COMPLETED;
- break;
- case 'Тэги:':
- loadedCheerio(this)
- .find('em > a')
- .each(function () {
- genre.push(loadedCheerio(this).text());
- });
- break;
- case 'Жанры:':
- loadedCheerio(this)
- .find('em > a')
- .each(function () {
- genre.push(loadedCheerio(this).text());
- });
- break;
- }
- });
+ loadedCheerio('div.span5 > p, .span5 > div:nth-child(2) > p').each(
+ function () {
+ switch (loadedCheerio(this).find('strong').text()) {
+ case 'Автор:':
+ novel.author = loadedCheerio(this).find('em > a').text().trim();
+ break;
+ case 'Выпуск:':
+ novel.status =
+ loadedCheerio(this).find('em').text().trim() === 'продолжается'
+ ? Status.Ongoing
+ : Status.Completed;
+ break;
+ case 'Тэги:':
+ loadedCheerio(this)
+ .find('em > a')
+ .each(function () {
+ genre.push(loadedCheerio(this).text());
+ });
+ break;
+ case 'Жанры:':
+ loadedCheerio(this)
+ .find('em > a')
+ .each(function () {
+ genre.push(loadedCheerio(this).text());
+ });
+ break;
+ }
+ },
+ );
if (genre.length > 0) {
novel.genre = genre.reverse().join(',');
diff --git a/src/sources/ru/bookriver.js b/src/sources/ru/bookriver.js
index 16b5b459c..fdf084115 100644
--- a/src/sources/ru/bookriver.js
+++ b/src/sources/ru/bookriver.js
@@ -91,16 +91,12 @@ const parseChapter = async (novelUrl, chapterUrl) => {
};
const searchNovels = async searchTerm => {
- const url = `${baseUrl}/search/books?keyword=${searchTerm}`;
+ const url = `https://api.bookriver.ru/api/v1/search/autocomplete?keyword=${searchTerm}&page=1&perPage=10`;
const result = await fetch(url);
- const body = await result.text();
-
- const loadedCheerio = cheerio.load(body);
- let json = loadedCheerio('#__NEXT_DATA__').html();
- json = JSON.parse(json);
+ const json = await result.json();
let novels = [];
- json.props.pageProps.state.catalog.books.books.forEach(novel =>
+ json?.data?.books?.forEach(novel =>
novels.push({
sourceId,
novelName: novel.name,
diff --git a/src/sources/ru/freedlit.ts b/src/sources/ru/freedlit.ts
new file mode 100644
index 000000000..6dcf71ec2
--- /dev/null
+++ b/src/sources/ru/freedlit.ts
@@ -0,0 +1,254 @@
+import * as cheerio from 'cheerio';
+import { FilterInputs } from '../types/filterTypes';
+import {
+ SourceChapter,
+ SourceChapterItem,
+ SourceNovel,
+ SourceNovelItem,
+} from '../types';
+
+const sourceId = 168;
+const sourceName = 'LitSpace';
+
+const baseUrl = 'https://freedlit.space';
+
+const popularNovels = async (page, { showLatestNovels, filters }) => {
+ let url = baseUrl + '/books/';
+ url += (filters?.genre || 'all') + '?sort=';
+ url += showLatestNovels ? 'recent' : filters?.sort || 'popular';
+ url += '&status=' + (filters?.status || 'all');
+ url += '&access=' + (filters?.access || 'all');
+ url += '&adult=' + (filters?.adult || 'hide');
+ url += '&page=' + page;
+
+ const result = await fetch(url);
+ const body = await result.text();
+ const loadedCheerio = cheerio.load(body);
+
+ const novels: SourceNovelItem[] = [];
+ loadedCheerio('#bookListBlock > div > div').each(function () {
+ const novelName = loadedCheerio(this).find('div > h4 > a').text()?.trim();
+ const novelCover = loadedCheerio(this)
+ .find('div > a > img')
+ .attr('src')
+ ?.trim();
+ const novelUrl = loadedCheerio(this)
+ .find('div > h4 > a')
+ .attr('href')
+ ?.trim();
+
+ novels.push({ sourceId, novelName, novelCover, novelUrl });
+ });
+
+ return { novels };
+};
+
+const parseNovelAndChapters = async novelUrl => {
+ const result = await fetch(novelUrl);
+ const body = await result.text();
+ const loadedCheerio = cheerio.load(body);
+
+ const novel: SourceNovel = {
+ sourceId,
+ sourceName,
+ novelUrl,
+ url: novelUrl,
+ novelName: loadedCheerio('.book-info > h4').text(),
+ novelCover: loadedCheerio('.book-cover > div > img').attr('src')?.trim(),
+ summary: loadedCheerio('#nav-home').text()?.trim(),
+ author: loadedCheerio('.book-info > h5 > a').text(),
+ genre: loadedCheerio('.genre-list > a')
+ .map((index, element) => loadedCheerio(element).text())
+ .get()
+ .join(','),
+ };
+
+ let chapters: SourceChapterItem[] = [];
+
+ loadedCheerio('#nav-contents > div').each(function () {
+ const chapterName = loadedCheerio(this).find('a').text();
+ const releaseDate = loadedCheerio(this).find('span[class="date"]').text();
+ const chapterUrl = loadedCheerio(this).find('a').attr('href');
+ if (chapterName && chapterUrl) {
+ chapters.push({ chapterName, releaseDate, chapterUrl });
+ }
+ });
+
+ novel.chapters = chapters;
+ return novel;
+};
+
+const parseChapter = async (novelUrl, chapterUrl) => {
+ const result = await fetch(chapterUrl);
+ const body = await result.text();
+ const loadedCheerio = cheerio.load(body);
+
+ loadedCheerio('div[class="standart-block"]').remove();
+ loadedCheerio('div[class="mobile-block"]').remove();
+
+ const chapter: SourceChapter = {
+ sourceId,
+ novelUrl,
+ chapterUrl,
+ chapterName: loadedCheerio('li[class="active"]').text()?.trim(),
+ chapterText: loadedCheerio('div[class="chapter"]').html(),
+ };
+
+ return chapter;
+};
+
+const searchNovels = async searchTerm => {
+ const url = `${baseUrl}/search?query=${searchTerm}&type=all`;
+ const result = await fetch(url);
+ const body = await result.text();
+ const loadedCheerio = cheerio.load(body);
+
+ let novels: Novel.Item[] = [];
+ loadedCheerio('#bookListBlock > div').each(function () {
+ const novelName = loadedCheerio(this).find('h4 > a').text()?.trim();
+ const novelCover = loadedCheerio(this).find('a > img').attr('src')?.trim();
+ const novelUrl = loadedCheerio(this).find('h4 > a').attr('href')?.trim();
+
+ novels.push({ sourceId, novelName, novelCover, novelUrl });
+ });
+
+ return novels;
+};
+
+const filters = [
+ {
+ key: 'sort',
+ label: 'Сортировка:',
+ values: [
+ { label: 'По популярности', value: 'popular' },
+ { label: 'По количеству комментариев', value: 'comments' },
+ { label: 'По количеству лайков', value: 'likes' },
+ { label: 'По новизне', value: 'recent' },
+ { label: 'По просмотрам', value: 'views' },
+ ],
+ inputType: FilterInputs.Picker,
+ },
+ {
+ key: 'genre',
+ label: 'Жанры:',
+ values: [
+ { label: 'Любой жанр', value: 'all' },
+ { label: 'Альтернативная история', value: 'alternative-history' },
+ { label: 'Антиутопия', value: 'dystopia' },
+ { label: 'Бизнес-литература', value: 'business-literature' },
+ { label: 'Боевая фантастика', value: 'combat-fiction' },
+ { label: 'Боевик', value: 'action' },
+ { label: 'Боевое фэнтези', value: 'combat-fantasy' },
+ { label: 'Бояръ-Аниме', value: 'boyar-anime' },
+ { label: 'Героическая фантастика', value: 'heroic-fiction' },
+ { label: 'Героическое фэнтези', value: 'heroic-fantasy' },
+ { label: 'Городское фэнтези', value: 'urban-fantasy' },
+ { label: 'Гримдарк', value: 'grimdark' },
+ { label: 'Детектив', value: 'mystery' },
+ { label: 'Детская литература', value: 'kids-literature' },
+ { label: 'Документальная проза', value: 'biography' },
+ { label: 'Историческая проза', value: 'historical-fiction' },
+ { label: 'Исторический детектив', value: 'historical-mystery' },
+ {
+ label: 'Исторический любовный роман',
+ value: 'historical-romantic-novel',
+ },
+ { label: 'Историческое фэнтези', value: 'historical-fantasy' },
+ { label: 'Киберпанк', value: 'cyberpunk' },
+ { label: 'Космическая фантастика', value: 'cosmic-fiction' },
+ { label: 'ЛитРПГ', value: 'litrpg' },
+ { label: 'Лоу / Низкое фэнтези', value: 'low-fantasy' },
+ { label: 'Любовное фэнтези', value: 'romantic-fantasy' },
+ { label: 'Любовный роман', value: 'romantic-novel' },
+ { label: 'Мистика', value: 'mystic' },
+ { label: 'Мистический детектив', value: 'mystic-detective' },
+ { label: 'Научная фантастика', value: 'science-fiction' },
+ { label: 'Подростковая проза', value: 'young-adult' },
+ { label: 'Политический роман', value: 'political-romance' },
+ { label: 'Попаданцы', value: 'accidental-travel' },
+ { label: 'Попаданцы в магические миры', value: 'magic-worlds-travel' },
+ { label: 'Попаданцы во времени', value: 'time-travel' },
+ { label: 'Порнотика', value: 'pornotica' },
+ { label: 'Постапокалипсис', value: 'post-apocalypse' },
+ { label: 'Поэзия', value: 'poetry' },
+ { label: 'Приключения', value: 'adventure' },
+ { label: 'Публицистика', value: 'journalism' },
+ { label: 'Пьеса', value: 'play' },
+ { label: 'Развитие личности', value: 'how-to-book' },
+ { label: 'Разное', value: 'other' },
+ { label: 'Реализм', value: 'Realism' },
+ { label: 'РеалРПГ', value: 'realrpg' },
+ { label: 'Репликация', value: 'replication' },
+ { label: 'Романтическая эротика', value: 'romantic-erotic-fiction' },
+ { label: 'Сказка', value: 'fairy-tale' },
+ { label: 'Слэш', value: 'slash' },
+ { label: 'Современная проза', value: 'modern-prose' },
+ { label: 'Современный любовный роман', value: 'modern-romantic-novel' },
+ { label: 'Социальная фантастика', value: 'social-fiction' },
+ { label: 'Стимпанк', value: 'steampunk' },
+ { label: 'Сценарий', value: 'scenario' },
+ { label: 'Сюаньхуань', value: 'xuanhuan' },
+ { label: 'Сянься', value: 'xianxia' },
+ { label: 'Тёмное фэнтези', value: 'dark-fantasy' },
+ { label: 'Триллер', value: 'thriller' },
+ { label: 'Уся', value: 'wuxia' },
+ { label: 'Фантастика', value: 'fiction' },
+ { label: 'Фантастический детектив', value: 'mystery-fiction' },
+ { label: 'Фанфик', value: 'fan-fiction' },
+ { label: 'Фемслэш', value: 'femslash' },
+ { label: 'Фэнтези', value: 'fantasy' },
+ { label: 'Хоррор', value: 'horror' },
+ { label: 'Шпионский детектив', value: 'spy-crime' },
+ { label: 'Эпическое фэнтези', value: 'epic-fantasy' },
+ { label: 'Эротика', value: 'erotic-fiction' },
+ { label: 'Эротическая фантастика', value: 'erotic-fiction' },
+ { label: 'Эротический фанфик', value: 'erotic-fan-fiction' },
+ { label: 'Эротическое фэнтези', value: 'erotic-fantasy' },
+ { label: 'Этническое фэнтези', value: 'ethnic-fantasy' },
+ { label: 'Юмор', value: 'humor' },
+ { label: 'Юмористическая фантастика', value: 'humor-fiction' },
+ { label: 'Юмористическое фэнтези', value: 'humor-fantasy' },
+ { label: 'RPS', value: 'rps' },
+ ],
+ inputType: FilterInputs.Picker,
+ },
+ {
+ key: 'status',
+ label: 'Статус:',
+ values: [
+ { label: 'Любой статус', value: 'all' },
+ { label: 'В процессе', value: 'in-process' },
+ { label: 'Завершено', value: 'finished' },
+ ],
+ inputType: FilterInputs.Picker,
+ },
+ {
+ key: 'access',
+ label: 'Доступ:',
+ values: [
+ { label: 'Любой доступ', value: 'all' },
+ { label: 'Бесплатные', value: 'free' },
+ { label: 'Платные', value: 'paid' },
+ ],
+ inputType: FilterInputs.Picker,
+ },
+ {
+ key: 'adult',
+ label: 'Возрастные ограничения:',
+ values: [
+ { label: 'Скрыть 18+', value: 'hide' },
+ { label: 'Показать +18', value: 'show' },
+ ],
+ inputType: FilterInputs.Picker,
+ },
+];
+
+const LitSpaceScraper = {
+ popularNovels,
+ parseNovelAndChapters,
+ parseChapter,
+ searchNovels,
+ filters,
+};
+
+export default LitSpaceScraper;
diff --git a/src/sources/ru/jaomix.js b/src/sources/ru/jaomix.js
index 149d5cfb9..290680367 100644
--- a/src/sources/ru/jaomix.js
+++ b/src/sources/ru/jaomix.js
@@ -8,17 +8,26 @@ const sourceName = 'Jaomix';
const baseUrl = 'https://jaomix.ru';
const popularNovels = async (page, { showLatestNovels, filters }) => {
- let url = baseUrl + '/?searchrn&sortby=';
- url += showLatestNovels ? 'upd' : filters?.sort || 'count';
+ let url = baseUrl + '/?searchrn';
- if (filters?.type?.length) {
- url += filters.type.map(i => `&lang[]=${i}`).join('');
+ if (filters?.lang instanceof Array) {
+ url += filters.lang.map((lang, idx) => `&lang[${idx}]=${lang}`).join('');
}
-
- if (filters?.genres?.length) {
- url += filters.genres.map(i => `&genre[]=${i}`).join('');
+ if (filters?.genre instanceof Array) {
+ url += filters.genre
+ .map((genre, idx) => `&genre[${idx}]=${genre}`)
+ .join('');
+ }
+ if (filters?.delgenre instanceof Array) {
+ url += filters.delgenre
+ .map((genre, idx) => `&delgenre[${idx}]=del ${genre}`)
+ .join('');
}
- url += `&page=${page}`;
+
+ url += '&sortcountchapt=' + (filters?.sortcountchapt || '1');
+ url += '&sortdaycreate=' + (filters?.sortdaycreate || '1');
+ url += '&sortby=' + (showLatestNovels ? 'upd' : filters?.sortby || 'topweek');
+ url += '&gpage=' + page;
const result = await fetch(url);
let body = await result.text();
@@ -136,30 +145,105 @@ const searchNovels = async searchTerm => {
const filters = [
{
- key: 'sort',
- label: 'Сортировка',
+ key: 'sortby',
+ label: 'Сортировка:',
values: [
- { label: 'Имя', value: 'alphabet' },
- { label: 'Просмотры', value: 'count' },
- { label: 'Дате добавления', value: 'new' },
- { label: 'Дате обновления', value: 'upd' },
+ { label: 'Топ недели', value: 'topweek' },
+ { label: 'По алфавиту', value: 'alphabet' },
+ { label: 'По дате обновления', value: 'upd' },
+ { label: 'По дате создания', value: 'new' },
+ { label: 'По просмотрам', value: 'count' },
+ { label: 'Топ года', value: 'topyear' },
+ { label: 'Топ дня', value: 'topday' },
+ { label: 'Топ за все время', value: 'alltime' },
+ { label: 'Топ месяца', value: 'topmonth' },
],
inputType: FilterInputs.Picker,
},
{
- key: 'type',
- label: 'Тип',
+ key: 'sortdaycreate',
+ label: 'Дата добавления:',
values: [
- { label: 'Английский', value: 'Английский' },
- { label: 'Китайский', value: 'Китайский' },
- { label: 'Корейский', value: 'Корейский' },
- { label: 'Японский', value: 'Японский' },
+ { label: 'Любое', value: '1' },
+ { label: 'От 120 до 180 дней', value: '1218' },
+ { label: 'От 180 до 365 дней', value: '1836' },
+ { label: 'От 30 до 60 дней', value: '3060' },
+ { label: 'От 365 дней', value: '365' },
+ { label: 'От 60 до 90 дней', value: '6090' },
+ { label: 'От 90 до 120 дней', value: '9012' },
+ { label: 'Послед. 30 дней', value: '30' },
+ ],
+ inputType: FilterInputs.Picker,
+ },
+ {
+ key: 'sortcountchapt',
+ label: 'Количество глав:',
+ values: [
+ { label: 'Любое кол-во глав', value: '1' },
+ { label: 'До 500', value: '500' },
+ { label: 'От 1000 до 2000', value: '1020' },
+ { label: 'От 2000 до 3000', value: '2030' },
+ { label: 'От 3000 до 4000', value: '3040' },
+ { label: 'От 4000', value: '400' },
+ { label: 'От 500 до 1000', value: '510' },
+ ],
+ inputType: FilterInputs.Picker,
+ },
+ {
+ key: 'genre',
+ label: 'Жанры:',
+ values: [
+ { label: 'Боевые Искусства', value: 'Боевые Искусства' },
+ { label: 'Виртуальный Мир', value: 'Виртуальный Мир' },
+ { label: 'Гарем', value: 'Гарем' },
+ { label: 'Детектив', value: 'Детектив' },
+ { label: 'Драма', value: 'Драма' },
+ { label: 'Игра', value: 'Игра' },
+ { label: 'Истории из жизни', value: 'Истории из жизни' },
+ { label: 'Исторический', value: 'Исторический' },
+ { label: 'История', value: 'История' },
+ { label: 'Исэкай', value: 'Исэкай' },
+ { label: 'Комедия', value: 'Комедия' },
+ { label: 'Меха', value: 'Меха' },
+ { label: 'Мистика', value: 'Мистика' },
+ { label: 'Научная Фантастика', value: 'Научная Фантастика' },
+ { label: 'Повседневность', value: 'Повседневность' },
+ { label: 'Постапокалипсис', value: 'Постапокалипсис' },
+ { label: 'Приключения', value: 'Приключения' },
+ { label: 'Психология', value: 'Психология' },
+ { label: 'Романтика', value: 'Романтика' },
+ { label: 'Сверхъестественное', value: 'Сверхъестественное' },
+ { label: 'Сёнэн', value: 'Сёнэн' },
+ { label: 'Сёнэн-ай', value: 'Сёнэн-ай' },
+ { label: 'Спорт', value: 'Спорт' },
+ { label: 'Сэйнэн', value: 'Сэйнэн' },
+ { label: 'Сюаньхуа', value: 'Сюаньхуа' },
+ { label: 'Трагедия', value: 'Трагедия' },
+ { label: 'Триллер', value: 'Триллер' },
+ { label: 'Фантастика', value: 'Фантастика' },
+ { label: 'Фэнтези', value: 'Фэнтези' },
+ { label: 'Хоррор', value: 'Хоррор' },
+ { label: 'Школьная жизнь', value: 'Школьная жизнь' },
+ { label: 'Шоунен', value: 'Шоунен' },
+ { label: 'Экшн', value: 'Экшн' },
+ { label: 'Этти', value: 'Этти' },
+ { label: 'Юри', value: 'Юри' },
+ { label: 'Adult', value: 'Adult' },
+ { label: 'Ecchi', value: 'Ecchi' },
+ { label: 'Josei', value: 'Josei' },
+ { label: 'Lolicon', value: 'Lolicon' },
+ { label: 'Mature', value: 'Mature' },
+ { label: 'Shoujo', value: 'Shoujo' },
+ { label: 'Wuxia', value: 'Wuxia' },
+ { label: 'Xianxia', value: 'Xianxia' },
+ { label: 'Xuanhuan', value: 'Xuanhuan' },
+ { label: 'Yaoi', value: 'Yaoi' },
],
inputType: FilterInputs.Checkbox,
},
{
- key: 'genres',
- label: 'Жанры',
+ key: 'delgenre',
+ label: 'Исключить жанры:',
values: [
{ label: 'Боевые Искусства', value: 'Боевые Искусства' },
{ label: 'Виртуальный Мир', value: 'Виртуальный Мир' },
@@ -209,6 +293,17 @@ const filters = [
],
inputType: FilterInputs.Checkbox,
},
+ {
+ key: 'lang',
+ label: 'Выбрать языки:',
+ values: [
+ { label: 'Английский', value: 'Английский' },
+ { label: 'Китайский', value: 'Китайский' },
+ { label: 'Корейский', value: 'Корейский' },
+ { label: 'Японский', value: 'Японский' },
+ ],
+ inputType: FilterInputs.Checkbox,
+ },
];
const JaomixScraper = {
diff --git a/src/sources/ru/renovels.js b/src/sources/ru/renovels.js
index 1f1035ee1..11a09747f 100644
--- a/src/sources/ru/renovels.js
+++ b/src/sources/ru/renovels.js
@@ -13,22 +13,26 @@ const popularNovels = async (page, { showLatestNovels, filters }) => {
url += filters?.order ? filters?.order?.replace('+', '') : '-';
url += showLatestNovels ? 'chapter_date' : filters?.sort || 'rating';
- if (filters?.type?.length) {
- url += filters.type.map(i => `&types=${i}`).join('');
+ if (filters?.genres instanceof Array) {
+ url += filters.genres.map(i => `&genres=${i}`).join('');
}
- if (filters?.statuss?.length) {
- url += filters?.statuss.map(i => `&status=${i}`).join('');
+ if (filters?.status instanceof Array) {
+ url += filters?.status.map(i => `&status=${i}`).join('');
}
- if (filters?.genres?.length) {
- url += filters.genres.map(i => `&genres=${i}`).join('');
+ if (filters?.types instanceof Array) {
+ url += filters.types.map(i => `&types=${i}`).join('');
}
- if (filters?.categories?.length) {
+ if (filters?.categories instanceof Array) {
url += filters.categories.map(i => `&categories=${i}`).join('');
}
+ if (filters?.age_limit instanceof Array) {
+ url += filters.age_limit.map(i => `&age_limit=${i}`).join('');
+ }
+
url += '&page=' + page;
const result = await fetch(url);
@@ -38,8 +42,9 @@ const popularNovels = async (page, { showLatestNovels, filters }) => {
body.content.forEach(novel =>
novels.push({
sourceId,
- novelName: novel.rus_name,
- cover: baseUrl + (novel.img?.high || novel.img?.mid || novel.img.low),
+ novelName: novel.main_name || novel.secondary_name,
+ novelCover:
+ baseUrl + (novel.img?.high || novel.img?.mid || novel.img.low),
novelUrl: novel.dir,
}),
);
@@ -56,13 +61,13 @@ const parseNovelAndChapters = async novelUrl => {
sourceName,
url: baseUrl + '/novel/' + body.content.dir,
novelUrl,
- novelName: body.content.rus_name,
+ novelName: body.content.main_name || body.content.secondary_name,
summary: htmlToText(body.content.description),
novelCover:
baseUrl +
(body.content.img?.high || body.content.img?.mid || body.content.img.low),
status:
- body.content.status.name === 'Продолжается'
+ body.content?.status?.name === 'Продолжается'
? Status.ONGOING
: Status.COMPLETED,
};
@@ -75,14 +80,15 @@ const parseNovelAndChapters = async novelUrl => {
novel.genre = tags.join(',');
}
- let all = (body.content.count_chapters / 100 + 1) ^ 0;
+ let all = Math.floor(body.content.count_chapters / 100 + 1);
+ let branch_id = body.content.branches?.[0]?.id || body.content.id;
let chapters = [];
for (let i = 0; i < all; i++) {
let chapterResult = await fetch(
baseUrl +
'/api/titles/chapters/?branch_id=' +
- body.content.branches[0].id +
+ branch_id +
'&count=100&page=' +
(i + 1),
);
@@ -128,8 +134,9 @@ const searchNovels = async searchTerm => {
body.content.forEach(novel =>
novels.push({
sourceId,
- novelName: novel.rus_name,
- cover: baseUrl + (novel.img?.high || novel.img?.mid || novel.img.low),
+ novelName: novel.main_name || novel.secondary_name,
+ novelCover:
+ baseUrl + (novel.img?.high || novel.img?.mid || novel.img.low),
novelUrl: novel.dir,
}),
);
@@ -155,41 +162,14 @@ const filters = [
key: 'order',
label: 'Порядок',
values: [
- { label: 'По убыванию', value: '-' }, // desc
- { label: 'По возрастанию', value: '+' }, // asc
+ { label: 'По убыванию', value: '-' },
+ { label: 'По возрастанию', value: '+' },
],
inputType: FilterInputs.Picker,
},
- {
- key: 'type',
- label: 'Тип',
- values: [
- { label: 'Авторское', value: '1' },
- { label: 'Другое', value: '7' },
- { label: 'Запад', value: '5' },
- { label: 'Китай', value: '4' },
- { label: 'Корея', value: '3' },
- { label: 'Фанфики', value: '6' },
- { label: 'Япония', value: '2' },
- ],
- inputType: FilterInputs.Checkbox,
- },
- {
- key: 'statuss',
- label: 'Статус тайтла',
- values: [
- { label: 'Закончен', value: '0' },
- { label: 'Продолжается', value: '1' },
- { label: 'Заморожен', value: '2' },
- { label: 'Нет переводчика', value: '3' },
- { label: 'Анонс', value: '4' },
- { label: 'Лицензировано', value: '5' },
- ],
- inputType: FilterInputs.Checkbox,
- },
{
key: 'genres',
- label: 'Жанры',
+ label: 'Жанры:',
values: [
{ label: 'Боевик', value: '112' },
{ label: 'Война', value: '123' },
@@ -226,7 +206,7 @@ const filters = [
},
{
key: 'categories',
- label: 'Категории',
+ label: 'Тэги:',
values: [
{ label: '[Награжденная работа]', value: '648' },
{ label: '18+', value: '423' },
@@ -928,6 +908,43 @@ const filters = [
],
inputType: FilterInputs.Checkbox,
},
+ {
+ key: 'types',
+ label: 'Типы:',
+ values: [
+ { label: 'Авторское', value: '1' },
+ { label: 'Другое', value: '7' },
+ { label: 'Запад', value: '5' },
+ { label: 'Китай', value: '4' },
+ { label: 'Корея', value: '3' },
+ { label: 'Фанфики', value: '6' },
+ { label: 'Япония', value: '2' },
+ ],
+ inputType: FilterInputs.Checkbox,
+ },
+ {
+ key: 'status',
+ label: 'Статус проекта:',
+ values: [
+ { label: 'Анонс', value: '4' },
+ { label: 'Закончен', value: '0' },
+ { label: 'Заморожен', value: '2' },
+ { label: 'Лицензировано', value: '5' },
+ { label: 'Нет переводчика', value: '3' },
+ { label: 'Продолжается', value: '1' },
+ ],
+ inputType: FilterInputs.Checkbox,
+ },
+ {
+ key: 'age_limit',
+ label: 'Возрастной рейтинг:',
+ values: [
+ { label: '16+', value: '1' },
+ { label: '18+', value: '2' },
+ { label: 'Для всех', value: '0' },
+ ],
+ inputType: FilterInputs.Checkbox,
+ },
];
const RenovelsScraper = {
diff --git a/src/sources/sourceManager.ts b/src/sources/sourceManager.ts
index e4e8e0ec9..65bfa091d 100644
--- a/src/sources/sourceManager.ts
+++ b/src/sources/sourceManager.ts
@@ -159,6 +159,8 @@ import {
KodScraper,
} from './multisrc/noveltl/NovelTlGenerator';
import NovelsOnlineScraper from './en/NovelOnline';
+import SmakolykyTlScraper from './ua/smakolykytl';
+import LitSpaceScraper from './ru/freedlit';
interface PopularNovelsResponse {
novels: SourceNovelItem[];
@@ -332,6 +334,8 @@ export const sourceManager = (sourceId: number): Scraper => {
164: BookRiverScraper, // @ts-ignore
165: LinovelibScraper, // @ts-ignore
166: NOVAScraper, // @ts-ignore
+ 167: SmakolykyTlScraper, // @ts-ignore
+ 168: LitSpaceScraper, // @ts-ignore
};
return scrapers[sourceId];
diff --git a/src/sources/sources.json b/src/sources/sources.json
index 671f44ad2..240ab5428 100644
--- a/src/sources/sources.json
+++ b/src/sources/sources.json
@@ -1013,5 +1013,19 @@
"url": "https://novelasligeras.net",
"lang": "Spanish",
"icon": "https://pbs.twimg.com/profile_images/1659040611507351552/DeLBdFep_400x400.jpg"
+ },
+ {
+ "sourceId": 167,
+ "sourceName": "Смаколики",
+ "url": "https://smakolykytl.site/",
+ "lang": "Ukraine",
+ "icon": "https://smakolykytl.site/img/favicon/apple-touch-icon.webp"
+ },
+ {
+ "sourceId": 168,
+ "sourceName": "LitSpace",
+ "url": "https://freedlit.space/",
+ "lang": "Russian",
+ "icon": "https://freedlit.space/images/fav/apple-touch-icon.png"
}
]
diff --git a/src/sources/ua/smakolykytl.ts b/src/sources/ua/smakolykytl.ts
new file mode 100644
index 000000000..8c72be92d
--- /dev/null
+++ b/src/sources/ua/smakolykytl.ts
@@ -0,0 +1,259 @@
+import { Status } from '../helpers/constants';
+import dayjs from 'dayjs';
+import { SourceChapter, SourceNovel, SourceNovelItem } from '../types';
+
+const sourceId = 167;
+const sourceName = 'Смаколики';
+const baseUrl = 'https://smakolykytl.site/';
+
+const popularNovels = async (page: number, { showLatestNovels }) => {
+ const url = showLatestNovels
+ ? 'https://api.smakolykytl.site/api/user/updates'
+ : 'https://api.smakolykytl.site/api/user/projects';
+
+ const result = await fetch(url);
+ const json = (await result.json()) as response;
+
+ const novels: SourceNovelItem[] = [];
+
+ (json?.projects || json?.updates)?.forEach(novel =>
+ novels.push({
+ sourceId,
+ novelName: novel.title,
+ novelCover: novel.image.url,
+ novelUrl: baseUrl + 'titles/' + novel.id,
+ }),
+ );
+
+ return { novels };
+};
+
+const parseNovelAndChapters = async (novelUrl: string) => {
+ const id = novelUrl.split('/').pop();
+ const result = await fetch(
+ 'https://api.smakolykytl.site/api/user/projects/' + id,
+ );
+ const book = (await result.json()) as response;
+
+ const novel: SourceNovel = {
+ sourceId,
+ sourceName,
+ novelUrl,
+ url: novelUrl,
+ novelName: book?.project?.title,
+ novelCover: book?.project?.image?.url,
+ summary: book?.project?.description,
+ chapters: [],
+ author: book?.project?.author,
+ status: book?.project?.status_translate.includes('Триває')
+ ? Status.ONGOING
+ : Status.COMPLETED,
+ };
+ let genre = [book?.project?.genres, book?.project?.tags]
+ .flat()
+ .map(tags => tags?.title)
+ .filter(tags => tags);
+
+ if (genre.length > 0) {
+ novel.genre = genre.join(', ');
+ }
+
+ const res = await fetch(
+ 'https://api.smakolykytl.site/api/user/projects/' + id + '/books',
+ );
+ const data = (await res.json()) as response;
+
+ data?.books?.forEach(volume =>
+ volume?.chapters?.map(chapter =>
+ novel.chapters.push({
+ chapterName: volume.title + ' ' + chapter.title,
+ releaseDate: dayjs(chapter.modifiedAt).format('LLL'),
+ chapterUrl: baseUrl + 'read/' + chapter.id,
+ }),
+ ),
+ );
+
+ return novel;
+};
+
+const parseChapter = async (novelUrl: string, chapterUrl: string) => {
+ const id = chapterUrl.split('/').pop();
+
+ const result = await fetch(
+ 'https://api.smakolykytl.site/api/user/chapters/' + id,
+ );
+ const json = (await result.json()) as response;
+ const chapterRaw: HTML[] = JSON.parse(json?.chapter?.content || '[]');
+
+ const chapter: SourceChapter = {
+ sourceId,
+ novelUrl,
+ chapterUrl,
+ chapterName: json?.chapter?.title,
+ chapterText: jsonToHtml(chapterRaw),
+ };
+
+ return chapter;
+};
+
+const searchNovels = async (searchTerm: string) => {
+ const result = await fetch('https://api.smakolykytl.site/api/user/projects');
+ const json = (await result.json()) as response;
+ const novels: SourceNovelItem[] = [];
+
+ json?.projects
+ ?.filter(
+ novel =>
+ novel.title.includes(searchTerm) || String(novel.id) === searchTerm,
+ )
+ ?.forEach(novel =>
+ novels.push({
+ sourceId,
+ novelName: novel.title,
+ novelCover: novel.image.url,
+ novelUrl: baseUrl + 'titles/' + novel.id,
+ }),
+ );
+ return novels;
+};
+
+function jsonToHtml(json: HTML[], html: string = '') {
+ json.forEach(element => {
+ switch (element.type) {
+ case 'hardBreak':
+ html += '
';
+ break;
+ case 'horizontalRule':
+ html += '
' +
+ (element.content ? jsonToHtml(element.content) : '
') +
+ '