aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRitesh Ghosh <[email protected]>2023-08-03 23:22:06 +0530
committerRitesh Ghosh <[email protected]>2023-08-03 23:22:06 +0530
commitc2c01f88afa51e30bad465854bf773e7f98924cd (patch)
treeeb4deb7b2d8f398b78344aa5d8146fca5e20a46a /src
parentaf70a9de1146b2c3bfdacd51f790f34f35b49877 (diff)
downloadaniwatch-api-c2c01f88afa51e30bad465854bf773e7f98924cd.tar.xz
aniwatch-api-c2c01f88afa51e30bad465854bf773e7f98924cd.zip
feat(newParser): added `animeAboutInfo` parser
Diffstat (limited to 'src')
-rw-r--r--src/parsers/animeAboutInfo.ts185
1 files changed, 185 insertions, 0 deletions
diff --git a/src/parsers/animeAboutInfo.ts b/src/parsers/animeAboutInfo.ts
new file mode 100644
index 0000000..baa0eb4
--- /dev/null
+++ b/src/parsers/animeAboutInfo.ts
@@ -0,0 +1,185 @@
+import axios, { AxiosError } from "axios";
+import { load, CheerioAPI, SelectorType } from "cheerio";
+import {
+ SRC_BASE_URL,
+ ACCEPT_HEADER,
+ USER_AGENT_HEADER,
+ ACCEPT_ENCODING_HEADER,
+ extractMostPopularAnimes,
+ extractAnimes,
+} from "../utils";
+
+import createHttpError, { HttpError } from "http-errors";
+import { ScrapedAnimeAboutInfo } from "../models";
+
+// /anime/info?id=${anime-id}
+async function scrapeAnimeAboutInfo(
+ id: string
+): Promise<ScrapedAnimeAboutInfo | HttpError> {
+ const res: ScrapedAnimeAboutInfo = {
+ anime: {
+ info: {
+ id: null,
+ name: null,
+ poster: null,
+ description: null,
+ stats: {
+ rating: null,
+ quality: null,
+ episodes: {
+ sub: null,
+ dub: null,
+ },
+ type: null,
+ duration: null,
+ },
+ },
+ moreInfo: {},
+ },
+ seasons: [],
+ mostPopularAnimes: [],
+ relatedAnimes: [],
+ recommendedAnimes: [],
+ };
+
+ try {
+ const animeUrl: URL = new URL(id, SRC_BASE_URL);
+ const mainPage = await axios.get(animeUrl.href, {
+ headers: {
+ "User-Agent": USER_AGENT_HEADER,
+ "Accept-Encoding": ACCEPT_ENCODING_HEADER,
+ Accept: ACCEPT_HEADER,
+ },
+ });
+
+ const $: CheerioAPI = load(mainPage.data);
+
+ const selector: SelectorType = "#ani_detail .container .anis-content";
+
+ res.anime.info.id =
+ $(selector)
+ ?.find(".anisc-detail .film-buttons a.btn-play")
+ ?.attr("href")
+ ?.split("/")
+ ?.pop() || null;
+ res.anime.info.name =
+ $(selector)
+ ?.find(".anisc-detail .film-name.dynamic-name")
+ ?.text()
+ ?.trim() || null;
+ res.anime.info.description =
+ $(selector)
+ ?.find(".anisc-detail .film-description .text")
+ .text()
+ ?.split("[")
+ ?.shift()
+ ?.trim() || null;
+ res.anime.info.poster =
+ $(selector)?.find(".film-poster .film-poster-img")?.attr("src")?.trim() ||
+ null;
+
+ // stats
+ res.anime.info.stats.rating =
+ $(`${selector} .film-stats .tick .tick-pg`)?.text()?.trim() || null;
+ res.anime.info.stats.quality =
+ $(`${selector} .film-stats .tick .tick-quality`)?.text()?.trim() || null;
+ res.anime.info.stats.episodes = {
+ sub:
+ Number($(`${selector} .film-stats .tick .tick-sub`)?.text()?.trim()) ||
+ null,
+ dub:
+ Number($(`${selector} .film-stats .tick .tick-dub`)?.text()?.trim()) ||
+ null,
+ };
+ res.anime.info.stats.type =
+ $(`${selector} .film-stats .tick`)
+ ?.text()
+ ?.trim()
+ ?.replace(/[\s\n]+/g, " ")
+ ?.split(" ")
+ ?.at(-2) || null;
+ res.anime.info.stats.duration =
+ $(`${selector} .film-stats .tick`)
+ ?.text()
+ ?.trim()
+ ?.replace(/[\s\n]+/g, " ")
+ ?.split(" ")
+ ?.pop() || null;
+
+ // more information
+ $(`${selector} .anisc-info-wrap .anisc-info .item:not(.w-hide)`).each(
+ (i, el) => {
+ let key = $(el)
+ .find(".item-head")
+ .text()
+ .toLowerCase()
+ .replace(":", "")
+ .trim();
+ key = key.includes(" ") ? key.replace(" ", "") : key;
+
+ const value = [
+ ...$(el)
+ .find("*:not(.item-head)")
+ .map((i, el) => $(el).text().trim()),
+ ]
+ .map((i) => `${i}`)
+ .toString()
+ .trim();
+
+ if (key === "genres") {
+ res.anime.moreInfo[key] = value.split(",").map((i) => i.trim());
+ return;
+ }
+ if (key === "producers") {
+ res.anime.moreInfo[key] = value.split(",").map((i) => i.trim());
+ return;
+ }
+ res.anime.moreInfo[key] = value;
+ }
+ );
+
+ // more seasons
+ const seasonsSelector: SelectorType = "#main-content .os-list a.os-item";
+ $(seasonsSelector).each((i, el) => {
+ res.seasons.push({
+ id: $(el)?.attr("href")?.slice(1)?.trim() || null,
+ name: $(el)?.attr("title")?.trim() || null,
+ title: $(el)?.find(".title")?.text()?.trim(),
+ poster:
+ $(el)
+ ?.find(".season-poster")
+ ?.attr("style")
+ ?.split(" ")
+ ?.pop()
+ ?.split("(")
+ ?.pop()
+ ?.split(")")[0] || null,
+ isCurrent: $(el).hasClass("active"),
+ });
+ });
+
+ const relatedAnimeSelector: SelectorType =
+ "#main-sidebar .block_area.block_area_sidebar.block_area-realtime:nth-of-type(1) .anif-block-ul ul li";
+ res.relatedAnimes = extractMostPopularAnimes($, relatedAnimeSelector);
+
+ const mostPopularSelector: SelectorType =
+ "#main-sidebar .block_area.block_area_sidebar.block_area-realtime:nth-of-type(2) .anif-block-ul ul li";
+ res.mostPopularAnimes = extractMostPopularAnimes($, mostPopularSelector);
+
+ const recommendedAnimeSelector: SelectorType =
+ "#main-content .block_area.block_area_category .tab-content .flw-item";
+ res.recommendedAnimes = extractAnimes($, recommendedAnimeSelector);
+
+ return res;
+ } catch (err: any) {
+ if (err instanceof AxiosError) {
+ throw createHttpError(
+ err?.response?.status || 500,
+ err?.response?.statusText || "Something went wrong"
+ );
+ }
+ throw createHttpError.InternalServerError(err?.message);
+ }
+}
+
+export default scrapeAnimeAboutInfo;