From b6720e86be1226dd1d28762cafa183f2082820f2 Mon Sep 17 00:00:00 2001 From: aka paul <50n50@noreply.localhost> Date: Wed, 10 Dec 2025 20:07:50 +0000 Subject: [PATCH] Add anicore/anicore.js --- anicore/anicore.js | 220 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 220 insertions(+) create mode 100644 anicore/anicore.js diff --git a/anicore/anicore.js b/anicore/anicore.js new file mode 100644 index 0000000..ebfb4b1 --- /dev/null +++ b/anicore/anicore.js @@ -0,0 +1,220 @@ +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 = ""; + + 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 (!englishSubtitle && result.type === 'sub' && result.data.subtitles && Array.isArray(result.data.subtitles)) { + const engSub = result.data.subtitles.find(sub => + sub.language === 'eng' || sub.language === 'en' || sub.name === 'eng' || sub.name === 'en' + ); + if (engSub) { + englishSubtitle = engSub.url || ""; + } + } + } + } + + return JSON.stringify({ + streams: streams.length > 0 ? streams : [], + subtitle: englishSubtitle + }); + } catch (err) { + return JSON.stringify({ + streams: [], + subtitle: "" + }); + } +} + +const clean = html => + html + .replace(//gi, '\n') + .replace(/<\/?i>/gi, '') + .replace(/<\/?b>/gi, '') + .replace(/<\/?[^>]+>/g, ''); +