diff options
| author | Ritesh Ghosh <[email protected]> | 2023-08-03 23:22:06 +0530 |
|---|---|---|
| committer | Ritesh Ghosh <[email protected]> | 2023-08-03 23:22:06 +0530 |
| commit | c2c01f88afa51e30bad465854bf773e7f98924cd (patch) | |
| tree | eb4deb7b2d8f398b78344aa5d8146fca5e20a46a /src | |
| parent | af70a9de1146b2c3bfdacd51f790f34f35b49877 (diff) | |
| download | aniwatch-api-c2c01f88afa51e30bad465854bf773e7f98924cd.tar.xz aniwatch-api-c2c01f88afa51e30bad465854bf773e7f98924cd.zip | |
feat(newParser): added `animeAboutInfo` parser
Diffstat (limited to 'src')
| -rw-r--r-- | src/parsers/animeAboutInfo.ts | 185 |
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; |
