mirror of
https://git.luna-app.eu/50n50/sources
synced 2025-12-21 21:26:19 +01:00
257 lines
12 KiB
JavaScript
257 lines
12 KiB
JavaScript
async function searchResults(keyword) {
|
|
const results = [];
|
|
|
|
const headers = {
|
|
"Host": 'graphql.anilist.co',
|
|
"User-Agent": 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:147.0) Gecko/20100101 Firefox/147.0',
|
|
"Accept": 'application/json',
|
|
"Accept-Language": 'en-US,en;q=0.9',
|
|
"Accept-Encoding": 'gzip, deflate, br, zstd',
|
|
"Referer": 'https://anicore.tv/',
|
|
"Content-Type": 'application/json',
|
|
"Content-Length": '1380',
|
|
"Origin": 'https://anicore.tv',
|
|
"Connection": 'keep-alive',
|
|
"Sec-Fetch-Dest": 'empty',
|
|
"Sec-Fetch-Mode": 'cors',
|
|
"Sec-Fetch-Site": 'cross-site',
|
|
"Priority": 'u=4',
|
|
"TE": 'trailers'
|
|
};
|
|
|
|
const postData = {"query":"\nquery ($page: Int = 1, $perPage: Int = 50, $type: MediaType = ANIME, $search: String, $format_in: [MediaFormat], $status: MediaStatus, $countryOfOrigin: CountryCode, $season: MediaSeason, $seasonYear: Int, $genre_in: [String], $tag_in: [String], $sort:[MediaSort], $isAdult: Boolean) {\n Page(page: $page, perPage: $perPage) {\n pageInfo {\n total\n perPage\n currentPage\n lastPage\n hasNextPage\n }\n media(type: $type, sort: $sort, season: $season, seasonYear: $seasonYear, search: $search, genre_in: $genre_in, tag_in: $tag_in, format_in: $format_in, status: $status, countryOfOrigin: $countryOfOrigin, isAdult: $isAdult){\n id\n title {\n english\n romaji\n }\n coverImage {\n extraLarge\n color\n }\n startDate {\n year\n month\n day\n }\n bannerImage\n season\n seasonYear\n description\n type\n format\n status(version: 2)\n episodes\n duration\n chapters\n volumes\n genres\n isAdult\n averageScore\n popularity\n nextAiringEpisode {\n airingAt\n timeUntilAiring\n episode\n }\n mediaListEntry {\n id\n status\n }\n }\n }\n}","variables":{"search":`${keyword}`,"type":"ANIME","sort":"POPULARITY_DESC","page":1}};
|
|
|
|
try {
|
|
const response = await fetchv2("https://graphql.anilist.co/", headers, "POST", postData);
|
|
const data = await response.json();
|
|
|
|
if (data.data && data.data.Page && data.data.Page.media) {
|
|
const media = data.data.Page.media;
|
|
for (const item of media) {
|
|
results.push({
|
|
title: item.title.english || item.title.romaji || "Unknown",
|
|
image: item.coverImage.extraLarge || "",
|
|
href: `${item.id}`
|
|
});
|
|
}
|
|
}
|
|
|
|
return JSON.stringify(results);
|
|
} catch (err) {
|
|
return JSON.stringify([{
|
|
title: "Error",
|
|
image: "Error",
|
|
href: "Error"
|
|
}]);
|
|
}
|
|
}
|
|
|
|
async function extractDetails(ID) {
|
|
try {
|
|
const headers = {
|
|
"Host": 'graphql.anilist.co',
|
|
"User-Agent": 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:147.0) Gecko/20100101 Firefox/147.0',
|
|
"Accept": 'application/json',
|
|
"Accept-Language": 'en-US,en;q=0.9',
|
|
"Accept-Encoding": 'gzip, deflate, br, zstd',
|
|
"Referer": 'https://anicore.tv/',
|
|
"Content-Type": 'application/json',
|
|
"Content-Length": '1380',
|
|
"Origin": 'https://anicore.tv',
|
|
"Connection": 'keep-alive',
|
|
"Sec-Fetch-Dest": 'empty',
|
|
"Sec-Fetch-Mode": 'cors',
|
|
"Sec-Fetch-Site": 'cross-site',
|
|
"Priority": 'u=4',
|
|
"TE": 'trailers'
|
|
};
|
|
|
|
const postData = {"query":"query media($id:Int,$type:MediaType,$isAdult:Boolean){Media(id:$id,type:$type,isAdult:$isAdult){id title{userPreferred romaji english native}coverImage{extraLarge large}bannerImage startDate{year month day}endDate{year month day}description season seasonYear type format status(version:2)episodes duration chapters volumes genres synonyms source(version:3)isAdult isLocked meanScore averageScore popularity favourites isFavouriteBlocked hashtag countryOfOrigin isLicensed isFavourite isRecommendationBlocked isFavouriteBlocked isReviewBlocked nextAiringEpisode{airingAt timeUntilAiring episode}relations{edges{id relationType(version:2)node{id title{userPreferred}format type status(version:2)bannerImage coverImage{large}}}}characterPreview:characters(perPage:6,sort:[ROLE,RELEVANCE,ID]){edges{id role name voiceActors(language:JAPANESE,sort:[RELEVANCE,ID]){id name{userPreferred}language:languageV2 image{large}}node{id name{userPreferred}image{large}}}}staffPreview:staff(perPage:8,sort:[RELEVANCE,ID]){edges{id role node{id name{userPreferred}language:languageV2 image{large}}}}studios{edges{isMain node{id name}}}reviewPreview:reviews(perPage:2,sort:[RATING_DESC,ID]){pageInfo{total}nodes{id summary rating ratingAmount user{id name avatar{large}}}}recommendations(perPage:7,sort:[RATING_DESC,ID]){pageInfo{total}nodes{id rating userRating mediaRecommendation{id title{userPreferred}format type status(version:2)bannerImage coverImage{large}}user{id name avatar{large}}}}externalLinks{id site url type language color icon notes isDisabled}streamingEpisodes{site title thumbnail url}trailer{id site}rankings{id rank type format year season allTime context}tags{id name description rank isMediaSpoiler isGeneralSpoiler userId}mediaListEntry{id status score}stats{statusDistribution{status amount}scoreDistribution{score amount}}}}","variables":{"id":ID,"type":"ANIME"}};
|
|
const response = await fetchv2("https://graphql.anilist.co/", headers, "POST", postData);
|
|
const data = await response.json();
|
|
|
|
const media = data.data.Media;
|
|
return JSON.stringify([{
|
|
description: clean(media.description),
|
|
aliases: media.title.romaji + " / " + media.title.english + " / " + media.title.native,
|
|
airdate: media.startDate.year
|
|
}]);
|
|
} catch (err) {
|
|
return JSON.stringify([{
|
|
description: "Error",
|
|
aliases: "Error",
|
|
airdate: "Error"
|
|
}]);
|
|
}
|
|
}
|
|
|
|
async function extractEpisodes(ID) {
|
|
const results = [];
|
|
try {
|
|
const response = await fetchv2("https://anicore-api.vercel.app/api/episodes?id=" + ID);
|
|
const data = await response.json();
|
|
|
|
if (Array.isArray(data)) {
|
|
for (const episode of data) {
|
|
results.push({
|
|
href: `${ID}-${episode.number}`,
|
|
number: episode.number
|
|
});
|
|
}
|
|
}
|
|
|
|
return JSON.stringify(results);
|
|
} catch (err) {
|
|
return JSON.stringify([{
|
|
href: "Error",
|
|
number: "Error"
|
|
}]);
|
|
}
|
|
}
|
|
|
|
async function extractStreamUrl(url) {
|
|
try {
|
|
const parts = url.split('-');
|
|
const animeID = parts[0];
|
|
const episodeNumber = parseInt(parts[1], 10);
|
|
|
|
const episodesResponse = await fetchv2("https://anicore-api.vercel.app/api/episodes?id=" + animeID);
|
|
const episodesData = await episodesResponse.json();
|
|
|
|
const episode = episodesData.find(ep => ep.number === episodeNumber);
|
|
if (!episode) {
|
|
return JSON.stringify({
|
|
streams: [],
|
|
subtitle: ""
|
|
});
|
|
}
|
|
|
|
const excludedProviders = ['oni', 'yuki', 'kami'];
|
|
const subProviders = (episode.subProviders || []).filter(p => !excludedProviders.includes(p));
|
|
const dubProviders = (episode.dubProviders || []).filter(p => !excludedProviders.includes(p));
|
|
|
|
if (subProviders.length === 0 && dubProviders.length === 0) {
|
|
return JSON.stringify({
|
|
streams: [],
|
|
subtitle: ""
|
|
});
|
|
}
|
|
|
|
const streamPromises = [];
|
|
|
|
for (const provider of subProviders) {
|
|
streamPromises.push(
|
|
fetchv2(`https://anicore-api.vercel.app/api/stream?id=${animeID}&host=${provider}&ep=${episodeNumber}&type=sub`)
|
|
.then(res => res.json())
|
|
.then(data => ({
|
|
provider,
|
|
type: 'sub',
|
|
data
|
|
}))
|
|
.catch(() => ({
|
|
provider,
|
|
type: 'sub',
|
|
data: null
|
|
}))
|
|
);
|
|
}
|
|
|
|
for (const provider of dubProviders) {
|
|
streamPromises.push(
|
|
fetchv2(`https://anicore-api.vercel.app/api/stream?id=${animeID}&host=${provider}&ep=${episodeNumber}&type=dub`)
|
|
.then(res => res.json())
|
|
.then(data => ({
|
|
provider,
|
|
type: 'dub',
|
|
data
|
|
}))
|
|
.catch(() => ({
|
|
provider,
|
|
type: 'dub',
|
|
data: null
|
|
}))
|
|
);
|
|
}
|
|
|
|
const streamResults = await Promise.all(streamPromises);
|
|
|
|
const streams = [];
|
|
let englishSubtitle = "";
|
|
let zenResult = null;
|
|
|
|
for (const result of streamResults) {
|
|
if (result.data && result.data.sources && result.data.sources.length > 0) {
|
|
const source = result.data.sources[0];
|
|
const typeLabel = result.type === 'dub' ? 'DUB' : 'SUB';
|
|
streams.push({
|
|
title: `${result.provider.toUpperCase()} - ${typeLabel}`,
|
|
streamUrl: source.url,
|
|
headers: result.data.headers || {}
|
|
});
|
|
|
|
if (result.provider === 'zen' && result.type === 'sub') {
|
|
zenResult = result;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (zenResult && zenResult.data && Array.isArray(zenResult.data.subtitles)) {
|
|
const engSub = zenResult.data.subtitles.find(sub =>
|
|
(sub.lang.includes('eng') || sub.lang.includes('en')) &&
|
|
!sub.label.toLowerCase().includes('signs') &&
|
|
!sub.label.toLowerCase().includes('songs')
|
|
);
|
|
if (engSub) {
|
|
englishSubtitle = engSub.url || "";
|
|
}
|
|
}
|
|
|
|
if (!englishSubtitle) {
|
|
for (const result of streamResults) {
|
|
if (result.type === 'sub' && result.data) {
|
|
if (Array.isArray(result.data.subtitles)) {
|
|
const engSub = result.data.subtitles.find(sub =>
|
|
(sub.lang.includes('eng') || sub.lang.includes('en') ||
|
|
sub.language === 'eng' || sub.language === 'en' || sub.name === 'eng' || sub.name === 'en') &&
|
|
!(sub.label && (sub.label.toLowerCase().includes('signs') || sub.label.toLowerCase().includes('songs')))
|
|
);
|
|
if (engSub) {
|
|
englishSubtitle = engSub.url || "";
|
|
break;
|
|
}
|
|
}
|
|
if (!englishSubtitle && Array.isArray(result.data.audio)) {
|
|
const engAudio = result.data.audio.find(audio =>
|
|
audio.language === 'eng' || audio.language === 'en' || audio.name === 'eng' || audio.name === 'en'
|
|
);
|
|
if (engAudio) {
|
|
englishSubtitle = engAudio.url || "";
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
console.log(JSON.stringify({
|
|
streams: streams.length > 0 ? streams : [],
|
|
subtitles: englishSubtitle
|
|
}));
|
|
return JSON.stringify({
|
|
streams: streams.length > 0 ? streams : [],
|
|
subtitles: englishSubtitle
|
|
});
|
|
} catch (err) {
|
|
return JSON.stringify({
|
|
streams: [],
|
|
subtitles: ""
|
|
});
|
|
}
|
|
}
|
|
|
|
const clean = html =>
|
|
html
|
|
.replace(/<br\s*\/?>/gi, '\n')
|
|
.replace(/<\/?i>/gi, '')
|
|
.replace(/<\/?b>/gi, '')
|
|
.replace(/<\/?[^>]+>/g, '');
|
|
|