mirror of
https://git.luna-app.eu/50n50/sources
synced 2025-12-21 13:16:21 +01:00
306 lines
12 KiB
JavaScript
306 lines
12 KiB
JavaScript
async function searchResults(keyword) {
|
||
const results = [];
|
||
try {
|
||
const response = await fetchv2("https://api.cdnlibs.org/api/anime?fields[]=rate_avg&fields[]=rate&fields[]=releaseDate&q=" + keyword);
|
||
const json = await response.json();
|
||
|
||
if (json && Array.isArray(json.data)) {
|
||
for (const item of json.data) {
|
||
const image = item.cover?.default || item.cover?.thumbnail || "";
|
||
results.push({
|
||
title: item.eng_name || item.name || "Unknown",
|
||
image: "https://passthrough-worker.simplepostrequest.workers.dev/?simple=" + image + "&referer=https://animelib.org/",
|
||
href: item.slug_url || item.slug || item.id
|
||
});
|
||
}
|
||
}
|
||
|
||
return JSON.stringify(results);
|
||
} catch (err) {
|
||
return JSON.stringify([{
|
||
title: "Error",
|
||
image: "Error",
|
||
href: "Error"
|
||
}]);
|
||
}
|
||
}
|
||
|
||
async function extractDetails(slug) {
|
||
try {
|
||
const response = await fetchv2(
|
||
"https://api.cdnlibs.org/api/anime/" + slug +
|
||
"?fields[]=background&fields[]=eng_name&fields[]=otherNames&fields[]=summary&fields[]=releaseDate&fields[]=type_id&fields[]=caution&fields[]=views&fields[]=close_view&fields[]=rate_avg&fields[]=rate&fields[]=genres&fields[]=tags&fields[]=teams&fields[]=user&fields[]=franchise&fields[]=authors&fields[]=publisher&fields[]=userRating&fields[]=moderated&fields[]=metadata&fields[]=metadata.count&fields[]=metadata.close_comments&fields[]=anime_status_id&fields[]=time&fields[]=episodes&fields[]=episodes_count&fields[]=episodesSchedule&fields[]=shiki_rate"
|
||
);
|
||
const json = await response.json();
|
||
const data = json.data || {};
|
||
const aliases = Array.isArray(data.otherNames) ? data.otherNames.join(", ") : "";
|
||
return JSON.stringify([{
|
||
description: data.summary || "No summary available",
|
||
airdate: data.releaseDate || "Unknown",
|
||
aliases: aliases
|
||
}]);
|
||
} catch (err) {
|
||
return JSON.stringify([{
|
||
description: "Error",
|
||
airdate: "Error",
|
||
aliases: ""
|
||
}]);
|
||
}
|
||
}
|
||
|
||
async function extractEpisodes(slug) {
|
||
const results = [];
|
||
try {
|
||
const response = await fetchv2("https://api.cdnlibs.org/api/episodes?anime_id=" + slug);
|
||
const json = await response.json();
|
||
|
||
if (json && Array.isArray(json.data)) {
|
||
for (const episode of json.data) {
|
||
results.push({
|
||
href: episode.id ? String(episode.id) : "",
|
||
number: parseFloat(episode.number) || 0
|
||
});
|
||
}
|
||
}
|
||
|
||
return JSON.stringify(results);
|
||
} catch (err) {
|
||
return JSON.stringify([{
|
||
href: "Error",
|
||
number: "Error"
|
||
}]);
|
||
}
|
||
}
|
||
|
||
async function extractStreamUrl(ID) {
|
||
try {
|
||
const response = await fetchv2("https://api.cdnlibs.org/api/episodes/" + ID);
|
||
const json = await response.json();
|
||
|
||
const data = json.data || {};
|
||
const players = data.players || [];
|
||
|
||
// const parserPromises = players
|
||
// .filter(player => player.src && player.team && player.team.name)
|
||
// .map(async (player) => {
|
||
// try {
|
||
// const kodikUrl = "https:" + player.src;
|
||
// const qualitiesJson = await kodikParser(kodikUrl);
|
||
// const qualities = JSON.parse(qualitiesJson);
|
||
|
||
// let highestQuality = null;
|
||
// let highestQualityNum = 0;
|
||
|
||
// for (const quality in qualities) {
|
||
// if (qualities[quality].src) {
|
||
// const qualityNum = parseInt(quality.replace('p', '')) || 0;
|
||
// if (qualityNum > highestQualityNum) {
|
||
// highestQualityNum = qualityNum;
|
||
// highestQuality = qualities[quality].src;
|
||
// }
|
||
// }
|
||
// }
|
||
|
||
// if (highestQuality) {
|
||
|
||
// if (highestQuality.startsWith('//')) {
|
||
// highestQuality = 'https:' + highestQuality;
|
||
// }
|
||
|
||
// return {
|
||
// title: player.team.name,
|
||
// streamUrl: highestQuality,
|
||
// headers: {
|
||
// "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)",
|
||
// "Referer": "https://kodik.info/"
|
||
// }
|
||
// };
|
||
// }
|
||
// return null;
|
||
// } catch (err) {
|
||
// return null;
|
||
// }
|
||
// });
|
||
|
||
players.sort((a, b) => {
|
||
const order = { Animelib: 0, Kodik: 1 };
|
||
return (order[a.player] ?? 99) - (order[b.player] ?? 99);
|
||
});
|
||
|
||
const parserPromises = players
|
||
.filter(player => player.team && player.team.name)
|
||
.map(async (player) => {
|
||
try {
|
||
let streamUrl = null;
|
||
let highestQualityNum = 0;
|
||
|
||
if (player.player === "Animelib" && player.video && player.video.quality) {
|
||
const qualities = player.video.quality;
|
||
|
||
console.log(qualities);
|
||
|
||
for (const qualityItem of qualities) {
|
||
if (qualityItem.href && qualityItem.quality > highestQualityNum) {
|
||
highestQualityNum = qualityItem.quality;
|
||
streamUrl = qualityItem.href;
|
||
|
||
console.log("Found Animelib quality: " + qualityItem.quality + " URL: " + streamUrl);
|
||
}
|
||
}
|
||
|
||
// Animelib URLs are relative, prepend base URL
|
||
if (streamUrl && !streamUrl.startsWith('http')) {
|
||
// https://video1.cdnlibs.org/.аs/
|
||
// https://video2.anilib.me/.аs/
|
||
// https://video3.anilib.me/.аs/
|
||
streamUrl = 'https://video1.cdnlibs.org/.%D0%B0s/' + streamUrl;
|
||
}
|
||
} else if (player.player === "Kodik" && player.src) {
|
||
const kodikUrl = "https:" + player.src;
|
||
const qualitiesJson = await kodikParser(kodikUrl);
|
||
const qualities = JSON.parse(qualitiesJson);
|
||
|
||
for (const quality in qualities) {
|
||
if (qualities[quality].src) {
|
||
const qualityNum = parseInt(quality.replace('p', '')) || 0;
|
||
if (qualityNum > highestQualityNum) {
|
||
highestQualityNum = qualityNum;
|
||
streamUrl = qualities[quality].src;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (streamUrl && streamUrl.startsWith('//')) {
|
||
streamUrl = 'https:' + streamUrl;
|
||
}
|
||
}
|
||
|
||
if (streamUrl) {
|
||
return {
|
||
title: player.team.name + (highestQualityNum ? ` (${highestQualityNum}p)` : '') + (player.player === "Animelib" ? " (Animelib)" : " (Kodik)"),
|
||
streamUrl,
|
||
headers: {
|
||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)",
|
||
"Referer": player.player === "Kodik" ? "https://kodik.info/" : "https://v3.animelib.org/"
|
||
}
|
||
};
|
||
}
|
||
|
||
return null;
|
||
} catch (err) {
|
||
return null;
|
||
}
|
||
});
|
||
|
||
const results = await Promise.all(parserPromises);
|
||
|
||
const streams = results.filter(stream => stream !== null);
|
||
|
||
return JSON.stringify({
|
||
streams: streams,
|
||
subtitle: "https://none.com"
|
||
});
|
||
} catch (err) {
|
||
return JSON.stringify({
|
||
streams: [],
|
||
subtitle: "https://none.com"
|
||
});
|
||
}
|
||
}
|
||
|
||
async function kodikParser(url) {
|
||
try {
|
||
const headers = {
|
||
"Referer": "https://v3.animelib.org/",
|
||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3"
|
||
};
|
||
const response = await fetchv2(url, headers);
|
||
const htmlText = await response.text();
|
||
|
||
const urlParamsMatch = htmlText.match(/var\s+urlParams\s*=\s*'([^']+)'/);
|
||
const videoInfoTypeMatch = htmlText.match(/videoInfo\.type\s*=\s*'([^']+)'/);
|
||
const videoInfoHashMatch = htmlText.match(/videoInfo\.hash\s*=\s*'([^']+)'/);
|
||
const videoInfoIdMatch = htmlText.match(/videoInfo\.id\s*=\s*'([^']+)'/);
|
||
|
||
const urlParams = urlParamsMatch ? JSON.parse(urlParamsMatch[1]) : {};
|
||
const videoInfo_type = videoInfoTypeMatch ? videoInfoTypeMatch[1] : '';
|
||
const videoInfo_hash = videoInfoHashMatch ? videoInfoHashMatch[1] : '';
|
||
const videoInfo_id = videoInfoIdMatch ? videoInfoIdMatch[1] : '';
|
||
|
||
const finalData =
|
||
`d=${urlParams.d}` +
|
||
`&d_sign=${urlParams.d_sign}` +
|
||
`&pd=${urlParams.pd}` +
|
||
`&pd_sign=${urlParams.pd_sign}` +
|
||
`&ref=${urlParams.ref}` +
|
||
`&ref_sign=${urlParams.ref_sign}` +
|
||
`&bad_user=false&cdn_is_working=false` +
|
||
`&type=${videoInfo_type}&hash=${videoInfo_hash}&id=${videoInfo_id}&info=%7B%7D`;
|
||
|
||
|
||
const headers2 = {
|
||
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
|
||
"Referer": "https://kodik.info",
|
||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3",
|
||
"X-Requested-With": "XMLHttpRequest"
|
||
};
|
||
const apiResponse = await fetchv2("https://kodik.info/ftor", headers2, "POST", finalData);
|
||
const apiJson = await apiResponse.json();
|
||
|
||
const qualities = {};
|
||
|
||
if (apiJson?.links) {
|
||
for (const quality in apiJson.links) {
|
||
const qualityData = apiJson.links[quality];
|
||
|
||
if (qualityData && qualityData[0] && qualityData[0].src) {
|
||
const encodedSrc = qualityData[0].src;
|
||
const decodedUrl = decode(encodedSrc);
|
||
|
||
qualities[quality] = {
|
||
src: decodedUrl,
|
||
type: qualityData[0].type || 'application/x-mpegURL'
|
||
};
|
||
}
|
||
}
|
||
}
|
||
|
||
return JSON.stringify(qualities, null, 2);
|
||
} catch (error) {
|
||
console.log(error);
|
||
return JSON.stringify({ error: "error.org" });
|
||
}
|
||
}
|
||
|
||
function decode(input) {
|
||
const _0x1a = ["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", "=", String.fromCharCode, ">="];
|
||
(function() {})();
|
||
const _map = _0x1a[0];
|
||
let _o = '',
|
||
_b = 0,
|
||
_c = 0;
|
||
const _r = [];
|
||
for (let _i = 0; _i < input.length; _i++) {
|
||
const _ch = input[_i];
|
||
if (/[a-zA-Z]/.test(_ch)) {
|
||
const _cc = _ch.charCodeAt(0);
|
||
const _max = _ch <= 'Z' ? 90 : 122;
|
||
let _sh = _cc + 18;
|
||
_r.push(String.fromCharCode(_sh <= _max ? _sh : _sh - 26));
|
||
} else _r.push(_ch);
|
||
}
|
||
const _rot = _r.join('');
|
||
for (let _j = 0; _j < _rot.length; _j++) {
|
||
const _ch = _rot[_j];
|
||
if (_ch === _0x1a[1]) break;
|
||
const _v = _map.indexOf(_ch);
|
||
if (_v === -1) continue;
|
||
_b = (_b << 6) | _v;
|
||
_c += 6;
|
||
if (_c >= 8) {
|
||
_c -= 8;
|
||
_o += _0x1a[2]((_b >> _c) & 0xFF);
|
||
}
|
||
}
|
||
return _o;
|
||
}
|