@xct007/frieren-scraper
Version:
283 lines (282 loc) • 9.9 kB
JavaScript
import { Axios, Cheerio } from "../Utils.js";
import { KomikuIdBaseUrl } from "../Constant.js";
class komiku {
constructor() { }
static async latest() {
try {
const { data } = await Axios.get(KomikuIdBaseUrl, {}).catch((e) => e?.response);
const $ = Cheerio(data);
const _temp = [];
$(komiku._latestLoader.base).each((i, e) => {
const title = $(e)
.find(komiku._latestLoader.titleLoader)
.text();
const updated = $(e)
.find(komiku._latestLoader.updatedLoader)
.text();
const chapter = $(e)
.find(komiku._latestLoader.chapterLoader)
.text();
let url = $(e)
.find(komiku._latestLoader.urlLoader.base)
.attr(komiku._latestLoader.urlLoader.attribute);
const thumbnail = $(e)
.find(komiku._latestLoader.thumbnailLoader.base)
.attr(komiku._latestLoader.thumbnailLoader.attribute)
.replace(/\?.*$/, "");
if (url.startsWith("http")) {
url = url;
}
else {
url = KomikuIdBaseUrl + url;
}
_temp.push({ title, updated, chapter, url, thumbnail });
});
if (Array.isArray(_temp) && _temp.length) {
return _temp;
}
else {
throw new Error(komiku._failed.latest);
}
}
catch (e) {
return {
error: true,
message: String(e),
};
}
}
static async detail(url) {
try {
if (!url.includes(KomikuIdBaseUrl)) {
throw new Error("Invalid url dude");
}
const { data } = await Axios.get(url).catch((e) => e?.response);
const $ = Cheerio(data);
if (/\/manga\//i.test(url)) {
const title = $(komiku._detailLoader.manga.titleLoader.title)
.text()
.trim();
const description = $(komiku._detailLoader.manga.descriptionLoader)
.text()
.trim();
const thumbnail = $(komiku._detailLoader.manga.thumbnailLoader.base).attr(komiku._detailLoader.manga.thumbnailLoader.attribute);
const _tempData = [];
let metadata = {};
$(komiku._detailLoader.manga.metadataLoader.firstChild).each((i, e) => {
_tempData.push($(e).text().replace(/:/, "").trim());
});
_tempData.forEach((e, i) => {
if (i % 2 === 0) {
Object.assign(metadata, {
[e.toLowerCase()]: _tempData[i + 1],
});
}
});
_tempData.splice(0, _tempData.length);
$(komiku._detailLoader.manga.metadataLoader.secondChild).each((i, e) => {
_tempData.push($(e).text());
});
_tempData.forEach((e, i) => {
if (i % 2 === 0) {
Object.assign(metadata, {
[e.replace(/\s/g, "_").toLowerCase().trim()]: _tempData[i + 1],
});
}
});
const genres = [];
$(komiku._detailLoader.manga.genresLoader.base).each((i, e) => {
genres.push($(e).text());
});
const chapters = [];
$(komiku._detailLoader.manga.chaptersLoader.base).each((i, e) => {
const chapter = $(e)
.find(komiku._detailLoader.manga.chaptersLoader.chapter)
.text();
const url = KomikuIdBaseUrl +
$(e).attr(komiku._detailLoader.manga.chaptersLoader.url.attribute);
chapters.push({ chapter, url });
});
return {
isManga: true,
title,
metadata,
description,
chapters,
};
}
else if (/\/ch\//i.test(url)) {
const _title = [];
$(komiku._detailLoader.chapter.titleLoader.title).each((i, e) => {
_title.push($(e).text());
});
const title = _title[0].replace(/[\t\n]/g, "").trim();
const images = [];
$(komiku._detailLoader.chapter.imagesLoader.base).each((i, e) => {
images.push($(e).attr(komiku._detailLoader.chapter.imagesLoader.attribute));
});
return {
isChapter: true,
title,
images,
};
}
else {
throw new Error(komiku._failed.detail);
}
}
catch (e) {
return {
error: true,
message: String(e),
};
}
}
static async search(query) {
try {
const { data } = await Axios.get(KomikuIdBaseUrl.replace("https://", "https://data.") + "/cari/", {
params: {
post_type: "manga",
s: query,
},
}).catch((e) => e?.response);
const $ = Cheerio(data);
const _temp = [];
$(komiku._searchLoader.base).each((i, e) => {
const title = $(e)
.find(komiku._searchLoader.titleLoader.title)
.text()
.trim();
const title_id = $(e)
.find(komiku._searchLoader.titleLoader.title_id)
.text()
.trim();
const description = $(e)
.find(komiku._searchLoader.descriptionLoader)
.text()
.trim();
const thumbnail = $(e)
.find(komiku._searchLoader.thumbnailLoader.base)
.attr(komiku._searchLoader.thumbnailLoader.attribute)
.replace(/\?.*$/, "");
const url = $(e)
.find(komiku._searchLoader.urlLoader.base)
.attr(komiku._searchLoader.urlLoader.attribute);
let metadata = {};
const _tempData = [];
$(e)
.find(komiku._searchLoader.metadataLoader)
.each((_i, _e) => {
_tempData.push($(_e).text().replace(/:/, "").trim());
});
_tempData.forEach((e, i) => {
if (i % 2 === 0) {
Object.assign(metadata, {
[e.replace(/\s/g, "_").toLowerCase().trim()]: _tempData[i + 1],
});
}
});
_temp.push({
title,
title_id,
...metadata,
description,
thumbnail,
url,
});
});
if (Array.isArray(_temp) && _temp.length) {
return _temp;
}
else {
throw new Error(komiku._failed.search);
}
}
catch (e) {
return {
error: true,
message: String(e),
};
}
}
}
komiku._failed = {
latest: `failed to get latest data from ${KomikuIdBaseUrl}`,
detail: `failed to get detail data from ${KomikuIdBaseUrl}`,
search: `failed to get search data from ${KomikuIdBaseUrl}`,
};
komiku._latestLoader = {
base: "#Terbaru > .ls4w > article.ls4",
titleLoader: "h4 > a",
updatedLoader: "span.ls4s",
chapterLoader: "a.ls24",
urlLoader: {
base: "h4 > a",
attribute: "href",
},
thumbnailLoader: {
base: "a > img",
attribute: "data-src",
},
};
komiku._detailLoader = {
manga: {
titleLoader: {
title: "h1[itemprop='name']",
},
descriptionLoader: "p.desc",
thumbnailLoader: {
base: ".ims > img",
attribute: "src",
},
metadataLoader: {
firstChild: "div.new1 > a > span",
secondChild: "table.inftable > tbody > tr > td",
},
genresLoader: {
base: "ul.genre > li > a",
},
chaptersLoader: {
base: "table#Daftar_Chapter > tbody > tr > td > a",
chapter: "span",
url: {
attribute: "href",
},
},
},
chapter: {
titleLoader: {
title: "#Judul > h1",
},
imagesLoader: {
base: "#Baca_Komik > img",
attribute: "src",
},
},
};
komiku._searchLoader = {
base: ".daftar > .bge",
titleLoader: {
title: ".kan > a > h3",
title_id: ".kan span.judul2",
},
descriptionLoader: ".kan > p",
thumbnailLoader: {
base: ".bgei > a > img",
attribute: "data-src",
},
urlLoader: {
base: ".bgei > a",
attribute: "href",
},
metadataLoader: ".new1 > a > span",
};
export const latest = async function () {
return await komiku.latest();
};
export const search = async function (query) {
return await komiku.search(query);
};
export const detail = async function (url) {
return await komiku.detail(url);
};