From 441d9fc439cdf41d6a00dda3582868eb86f4f770 Mon Sep 17 00:00:00 2001 From: nothing Date: Sun, 22 Mar 2026 22:18:44 +0700 Subject: [PATCH 1/3] Add LightNovelWorldOrg Parser --- plugin/js/parsers/LightNovelWorldOrgParser.js | 80 +++++++++++++++++++ plugin/popup.html | 1 + 2 files changed, 81 insertions(+) create mode 100644 plugin/js/parsers/LightNovelWorldOrgParser.js diff --git a/plugin/js/parsers/LightNovelWorldOrgParser.js b/plugin/js/parsers/LightNovelWorldOrgParser.js new file mode 100644 index 00000000..c330ff4e --- /dev/null +++ b/plugin/js/parsers/LightNovelWorldOrgParser.js @@ -0,0 +1,80 @@ +"use strict"; + +// Use one or more of these to specify when the parser is to be used + +parserFactory.register("lightnovelworld.org", () => new LightNovelWorldOrgParser()); + +class LightNovelWorldOrgParser extends Parser { + constructor() { + super(); + } + + // eslint-disable-next-line no-unused-vars + async getChapterUrls(dom, chapterUrlsUI) { + return await this.getChapterUrlsFromApi(); + } + + async getChapterUrlsFromApi() { + const baseUrl = "https://lightnovelworld.org/api/novel/shadow-slave/chapters/"; + const limit = 500; // max limit (more than 500 just defaults to 500) + let offset = 0; + let allChapters = []; + let hasMore = true; + + while (hasMore) { + const apiUrl = `${baseUrl}?offset=${offset}&limit=${limit}`; + const response = await HttpClient.fetchJson(apiUrl); + const data = response.json; + + if (data.chapters) { + const chapters = data.chapters.map(chapter => ({ + sourceUrl: `https://lightnovelworld.org/novel/shadow-slave/chapter/${chapter.number}/`, + title: chapter.title + })); + allChapters.push(...chapters); + } + + hasMore = data.has_more; + offset += limit; + } + + return allChapters; + } + + findContent(dom) { + return dom.querySelector(".chapter-content"); + } + + extractTitleImpl(dom) { + return dom.querySelector(".novel-title"); + } + + + extractAuthor(dom) { + let authorLabel = dom.querySelector(".novel-author"); + let authorText = authorLabel?.textContent?.trim() ?? super.extractAuthor(dom); + // Remove "Author: " prefix if present + return authorText.replace(/^Author:\s*/i, ""); + } + + extractLanguage(dom) { + return dom.querySelector("html").getAttribute("lang"); + } + + extractSubject(dom) { + let tags = [...dom.querySelectorAll(".genre-tags")]; + return tags.map(e => e.textContent.trim()).join(", "); + } + + extractDescription(dom) { + return dom.querySelector(".summary-content").textContent.trim(); + } + + findChapterTitle(dom) { + return dom.querySelector(".chapter-title"); + } + + findCoverImageUrl(dom) { + return util.getFirstImgSrc(dom, ".novel-cover-container"); + } +} diff --git a/plugin/popup.html b/plugin/popup.html index 726a0337..8dab1465 100644 --- a/plugin/popup.html +++ b/plugin/popup.html @@ -743,6 +743,7 @@

Instructions

+ From 70a383f975ca868fc322ad10d4e62286370f5c65 Mon Sep 17 00:00:00 2001 From: nothing Date: Sun, 22 Mar 2026 22:33:02 +0700 Subject: [PATCH 2/3] fix parser --- plugin/js/parsers/LightNovelWorldOrgParser.js | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/plugin/js/parsers/LightNovelWorldOrgParser.js b/plugin/js/parsers/LightNovelWorldOrgParser.js index c330ff4e..2f5b89a2 100644 --- a/plugin/js/parsers/LightNovelWorldOrgParser.js +++ b/plugin/js/parsers/LightNovelWorldOrgParser.js @@ -11,11 +11,17 @@ class LightNovelWorldOrgParser extends Parser { // eslint-disable-next-line no-unused-vars async getChapterUrls(dom, chapterUrlsUI) { - return await this.getChapterUrlsFromApi(); + const url = dom.baseURI; + const match = url.match(/\/novel\/([^\/]+)/); + if (!match) { + throw new Error("Could not extract novel name from URL"); + } + const novelName = match[1]; + return await this.getChapterUrlsFromApi(novelName); } - async getChapterUrlsFromApi() { - const baseUrl = "https://lightnovelworld.org/api/novel/shadow-slave/chapters/"; + async getChapterUrlsFromApi(novelName) { + const baseUrl = `https://lightnovelworld.org/api/novel/${novelName}/chapters/`; const limit = 500; // max limit (more than 500 just defaults to 500) let offset = 0; let allChapters = []; @@ -28,7 +34,7 @@ class LightNovelWorldOrgParser extends Parser { if (data.chapters) { const chapters = data.chapters.map(chapter => ({ - sourceUrl: `https://lightnovelworld.org/novel/shadow-slave/chapter/${chapter.number}/`, + sourceUrl: `https://lightnovelworld.org/novel/${novelName}/chapter/${chapter.number}/`, title: chapter.title })); allChapters.push(...chapters); From 5d509a58bdb9a0943fa50f71b4bdb409137746a2 Mon Sep 17 00:00:00 2001 From: nothing Date: Sun, 22 Mar 2026 22:36:58 +0700 Subject: [PATCH 3/3] fix parser (again) --- plugin/js/parsers/LightNovelWorldOrgParser.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/js/parsers/LightNovelWorldOrgParser.js b/plugin/js/parsers/LightNovelWorldOrgParser.js index 2f5b89a2..0dacebb6 100644 --- a/plugin/js/parsers/LightNovelWorldOrgParser.js +++ b/plugin/js/parsers/LightNovelWorldOrgParser.js @@ -12,7 +12,7 @@ class LightNovelWorldOrgParser extends Parser { // eslint-disable-next-line no-unused-vars async getChapterUrls(dom, chapterUrlsUI) { const url = dom.baseURI; - const match = url.match(/\/novel\/([^\/]+)/); + const match = url.match(new RegExp("/novel/([^/]+)")); if (!match) { throw new Error("Could not extract novel name from URL"); }