diff --git a/1movies/1movies.js b/1movies/1movies.js index 3858307..cb77c7f 100644 --- a/1movies/1movies.js +++ b/1movies/1movies.js @@ -27,7 +27,7 @@ async function searchResults(query) { if (fullHref && imageSrc && cleanTitle) { results.push({ href: fullHref, - image: imageSrc, + image: "https://deno-proxies-sznvnpnxwhbv.deno.dev/?url=" + encodeURIComponent(imageSrc), title: cleanTitle }); } @@ -44,7 +44,7 @@ async function searchResults(query) { `${searchBaseUrl}${encodedQuery}&page=3` ]; - const responses = await Promise.all(urls.map(url => fetchv2(url))); + const responses = await Promise.all(urls.map(url => fetchv2("https://deno-proxies-sznvnpnxwhbv.deno.dev/?url=" + encodeURIComponent(url)))); const htmlTexts = await Promise.all(responses.map(response => response.text())); @@ -147,15 +147,17 @@ async function extractStreamUrl(url) { const responseData = await response.json(); const cleanedHtml = cleanJsonHtml(responseData.result); - const server1Regex = /
]*data-lid="([^"]+)"[^>]*>\s*Server 1<\/span>/; - const server1Match = server1Regex.exec(cleanedHtml); + const spanRegex = /
]*data-lid="([^"]+)"[^>]*>/g; + const ids = []; + let match; + while ((match = spanRegex.exec(cleanedHtml)) !== null) ids.push(match[1]); - if (!server1Match) { - console.log("Server 1 not found"); + if (ids.length === 0) { + console.log("No servers found"); return "error"; } - const serverId = server1Match[1]; + const serverId = ids.length > 1 ? ids[1] : ids[0]; const tokenData = await fetchv2(`https://enc-dec.app/api/enc-movies-flix?text=${encodeURIComponent(serverId)}`) .then(res => res.json()); @@ -203,7 +205,25 @@ async function extractStreamUrl(url) { ? subtitles.find(sub => sub.label === "English")?.file.replace(/\\\//g, "/") : "N/A"; - const mediaResponse = await fetchv2(decryptedUrl.replace("/e/", "/media/"), headers); + let finalUrl = decryptedUrl; + if (finalUrl.includes(".to/iframe")) { + try { + const iframeResponse = await fetchv2(finalUrl, headers); + const iframeHtml = await iframeResponse.text(); + const iframeSrcMatch = iframeHtml.match(/]+src="([^"]+)"/i); + if (iframeSrcMatch && iframeSrcMatch[1]) { + finalUrl = iframeSrcMatch[1]; + } else { + console.log("No iframe src found in:", finalUrl); + return "error"; + } + } catch (e) { + console.log("Error fetching iframe:", e); + return "error"; + } + } + + const mediaResponse = await fetchv2(finalUrl.replace("/e/", "/media/"), headers); const mediaJson = await mediaResponse.json(); const result = mediaJson?.result; @@ -220,8 +240,16 @@ async function extractStreamUrl(url) { ).then(res => res.json()); console.log("Final JSON: " + JSON.stringify(finalJson)); const m3u8Link = finalJson?.result?.sources?.[0]?.file; - - const m3u8Response = await fetchv2(m3u8Link); + + const streams = []; + if (m3u8Link) { + streams.push({ + title: "Auto", + streamUrl: "https://1anime.app/api/m3u8-proxy?url=" + m3u8Link + }); + } + /* + const m3u8Response = await fetchv2("https://1anime.app/api/m3u8-proxy?url=" + encodeURIComponent(m3u8Link)); const m3u8Text = await m3u8Response.text(); const baseUrl = m3u8Link.substring(0, m3u8Link.lastIndexOf('/') + 1); @@ -244,12 +272,12 @@ async function extractStreamUrl(url) { const streamPath = lines[i + 1].trim(); streams.push({ title: quality, - streamUrl: baseUrl + streamPath + streamUrl: "https://1anime.app/api/m3u8-proxy?url=" + encodeURIComponent(baseUrl + streamPath) }); } } } - + */ const returnValue = { streams: streams, subtitles: englishSubUrl !== "N/A" ? englishSubUrl : "" diff --git a/1movies/1movies.json b/1movies/1movies.json index 4a8f759..7404a62 100644 --- a/1movies/1movies.json +++ b/1movies/1movies.json @@ -5,7 +5,7 @@ "name": "50/50", "icon": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQ3122kQwublLkZ6rf1fEpUP79BxZOFmH9BSA&s" }, - "version": "1.2.3", + "version": "1.2.4", "language": "English", "streamType": "HLS", "quality": "1080p", diff --git a/animekai/animekai.js b/animekai/animekai.js index 64fee87..2f8ddd2 100644 --- a/animekai/animekai.js +++ b/animekai/animekai.js @@ -117,20 +117,27 @@ async function extractEpisodes(url) { async function extractStreamUrl(url) { const headers = { "Referer": "https://anikai.to/", - "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36" + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:134.0) Gecko/20100101 Firefox/134.0", + "Accept": "text/html, */*; q=0.01", + "Accept-Language": "en-US,en;q=0.5", + "Sec-Fetch-Dest": "empty", + "Sec-Fetch-Mode": "cors", + "Sec-Fetch-Site": "same-origin", + "Pragma": "no-cache", + "Cache-Control": "no-cache" }; - let actualUrl = url; try { - const tokenMatch = actualUrl.match(/token=([^&]+)/); - if (tokenMatch && tokenMatch[1]) { - const rawToken = tokenMatch[1]; - const encryptResponse = await fetchv2(`https://enc-dec.app/api/enc-kai?text=${encodeURIComponent(rawToken)}`); - const encryptData = await encryptResponse.json(); - const encryptedToken = encryptData.result; - actualUrl = actualUrl.replace('&_=ENCRYPT_ME', `&_=${encryptedToken}`); - } - + const tokenMatch = url.match(/token=([^&]+)/); + if (!tokenMatch?.[1]) throw new Error("No token found in URL"); + const rawToken = tokenMatch[1]; + + const encTokenRes = await fetchv2(`https://enc-dec.app/api/enc-kai?text=${encodeURIComponent(rawToken)}`); + const encTokenData = await encTokenRes.json(); + const encryptedToken = encTokenData.result; + + const actualUrl = url.replace('&_=ENCRYPT_ME', `&_=${encryptedToken}`); + const response = await fetchv2(actualUrl); const text = await response.text(); @@ -144,115 +151,96 @@ async function extractStreamUrl(url) { const cleanedAjaxResultHtml = cleanJsonHtml(ajaxResultHtml); const serverHtmlSource = cleanedAjaxResultHtml || cleanedHtml; - const subRegex = /
]*>([\s\S]*?)<\/div>/; - const softsubRegex = /
]*>([\s\S]*?)<\/div>/; - const dubRegex = /
]*>([\s\S]*?)<\/div>/; - const subMatch = subRegex.exec(serverHtmlSource); - const softsubMatch = softsubRegex.exec(serverHtmlSource); - const dubMatch = dubRegex.exec(serverHtmlSource); - - const subContent = subMatch ? subMatch[1].trim() : ""; - const softsubContent = softsubMatch ? softsubMatch[1].trim() : ""; - const dubContent = dubMatch ? dubMatch[1].trim() : ""; - - const extractServerId = (content) => { - if (!content) return null; - const preferred = /]*data-lid="([^"]+)"[^>]*>\s*Server\s*1\s*<\/span>/i.exec(content); - if (preferred?.[1]) return preferred[1]; - return /]*data-lid="([^"]+)"/i.exec(content)?.[1] || null; + const extractServerIds = (type) => { + const regex = new RegExp(`
]*>([\\s\\S]*?)<\\/div>`); + const content = regex.exec(serverHtmlSource)?.[1] ?? ""; + const spanRegex = /]*data-lid="([^"]+)"[^>]*>/g; + const ids = []; + let match; + while ((match = spanRegex.exec(content)) !== null) ids.push(match[1]); + console.log(`[extractStreamUrl] ${type} ids:`, ids); + return ids.length > 1 ? ids[1] : ids[0] ?? null; }; - const serverIdDub = extractServerId(dubContent); - const serverIdSoftsub = extractServerId(softsubContent); - const serverIdSub = extractServerId(subContent); + const dubType = url.includes("dub") ? "dub" : "sub"; + const types = dubType === "sub" ? ["sub", "softsub"] : ["dub"]; - const tokenRequestData = [ - { name: "Dub", data: serverIdDub }, - { name: "Softsub", data: serverIdSoftsub }, - { name: "Sub", data: serverIdSub } - ].filter(item => item.data); + const servers = types + .map(type => ({ type, lid: extractServerIds(type) })) + .filter(s => s.lid); - const tokenPromises = tokenRequestData.map(item => - fetchv2(`https://enc-dec.app/api/enc-kai?text=${encodeURIComponent(item.data)}`) - .then(res => res.json()) - .then(json => ({ name: item.name, data: json.result })) - .catch(err => ({ name: item.name, error: err.toString() })) - ); - const tokenResults = await Promise.all(tokenPromises); + const streams = []; + const subtitles = []; - const serverIdMap = { - "Dub": serverIdDub, - "Softsub": serverIdSoftsub, - "Sub": serverIdSub - }; - - const streamUrls = tokenResults.map(result => ({ - type: result.name, - url: `https://anikai.to/ajax/links/view?id=${serverIdMap[result.name]}&_=${result.data}` - })); - - const streamResponses = await Promise.all( - streamUrls.map(async ({ type, url }) => { - try { - const res = await fetchv2(url); - const json = await res.json(); - return { type, result: json.result }; - } catch { - return { type, result: null }; - } - }) - ); - - const decryptPromises = streamResponses - .filter(item => item.result) - .map(item => - fetchv2(`https://enc-dec.app/api/dec-kai?text=${item.result}`, headers) - .then(res => res.json()) - .then(json => ({ name: item.type, url: json.result?.url || null })) - .catch(() => ({ name: item.type, url: null })) - ); - const decryptResults = await Promise.all(decryptPromises); - - const urlMap = Object.fromEntries(decryptResults.map(i => [i.name, i.url])); - - const decryptedSub = urlMap.Sub; - const decryptedDub = urlMap.Dub; - const decryptedRaw = urlMap.Softsub; - - async function getStream(url) { + await Promise.all(servers.map(async ({ type, lid }) => { try { - const response = await fetchv2(url.replace("/e/", "/media/"), headers); - const responseJson = await response.json(); - const result = responseJson?.result; + const decLidRes = await fetchv2(`https://enc-dec.app/api/enc-kai?text=${encodeURIComponent(lid)}`); + const decLidData = await decLidRes.json(); + const decodedLid = decLidData.result; - const finalResponse = await fetchv2( + const viewRes = await fetchv2(`https://anikai.to/ajax/links/view?id=${lid}&_=${decodedLid}`); + const viewJson = await viewRes.json(); + const encodedResult = viewJson.result; + + const decRes = await fetchv2( + "https://enc-dec.app/api/dec-kai", + { "Content-Type": "application/json" }, + "POST", + JSON.stringify({ text: encodedResult }) + ); + const decJson = await decRes.json(); + let iframeUrl = decJson.result?.url ?? null; + + if (!iframeUrl) return; + + if (iframeUrl.includes("anikai.to/iframe")) { + const iframePageRes = await fetchv2(iframeUrl, headers); + const iframePageText = await iframePageRes.text(); + const iframeSrcMatch = iframePageText.match(/]+src="([^"]+)"/i); + if (iframeSrcMatch && iframeSrcMatch[1]) { + iframeUrl = iframeSrcMatch[1]; + console.log(`[extractStreamUrl] fallback iframeUrl for ${type}:`, iframeUrl); + } + } + + const mediaUrl = iframeUrl.replace("/e/", "/media/").replace("/e2/", "/media/"); + + const mediaRes = await fetchv2(mediaUrl, headers); + const mediaJson = await mediaRes.json(); + const encodedM3u8 = mediaJson?.result; + + if (!encodedM3u8) return; + + const finalRes = await fetchv2( "https://enc-dec.app/api/dec-mega", { "Content-Type": "application/json" }, "POST", - JSON.stringify({ text: result, agent: headers["User-Agent"] }) + JSON.stringify({ text: encodedM3u8, agent: headers["User-Agent"] }) ); + const finalJson = await finalRes.json(); - const finalJson = await finalResponse.json(); - return finalJson?.result?.sources?.[0]?.file || null; - } catch { - return null; + const sources = finalJson?.result?.sources ?? []; + const tracks = finalJson?.result?.tracks ?? []; + + const file = sources[0]?.file ?? null; + + if (file) { + const titleMap = { sub: "Hardsub English", softsub: "Original audio", dub: "Dubbed English" }; + streams.push({ title: titleMap[type] || type, streamUrl: "https://1anime.app/api/m3u8-proxy?url=" + file }); + } + + for (const track of tracks) { + if (track.file && track.label) { + subtitles.push({ url: track.file, language: track.label }); + } + } + + } catch (e) { + console.log(`[extractStreamUrl] error for ${type}:`, e.toString()); } - } + })); - const [subStream, dubStream, rawStream] = await Promise.all([ - decryptedSub ? getStream(decryptedSub) : Promise.resolve(null), - decryptedDub ? getStream(decryptedDub) : Promise.resolve(null), - decryptedRaw ? getStream(decryptedRaw) : Promise.resolve(null) - ]); - - console.log("[extractStreamUrl] Sub:", subStream, "Dub:", dubStream, "Softsub:", rawStream); - - const streams = []; - if (subStream) streams.push({ title: "Hardsub English", streamUrl: subStream }); - if (dubStream) streams.push({ title: "Dubbed English", streamUrl: dubStream }); - if (rawStream) streams.push({ title: "Original audio", streamUrl: rawStream }); - - return JSON.stringify({ streams, subtitles: "" }); + return JSON.stringify({ streams, subtitles }); } catch (error) { console.error("Animekai fetch error:" + error); @@ -260,6 +248,9 @@ async function extractStreamUrl(url) { } } + + + function cleanHtmlSymbols(string) { if (!string) { return ""; diff --git a/animekai/dub/animekai.js b/animekai/dub/animekai.js index 41eb8ec..622614b 100644 --- a/animekai/dub/animekai.js +++ b/animekai/dub/animekai.js @@ -114,138 +114,134 @@ async function extractEpisodes(url) { } async function extractStreamUrl(url) { - const headers = { - "Referer": "https://anikai.to/", - "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36" - }; + const headers = { + "Referer": "https://anikai.to/", + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:134.0) Gecko/20100101 Firefox/134.0", + "Accept": "text/html, */*; q=0.01", + "Accept-Language": "en-US,en;q=0.5", + "Sec-Fetch-Dest": "empty", + "Sec-Fetch-Mode": "cors", + "Sec-Fetch-Site": "same-origin", + "Pragma": "no-cache", + "Cache-Control": "no-cache" + }; - try { - const tokenMatch = url.match(/token=([^&]+)/); - if (tokenMatch && tokenMatch[1]) { - const rawToken = tokenMatch[1]; - const encryptResponse = await fetchv2(`https://enc-dec.app/api/enc-kai?text=${encodeURIComponent(rawToken)}`); - const encryptData = await encryptResponse.json(); - const encryptedToken = encryptData.result; - url = url.replace('&_=ENCRYPT_ME', `&_=${encryptedToken}`); - } - - const response = await fetchv2("https://deno-proxies-sznvnpnxwhbv.deno.dev/?url=" + encodeURIComponent(url)); - const text = await response.text(); - - let ajaxResultHtml = ""; try { - const parsedAjax = JSON.parse(text); - ajaxResultHtml = parsedAjax?.result || ""; - } catch {} + const tokenMatch = url.match(/token=([^&]+)/); + if (!tokenMatch?.[1]) throw new Error("No token found in URL"); + const rawToken = tokenMatch[1]; - const cleanedHtml = cleanJsonHtml(text); - const cleanedAjaxResultHtml = cleanJsonHtml(ajaxResultHtml); - const serverHtmlSource = cleanedAjaxResultHtml || cleanedHtml; + const encTokenRes = await fetchv2(`https://enc-dec.app/api/enc-kai?text=${encodeURIComponent(rawToken)}`); + const encTokenData = await encTokenRes.json(); + const encryptedToken = encTokenData.result; - const subRegex = /
]*>([\s\S]*?)<\/div>/; - const softsubRegex = /
]*>([\s\S]*?)<\/div>/; - const dubRegex = /
]*>([\s\S]*?)<\/div>/; - const subContent = subRegex.exec(serverHtmlSource)?.[1]?.trim() || ""; - const softsubContent = softsubRegex.exec(serverHtmlSource)?.[1]?.trim() || ""; - const dubContent = dubRegex.exec(serverHtmlSource)?.[1]?.trim() || ""; + const actualUrl = url.replace('&_=ENCRYPT_ME', `&_=${encryptedToken}`); - const extractServerId = (content) => { - if (!content) return null; - const preferred = /]*data-lid="([^"]+)"[^>]*>\s*Server\s*1\s*<\/span>/i.exec(content); - if (preferred?.[1]) return preferred[1]; - return /]*data-lid="([^"]+)"/i.exec(content)?.[1] || null; - }; + const response = await fetchv2(actualUrl); + const text = await response.text(); - const serverIdDub = extractServerId(dubContent); - const serverIdSoftsub = extractServerId(softsubContent); - const serverIdSub = extractServerId(subContent); + let ajaxResultHtml = ""; + try { + const parsedAjax = JSON.parse(text); + ajaxResultHtml = parsedAjax?.result || ""; + } catch {} - const tokenRequestData = [ - { name: "Dub", data: serverIdDub }, - { name: "Softsub", data: serverIdSoftsub }, - { name: "Sub", data: serverIdSub } - ].filter(item => item.data); + const cleanedHtml = cleanJsonHtml(text); + const cleanedAjaxResultHtml = cleanJsonHtml(ajaxResultHtml); + const serverHtmlSource = cleanedAjaxResultHtml || cleanedHtml; - const tokenPromises = tokenRequestData.map(item => - fetchv2(`https://enc-dec.app/api/enc-kai?text=${encodeURIComponent(item.data)}`) - .then(res => res.json()) - .then(json => ({ name: item.name, data: json.result })) - .catch(err => ({ name: item.name, error: err.toString() })) - ); - const tokenResults = await Promise.all(tokenPromises); - - const serverIdMap = { - "Dub": serverIdDub, - "Softsub": serverIdSoftsub, - "Sub": serverIdSub - }; - - const streamUrls = tokenResults.map(result => ({ - type: result.name, - url: `https://anikai.to/ajax/links/view?id=${serverIdMap[result.name]}&_=${result.data}` - })); - - // Step 1: fetch links/view via proxy - const streamResponses = await Promise.all( - streamUrls.map(async ({ type, url }) => { - try { - const res = await fetchv2("https://deno-proxies-sznvnpnxwhbv.deno.dev/?url=" + encodeURIComponent(url)); - const json = await res.json(); - return { type, result: json.result }; - } catch (error) { - console.log(`Error fetching ${type} stream:`, error); - return { type, result: null }; - } - }) - ); - - // Step 2: decrypt with browser UA — no encodeURIComponent - const decryptPromises = streamResponses - .filter(item => item.result) - .map(item => - fetchv2(`https://enc-dec.app/api/dec-kai?text=${item.result}`, headers) - .then(res => res.json()) - .then(json => { - console.log(`decrypted ${item.type} URL:`, json.result?.url); - return { name: item.type, url: json.result?.url || null }; - }) - .catch(err => ({ name: item.type, url: null })) - ); - const decryptResults = await Promise.all(decryptPromises); - - const urlMap = Object.fromEntries(decryptResults.map(i => [i.name, i.url])); - const decryptedDub = urlMap.Dub || urlMap.Sub || urlMap.Softsub; - - console.log("Using URL:", decryptedDub); - - if (decryptedDub) { - const mediaResponse = await fetchv2(decryptedDub.replace("/e/", "/media/"), headers); - const responseJson = await mediaResponse.json(); - const result = responseJson?.result; - - const postData = { - "text": result, - "agent": headers["User-Agent"] + const extractServerIds = (type) => { + const regex = new RegExp(`
]*>([\\s\\S]*?)<\\/div>`); + const content = regex.exec(serverHtmlSource)?.[1] ?? ""; + const spanRegex = /]*data-lid="([^"]+)"[^>]*>/g; + const ids = []; + let match; + while ((match = spanRegex.exec(content)) !== null) ids.push(match[1]); + return ids.length > 1 ? ids[1] : ids[0] ?? null; }; - const finalResponse = await fetchv2( - "https://enc-dec.app/api/dec-mega", - { "Content-Type": "application/json" }, - "POST", - JSON.stringify(postData) - ); - const finalJson = await finalResponse.json(); - console.log("dec-mega result:", finalJson); - const m3u8Link = finalJson?.result?.sources?.[0]?.file; + const types = ["dub"]; - return m3u8Link; + const servers = types + .map(type => ({ type, lid: extractServerIds(type) })) + .filter(s => s.lid); + + const streams = []; + const subtitles = []; + + await Promise.all(servers.map(async ({ type, lid }) => { + try { + const decLidRes = await fetchv2(`https://enc-dec.app/api/enc-kai?text=${encodeURIComponent(lid)}`); + const decLidData = await decLidRes.json(); + const decodedLid = decLidData.result; + + const viewUrl = `https://anikai.to/ajax/links/view?id=${lid}&_=${decodedLid}`; + const viewRes = await fetchv2(viewUrl); + const viewJson = await viewRes.json(); + const encodedResult = viewJson.result; + + const decRes = await fetchv2( + "https://enc-dec.app/api/dec-kai", + { "Content-Type": "application/json" }, + "POST", + JSON.stringify({ text: encodedResult }) + ); + const decJson = await decRes.json(); + let iframeUrl = decJson.result?.url ?? null; + + if (!iframeUrl) return; + + if (iframeUrl.includes("anikai.to/iframe")) { + const iframePageRes = await fetchv2(iframeUrl, headers); + const iframePageText = await iframePageRes.text(); + const iframeSrcMatch = iframePageText.match(/]+src="([^"]+)"/i); + if (iframeSrcMatch && iframeSrcMatch[1]) { + iframeUrl = iframeSrcMatch[1]; + } + } + + const mediaUrl = iframeUrl.replace("/e/", "/media/").replace("/e2/", "/media/"); + + const mediaRes = await fetchv2(mediaUrl, headers); + const mediaJson = await mediaRes.json(); + const encodedM3u8 = mediaJson?.result; + + if (!encodedM3u8) return; + + const finalRes = await fetchv2( + "https://enc-dec.app/api/dec-mega", + { "Content-Type": "application/json" }, + "POST", + JSON.stringify({ text: encodedM3u8, agent: headers["User-Agent"] }) + ); + const finalJson = await finalRes.json(); + + const sources = finalJson?.result?.sources ?? []; + const tracks = finalJson?.result?.tracks ?? []; + + const file = sources[0]?.file ?? null; + + if (file) { + const titleMap = { dub: "Dubbed English" }; + streams.push({ title: titleMap[type] || type, streamUrl: "https://1anime.app/api/m3u8-proxy?url=" + file }); + } + + for (const track of tracks) { + if (track.file && track.label) { + subtitles.push({ url: track.file, language: track.label }); + } + } + + } catch (e) { + console.log(`[extractStreamUrl] error for ${type}:`, e.toString()); + } + })); + + return streams.length > 0 ? streams[0].streamUrl : "error"; + } catch (error) { + console.error("Animekai fetch error:" + error); + return "https://error.org"; } - - return "error"; - } catch (error) { - console.log("Fetch error:" + error); - return "https://error.org"; - } } function cleanHtmlSymbols(string) { diff --git a/animekai/dub/animekai.json b/animekai/dub/animekai.json index 797c9c5..ab38d8e 100644 --- a/animekai/dub/animekai.json +++ b/animekai/dub/animekai.json @@ -5,7 +5,7 @@ "name": "50/50", "icon": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQ3122kQwublLkZ6rf1fEpUP79BxZOFmH9BSA&s" }, - "version": "1.1.5", + "version": "1.1.6", "language": "English", "streamType": "HLS", "quality": "1080p", diff --git a/animekai/hardsub/animekai.js b/animekai/hardsub/animekai.js index e887984..27dd148 100644 --- a/animekai/hardsub/animekai.js +++ b/animekai/hardsub/animekai.js @@ -121,131 +121,120 @@ async function extractStreamUrl(url) { try { const tokenMatch = url.match(/token=([^&]+)/); - if (tokenMatch && tokenMatch[1]) { - const rawToken = tokenMatch[1]; - const encryptResponse = await fetchv2(`https://enc-dec.app/api/enc-kai?text=${encodeURIComponent(rawToken)}`); - const encryptData = await encryptResponse.json(); - const encryptedToken = encryptData.result; - url = url.replace('&_=ENCRYPT_ME', `&_=${encryptedToken}`); - } - - const response = await fetchv2("https://deno-proxies-sznvnpnxwhbv.deno.dev/?url=" + encodeURIComponent(url)); - const text = await response.text(); + if (!tokenMatch?.[1]) throw new Error("No token found in URL"); + const rawToken = tokenMatch[1]; - let ajaxResultHtml = ""; - try { - const parsedAjax = JSON.parse(text); - ajaxResultHtml = parsedAjax?.result || ""; - } catch {} + const encTokenRes = await fetchv2(`https://enc-dec.app/api/enc-kai?text=${encodeURIComponent(rawToken)}`); + const encTokenData = await encTokenRes.json(); + const encryptedToken = encTokenData.result; - const cleanedHtml = cleanJsonHtml(text); - const cleanedAjaxResultHtml = cleanJsonHtml(ajaxResultHtml); - const serverHtmlSource = cleanedAjaxResultHtml || cleanedHtml; + const actualUrl = url.replace('&_=ENCRYPT_ME', `&_=${encryptedToken}`); - const subRegex = /
]*>([\s\S]*?)<\/div>/; - const softsubRegex = /
]*>([\s\S]*?)<\/div>/; - const dubRegex = /
]*>([\s\S]*?)<\/div>/; - const subContent = subRegex.exec(serverHtmlSource)?.[1]?.trim() || ""; - const softsubContent = softsubRegex.exec(serverHtmlSource)?.[1]?.trim() || ""; - const dubContent = dubRegex.exec(serverHtmlSource)?.[1]?.trim() || ""; + const response = await fetchv2(actualUrl); + const text = await response.text(); - const extractServerId = (content) => { - if (!content) return null; - const preferred = /]*data-lid="([^"]+)"[^>]*>\s*Server\s*1\s*<\/span>/i.exec(content); - if (preferred?.[1]) return preferred[1]; - return /]*data-lid="([^"]+)"/i.exec(content)?.[1] || null; - }; + let ajaxResultHtml = ""; + try { + const parsedAjax = JSON.parse(text); + ajaxResultHtml = parsedAjax?.result || ""; + } catch {} - const serverIdDub = extractServerId(dubContent); - const serverIdSoftsub = extractServerId(softsubContent); - const serverIdSub = extractServerId(subContent); + const cleanedHtml = cleanJsonHtml(text); + const cleanedAjaxResultHtml = cleanJsonHtml(ajaxResultHtml); + const serverHtmlSource = cleanedAjaxResultHtml || cleanedHtml; - const tokenRequestData = [ - { name: "Dub", data: serverIdDub }, - { name: "Softsub", data: serverIdSoftsub }, - { name: "Sub", data: serverIdSub } - ].filter(item => item.data); - - const tokenPromises = tokenRequestData.map(item => - fetchv2(`https://enc-dec.app/api/enc-kai?text=${encodeURIComponent(item.data)}`) - .then(res => res.json()) - .then(json => ({ name: item.name, data: json.result })) - .catch(err => ({ name: item.name, error: err.toString() })) - ); - const tokenResults = await Promise.all(tokenPromises); - - const serverIdMap = { - "Dub": serverIdDub, - "Softsub": serverIdSoftsub, - "Sub": serverIdSub - }; - - const streamUrls = tokenResults.map(result => ({ - type: result.name, - url: `https://anikai.to/ajax/links/view?id=${serverIdMap[result.name]}&_=${result.data}` - })); - - // Step 1: fetch links/view via proxy - const streamResponses = await Promise.all( - streamUrls.map(async ({ type, url }) => { - try { - const res = await fetchv2("https://deno-proxies-sznvnpnxwhbv.deno.dev/?url=" + encodeURIComponent(url)); - const json = await res.json(); - return { type, result: json.result }; - } catch (error) { - console.log(`Error fetching ${type} stream:`, error); - return { type, result: null }; - } - }) - ); - - // Step 2: decrypt with browser UA — no encodeURIComponent - const decryptPromises = streamResponses - .filter(item => item.result) - .map(item => - fetchv2(`https://enc-dec.app/api/dec-kai?text=${item.result}`, headers) - .then(res => res.json()) - .then(json => { - console.log(`decrypted ${item.type} URL:`, json.result?.url); - return { name: item.type, url: json.result?.url || null }; - }) - .catch(err => ({ name: item.type, url: null })) - ); - const decryptResults = await Promise.all(decryptPromises); - - const urlMap = Object.fromEntries(decryptResults.map(i => [i.name, i.url])); - const decryptedSub = urlMap.Sub || urlMap.Dub || urlMap.Softsub; - - console.log("Using URL:", decryptedSub); - - if (decryptedSub) { - const mediaResponse = await fetchv2(decryptedSub.replace("/e/", "/media/"), headers); - const responseJson = await mediaResponse.json(); - const result = responseJson?.result; - - const postData = { - "text": result, - "agent": headers["User-Agent"] + const extractServerIds = (type) => { + const regex = new RegExp(`
]*>([\\s\\S]*?)<\\/div>`); + const content = regex.exec(serverHtmlSource)?.[1] ?? ""; + const spanRegex = /]*data-lid="([^"]+)"[^>]*>/g; + const ids = []; + let match; + while ((match = spanRegex.exec(content)) !== null) ids.push(match[1]); + return ids.length > 1 ? ids[1] : ids[0] ?? null; }; - const finalResponse = await fetchv2( - "https://enc-dec.app/api/dec-mega", - { "Content-Type": "application/json" }, - "POST", - JSON.stringify(postData) - ); - const finalJson = await finalResponse.json(); - console.log("dec-mega result:", finalJson); - const m3u8Link = finalJson?.result?.sources?.[0]?.file; + const types = ["sub"]; - return m3u8Link; + const servers = types + .map(type => ({ type, lid: extractServerIds(type) })) + .filter(s => s.lid); + + const streams = []; + const subtitles = []; + + await Promise.all(servers.map(async ({ type, lid }) => { + try { + const decLidRes = await fetchv2(`https://enc-dec.app/api/enc-kai?text=${encodeURIComponent(lid)}`); + const decLidData = await decLidRes.json(); + const decodedLid = decLidData.result; + + const viewUrl = `https://anikai.to/ajax/links/view?id=${lid}&_=${decodedLid}`; + const viewRes = await fetchv2(viewUrl); + const viewJson = await viewRes.json(); + const encodedResult = viewJson.result; + + const decRes = await fetchv2( + "https://enc-dec.app/api/dec-kai", + { "Content-Type": "application/json" }, + "POST", + JSON.stringify({ text: encodedResult }) + ); + const decJson = await decRes.json(); + let iframeUrl = decJson.result?.url ?? null; + + if (!iframeUrl) return; + + if (iframeUrl.includes("anikai.to/iframe")) { + const iframePageRes = await fetchv2(iframeUrl, headers); + const iframePageText = await iframePageRes.text(); + const iframeSrcMatch = iframePageText.match(/]+src="([^"]+)"/i); + if (iframeSrcMatch && iframeSrcMatch[1]) { + iframeUrl = iframeSrcMatch[1]; + } + } + + const mediaUrl = iframeUrl.replace("/e/", "/media/").replace("/e2/", "/media/"); + + const mediaRes = await fetchv2(mediaUrl, headers); + const mediaJson = await mediaRes.json(); + const encodedM3u8 = mediaJson?.result; + + if (!encodedM3u8) return; + + const finalRes = await fetchv2( + "https://enc-dec.app/api/dec-mega", + { "Content-Type": "application/json" }, + "POST", + JSON.stringify({ text: encodedM3u8, agent: headers["User-Agent"] }) + ); + const finalJson = await finalRes.json(); + + const sources = finalJson?.result?.sources ?? []; + const tracks = finalJson?.result?.tracks ?? []; + + const file = sources[0]?.file ?? null; + + if (file) { + const titleMap = { sub: "Hardsub English" }; + streams.push({ title: titleMap[type] || type, streamUrl: "https://1anime.app/api/m3u8-proxy?url=" + file }); + } + + for (const track of tracks) { + if (track.file && track.label) { + subtitles.push({ url: track.file, language: track.label }); + } + } + + } catch (e) { + console.log(`[extractStreamUrl] error for ${type}:`, e.toString()); + } + })); + + return streams.length > 0 ? streams[0].streamUrl : "error"; + } catch (error) { + console.error("Animekai fetch error:" + error); + return "https://error.org"; } - - return "error"; - } catch (error) { - console.log("Fetch error:" + error); - return "https://error.org"; - } } function cleanHtmlSymbols(string) { diff --git a/animekai/hardsub/animekai.json b/animekai/hardsub/animekai.json index 849774b..10f6acd 100644 --- a/animekai/hardsub/animekai.json +++ b/animekai/hardsub/animekai.json @@ -5,7 +5,7 @@ "name": "50/50", "icon": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQ3122kQwublLkZ6rf1fEpUP79BxZOFmH9BSA&s" }, - "version": "1.1.3", + "version": "1.1.4", "language": "English", "streamType": "HLS", "quality": "1080p", diff --git a/ashi/ashi.js b/ashi/ashi.js index 49dab73..de5e376 100644 --- a/ashi/ashi.js +++ b/ashi/ashi.js @@ -650,7 +650,16 @@ async function extractStreamUrl(url) { async function getStream(url) { try { - const response = await fetchv2(url.replace("/e/", "/media/"), headers); + if (url.includes("anikai.to/iframe")) { + const iframePageRes = await fetchv2(url, headers); + const iframePageText = await iframePageRes.text(); + const iframeSrcMatch = iframePageText.match(/]+src="([^"]+)"/i); + if (iframeSrcMatch && iframeSrcMatch[1]) { + url = iframeSrcMatch[1]; + } + } + + const response = await fetchv2(url.replace("/e/", "/media/").replace("/e2/", "/media/"), headers); const responseJson = await response.json(); const result = responseJson?.result; const finalResponse = await fetchv2( @@ -673,9 +682,9 @@ async function extractStreamUrl(url) { ]); const streams = []; - if (subStream) streams.push({ title: "Hardsub English", streamUrl: subStream }); - if (dubStream) streams.push({ title: "Dubbed English", streamUrl: dubStream }); - if (rawStream) streams.push({ title: "Original audio", streamUrl: rawStream }); + if (subStream) streams.push({ title: "Hardsub English", streamUrl: "https://1anime.app/api/m3u8-proxy?url=" + subStream }); + if (dubStream) streams.push({ title: "Dubbed English", streamUrl: "https://1anime.app/api/m3u8-proxy?url=" + dubStream }); + if (rawStream) streams.push({ title: "Original audio", streamUrl: "https://1anime.app/api/m3u8-proxy?url=" + rawStream }); const final = { streams, subtitles: "" }; console.log("RETURN: " + JSON.stringify(final)); @@ -702,19 +711,21 @@ async function extractStreamUrl(url) { actualUrl = actualUrl.replace('&_=ENCRYPT_ME', `&_=${encryptedToken}`); } - const response = await fetchv2("https://deno-proxies-sznvnpnxwhbv.deno.dev/?url=" + encodeURIComponent(actualUrl)); + const response = await fetchv2(actualUrl); const responseData = await response.json(); const cleanedHtml = cleanJsonHtml(responseData.result); - const server1Regex = /
]*data-lid="([^"]+)"[^>]*>\s*Server 1<\/span>/; - const server1Match = server1Regex.exec(cleanedHtml); + const spanRegex = /
]*data-lid="([^"]+)"[^>]*>/g; + const ids = []; + let match; + while ((match = spanRegex.exec(cleanedHtml)) !== null) ids.push(match[1]); - if (!server1Match) { - console.log("Server 1 not found"); + if (ids.length === 0) { + console.log("No servers found"); return "error"; } - const serverId = server1Match[1]; + const serverId = ids.length > 1 ? ids[1] : ids[0]; const tokenData = await fetchv2(`https://enc-dec.app/api/enc-movies-flix?text=${encodeURIComponent(serverId)}`) .then(res => res.json()); const token = tokenData.result; @@ -725,7 +736,7 @@ async function extractStreamUrl(url) { } const streamUrl = `https://1movies.bz/ajax/links/view?id=${serverId}&_=${token}`; - const streamResponse = await fetchv2("https://deno-proxies-sznvnpnxwhbv.deno.dev/?url=" + encodeURIComponent(streamUrl)); + const streamResponse = await fetchv2(streamUrl); const streamData = await streamResponse.json(); if (!streamData.result) { @@ -762,7 +773,25 @@ async function extractStreamUrl(url) { ? subtitles.find(sub => sub.label === "English")?.file.replace(/\\\//g, "/") : "N/A"; - const mediaResponse = await fetchv2(decryptedUrl.replace("/e/", "/media/"), headers); + let finalUrl = decryptedUrl; + if (finalUrl.includes(".to/iframe")) { + try { + const iframeResponse = await fetchv2(finalUrl, headers); + const iframeHtml = await iframeResponse.text(); + const iframeSrcMatch = iframeHtml.match(/]+src="([^"]+)"/i); + if (iframeSrcMatch && iframeSrcMatch[1]) { + finalUrl = iframeSrcMatch[1]; + } else { + console.log("No iframe src found in:", finalUrl); + return "error"; + } + } catch (e) { + console.log("Error fetching iframe:", e); + return "error"; + } + } + + const mediaResponse = await fetchv2(finalUrl.replace("/e/", "/media/"), headers); const mediaJson = await mediaResponse.json(); const result = mediaJson?.result; @@ -775,29 +804,12 @@ async function extractStreamUrl(url) { const finalJson = JSON.parse(await finalResponse.text()); const m3u8Link = finalJson?.result?.sources?.[0]?.file; - const m3u8Response = await fetchv2(m3u8Link); - const m3u8Text = await m3u8Response.text(); - - const baseUrl = m3u8Link.substring(0, m3u8Link.lastIndexOf('/') + 1); const streams = []; - const lines = m3u8Text.split('\n'); - - for (let i = 0; i < lines.length; i++) { - const line = lines[i].trim(); - if (line.startsWith('#EXT-X-STREAM-INF:')) { - const resolutionMatch = line.match(/RESOLUTION=(\d+x\d+)/); - let quality = 'Unknown'; - if (resolutionMatch) { - const [width, height] = resolutionMatch[1].split('x'); - quality = `${height}p`; - } - if (i + 1 < lines.length) { - streams.push({ - title: quality, - streamUrl: baseUrl + lines[i + 1].trim() - }); - } - } + if (m3u8Link) { + streams.push({ + title: "Auto", + streamUrl: "https://1anime.app/api/m3u8-proxy?url=" + m3u8Link + }); } const returnValue = { diff --git a/ashi/ashi.json b/ashi/ashi.json index d7a17c0..ccc8a09 100644 --- a/ashi/ashi.json +++ b/ashi/ashi.json @@ -5,7 +5,7 @@ "name": "50/50", "icon": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQ3122kQwublLkZ6rf1fEpUP79BxZOFmH9BSA&s" }, - "version": "1.3.1", + "version": "1.3.2", "language": "English", "streamType": "HLS", "quality": "1080p",