Refactor Webtoons: format code, simplify logic with mangaFromElement

This commit is contained in:
xMohnad
2025-06-15 03:13:40 +03:00
parent de2c69d2d3
commit b2ad2a2051

View File

@@ -1,3 +1,4 @@
// prettier-ignore
const mangayomiSources = [{ const mangayomiSources = [{
"name": "Webtoons", "name": "Webtoons",
"langs": ["en", "fr", "id", "th", "es", "zh", "de"], "langs": ["en", "fr", "id", "th", "es", "zh", "de"],
@@ -15,12 +16,13 @@ const mangayomiSources = [{
class DefaultExtension extends MProvider { class DefaultExtension extends MProvider {
headers = { headers = {
"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" "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",
}; };
getHeaders(url) { getHeaders(url) {
return { return {
Referer: this.source.baseUrl Referer: this.source.baseUrl,
} };
} }
async getItem(url, selector) { async getItem(url, selector) {
@@ -44,70 +46,52 @@ class DefaultExtension extends MProvider {
name: name, name: name,
imageUrl: imageUrl, imageUrl: imageUrl,
link: link, link: link,
genre: genre genre: genre,
}); });
} }
return mangas; return mangas;
} }
mangaFromElement(doc) {
const list = [];
for (const el of doc.select(`div.webtoon_list_wrap li a`)) {
const imageUrl = el.selectFirst("img").getSrc;
const name = el.selectFirst("strong.title").text;
const link = el.getHref;
list.push({ name, imageUrl, link });
}
return list;
}
async getPopular(page) { async getPopular(page) {
const baseUrl = this.source.baseUrl; const baseUrl = this.source.baseUrl;
const client = new Client(); const res = await new Client().get(
const res = await client.get(`${baseUrl}/${this.langCode()}/originals`); `${baseUrl}/${this.langCode()}/originals`,
);
const doc = new Document(res.body); const doc = new Document(res.body);
const days = ["MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY", "SATURDAY", "SUNDAY"];
let dayElements = [];
for (const day of days) {
const elements = doc.select(`div.daily_section._list_${day} li`);
dayElements.push(elements);
}
const maxElements = Math.max(...dayElements.map(elements => elements.length));
let list = [];
for (let i = 0; i < maxElements; i++) {
for (let j = 0; j < days.length; j++) {
const elements = dayElements[j];
if (i < elements.length) {
const element = elements[i];
const linkElement = element.selectFirst("a");
const imageElement = linkElement.selectFirst("img");
const imageUrl = imageElement.attr("src");
const name = element.selectFirst("p.subj").text;
const link = linkElement.attr("href");
list.push({ name, imageUrl, link });
}
}
}
const completed = doc.select("div.daily_lst.comp li");
for (const element of completed) {
const linkElement = element.selectFirst("a");
const imageElement = linkElement.selectFirst("img");
const imageUrl = imageElement.attr("src");
const name = element.selectFirst("p.subj").text;
const link = linkElement.attr("href");
list.push({ name, imageUrl, link });
}
return { return {
list: list, list: this.mangaFromElement(doc),
hasNextPage: false hasNextPage: false,
}; };
} }
async getLatestUpdates(page) { async getLatestUpdates(page) {
const Day = ['SUNDAY', 'MONDAY', 'TUESDAY', 'WEDNESDAY', 'THURSDAY', 'FRIDAY', 'SATURDAY']; const baseUrl = this.source.baseUrl;
const list = await this.getItem(`/${this.langCode()}/originals?sortOrder=UPDATE`, "div.daily_section._list_" + Day[new Date().getDay()] + " li"); const res = await new Client().get(
`${baseUrl}/${this.langCode()}/originals?sortOrder=UPDATE`,
);
const doc = new Document(res.body);
return { return {
list: list, list: this.mangaFromElement(doc),
hasNextPage: false hasNextPage: false,
}; };
} }
async search(query, page, filters) { async search(query, page, filters) {
let keyword = query.trim().replace(/\s+/g, '+'); let keyword = query.trim().replace(/\s+/g, "+");
let hasNextPage = true; let hasNextPage = true;
let type_originals = "WEBTOON"; let type_originals = "WEBTOON";
let type_canvas = "CHALLENGE"; let type_canvas = "CHALLENGE";
@@ -118,18 +102,30 @@ class DefaultExtension extends MProvider {
let list = []; let list = [];
if (query !== "") { if (query !== "") {
list_originals = await this.getItem(`/${this.langCode()}/search?keyword=${keyword}&searchType=` + type_originals + `&page=${page}`, fetch_originals); list_originals = await this.getItem(
list_canvas = await this.getItem(`/${this.langCode()}/search?keyword=${keyword}&searchType=` + type_canvas + `&page=${page}`, fetch_canvas); `/${this.langCode()}/search?keyword=${keyword}&searchType=` +
if (filters) { } type_originals +
`&page=${page}`,
fetch_originals,
);
list_canvas = await this.getItem(
`/${this.langCode()}/search?keyword=${keyword}&searchType=` +
type_canvas +
`&page=${page}`,
fetch_canvas,
);
if (filters) {
}
list = list_originals.concat(list_canvas); list = list_originals.concat(list_canvas);
} else { } else {
} }
if (list.length === 0) { hasNextPage = false; } if (list.length === 0) {
hasNextPage = false;
}
return { return {
list: list, list: list,
hasNextPage: hasNextPage hasNextPage: hasNextPage,
}; };
} }
@@ -137,10 +133,23 @@ class DefaultExtension extends MProvider {
const res = await new Client().get(url); const res = await new Client().get(url);
const doc = new Document(res.body); const doc = new Document(res.body);
const info = doc.selectFirst("div.cont_box"); const info = doc.selectFirst("div.cont_box");
const cover = info.selectFirst("div.detail_body")?.attr("style")?.match(/url\(['"]?(.*?)['"]?\)/)?.[1] ?? info.selectFirst("span.thmb img")?.attr("src"); const cover =
info
.selectFirst("div.detail_body")
?.attr("style")
?.match(/url\(['"]?(.*?)['"]?\)/)?.[1] ??
info.selectFirst("span.thmb img")?.attr("src");
const title = info.selectFirst("h1.subj, h3.subj").text.trim(); const title = info.selectFirst("h1.subj, h3.subj").text.trim();
const genre = Array.from(info.select("p.genre")).map(el => el.text) != '' ? Array.from(info.select("p.genre")).map(el => el.text) : [info.selectFirst("div.info h2").text]; const genre =
const author = info.selectFirst("div.author_area").text.replace(/\s+/g, ' ').replace(/author info/g, '').trim() ?? info.selectFirst("a.author").text; Array.from(info.select("p.genre")).map((el) => el.text) != ""
? Array.from(info.select("p.genre")).map((el) => el.text)
: [info.selectFirst("div.info h2").text];
const author =
info
.selectFirst("div.author_area")
.text.replace(/\s+/g, " ")
.replace(/author info/g, "")
.trim() ?? info.selectFirst("a.author").text;
const status_str = info.selectFirst("p.day_info").text; const status_str = info.selectFirst("p.day_info").text;
var status; var status;
if (status_str == "COMPLETED") { if (status_str == "COMPLETED") {
@@ -148,7 +157,7 @@ class DefaultExtension extends MProvider {
} else { } else {
status = 0; status = 0;
} }
const desc = info.selectFirst("p.summary").text.replace(/\s+/g, ' ').trim(); const desc = info.selectFirst("p.summary").text.replace(/\s+/g, " ").trim();
const chapters = []; const chapters = [];
let tester = ""; let tester = "";
let page = 1; let page = 1;
@@ -162,13 +171,15 @@ class DefaultExtension extends MProvider {
for (const element of elements) { for (const element of elements) {
tester = element.selectFirst("span.tx").text.trim(); tester = element.selectFirst("span.tx").text.trim();
const dateString = element.selectFirst("span.date").text.trim(); const dateString = element.selectFirst("span.date").text.trim();
const date = new Date(this.formatDateString(dateString, this.source.lang)); const date = new Date(
this.formatDateString(dateString, this.source.lang),
);
const millisecondsSinceEpoch = date.getTime(); const millisecondsSinceEpoch = date.getTime();
const millisecondsString = millisecondsSinceEpoch.toString(); const millisecondsString = millisecondsSinceEpoch.toString();
chapters.push({ chapters.push({
name: tester + " " + element.selectFirst("span.subj span").text, name: tester + " " + element.selectFirst("span.subj span").text,
url: element.selectFirst('a').attr("href"), url: element.selectFirst("a").attr("href"),
dateUpload: millisecondsString dateUpload: millisecondsString,
}); });
} }
page++; page++;
@@ -181,12 +192,10 @@ class DefaultExtension extends MProvider {
imageUrl: cover, imageUrl: cover,
author: author, author: author,
status: status, status: status,
episodes: chapters episodes: chapters,
}; };
} }
langCode() { langCode() {
return { return {
en: "en", en: "en",
@@ -195,20 +204,85 @@ class DefaultExtension extends MProvider {
th: "th", th: "th",
es: "es", es: "es",
zh: "zh-hant", zh: "zh-hant",
de: "de" de: "de",
}[this.source.lang]; }[this.source.lang];
} }
formatDateString(dateStr, lang) { formatDateString(dateStr, lang) {
// Month translations for supported languages // Month translations for supported languages
const monthTranslations = { const monthTranslations = {
en: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], en: [
fr: ["janv.", "févr.", "mars", "avr.", "mai", "juin", "juil.", "août", "sept.", "oct.", "nov.", "déc."], "Jan",
id: ["Jan", "Feb", "Mar", "Apr", "Mei", "Jun", "Jul", "Agt", "Sep", "Okt", "Nov", "Des"], "Feb",
th: ["ม.ค.", "ก.พ.", "มี.ค.", "เม.ย.", "พ.ค.", "มิ.ย.", "ก.ค.", "ส.ค.", "ก.ย.", "ต.ค.", "พ.ย.", "ธ.ค."], "Mar",
es: ["ene.", "feb.", "mar.", "abr.", "may.", "jun.", "jul.", "ago.", "sep.", "oct.", "nov.", "dic."], "Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec",
],
fr: [
"janv.",
"févr.",
"mars",
"avr.",
"mai",
"juin",
"juil.",
"août",
"sept.",
"oct.",
"nov.",
"déc.",
],
id: [
"Jan",
"Feb",
"Mar",
"Apr",
"Mei",
"Jun",
"Jul",
"Agt",
"Sep",
"Okt",
"Nov",
"Des",
],
th: [
"ม.ค.",
"ก.พ.",
"มี.ค.",
"เม.ย.",
"พ.ค.",
"มิ.ย.",
"ก.ค.",
"ส.ค.",
"ก.ย.",
"ต.ค.",
"พ.ย.",
"ธ.ค.",
],
es: [
"ene.",
"feb.",
"mar.",
"abr.",
"may.",
"jun.",
"jul.",
"ago.",
"sep.",
"oct.",
"nov.",
"dic.",
],
zh: [], // No need for month names; uses yyyy年MM月dd日 format zh: [], // No need for month names; uses yyyy年MM月dd日 format
de: [] // No need for month names; uses dd.MM.yyyy format de: [], // No need for month names; uses dd.MM.yyyy format
}; };
const months = monthTranslations[lang]; const months = monthTranslations[lang];
let parts; let parts;
@@ -225,7 +299,7 @@ class DefaultExtension extends MProvider {
day = match[3]; day = match[3];
case "de": case "de":
// Expected format: dd.MM.yyyy // Expected format: dd.MM.yyyy
parts = dateStr.split('.'); parts = dateStr.split(".");
if (parts.length === 3) { if (parts.length === 3) {
month = parts[1]; month = parts[1];
day = parts[0]; day = parts[0];
@@ -236,7 +310,7 @@ class DefaultExtension extends MProvider {
case "id": case "id":
case "th": case "th":
// Expected format: dd MMM yyyy // Expected format: dd MMM yyyy
parts = dateStr.split(' '); parts = dateStr.split(" ");
if (parts.length === 3) { if (parts.length === 3) {
month = months.indexOf(parts[1]) + 1; month = months.indexOf(parts[1]) + 1;
day = parts[0]; day = parts[0];
@@ -244,141 +318,142 @@ class DefaultExtension extends MProvider {
} }
break; break;
default: default:
parts = dateStr.split(' '); parts = dateStr.split(" ");
if (parts.length === 3) { if (parts.length === 3) {
month = months.indexOf(parts[0]) + 1; month = months.indexOf(parts[0]) + 1;
day = parts[1].replace(',', ''); day = parts[1].replace(",", "");
year = parts[2]; year = parts[2];
} }
} }
if (!month || !year || !day) { if (!month || !year || !day) {
return Date.now(); return Date.now();
} }
return `${year}-${month.toString().padStart(2, '0')}-${day.toString().padStart(2, '0')}`; return `${year}-${month.toString().padStart(2, "0")}-${day.toString().padStart(2, "0")}`;
} }
async getPageList(url) { async getPageList(url) {
const res = await new Client().get(url); const res = await new Client().get(url);
const doc = new Document(res.body); const doc = new Document(res.body);
const urls = []; const urls = [];
const imageElement = doc.selectFirst('div#_imageList'); const imageElement = doc.selectFirst("div#_imageList");
const img_urls = imageElement.select('img'); const img_urls = imageElement.select("img");
for (let i = 0; i < img_urls.length; i++) { for (let i = 0; i < img_urls.length; i++) {
urls.push(img_urls[i].attr("data-url")); urls.push(img_urls[i].attr("data-url"));
} }
return urls; return urls;
} }
getFilterList() { getFilterList() {
return [{ return [
{
type: "sort", type: "sort",
name: "Official or Challenge", name: "Official or Challenge",
type_name: "SelectFilter", type_name: "SelectFilter",
values: [{ values: [
{
type_name: "SelectOption", type_name: "SelectOption",
name: "Any", name: "Any",
value: "any" value: "any",
}, },
{ {
type_name: "SelectOption", type_name: "SelectOption",
name: "Official only", name: "Official only",
value: "official" value: "official",
}, },
{ {
type_name: "SelectOption", type_name: "SelectOption",
name: "Challenge only", name: "Challenge only",
value: "challenge" value: "challenge",
}] },
],
}, },
{ {
type: "categories", type: "categories",
name: "Genre", name: "Genre",
type_name: "SelectFilter", type_name: "SelectFilter",
values: [{ values: [
{
type_name: "SelectOption", type_name: "SelectOption",
name: "All", name: "All",
value: "" value: "",
}, },
{ {
type_name: "SelectOption", type_name: "SelectOption",
name: "Action", name: "Action",
value: "action" value: "action",
}, },
{ {
type_name: "SelectOption", type_name: "SelectOption",
name: "Comedy", name: "Comedy",
value: "comedy" value: "comedy",
}, },
{ {
type_name: "SelectOption", type_name: "SelectOption",
name: "Drama", name: "Drama",
value: "drama" value: "drama",
}, },
{ {
type_name: "SelectOption", type_name: "SelectOption",
name: "Fantasy", name: "Fantasy",
value: "fantasy" value: "fantasy",
}, },
{ {
type_name: "SelectOption", type_name: "SelectOption",
name: "Heartwarming", name: "Heartwarming",
value: "heartwarming" value: "heartwarming",
}, },
{ {
type_name: "SelectOption", type_name: "SelectOption",
name: "Historical", name: "Historical",
value: "historical" value: "historical",
}, },
{ {
type_name: "SelectOption", type_name: "SelectOption",
name: "Horror", name: "Horror",
value: "horror" value: "horror",
}, },
{ {
type_name: "SelectOption", type_name: "SelectOption",
name: "Informative", name: "Informative",
value: "tiptoon" value: "tiptoon",
}, },
{ {
type_name: "SelectOption", type_name: "SelectOption",
name: "Mystery", name: "Mystery",
value: "mystery" value: "mystery",
}, },
{ {
type_name: "SelectOption", type_name: "SelectOption",
name: "Romance", name: "Romance",
value: "romance" value: "romance",
}, },
{ {
type_name: "SelectOption", type_name: "SelectOption",
name: "Sci-fi", name: "Sci-fi",
value: "sf" value: "sf",
}, },
{ {
type_name: "SelectOption", type_name: "SelectOption",
name: "Slice of life", name: "Slice of life",
value: "slice_of_life" value: "slice_of_life",
}, },
{ {
type_name: "SelectOption", type_name: "SelectOption",
name: "Sports", name: "Sports",
value: "sports" value: "sports",
}, },
{ {
type_name: "SelectOption", type_name: "SelectOption",
name: "Superhero", name: "Superhero",
value: "super_hero" value: "super_hero",
}, },
{ {
type_name: "SelectOption", type_name: "SelectOption",
name: "Supernatural", name: "Supernatural",
value: "supernatural" value: "supernatural",
}] },
} ],
},
]; ];
} }
} }