diff --git a/.tmp.driveupload/2714 b/.tmp.driveupload/2714 new file mode 100644 index 0000000..fd1b7b2 Binary files /dev/null and b/.tmp.driveupload/2714 differ diff --git a/.tmp.driveupload/2744 b/.tmp.driveupload/2744 new file mode 100644 index 0000000..2eb77a7 --- /dev/null +++ b/.tmp.driveupload/2744 @@ -0,0 +1,296 @@ +async function searchResults(query) { + const encodeQuery = keyword => encodeURIComponent(keyword); + const searchBaseUrl = "https://animekai.to/browser?keyword="; + const baseUrl = "https://animekai.to"; + + const posterHrefRegex = /href="[^"]*" class="poster"/g; + const titleRegex = /class="title"[^>]*title="[^"]*"/g; + const imageRegex = /data-src="[^"]*"/g; + const extractHrefRegex = /href="([^"]*)"/; + const extractImageRegex = /data-src="([^"]*)"/; + const extractTitleRegex = /title="([^"]*)"/; + + try { + const encodedQuery = encodeQuery(query); + const searchUrl = searchBaseUrl + encodedQuery; + const response = await fetchv2(searchUrl); + const htmlText = await response.text(); + + const results = []; + const posterMatches = htmlText.match(posterHrefRegex) || []; + const titleMatches = htmlText.match(titleRegex) || []; + const imageMatches = htmlText.match(imageRegex) || []; + + const minLength = Math.min(posterMatches.length, titleMatches.length, imageMatches.length); + + for (let index = 0; index < minLength; index++) { + const hrefMatch = posterMatches[index].match(extractHrefRegex); + const fullHref = hrefMatch ? + (hrefMatch[1].startsWith("http") ? hrefMatch[1] : baseUrl + hrefMatch[1]) : + null; + + const imageMatch = imageMatches[index].match(extractImageRegex); + const imageSrc = imageMatch ? imageMatch[1] : null; + + const titleMatch = titleMatches[index].match(extractTitleRegex); + const cleanTitle = titleMatch ? + decodeHtmlEntities(titleMatch[1]) : + null; + + if (fullHref && imageSrc && cleanTitle) { + results.push({ + href: fullHref, + image: imageSrc, + title: cleanTitle + }); + } + } + + return JSON.stringify(results); + } catch (error) { + return JSON.stringify([{ + href: "", + image: "", + title: "Search failed: " + error.message + }]); + } +} + +async function extractDetails(url) { + try { + const response = await fetchv2(url); + const htmlText = await response.text(); + console.log(htmlText); + + const descriptionMatch = (/
([\s\S]*?)<\/div>/.exec(htmlText) || [])[1]; + const aliasesMatch = (/([\s\S]*?)<\/small>/.exec(htmlText) || [])[1]; + + return JSON.stringify([{ + description: descriptionMatch ? cleanHtmlSymbols(descriptionMatch) : "Not available", + aliases: aliasesMatch ? cleanHtmlSymbols(aliasesMatch) : "Not available", + airdate: "If stream doesn't load try later or disable VPN/DNS" + }]); + } catch (error) { + console.error("Error fetching details:" + error); + return [{ + description: "Error loading description", + aliases: "Aliases: Unknown", + airdate: "Aired: Unknown" + }]; + } +} + +async function extractEpisodes(url) { + try { + const actualUrl = url.replace("Animekai:", "").trim(); + const htmlText = await (await fetchv2(actualUrl)).text(); + const animeIdMatch = (htmlText.match(/
]*data-id="([^"]+)"/) || [])[1]; + if (!animeIdMatch) return JSON.stringify([{ error: "AniID not found" }]); + + const tokenResponse = await fetchv2(`https://enc-dec.app/api/enc-kai?text=${encodeURIComponent(animeIdMatch)}`); + const tokenData = await tokenResponse.json(); + const token = tokenData.result; + + const episodeListUrl = `https://animekai.to/ajax/episodes/list?ani_id=${animeIdMatch}&_=${token}`; + const episodeListData = await (await fetchv2(episodeListUrl)).json(); + const cleanedHtml = cleanJsonHtml(episodeListData.result); + + const episodeRegex = /]+num="([^"]+)"[^>]+token="([^"]+)"[^>]*>/g; + const episodeMatches = [...cleanedHtml.matchAll(episodeRegex)]; + + const episodes = episodeMatches.map(([_, episodeNum, episodeToken]) => ({ + number: parseInt(episodeNum, 10), + href: `https://animekai.to/ajax/links/list?token=${episodeToken}&_=ENCRYPT_ME` + })); + + return JSON.stringify(episodes); + } catch (err) { + console.error("Error fetching episodes:" + err); + return [{ + number: 1, + href: "Error fetching episodes" + }]; + } +} + +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 fetchUrl = `${url}`; + const response = await fetchv2(fetchUrl); + const text = await response.text(); + const cleanedHtml = cleanJsonHtml(text); + const subRegex = /
]*>([\s\S]*?)<\/div>/; + const softsubRegex = /
]*>([\s\S]*?)<\/div>/; + const dubRegex = /
]*>([\s\S]*?)<\/div>/; + const subMatch = subRegex.exec(cleanedHtml); + const softsubMatch = softsubRegex.exec(cleanedHtml); + const dubMatch = dubRegex.exec(cleanedHtml); + const subContent = subMatch ? subMatch[1].trim() : ""; + const softsubContent = softsubMatch ? softsubMatch[1].trim() : ""; + const dubContent = dubMatch ? dubMatch[1].trim() : ""; + const serverSpanRegex = /]*data-lid="([^"]+)"[^>]*>Server 1<\/span>/; + const serverIdDub = serverSpanRegex.exec(dubContent)?.[1]; + const serverIdSoftsub = serverSpanRegex.exec(softsubContent)?.[1]; + const serverIdSub = serverSpanRegex.exec(subContent)?.[1]; + + 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 streamUrls = tokenResults.map(result => { + const serverIdMap = { + "Dub": serverIdDub, + "Softsub": serverIdSoftsub, + "Sub": serverIdSub + }; + return { + type: result.name, + url: `https://animekai.to/ajax/links/view?id=${serverIdMap[result.name]}&_=${result.data}` + }; + }); + + const processStreams = async (streamUrls) => { + const streamResponses = await Promise.all( + streamUrls.map(async ({ type, url }) => { + try { + const res = await fetchv2(url); + const json = await res.json(); + return { + type: type, + result: json.result + }; + } catch (error) { + console.log(`Error fetching ${type} stream:`, error); + return { + type: type, + result: null + }; + } + }) + ); + + const decryptRequestData = streamResponses + .filter(item => item.result) + .map(item => ({ + name: item.type, + data: item.result + })); + + if (decryptRequestData.length === 0) { + return {}; + } + + const decryptPromises = decryptRequestData.map(item => + fetchv2(`https://enc-dec.app/api/dec-kai?text=${encodeURIComponent(item.data)}`) + .then(res => res.json()) + .then(json => ({ name: item.name, data: JSON.stringify(json.result) })) + .catch(err => ({ name: item.name, error: err.toString() })) + ); + const decryptResults = await Promise.all(decryptPromises); + + const finalResults = {}; + decryptResults.forEach(result => { + try { + const parsed = JSON.parse(result.data); + finalResults[result.name] = parsed.url; + console.log(`decrypted${result.name} URL:` + parsed.url); + } catch (error) { + console.log(`Error parsing ${result.name} result:`, error); + finalResults[result.name] = null; + } + }); + + return finalResults; + }; + + const decryptedUrls = await processStreams(streamUrls); + const decryptedSub = decryptedUrls.Sub || decryptedUrls.Dub || decryptedUrls.Softsub; + + console.log(decryptedSub); + const headers = { + "Referer": "https://animekai.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" + }; + + if (decryptedSub) { + const response = await fetchv2(decryptedSub.replace("/e/", "/media/").replace("megaup22", "megaup.site"), headers); + const responseJson = await response.json(); + + const result = responseJson?.result; + + const postData = { + "text": result, + "Useragent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36" + } + + const finalResponse = await fetchv2("https://ilovekai.simplepostrequest.workers.dev/ilovebush", {}, "POST", JSON.stringify(postData)); + const finalJson = await finalResponse.json(); + const m3u8Link = finalJson?.result?.sources?.[0]?.file; + + return m3u8Link; + } + + return "error"; + } catch (error) { + console.log("Fetch error:"+ error); + return "https://error.org"; + } +} + +function cleanHtmlSymbols(string) { + if (!string) { + return ""; + } + return string + .replace(/’/g, "'") + .replace(/–/g, "-") + .replace(/&#[0-9]+;/g, "") + .replace(/\r?\n|\r/g, " ") + .replace(/\s+/g, " ") + .trim(); +} + +function cleanJsonHtml(jsonHtml) { + if (!jsonHtml) { + return ""; + } + return jsonHtml + .replace(/\\"/g, "\"") + .replace(/\\'/g, "'") + .replace(/\\\\/g, "\\") + .replace(/\\n/g, "\n") + .replace(/\\t/g, "\t") + .replace(/\\r/g, "\r"); +} + +function decodeHtmlEntities(text) { + if (!text) { + return ""; + } + return text + .replace(/'/g, "'") + .replace(/"/g, "\"") + .replace(/&/g, "&") + .replace(/</g, "<") + .replace(/>/g, ">") + .replace(/ /g, " "); +} diff --git a/.tmp.driveupload/2746 b/.tmp.driveupload/2746 new file mode 100644 index 0000000..3639642 --- /dev/null +++ b/.tmp.driveupload/2746 @@ -0,0 +1,20 @@ +{ + "sourceName": "AnimeKai (Hardsub)", + "iconUrl": "https://apktodo.io/uploads/2025/5/animekai-icon.jpg", + "author": { + "name": "50/50", + "icon": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQ3122kQwublLkZ6rf1fEpUP79BxZOFmH9BSA&s" + }, + "version": "1.0.5", + "language": "English", + "streamType": "HLS", + "quality": "1080p", + "baseUrl": "https://animekai.to/", + "searchBaseUrl": "https://animekai.to/", + "scriptUrl": "https://git.luna-app.eu/50n50/sources/raw/branch/main/animekai/hardsub/animekai.js", + "type": "anime", + "asyncJS": true, + "softsub": false, + "downloadSupport": true, + "note": "Make sure you're on the latest version of Sora." +} diff --git a/.tmp.driveupload/2750 b/.tmp.driveupload/2750 new file mode 100644 index 0000000..b0629d2 --- /dev/null +++ b/.tmp.driveupload/2750 @@ -0,0 +1,296 @@ +async function searchResults(query) { + const encodeQuery = keyword => encodeURIComponent(keyword); + const searchBaseUrl = "https://animekai.to/browser?keyword="; + const baseUrl = "https://animekai.to"; + + const posterHrefRegex = /href="[^"]*" class="poster"/g; + const titleRegex = /class="title"[^>]*title="[^"]*"/g; + const imageRegex = /data-src="[^"]*"/g; + const extractHrefRegex = /href="([^"]*)"/; + const extractImageRegex = /data-src="([^"]*)"/; + const extractTitleRegex = /title="([^"]*)"/; + + try { + const encodedQuery = encodeQuery(query); + const searchUrl = searchBaseUrl + encodedQuery; + const response = await fetchv2(searchUrl); + const htmlText = await response.text(); + + const results = []; + const posterMatches = htmlText.match(posterHrefRegex) || []; + const titleMatches = htmlText.match(titleRegex) || []; + const imageMatches = htmlText.match(imageRegex) || []; + + const minLength = Math.min(posterMatches.length, titleMatches.length, imageMatches.length); + + for (let index = 0; index < minLength; index++) { + const hrefMatch = posterMatches[index].match(extractHrefRegex); + const fullHref = hrefMatch ? + (hrefMatch[1].startsWith("http") ? hrefMatch[1] : baseUrl + hrefMatch[1]) : + null; + + const imageMatch = imageMatches[index].match(extractImageRegex); + const imageSrc = imageMatch ? imageMatch[1] : null; + + const titleMatch = titleMatches[index].match(extractTitleRegex); + const cleanTitle = titleMatch ? + decodeHtmlEntities(titleMatch[1]) : + null; + + if (fullHref && imageSrc && cleanTitle) { + results.push({ + href: fullHref, + image: imageSrc, + title: cleanTitle + }); + } + } + + return JSON.stringify(results); + } catch (error) { + return JSON.stringify([{ + href: "", + image: "", + title: "Search failed: " + error.message + }]); + } +} + +async function extractDetails(url) { + try { + const response = await fetchv2(url); + const htmlText = await response.text(); + console.log(htmlText); + + const descriptionMatch = (/
([\s\S]*?)<\/div>/.exec(htmlText) || [])[1]; + const aliasesMatch = (/([\s\S]*?)<\/small>/.exec(htmlText) || [])[1]; + + return JSON.stringify([{ + description: descriptionMatch ? cleanHtmlSymbols(descriptionMatch) : "Not available", + aliases: aliasesMatch ? cleanHtmlSymbols(aliasesMatch) : "Not available", + airdate: "If stream doesn't load try later or disable VPN/DNS" + }]); + } catch (error) { + console.error("Error fetching details:" + error); + return [{ + description: "Error loading description", + aliases: "Aliases: Unknown", + airdate: "Aired: Unknown" + }]; + } +} + +async function extractEpisodes(url) { + try { + const actualUrl = url.replace("Animekai:", "").trim(); + const htmlText = await (await fetchv2(actualUrl)).text(); + const animeIdMatch = (htmlText.match(/
]*data-id="([^"]+)"/) || [])[1]; + if (!animeIdMatch) return JSON.stringify([{ error: "AniID not found" }]); + + const tokenResponse = await fetchv2(`https://enc-dec.app/api/enc-kai?text=${encodeURIComponent(animeIdMatch)}`); + const tokenData = await tokenResponse.json(); + const token = tokenData.result; + + const episodeListUrl = `https://animekai.to/ajax/episodes/list?ani_id=${animeIdMatch}&_=${token}`; + const episodeListData = await (await fetchv2(episodeListUrl)).json(); + const cleanedHtml = cleanJsonHtml(episodeListData.result); + + const episodeRegex = /]+num="([^"]+)"[^>]+token="([^"]+)"[^>]*>/g; + const episodeMatches = [...cleanedHtml.matchAll(episodeRegex)]; + + const episodes = episodeMatches.map(([_, episodeNum, episodeToken]) => ({ + number: parseInt(episodeNum, 10), + href: `https://animekai.to/ajax/links/list?token=${episodeToken}&_=ENCRYPT_ME` + })); + + return JSON.stringify(episodes); + } catch (err) { + console.error("Error fetching episodes:" + err); + return [{ + number: 1, + href: "Error fetching episodes" + }]; + } +} + +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 fetchUrl = `${url}`; + const response = await fetchv2(fetchUrl); + const text = await response.text(); + const cleanedHtml = cleanJsonHtml(text); + const subRegex = /
]*>([\s\S]*?)<\/div>/; + const softsubRegex = /
]*>([\s\S]*?)<\/div>/; + const dubRegex = /
]*>([\s\S]*?)<\/div>/; + const subMatch = subRegex.exec(cleanedHtml); + const softsubMatch = softsubRegex.exec(cleanedHtml); + const dubMatch = dubRegex.exec(cleanedHtml); + const subContent = subMatch ? subMatch[1].trim() : ""; + const softsubContent = softsubMatch ? softsubMatch[1].trim() : ""; + const dubContent = dubMatch ? dubMatch[1].trim() : ""; + const serverSpanRegex = /]*data-lid="([^"]+)"[^>]*>Server 1<\/span>/; + const serverIdDub = serverSpanRegex.exec(dubContent)?.[1]; + const serverIdSoftsub = serverSpanRegex.exec(softsubContent)?.[1]; + const serverIdSub = serverSpanRegex.exec(subContent)?.[1]; + + 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 streamUrls = tokenResults.map(result => { + const serverIdMap = { + "Dub": serverIdDub, + "Softsub": serverIdSoftsub, + "Sub": serverIdSub + }; + return { + type: result.name, + url: `https://animekai.to/ajax/links/view?id=${serverIdMap[result.name]}&_=${result.data}` + }; + }); + + const processStreams = async (streamUrls) => { + const streamResponses = await Promise.all( + streamUrls.map(async ({ type, url }) => { + try { + const res = await fetchv2(url); + const json = await res.json(); + return { + type: type, + result: json.result + }; + } catch (error) { + console.log(`Error fetching ${type} stream:`, error); + return { + type: type, + result: null + }; + } + }) + ); + + const decryptRequestData = streamResponses + .filter(item => item.result) + .map(item => ({ + name: item.type, + data: item.result + })); + + if (decryptRequestData.length === 0) { + return {}; + } + + const decryptPromises = decryptRequestData.map(item => + fetchv2(`https://enc-dec.app/api/dec-kai?text=${encodeURIComponent(item.data)}`) + .then(res => res.json()) + .then(json => ({ name: item.name, data: JSON.stringify(json.result) })) + .catch(err => ({ name: item.name, error: err.toString() })) + ); + const decryptResults = await Promise.all(decryptPromises); + + const finalResults = {}; + decryptResults.forEach(result => { + try { + const parsed = JSON.parse(result.data); + finalResults[result.name] = parsed.url; + console.log(`decrypted${result.name} URL:` + parsed.url); + } catch (error) { + console.log(`Error parsing ${result.name} result:`, error); + finalResults[result.name] = null; + } + }); + + return finalResults; + }; + + const decryptedUrls = await processStreams(streamUrls); + const decryptedDub = decryptedUrls.Dub || decryptedUrls.Sub || decryptedUrls.Softsub; + + console.log(decryptedDub); + const headers = { + "Referer": "https://animekai.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" + }; + + if (decryptedDub) { + const response = await fetchv2(decryptedDub.replace("/e/", "/media/").replace("megaup22", "megaup.site"), headers); + const responseJson = await response.json(); + + const result = responseJson?.result; + + const postData = { + "text": result, + "Useragent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36" + } + + const finalResponse = await fetchv2("https://ilovekai.simplepostrequest.workers.dev/ilovebush", {}, "POST", JSON.stringify(postData)); + const finalJson = await finalResponse.json(); + const m3u8Link = finalJson?.result?.sources?.[0]?.file; + + return m3u8Link; + } + + return "error"; + } catch (error) { + console.log("Fetch error:"+ error); + return "https://error.org"; + } +} + +function cleanHtmlSymbols(string) { + if (!string) { + return ""; + } + return string + .replace(/’/g, "'") + .replace(/–/g, "-") + .replace(/&#[0-9]+;/g, "") + .replace(/\r?\n|\r/g, " ") + .replace(/\s+/g, " ") + .trim(); +} + +function cleanJsonHtml(jsonHtml) { + if (!jsonHtml) { + return ""; + } + return jsonHtml + .replace(/\\"/g, "\"") + .replace(/\\'/g, "'") + .replace(/\\\\/g, "\\") + .replace(/\\n/g, "\n") + .replace(/\\t/g, "\t") + .replace(/\\r/g, "\r"); +} + +function decodeHtmlEntities(text) { + if (!text) { + return ""; + } + return text + .replace(/'/g, "'") + .replace(/"/g, "\"") + .replace(/&/g, "&") + .replace(/</g, "<") + .replace(/>/g, ">") + .replace(/ /g, " "); +} diff --git a/.tmp.driveupload/2752 b/.tmp.driveupload/2752 new file mode 100644 index 0000000..4b6f849 --- /dev/null +++ b/.tmp.driveupload/2752 @@ -0,0 +1,20 @@ +{ + "sourceName": "AnimeKai (Dub)", + "iconUrl": "https://apktodo.io/uploads/2025/5/animekai-icon.jpg", + "author": { + "name": "50/50", + "icon": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQ3122kQwublLkZ6rf1fEpUP79BxZOFmH9BSA&s" + }, + "version": "1.0.6", + "language": "English", + "streamType": "HLS", + "quality": "1080p", + "baseUrl": "https://animekai.to/", + "searchBaseUrl": "https://animekai.to/", + "scriptUrl": "https://git.luna-app.eu/50n50/sources/raw/branch/main/animekai/dub/animekai.js", + "type": "anime", + "asyncJS": true, + "softsub": false, + "downloadSupport": true, + "note": "Make sure you're on the latest version of Sora." +} diff --git a/.tmp.driveupload/3128 b/.tmp.driveupload/3128 new file mode 100644 index 0000000..e3f4c51 --- /dev/null +++ b/.tmp.driveupload/3128 @@ -0,0 +1,19 @@ +{ + "sourceName": "1Movies", + "iconUrl": "https://1movies.bz/assets/uploads/675b5c22f2829fc8e3a4030af7f4284acad017e5241280b3dc21.png", + "author": { + "name": "50/50", + "icon": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQ3122kQwublLkZ6rf1fEpUP79BxZOFmH9BSA&s" + }, + "version": "1.0.9", + "language": "English", + "streamType": "HLS", + "quality": "1080p", + "baseUrl": "https://animekai.to/", + "searchBaseUrl": "https://1movies.bz/home", + "scriptUrl": "https://git.luna-app.eu/50n50/sources/raw/branch/main/1movies/1movies.js", + "type": "shows/movies", + "asyncJS": true, + "softsub": true, + "downloadSupport": true +} diff --git a/.tmp.driveupload/3130 b/.tmp.driveupload/3130 new file mode 100644 index 0000000..d7942ea --- /dev/null +++ b/.tmp.driveupload/3130 @@ -0,0 +1,318 @@ +async function searchResults(query) { + const encodeQuery = keyword => encodeURIComponent(keyword); + const searchBaseUrl = "https://1movies.bz/browser?keyword="; + const baseUrl = "https://1movies.bz"; + + const posterHrefRegex = /href="([^"]*)" class="poster"/g; + const titleRegex = /class="title" href="[^"]*">([^<]*) { + const results = []; + const posterMatches = [...htmlText.matchAll(posterHrefRegex)]; + const titleMatches = [...htmlText.matchAll(titleRegex)]; + const imageMatches = [...htmlText.matchAll(imageRegex)]; + + const minLength = Math.min(posterMatches.length, titleMatches.length, imageMatches.length); + + for (let index = 0; index < minLength; index++) { + const href = posterMatches[index][1]; + const fullHref = href.startsWith("http") ? href : baseUrl + href; + + const imageSrc = imageMatches[index][1]; + + const title = titleMatches[index][1]; + const cleanTitle = decodeHtmlEntities(title); + + if (fullHref && imageSrc && cleanTitle) { + results.push({ + href: fullHref, + image: imageSrc, + title: cleanTitle + }); + } + } + return results; + }; + + try { + const encodedQuery = encodeQuery(query); + + const urls = [ + `${searchBaseUrl}${encodedQuery}`, + `${searchBaseUrl}${encodedQuery}&page=2`, + `${searchBaseUrl}${encodedQuery}&page=3` + ]; + + const responses = await Promise.all(urls.map(url => fetchv2(url))); + + const htmlTexts = await Promise.all(responses.map(response => response.text())); + + const allResults = []; + htmlTexts.forEach(htmlText => { + const pageResults = extractResultsFromHTML(htmlText); + allResults.push(...pageResults); + }); + + return JSON.stringify(allResults); + } catch (error) { + return JSON.stringify([{ + href: "", + image: "", + title: "Search failed: " + error.message + }]); + } +} + +async function extractDetails(url) { + try { + const response = await fetchv2(url); + const htmlText = await response.text(); + + const descriptionMatch = (/
([\s\S]*?)<\/div>/.exec(htmlText) || [])[1]; + const aliasesMatch = (/([\s\S]*?)<\/small>/.exec(htmlText) || [])[1]; + const airdateMatch = (/
  • Released:\s*]*>(.*?)<\/span>/.exec(htmlText) || [])[1]; + + return JSON.stringify([{ + description: descriptionMatch ? cleanHtmlSymbols(descriptionMatch) : "Not available", + aliases: aliasesMatch ? cleanHtmlSymbols(aliasesMatch) : "Not aliases", + airdate: airdateMatch ? cleanHtmlSymbols(airdateMatch) : "Not available" + }]); + } catch (error) { + console.error("Error fetching details:" + error); + return [{ + description: "Error loading description", + aliases: "Not available", + airdate: "Not available" + }]; + } +} + +async function extractEpisodes(movieUrl) { + try { + const response = await fetchv2(movieUrl); + const htmlText = await response.text(); + const movieIDMatch = (htmlText.match(/
    ]*id="movie-rating"[^>]*data-id="([^"]+)"/) || [])[1]; + if (!movieIDMatch) { + return [{ + error: "MovieID not found" + }]; + } + + const movieIdApiUrl = `https://enc-dec.app/api/enc-movies-flix?text=${movieIDMatch}`; + const movieIdTokenResponse = await fetchv2(movieIdApiUrl); + const movieIdTokenData = await movieIdTokenResponse.json(); + const token = movieIdTokenData.result; + + const episodeListUrl = `https://1movies.bz/ajax/episodes/list?id=${movieIDMatch}&_=${token}`; + const episodeListResponse = await fetchv2(episodeListUrl); + const episodeListData = await episodeListResponse.json(); + const cleanedHtml = cleanJsonHtml(episodeListData.result); + + const episodeRegex = /]+eid="([^"]+)"[^>]+num="([^"]+)"[^>]*>/g; + const episodeMatches = [...cleanedHtml.matchAll(episodeRegex)]; + + const episodes = episodeMatches.map(([_, episodeToken, episodeNum]) => ({ + number: parseInt(episodeNum, 10), + href: `https://1movies.bz/ajax/links/list?eid=${episodeToken}&_=ENCRYPT_ME` + })); + + return JSON.stringify(episodes); + } catch (err) { + console.error("Error fetching episodes:" + err); + return [{ + number: 1, + href: "Error fetching episodes" + }]; + } +} + +async function extractStreamUrl(url) { + try { + const eidMatch = url.match(/eid=([^&]+)/); + if (eidMatch && eidMatch[1]) { + const rawEpisodeToken = eidMatch[1]; + const encryptResponse = await fetchv2(`https://enc-dec.app/api/enc-movies-flix?text=${rawEpisodeToken}`); + const encryptData = await encryptResponse.json(); + const encryptedToken = encryptData.result; + url = url.replace('&_=ENCRYPT_ME', `&_=${encryptedToken}`); + } + + const fetchUrl = `${url}`; + const response = await fetchv2(fetchUrl); + const responseData = await response.json(); + const cleanedHtml = cleanJsonHtml(responseData.result); + + const server1Regex = /
    ]*data-lid="([^"]+)"[^>]*>\s*Server 1<\/span>/; + const server1Match = server1Regex.exec(cleanedHtml); + + if (!server1Match) { + console.log("Server 1 not found"); + return "error"; + } + + const serverId = server1Match[1]; + + const tokenRequestData = [{ name: "Server1", data: serverId }]; + + const tokenBatchResponse = await fetchv2( + "https://ilovekai.simplepostrequest.workers.dev/ilovethighs", + {}, + "POST", + JSON.stringify(tokenRequestData) + ); + const tokenResults = await tokenBatchResponse.json(); + const token = tokenResults[0]?.data; + + if (!token) { + console.log("Token not found"); + return "error"; + } + + const streamUrl = `https://1movies.bz/ajax/links/view?id=${serverId}&_=${token}`; + const streamResponse = await fetchv2(streamUrl); + const streamData = await streamResponse.json(); + + if (!streamData.result) { + console.log("Stream result not found"); + return "error"; + } + + const decryptRequestData = [{ name: "Server1", data: streamData.result }]; + + const decryptBatchResponse = await fetchv2( + "https://ilovekai.simplepostrequest.workers.dev/iloveboobs", + {}, + "POST", + JSON.stringify(decryptRequestData) + ); + const decryptedResponse = await decryptBatchResponse.json(); + const decryptedUrl = decryptedResponse[0]?.data.url; + + const subListEncoded = decryptedUrl.split("sub.list=")[1]?.split("&")[0]; + let subtitles = "N/A"; + + if (subListEncoded) { + try { + const subListUrl = decodeURIComponent(subListEncoded); + const subResponse = await fetchv2(subListUrl); + subtitles = await subResponse.json(); + } catch { + subtitles = "N/A"; + } + } + + const englishSubUrl = Array.isArray(subtitles) + ? subtitles.find(sub => sub.label === "English")?.file.replace(/\\\//g, "/") + : "N/A"; + + if (!decryptedUrl) { + console.log("Decryption failed"); + return "error"; + } + + const headers = { + "Referer": "https://1movies.bz/", + "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 mediaResponse = await fetchv2(decryptedUrl.replace("/e/", "/media/"), headers); + const mediaJson = await mediaResponse.json(); + + const result = mediaJson?.result; + if (!result) { + console.log("Media result not found"); + return "error"; + } + + const postData = { + "text": result, + "Useragent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36" + }; + + const finalResponse = await fetchv2("https://ilovekai.simplepostrequest.workers.dev/ilovebush", {}, "POST", JSON.stringify(postData)); + const finalJson = await finalResponse.json(); + + 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) { + const streamPath = lines[i + 1].trim(); + const streamUrl = baseUrl + streamPath; + + streams.push({ + title: quality, + streamUrl: streamUrl + }); + } + } + } + + const returnValue = { + streams: streams, + subtitle: englishSubUrl !== "N/A" ? englishSubUrl : "" + }; + console.log("RETURN: " + JSON.stringify(returnValue)); + return JSON.stringify(returnValue); + } catch (error) { + console.log("Fetch error:"+ error); + return "https://error.org"; + } +} + +function cleanHtmlSymbols(string) { + if (!string) { + return ""; + } + return string + .replace(/’/g, "'") + .replace(/–/g, "-") + .replace(/&#[0-9]+;/g, "") + .replace(/\r?\n|\r/g, " ") + .replace(/\s+/g, " ") + .trim(); +} + +function cleanJsonHtml(jsonHtml) { + if (!jsonHtml) { + return ""; + } + return jsonHtml + .replace(/\\"/g, "\"") + .replace(/\\'/g, "'") + .replace(/\\\\/g, "\\") + .replace(/\\n/g, "\n") + .replace(/\\t/g, "\t") + .replace(/\\r/g, "\r"); +} + +function decodeHtmlEntities(text) { + if (!text) { + return ""; + } + return text + .replace(/'/g, "'") + .replace(/"/g, "\"") + .replace(/&/g, "&") + .replace(/</g, "<") + .replace(/>/g, ">") + .replace(/ /g, " "); +} diff --git a/.tmp.driveupload/3326 b/.tmp.driveupload/3326 new file mode 100644 index 0000000..8e8e23c --- /dev/null +++ b/.tmp.driveupload/3326 @@ -0,0 +1,36 @@ +
    + +
    +

    ⚠️ IMPORTANT

    +

    Any app meeting the following criteria is free to use my modules:

    +
      +
    1. No paywall, subscription, or payment required for my modules + (you may charge for other parts of your app).
    2. +
    3. No advertisements during the usage of my modules.
    4. +
    5. Open source: your app’s source code must be publicly available.
    6. +
    +

    All the above terms are mandatory unless given permission by me.
    +In short: no commercial use and transparency is required.

    +
    + +
    + +
    +

    🚫 CAUTION

    +

    Do not pay to use these modules — if someone is charging you, it's a scam!

    +

    Neither should you bear watching ads to use these modules. Please report apps that do this forcibly!

    +
    + +
    + +
    + +[![Discord Presence](https://lanyard.cnrad.dev/api/1072985316916469870?theme=dark&bg=000000&animated=false&hideDiscrim=true&borderRadius=30px&idleMessage=For%20requests%20or%20issues%2C%20use%20the%20Sora%20server.%20For%20module-usage%20questions%2C%20DM%20me.)](https://discord.com/users/1072985316916469870) + +
    + +[![Ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/50n50) + +
    +
    + diff --git a/.tmp.driveupload/3462 b/.tmp.driveupload/3462 new file mode 100644 index 0000000..41bffab --- /dev/null +++ b/.tmp.driveupload/3462 @@ -0,0 +1,19 @@ +{ + "sourceName": "Ashi (あし) - Literally Everything", + "iconUrl": "https://files.catbox.moe/y8v199.png", + "author": { + "name": "50/50", + "icon": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQ3122kQwublLkZ6rf1fEpUP79BxZOFmH9BSA&s" + }, + "version": "1.1.1", + "language": "English", + "streamType": "HLS", + "quality": "1080p", + "baseUrl": "https://animekai.to/", + "searchBaseUrl": "https://animekai.to/", + "scriptUrl": "https://git.luna-app.eu/50n50/sources/raw/branch/main/ashi/ashi.js", + "type": "anime/movies/shows", + "asyncJS": true, + "softsub": true, + "downloadSupport": true +} diff --git a/.tmp.driveupload/3464 b/.tmp.driveupload/3464 new file mode 100644 index 0000000..69436d5 --- /dev/null +++ b/.tmp.driveupload/3464 @@ -0,0 +1,761 @@ +// +// +// Main functions +// +// + +async function searchResults(query) { + const encodeQuery = keyword => encodeURIComponent(keyword); + + const decodeHtmlEntities = (str) => { + if (!str) return str; + return str.replace(/&#(\d+);/g, (match, dec) => String.fromCharCode(dec)) + .replace(/"/g, '"') + .replace(/&/g, '&') + .replace(/</g, '<') + .replace(/>/g, '>'); + }; + + const fuzzyMatch = (query, title) => { + const q = query.toLowerCase().trim(); + const t = title.toLowerCase().trim(); + + if (t === q) return 1000; + + if (t.startsWith(q + ' ') || t.startsWith(q + ':') || t.startsWith(q + '-')) return 950; + + const wordBoundaryRegex = new RegExp(`\\b${q.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\b`); + if (wordBoundaryRegex.test(t)) return 900; + + const qTokens = q.split(/\s+/).filter(token => token.length > 0); + const tTokens = t.split(/[\s\-:]+/).filter(token => token.length > 0); + + const stopwords = new Set(['the', 'a', 'an', 'and', 'or', 'of', 'in', 'on', 'at', 'to', 'for', 'with']); + + let score = 0; + let exactMatches = 0; + let partialMatches = 0; + let significantMatches = 0; + + qTokens.forEach(qToken => { + const isStopword = stopwords.has(qToken); + let bestMatch = 0; + let hasExactMatch = false; + + tTokens.forEach(tToken => { + let matchScore = 0; + + if (tToken === qToken) { + matchScore = isStopword ? 25 : 120; + hasExactMatch = true; + if (!isStopword) significantMatches++; + } + else if (qToken.includes(tToken) && tToken.length >= 3 && qToken.length <= tToken.length + 2) { + matchScore = isStopword ? 8 : 40; + if (!isStopword) significantMatches++; + } + else if (tToken.startsWith(qToken) && qToken.length >= 3) { + matchScore = isStopword ? 12 : 70; + if (!isStopword) significantMatches++; + } + else if (qToken.length >= 4 && tToken.length >= 4) { + const dist = levenshteinDistance(qToken, tToken); + const maxLen = Math.max(qToken.length, tToken.length); + const similarity = 1 - (dist / maxLen); + + if (similarity > 0.8) { + matchScore = Math.floor(similarity * 60); + if (!isStopword) significantMatches++; + } + } + + bestMatch = Math.max(bestMatch, matchScore); + }); + + if (bestMatch > 0) { + score += bestMatch; + if (hasExactMatch) exactMatches++; + else partialMatches++; + } + }); + + const significantTokens = qTokens.filter(t => !stopwords.has(t)).length; + + const requiredMatches = Math.max(1, Math.ceil(significantTokens * 0.8)); + if (significantMatches < requiredMatches) { + return 0; + } + + if (exactMatches + partialMatches >= qTokens.length) { + score += 80; + } + + score += exactMatches * 20; + + const extraWords = tTokens.length - qTokens.length; + if (extraWords > 2) { + score -= (extraWords - 2) * 25; + } + + let orderBonus = 0; + for (let i = 0; i < qTokens.length - 1; i++) { + const currentTokenIndex = tTokens.findIndex(t => t.includes(qTokens[i])); + const nextTokenIndex = tTokens.findIndex(t => t.includes(qTokens[i + 1])); + + if (currentTokenIndex !== -1 && nextTokenIndex !== -1 && currentTokenIndex < nextTokenIndex) { + orderBonus += 15; + } + } + score += orderBonus; + + return Math.max(0, score); + }; + + const levenshteinDistance = (a, b) => { + const matrix = []; + + for (let i = 0; i <= b.length; i++) { + matrix[i] = [i]; + } + + for (let j = 0; j <= a.length; j++) { + matrix[0][j] = j; + } + + for (let i = 1; i <= b.length; i++) { + for (let j = 1; j <= a.length; j++) { + if (b.charAt(i - 1) === a.charAt(j - 1)) { + matrix[i][j] = matrix[i - 1][j - 1]; + } else { + matrix[i][j] = Math.min( + matrix[i - 1][j - 1] + 1, + matrix[i][j - 1] + 1, + matrix[i - 1][j] + 1 + ); + } + } + } + + return matrix[b.length][a.length]; + }; + + const animekaiSearch = async () => { + const searchBaseUrl = "https://animekai.to/browser?keyword="; + const baseUrl = "https://animekai.to"; + + const posterHrefRegex = /href="[^"]*" class="poster"/g; + const titleRegex = /class="title"[^>]*title="[^"]*"/g; + const imageRegex = /data-src="[^"]*"/g; + const extractHrefRegex = /href="([^"]*)"/; + const extractImageRegex = /data-src="([^"]*)"/; + const extractTitleRegex = /title="([^"]*)"/; + + const extractResultsFromHTML = (htmlText) => { + const results = []; + const posterMatches = htmlText.match(posterHrefRegex) || []; + const titleMatches = htmlText.match(titleRegex) || []; + const imageMatches = htmlText.match(imageRegex) || []; + const minLength = Math.min(posterMatches.length, titleMatches.length, imageMatches.length); + + for (let i = 0; i < minLength; i++) { + const hrefMatch = posterMatches[i].match(extractHrefRegex); + const fullHref = hrefMatch ? (hrefMatch[1].startsWith("http") ? hrefMatch[1] : baseUrl + hrefMatch[1]) : null; + + const imageMatch = imageMatches[i].match(extractImageRegex); + const imageSrc = imageMatch ? imageMatch[1] : null; + + const titleMatch = titleMatches[i].match(extractTitleRegex); + const cleanTitle = titleMatch ? decodeHtmlEntities(titleMatch[1]) : null; + + if (fullHref && imageSrc && cleanTitle) { + results.push({ + href: `Animekai:${fullHref}`, + image: imageSrc, + title: cleanTitle + }); + } + } + + return results; + }; + + try { + const encodedQuery = encodeQuery(query); + const urls = [ + `${searchBaseUrl}${encodedQuery}`, + `${searchBaseUrl}${encodedQuery}&page=2`, + `${searchBaseUrl}${encodedQuery}&page=3` + ]; + + const responses = await Promise.all(urls.map(url => fetchv2(url))); + const htmlTexts = await Promise.all(responses.map(res => res.text())); + + const allResults = []; + htmlTexts.forEach(html => allResults.push(...extractResultsFromHTML(html))); + return allResults; + } catch (error) { + console.error("Animekai search error:" + error); + return []; + } + }; + + const oneMoviesSearch = async () => { + const searchBaseUrl = "https://1movies.bz/browser?keyword="; + const baseUrl = "https://1movies.bz"; + + const posterHrefRegex = /href="([^"]*)" class="poster"/g; + const titleRegex = /class="title" href="[^"]*">([^<]*) { + const results = []; + const posterMatches = [...htmlText.matchAll(posterHrefRegex)]; + const titleMatches = [...htmlText.matchAll(titleRegex)]; + const imageMatches = [...htmlText.matchAll(imageRegex)]; + const minLength = Math.min(posterMatches.length, titleMatches.length, imageMatches.length); + + for (let i = 0; i < minLength; i++) { + const href = posterMatches[i][1]; + const fullHref = href.startsWith("http") ? href : baseUrl + href; + + const imageSrc = imageMatches[i][1]; + const title = decodeHtmlEntities(titleMatches[i][1]); + + results.push({ href: fullHref, image: imageSrc, title }); + } + return results; + }; + + try { + const encodedQuery = encodeQuery(query); + const urls = [ + `${searchBaseUrl}${encodedQuery}`, + `${searchBaseUrl}${encodedQuery}&page=2`, + `${searchBaseUrl}${encodedQuery}&page=3` + ]; + + const responses = await Promise.all(urls.map(url => fetchv2(url))); + const htmlTexts = await Promise.all(responses.map(res => res.text())); + + const allResults = []; + htmlTexts.forEach(html => allResults.push(...extractResultsFromHTML(html))); + return allResults; + } catch (error) { + console.error("1Movies search error:" + error); + return []; + } + }; + + try { + const [animekaiResults, oneMoviesResults] = await Promise.all([ + animekaiSearch(), + oneMoviesSearch() + ]); + + const mergedResults = [...animekaiResults, ...oneMoviesResults]; + + const scoredResults = mergedResults.map(r => ({ + ...r, + score: fuzzyMatch(query, r.title) + })); + + const filteredResults = scoredResults + .filter(r => r.score > 50) + .sort((a, b) => b.score - a.score) + .map(({ score, ...rest }) => rest); + + return JSON.stringify(filteredResults.length > 0 ? filteredResults : [{ + href: "", + image: "", + title: "No results found, please refine query." + }]); + } catch (error) { + return JSON.stringify([{ + href: "", + image: "", + title: "Search failed: " + error.message + }]); + } +} + +async function extractDetails(url) { + + if (url.startsWith("Animekai:")) { + const actualUrl = url.replace("Animekai:", "").trim(); + + try { + const response = await fetchv2(actualUrl); + const htmlText = await response.text(); + + const descriptionMatch = (/
    ([\s\S]*?)<\/div>/.exec(htmlText) || [])[1]; + const aliasesMatch = (/([\s\S]*?)<\/small>/.exec(htmlText) || [])[1]; + + return JSON.stringify([{ + description: descriptionMatch ? cleanHtmlSymbols(descriptionMatch) : "Not available", + aliases: aliasesMatch ? cleanHtmlSymbols(aliasesMatch) : "Not available", + airdate: "If stream doesn't load try later or disable VPN/DNS" + }]); + } catch (error) { + console.error("Error fetching Animekai details:" + error); + return JSON.stringify([{ + description: "Error loading description", + aliases: "Aliases: Unknown", + airdate: "Aired: Unknown" + }]); + } + } else { + try { + const response = await fetchv2(url); + const htmlText = await response.text(); + + const descriptionMatch = (/
    ([\s\S]*?)<\/div>/.exec(htmlText) || [])[1]; + const aliasesMatch = (/([\s\S]*?)<\/small>/.exec(htmlText) || [])[1]; + const airdateMatch = (/
  • Released:\s*]*>(.*?)<\/span>/.exec(htmlText) || [])[1]; + + return JSON.stringify([{ + description: descriptionMatch ? cleanHtmlSymbols(descriptionMatch) : "Not available", + aliases: aliasesMatch ? cleanHtmlSymbols(aliasesMatch) : "Not aliases", + airdate: airdateMatch ? cleanHtmlSymbols(airdateMatch) : "Not available" + }]); + } catch (error) { + console.error("Error fetching 1Movies details:"+ error); + return JSON.stringify([{ + description: "Error loading description", + aliases: "Not available", + airdate: "Not available" + }]); + } + } +} + +async function extractEpisodes(url) { + try { + if (url.startsWith("Animekai:")) { + const actualUrl = url.replace("Animekai:", "").trim(); + const htmlText = await (await fetchv2(actualUrl)).text(); + const animeIdMatch = (htmlText.match(/
    ]*data-id="([^"]+)"/) || [])[1]; + if (!animeIdMatch) return JSON.stringify([{ error: "AniID not found" }]); + + const tokenResponse = await fetchv2(`https://enc-dec.app/api/enc-kai?text=${encodeURIComponent(animeIdMatch)}`); + const tokenData = await tokenResponse.json(); + const token = tokenData.result; + + const episodeListUrl = `https://animekai.to/ajax/episodes/list?ani_id=${animeIdMatch}&_=${token}`; + const episodeListData = await (await fetchv2(episodeListUrl)).json(); + const cleanedHtml = cleanJsonHtml(episodeListData.result); + + const episodeRegex = /]+num="([^"]+)"[^>]+token="([^"]+)"[^>]*>/g; + const episodeMatches = [...cleanedHtml.matchAll(episodeRegex)]; + + const episodes = episodeMatches.map(([_, episodeNum, episodeToken]) => ({ + number: parseInt(episodeNum, 10), + href: `Animekai:https://animekai.to/ajax/links/list?token=${episodeToken}&_=ENCRYPT_ME` + })); + + return JSON.stringify(episodes); + } else { + const htmlText = await (await fetchv2(url)).text(); + const movieIDMatch = (htmlText.match(/
    ]*id="movie-rating"[^>]*data-id="([^"]+)"/) || [])[1]; + if (!movieIDMatch) return JSON.stringify([{ error: "MovieID not found" }]); + + const tokenResponse = await fetchv2("https://enc-dec.app/api/enc-movies-flix?text=" + encodeURIComponent(movieIDMatch)); + const temp = await tokenResponse.json(); + const token = temp.result; + + const episodeListUrl = `https://1movies.bz/ajax/episodes/list?id=${movieIDMatch}&_=${token}`; + const episodeListData = await (await fetchv2(episodeListUrl)).json(); + const cleanedHtml = cleanJsonHtml(episodeListData.result); + + const episodeRegex = /]+eid="([^"]+)"[^>]+num="([^"]+)"[^>]*>/g; + const episodeMatches = [...cleanedHtml.matchAll(episodeRegex)]; + + const episodes = episodeMatches.map(([_, episodeToken, episodeNum]) => ({ + number: parseInt(episodeNum, 10), + href: `https://1movies.bz/ajax/links/list?eid=${episodeToken}&_=ENCRYPT_ME` + })); + + return JSON.stringify(episodes); + } + } catch (err) { + console.error("Error fetching episodes:" + err); + return JSON.stringify([{ number: 1, href: "Error fetching episodes" }]); + } +} + +async function extractStreamUrl(url) { + let source, actualUrl; + + if (url.startsWith("Animekai:")) { + source = "Animekai"; + actualUrl = url.replace("Animekai:", "").trim(); + } else if (url.includes("1movies.bz")) { + source = "1Movies"; + actualUrl = url.trim(); + } else { + console.log("Failed to match URL:", url); + return "Invalid URL format: " + url; + } + + if (source === "Animekai") { + 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 response = await fetchv2(actualUrl); + const text = await response.text(); + const cleanedHtml = cleanJsonHtml(text); + const subRegex = /
    ]*>([\s\S]*?)<\/div>/; + const softsubRegex = /
    ]*>([\s\S]*?)<\/div>/; + const dubRegex = /
    ]*>([\s\S]*?)<\/div>/; + const subMatch = subRegex.exec(cleanedHtml); + const softsubMatch = softsubRegex.exec(cleanedHtml); + const dubMatch = dubRegex.exec(cleanedHtml); + const subContent = subMatch ? subMatch[1].trim() : ""; + const softsubContent = softsubMatch ? softsubMatch[1].trim() : ""; + const dubContent = dubMatch ? dubMatch[1].trim() : ""; + const serverSpanRegex = /]*data-lid="([^"]+)"[^>]*>Server 1<\/span>/; + const serverIdDub = serverSpanRegex.exec(dubContent)?.[1]; + const serverIdSoftsub = serverSpanRegex.exec(softsubContent)?.[1]; + const serverIdSub = serverSpanRegex.exec(subContent)?.[1]; + + 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 streamUrls = tokenResults.map(result => { + const serverIdMap = { + "Dub": serverIdDub, + "Softsub": serverIdSoftsub, + "Sub": serverIdSub + }; + return { + type: result.name, + url: `https://animekai.to/ajax/links/view?id=${serverIdMap[result.name]}&_=${result.data}` + }; + }); + + const processStreams = async (streamUrls) => { + const streamResponses = await Promise.all( + streamUrls.map(async ({ type, url }) => { + try { + const res = await fetchv2(url); + const json = await res.json(); + return { + type: type, + result: json.result + }; + } catch (error) { + console.log(`Error fetching ${type} stream:` + error); + return { + type: type, + result: null + }; + } + }) + ); + + const decryptRequestData = streamResponses + .filter(item => item.result) + .map(item => ({ + name: item.type, + data: item.result + })); + + if (decryptRequestData.length === 0) { + return {}; + } + + const decryptPromises = decryptRequestData.map(item => + fetchv2(`https://enc-dec.app/api/dec-kai?text=${encodeURIComponent(item.data)}`) + .then(res => res.json()) + .then(json => ({ name: item.name, data: JSON.stringify(json.result) })) + .catch(err => ({ name: item.name, error: err.toString() })) + ); + const decryptResults = await Promise.all(decryptPromises); + + const finalResults = {}; + decryptResults.forEach(result => { + try { + const parsed = JSON.parse(result.data); + finalResults[result.name] = parsed.url; + console.log(`decrypted${result.name} URL:` + parsed.url); + } catch (error) { + console.log(`Error parsing ${result.name} result:` + error); + finalResults[result.name] = null; + } + }); + + return finalResults; + }; + + const decryptedUrls = await processStreams(streamUrls); + const decryptedSub = decryptedUrls.Sub; + const decryptedDub = decryptedUrls.Dub; + const decryptedRaw = decryptedUrls.Softsub; + + const headers = { + "Referer": "https://animekai.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" + }; + + async function getStream(url) { + try { + const response = await fetchv2(url.replace("/e/", "/media/"), headers); + const responseJson = await response.json(); + + const result = responseJson?.result; + + const postData = { + "text": result, + "Useragent": headers["User-Agent"] + }; + + const finalResponse = await fetchv2( + "https://ilovekai.simplepostrequest.workers.dev/ilovebush", + {}, + "POST", + JSON.stringify(postData) + ); + + const finalJson = await finalResponse.json(); + return finalJson?.result?.sources?.[0]?.file || null; + } catch { + return null; + } + } + + const streams = []; + + const subStream = decryptedSub ? await getStream(decryptedSub.replace("megaup22", "megaup.site")) : null; + if (subStream) streams.push("Hardsub English", subStream); + + const dubStream = decryptedDub ? await getStream(decryptedDub.replace("megaup22", "megaup.site")) : null; + if (dubStream) streams.push("Dubbed English", dubStream); + + const rawStream = decryptedRaw ? await getStream(decryptedRaw.replace("megaup22", "megaup.site")) : null; + if (rawStream) streams.push("Original audio", rawStream); + + const final = { + streams, + subtitles: "" + }; + + console.log("RETURN: " + JSON.stringify(final)); + return JSON.stringify(final); + + } catch (error) { + console.log("Animekai fetch error:" + error); + return "https://error.org"; + } + } else if (source === "1Movies") { + try { + const eidMatch = actualUrl.match(/eid=([^&]+)/); + if (eidMatch && eidMatch[1]) { + const rawEpisodeToken = eidMatch[1]; + const encryptResponse = await fetchv2(`https://enc-dec.app/api/enc-movies-flix?text=${rawEpisodeToken}`); + const encryptData = await encryptResponse.json(); + const encryptedToken = encryptData.result; + actualUrl = actualUrl.replace('&_=ENCRYPT_ME', `&_=${encryptedToken}`); + } + + 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); + + if (!server1Match) { + console.log("Server 1 not found"); + return "error"; + } + + const serverId = server1Match[1]; + + const tokenRequestData = [{ name: "Server1", data: serverId }]; + + const tokenBatchResponse = await fetchv2( + "https://ilovekai.simplepostrequest.workers.dev/ilovethighs", + {}, + "POST", + JSON.stringify(tokenRequestData) + ); + const tokenResults = await tokenBatchResponse.json(); + const token = tokenResults[0]?.data; + + if (!token) { + console.log("Token not found"); + return "error"; + } + + const streamUrl = `https://1movies.bz/ajax/links/view?id=${serverId}&_=${token}`; + const streamResponse = await fetchv2(streamUrl); + const streamData = await streamResponse.json(); + + if (!streamData.result) { + console.log("Stream result not found"); + return "error"; + } + + const decryptRequestData = [{ name: "Server1", data: streamData.result }]; + + const decryptBatchResponse = await fetchv2( + "https://ilovekai.simplepostrequest.workers.dev/iloveboobs", + {}, + "POST", + JSON.stringify(decryptRequestData) + ); + const decryptedResponse = await decryptBatchResponse.json(); + console.log("Decrypted response:" + JSON.stringify(decryptedResponse)); + const decryptedUrl = decryptedResponse[0]?.data.url; + + const subListEncoded = decryptedUrl.split("sub.list=")[1]?.split("&")[0]; + let subtitles = "N/A"; + + if (subListEncoded) { + try { + const subListUrl = decodeURIComponent(subListEncoded); + const subResponse = await fetchv2(subListUrl); + subtitles = await subResponse.json(); + } catch { + subtitles = "N/A"; + } + } + + const englishSubUrl = Array.isArray(subtitles) + ? subtitles.find(sub => sub.label === "English")?.file.replace(/\\\//g, "/") + : "N/A"; + + if (!decryptedUrl) { + console.log("Decryption failed"); + return "error"; + } + + const headers = { + "Referer": "https://1movies.bz/", + "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 mediaResponse = await fetchv2(decryptedUrl.replace("/e/", "/media/"), headers); + const mediaJson = await mediaResponse.json(); + + const result = mediaJson?.result; + if (!result) { + console.log("Media result not found"); + return "error"; + } + + const postData = { + "text": result, + "Useragent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36" + }; + + const finalResponse = await fetchv2("https://ilovekai.simplepostrequest.workers.dev/iloveass", {}, "POST", JSON.stringify(postData)); + const finalJson = await finalResponse.json(); + + 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) { + const streamPath = lines[i + 1].trim(); + const streamUrl = baseUrl + streamPath; + + streams.push({ + title: quality, + streamUrl: streamUrl + }); + } + } + } + + const returnValue = { + streams: streams, + subtitle: englishSubUrl !== "N/A" ? englishSubUrl : "" + }; + console.log("RETURN: " + JSON.stringify(returnValue)); + return JSON.stringify(returnValue); + } catch (error) { + console.log("1Movies fetch error:" + error); + return "https://error.org"; + } + } +} + +/// +/// +/// Helper functions +/// +/// + +function cleanHtmlSymbols(string) { + if (!string) { + return ""; + } + return string + .replace(/’/g, "'") + .replace(/–/g, "-") + .replace(/&#[0-9]+;/g, "") + .replace(/\r?\n|\r/g, " ") + .replace(/\s+/g, " ") + .trim(); +} + +function cleanJsonHtml(jsonHtml) { + if (!jsonHtml) { + return ""; + } + return jsonHtml + .replace(/\\"/g, "\"") + .replace(/\\'/g, "'") + .replace(/\\\\/g, "\\") + .replace(/\\n/g, "\n") + .replace(/\\t/g, "\t") + .replace(/\\r/g, "\r"); +} + +function decodeHtmlEntities(text) { + if (!text) { + return ""; + } + return text + .replace(/'/g, "'") + .replace(/"/g, "\"") + .replace(/&/g, "&") + .replace(/</g, "<") + .replace(/>/g, ">") + .replace(/ /g, " "); +} \ No newline at end of file diff --git a/.tmp.driveupload/508 b/.tmp.driveupload/508 new file mode 100644 index 0000000..3de7c36 --- /dev/null +++ b/.tmp.driveupload/508 @@ -0,0 +1,439 @@ +async function searchContent(input,page=0){ + function parseSearchResults(html) { + const results = []; + const regex = /
    [\s\S]*?]*class="poster"[\s\S]*?]*alt="([^"]*)"/g; + + let match; + while ((match = regex.exec(html)) !== null) { + results.push({ + title: match[3], + imageURL: match[2], + id: match[1] + }); + } + + return results; + } const vrf = generate_vrf(input); + const response = await fetch("https://mangafire.to/filter?keyword=" + encodeURIComponent(input) + "&vrf=" + vrf); + const data = await response.text(); + console.log(JSON.stringify(parseSearchResults(data))); + return parseSearchResults(data); +} + +async function getContentData(url) { + function parseHtmlData(htmlContent) { + const genreRegex = /([^<]+)<\/a>/g; + const tags = []; + let match; + + while ((match = genreRegex.exec(htmlContent)) !== null) { + if (match[1].trim()) tags.push(match[1].trim()); + } + + const uniqueTags = [...new Set(tags)]; + + const ogDescriptionRegex = + /') + .replace(/\s+/g, ' ') + .trim(); + + if (uniqueTags.length === 0) { + uniqueTags.push("Unknown"); + } + + return { + description: description, + tags: uniqueTags + }; + } + + const response = await fetch(`https://mangafire.to${url}`); + const data = await response.text(); + console.log(JSON.stringify(parseHtmlData(data))); + return parseHtmlData(data); +} + +async function getChapters(url) { + const mangaIdMatch = url.match(/\.([a-z0-9]+)$/); + const mangaId = mangaIdMatch ? mangaIdMatch[1] : null; + + vrf = generate_vrf(`${mangaId}@chapter@en`); + if (!mangaId) { + console.error("Could not extract manga ID from URL"); + return null; + } + + function parseChapters(htmlContent) { + const chapters = {}; + + const chapterRegex = + /]*>(.*?)<\/a>/gs; + + let match; + while ((match = chapterRegex.exec(htmlContent)) !== null) { + const langCode = match[1]; + const chapterNumber = match[2]; + const chapterId = match[3]; + const title = match[4].replace(/<[^>]*>/g, '').trim(); + + if (!chapters[langCode]) chapters[langCode] = []; + + chapters[langCode].push([ + chapterNumber, + [ + { + id: chapterId, + title: title, + chapter: Number(chapterNumber), + scanlation_group: "Mangafire" + } + ] + ]); + } + + Object.keys(chapters).forEach(lang => chapters[lang].reverse()); + + return chapters; + } + + try { + const response = await fetch(`https://mangafire.to/ajax/read/${mangaId}/chapter/en?vrf=${vrf}`); + const data = await response.json(); + + if (data.status === 200 && data.result && data.result.html) { + const chapters = parseChapters(data.result.html); + console.log(JSON.stringify(chapters)); + return chapters; + } else { + console.error("Invalid response from server"); + return null; + } + } catch (error) { + console.error("Error fetching chapters:" + error); + return null; + } +} + +async function getChapterImages(ID) { + vrf = generate_vrf(`chapter@${ID}`); + + try { + const response = await fetch(`https://mangafire.to/ajax/read/chapter/${ID}?vrf=${vrf}`); + const data = await response.json(); + + if (data.status === 200 && data.result && data.result.images) { + const images = data.result.images.map(img => img[0]); + console.log(JSON.stringify(images)); + return images; + } else { + console.error("Invalid response from server"); + return null; + } + + } catch (error) { + console.error("Error fetching chapters:" + error); + return null; + } +} + +function b64encode(data) { + const keystr = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + function atobLookup(chr) { + const index = keystr.indexOf(chr); + return index < 0 ? undefined : index; + } + + data = `${data}`; + data = data.replace(/[ \t\n\f\r]/g, ""); + if (data.length % 4 === 0) { + data = data.replace(/==?$/, ""); + } + if (data.length % 4 === 1 || /[^+/0-9A-Za-z]/.test(data)) { + return null; + } + let output = ""; + let buffer = 0; + let accumulatedBits = 0; + for (let i = 0; i < data.length; i++) { + buffer <<= 6; + buffer |= atobLookup(data[i]); + accumulatedBits += 6; + if (accumulatedBits === 24) { + output += String.fromCharCode((buffer & 0xff0000) >> 16); + output += String.fromCharCode((buffer & 0xff00) >> 8); + output += String.fromCharCode(buffer & 0xff); + buffer = accumulatedBits = 0; + } + } + if (accumulatedBits === 12) { + buffer >>= 4; + output += String.fromCharCode(buffer); + } else if (accumulatedBits === 18) { + buffer >>= 2; + output += String.fromCharCode((buffer & 0xff00) >> 8); + output += String.fromCharCode(buffer & 0xff); + } + return output; + } + +function b64decode(s) { + const keystr = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + function btoaLookup(index) { + if (index >= 0 && index < 64) { + return keystr[index]; + } + + return undefined; + } + + let i; + s = `${s}`; + for (i = 0; i < s.length; i++) { + if (s.charCodeAt(i) > 255) { + return null; + } + } + let out = ""; + for (i = 0; i < s.length; i += 3) { + const groupsOfSix = [undefined, undefined, undefined, undefined]; + groupsOfSix[0] = s.charCodeAt(i) >> 2; + groupsOfSix[1] = (s.charCodeAt(i) & 0x03) << 4; + if (s.length > i + 1) { + groupsOfSix[1] |= s.charCodeAt(i + 1) >> 4; + groupsOfSix[2] = (s.charCodeAt(i + 1) & 0x0f) << 2; + } + if (s.length > i + 2) { + groupsOfSix[2] |= s.charCodeAt(i + 2) >> 6; + groupsOfSix[3] = s.charCodeAt(i + 2) & 0x3f; + } + for (let j = 0; j < groupsOfSix.length; j++) { + if (typeof groupsOfSix[j] === "undefined") { + out += "="; + } else { + out += btoaLookup(groupsOfSix[j]); + } + } + } + return out; + } + +const toBytes = (str) => Array.from(str, (c) => c.charCodeAt(0) & 0xff); +const fromBytes = (bytes) => + bytes.map((b) => String.fromCharCode(b & 0xff)).join(""); + +function rc4Bytes(key, input) { + const s = Array.from({ length: 256 }, (_, i) => i); + let j = 0; + + for (let i = 0; i < 256; i++) { + j = (j + s[i] + key.charCodeAt(i % key.length)) & 0xff; + [s[i], s[j]] = [s[j], s[i]]; + } + + const out = new Array(input.length); + let i = 0; + j = 0; + for (let y = 0; y < input.length; y++) { + i = (i + 1) & 0xff; + j = (j + s[i]) & 0xff; + [s[i], s[j]] = [s[j], s[i]]; + const k = s[(s[i] + s[j]) & 0xff]; + out[y] = (input[y] ^ k) & 0xff; + } + return out; + } + +function transform(input, initSeedBytes, prefixKeyBytes, prefixLen, schedule) { + const out = []; + for (let i = 0; i < input.length; i++) { + if (i < prefixLen) out.push(prefixKeyBytes[i]); + + out.push( + schedule[i % 10]((input[i] ^ initSeedBytes[i % 32]) & 0xff) & 0xff + ); + } + return out; + } + +const add8 = (n) => (c) => (c + n) & 0xff; +const sub8 = (n) => (c) => (c - n + 256) & 0xff; +const xor8 = (n) => (c) => (c ^ n) & 0xff; +const rotl8 = (n) => (c) => ((c << n) | (c >>> (8 - n))) & 0xff; + +function base64UrlEncodeBytes(bytes) { + const std = b64decode(fromBytes(bytes)); + return std.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, ""); +} + +function bytesFromBase64(b64) { + return toBytes(b64encode(b64)); +} + +const rotr8 = (n) => (c) => ((c >>> n) | (c << (8 - n))) & 0xff; + +function generate_vrf(input) { + const schedule0 = [ + sub8(223), + rotr8(4), + rotr8(4), + add8(234), + rotr8(7), + rotr8(2), + rotr8(7), + sub8(223), + rotr8(7), + rotr8(6), + ]; + + const schedule1 = [ + add8(19), + rotr8(7), + add8(19), + rotr8(6), + add8(19), + rotr8(1), + add8(19), + rotr8(6), + rotr8(7), + rotr8(4), + ]; + + const schedule2 = [ + sub8(223), + rotr8(1), + add8(19), + sub8(223), + rotl8(2), + sub8(223), + add8(19), + rotl8(1), + rotl8(2), + rotl8(1), + ]; + + const schedule3 = [ + add8(19), + rotl8(1), + rotl8(1), + rotr8(1), + add8(234), + rotl8(1), + sub8(223), + rotl8(6), + rotl8(4), + rotl8(1), + ]; + + const schedule4 = [ + rotr8(1), + rotl8(1), + rotl8(6), + rotr8(1), + rotl8(2), + rotr8(4), + rotl8(1), + rotl8(1), + sub8(223), + rotl8(2), + ]; + + const CONST = { + "rc4Keys": [ + "FgxyJUQDPUGSzwbAq/ToWn4/e8jYzvabE+dLMb1XU1o=", + "CQx3CLwswJAnM1VxOqX+y+f3eUns03ulxv8Z+0gUyik=", + "fAS+otFLkKsKAJzu3yU+rGOlbbFVq+u+LaS6+s1eCJs=", + "Oy45fQVK9kq9019+VysXVlz1F9S1YwYKgXyzGlZrijo=", + "aoDIdXezm2l3HrcnQdkPJTDT8+W6mcl2/02ewBHfPzg=", + ], + "seeds32": [ + "yH6MXnMEcDVWO/9a6P9W92BAh1eRLVFxFlWTHUqQ474=", + "RK7y4dZ0azs9Uqz+bbFB46Bx2K9EHg74ndxknY9uknA=", + "rqr9HeTQOg8TlFiIGZpJaxcvAaKHwMwrkqojJCpcvoc=", + "/4GPpmZXYpn5RpkP7FC/dt8SXz7W30nUZTe8wb+3xmU=", + "wsSGSBXKWA9q1oDJpjtJddVxH+evCfL5SO9HZnUDFU8=", + ], + "prefixKeys": [ + "l9PavRg=", + "Ml2v7ag1Jg==", + "i/Va0UxrbMo=", + "WFjKAHGEkQM=", + "5Rr27rWd", + ], + }; + + // Stage 0: normalize to URI-encoded bytes + let bytes = toBytes(encodeURIComponent(input)); + + // RC4 + bytes = rc4Bytes(b64encode(CONST.rc4Keys[0]), bytes); + const prefixKey0 = bytesFromBase64(CONST.prefixKeys[0]); + bytes = transform( + bytes, + bytesFromBase64(CONST.seeds32[0]), + prefixKey0, + prefixKey0.length, + schedule0 + ); + + bytes = rc4Bytes(b64encode(CONST.rc4Keys[1]), bytes); + const prefixKey1 = bytesFromBase64(CONST.prefixKeys[1]); + bytes = transform( + bytes, + bytesFromBase64(CONST.seeds32[1]), + prefixKey1, + prefixKey1.length, + schedule1 + ); + + bytes = rc4Bytes(b64encode(CONST.rc4Keys[2]), bytes); + const prefixKey2 = bytesFromBase64(CONST.prefixKeys[2]); + bytes = transform( + bytes, + bytesFromBase64(CONST.seeds32[2]), + prefixKey2, + prefixKey2.length, + schedule2 + ); + + bytes = rc4Bytes(b64encode(CONST.rc4Keys[3]), bytes); + const prefixKey3 = bytesFromBase64(CONST.prefixKeys[3]); + bytes = transform( + bytes, + bytesFromBase64(CONST.seeds32[3]), + prefixKey3, + prefixKey3.length, + schedule3 + ); + + bytes = rc4Bytes(b64encode(CONST.rc4Keys[4]), bytes); + const prefixKey4 = bytesFromBase64(CONST.prefixKeys[4]); + bytes = transform( + bytes, + bytesFromBase64(CONST.seeds32[4]), + prefixKey4, + prefixKey4.length, + schedule4 + ); + + return base64UrlEncodeBytes(bytes); +} \ No newline at end of file diff --git a/.tmp.driveupload/530 b/.tmp.driveupload/530 new file mode 100644 index 0000000..d8d9cae --- /dev/null +++ b/.tmp.driveupload/530 @@ -0,0 +1 @@ +baaf3c1d221e67bbcf3ebda4bb52f4e520cd0974 diff --git a/.tmp.driveupload/560 b/.tmp.driveupload/560 new file mode 100644 index 0000000..47d8cdc --- /dev/null +++ b/.tmp.driveupload/560 @@ -0,0 +1 @@ +312c50343fe37511a49ec4a312b393069fbfde08 diff --git a/.tmp.driveupload/576 b/.tmp.driveupload/576 new file mode 100644 index 0000000..00e49c4 --- /dev/null +++ b/.tmp.driveupload/576 @@ -0,0 +1,12 @@ +0000000000000000000000000000000000000000 09c423e95a233553b774b005d8f6e6bdb31fc8f1 50/50 <80717571+50n50@users.noreply.github.com> 1760195925 +0200 commit (initial): Upload +09c423e95a233553b774b005d8f6e6bdb31fc8f1 4bdd7bbd2beccee5506770f77db7626a69b74f12 50/50 <80717571+50n50@users.noreply.github.com> 1760196216 +0200 commit: Fix script url +4bdd7bbd2beccee5506770f77db7626a69b74f12 9eacd16f54e6f8a4a51e1ac7aa87b2e1d942c072 50/50 <80717571+50n50@users.noreply.github.com> 1760287264 +0200 pull --ff --recurse-submodules --progress origin: Fast-forward +9eacd16f54e6f8a4a51e1ac7aa87b2e1d942c072 5c721916282c3ea70c4dbec930204eccbf270d6d 50/50 <80717571+50n50@users.noreply.github.com> 1760474661 +0200 pull --ff --recurse-submodules --progress origin: Fast-forward +5c721916282c3ea70c4dbec930204eccbf270d6d b9ea9732f6939fe3cd04049c7e640654511dbed8 50/50 <80717571+50n50@users.noreply.github.com> 1760474668 +0200 commit: test +b9ea9732f6939fe3cd04049c7e640654511dbed8 9e3a7a915a80ce7500fdaf5f651d43338760a561 50/50 <80717571+50n50@users.noreply.github.com> 1761677670 +0100 pull --ff --recurse-submodules --progress origin: Fast-forward +9e3a7a915a80ce7500fdaf5f651d43338760a561 e5b8e16feb85c3fa48aac5dc68758d7b62963aa2 50/50 <80717571+50n50@users.noreply.github.com> 1762117625 +0100 pull --ff --recurse-submodules --progress origin: Fast-forward +e5b8e16feb85c3fa48aac5dc68758d7b62963aa2 7069fa8ca49507d435963f2a92f3fe1823c535d9 50/50 <80717571+50n50@users.noreply.github.com> 1762117632 +0100 revert: Revert "Update mediafusion/mediafusion.js" +7069fa8ca49507d435963f2a92f3fe1823c535d9 866a5b750628eb0612f91ec3773200b754a3a8c6 50/50 <80717571+50n50@users.noreply.github.com> 1762980132 +0100 pull --ff --recurse-submodules --progress origin: Fast-forward +866a5b750628eb0612f91ec3773200b754a3a8c6 ac2ff67c141519c770b52bbcc46c1c8323b4e053 50/50 <80717571+50n50@users.noreply.github.com> 1764355727 +0100 pull --ff --recurse-submodules --progress origin: Fast-forward +ac2ff67c141519c770b52bbcc46c1c8323b4e053 baaf3c1d221e67bbcf3ebda4bb52f4e520cd0974 50/50 <80717571+50n50@users.noreply.github.com> 1764535876 +0100 pull --ff --recurse-submodules --progress origin: Fast-forward +baaf3c1d221e67bbcf3ebda4bb52f4e520cd0974 312c50343fe37511a49ec4a312b393069fbfde08 50/50 <80717571+50n50@users.noreply.github.com> 1765037272 +0100 pull --ff --recurse-submodules --progress origin: Fast-forward diff --git a/.tmp.driveupload/578 b/.tmp.driveupload/578 new file mode 100644 index 0000000..00e49c4 --- /dev/null +++ b/.tmp.driveupload/578 @@ -0,0 +1,12 @@ +0000000000000000000000000000000000000000 09c423e95a233553b774b005d8f6e6bdb31fc8f1 50/50 <80717571+50n50@users.noreply.github.com> 1760195925 +0200 commit (initial): Upload +09c423e95a233553b774b005d8f6e6bdb31fc8f1 4bdd7bbd2beccee5506770f77db7626a69b74f12 50/50 <80717571+50n50@users.noreply.github.com> 1760196216 +0200 commit: Fix script url +4bdd7bbd2beccee5506770f77db7626a69b74f12 9eacd16f54e6f8a4a51e1ac7aa87b2e1d942c072 50/50 <80717571+50n50@users.noreply.github.com> 1760287264 +0200 pull --ff --recurse-submodules --progress origin: Fast-forward +9eacd16f54e6f8a4a51e1ac7aa87b2e1d942c072 5c721916282c3ea70c4dbec930204eccbf270d6d 50/50 <80717571+50n50@users.noreply.github.com> 1760474661 +0200 pull --ff --recurse-submodules --progress origin: Fast-forward +5c721916282c3ea70c4dbec930204eccbf270d6d b9ea9732f6939fe3cd04049c7e640654511dbed8 50/50 <80717571+50n50@users.noreply.github.com> 1760474668 +0200 commit: test +b9ea9732f6939fe3cd04049c7e640654511dbed8 9e3a7a915a80ce7500fdaf5f651d43338760a561 50/50 <80717571+50n50@users.noreply.github.com> 1761677670 +0100 pull --ff --recurse-submodules --progress origin: Fast-forward +9e3a7a915a80ce7500fdaf5f651d43338760a561 e5b8e16feb85c3fa48aac5dc68758d7b62963aa2 50/50 <80717571+50n50@users.noreply.github.com> 1762117625 +0100 pull --ff --recurse-submodules --progress origin: Fast-forward +e5b8e16feb85c3fa48aac5dc68758d7b62963aa2 7069fa8ca49507d435963f2a92f3fe1823c535d9 50/50 <80717571+50n50@users.noreply.github.com> 1762117632 +0100 revert: Revert "Update mediafusion/mediafusion.js" +7069fa8ca49507d435963f2a92f3fe1823c535d9 866a5b750628eb0612f91ec3773200b754a3a8c6 50/50 <80717571+50n50@users.noreply.github.com> 1762980132 +0100 pull --ff --recurse-submodules --progress origin: Fast-forward +866a5b750628eb0612f91ec3773200b754a3a8c6 ac2ff67c141519c770b52bbcc46c1c8323b4e053 50/50 <80717571+50n50@users.noreply.github.com> 1764355727 +0100 pull --ff --recurse-submodules --progress origin: Fast-forward +ac2ff67c141519c770b52bbcc46c1c8323b4e053 baaf3c1d221e67bbcf3ebda4bb52f4e520cd0974 50/50 <80717571+50n50@users.noreply.github.com> 1764535876 +0100 pull --ff --recurse-submodules --progress origin: Fast-forward +baaf3c1d221e67bbcf3ebda4bb52f4e520cd0974 312c50343fe37511a49ec4a312b393069fbfde08 50/50 <80717571+50n50@users.noreply.github.com> 1765037272 +0100 pull --ff --recurse-submodules --progress origin: Fast-forward