mirror of
https://git.luna-app.eu/50n50/sources
synced 2025-12-21 21:26:19 +01:00
236 lines
8.6 KiB
JavaScript
236 lines
8.6 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;
|
|
}
|
|
});
|
|
|
|
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;
|
|
}
|