From fc26da62d1d0cea6e52cf45c5b33d23eee3bbf10 Mon Sep 17 00:00:00 2001 From: aka paul <50n50@noreply.localhost> Date: Wed, 4 Feb 2026 20:19:44 +0000 Subject: [PATCH] Add jiao/jiao.js --- jiao/jiao.js | 323 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 323 insertions(+) create mode 100644 jiao/jiao.js diff --git a/jiao/jiao.js b/jiao/jiao.js new file mode 100644 index 0000000..6776da5 --- /dev/null +++ b/jiao/jiao.js @@ -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 = /]*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; + } + } +}