From 70675987e959427061f4a9960a5f3eb4b7ccf863 Mon Sep 17 00:00:00 2001 From: xMohnad Date: Tue, 17 Jun 2025 00:11:23 +0300 Subject: [PATCH] feat(ar/kolnovel): add initial source integration for KolNovel --- javascript/novel/src/ar/kolnovel.js | 94 +++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 javascript/novel/src/ar/kolnovel.js diff --git a/javascript/novel/src/ar/kolnovel.js b/javascript/novel/src/ar/kolnovel.js new file mode 100644 index 00000000..0e0b6e9b --- /dev/null +++ b/javascript/novel/src/ar/kolnovel.js @@ -0,0 +1,94 @@ +// prettier-ignore +const mangayomiSources = [{ + "name": "ملوك الروايات", + "lang": "ar", + "baseUrl": "https://kolnovel.com", + "apiUrl": "", + "iconUrl": "https://www.google.com/s2/favicons?sz=256&domain=https://kolnovel.com", + "typeSource": "single", + "itemType": 2, + "version": "0.0.1", + "pkgPath": "novel/src/ar/kolnovel.js", + "notes": "" +}]; + +class DefaultExtension extends MProvider { + headers = { + Referer: this.source.baseUrl, + Origin: this.source.baseUrl, + "Sec-Fetch-Mode": "cors", + "Accept-Encoding": "gzip, deflate", + "User-Agent": + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36", + }; + + getHeaders(url) { + throw new Error("getHeaders not implemented"); + } + + cleanTitle(title) { + title = title.replace(/[-@%&]*\b(?:kol|كول)\b[-@%&]*/gi, ""); + title = title.replace(/[-@%&]+/g, " "); + title = title.replace(/\s+/g, " ").trim(); + return title; + } + + novelFromElement(res) { + const doc = new Document(res.body); + const elements = doc.select("div.listupd article"); + const list = []; + for (const el of elements) { + const name = this.cleanTitle(el.selectFirst("h2 a").text); + const imageUrl = el.selectFirst("img").getSrc; + const link = el.selectFirst("h2 a").getHref; + list.push({ name, imageUrl, link }); + } + const hasNextPage = doc.selectFirst("div.hpage > a.r").text == "Next "; + return { list, hasNextPage }; + } + + async getPopular(page) { + const res = await new Client().get( + `${this.source.baseUrl}/series/?page=${page}&order=popular`, + this.headers, + ); + return this.novelFromElement(res); + } + + async getLatestUpdates(page) { + const res = await new Client().get( + `${this.source.baseUrl}/series/?page=${page}&order=update`, + this.headers, + ); + return this.novelFromElement(res); + } + + async search(query, page, filters) { + throw new Error("search not implemented"); + } + async getDetail(url) { + throw new Error("getDetail not implemented"); + } + // For novel html content + async getHtmlContent(name, url) { + throw new Error("getHtmlContent not implemented"); + } + // Clean html up for reader + async cleanHtmlContent(html) { + throw new Error("cleanHtmlContent not implemented"); + } + // For anime episode video list + async getVideoList(url) { + throw new Error("getVideoList not implemented"); + } + // For manga chapter pages + async getPageList(url) { + throw new Error("getPageList not implemented"); + } + getFilterList() { + throw new Error("getFilterList not implemented"); + } + getSourcePreferences() { + throw new Error("getSourcePreferences not implemented"); + } +}