diff --git a/plugins/english/lnori.ts b/plugins/english/lnori.ts new file mode 100644 index 000000000..a3b459d80 --- /dev/null +++ b/plugins/english/lnori.ts @@ -0,0 +1,360 @@ +import { fetchText } from '@libs/fetch'; +import { Plugin } from '@/types/plugin'; +import { Filters, FilterTypes } from '@libs/filterInputs'; +import { load as parseHTML } from 'cheerio'; +import { defaultCover } from '@libs/defaultCover'; + +class LnorisPlugin implements Plugin.PluginBase { + id = 'lnori'; + name = 'LNORI'; + icon = 'src/en/lnori/icon.png'; + site = 'https://lnori.com/'; + version = '1.0.0'; + + async popularNovels( + pageNo: number, + { filters }: Plugin.PopularNovelsOptions, + ): Promise { + const url = this.site + 'library'; + const body = await fetchText(url); + const $ = parseHTML(body); + + const parsedList: { + novel: Plugin.NovelItem; + author: string; + tags: string[]; + }[] = []; + + $('article.card').each((i, el) => { + const name = $(el).attr('data-t') || ''; + const author = $(el).attr('data-a') || ''; + const tagsAttr = $(el).attr('data-tags') || ''; + const tags = tagsAttr.split(',').map(t => t.trim().toLowerCase()); + + const coverImg = $(el).find('.card-cover img').first(); + let cover = coverImg.attr('src') || ''; + if (cover && cover.startsWith('/')) { + cover = this.site + cover.substring(1); + } + + const link = $(el).find('a.stretched-link').first(); + let path = link.attr('href') || ''; + if (path.startsWith('/')) { + path = path.substring(1); + } + + if (path && name) { + parsedList.push({ + novel: { + name, + path, + cover: cover || defaultCover, + }, + author, + tags, + }); + } + }); + + let filteredList = parsedList; + const selectedGenre = filters?.genre?.value; + if (selectedGenre) { + filteredList = filteredList.filter(item => + item.tags.includes(selectedGenre.toLowerCase()), + ); + } + + const selectedSort = filters?.sort?.value; + if (selectedSort === 'title-az') { + filteredList.sort((a, b) => a.novel.name.localeCompare(b.novel.name)); + } else if (selectedSort === 'title-za') { + filteredList.sort((a, b) => b.novel.name.localeCompare(a.novel.name)); + } + + const pageSize = 36; + const offset = (pageNo - 1) * pageSize; + return filteredList + .slice(offset, offset + pageSize) + .map(item => item.novel); + } + + async parseNovel(novelPath: string): Promise { + const url = this.site + novelPath; + const body = await fetchText(url); + const $ = parseHTML(body); + + const novel: Plugin.SourceNovel = { + path: novelPath, + name: $('.hero-card h1.s-title').text().trim() || 'Untitled', + }; + + const coverUrl = $('.hero-card .cover-wrap img').attr('src'); + if (coverUrl) { + novel.cover = coverUrl.startsWith('/') + ? this.site + coverUrl.substring(1) + : coverUrl; + } else { + novel.cover = defaultCover; + } + + const dataTagsAttr = $('nav.tags-box.desktop').attr('data-tags'); + if (dataTagsAttr) { + try { + const parsedTags = JSON.parse(dataTagsAttr); + novel.genres = parsedTags + .map((t: { name: string }) => t.name) + .join(', '); + } catch (e) { + // Fallback + } + } + + if (!novel.genres) { + const genres: string[] = []; + $('nav.tags-box.desktop a, nav.tags-box a').each((i, el) => { + const text = $(el).text().trim(); + if (text) genres.push(text); + }); + novel.genres = genres.join(', '); + } + + const summaryParagraphs: string[] = []; + $('section.desc-box p.description').each((i, el) => { + const text = $(el).text().trim(); + if (text) summaryParagraphs.push(text); + }); + novel.summary = summaryParagraphs.join('\n\n'); + + novel.author = $('.hero-card p.author').text().trim(); + + // Map unique volume URLs + const volumeMap: Record = {}; + $('a[href^="/book/"]').each((i, el) => { + const href = $(el).attr('href'); + const text = $(el).text().trim().replace(/\s+/g, ' '); + if (href) { + if ( + !volumeMap[href] || + (text && text.length > volumeMap[href].length) + ) { + volumeMap[href] = text; + } + } + }); + + const getVolumeName = (href: string, text: string) => { + let cleanText = text.replace(/Start Reading/gi, '').trim(); + if (!cleanText) { + const parts = href.split('/'); + const slug = parts[parts.length - 1] || parts[parts.length - 2] || ''; + cleanText = slug + .split('-') + .map(word => word.charAt(0).toUpperCase() + word.slice(1)) + .join(' '); + } + return cleanText; + }; + + const volumeUrls = Object.keys(volumeMap); + const volumePromises = volumeUrls.map(async volUrl => { + const fullVolUrl = this.site.replace(/\/$/, '') + volUrl; + const volHtml = await fetchText(fullVolUrl); + const $vol = parseHTML(volHtml); + + const tocMap: Record = {}; + $vol('nav.toc-view a[href^="#"], nav#toc-list a[href^="#"]').each( + (i, el) => { + const href = $vol(el).attr('href'); + const text = $vol(el).text().trim().replace(/\s+/g, ' '); + if (href && text) { + tocMap[href.substring(1)] = text; + } + }, + ); + + const volChapters: Plugin.ChapterItem[] = []; + $vol('section.chapter').each((i, el) => { + const id = $vol(el).attr('id'); + if (id) { + const tocTitle = tocMap[id]; + const h2Title = $vol(el) + .find('h2.chapter-title, h2, h3') + .first() + .text() + .trim(); + const chapterName = + tocTitle || h2Title || `Page ${id.replace(/\D/g, '')}`; + + if (!tocTitle && !h2Title) return; + + const volTitle = getVolumeName(volUrl, volumeMap[volUrl]); + let path = volUrl; + if (path.startsWith('/')) { + path = path.substring(1); + } + path = path + '#' + id; + + volChapters.push({ + name: `${volTitle} - ${chapterName}`, + path, + }); + } + }); + return volChapters; + }); + + const chapters2D = await Promise.all(volumePromises); + const chapters = chapters2D.flat(); + + novel.chapters = chapters.map((chap, idx) => ({ + ...chap, + chapterNumber: idx + 1, + })); + + return novel; + } + + async parseChapter(chapterPath: string): Promise { + const [pathWithoutAnchor, anchor] = chapterPath.split('#'); + const url = this.site.replace(/\/$/, '') + '/' + pathWithoutAnchor; + + const body = await fetchText(url); + const $ = parseHTML(body); + + const chapterSelector = anchor ? `section#${anchor}` : 'section.chapter'; + const section = $(chapterSelector); + + if (!section.length) { + throw new Error(`Chapter section not found: ${chapterPath}`); + } + + const mainContent = section.find('.main').length + ? section.find('.main').clone() + : section.clone(); + + mainContent.find('h2, h3, .chapter-title').remove(); + + mainContent.find('img').each((i, el) => { + const src = $(el).attr('src'); + if (src && src.startsWith('/')) { + $(el).attr('src', this.site.replace(/\/$/, '') + src); + } + }); + + mainContent.find('source').each((i, el) => { + const srcset = $(el).attr('srcset'); + if (srcset && srcset.startsWith('/')) { + $(el).attr('srcset', this.site.replace(/\/$/, '') + srcset); + } + }); + + return mainContent.html() || ''; + } + + async searchNovels( + searchTerm: string, + pageNo: number, + ): Promise { + const url = this.site + 'library'; + const body = await fetchText(url); + const $ = parseHTML(body); + + const parsedList: { + novel: Plugin.NovelItem; + author: string; + tags: string[]; + }[] = []; + + $('article.card').each((i, el) => { + const name = $(el).attr('data-t') || ''; + const author = $(el).attr('data-a') || ''; + const tagsAttr = $(el).attr('data-tags') || ''; + const tags = tagsAttr.split(',').map(t => t.trim().toLowerCase()); + + const coverImg = $(el).find('.card-cover img').first(); + let cover = coverImg.attr('src') || ''; + if (cover && cover.startsWith('/')) { + cover = this.site + cover.substring(1); + } + + const link = $(el).find('a.stretched-link').first(); + let path = link.attr('href') || ''; + if (path.startsWith('/')) { + path = path.substring(1); + } + + if (path && name) { + parsedList.push({ + novel: { + name, + path, + cover: cover || defaultCover, + }, + author, + tags, + }); + } + }); + + const term = searchTerm.toLowerCase(); + const filteredList = parsedList.filter(item => { + return ( + item.novel.name.toLowerCase().includes(term) || + item.author.toLowerCase().includes(term) || + item.tags.some(t => t.includes(term)) + ); + }); + + const pageSize = 36; + const offset = (pageNo - 1) * pageSize; + return filteredList + .slice(offset, offset + pageSize) + .map(item => item.novel); + } + + resolveUrl = (path: string, _isNovel?: boolean) => { + return new URL(path, this.site).href; + }; + + filters = { + sort: { + label: 'Sort By', + value: 'popular', + options: [ + { label: 'Popular (Default)', value: 'popular' }, + { label: 'Title A-Z', value: 'title-az' }, + { label: 'Title Z-A', value: 'title-za' }, + ], + type: FilterTypes.Picker, + }, + genre: { + label: 'Genre', + value: '', + options: [ + { label: 'All', value: '' }, + { label: 'Academy', value: 'academy' }, + { label: 'Action', value: 'action' }, + { label: 'Adventure', value: 'adventure' }, + { label: 'Comedy', value: 'comedy' }, + { label: 'Drama', value: 'drama' }, + { label: 'Fantasy', value: 'fantasy' }, + { label: 'Harem', value: 'harem' }, + { label: 'Historical', value: 'historical' }, + { label: 'Isekai', value: 'isekai' }, + { label: 'Magic', value: 'magic' }, + { label: 'Mystery', value: 'mystery' }, + { label: 'Psychological', value: 'psychological' }, + { label: 'Reincarnation', value: 'reincarnation' }, + { label: 'Romance', value: 'romance' }, + { label: 'Sci-Fi', value: 'sci-fi' }, + { label: 'Slice of Life', value: 'slice-of-life' }, + { label: 'Tragedy', value: 'tragedy' }, + { label: 'Female Protagonist', value: 'female protagonist' }, + { label: 'Male Protagonist', value: 'male protagonist' }, + ], + type: FilterTypes.Picker, + }, + } satisfies Filters; +} + +export default new LnorisPlugin(); diff --git a/plugins/index.ts b/plugins/index.ts index 14af62d51..454b5f3bc 100644 --- a/plugins/index.ts +++ b/plugins/index.ts @@ -131,122 +131,123 @@ import p_128 from '@plugins/english/inoveltranslation'; import p_129 from '@plugins/english/leafstudio'; import p_130 from '@plugins/english/lightnoveltranslation'; import p_131 from '@plugins/english/lnmtl'; -import p_132 from '@plugins/english/mvlempyr'; -import p_133 from '@plugins/english/novelbuddy'; -import p_134 from '@plugins/english/novelfire'; -import p_135 from '@plugins/english/novelhall'; -import p_136 from '@plugins/english/novelhi'; -import p_137 from '@plugins/english/novelight'; -import p_138 from '@plugins/english/novelrest'; -import p_139 from '@plugins/english/novelupdates'; -import p_140 from '@plugins/english/pawread'; -import p_141 from '@plugins/english/rainofsnow'; -import p_142 from '@plugins/english/readfrom'; -import p_143 from '@plugins/english/relibrary'; -import p_144 from '@plugins/english/royalroad'; -import p_145 from '@plugins/english/scribblehub'; -import p_146 from '@plugins/english/vynovel'; -import p_147 from '@plugins/english/wct'; -import p_148 from '@plugins/english/webnovel'; -import p_149 from '@plugins/english/wtrlab'; -import p_150 from '@plugins/english/wuxiaworld'; -import p_151 from '@plugins/french/LighNovelFR[lightnovelwp]'; -import p_152 from '@plugins/french/MTLNovel(FR)[mtlnovel]'; -import p_153 from '@plugins/french/MassNovel[madara]'; -import p_154 from '@plugins/french/WorldNovel[madara]'; -import p_155 from '@plugins/french/chireads'; -import p_156 from '@plugins/french/harkeneliwood'; -import p_157 from '@plugins/french/kisswood'; -import p_158 from '@plugins/french/noveldeglace'; -import p_159 from '@plugins/french/novelfrance'; -import p_160 from '@plugins/french/novhell'; -import p_161 from '@plugins/french/warriorlegendtrad'; -import p_162 from '@plugins/french/wuxialnscantrad'; -import p_163 from '@plugins/french/xiaowaz'; -import p_164 from '@plugins/indonesian/BacaLightNovel[lightnovelwp]'; -import p_165 from '@plugins/indonesian/MTLNovel(ID)[mtlnovel]'; -import p_166 from '@plugins/indonesian/MeioNovel[madara]'; -import p_167 from '@plugins/indonesian/NovelBookID[madara]'; -import p_168 from '@plugins/indonesian/SekteNovel[lightnovelwp]'; -import p_169 from '@plugins/indonesian/Vanovel[madara]'; -import p_170 from '@plugins/indonesian/WBNovel[madara]'; -import p_171 from '@plugins/indonesian/indowebnovel'; -import p_172 from '@plugins/indonesian/sakuranovel'; -import p_173 from '@plugins/japanese/Syosetu'; -import p_174 from '@plugins/japanese/kakuyomu'; -import p_175 from '@plugins/korean/Agitoon'; -import p_176 from '@plugins/korean/FortuneEternal[madara]'; -import p_177 from '@plugins/multi/komga'; -import p_178 from '@plugins/polish/novelki'; -import p_179 from '@plugins/portuguese/BetterNovels[lightnovelwp]'; -import p_180 from '@plugins/portuguese/CentralNovel[lightnovelwp]'; -import p_181 from '@plugins/portuguese/Kiniga[madara]'; -import p_182 from '@plugins/portuguese/LaNovels[hotnovelpub]'; -import p_183 from '@plugins/portuguese/LightNovelBrasil[lightnovelwp]'; -import p_184 from '@plugins/portuguese/MTLNovel(PT)[mtlnovel]'; -import p_185 from '@plugins/portuguese/blogdoamonnovels'; -import p_186 from '@plugins/portuguese/illusia'; -import p_187 from '@plugins/portuguese/novelmania'; -import p_188 from '@plugins/portuguese/tsundoku'; -import p_189 from '@plugins/russian/Bllate[rulate]'; -import p_190 from '@plugins/russian/Bookhamster[ifreedom]'; -import p_191 from '@plugins/russian/Erolate[rulate]'; -import p_192 from '@plugins/russian/EzNovels[hotnovelpub]'; -import p_193 from '@plugins/russian/MTLNovel(RU)[mtlnovel]'; -import p_194 from '@plugins/russian/NovelCool(RU)[novelcool]'; -import p_195 from '@plugins/russian/Ranobes(RU)[ranobes]'; -import p_196 from '@plugins/russian/Rulate[rulate]'; -import p_197 from '@plugins/russian/authortoday'; -import p_198 from '@plugins/russian/bookriver'; -import p_199 from '@plugins/russian/ficbook'; -import p_200 from '@plugins/russian/jaomix'; -import p_201 from '@plugins/russian/neobook'; -import p_202 from '@plugins/russian/novelTL'; -import p_203 from '@plugins/russian/ranobehub'; -import p_204 from '@plugins/russian/ranobelib'; -import p_205 from '@plugins/russian/ranoberf'; -import p_206 from '@plugins/russian/renovels'; -import p_207 from '@plugins/russian/topliba'; -import p_208 from '@plugins/russian/zelluloza'; -import p_209 from '@plugins/russian/СвободныйМирРанобэ[ifreedom]'; -import p_210 from '@plugins/spanish/AllNovelRead[lightnovelwp]'; -import p_211 from '@plugins/spanish/AnimesHoy12[madara]'; -import p_212 from '@plugins/spanish/LightNovelDaily[hotnovelpub]'; -import p_213 from '@plugins/spanish/MTLNovel(ES)[mtlnovel]'; -import p_214 from '@plugins/spanish/NOVA'; -import p_215 from '@plugins/spanish/PanchoTranslations[madara]'; -import p_216 from '@plugins/spanish/TC&Sega[lightnovelwp]'; -import p_217 from '@plugins/spanish/TraduccionesAmistosas[madara]'; -import p_218 from '@plugins/spanish/hasutl'; -import p_219 from '@plugins/spanish/novelasligera'; -import p_220 from '@plugins/spanish/novelawuxia'; -import p_221 from '@plugins/spanish/novelyra'; -import p_222 from '@plugins/spanish/oasistranslations'; -import p_223 from '@plugins/spanish/skynovels'; -import p_224 from '@plugins/spanish/tunovelaligera'; -import p_225 from '@plugins/spanish/yukitls'; -import p_226 from '@plugins/thai/NovelLucky[madara]'; -import p_227 from '@plugins/thai/NovelPDF[madara]'; -import p_228 from '@plugins/turkish/ArazNovel[madara]'; -import p_229 from '@plugins/turkish/EKTAPLAR[madara]'; -import p_230 from '@plugins/turkish/KodeksLibrary[lightnovelwp]'; -import p_231 from '@plugins/turkish/MangaTR'; -import p_232 from '@plugins/turkish/NABSCANS[madara]'; -import p_233 from '@plugins/turkish/Namevt[lightnovelwp]'; -import p_234 from '@plugins/turkish/NovelTR[lightnovelwp]'; -import p_235 from '@plugins/turkish/Noveloku[madara]'; -import p_236 from '@plugins/turkish/RagnarScans[madara]'; -import p_237 from '@plugins/turkish/ThNovels[hotnovelpub]'; -import p_238 from '@plugins/turkish/TurkceLightNovels[madara]'; -import p_239 from '@plugins/turkish/WebNovelOku[madara]'; -import p_240 from '@plugins/turkish/epiknovel'; -import p_241 from '@plugins/turkish/kakikata[madara]'; -import p_242 from '@plugins/ukrainian/bakainua'; -import p_243 from '@plugins/ukrainian/smakolykytl'; -import p_244 from '@plugins/vietnamese/LNHako'; -import p_245 from '@plugins/vietnamese/lightnovelvn'; -import p_246 from '@plugins/vietnamese/nettruyen'; -import p_247 from '@plugins/vietnamese/truyenss'; +import p_132 from '@plugins/english/lnori'; +import p_133 from '@plugins/english/mvlempyr'; +import p_134 from '@plugins/english/novelbuddy'; +import p_135 from '@plugins/english/novelfire'; +import p_136 from '@plugins/english/novelhall'; +import p_137 from '@plugins/english/novelhi'; +import p_138 from '@plugins/english/novelight'; +import p_139 from '@plugins/english/novelrest'; +import p_140 from '@plugins/english/novelupdates'; +import p_141 from '@plugins/english/pawread'; +import p_142 from '@plugins/english/rainofsnow'; +import p_143 from '@plugins/english/readfrom'; +import p_144 from '@plugins/english/relibrary'; +import p_145 from '@plugins/english/royalroad'; +import p_146 from '@plugins/english/scribblehub'; +import p_147 from '@plugins/english/vynovel'; +import p_148 from '@plugins/english/wct'; +import p_149 from '@plugins/english/webnovel'; +import p_150 from '@plugins/english/wtrlab'; +import p_151 from '@plugins/english/wuxiaworld'; +import p_152 from '@plugins/french/LighNovelFR[lightnovelwp]'; +import p_153 from '@plugins/french/MTLNovel(FR)[mtlnovel]'; +import p_154 from '@plugins/french/MassNovel[madara]'; +import p_155 from '@plugins/french/WorldNovel[madara]'; +import p_156 from '@plugins/french/chireads'; +import p_157 from '@plugins/french/harkeneliwood'; +import p_158 from '@plugins/french/kisswood'; +import p_159 from '@plugins/french/noveldeglace'; +import p_160 from '@plugins/french/novelfrance'; +import p_161 from '@plugins/french/novhell'; +import p_162 from '@plugins/french/warriorlegendtrad'; +import p_163 from '@plugins/french/wuxialnscantrad'; +import p_164 from '@plugins/french/xiaowaz'; +import p_165 from '@plugins/indonesian/BacaLightNovel[lightnovelwp]'; +import p_166 from '@plugins/indonesian/MTLNovel(ID)[mtlnovel]'; +import p_167 from '@plugins/indonesian/MeioNovel[madara]'; +import p_168 from '@plugins/indonesian/NovelBookID[madara]'; +import p_169 from '@plugins/indonesian/SekteNovel[lightnovelwp]'; +import p_170 from '@plugins/indonesian/Vanovel[madara]'; +import p_171 from '@plugins/indonesian/WBNovel[madara]'; +import p_172 from '@plugins/indonesian/indowebnovel'; +import p_173 from '@plugins/indonesian/sakuranovel'; +import p_174 from '@plugins/japanese/Syosetu'; +import p_175 from '@plugins/japanese/kakuyomu'; +import p_176 from '@plugins/korean/Agitoon'; +import p_177 from '@plugins/korean/FortuneEternal[madara]'; +import p_178 from '@plugins/multi/komga'; +import p_179 from '@plugins/polish/novelki'; +import p_180 from '@plugins/portuguese/BetterNovels[lightnovelwp]'; +import p_181 from '@plugins/portuguese/CentralNovel[lightnovelwp]'; +import p_182 from '@plugins/portuguese/Kiniga[madara]'; +import p_183 from '@plugins/portuguese/LaNovels[hotnovelpub]'; +import p_184 from '@plugins/portuguese/LightNovelBrasil[lightnovelwp]'; +import p_185 from '@plugins/portuguese/MTLNovel(PT)[mtlnovel]'; +import p_186 from '@plugins/portuguese/blogdoamonnovels'; +import p_187 from '@plugins/portuguese/illusia'; +import p_188 from '@plugins/portuguese/novelmania'; +import p_189 from '@plugins/portuguese/tsundoku'; +import p_190 from '@plugins/russian/Bllate[rulate]'; +import p_191 from '@plugins/russian/Bookhamster[ifreedom]'; +import p_192 from '@plugins/russian/Erolate[rulate]'; +import p_193 from '@plugins/russian/EzNovels[hotnovelpub]'; +import p_194 from '@plugins/russian/MTLNovel(RU)[mtlnovel]'; +import p_195 from '@plugins/russian/NovelCool(RU)[novelcool]'; +import p_196 from '@plugins/russian/Ranobes(RU)[ranobes]'; +import p_197 from '@plugins/russian/Rulate[rulate]'; +import p_198 from '@plugins/russian/authortoday'; +import p_199 from '@plugins/russian/bookriver'; +import p_200 from '@plugins/russian/ficbook'; +import p_201 from '@plugins/russian/jaomix'; +import p_202 from '@plugins/russian/neobook'; +import p_203 from '@plugins/russian/novelTL'; +import p_204 from '@plugins/russian/ranobehub'; +import p_205 from '@plugins/russian/ranobelib'; +import p_206 from '@plugins/russian/ranoberf'; +import p_207 from '@plugins/russian/renovels'; +import p_208 from '@plugins/russian/topliba'; +import p_209 from '@plugins/russian/zelluloza'; +import p_210 from '@plugins/russian/СвободныйМирРанобэ[ifreedom]'; +import p_211 from '@plugins/spanish/AllNovelRead[lightnovelwp]'; +import p_212 from '@plugins/spanish/AnimesHoy12[madara]'; +import p_213 from '@plugins/spanish/LightNovelDaily[hotnovelpub]'; +import p_214 from '@plugins/spanish/MTLNovel(ES)[mtlnovel]'; +import p_215 from '@plugins/spanish/NOVA'; +import p_216 from '@plugins/spanish/PanchoTranslations[madara]'; +import p_217 from '@plugins/spanish/TC&Sega[lightnovelwp]'; +import p_218 from '@plugins/spanish/TraduccionesAmistosas[madara]'; +import p_219 from '@plugins/spanish/hasutl'; +import p_220 from '@plugins/spanish/novelasligera'; +import p_221 from '@plugins/spanish/novelawuxia'; +import p_222 from '@plugins/spanish/novelyra'; +import p_223 from '@plugins/spanish/oasistranslations'; +import p_224 from '@plugins/spanish/skynovels'; +import p_225 from '@plugins/spanish/tunovelaligera'; +import p_226 from '@plugins/spanish/yukitls'; +import p_227 from '@plugins/thai/NovelLucky[madara]'; +import p_228 from '@plugins/thai/NovelPDF[madara]'; +import p_229 from '@plugins/turkish/ArazNovel[madara]'; +import p_230 from '@plugins/turkish/EKTAPLAR[madara]'; +import p_231 from '@plugins/turkish/KodeksLibrary[lightnovelwp]'; +import p_232 from '@plugins/turkish/MangaTR'; +import p_233 from '@plugins/turkish/NABSCANS[madara]'; +import p_234 from '@plugins/turkish/Namevt[lightnovelwp]'; +import p_235 from '@plugins/turkish/NovelTR[lightnovelwp]'; +import p_236 from '@plugins/turkish/Noveloku[madara]'; +import p_237 from '@plugins/turkish/RagnarScans[madara]'; +import p_238 from '@plugins/turkish/ThNovels[hotnovelpub]'; +import p_239 from '@plugins/turkish/TurkceLightNovels[madara]'; +import p_240 from '@plugins/turkish/WebNovelOku[madara]'; +import p_241 from '@plugins/turkish/epiknovel'; +import p_242 from '@plugins/turkish/kakikata[madara]'; +import p_243 from '@plugins/ukrainian/bakainua'; +import p_244 from '@plugins/ukrainian/smakolykytl'; +import p_245 from '@plugins/vietnamese/LNHako'; +import p_246 from '@plugins/vietnamese/lightnovelvn'; +import p_247 from '@plugins/vietnamese/nettruyen'; +import p_248 from '@plugins/vietnamese/truyenss'; const PLUGINS: Plugin.PluginBase[] = [ p_0, @@ -497,5 +498,6 @@ const PLUGINS: Plugin.PluginBase[] = [ p_245, p_246, p_247, + p_248, ]; export default PLUGINS; diff --git a/public/static/src/en/lnori/icon.png b/public/static/src/en/lnori/icon.png new file mode 100644 index 000000000..01c2b70d6 Binary files /dev/null and b/public/static/src/en/lnori/icon.png differ