update
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
async function getDomainsList() {
|
||||
try {
|
||||
console.log("Fetching domains from anime-sama.pw...");
|
||||
const response = await fetchv2("https://anime-sama.pw/");
|
||||
const html = await response.text();
|
||||
console.log("Fetched HTML length:", html.length);
|
||||
|
||||
const domainRegex = /{ name: '([^']+)' }/g;
|
||||
const domains = [];
|
||||
@@ -10,37 +12,47 @@ async function getDomainsList() {
|
||||
domains.push(match[1]);
|
||||
}
|
||||
|
||||
console.log("Parsed domains:", domains);
|
||||
return domains.length > 0 ? domains : ["anime-sama.tv"];
|
||||
} catch (err) {
|
||||
console.error("Error in getDomainsList:", err);
|
||||
return ["anime-sama.tv"];
|
||||
}
|
||||
}
|
||||
|
||||
async function searchResults(keyword) {
|
||||
console.log("searchResults keyword:", keyword);
|
||||
const domains = await getDomainsList();
|
||||
const regex = /<a[^>]+href="([^"]+)"[\s\S]*?<img[^>]+src="([^"]+)"[\s\S]*?<h3[^>]*>(.*?)<\/h3>/gi;
|
||||
|
||||
const firstDomain = domains[0];
|
||||
console.log("Trying first domain:", firstDomain);
|
||||
const firstResult = await trySearch(firstDomain, keyword, regex);
|
||||
if (firstResult && firstResult.length > 0) {
|
||||
console.log("Results found in first domain:", firstDomain);
|
||||
return JSON.stringify(firstResult);
|
||||
}
|
||||
|
||||
console.log("No results in first domain, trying others...");
|
||||
const otherDomains = domains.slice(1);
|
||||
const promises = otherDomains.map(domain => trySearch(domain, keyword, regex));
|
||||
const results = await Promise.all(promises);
|
||||
|
||||
for (let result of results) {
|
||||
for (let i = 0; i < results.length; i++) {
|
||||
const result = results[i];
|
||||
if (result && result.length > 0) {
|
||||
console.log("Results found in domain:", otherDomains[i]);
|
||||
return JSON.stringify(result);
|
||||
}
|
||||
}
|
||||
|
||||
console.log("No results found in any domain.");
|
||||
return JSON.stringify([]);
|
||||
}
|
||||
|
||||
async function trySearch(domain, keyword, regex) {
|
||||
try {
|
||||
console.log("trySearch domain:", domain, "keyword:", keyword);
|
||||
const headers = {
|
||||
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
|
||||
"X-Requested-With": "XMLHttpRequest",
|
||||
@@ -54,6 +66,7 @@ async function trySearch(domain, keyword, regex) {
|
||||
`query=${encodeURIComponent(keyword)}`
|
||||
);
|
||||
const html = await response.text();
|
||||
console.log("trySearch HTML length:", html.length);
|
||||
|
||||
const results = [];
|
||||
let match;
|
||||
@@ -66,8 +79,10 @@ async function trySearch(domain, keyword, regex) {
|
||||
});
|
||||
}
|
||||
|
||||
console.log("trySearch found results:", results.length);
|
||||
return results;
|
||||
} catch (err) {
|
||||
console.error("trySearch error for domain", domain, ":", err);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 110 KiB After Width: | Height: | Size: 110 KiB |
|
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 61 KiB |
|
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 55 KiB |
@@ -107,11 +107,8 @@ async function extractEpisodes(url) {
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`[Debug] Found ${results.length} episodes`);
|
||||
console.log(`[Debug]`, JSON.stringify(results, null, 2));
|
||||
return JSON.stringify(results.reverse());
|
||||
} catch (err) {
|
||||
console.error('Error extracting episodes:', err);
|
||||
return JSON.stringify([{ href: "Error", number: "Error" }]);
|
||||
}
|
||||
}
|
||||
@@ -121,7 +118,7 @@ async function extractStreamUrl(url) {
|
||||
const firstresponse = await fetchv2(url);
|
||||
const firsthtml = await firstresponse.text();
|
||||
|
||||
const idMatch = firsthtml.match(/href=['"]https:\/\/www3\.veziseriale\.org\/\?p=(\d+)['"]/);
|
||||
const idMatch = firsthtml.match(/href=['"][^'"]+\?p=(\d+)['"]/) || firsthtml.match(/\?p=(\d+)/);
|
||||
if (!idMatch) throw new Error('ID not found');
|
||||
const id = idMatch[1];
|
||||
|
||||
@@ -160,11 +157,10 @@ async function extractStreamUrl(url) {
|
||||
});
|
||||
|
||||
} catch (err) {
|
||||
console.error('Error extracting stream URL: ' + err);
|
||||
return {
|
||||
stream: "https://files.catbox.moe/avolvc.mp4",
|
||||
return JSON.stringify({
|
||||
stream: "",
|
||||
subtitles: ""
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,10 +52,31 @@ async function extractDetails(url) {
|
||||
async function extractEpisodes(url) {
|
||||
const results = [];
|
||||
|
||||
function myAtob(input) {
|
||||
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
|
||||
let str = '';
|
||||
let buffer = 0;
|
||||
let bits = 0;
|
||||
for (let i = 0; i < input.length; i++) {
|
||||
const char = input.charAt(i);
|
||||
if (char === '=') break;
|
||||
const index = chars.indexOf(char);
|
||||
if (index === -1) continue;
|
||||
buffer = (buffer << 6) | index;
|
||||
bits += 6;
|
||||
if (bits >= 8) {
|
||||
bits -= 8;
|
||||
str += String.fromCharCode((buffer >> bits) & 0xFF);
|
||||
buffer &= (1 << bits) - 1;
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
function decryptEpisodeData(encodedData) {
|
||||
const parts = encodedData.split('.');
|
||||
const encryptedData = atob(parts[0]);
|
||||
const xorKey = atob(parts[1]);
|
||||
const encryptedData = myAtob(parts[0]);
|
||||
const xorKey = myAtob(parts[1]);
|
||||
|
||||
let decryptedString = '';
|
||||
|
||||
@@ -66,6 +87,10 @@ async function extractEpisodes(url) {
|
||||
decryptedString += decryptedChar;
|
||||
}
|
||||
|
||||
try {
|
||||
decryptedString = decodeURIComponent(escape(decryptedString));
|
||||
} catch (e) {}
|
||||
|
||||
return JSON.parse(decryptedString);
|
||||
}
|
||||
|
||||
@@ -79,20 +104,58 @@ async function extractEpisodes(url) {
|
||||
const encodedData = dataMatch ? dataMatch[1] : null;
|
||||
|
||||
if (encodedData) {
|
||||
const decoded = decryptEpisodeData(encodedData);
|
||||
try {
|
||||
const decoded = decryptEpisodeData(encodedData);
|
||||
|
||||
const addEpisode = (ep) => {
|
||||
const num = parseInt(ep.number, 10);
|
||||
results.push({ href: ep.url, number: isNaN(num) ? 0 : num });
|
||||
};
|
||||
const addEpisode = (ep) => {
|
||||
const num = parseInt(ep.number, 10);
|
||||
results.push({ href: ep.url, number: isNaN(num) ? 0 : num });
|
||||
};
|
||||
|
||||
if (Array.isArray(decoded)) {
|
||||
decoded.forEach(addEpisode);
|
||||
} else {
|
||||
addEpisode(decoded);
|
||||
if (Array.isArray(decoded)) {
|
||||
decoded.forEach(addEpisode);
|
||||
} else {
|
||||
addEpisode(decoded);
|
||||
}
|
||||
|
||||
return JSON.stringify(results);
|
||||
} catch (innerErr) {
|
||||
console.log("Decryption failed, using fallback...");
|
||||
}
|
||||
}
|
||||
|
||||
return JSON.stringify(results);
|
||||
const regex = /openEpisode\('([^']+)'\)[\s\S]*?>[^<]*?(\d+)[^<]*?<\/a>/gi;
|
||||
let match;
|
||||
const seenHrefs = new Set();
|
||||
|
||||
while ((match = regex.exec(html)) !== null) {
|
||||
const href = myAtob(match[1]);
|
||||
const number = parseInt(match[2], 10);
|
||||
|
||||
if (!seenHrefs.has(href)) {
|
||||
results.push({
|
||||
href: href,
|
||||
number: isNaN(number) ? 0 : number
|
||||
});
|
||||
seenHrefs.add(href);
|
||||
}
|
||||
}
|
||||
|
||||
if (results.length === 0) {
|
||||
const fallbackRegex = /openEpisode\('([^']+)'\)/gi;
|
||||
while ((match = fallbackRegex.exec(html)) !== null) {
|
||||
const href = atob(match[1]);
|
||||
if (!seenHrefs.has(href)) {
|
||||
const numMatch = href.match(/-(\d+)\/?$/);
|
||||
const number = numMatch ? parseInt(numMatch[1], 10) : results.length + 1;
|
||||
|
||||
results.push({
|
||||
href: href,
|
||||
number: number
|
||||
});
|
||||
seenHrefs.add(href);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return JSON.stringify(results);
|
||||
+27
-11
@@ -1,7 +1,7 @@
|
||||
async function searchResults(keyword) {
|
||||
const results = [];
|
||||
try {
|
||||
const response = await fetchv2("https://123animes.ru/search?keyword=" + encodeURIComponent(keyword));
|
||||
const response = await fetchv2("https://123animehub.cc/search?keyword=" + encodeURIComponent(keyword));
|
||||
const html = await response.text();
|
||||
|
||||
const filmListMatch = html.match(/<div class="film-list">([\s\S]*?)<div class="clearfix"><\/div>/);
|
||||
@@ -15,8 +15,8 @@ async function searchResults(keyword) {
|
||||
while ((match = itemRegex.exec(filmList)) !== null) {
|
||||
results.push({
|
||||
title: match[2].trim(),
|
||||
image: "https://123animes.ru" + match[3].trim(),
|
||||
href: "https://123animes.ru" + match[1].trim()
|
||||
image: "https://123animehub.cc" + match[3].trim(),
|
||||
href: "https://123animehub.cc" + match[1].trim()
|
||||
});
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ async function extractEpisodes(url) {
|
||||
try {
|
||||
const animeId = url.split('/').pop();
|
||||
|
||||
const response = await fetchv2("https://123animes.ru/ajax/film/sv?id=" + animeId);
|
||||
const response = await fetchv2("https://123animehub.cc/ajax/film/sv?id=" + animeId);
|
||||
const jsonData = await response.json();
|
||||
const html = jsonData.html;
|
||||
|
||||
@@ -111,19 +111,35 @@ async function extractEpisodes(url) {
|
||||
|
||||
async function extractStreamUrl(ID) {
|
||||
try {
|
||||
const response = await fetchv2("https://123animes.ru/ajax/episode/info?epr=" + ID);
|
||||
const response = await fetchv2("https://123animehub.cc/ajax/episode/info?epr=" + encodeURIComponent(ID));
|
||||
const data = await response.json();
|
||||
|
||||
const target = data.target;
|
||||
const streamID = target.split('/').pop();
|
||||
|
||||
const responseTwo = await fetchv2("https://play.shipimagesbolt.online/hs/getSources?id=" + streamID);
|
||||
const dataTwo = await responseTwo.json();
|
||||
if (!target) throw new Error("No target in response: " + JSON.stringify(data));
|
||||
|
||||
const stream = dataTwo.sources;
|
||||
const responseTarget = await fetchv2(target);
|
||||
const htmlTarget = await responseTarget.text();
|
||||
const zrpart2Match = htmlTarget.match(/var\s+zrpart2\s*=\s*'([^']+)';/);
|
||||
if (!zrpart2Match) throw new Error("zrpart2 not found");
|
||||
const zrpart2 = zrpart2Match[1];
|
||||
|
||||
return stream;
|
||||
const originMatch = target.match(/^(https?:\/\/[^\/]+)/);
|
||||
const origin = originMatch ? originMatch[1] : "";
|
||||
|
||||
const hsUrl = `${origin}/hs/${zrpart2}`;
|
||||
const responseHs = await fetchv2(hsUrl);
|
||||
const htmlHs = await responseHs.text();
|
||||
const dataIdMatch = htmlHs.match(/id="mg-player"[^>]*data-id="([^"]+)"/);
|
||||
if (!dataIdMatch) throw new Error("data-id not found");
|
||||
const dataId = dataIdMatch[1];
|
||||
|
||||
const sourcesUrl = `${origin}/hs/getSources?id=${dataId}`;
|
||||
const responseSources = await fetchv2(sourcesUrl);
|
||||
const dataSources = await responseSources.json();
|
||||
|
||||
return dataSources.sources;
|
||||
} catch (err) {
|
||||
console.log("Stream URL Error details:", err.message, err.stack);
|
||||
return "https://error.org/";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
{
|
||||
"sourceName": "123Anime",
|
||||
"iconUrl": "https://123animes.ru/assets/favicons/apple-touch-icon.png",
|
||||
"iconUrl": "https://123animehub.cc/assets/favicons/apple-touch-icon.png",
|
||||
"author": {
|
||||
"name": "50/50",
|
||||
"icon": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQ3122kQwublLkZ6rf1fEpUP79BxZOFmH9BSA&s"
|
||||
},
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"language": "English (DUB/HARDSUB)",
|
||||
"streamType": "HLS",
|
||||
"quality": "1080p",
|
||||
"baseUrl": "https://play.shipimagesbolt.online/",
|
||||
"searchBaseUrl": "https://play.shipimagesbolt.online/",
|
||||
"baseUrl": "https://123animehub.cc/",
|
||||
"searchBaseUrl": "https://123animehub.cc/",
|
||||
"scriptUrl": "https://git.luna-app.eu/50n50/sources/raw/branch/main/123anime/123anime.js",
|
||||
"type": "anime",
|
||||
"asyncJS": true,
|
||||
|
||||
@@ -22,7 +22,7 @@ async function searchResults(keyword) {
|
||||
if (linkMatch) {
|
||||
results.push({
|
||||
href: linkMatch[1].trim(),
|
||||
title: decodeHtml(linkMatch[2].trim()),
|
||||
title: decodeHtml(linkMatch[2].trim()).replace(/^Watch\s+/i, ""),
|
||||
image: image
|
||||
});
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"name": "50/50",
|
||||
"icon": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQ3122kQwublLkZ6rf1fEpUP79BxZOFmH9BSA&s"
|
||||
},
|
||||
"version": "1.0.1",
|
||||
"version": "1.0.2",
|
||||
"language": "Tamil",
|
||||
"streamType": "HLS",
|
||||
"quality": "1080p",
|
||||
|
||||
+52
-54
@@ -71,9 +71,17 @@ async function extractEpisodes(url) {
|
||||
const movieRegex = /<a[^>]+href=["']([^"']+)["'][^>]+class=["'][^"']*link-btn link-show[^"']*["'][^>]*>/i;
|
||||
const movieMatch = movieRegex.exec(html);
|
||||
|
||||
const buildHref = (extractedHref) => {
|
||||
const watchMatch = extractedHref.match(/\/watch\/(\d+)/i);
|
||||
if (watchMatch) {
|
||||
return url.replace(/\/(movie|series|episode)\//i, `/watch/${watchMatch[1]}/`);
|
||||
}
|
||||
return extractedHref;
|
||||
};
|
||||
|
||||
if (movieMatch && movieMatch[1]) {
|
||||
episodes.push({
|
||||
href: movieMatch[1],
|
||||
href: buildHref(movieMatch[1]),
|
||||
number: 1
|
||||
});
|
||||
} else {
|
||||
@@ -86,7 +94,7 @@ async function extractEpisodes(url) {
|
||||
const hrefMatch = block.match(/href=["']([^"']+)["']/);
|
||||
if (hrefMatch) {
|
||||
episodes.push({
|
||||
href: hrefMatch[1],
|
||||
href: buildHref(hrefMatch[1]),
|
||||
number: index + 1
|
||||
});
|
||||
}
|
||||
@@ -99,67 +107,57 @@ async function extractEpisodes(url) {
|
||||
}
|
||||
|
||||
async function extractStreamUrl(url) {
|
||||
let stream = null;
|
||||
const response = await fetchv2(url);
|
||||
const html = await response.text();
|
||||
const urlMatch = html.match(/<meta property="og:url" content="([^"]+)"/);
|
||||
const isEpisode = urlMatch && urlMatch[1] && urlMatch[1].includes("/episode/");
|
||||
const streams = [];
|
||||
try {
|
||||
let streamPageUrl = url;
|
||||
|
||||
if (isEpisode) {
|
||||
const linkBtnMatches = html.match(/<a[^>]*class="link-btn link-show[^"]*"[^>]*>[\s\S]*?<\/a>/g);
|
||||
let match = null;
|
||||
|
||||
if (linkBtnMatches && linkBtnMatches.length > 0) {
|
||||
const hrefMatch = linkBtnMatches[0].match(/href="([^"]+)"/);
|
||||
if (hrefMatch && hrefMatch[1]) {
|
||||
match = [null, hrefMatch[1]];
|
||||
}
|
||||
}
|
||||
|
||||
if (match && match[1]) {
|
||||
try {
|
||||
const shortnerResponse = await fetch(match[1]);
|
||||
const shortnerHtml = await shortnerResponse;
|
||||
|
||||
const finalMatch = shortnerHtml.match(/<div class="d-none d-md-block">\s*<a href="([^"]+)"/);
|
||||
|
||||
if (finalMatch && finalMatch[1]) {
|
||||
let finalUrl = finalMatch[1].replace("two.akw.cam", "ak.sv");
|
||||
|
||||
const lastResponse = await fetch(finalUrl);
|
||||
const lastHtml = await lastResponse;
|
||||
const videoMatch = lastHtml.match(/<source\s+src="([^"]+)"\s+type="video\/mp4"/);
|
||||
|
||||
if (videoMatch && videoMatch[1]) {
|
||||
stream = videoMatch[1];
|
||||
}
|
||||
if (url.includes("/episode/")) {
|
||||
const epResponse = await fetchv2(url);
|
||||
const epHtml = await epResponse.text();
|
||||
|
||||
const linkRegex = /<a[^>]+href=["']([^"']+)["'][^>]+class=["'][^"']*link-btn link-show[^"']*["'][^>]*>/i;
|
||||
const linkMatch = linkRegex.exec(epHtml);
|
||||
|
||||
if (linkMatch && linkMatch[1]) {
|
||||
const watchMatch = linkMatch[1].match(/\/watch\/(\d+)/i);
|
||||
if (watchMatch) {
|
||||
streamPageUrl = url.replace(/\/(episode)\//i, `/watch/${watchMatch[1]}/`);
|
||||
} else {
|
||||
streamPageUrl = linkMatch[1];
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching shortener URL:", error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const finalMatch = html.match(/<div class="d-none d-md-block">\s*<a href="([^"]+)"/);
|
||||
if (finalMatch && finalMatch[1]) {
|
||||
try {
|
||||
let finalUrl = finalMatch[1].replace("two.akw.cam", "ak.sv");
|
||||
const lastResponse = await fetch(finalUrl);
|
||||
const lastHtml = await lastResponse;
|
||||
const videoMatch = lastHtml.match(/<source\s+src="([^"]+)"\s+type="video\/mp4"/);
|
||||
|
||||
if (videoMatch && videoMatch[1]) {
|
||||
stream = videoMatch[1];
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching final URL:", error);
|
||||
return null;
|
||||
const response = await fetchv2(streamPageUrl);
|
||||
const html = await response.text();
|
||||
|
||||
const sourceTagRegex = /<source[^>]+>/gi;
|
||||
let match;
|
||||
|
||||
while ((match = sourceTagRegex.exec(html)) !== null) {
|
||||
const sourceHtml = match[0];
|
||||
const srcMatch = sourceHtml.match(/src=["']([^"']+)["']/i);
|
||||
const sizeMatch = sourceHtml.match(/size=["']([^"']+)["']/i);
|
||||
|
||||
if (srcMatch) {
|
||||
streams.push({
|
||||
title: sizeMatch ? sizeMatch[1] : "Default",
|
||||
streamUrl: srcMatch[1],
|
||||
headers: {}
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching stream:", error);
|
||||
}
|
||||
|
||||
console.log(stream);
|
||||
return stream;
|
||||
const result = {
|
||||
streams: streams,
|
||||
subtitle: ""
|
||||
};
|
||||
|
||||
console.log(JSON.stringify(result));
|
||||
return JSON.stringify(result);
|
||||
}
|
||||
|
||||
function decodeHTMLEntities(text) {
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
"name": "50/50",
|
||||
"icon": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQ3122kQwublLkZ6rf1fEpUP79BxZOFmH9BSA&s"
|
||||
},
|
||||
"version": "1.0.5",
|
||||
"version": "1.0.6",
|
||||
"language": "Arabic (SUB)",
|
||||
"streamType": "MP4",
|
||||
"quality": "1080p",
|
||||
|
||||
+118
-138
@@ -1,57 +1,53 @@
|
||||
async function searchResults(keyword) {
|
||||
const results = [];
|
||||
const headers = {
|
||||
"Content-Type": "multipart/form-data; boundary=----geckoformboundary38c356867533a17de80e8c65d9125df5"
|
||||
};
|
||||
const postData = `------geckoformboundary38c356867533a17de80e8c65d9125df5
|
||||
Content-Disposition: form-data; name="s_keyword"
|
||||
|
||||
${keyword}
|
||||
------geckoformboundary38c356867533a17de80e8c65d9125df5
|
||||
Content-Disposition: form-data; name="orderby"
|
||||
|
||||
popular
|
||||
------geckoformboundary38c356867533a17de80e8c65d9125df5
|
||||
Content-Disposition: form-data; name="order"
|
||||
|
||||
DESC
|
||||
------geckoformboundary38c356867533a17de80e8c65d9125df5
|
||||
Content-Disposition: form-data; name="action"
|
||||
|
||||
advanced_search
|
||||
------geckoformboundary38c356867533a17de80e8c65d9125df5
|
||||
Content-Disposition: form-data; name="page"
|
||||
|
||||
1
|
||||
------geckoformboundary38c356867533a17de80e8c65d9125df5--`;
|
||||
|
||||
|
||||
try {
|
||||
const response = await fetchv2("https://an1me.to/wp-admin/admin-ajax.php", headers, "POST", postData);
|
||||
const data = await response.json();
|
||||
const html = data.data.html;
|
||||
const articlePattern = /<article[^>]*class="anime-card[^"]*"[^>]*>([\s\S]*?)<\/article>/g;
|
||||
let articleMatch;
|
||||
|
||||
while ((articleMatch = articlePattern.exec(html)) !== null) {
|
||||
const articleHtml = articleMatch[1];
|
||||
|
||||
const imgMatch = articleHtml.match(/<img[^>]+src=['"]([^'"]+)['"][^>]+alt=['"]([^'"]+)['"]/);
|
||||
|
||||
const url = "https://an1me.to/wp-admin/admin-ajax.php?action=instant_search&query=" + encodeURIComponent(keyword);
|
||||
const headers = {
|
||||
"Accept": "application/json, text/javascript, */*; q=0.01",
|
||||
"X-Requested-With": "XMLHttpRequest",
|
||||
"Referer": "https://an1me.to/",
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36"
|
||||
};
|
||||
const response = await fetchv2(url, headers);
|
||||
const text = await response.text();
|
||||
|
||||
const linkMatch = articleHtml.match(/<h3[^>]*>[\s\S]*?<a[^>]+href=['"]([^'"]+)['"][^>]*title=['"]([^'"]+)['"]/);
|
||||
let data;
|
||||
try {
|
||||
data = JSON.parse(text);
|
||||
} catch (e) {
|
||||
return JSON.stringify(results);
|
||||
}
|
||||
|
||||
if (!data.success || !data.data || !data.data.html) {
|
||||
return JSON.stringify(results);
|
||||
}
|
||||
|
||||
const html = data.data.html;
|
||||
const anchorPattern = /<a[^>]+href=["']([^"']+)["'][^>]*title=["']([^"']+)["'][^>]*>([\s\S]*?)<\/a>/g;
|
||||
let anchorMatch;
|
||||
let matchCount = 0;
|
||||
|
||||
while ((anchorMatch = anchorPattern.exec(html)) !== null) {
|
||||
matchCount++;
|
||||
const href = anchorMatch[1];
|
||||
const title = anchorMatch[2];
|
||||
const innerHtml = anchorMatch[3];
|
||||
|
||||
if (imgMatch && linkMatch) {
|
||||
const imgMatch = innerHtml.match(/<img[^>]+src=["']([^"']+)["'][^>]*>/);
|
||||
|
||||
if (imgMatch) {
|
||||
results.push({
|
||||
title: linkMatch[2].trim(),
|
||||
title: title.trim(),
|
||||
image: imgMatch[1].trim(),
|
||||
href: linkMatch[1].trim()
|
||||
href: href.trim()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return JSON.stringify(results);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
console.log("Search error:", err.message);
|
||||
return JSON.stringify([{
|
||||
title: "Error",
|
||||
image: "Error",
|
||||
@@ -62,15 +58,18 @@ Content-Disposition: form-data; name="page"
|
||||
|
||||
async function extractDetails(url) {
|
||||
try {
|
||||
const response = await fetchv2(url);
|
||||
const headers = {
|
||||
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8",
|
||||
"Referer": "https://an1me.to/",
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36"
|
||||
};
|
||||
const response = await fetchv2(url, headers);
|
||||
const html = await response.text();
|
||||
|
||||
const match = html.match(
|
||||
/<div class="anime-synopsis">[\s\S]*?<p>([\s\S]*?)<\/p>/
|
||||
);
|
||||
const match = html.match(/aria-label="Anime Overview"[^>]*>([\s\S]*?)<\/section>/);
|
||||
|
||||
const description = match
|
||||
? match[1].replace(/\s+/g, " ").trim()
|
||||
? match[1].replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim()
|
||||
: "N/A";
|
||||
|
||||
return JSON.stringify([{
|
||||
@@ -78,7 +77,8 @@ async function extractDetails(url) {
|
||||
aliases: "N/A",
|
||||
airdate: "N/A"
|
||||
}]);
|
||||
} catch {
|
||||
} catch (err) {
|
||||
console.log("extractDetails error:", err.message);
|
||||
return JSON.stringify([{
|
||||
description: "Error",
|
||||
aliases: "Error",
|
||||
@@ -91,30 +91,64 @@ async function extractDetails(url) {
|
||||
async function extractEpisodes(url) {
|
||||
const results = [];
|
||||
try {
|
||||
const response = await fetchv2(url);
|
||||
const headers = {
|
||||
"Accept": "application/json, text/javascript, */*; q=0.01",
|
||||
"X-Requested-With": "XMLHttpRequest",
|
||||
"Referer": "https://an1me.to/",
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36"
|
||||
};
|
||||
const response = await fetchv2(url, headers);
|
||||
const html = await response.text();
|
||||
|
||||
const postIdMatch = html.match(/postid-(\d+)/) ||
|
||||
html.match(/post_id['"]\s*,\s*['"](\d+)['"]/) ||
|
||||
html.match(/anime_id['"]\s*:\s*(\d+)/);
|
||||
|
||||
const regex = /<a href="([^"]+)"[^>]*class="episode-list-display-box episode-list-item[^"]*"[^>]*>[\s\S]*?<span class="episode-list-item-number">\s*(\d+)\s*<\/span>/g;
|
||||
|
||||
let match;
|
||||
while ((match = regex.exec(html)) !== null) {
|
||||
results.push({
|
||||
href: match[1].trim(),
|
||||
number: parseInt(match[2], 10)
|
||||
});
|
||||
if (!postIdMatch) {
|
||||
console.log("Could not find anime_id (postid)");
|
||||
return JSON.stringify(results);
|
||||
}
|
||||
|
||||
const animeId = postIdMatch[1];
|
||||
|
||||
if (results.length === 0 && url) {
|
||||
results.push({
|
||||
href: url,
|
||||
number: 1
|
||||
const firstPageUrl = `https://an1me.to/wp-admin/admin-ajax.php?action=get_episodes&anime_id=${animeId}&page=1&order=desc`;
|
||||
const firstPageRes = await fetchv2(firstPageUrl, headers);
|
||||
const firstPageData = await firstPageRes.json();
|
||||
|
||||
if (firstPageData.success && firstPageData.data && Array.isArray(firstPageData.data.episodes)) {
|
||||
firstPageData.data.episodes.forEach(ep => {
|
||||
results.push({
|
||||
href: ep.url,
|
||||
number: parseFloat(ep.meta_number)
|
||||
});
|
||||
});
|
||||
|
||||
const maxPages = firstPageData.data.max_episodes_page || 1;
|
||||
|
||||
if (maxPages > 1) {
|
||||
const promises = [];
|
||||
for (let i = 2; i <= maxPages; i++) {
|
||||
const pageUrl = `https://an1me.to/wp-admin/admin-ajax.php?action=get_episodes&anime_id=${animeId}&page=${i}&order=desc`;
|
||||
promises.push(fetchv2(pageUrl, headers).then(res => res.json()));
|
||||
}
|
||||
|
||||
const otherPagesData = await Promise.all(promises);
|
||||
otherPagesData.forEach(data => {
|
||||
if (data.success && data.data && Array.isArray(data.data.episodes)) {
|
||||
data.data.episodes.forEach(ep => {
|
||||
results.push({
|
||||
href: ep.url,
|
||||
number: parseFloat(ep.meta_number)
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return JSON.stringify(results);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
console.log("Error in extractEpisodes:", err);
|
||||
return JSON.stringify([{
|
||||
href: "Error",
|
||||
number: "Error"
|
||||
@@ -124,85 +158,31 @@ async function extractEpisodes(url) {
|
||||
|
||||
async function extractStreamUrl(url) {
|
||||
try {
|
||||
const response = await fetchv2(url);
|
||||
const headers = {
|
||||
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8",
|
||||
"Referer": "https://an1me.to/",
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36"
|
||||
};
|
||||
const response = await fetchv2(url, headers);
|
||||
const html = await response.text();
|
||||
const sources = await getSourcesFromEpisode(url);
|
||||
if(sources == null) return null;
|
||||
|
||||
const streams = await extractStreamsFromSources(sources);
|
||||
if(streams == null) return null;
|
||||
console.log("Streams: " + JSON.stringify(streams));
|
||||
|
||||
const streamUrl = streams[0].stream;
|
||||
console.log("Stream URL: " + streamUrl);
|
||||
return streamUrl;
|
||||
|
||||
const iframeMatch = html.match(/<iframe[^>]+src=["']([^"']+)["']/i);
|
||||
if (!iframeMatch) throw new Error("Iframe not found");
|
||||
|
||||
let iframeUrl = iframeMatch[1].replace(/&/g, '&').replace(/&/g, '&');
|
||||
const iframeResponse = await fetchv2(iframeUrl, headers);
|
||||
const iframeHtml = await iframeResponse.text();
|
||||
|
||||
const paramsMatch = iframeHtml.match(/const\s+params\s*=\s*({.*?});/s);
|
||||
if (!paramsMatch) throw new Error("Params not found");
|
||||
|
||||
const params = JSON.parse(paramsMatch[1]);
|
||||
const streamUrl = params.sources?.[0]?.url;
|
||||
|
||||
console.log("Stream URL secured:", streamUrl);
|
||||
return streamUrl || "https://files.catbox.moe/avolvc.mp4";
|
||||
} catch (err) {
|
||||
console.log("extractStreamUrl error:", err.message);
|
||||
return "https://files.catbox.moe/avolvc.mp4";
|
||||
}
|
||||
}
|
||||
|
||||
async function getSourcesFromEpisode(url) {
|
||||
const sources = [];
|
||||
try {
|
||||
const res = await fetchv2(url);
|
||||
const html = await res.text();
|
||||
|
||||
const regex = /<span[^>]+data-embed-id="([^"]+)"[^>]*>/gi;
|
||||
let match;
|
||||
|
||||
while ((match = regex.exec(html)) !== null) {
|
||||
const dataEmbedId = match[1];
|
||||
const [_, iframeBase64] = dataEmbedId.split(":");
|
||||
if (!iframeBase64) continue;
|
||||
|
||||
const iframeHtml = atob(iframeBase64);
|
||||
|
||||
const srcMatch = iframeHtml.match(/src\s*=\s*["']([^"']+)["']/i);
|
||||
if (!srcMatch) continue;
|
||||
|
||||
const isSub = /class="[^"]*player-sub[^"]*"/.test(match[0]);
|
||||
|
||||
sources.push({
|
||||
source: srcMatch[1],
|
||||
audio: isSub ? 'original' : 'Greek'
|
||||
});
|
||||
}
|
||||
|
||||
return sources;
|
||||
} catch (e) {
|
||||
console.error('Error extracting source: ' + e.message);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
async function extractStreamsFromSources(sources) {
|
||||
const streams = [];
|
||||
|
||||
for(let source of sources) {
|
||||
try {
|
||||
const res = await fetchv2(source.source);
|
||||
const html = await res.text();
|
||||
|
||||
const jsonString = html.match(/params[\s]*=[\s]*(\{[^;]*);/)?.[1];
|
||||
if(jsonString == null) continue;
|
||||
|
||||
const json = JSON.parse(jsonString);
|
||||
if(json?.sources == null || json.sources.length <= 0) continue;
|
||||
|
||||
for(let s of json.sources) {
|
||||
const resolution = s?.html ?? null;
|
||||
let arrayLength = streams.push(source);
|
||||
let i = arrayLength - 1;
|
||||
|
||||
streams[i].stream = s.url;
|
||||
streams[i].resolution = resolution != null ? resolution.slice(0, -1) : null;
|
||||
}
|
||||
|
||||
|
||||
} catch(e) {
|
||||
console.warn('Error extracting stream: ' + e.message);
|
||||
}
|
||||
}
|
||||
|
||||
return streams.filter(source => source.stream != null);
|
||||
}
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
"name": "50/50",
|
||||
"icon": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQ3122kQwublLkZ6rf1fEpUP79BxZOFmH9BSA&s"
|
||||
},
|
||||
"version": "1.0.2",
|
||||
"version": "1.0.3",
|
||||
"language": "Greek",
|
||||
"streamType": "HLS",
|
||||
"encrypted": true,
|
||||
|
||||
+215
-43
@@ -63,10 +63,19 @@ Content-Disposition: form-data; name="page"
|
||||
|
||||
async function extractDetails(url) {
|
||||
try {
|
||||
const response = await fetchv2(url);
|
||||
const headers = {
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36",
|
||||
"Referer": "https://anihq.to/"
|
||||
};
|
||||
const response = await fetchv2(url, headers);
|
||||
const html = await response.text();
|
||||
|
||||
const descMatch = html.match(/<div\s+data-synopsis[^>]*>([\s\S]*?)<\/div>/);
|
||||
let descMatch = html.match(/<div\s+class=["']anime-synopsis["']>[\s\S]*?<div[^>]+class=["']prose[^"']*["'][^>]*>([\s\S]*?)<\/div>/i);
|
||||
|
||||
if (!descMatch) {
|
||||
descMatch = html.match(/<section[^>]+aria-label=["']Anime Overview["'][^>]*>([\s\S]*?)<\/section>/i);
|
||||
}
|
||||
|
||||
let description = "N/A";
|
||||
|
||||
if (descMatch) {
|
||||
@@ -84,7 +93,7 @@ async function extractDetails(url) {
|
||||
}]);
|
||||
} catch (err) {
|
||||
return JSON.stringify([{
|
||||
description: "Error",
|
||||
description: "Error: " + err.message,
|
||||
aliases: "Error",
|
||||
airdate: "Error"
|
||||
}]);
|
||||
@@ -139,46 +148,209 @@ async function extractEpisodes(url) {
|
||||
|
||||
async function extractStreamUrl(url) {
|
||||
try {
|
||||
const response = await fetchv2(url);
|
||||
const html = await response.text();
|
||||
|
||||
const iframeMatch = html.match(/<iframe[^>]+src=['"]https:\/\/([^'"]+\.playerp2p\.com)\/#([^'"]+)['"]/);
|
||||
|
||||
if (!iframeMatch) {
|
||||
console.log("No iframe ID found");
|
||||
return "https://error.org/";
|
||||
}
|
||||
|
||||
const domain = iframeMatch[1];
|
||||
const videoId = iframeMatch[2];
|
||||
|
||||
const apiUrl = `https://${domain}/api/v1/video?id=${videoId}&w=1792&h=1120&r=anihq.to`;
|
||||
const apiResponse = await fetchv2(apiUrl);
|
||||
const encodedString = await apiResponse.text();
|
||||
|
||||
const hasUppercase = /[A-Z]/.test(encodedString);
|
||||
|
||||
let stringToSend;
|
||||
if (hasUppercase) {
|
||||
stringToSend = atob(encodedString);
|
||||
console.log("Decoded string: " + stringToSend);
|
||||
} else {
|
||||
stringToSend = encodedString;
|
||||
console.log("Using encoded string directly (no uppercase found)");
|
||||
}
|
||||
|
||||
const postData = {
|
||||
text: stringToSend
|
||||
const headers = {
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36",
|
||||
"Referer": "https://anihq.to/"
|
||||
};
|
||||
const headers = { "Content-Type": "application/json" };
|
||||
const response2 = await fetchv2("https://enc-dec.app/api/dec-vidstack", headers, "POST", postData);
|
||||
const data = await response2.json();
|
||||
console.log(JSON.stringify(data));
|
||||
console.log("Final URL: " + data.result.source);
|
||||
return data.result.cf;
|
||||
const response = await fetchv2(url, headers);
|
||||
const html = await response.text();
|
||||
|
||||
const iframeMatch = html.match(/<iframe[^>]+src=['"]([^'"]+)['"]/i);
|
||||
if (!iframeMatch) {
|
||||
console.log("No iframe found on page");
|
||||
return null;
|
||||
}
|
||||
|
||||
const iframeUrl = iframeMatch[1];
|
||||
console.log("Found iframe URL:", iframeUrl);
|
||||
|
||||
const iframeResponse = await fetchv2(iframeUrl, headers);
|
||||
const iframeHtml = await iframeResponse.text();
|
||||
|
||||
let streamData = null;
|
||||
try {
|
||||
streamData = voeExtractor(iframeHtml);
|
||||
} catch (error) {
|
||||
console.log("VOE extraction error:", error.message || error);
|
||||
return null;
|
||||
}
|
||||
|
||||
const streamUrlResult = typeof streamData === "string" ? streamData : getStreamUrl(streamData);
|
||||
|
||||
} catch (err) {
|
||||
console.log("Error: " + err.message);
|
||||
return "https://error.org/";
|
||||
if (streamUrlResult) {
|
||||
const origin = "https://bryantenunder.com";
|
||||
console.log("Stream URL secured:", streamUrlResult);
|
||||
|
||||
return JSON.stringify({
|
||||
streams: [
|
||||
{
|
||||
title: "Server 1",
|
||||
streamUrl: streamUrlResult,
|
||||
headers: {
|
||||
"Origin": origin,
|
||||
"Referer": origin + "/"
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
console.log("No stream URL found");
|
||||
return null;
|
||||
} catch (error) {
|
||||
console.log("Fetch error:", error.message || error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* SCHEME START */
|
||||
|
||||
/**
|
||||
* @name voeExtractor
|
||||
* @author Cufiy
|
||||
*/
|
||||
|
||||
function voeExtractor(html, url = null) {
|
||||
const regex = /<script[^>]+type=["']application\/json["'][^>]*>([\s\S]*?)<\/script>/gi;
|
||||
let match;
|
||||
let obfuscatedString = null;
|
||||
while ((match = regex.exec(html)) !== null) {
|
||||
try {
|
||||
const data = JSON.parse(match[1].trim());
|
||||
if (Array.isArray(data) && typeof data[0] === "string") {
|
||||
obfuscatedString = data[0];
|
||||
break;
|
||||
}
|
||||
} catch (e) {
|
||||
// Ignore syntax/parse errors for other script tags
|
||||
}
|
||||
}
|
||||
|
||||
if (!obfuscatedString) {
|
||||
console.log("No valid VOE application/json script tag found");
|
||||
return null;
|
||||
}
|
||||
|
||||
// Step 1: ROT13
|
||||
let step1 = voeRot13(obfuscatedString);
|
||||
|
||||
// Step 2: Remove patterns
|
||||
let step2 = voeRemovePatterns(step1);
|
||||
|
||||
// Step 3: Base64 decode
|
||||
let step3 = voeBase64Decode(step2);
|
||||
|
||||
// Step 4: Subtract 3 from each char code
|
||||
let step4 = voeShiftChars(step3, 3);
|
||||
|
||||
// Step 5: Reverse string
|
||||
let step5 = step4.split("").reverse().join("");
|
||||
|
||||
// Step 6: Base64 decode again
|
||||
let step6 = voeBase64Decode(step5);
|
||||
|
||||
// Step 7: Parse as JSON
|
||||
let result;
|
||||
try {
|
||||
result = JSON.parse(step6);
|
||||
} catch (e) {
|
||||
throw new Error("Final JSON parse error: " + e.message);
|
||||
}
|
||||
|
||||
// check if direct_access_url is set, not null and starts with http
|
||||
const streamUrl = getStreamUrl(result);
|
||||
if (streamUrl) {
|
||||
console.log("Voe Stream URL: " + streamUrl);
|
||||
return streamUrl;
|
||||
} else {
|
||||
console.log("No stream URL found in the decoded JSON");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function voeRot13(str) {
|
||||
return str.replace(/[a-zA-Z]/g, function (c) {
|
||||
return String.fromCharCode(
|
||||
(c <= "Z" ? 90 : 122) >= (c = c.charCodeAt(0) + 13)
|
||||
? c
|
||||
: c - 26
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function voeRemovePatterns(str) {
|
||||
const patterns = ["@$", "^^", "~@", "%?", "*~", "!!", "#&"];
|
||||
let result = str;
|
||||
for (const pat of patterns) {
|
||||
result = result.split(pat).join("");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function voeBase64Decode(str) {
|
||||
if (typeof atob === "function") {
|
||||
try {
|
||||
return atob(str);
|
||||
} catch (e) {
|
||||
// fallback if atob fails
|
||||
}
|
||||
}
|
||||
|
||||
// Pure Javascript Base64 decoding fallback to avoid reliance on Buffer or atob
|
||||
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
||||
let cleaned = str.replace(/=+$/, '').replace(/[^A-Za-z0-9+/]/g, '');
|
||||
let output = '';
|
||||
let buffer = 0;
|
||||
let bits = 0;
|
||||
|
||||
for (let i = 0; i < cleaned.length; i++) {
|
||||
const char = cleaned[i];
|
||||
const idx = chars.indexOf(char);
|
||||
if (idx === -1) continue;
|
||||
|
||||
buffer = (buffer << 6) | idx;
|
||||
bits += 6;
|
||||
|
||||
if (bits >= 8) {
|
||||
bits -= 8;
|
||||
const byte = (buffer >> bits) & 0xFF;
|
||||
output += String.fromCharCode(byte);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
return decodeURIComponent(escape(output));
|
||||
} catch (e) {
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
function voeShiftChars(str, shift) {
|
||||
return str
|
||||
.split("")
|
||||
.map((c) => String.fromCharCode(c.charCodeAt(0) - shift))
|
||||
.join("");
|
||||
}
|
||||
|
||||
function getStreamUrl(result) {
|
||||
if (!result) return null;
|
||||
if (typeof result === "string" && result.startsWith("http")) {
|
||||
return result;
|
||||
}
|
||||
if (typeof result === "object") {
|
||||
if (typeof result.source === "string" && result.source.startsWith("http")) {
|
||||
return result.source;
|
||||
}
|
||||
if (typeof result.direct_access_url === "string" && result.direct_access_url.startsWith("http")) {
|
||||
return result.direct_access_url;
|
||||
}
|
||||
if (Array.isArray(result.source)) {
|
||||
const url = result.source
|
||||
.map((source) => typeof source === "string" ? source : (source.direct_access_url || source.file || source.url))
|
||||
.find((url) => url && url.startsWith("http"));
|
||||
if (url) return url;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/* SCHEME END */
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
"name": "50/50",
|
||||
"icon": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQ3122kQwublLkZ6rf1fEpUP79BxZOFmH9BSA&s"
|
||||
},
|
||||
"version": "1.0.1",
|
||||
"version": "1.0.2",
|
||||
"language": "English",
|
||||
"streamType": "HLS",
|
||||
"quality": "1080p",
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
{
|
||||
"sourceName": "Anime-Sama",
|
||||
"iconUrl": "https://cdn.statically.io/gh/Anime-Sama/IMG/img/autres/logo_icon.png",
|
||||
"author": {
|
||||
"name": "50/50",
|
||||
"icon": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQ3122kQwublLkZ6rf1fEpUP79BxZOFmH9BSA&s"
|
||||
},
|
||||
"version": "1.1.1",
|
||||
"language": "French",
|
||||
"streamType": "HLS",
|
||||
"quality": "1080p",
|
||||
"baseUrl": "https://anime-sama.fr/",
|
||||
"searchBaseUrl": "https://anime-sama.fr/",
|
||||
"scriptUrl": "https://git.luna-app.eu/50n50/sources/raw/branch/main/anime-sama/anime-sama.js",
|
||||
"type": "anime",
|
||||
"asyncJS": true,
|
||||
"softsub": false,
|
||||
"downloadSupport": false,
|
||||
"supportsMojuru": true,
|
||||
"supportsDartotsu": true,
|
||||
"supportsSora": true,
|
||||
"supportsLuna": true,
|
||||
"supportsAnymex": true,
|
||||
"supportsTsumi": true,
|
||||
"supportsHiyoku": true
|
||||
}
|
||||
@@ -66,7 +66,7 @@ async function extractEpisodes(url) {
|
||||
server.server_data?.forEach(ep => {
|
||||
results.push({
|
||||
number: parseInt(ep.name, 10),
|
||||
href: "https://anibd.app/playid/" + postid + "/?server=" + server.id + "&slug=" + ep.slug
|
||||
href: "https://epeng.animeapps.top/apilink.php?data=" + ep.link
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -79,26 +79,45 @@ async function extractEpisodes(url) {
|
||||
|
||||
async function extractStreamUrl(url) {
|
||||
try {
|
||||
const pageHtml = await (await fetchv2(url)).text();
|
||||
const iframeUrl = pageHtml.match(/id="video-player-iframe"\s+src="([^"]+)"/)?.[1]?.replace(/&/g, '&');
|
||||
if (!iframeUrl) return JSON.stringify({ streams: [], subtitle: "" });
|
||||
|
||||
const iframeHtml = await (await fetchv2(iframeUrl, { "Referer": "https://anibd.app/" })).text();
|
||||
let streamUrl = iframeHtml.match(/url:\s*['"]([^'"]+\.m3u8)['"]/)?.[1] || iframeHtml.match(/videoUrl:\s*["']([^"']+\.m3u8)['"]/)?.[1];
|
||||
|
||||
if (streamUrl) {
|
||||
const fullUrl = streamUrl.startsWith("/") ? "https://playeng.animeapps.top" + streamUrl : streamUrl.startsWith("http") ? streamUrl : "https://playeng.animeapps.top/r2/" + streamUrl;
|
||||
return JSON.stringify({
|
||||
streams: [{
|
||||
title: "Server 1",
|
||||
streamUrl: fullUrl,
|
||||
headers: { "Referer": "https://anibd.app/" }
|
||||
}],
|
||||
subtitle: ""
|
||||
});
|
||||
}
|
||||
return JSON.stringify({ streams: [], subtitle: "" });
|
||||
const response = await fetchv2(url);
|
||||
const servers = await response.json();
|
||||
const headers = {
|
||||
"Referer": "https://anibd.app/"
|
||||
};
|
||||
|
||||
const promises = servers.map(async (server) => {
|
||||
try {
|
||||
const res = await fetchv2(server.link, headers);
|
||||
const html = await res.text();
|
||||
const match = html.match(/url:\s*['"]([^'"]+)['"]/);
|
||||
if (match) {
|
||||
let streamUrl = match[1];
|
||||
if (!streamUrl.startsWith("http")) {
|
||||
const baseUrl = server.link.substring(0, server.link.lastIndexOf("/") + 1);
|
||||
streamUrl = baseUrl + streamUrl;
|
||||
}
|
||||
return {
|
||||
title: server.server,
|
||||
streamUrl: streamUrl
|
||||
};
|
||||
}
|
||||
} catch (err) {}
|
||||
return null;
|
||||
});
|
||||
|
||||
const results = await Promise.all(promises);
|
||||
const streams = results.filter(s => s !== null);
|
||||
|
||||
return JSON.stringify({
|
||||
type: "servers",
|
||||
streams: streams,
|
||||
subtitle: null
|
||||
});
|
||||
} catch (err) {
|
||||
return JSON.stringify({ streams: [], subtitle: "" });
|
||||
return JSON.stringify({
|
||||
type: "servers",
|
||||
streams: [],
|
||||
subtitle: null
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
"name": "50/50",
|
||||
"icon": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQ3122kQwublLkZ6rf1fEpUP79BxZOFmH9BSA&s"
|
||||
},
|
||||
"version": "1.0.4",
|
||||
"version": "1.0.5",
|
||||
"language": "English (SUB)",
|
||||
"streamType": "HLS",
|
||||
"quality": "1080p",
|
||||
|
||||
@@ -58,7 +58,7 @@ async function extractEpisodes(url) {
|
||||
const html = await response.text();
|
||||
const episodes = [];
|
||||
|
||||
const episodeRegex = /<a[^>]+id="([^"]+)"[^>]*>[\s\S]*?<div class='[^']*watch2 bc'[^>]*>(\d+)<\/div>/g;
|
||||
const episodeRegex = /<a[^>]+id="([^"]+)"[^>]*>[\s\S]*?<div class='watch2[^']*'>(\d+)<\/div>/g;
|
||||
|
||||
let match;
|
||||
while ((match = episodeRegex.exec(html)) !== null) {
|
||||
@@ -75,7 +75,6 @@ async function extractEpisodes(url) {
|
||||
|
||||
episodes.reverse();
|
||||
|
||||
console.log(episodes);
|
||||
return JSON.stringify(episodes);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"name": "50/50",
|
||||
"icon": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQ3122kQwublLkZ6rf1fEpUP79BxZOFmH9BSA&s"
|
||||
},
|
||||
"version": "1.0.7",
|
||||
"version": "1.0.8",
|
||||
"language": "English (SUB)",
|
||||
"streamType": "HLS",
|
||||
"quality": "720p",
|
||||
|
||||
+16
-5
@@ -49,17 +49,28 @@ async function extractEpisodes(url) {
|
||||
const response = await fetchv2(url);
|
||||
const html = await response.text();
|
||||
|
||||
const regex = /<div class="inepcx">\s*<a href="([^"#]+)">\s*<span>New Episode<\/span>/;
|
||||
const match = regex.exec(html);
|
||||
const episodeRegex = /<li[^>]*>\s*<a href="([^"]+)"[^>]*>\s*<div class="epl-num">(\d+)<\/div>/g;
|
||||
let match;
|
||||
|
||||
if (match) {
|
||||
while ((match = episodeRegex.exec(html)) !== null) {
|
||||
results.push({
|
||||
href: match[1].trim(),
|
||||
number: 1
|
||||
number: parseInt(match[2], 10)
|
||||
});
|
||||
}
|
||||
|
||||
if (results.length === 0) {
|
||||
const singleRegex = /<div class="inepcx">\s*<a href="([^"#]+)">\s*<span>New Episode<\/span>/;
|
||||
const singleMatch = singleRegex.exec(html);
|
||||
if (singleMatch) {
|
||||
results.push({
|
||||
href: singleMatch[1].trim(),
|
||||
number: 1
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return JSON.stringify(results);
|
||||
return JSON.stringify(results.reverse());
|
||||
}
|
||||
async function extractStreamUrl(url) {
|
||||
try {
|
||||
|
||||
+41
-6
@@ -1,8 +1,13 @@
|
||||
async function searchResults(keyword) {
|
||||
const results = [];
|
||||
const headers = {
|
||||
"Referer": "https://v3.animelib.org/",
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3"
|
||||
};
|
||||
try {
|
||||
const response = await fetchv2(
|
||||
"https://hapi.hentaicdn.org/api/anime?fields[]=rate_avg&fields[]=rate&fields[]=releaseDate&q=" + keyword
|
||||
"https://hapi.hentaicdn.org/api/anime?fields[]=rate_avg&fields[]=rate&fields[]=releaseDate&q=" + keyword,
|
||||
headers
|
||||
);
|
||||
const json = await response.json();
|
||||
|
||||
@@ -15,7 +20,7 @@ async function searchResults(keyword) {
|
||||
title,
|
||||
image: "https://passthrough-worker.simplepostrequest.workers.dev/?simple=" +
|
||||
image +
|
||||
"&referer=https://animelib.org/",
|
||||
"&referer=https://v3.animelib.org/",
|
||||
href: item.slug_url || item.slug || item.id,
|
||||
_score: scoreTitle(title, keyword)
|
||||
});
|
||||
@@ -47,16 +52,38 @@ function scoreTitle(title, keyword) {
|
||||
}
|
||||
|
||||
async function extractDetails(slug) {
|
||||
const headers = {
|
||||
"Referer": "https://v3.animelib.org/",
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3"
|
||||
};
|
||||
try {
|
||||
const response = await fetchv2(
|
||||
"https://hapi.hentaicdn.org/api/anime/" + slug +
|
||||
"?fields[]=background&fields[]=eng_name&fields[]=otherNames&fields[]=summary&fields[]=releaseDate&fields[]=type_id&fields[]=caution&fields[]=views&fields[]=close_view&fields[]=rate_avg&fields[]=rate&fields[]=genres&fields[]=tags&fields[]=teams&fields[]=user&fields[]=franchise&fields[]=authors&fields[]=publisher&fields[]=userRating&fields[]=moderated&fields[]=metadata&fields[]=metadata.count&fields[]=metadata.close_comments&fields[]=anime_status_id&fields[]=time&fields[]=episodes&fields[]=episodes_count&fields[]=episodesSchedule&fields[]=shiki_rate"
|
||||
);
|
||||
, headers);
|
||||
const json = await response.json();
|
||||
const data = json.data || {};
|
||||
|
||||
let description = "No summary available";
|
||||
if (data.summary) {
|
||||
if (typeof data.summary === "string") {
|
||||
description = data.summary;
|
||||
} else if (data.summary.content && Array.isArray(data.summary.content)) {
|
||||
description = data.summary.content
|
||||
.map(block => {
|
||||
if (block.content && Array.isArray(block.content)) {
|
||||
return block.content.map(t => t.text || "").join("");
|
||||
}
|
||||
return "";
|
||||
})
|
||||
.join("\n")
|
||||
.trim();
|
||||
}
|
||||
}
|
||||
|
||||
const aliases = Array.isArray(data.otherNames) ? data.otherNames.join(", ") : "";
|
||||
return JSON.stringify([{
|
||||
description: data.summary || "No summary available",
|
||||
description: description,
|
||||
airdate: data.releaseDate || "Unknown",
|
||||
aliases: aliases
|
||||
}]);
|
||||
@@ -71,8 +98,12 @@ async function extractDetails(slug) {
|
||||
|
||||
async function extractEpisodes(slug) {
|
||||
const results = [];
|
||||
const headers = {
|
||||
"Referer": "https://v3.animelib.org/",
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3"
|
||||
};
|
||||
try {
|
||||
const response = await fetchv2("https://hapi.hentaicdn.org/api/episodes?anime_id=" + slug);
|
||||
const response = await fetchv2("https://hapi.hentaicdn.org/api/episodes?anime_id=" + slug, headers);
|
||||
const json = await response.json();
|
||||
|
||||
if (json && Array.isArray(json.data)) {
|
||||
@@ -94,9 +125,13 @@ async function extractEpisodes(slug) {
|
||||
}
|
||||
|
||||
async function extractStreamUrl(ID) {
|
||||
const headers = {
|
||||
"Referer": "https://v3.animelib.org/",
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3"
|
||||
};
|
||||
try {
|
||||
const url = "https://hapi.hentaicdn.org/api/episodes/" + ID;
|
||||
const response = await fetchv2(url);
|
||||
const response = await fetchv2(url, headers);
|
||||
const json = await response.json();
|
||||
|
||||
const data = json.data || {};
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"name": "50/50",
|
||||
"icon": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQ3122kQwublLkZ6rf1fEpUP79BxZOFmH9BSA&s"
|
||||
},
|
||||
"version": "1.0.4",
|
||||
"version": "1.0.5",
|
||||
"language": "Russian",
|
||||
"streamType": "MP4 & HLS",
|
||||
"quality": "4K",
|
||||
|
||||
+71
-21
@@ -56,7 +56,7 @@ async function extractEpisodes(url) {
|
||||
while ((match = regex.exec(html)) !== null) {
|
||||
results.push({
|
||||
href: match[1].trim(),
|
||||
number: parseInt(match[2], 10)
|
||||
number: parseFloat(match[2])
|
||||
});
|
||||
}
|
||||
results.reverse();
|
||||
@@ -65,28 +65,78 @@ async function extractEpisodes(url) {
|
||||
|
||||
|
||||
async function extractStreamUrl(url) {
|
||||
const response = await fetchv2(url);
|
||||
const html = await response.text();
|
||||
try {
|
||||
const response = await fetchv2(url);
|
||||
const html = await response.text();
|
||||
const streams = [];
|
||||
|
||||
const optionRegex = /<option value="([^"]+)"[^>]*>\s*([^<]*Omega[^<]*)\s*<\/option>/gi;
|
||||
|
||||
let optionMatch;
|
||||
while ((optionMatch = optionRegex.exec(html)) !== null) {
|
||||
const base64Value = optionMatch[1];
|
||||
const label = optionMatch[2].trim();
|
||||
|
||||
if (!base64Value) continue;
|
||||
|
||||
const regexSub = /<option value="([^"]+)"[^>]*>\s*SUB - Omega\s*<\/option>/;
|
||||
const regexFallback = /<option value="([^"]+)"[^>]*>\s*Omega\s*<\/option>/;
|
||||
const anotherFallbackDawggggWhatsWrongWithTHisWebsite = /<option value="([^"]+)"[^>]*>\s*SUB v2 - Omega\s*<\/option>/;
|
||||
try {
|
||||
const decodedHtml = atob(base64Value);
|
||||
const iframeMatch = decodedHtml.match(/<iframe[^>]+src=["']([^"']+)["']/i);
|
||||
|
||||
if (iframeMatch) {
|
||||
let iframeUrl = iframeMatch[1];
|
||||
if (iframeUrl.startsWith("//")) iframeUrl = "https:" + iframeUrl;
|
||||
|
||||
const responseTwo = await fetchv2(iframeUrl);
|
||||
const htmlTwo = await responseTwo.text();
|
||||
|
||||
let match = html.match(regexSub) || html.match(regexFallback) || html.match(anotherFallbackDawggggWhatsWrongWithTHisWebsite);
|
||||
if (!match) return null;
|
||||
const m3u8Match = htmlTwo.match(/sources\s*:\s*\[\s*\{\s*file\s*:\s*['"]([^'"]+master\.m3u8[^'"]*)['"]/i) ||
|
||||
htmlTwo.match(/file\s*:\s*['"]([^'"]+\.m3u8[^'"]*)['"]/i);
|
||||
|
||||
if (m3u8Match) {
|
||||
streams.push({
|
||||
title: label,
|
||||
streamUrl: m3u8Match[1],
|
||||
headers: {
|
||||
"Referer": "https://vidmoly.biz/",
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (innerErr) {
|
||||
}
|
||||
}
|
||||
|
||||
const decodedHtml = atob(match[1]); // Decode base64
|
||||
const iframeMatch = decodedHtml.match(/<iframe\s+src="([^"]+)"/);
|
||||
return JSON.stringify({
|
||||
streams: streams,
|
||||
subtitle: ""
|
||||
});
|
||||
} catch (err) {
|
||||
return JSON.stringify({
|
||||
streams: [],
|
||||
subtitle: ""
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (!iframeMatch) return null;
|
||||
|
||||
const streamUrl = iframeMatch[1].startsWith("//") ? "https:" + iframeMatch[1] : iframeMatch[1];
|
||||
|
||||
const responseTwo = await fetchv2(streamUrl);
|
||||
const htmlTwo = await responseTwo.text();
|
||||
|
||||
const m3u8Match = htmlTwo.match(/sources:\s*\[\{file:"([^"]+\.m3u8)"/);
|
||||
console.error(m3u8Match ? m3u8Match[1] : null);
|
||||
return m3u8Match ? m3u8Match[1] : null;
|
||||
}
|
||||
function atob(input) {
|
||||
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
|
||||
let str = '';
|
||||
let buffer = 0;
|
||||
let bits = 0;
|
||||
for (let i = 0; i < input.length; i++) {
|
||||
const char = input.charAt(i);
|
||||
if (char === '=') break;
|
||||
const index = chars.indexOf(char);
|
||||
if (index === -1) continue;
|
||||
buffer = (buffer << 6) | index;
|
||||
bits += 6;
|
||||
if (bits >= 8) {
|
||||
bits -= 8;
|
||||
str += String.fromCharCode((buffer >> bits) & 0xFF);
|
||||
buffer &= (1 << bits) - 1;
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"name": "50/50",
|
||||
"icon": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQ3122kQwublLkZ6rf1fEpUP79BxZOFmH9BSA&s"
|
||||
},
|
||||
"version": "1.0.4",
|
||||
"version": "1.0.5",
|
||||
"language": "English (SUB/DUB)",
|
||||
"streamType": "HLS",
|
||||
"quality": "1080p",
|
||||
|
||||
+126
-63
@@ -124,79 +124,142 @@ async function extractStreamUrl(url) {
|
||||
const responseText = await ddosInterceptor.fetchWithBypass(url);
|
||||
const dataText = await responseText.text();
|
||||
|
||||
const buttonMatches = dataText.match(/<button[^>]*data-src="([^"]*)"[^>]*>/g);
|
||||
if (!buttonMatches) {
|
||||
const buttonRegex = /<button[^>]*data-src="([^"]+)"[^>]*data-fansub="([^"]+)"[^>]*data-resolution="([^"]+)"[^>]*data-audio="([^"]+)"[^>]*>/g;
|
||||
const buttons = [];
|
||||
let match;
|
||||
while ((match = buttonRegex.exec(dataText)) !== null) {
|
||||
buttons.push({
|
||||
src: match[1],
|
||||
fansub: match[2],
|
||||
resolution: match[3],
|
||||
audio: match[4]
|
||||
});
|
||||
}
|
||||
|
||||
if (buttons.length === 0) {
|
||||
const buttonMatches = dataText.match(/<button[^>]*data-src="([^"]*)"[^>]*>/g);
|
||||
if (!buttonMatches) {
|
||||
return JSON.stringify({ streams: [], subtitle: "" });
|
||||
}
|
||||
return JSON.stringify({ streams: [], subtitle: "" });
|
||||
}
|
||||
|
||||
const streamPromises = buttonMatches.map(async (buttonHtml) => {
|
||||
const srcMatch = buttonHtml.match(/data-src="([^"]*)"/);
|
||||
const resMatch = buttonHtml.match(/data-resolution="([^"]*)"/);
|
||||
const audioMatch = buttonHtml.match(/data-audio="([^"]*)"/);
|
||||
const fansubMatch = buttonHtml.match(/data-fansub="([^"]*)"/);
|
||||
|
||||
if (!srcMatch || !srcMatch[1].includes('kwik.cx')) return null;
|
||||
|
||||
const kwikUrl = srcMatch[1];
|
||||
const resolution = resMatch ? resMatch[1] : "Unknown";
|
||||
const audio = audioMatch ? audioMatch[1] : "jpn";
|
||||
const fansub = fansubMatch ? fansubMatch[1] : "Unknown";
|
||||
|
||||
try {
|
||||
const html = await fetchv2(kwikUrl).then(r => r.text());
|
||||
const scriptMatch = html.match(/<script>(.*?)<\/script>/s);
|
||||
|
||||
if (scriptMatch) {
|
||||
const scriptContent = scriptMatch[1];
|
||||
let unpacked = null;
|
||||
|
||||
if (scriptContent.includes('));eval(')) {
|
||||
const parts = scriptContent.split('));eval(');
|
||||
if (parts.length === 2) {
|
||||
const layer2Packed = parts[1].substring(0, parts[1].length - 1);
|
||||
unpacked = unpack(layer2Packed);
|
||||
}
|
||||
} else {
|
||||
unpacked = unpack(scriptContent);
|
||||
}
|
||||
|
||||
if (unpacked) {
|
||||
const urlMatch = unpacked.match(/const source=\\?['"]([^'"]+)['"]/) ||
|
||||
unpacked.match(/https:\/\/[^\s'";]+\.m3u8/);
|
||||
|
||||
if (urlMatch) {
|
||||
let hlsUrl = (urlMatch[1] || urlMatch[0]).replace(/\\+$/, '');
|
||||
const audioType = audio === "eng" ? "Dub" : "Hardsub";
|
||||
const title = `${resolution}p • ${audioType}`;
|
||||
|
||||
hlsUrl = hlsUrl
|
||||
.replace("/stream/", "/hls/")
|
||||
.replace("uwu.m3u8", "owo.m3u8");
|
||||
|
||||
return {
|
||||
title: title,
|
||||
streamUrl: hlsUrl,
|
||||
headers: {
|
||||
"Referer": "https://kwik.cx/",
|
||||
"Origin": "https://kwik.cx"
|
||||
}
|
||||
};
|
||||
const deepUnpack = (source) => {
|
||||
let decoded = source;
|
||||
let safety = 0;
|
||||
while (/eval\(function\(p,a,c,k,e,d\)/.test(decoded) && safety < 5) {
|
||||
try {
|
||||
decoded = unpack(decoded);
|
||||
safety++;
|
||||
} catch (e) {
|
||||
console.warn("[Animepahe] Unpack error at depth " + safety + ": " + e.message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return decoded;
|
||||
};
|
||||
|
||||
const streamPromises = buttons.map(async (btn) => {
|
||||
const kwikUrl = btn.src;
|
||||
const audioType = btn.audio === "jpn" ? "Hardsub" : "Dub";
|
||||
const title = btn.resolution + "p • " + audioType;
|
||||
|
||||
try {
|
||||
const headers = {
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36",
|
||||
"Referer": "https://animepahe.pw/",
|
||||
"Origin": "https://kwik.cx",
|
||||
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
|
||||
};
|
||||
const resp = await fetchv2(kwikUrl, headers);
|
||||
const html = await resp.text();
|
||||
const evalRegex = /eval\(function\(p,a,c,k,e,d\)\{[^}]*\}\('[^']*',\d+,\d+,'[^']*'\.split\('\|'\)[^)]*\)/g;
|
||||
const evalBlocks = [...html.matchAll(evalRegex)].map(m => m[0]);
|
||||
|
||||
if (evalBlocks.length === 0) {
|
||||
const scriptMatch = html.match(/<script>(.*?)<\/script>/s);
|
||||
if (scriptMatch) {
|
||||
const scriptContent = scriptMatch[1];
|
||||
let unpacked = null;
|
||||
if (scriptContent.includes('));eval(')) {
|
||||
const parts = scriptContent.split('));eval(');
|
||||
if (parts.length === 2) {
|
||||
const layer2Packed = parts[1].substring(0, parts[1].length - 1);
|
||||
try { unpacked = unpack(layer2Packed); } catch(e) {}
|
||||
}
|
||||
} else {
|
||||
try { unpacked = unpack(scriptContent); } catch(e) {}
|
||||
}
|
||||
if (unpacked) {
|
||||
const urlMatch = unpacked.match(/const source=\\?['"]([^'"]+)['"]/) ||
|
||||
unpacked.match(/https:\/\/[^\s'";]+\.m3u8/);
|
||||
if (urlMatch) {
|
||||
let hlsUrl = (urlMatch[1] || urlMatch[0]).replace(/\\+$/, '');
|
||||
hlsUrl = hlsUrl.replace("/stream/", "/hls/").replace("uwu.m3u8", "owo.m3u8");
|
||||
return {
|
||||
title: title,
|
||||
streamUrl: hlsUrl,
|
||||
headers: { "Referer": "https://kwik.cx/", "Origin": "https://kwik.cx" }
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
let hlsUrl = null;
|
||||
for (const block of evalBlocks) {
|
||||
try {
|
||||
const unpacked = deepUnpack(block);
|
||||
console.log("[Animepahe] Unpacked snippet: " + unpacked.substring(0, 150));
|
||||
const sourceMatch = unpacked.match(/(?:source\s*=\s*['"]([^'"]+\.m3u8)['"])/i);
|
||||
if (sourceMatch) {
|
||||
hlsUrl = sourceMatch[1];
|
||||
break;
|
||||
}
|
||||
const directMatch = unpacked.match(/https?:\/\/[^\s'"<>]+\.m3u8[^\s'"<>]*/i);
|
||||
if (directMatch) {
|
||||
hlsUrl = directMatch[0];
|
||||
break;
|
||||
}
|
||||
} catch (e) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!hlsUrl) {
|
||||
return null;
|
||||
}
|
||||
|
||||
hlsUrl = hlsUrl.replace(/\\+$/, '');
|
||||
hlsUrl = hlsUrl.replace("/stream/", "/hls/").replace("uwu.m3u8", "owo.m3u8");
|
||||
return {
|
||||
title: title,
|
||||
streamUrl: hlsUrl,
|
||||
headers: { "Referer": "https://kwik.cx/", "Origin": "https://kwik.cx" }
|
||||
};
|
||||
} catch (e) {
|
||||
// Continue to next
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
});
|
||||
|
||||
const streamResults = await Promise.all(streamPromises);
|
||||
const streams = streamResults.filter(s => s !== null);
|
||||
|
||||
return JSON.stringify({
|
||||
streams: streams,
|
||||
subtitle: ""
|
||||
|
||||
const results = await Promise.allSettled(streamPromises);
|
||||
const streams = results
|
||||
.filter(r => r.status === "fulfilled" && r.value)
|
||||
.map(r => r.value);
|
||||
|
||||
|
||||
streams.sort((a, b) => {
|
||||
const aIsSub = a.title.includes("Hardsub") ? 0 : 1;
|
||||
const bIsSub = b.title.includes("Hardsub") ? 0 : 1;
|
||||
if (aIsSub !== bIsSub) return aIsSub - bIsSub;
|
||||
const aRes = parseInt(a.title.match(/(\d+)p/)?.[1] || 0);
|
||||
const bRes = parseInt(b.title.match(/(\d+)p/)?.[1] || 0);
|
||||
return bRes - aRes;
|
||||
});
|
||||
|
||||
const finalResult = JSON.stringify({ streams: streams, subtitle: "" });
|
||||
return finalResult;
|
||||
|
||||
} catch (err) {
|
||||
return JSON.stringify({ streams: [], subtitle: "" });
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"name": "50/50",
|
||||
"icon": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQ3122kQwublLkZ6rf1fEpUP79BxZOFmH9BSA&s"
|
||||
},
|
||||
"version": "1.0.3",
|
||||
"version": "1.0.4",
|
||||
"language": "English",
|
||||
"streamType": "HLS",
|
||||
"quality": "1080p",
|
||||
|
||||
+65
-47
@@ -29,12 +29,17 @@ async function extractDetails(url) {
|
||||
try {
|
||||
const response = await fetchv2(url);
|
||||
const html = await response.text();
|
||||
const regex = /<div class="view-stocon"><div class="c" id="animeContents">([\s\S]*?)<\/div><\/div>/;
|
||||
const regex = /<div class="view-stocon"><div class="c"[^>]*>([\s\S]*?)<\/div>/;
|
||||
|
||||
let description = "N/A";
|
||||
const match = regex.exec(html);
|
||||
if (match) {
|
||||
description = match[1].replace(/<br>/g, "\n").replace(/ /g, " ").replace(/<[^>]*>/g, "").replace(/\n\n+/g, "\n").trim();
|
||||
description = match[1]
|
||||
.replace(/<br\s*\/?>/gi, "\n")
|
||||
.replace(/ /g, " ")
|
||||
.replace(/<[^>]*>/g, "")
|
||||
.replace(/\n\s*\n+/g, "\n")
|
||||
.trim();
|
||||
}
|
||||
|
||||
return JSON.stringify([{
|
||||
@@ -74,57 +79,70 @@ async function extractEpisodes(url) {
|
||||
}]);
|
||||
}
|
||||
}
|
||||
|
||||
async function extractStreamUrl(url) {
|
||||
try {
|
||||
const response = await fetchv2(url);
|
||||
const html = await response.text();
|
||||
const regex = /<input type="hidden" name="vurl" value="https:\/\/michealcdn\.com\/video\/([^"]+)"/;
|
||||
|
||||
const match = regex.exec(html);
|
||||
if (match) {
|
||||
try {
|
||||
const videoId = match[1];
|
||||
console.log("Video ID: " + videoId);
|
||||
const postData = "hash=" + videoId + "&r=https%3A%2F%2Fmm.viaproducciones.net%2F"
|
||||
const headers = {
|
||||
"X-Requested-With": "XMLHttpRequest",
|
||||
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
|
||||
};
|
||||
const response = await fetchv2("https://michealcdn.com/player/index.php?data=" + videoId + "&do=getVideo", headers, "POST", postData);
|
||||
const data = await response.json();
|
||||
console.log("Fetched video data: " + JSON.stringify(data));
|
||||
|
||||
const streamUrl = data.securedLink;
|
||||
return JSON.stringify({
|
||||
"streams": [
|
||||
{
|
||||
"title": "Stream 1",
|
||||
"streamUrl": streamUrl,
|
||||
"headers": {
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
|
||||
"Accept": "*/*",
|
||||
"Accept-Language": "en-US,en;q=0.9",
|
||||
"Accept-Encoding": "gzip, deflate, br",
|
||||
"Referer": "https://michealcdn.com/",
|
||||
"Origin": "https://michealcdn.com",
|
||||
"Sec-Fetch-Dest": "video",
|
||||
"Sec-Fetch-Mode": "cors",
|
||||
"Sec-Fetch-Site": "same-origin",
|
||||
"Range": "bytes=0-"
|
||||
}
|
||||
}
|
||||
],
|
||||
"subtitle": ""
|
||||
});
|
||||
} catch (err) {
|
||||
console.log("Error fetching video URL:"+ err);
|
||||
}
|
||||
return JSON.stringify({"streams": [{"title": "Error", "streamUrl": "https://error.org/", "headers": {}}], "subtitle": ""});
|
||||
|
||||
const vMatch = html.match(/<input type="hidden" name="v" value="([^"]+)"/);
|
||||
if (!vMatch) {
|
||||
return JSON.stringify({ streams: [], subtitle: "" });
|
||||
}
|
||||
|
||||
return JSON.stringify({"streams": [{"title": "Error", "streamUrl": "https://error.org/", "headers": {}}], "subtitle": ""});
|
||||
const vValue = vMatch[1];
|
||||
const glamovUrl = `https://ani.glamov.com/tv-show.php?v=${vValue}`;
|
||||
|
||||
const glamovResponse = await fetchv2(glamovUrl);
|
||||
const glamovHtml = await glamovResponse.text();
|
||||
|
||||
const iframeMatch = glamovHtml.match(/<iframe src="([^"]+)"/);
|
||||
if (!iframeMatch) {
|
||||
return JSON.stringify({ streams: [], subtitle: "" });
|
||||
}
|
||||
|
||||
let iframeUrl = iframeMatch[1];
|
||||
if (iframeUrl.startsWith("//")) iframeUrl = "https:" + iframeUrl;
|
||||
|
||||
const videoIdMatch = iframeUrl.match(/\/video\/([^/?#]+)/);
|
||||
if (!videoIdMatch) {
|
||||
return JSON.stringify({ streams: [], subtitle: "" });
|
||||
}
|
||||
const videoId = videoIdMatch[1];
|
||||
|
||||
let iframeOrigin = "";
|
||||
const originMatch = iframeUrl.match(/^(https?:\/\/[^/]+)/);
|
||||
if (originMatch) {
|
||||
iframeOrigin = originMatch[1];
|
||||
} else {
|
||||
return JSON.stringify({ streams: [], subtitle: "" });
|
||||
}
|
||||
|
||||
const apiUrl = `${iframeOrigin}/player/index.php?data=${videoId}&do=getVideo`;
|
||||
|
||||
const postData = `hash=${videoId}&r=https%3A%2F%2Fani.glamov.com%2F`;
|
||||
const headers = {
|
||||
"X-Requested-With": "XMLHttpRequest",
|
||||
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
|
||||
};
|
||||
|
||||
const apiResponse = await fetchv2(apiUrl, headers, "POST", postData);
|
||||
const apiJson = await apiResponse.json();
|
||||
|
||||
if (apiJson && apiJson.videoSource) {
|
||||
return JSON.stringify({
|
||||
streams: [{
|
||||
title: "Stream 1",
|
||||
streamUrl: apiJson.videoSource.replace(/\\\//g, "/"),
|
||||
headers: {}
|
||||
}],
|
||||
subtitle: ""
|
||||
});
|
||||
}
|
||||
|
||||
return JSON.stringify({ streams: [], subtitle: "" });
|
||||
|
||||
} catch (err) {
|
||||
return JSON.stringify({"streams": [{"title": "Error", "streamUrl": "https://error.org/", "headers": {}}], "subtitle": ""});
|
||||
return JSON.stringify({ streams: [], subtitle: "" });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"name": "50/50",
|
||||
"icon": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQ3122kQwublLkZ6rf1fEpUP79BxZOFmH9BSA&s"
|
||||
},
|
||||
"version": "1.0.8",
|
||||
"version": "1.0.9",
|
||||
"language": "Korean",
|
||||
"streamType": "HLS",
|
||||
"quality": "1080p",
|
||||
|
||||
@@ -131,3 +131,4 @@ async function extractStreamUrl(url) {
|
||||
subtitles: ""
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+24
-5
@@ -33,7 +33,17 @@ async function extractDetails(url) {
|
||||
const regex = /<div id="sinopse2">(.*?)<\/div>/s;
|
||||
const match = regex.exec(html);
|
||||
|
||||
const description = match ? match[1].trim() : "N/A";
|
||||
let description = "N/A";
|
||||
if (match) {
|
||||
description = match[1]
|
||||
.replace(/<br\s*\/?>/gi, "\n")
|
||||
.replace(/<p[^>]*>/gi, "")
|
||||
.replace(/<\/p>/gi, "\n")
|
||||
.replace(/ /g, " ")
|
||||
.replace(/<[^>]*>/g, "")
|
||||
.replace(/\n\s*\n+/g, "\n")
|
||||
.trim();
|
||||
}
|
||||
|
||||
return JSON.stringify([{
|
||||
description: description,
|
||||
@@ -62,7 +72,7 @@ async function extractEpisodes(url) {
|
||||
while ((match = epRegex.exec(html)) !== null) {
|
||||
const href = match[1].trim();
|
||||
|
||||
if (href === "https://www.anitube.news") continue;
|
||||
if (!href.includes("/video/")) continue;
|
||||
|
||||
const title = match[2];
|
||||
const numMatch = /Episódio\s+(\d+)/.exec(title);
|
||||
@@ -96,13 +106,22 @@ async function extractStreamUrl(url) {
|
||||
const match = regex.exec(html);
|
||||
|
||||
if (!match) {
|
||||
return "Error: stream not found";
|
||||
return JSON.stringify({ streams: [], subtitle: "" });
|
||||
}
|
||||
|
||||
const hlsUrl = decodeURIComponent(match[1]);
|
||||
|
||||
return hlsUrl;
|
||||
return JSON.stringify({
|
||||
streams: [{
|
||||
title: "Standard",
|
||||
streamUrl: hlsUrl,
|
||||
headers: {
|
||||
"Referer": "https://api.anivideo.net/"
|
||||
}
|
||||
}],
|
||||
subtitle: ""
|
||||
});
|
||||
} catch (err) {
|
||||
return "Error: " + err.message;
|
||||
return JSON.stringify({ streams: [], subtitle: "" });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"name": "50/50",
|
||||
"icon": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQ3122kQwublLkZ6rf1fEpUP79BxZOFmH9BSA&s"
|
||||
},
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"language": "Portuguese",
|
||||
"streamType": "HLS",
|
||||
"quality": "1080p",
|
||||
|
||||
+47
-177
@@ -76,194 +76,64 @@ async function extractEpisodes(url) {
|
||||
|
||||
async function extractStreamUrl(url) {
|
||||
try {
|
||||
console.log("Fetching URL: " + url);
|
||||
const response = await fetchv2(url);
|
||||
const html = await response.text();
|
||||
const streams = [];
|
||||
|
||||
const fmMatch = html.match(/https:\/\/filemoon\.to\/e\/[a-zA-Z0-9]+/);
|
||||
if (fmMatch) {
|
||||
const fmEmbedUrl = fmMatch[0];
|
||||
const fmResp = await fetchv2(fmEmbedUrl);
|
||||
const fmHtml = await fmResp.text();
|
||||
const okMatch = html.match(/https?:\/\/ok\.ru\/(?:videoembed|video)\/\d+/);
|
||||
console.log("OK.ru match: " + (okMatch ? okMatch[0] : "none"));
|
||||
|
||||
return filemoonExtractor(fmHtml, url);
|
||||
}
|
||||
if (okMatch) {
|
||||
let okUrl = okMatch[0].replace("/video/", "/videoembed/");
|
||||
console.log("Fetching OK.ru Embed: " + okUrl);
|
||||
const okResp = await fetchv2(okUrl);
|
||||
const okHtml = await okResp.text();
|
||||
|
||||
let hlsUrl = null;
|
||||
|
||||
return "No video found";
|
||||
} catch (err) {
|
||||
return "Error";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
async function filemoonExtractor(html, url = null) {
|
||||
// check if contains iframe, if does, extract the src and get the url
|
||||
const regex = /<iframe[^>]+src="([^"]+)"[^>]*><\/iframe>/;
|
||||
const match = html.match(regex);
|
||||
if (match) {
|
||||
console.log("Iframe URL: " + match[1]);
|
||||
const iframeUrl = match[1];
|
||||
const iframeResponse = await soraFetch(iframeUrl, {
|
||||
headers: {
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3",
|
||||
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
|
||||
"Referer": url,
|
||||
const optionsMatch = okHtml.match(/data-options="([^"]+)"/);
|
||||
if (optionsMatch) {
|
||||
try {
|
||||
const optionsJson = optionsMatch[1].replace(/"/g, '"');
|
||||
const options = JSON.parse(optionsJson);
|
||||
const metadata = JSON.parse(options.flashvars.metadata);
|
||||
hlsUrl = metadata.hlsManifestUrl;
|
||||
} catch (e) {
|
||||
console.log("Failed parsing OK.ru JSON metadata");
|
||||
}
|
||||
}
|
||||
});
|
||||
console.log("Iframe Response: " + iframeResponse.status);
|
||||
html = await iframeResponse.text();
|
||||
}
|
||||
// console.log("HTML: " + html);
|
||||
// get /<script[^>]*>([\s\S]*?)<\/script>/gi
|
||||
const scriptRegex = /<script[^>]*>([\s\S]*?)<\/script>/gi;
|
||||
const scripts = [];
|
||||
let scriptMatch;
|
||||
while ((scriptMatch = scriptRegex.exec(html)) !== null) {
|
||||
scripts.push(scriptMatch[1]);
|
||||
}
|
||||
// get the script with eval and m3u8
|
||||
const evalRegex = /eval\((.*?)\)/;
|
||||
const m3u8Regex = /m3u8/;
|
||||
// console.log("Scripts: " + scripts);
|
||||
const evalScript = scripts.find(script => evalRegex.test(script) && m3u8Regex.test(script));
|
||||
if (!evalScript) {
|
||||
console.log("No eval script found");
|
||||
return null;
|
||||
}
|
||||
const unpackedScript = unpack(evalScript);
|
||||
// get the m3u8 url
|
||||
const m3u8Regex2 = /https?:\/\/[^\s]+master\.m3u8[^\s]*?(\?[^"]*)?/;
|
||||
const m3u8Match = unpackedScript.match(m3u8Regex2);
|
||||
if (m3u8Match) {
|
||||
return m3u8Match[0];
|
||||
} else {
|
||||
console.log("No M3U8 URL found");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hlsUrl) {
|
||||
const match = okHtml.match(/hlsManifestUrl.*?(https.*?.m3u8.*?)(?:\\\\"|\\"|"|"|\\")/);
|
||||
if (match) hlsUrl = match[1];
|
||||
}
|
||||
|
||||
console.log("HLS match: " + (hlsUrl ? "Found" : "Not Found"));
|
||||
|
||||
/* REMOVE_START */
|
||||
|
||||
|
||||
class Unbaser {
|
||||
constructor(base) {
|
||||
this.ALPHABET = {
|
||||
62: "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
|
||||
95: "' !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~'",
|
||||
};
|
||||
this.dictionary = {};
|
||||
this.base = base;
|
||||
if (36 < base && base < 62) {
|
||||
this.ALPHABET[base] = this.ALPHABET[base] ||
|
||||
this.ALPHABET[62].substr(0, base);
|
||||
}
|
||||
if (2 <= base && base <= 36) {
|
||||
this.unbase = (value) => parseInt(value, base);
|
||||
}
|
||||
else {
|
||||
try {
|
||||
[...this.ALPHABET[base]].forEach((cipher, index) => {
|
||||
this.dictionary[cipher] = index;
|
||||
if (hlsUrl) {
|
||||
hlsUrl = hlsUrl
|
||||
.replace(/\\u0026/g, "&")
|
||||
.replace(/&/g, "&")
|
||||
.replace(/\\\//g, "/");
|
||||
|
||||
if (hlsUrl.startsWith("//")) hlsUrl = "https:" + hlsUrl;
|
||||
|
||||
console.log("Final HLS URL: " + hlsUrl);
|
||||
streams.push({
|
||||
title: "OK.ru",
|
||||
streamUrl: hlsUrl,
|
||||
headers: { "Referer": "https://ok.ru/" }
|
||||
});
|
||||
}
|
||||
catch (er) {
|
||||
throw Error("Unsupported base encoding.");
|
||||
}
|
||||
this.unbase = this._dictunbaser;
|
||||
}
|
||||
}
|
||||
_dictunbaser(value) {
|
||||
let ret = 0;
|
||||
[...value].reverse().forEach((cipher, index) => {
|
||||
ret = ret + ((Math.pow(this.base, index)) * this.dictionary[cipher]);
|
||||
|
||||
return JSON.stringify({
|
||||
streams: streams,
|
||||
subtitle: ""
|
||||
});
|
||||
return ret;
|
||||
} catch (err) {
|
||||
console.log("Error in extractStreamUrl: " + err.message);
|
||||
return JSON.stringify({ streams: [], subtitle: "" });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function unpack(source) {
|
||||
let { payload, symtab, radix, count } = _filterargs(source);
|
||||
if (count != symtab.length) {
|
||||
throw Error("Malformed p.a.c.k.e.r. symtab.");
|
||||
}
|
||||
let unbase;
|
||||
try {
|
||||
unbase = new Unbaser(radix);
|
||||
}
|
||||
catch (e) {
|
||||
throw Error("Unknown p.a.c.k.e.r. encoding.");
|
||||
}
|
||||
function lookup(match) {
|
||||
const word = match;
|
||||
let word2;
|
||||
if (radix == 1) {
|
||||
word2 = symtab[parseInt(word)];
|
||||
}
|
||||
else {
|
||||
word2 = symtab[unbase.unbase(word)];
|
||||
}
|
||||
return word2 || word;
|
||||
}
|
||||
source = payload.replace(/\b\w+\b/g, lookup);
|
||||
return _replacestrings(source);
|
||||
function _filterargs(source) {
|
||||
const juicers = [
|
||||
/}\('(.*)', *(\d+|\[\]), *(\d+), *'(.*)'\.split\('\|'\), *(\d+), *(.*)\)\)/,
|
||||
/}\('(.*)', *(\d+|\[\]), *(\d+), *'(.*)'\.split\('\|'\)/,
|
||||
];
|
||||
for (const juicer of juicers) {
|
||||
const args = juicer.exec(source);
|
||||
if (args) {
|
||||
let a = args;
|
||||
if (a[2] == "[]") {
|
||||
}
|
||||
try {
|
||||
return {
|
||||
payload: a[1],
|
||||
symtab: a[4].split("|"),
|
||||
radix: parseInt(a[2]),
|
||||
count: parseInt(a[3]),
|
||||
};
|
||||
}
|
||||
catch (ValueError) {
|
||||
throw Error("Corrupted p.a.c.k.e.r. data.");
|
||||
}
|
||||
}
|
||||
}
|
||||
throw Error("Could not make sense of p.a.c.k.e.r data (unexpected code structure)");
|
||||
}
|
||||
function _replacestrings(source) {
|
||||
return source;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Uses Sora's fetchv2 on ipad, fallbacks to regular fetch on Windows
|
||||
* @author ShadeOfChaos
|
||||
*
|
||||
* @param {string} url The URL to make the request to.
|
||||
* @param {object} [options] The options to use for the request.
|
||||
* @param {object} [options.headers] The headers to send with the request.
|
||||
* @param {string} [options.method='GET'] The method to use for the request.
|
||||
* @param {string} [options.body=null] The body of the request.
|
||||
*
|
||||
* @returns {Promise<Response|null>} The response from the server, or null if the
|
||||
* request failed.
|
||||
*/
|
||||
async function soraFetch(url, options = { headers: {}, method: 'GET', body: null }) {
|
||||
try {
|
||||
return await fetchv2(url, options.headers ?? {}, options.method ?? 'GET', options.body ?? null);
|
||||
} catch(e) {
|
||||
try {
|
||||
return await fetch(url, options);
|
||||
} catch(error) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* REMOVE_END */
|
||||
|
||||
/* SCHEME END */
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user