mirror of
https://github.com/JustAnimeCore/HiAnime-Api.git
synced 2026-04-17 22:01:44 +00:00
feature, not a bug
This commit is contained in:
194
src/extractors/animeInfo.extractor.js
Normal file
194
src/extractors/animeInfo.extractor.js
Normal file
@@ -0,0 +1,194 @@
|
||||
import axios from "axios";
|
||||
import * as cheerio from "cheerio";
|
||||
import formatTitle from "../helper/formatTitle.helper.js";
|
||||
import { v1_base_url } from "../utils/base_v1.js";
|
||||
import extractRecommendedData from "./recommend.extractor.js";
|
||||
import extractRelatedData from "./related.extractor.js";
|
||||
import extractPopularData from "./popular.extractor.js";
|
||||
|
||||
async function extractAnimeInfo(id) {
|
||||
try {
|
||||
const [resp, characterData] = await Promise.all([
|
||||
axios.get(`https://${v1_base_url}/${id}`),
|
||||
axios.get(
|
||||
`https://${v1_base_url}/ajax/character/list/${id.split("-").pop()}`
|
||||
),
|
||||
]);
|
||||
const characterHtml = characterData.data?.html || "";
|
||||
const $1 = cheerio.load(characterHtml);
|
||||
const $ = cheerio.load(resp.data);
|
||||
const data_id = id.split("-").pop();
|
||||
const titleElement = $("#ani_detail .film-name");
|
||||
const showType = $("#ani_detail .prebreadcrumb ol li")
|
||||
.eq(1)
|
||||
.find("a")
|
||||
.text()
|
||||
.trim();
|
||||
const posterElement = $("#ani_detail .film-poster");
|
||||
const tvInfoElement = $("#ani_detail .film-stats");
|
||||
const tvInfo = {};
|
||||
tvInfoElement.find(".tick-item, span.item").each((_, element) => {
|
||||
const el = $(element);
|
||||
const text = el.text().trim();
|
||||
if (el.hasClass("tick-quality")) tvInfo.quality = text;
|
||||
else if (el.hasClass("tick-sub")) tvInfo.sub = text;
|
||||
else if (el.hasClass("tick-dub")) tvInfo.dub = text;
|
||||
else if (el.hasClass("tick-eps")) tvInfo.eps = text;
|
||||
else if (el.hasClass("tick-pg")) tvInfo.rating = text;
|
||||
else if (el.is("span.item")) {
|
||||
if (!tvInfo.showType) tvInfo.showType = text;
|
||||
else if (!tvInfo.duration) tvInfo.duration = text;
|
||||
}
|
||||
});
|
||||
|
||||
const element = $(
|
||||
"#ani_detail > .ani_detail-stage > .container > .anis-content > .anisc-info-wrap > .anisc-info > .item"
|
||||
);
|
||||
const overviewElement = $("#ani_detail .film-description .text");
|
||||
|
||||
const title = titleElement.text().trim();
|
||||
const japanese_title = titleElement.attr("data-jname");
|
||||
const synonyms = $('.item.item-title:has(.item-head:contains("Synonyms")) .name').text().trim();
|
||||
const poster = posterElement.find("img").attr("src");
|
||||
const syncDataScript = $("#syncData").html();
|
||||
let anilistId = null;
|
||||
let malId = null;
|
||||
|
||||
if (syncDataScript) {
|
||||
try {
|
||||
const syncData = JSON.parse(syncDataScript);
|
||||
anilistId = syncData.anilist_id || null;
|
||||
malId = syncData.mal_id || null;
|
||||
} catch (error) {
|
||||
console.error("Error parsing syncData:", error);
|
||||
}
|
||||
}
|
||||
|
||||
const animeInfo = {};
|
||||
element.each((_, el) => {
|
||||
const key = $(el).find(".item-head").text().trim().replace(":", "");
|
||||
const value =
|
||||
key === "Genres" || key === "Producers"
|
||||
? $(el)
|
||||
.find("a")
|
||||
.map((_, a) => $(a).text().split(" ").join("-").trim())
|
||||
.get()
|
||||
: $(el).find(".name").text().split(" ").join("-").trim();
|
||||
animeInfo[key] = value;
|
||||
});
|
||||
|
||||
const trailers = [];
|
||||
$('.block_area-promotions-list .screen-items .item').each((_, element) => {
|
||||
const el = $(element);
|
||||
const title = el.attr('data-title');
|
||||
const url = el.attr('data-src');
|
||||
if (url) {
|
||||
const fullUrl = url.startsWith('//') ? `https:${url}` : url;
|
||||
let videoId = null;
|
||||
const match = fullUrl.match(/\/embed\/([^?&]+)/);
|
||||
if (match && match[1]) {
|
||||
videoId = match[1];
|
||||
}
|
||||
trailers.push({
|
||||
title: title || null,
|
||||
url: fullUrl,
|
||||
thumbnail: videoId ? `https://img.youtube.com/vi/${videoId}/hqdefault.jpg` : null
|
||||
});
|
||||
}
|
||||
});
|
||||
animeInfo.trailers = trailers;
|
||||
|
||||
const season_id = formatTitle(title, data_id);
|
||||
animeInfo["Overview"] = overviewElement.text().trim();
|
||||
animeInfo["tvInfo"] = tvInfo;
|
||||
|
||||
let adultContent = false;
|
||||
const tickRateText = $(".tick-rate", posterElement).text().trim();
|
||||
if (tickRateText.includes("18+")) {
|
||||
adultContent = true;
|
||||
}
|
||||
|
||||
const [recommended_data, related_data, popular_data] = await Promise.all([
|
||||
extractRecommendedData($),
|
||||
extractRelatedData($),
|
||||
extractPopularData($),
|
||||
]);
|
||||
let charactersVoiceActors = [];
|
||||
if (characterHtml) {
|
||||
charactersVoiceActors = $1(".bac-list-wrap .bac-item")
|
||||
.map((index, el) => {
|
||||
const character = {
|
||||
id:
|
||||
$1(el)
|
||||
.find(".per-info.ltr .pi-avatar")
|
||||
.attr("href")
|
||||
?.split("/")[2] || "",
|
||||
poster:
|
||||
$1(el).find(".per-info.ltr .pi-avatar img").attr("data-src") ||
|
||||
"",
|
||||
name: $1(el).find(".per-info.ltr .pi-detail a").text(),
|
||||
cast: $1(el).find(".per-info.ltr .pi-detail .pi-cast").text(),
|
||||
};
|
||||
|
||||
let voiceActors = [];
|
||||
const rtlVoiceActors = $1(el).find(".per-info.rtl");
|
||||
const xxVoiceActors = $1(el).find(
|
||||
".per-info.per-info-xx .pix-list .pi-avatar"
|
||||
);
|
||||
if (rtlVoiceActors.length > 0) {
|
||||
voiceActors = rtlVoiceActors
|
||||
.map((_, actorEl) => ({
|
||||
id: $1(actorEl).find("a").attr("href")?.split("/").pop() || "",
|
||||
poster: $1(actorEl).find("img").attr("data-src") || "",
|
||||
name:
|
||||
$1(actorEl).find(".pi-detail .pi-name a").text().trim() || "",
|
||||
}))
|
||||
.get();
|
||||
} else if (xxVoiceActors.length > 0) {
|
||||
voiceActors = xxVoiceActors
|
||||
.map((_, actorEl) => ({
|
||||
id: $1(actorEl).attr("href")?.split("/").pop() || "",
|
||||
poster: $1(actorEl).find("img").attr("data-src") || "",
|
||||
name: $1(actorEl).attr("title") || "",
|
||||
}))
|
||||
.get();
|
||||
}
|
||||
if (voiceActors.length === 0) {
|
||||
voiceActors = $1(el)
|
||||
.find(".per-info.per-info-xx .pix-list .pi-avatar")
|
||||
.map((_, actorEl) => ({
|
||||
id: $1(actorEl).attr("href")?.split("/")[2] || "",
|
||||
poster: $1(actorEl).find("img").attr("data-src") || "",
|
||||
name: $1(actorEl).attr("title") || "",
|
||||
}))
|
||||
.get();
|
||||
}
|
||||
|
||||
return { character, voiceActors };
|
||||
})
|
||||
.get();
|
||||
}
|
||||
|
||||
return {
|
||||
adultContent,
|
||||
data_id,
|
||||
id: season_id,
|
||||
anilistId,
|
||||
malId,
|
||||
title,
|
||||
japanese_title,
|
||||
synonyms,
|
||||
poster,
|
||||
showType,
|
||||
animeInfo,
|
||||
charactersVoiceActors,
|
||||
recommended_data,
|
||||
related_data,
|
||||
popular_data,
|
||||
};
|
||||
} catch (e) {
|
||||
console.error("Error extracting anime info:", e);
|
||||
}
|
||||
}
|
||||
|
||||
export default extractAnimeInfo;
|
||||
Reference in New Issue
Block a user