From 158fcc1e4d0648b7c5d47afde9927bf54d1f793c Mon Sep 17 00:00:00 2001 From: JhoendryB Date: Sat, 4 Apr 2026 21:14:19 -0400 Subject: [PATCH 1/6] add new plugin spanish Novelyra --- plugins/spanish/novelyra.ts | 281 +++++++++++++++++++++++++ public/static/src/es/novelyra/icon.png | Bin 0 -> 1617 bytes 2 files changed, 281 insertions(+) create mode 100644 plugins/spanish/novelyra.ts create mode 100644 public/static/src/es/novelyra/icon.png diff --git a/plugins/spanish/novelyra.ts b/plugins/spanish/novelyra.ts new file mode 100644 index 000000000..2770f4272 --- /dev/null +++ b/plugins/spanish/novelyra.ts @@ -0,0 +1,281 @@ +import { fetchApi } from '@libs/fetch'; +import { Plugin } from '@/types/plugin'; +import { FilterTypes, Filters } from '@libs/filterInputs'; +import { load as loadCheerio } from 'cheerio'; +import { defaultCover } from '@libs/defaultCover'; +import { NovelStatus } from '@libs/novelStatus'; + +function parseSpanishTextToISO(text: string) { + if (!text) return null; + + const now = new Date(); + const textLower = text.trim().toLowerCase(); + + // --- 1. MAPEOS Y EXPRESIONES REGULARES --- + const months = { + enero: 0, + febrero: 1, + marzo: 2, + abril: 3, + mayo: 4, + junio: 5, + julio: 6, + agosto: 7, + septiembre: 8, + octubre: 9, + noviembre: 10, + diciembre: 11, + }; + + // Expresión para: "21 de febrero de 2026" + const absoluteRegex = /^(\d{1,2})\s+de\s+([a-z]+)\s+de\s+(\d{4})$/i; + + // --- 2. EVALUAR FECHAS ABSOLUTAS --- + const absoluteMatch = textLower.match(absoluteRegex); + if (absoluteMatch) { + const day = parseInt(absoluteMatch[1], 10); + const monthStr = absoluteMatch[2]; + const year = parseInt(absoluteMatch[3], 10); + + const monthIndex = months[monthStr as keyof typeof months]; + if (monthIndex !== undefined) { + // Se crea la fecha en hora local (00:00:00) + const date = new Date(year, monthIndex, day); + return date.toISOString(); + } + } + + // --- 3. EVALUAR FECHAS RELATIVAS ("hace...") --- + if (textLower.startsWith('hace')) { + // Normalizar "un" / "una" a "1" para facilitar el cálculo + let normalized = textLower + .replace(/\b(un|una)\b/g, '1') + .replace('un momento', '0 segundos'); + + if (normalized.includes('momento')) { + return now.toISOString(); + } + + const relativeRegex = /(\d+)\s+([a-zñáéíóú]+)/i; + const relativeMatch = normalized.match(relativeRegex); + + if (relativeMatch) { + const value = parseInt(relativeMatch[1], 10); + const unit = relativeMatch[2]; + + const date = new Date(now); // Clonamos la fecha actual + + if (unit.startsWith('segundo')) { + date.setSeconds(date.getSeconds() - value); + } else if (unit.startsWith('minuto')) { + date.setMinutes(date.getMinutes() - value); + } else if (unit.startsWith('hora')) { + date.setHours(date.getHours() - value); + } else if (unit.startsWith('dia') || unit.startsWith('día')) { + date.setDate(date.getDate() - value); + } else if (unit.startsWith('mes')) { + date.setMonth(date.getMonth() - value); + } else if (unit.startsWith('año') || unit.startsWith('ano')) { + date.setFullYear(date.getFullYear() - value); + } + + return date.toISOString(); + } + } + + // Si no coincide con ningún formato conocido, intentar el parse nativo o lanzar error + try { + const fallbackDate = new Date(text); + if (!isNaN(fallbackDate.getTime())) return fallbackDate.toISOString(); + } catch (e) { + // No se pudo parsear + } + + throw new Error(`Formato de fecha no soportado: "${text}"`); +} + +class Novelyra implements Plugin.PluginBase { + id = 'novelyra'; + name = 'Novelyra'; + icon = 'src/es/novelyra/icon.png'; + site = 'https://novelyra.com'; + version = '1.0.0'; + filters?: Filters | undefined = { + genres: { + type: FilterTypes.Picker, + label: 'Generos', + value: '', + options: [ + { label: 'Acción', value: 'accion' }, + { label: 'Aventura', value: 'aventura' }, + { label: 'Fantasía', value: 'fantasia' }, + { label: 'Artes Marciales', value: 'artes-marciales' }, + { label: 'Harén', value: 'haren' }, + { label: 'Romance', value: 'romance' }, + { label: 'Sobrenatural', value: 'sobrenatural' }, + { label: 'Xuanhuan', value: 'xuanhuan' }, + { label: 'Xianxia', value: 'xianxia' }, + { label: 'Comedia', value: 'comedia' }, + { label: 'Ciencia Ficción', value: 'ciencia-ficcion' }, + { label: 'Misterio', value: 'misterio' }, + { label: 'Maduro', value: 'maduro' }, + { label: 'Psicológico', value: 'psicologico' }, + { label: 'Shounen', value: 'shounen' }, + { label: 'Reencarnación', value: 'reencarnacion' }, + { label: 'Mecha', value: 'mecha' }, + { label: 'Vida Escolar', value: 'vida-escolar' }, + { label: 'Josei', value: 'josei' }, + { label: 'Drama', value: 'drama' }, + { label: 'Urbano', value: 'urbano' }, + { label: 'Oriental', value: 'oriental' }, + { label: 'Horror', value: 'horror' }, + { label: 'Tragedia', value: 'tragedia' }, + { label: 'Juegos', value: 'juegos' }, + ], + }, + } satisfies Filters; + imageRequestInit?: Plugin.ImageRequestInit | undefined = undefined; + + //flag indicates whether access to LocalStorage, SesesionStorage is required. + webStorageUtilized?: boolean; + + async popularNovels( + pageNo: number, + { + showLatestNovels, + filters, + }: Plugin.PopularNovelsOptions, + ): Promise { + let url = this.site; + + const isFilters = filters?.genres.value != ''; + + if (isFilters) { + url = `${this.site}/browse.php?genre=${filters?.genres.value}&page=${pageNo}`; + } + + const result = await fetchApi(url); + const body = await result.text(); + + const loadedCheerio = loadCheerio(body); + const novels: Plugin.NovelItem[] = []; + + const typeNovel = isFilters + ? '.novels-grid .novel-card' + : showLatestNovels + ? '#novelas .novel-card' + : '.section-gray .novel-card'; + + loadedCheerio(typeNovel).each((idx, ele) => { + const novel = loadedCheerio(ele); + novels.push({ + name: novel.find('h3').text(), + path: novel.find('a').attr('href') || '', + cover: novel.find('img').attr('src') || defaultCover, + }); + }); + + return novels; + } + async parseNovel(novelPath: string): Promise { + const result = await fetchApi(novelPath); + const body = await result.text(); + + const loadedCheerio = loadCheerio(body); + + const novel: Plugin.SourceNovel = { + path: novelPath, + name: loadedCheerio('h1').text(), + }; + + novel.cover = loadedCheerio('img').attr('src') || defaultCover; + novel.genres = loadedCheerio('.novel-meta .novel-genres') + .text() + .trim() + .replace('\n', ', '); + console.log(novel.genres); + novel.status = NovelStatus.Completed; + novel.summary = loadedCheerio('.novel-description-detail').text().trim(); + + const chapters: Plugin.ChapterItem[] = []; + + loadedCheerio('.chapter-item-wrapper').each((idx, ele) => { + const cptr = loadedCheerio(ele); + const numberText = cptr.find('.chapter-number').text(); + const numberMatch = numberText.match(/(\d+)/); + const chapterNumber = numberMatch ? parseInt(numberMatch[1]) : 0; + const chapter: Plugin.ChapterItem = { + name: cptr.find('.chapter-title').text(), + path: cptr.find('a').attr('href') || '', + releaseTime: parseSpanishTextToISO(cptr.find('.chapter-date').text()), + chapterNumber: chapterNumber, + }; + chapters.push(chapter); + }); + + novel.chapters = chapters; + return novel; + } + async parseChapter(chapterPath: string): Promise { + const myHeaders = new Headers(); + myHeaders.set( + 'User-Agent', + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36', + ); + myHeaders.set( + 'Accept', + 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8', + ); + myHeaders.set('Accept-Language', 'es-ES,es;q=0.9'); + myHeaders.set('Referer', 'https://novelyra.com/'); + myHeaders.set('Cache-Control', 'no-cache'); + + const result = await fetchApi(chapterPath, { + method: 'GET', + headers: myHeaders, + }); + + const body = await result.text(); + + const loadedCheerio = loadCheerio(body); + + // Quita scripts + loadedCheerio('script').remove(); + // Quita bloques de anuncios + loadedCheerio('.chapter-ad').remove(); + // Quita tags de adsense si los hay + loadedCheerio('ins').remove(); + + const chapterText = loadedCheerio('.chapter-content').html(); + + return chapterText?.replace(/\n/g, '
') || ''; + } + async searchNovels( + searchTerm: string, + pageNo: number, + ): Promise { + searchTerm = searchTerm.toLowerCase(); + + const url = `${this.site}/?search=${searchTerm}`; + + const result = await fetchApi(url); + const body = await result.text(); + + const loadedCheerio = loadCheerio(body); + + const novels: Plugin.NovelItem[] = []; + + loadedCheerio('#novelas .novel-card').each((idx, ele) => { + const novel = loadedCheerio(ele); + novels.push({ + name: novel.find('h3').text(), + path: novel.find('a').attr('href') || '', + cover: novel.find('img').attr('src') || defaultCover, + }); + }); + + return novels; + } +} + +export default new Novelyra(); diff --git a/public/static/src/es/novelyra/icon.png b/public/static/src/es/novelyra/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..5526fadc29ad579d648329e01b69ce229c9c88c2 GIT binary patch literal 1617 zcmV-X2Cn&uP)qCi1m1>{SdB8u-O^Bdouba#7?+1s6+^L^IN?au4__WS*JZg$6;I8g=s z)a(C0vAW)Tb#1-*^~%QH&#U$3_0{^`ot5=wd$ry)vz!iN*t=t6xK3=uNUX$M06LXh zfO`GkQ!5*{-?k_AdrQ^+R$6Ttt=`l|zi3bFj8b|*Yg?*j`{ytQye4?C4fVH)~rx|WqsZVg`<6xfJ!UjgLg4raoj}?Fkr>*rL*4R9M)!6X8 zwq=;XZd|XC0x-ca;h^j|LsH*Mz%jEoCXQimRZniH0CZ%6>1iz)Zvrrc<*<&K0x)#w zIINSD`w@U8OtX3o2*BiFl=?oav6ST}08`lZTNn_)B>Fq|{ng*{DCH}N1*Wj=cikgE z=N?w>cKRt5mtXEM?po{$;GW`)`nX#o2jvj3j2-Ka^{xPIQ+t(smx zfW@S?Qg5V%vM-katYMB9C%}PTIFB+ENGhKItYMBPCxE?AeT9sqa0F83NoPWkJD+gu zQ%}pVPgnpv zp?JXF-UXSZP!7dUKLN9p7^6@07fU`20oW%z6ohdnUit~Z-hKu37fU`Q0TCc1?F?U0 z2(Y$sTUC)VcmywsLV(~=N90fhs8|dUKm@3mK*{dMnU@hTj!?<<(F<_y<>R^5k3Row zLD9Elep8!|S^xl^d+B(tAWuD(DEhv3;o)5ULv@N;fajlkXlf2;&(@~4QKo^Y1t=nL zMnVyG%CZr)0NcOapE~ZV*X~Viqf7&F3$T4(HPVlHF5ujp)kEQ?>L-lbl0{GA>p{)o|0#qN9(F?$GM4tDFWG%?&G8obp z_^js)sUBI(6EJ;cEodaB(Ur0mG@8#$)G`ucKGCS>09gyF_|n;ywV-MhkhP#{`Ok&- z0_T9a;8l2#B0%9t{S1l#e!L2AEdmsd)X!k_0yOYEoxaB#=G7gY88KUq+H%Ayv)Cy-ffD*{xkoCqKSR7{{^_c8)Rfa?Aq zp^Di%_c8(;hUz{CYj$jsEi8c@*xS1xrHs};hV?DpQsz#8V`hJghXTP8h5)Q#jyESjqw)AHd+;p< zlFBClYnbE79>!?WARzLeEOkN zmO@Db1YiRrSix+dK}Nwu0;K)8hdriSr?pYv;4Cel_dP6N0vj0l@bD4NAZ`#FF%l~=6FUrGVe4~k4*&oF|Np~HED!(y00v1!K~w_(RyDHl5$YmM P00000NkvXXu0mjftkLrg literal 0 HcmV?d00001 From 2e8aefb27a2718c357ff29b1f36abe9f8f3fc2a1 Mon Sep 17 00:00:00 2001 From: JhoendryB Date: Sat, 4 Apr 2026 21:19:52 -0400 Subject: [PATCH 2/6] fix index.ts add novelyra --- plugins/index.ts | 476 ++++++++++++++++++++++++----------------------- 1 file changed, 248 insertions(+), 228 deletions(-) diff --git a/plugins/index.ts b/plugins/index.ts index 4152a37f8..d8e609e2b 100644 --- a/plugins/index.ts +++ b/plugins/index.ts @@ -5,234 +5,244 @@ import p_2 from '@plugins/arabic/dilartube'; import p_3 from '@plugins/arabic/FreeKolNovel[lightnovelwp]'; import p_4 from '@plugins/arabic/HizoManga[madara]'; import p_5 from '@plugins/arabic/KolNovel[lightnovelwp]'; -import p_6 from '@plugins/arabic/Novel4Up[madara]'; -import p_7 from '@plugins/arabic/NovelsParadise[lightnovelwp]'; -import p_8 from '@plugins/arabic/Olaoecyou[madara]'; -import p_9 from '@plugins/arabic/rewayatclub'; -import p_10 from '@plugins/arabic/Riwyat[madara]'; -import p_11 from '@plugins/arabic/sunovels'; -import p_12 from '@plugins/chinese/69shu'; -import p_13 from '@plugins/chinese/ixdzs8'; -import p_14 from '@plugins/chinese/linovel'; -import p_15 from '@plugins/chinese/linovelib'; -import p_16 from '@plugins/chinese/linovelib_tw'; -import p_17 from '@plugins/chinese/novel543'; -import p_18 from '@plugins/chinese/Quanben'; -import p_19 from '@plugins/english/AllNovelFull[readnovelfull]'; -import p_20 from '@plugins/english/AllNovel[readnovelfull]'; -import p_21 from '@plugins/english/ao3'; -import p_22 from '@plugins/english/ArcaneTranslations[lightnovelwp]'; -import p_23 from '@plugins/english/BelleReservoir[madara]'; -import p_24 from '@plugins/english/BoxNovel[readnovelfull]'; -import p_25 from '@plugins/english/chrysanthemumgarden'; -import p_26 from '@plugins/english/CitrusAurora[madara]'; -import p_27 from '@plugins/english/CoralBoutique[madara]'; -import p_28 from '@plugins/english/CPUnovel[lightnovelwp]'; -import p_29 from '@plugins/english/crimsonscrolls'; -import p_30 from '@plugins/english/DaoistQuest[fictioneer]'; -import p_31 from '@plugins/english/DaoNovel[madara]'; -import p_32 from '@plugins/english/DaoTranslate[lightnovelwp]'; -import p_33 from '@plugins/english/DearestRosalie[fictioneer]'; -import p_34 from '@plugins/english/divinedaolibrary'; -import p_35 from '@plugins/english/Dragonholic[madara]'; -import p_36 from '@plugins/english/DragonTea[madara]'; -import p_37 from '@plugins/english/dreambigtl'; -import p_38 from '@plugins/english/DuskBlossoms[madara]'; -import p_39 from '@plugins/english/ElloTL[lightnovelwp]'; -import p_40 from '@plugins/english/Eternalune[madara]'; -import p_41 from '@plugins/english/EtudeTranslations[madara]'; -import p_42 from '@plugins/english/FanNovel[readwn]'; -import p_43 from '@plugins/english/FansMTL[readwn]'; -import p_44 from '@plugins/english/FansTranslations[madara]'; -import p_45 from '@plugins/english/faqwikius'; -import p_46 from '@plugins/english/fenrirrealm'; -import p_47 from '@plugins/english/fictionzone'; -import p_48 from '@plugins/english/FirstKissNovel[madara]'; -import p_49 from '@plugins/english/Foxaholic[madara]'; -import p_50 from '@plugins/english/foxteller'; -import p_51 from '@plugins/english/FreeWebNovel[readnovelfull]'; -import p_52 from '@plugins/english/GalaxyTranslations[madara]'; -import p_53 from '@plugins/english/genesis'; -import p_54 from '@plugins/english/Guavaread[madara]'; -import p_55 from '@plugins/english/HiraethTranslation[madara]'; -import p_56 from '@plugins/english/HotNovelPub[hotnovelpub]'; -import p_57 from '@plugins/english/inkitt'; -import p_58 from '@plugins/english/Ippotranslations[lightnovelwp]'; -import p_59 from '@plugins/english/KDTNovels[lightnovelwp]'; -import p_60 from '@plugins/english/KeopiTranslations[lightnovelwp]'; -import p_61 from '@plugins/english/KnoxT[lightnovelwp]'; -import p_62 from '@plugins/english/LazyGirlTranslations[lightnovelwp]'; -import p_63 from '@plugins/english/leafstudio'; -import p_64 from '@plugins/english/LibRead[readnovelfull]'; -import p_65 from '@plugins/english/LightNovelCave[lightnovelworld]'; -import p_66 from '@plugins/english/LightNovelHeaven[madara]'; -import p_67 from '@plugins/english/LightNovelPlus[readnovelfull]'; -import p_68 from '@plugins/english/LightNovelPubVip[lightnovelworld]'; -import p_69 from '@plugins/english/lightnoveltranslation'; -import p_70 from '@plugins/english/LightNovelUpdates[madara]'; -import p_71 from '@plugins/english/LilyontheValley[fictioneer]'; -import p_72 from '@plugins/english/lnmtl'; -import p_73 from '@plugins/english/Ltnovel[readwn]'; -import p_74 from '@plugins/english/LunarLetters[madara]'; -import p_75 from '@plugins/english/Meownovel[madara]'; -import p_76 from '@plugins/english/MoonlightNovels[lightnovelwp]'; -import p_77 from '@plugins/english/MostNovel[madara]'; -import p_78 from '@plugins/english/MTLNovel[madara]'; -import p_79 from '@plugins/english/MTLNovel[mtlnovel]'; -import p_80 from '@plugins/english/mtlreader'; -import p_81 from '@plugins/english/mvlempyr'; -import p_82 from '@plugins/english/MysticalSeries[madara]'; -import p_83 from '@plugins/english/NeoSekaiTranslations[madara]'; -import p_84 from '@plugins/english/NitroManga[madara]'; -import p_85 from '@plugins/english/NobleMTL[lightnovelwp]'; -import p_86 from '@plugins/english/NoiceTranslations[madara]'; -import p_87 from '@plugins/english/NovelBin[readnovelfull]'; -import p_88 from '@plugins/english/novelbuddy'; -import p_89 from '@plugins/english/NovelCool[novelcool]'; -import p_90 from '@plugins/english/novelfire'; -import p_91 from '@plugins/english/NovelFull[readnovelfull]'; -import p_92 from '@plugins/english/novelhall'; -import p_93 from '@plugins/english/novelight'; -import p_94 from '@plugins/english/NovelLib[fictioneer]'; -import p_95 from '@plugins/english/NovelMultiverse[madara]'; -import p_96 from '@plugins/english/NovelOnline'; -import p_97 from '@plugins/english/NovelsKnight[lightnovelwp]'; -import p_98 from '@plugins/english/NovelTranslate[madara]'; -import p_99 from '@plugins/english/novelupdates'; -import p_100 from '@plugins/english/PandaMachineTranslations[lightnovelwp]'; -import p_101 from '@plugins/english/PastelTales[madara]'; -import p_102 from '@plugins/english/pawread'; -import p_103 from '@plugins/english/PenguinSquad[fictioneer]'; -import p_104 from '@plugins/english/Prizma[fictioneer]'; -import p_105 from '@plugins/english/rainofsnow'; -import p_106 from '@plugins/english/Ranobes[ranobes]'; -import p_107 from '@plugins/english/Ranovel[madara]'; -import p_108 from '@plugins/english/ReadFanfic[madara]'; -import p_109 from '@plugins/english/readfrom'; -import p_110 from '@plugins/english/ReadNovelFull[readnovelfull]'; -import p_111 from '@plugins/english/relibrary'; -import p_112 from '@plugins/english/RequiemTranslations[lightnovelwp]'; -import p_113 from '@plugins/english/royalroad'; -import p_114 from '@plugins/english/SalmonLatte[madara]'; -import p_115 from '@plugins/english/scribblehub'; -import p_116 from '@plugins/english/SleepyTranslations[madara]'; -import p_117 from '@plugins/english/SonicMTL[madara]'; -import p_118 from '@plugins/english/SrankManga[madara]'; -import p_119 from '@plugins/english/StorySeedling'; -import p_120 from '@plugins/english/SweetEscape[madara]'; -import p_121 from '@plugins/english/SystemTranslation[lightnovelwp]'; -import p_122 from '@plugins/english/TranslatinOtaku[madara]'; -import p_123 from '@plugins/english/TranslationWeaver[lightnovelwp]'; -import p_124 from '@plugins/english/UniversalNovel[lightnovelwp]'; -import p_125 from '@plugins/english/VandyTranslate[lightnovelwp]'; -import p_126 from '@plugins/english/VioletLily[madara]'; -import p_127 from '@plugins/english/vynovel'; -import p_128 from '@plugins/english/webnovel'; -import p_129 from '@plugins/english/WebNovelLover[madara]'; -import p_130 from '@plugins/english/WebNovelPub[lightnovelworld]'; -import p_131 from '@plugins/english/WebNovelTranslation[madara]'; -import p_132 from '@plugins/english/WhiteMoonlightNovels[lightnovelwp]'; -import p_133 from '@plugins/english/WooksTeahouse[madara]'; -import p_134 from '@plugins/english/WordExcerpt[madara]'; -import p_135 from '@plugins/english/wtrlab'; -import p_136 from '@plugins/english/Wuxiabox[readwn]'; -import p_137 from '@plugins/english/Wuxiafox[readwn]'; -import p_138 from '@plugins/english/WuxiaSpace[readwn]'; -import p_139 from '@plugins/english/WuxiaV[readwn]'; -import p_140 from '@plugins/english/wuxiaworld'; -import p_141 from '@plugins/english/WuxiaWorldSite[madara]'; -import p_142 from '@plugins/english/ZetroTranslation[madara]'; -import p_143 from '@plugins/french/chireads'; -import p_144 from '@plugins/french/harkeneliwood'; -import p_145 from '@plugins/french/kisswood'; -import p_146 from '@plugins/french/LighNovelFR[lightnovelwp]'; -import p_147 from '@plugins/french/MassNovel[madara]'; -import p_148 from '@plugins/french/MTLNovel(FR)[mtlnovel]'; -import p_149 from '@plugins/french/noveldeglace'; -import p_150 from '@plugins/french/novhell'; -import p_151 from '@plugins/french/warriorlegendtrad'; -import p_152 from '@plugins/french/WorldNovel[madara]'; -import p_153 from '@plugins/french/wuxialnscantrad'; -import p_154 from '@plugins/french/xiaowaz'; -import p_155 from '@plugins/indonesian/BacaLightNovel[lightnovelwp]'; -import p_156 from '@plugins/indonesian/indowebnovel'; -import p_157 from '@plugins/indonesian/MeioNovel[madara]'; -import p_158 from '@plugins/indonesian/MTLNovel(ID)[mtlnovel]'; -import p_159 from '@plugins/indonesian/NovelBookID[madara]'; -import p_160 from '@plugins/indonesian/sakuranovel'; -import p_161 from '@plugins/indonesian/SekteNovel[lightnovelwp]'; -import p_162 from '@plugins/indonesian/Vanovel[madara]'; -import p_163 from '@plugins/indonesian/WBNovel[madara]'; -import p_164 from '@plugins/japanese/kakuyomu'; -import p_165 from '@plugins/japanese/Syosetu'; -import p_166 from '@plugins/korean/Agitoon'; -import p_167 from '@plugins/korean/FortuneEternal[madara]'; -import p_168 from '@plugins/multi/komga'; -import p_169 from '@plugins/polish/novelki'; -import p_170 from '@plugins/portuguese/BetterNovels[lightnovelwp]'; -import p_171 from '@plugins/portuguese/blogdoamonnovels'; -import p_172 from '@plugins/portuguese/CentralNovel[lightnovelwp]'; -import p_173 from '@plugins/portuguese/Kiniga[madara]'; -import p_174 from '@plugins/portuguese/LaNovels[hotnovelpub]'; -import p_175 from '@plugins/portuguese/LightNovelBrasil[lightnovelwp]'; -import p_176 from '@plugins/portuguese/MTLNovel(PT)[mtlnovel]'; -import p_177 from '@plugins/portuguese/novelmania'; -import p_178 from '@plugins/portuguese/tsundoku'; -import p_179 from '@plugins/russian/authortoday'; -import p_180 from '@plugins/russian/Bookhamster[ifreedom]'; -import p_181 from '@plugins/russian/bookriver'; -import p_182 from '@plugins/russian/Erolate[rulate]'; -import p_183 from '@plugins/russian/EzNovels[hotnovelpub]'; -import p_184 from '@plugins/russian/ficbook'; -import p_185 from '@plugins/russian/jaomix'; -import p_186 from '@plugins/russian/MTLNovel(RU)[mtlnovel]'; -import p_187 from '@plugins/russian/neobook'; -import p_188 from '@plugins/russian/NovelCool(RU)[novelcool]'; -import p_189 from '@plugins/russian/novelTL'; -import p_190 from '@plugins/russian/ranobehub'; -import p_191 from '@plugins/russian/ranobelib'; -import p_192 from '@plugins/russian/ranoberf'; -import p_193 from '@plugins/russian/Ranobes(RU)[ranobes]'; -import p_194 from '@plugins/russian/renovels'; -import p_195 from '@plugins/russian/Rulate[rulate]'; -import p_196 from '@plugins/russian/topliba'; -import p_197 from '@plugins/russian/zelluloza'; -import p_198 from '@plugins/russian/СвободныйМирРанобэ[ifreedom]'; -import p_199 from '@plugins/spanish/AllNovelRead[lightnovelwp]'; -import p_200 from '@plugins/spanish/AnimesHoy12[madara]'; -import p_201 from '@plugins/spanish/hasutl'; -import p_202 from '@plugins/spanish/LightNovelDaily[hotnovelpub]'; -import p_203 from '@plugins/spanish/MTLNovel(ES)[mtlnovel]'; -import p_204 from '@plugins/spanish/novelasligera'; -import p_205 from '@plugins/spanish/novelawuxia'; -import p_206 from '@plugins/spanish/oasistranslations'; -import p_207 from '@plugins/spanish/PanchoTranslations[madara]'; -import p_208 from '@plugins/spanish/skynovels'; -import p_209 from '@plugins/spanish/TC&Sega[lightnovelwp]'; -import p_210 from '@plugins/spanish/TraduccionesAmistosas[madara]'; -import p_211 from '@plugins/spanish/tunovelaligera'; -import p_212 from '@plugins/spanish/yukitls'; -import p_213 from '@plugins/thai/NovelLucky[madara]'; -import p_214 from '@plugins/thai/NovelPDF[madara]'; -import p_215 from '@plugins/turkish/ArazNovel[madara]'; -import p_216 from '@plugins/turkish/EKTAPLAR[madara]'; -import p_217 from '@plugins/turkish/epiknovel'; -import p_218 from '@plugins/turkish/kakikata[madara]'; -import p_219 from '@plugins/turkish/KodeksLibrary[lightnovelwp]'; -import p_220 from '@plugins/turkish/MangaTR'; -import p_221 from '@plugins/turkish/NABSCANS[madara]'; -import p_222 from '@plugins/turkish/Namevt[lightnovelwp]'; -import p_223 from '@plugins/turkish/Noveloku[madara]'; -import p_224 from '@plugins/turkish/NovelTR[lightnovelwp]'; -import p_225 from '@plugins/turkish/RagnarScans[madara]'; -import p_226 from '@plugins/turkish/ThNovels[hotnovelpub]'; -import p_227 from '@plugins/turkish/TurkceLightNovels[madara]'; -import p_228 from '@plugins/turkish/WebNovelOku[madara]'; -import p_229 from '@plugins/ukrainian/bakainua'; -import p_230 from '@plugins/ukrainian/smakolykytl'; -import p_231 from '@plugins/vietnamese/lightnovelvn'; -import p_232 from '@plugins/vietnamese/LNHako'; -import p_233 from '@plugins/vietnamese/nettruyen'; +import p_6 from '@plugins/arabic/Markazriwayat[madara]'; +import p_7 from '@plugins/arabic/Novel4Up[madara]'; +import p_8 from '@plugins/arabic/NovelsParadise[lightnovelwp]'; +import p_9 from '@plugins/arabic/Olaoecyou[madara]'; +import p_10 from '@plugins/arabic/rewayatclub'; +import p_11 from '@plugins/arabic/Riwyat[madara]'; +import p_12 from '@plugins/arabic/sunovels'; +import p_13 from '@plugins/chinese/69shu'; +import p_14 from '@plugins/chinese/ixdzs8'; +import p_15 from '@plugins/chinese/linovel'; +import p_16 from '@plugins/chinese/linovelib'; +import p_17 from '@plugins/chinese/linovelib_tw'; +import p_18 from '@plugins/chinese/novel543'; +import p_19 from '@plugins/chinese/Quanben'; +import p_20 from '@plugins/english/AllNovelFull[readnovelfull]'; +import p_21 from '@plugins/english/AllNovel[readnovelfull]'; +import p_22 from '@plugins/english/ao3'; +import p_23 from '@plugins/english/ArcaneTranslations[lightnovelwp]'; +import p_24 from '@plugins/english/BelleReservoir[madara]'; +import p_25 from '@plugins/english/BoxNovel[readnovelfull]'; +import p_26 from '@plugins/english/chrysanthemumgarden'; +import p_27 from '@plugins/english/CitrusAurora[madara]'; +import p_28 from '@plugins/english/CoralBoutique[madara]'; +import p_29 from '@plugins/english/CPUnovel[lightnovelwp]'; +import p_30 from '@plugins/english/crimsonscrolls'; +import p_31 from '@plugins/english/DaoistQuest[fictioneer]'; +import p_32 from '@plugins/english/DaoNovel[madara]'; +import p_33 from '@plugins/english/DaoTranslate[lightnovelwp]'; +import p_34 from '@plugins/english/DearestRosalie[fictioneer]'; +import p_35 from '@plugins/english/divinedaolibrary'; +import p_36 from '@plugins/english/Dragonholic[madara]'; +import p_37 from '@plugins/english/DragonTea[madara]'; +import p_38 from '@plugins/english/dreambigtl'; +import p_39 from '@plugins/english/DuskBlossoms[madara]'; +import p_40 from '@plugins/english/ElloTL[lightnovelwp]'; +import p_41 from '@plugins/english/Eternalune[madara]'; +import p_42 from '@plugins/english/EtudeTranslations[madara]'; +import p_43 from '@plugins/english/FanNovel[readwn]'; +import p_44 from '@plugins/english/FansMTL[readwn]'; +import p_45 from '@plugins/english/FansTranslations[madara]'; +import p_46 from '@plugins/english/faqwikius'; +import p_47 from '@plugins/english/fenrirrealm'; +import p_48 from '@plugins/english/fictionzone'; +import p_49 from '@plugins/english/FirstKissNovel[madara]'; +import p_50 from '@plugins/english/Foxaholic[madara]'; +import p_51 from '@plugins/english/foxteller'; +import p_52 from '@plugins/english/FreeWebNovel[readnovelfull]'; +import p_53 from '@plugins/english/GalaxyTranslations[madara]'; +import p_54 from '@plugins/english/genesis'; +import p_55 from '@plugins/english/Guavaread[madara]'; +import p_56 from '@plugins/english/HiraethTranslation[madara]'; +import p_57 from '@plugins/english/HotNovelPub[hotnovelpub]'; +import p_58 from '@plugins/english/indraTranslations'; +import p_59 from '@plugins/english/inkitt'; +import p_60 from '@plugins/english/Ippotranslations[lightnovelwp]'; +import p_61 from '@plugins/english/KDTNovels[lightnovelwp]'; +import p_62 from '@plugins/english/KeopiTranslations[lightnovelwp]'; +import p_63 from '@plugins/english/KnoxT[lightnovelwp]'; +import p_64 from '@plugins/english/LazyGirlTranslations[lightnovelwp]'; +import p_65 from '@plugins/english/leafstudio'; +import p_66 from '@plugins/english/LibRead[readnovelfull]'; +import p_67 from '@plugins/english/LightNovelCave[lightnovelworld]'; +import p_68 from '@plugins/english/LightNovelHeaven[madara]'; +import p_69 from '@plugins/english/LightNovelPlus[readnovelfull]'; +import p_70 from '@plugins/english/LightNovelPubVip[lightnovelworld]'; +import p_71 from '@plugins/english/lightnoveltranslation'; +import p_72 from '@plugins/english/LightNovelUpdates[madara]'; +import p_73 from '@plugins/english/LilyontheValley[fictioneer]'; +import p_74 from '@plugins/english/lnmtl'; +import p_75 from '@plugins/english/Ltnovel[readwn]'; +import p_76 from '@plugins/english/LulloBox[madara]'; +import p_77 from '@plugins/english/LunarLetters[madara]'; +import p_78 from '@plugins/english/Meownovel[madara]'; +import p_79 from '@plugins/english/MoonlightNovels[lightnovelwp]'; +import p_80 from '@plugins/english/MostNovel[madara]'; +import p_81 from '@plugins/english/MTLNovel[madara]'; +import p_82 from '@plugins/english/MTLNovel[mtlnovel]'; +import p_83 from '@plugins/english/mtlreader'; +import p_84 from '@plugins/english/mvlempyr'; +import p_85 from '@plugins/english/MysticalSeries[madara]'; +import p_86 from '@plugins/english/NeoSekaiTranslations[madara]'; +import p_87 from '@plugins/english/NitroManga[madara]'; +import p_88 from '@plugins/english/NobleMTL[lightnovelwp]'; +import p_89 from '@plugins/english/NoiceTranslations[madara]'; +import p_90 from '@plugins/english/NovelBin[readnovelfull]'; +import p_91 from '@plugins/english/novelbuddy'; +import p_92 from '@plugins/english/NovelCool[novelcool]'; +import p_93 from '@plugins/english/novelfire'; +import p_94 from '@plugins/english/NovelFull[readnovelfull]'; +import p_95 from '@plugins/english/novelhall'; +import p_96 from '@plugins/english/novelhi'; +import p_97 from '@plugins/english/novelight'; +import p_98 from '@plugins/english/NovelLib[fictioneer]'; +import p_99 from '@plugins/english/NovelMultiverse[madara]'; +import p_100 from '@plugins/english/NovelNinja[madara]'; +import p_101 from '@plugins/english/NovelOnline'; +import p_102 from '@plugins/english/novelrest'; +import p_103 from '@plugins/english/NovelsKnight[lightnovelwp]'; +import p_104 from '@plugins/english/NovelTranslate[madara]'; +import p_105 from '@plugins/english/novelupdates'; +import p_106 from '@plugins/english/PandaMachineTranslations[lightnovelwp]'; +import p_107 from '@plugins/english/PastelTales[madara]'; +import p_108 from '@plugins/english/pawread'; +import p_109 from '@plugins/english/PenguinSquad[fictioneer]'; +import p_110 from '@plugins/english/Prizma[fictioneer]'; +import p_111 from '@plugins/english/rainofsnow'; +import p_112 from '@plugins/english/Ranobes[ranobes]'; +import p_113 from '@plugins/english/Ranovel[madara]'; +import p_114 from '@plugins/english/ReadFanfic[madara]'; +import p_115 from '@plugins/english/readfrom'; +import p_116 from '@plugins/english/ReadNovelFull[readnovelfull]'; +import p_117 from '@plugins/english/relibrary'; +import p_118 from '@plugins/english/RequiemTranslations[lightnovelwp]'; +import p_119 from '@plugins/english/royalroad'; +import p_120 from '@plugins/english/SalmonLatte[madara]'; +import p_121 from '@plugins/english/scribblehub'; +import p_122 from '@plugins/english/SleepyTranslations[madara]'; +import p_123 from '@plugins/english/SonicMTL[madara]'; +import p_124 from '@plugins/english/SrankManga[madara]'; +import p_125 from '@plugins/english/StorySeedling'; +import p_126 from '@plugins/english/SweetEscape[madara]'; +import p_127 from '@plugins/english/SystemTranslation[lightnovelwp]'; +import p_128 from '@plugins/english/TranslatinOtaku[madara]'; +import p_129 from '@plugins/english/TranslationWeaver[lightnovelwp]'; +import p_130 from '@plugins/english/UniversalNovel[lightnovelwp]'; +import p_131 from '@plugins/english/VandyTranslate[lightnovelwp]'; +import p_132 from '@plugins/english/VioletLily[madara]'; +import p_133 from '@plugins/english/vynovel'; +import p_134 from '@plugins/english/webnovel'; +import p_135 from '@plugins/english/WebNovelLover[madara]'; +import p_136 from '@plugins/english/WebNovelPub[lightnovelworld]'; +import p_137 from '@plugins/english/WebNovelTranslation[madara]'; +import p_138 from '@plugins/english/WhiteMoonlightNovels[lightnovelwp]'; +import p_139 from '@plugins/english/WooksTeahouse[madara]'; +import p_140 from '@plugins/english/WordExcerpt[madara]'; +import p_141 from '@plugins/english/wtrlab'; +import p_142 from '@plugins/english/Wuxiabox[readwn]'; +import p_143 from '@plugins/english/Wuxiafox[readwn]'; +import p_144 from '@plugins/english/WuxiaSpace[readwn]'; +import p_145 from '@plugins/english/WuxiaV[readwn]'; +import p_146 from '@plugins/english/wuxiaworld'; +import p_147 from '@plugins/english/WuxiaWorldSite[madara]'; +import p_148 from '@plugins/english/ZetroTranslation[madara]'; +import p_149 from '@plugins/french/chireads'; +import p_150 from '@plugins/french/harkeneliwood'; +import p_151 from '@plugins/french/kisswood'; +import p_152 from '@plugins/french/LighNovelFR[lightnovelwp]'; +import p_153 from '@plugins/french/MassNovel[madara]'; +import p_154 from '@plugins/french/MTLNovel(FR)[mtlnovel]'; +import p_155 from '@plugins/french/noveldeglace'; +import p_156 from '@plugins/french/novhell'; +import p_157 from '@plugins/french/warriorlegendtrad'; +import p_158 from '@plugins/french/WorldNovel[madara]'; +import p_159 from '@plugins/french/wuxialnscantrad'; +import p_160 from '@plugins/french/xiaowaz'; +import p_161 from '@plugins/indonesian/BacaLightNovel[lightnovelwp]'; +import p_162 from '@plugins/indonesian/indowebnovel'; +import p_163 from '@plugins/indonesian/MeioNovel[madara]'; +import p_164 from '@plugins/indonesian/MTLNovel(ID)[mtlnovel]'; +import p_165 from '@plugins/indonesian/NovelBookID[madara]'; +import p_166 from '@plugins/indonesian/sakuranovel'; +import p_167 from '@plugins/indonesian/SekteNovel[lightnovelwp]'; +import p_168 from '@plugins/indonesian/Vanovel[madara]'; +import p_169 from '@plugins/indonesian/WBNovel[madara]'; +import p_170 from '@plugins/japanese/kakuyomu'; +import p_171 from '@plugins/japanese/Syosetu'; +import p_172 from '@plugins/korean/Agitoon'; +import p_173 from '@plugins/korean/FortuneEternal[madara]'; +import p_174 from '@plugins/multi/komga'; +import p_175 from '@plugins/polish/novelki'; +import p_176 from '@plugins/portuguese/BetterNovels[lightnovelwp]'; +import p_177 from '@plugins/portuguese/blogdoamonnovels'; +import p_178 from '@plugins/portuguese/CentralNovel[lightnovelwp]'; +import p_179 from '@plugins/portuguese/illusia'; +import p_180 from '@plugins/portuguese/Kiniga[madara]'; +import p_181 from '@plugins/portuguese/LaNovels[hotnovelpub]'; +import p_182 from '@plugins/portuguese/LightNovelBrasil[lightnovelwp]'; +import p_183 from '@plugins/portuguese/MTLNovel(PT)[mtlnovel]'; +import p_184 from '@plugins/portuguese/novelmania'; +import p_185 from '@plugins/portuguese/tsundoku'; +import p_186 from '@plugins/russian/authortoday'; +import p_187 from '@plugins/russian/Bllate[rulate]'; +import p_188 from '@plugins/russian/Bookhamster[ifreedom]'; +import p_189 from '@plugins/russian/bookriver'; +import p_190 from '@plugins/russian/Erolate[rulate]'; +import p_191 from '@plugins/russian/EzNovels[hotnovelpub]'; +import p_192 from '@plugins/russian/ficbook'; +import p_193 from '@plugins/russian/jaomix'; +import p_194 from '@plugins/russian/MTLNovel(RU)[mtlnovel]'; +import p_195 from '@plugins/russian/neobook'; +import p_196 from '@plugins/russian/NovelCool(RU)[novelcool]'; +import p_197 from '@plugins/russian/novelTL'; +import p_198 from '@plugins/russian/ranobehub'; +import p_199 from '@plugins/russian/ranobelib'; +import p_200 from '@plugins/russian/ranoberf'; +import p_201 from '@plugins/russian/Ranobes(RU)[ranobes]'; +import p_202 from '@plugins/russian/renovels'; +import p_203 from '@plugins/russian/Rulate[rulate]'; +import p_204 from '@plugins/russian/topliba'; +import p_205 from '@plugins/russian/zelluloza'; +import p_206 from '@plugins/russian/СвободныйМирРанобэ[ifreedom]'; +import p_207 from '@plugins/spanish/AllNovelRead[lightnovelwp]'; +import p_208 from '@plugins/spanish/AnimesHoy12[madara]'; +import p_209 from '@plugins/spanish/hasutl'; +import p_210 from '@plugins/spanish/LightNovelDaily[hotnovelpub]'; +import p_211 from '@plugins/spanish/MTLNovel(ES)[mtlnovel]'; +import p_212 from '@plugins/spanish/NOVA'; +import p_213 from '@plugins/spanish/novelasligera'; +import p_214 from '@plugins/spanish/novelawuxia'; +import p_215 from '@plugins/spanish/novelyra'; +import p_216 from '@plugins/spanish/oasistranslations'; +import p_217 from '@plugins/spanish/PanchoTranslations[madara]'; +import p_218 from '@plugins/spanish/skynovels'; +import p_219 from '@plugins/spanish/TC&Sega[lightnovelwp]'; +import p_220 from '@plugins/spanish/TraduccionesAmistosas[madara]'; +import p_221 from '@plugins/spanish/tunovelaligera'; +import p_222 from '@plugins/spanish/yukitls'; +import p_223 from '@plugins/thai/NovelLucky[madara]'; +import p_224 from '@plugins/thai/NovelPDF[madara]'; +import p_225 from '@plugins/turkish/ArazNovel[madara]'; +import p_226 from '@plugins/turkish/EKTAPLAR[madara]'; +import p_227 from '@plugins/turkish/epiknovel'; +import p_228 from '@plugins/turkish/kakikata[madara]'; +import p_229 from '@plugins/turkish/KodeksLibrary[lightnovelwp]'; +import p_230 from '@plugins/turkish/MangaTR'; +import p_231 from '@plugins/turkish/NABSCANS[madara]'; +import p_232 from '@plugins/turkish/Namevt[lightnovelwp]'; +import p_233 from '@plugins/turkish/Noveloku[madara]'; +import p_234 from '@plugins/turkish/NovelTR[lightnovelwp]'; +import p_235 from '@plugins/turkish/RagnarScans[madara]'; +import p_236 from '@plugins/turkish/ThNovels[hotnovelpub]'; +import p_237 from '@plugins/turkish/TurkceLightNovels[madara]'; +import p_238 from '@plugins/turkish/WebNovelOku[madara]'; +import p_239 from '@plugins/ukrainian/bakainua'; +import p_240 from '@plugins/ukrainian/smakolykytl'; +import p_241 from '@plugins/vietnamese/lightnovelvn'; +import p_242 from '@plugins/vietnamese/LNHako'; +import p_243 from '@plugins/vietnamese/nettruyen'; const PLUGINS: Plugin.PluginBase[] = [ p_0, @@ -469,5 +479,15 @@ const PLUGINS: Plugin.PluginBase[] = [ p_231, p_232, p_233, + p_234, + p_235, + p_236, + p_237, + p_238, + p_239, + p_240, + p_241, + p_242, + p_243, ]; export default PLUGINS; From 4f55da08bf9a003763e4472f04cdb463ffbac18f Mon Sep 17 00:00:00 2001 From: JhoendryB Date: Tue, 7 Apr 2026 03:47:50 -0400 Subject: [PATCH 3/6] [ES]Novelyra: refactor popular Novels and improve paragraph logic --- plugins/spanish/novelyra.ts | 136 +++++++++++++++++++++++------------- 1 file changed, 88 insertions(+), 48 deletions(-) diff --git a/plugins/spanish/novelyra.ts b/plugins/spanish/novelyra.ts index 2770f4272..dad78764d 100644 --- a/plugins/spanish/novelyra.ts +++ b/plugins/spanish/novelyra.ts @@ -98,14 +98,15 @@ class Novelyra implements Plugin.PluginBase { id = 'novelyra'; name = 'Novelyra'; icon = 'src/es/novelyra/icon.png'; - site = 'https://novelyra.com'; + site = 'https://novelyra.com/'; version = '1.0.0'; - filters?: Filters | undefined = { + filters: Filters = { genres: { type: FilterTypes.Picker, label: 'Generos', value: '', options: [ + { label: 'Todos', value: '' }, { label: 'Acción', value: 'accion' }, { label: 'Aventura', value: 'aventura' }, { label: 'Fantasía', value: 'fantasia' }, @@ -133,11 +134,36 @@ class Novelyra implements Plugin.PluginBase { { label: 'Juegos', value: 'juegos' }, ], }, + browse: { + type: FilterTypes.Picker, + label: 'Novelas Populares', + value: 'browse.php', + options: [ + { label: 'Todas las Novelas', value: 'browse.php' }, + { label: '🔥 Hoy', value: 'popular.php?period=today' }, + { label: '📅 Este Mes', value: 'popular.php?period=month' }, + { label: '👑 De Siempre', value: 'popular.php?period=alltime' }, + ], + }, } satisfies Filters; - imageRequestInit?: Plugin.ImageRequestInit | undefined = undefined; - //flag indicates whether access to LocalStorage, SesesionStorage is required. - webStorageUtilized?: boolean; + private loadNovels( + loadedCheerio: any, + typeNovel: string, + ): Plugin.NovelItem[] { + const novels: Plugin.NovelItem[] = []; + + loadedCheerio(typeNovel).each((_: number, ele: any) => { + const novel = loadedCheerio(ele); + novels.push({ + name: novel.find('h3').text(), + path: novel.find('a').attr('href')?.replace(this.site, '') || '', + cover: novel.find('img').attr('src') || defaultCover, + }); + }); + + return novels; + } async popularNovels( pageNo: number, @@ -147,38 +173,32 @@ class Novelyra implements Plugin.PluginBase { }: Plugin.PopularNovelsOptions, ): Promise { let url = this.site; - - const isFilters = filters?.genres.value != ''; - - if (isFilters) { - url = `${this.site}/browse.php?genre=${filters?.genres.value}&page=${pageNo}`; + let typeNovel = '#novelas .novel-card'; + const genre = filters.genres?.value as string; + const browse = filters.browse?.value as string; + if (!showLatestNovels) { + if (browse.startsWith('popular.php')) { + url = `${this.site}${browse}`; + typeNovel = '.popular-item'; + } else { + const params = new URLSearchParams(); + params.append('page', String(pageNo)); + if (genre) { + params.append('genre', genre); + } + url = `${this.site}${browse}?${params.toString()}`; + typeNovel = '.novels-grid .novel-card'; + } } const result = await fetchApi(url); const body = await result.text(); - const loadedCheerio = loadCheerio(body); - const novels: Plugin.NovelItem[] = []; - const typeNovel = isFilters - ? '.novels-grid .novel-card' - : showLatestNovels - ? '#novelas .novel-card' - : '.section-gray .novel-card'; - - loadedCheerio(typeNovel).each((idx, ele) => { - const novel = loadedCheerio(ele); - novels.push({ - name: novel.find('h3').text(), - path: novel.find('a').attr('href') || '', - cover: novel.find('img').attr('src') || defaultCover, - }); - }); - - return novels; + return this.loadNovels(loadedCheerio, typeNovel); } async parseNovel(novelPath: string): Promise { - const result = await fetchApi(novelPath); + const result = await fetchApi(this.site + novelPath); const body = await result.text(); const loadedCheerio = loadCheerio(body); @@ -193,7 +213,7 @@ class Novelyra implements Plugin.PluginBase { .text() .trim() .replace('\n', ', '); - console.log(novel.genres); + novel.status = NovelStatus.Completed; novel.summary = loadedCheerio('.novel-description-detail').text().trim(); @@ -206,7 +226,7 @@ class Novelyra implements Plugin.PluginBase { const chapterNumber = numberMatch ? parseInt(numberMatch[1]) : 0; const chapter: Plugin.ChapterItem = { name: cptr.find('.chapter-title').text(), - path: cptr.find('a').attr('href') || '', + path: cptr.find('a').attr('href')?.replace(this.site, '') || '', releaseTime: parseSpanishTextToISO(cptr.find('.chapter-date').text()), chapterNumber: chapterNumber, }; @@ -227,10 +247,10 @@ class Novelyra implements Plugin.PluginBase { 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8', ); myHeaders.set('Accept-Language', 'es-ES,es;q=0.9'); - myHeaders.set('Referer', 'https://novelyra.com/'); + myHeaders.set('Referer', this.site); myHeaders.set('Cache-Control', 'no-cache'); - const result = await fetchApi(chapterPath, { + const result = await fetchApi(this.site + chapterPath, { method: 'GET', headers: myHeaders, }); @@ -246,9 +266,38 @@ class Novelyra implements Plugin.PluginBase { // Quita tags de adsense si los hay loadedCheerio('ins').remove(); - const chapterText = loadedCheerio('.chapter-content').html(); - - return chapterText?.replace(/\n/g, '
') || ''; + const chapterText = loadedCheerio('.chapter-content'); + let paragraph: string[] = []; + const chapterHtml: string[] = []; + const tagsPermisive: string[] = ['b', 'i', 'u', 'strong', 'em', 'span']; + + chapterText.contents().each((_, element) => { + switch (element.type) { + case 'text': + if (element.data.trim()) { + paragraph.push(element.data.trim()); + } + break; + case 'tag': + const originalTag = element.tagName; + if (tagsPermisive.includes(originalTag)) { + paragraph.push(loadedCheerio.html(element)); + } else { + if (paragraph.length > 0) { + chapterHtml.push(`

${paragraph.join(' ').trim()}

`); + paragraph = []; + if (originalTag === 'br') break; + } + chapterHtml.push(loadedCheerio.html(element)); + } + break; + } + }); + // Close any remaining paragraph + if (paragraph.length > 0) { + chapterHtml.push(`

${paragraph.join(' ').trim()}

`); + } + return chapterHtml.join(''); } async searchNovels( searchTerm: string, @@ -256,25 +305,16 @@ class Novelyra implements Plugin.PluginBase { ): Promise { searchTerm = searchTerm.toLowerCase(); - const url = `${this.site}/?search=${searchTerm}`; + const url = `${this.site}?search=${encodeURIComponent(searchTerm)}`; const result = await fetchApi(url); const body = await result.text(); const loadedCheerio = loadCheerio(body); - const novels: Plugin.NovelItem[] = []; - - loadedCheerio('#novelas .novel-card').each((idx, ele) => { - const novel = loadedCheerio(ele); - novels.push({ - name: novel.find('h3').text(), - path: novel.find('a').attr('href') || '', - cover: novel.find('img').attr('src') || defaultCover, - }); - }); + const typeNovel = '#novelas .novel-card'; - return novels; + return this.loadNovels(loadedCheerio, typeNovel); } } From 98bf2a6961daf4cfba6f6ddf3982e2252e8f6114 Mon Sep 17 00:00:00 2001 From: JhoendryB Date: Tue, 7 Apr 2026 10:12:37 -0400 Subject: [PATCH 4/6] [ES]Novelyra: fix changed of type --- plugins/spanish/novelyra.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/spanish/novelyra.ts b/plugins/spanish/novelyra.ts index dad78764d..66b321220 100644 --- a/plugins/spanish/novelyra.ts +++ b/plugins/spanish/novelyra.ts @@ -1,7 +1,7 @@ import { fetchApi } from '@libs/fetch'; import { Plugin } from '@/types/plugin'; import { FilterTypes, Filters } from '@libs/filterInputs'; -import { load as loadCheerio } from 'cheerio'; +import { CheerioAPI, load as loadCheerio } from 'cheerio'; import { defaultCover } from '@libs/defaultCover'; import { NovelStatus } from '@libs/novelStatus'; @@ -148,12 +148,12 @@ class Novelyra implements Plugin.PluginBase { } satisfies Filters; private loadNovels( - loadedCheerio: any, + loadedCheerio: CheerioAPI, typeNovel: string, ): Plugin.NovelItem[] { const novels: Plugin.NovelItem[] = []; - loadedCheerio(typeNovel).each((_: number, ele: any) => { + loadedCheerio(typeNovel).each((_, ele) => { const novel = loadedCheerio(ele); novels.push({ name: novel.find('h3').text(), From e249894cedb88dfb427424e4ad6d8e046e9d13d1 Mon Sep 17 00:00:00 2001 From: JhoendryB Date: Mon, 20 Apr 2026 22:11:10 -0400 Subject: [PATCH 5/6] SkyNovels[ES] feat: add filters, pagination and resolve fix search --- plugins/spanish/skynovels.ts | 99 ++++++++++++++++++++++++++++++------ 1 file changed, 84 insertions(+), 15 deletions(-) diff --git a/plugins/spanish/skynovels.ts b/plugins/spanish/skynovels.ts index ca1dfaa46..944738b02 100644 --- a/plugins/spanish/skynovels.ts +++ b/plugins/spanish/skynovels.ts @@ -1,5 +1,6 @@ import { fetchApi } from '@libs/fetch'; import { Plugin } from '@/types/plugin'; +import { FilterTypes, Filters } from '@libs/filterInputs'; class SkyNovels implements Plugin.PluginBase { id = 'skynovels'; @@ -8,11 +9,68 @@ class SkyNovels implements Plugin.PluginBase { apiSite = 'https://api.skynovels.net/api/'; version = '1.0.1'; icon = 'src/es/skynovels/icon.png'; - - async popularNovels(): Promise { - const url = this.apiSite + 'novels?&q'; - - const result = await fetchApi(url); + filters: Filters | undefined = { + genres: { + type: FilterTypes.CheckboxGroup, + label: 'Generos', + value: [], + options: [ + { label: 'Acción', value: '9' }, + { label: 'Adulto', value: '38' }, + { label: 'Artes marciales', value: '3' }, + { label: 'Aventura', value: '2' }, + { label: 'BL', value: '40' }, + { label: 'Comedia', value: '7' }, + { label: 'Cosas de la vida', value: '26' }, + { label: 'Cultivación', value: '19' }, + { label: 'Drama', value: '8' }, + { label: 'Ecchi', value: '21' }, + { label: 'Fantasia', value: '4' }, + { label: 'Gender Bender', value: '10' }, + { label: 'GL', value: '41' }, + { label: 'Harem', value: '12' }, + { label: 'Histórico', value: '32' }, + { label: 'Horror', value: '39' }, + { label: 'LitRPG', value: '31' }, + { label: 'Maduro', value: '1' }, + { label: 'Magia', value: '16' }, + { label: 'Misterio', value: '22' }, + { label: 'Mundo Moderno', value: '34' }, + { label: 'Psicológico', value: '27' }, + { label: 'Recuentos de la vida', value: '36' }, + { label: 'Reencarnación', value: '23' }, + { label: 'Romance', value: '5' }, + { label: 'Sci-Fi', value: '17' }, + { label: 'Seinen', value: '18' }, + { label: 'Shoujo', value: '33' }, + { label: 'Shounen', value: '13' }, + { label: 'Sobrenatural', value: '20' }, + { label: 'Supervivencia', value: '25' }, + { label: 'Suspenso', value: '35' }, + { label: 'Tragedia', value: '14' }, + { label: 'Transmigración', value: '24' }, + { label: 'Vida Escolar', value: '29' }, + { label: 'Xianxia', value: '6' }, + { label: 'Xuanhuan', value: '11' }, + { label: 'Yaoi', value: '30' }, + { label: 'Sin género indicado', value: '37' }, + ], + }, + } satisfies Filters; + + async popularNovels( + pageNo: number, + { filters }: Plugin.PopularNovelsOptions, + ): Promise { + const genres = (filters?.genres?.value as string[]) || []; + const order = genres.length > 0 ? 'updated' : 'rating'; + const url = `${this.apiSite}novels?page=${pageNo}&order=${order}&genres=${genres.join(',')}`; + + const result = await fetchApi(url, { + headers: { + 'Cache-Control': 'no-cache', + }, + }); const body = (await result.json()) as response; const novels: Plugin.NovelItem[] = []; @@ -31,7 +89,11 @@ class SkyNovels implements Plugin.PluginBase { const novelId = novelPath.split('/')[1]; const url = this.apiSite + 'novel/' + novelId + '/reading?&q'; - const result = await fetchApi(url); + const result = await fetchApi(url, { + headers: { + 'Cache-Control': 'no-cache', + }, + }); const body = (await result.json()) as responseBook; const item = body?.novel?.[0]; @@ -74,7 +136,11 @@ class SkyNovels implements Plugin.PluginBase { const chapterId: string = chapterPath.split('/')[3]; const url = `${this.apiSite}novel-chapter/${chapterId}`; - const result = await fetchApi(url); + const result = await fetchApi(url, { + headers: { + 'Cache-Control': 'no-cache', + }, + }); const body = (await result.json()) as responseChapter; const item = body?.chapter?.[0]; @@ -84,20 +150,23 @@ class SkyNovels implements Plugin.PluginBase { return chapterText.replace(/\n/g, '
'); } - async searchNovels(searchTerm: string): Promise { + async searchNovels( + searchTerm: string, + pageNo: number, + ): Promise { searchTerm = searchTerm.toLowerCase(); - const url = this.apiSite + 'novels?&q'; + const url = `${this.apiSite}novels?page=${pageNo}&q=${searchTerm}`; - const result = await fetchApi(url); + const result = await fetchApi(url, { + headers: { + 'Cache-Control': 'no-cache', + }, + }); const body = (await result.json()) as response; - const results = body?.novels?.filter(novel => - novel.nvl_title.toLowerCase().includes(searchTerm), - ); - const novels: Plugin.NovelItem[] = []; - results?.forEach(res => { + body?.novels?.forEach(res => { const name = res.nvl_title; const cover = this.apiSite + 'get-image/' + res.image + '/novels/false'; const path = 'novelas/' + res.id + '/' + res.nvl_name + '/'; From 2484aa57a589008302307b716d93a3235712b3e5 Mon Sep 17 00:00:00 2001 From: JhoendryB Date: Mon, 20 Apr 2026 22:24:50 -0400 Subject: [PATCH 6/6] SkyNovels[ES] Fix: changed version --- plugins/spanish/skynovels.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/spanish/skynovels.ts b/plugins/spanish/skynovels.ts index 944738b02..69462cdae 100644 --- a/plugins/spanish/skynovels.ts +++ b/plugins/spanish/skynovels.ts @@ -7,7 +7,7 @@ class SkyNovels implements Plugin.PluginBase { name = 'SkyNovels'; site = 'https://www.skynovels.net/'; apiSite = 'https://api.skynovels.net/api/'; - version = '1.0.1'; + version = '1.1.0'; icon = 'src/es/skynovels/icon.png'; filters: Filters | undefined = { genres: {