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; }