Add jiao/jiao.js

This commit is contained in:
aka paul
2026-02-04 20:19:44 +00:00
parent 534c66f496
commit fc26da62d1
+323
View File
@@ -0,0 +1,323 @@
async function searchResults(keyword) {
try {
let transformedResults = [];
const encodedKeyword = encodeURIComponent(keyword);
const apiUrl = `https://thedatabase-brown.vercel.app/api/search?q=${encodedKeyword}&limit=50`;
const response = await soraFetch(apiUrl);
const data = await response.json();
let dataResults = data.results || [];
if (dataResults.length > 0) {
transformedResults = dataResults
.map(result => {
const isMovie = result.url.includes('/movies/');
const isTV = result.url.includes('/tvs/');
return {
title: result.title || "Untitled",
image: result.poster_path || "",
href: isMovie ? `movie/${result.tmdb_id}` : isTV ? `tv/${result.tmdb_id}/1/1` : "",
};
})
}
console.log("Transformed Results: " + JSON.stringify(transformedResults));
return JSON.stringify(transformedResults);
} catch (error) {
console.log("Fetch error in searchResults: " + error);
return JSON.stringify([{ title: "Error", image: "", href: "" }]);
}
}
async function extractDetails(url) {
try {
if(url.includes('movie')) {
const match = url.match(/movie\/([^\/]+)/);
if (!match) throw new Error("Invalid URL format");
const movieId = match[1];
const responseText = await soraFetch(`https://post-eosin.vercel.app/api/proxy?url=${encodeURIComponent(`https://api.themoviedb.org/3/movie/${movieId}?api_key=ad301b7cc82ffe19273e55e4d4206885`)}&simple=true`);
const data = await responseText.json();
const transformedResults = [{
description: data.overview || 'No description available',
aliases: `Duration: ${data.runtime ? data.runtime + " minutes" : 'Unknown'}`,
airdate: `Released: ${data.release_date ? data.release_date : 'Unknown'}`
}];
return JSON.stringify(transformedResults);
} else if(url.includes('tv')) {
const match = url.match(/tv\/([^\/]+)/);
if (!match) throw new Error("Invalid URL format");
const showId = match[1];
const responseText = await soraFetch(`https://post-eosin.vercel.app/api/proxy?url=${encodeURIComponent(`https://api.themoviedb.org/3/tv/${showId}?api_key=ad301b7cc82ffe19273e55e4d4206885`)}&simple=true`);
const data = await responseText.json();
const transformedResults = [{
description: data.overview || 'No description available',
aliases: `Duration: ${data.episode_run_time && data.episode_run_time.length ? data.episode_run_time.join(', ') + " minutes" : 'Unknown'}`,
airdate: `Aired: ${data.first_air_date ? data.first_air_date : 'Unknown'}`
}];
console.log(JSON.stringify(transformedResults));
return JSON.stringify(transformedResults);
} else {
throw new Error("Invalid URL format");
}
} catch (error) {
console.log('Details error: ' + error);
return JSON.stringify([{
description: 'Error loading description',
aliases: 'Duration: Unknown',
airdate: 'Aired/Released: Unknown'
}]);
}
}
async function extractEpisodes(url) {
try {
if(url.includes('movie')) {
const match = url.match(/movie\/([^\/]+)/);
if (!match) throw new Error("Invalid URL format");
const movieId = match[1];
const movie = [
{ href: `/movie/${movieId}`, number: 1, title: "Full Movie" }
];
console.log(movie);
return JSON.stringify(movie);
} else if(url.includes('tv')) {
const match = url.match(/tv\/([^\/]+)\/([^\/]+)\/([^\/]+)/);
if (!match) throw new Error("Invalid URL format");
const showId = match[1];
const showResponseText = await soraFetch(`https://post-eosin.vercel.app/api/proxy?url=${encodeURIComponent(`https://api.themoviedb.org/3/tv/${showId}?api_key=ad301b7cc82ffe19273e55e4d4206885`)}&simple=true`);
const showData = await showResponseText.json();
let allEpisodes = [];
for (const season of showData.seasons) {
const seasonNumber = season.season_number;
if(seasonNumber === 0) continue;
const seasonResponseText = await soraFetch(`https://post-eosin.vercel.app/api/proxy?url=${encodeURIComponent(`https://api.themoviedb.org/3/tv/${showId}/season/${seasonNumber}?api_key=ad301b7cc82ffe19273e55e4d4206885`)}&simple=true`);
const seasonData = await seasonResponseText.json();
if (seasonData.episodes && seasonData.episodes.length) {
const episodes = seasonData.episodes.map(episode => ({
href: `/tv/${showId}/${seasonNumber}/${episode.episode_number}`,
number: episode.episode_number,
title: episode.name || ""
}));
allEpisodes = allEpisodes.concat(episodes);
}
}
console.log(allEpisodes);
return JSON.stringify(allEpisodes);
} else {
throw new Error("Invalid URL format");
}
} catch (error) {
console.log('Fetch error in extractEpisodes: ' + error);
return JSON.stringify([]);
}
}
async function extractStreamUrl(ID) {
const parts = ID.split('/').filter(Boolean);
const type = parts[0];
const id = parts[1];
const season = parts[2];
const episode = parts[3];
try {
if (type === 'movie') {
const response = await soraFetch(`https://thedatabase-brown.vercel.app/api/search?tmdb=${id}`);
const data = await response.json();
const baseUrl = data.results[0].full_url;
console.log("Base URL: " + baseUrl);
const htmlResponse = await soraFetch(baseUrl);
const htmlText = htmlResponse ? await htmlResponse.text() : "";
if (htmlText.includes('Error') && htmlText.includes('1015') && htmlText.includes('rate limited')) {
return JSON.stringify({
streams: [{
title: "Rate Limited - Please slow down and try again later",
streamUrl: "",
headers: {}
}],
subtitle: "None"
});
}
const fileRegex1 = /<tr data-entry="true"[^>]*data-name="([^"]+)"[^>]*data-url="([^"]+)"[\s\S]*?data-sort="(\d+)"/g;
const fileRegex2 = /data-name="([^"]+)"[^>]*data-url="([^"]+)"[\s\S]*?data-sort="(\d+)"/g;
let matches = Array.from(htmlText.matchAll(fileRegex1));
console.log("Regex1 matches: " + matches.length);
if (matches.length === 0) {
matches = Array.from(htmlText.matchAll(fileRegex2));
console.log("Regex2 matches: " + matches.length);
}
const streams = [];
for (const match of matches) {
const filename = match[1];
const fileUrl = match[2];
const sizeBytes = parseInt(match[3]);
const sizeGB = (sizeBytes / 1073741824).toFixed(1);
const fileExt = filename.split('.').pop().toUpperCase();
const isValidType = fileExt === 'MP4' || fileExt === 'MKV';
console.log(`File: ${filename}, Ext: ${fileExt}, Valid: ${isValidType}`);
if (isValidType) {
const cleanName = filename.replace(/\./g, ' ').replace(/\.[^.]+$/, '').trim();
streams.push({
title: `[${fileExt}] [${sizeGB} GB] ${cleanName}`,
streamUrl: `${baseUrl}${filename}`,
headers: {},
sizeGB: parseFloat(sizeGB)
});
}
}
streams.sort((a, b) => a.sizeGB - b.sizeGB);
streams.forEach(stream => delete stream.sizeGB);
const result = {
streams: streams,
subtitle: "None"
};
console.log("Extracted streams: " + JSON.stringify(result));
return JSON.stringify(result);
} else if (type === 'tv') {
const response = await soraFetch(`https://thedatabase-brown.vercel.app/api/search?tmdb=${id}`);
const data = await response.json();
const baseUrl = data.results[0].full_url;
const seasonListHtml = await (await soraFetch(baseUrl)).text();
if (seasonListHtml.includes('Error') && seasonListHtml.includes('1015') && seasonListHtml.includes('rate limited')) {
return JSON.stringify({
streams: [{
title: "Rate Limited - Please slow down and try again later",
streamUrl: "",
headers: {}
}],
subtitle: "None"
});
}
if (!seasonListHtml) {
return JSON.stringify({ streams: [], subtitle: "None" });
}
const seasonRegex = new RegExp(`data-name="Season\\s+${season}"[^>]*data-url="([^"]+)"`, 'i');
const seasonMatch = seasonListHtml.match(seasonRegex);
if (!seasonMatch) {
return JSON.stringify({ streams: [], subtitle: "None" });
}
const domain = baseUrl.split('/').slice(0, 3).join('/');
const seasonUrl = `${domain}${seasonMatch[1]}`;
const episodeListHtml = await (await soraFetch(seasonUrl)).text();
if (episodeListHtml.includes('Error') && episodeListHtml.includes('1015') && episodeListHtml.includes('rate limited')) {
return JSON.stringify({
streams: [{
title: "Rate Limited - Please slow down and try again later",
streamUrl: "",
headers: {}
}],
subtitle: "None"
});
}
if (!episodeListHtml) {
return JSON.stringify({ streams: [], subtitle: "None" });
}
const episodePadded = String(episode).padStart(2, '0');
const seasonPadded = String(season).padStart(2, '0');
const episodePattern = `S${seasonPadded}E${episodePadded}`;
const fileRegex = new RegExp(`data-name="([^"]*${episodePattern}[^"]*)"[^>]*data-url="([^"]+)"[\\s\\S]*?data-sort="(\\d+)"`, 'gi');
const matches = Array.from(episodeListHtml.matchAll(fileRegex));
const streams = [];
for (const match of matches) {
const filename = match[1];
const sizeBytes = parseInt(match[3]);
const sizeGB = (sizeBytes / 1073741824).toFixed(1);
const fileExt = filename.split('.').pop().toUpperCase();
if (fileExt === 'MP4' || fileExt === 'MKV') {
const cleanName = filename.replace(/\./g, ' ').replace(/\.[^.]+$/, '').trim();
streams.push({
title: `[${fileExt}] [${sizeGB} GB] ${cleanName}`,
streamUrl: `${seasonUrl}${filename}`,
headers: {},
sizeGB: parseFloat(sizeGB)
});
}
}
streams.sort((a, b) => a.sizeGB - b.sizeGB);
streams.forEach(stream => delete stream.sizeGB);
return JSON.stringify({
streams: streams,
subtitle: "None"
});
}
} catch (error) {
console.log('Fetch error in extractStreamUrl: ' + error);
return JSON.stringify({
streams: [],
subtitle: "None"
});
}
}
async function soraFetch(url, options = { headers: {}, method: 'GET', body: null, encoding: 'utf-8' }) {
try {
return await fetchv2(
url,
options.headers ?? {},
options.method ?? 'GET',
options.body ?? null,
true,
options.encoding ?? 'utf-8'
);
} catch(e) {
try {
return await fetch(url, options);
} catch(error) {
return null;
}
}
}