diff --git a/javascript/novel/src/en/novelupdates.js b/javascript/novel/src/en/novelupdates.js index e83591c6..cca98911 100644 --- a/javascript/novel/src/en/novelupdates.js +++ b/javascript/novel/src/en/novelupdates.js @@ -7,7 +7,7 @@ const mangayomiSources = [{ "https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/main/javascript/icon/en.novelupdates.png", "typeSource": "single", "itemType": 2, - "version": "0.0.2", + "version": "0.0.3", "dateFormat": "", "dateFormatLocale": "", "pkgPath": "novel/src/en/novelupdates.js", @@ -188,8 +188,13 @@ class DefaultExtension extends MProvider { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36", }); - const doc = new Document(res.body); - const domain = res.body; + return await this.cleanHtmlContent(res.body); + } + + async cleanHtmlContent(html) { + const client = await new Client(); + const doc = new Document(html); + const domain = html; if (domain.includes("anotivereads")) { const title = @@ -424,50 +429,49 @@ class DefaultExtension extends MProvider { return e?.toLowerCase().includes("wordpress") || e?.toLowerCase().includes("site kit by google") }); - let title = - doc.selectFirst(".entry-title")?.text.trim() || - doc.selectFirst(".entry-title-main")?.text.trim() || - doc.selectFirst(".chapter__title")?.text.trim() || - doc.selectFirst(".sp-title")?.text.trim() || - doc.selectFirst(".title-content")?.text.trim() || - doc.selectFirst(".wp-block-post-title")?.text.trim() || - doc.selectFirst(".title_story")?.text.trim() || - doc.selectFirst(".active")?.text.trim() || - doc.selectFirst("head title")?.text.trim() || - doc.selectFirst("h1.leading-none ~ h2")?.text.trim() || - ""; - const subtitle = - doc.selectFirst(".cat-series")?.text.trim() || - doc.selectFirst("h1.leading-none ~ span")?.text.trim() || - ""; - if (subtitle && subtitle != "") { - title = subtitle; - } - const content = - doc.selectFirst(".rdminimal")?.innerHtml || - doc.selectFirst(".entry-content")?.innerHtml || - doc.selectFirst(".chapter__content")?.innerHtml || - doc.selectFirst(".prevent-select")?.innerHtml || - doc.selectFirst(".text_story")?.innerHtml || - doc.selectFirst(".contenta")?.innerHtml || - doc.selectFirst(".single_post")?.innerHtml || - doc.selectFirst(".post-entry")?.innerHtml || - doc.selectFirst(".main-content")?.innerHtml || - doc.selectFirst(".post-content")?.innerHtml || - doc.selectFirst(".content")?.innerHtml || - doc.selectFirst(".page-body")?.innerHtml || - doc.selectFirst(".td-page-content")?.innerHtml || - doc.selectFirst(".reader-content")?.innerHtml || - doc.selectFirst("#content")?.innerHtml || - doc.selectFirst("#the-content")?.innerHtml || - doc.selectFirst("article.post")?.innerHtml; - - if (isWordpress || domain.includes("etherreads") || domain.includes("soafp")) { - return `

${title}



${content}`; + doc.selectFirst(".entry-title")?.text.trim() || + doc.selectFirst(".entry-title-main")?.text.trim() || + doc.selectFirst(".chapter__title")?.text.trim() || + doc.selectFirst(".sp-title")?.text.trim() || + doc.selectFirst(".title-content")?.text.trim() || + doc.selectFirst(".wp-block-post-title")?.text.trim() || + doc.selectFirst(".title_story")?.text.trim() || + doc.selectFirst(".active")?.text.trim() || + doc.selectFirst("head title")?.text.trim() || + doc.selectFirst("h1.leading-none ~ h2")?.text.trim() || + ""; + const subtitle = + doc.selectFirst(".cat-series")?.text.trim() || + doc.selectFirst("h1.leading-none ~ span")?.text.trim() || + ""; + if (subtitle && subtitle != "") { + title = subtitle; } + const content = + doc.selectFirst(".rdminimal")?.innerHtml || + doc.selectFirst(".entry-content")?.innerHtml || + doc.selectFirst(".chapter__content")?.innerHtml || + doc.selectFirst(".prevent-select")?.innerHtml || + doc.selectFirst(".text_story")?.innerHtml || + doc.selectFirst(".contenta")?.innerHtml || + doc.selectFirst(".single_post")?.innerHtml || + doc.selectFirst(".post-entry")?.innerHtml || + doc.selectFirst(".main-content")?.innerHtml || + doc.selectFirst(".post-content")?.innerHtml || + doc.selectFirst(".content")?.innerHtml || + doc.selectFirst(".page-body")?.innerHtml || + doc.selectFirst(".td-page-content")?.innerHtml || + doc.selectFirst(".reader-content")?.innerHtml || + doc.selectFirst("#content")?.innerHtml || + doc.selectFirst("#the-content")?.innerHtml || + doc.selectFirst("article.post")?.innerHtml; - return `

Domain not supported yet. Content might not load properly!

+ if (isWordpress || domain.includes("etherreads") || domain.includes("soafp")) { + return `

${title}



${content}`; + } + + return `

Domain not supported yet. Content might not load properly!


${title}



${content}`; } diff --git a/javascript/novel/src/en/wordrain69.js b/javascript/novel/src/en/wordrain69.js index 80f2a996..7180abe9 100644 --- a/javascript/novel/src/en/wordrain69.js +++ b/javascript/novel/src/en/wordrain69.js @@ -1,156 +1,160 @@ const mangayomiSources = [{ - "name": "Wordrain69", - "lang": "en", - "baseUrl": "https://wordrain69.com", - "apiUrl": "", - "iconUrl": - "https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/main/javascript/icon/en.wordrain69.png", - "typeSource": "single", - "itemType": 2, - "version": "0.0.1", - "dateFormat": "", - "dateFormatLocale": "", - "pkgPath": "novel/src/en/wordrain69.js", - "appMinVerReq": "0.4.0", - "isNsfw": false, - "hasCloudflare": false - }]; - - class DefaultExtension extends MProvider { - getHeaders(url) { - throw new Error("getHeaders not implemented"); - } - - mangaListFromPage(res) { - const doc = new Document(res.body); - const mangaElements = doc.select("div.page-item-detail"); - const list = []; - for (const element of mangaElements) { - const name = element.selectFirst(".item-thumb > a").attr("title"); - const link = element.selectFirst(".item-thumb > a").getHref; - const imageUrl = element.selectFirst("img").getSrc; - list.push({ name, imageUrl, link }); - } - const hasNextPage = - doc.selectFirst("nav > div.nav-links > a").text?.includes("Posts") ?? false; - return { list: list, hasNextPage }; - } - - toStatus(status) { - if (status.includes("OnGoing")) return 0; - else if (status.includes("Completed")) return 1; - else if (status.includes("Hiatus")) return 2; - else if (status.includes("Dropped")) return 3; - else return 5; - } - - async getPopular(page) { - const res = await new Client().get( - `${this.source.baseUrl}/manga-genre/novel/page/${page}/?m_orderby=trending`, - ); - return this.mangaListFromPage(res); - } - - async getLatestUpdates(page) { - const res = await new Client().get( - `${this.source.baseUrl}/manga-genre/novel/page/${page}/?m_orderby=latest`, - ); - return this.mangaListFromPage(res); - } - - async search(query, page, filters) { - let url = `${this.source.baseUrl}/?s=${query}`; - const res = await new Client().get(url); - return this.mangaListFromPage(res); - } - - async getDetail(url) { - const client = new Client(); - const res = await client.get(url); - const doc = new Document(res.body); - const imageUrl = doc.selectFirst("div.summary_image > a > img")?.getSrc; - const description = doc.select("div.summary__content > p > span").map((el) => el.text).join(" "); - const author = doc.selectFirst("div.author-content > a")?.text.trim(); - const artist = doc.selectFirst("div.artist-content > a")?.text.trim(); - const status = this.toStatus(doc.selectFirst("div.post-status > div.post-content_item > div.summary-content")?.text.trim()); - const tags = doc.select("div.summary-content > div.tags-content > a").map((el) => el.text.trim()); - let genre = doc.select("div.summary-content > div.genres-content > a").map((el) => el.text.trim()); - if (tags.length != 0) { - genre.push(tags); - } + "name": "Wordrain69", + "lang": "en", + "baseUrl": "https://wordrain69.com", + "apiUrl": "", + "iconUrl": + "https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/main/javascript/icon/en.wordrain69.png", + "typeSource": "single", + "itemType": 2, + "version": "0.0.2", + "dateFormat": "", + "dateFormatLocale": "", + "pkgPath": "novel/src/en/wordrain69.js", + "appMinVerReq": "0.4.0", + "isNsfw": false, + "hasCloudflare": false +}]; - const chapters = []; - const chapterRes = await client.post(`${url}ajax/chapters/`, { - Priority: "u=0, i", - "Origin": this.source.baseUrl, - "Referer": url, - }); - const chapterDoc = new Document(chapterRes.body); - - const chapterElements = chapterDoc.select("li.free-chap"); - for (const el of chapterElements) { - let chapterName = el.selectFirst("a")?.text.trim(); - const chapterUrl = el.selectFirst("a").getHref; - let dateUpload; - try { - dateUpload = this.parseDate(el.selectFirst("span.chapter-release-date > i")?.text.trim()); - } catch (_) { - dateUpload = null; - } - chapters.push({ - name: chapterName, - url: chapterUrl, - dateUpload: dateUpload, - scanlator: null, - }); - } - - chapters.reverse(); - - return { - imageUrl, - description, - genre, - author, - artist, - status, - chapters, - }; - } - - async getHtmlContent(url) { - const client = await new Client(); - const res = await client.get(url); - const doc = new Document(res.body); - const title = - doc.selectFirst("#chapter-heading")?.text.trim() || - ""; - const content = doc.selectFirst(".entry-content")?.innerHtml; - return `

${title}



${content}`; - } - - getFilterList() { - return []; - } - - getSourcePreferences() { - throw new Error("getSourcePreferences not implemented"); - } - - parseDate(date) { - const months = { - "January": "01", "February": "02", "March": "03", "April": "04", "May": "05", "June": "06", - "July": "07", "August": "08", "September": "09", "October": "10", "November": "11", "December": "12" - }; - date = date.toLowerCase().replace(",", "").split(" "); - - if (!(date[0] in months)) { - return String(new Date().valueOf()) - } - - date[0] = months[date[0]]; - date = [date[2], date[0], date[1]]; - date = date.join("-"); - return String(new Date(date).valueOf()); - } +class DefaultExtension extends MProvider { + getHeaders(url) { + throw new Error("getHeaders not implemented"); } + + mangaListFromPage(res) { + const doc = new Document(res.body); + const mangaElements = doc.select("div.page-item-detail"); + const list = []; + for (const element of mangaElements) { + const name = element.selectFirst(".item-thumb > a").attr("title"); + const link = element.selectFirst(".item-thumb > a").getHref; + const imageUrl = element.selectFirst("img").getSrc; + list.push({ name, imageUrl, link }); + } + const hasNextPage = + doc.selectFirst("nav > div.nav-links > a").text?.includes("Posts") ?? false; + return { list: list, hasNextPage }; + } + + toStatus(status) { + if (status.includes("OnGoing")) return 0; + else if (status.includes("Completed")) return 1; + else if (status.includes("Hiatus")) return 2; + else if (status.includes("Dropped")) return 3; + else return 5; + } + + async getPopular(page) { + const res = await new Client().get( + `${this.source.baseUrl}/manga-genre/novel/page/${page}/?m_orderby=trending`, + ); + return this.mangaListFromPage(res); + } + + async getLatestUpdates(page) { + const res = await new Client().get( + `${this.source.baseUrl}/manga-genre/novel/page/${page}/?m_orderby=latest`, + ); + return this.mangaListFromPage(res); + } + + async search(query, page, filters) { + let url = `${this.source.baseUrl}/?s=${query}`; + const res = await new Client().get(url); + return this.mangaListFromPage(res); + } + + async getDetail(url) { + const client = new Client(); + const res = await client.get(url); + const doc = new Document(res.body); + const imageUrl = doc.selectFirst("div.summary_image > a > img")?.getSrc; + const description = doc.select("div.summary__content > p > span").map((el) => el.text).join(" "); + const author = doc.selectFirst("div.author-content > a")?.text.trim(); + const artist = doc.selectFirst("div.artist-content > a")?.text.trim(); + const status = this.toStatus(doc.selectFirst("div.post-status > div.post-content_item > div.summary-content")?.text.trim()); + const tags = doc.select("div.summary-content > div.tags-content > a").map((el) => el.text.trim()); + let genre = doc.select("div.summary-content > div.genres-content > a").map((el) => el.text.trim()); + if (tags.length != 0) { + genre.push(tags); + } + + const chapters = []; + const chapterRes = await client.post(`${url}ajax/chapters/`, { + Priority: "u=0, i", + "Origin": this.source.baseUrl, + "Referer": url, + }); + const chapterDoc = new Document(chapterRes.body); + + const chapterElements = chapterDoc.select("li.free-chap"); + for (const el of chapterElements) { + let chapterName = el.selectFirst("a")?.text.trim(); + const chapterUrl = el.selectFirst("a").getHref; + let dateUpload; + try { + dateUpload = this.parseDate(el.selectFirst("span.chapter-release-date > i")?.text.trim()); + } catch (_) { + dateUpload = null; + } + chapters.push({ + name: chapterName, + url: chapterUrl, + dateUpload: dateUpload, + scanlator: null, + }); + } + + chapters.reverse(); + + return { + imageUrl, + description, + genre, + author, + artist, + status, + chapters, + }; + } + + async getHtmlContent(url) { + const client = await new Client(); + const res = await client.get(url); + return await this.cleanHtmlContent(res.body); + } + + async cleanHtmlContent(html) { + const doc = new Document(html); + const title = + doc.selectFirst("#chapter-heading")?.text.trim() || + ""; + const content = doc.selectFirst(".entry-content")?.innerHtml; + return `

${title}



${content}`; + } + + getFilterList() { + return []; + } + + getSourcePreferences() { + throw new Error("getSourcePreferences not implemented"); + } + + parseDate(date) { + const months = { + "January": "01", "February": "02", "March": "03", "April": "04", "May": "05", "June": "06", + "July": "07", "August": "08", "September": "09", "October": "10", "November": "11", "December": "12" + }; + date = date.toLowerCase().replace(",", "").split(" "); + + if (!(date[0] in months)) { + return String(new Date().valueOf()) + } + + date[0] = months[date[0]]; + date = [date[2], date[0], date[1]]; + date = date.join("-"); + return String(new Date(date).valueOf()); + } +} \ No newline at end of file diff --git a/wip/wuxiaclick.js b/wip/wuxiaclick.js new file mode 100644 index 00000000..59ab3e28 --- /dev/null +++ b/wip/wuxiaclick.js @@ -0,0 +1,150 @@ +const mangayomiSources = [{ + "name": "WuxiaClick", + "lang": "en", + "baseUrl": "https://wuxia.click", + "apiUrl": "", + "iconUrl": + "https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/main/javascript/icon/en.wuxiaclick.png", + "typeSource": "single", + "itemType": 2, + "version": "0.0.1", + "dateFormat": "", + "dateFormatLocale": "", + "pkgPath": "novel/src/en/wuxiaclick.js", + "appMinVerReq": "0.4.0", + "isNsfw": false, + "hasCloudflare": false + }]; + + class DefaultExtension extends MProvider { + getHeaders(url) { + throw new Error("getHeaders not implemented"); + } + + mangaListFromPage(res) { + const doc = new Document(res.body); + const mangaElements = doc.select("div.mantine-grid-root > div.mantine-grid-col > div"); + const list = []; + for (const element of mangaElements) { + const name = element.selectFirst("a > div > div > div.mantine-Text-root")?.text.trim(); + const link = this.source.baseUrl + element.selectFirst("a").getHref; + const imageUrl = element.selectFirst("img").getSrc; + list.push({ name, imageUrl, link }); + } + const pagination = doc.select("button.mantine-y4zem1 > svg > path").map((el) => el.attr("d")); + const hasNextPage = pagination.length > 1 ? pagination[1].startsWith("M8") : false; + return { list: list, hasNextPage }; + } + + toStatus(status) { + if (status.includes("Ongoing")) return 0; + else if (status.includes("Completed")) return 1; + else if (status.includes("Hiatus")) return 2; + else if (status.includes("Dropped")) return 3; + else return 5; + } + + async getPopular(page) { + const res = await new Client().get( + `${this.source.baseUrl}/advance_search?order=-weekly_views&page=${page}`, + ); + return this.mangaListFromPage(res); + } + + async getLatestUpdates(page) { + const res = await new Client().get( + `${this.source.baseUrl}/advance_search?order=-created_at&page=${page}`, + ); + return this.mangaListFromPage(res); + } + + async search(query, page, filters) { + let url = `${this.source.baseUrl}/advance_search?order=&page=${page}&search=${encodeURI(query)}`; + const res = await new Client().get(url); + return this.mangaListFromPage(res); + } + + async getDetail(url) { + const client = new Client(); + const res = await client.get(url); + const doc = new Document(res.body); + const imageUrl = doc.selectFirst("figure > div > img")?.getSrc; + const description = doc.select("div.mantine-Spoiler-root > div > div > div.mantine-Text-root")?.text.trim(); + const author = doc.selectFirst("div.mantine-lqk3v2 > div")?.text.trim(); + const status = this.toStatus(doc.selectFirst("div.mantine-1uxmzbt > div.mantine-1huvzos")?.text.trim()); + const genre = doc.select("div.mantine-bl3g33 > div > a > div > div > span").map((el) => el.text.trim()); + + const chapterElements = doc.select("div.mantine-1x5ubwi > div"); + for (const el of chapterElements) { + let chapterName = el.selectFirst("div.mantine-Group-root > div > a > div > h4")?.text.trim(); + if (!chapterName) { + continue; + } + const chapterUrl = this.source.baseUrl + el.selectFirst("div.mantine-Group-root > div > a").getHref; + let dateUpload; + try { + dateUpload = this.parseDate(el.selectFirst("div > a > div > div > div.mantine-Text-root")?.text.trim()); + } catch (_) { + dateUpload = null; + } + chapters.push({ + name: chapterName, + url: chapterUrl, + dateUpload: dateUpload, + scanlator: null, + }); + } + + chapters.reverse(); + + return { + imageUrl, + description, + genre, + author, + artist, + status, + chapters, + }; + } + + async getHtmlContent(url) { + const client = await new Client(); + const res = await client.get(url); + return await this.cleanHtmlContent(res.body); + } + + async cleanHtmlContent(html) { + const doc = new Document(html); + const title = + doc.selectFirst("div.mantine-Center-root > h1.mantine-Title-root")?.text.trim() || + ""; + const content = doc.select("div.mantine-Container-root > div.mantine-Paper-root > div")[2]?.innerHtml; + return `

${title}



${content}`; + } + + getFilterList() { + return []; + } + + getSourcePreferences() { + throw new Error("getSourcePreferences not implemented"); + } + + parseDate(date) { + const months = { + "January": "01", "February": "02", "March": "03", "April": "04", "May": "05", "June": "06", + "July": "07", "August": "08", "September": "09", "October": "10", "November": "11", "December": "12" + }; + date = date.toLowerCase().replace(",", "").split(" "); + + if (!(date[0] in months)) { + return String(new Date().valueOf()) + } + + date[0] = months[date[0]]; + date = [date[2], date[0], date[1]]; + date = date.join("-"); + return String(new Date(date).valueOf()); + } + }