From 65ae9ba1128f059d71b5fa5a254fd8dd213a26e4 Mon Sep 17 00:00:00 2001 From: nyagami Date: Sat, 20 Jan 2024 21:20:28 +0700 Subject: [PATCH] Fix: non-english broken plugins (#701) * fix epiknovel * fix: hasutl * fix: Novelas Ligera * fix: ReinoWuxia * fix: Oasis * fix: json script * fix: Skynovels * fix: Yuuki Tls * fix: Agitoon * fix: Syosetu * fix: IndoWebNovel * fix: Novel Ringan * fix: Sakura Novel * fix: Hako * minor: type checking when PRing --- .dist/nyagami/plugins.json | 847 ++++++++++++++++++ .dist/nyagami/plugins.min.json | 1 + .github/workflows/typechecking.yml | 29 + .github/workflows/updatejson.yml | 2 +- .js/plugins/indonesian/indowebnovel.js | 200 +++++ .js/plugins/indonesian/novelringan.js | 211 +++++ .js/plugins/indonesian/sakuranovel.js | 209 +++++ .js/plugins/japanese/Syosetu.js | 280 ++++++ .js/plugins/korean/Agitoon.js | 216 +++++ .js/plugins/spanish/hasutl.js | 195 ++++ .js/plugins/spanish/novelasligera.js | 239 +++++ .js/plugins/spanish/novelawuxia.js | 245 +++++ .js/plugins/spanish/oasistranslations.js | 220 +++++ .js/plugins/spanish/skynovels.js | 194 ++++ .js/plugins/spanish/yukitls.js | 239 +++++ .js/plugins/turkish/epiknovel.js | 208 +++++ .js/plugins/vietnamese/LNHako.js | 87 +- index.ts | 9 +- package.json | 2 +- plugins/indonesian/indowebnovel.broken.ts | 143 --- plugins/indonesian/indowebnovel.ts | 146 +++ plugins/indonesian/novelringan.broken.ts | 159 ---- plugins/indonesian/novelringan.ts | 163 ++++ plugins/indonesian/sakuranovel.broken.ts | 156 ---- plugins/indonesian/sakuranovel.ts | 156 ++++ plugins/japanese/Syosetu.broken.ts | 196 ---- plugins/japanese/Syosetu.ts | 207 +++++ plugins/korean/Agitoon.broken.ts | 183 ---- plugins/korean/Agitoon.ts | 186 ++++ plugins/spanish/hasutl.broken.ts | 142 --- plugins/spanish/hasutl.ts | 145 +++ plugins/spanish/novelasligera.broken.ts | 177 ---- plugins/spanish/novelasligera.ts | 180 ++++ plugins/spanish/novelawuxia.broken.ts | 214 ----- plugins/spanish/novelawuxia.ts | 203 +++++ plugins/spanish/oasistranslations.broken.ts | 164 ---- plugins/spanish/oasistranslations.ts | 171 ++++ .../{skynovels.broken.ts => skynovels.ts} | 61 +- plugins/spanish/yukitls.broken.ts | 180 ---- plugins/spanish/yukitls.ts | 192 ++++ plugins/turkish/epiknovel.broken.ts | 169 ---- plugins/turkish/epiknovel.ts | 169 ++++ plugins/vietnamese/LNHako.ts | 103 ++- test_web/index.html | 2 +- test_web/static/js/index.js | 4 +- 45 files changed, 5606 insertions(+), 1998 deletions(-) create mode 100644 .dist/nyagami/plugins.json create mode 100644 .dist/nyagami/plugins.min.json create mode 100644 .github/workflows/typechecking.yml create mode 100644 .js/plugins/indonesian/indowebnovel.js create mode 100644 .js/plugins/indonesian/novelringan.js create mode 100644 .js/plugins/indonesian/sakuranovel.js create mode 100644 .js/plugins/japanese/Syosetu.js create mode 100644 .js/plugins/korean/Agitoon.js create mode 100644 .js/plugins/spanish/hasutl.js create mode 100644 .js/plugins/spanish/novelasligera.js create mode 100644 .js/plugins/spanish/novelawuxia.js create mode 100644 .js/plugins/spanish/oasistranslations.js create mode 100644 .js/plugins/spanish/skynovels.js create mode 100644 .js/plugins/spanish/yukitls.js create mode 100644 .js/plugins/turkish/epiknovel.js delete mode 100644 plugins/indonesian/indowebnovel.broken.ts create mode 100644 plugins/indonesian/indowebnovel.ts delete mode 100644 plugins/indonesian/novelringan.broken.ts create mode 100644 plugins/indonesian/novelringan.ts delete mode 100644 plugins/indonesian/sakuranovel.broken.ts create mode 100644 plugins/indonesian/sakuranovel.ts delete mode 100644 plugins/japanese/Syosetu.broken.ts create mode 100644 plugins/japanese/Syosetu.ts delete mode 100644 plugins/korean/Agitoon.broken.ts create mode 100644 plugins/korean/Agitoon.ts delete mode 100644 plugins/spanish/hasutl.broken.ts create mode 100644 plugins/spanish/hasutl.ts delete mode 100644 plugins/spanish/novelasligera.broken.ts create mode 100644 plugins/spanish/novelasligera.ts delete mode 100644 plugins/spanish/novelawuxia.broken.ts create mode 100644 plugins/spanish/novelawuxia.ts delete mode 100644 plugins/spanish/oasistranslations.broken.ts create mode 100644 plugins/spanish/oasistranslations.ts rename plugins/spanish/{skynovels.broken.ts => skynovels.ts} (81%) delete mode 100644 plugins/spanish/yukitls.broken.ts create mode 100644 plugins/spanish/yukitls.ts delete mode 100644 plugins/turkish/epiknovel.broken.ts create mode 100644 plugins/turkish/epiknovel.ts diff --git a/.dist/nyagami/plugins.json b/.dist/nyagami/plugins.json new file mode 100644 index 0000000..77e7dfa --- /dev/null +++ b/.dist/nyagami/plugins.json @@ -0,0 +1,847 @@ +{ + "العربية": [ + { + "id": "ar-mtl", + "name": "ArMTL[madara]", + "site": "https://ar-mtl.club/", + "lang": "العربية", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/arabic/ArMTL[madara].js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/armtl.png" + }, + { + "id": "arnovel", + "name": "ArNovel[madara]", + "site": "https://arnovel.me/", + "lang": "العربية", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/arabic/ArNovel[madara].js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/arnovel.png" + }, + { + "id": "hizomanga", + "name": "HizoManga[madara]", + "site": "https://hizomanga.com/", + "lang": "العربية", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/arabic/HizoManga[madara].js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/hizomanga.png" + }, + { + "id": "kol-novel", + "name": "Kol Novel[wpmangastream]", + "site": "https://kolnovel.com/", + "lang": "العربية", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/arabic/KolNovel[wpmangastream].js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/wpmangastream/icons/kol-novel.png" + }, + { + "id": "kolnovel", + "name": "KolNovel", + "site": "https://kolnovel.lol/", + "lang": "العربية", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/arabic/kolnovel.js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/wpmangastream/icons/kolnovel.png" + }, + { + "id": "novel4up", + "name": "Novel4Up[madara]", + "site": "https://novel4up.com/", + "lang": "العربية", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/arabic/Novel4Up[madara].js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/novel4up.png" + }, + { + "id": "riwyat", + "name": "Riwyat[madara]", + "site": "https://riwyat.com/", + "lang": "العربية", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/arabic/Riwyat[madara].js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/riwyat.png" + }, + { + "id": "teamxnovel", + "name": "TeamXNovel[madara]", + "site": "https://teamxnovel.com/", + "lang": "العربية", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/arabic/TeamXNovel[madara].js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/teamxnovel.png" + } + ], + "中文, 汉语, 漢語": [ + { + "id": "linovelib", + "name": "Linovelib", + "site": "https://w.linovelib.com", + "lang": "中文, 汉语, 漢語", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/chinese/linovelib.js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/cn/linovelib/icon.png" + } + ], + "English": [ + { + "id": "1stkissnovel", + "name": "FirstKissNovel[madara]", + "site": "https://1stkissnovel.org/", + "lang": "English", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/FirstKissNovel[madara].js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/firstkissnovel.png" + }, + { + "id": "anf.net", + "name": "AllNovelFull", + "site": "https://allnovelfull.net", + "lang": "English", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/allnovelfull.js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/en/allnovelfull/icon.png" + }, + { + "id": "BLN.com", + "name": "BestLightNovel", + "site": "https://bestlightnovel.com/", + "lang": "English", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/bestlightnovel.js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/en/bestlightnovel/icon.png" + }, + { + "id": "boxnovel", + "name": "BoxNovel[madara]", + "site": "https://boxnovel.com/", + "lang": "English", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/BoxNovel[madara].js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/boxnovel.png" + }, + { + "id": "clicknovel", + "name": "ClickNovel[madara]", + "site": "https://clicknovel.net/", + "lang": "English", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/ClickNovel[madara].js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/clicknovel.png" + }, + { + "id": "comrademao", + "name": "Comrade Mao", + "site": "https://comrademao.com/", + "lang": "English", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/comrademao.js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/en/comrademao/icon.png" + }, + { + "id": "cratenovel", + "name": "CrateNovel[madara]", + "site": "https://cratenovel.com/", + "lang": "English", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/CrateNovel[madara].js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/cratenovel.png" + }, + { + "id": "daonovel", + "name": "DaoNovel[madara]", + "site": "https://daonovel.com/", + "lang": "English", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/DaoNovel[madara].js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/daonovel.png" + }, + { + "id": "DDL.com", + "name": "Divine Dao Library", + "site": "https://www.divinedaolibrary.com/", + "lang": "English", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/divinedaolibrary.js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/en/divinedaolibrary/icon.png" + }, + { + "id": "earlynovel", + "name": "Early Novel", + "site": "https://earlynovel.net/", + "lang": "English", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/earlynovel.js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/latestnovel.png" + }, + { + "id": "fanTLS", + "name": "Fans Translations[madara]", + "site": "https://fanstranslations.com/", + "lang": "English", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/FansTranslations[madara].js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/fanstranslations.png" + }, + { + "id": "freenovel.me", + "name": "FreeNovelMe[madara]", + "site": "https://freenovel.me/", + "lang": "English", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/FreeNovelMe[madara].js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/freenovelme.png" + }, + { + "id": "FWN.com", + "name": "Web NOVEL", + "site": "https://freewebnovel.com", + "lang": "English", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/freewebnovel.js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/en/freewebnovel/icon.png" + }, + { + "id": "guavaread", + "name": "Guavaread[madara]", + "site": "https://guavaread.com/", + "lang": "English", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/Guavaread[madara].js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/guavaread.png" + }, + { + "id": "lnheaven", + "name": "LightNovelHeaven[madara]", + "site": "https://lightnovelheaven.com/", + "lang": "English", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/LightNovelHeaven[madara].js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/lightnovelheaven.png" + }, + { + "id": "Ltnovel.com", + "name": "Ltnovel[readwn]", + "site": "https://www.ltnovel.com", + "lang": "English", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/Ltnovel[readwn].js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/readwn/icons/ltnovel.png" + }, + { + "id": "lunarletters", + "name": "LunarLetters[madara]", + "site": "https://www.lunarletters.com/", + "lang": "English", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/LunarLetters[madara].js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/lunarletters.png" + }, + { + "id": "mostnovel", + "name": "MostNovel[madara]", + "site": "https://mostnovel.com/", + "lang": "English", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/MostNovel[madara].js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/mostnovel.png" + }, + { + "id": "mtl-novel", + "name": "MTL-Novel[madara]", + "site": "https://mtl-novel.com/", + "lang": "English", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/MTLNovel[madara].js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/mtl-novel.png" + }, + { + "id": "mtlnovel.club", + "name": "MTLNovel.Club[madara]", + "site": "https://mtlnovel.club/", + "lang": "English", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/MTLNovelClub[madara].js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/mtlnovel.club.png" + }, + { + "id": "mysticalmerries", + "name": "MysticalSeries[madara]", + "site": "https://mysticalmerries.com/", + "lang": "English", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/MysticalSeries[madara].js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/mysticalseries.png" + }, + { + "id": "neosekaiTLS", + "name": "NeoSekai Translations[madara]", + "site": "https://www.neosekaitranslations.com/", + "lang": "English", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/NeoSekaiTranslations[madara].js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/neosekaitranslations.png" + }, + { + "id": "noblemtl", + "name": "NobleMTL", + "site": "https://noblemtl.com/", + "lang": "English", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/nobleMTL.js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/en/noblemtl/icon.png" + }, + { + "id": "nocturneTLS", + "name": "Nocturne Translations[madara]", + "site": "https://nocturnetls.net/", + "lang": "English", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/NocturneTranslations[madara].js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/nocturnetranslations.png" + }, + { + "id": "noobchanTL", + "name": "Noobchan Translation[madara]", + "site": "https://noobchan.xyz/", + "lang": "English", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/NoobchanTranslation[madara].js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/noobchantranslation.png" + }, + { + "id": "novelmultiverse", + "name": "NovelMultiverse[madara]", + "site": "https://www.novelmultiverse.com/", + "lang": "English", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/NovelMultiverse[madara].js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/novelmultiverse.png" + }, + { + "id": "novelr18", + "name": "NovelR18[madara]", + "site": "https://novelr18.com/", + "lang": "English", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/NovelR18[madara].js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/novelr18.png" + }, + { + "id": "novelroom", + "name": "Novelroom.net[madara]", + "site": "https://novelroom.net/", + "lang": "English", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/Novelroomnet[madara].js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/novelroom.net.png" + }, + { + "id": "novelstic", + "name": "Novelstic[madara]", + "site": "https://novelstic.com/", + "lang": "English", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/Novelstic[madara].js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/novelstic.png" + }, + { + "id": "novelTL", + "name": "NovelTranslate[madara]", + "site": "https://noveltranslate.com/", + "lang": "English", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/NovelTranslate[madara].js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/noveltranslate.png" + }, + { + "id": "onlymtl", + "name": "OnlyMTL[madara]", + "site": "https://www.onlymtl.com/", + "lang": "English", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/OnlyMTL[madara].js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/onlymtl.png" + }, + { + "id": "pandamtl", + "name": "PandaMTL", + "site": "https://pandamtl.com/", + "lang": "English", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/pandaMTL.js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/en/wordpress/icon.png" + }, + { + "id": "readwebnovels", + "name": "ReadWebNovels[madara]", + "site": "https://readwebnovels.net/", + "lang": "English", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/ReadWebNovels[madara].js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/readwebnovels.png" + }, + { + "id": "sleeptTLS", + "name": "SleepyTranslations[madara]", + "site": "https://sleepytranslations.com/", + "lang": "English", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/SleepyTranslations[madara].js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/sleepytranslations.png" + }, + { + "id": "sonicmtl", + "name": "SonicMTL[madara]", + "site": "https://www.sonicmtl.com/", + "lang": "English", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/SonicMTL[madara].js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/sonicmtl.png" + }, + { + "id": "sugarbbscan", + "name": "Sugar Babies[madara]", + "site": "https://sugarbbscan.com/", + "lang": "English", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/SugarBabies[madara].js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/sugarbabies.png" + }, + { + "id": "sweetEscapeTL", + "name": "Sweet Escape Translations[madara]", + "site": "https://sweetescapetranslations.com/", + "lang": "English", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/SweetEscapeTranslations[madara].js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/sweetescapetranslations.png" + }, + { + "id": "webnovelover", + "name": "WebNovelLover[madara]", + "site": "https://www.webnovelover.com/", + "lang": "English", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/WebNovelLover[madara].js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/webnovellover.png" + }, + { + "id": "wuxiacity", + "name": "Wuxiacity[readwn]", + "site": "https://www.wuxiacity.com", + "lang": "English", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/Wuxiacity[readwn].js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/readwn/icons/wuxiacity.png" + }, + { + "id": "wuxiap", + "name": "Wuxiap[readwn]", + "site": "https://www.wuxiap.com", + "lang": "English", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/Wuxiap[readwn].js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/readwn/icons/wuxiap.png" + }, + { + "id": "wuxiaworld.site", + "name": "WuxiaWorld.Site[madara]", + "site": "https://wuxiaworld.site/", + "lang": "English", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/WuxiaWorldSite[madara].js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/wuxiaworld.site.png" + }, + { + "id": "zetroTL", + "name": "Zetro Translation[madara]", + "site": "https://zetrotranslation.com/", + "lang": "English", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/ZetroTranslation[madara].js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/zetrotranslation.png" + }, + { + "id": "zinnovel", + "name": "ZinnNovel[madara]", + "site": "https://zinnovel.com/", + "lang": "English", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/ZinnNovel[madara].js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/zinnnovel.png" + } + ], + "français, française": [ + { + "id": "chireads.com", + "name": "Chireads", + "site": "https://chireads.com", + "lang": "français, française", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/french/chireads.js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/fr/chireads/icon.png" + }, + { + "id": "lightnovelfr", + "name": "Ligh Novel FR[wpmangastream]", + "site": "https://lightnovelfr.com/", + "lang": "français, française", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/french/LighNovelFR[wpmangastream].js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/wpmangastream/icons/lightnovelfr.png" + }, + { + "id": "NDG.com", + "name": "NovelDeGlace", + "site": "https://noveldeglace.com/", + "lang": "français, française", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/french/noveldeglace.js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/fr/noveldeglace/icon.png" + } + ], + "Bahasa Indonesia": [ + { + "id": "IDWN.id", + "name": "IndoWebNovel", + "site": "https://indowebnovel.id/id/", + "lang": "Bahasa Indonesia", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/indonesian/indowebnovel.js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/id/indowebnovel/icon.png" + }, + { + "id": "meionovel", + "name": "MeioNovel[madara]", + "site": "https://meionovel.id/", + "lang": "Bahasa Indonesia", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/indonesian/MeioNovel[madara].js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/meionovel.png" + }, + { + "id": "morenovel", + "name": "MoreNovel[madara]", + "site": "https://morenovel.net/", + "lang": "Bahasa Indonesia", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/indonesian/MoreNovel[madara].js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/morenovel.png" + }, + { + "id": "novelringan.com", + "name": "NovelRingan", + "site": "https://novelringan.com/", + "lang": "Bahasa Indonesia", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/indonesian/novelringan.js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/id/novelringan/icon.png" + }, + { + "id": "sakura.id", + "name": "SakuraNovel", + "site": "https://sakuranovel.id/", + "lang": "Bahasa Indonesia", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/indonesian/sakuranovel.js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/id/sakuranovel/icon.png" + }, + { + "id": "wbnovel", + "name": "WBNovel[madara]", + "site": "https://wbnovel.com/", + "lang": "Bahasa Indonesia", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/indonesian/WBNovel[madara].js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/wbnovel.png" + } + ], + "日本語": [ + { + "id": "yomou.syosetu", + "name": "Syosetu", + "site": "https://yomou.syosetu.com/", + "lang": "日本語", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/japanese/Syosetu.js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/jp/syosetu/icon.png" + } + ], + "한국어, 조선말": [ + { + "id": "agit.xyz", + "name": "Agitoon", + "site": "https://agit501.xyz/", + "lang": "한국어, 조선말", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/korean/Agitoon.js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/kr/agitoon/agit.png" + } + ], + "Português": [ + { + "id": "lightnovelbrasil", + "name": "Light Novel Brasil", + "site": "https://lightnovelbrasil.com/", + "lang": "Português", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/portuguese/lightnovelbrasil.js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/wpmangastream/icons/lightnovelbrasil.png" + } + ], + "русский язык": [ + { + "id": "AT", + "name": "Автор Тудей", + "site": "https://author.today", + "lang": "русский язык", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/russian/authortoday.js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/ru/authortoday/icon.png" + }, + { + "id": "bookhamster", + "name": "Bookhamster[ifreedom]", + "site": "https://bookhamster.ru", + "lang": "русский язык", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/russian/Bookhamster[ifreedom].js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/ifreedom/icons/bookhamster.png" + }, + { + "id": "bookriver", + "name": "Bookriver", + "site": "https://bookriver.ru", + "lang": "русский язык", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/russian/bookriver.js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/ru/bookriver/icon.png" + }, + { + "id": "erolate", + "name": "Erolate[rulate]", + "site": "https://erolate.com", + "lang": "русский язык", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/russian/Erolate[rulate].js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/rulate/icons/erolate.png" + }, + { + "id": "ficbook", + "name": "ficbook", + "site": "https://ficbook.net", + "lang": "русский язык", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/russian/ficbook.js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/ru/ficbook/icon.png" + }, + { + "id": "freedlit.space", + "name": "LitSpace", + "site": "https://freedlit.space", + "lang": "русский язык", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/russian/LitSpace.js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/ru/freedlit/icon.png" + }, + { + "id": "ifreedom", + "name": "Свободный Мир Ранобэ[ifreedom]", + "site": "https://ifreedom.su", + "lang": "русский язык", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/russian/СвободныйМирРанобэ[ifreedom].js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/ifreedom/icons/ifreedom.png" + }, + { + "id": "jaomix.ru", + "name": "Jaomix", + "site": "https://jaomix.ru", + "lang": "русский язык", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/russian/jaomix.js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/ru/jaomix/icon.png" + }, + { + "id": "ReN", + "name": "Renovels", + "site": "https://renovels.org", + "lang": "русский язык", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/russian/renovels.js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/ru/renovels/icon.png" + }, + { + "id": "RLIB", + "name": "RanobeLib", + "site": "https://ranobelib.me", + "lang": "русский язык", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/russian/ranobelib.js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/ru/ranobelib/icon.png" + }, + { + "id": "RNBH.org", + "name": "RanobeHub", + "site": "https://ranobehub.org/", + "lang": "русский язык", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/russian/ranobehub.js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/ru/ranobehub/icon.png" + }, + { + "id": "RNRF", + "name": "РанобэРФ", + "site": "https://ранобэ.рф", + "lang": "русский язык", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/russian/ranoberf.js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/ru/ranoberf/icon.png" + }, + { + "id": "TL", + "name": "NovelTL", + "site": "https://novel.tl", + "lang": "русский язык", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/russian/novelTL.js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/ru/noveltl/icon.png" + }, + { + "id": "tl.rulate", + "name": "Rulate[rulate]", + "site": "https://tl.rulate.ru", + "lang": "русский язык", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/russian/Rulate[rulate].js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/rulate/icons/rulate.png" + } + ], + "español, castellano": [ + { + "id": "awuxia.com", + "name": "ReinoWuxia", + "site": "http://www.reinowuxia.com/", + "lang": "español, castellano", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/spanish/novelawuxia.js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/es/novelawuxia/icon.png" + }, + { + "id": "HasuTL", + "name": "Hasu Translations", + "site": "https://hasutl.wordpress.com/", + "lang": "español, castellano", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/spanish/hasutl.js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/es/hasutl/icon.png" + }, + { + "id": "ligera.com", + "name": "Novelas Ligera", + "site": "https://novelasligera.com/", + "lang": "español, castellano", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/spanish/novelasligera.js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/es/novelasligera/icon.png" + }, + { + "id": "oasisTL.wp", + "name": "Oasis Translations", + "site": "https://oasistranslations.wordpress.com/", + "lang": "español, castellano", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/spanish/oasistranslations.js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/es/oasistranslations/icon.png" + }, + { + "id": "skynovels.net", + "name": "SkyNovels", + "site": "https://www.skynovels.net/", + "lang": "español, castellano", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/spanish/skynovels.js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/es/skynovels/icon.png" + }, + { + "id": "tunovelaligera", + "name": "TuNovelaLigera", + "site": "https://tunovelaligera.com/", + "lang": "español, castellano", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/spanish/tunovelaligera.js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/es/tunovelaligera/icon.png" + }, + { + "id": "yuukitls.com", + "name": "Yuuki Tls", + "site": "https://yuukitls.com/", + "lang": "español, castellano", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/spanish/yukitls.js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/es/yuukitls/icon.png" + } + ], + "Türkçe": [ + { + "id": "epiknovel.com", + "name": "EpikNovel", + "site": "https://www.epiknovel.com/", + "lang": "Türkçe", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/turkish/epiknovel.js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/tr/epiknovel/icon.png" + }, + { + "id": "lshnovel", + "name": "Liebe Schnee Hiver Novel", + "site": "https://lshnovel.com/", + "lang": "Türkçe", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/turkish/lshnovel.js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/wpmangastream/icons/lshnovel.png" + }, + { + "id": "turkcelightnovels", + "name": "TurkceLightNovels[madara]", + "site": "https://turkcelightnovels.com/", + "lang": "Türkçe", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/turkish/TurkceLightNovels[madara].js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/turkcelightnovels.png" + }, + { + "id": "webnoveloku", + "name": "WebNovelOku [madara]", + "site": "https://www.webnoveloku.com/", + "lang": "Türkçe", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/turkish/WebNovelOku[madara].js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/webnoveloku.png" + } + ], + "Україна": [ + { + "id": "smakolykytl", + "name": "Смаколики", + "site": "https://smakolykytl.site/", + "lang": "Україна", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/ukraine/smakolykytl.js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/ua/smakolykytl/icon.png" + } + ], + "Tiếng Việt": [ + { + "id": "ln.hako", + "name": "Hako", + "site": "https://ln.hako.vn", + "lang": "Tiếng Việt", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/vietnamese/LNHako.js", + "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/vi/hakolightnovel/icon.png" + } + ] +} \ No newline at end of file diff --git a/.dist/nyagami/plugins.min.json b/.dist/nyagami/plugins.min.json new file mode 100644 index 0000000..0c5bb0c --- /dev/null +++ b/.dist/nyagami/plugins.min.json @@ -0,0 +1 @@ +{"العربية":[{"id":"ar-mtl","name":"ArMTL[madara]","site":"https://ar-mtl.club/","lang":"العربية","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/arabic/ArMTL[madara].js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/armtl.png"},{"id":"arnovel","name":"ArNovel[madara]","site":"https://arnovel.me/","lang":"العربية","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/arabic/ArNovel[madara].js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/arnovel.png"},{"id":"hizomanga","name":"HizoManga[madara]","site":"https://hizomanga.com/","lang":"العربية","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/arabic/HizoManga[madara].js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/hizomanga.png"},{"id":"kol-novel","name":"Kol Novel[wpmangastream]","site":"https://kolnovel.com/","lang":"العربية","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/arabic/KolNovel[wpmangastream].js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/wpmangastream/icons/kol-novel.png"},{"id":"kolnovel","name":"KolNovel","site":"https://kolnovel.lol/","lang":"العربية","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/arabic/kolnovel.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/wpmangastream/icons/kolnovel.png"},{"id":"novel4up","name":"Novel4Up[madara]","site":"https://novel4up.com/","lang":"العربية","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/arabic/Novel4Up[madara].js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/novel4up.png"},{"id":"riwyat","name":"Riwyat[madara]","site":"https://riwyat.com/","lang":"العربية","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/arabic/Riwyat[madara].js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/riwyat.png"},{"id":"teamxnovel","name":"TeamXNovel[madara]","site":"https://teamxnovel.com/","lang":"العربية","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/arabic/TeamXNovel[madara].js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/teamxnovel.png"}],"中文, 汉语, 漢語":[{"id":"linovelib","name":"Linovelib","site":"https://w.linovelib.com","lang":"中文, 汉语, 漢語","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/chinese/linovelib.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/cn/linovelib/icon.png"}],"English":[{"id":"1stkissnovel","name":"FirstKissNovel[madara]","site":"https://1stkissnovel.org/","lang":"English","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/FirstKissNovel[madara].js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/firstkissnovel.png"},{"id":"anf.net","name":"AllNovelFull","site":"https://allnovelfull.net","lang":"English","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/allnovelfull.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/en/allnovelfull/icon.png"},{"id":"BLN.com","name":"BestLightNovel","site":"https://bestlightnovel.com/","lang":"English","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/bestlightnovel.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/en/bestlightnovel/icon.png"},{"id":"boxnovel","name":"BoxNovel[madara]","site":"https://boxnovel.com/","lang":"English","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/BoxNovel[madara].js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/boxnovel.png"},{"id":"clicknovel","name":"ClickNovel[madara]","site":"https://clicknovel.net/","lang":"English","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/ClickNovel[madara].js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/clicknovel.png"},{"id":"comrademao","name":"Comrade Mao","site":"https://comrademao.com/","lang":"English","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/comrademao.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/en/comrademao/icon.png"},{"id":"cratenovel","name":"CrateNovel[madara]","site":"https://cratenovel.com/","lang":"English","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/CrateNovel[madara].js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/cratenovel.png"},{"id":"daonovel","name":"DaoNovel[madara]","site":"https://daonovel.com/","lang":"English","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/DaoNovel[madara].js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/daonovel.png"},{"id":"DDL.com","name":"Divine Dao Library","site":"https://www.divinedaolibrary.com/","lang":"English","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/divinedaolibrary.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/en/divinedaolibrary/icon.png"},{"id":"earlynovel","name":"Early Novel","site":"https://earlynovel.net/","lang":"English","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/earlynovel.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/latestnovel.png"},{"id":"fanTLS","name":"Fans Translations[madara]","site":"https://fanstranslations.com/","lang":"English","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/FansTranslations[madara].js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/fanstranslations.png"},{"id":"freenovel.me","name":"FreeNovelMe[madara]","site":"https://freenovel.me/","lang":"English","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/FreeNovelMe[madara].js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/freenovelme.png"},{"id":"FWN.com","name":"Web NOVEL","site":"https://freewebnovel.com","lang":"English","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/freewebnovel.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/en/freewebnovel/icon.png"},{"id":"guavaread","name":"Guavaread[madara]","site":"https://guavaread.com/","lang":"English","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/Guavaread[madara].js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/guavaread.png"},{"id":"lnheaven","name":"LightNovelHeaven[madara]","site":"https://lightnovelheaven.com/","lang":"English","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/LightNovelHeaven[madara].js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/lightnovelheaven.png"},{"id":"Ltnovel.com","name":"Ltnovel[readwn]","site":"https://www.ltnovel.com","lang":"English","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/Ltnovel[readwn].js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/readwn/icons/ltnovel.png"},{"id":"lunarletters","name":"LunarLetters[madara]","site":"https://www.lunarletters.com/","lang":"English","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/LunarLetters[madara].js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/lunarletters.png"},{"id":"mostnovel","name":"MostNovel[madara]","site":"https://mostnovel.com/","lang":"English","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/MostNovel[madara].js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/mostnovel.png"},{"id":"mtl-novel","name":"MTL-Novel[madara]","site":"https://mtl-novel.com/","lang":"English","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/MTLNovel[madara].js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/mtl-novel.png"},{"id":"mtlnovel.club","name":"MTLNovel.Club[madara]","site":"https://mtlnovel.club/","lang":"English","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/MTLNovelClub[madara].js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/mtlnovel.club.png"},{"id":"mysticalmerries","name":"MysticalSeries[madara]","site":"https://mysticalmerries.com/","lang":"English","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/MysticalSeries[madara].js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/mysticalseries.png"},{"id":"neosekaiTLS","name":"NeoSekai Translations[madara]","site":"https://www.neosekaitranslations.com/","lang":"English","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/NeoSekaiTranslations[madara].js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/neosekaitranslations.png"},{"id":"noblemtl","name":"NobleMTL","site":"https://noblemtl.com/","lang":"English","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/nobleMTL.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/en/noblemtl/icon.png"},{"id":"nocturneTLS","name":"Nocturne Translations[madara]","site":"https://nocturnetls.net/","lang":"English","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/NocturneTranslations[madara].js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/nocturnetranslations.png"},{"id":"noobchanTL","name":"Noobchan Translation[madara]","site":"https://noobchan.xyz/","lang":"English","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/NoobchanTranslation[madara].js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/noobchantranslation.png"},{"id":"novelmultiverse","name":"NovelMultiverse[madara]","site":"https://www.novelmultiverse.com/","lang":"English","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/NovelMultiverse[madara].js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/novelmultiverse.png"},{"id":"novelr18","name":"NovelR18[madara]","site":"https://novelr18.com/","lang":"English","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/NovelR18[madara].js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/novelr18.png"},{"id":"novelroom","name":"Novelroom.net[madara]","site":"https://novelroom.net/","lang":"English","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/Novelroomnet[madara].js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/novelroom.net.png"},{"id":"novelstic","name":"Novelstic[madara]","site":"https://novelstic.com/","lang":"English","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/Novelstic[madara].js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/novelstic.png"},{"id":"novelTL","name":"NovelTranslate[madara]","site":"https://noveltranslate.com/","lang":"English","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/NovelTranslate[madara].js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/noveltranslate.png"},{"id":"onlymtl","name":"OnlyMTL[madara]","site":"https://www.onlymtl.com/","lang":"English","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/OnlyMTL[madara].js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/onlymtl.png"},{"id":"pandamtl","name":"PandaMTL","site":"https://pandamtl.com/","lang":"English","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/pandaMTL.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/en/wordpress/icon.png"},{"id":"readwebnovels","name":"ReadWebNovels[madara]","site":"https://readwebnovels.net/","lang":"English","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/ReadWebNovels[madara].js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/readwebnovels.png"},{"id":"sleeptTLS","name":"SleepyTranslations[madara]","site":"https://sleepytranslations.com/","lang":"English","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/SleepyTranslations[madara].js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/sleepytranslations.png"},{"id":"sonicmtl","name":"SonicMTL[madara]","site":"https://www.sonicmtl.com/","lang":"English","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/SonicMTL[madara].js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/sonicmtl.png"},{"id":"sugarbbscan","name":"Sugar Babies[madara]","site":"https://sugarbbscan.com/","lang":"English","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/SugarBabies[madara].js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/sugarbabies.png"},{"id":"sweetEscapeTL","name":"Sweet Escape Translations[madara]","site":"https://sweetescapetranslations.com/","lang":"English","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/SweetEscapeTranslations[madara].js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/sweetescapetranslations.png"},{"id":"webnovelover","name":"WebNovelLover[madara]","site":"https://www.webnovelover.com/","lang":"English","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/WebNovelLover[madara].js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/webnovellover.png"},{"id":"wuxiacity","name":"Wuxiacity[readwn]","site":"https://www.wuxiacity.com","lang":"English","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/Wuxiacity[readwn].js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/readwn/icons/wuxiacity.png"},{"id":"wuxiap","name":"Wuxiap[readwn]","site":"https://www.wuxiap.com","lang":"English","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/Wuxiap[readwn].js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/readwn/icons/wuxiap.png"},{"id":"wuxiaworld.site","name":"WuxiaWorld.Site[madara]","site":"https://wuxiaworld.site/","lang":"English","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/WuxiaWorldSite[madara].js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/wuxiaworld.site.png"},{"id":"zetroTL","name":"Zetro Translation[madara]","site":"https://zetrotranslation.com/","lang":"English","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/ZetroTranslation[madara].js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/zetrotranslation.png"},{"id":"zinnovel","name":"ZinnNovel[madara]","site":"https://zinnovel.com/","lang":"English","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/english/ZinnNovel[madara].js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/zinnnovel.png"}],"français, française":[{"id":"chireads.com","name":"Chireads","site":"https://chireads.com","lang":"français, française","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/french/chireads.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/fr/chireads/icon.png"},{"id":"lightnovelfr","name":"Ligh Novel FR[wpmangastream]","site":"https://lightnovelfr.com/","lang":"français, française","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/french/LighNovelFR[wpmangastream].js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/wpmangastream/icons/lightnovelfr.png"},{"id":"NDG.com","name":"NovelDeGlace","site":"https://noveldeglace.com/","lang":"français, française","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/french/noveldeglace.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/fr/noveldeglace/icon.png"}],"Bahasa Indonesia":[{"id":"IDWN.id","name":"IndoWebNovel","site":"https://indowebnovel.id/id/","lang":"Bahasa Indonesia","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/indonesian/indowebnovel.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/id/indowebnovel/icon.png"},{"id":"meionovel","name":"MeioNovel[madara]","site":"https://meionovel.id/","lang":"Bahasa Indonesia","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/indonesian/MeioNovel[madara].js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/meionovel.png"},{"id":"morenovel","name":"MoreNovel[madara]","site":"https://morenovel.net/","lang":"Bahasa Indonesia","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/indonesian/MoreNovel[madara].js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/morenovel.png"},{"id":"novelringan.com","name":"NovelRingan","site":"https://novelringan.com/","lang":"Bahasa Indonesia","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/indonesian/novelringan.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/id/novelringan/icon.png"},{"id":"sakura.id","name":"SakuraNovel","site":"https://sakuranovel.id/","lang":"Bahasa Indonesia","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/indonesian/sakuranovel.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/id/sakuranovel/icon.png"},{"id":"wbnovel","name":"WBNovel[madara]","site":"https://wbnovel.com/","lang":"Bahasa Indonesia","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/indonesian/WBNovel[madara].js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/wbnovel.png"}],"日本語":[{"id":"yomou.syosetu","name":"Syosetu","site":"https://yomou.syosetu.com/","lang":"日本語","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/japanese/Syosetu.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/jp/syosetu/icon.png"}],"한국어, 조선말":[{"id":"agit.xyz","name":"Agitoon","site":"https://agit501.xyz/","lang":"한국어, 조선말","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/korean/Agitoon.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/kr/agitoon/agit.png"}],"Português":[{"id":"lightnovelbrasil","name":"Light Novel Brasil","site":"https://lightnovelbrasil.com/","lang":"Português","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/portuguese/lightnovelbrasil.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/wpmangastream/icons/lightnovelbrasil.png"}],"русский язык":[{"id":"AT","name":"Автор Тудей","site":"https://author.today","lang":"русский язык","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/russian/authortoday.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/ru/authortoday/icon.png"},{"id":"bookhamster","name":"Bookhamster[ifreedom]","site":"https://bookhamster.ru","lang":"русский язык","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/russian/Bookhamster[ifreedom].js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/ifreedom/icons/bookhamster.png"},{"id":"bookriver","name":"Bookriver","site":"https://bookriver.ru","lang":"русский язык","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/russian/bookriver.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/ru/bookriver/icon.png"},{"id":"erolate","name":"Erolate[rulate]","site":"https://erolate.com","lang":"русский язык","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/russian/Erolate[rulate].js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/rulate/icons/erolate.png"},{"id":"ficbook","name":"ficbook","site":"https://ficbook.net","lang":"русский язык","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/russian/ficbook.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/ru/ficbook/icon.png"},{"id":"freedlit.space","name":"LitSpace","site":"https://freedlit.space","lang":"русский язык","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/russian/LitSpace.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/ru/freedlit/icon.png"},{"id":"ifreedom","name":"Свободный Мир Ранобэ[ifreedom]","site":"https://ifreedom.su","lang":"русский язык","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/russian/СвободныйМирРанобэ[ifreedom].js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/ifreedom/icons/ifreedom.png"},{"id":"jaomix.ru","name":"Jaomix","site":"https://jaomix.ru","lang":"русский язык","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/russian/jaomix.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/ru/jaomix/icon.png"},{"id":"ReN","name":"Renovels","site":"https://renovels.org","lang":"русский язык","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/russian/renovels.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/ru/renovels/icon.png"},{"id":"RLIB","name":"RanobeLib","site":"https://ranobelib.me","lang":"русский язык","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/russian/ranobelib.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/ru/ranobelib/icon.png"},{"id":"RNBH.org","name":"RanobeHub","site":"https://ranobehub.org/","lang":"русский язык","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/russian/ranobehub.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/ru/ranobehub/icon.png"},{"id":"RNRF","name":"РанобэРФ","site":"https://ранобэ.рф","lang":"русский язык","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/russian/ranoberf.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/ru/ranoberf/icon.png"},{"id":"TL","name":"NovelTL","site":"https://novel.tl","lang":"русский язык","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/russian/novelTL.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/ru/noveltl/icon.png"},{"id":"tl.rulate","name":"Rulate[rulate]","site":"https://tl.rulate.ru","lang":"русский язык","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/russian/Rulate[rulate].js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/rulate/icons/rulate.png"}],"español, castellano":[{"id":"awuxia.com","name":"ReinoWuxia","site":"http://www.reinowuxia.com/","lang":"español, castellano","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/spanish/novelawuxia.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/es/novelawuxia/icon.png"},{"id":"HasuTL","name":"Hasu Translations","site":"https://hasutl.wordpress.com/","lang":"español, castellano","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/spanish/hasutl.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/es/hasutl/icon.png"},{"id":"ligera.com","name":"Novelas Ligera","site":"https://novelasligera.com/","lang":"español, castellano","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/spanish/novelasligera.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/es/novelasligera/icon.png"},{"id":"oasisTL.wp","name":"Oasis Translations","site":"https://oasistranslations.wordpress.com/","lang":"español, castellano","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/spanish/oasistranslations.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/es/oasistranslations/icon.png"},{"id":"skynovels.net","name":"SkyNovels","site":"https://www.skynovels.net/","lang":"español, castellano","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/spanish/skynovels.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/es/skynovels/icon.png"},{"id":"tunovelaligera","name":"TuNovelaLigera","site":"https://tunovelaligera.com/","lang":"español, castellano","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/spanish/tunovelaligera.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/es/tunovelaligera/icon.png"},{"id":"yuukitls.com","name":"Yuuki Tls","site":"https://yuukitls.com/","lang":"español, castellano","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/spanish/yukitls.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/es/yuukitls/icon.png"}],"Türkçe":[{"id":"epiknovel.com","name":"EpikNovel","site":"https://www.epiknovel.com/","lang":"Türkçe","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/turkish/epiknovel.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/tr/epiknovel/icon.png"},{"id":"lshnovel","name":"Liebe Schnee Hiver Novel","site":"https://lshnovel.com/","lang":"Türkçe","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/turkish/lshnovel.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/wpmangastream/icons/lshnovel.png"},{"id":"turkcelightnovels","name":"TurkceLightNovels[madara]","site":"https://turkcelightnovels.com/","lang":"Türkçe","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/turkish/TurkceLightNovels[madara].js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/turkcelightnovels.png"},{"id":"webnoveloku","name":"WebNovelOku [madara]","site":"https://www.webnoveloku.com/","lang":"Türkçe","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/turkish/WebNovelOku[madara].js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/multisrc/madara/icons/webnoveloku.png"}],"Україна":[{"id":"smakolykytl","name":"Смаколики","site":"https://smakolykytl.site/","lang":"Україна","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/ukraine/smakolykytl.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/ua/smakolykytl/icon.png"}],"Tiếng Việt":[{"id":"ln.hako","name":"Hako","site":"https://ln.hako.vn","lang":"Tiếng Việt","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/.js/plugins/vietnamese/LNHako.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/fix-plugins/icons/src/vi/hakolightnovel/icon.png"}]} \ No newline at end of file diff --git a/.github/workflows/typechecking.yml b/.github/workflows/typechecking.yml new file mode 100644 index 0000000..1148191 --- /dev/null +++ b/.github/workflows/typechecking.yml @@ -0,0 +1,29 @@ +name: Update json files + +on: + pull_request: + branches: + - plugins + +jobs: + typechecking: + if: github.repository == 'LNReader/lnreader-sources' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: "18" + - name: Install dependencies + run: npm install + + - name: Typescript checking + run: | + cat > config.json << EOF + { + "githubUsername": "LNReader", + "githubRepository": "lnreader-sources", + "githubBranch": "plugins" + } + EOF + tsc diff --git a/.github/workflows/updatejson.yml b/.github/workflows/updatejson.yml index 9ff5b84..7184e26 100644 --- a/.github/workflows/updatejson.yml +++ b/.github/workflows/updatejson.yml @@ -13,7 +13,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: - node-version: "16" + node-version: "18" - name: Install dependencies run: npm install diff --git a/.js/plugins/indonesian/indowebnovel.js b/.js/plugins/indonesian/indowebnovel.js new file mode 100644 index 0000000..49c70c5 --- /dev/null +++ b/.js/plugins/indonesian/indowebnovel.js @@ -0,0 +1,200 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var cheerio_1 = require("cheerio"); +var fetch_1 = require("@libs/fetch"); +var defaultCover_1 = require("@libs/defaultCover"); +var IndoWebNovel = /** @class */ (function () { + function IndoWebNovel() { + this.id = "IDWN.id"; + this.name = "IndoWebNovel"; + this.icon = "src/id/indowebnovel/icon.png"; + this.site = "https://indowebnovel.id/id/"; + this.version = "1.0.0"; + this.baseUrl = this.site; + } + IndoWebNovel.prototype.popularNovels = function (pageNo, options) { + return __awaiter(this, void 0, void 0, function () { + var url, result, body, loadedCheerio, novels; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + url = "".concat(this.baseUrl, "daftar-novel/"); + return [4 /*yield*/, (0, fetch_1.fetchApi)(url)]; + case 1: + result = _a.sent(); + return [4 /*yield*/, result.text()]; + case 2: + body = _a.sent(); + loadedCheerio = (0, cheerio_1.load)(body); + novels = []; + loadedCheerio(".novellist-blc li").each(function () { + var novelName = loadedCheerio(this).find("a").text(); + var novelCover = defaultCover_1.defaultCover; + var novelUrl = loadedCheerio(this).find("a").attr("href"); + if (!novelUrl || !novelName) + return; + var novel = { + name: novelName, + cover: novelCover, + url: novelUrl, + }; + novels.push(novel); + }); + return [2 /*return*/, novels]; + } + }); + }); + }; + IndoWebNovel.prototype.parseNovelAndChapters = function (novelUrl) { + return __awaiter(this, void 0, void 0, function () { + var url, result, body, loadedCheerio, novel, genres, chapters; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + url = novelUrl; + return [4 /*yield*/, (0, fetch_1.fetchApi)(url)]; + case 1: + result = _a.sent(); + return [4 /*yield*/, result.text()]; + case 2: + body = _a.sent(); + loadedCheerio = (0, cheerio_1.load)(body); + novel = { + url: url, + name: "", + cover: "", + author: "", + status: "", + genres: "", + summary: "", + chapters: [], + }; + novel.name = loadedCheerio(".series-title").text().trim(); + novel.cover = loadedCheerio(".series-thumb > img").attr("src"); + novel.summary = loadedCheerio(".series-synops").text().trim(); + novel.status = loadedCheerio(".status").text().trim(); + genres = []; + loadedCheerio(".series-genres").each(function () { + genres.push(loadedCheerio(this).find("a").text().trim()); + }); + novel.genres = genres.join(","); + chapters = []; + loadedCheerio(".series-chapterlist li").each(function () { + var chapterName = loadedCheerio(this).find("a").text().trim(); + var releaseDate = null; + var chapterUrl = loadedCheerio(this).find("a").attr("href"); + if (!chapterUrl) + return; + chapters.push({ + name: chapterName, + releaseTime: releaseDate, + url: chapterUrl, + }); + }); + novel.chapters = chapters.reverse(); + return [2 /*return*/, novel]; + } + }); + }); + }; + IndoWebNovel.prototype.parseChapter = function (chapterUrl) { + return __awaiter(this, void 0, void 0, function () { + var url, result, body, loadedCheerio, chapterText; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + url = chapterUrl; + return [4 /*yield*/, (0, fetch_1.fetchApi)(url)]; + case 1: + result = _a.sent(); + return [4 /*yield*/, result.text()]; + case 2: + body = _a.sent(); + loadedCheerio = (0, cheerio_1.load)(body); + chapterText = loadedCheerio(".readerss").html() || ''; + return [2 /*return*/, chapterText]; + } + }); + }); + }; + IndoWebNovel.prototype.searchNovels = function (searchTerm, pageNo) { + return __awaiter(this, void 0, void 0, function () { + var url, result, body, loadedCheerio, novels; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + url = "".concat(this.baseUrl, "daftar-novel/"); + return [4 /*yield*/, (0, fetch_1.fetchApi)(url)]; + case 1: + result = _a.sent(); + return [4 /*yield*/, result.text()]; + case 2: + body = _a.sent(); + loadedCheerio = (0, cheerio_1.load)(body); + novels = []; + loadedCheerio(".novellist-blc li").each(function () { + var novelName = loadedCheerio(this).find("a").text(); + var novelCover = defaultCover_1.defaultCover; + var novelUrl = loadedCheerio(this).find("a").attr("href"); + if (!novelUrl) + return; + var novel = { + name: novelName, + cover: novelCover, + url: novelUrl, + }; + if (novelName.toLowerCase().includes(searchTerm.toLowerCase())) { + novels.push(novel); + } + }); + return [2 /*return*/, novels]; + } + }); + }); + }; + IndoWebNovel.prototype.fetchImage = function (url) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, (0, fetch_1.fetchFile)(url)]; + }); + }); + }; + return IndoWebNovel; +}()); +exports.default = new IndoWebNovel(); diff --git a/.js/plugins/indonesian/novelringan.js b/.js/plugins/indonesian/novelringan.js new file mode 100644 index 0000000..8cc5ea7 --- /dev/null +++ b/.js/plugins/indonesian/novelringan.js @@ -0,0 +1,211 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var cheerio_1 = require("cheerio"); +var fetch_1 = require("@libs/fetch"); +var novelStatus_1 = require("@libs/novelStatus"); +var NovelRingan = /** @class */ (function () { + function NovelRingan() { + this.id = "novelringan.com"; + this.name = "NovelRingan"; + this.icon = "src/id/novelringan/icon.png"; + this.site = "https://novelringan.com/"; + this.version = "1.0.0"; + this.baseUrl = this.site; + this.coverUriPrefix = "https://i0.wp.com/novelringan.com/wp-content/uploads/"; + } + NovelRingan.prototype.popularNovels = function (pageNo, options) { + return __awaiter(this, void 0, void 0, function () { + var url, result, body, loadedCheerio, novels; + var _this = this; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + url = "".concat(this.baseUrl, "/top-novel/page/").concat(pageNo); + return [4 /*yield*/, (0, fetch_1.fetchApi)(url)]; + case 1: + result = _a.sent(); + return [4 /*yield*/, result.text()]; + case 2: + body = _a.sent(); + loadedCheerio = (0, cheerio_1.load)(body); + novels = []; + loadedCheerio("article.post").each(function (idx, ele) { + var _a; + var novelName = (_a = loadedCheerio(ele) + .find(".entry-title") + .text()) === null || _a === void 0 ? void 0 : _a.trim(); + var novelCover = _this.coverUriPrefix + loadedCheerio(ele).find("img").attr("data-sxrx"); + var novelUrl = loadedCheerio(ele).find("h2 > a").attr("href"); + if (!novelUrl) + return; + var novel = { + name: novelName, + cover: novelCover, + url: novelUrl, + }; + novels.push(novel); + }); + return [2 /*return*/, novels]; + } + }); + }); + }; + NovelRingan.prototype.parseNovelAndChapters = function (novelUrl) { + var _a; + return __awaiter(this, void 0, void 0, function () { + var url, result, body, loadedCheerio, novel, genreSelector, statusSelector, chapters; + return __generator(this, function (_b) { + switch (_b.label) { + case 0: + url = novelUrl; + return [4 /*yield*/, (0, fetch_1.fetchApi)(url)]; + case 1: + result = _b.sent(); + return [4 /*yield*/, result.text()]; + case 2: + body = _b.sent(); + loadedCheerio = (0, cheerio_1.load)(body); + novel = { + url: url, + name: "", + cover: "", + genres: "", + author: "", + status: novelStatus_1.NovelStatus.Unknown, + summary: "", + chapters: [], + }; + novel.name = (_a = loadedCheerio(".entry-title").text()) === null || _a === void 0 ? void 0 : _a.trim(); + novel.cover = + this.coverUriPrefix + + loadedCheerio("img.ts-post-image").attr("data-sxrx"); + novel.summary = loadedCheerio("body > div.site-container > div > main > article > div > div.maininfo > span > p").text(); + genreSelector = loadedCheerio("body > div.site-container > div > main > article > div > div.maininfo > span > ul > li:nth-child(4)").text(); + novel.genres = genreSelector.includes("Genre") + ? genreSelector.replace("Genre:", "").trim() + : ""; + statusSelector = loadedCheerio("body > div.site-container > div > main > article > div > div.maininfo > span > ul > li:nth-child(3)").text(); + novel.status = statusSelector.includes("Status") + ? statusSelector.replace("Status:", "").trim() + : novelStatus_1.NovelStatus.Unknown; + chapters = []; + loadedCheerio(".bxcl > ul > li").each(function () { + var chapterName = loadedCheerio(this).find("a").text(); + var releaseDate = null; + var chapterUrl = loadedCheerio(this).find("a").attr("href"); + if (!chapterUrl) + return; + var chapter = { + name: chapterName, + releaseTime: releaseDate, + url: chapterUrl, + }; + chapters.push(chapter); + }); + novel.chapters = chapters.reverse(); + return [2 /*return*/, novel]; + } + }); + }); + }; + NovelRingan.prototype.parseChapter = function (chapterUrl) { + return __awaiter(this, void 0, void 0, function () { + var url, result, body, loadedCheerio, chapterText; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + url = chapterUrl; + return [4 /*yield*/, (0, fetch_1.fetchApi)(url)]; + case 1: + result = _a.sent(); + return [4 /*yield*/, result.text()]; + case 2: + body = _a.sent(); + loadedCheerio = (0, cheerio_1.load)(body); + loadedCheerio('.entry-content div[style="display:none"]').remove(); + chapterText = loadedCheerio(".entry-content").html() || ''; + return [2 /*return*/, chapterText]; + } + }); + }); + }; + NovelRingan.prototype.searchNovels = function (searchTerm, pageNo) { + return __awaiter(this, void 0, void 0, function () { + var url, result, body, loadedCheerio, novels; + var _this = this; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + url = this.baseUrl + "?s=" + searchTerm; + return [4 /*yield*/, (0, fetch_1.fetchApi)(url)]; + case 1: + result = _a.sent(); + return [4 /*yield*/, result.text()]; + case 2: + body = _a.sent(); + loadedCheerio = (0, cheerio_1.load)(body); + novels = []; + loadedCheerio("article.post").each(function (idx, ele) { + var novelName = loadedCheerio(ele).find(".entry-title").text(); + var novelCover = _this.coverUriPrefix + loadedCheerio(ele).find("img").attr("data-sxrx"); + var novelUrl = loadedCheerio(ele).find("h2 > a").attr("href"); + if (!novelUrl) + return; + var novel = { + name: novelName, + cover: novelCover, + url: novelUrl, + }; + novels.push(novel); + }); + return [2 /*return*/, novels]; + } + }); + }); + }; + NovelRingan.prototype.fetchImage = function (url) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, (0, fetch_1.fetchFile)(url)]; + }); + }); + }; + return NovelRingan; +}()); +exports.default = new NovelRingan(); diff --git a/.js/plugins/indonesian/sakuranovel.js b/.js/plugins/indonesian/sakuranovel.js new file mode 100644 index 0000000..853ee62 --- /dev/null +++ b/.js/plugins/indonesian/sakuranovel.js @@ -0,0 +1,209 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var cheerio_1 = require("cheerio"); +var fetch_1 = require("@libs/fetch"); +var SakuraNovel = /** @class */ (function () { + function SakuraNovel() { + this.id = "sakura.id"; + this.name = "SakuraNovel"; + this.icon = "src/id/sakuranovel/icon.png"; + this.site = "https://sakuranovel.id/"; + this.version = "1.0.0"; + this.baseUrl = this.site; + } + SakuraNovel.prototype.popularNovels = function (pageNo, options) { + return __awaiter(this, void 0, void 0, function () { + var url, result, body, loadedCheerio, novels; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + url = "".concat(this.baseUrl, "advanced-search/page/").concat(pageNo, "/?title&author&yearx&status&type&order=rating&country%5B0%5D=china&country%5B1%5D=jepang&country%5B2%5D=unknown"); + return [4 /*yield*/, (0, fetch_1.fetchApi)(url)]; + case 1: + result = _a.sent(); + return [4 /*yield*/, result.text()]; + case 2: + body = _a.sent(); + loadedCheerio = (0, cheerio_1.load)(body); + novels = []; + loadedCheerio(".flexbox2-item").each(function () { + var novelName = loadedCheerio(this) + .find(".flexbox2-title span") + .first() + .text(); + var novelCover = loadedCheerio(this).find("img").attr("src"); + var novelUrl = loadedCheerio(this) + .find(".flexbox2-content > a") + .attr("href"); + if (!novelUrl) + return; + var novel = { name: novelName, cover: novelCover, url: novelUrl }; + novels.push(novel); + }); + return [2 /*return*/, novels]; + } + }); + }); + }; + SakuraNovel.prototype.parseNovelAndChapters = function (novelUrl) { + return __awaiter(this, void 0, void 0, function () { + var result, body, loadedCheerio, novel, chapters; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, (0, fetch_1.fetchApi)(novelUrl)]; + case 1: + result = _a.sent(); + return [4 /*yield*/, result.text()]; + case 2: + body = _a.sent(); + loadedCheerio = (0, cheerio_1.load)(body); + novel = { + url: novelUrl, + }; + novel.name = loadedCheerio(".series-title h2").text().trim(); + novel.cover = loadedCheerio(".series-thumb img").attr("src"); + loadedCheerio(".series-infolist > li").each(function () { + var detailName = loadedCheerio(this).find("b").text().trim(); + var detail = loadedCheerio(this).find("b").next().text().trim(); + switch (detailName) { + case "Author": + novel.author = detail; + break; + } + }); + novel.status = loadedCheerio(".status").text().trim(); + novel.genres = loadedCheerio(".series-genres") + .children("a") + .map(function (i, el) { return loadedCheerio(el).text(); }) + .toArray() + .join(","); + loadedCheerio(".series-synops div").remove(); + novel.summary = loadedCheerio(".series-synops").text().trim(); + chapters = []; + loadedCheerio(".series-chapterlist li").each(function () { + var chapterName = loadedCheerio(this) + .find("a span") + .first() + .text() + .replace(/.*?(Chapter.|[0-9])/g, "$1") + .replace(/Bahasa Indonesia/g, "") + .replace(/\s+/g, " ") + .trim(); + var releaseDate = loadedCheerio(this) + .find("a span") + .first() + .next() + .text(); + var chapterUrl = loadedCheerio(this).find("a").attr("href"); + if (!chapterUrl) + return; + chapters.push({ + name: chapterName, + releaseTime: releaseDate, + url: chapterUrl, + }); + }); + novel.chapters = chapters.reverse(); + return [2 /*return*/, novel]; + } + }); + }); + }; + SakuraNovel.prototype.parseChapter = function (chapterUrl) { + return __awaiter(this, void 0, void 0, function () { + var result, body, loadedCheerio, chapterText; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, (0, fetch_1.fetchApi)(chapterUrl)]; + case 1: + result = _a.sent(); + return [4 /*yield*/, result.text()]; + case 2: + body = _a.sent(); + loadedCheerio = (0, cheerio_1.load)(body); + chapterText = loadedCheerio(".readerss").html() || ''; + return [2 /*return*/, chapterText]; + } + }); + }); + }; + SakuraNovel.prototype.searchNovels = function (searchTerm, pageNo) { + return __awaiter(this, void 0, void 0, function () { + var url, result, body, loadedCheerio, novels; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + url = "".concat(this.baseUrl, "?s=").concat(searchTerm); + return [4 /*yield*/, (0, fetch_1.fetchApi)(url)]; + case 1: + result = _a.sent(); + return [4 /*yield*/, result.text()]; + case 2: + body = _a.sent(); + loadedCheerio = (0, cheerio_1.load)(body); + novels = []; + loadedCheerio(".flexbox2-item").each(function () { + var novelName = loadedCheerio(this) + .find(".flexbox2-title span") + .first() + .text(); + var novelCover = loadedCheerio(this).find("img").attr("src"); + var novelUrl = loadedCheerio(this) + .find(".flexbox2-content > a") + .attr("href"); + if (!novelUrl) + return; + var novel = { name: novelName, cover: novelCover, url: novelUrl }; + novels.push(novel); + }); + return [2 /*return*/, novels]; + } + }); + }); + }; + SakuraNovel.prototype.fetchImage = function (url) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, (0, fetch_1.fetchFile)(url)]; + }); + }); + }; + return SakuraNovel; +}()); +exports.default = new SakuraNovel(); diff --git a/.js/plugins/japanese/Syosetu.js b/.js/plugins/japanese/Syosetu.js new file mode 100644 index 0000000..f127eee --- /dev/null +++ b/.js/plugins/japanese/Syosetu.js @@ -0,0 +1,280 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.site = exports.version = exports.icon = exports.name = exports.id = void 0; +var cheerio_1 = require("cheerio"); +var fetch_1 = require("@libs/fetch"); +var defaultCover_1 = require("@libs/defaultCover"); +// const novelStatus = require('@libs/novelStatus'); +// const isUrlAbsolute = require('@libs/isAbsoluteUrl'); +// const parseDate = require('@libs/parseDate'); +var pluginId = "yomou.syosetu"; +exports.id = pluginId; +exports.name = "Syosetu"; +exports.icon = "src/jp/syosetu/icon.png"; +exports.version = "1.0.0"; +exports.site = "https://yomou.syosetu.com/"; +var Syosetu = /** @class */ (function () { + function Syosetu() { + this.id = "yomou.syosetu"; + this.name = "Syosetu"; + this.icon = "src/jp/syosetu/icon.png"; + this.site = "https://yomou.syosetu.com/"; + this.version = "1.0.0"; + this.headers = { + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" + }; + this.searchUrl = function (pagenum, order) { + return "https://yomou.syosetu.com/search.php?order=".concat(order || "hyoka").concat(pagenum !== undefined + ? "&p=".concat(pagenum <= 1 || pagenum > 100 ? "1" : pagenum) // check if pagenum is between 1 and 100 + : "" // if isn't don't set ?p + ); + }; + } + Syosetu.prototype.popularNovels = function (pageNo, options) { + return __awaiter(this, void 0, void 0, function () { + var getNovelsFromPage, novels; + var _this = this; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + getNovelsFromPage = function (pagenumber) { return __awaiter(_this, void 0, void 0, function () { + var result, body, cheerioQuery, pageNovels; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, fetch(this.searchUrl(pagenumber), { headers: this.headers })]; + case 1: + result = _a.sent(); + return [4 /*yield*/, result.text()]; + case 2: + body = _a.sent(); + cheerioQuery = (0, cheerio_1.load)(body, { decodeEntities: false }); + pageNovels = []; + // find class=searchkekka_box + cheerioQuery(".searchkekka_box").each(function (i, e) { + // get div with link and name + var novelDIV = cheerioQuery(this).find(".novel_h"); + // get link element + var novelA = novelDIV.children()[0]; + // add new novel to array + pageNovels.push({ + name: novelDIV.text(), + url: novelA.attribs.href, + cover: defaultCover_1.defaultCover, + }); + }); + // return all novels from this page + return [2 /*return*/, pageNovels]; + } + }); + }); }; + return [4 /*yield*/, getNovelsFromPage(pageNo)]; + case 1: + novels = _a.sent(); + return [2 /*return*/, novels]; + } + }); + }); + }; + Syosetu.prototype.parseNovelAndChapters = function (novelUrl) { + return __awaiter(this, void 0, void 0, function () { + var chapters, result, body, loadedCheerio, novel, cqGetChapters, nameResult, nameBody, summaryQuery, foundText; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + chapters = []; + return [4 /*yield*/, fetch(novelUrl, { headers: this.headers })]; + case 1: + result = _a.sent(); + return [4 /*yield*/, result.text()]; + case 2: + body = _a.sent(); + loadedCheerio = (0, cheerio_1.load)(body, { decodeEntities: false }); + novel = { + url: novelUrl, + name: loadedCheerio(".novel_title").text(), + author: loadedCheerio(".novel_writername") + .text() + .replace("作者:", ""), + cover: defaultCover_1.defaultCover, + }; + cqGetChapters = loadedCheerio(".novel_sublist2"); + if (!(cqGetChapters.length !== 0)) return [3 /*break*/, 3]; + // has more than 1 chapter + novel.summary = loadedCheerio("#novel_ex") + .text() + .replace(/<\s*br.*?>/g, "\n"); + cqGetChapters.each(function (i, e) { + var chapterA = loadedCheerio(this).find("a"); + var _a = [ + // set the variables + chapterA.text(), + loadedCheerio(this) + .find("dt") // get title + .text() // get text + .replace(/(.)/g, "") // remove "(edited)" mark + .trim(), + "https://ncode.syosetu.com" + chapterA.attr("href"), + ], chapterName = _a[0], releaseDate = _a[1], chapterUrl = _a[2]; + chapters.push({ + name: chapterName, + releaseTime: releaseDate, + url: chapterUrl, + }); + }); + return [3 /*break*/, 6]; + case 3: return [4 /*yield*/, fetch(this.searchUrl() + "&word=".concat(novel.name), { headers: this.headers })]; + case 4: + nameResult = _a.sent(); + return [4 /*yield*/, nameResult.text()]; + case 5: + nameBody = _a.sent(); + summaryQuery = (0, cheerio_1.load)(nameBody, { + decodeEntities: false, + }); + foundText = summaryQuery(".searchkekka_box") + .first() + .find(".ex") + .text() + .replace(/\s{2,}/g, "\n"); + novel.summary = foundText; + // add single chapter + chapters.push({ + name: "Oneshot", + releaseTime: loadedCheerio("head") + .find("meta[name='WWWC']") + .attr("content"), + url: novelUrl, // set chapterUrl to oneshot so that chapterScraper knows it's a one-shot, + }); + _a.label = 6; + case 6: + novel.chapters = chapters; + return [2 /*return*/, novel]; + } + }); + }); + }; + Syosetu.prototype.parseChapter = function (chapterUrl) { + return __awaiter(this, void 0, void 0, function () { + var result, body, cheerioQuery, chapterText; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, fetch(chapterUrl, { headers: this.headers })]; + case 1: + result = _a.sent(); + return [4 /*yield*/, result.text()]; + case 2: + body = _a.sent(); + cheerioQuery = (0, cheerio_1.load)(body, { + decodeEntities: false, + }); + chapterText = cheerioQuery("#novel_honbun") // get chapter text + .html() || ''; + return [2 /*return*/, chapterText]; + } + }); + }); + }; + Syosetu.prototype.searchNovels = function (searchTerm, pageNo) { + return __awaiter(this, void 0, void 0, function () { + var novels, getNovelsFromPage; + var _this = this; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + novels = []; + getNovelsFromPage = function (pagenumber) { return __awaiter(_this, void 0, void 0, function () { + var result, body, cheerioQuery, pageNovels; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, fetch(this.searchUrl(pagenumber) + "&word=".concat(searchTerm), { headers: this.headers })]; + case 1: + result = _a.sent(); + return [4 /*yield*/, result.text()]; + case 2: + body = _a.sent(); + cheerioQuery = (0, cheerio_1.load)(body, { decodeEntities: false }); + pageNovels = []; + // find class=searchkekka_box + cheerioQuery(".searchkekka_box").each(function (i, e) { + // get div with link and name + var novelDIV = cheerioQuery(this).find(".novel_h"); + // get link element + var novelA = novelDIV.children()[0]; + // add new novel to array + pageNovels.push({ + name: novelDIV.text(), + url: novelA.attribs.href, + cover: defaultCover_1.defaultCover, + }); + }); + // return all novels from this page + return [2 /*return*/, pageNovels]; + } + }); + }); }; + return [4 /*yield*/, getNovelsFromPage(1)]; + case 1: + // counter of loaded pages + // let pagesLoaded = 0; + // do { + // // always load first one + // novels.push(...(await getNovelsFromPage(pagesLoaded + 1))); + // pagesLoaded++; + // } while (pagesLoaded < maxPageLoad && isNext); // check if we should load more + novels = _a.sent(); + /** Use + * novels.push(...(await getNovelsFromPage(pageNumber))) + * if you want to load more + */ + // respond with novels! + return [2 /*return*/, novels]; + } + }); + }); + }; + Syosetu.prototype.fetchImage = function (url) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, (0, fetch_1.fetchFile)(url)]; + }); + }); + }; + return Syosetu; +}()); +exports.default = new Syosetu(); diff --git a/.js/plugins/korean/Agitoon.js b/.js/plugins/korean/Agitoon.js new file mode 100644 index 0000000..2c90cab --- /dev/null +++ b/.js/plugins/korean/Agitoon.js @@ -0,0 +1,216 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.icon = exports.version = exports.site = exports.name = exports.id = void 0; +var cheerio_1 = require("cheerio"); +var fetch_1 = require("@libs/fetch"); +exports.id = "agit.xyz"; +exports.name = "Agitoon"; +exports.site = "https://agit501.xyz/"; +exports.version = "1.0.0"; +exports.icon = "src/kr/agitoon/agit.png"; +var baseUrl = exports.site; +var Agitoon = /** @class */ (function () { + function Agitoon() { + this.id = "agit.xyz"; + this.name = "Agitoon"; + this.icon = "src/kr/agitoon/agit.png"; + this.site = "https://agit501.xyz/"; + this.version = "1.0.0"; + } + Agitoon.prototype.popularNovels = function (pageNo, options) { + var _a; + return __awaiter(this, void 0, void 0, function () { + var list_limit, day, res, resJson, novels; + return __generator(this, function (_b) { + switch (_b.label) { + case 0: + list_limit = 20 * (pageNo - 1); + day = new Date().getDay(); + return [4 /*yield*/, (0, fetch_1.fetchApi)(baseUrl + "novel/index.update.php", { + headers: { + "content-type": "application/x-www-form-urlencoded; charset=UTF-8", + }, + body: "mode=get_data_novel_list_p&novel_menu=3&np_day=".concat(day, "&np_rank=1&np_distributor=0&np_genre=00&np_order=1&np_genre_ex_1=00&np_genre_ex_2=00&list_limit=").concat(list_limit, "&is_query_first=true"), + method: "POST", + })]; + case 1: + res = _b.sent(); + return [4 /*yield*/, res.json()]; + case 2: + resJson = _b.sent(); + novels = []; + (_a = resJson === null || resJson === void 0 ? void 0 : resJson.list) === null || _a === void 0 ? void 0 : _a.forEach(function (novel) { + novels.push({ + url: baseUrl + "novel/list/" + novel.wr_id, + name: novel.wr_subject, + cover: baseUrl + novel.np_dir + "/thumbnail/" + novel.np_thumbnail, + }); + }); + return [2 /*return*/, novels]; + } + }); + }); + }; + Agitoon.prototype.parseNovelAndChapters = function (novelUrl) { + var _a; + return __awaiter(this, void 0, void 0, function () { + var novelId, result, body, loadedCheerio, name, summary, author, cover, genresTag, genres, chapters, res, resJson, novel; + return __generator(this, function (_b) { + switch (_b.label) { + case 0: + novelId = novelUrl.split("/").reverse()[0]; + return [4 /*yield*/, (0, fetch_1.fetchApi)(novelUrl)]; + case 1: + result = _b.sent(); + return [4 /*yield*/, result.text()]; + case 2: + body = _b.sent(); + loadedCheerio = (0, cheerio_1.load)(body, { decodeEntities: false }); + name = loadedCheerio("h5.pt-2").text(); + summary = loadedCheerio(".pt-1.mt-1.pb-1.mb-1").text(); + author = loadedCheerio(".post-item-list-cate-v") + .first() + .text() + .split(" : ") + .reverse()[0]; + cover = baseUrl.slice(0, baseUrl.length - 1) + + loadedCheerio("div.col-5.pr-0.pl-0 img").attr("src"); + genresTag = loadedCheerio(".col-7 > .post-item-list-cate > span"); + genres = ""; + genresTag.each(function (_, element) { + genres += loadedCheerio(element).text(); + genres += ", "; + }); + genres = genres.slice(0, genres.length - 2); + chapters = []; + return [4 /*yield*/, (0, fetch_1.fetchApi)(baseUrl + "novel/list.update.php", { + headers: { + "content-type": "application/x-www-form-urlencoded; charset=UTF-8", + }, + body: "mode=get_data_novel_list_c&wr_id_p=".concat(novelId, "&page_no=1&cnt_list=10000&order_type=Asc"), + method: "POST", + })]; + case 3: + res = _b.sent(); + return [4 /*yield*/, res.json()]; + case 4: + resJson = _b.sent(); + (_a = resJson === null || resJson === void 0 ? void 0 : resJson.list) === null || _a === void 0 ? void 0 : _a.forEach(function (chapter) { + chapters.push({ + name: chapter.wr_subject, + url: baseUrl + "novel/view/".concat(chapter.wr_id, "/2"), + releaseTime: chapter.wr_datetime, + }); + }); + novel = { + url: novelUrl, + name: name, + cover: cover, + summary: summary, + author: author, + status: "", + genres: genres, + chapters: chapters, + }; + return [2 /*return*/, novel]; + } + }); + }); + }; + Agitoon.prototype.parseChapter = function (chapterUrl) { + return __awaiter(this, void 0, void 0, function () { + var result, body, loadedCheerio, content; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, (0, fetch_1.fetchApi)(chapterUrl)]; + case 1: + result = _a.sent(); + return [4 /*yield*/, result.text()]; + case 2: + body = _a.sent(); + loadedCheerio = (0, cheerio_1.load)(body); + content = loadedCheerio("#id_wr_content").html() || ''; + // gets rid of the popup thingy + content = content.replace("팝업메뉴는 빈공간을 더치하거나 스크룰시 사라집니다", ""); + return [2 /*return*/, content]; + } + }); + }); + }; + Agitoon.prototype.searchNovels = function (searchTerm, pageNo) { + var _a; + return __awaiter(this, void 0, void 0, function () { + var rawResults, resJson, novels; + return __generator(this, function (_b) { + switch (_b.label) { + case 0: return [4 /*yield*/, (0, fetch_1.fetchApi)("https://agit501.xyz/novel/search.php", { + headers: { + "content-type": "application/x-www-form-urlencoded; charset=UTF-8", + }, + body: "mode=get_data_novel_list_p_sch&search_novel=".concat(searchTerm, "&list_limit=0"), + method: "POST", + })]; + case 1: + rawResults = _b.sent(); + return [4 /*yield*/, rawResults.json()]; + case 2: + resJson = _b.sent(); + novels = []; + (_a = resJson === null || resJson === void 0 ? void 0 : resJson.list) === null || _a === void 0 ? void 0 : _a.forEach(function (novel) { + novels.push({ + url: baseUrl + "novel/list/" + novel.wr_id, + name: novel.wr_subject, + cover: baseUrl + novel.np_dir + "/thumbnail/" + novel.np_thumbnail, + }); + }); + return [2 /*return*/, novels]; + } + }); + }); + }; + Agitoon.prototype.fetchImage = function (url) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, (0, fetch_1.fetchFile)(url)]; + }); + }); + }; + return Agitoon; +}()); +exports.default = new Agitoon(); diff --git a/.js/plugins/spanish/hasutl.js b/.js/plugins/spanish/hasutl.js new file mode 100644 index 0000000..85ffbad --- /dev/null +++ b/.js/plugins/spanish/hasutl.js @@ -0,0 +1,195 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var cheerio_1 = require("cheerio"); +var fetch_1 = require("@libs/fetch"); +var HasulTL = /** @class */ (function () { + function HasulTL() { + this.id = "HasuTL"; + this.name = "Hasu Translations"; + this.icon = "src/es/hasutl/icon.png"; + this.site = "https://hasutl.wordpress.com/"; + this.version = "1.0.0"; + this.baseUrl = this.site; + } + HasulTL.prototype.popularNovels = function (pageNo, options) { + return __awaiter(this, void 0, void 0, function () { + var url, result, body, loadedCheerio, novels; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + url = this.baseUrl + "light-novels-activas/"; + return [4 /*yield*/, fetch(url)]; + case 1: + result = _a.sent(); + return [4 /*yield*/, result.text()]; + case 2: + body = _a.sent(); + loadedCheerio = (0, cheerio_1.load)(body); + novels = []; + loadedCheerio("div.wp-block-columns").each(function () { + var novelName = loadedCheerio(this).find(".wp-block-button").text(); + var novelCover = loadedCheerio(this).find("img").attr("src"); + var novelUrl = loadedCheerio(this) + .find(".wp-block-button > a") + .attr("href"); + if (!novelUrl) + return; + var novel = { + name: novelName, + cover: novelCover, + url: novelUrl, + }; + novels.push(novel); + }); + return [2 /*return*/, novels]; + } + }); + }); + }; + HasulTL.prototype.parseNovelAndChapters = function (novelUrl) { + return __awaiter(this, void 0, void 0, function () { + var url, result, body, loadedCheerio, novel, novelSummary, novelChapters; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + url = novelUrl; + return [4 /*yield*/, fetch(url)]; + case 1: + result = _a.sent(); + return [4 /*yield*/, result.text()]; + case 2: + body = _a.sent(); + loadedCheerio = (0, cheerio_1.load)(body); + novel = { + url: url, + }; + novel.url = novelUrl; + novel.name = loadedCheerio(".post-header").text(); + novel.cover = loadedCheerio(".featured-media > img").attr("src"); + novelSummary = loadedCheerio(".post-content").find("p").html(); + novel.summary = novelSummary; + novelChapters = []; + loadedCheerio(".wp-block-media-text__content") + .find("a") + .each(function () { + var chapterName = loadedCheerio(this).text().trim(); + var releaseDate = null; + var chapterUrl = loadedCheerio(this).attr("href"); + if (!chapterUrl) + return; + var chapter = { + name: chapterName, + releaseTime: releaseDate, + url: chapterUrl, + }; + novelChapters.push(chapter); + }); + novel.chapters = novelChapters; + return [2 /*return*/, novel]; + } + }); + }); + }; + HasulTL.prototype.parseChapter = function (chapterUrl) { + return __awaiter(this, void 0, void 0, function () { + var url, result, body, loadedCheerio, chapterText; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + url = chapterUrl; + return [4 /*yield*/, fetch(url)]; + case 1: + result = _a.sent(); + return [4 /*yield*/, result.text()]; + case 2: + body = _a.sent(); + loadedCheerio = (0, cheerio_1.load)(body); + chapterText = loadedCheerio(".post-content").html() || ''; + return [2 /*return*/, chapterText]; + } + }); + }); + }; + HasulTL.prototype.searchNovels = function (searchTerm, pageNo) { + return __awaiter(this, void 0, void 0, function () { + var url, result, body, loadedCheerio, novels; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + url = "".concat(this.baseUrl, "?s=").concat(searchTerm, "&post_type=wp-manga"); + return [4 /*yield*/, fetch(url)]; + case 1: + result = _a.sent(); + return [4 /*yield*/, result.text()]; + case 2: + body = _a.sent(); + loadedCheerio = (0, cheerio_1.load)(body); + novels = []; + loadedCheerio(".post-container").each(function () { + var novelName = loadedCheerio(this).find(".post-header").text(); + if (!novelName.includes("Cap") && + !novelName.includes("Vol") && + !novelName.includes("Light Novels")) { + var novelCover = loadedCheerio(this).find("img").attr("src"); + var novelUrl = loadedCheerio(this).find("a").attr("href"); + if (!novelUrl) + return; + var novel = { + name: novelName, + cover: novelCover, + url: novelUrl, + }; + novels.push(novel); + } + }); + return [2 /*return*/, novels]; + } + }); + }); + }; + HasulTL.prototype.fetchImage = function (url) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, (0, fetch_1.fetchFile)(url)]; + }); + }); + }; + return HasulTL; +}()); +exports.default = new HasulTL(); diff --git a/.js/plugins/spanish/novelasligera.js b/.js/plugins/spanish/novelasligera.js new file mode 100644 index 0000000..9270555 --- /dev/null +++ b/.js/plugins/spanish/novelasligera.js @@ -0,0 +1,239 @@ +"use strict"; +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var cheerio_1 = require("cheerio"); +var fetch_1 = require("@libs/fetch"); +var Ligera = /** @class */ (function () { + function Ligera() { + this.id = "ligera.com"; + this.name = "Novelas Ligera"; + this.icon = "src/es/novelasligera/icon.png"; + this.site = "https://novelasligera.com/"; + this.version = "1.0.0"; + this.baseUrl = this.site; + } + Ligera.prototype.popularNovels = function (pageNo, options) { + return __awaiter(this, void 0, void 0, function () { + var url, result, body, loadedCheerio, novels; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + url = this.baseUrl; + return [4 /*yield*/, fetch(url)]; + case 1: + result = _a.sent(); + return [4 /*yield*/, result.text()]; + case 2: + body = _a.sent(); + loadedCheerio = (0, cheerio_1.load)(body); + novels = []; + loadedCheerio(".elementor-column").each(function () { + var novelName = loadedCheerio(this) + .find(".widget-image-caption.wp-caption-text") + .text(); + if (novelName) { + var novelCover = loadedCheerio(this) + .find("a > img") + .attr("data-lazy-src"); + var novelUrl = loadedCheerio(this).find("a").attr("href"); + if (!novelUrl) + return; + var novel = { + name: novelName, + cover: novelCover, + url: novelUrl, + }; + novels.push(novel); + } + }); + return [2 /*return*/, novels]; + } + }); + }); + }; + Ligera.prototype.parseNovelAndChapters = function (novelUrl) { + return __awaiter(this, void 0, void 0, function () { + var url, result, body, loadedCheerio, novel, novelChapters; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + url = this.baseUrl + "novela/" + novelUrl; + return [4 /*yield*/, fetch(url)]; + case 1: + result = _a.sent(); + return [4 /*yield*/, result.text()]; + case 2: + body = _a.sent(); + loadedCheerio = (0, cheerio_1.load)(body); + novel = { url: url }; + novel.name = loadedCheerio("h1").text(); + novel.cover = loadedCheerio(".elementor-widget-container") + .find("img") + .attr("src"); + loadedCheerio(".elementor-row") + .find("p") + .each(function () { + if (loadedCheerio(this).text().includes("Autor:")) { + novel.author = loadedCheerio(this) + .text() + .replace("Autor:", "") + .trim(); + } + if (loadedCheerio(this).text().includes("Estado:")) { + novel.status = loadedCheerio(this) + .text() + .replace("Estado: ", "") + .trim(); + } + if (loadedCheerio(this).text().includes("Género:")) { + loadedCheerio(this).find("span").remove(); + novel.genres = loadedCheerio(this) + .text() + .replace(/,\s/g, ","); + } + }); + novel.summary = loadedCheerio(".elementor-text-editor.elementor-clearfix").text(); + novelChapters = []; + loadedCheerio(".elementor-accordion-item").remove(); + loadedCheerio(".elementor-tab-content") + .find("li") + .each(function () { + var chapterName = loadedCheerio(this).text(); + var releaseDate = null; + var chapterUrl = loadedCheerio(this).find("a").attr("href"); + if (!chapterUrl) + return; + var chapter = { + name: chapterName, + releaseTime: releaseDate, + url: chapterUrl, + }; + novelChapters.push(chapter); + }); + novel.chapters = novelChapters; + return [2 /*return*/, novel]; + } + }); + }); + }; + Ligera.prototype.parseChapter = function (chapterUrl) { + return __awaiter(this, void 0, void 0, function () { + var url, result, body, loadedCheerio, chapterText; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + url = chapterUrl; + return [4 /*yield*/, fetch(url)]; + case 1: + result = _a.sent(); + return [4 /*yield*/, result.text()]; + case 2: + body = _a.sent(); + loadedCheerio = (0, cheerio_1.load)(body); + loadedCheerio(".osny-nightmode.osny-nightmode--left").remove(); + loadedCheerio(".code-block.code-block-1").remove(); + loadedCheerio(".adsb30").remove(); + loadedCheerio(".saboxplugin-wrap").remove(); + loadedCheerio(".wp-post-navigation").remove(); + chapterText = loadedCheerio(".entry-content").html() || ''; + return [2 /*return*/, chapterText]; + } + }); + }); + }; + Ligera.prototype.searchNovels = function (searchTerm, pageNo) { + return __awaiter(this, void 0, void 0, function () { + var url, result, body, loadedCheerio, novels; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + url = this.baseUrl + "?s=" + searchTerm + "&post_type=wp-manga"; + return [4 /*yield*/, fetch(url)]; + case 1: + result = _a.sent(); + return [4 /*yield*/, result.text()]; + case 2: + body = _a.sent(); + loadedCheerio = (0, cheerio_1.load)(body); + novels = []; + loadedCheerio(".inside-article").each(function () { + var novelCover = loadedCheerio(this).find("img").attr("src"); + var novelUrl = loadedCheerio(this).find("a").attr("href"); + var novelName; + if (novelUrl) { + novelName = novelUrl.replace(/-/g, " ").replace(/^./, function (x) { + return x.toUpperCase(); + }); + } + novelUrl += "/"; + if (!novelName || !novelUrl) + return; + var novel = { + name: novelName, + cover: novelCover, + url: novelUrl, + }; + novels.push(novel); + }); + novels = [__assign({}, novels[1])]; + return [2 /*return*/, novels]; + } + }); + }); + }; + Ligera.prototype.fetchImage = function (url) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, (0, fetch_1.fetchFile)(url)]; + }); + }); + }; + return Ligera; +}()); +exports.default = new Ligera(); diff --git a/.js/plugins/spanish/novelawuxia.js b/.js/plugins/spanish/novelawuxia.js new file mode 100644 index 0000000..539f161 --- /dev/null +++ b/.js/plugins/spanish/novelawuxia.js @@ -0,0 +1,245 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var fetch_1 = require("@libs/fetch"); +var cheerio_1 = require("cheerio"); +var defaultCover_1 = require("@libs/defaultCover"); +var ReinoWuxia = /** @class */ (function () { + function ReinoWuxia() { + this.id = "awuxia.com"; + this.name = "ReinoWuxia"; + this.icon = "src/es/novelawuxia/icon.png"; + this.version = "1.0.0"; + this.site = "http://www.reinowuxia.com/"; + this.baseUrl = this.site; + } + ReinoWuxia.prototype.getNovelName = function (y) { + return y === null || y === void 0 ? void 0 : y.replace(/-/g, " ").replace(/(?:^|\s)\S/g, function (a) { return a.toUpperCase(); }); + }; + ReinoWuxia.prototype.popularNovels = function (pageNo, options) { + return __awaiter(this, void 0, void 0, function () { + var url, result, body, loadedCheerio, novels; + var _this = this; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + url = this.baseUrl + "p/todas-las-novelas.html"; + return [4 /*yield*/, (0, fetch_1.fetchApi)(url, { + method: "GET", + })]; + case 1: + result = _a.sent(); + return [4 /*yield*/, result.text()]; + case 2: + body = _a.sent(); + loadedCheerio = (0, cheerio_1.load)(body); + novels = []; + loadedCheerio(".post-body.entry-content") + .find("a") + .each(function (idx, ele) { + var _a, _b; + var novelName = (_b = (_a = loadedCheerio(ele) + .attr("href")) === null || _a === void 0 ? void 0 : _a.split("/").pop()) === null || _b === void 0 ? void 0 : _b.replace(".html", ""); + novelName = _this.getNovelName(novelName); + var novelCover = loadedCheerio(ele).find("img").attr("src"); + var novelUrl = loadedCheerio(ele).attr("href"); + if (!novelName || !novelUrl) + return; + var novel = { + name: novelName, + cover: novelCover, + url: novelUrl, + }; + novels.push(novel); + }); + return [2 /*return*/, novels]; + } + }); + }); + }; + ReinoWuxia.prototype.parseNovelAndChapters = function (novelUrl) { + return __awaiter(this, void 0, void 0, function () { + var url, result, body, loadedCheerio, novel, novelChapters; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + url = novelUrl; + return [4 /*yield*/, (0, fetch_1.fetchApi)(url)]; + case 1: + result = _a.sent(); + return [4 /*yield*/, result.text()]; + case 2: + body = _a.sent(); + loadedCheerio = (0, cheerio_1.load)(body); + novel = { url: url }; + novel.name = loadedCheerio("h1.post-title").text().trim(); + novel.cover = loadedCheerio("div.separator").find("a").attr("href"); + novel.status = ""; + loadedCheerio("div > b").each(function () { + var detailName = loadedCheerio(this).text(); + var detail = loadedCheerio(this)[0].nextSibling; + if (detailName && detail) { + var text = loadedCheerio(detail).text(); + if (detailName.includes("Autor")) { + novel.author = text.replace("Autor:", ""); + } + if (detailName.includes("Estatus")) { + novel.status = text.replace("Estatus: ", ""); + } + if (detailName.includes("Géneros:")) { + novel.genres = text + .replace("Géneros: ", "") + .replace(/,\s/g, ","); + } + } + }); + novelChapters = []; + loadedCheerio("div").each(function () { + var detailName = loadedCheerio(this).text(); + if (detailName.includes("Sinopsis")) { + novel.summary = + loadedCheerio(this).next().text() !== "" + ? loadedCheerio(this) + .next() + .text() + .replace("Sinopsis", "") + .trim() + : loadedCheerio(this) + .next() + .next() + .text() + .replace("Sinopsis", "") + .trim(); + } + if (detailName.includes("Lista de Capítulos")) { + loadedCheerio(this) + .find("a") + .each(function (res) { + var chapterName = loadedCheerio(this).text(); + var chapterUrl = loadedCheerio(this).attr("href"); + var releaseDate = null; + if (chapterName && + chapterUrl && + !novelChapters.some(function (chap) { return chap.name === chapterName; })) { + var chapter = { + name: chapterName, + releaseTime: releaseDate, + url: chapterUrl, + }; + novelChapters.push(chapter); + } + }); + } + }); + novel.chapters = novelChapters; + return [2 /*return*/, novel]; + } + }); + }); + }; + ReinoWuxia.prototype.parseChapter = function (chapterUrl) { + return __awaiter(this, void 0, void 0, function () { + var url, result, body, loadedCheerio, chapterText; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + url = chapterUrl; + return [4 /*yield*/, (0, fetch_1.fetchApi)(url)]; + case 1: + result = _a.sent(); + return [4 /*yield*/, result.text()]; + case 2: + body = _a.sent(); + loadedCheerio = (0, cheerio_1.load)(body); + chapterText = loadedCheerio(".post-body.entry-content").html() || ''; + return [2 /*return*/, chapterText]; + } + }); + }); + }; + ReinoWuxia.prototype.searchNovels = function (searchTerm, pageNo) { + return __awaiter(this, void 0, void 0, function () { + var url, result, body, loadedCheerio, novels; + var _this = this; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + url = "".concat(this.baseUrl, "search?q=").concat(searchTerm); + return [4 /*yield*/, (0, fetch_1.fetchApi)(url)]; + case 1: + result = _a.sent(); + return [4 /*yield*/, result.text()]; + case 2: + body = _a.sent(); + loadedCheerio = (0, cheerio_1.load)(body); + novels = []; + loadedCheerio(".date-outer").each(function (idx, ele) { + var _a, _b; + var novelName = (_b = (_a = loadedCheerio(ele) + .find("a") + .attr("href")) === null || _a === void 0 ? void 0 : _a.split("/").pop()) === null || _b === void 0 ? void 0 : _b.replace(/-capitulo(.*?).html/, ""); + var novelUrl = novelName + ".html/"; + novelName = _this.getNovelName(novelName); + var exists = novels.some(function (novel) { return novel.name === novelName; }); + if (!exists) { + var novelCover = defaultCover_1.defaultCover; + if (!novelUrl || !novelName) + return; + var novel = { + name: novelName, + cover: novelCover, + url: novelUrl, + }; + novels.push(novel); + } + }); + return [2 /*return*/, novels]; + } + }); + }); + }; + ReinoWuxia.prototype.fetchImage = function (url) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, (0, fetch_1.fetchFile)(url)]; + }); + }); + }; + return ReinoWuxia; +}()); +exports.default = new ReinoWuxia(); diff --git a/.js/plugins/spanish/oasistranslations.js b/.js/plugins/spanish/oasistranslations.js new file mode 100644 index 0000000..168e202 --- /dev/null +++ b/.js/plugins/spanish/oasistranslations.js @@ -0,0 +1,220 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.icon = exports.version = exports.site = exports.name = exports.id = void 0; +var fetch_1 = require("@libs/fetch"); +var cheerio_1 = require("cheerio"); +exports.id = "oasisTL.wp"; +exports.name = "Oasis Translations"; +exports.site = "https://oasistranslations.wordpress.com/"; +exports.version = "1.0.0"; +exports.icon = "src/es/oasistranslations/icon.png"; +var baseUrl = exports.site; +var Oasis = /** @class */ (function () { + function Oasis() { + this.id = "oasisTL.wp"; + this.name = "Oasis Translations"; + this.site = "https://oasistranslations.wordpress.com/"; + this.version = "1.0.0"; + this.icon = "src/es/oasistranslations/icon.png"; + } + Oasis.prototype.popularNovels = function (pageNo, options) { + return __awaiter(this, void 0, void 0, function () { + var url, result, body, loadedCheerio, novels; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + url = baseUrl; + return [4 /*yield*/, (0, fetch_1.fetchApi)(url)]; + case 1: + result = _a.sent(); + return [4 /*yield*/, result.text()]; + case 2: + body = _a.sent(); + loadedCheerio = (0, cheerio_1.load)(body); + novels = []; + loadedCheerio(".menu-item-1819") + .find(".sub-menu > li") + .each(function () { + var novelName = loadedCheerio(this).text(); + if (!novelName.match(/Activas|Finalizadas|Dropeadas/)) { + var novelCover = loadedCheerio(this).find("img").attr("src"); + var novelUrl = loadedCheerio(this).find("a").attr("href"); + if (!novelUrl) + return; + var novel = { + name: novelName, + cover: novelCover, + url: novelUrl, + }; + novels.push(novel); + } + }); + return [2 /*return*/, novels]; + } + }); + }); + }; + Oasis.prototype.parseNovelAndChapters = function (novelUrl) { + return __awaiter(this, void 0, void 0, function () { + var url, result, body, loadedCheerio, novel, novelChapters; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + url = novelUrl; + return [4 /*yield*/, (0, fetch_1.fetchApi)(url)]; + case 1: + result = _a.sent(); + return [4 /*yield*/, result.text()]; + case 2: + body = _a.sent(); + loadedCheerio = (0, cheerio_1.load)(body); + novel = { url: url }; + novel.name = loadedCheerio("h1.entry-title") + .text() + .replace(/[\t\n]/g, "") + .trim(); + novel.cover = loadedCheerio('img[loading="lazy"]').attr("src"); + loadedCheerio(".entry-content > p").each(function (res) { + var _a, _b; + if (loadedCheerio(this).text().includes("Autor")) { + var details = (_b = (_a = loadedCheerio(this).html()) === null || _a === void 0 ? void 0 : _a.match(/<\/strong>(.|\n)*?
/g)) === null || _b === void 0 ? void 0 : _b.map(function (detail) { return detail.replace(/|<\/strong>|
|:\s/g, ""); }); + novel.genres = ""; + if (details) { + novel.author = details[2]; + novel.genres = details[4].replace(/\s| /g, ""); + } + } + }); + // let novelSummary = $(this).next().html(); + novel.summary = ""; + novelChapters = []; + // if ($(".entry-content").find("li").length) { + loadedCheerio(".entry-content") + .find("a") + .each(function () { + var chapterUrl = loadedCheerio(this).attr("href"); + if (chapterUrl && chapterUrl.includes(baseUrl)) { + var chapterName = loadedCheerio(this).text(); + var releaseDate = null; + var chapter = { + name: chapterName, + releaseTime: releaseDate, + url: chapterUrl, + }; + novelChapters.push(chapter); + } + }); + novel.chapters = novelChapters; + return [2 /*return*/, novel]; + } + }); + }); + }; + Oasis.prototype.parseChapter = function (chapterUrl) { + return __awaiter(this, void 0, void 0, function () { + var url, result, body, loadedCheerio, chapterText; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + url = chapterUrl; + return [4 /*yield*/, (0, fetch_1.fetchApi)(url)]; + case 1: + result = _a.sent(); + return [4 /*yield*/, result.text()]; + case 2: + body = _a.sent(); + loadedCheerio = (0, cheerio_1.load)(body); + loadedCheerio("div#jp-post-flair").remove(); + chapterText = loadedCheerio(".entry-content").html() || ''; + return [2 /*return*/, chapterText]; + } + }); + }); + }; + Oasis.prototype.searchNovels = function (searchTerm, pageNo) { + return __awaiter(this, void 0, void 0, function () { + var url, result, body, loadedCheerio, novels; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + searchTerm = searchTerm.toLowerCase(); + url = baseUrl; + return [4 /*yield*/, (0, fetch_1.fetchApi)(url)]; + case 1: + result = _a.sent(); + return [4 /*yield*/, result.text()]; + case 2: + body = _a.sent(); + loadedCheerio = (0, cheerio_1.load)(body); + novels = []; + loadedCheerio(".menu-item-1819") + .find(".sub-menu > li") + .each(function () { + var novelName = loadedCheerio(this).text(); + if (!novelName.match(/Activas|Finalizadas|Dropeadas/)) { + var novelCover = loadedCheerio(this).find("img").attr("src"); + var novelUrl = loadedCheerio(this).find("a").attr("href"); + if (!novelUrl) + return; + var novel = { + name: novelName, + cover: novelCover, + url: novelUrl, + }; + novels.push(novel); + } + }); + novels = novels.filter(function (novel) { + return novel.name.toLowerCase().includes(searchTerm); + }); + return [2 /*return*/, novels]; + } + }); + }); + }; + Oasis.prototype.fetchImage = function (url) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, (0, fetch_1.fetchFile)(url)]; + }); + }); + }; + return Oasis; +}()); +exports.default = new Oasis(); diff --git a/.js/plugins/spanish/skynovels.js b/.js/plugins/spanish/skynovels.js new file mode 100644 index 0000000..c2d4e01 --- /dev/null +++ b/.js/plugins/spanish/skynovels.js @@ -0,0 +1,194 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var fetch_1 = require("@libs/fetch"); +var SkyNovels = /** @class */ (function () { + function SkyNovels() { + this.id = "skynovels.net"; + this.name = "SkyNovels"; + this.site = "https://www.skynovels.net/"; + this.version = "1.0.0"; + this.icon = "src/es/skynovels/icon.png"; + this.baseUrl = this.site; + } + SkyNovels.prototype.popularNovels = function (pageNo, options) { + var _a; + return __awaiter(this, void 0, void 0, function () { + var url, result, body, novels; + var _this = this; + return __generator(this, function (_b) { + switch (_b.label) { + case 0: + url = "https://api.skynovels.net/api/novels?&q"; + return [4 /*yield*/, (0, fetch_1.fetchApi)(url)]; + case 1: + result = _b.sent(); + return [4 /*yield*/, result.json()]; + case 2: + body = _b.sent(); + novels = []; + (_a = body.novels) === null || _a === void 0 ? void 0 : _a.forEach(function (res) { + var novelName = res.nvl_title; + var novelCover = "https://api.skynovels.net/api/get-image/" + + res.image + + "/novels/false"; + var novelUrl = _this.baseUrl + "novelas/" + res.id + "/" + res.nvl_name + "/"; + var novel = { name: novelName, url: novelUrl, cover: novelCover }; + novels.push(novel); + }); + return [2 /*return*/, novels]; + } + }); + }); + }; + SkyNovels.prototype.parseNovelAndChapters = function (novelUrl) { + var _a, _b, _c; + return __awaiter(this, void 0, void 0, function () { + var novelId, url, result, body, item, novel, genres, novelChapters; + return __generator(this, function (_d) { + switch (_d.label) { + case 0: + novelId = novelUrl.split("/")[4]; + url = "https://api.skynovels.net/api/novel/" + novelId + "/reading?&q"; + return [4 /*yield*/, (0, fetch_1.fetchApi)(url)]; + case 1: + result = _d.sent(); + return [4 /*yield*/, result.json()]; + case 2: + body = _d.sent(); + item = (_a = body === null || body === void 0 ? void 0 : body.novel) === null || _a === void 0 ? void 0 : _a[0]; + novel = { url: novelUrl }; + novel.name = item === null || item === void 0 ? void 0 : item.nvl_title; + novel.cover = + "https://api.skynovels.net/api/get-image/" + + (item === null || item === void 0 ? void 0 : item.image) + + "/novels/false"; + genres = []; + (_b = item === null || item === void 0 ? void 0 : item.genres) === null || _b === void 0 ? void 0 : _b.forEach(function (genre) { return genres.push(genre.genre_name); }); + novel.genres = genres.join(","); + novel.author = item === null || item === void 0 ? void 0 : item.nvl_writer; + novel.summary = item === null || item === void 0 ? void 0 : item.nvl_content; + novel.status = item === null || item === void 0 ? void 0 : item.nvl_status; + novelChapters = []; + (_c = item === null || item === void 0 ? void 0 : item.volumes) === null || _c === void 0 ? void 0 : _c.forEach(function (volume) { + var _a; + (_a = volume === null || volume === void 0 ? void 0 : volume.chapters) === null || _a === void 0 ? void 0 : _a.forEach(function (chapter) { + var chapterName = chapter.chp_index_title; + var releaseDate = new Date(chapter.createdAt).toDateString(); + var chapterUrl = novelUrl + chapter.id + "/" + chapter.chp_name; + var chap = { + name: chapterName, + releaseTime: releaseDate, + url: chapterUrl, + }; + novelChapters.push(chap); + }); + }); + novel.chapters = novelChapters; + return [2 /*return*/, novel]; + } + }); + }); + }; + SkyNovels.prototype.parseChapter = function (chapterUrl) { + var _a; + return __awaiter(this, void 0, void 0, function () { + var chapterId, url, result, body, item, chapterText; + return __generator(this, function (_b) { + switch (_b.label) { + case 0: + chapterId = chapterUrl.split("/")[6]; + url = "https://api.skynovels.net/api/novel-chapter/".concat(chapterId); + return [4 /*yield*/, (0, fetch_1.fetchApi)(url)]; + case 1: + result = _b.sent(); + return [4 /*yield*/, result.json()]; + case 2: + body = _b.sent(); + item = (_a = body === null || body === void 0 ? void 0 : body.chapter) === null || _a === void 0 ? void 0 : _a[0]; + chapterText = (item === null || item === void 0 ? void 0 : item.chp_content) || '404'; + return [2 /*return*/, chapterText]; + } + }); + }); + }; + SkyNovels.prototype.searchNovels = function (searchTerm, pageNo) { + var _a; + return __awaiter(this, void 0, void 0, function () { + var url, result, body, results, novels; + var _this = this; + return __generator(this, function (_b) { + switch (_b.label) { + case 0: + searchTerm = searchTerm.toLowerCase(); + url = "https://api.skynovels.net/api/novels?&q"; + return [4 /*yield*/, (0, fetch_1.fetchApi)(url)]; + case 1: + result = _b.sent(); + return [4 /*yield*/, result.json()]; + case 2: + body = _b.sent(); + ; + results = (_a = body === null || body === void 0 ? void 0 : body.novels) === null || _a === void 0 ? void 0 : _a.filter(function (novel) { + return novel.nvl_title.toLowerCase().includes(searchTerm); + }); + novels = []; + results === null || results === void 0 ? void 0 : results.forEach(function (res) { + var novelName = res.nvl_title; + var novelCover = "https://api.skynovels.net/api/get-image/" + + res.image + + "/novels/false"; + var novelUrl = _this.baseUrl + "novelas/" + res.id + "/" + res.nvl_name + "/"; + var novel = { name: novelName, url: novelUrl, cover: novelCover }; + novels.push(novel); + }); + return [2 /*return*/, novels]; + } + }); + }); + }; + SkyNovels.prototype.fetchImage = function (url) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, (0, fetch_1.fetchFile)(url)]; + }); + }); + }; + return SkyNovels; +}()); +exports.default = new SkyNovels(); diff --git a/.js/plugins/spanish/yukitls.js b/.js/plugins/spanish/yukitls.js new file mode 100644 index 0000000..46cc9db --- /dev/null +++ b/.js/plugins/spanish/yukitls.js @@ -0,0 +1,239 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.icon = exports.version = exports.site = exports.name = exports.id = void 0; +var fetch_1 = require("@libs/fetch"); +var cheerio_1 = require("cheerio"); +exports.id = "yuukitls.com"; +exports.name = "Yuuki Tls"; +exports.site = "https://yuukitls.com/"; +exports.version = "1.0.0"; +exports.icon = "src/es/yuukitls/icon.png"; +var baseUrl = exports.site; +var Yuuki = /** @class */ (function () { + function Yuuki() { + this.id = "yuukitls.com"; + this.name = "Yuuki Tls"; + this.icon = "src/es/yuukitls/icon.png"; + this.site = "https://yuukitls.com/"; + this.version = "1.0.0"; + this.baseUrl = this.site; + } + Yuuki.prototype.popularNovels = function (pageNo, options) { + return __awaiter(this, void 0, void 0, function () { + var url, result, body, loadedCheerio, novels; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + url = baseUrl; + return [4 /*yield*/, (0, fetch_1.fetchApi)(url)]; + case 1: + result = _a.sent(); + return [4 /*yield*/, result.text()]; + case 2: + body = _a.sent(); + loadedCheerio = (0, cheerio_1.load)(body); + novels = []; + loadedCheerio(".quadmenu-navbar-collapse ul li:nth-child(2)") + .find("li") + .each(function () { + var novelName = loadedCheerio(this) + .text() + .replace(/[\s\n]+/g, " "); + var novelCover = loadedCheerio(this).find("img").attr("src"); + var novelUrl = loadedCheerio(this).find("a").attr("href"); + if (!novelUrl) + return; + var novel = { + name: novelName, + cover: novelCover, + url: novelUrl, + }; + novels.push(novel); + }); + return [2 /*return*/, novels]; + } + }); + }); + }; + Yuuki.prototype.parseNovelAndChapters = function (novelUrl) { + return __awaiter(this, void 0, void 0, function () { + var url, result, body, loadedCheerio, novel, novelChapters; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + url = novelUrl; + return [4 /*yield*/, (0, fetch_1.fetchApi)(url)]; + case 1: + result = _a.sent(); + return [4 /*yield*/, result.text()]; + case 2: + body = _a.sent(); + loadedCheerio = (0, cheerio_1.load)(body); + novel = { + url: url, + }; + novel.name = loadedCheerio("h1.entry-title") + .text() + .replace(/[\t\n]/g, "") + .trim(); + novel.cover = loadedCheerio('img[loading="lazy"]').attr("src"); + loadedCheerio(".entry-content") + .find("div") + .each(function () { + if (loadedCheerio(this).text().includes("Escritor:")) { + novel.author = loadedCheerio(this) + .text() + .replace("Escritor: ", "") + .trim(); + } + if (loadedCheerio(this).text().includes("Género:")) { + novel.genres = loadedCheerio(this) + .text() + .replace(/Género: |\s/g, ""); + } + if (loadedCheerio(this).text().includes("Sinopsis:")) { + novel.summary = loadedCheerio(this).next().text(); + } + }); + novelChapters = []; + if (loadedCheerio(".entry-content").find("li").length) { + loadedCheerio(".entry-content") + .find("li") + .each(function () { + var chapterUrl = loadedCheerio(this).find("a").attr("href"); + if (chapterUrl && chapterUrl.includes(baseUrl)) { + var chapterName = loadedCheerio(this).text(); + var releaseDate = null; + var chapter = { + name: chapterName, + releaseTime: releaseDate, + url: chapterUrl, + }; + novelChapters.push(chapter); + } + }); + } + else { + loadedCheerio(".entry-content") + .find("p") + .each(function () { + var chapterUrl = loadedCheerio(this).find("a").attr("href"); + if (chapterUrl && chapterUrl.includes(baseUrl)) { + var chapterName = loadedCheerio(this).text(); + var releaseDate = null; + var chapter = { + name: chapterName, + releaseTime: releaseDate, + url: chapterUrl, + }; + novelChapters.push(chapter); + } + }); + } + novel.chapters = novelChapters; + return [2 /*return*/, novel]; + } + }); + }); + }; + Yuuki.prototype.parseChapter = function (chapterUrl) { + return __awaiter(this, void 0, void 0, function () { + var url, result, body, loadedCheerio, chapterText; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + url = chapterUrl; + return [4 /*yield*/, (0, fetch_1.fetchApi)(url)]; + case 1: + result = _a.sent(); + return [4 /*yield*/, result.text()]; + case 2: + body = _a.sent(); + loadedCheerio = (0, cheerio_1.load)(body); + chapterText = loadedCheerio(".entry-content").html() || ''; + return [2 /*return*/, chapterText]; + } + }); + }); + }; + Yuuki.prototype.searchNovels = function (searchTerm, pageNo) { + return __awaiter(this, void 0, void 0, function () { + var url, result, body, loadedCheerio, novels; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + searchTerm = searchTerm.toLowerCase(); + url = baseUrl; + return [4 /*yield*/, (0, fetch_1.fetchApi)(url)]; + case 1: + result = _a.sent(); + return [4 /*yield*/, result.text()]; + case 2: + body = _a.sent(); + loadedCheerio = (0, cheerio_1.load)(body); + novels = []; + loadedCheerio(".menu-item-2869") + .find(".menu-item.menu-item-type-post_type.menu-item-object-post") + .each(function () { + var novelName = loadedCheerio(this).text(); + var novelCover = loadedCheerio(this).find("img").attr("src"); + var novelUrl = loadedCheerio(this).find("a").attr("href"); + if (!novelUrl) + return; + var novel = { + name: novelName, + cover: novelCover, + url: novelUrl, + }; + novels.push(novel); + }); + novels = novels.filter(function (novel) { + return novel.name.toLowerCase().includes(searchTerm); + }); + return [2 /*return*/, novels]; + } + }); + }); + }; + Yuuki.prototype.fetchImage = function (url) { + return (0, fetch_1.fetchFile)(url); + }; + return Yuuki; +}()); +exports.default = new Yuuki(); diff --git a/.js/plugins/turkish/epiknovel.js b/.js/plugins/turkish/epiknovel.js new file mode 100644 index 0000000..df2eca1 --- /dev/null +++ b/.js/plugins/turkish/epiknovel.js @@ -0,0 +1,208 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var cheerio_1 = require("cheerio"); +var fetch_1 = require("@libs/fetch"); +var EpikNovel = /** @class */ (function () { + function EpikNovel() { + this.id = "epiknovel.com"; + this.name = "EpikNovel"; + this.icon = "src/tr/epiknovel/icon.png"; + this.site = "https://www.epiknovel.com/"; + this.version = "1.0.0"; + this.baseUrl = this.site; + } + EpikNovel.prototype.popularNovels = function (pageNo, options) { + return __awaiter(this, void 0, void 0, function () { + var url, result, body, loadedCheerio, novels; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + url = this.baseUrl + "seri-listesi?Sayfa=" + pageNo; + return [4 /*yield*/, fetch(url)]; + case 1: + result = _a.sent(); + return [4 /*yield*/, result.text()]; + case 2: + body = _a.sent(); + loadedCheerio = (0, cheerio_1.load)(body); + novels = []; + loadedCheerio("div.col-lg-12.col-md-12").each(function () { + var novelName = loadedCheerio(this).find("h3").text(); + var novelCover = loadedCheerio(this).find("img").attr("data-src"); + var novelUrl = loadedCheerio(this).find("h3 > a").attr("href"); + if (!novelUrl) + return; + var novel = { + name: novelName, + cover: novelCover, + url: novelUrl, + }; + novels.push(novel); + }); + // console.log(novels); + return [2 /*return*/, novels]; + } + }); + }); + }; + EpikNovel.prototype.parseNovelAndChapters = function (novelUrl) { + return __awaiter(this, void 0, void 0, function () { + var url, result, body, loadedCheerio, novel, novelChapters; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + url = novelUrl; + return [4 /*yield*/, fetch(url)]; + case 1: + result = _a.sent(); + return [4 /*yield*/, result.text()]; + case 2: + body = _a.sent(); + loadedCheerio = (0, cheerio_1.load)(body); + novel = { url: url }; + novel.name = loadedCheerio("h1#tables").text().trim(); + novel.cover = loadedCheerio("img.manga-cover").attr("src"); + novel.summary = loadedCheerio("#wrapper > div.row > div.col-md-9 > div:nth-child(6) > p:nth-child(3)") + .text() + .trim(); + novel.status = loadedCheerio("#wrapper > div.row > div.col-md-9 > div.row > div.col-md-9 > h4:nth-child(3) > a") + .text() + .trim(); + novel.author = loadedCheerio("#NovelInfo > p:nth-child(4)") + .text() + .replace(/Publisher:|\s/g, "") + .trim(); + novelChapters = []; + loadedCheerio("table").find("tr").first().remove(); + loadedCheerio("table") + .find("tr") + .each(function () { + var releaseDate = loadedCheerio(this) + .find("td:nth-child(3)") + .text(); + var chapterName = loadedCheerio(this) + .find("td:nth-child(1) > a") + .text(); + if (loadedCheerio(this).find("td:nth-child(1) > span").length > + 0) { + chapterName = "🔒 " + chapterName; + } + var chapterUrl = loadedCheerio(this) + .find(" td:nth-child(1) > a") + .attr("href"); + if (!chapterUrl) + return; + novelChapters.push({ + name: chapterName, + url: chapterUrl, + releaseTime: releaseDate, + }); + }); + novel.chapters = novelChapters; + // console.log(novel); + return [2 /*return*/, novel]; + } + }); + }); + }; + EpikNovel.prototype.parseChapter = function (chapterUrl) { + return __awaiter(this, void 0, void 0, function () { + var url, result, body, loadedCheerio, chapterText; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + url = chapterUrl; + return [4 /*yield*/, fetch(url)]; + case 1: + result = _a.sent(); + return [4 /*yield*/, result.text()]; + case 2: + body = _a.sent(); + loadedCheerio = (0, cheerio_1.load)(body); + chapterText = ''; + if (result.url === "https://www.epiknovel.com/login") { + chapterText = "Premium Chapter"; + } + else { + chapterText = loadedCheerio("div#icerik").html() || ''; + } + return [2 /*return*/, chapterText]; + } + }); + }); + }; + EpikNovel.prototype.searchNovels = function (searchTerm, pageNo) { + return __awaiter(this, void 0, void 0, function () { + var url, result, body, loadedCheerio, novels; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + url = this.baseUrl + "seri-listesi?q=" + searchTerm + '&Sayfa=' + pageNo; + return [4 /*yield*/, fetch(url)]; + case 1: + result = _a.sent(); + return [4 /*yield*/, result.text()]; + case 2: + body = _a.sent(); + loadedCheerio = (0, cheerio_1.load)(body); + novels = []; + loadedCheerio("div.col-lg-12.col-md-12").each(function () { + var novelName = loadedCheerio(this).find("h3").text(); + var novelCover = loadedCheerio(this).find("img").attr("data-src"); + var novelUrl = loadedCheerio(this).find("h3 > a").attr("href"); + if (!novelUrl) + return; + var novel = { + name: novelName, + cover: novelCover, + url: novelUrl, + }; + novels.push(novel); + }); + return [2 /*return*/, novels]; + } + }); + }); + }; + EpikNovel.prototype.fetchImage = function (url) { + return (0, fetch_1.fetchFile)(url); + }; + return EpikNovel; +}()); +exports.default = new EpikNovel(); diff --git a/.js/plugins/vietnamese/LNHako.js b/.js/plugins/vietnamese/LNHako.js index 906a0f5..76ef99d 100644 --- a/.js/plugins/vietnamese/LNHako.js +++ b/.js/plugins/vietnamese/LNHako.js @@ -39,6 +39,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); var cheerio_1 = require("cheerio"); var fetch_1 = require("@libs/fetch"); var isAbsoluteUrl_1 = require("@libs/isAbsoluteUrl"); +var novelStatus_1 = require("@libs/novelStatus"); var HakoPlugin = /** @class */ (function () { function HakoPlugin() { this.id = "ln.hako"; @@ -50,7 +51,7 @@ var HakoPlugin = /** @class */ (function () { HakoPlugin.prototype.parseNovels = function (loadedCheerio) { var _this = this; var novels = []; - loadedCheerio(".row > .thumb-item-flow").each(function (index, ele) { + loadedCheerio("#mainpart .row .thumb-item-flow").each(function (index, ele) { var url = loadedCheerio(ele) .find("div.thumb_attr.series-title > a") .attr("href"); @@ -97,7 +98,7 @@ var HakoPlugin = /** @class */ (function () { }; HakoPlugin.prototype.parseNovelAndChapters = function (novelUrl) { return __awaiter(this, void 0, void 0, function () { - var novel, result, body, loadedCheerio, background, novelCover, chapters; + var novel, result, body, loadedCheerio, background, novelCover, num, part, chapters; var _this = this; return __generator(this, function (_a) { switch (_a.label) { @@ -112,7 +113,7 @@ var HakoPlugin = /** @class */ (function () { case 2: body = _a.sent(); loadedCheerio = (0, cheerio_1.load)(body); - novel.name = loadedCheerio(".series-name").text(); + novel.name = loadedCheerio(".series-name").text().trim(); background = loadedCheerio(".series-cover > .a6-ratio > div").attr("style") || ""; novelCover = background.substring(background.indexOf("http"), background.length - 2); @@ -122,41 +123,61 @@ var HakoPlugin = /** @class */ (function () { : this.site + novelCover : ""; novel.summary = loadedCheerio(".summary-content").text().trim(); - novel.author = loadedCheerio("#mainpart > div:nth-child(2) > div > div:nth-child(1) > section > main > div.top-part > div > div.col-12.col-md-9 > div.series-information > div:nth-child(2) > span.info-value > a") - .text() - .trim(); - novel.genres = loadedCheerio(".series-gernes") + novel.genres = loadedCheerio(".series-information > div:nth-child(1)") .text() .trim() - .replace(/ +/g, " ") - .split("\n") - .filter(function (e) { return e.trim(); }) - .join(", "); - novel.status = loadedCheerio("#mainpart > div:nth-child(2) > div > div:nth-child(1) > section > main > div.top-part > div > div.col-12.col-md-9 > div.series-information > div:nth-child(4) > span.info-value > a") + .split(/\n[\s\n]*/).join(','); + novel.author = loadedCheerio('.series-information > div:nth-child(2) > .info-value') .text() .trim(); - chapters = []; - loadedCheerio(".list-chapters li").each(function (index, ele) { - var chapterUrl = loadedCheerio(ele).find("a").attr("href"); - if (chapterUrl && !(0, isAbsoluteUrl_1.isUrlAbsolute)(chapterUrl)) { - chapterUrl = _this.site + chapterUrl; + novel.artist = loadedCheerio('.series-information > div:nth-child(3) > .info-value') + .text() + .trim(); + novel.status = loadedCheerio('.series-information > div:nth-child(4) > .info-value') + .text() + .trim(); + switch (novel.status) { + case 'Đang tiến hành': + novel.status = novelStatus_1.NovelStatus.Ongoing; + break; + case 'Tạm ngưng': + novel.status = novelStatus_1.NovelStatus.OnHiatus; + break; + case 'Completed': + novel.status = novelStatus_1.NovelStatus.Completed; + break; + default: + novel.status = novelStatus_1.NovelStatus.Unknown; + } + num = 0, part = 1; + chapters = loadedCheerio('.list-chapters li').toArray().map(function (ele) { + var _a; + var chapterUrl = _this.site + loadedCheerio(ele).find("a").attr("href"); + var chapterName = loadedCheerio(ele) + .find(".chapter-name") + .text() + .trim(); + var chapterNumber = Number((_a = chapterName.match(/Chương\s*(\d+)/i)) === null || _a === void 0 ? void 0 : _a[1]); + if (chapterNumber) { + num = chapterNumber; + part = 1; } - if (chapterUrl) { - var chapterName = loadedCheerio(ele) - .find(".chapter-name") - .text() - .trim(); - var releaseTime = loadedCheerio(ele) - .find(".chapter-time") - .text(); - var chapter = { - name: chapterName, - releaseTime: releaseTime, - url: chapterUrl, - }; - chapters.push(chapter); + else { + chapterNumber = num + part / 10; + part++; } - }); + var chapterTime = loadedCheerio(ele) + .find(".chapter-time") + .text() + .split('/') + .map(function (x) { return Number(x); }); + return { + url: chapterUrl || '', + name: chapterName, + releaseTime: new Date(chapterTime[2], chapterTime[1], chapterTime[0]).toISOString(), + chapterNumber: chapterNumber, + }; + }).filter(function (c) { return c.url; }); novel.chapters = chapters; return [2 /*return*/, novel]; } @@ -187,7 +208,7 @@ var HakoPlugin = /** @class */ (function () { return __generator(this, function (_a) { switch (_a.label) { case 0: - url = this.site + "/tim-kiem?keywords=" + searchTerm; + url = this.site + "/tim-kiem?keywords=" + searchTerm + '&page=' + pageNo; return [4 /*yield*/, fetch(url)]; case 1: result = _a.sent(); diff --git a/index.ts b/index.ts index 7b99c88..3adeb1a 100644 --- a/index.ts +++ b/index.ts @@ -20,6 +20,13 @@ export const getHeaders = () => { app.use((req, res, next) => { const xHeaders = req.headers["x-custom-headers"]; if (xHeaders && typeof xHeaders === "string") { + for (const [headerName, headerValue] of Object.entries(pluginApi.fetchHeaders)) { + if ( + typeof headerName === "string" && + typeof headerValue === "string" + ) + delete pluginApi.fetchHeaders[headerName]; + } const headers = JSON.parse(xHeaders); for (const [headerName, headerValue] of Object.entries(headers)) { if ( @@ -80,7 +87,7 @@ app.post("/fetchImage/", async (req, res) => { req.body["pluginRequirePath"], req.body["url"] ); - res.json(base64); + res.send(base64); }); app.get("/", (req, res) => { diff --git a/package.json b/package.json index 7b710e9..97ed809 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "scripts": { "start": "tsc-watch --onSuccess \"node ./.js/index.js\"", "test": "exit 0", - "json": "tsc && rm ./.js/index.js && node ./.js/scripts/json_plugins.js && git add plugins && git add .dist && git add .js/plugins", + "json": "tsc && mv ./.js/index.js ./.js/index.js.temp && node ./.js/scripts/json_plugins.js && mv ./.js/index.js.temp ./.js/index.js && git add plugins && git add .dist && git add .js/plugins", "generate": "ts-node ./scripts/multisrc/generate.ts && tsc", "clearMulti": "ts-node ./scripts/clearMultisrc.ts", "less": "npx less ./test_web/static/css/index.less ./test_web/static/css/index.css" diff --git a/plugins/indonesian/indowebnovel.broken.ts b/plugins/indonesian/indowebnovel.broken.ts deleted file mode 100644 index 84abde2..0000000 --- a/plugins/indonesian/indowebnovel.broken.ts +++ /dev/null @@ -1,143 +0,0 @@ -import { load as parseHTML } from "cheerio"; -import { fetchApi, fetchFile } from "@libs/fetch"; -import { Chapter, Novel, Plugin } from "@typings/plugin"; -import { defaultCover } from "@libs/defaultCover"; - -export const id = "IDWN.id"; -export const name = "IndoWebNovel"; -export const site = "https://indowebnovel.id/id/"; -export const icon = "src/id/indowebnovel/icon.png"; -export const version = "1.0.0"; - -const baseUrl = site; - -export const popularNovels: Plugin.popularNovels = async function (page) { - const url = `${baseUrl}daftar-novel/`; - - const result = await fetchApi(url); - const body = await result.text(); - - const loadedCheerio = parseHTML(body); - - let novels: Novel.Item[] = []; - - loadedCheerio(".novellist-blc li").each(function () { - const novelName = loadedCheerio(this).find("a").text(); - const novelCover = defaultCover; - const novelUrl = loadedCheerio(this).find("a").attr("href"); - - if (!novelUrl || !novelName) return; - - const novel = { - name: novelName, - cover: novelCover, - url: novelUrl, - }; - - novels.push(novel); - }); - - return novels; -}; - -export const parseNovelAndChapters: Plugin.parseNovelAndChapters = - async function (novelUrl) { - const url = novelUrl; - - const result = await fetchApi(url); - const body = await result.text(); - - let loadedCheerio = parseHTML(body); - - let novel: Novel.instance = { - url, - name: "", - cover: "", - author: "", - status: "", - genres: "", - summary: "", - chapters: [], - }; - - novel.name = loadedCheerio(".series-title").text().trim(); - - novel.cover = loadedCheerio(".series-thumb > img").attr("src"); - - novel.summary = loadedCheerio(".series-synops").text().trim(); - - novel.status = loadedCheerio(".status").text().trim(); - - const genres: string[] = []; - - loadedCheerio(".series-genres").each(function () { - genres.push(loadedCheerio(this).find("a").text().trim()); - }); - - novel.genres = genres.join(","); - - let chapters: Chapter.Item[] = []; - - loadedCheerio(".series-chapterlist li").each(function () { - const chapterName = loadedCheerio(this).find("a").text().trim(); - const releaseDate = null; - const chapterUrl = loadedCheerio(this).find("a").attr("href"); - - if (!chapterUrl) return; - - chapters.push({ - name: chapterName, - releaseTime: releaseDate, - url: chapterUrl, - }); - }); - - novel.chapters = chapters.reverse(); - - return novel; - }; - -export const parseChapter: Plugin.parseChapter = async function (chapterUrl) { - const url = chapterUrl; - - const result = await fetchApi(url); - const body = await result.text(); - - let loadedCheerio = parseHTML(body); - - const chapterText = loadedCheerio(".reader").html(); - - return chapterText; -}; - -export const searchNovels: Plugin.searchNovels = async function (searchTerm) { - const url = `${baseUrl}daftar-novel/`; - - const result = await fetchApi(url); - const body = await result.text(); - - const loadedCheerio = parseHTML(body); - - let novels: Novel.Item[] = []; - - loadedCheerio(".novellist-blc li").each(function () { - const novelName = loadedCheerio(this).find("a").text(); - const novelCover = defaultCover; - const novelUrl = loadedCheerio(this).find("a").attr("href"); - - if (!novelUrl) return; - - const novel = { - name: novelName, - cover: novelCover, - url: novelUrl, - }; - - if (novelName.toLowerCase().includes(searchTerm.toLowerCase())) { - novels.push(novel); - } - }); - - return novels; -}; -export const fetchImage: Plugin.fetchImage = fetchFile; diff --git a/plugins/indonesian/indowebnovel.ts b/plugins/indonesian/indowebnovel.ts new file mode 100644 index 0000000..0126e06 --- /dev/null +++ b/plugins/indonesian/indowebnovel.ts @@ -0,0 +1,146 @@ +import { load as parseHTML } from "cheerio"; +import { fetchApi, fetchFile } from "@libs/fetch"; +import { Plugin } from "@typings/plugin"; +import { defaultCover } from "@libs/defaultCover"; +import { Filters } from "@libs/filterInputs"; + +class IndoWebNovel implements Plugin.PluginBase { + id = "IDWN.id"; + name = "IndoWebNovel"; + icon = "src/id/indowebnovel/icon.png"; + site = "https://indowebnovel.id/id/"; + filters?: Filters | undefined; + version = "1.0.0"; + baseUrl = this.site + async popularNovels(pageNo: number, options: Plugin.PopularNovelsOptions): Promise { + const url = `${this.baseUrl}daftar-novel/`; + + const result = await fetchApi(url); + const body = await result.text(); + + const loadedCheerio = parseHTML(body); + + let novels: Plugin.NovelItem[] = []; + + loadedCheerio(".novellist-blc li").each(function () { + const novelName = loadedCheerio(this).find("a").text(); + const novelCover = defaultCover; + const novelUrl = loadedCheerio(this).find("a").attr("href"); + + if (!novelUrl || !novelName) return; + + const novel = { + name: novelName, + cover: novelCover, + url: novelUrl, + }; + + novels.push(novel); + }); + + return novels; + } + async parseNovelAndChapters(novelUrl: string): Promise { + const url = novelUrl; + + const result = await fetchApi(url); + const body = await result.text(); + + let loadedCheerio = parseHTML(body); + + let novel: Plugin.SourceNovel = { + url, + name: "", + cover: "", + author: "", + status: "", + genres: "", + summary: "", + chapters: [], + }; + + novel.name = loadedCheerio(".series-title").text().trim(); + + novel.cover = loadedCheerio(".series-thumb > img").attr("src"); + + novel.summary = loadedCheerio(".series-synops").text().trim(); + + novel.status = loadedCheerio(".status").text().trim(); + + const genres: string[] = []; + + loadedCheerio(".series-genres").each(function () { + genres.push(loadedCheerio(this).find("a").text().trim()); + }); + + novel.genres = genres.join(","); + + let chapters: Plugin.ChapterItem[] = []; + + loadedCheerio(".series-chapterlist li").each(function () { + const chapterName = loadedCheerio(this).find("a").text().trim(); + const releaseDate = null; + const chapterUrl = loadedCheerio(this).find("a").attr("href"); + + if (!chapterUrl) return; + + chapters.push({ + name: chapterName, + releaseTime: releaseDate, + url: chapterUrl, + }); + }); + + novel.chapters = chapters.reverse(); + + return novel; + } + async parseChapter(chapterUrl: string): Promise { + const url = chapterUrl; + + const result = await fetchApi(url); + const body = await result.text(); + + let loadedCheerio = parseHTML(body); + + const chapterText = loadedCheerio(".readerss").html() || ''; + + return chapterText; + } + async searchNovels(searchTerm: string, pageNo: number): Promise { + const url = `${this.baseUrl}daftar-novel/`; + + const result = await fetchApi(url); + const body = await result.text(); + + const loadedCheerio = parseHTML(body); + + let novels: Plugin.NovelItem[] = []; + + loadedCheerio(".novellist-blc li").each(function () { + const novelName = loadedCheerio(this).find("a").text(); + const novelCover = defaultCover; + const novelUrl = loadedCheerio(this).find("a").attr("href"); + + if (!novelUrl) return; + + const novel = { + name: novelName, + cover: novelCover, + url: novelUrl, + }; + + if (novelName.toLowerCase().includes(searchTerm.toLowerCase())) { + novels.push(novel); + } + }); + + return novels; + } + async fetchImage(url: string): Promise { + return fetchFile(url); + } + +} + +export default new IndoWebNovel(); diff --git a/plugins/indonesian/novelringan.broken.ts b/plugins/indonesian/novelringan.broken.ts deleted file mode 100644 index 0e15f9d..0000000 --- a/plugins/indonesian/novelringan.broken.ts +++ /dev/null @@ -1,159 +0,0 @@ -import { load as parseHTML } from "cheerio"; -import { fetchApi, fetchFile } from "@libs/fetch"; -import { NovelStatus } from "@libs/novelStatus"; -import { Chapter, Novel, Plugin } from "@typings/plugin"; - -export const id = "novelringan.com"; -export const name = "NovelRingan"; -export const site = "https://novelringan.com/"; -export const icon = "src/id/novelringan/icon.png"; -export const version = "1.0.0"; - -const baseUrl = site; -const coverUriPrefix = "https://i0.wp.com/novelringan.com/wp-content/uploads/"; - -export const popularNovels: Plugin.popularNovels = async function (page) { - const url = `${baseUrl}/top-novel/page/${page}`; - - const result = await fetchApi(url); - const body = await result.text(); - - const loadedCheerio = parseHTML(body); - - const novels: Novel.Item[] = []; - - loadedCheerio("article.post").each(function () { - const novelName = loadedCheerio(this) - .find(".entry-title") - .text() - ?.trim(); - const novelCover = - coverUriPrefix + loadedCheerio(this).find("img").attr("data-sxrx"); - const novelUrl = loadedCheerio(this).find("h2 > a").attr("href"); - - if (!novelUrl) return; - - const novel = { - name: novelName, - cover: novelCover, - url: novelUrl, - }; - - novels.push(novel); - }); - - return novels; -}; - -export const parseNovelAndChapters: Plugin.parseNovelAndChapters = - async function (novelUrl) { - const url = novelUrl; - - const result = await fetchApi(url); - const body = await result.text(); - - const loadedCheerio = parseHTML(body); - - let novel: Novel.instance = { - url, - name: "", - cover: "", - genres: "", - author: "", - status: NovelStatus.Unknown, - summary: "", - chapters: [], - }; - - novel.name = loadedCheerio(".entry-title").text()?.trim(); - novel.cover = - coverUriPrefix + - loadedCheerio("img.ts-post-image").attr("data-sxrx"); - novel.summary = loadedCheerio( - "body > div.site-container > div > main > article > div > div.maininfo > span > p" - ).text(); - - let genreSelector = loadedCheerio( - "body > div.site-container > div > main > article > div > div.maininfo > span > ul > li:nth-child(4)" - ).text(); - - novel.genres = genreSelector.includes("Genre") - ? genreSelector.replace("Genre:", "").trim() - : ""; - - let statusSelector = loadedCheerio( - "body > div.site-container > div > main > article > div > div.maininfo > span > ul > li:nth-child(3)" - ).text(); - - novel.status = statusSelector.includes("Status") - ? statusSelector.replace("Status:", "").trim() - : NovelStatus.Unknown; - - let chapters: Chapter.Item[] = []; - - loadedCheerio(".bxcl > ul > li").each(function () { - const chapterName = loadedCheerio(this).find("a").text(); - const releaseDate = null; - const chapterUrl = loadedCheerio(this).find("a").attr("href"); - - if (!chapterUrl) return; - - const chapter = { - name: chapterName, - releaseTime: releaseDate, - url: chapterUrl, - }; - - chapters.push(chapter); - }); - - novel.chapters = chapters.reverse(); - - return novel; - }; - -export const parseChapter: Plugin.parseChapter = async function (chapterUrl) { - const url = chapterUrl; - - const result = await fetchApi(url); - const body = await result.text(); - - const loadedCheerio = parseHTML(body); - - loadedCheerio('.entry-content div[style="display:none"]').remove(); - - const chapterText = loadedCheerio(".entry-content").html(); - - return chapterText; -}; - -export const searchNovels: Plugin.searchNovels = async function (searchTerm) { - const url = baseUrl + "?s=" + searchTerm; - - const result = await fetchApi(url); - const body = await result.text(); - - const loadedCheerio = parseHTML(body); - - let novels: Novel.Item[] = []; - - loadedCheerio("article.post").each(function () { - const novelName = loadedCheerio(this).find(".entry-title").text(); - const novelCover = - coverUriPrefix + loadedCheerio(this).find("img").attr("data-sxrx"); - - const novelUrl = loadedCheerio(this).find("h2 > a").attr("href"); - - if (!novelUrl) return; - - const novel = { - name: novelName, - cover: novelCover, - url: novelUrl, - }; - - novels.push(novel); - }); - return novels; -}; -export const fetchImage: Plugin.fetchImage = fetchFile; diff --git a/plugins/indonesian/novelringan.ts b/plugins/indonesian/novelringan.ts new file mode 100644 index 0000000..b86115e --- /dev/null +++ b/plugins/indonesian/novelringan.ts @@ -0,0 +1,163 @@ +import { load as parseHTML } from "cheerio"; +import { fetchApi, fetchFile } from "@libs/fetch"; +import { NovelStatus } from "@libs/novelStatus"; +import { Plugin } from "@typings/plugin"; +import { Filters } from "@libs/filterInputs"; + +class NovelRingan implements Plugin.PluginBase { + id = "novelringan.com"; + name = "NovelRingan"; + icon = "src/id/novelringan/icon.png"; + site = "https://novelringan.com/"; + filters?: Filters | undefined; + version = "1.0.0"; + baseUrl = this.site; + coverUriPrefix = "https://i0.wp.com/novelringan.com/wp-content/uploads/"; + + async popularNovels(pageNo: number, options: Plugin.PopularNovelsOptions): Promise { + const url = `${this.baseUrl}/top-novel/page/${pageNo}`; + + const result = await fetchApi(url); + const body = await result.text(); + + const loadedCheerio = parseHTML(body); + + const novels: Plugin.NovelItem[] = []; + + loadedCheerio("article.post").each((idx, ele) => { + const novelName = loadedCheerio(ele) + .find(".entry-title") + .text() + ?.trim(); + const novelCover = + this.coverUriPrefix + loadedCheerio(ele).find("img").attr("data-sxrx"); + const novelUrl = loadedCheerio(ele).find("h2 > a").attr("href"); + + if (!novelUrl) return; + + const novel = { + name: novelName, + cover: novelCover, + url: novelUrl, + }; + + novels.push(novel); + }); + + return novels; + } + async parseNovelAndChapters(novelUrl: string): Promise { + const url = novelUrl; + + const result = await fetchApi(url); + const body = await result.text(); + + const loadedCheerio = parseHTML(body); + + let novel: Plugin.SourceNovel = { + url, + name: "", + cover: "", + genres: "", + author: "", + status: NovelStatus.Unknown, + summary: "", + chapters: [], + }; + + novel.name = loadedCheerio(".entry-title").text()?.trim(); + novel.cover = + this.coverUriPrefix + + loadedCheerio("img.ts-post-image").attr("data-sxrx"); + novel.summary = loadedCheerio( + "body > div.site-container > div > main > article > div > div.maininfo > span > p" + ).text(); + + let genreSelector = loadedCheerio( + "body > div.site-container > div > main > article > div > div.maininfo > span > ul > li:nth-child(4)" + ).text(); + + novel.genres = genreSelector.includes("Genre") + ? genreSelector.replace("Genre:", "").trim() + : ""; + + let statusSelector = loadedCheerio( + "body > div.site-container > div > main > article > div > div.maininfo > span > ul > li:nth-child(3)" + ).text(); + + novel.status = statusSelector.includes("Status") + ? statusSelector.replace("Status:", "").trim() + : NovelStatus.Unknown; + + let chapters: Plugin.ChapterItem[] = []; + + loadedCheerio(".bxcl > ul > li").each(function () { + const chapterName = loadedCheerio(this).find("a").text(); + const releaseDate = null; + const chapterUrl = loadedCheerio(this).find("a").attr("href"); + + if (!chapterUrl) return; + + const chapter = { + name: chapterName, + releaseTime: releaseDate, + url: chapterUrl, + }; + + chapters.push(chapter); + }); + + novel.chapters = chapters.reverse(); + + return novel; + } + async parseChapter(chapterUrl: string): Promise { + const url = chapterUrl; + + const result = await fetchApi(url); + const body = await result.text(); + + const loadedCheerio = parseHTML(body); + + loadedCheerio('.entry-content div[style="display:none"]').remove(); + + const chapterText = loadedCheerio(".entry-content").html() || ''; + + return chapterText; + } + async searchNovels(searchTerm: string, pageNo: number): Promise { + const url = this.baseUrl + "?s=" + searchTerm; + + const result = await fetchApi(url); + const body = await result.text(); + + const loadedCheerio = parseHTML(body); + + let novels: Plugin.NovelItem[] = []; + + loadedCheerio("article.post").each((idx, ele) => { + const novelName = loadedCheerio(ele).find(".entry-title").text(); + const novelCover = + this.coverUriPrefix + loadedCheerio(ele).find("img").attr("data-sxrx"); + + const novelUrl = loadedCheerio(ele).find("h2 > a").attr("href"); + + if (!novelUrl) return; + + const novel = { + name: novelName, + cover: novelCover, + url: novelUrl, + }; + + novels.push(novel); + }); + return novels; + } + async fetchImage(url: string): Promise { + return fetchFile(url); + } + +} + +export default new NovelRingan(); diff --git a/plugins/indonesian/sakuranovel.broken.ts b/plugins/indonesian/sakuranovel.broken.ts deleted file mode 100644 index 48dd452..0000000 --- a/plugins/indonesian/sakuranovel.broken.ts +++ /dev/null @@ -1,156 +0,0 @@ -import { load as parseHTML } from "cheerio"; -import { fetchApi, fetchFile } from "@libs/fetch"; -import { Chapter, Novel, Plugin } from "@typings/plugin"; - -export const id = "sakura.id"; -export const name = "SakuraNovel"; -export const site = "https://sakuranovel.id/"; -export const icon = "src/id/sakuranovel/icon.png"; -export const version = "1.0.0"; - -const pluginId = id; -const sourceName = name; - -const baseUrl = site; - -export const popularNovels: Plugin.popularNovels = async function (page) { - const url = `${baseUrl}advanced-search/page/${page}/?title&author&yearx&status&type&order=rating&country%5B0%5D=china&country%5B1%5D=jepang&country%5B2%5D=unknown`; - - const result = await fetchApi(url, {}, pluginId); - const body = await result.text(); - - const loadedCheerio = parseHTML(body); - - let novels: Novel.Item[] = []; - - loadedCheerio(".flexbox2-item").each(function () { - const novelName = loadedCheerio(this) - .find(".flexbox2-title span") - .first() - .text(); - const novelCover = loadedCheerio(this).find("img").attr("src"); - const novelUrl = loadedCheerio(this) - .find(".flexbox2-content > a") - .attr("href"); - - if (!novelUrl) return; - - const novel = { name: novelName, cover: novelCover, url: novelUrl }; - - novels.push(novel); - }); - - return novels; -}; - -export const parseNovelAndChapters: Plugin.parseNovelAndChapters = - async function (novelUrl) { - const result = await fetchApi(novelUrl, {}, pluginId); - const body = await result.text(); - - let loadedCheerio = parseHTML(body); - - let novel: Novel.instance = { - name: sourceName, - url: novelUrl, - }; - - novel.name = loadedCheerio(".series-title h2").text().trim(); - - novel.cover = loadedCheerio(".series-thumb img").attr("src"); - - loadedCheerio(".series-infolist > li").each(function () { - const detailName = loadedCheerio(this).find("b").text().trim(); - const detail = loadedCheerio(this).find("b").next().text().trim(); - - switch (detailName) { - case "Author": - novel.author = detail; - break; - } - }); - - novel.status = loadedCheerio(".status").text().trim(); - - novel.genres = loadedCheerio(".series-genres") - .children("a") - .map((i, el) => loadedCheerio(el).text()) - .toArray() - .join(","); - - loadedCheerio(".series-synops div").remove(); - novel.summary = loadedCheerio(".series-synops").text().trim(); - - let chapters: Chapter.Item[] = []; - - loadedCheerio(".series-chapterlist li").each(function () { - const chapterName = loadedCheerio(this) - .find("a span") - .first() - .text() - .replace(/.*?(Chapter.|[0-9])/g, "$1") - .replace(/Bahasa Indonesia/g, "") - .replace(/\s+/g, " ") - .trim(); - - const releaseDate = loadedCheerio(this) - .find("a span") - .first() - .next() - .text(); - const chapterUrl = loadedCheerio(this).find("a").attr("href"); - - if (!chapterUrl) return; - - chapters.push({ - name: chapterName, - releaseTime: releaseDate, - url: chapterUrl, - }); - }); - - novel.chapters = chapters.reverse(); - - return novel; - }; - -export const parseChapter: Plugin.parseChapter = async function (chapterUrl) { - const result = await fetchApi(chapterUrl, {}, pluginId); - const body = await result.text(); - - let loadedCheerio = parseHTML(body); - - const chapterText = loadedCheerio(".readers").html(); - - return chapterText; -}; - -export const searchNovels: Plugin.searchNovels = async function (searchTerm) { - const url = `${baseUrl}?s=${searchTerm}`; - const result = await fetchApi(url, {}, pluginId); - const body = await result.text(); - - let loadedCheerio = parseHTML(body); - - let novels: Novel.Item[] = []; - - loadedCheerio(".flexbox2-item").each(function () { - const novelName = loadedCheerio(this) - .find(".flexbox2-title span") - .first() - .text(); - const novelCover = loadedCheerio(this).find("img").attr("src"); - const novelUrl = loadedCheerio(this) - .find(".flexbox2-content > a") - .attr("href"); - - if (!novelUrl) return; - - const novel = { name: novelName, cover: novelCover, url: novelUrl }; - - novels.push(novel); - }); - - return novels; -}; -export const fetchImage: Plugin.fetchImage = fetchFile; diff --git a/plugins/indonesian/sakuranovel.ts b/plugins/indonesian/sakuranovel.ts new file mode 100644 index 0000000..9d6afff --- /dev/null +++ b/plugins/indonesian/sakuranovel.ts @@ -0,0 +1,156 @@ +import { load as parseHTML } from "cheerio"; +import { fetchApi, fetchFile } from "@libs/fetch"; +import { Plugin } from "@typings/plugin"; +import { Filters } from "@libs/filterInputs"; + +class SakuraNovel implements Plugin.PluginBase { + id = "sakura.id"; + name = "SakuraNovel"; + icon = "src/id/sakuranovel/icon.png"; + site = "https://sakuranovel.id/"; + filters?: Filters | undefined; + version = "1.0.0"; + baseUrl = this.site; + + async popularNovels(pageNo: number, options: Plugin.PopularNovelsOptions): Promise { + const url = `${this.baseUrl}advanced-search/page/${pageNo}/?title&author&yearx&status&type&order=rating&country%5B0%5D=china&country%5B1%5D=jepang&country%5B2%5D=unknown`; + + const result = await fetchApi(url); + const body = await result.text(); + + const loadedCheerio = parseHTML(body); + + let novels: Plugin.NovelItem[] = []; + + loadedCheerio(".flexbox2-item").each(function () { + const novelName = loadedCheerio(this) + .find(".flexbox2-title span") + .first() + .text(); + const novelCover = loadedCheerio(this).find("img").attr("src"); + const novelUrl = loadedCheerio(this) + .find(".flexbox2-content > a") + .attr("href"); + + if (!novelUrl) return; + + const novel = { name: novelName, cover: novelCover, url: novelUrl }; + + novels.push(novel); + }); + + return novels; + } + async parseNovelAndChapters(novelUrl: string): Promise { + const result = await fetchApi(novelUrl); + const body = await result.text(); + + let loadedCheerio = parseHTML(body); + + let novel: Plugin.SourceNovel = { + url: novelUrl, + }; + + novel.name = loadedCheerio(".series-title h2").text().trim(); + + novel.cover = loadedCheerio(".series-thumb img").attr("src"); + + loadedCheerio(".series-infolist > li").each(function () { + const detailName = loadedCheerio(this).find("b").text().trim(); + const detail = loadedCheerio(this).find("b").next().text().trim(); + + switch (detailName) { + case "Author": + novel.author = detail; + break; + } + }); + + novel.status = loadedCheerio(".status").text().trim(); + + novel.genres = loadedCheerio(".series-genres") + .children("a") + .map((i, el) => loadedCheerio(el).text()) + .toArray() + .join(","); + + loadedCheerio(".series-synops div").remove(); + novel.summary = loadedCheerio(".series-synops").text().trim(); + + let chapters: Plugin.ChapterItem[] = []; + + loadedCheerio(".series-chapterlist li").each(function () { + const chapterName = loadedCheerio(this) + .find("a span") + .first() + .text() + .replace(/.*?(Chapter.|[0-9])/g, "$1") + .replace(/Bahasa Indonesia/g, "") + .replace(/\s+/g, " ") + .trim(); + + const releaseDate = loadedCheerio(this) + .find("a span") + .first() + .next() + .text(); + const chapterUrl = loadedCheerio(this).find("a").attr("href"); + + if (!chapterUrl) return; + + chapters.push({ + name: chapterName, + releaseTime: releaseDate, + url: chapterUrl, + }); + }); + + novel.chapters = chapters.reverse(); + + return novel; + } + async parseChapter(chapterUrl: string): Promise { + const result = await fetchApi(chapterUrl); + const body = await result.text(); + + let loadedCheerio = parseHTML(body); + + const chapterText = loadedCheerio(".readerss").html() || ''; + + return chapterText; + } + async searchNovels(searchTerm: string, pageNo: number): Promise { + const url = `${this.baseUrl}?s=${searchTerm}`; + const result = await fetchApi(url); + const body = await result.text(); + + let loadedCheerio = parseHTML(body); + + let novels: Plugin.NovelItem[] = []; + + loadedCheerio(".flexbox2-item").each(function () { + const novelName = loadedCheerio(this) + .find(".flexbox2-title span") + .first() + .text(); + const novelCover = loadedCheerio(this).find("img").attr("src"); + const novelUrl = loadedCheerio(this) + .find(".flexbox2-content > a") + .attr("href"); + + if (!novelUrl) return; + + const novel = { name: novelName, cover: novelCover, url: novelUrl }; + + novels.push(novel); + }); + + return novels; + } + async fetchImage(url: string): Promise { + return fetchFile(url); + } + +} + +export default new SakuraNovel(); diff --git a/plugins/japanese/Syosetu.broken.ts b/plugins/japanese/Syosetu.broken.ts deleted file mode 100644 index 442f509..0000000 --- a/plugins/japanese/Syosetu.broken.ts +++ /dev/null @@ -1,196 +0,0 @@ -import { load as loadCheerio } from "cheerio"; -import { fetchApi, fetchFile } from "@libs/fetch"; -import { Chapter, Novel, Plugin } from "@typings/plugin"; -import { defaultCover } from "@libs/defaultCover"; -// const novelStatus = require('@libs/novelStatus'); -// const isUrlAbsolute = require('@libs/isAbsoluteUrl'); -// const parseDate = require('@libs/parseDate'); - -const pluginId = "yomou.syosetu"; - -export const id = pluginId; -export const name = "Syosetu"; -export const icon = "src/jp/syosetu/icon.png"; -export const version = "1.0.0"; -export const site = "https//yomou.syosetu.com/"; - -const searchUrl = (pagenum?: number, order?: string) => { - return `https://yomou.syosetu.com/search.php?order=${order || "hyoka"}${ - pagenum !== undefined - ? `&p=${pagenum <= 1 || pagenum > 100 ? "1" : pagenum}` // check if pagenum is between 1 and 100 - : "" // if isn't don't set ?p - }`; -}; - -export const popularNovels: Plugin.popularNovels = async function (pageNo) { - async function getNovelsFromPage(pagenumber: number) { - // load page - const result = await fetchApi(searchUrl(pagenumber)); - const body = await result.text(); - // Cheerio it! - const cheerioQuery = loadCheerio(body, { decodeEntities: false }); - let pageNovels: Novel.Item[] = []; - // find class=searchkekka_box - cheerioQuery(".searchkekka_box").each(function (i, e) { - // get div with link and name - const novelDIV = cheerioQuery(this).find(".novel_h"); - // get link element - const novelA = novelDIV.children()[0]; - // add new novel to array - pageNovels.push({ - name: novelDIV.text(), // get the name - url: novelA.attribs.href, // get last part of the link - cover: defaultCover, - }); - }); - // return all novels from this page - return pageNovels; - } - const novels = await getNovelsFromPage(pageNo); - return novels; -}; - -export const parseNovelAndChapters: Plugin.parseNovelAndChapters = - async function (novelUrl) { - let chapters: Chapter.Item[] = []; - const result = await fetchApi(novelUrl); - const body = await result.text(); - const loadedCheerio = loadCheerio(body, { decodeEntities: false }); - - // create novel object - let novel: Novel.instance = { - url: novelUrl, - name: loadedCheerio(".novel_title").text(), - author: loadedCheerio(".novel_writername") - .text() - .replace("作者:", ""), - cover: defaultCover, - }; - - // Get all the chapters - const cqGetChapters = loadedCheerio(".novel_sublist2"); - if (cqGetChapters.length !== 0) { - // has more than 1 chapter - novel.summary = loadedCheerio("#novel_ex") - .text() - .replace(/<\s*br.*?>/g, "\n"); - cqGetChapters.each(function (i, e) { - const chapterA = loadedCheerio(this).find("a"); - const [chapterName, releaseDate, chapterUrl] = [ - // set the variables - chapterA.text(), - loadedCheerio(this) - .find("dt") // get title - .text() // get text - .replace(/(.)/g, "") // remove "(edited)" mark - .trim(), // trim spaces - "https://ncode.syosetu.com" + chapterA.attr("href"), - ]; - chapters.push({ - name: chapterName, - releaseTime: releaseDate, - url: chapterUrl, - }); - }); - } else { - /** - * Because there are oneshots on the site, they have to be treated with special care - * that's what pisses me off in Shosetsu app. They have this extension, - * but every oneshot is set as "there are no chapters" and all contents are thrown into the description!! - */ - // get summary for oneshot chapter - - const nameResult = await fetchApi( - searchUrl() + `&word=${novel.name}` - ); - const nameBody = await nameResult.text(); - const summaryQuery = loadCheerio(nameBody, { - decodeEntities: false, - }); - const foundText = summaryQuery(".searchkekka_box") - .first() - .find(".ex") - .text() - .replace(/\s{2,}/g, "\n"); - novel.summary = foundText; - - // add single chapter - chapters.push({ - name: "Oneshot", - releaseTime: loadedCheerio("head") - .find("meta[name='WWWC']") - .attr("content"), // get date from metadata - url: novelUrl, // set chapterUrl to oneshot so that chapterScraper knows it's a one-shot, - }); - } - novel.chapters = chapters; - return novel; - }; - -export const parseChapter: Plugin.parseChapter = async function (chapterUrl) { - const result = await fetchApi(chapterUrl); - const body = await result.text(); - - // create cheerioQuery - const cheerioQuery = loadCheerio(body, { - decodeEntities: false, - }); - - let chapterText = cheerioQuery("#novel_honbun") // get chapter text - .html(); - return chapterText; -}; - -export const searchNovels: Plugin.searchNovels = async function (searchTerm) { - let novels = []; - - // returns list of novels from given page - async function getNovelsFromPage(pagenumber: number) { - // load page - const result = await fetchApi( - searchUrl(pagenumber) + `&word=${searchTerm}` - ); - const body = await result.text(); - // Cheerio it! - const cheerioQuery = loadCheerio(body, { decodeEntities: false }); - - let pageNovels: Novel.Item[] = []; - // find class=searchkekka_box - cheerioQuery(".searchkekka_box").each(function (i, e) { - // get div with link and name - const novelDIV = cheerioQuery(this).find(".novel_h"); - // get link element - const novelA = novelDIV.children()[0]; - // add new novel to array - pageNovels.push({ - name: novelDIV.text(), // get the name - url: novelA.attribs.href, // get last part of the link - cover: defaultCover, - }); - }); - // return all novels from this page - return pageNovels; - } - - // counter of loaded pages - // let pagesLoaded = 0; - // do { - // // always load first one - // novels.push(...(await getNovelsFromPage(pagesLoaded + 1))); - // pagesLoaded++; - // } while (pagesLoaded < maxPageLoad && isNext); // check if we should load more - - novels = await getNovelsFromPage(1); - - /** Use - * novels.push(...(await getNovelsFromPage(pageNumber))) - * if you want to load more - */ - - // respond with novels! - return novels; -}; - -export const fetchImage: Plugin.fetchImage = async function (url) { - return await fetchFile(url); -}; diff --git a/plugins/japanese/Syosetu.ts b/plugins/japanese/Syosetu.ts new file mode 100644 index 0000000..e9b2981 --- /dev/null +++ b/plugins/japanese/Syosetu.ts @@ -0,0 +1,207 @@ +import { load as loadCheerio } from "cheerio"; +import { fetchFile } from "@libs/fetch"; +import { Plugin } from "@typings/plugin"; +import { defaultCover } from "@libs/defaultCover"; +import { Filters } from "@libs/filterInputs"; +// const novelStatus = require('@libs/novelStatus'); +// const isUrlAbsolute = require('@libs/isAbsoluteUrl'); +// const parseDate = require('@libs/parseDate'); + +const pluginId = "yomou.syosetu"; + +export const id = pluginId; +export const name = "Syosetu"; +export const icon = "src/jp/syosetu/icon.png"; +export const version = "1.0.0"; +export const site = "https://yomou.syosetu.com/"; + +class Syosetu implements Plugin.PluginBase { + id = "yomou.syosetu"; + name = "Syosetu"; + icon = "src/jp/syosetu/icon.png"; + site = "https://yomou.syosetu.com/"; + filters?: Filters | undefined; + version = "1.0.0"; + headers = { + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" + } + searchUrl = (pagenum?: number, order?: string) => { + return `https://yomou.syosetu.com/search.php?order=${order || "hyoka"}${ + pagenum !== undefined + ? `&p=${pagenum <= 1 || pagenum > 100 ? "1" : pagenum}` // check if pagenum is between 1 and 100 + : "" // if isn't don't set ?p + }`; + }; + async popularNovels(pageNo: number, options: Plugin.PopularNovelsOptions): Promise { + const getNovelsFromPage = async (pagenumber: number) => { + // load page + + const result = await fetch(this.searchUrl(pagenumber), {headers: this.headers}); + const body = await result.text(); + // Cheerio it! + const cheerioQuery = loadCheerio(body, { decodeEntities: false }); + let pageNovels: Plugin.NovelItem[] = []; + // find class=searchkekka_box + cheerioQuery(".searchkekka_box").each(function (i, e) { + // get div with link and name + const novelDIV = cheerioQuery(this).find(".novel_h"); + // get link element + const novelA = novelDIV.children()[0]; + // add new novel to array + pageNovels.push({ + name: novelDIV.text(), // get the name + url: novelA.attribs.href, // get last part of the link + cover: defaultCover, + }); + }); + // return all novels from this page + return pageNovels; + } + const novels = await getNovelsFromPage(pageNo); + return novels; + } + async parseNovelAndChapters(novelUrl: string): Promise { + let chapters: Plugin.ChapterItem[] = []; + const result = await fetch(novelUrl, {headers: this.headers}); + const body = await result.text(); + const loadedCheerio = loadCheerio(body, { decodeEntities: false }); + + // create novel object + let novel: Plugin.SourceNovel = { + url: novelUrl, + name: loadedCheerio(".novel_title").text(), + author: loadedCheerio(".novel_writername") + .text() + .replace("作者:", ""), + cover: defaultCover, + }; + + // Get all the chapters + const cqGetChapters = loadedCheerio(".novel_sublist2"); + if (cqGetChapters.length !== 0) { + // has more than 1 chapter + novel.summary = loadedCheerio("#novel_ex") + .text() + .replace(/<\s*br.*?>/g, "\n"); + cqGetChapters.each(function (i, e) { + const chapterA = loadedCheerio(this).find("a"); + const [chapterName, releaseDate, chapterUrl] = [ + // set the variables + chapterA.text(), + loadedCheerio(this) + .find("dt") // get title + .text() // get text + .replace(/(.)/g, "") // remove "(edited)" mark + .trim(), // trim spaces + "https://ncode.syosetu.com" + chapterA.attr("href"), + ]; + chapters.push({ + name: chapterName, + releaseTime: releaseDate, + url: chapterUrl, + }); + }); + } else { + /** + * Because there are oneshots on the site, they have to be treated with special care + * that's what pisses me off in Shosetsu app. They have this extension, + * but every oneshot is set as "there are no chapters" and all contents are thrown into the description!! + */ + // get summary for oneshot chapter + + const nameResult = await fetch( + this.searchUrl() + `&word=${novel.name}`, + {headers: this.headers} + ); + const nameBody = await nameResult.text(); + const summaryQuery = loadCheerio(nameBody, { + decodeEntities: false, + }); + const foundText = summaryQuery(".searchkekka_box") + .first() + .find(".ex") + .text() + .replace(/\s{2,}/g, "\n"); + novel.summary = foundText; + + // add single chapter + chapters.push({ + name: "Oneshot", + releaseTime: loadedCheerio("head") + .find("meta[name='WWWC']") + .attr("content"), // get date from metadata + url: novelUrl, // set chapterUrl to oneshot so that chapterScraper knows it's a one-shot, + }); + } + novel.chapters = chapters; + return novel; + } + async parseChapter(chapterUrl: string): Promise { + const result = await fetch(chapterUrl, {headers: this.headers}); + const body = await result.text(); + + // create cheerioQuery + const cheerioQuery = loadCheerio(body, { + decodeEntities: false, + }); + + let chapterText = cheerioQuery("#novel_honbun") // get chapter text + .html() || ''; + return chapterText; + } + async searchNovels(searchTerm: string, pageNo: number): Promise { + let novels = []; + + // returns list of novels from given page + const getNovelsFromPage = async (pagenumber: number) => { + // load page + const result = await fetch( + this.searchUrl(pagenumber) + `&word=${searchTerm}`, + {headers: this.headers} + ); + const body = await result.text(); + // Cheerio it! + const cheerioQuery = loadCheerio(body, { decodeEntities: false }); + + let pageNovels: Plugin.NovelItem[] = []; + // find class=searchkekka_box + cheerioQuery(".searchkekka_box").each(function (i, e) { + // get div with link and name + const novelDIV = cheerioQuery(this).find(".novel_h"); + // get link element + const novelA = novelDIV.children()[0]; + // add new novel to array + pageNovels.push({ + name: novelDIV.text(), // get the name + url: novelA.attribs.href, // get last part of the link + cover: defaultCover, + }); + }); + // return all novels from this page + return pageNovels; + } + + // counter of loaded pages + // let pagesLoaded = 0; + // do { + // // always load first one + // novels.push(...(await getNovelsFromPage(pagesLoaded + 1))); + // pagesLoaded++; + // } while (pagesLoaded < maxPageLoad && isNext); // check if we should load more + + novels = await getNovelsFromPage(1); + + /** Use + * novels.push(...(await getNovelsFromPage(pageNumber))) + * if you want to load more + */ + + // respond with novels! + return novels; + } + async fetchImage(url: string): Promise { + return fetchFile(url); + } +} + +export default new Syosetu(); diff --git a/plugins/korean/Agitoon.broken.ts b/plugins/korean/Agitoon.broken.ts deleted file mode 100644 index a86d988..0000000 --- a/plugins/korean/Agitoon.broken.ts +++ /dev/null @@ -1,183 +0,0 @@ -import { load as parseHTML } from "cheerio"; -import { fetchApi, fetchFile } from "@libs/fetch"; -import { Chapter, Novel, Plugin } from "@typings/plugin"; - -export const id = "agit.xyz"; -export const name = "Agitoon"; -export const site = "https://agit501.xyz/"; -export const version = "1.0.0"; -export const icon = "src/kr/agitoon/agit.png"; - -const baseUrl = site; - -export const popularNovels: Plugin.popularNovels = async function (page) { - const list_limit = 20 * (page - 1); - const day = new Date().getDay(); - - const res = await fetchApi(baseUrl + "novel/index.update.php", { - headers: { - "content-type": "application/x-www-form-urlencoded; charset=UTF-8", - }, - body: `mode=get_data_novel_list_p&novel_menu=3&np_day=${day}&np_rank=1&np_distributor=0&np_genre=00&np_order=1&np_genre_ex_1=00&np_genre_ex_2=00&list_limit=${list_limit}&is_query_first=true`, - method: "POST", - }); - const resJson = await res.json() as response; - - const novels: Novel.Item[] = [] - - resJson?.list?.forEach((novel) => { - novels.push({ - url: baseUrl + "novel/list/" + novel.wr_id, - name: novel.wr_subject, - cover: baseUrl + novel.np_dir + "/thumbnail/" + novel.np_thumbnail, - }); - }); - - return novels; -}; - -export const parseNovelAndChapters: Plugin.parseNovelAndChapters = - async function (novelUrl) { - const novelId = novelUrl.split("/").reverse()[0]; - - // cheerio - const result = await fetchApi(novelUrl); - const body = await result.text(); - - const loadedCheerio = parseHTML(body, { decodeEntities: false }); - const name = loadedCheerio("h5.pt-2").text(); - const summary = loadedCheerio(".pt-1.mt-1.pb-1.mb-1").text(); - const author = loadedCheerio(".post-item-list-cate-v") - .first() - .text() - .split(" : ") - .reverse()[0]; - const cover = - baseUrl.slice(0, baseUrl.length - 1) + - loadedCheerio("div.col-5.pr-0.pl-0 img").attr("src"); - const genresTag = loadedCheerio(".col-7 > .post-item-list-cate > span"); - let genres = ""; - - genresTag.each((_, element) => { - genres += loadedCheerio(element).text(); - genres += ", "; - }); - genres = genres.slice(0, genres.length - 2); - - // normal REST HTTP requests - let chapters: Chapter.Item[] = []; - - const res = await fetchApi(baseUrl + "novel/list.update.php", { - headers: { - "content-type": - "application/x-www-form-urlencoded; charset=UTF-8", - }, - body: `mode=get_data_novel_list_c&wr_id_p=${novelId}&page_no=1&cnt_list=10000&order_type=Asc`, - method: "POST", - }); - - const resJson = await res.json() as responseBook - - resJson?.list?.forEach((chapter) => { - chapters.push({ - name: chapter.wr_subject, - url: baseUrl + `novel/view/${chapter.wr_id}/2`, - releaseTime: chapter.wr_datetime, - }); - }); - - const novel: Novel.instance = { - url: novelUrl, - name, - cover, - summary, - author, - status: "", - genres: genres, - chapters, - }; - return novel; - }; - -export const parseChapter: Plugin.parseChapter = async function (chapterUrl) { - const result = await fetchApi(chapterUrl); - const body = await result.text(); - - const loadedCheerio = parseHTML(body); - - const contentTag = loadedCheerio("#id_wr_content > p"); - - let content = ""; - contentTag.each((_, element) => { - content += loadedCheerio(element).text(); - content += "
"; - }); - - // gets rid of the popup thingy - content = content.replace( - "팝업메뉴는 빈공간을 더치하거나 스크룰시 사라집니다", - "" - ); - - return content; -}; - -export const searchNovels: Plugin.searchNovels = async function (searchTerm) { - const rawResults = await fetchApi("https://agit501.xyz/novel/search.php", { - headers: { - "content-type": "application/x-www-form-urlencoded; charset=UTF-8", - }, - body: `mode=get_data_novel_list_p_sch&search_novel=${searchTerm}&list_limit=0`, - method: "POST", - }); - const resJson = await rawResults.json() as response; - - const novels: Novel.Item[] = [] - - resJson?.list?.forEach((novel) => { - novels.push({ - url: baseUrl + "novel/list/" + novel.wr_id, - name: novel.wr_subject, - cover: baseUrl + novel.np_dir + "/thumbnail/" + novel.np_thumbnail, - }); - }); - - return novels; -}; - -export const fetchImage: Plugin.fetchImage = fetchFile; - -interface response { - list_limit: number; - list?: (ListEntity)[] | null; - list_count: number; -} -interface ListEntity { - wr_id: string; - wr_subject: string; - np_dir: string; - np_type_02: string; - np_thumbnail: string; - np_author: string; - wr_subject2: string; - wr_datetime: string; - np_distributor: string; - np_genre: string; - np_country: string; - np_age: string; - is_scrap: number; -} - -interface responseBook { - list?: (ListEntity2)[] | null; - download_time: string; -} -interface ListEntity2 { - wr_id: string; - wr_subject: string; - wr_datetime: string; - url_view1: string; - novel_c_style1: string; - novel_c_str1: string; - data_novel_c_view: string; -} diff --git a/plugins/korean/Agitoon.ts b/plugins/korean/Agitoon.ts new file mode 100644 index 0000000..bb94a1b --- /dev/null +++ b/plugins/korean/Agitoon.ts @@ -0,0 +1,186 @@ +import { load as parseHTML } from "cheerio"; +import { fetchApi, fetchFile } from "@libs/fetch"; +import { Plugin } from "@typings/plugin"; +import { Filters } from "@libs/filterInputs"; + +export const id = "agit.xyz"; +export const name = "Agitoon"; +export const site = "https://agit501.xyz/"; +export const version = "1.0.0"; +export const icon = "src/kr/agitoon/agit.png"; + +const baseUrl = site; + +class Agitoon implements Plugin.PluginBase { + id = "agit.xyz"; + name = "Agitoon"; + icon = "src/kr/agitoon/agit.png"; + site = "https://agit501.xyz/"; + filters?: Filters | undefined; + version = "1.0.0"; + async popularNovels(pageNo: number, options: Plugin.PopularNovelsOptions): Promise { + const list_limit = 20 * (pageNo - 1); + const day = new Date().getDay(); + + const res = await fetchApi(baseUrl + "novel/index.update.php", { + headers: { + "content-type": "application/x-www-form-urlencoded; charset=UTF-8", + }, + body: `mode=get_data_novel_list_p&novel_menu=3&np_day=${day}&np_rank=1&np_distributor=0&np_genre=00&np_order=1&np_genre_ex_1=00&np_genre_ex_2=00&list_limit=${list_limit}&is_query_first=true`, + method: "POST", + }); + const resJson = await res.json() as response; + + const novels: Plugin.NovelItem[] = [] + + resJson?.list?.forEach((novel) => { + novels.push({ + url: baseUrl + "novel/list/" + novel.wr_id, + name: novel.wr_subject, + cover: baseUrl + novel.np_dir + "/thumbnail/" + novel.np_thumbnail, + }); + }); + + return novels; + } + async parseNovelAndChapters(novelUrl: string): Promise { + const novelId = novelUrl.split("/").reverse()[0]; + + // cheerio + const result = await fetchApi(novelUrl); + const body = await result.text(); + + const loadedCheerio = parseHTML(body, { decodeEntities: false }); + const name = loadedCheerio("h5.pt-2").text(); + const summary = loadedCheerio(".pt-1.mt-1.pb-1.mb-1").text(); + const author = loadedCheerio(".post-item-list-cate-v") + .first() + .text() + .split(" : ") + .reverse()[0]; + const cover = + baseUrl.slice(0, baseUrl.length - 1) + + loadedCheerio("div.col-5.pr-0.pl-0 img").attr("src"); + const genresTag = loadedCheerio(".col-7 > .post-item-list-cate > span"); + let genres = ""; + + genresTag.each((_, element) => { + genres += loadedCheerio(element).text(); + genres += ", "; + }); + genres = genres.slice(0, genres.length - 2); + + // normal REST HTTP requests + let chapters: Plugin.ChapterItem[] = []; + + const res = await fetchApi(baseUrl + "novel/list.update.php", { + headers: { + "content-type": + "application/x-www-form-urlencoded; charset=UTF-8", + }, + body: `mode=get_data_novel_list_c&wr_id_p=${novelId}&page_no=1&cnt_list=10000&order_type=Asc`, + method: "POST", + }); + + const resJson = await res.json() as responseBook + + resJson?.list?.forEach((chapter) => { + chapters.push({ + name: chapter.wr_subject, + url: baseUrl + `novel/view/${chapter.wr_id}/2`, + releaseTime: chapter.wr_datetime, + }); + }); + + const novel: Plugin.SourceNovel = { + url: novelUrl, + name, + cover, + summary, + author, + status: "", + genres: genres, + chapters, + }; + return novel; + } + async parseChapter(chapterUrl: string): Promise { + const result = await fetchApi(chapterUrl); + const body = await result.text(); + + const loadedCheerio = parseHTML(body); + + let content = loadedCheerio("#id_wr_content").html() || ''; + + // gets rid of the popup thingy + content = content.replace( + "팝업메뉴는 빈공간을 더치하거나 스크룰시 사라집니다", + "" + ); + + return content; + } + async searchNovels(searchTerm: string, pageNo: number): Promise { + const rawResults = await fetchApi("https://agit501.xyz/novel/search.php", { + headers: { + "content-type": "application/x-www-form-urlencoded; charset=UTF-8", + }, + body: `mode=get_data_novel_list_p_sch&search_novel=${searchTerm}&list_limit=0`, + method: "POST", + }); + const resJson = await rawResults.json() as response; + + const novels: Plugin.NovelItem[] = [] + + resJson?.list?.forEach((novel) => { + novels.push({ + url: baseUrl + "novel/list/" + novel.wr_id, + name: novel.wr_subject, + cover: baseUrl + novel.np_dir + "/thumbnail/" + novel.np_thumbnail, + }); + }); + + return novels; + } + async fetchImage(url: string): Promise { + return fetchFile(url); + } + +} + +export default new Agitoon(); + +interface response { + list_limit: number; + list?: (ListEntity)[] | null; + list_count: number; +} +interface ListEntity { + wr_id: string; + wr_subject: string; + np_dir: string; + np_type_02: string; + np_thumbnail: string; + np_author: string; + wr_subject2: string; + wr_datetime: string; + np_distributor: string; + np_genre: string; + np_country: string; + np_age: string; + is_scrap: number; +} + +interface responseBook { + list?: (ListEntity2)[] | null; + download_time: string; +} +interface ListEntity2 { + wr_id: string; + wr_subject: string; + wr_datetime: string; + url_view1: string; + novel_c_style1: string; + novel_c_str1: string; + data_novel_c_view: string; +} diff --git a/plugins/spanish/hasutl.broken.ts b/plugins/spanish/hasutl.broken.ts deleted file mode 100644 index c976ece..0000000 --- a/plugins/spanish/hasutl.broken.ts +++ /dev/null @@ -1,142 +0,0 @@ -import { load as parseHTML } from "cheerio"; -import { fetchApi, fetchFile } from "@libs/fetch"; -import { Chapter, Novel, Plugin } from "@typings/plugin"; - -export const id = "HasuTL"; -export const name = "Hasu Translations"; -export const site = "https://hasutl.wordpress.com/"; -export const version = "1.0.0"; -export const icon = "src/es/hasutl/icon.png"; - -const baseUrl = site; - -export const popularNovels: Plugin.popularNovels = async function (page) { - let url = baseUrl + "light-novels-activas/"; - - const result = await fetchApi(url); - const body = await result.text(); - - let loadedCheerio = parseHTML(body); - - let novels: Novel.Item[] = []; - - loadedCheerio("div.wp-block-columns").each(function () { - const novelName = loadedCheerio(this).find(".wp-block-button").text(); - const novelCover = loadedCheerio(this).find("img").attr("src"); - - let novelUrl = loadedCheerio(this) - .find(".wp-block-button > a") - .attr("href"); - - if (!novelUrl) return; - - const novel = { - name: novelName, - cover: novelCover, - url: novelUrl, - }; - - novels.push(novel); - }); - - return novels; -}; - -export const parseNovelAndChapters: Plugin.parseNovelAndChapters = - async function (novelUrl) { - const url = novelUrl; - - const result = await fetchApi(url); - const body = await result.text(); - - let loadedCheerio = parseHTML(body); - - let novel: Novel.instance = { - url, - }; - - novel.url = novelUrl; - - novel.name = loadedCheerio(".post-header").text(); - - novel.cover = loadedCheerio(".featured-media > img").attr("src"); - - let novelSummary = loadedCheerio(".post-content").find("p").html()!; - novel.summary = novelSummary; - - let novelChapters: Chapter.Item[] = []; - - loadedCheerio(".wp-block-media-text__content") - .find("a") - .each(function () { - const chapterName = loadedCheerio(this).text().trim(); - - const releaseDate = null; - - let chapterUrl = loadedCheerio(this).attr("href"); - - if (!chapterUrl) return; - - const chapter = { - name: chapterName, - releaseTime: releaseDate, - url: chapterUrl, - }; - - novelChapters.push(chapter); - }); - - novel.chapters = novelChapters; - - return novel; - }; - -export const parseChapter: Plugin.parseChapter = async function (chapterUrl) { - const url = chapterUrl; - - const result = await fetchApi(url); - const body = await result.text(); - - let loadedCheerio = parseHTML(body); - - let chapterText = loadedCheerio(".post-content").html(); - - return chapterText; -}; - -export const searchNovels: Plugin.searchNovels = async function (searchTerm) { - const url = `${baseUrl}?s=${searchTerm}&post_type=wp-manga`; - - const result = await fetchApi(url); - const body = await result.text(); - - let loadedCheerio = parseHTML(body); - - let novels: Novel.Item[] = []; - - loadedCheerio(".post-container ").each(function () { - const novelName = loadedCheerio(this).find(".post-header").text(); - if ( - !novelName.includes("Cap") && - !novelName.includes("Vol") && - !novelName.includes("Light Novels") - ) { - const novelCover = loadedCheerio(this).find("img").attr("src"); - - let novelUrl = loadedCheerio(this).find("a").attr("href"); - - if (!novelUrl) return; - - const novel = { - name: novelName, - cover: novelCover, - url: novelUrl, - }; - - novels.push(novel); - } - }); - - return novels; -}; -export const fetchImage: Plugin.fetchImage = fetchFile; diff --git a/plugins/spanish/hasutl.ts b/plugins/spanish/hasutl.ts new file mode 100644 index 0000000..6d77bc4 --- /dev/null +++ b/plugins/spanish/hasutl.ts @@ -0,0 +1,145 @@ +import { load as parseHTML } from "cheerio"; +import { fetchFile } from "@libs/fetch"; +import { Plugin } from "@typings/plugin"; +import { Filters } from "@libs/filterInputs"; + +class HasulTL implements Plugin.PluginBase { + id = "HasuTL"; + name = "Hasu Translations"; + icon = "src/es/hasutl/icon.png"; + site = "https://hasutl.wordpress.com/"; + filters?: Filters | undefined; + version = "1.0.0"; + baseUrl = this.site + async popularNovels(pageNo: number, options: Plugin.PopularNovelsOptions): Promise { + let url = this.baseUrl + "light-novels-activas/"; + + const result = await fetch(url); + const body = await result.text(); + + let loadedCheerio = parseHTML(body); + + let novels: Plugin.NovelItem[] = []; + + loadedCheerio("div.wp-block-columns").each(function () { + const novelName = loadedCheerio(this).find(".wp-block-button").text(); + const novelCover = loadedCheerio(this).find("img").attr("src"); + + let novelUrl = loadedCheerio(this) + .find(".wp-block-button > a") + .attr("href"); + + if (!novelUrl) return; + + const novel = { + name: novelName, + cover: novelCover, + url: novelUrl, + }; + + novels.push(novel); + }); + + return novels; + } + async parseNovelAndChapters(novelUrl: string): Promise { + const url = novelUrl; + + const result = await fetch(url); + const body = await result.text(); + + let loadedCheerio = parseHTML(body); + + let novel: Plugin.SourceNovel = { + url, + }; + + novel.url = novelUrl; + + novel.name = loadedCheerio(".post-header").text(); + + novel.cover = loadedCheerio(".featured-media > img").attr("src"); + + let novelSummary = loadedCheerio(".post-content").find("p").html()!; + novel.summary = novelSummary; + + let novelChapters: Plugin.ChapterItem[] = []; + + loadedCheerio(".wp-block-media-text__content") + .find("a") + .each(function () { + const chapterName = loadedCheerio(this).text().trim(); + + const releaseDate = null; + + let chapterUrl = loadedCheerio(this).attr("href"); + + if (!chapterUrl) return; + + const chapter = { + name: chapterName, + releaseTime: releaseDate, + url: chapterUrl, + }; + + novelChapters.push(chapter); + }); + + novel.chapters = novelChapters; + + return novel; + } + async parseChapter(chapterUrl: string): Promise { + const url = chapterUrl; + + const result = await fetch(url); + const body = await result.text(); + + let loadedCheerio = parseHTML(body); + + let chapterText = loadedCheerio(".post-content").html() || ''; + + return chapterText; + } + async searchNovels(searchTerm: string, pageNo: number): Promise { + const url = `${this.baseUrl}?s=${searchTerm}&post_type=wp-manga`; + + const result = await fetch(url); + const body = await result.text(); + + let loadedCheerio = parseHTML(body); + + let novels: Plugin.NovelItem[] = []; + + loadedCheerio(".post-container").each(function () { + const novelName = loadedCheerio(this).find(".post-header").text(); + if ( + !novelName.includes("Cap") && + !novelName.includes("Vol") && + !novelName.includes("Light Novels") + ) { + const novelCover = loadedCheerio(this).find("img").attr("src"); + + let novelUrl = loadedCheerio(this).find("a").attr("href"); + + if (!novelUrl) return; + + const novel = { + name: novelName, + cover: novelCover, + url: novelUrl, + }; + + novels.push(novel); + } + }); + + return novels; + } + async fetchImage(url: string): Promise { + return fetchFile(url); + } + +} + +export default new HasulTL(); diff --git a/plugins/spanish/novelasligera.broken.ts b/plugins/spanish/novelasligera.broken.ts deleted file mode 100644 index 03b5a0c..0000000 --- a/plugins/spanish/novelasligera.broken.ts +++ /dev/null @@ -1,177 +0,0 @@ -import { load as parseHTML } from "cheerio"; -import { fetchApi, fetchFile } from "@libs/fetch"; -import { Chapter, Novel, Plugin } from "@typings/plugin"; - -export const id = "ligera.com"; -export const name = "Novelas Ligera"; -export const site = "https://novelasligera.com/"; -export const version = "1.0.0"; -export const icon = "src/es/novelasligera/icon.png"; - -const baseUrl = site; - -export const popularNovels: Plugin.popularNovels = async function (page) { - let url = baseUrl; - - const result = await fetchApi(url); - const body = await result.text(); - - let loadedCheerio = parseHTML(body); - - let novels: Novel.Item[] = []; - - loadedCheerio(".elementor-column").each(function () { - const novelName = loadedCheerio(this) - .find(".widget-image-caption.wp-caption-text") - .text(); - if (novelName) { - const novelCover = loadedCheerio(this) - .find("a > img") - .attr("data-lazy-src"); - - let novelUrl = loadedCheerio(this).find("a").attr("href"); - if (!novelUrl) return; - const novel = { - name: novelName, - cover: novelCover, - url: novelUrl, - }; - - novels.push(novel); - } - }); - - return novels; -}; - -export const parseNovelAndChapters: Plugin.parseNovelAndChapters = - async function (novelUrl) { - const url = baseUrl + "novela/" + novelUrl; - - // console.log(url); - - const result = await fetchApi(url); - const body = await result.text(); - - let loadedCheerio = parseHTML(body); - - let novel: Novel.instance = { url }; - - novel.name = loadedCheerio("h1").text(); - - novel.cover = loadedCheerio(".elementor-widget-container") - .find("img") - .attr("src"); - - loadedCheerio(".elementor-row") - .find("p") - .each(function () { - if (loadedCheerio(this).text().includes("Autor:")) { - novel.author = loadedCheerio(this) - .text() - .replace("Autor:", "") - .trim(); - } - if (loadedCheerio(this).text().includes("Estado:")) { - novel.status = loadedCheerio(this) - .text() - .replace("Estado: ", "") - .trim(); - } - - if (loadedCheerio(this).text().includes("Género:")) { - loadedCheerio(this).find("span").remove(); - novel.genres = loadedCheerio(this) - .text() - .replace(/,\s/g, ","); - } - }); - - novel.summary = loadedCheerio( - ".elementor-text-editor.elementor-clearfix" - ).text(); - - let novelChapters: Chapter.Item[] = []; - - loadedCheerio(".elementor-accordion-item").remove(); - - loadedCheerio(".elementor-tab-content") - .find("li") - .each(function () { - const chapterName = loadedCheerio(this).text(); - const releaseDate = null; - const chapterUrl = loadedCheerio(this).find("a").attr("href"); - if (!chapterUrl) return; - const chapter = { - name: chapterName, - releaseTime: releaseDate, - url: chapterUrl, - }; - - novelChapters.push(chapter); - }); - - novel.chapters = novelChapters; - - return novel; - }; - -export const parseChapter: Plugin.parseChapter = async function (chapterUrl) { - const url = chapterUrl; - // console.log(url); - - const result = await fetchApi(url); - const body = await result.text(); - - let loadedCheerio = parseHTML(body); - loadedCheerio(".osny-nightmode.osny-nightmode--left").remove(); - loadedCheerio(".code-block.code-block-1").remove(); - loadedCheerio(".adsb30").remove(); - loadedCheerio(".saboxplugin-wrap").remove(); - loadedCheerio(".wp-post-navigation").remove(); - - let chapterText = loadedCheerio(".entry-content").html(); - return chapterText; -}; - -export const searchNovels: Plugin.searchNovels = async function (searchTerm) { - const url = baseUrl + "?s=" + searchTerm + "&post_type=wp-manga"; - // console.log(url); - - const result = await fetchApi(url); - const body = await result.text(); - - let loadedCheerio = parseHTML(body); - - let novels: Novel.Item[] = []; - - loadedCheerio(".inside-article").each(function () { - const novelCover = loadedCheerio(this).find("img").attr("src"); - let novelUrl = loadedCheerio(this).find("a").attr("href"); - - let novelName; - - if (novelUrl) { - novelName = novelUrl.replace(/-/g, " ").replace(/^./, function (x) { - return x.toUpperCase(); - }); - } - - novelUrl += "/"; - - if (!novelName || !novelUrl) return; - - const novel = { - name: novelName, - cover: novelCover, - url: novelUrl, - }; - - novels.push(novel); - }); - - novels = [{ ...novels[1] }]; - - return novels; -}; -export const fetchImage: Plugin.fetchImage = fetchFile; diff --git a/plugins/spanish/novelasligera.ts b/plugins/spanish/novelasligera.ts new file mode 100644 index 0000000..a0720f8 --- /dev/null +++ b/plugins/spanish/novelasligera.ts @@ -0,0 +1,180 @@ +import { load as parseHTML } from "cheerio"; +import { fetchFile } from "@libs/fetch"; +import { Plugin } from "@typings/plugin"; +import { Filters } from "@libs/filterInputs"; + +class Ligera implements Plugin.PluginBase { + id = "ligera.com"; + name = "Novelas Ligera"; + icon = "src/es/novelasligera/icon.png"; + site = "https://novelasligera.com/"; + filters?: Filters | undefined; + version = "1.0.0"; + baseUrl = this.site; + async popularNovels(pageNo: number, options: Plugin.PopularNovelsOptions): Promise { + let url = this.baseUrl; + + const result = await fetch(url); + const body = await result.text(); + + let loadedCheerio = parseHTML(body); + + let novels: Plugin.NovelItem[] = []; + + loadedCheerio(".elementor-column").each(function () { + const novelName = loadedCheerio(this) + .find(".widget-image-caption.wp-caption-text") + .text(); + if (novelName) { + const novelCover = loadedCheerio(this) + .find("a > img") + .attr("data-lazy-src"); + + let novelUrl = loadedCheerio(this).find("a").attr("href"); + if (!novelUrl) return; + const novel = { + name: novelName, + cover: novelCover, + url: novelUrl, + }; + + novels.push(novel); + } + }); + + return novels; + } + async parseNovelAndChapters(novelUrl: string): Promise { + const url = this.baseUrl + "novela/" + novelUrl; + + // console.log(url); + + const result = await fetch(url); + const body = await result.text(); + + let loadedCheerio = parseHTML(body); + + let novel: Plugin.SourceNovel = { url }; + + novel.name = loadedCheerio("h1").text(); + + novel.cover = loadedCheerio(".elementor-widget-container") + .find("img") + .attr("src"); + + loadedCheerio(".elementor-row") + .find("p") + .each(function () { + if (loadedCheerio(this).text().includes("Autor:")) { + novel.author = loadedCheerio(this) + .text() + .replace("Autor:", "") + .trim(); + } + if (loadedCheerio(this).text().includes("Estado:")) { + novel.status = loadedCheerio(this) + .text() + .replace("Estado: ", "") + .trim(); + } + + if (loadedCheerio(this).text().includes("Género:")) { + loadedCheerio(this).find("span").remove(); + novel.genres = loadedCheerio(this) + .text() + .replace(/,\s/g, ","); + } + }); + + novel.summary = loadedCheerio( + ".elementor-text-editor.elementor-clearfix" + ).text(); + + let novelChapters: Plugin.ChapterItem[] = []; + + loadedCheerio(".elementor-accordion-item").remove(); + + loadedCheerio(".elementor-tab-content") + .find("li") + .each(function () { + const chapterName = loadedCheerio(this).text(); + const releaseDate = null; + const chapterUrl = loadedCheerio(this).find("a").attr("href"); + if (!chapterUrl) return; + const chapter = { + name: chapterName, + releaseTime: releaseDate, + url: chapterUrl, + }; + + novelChapters.push(chapter); + }); + + novel.chapters = novelChapters; + + return novel; + } + async parseChapter(chapterUrl: string): Promise { + const url = chapterUrl; + // console.log(url); + + const result = await fetch(url); + const body = await result.text(); + + let loadedCheerio = parseHTML(body); + loadedCheerio(".osny-nightmode.osny-nightmode--left").remove(); + loadedCheerio(".code-block.code-block-1").remove(); + loadedCheerio(".adsb30").remove(); + loadedCheerio(".saboxplugin-wrap").remove(); + loadedCheerio(".wp-post-navigation").remove(); + + let chapterText = loadedCheerio(".entry-content").html() || ''; + return chapterText; + } + async searchNovels(searchTerm: string, pageNo: number): Promise { + const url = this.baseUrl + "?s=" + searchTerm + "&post_type=wp-manga"; + // console.log(url); + + const result = await fetch(url); + const body = await result.text(); + + let loadedCheerio = parseHTML(body); + + let novels: Plugin.NovelItem[] = []; + + loadedCheerio(".inside-article").each(function () { + const novelCover = loadedCheerio(this).find("img").attr("src"); + let novelUrl = loadedCheerio(this).find("a").attr("href"); + + let novelName; + + if (novelUrl) { + novelName = novelUrl.replace(/-/g, " ").replace(/^./, function (x) { + return x.toUpperCase(); + }); + } + + novelUrl += "/"; + + if (!novelName || !novelUrl) return; + + const novel = { + name: novelName, + cover: novelCover, + url: novelUrl, + }; + + novels.push(novel); + }); + + novels = [{ ...novels[1] }]; + + return novels; + } + async fetchImage(url: string): Promise { + return fetchFile(url); + } + +} + +export default new Ligera(); \ No newline at end of file diff --git a/plugins/spanish/novelawuxia.broken.ts b/plugins/spanish/novelawuxia.broken.ts deleted file mode 100644 index 75b4f46..0000000 --- a/plugins/spanish/novelawuxia.broken.ts +++ /dev/null @@ -1,214 +0,0 @@ -import { fetchApi, fetchFile } from "@libs/fetch"; -import { Chapter, Novel, Plugin } from "@typings/plugin"; -import { load as parseHTML } from "cheerio"; -import { defaultCover } from "@libs/defaultCover"; - -const pluginId = "awuxia.com"; -const baseUrl = "http://www.reinowuxia.com/"; - -function getNovelName(y: string | undefined) { - return y?.replace(/-/g, " ").replace(/(?:^|\s)\S/g, (a) => a.toUpperCase()); -} - -export const popularNovels: Plugin.popularNovels = async function (page) { - let url = baseUrl + "p/todas-las-novelas.html"; - - let headers = { - "User-Agent": - "'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36", - }; - - const result = await fetchApi(url, { - method: "GET", - headers: headers, - }); - const body = await result.text(); - - let loadedCheerio = parseHTML(body); - - let novels: Novel.Item[] = []; - - loadedCheerio(".post-body.entry-content") - .find("a") - .each(function () { - let novelName = loadedCheerio(this) - .attr("href") - ?.split("/") - .pop() - ?.replace(".html", ""); - novelName = getNovelName(novelName); - const novelCover = loadedCheerio(this).find("img").attr("src"); - - let novelUrl = loadedCheerio(this).attr("href"); - - if (!novelName || !novelUrl) return; - - const novel = { - name: novelName, - cover: novelCover, - url: novelUrl, - }; - - novels.push(novel); - }); - - return novels; -}; - -export const parseNovelAndChapters: Plugin.parseNovelAndChapters = - async function (novelUrl) { - const url = novelUrl; - - const result = await fetchApi(url); - const body = await result.text(); - - let loadedCheerio = parseHTML(body); - - let novel: Novel.instance = { url }; - - novel.name = loadedCheerio("h1.post-title").text().trim(); - - novel.cover = loadedCheerio("div.separator").find("a").attr("href"); - - novel.status = ""; - - loadedCheerio("div > b").each(function () { - const detailName = loadedCheerio(this).text(); - let detail = loadedCheerio(this)[0].nextSibling; - - if (detailName && detail) { - detail = detail.nodeValue; - - if (detailName.includes("Autor")) { - novel.author = detail.replace("Autor:", ""); - } - - if (detailName.includes("Estatus")) { - novel.status = detail.replace("Estatus: ", ""); - } - if (detailName.includes("Géneros:")) { - novel.genres = detail - .replace("Géneros: ", "") - .replace(/,\s/g, ","); - } - } - }); - - let novelChapters: Chapter.Item[] = []; - - loadedCheerio("div").each(function () { - const detailName = loadedCheerio(this).text(); - if (detailName.includes("Sinopsis")) { - novel.summary = - loadedCheerio(this).next().text() !== "" - ? loadedCheerio(this) - .next() - .text() - .replace("Sinopsis", "") - .trim() - : loadedCheerio(this) - .next() - .next() - .text() - .replace("Sinopsis", "") - .trim(); - } - - if (detailName.includes("Lista de Capítulos")) { - loadedCheerio(this) - .find("a") - .each(function (res) { - const chapterName = loadedCheerio(this).text(); - let chapterUrl = loadedCheerio(this).attr("href"); - const releaseDate = null; - - if ( - chapterName && - chapterUrl && - !novelChapters.some( - (chap) => chap.name === chapterName - ) - ) { - const chapter = { - name: chapterName, - releaseTime: releaseDate, - url: chapterUrl, - }; - - novelChapters.push(chapter); - } - }); - } - }); - - novel.chapters = novelChapters; - - return novel; - }; - -export const parseChapter: Plugin.parseChapter = async function (chapterUrl) { - const url = chapterUrl; - - const result = await fetchApi(url); - const body = await result.text(); - - let loadedCheerio = parseHTML(body); - - let chapterText = loadedCheerio(".post-body.entry-content").html(); - - return chapterText; -}; - -export const searchNovels: Plugin.searchNovels = async (searchTerm) => { - const url = `${baseUrl}search?q=${searchTerm}`; - - const result = await fetchApi(url); - const body = await result.text(); - - let loadedCheerio = parseHTML(body); - - let novels: Novel.Item[] = []; - - loadedCheerio(".date-outer").each(function () { - let novelName = loadedCheerio(this) - .find("a") - .attr("href") - ?.split("/") - .pop() - ?.replace(/-capitulo(.*?).html/, ""); - - const novelUrl = novelName + ".html/"; - - novelName = getNovelName(novelName); - - const exists = novels.some((novel) => novel.name === novelName); - - if (!exists) { - const novelCover = defaultCover; - - if (!novelUrl || !novelName) return; - const novel = { - name: novelName, - cover: novelCover, - url: novelUrl, - }; - - novels.push(novel); - } - }); - - return novels; -}; - -module.exports = { - id: pluginId, - name: "ReinoWuxia", - site: baseUrl, - version: "1.0.0", - icon: "src/es/novelawuxia/icon.png", - popularNovels, - parseNovelAndChapters, - parseChapter, - searchNovels, - fetchImage: fetchFile, -}; diff --git a/plugins/spanish/novelawuxia.ts b/plugins/spanish/novelawuxia.ts new file mode 100644 index 0000000..128b785 --- /dev/null +++ b/plugins/spanish/novelawuxia.ts @@ -0,0 +1,203 @@ +import { fetchApi, fetchFile } from "@libs/fetch"; +import { Plugin } from "@typings/plugin"; +import { load as parseHTML } from "cheerio"; +import { defaultCover } from "@libs/defaultCover"; +import { Filters } from "@libs/filterInputs"; + +class ReinoWuxia implements Plugin.PluginBase { + id = "awuxia.com"; + name = "ReinoWuxia"; + icon = "src/es/novelawuxia/icon.png"; + filters?: Filters | undefined; + version = "1.0.0"; + site = "http://www.reinowuxia.com/" + baseUrl = this.site; + getNovelName(y: string | undefined) { + return y?.replace(/-/g, " ").replace(/(?:^|\s)\S/g, (a) => a.toUpperCase()); + } + async popularNovels(pageNo: number, options: Plugin.PopularNovelsOptions): Promise { + let url = this.baseUrl + "p/todas-las-novelas.html"; + + const result = await fetchApi(url, { + method: "GET", + }); + const body = await result.text(); + + let loadedCheerio = parseHTML(body); + + let novels: Plugin.NovelItem[] = []; + + loadedCheerio(".post-body.entry-content") + .find("a") + .each( (idx, ele) => { + let novelName = loadedCheerio(ele) + .attr("href") + ?.split("/") + .pop() + ?.replace(".html", ""); + novelName = this.getNovelName(novelName); + const novelCover = loadedCheerio(ele).find("img").attr("src"); + + let novelUrl = loadedCheerio(ele).attr("href"); + + if (!novelName || !novelUrl) return; + + const novel = { + name: novelName, + cover: novelCover, + url: novelUrl, + }; + + novels.push(novel); + }); + + return novels; + } + async parseNovelAndChapters(novelUrl: string): Promise { + const url = novelUrl; + + const result = await fetchApi(url); + const body = await result.text(); + + let loadedCheerio = parseHTML(body); + + let novel: Plugin.SourceNovel = { url }; + + novel.name = loadedCheerio("h1.post-title").text().trim(); + + novel.cover = loadedCheerio("div.separator").find("a").attr("href"); + + novel.status = ""; + + loadedCheerio("div > b").each(function () { + const detailName = loadedCheerio(this).text(); + let detail = loadedCheerio(this)[0].nextSibling; + + if (detailName && detail) { + const text = loadedCheerio(detail).text(); + + if (detailName.includes("Autor")) { + novel.author = text.replace("Autor:", ""); + } + + if (detailName.includes("Estatus")) { + novel.status = text.replace("Estatus: ", ""); + } + if (detailName.includes("Géneros:")) { + novel.genres = text + .replace("Géneros: ", "") + .replace(/,\s/g, ","); + } + } + }); + + let novelChapters: Plugin.ChapterItem[] = []; + + loadedCheerio("div").each(function () { + const detailName = loadedCheerio(this).text(); + if (detailName.includes("Sinopsis")) { + novel.summary = + loadedCheerio(this).next().text() !== "" + ? loadedCheerio(this) + .next() + .text() + .replace("Sinopsis", "") + .trim() + : loadedCheerio(this) + .next() + .next() + .text() + .replace("Sinopsis", "") + .trim(); + } + + if (detailName.includes("Lista de Capítulos")) { + loadedCheerio(this) + .find("a") + .each(function (res) { + const chapterName = loadedCheerio(this).text(); + let chapterUrl = loadedCheerio(this).attr("href"); + const releaseDate = null; + + if ( + chapterName && + chapterUrl && + !novelChapters.some( + (chap) => chap.name === chapterName + ) + ) { + const chapter = { + name: chapterName, + releaseTime: releaseDate, + url: chapterUrl, + }; + + novelChapters.push(chapter); + } + }); + } + }); + + novel.chapters = novelChapters; + + return novel; + } + async parseChapter(chapterUrl: string): Promise { + const url = chapterUrl; + + const result = await fetchApi(url); + const body = await result.text(); + + let loadedCheerio = parseHTML(body); + + let chapterText = loadedCheerio(".post-body.entry-content").html() || ''; + + return chapterText; + } + async searchNovels(searchTerm: string, pageNo: number): Promise { + const url = `${this.baseUrl}search?q=${searchTerm}`; + + const result = await fetchApi(url); + const body = await result.text(); + + let loadedCheerio = parseHTML(body); + + let novels: Plugin.NovelItem[] = []; + + loadedCheerio(".date-outer").each((idx, ele) => { + let novelName = loadedCheerio(ele) + .find("a") + .attr("href") + ?.split("/") + .pop() + ?.replace(/-capitulo(.*?).html/, ""); + + const novelUrl = novelName + ".html/"; + + novelName = this.getNovelName(novelName); + + const exists = novels.some((novel) => novel.name === novelName); + + if (!exists) { + const novelCover = defaultCover; + + if (!novelUrl || !novelName) return; + const novel = { + name: novelName, + cover: novelCover, + url: novelUrl, + }; + + novels.push(novel); + } + }); + + return novels; + } + async fetchImage(url: string): Promise { + return fetchFile(url); + } + +} + +export default new ReinoWuxia(); \ No newline at end of file diff --git a/plugins/spanish/oasistranslations.broken.ts b/plugins/spanish/oasistranslations.broken.ts deleted file mode 100644 index 535d527..0000000 --- a/plugins/spanish/oasistranslations.broken.ts +++ /dev/null @@ -1,164 +0,0 @@ -import { fetchFile, fetchApi } from "@libs/fetch"; -import { Chapter, Novel, Plugin } from "@typings/plugin"; -import { load as parseHTML } from "cheerio"; - -export const id = "oasisTL.wp"; -export const name = "Oasis Translations"; -export const site = "https://oasistranslations.wordpress.com/"; -export const version = "1.0.0"; -export const icon = "src/es/oasistranslations/icon.png"; - -const baseUrl = site; - -export const popularNovels: Plugin.popularNovels = async function (page) { - let url = baseUrl; - - const result = await fetchApi(url); - const body = await result.text(); - - let loadedCheerio = parseHTML(body); - - let novels: Novel.Item[] = []; - - loadedCheerio(".menu-item-1819") - .find(".sub-menu > li") - .each(function () { - const novelName = loadedCheerio(this).text(); - if (!novelName.match(/Activas|Finalizadas|Dropeadas/)) { - const novelCover = loadedCheerio(this).find("img").attr("src"); - - let novelUrl = loadedCheerio(this).find("a").attr("href"); - - if (!novelUrl) return; - - const novel = { - name: novelName, - cover: novelCover, - url: novelUrl, - }; - - novels.push(novel); - } - }); - - return novels; -}; - -export const parseNovelAndChapters: Plugin.parseNovelAndChapters = - async function (novelUrl) { - const url = novelUrl; - - const result = await fetchApi(url); - const body = await result.text(); - - let loadedCheerio = parseHTML(body); - - let novel: Novel.instance = { url }; - - novel.name = loadedCheerio("h1.entry-title") - .text() - .replace(/[\t\n]/g, "") - .trim(); - - novel.cover = loadedCheerio('img[loading="lazy"]').attr("src"); - - loadedCheerio(".entry-content > p").each(function (res) { - if (loadedCheerio(this).text().includes("Autor")) { - let details = loadedCheerio(this).html()!; - details = details.match(/<\/strong>(.|\n)*?
/g); - details = details.map((detail) => - detail.replace(/|<\/strong>|
|:\s/g, "") - ); - - novel.genres = ""; - - novel.author = details[2]; - novel.genres = details[4].replace(/\s| /g, ""); - } - }); - - // let novelSummary = $(this).next().html(); - novel.summary = ""; - - let novelChapters: Chapter.Item[] = []; - - // if ($(".entry-content").find("li").length) { - loadedCheerio(".entry-content") - .find("a") - .each(function () { - let chapterUrl = loadedCheerio(this).attr("href"); - - if (chapterUrl && chapterUrl.includes(baseUrl)) { - const chapterName = loadedCheerio(this).text(); - const releaseDate = null; - - const chapter = { - name: chapterName, - releaseTime: releaseDate, - url: chapterUrl, - }; - - novelChapters.push(chapter); - } - }); - - novel.chapters = novelChapters; - - return novel; - }; - -export const parseChapter: Plugin.parseChapter = async function (chapterUrl) { - const url = chapterUrl; - - const result = await fetchApi(url); - const body = await result.text(); - - let loadedCheerio = parseHTML(body); - - loadedCheerio("div#jp-post-flair").remove(); - - let chapterText = loadedCheerio(".entry-content").html(); - - return chapterText; -}; - -export const searchNovels: Plugin.searchNovels = async function (searchTerm) { - searchTerm = searchTerm.toLowerCase(); - - let url = baseUrl; - - const result = await fetchApi(url); - const body = await result.text(); - - let loadedCheerio = parseHTML(body); - - let novels: Novel.Item[] = []; - loadedCheerio(".menu-item-1819") - .find(".sub-menu > li") - .each(function () { - const novelName = loadedCheerio(this).text(); - if (!novelName.match(/Activas|Finalizadas|Dropeadas/)) { - const novelCover = loadedCheerio(this).find("img").attr("src"); - - let novelUrl = loadedCheerio(this).find("a").attr("href"); - - if (!novelUrl) return; - - const novel = { - name: novelName, - cover: novelCover, - url: novelUrl, - }; - - novels.push(novel); - } - }); - - novels = novels.filter((novel) => - novel.name.toLowerCase().includes(searchTerm) - ); - - return novels; -}; - -export const fetchImage: Plugin.fetchImage = fetchFile; \ No newline at end of file diff --git a/plugins/spanish/oasistranslations.ts b/plugins/spanish/oasistranslations.ts new file mode 100644 index 0000000..34b2ac6 --- /dev/null +++ b/plugins/spanish/oasistranslations.ts @@ -0,0 +1,171 @@ +import { fetchFile, fetchApi } from "@libs/fetch"; +import { Filters } from "@libs/filterInputs"; +import { Plugin } from "@typings/plugin"; +import { load as parseHTML } from "cheerio"; + +export const id = "oasisTL.wp"; +export const name = "Oasis Translations"; +export const site = "https://oasistranslations.wordpress.com/"; +export const version = "1.0.0"; +export const icon = "src/es/oasistranslations/icon.png"; + +const baseUrl = site; + +class Oasis implements Plugin.PluginBase { + id = "oasisTL.wp"; + name = "Oasis Translations"; + site = "https://oasistranslations.wordpress.com/"; + version = "1.0.0"; + filters?: Filters | undefined; + icon = "src/es/oasistranslations/icon.png"; + async popularNovels(pageNo: number, options: Plugin.PopularNovelsOptions): Promise { + let url = baseUrl; + + const result = await fetchApi(url); + const body = await result.text(); + + let loadedCheerio = parseHTML(body); + + let novels: Plugin.NovelItem[] = []; + + loadedCheerio(".menu-item-1819") + .find(".sub-menu > li") + .each(function () { + const novelName = loadedCheerio(this).text(); + if (!novelName.match(/Activas|Finalizadas|Dropeadas/)) { + const novelCover = loadedCheerio(this).find("img").attr("src"); + + let novelUrl = loadedCheerio(this).find("a").attr("href"); + + if (!novelUrl) return; + + const novel = { + name: novelName, + cover: novelCover, + url: novelUrl, + }; + + novels.push(novel); + } + }); + + return novels; + } + async parseNovelAndChapters(novelUrl: string): Promise { + const url = novelUrl; + + const result = await fetchApi(url); + const body = await result.text(); + + let loadedCheerio = parseHTML(body); + + let novel: Plugin.SourceNovel = { url }; + + novel.name = loadedCheerio("h1.entry-title") + .text() + .replace(/[\t\n]/g, "") + .trim(); + + novel.cover = loadedCheerio('img[loading="lazy"]').attr("src"); + + loadedCheerio(".entry-content > p").each(function (res) { + if (loadedCheerio(this).text().includes("Autor")) { + const details = loadedCheerio(this).html()?.match(/<\/strong>(.|\n)*?
/g)?. + map((detail) => detail.replace(/|<\/strong>|
|:\s/g, "")); + + novel.genres = ""; + if (details){ + novel.author = details[2]; + novel.genres = details[4].replace(/\s| /g, ""); + } + } + }); + + // let novelSummary = $(this).next().html(); + novel.summary = ""; + + let novelChapters: Plugin.ChapterItem[] = []; + + // if ($(".entry-content").find("li").length) { + loadedCheerio(".entry-content") + .find("a") + .each(function () { + let chapterUrl = loadedCheerio(this).attr("href"); + + if (chapterUrl && chapterUrl.includes(baseUrl)) { + const chapterName = loadedCheerio(this).text(); + const releaseDate = null; + + const chapter = { + name: chapterName, + releaseTime: releaseDate, + url: chapterUrl, + }; + + novelChapters.push(chapter); + } + }); + + novel.chapters = novelChapters; + + return novel; + } + async parseChapter(chapterUrl: string): Promise { + const url = chapterUrl; + + const result = await fetchApi(url); + const body = await result.text(); + + let loadedCheerio = parseHTML(body); + + loadedCheerio("div#jp-post-flair").remove(); + + let chapterText = loadedCheerio(".entry-content").html() || ''; + + return chapterText; + } + async searchNovels(searchTerm: string, pageNo: number): Promise { + searchTerm = searchTerm.toLowerCase(); + + let url = baseUrl; + + const result = await fetchApi(url); + const body = await result.text(); + + let loadedCheerio = parseHTML(body); + + let novels: Plugin.NovelItem[] = []; + loadedCheerio(".menu-item-1819") + .find(".sub-menu > li") + .each(function () { + const novelName = loadedCheerio(this).text(); + if (!novelName.match(/Activas|Finalizadas|Dropeadas/)) { + const novelCover = loadedCheerio(this).find("img").attr("src"); + + let novelUrl = loadedCheerio(this).find("a").attr("href"); + + if (!novelUrl) return; + + const novel = { + name: novelName, + cover: novelCover, + url: novelUrl, + }; + + novels.push(novel); + } + }); + + novels = novels.filter((novel) => + novel.name.toLowerCase().includes(searchTerm) + ); + + return novels; + } + async fetchImage(url: string): Promise { + return fetchFile(url); + } + +} + +export default new Oasis(); diff --git a/plugins/spanish/skynovels.broken.ts b/plugins/spanish/skynovels.ts similarity index 81% rename from plugins/spanish/skynovels.broken.ts rename to plugins/spanish/skynovels.ts index d2ef97e..5db2339 100644 --- a/plugins/spanish/skynovels.broken.ts +++ b/plugins/spanish/skynovels.ts @@ -1,21 +1,22 @@ import { fetchApi, fetchFile } from "@libs/fetch"; -import { Chapter, Novel, Plugin } from "@typings/plugin"; +import { Filters } from "@libs/filterInputs"; +import { Plugin } from "@typings/plugin"; -export const id = "skynovels.net"; -export const name = "SkyNovels"; -export const site = "https://www.skynovels.net/"; -export const version = "1.0.0"; -export const icon = "src/es/skynovels/icon.png"; +class SkyNovels implements Plugin.PluginBase { + id = "skynovels.net"; + name = "SkyNovels"; + site = "https://www.skynovels.net/"; + version = "1.0.0"; + icon = "src/es/skynovels/icon.png"; + baseUrl = this.site; -const baseUrl = site; - -export const popularNovels: Plugin.popularNovels = async function (page) { + async popularNovels(pageNo: number, options: Plugin.PopularNovelsOptions): Promise { const url = "https://api.skynovels.net/api/novels?&q"; const result = await fetchApi(url); const body = await result.json() as response; - const novels: Novel.Item[] = []; + const novels: Plugin.NovelItem[] = []; body.novels?.forEach((res) => { const novelName = res.nvl_title; @@ -24,7 +25,7 @@ export const popularNovels: Plugin.popularNovels = async function (page) { res.image + "/novels/false"; const novelUrl = - baseUrl + "novelas/" + res.id + "/" + res.nvl_name + "/"; + this.baseUrl + "novelas/" + res.id + "/" + res.nvl_name + "/"; const novel = { name: novelName, url: novelUrl, cover: novelCover }; @@ -32,11 +33,9 @@ export const popularNovels: Plugin.popularNovels = async function (page) { }); return novels; -}; - -export const parseNovelAndChapters: Plugin.parseNovelAndChapters = - async function (novUrl) { - const novelId = novUrl.split("/")[4]; + } + async parseNovelAndChapters(novelUrl: string): Promise { + const novelId = novelUrl.split("/")[4]; const url = "https://api.skynovels.net/api/novel/" + novelId + "/reading?&q"; @@ -45,7 +44,7 @@ export const parseNovelAndChapters: Plugin.parseNovelAndChapters = const item = body?.novel?.[0]; - let novel: Novel.instance = { url: novUrl }; + let novel: Plugin.SourceNovel = { url: novelUrl }; novel.name = item?.nvl_title; @@ -61,13 +60,13 @@ export const parseNovelAndChapters: Plugin.parseNovelAndChapters = novel.summary = item?.nvl_content; novel.status = item?.nvl_status; - let novelChapters: Chapter.Item[] = []; + let novelChapters: Plugin.ChapterItem[] = []; item?.volumes?.forEach((volume) => { volume?.chapters?.forEach((chapter) => { const chapterName = chapter.chp_index_title; const releaseDate = new Date(chapter.createdAt).toDateString(); - const chapterUrl = novUrl + chapter.id + "/" + chapter.chp_name; + const chapterUrl = novelUrl + chapter.id + "/" + chapter.chp_name; const chap = { name: chapterName, @@ -82,10 +81,9 @@ export const parseNovelAndChapters: Plugin.parseNovelAndChapters = novel.chapters = novelChapters; return novel; - }; - -export const parseChapter: Plugin.parseChapter = async function (chapUrl) { - let chapterId: string = chapUrl.split("/")[6]; + } + async parseChapter(chapterUrl: string): Promise { + let chapterId: string = chapterUrl.split("/")[6]; const url = `https://api.skynovels.net/api/novel-chapter/${chapterId}`; const result = await fetchApi(url); @@ -96,9 +94,8 @@ export const parseChapter: Plugin.parseChapter = async function (chapUrl) { let chapterText = item?.chp_content || '404'; return chapterText; -}; - -export const searchNovels: Plugin.searchNovels = async function (searchTerm) { + } + async searchNovels(searchTerm: string, pageNo: number): Promise { searchTerm = searchTerm.toLowerCase(); const url = "https://api.skynovels.net/api/novels?&q"; @@ -109,7 +106,7 @@ export const searchNovels: Plugin.searchNovels = async function (searchTerm) { novel.nvl_title.toLowerCase().includes(searchTerm) ); - const novels: Novel.Item[] = []; + const novels: Plugin.NovelItem[] = []; results?.forEach((res) => { const novelName = res.nvl_title; @@ -118,7 +115,7 @@ export const searchNovels: Plugin.searchNovels = async function (searchTerm) { res.image + "/novels/false"; const novelUrl = - baseUrl + "novelas/" + res.id + "/" + res.nvl_name + "/"; + this.baseUrl + "novelas/" + res.id + "/" + res.nvl_name + "/"; const novel = { name: novelName, url: novelUrl, cover: novelCover }; @@ -126,9 +123,13 @@ export const searchNovels: Plugin.searchNovels = async function (searchTerm) { }); return novels; -}; + } + async fetchImage(url: string): Promise { + return fetchFile(url); + } +} -export const fetchImage: Plugin.fetchImage = fetchFile; +export default new SkyNovels(); interface response { novels?: (NovelsEntity)[] | null; diff --git a/plugins/spanish/yukitls.broken.ts b/plugins/spanish/yukitls.broken.ts deleted file mode 100644 index 5277459..0000000 --- a/plugins/spanish/yukitls.broken.ts +++ /dev/null @@ -1,180 +0,0 @@ -import { fetchApi, fetchFile } from "@libs/fetch"; -import { Chapter, Novel, Plugin } from "@typings/plugin"; -import { load as parseHTML } from "cheerio"; - -export const id = "yuukitls.com"; -export const name = "Yuuki Tls"; -export const site = "https://yuukitls.com/"; -export const version = "1.0.0"; -export const icon = "src/es/yuukitls/icon.png"; - -const baseUrl = site; - -export const popularNovels: Plugin.popularNovels = async function (page) { - let url = baseUrl; - - const result = await fetchApi(url); - const body = await result.text(); - - let loadedCheerio = parseHTML(body); - - let novels: Novel.Item[] = []; - - loadedCheerio(".quadmenu-navbar-collapse ul li:nth-child(2)") - .find("li") - .each(function () { - const novelName = loadedCheerio(this) - .text() - .replace(/[\s\n]+/g, " "); - const novelCover = loadedCheerio(this).find("img").attr("src"); - - let novelUrl = loadedCheerio(this).find("a").attr("href"); - if (!novelUrl) return; - const novel = { - name: novelName, - cover: novelCover, - url: novelUrl, - }; - - novels.push(novel); - }); - - return novels; -}; - -export const parseNovelAndChapters: Plugin.parseNovelAndChapters = - async function (novelUrl) { - const url = novelUrl; - - const result = await fetchApi(url); - const body = await result.text(); - - let loadedCheerio = parseHTML(body); - - let novel: Novel.instance = { - url, - }; - - novel.name = loadedCheerio("h1.entry-title") - .text() - .replace(/[\t\n]/g, "") - .trim(); - - novel.cover = loadedCheerio('img[loading="lazy"]').attr("src"); - - loadedCheerio(".entry-content") - .find("div") - .each(function () { - if (loadedCheerio(this).text().includes("Escritor:")) { - novel.author = loadedCheerio(this) - .text() - .replace("Escritor: ", "") - .trim(); - } - if (loadedCheerio(this).text().includes("Género:")) { - novel.genres = loadedCheerio(this) - .text() - .replace(/Género: |\s/g, ""); - } - - if (loadedCheerio(this).text().includes("Sinopsis:")) { - novel.summary = loadedCheerio(this).next().text(); - } - }); - - let novelChapters: Chapter.Item[] = []; - - if (loadedCheerio(".entry-content").find("li").length) { - loadedCheerio(".entry-content") - .find("li") - .each(function () { - let chapterUrl = loadedCheerio(this).find("a").attr("href"); - - if (chapterUrl && chapterUrl.includes(baseUrl)) { - const chapterName = loadedCheerio(this).text(); - const releaseDate = null; - - const chapter = { - name: chapterName, - releaseTime: releaseDate, - url: chapterUrl, - }; - - novelChapters.push(chapter); - } - }); - } else { - loadedCheerio(".entry-content") - .find("p") - .each(function () { - let chapterUrl = loadedCheerio(this).find("a").attr("href"); - - if (chapterUrl && chapterUrl.includes(baseUrl)) { - const chapterName = loadedCheerio(this).text(); - const releaseDate = null; - - const chapter = { - name: chapterName, - releaseTime: releaseDate, - url: chapterUrl, - }; - - novelChapters.push(chapter); - } - }); - } - - novel.chapters = novelChapters; - - return novel; - }; - -export const parseChapter: Plugin.parseChapter = async function (chapterUrl) { - const url = chapterUrl; - - const result = await fetchApi(url); - const body = await result.text(); - - let loadedCheerio = parseHTML(body); - let chapterText = loadedCheerio(".entry-content").html(); - - return chapterText; -}; - -export const searchNovels: Plugin.searchNovels = async function (searchTerm) { - searchTerm = searchTerm.toLowerCase(); - - let url = baseUrl; - - const result = await fetchApi(url); - const body = await result.text(); - - let loadedCheerio = parseHTML(body); - - let novels: Novel.Item[] = []; - - loadedCheerio(".menu-item-2869") - .find(".menu-item.menu-item-type-post_type.menu-item-object-post") - .each(function () { - const novelName = loadedCheerio(this).text(); - const novelCover = loadedCheerio(this).find("img").attr("src"); - - let novelUrl = loadedCheerio(this).find("a").attr("href"); - if (!novelUrl) return; - - const novel = { - name: novelName, - cover: novelCover, - url: novelUrl, - }; - - novels.push(novel); - }); - - novels = novels.filter((novel) => - novel.name.toLowerCase().includes(searchTerm) - ); - - return novels; -}; -export const fetchImage: Plugin.fetchImage = fetchFile; diff --git a/plugins/spanish/yukitls.ts b/plugins/spanish/yukitls.ts new file mode 100644 index 0000000..980b755 --- /dev/null +++ b/plugins/spanish/yukitls.ts @@ -0,0 +1,192 @@ +import { fetchApi, fetchFile } from "@libs/fetch"; +import { Filters } from "@libs/filterInputs"; +import { Plugin } from "@typings/plugin"; +import { load as parseHTML } from "cheerio"; + +export const id = "yuukitls.com"; +export const name = "Yuuki Tls"; +export const site = "https://yuukitls.com/"; +export const version = "1.0.0"; +export const icon = "src/es/yuukitls/icon.png"; + +const baseUrl = site; + +class Yuuki implements Plugin.PluginBase { + id = "yuukitls.com"; + name = "Yuuki Tls"; + icon = "src/es/yuukitls/icon.png"; + site = "https://yuukitls.com/"; + filters?: Filters | undefined; + version = "1.0.0"; + baseUrl = this.site; + + async popularNovels(pageNo: number, options: Plugin.PopularNovelsOptions): Promise { + let url = baseUrl; + + const result = await fetchApi(url); + const body = await result.text(); + + let loadedCheerio = parseHTML(body); + + let novels: Plugin.NovelItem[] = []; + + loadedCheerio(".quadmenu-navbar-collapse ul li:nth-child(2)") + .find("li") + .each(function () { + const novelName = loadedCheerio(this) + .text() + .replace(/[\s\n]+/g, " "); + const novelCover = loadedCheerio(this).find("img").attr("src"); + + let novelUrl = loadedCheerio(this).find("a").attr("href"); + if (!novelUrl) return; + const novel = { + name: novelName, + cover: novelCover, + url: novelUrl, + }; + + novels.push(novel); + }); + + return novels; + } + async parseNovelAndChapters(novelUrl: string): Promise { + const url = novelUrl; + + const result = await fetchApi(url); + const body = await result.text(); + + let loadedCheerio = parseHTML(body); + + let novel: Plugin.SourceNovel = { + url, + }; + + novel.name = loadedCheerio("h1.entry-title") + .text() + .replace(/[\t\n]/g, "") + .trim(); + + novel.cover = loadedCheerio('img[loading="lazy"]').attr("src"); + + loadedCheerio(".entry-content") + .find("div") + .each(function () { + if (loadedCheerio(this).text().includes("Escritor:")) { + novel.author = loadedCheerio(this) + .text() + .replace("Escritor: ", "") + .trim(); + } + if (loadedCheerio(this).text().includes("Género:")) { + novel.genres = loadedCheerio(this) + .text() + .replace(/Género: |\s/g, ""); + } + + if (loadedCheerio(this).text().includes("Sinopsis:")) { + novel.summary = loadedCheerio(this).next().text(); + } + }); + + let novelChapters: Plugin.ChapterItem[] = []; + + if (loadedCheerio(".entry-content").find("li").length) { + loadedCheerio(".entry-content") + .find("li") + .each(function () { + let chapterUrl = loadedCheerio(this).find("a").attr("href"); + + if (chapterUrl && chapterUrl.includes(baseUrl)) { + const chapterName = loadedCheerio(this).text(); + const releaseDate = null; + + const chapter = { + name: chapterName, + releaseTime: releaseDate, + url: chapterUrl, + }; + + novelChapters.push(chapter); + } + }); + } else { + loadedCheerio(".entry-content") + .find("p") + .each(function () { + let chapterUrl = loadedCheerio(this).find("a").attr("href"); + + if (chapterUrl && chapterUrl.includes(baseUrl)) { + const chapterName = loadedCheerio(this).text(); + const releaseDate = null; + + const chapter = { + name: chapterName, + releaseTime: releaseDate, + url: chapterUrl, + }; + + novelChapters.push(chapter); + } + }); + } + + novel.chapters = novelChapters; + + return novel; + } + async parseChapter(chapterUrl: string): Promise { + const url = chapterUrl; + + const result = await fetchApi(url); + const body = await result.text(); + + let loadedCheerio = parseHTML(body); + let chapterText = loadedCheerio(".entry-content").html() || ''; + + return chapterText; + } + async searchNovels(searchTerm: string, pageNo: number): Promise { + searchTerm = searchTerm.toLowerCase(); + + let url = baseUrl; + + const result = await fetchApi(url); + const body = await result.text(); + + let loadedCheerio = parseHTML(body); + + let novels: Plugin.NovelItem[] = []; + + loadedCheerio(".menu-item-2869") + .find(".menu-item.menu-item-type-post_type.menu-item-object-post") + .each(function () { + const novelName = loadedCheerio(this).text(); + const novelCover = loadedCheerio(this).find("img").attr("src"); + + let novelUrl = loadedCheerio(this).find("a").attr("href"); + if (!novelUrl) return; + + const novel = { + name: novelName, + cover: novelCover, + url: novelUrl, + }; + + novels.push(novel); + }); + + novels = novels.filter((novel) => + novel.name.toLowerCase().includes(searchTerm) + ); + + return novels; + } + fetchImage(url: string): Promise { + return fetchFile(url); + } + +} + +export default new Yuuki(); diff --git a/plugins/turkish/epiknovel.broken.ts b/plugins/turkish/epiknovel.broken.ts deleted file mode 100644 index 93c3589..0000000 --- a/plugins/turkish/epiknovel.broken.ts +++ /dev/null @@ -1,169 +0,0 @@ -import { load as parseHTML } from "cheerio"; -import { fetchApi, fetchFile } from "@libs/fetch"; -import { Chapter, Novel, Plugin } from "@typings/plugin"; - -export const id = "epiknovel.com"; -export const name = "EpikNovel"; -export const site = "https://www.epiknovel.com/"; -export const version = "1.0.0"; -export const icon = "src/tr/epiknovel/icon.png"; - -const baseUrl = site; - -export const popularNovels: Plugin.popularNovels = async function (page) { - let url = baseUrl + "seri-listesi?Sayfa=" + page; - - const result = await fetchApi(url); - const body = await result.text(); - - let loadedCheerio = parseHTML(body); - - let novels: Novel.Item[] = []; - - loadedCheerio("div.col-lg-12.col-md-12").each(function () { - const novelName = loadedCheerio(this).find("h3").text(); - const novelCover = loadedCheerio(this).find("img").attr("data-src"); - const novelUrl = loadedCheerio(this).find("h3 > a").attr("href"); - - if (!novelUrl) return; - - const novel = { - name: novelName, - cover: novelCover, - url: novelUrl, - }; - - novels.push(novel); - }); - - // console.log(novels); - - return novels; -}; - -export const parseNovelAndChapters: Plugin.parseNovelAndChapters = - async function (novelUrl) { - const url = novelUrl; - // console.log(url); - - const result = await fetchApi(url); - const body = await result.text(); - - let loadedCheerio = parseHTML(body); - - let novel: Novel.instance = { url }; - - novel.name = loadedCheerio("h1#tables").text().trim(); - - novel.cover = loadedCheerio("img.manga-cover").attr("src"); - - novel.summary = loadedCheerio( - "#wrapper > div.row > div.col-md-9 > div:nth-child(6) > p:nth-child(3)" - ) - .text() - .trim(); - - novel.status = loadedCheerio( - "#wrapper > div.row > div.col-md-9 > div.row > div.col-md-9 > h4:nth-child(3) > a" - ) - .text() - .trim(); - - novel.author = loadedCheerio("#NovelInfo > p:nth-child(4)") - .text() - .replace(/Publisher:|\s/g, "") - .trim(); - - let novelChapters: Chapter.Item[] = []; - - loadedCheerio("table").find("tr").first().remove(); - - loadedCheerio("table") - .find("tr") - .each(function () { - const releaseDate = loadedCheerio(this) - .find("td:nth-child(3)") - .text(); - - let chapterName = loadedCheerio(this) - .find("td:nth-child(1) > a") - .text(); - - if ( - loadedCheerio(this).find("td:nth-child(1) > span").length > - 0 - ) { - chapterName = "🔒 " + chapterName; - } - - const chapterUrl = loadedCheerio(this) - .find(" td:nth-child(1) > a") - .attr("href"); - - if (!chapterUrl) return; - - novelChapters.push({ - name: chapterName, - url: chapterUrl, - releaseTime: releaseDate, - }); - }); - - novel.chapters = novelChapters; - // console.log(novel); - - return novel; - }; - -export const parseChapter: Plugin.parseChapter = async function (chapterUrl) { - const url = chapterUrl; - - // console.log(url); - - const result = await fetchApi(url); - const body = await result.text(); - - let loadedCheerio = parseHTML(body); - - let chapterName, chapterText; - - if (result.url === "https://www.epiknovel.com/login") { - chapterName = ""; - chapterText = "Premium Chapter"; - } else { - chapterName = loadedCheerio("#icerik > center > h4 > b").text(); - chapterText = loadedCheerio("div#icerik").html(); - } - - return chapterText; -}; - -export const searchNovels: Plugin.searchNovels = async function (searchTerm) { - const url = baseUrl + "seri-listesi?q=" + searchTerm; - - const result = await fetchApi(url); - const body = await result.text(); - - let loadedCheerio = parseHTML(body); - - let novels: Novel.Item[] = []; - - loadedCheerio("div.col-lg-12.col-md-12").each(function () { - const novelName = loadedCheerio(this).find("h3").text(); - const novelCover = loadedCheerio(this).find("img").attr("data-src"); - const novelUrl = loadedCheerio(this).find("h3 > a").attr("href"); - - if (!novelUrl) return; - - const novel = { - name: novelName, - cover: novelCover, - url: novelUrl, - }; - - novels.push(novel); - }); - - return novels; -}; -export const fetchImage: Plugin.fetchImage = fetchFile; diff --git a/plugins/turkish/epiknovel.ts b/plugins/turkish/epiknovel.ts new file mode 100644 index 0000000..2569cdf --- /dev/null +++ b/plugins/turkish/epiknovel.ts @@ -0,0 +1,169 @@ +import { load as parseHTML } from "cheerio"; +import { fetchFile } from "@libs/fetch"; +import { Plugin } from "@typings/plugin"; +import { Filters } from "@libs/filterInputs"; + +class EpikNovel implements Plugin.PluginBase { + id = "epiknovel.com"; + name = "EpikNovel"; + icon = "src/tr/epiknovel/icon.png"; + site = "https://www.epiknovel.com/"; + version = "1.0.0"; + baseUrl = this.site; + async popularNovels(pageNo: number, options: Plugin.PopularNovelsOptions): Promise { + let url = this.baseUrl + "seri-listesi?Sayfa=" + pageNo; + + const result = await fetch(url); + const body = await result.text(); + + let loadedCheerio = parseHTML(body); + + let novels: Plugin.NovelItem[] = []; + + loadedCheerio("div.col-lg-12.col-md-12").each(function () { + const novelName = loadedCheerio(this).find("h3").text(); + const novelCover = loadedCheerio(this).find("img").attr("data-src"); + const novelUrl = loadedCheerio(this).find("h3 > a").attr("href"); + + if (!novelUrl) return; + + const novel = { + name: novelName, + cover: novelCover, + url: novelUrl, + }; + + novels.push(novel); + }); + + // console.log(novels); + + return novels; + } + async parseNovelAndChapters(novelUrl: string): Promise { + const url = novelUrl; + // console.log(url); + + const result = await fetch(url); + const body = await result.text(); + + let loadedCheerio = parseHTML(body); + + let novel: Plugin.SourceNovel = { url }; + + novel.name = loadedCheerio("h1#tables").text().trim(); + + novel.cover = loadedCheerio("img.manga-cover").attr("src"); + + novel.summary = loadedCheerio( + "#wrapper > div.row > div.col-md-9 > div:nth-child(6) > p:nth-child(3)" + ) + .text() + .trim(); + + novel.status = loadedCheerio( + "#wrapper > div.row > div.col-md-9 > div.row > div.col-md-9 > h4:nth-child(3) > a" + ) + .text() + .trim(); + + novel.author = loadedCheerio("#NovelInfo > p:nth-child(4)") + .text() + .replace(/Publisher:|\s/g, "") + .trim(); + + let novelChapters: Plugin.ChapterItem[] = []; + + loadedCheerio("table").find("tr").first().remove(); + + loadedCheerio("table") + .find("tr") + .each(function () { + const releaseDate = loadedCheerio(this) + .find("td:nth-child(3)") + .text(); + + let chapterName = loadedCheerio(this) + .find("td:nth-child(1) > a") + .text(); + + if ( + loadedCheerio(this).find("td:nth-child(1) > span").length > + 0 + ) { + chapterName = "🔒 " + chapterName; + } + + const chapterUrl = loadedCheerio(this) + .find(" td:nth-child(1) > a") + .attr("href"); + + if (!chapterUrl) return; + + novelChapters.push({ + name: chapterName, + url: chapterUrl, + releaseTime: releaseDate, + }); + }); + + novel.chapters = novelChapters; + // console.log(novel); + + return novel; + } + async parseChapter(chapterUrl: string): Promise { + const url = chapterUrl; + + // console.log(url); + + const result = await fetch(url); + const body = await result.text(); + + let loadedCheerio = parseHTML(body); + + let chapterText = ''; + + if (result.url === "https://www.epiknovel.com/login") { + chapterText = "Premium Chapter"; + } else { + chapterText = loadedCheerio("div#icerik").html() || ''; + } + + return chapterText; + } + async searchNovels(searchTerm: string, pageNo: number): Promise { + const url = this.baseUrl + "seri-listesi?q=" + searchTerm + '&Sayfa=' + pageNo; + + const result = await fetch(url); + const body = await result.text(); + + let loadedCheerio = parseHTML(body); + + let novels: Plugin.NovelItem[] = []; + + loadedCheerio("div.col-lg-12.col-md-12").each(function () { + const novelName = loadedCheerio(this).find("h3").text(); + const novelCover = loadedCheerio(this).find("img").attr("data-src"); + const novelUrl = loadedCheerio(this).find("h3 > a").attr("href"); + + if (!novelUrl) return; + + const novel = { + name: novelName, + cover: novelCover, + url: novelUrl, + }; + + novels.push(novel); + }); + + return novels; + } + fetchImage(url: string): Promise { + return fetchFile(url); + } + +} + +export default new EpikNovel(); \ No newline at end of file diff --git a/plugins/vietnamese/LNHako.ts b/plugins/vietnamese/LNHako.ts index b4f40dd..7ecce94 100644 --- a/plugins/vietnamese/LNHako.ts +++ b/plugins/vietnamese/LNHako.ts @@ -1,7 +1,8 @@ import { CheerioAPI, load as parseHTML } from "cheerio"; -import { fetchApi, fetchFile } from "@libs/fetch"; +import { fetchFile } from "@libs/fetch"; import { Plugin } from "@typings/plugin"; import { isUrlAbsolute } from "@libs/isAbsoluteUrl"; +import { NovelStatus } from "@libs/novelStatus"; class HakoPlugin implements Plugin.PluginBase { id: string; name: string; @@ -9,18 +10,16 @@ class HakoPlugin implements Plugin.PluginBase { site: string; version: string; - constructor() { this.id = "ln.hako"; this.name = "Hako"; this.icon = "src/vi/hakolightnovel/icon.png"; this.site = "https://ln.hako.vn"; this.version = "1.0.0"; - } parseNovels(loadedCheerio: CheerioAPI) { const novels: Plugin.NovelItem[] = []; - loadedCheerio(".row > .thumb-item-flow").each((index, ele) => { + loadedCheerio("#mainpart .row .thumb-item-flow").each((index, ele) => { let url = loadedCheerio(ele) .find("div.thumb_attr.series-title > a") .attr("href"); @@ -71,7 +70,7 @@ class HakoPlugin implements Plugin.PluginBase { let loadedCheerio = parseHTML(body); - novel.name = loadedCheerio(".series-name").text(); + novel.name = loadedCheerio(".series-name").text().trim(); const background = loadedCheerio(".series-cover > .a6-ratio > div").attr("style") || @@ -89,52 +88,64 @@ class HakoPlugin implements Plugin.PluginBase { novel.summary = loadedCheerio(".summary-content").text().trim(); - novel.author = loadedCheerio( - "#mainpart > div:nth-child(2) > div > div:nth-child(1) > section > main > div.top-part > div > div.col-12.col-md-9 > div.series-information > div:nth-child(2) > span.info-value > a" - ) - .text() - .trim(); - - novel.genres = loadedCheerio(".series-gernes") + novel.genres = loadedCheerio(".series-information > div:nth-child(1)") .text() .trim() - .replace(/ +/g, " ") - .split("\n") - .filter((e) => e.trim()) - .join(", "); - - novel.status = loadedCheerio( - "#mainpart > div:nth-child(2) > div > div:nth-child(1) > section > main > div.top-part > div > div.col-12.col-md-9 > div.series-information > div:nth-child(4) > span.info-value > a" - ) + .split(/\n[\s\n]*/).join(','); + + novel.author = loadedCheerio('.series-information > div:nth-child(2) > .info-value') + .text() + .trim(); + novel.artist = loadedCheerio('.series-information > div:nth-child(3) > .info-value') .text() .trim(); - const chapters: Plugin.ChapterItem[] = []; - loadedCheerio(".list-chapters li").each((index, ele) => { - let chapterUrl = loadedCheerio(ele).find("a").attr("href"); + novel.status = loadedCheerio('.series-information > div:nth-child(4) > .info-value') + .text() + .trim(); + + switch (novel.status) { + case 'Đang tiến hành': + novel.status = NovelStatus.Ongoing; + break; + case 'Tạm ngưng': + novel.status = NovelStatus.OnHiatus; + break; + case 'Completed': + novel.status = NovelStatus.Completed; + break; + default: + novel.status = NovelStatus.Unknown; + } - if (chapterUrl && !isUrlAbsolute(chapterUrl)) { - chapterUrl = this.site + chapterUrl; + let num = 0, part = 1; + const chapters: Plugin.ChapterItem[] = loadedCheerio('.list-chapters li').toArray().map((ele) => { + let chapterUrl = this.site + loadedCheerio(ele).find("a").attr("href"); + const chapterName = loadedCheerio(ele) + .find(".chapter-name") + .text() + .trim(); + let chapterNumber = Number(chapterName.match(/Chương\s*(\d+)/i)?.[1]); + if(chapterNumber){ + num = chapterNumber; + part = 1; + }else{ + chapterNumber = num + part / 10; + part ++; } + const chapterTime = loadedCheerio(ele) + .find(".chapter-time") + .text() + .split('/') + .map(x => Number(x)); + return { + url: chapterUrl || '', + name: chapterName, + releaseTime: new Date(chapterTime[2], chapterTime[1], chapterTime[0]).toISOString(), + chapterNumber: chapterNumber, + }; + }).filter(c => c.url); - if (chapterUrl) { - const chapterName = loadedCheerio(ele) - .find(".chapter-name") - .text() - .trim(); - const releaseTime = loadedCheerio(ele) - .find(".chapter-time") - .text(); - - const chapter = { - name: chapterName, - releaseTime: releaseTime, - url: chapterUrl, - }; - - chapters.push(chapter); - } - }); novel.chapters = chapters; return novel; } @@ -150,11 +161,11 @@ class HakoPlugin implements Plugin.PluginBase { } async searchNovels( searchTerm: string, - pageNo?: number | undefined + pageNo: number ): Promise { - const url = this.site + "/tim-kiem?keywords=" + searchTerm; + const url = this.site + "/tim-kiem?keywords=" + searchTerm + '&page=' + pageNo; const result = await fetch(url); - const body = await result.text(); + const body = await result.text(); const loadedCheerio = parseHTML(body); return this.parseNovels(loadedCheerio); } diff --git a/test_web/index.html b/test_web/index.html index 67e1fba..66c5088 100644 --- a/test_web/index.html +++ b/test_web/index.html @@ -276,7 +276,7 @@
fetchImage
- +
diff --git a/test_web/static/js/index.js b/test_web/static/js/index.js index cae5c14..b24804e 100644 --- a/test_web/static/js/index.js +++ b/test_web/static/js/index.js @@ -56,8 +56,8 @@ const getHeaders = () => { if (nameSpan && valueSpan) { const { innerText: name } = nameSpan; const { innerText: value } = valueSpan; - if (typeof name === "string" && typeof value === "string") { - headers[name] = value; + if (typeof name === "string" && typeof value === "string" && value.trim()) { + headers[name] = value.trim(); } } });