mirror of
https://git.luna-app.eu/50n50/sources
synced 2025-12-21 21:26:19 +01:00
Add vidsrc/vidsrc.js
This commit is contained in:
parent
367d28a2b4
commit
8431a37e5d
1 changed files with 379 additions and 0 deletions
379
vidsrc/vidsrc.js
Normal file
379
vidsrc/vidsrc.js
Normal file
|
|
@ -0,0 +1,379 @@
|
|||
//Thanks ibro for the TMDB search!
|
||||
|
||||
async function searchResults(keyword) {
|
||||
try {
|
||||
let transformedResults = [];
|
||||
|
||||
const keywordGroups = {
|
||||
trending: ["!trending", "!hot", "!tr", "!!"],
|
||||
topRatedMovie: ["!top-rated-movie", "!topmovie", "!tm", "??"],
|
||||
topRatedTV: ["!top-rated-tv", "!toptv", "!tt", "::"],
|
||||
popularMovie: ["!popular-movie", "!popmovie", "!pm", ";;"],
|
||||
popularTV: ["!popular-tv", "!poptv", "!pt", "++"],
|
||||
};
|
||||
|
||||
const skipTitleFilter = Object.values(keywordGroups).flat();
|
||||
|
||||
const shouldFilter = !matchesKeyword(keyword, skipTitleFilter);
|
||||
|
||||
// --- TMDB Section ---
|
||||
const encodedKeyword = encodeURIComponent(keyword);
|
||||
let baseUrl = null;
|
||||
|
||||
if (matchesKeyword(keyword, keywordGroups.trending)) {
|
||||
baseUrl = `https://api.themoviedb.org/3/trending/all/week?api_key=9801b6b0548ad57581d111ea690c85c8&include_adult=false&page=`;
|
||||
} else if (matchesKeyword(keyword, keywordGroups.topRatedMovie)) {
|
||||
baseUrl = `https://api.themoviedb.org/3/movie/top_rated?api_key=9801b6b0548ad57581d111ea690c85c8&include_adult=false&page=`;
|
||||
} else if (matchesKeyword(keyword, keywordGroups.topRatedTV)) {
|
||||
baseUrl = `https://api.themoviedb.org/3/tv/top_rated?api_key=9801b6b0548ad57581d111ea690c85c8&include_adult=false&page=`;
|
||||
} else if (matchesKeyword(keyword, keywordGroups.popularMovie)) {
|
||||
baseUrl = `https://api.themoviedb.org/3/movie/popular?api_key=9801b6b0548ad57581d111ea690c85c8&include_adult=false&page=`;
|
||||
} else if (matchesKeyword(keyword, keywordGroups.popularTV)) {
|
||||
baseUrl = `https://api.themoviedb.org/3/tv/popular?api_key=9801b6b0548ad57581d111ea690c85c8&include_adult=false&page=`;
|
||||
} else {
|
||||
baseUrl = `https://api.themoviedb.org/3/search/multi?api_key=9801b6b0548ad57581d111ea690c85c8&query=${encodedKeyword}&include_adult=false&page=`;
|
||||
}
|
||||
|
||||
let dataResults = [];
|
||||
|
||||
if (baseUrl) {
|
||||
const pagePromises = Array.from({ length: 5 }, (_, i) =>
|
||||
soraFetch(baseUrl + (i + 1)).then(r => r.json())
|
||||
);
|
||||
const pages = await Promise.all(pagePromises);
|
||||
dataResults = pages.flatMap(p => p.results || []);
|
||||
}
|
||||
|
||||
if (dataResults.length > 0) {
|
||||
transformedResults = transformedResults.concat(
|
||||
dataResults
|
||||
.map(result => {
|
||||
if (result.media_type === "movie" || result.title) {
|
||||
return {
|
||||
title: result.title || result.name || result.original_title || result.original_name || "Untitled",
|
||||
image: result.poster_path ? `https://image.tmdb.org/t/p/w500${result.poster_path}` : "",
|
||||
href: `movie/${result.id}`,
|
||||
};
|
||||
} else if (result.media_type === "tv" || result.name) {
|
||||
return {
|
||||
title: result.name || result.title || result.original_name || result.original_title || "Untitled",
|
||||
image: result.poster_path ? `https://image.tmdb.org/t/p/w500${result.poster_path}` : "",
|
||||
href: `tv/${result.id}/1/1`,
|
||||
};
|
||||
}
|
||||
})
|
||||
.filter(Boolean)
|
||||
.filter(result => result.title !== "Overflow")
|
||||
.filter(result => result.title !== "My Marriage Partner Is My Student, a Cocky Troublemaker")
|
||||
.filter(r => !shouldFilter || r.title.toLowerCase().includes(keyword.toLowerCase()))
|
||||
);
|
||||
}
|
||||
|
||||
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: "" }]);
|
||||
}
|
||||
}
|
||||
|
||||
function matchesKeyword(keyword, commands) {
|
||||
const lower = keyword.toLowerCase();
|
||||
return commands.some(cmd => lower.startsWith(cmd.toLowerCase()));
|
||||
}
|
||||
|
||||
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://api.themoviedb.org/3/movie/${movieId}?api_key=ad301b7cc82ffe19273e55e4d4206885`);
|
||||
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://api.themoviedb.org/3/tv/${showId}?api_key=ad301b7cc82ffe19273e55e4d4206885`);
|
||||
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://api.themoviedb.org/3/tv/${showId}?api_key=ad301b7cc82ffe19273e55e4d4206885`);
|
||||
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://api.themoviedb.org/3/tv/${showId}/season/${seasonNumber}?api_key=ad301b7cc82ffe19273e55e4d4206885`);
|
||||
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) {
|
||||
if (ID.includes('movie')) {
|
||||
const tmdbID = ID.replace('/movie/', '');
|
||||
const headersOne = {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": "Bearer eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiI2NTQ0MWU0MTg4NjhhMWI0NDZiM2I0Mzg1MmE4OWQ2NyIsIm5iZiI6MTYzMDg4NDI0My40NzMsInN1YiI6IjYxMzU1MTkzZmQ0YTk2MDA0NDVkMTJjNiIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.Hm0W-hUx-7ph-ASvk2TpMxZbMtwVa5DEXWcgNgcqXJM",
|
||||
"Referer": "https://player.smashystream.com/",
|
||||
"Origin": "https://player.smashystream.com",
|
||||
"X-Requested-With": "XMLHttpRequest",
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/"
|
||||
};
|
||||
const tmdbResponse = await fetchv2(`https://api.themoviedb.org/3/movie/${tmdbID}?append_to_response=external_ids`, headersOne);
|
||||
const tmdbData = await tmdbResponse.json();
|
||||
|
||||
const imdbID = tmdbData.imdb_id;
|
||||
|
||||
const responseTwo = await fetchv2(`https://vsrc.su/embed/${imdbID}`);
|
||||
const responseTwoText = await responseTwo.text();
|
||||
const match = responseTwoText.match(/<iframe[^>]+src=["']([^"']+)["']/);
|
||||
const iframeSrc = match ? match[1] : null;
|
||||
|
||||
console.log(iframeSrc)
|
||||
|
||||
const responseThree = await fetchv2(`https:${iframeSrc}`, {
|
||||
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:145.0) Gecko/20100101 Firefox/145.0",
|
||||
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
||||
"accept-language": "en-US,en;q=0.5",
|
||||
"accept-encoding": "gzip, deflate, br, zstd",
|
||||
"referer": "https://vsrc.su/",
|
||||
"upgrade-insecure-requests": "1",
|
||||
"sec-fetch-dest": "iframe",
|
||||
"sec-fetch-mode": "navigate",
|
||||
"sec-fetch-site": "cross-site",
|
||||
"priority": "u=4",
|
||||
"te": "trailers"
|
||||
});
|
||||
const responseThreeText = await responseThree.text();
|
||||
const srcMatch = responseThreeText.match(/src:\s*['"]([^'"]+)['"]/);
|
||||
const prorcpSrc = srcMatch ? srcMatch[1] : null;
|
||||
|
||||
const responseFour = await fetchv2(`https://cloudnestra.com${prorcpSrc}`, {
|
||||
"referer": "https://cloudnestra.com/",
|
||||
});
|
||||
const responseFourText = await responseFour.text();
|
||||
console.log(responseFourText);
|
||||
const hiddenDivMatch = responseFourText.match(/<div id="([^"]+)"[^>]*style=["']display\s*:\s*none;?["'][^>]*>([a-zA-Z0-9:\/.,{}\-_=+ ]+)<\/div>/);
|
||||
const hiddenDivId = hiddenDivMatch ? hiddenDivMatch[1] : null;
|
||||
const hiddenDivContents = hiddenDivMatch ? hiddenDivMatch[2] : null;
|
||||
console.log(`Hidden Div ID: ${hiddenDivId}`);
|
||||
console.log(`Hidden Div Contents: ${hiddenDivContents}`);
|
||||
|
||||
const postData = {
|
||||
"text": hiddenDivContents,
|
||||
"div_id": hiddenDivId
|
||||
};
|
||||
|
||||
const decryptHeaders = {
|
||||
"Content-Type": "application/json"
|
||||
};
|
||||
const decryptResponse = await fetchv2(
|
||||
`https://enc-dec.app/api/dec-cloudnestra`,
|
||||
decryptHeaders,
|
||||
"POST",
|
||||
JSON.stringify(postData)
|
||||
);
|
||||
const decryptData = await decryptResponse.json();
|
||||
console.log(JSON.stringify(decryptData));
|
||||
let streams = [];
|
||||
if (decryptData && decryptData.result && Array.isArray(decryptData.result)) {
|
||||
streams = decryptData.result.map((url, idx) => ({
|
||||
title: `Server ${idx + 1}`,
|
||||
streamUrl: url,
|
||||
headers: {
|
||||
referer: "https://cloudnestra.com/",
|
||||
origin: "https://cloudnestra.com"
|
||||
}
|
||||
}));
|
||||
}
|
||||
const resultObj = {
|
||||
streams,
|
||||
subtitle: ""
|
||||
};
|
||||
return JSON.stringify(resultObj);
|
||||
|
||||
} else if (ID.includes('tv')) {
|
||||
const parts = ID.split('/');
|
||||
const tmdbID = parts[2];
|
||||
const seasonNumber = parts[3];
|
||||
const episodeNumber = parts[4];
|
||||
console.log(`TMDB ID: ${tmdbID}, Season: ${seasonNumber}, Episode: ${episodeNumber}`);
|
||||
const headersOne = {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": "Bearer eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiI2NTQ0MWU0MTg4NjhhMWI0NDZiM2I0Mzg1MmE4OWQ2NyIsIm5iZiI6MTYzMDg4NDI0My40NzMsInN1YiI6IjYxMzU1MTkzZmQ0YTk2MDA0NDVkMTJjNiIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.Hm0W-hUx-7ph-ASvk2TpMxZbMtwVa5DEXWcgNgcqXJM",
|
||||
"Referer": "https://player.smashystream.com/",
|
||||
"Origin": "https://player.smashystream.com",
|
||||
"X-Requested-With": "XMLHttpRequest",
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/"
|
||||
};
|
||||
const tmdbResponse = await fetchv2(`https://api.themoviedb.org/3/tv/${tmdbID}?append_to_response=external_ids`, headersOne);
|
||||
const tmdbData = await tmdbResponse.json();
|
||||
console.log(JSON.stringify(tmdbData));
|
||||
const imdbID = tmdbData.external_ids.imdb_id;
|
||||
|
||||
|
||||
const responseTwo = await fetchv2(`https://vsrc.su/embed/tv?imdb=${imdbID}&season=${seasonNumber}&episode=${episodeNumber}`);
|
||||
const responseTwoText = await responseTwo.text();
|
||||
const match = responseTwoText.match(/<iframe[^>]+src=["']([^"']+)["']/);
|
||||
const iframeSrc = match ? match[1] : null;
|
||||
|
||||
console.log(iframeSrc)
|
||||
|
||||
const responseThree = await fetchv2(`https:${iframeSrc}`, {
|
||||
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:145.0) Gecko/20100101 Firefox/145.0",
|
||||
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
||||
"accept-language": "en-US,en;q=0.5",
|
||||
"accept-encoding": "gzip, deflate, br, zstd",
|
||||
"referer": "https://vsrc.su/",
|
||||
"upgrade-insecure-requests": "1",
|
||||
"sec-fetch-dest": "iframe",
|
||||
"sec-fetch-mode": "navigate",
|
||||
"sec-fetch-site": "cross-site",
|
||||
"priority": "u=4",
|
||||
"te": "trailers"
|
||||
});
|
||||
|
||||
const responseThreeText = await responseThree.text();
|
||||
const srcMatch = responseThreeText.match(/src:\s*['"]([^'"]+)['"]/);
|
||||
const prorcpSrc = srcMatch ? srcMatch[1] : null;
|
||||
|
||||
const responseFour = await fetchv2(`https://cloudnestra.com${prorcpSrc}`, {
|
||||
"referer": "https://cloudnestra.com/",
|
||||
});
|
||||
const responseFourText = await responseFour.text();
|
||||
console.log(responseFourText);
|
||||
const hiddenDivMatch = responseFourText.match(/<div id="([^"]+)"[^>]*style=["']display\s*:\s*none;?["'][^>]*>([a-zA-Z0-9:\/.,{}\-_=+ ]+)<\/div>/);
|
||||
const hiddenDivId = hiddenDivMatch ? hiddenDivMatch[1] : null;
|
||||
const hiddenDivContents = hiddenDivMatch ? hiddenDivMatch[2] : null;
|
||||
console.log(`Hidden Div ID: ${hiddenDivId}`);
|
||||
console.log(`Hidden Div Contents: ${hiddenDivContents}`);
|
||||
|
||||
const postData = {
|
||||
"text": hiddenDivContents,
|
||||
"div_id": hiddenDivId
|
||||
};
|
||||
|
||||
const decryptHeaders = {
|
||||
"Content-Type": "application/json"
|
||||
};
|
||||
const decryptResponse = await fetchv2(
|
||||
`https://enc-dec.app/api/dec-cloudnestra`,
|
||||
decryptHeaders,
|
||||
"POST",
|
||||
JSON.stringify(postData)
|
||||
);
|
||||
const decryptData = await decryptResponse.json();
|
||||
console.log(JSON.stringify(decryptData));
|
||||
let streams = [];
|
||||
if (decryptData && decryptData.result && Array.isArray(decryptData.result)) {
|
||||
streams = decryptData.result.map((url, idx) => ({
|
||||
title: `Server ${idx + 1}`,
|
||||
streamUrl: url,
|
||||
headers: {
|
||||
referer: "https://cloudnestra.com/",
|
||||
origin: "https://cloudnestra.com"
|
||||
}
|
||||
}));
|
||||
}
|
||||
const resultObj = {
|
||||
streams,
|
||||
subtitle: ""
|
||||
};
|
||||
return JSON.stringify(resultObj);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue