Files
TMDB-Embed-API/providers/uhdmovies.js
T

1421 lines
57 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
const axios = require('axios');
const cheerio = require('cheerio');
const { URLSearchParams, URL } = require('url');
const FormData = require('form-data');
const { CookieJar } = require('tough-cookie');
const fs = require('fs').promises;
const path = require('path');
// Dynamic import for axios-cookiejar-support
let axiosCookieJarSupport = null;
const getAxiosCookieJarSupport = async () => {
if (!axiosCookieJarSupport) {
axiosCookieJarSupport = await import('axios-cookiejar-support');
}
return axiosCookieJarSupport;
};
// All requests are direct
// --- Domain Fetching ---
let uhdMoviesDomain = 'https://uhdmovies.email'; // Fallback domain
let domainCacheTimestamp = 0;
const DOMAIN_CACHE_TTL = 4 * 60 * 60 * 1000; // 4 hours
async function getUHDMoviesDomain() {
const now = Date.now();
if (now - domainCacheTimestamp < DOMAIN_CACHE_TTL) {
return uhdMoviesDomain;
}
try {
console.log('[UHDMovies] Fetching latest domain...');
const response = await makeRequest('https://raw.githubusercontent.com/phisher98/TVVVV/refs/heads/main/domains.json', { timeout: 10000 });
if (response.data && response.data.UHDMovies) {
uhdMoviesDomain = response.data.UHDMovies;
domainCacheTimestamp = now;
console.log(`[UHDMovies] Updated domain to: ${uhdMoviesDomain}`);
} else {
console.warn('[UHDMovies] Domain JSON fetched, but "UHDMovies" key was not found. Using fallback.');
}
} catch (error) {
console.error(`[UHDMovies] Failed to fetch latest domain, using fallback. Error: ${error.message}`);
}
return uhdMoviesDomain;
}
// Constants
const { getTmdbApiKey } = require('../utils/tmdbKey');
function getUhdMoviesKey(){
const k = getTmdbApiKey();
if(!k) console.warn('[UHDMovies] TMDB API key missing; certain metadata features skipped.');
return k;
}
// --- Caching Configuration ---
const CACHE_ENABLED = process.env.DISABLE_CACHE !== 'true'; // Set to true to disable caching for this provider
console.log(`[UHDMovies] Internal cache is ${CACHE_ENABLED ? 'enabled' : 'disabled'}.`);
const CACHE_DIR = process.env.VERCEL ? path.join('/tmp', '.uhd_cache') : path.join(__dirname, '.cache', 'uhdmovies'); // Cache directory inside providers/uhdmovies
// Caching layer simplified: placeholders only (extend for FS persistence if needed)
// --- Caching Helper Functions ---
const ensureCacheDir = async () => {
if (!CACHE_ENABLED) return;
try {
await fs.mkdir(CACHE_DIR, { recursive: true });
} catch (error) {
if (error.code !== 'EEXIST') {
console.error(`[UHDMovies Cache] Error creating cache directory: ${error.message}`);
}
}
};
const getFromCache = async (key) => {
if (!CACHE_ENABLED) return null;
return null; // no-op
};
const saveToCache = async (key, data) => {
if (!CACHE_ENABLED) return;
// no-op (placeholder for future FS caching)
};
// Initialize cache directory on startup
ensureCacheDir();
// Configure axios with headers to mimic a browser
const createAxiosInstance = () => {
const config = {
headers: {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'Accept-Language': 'en-US,en;q=0.5',
'Connection': 'keep-alive',
'Upgrade-Insecure-Requests': '1',
'Cache-Control': 'max-age=0'
},
timeout: 30000
};
return axios.create(config);
};
const axiosInstance = createAxiosInstance();
// Request helper
const makeRequest = async (url, options = {}) => {
console.log(`[UHDMovies] Making direct request to: ${url}`);
return axiosInstance.get(url, options);
};
// Removed unused in-memory cache structure (uhdMoviesCache)
// Function to search for movies
async function searchMovies(query) {
try {
const baseUrl = await getUHDMoviesDomain();
console.log(`[UHDMovies] Searching for: ${query}`);
const searchUrl = `${baseUrl}/search/${encodeURIComponent(query)}`;
const response = await makeRequest(searchUrl);
const $ = cheerio.load(response.data);
const searchResults = [];
// New logic for grid-based search results
$('article.gridlove-post').each((index, element) => {
const linkElement = $(element).find('a[href*="/download-"]');
if (linkElement.length > 0) {
const link = linkElement.first().attr('href');
// Prefer the 'title' attribute, fallback to h1 text
const title = linkElement.first().attr('title') || $(element).find('h1.sanket').text().trim();
if (link && title && !searchResults.some(item => item.link === link)) {
searchResults.push({
title,
link: link.startsWith('http') ? link : `${baseUrl}${link}`
});
}
}
});
// Fallback for original list-based search if new logic fails
if (searchResults.length === 0) {
console.log('[UHDMovies] Grid search logic found no results, trying original list-based logic...');
$('a[href*="/download-"]').each((index, element) => {
const link = $(element).attr('href');
// Avoid duplicates by checking if link already exists in results
if (link && !searchResults.some(item => item.link === link)) {
const title = $(element).text().trim();
if (title) {
searchResults.push({
title,
link: link.startsWith('http') ? link : `${baseUrl}${link}`
});
}
}
});
}
console.log(`[UHDMovies] Found ${searchResults.length} results`);
return searchResults;
} catch (error) {
console.error(`[UHDMovies] Error searching movies: ${error.message}`);
return [];
}
}
// Function to extract clean quality information from verbose text
function extractCleanQuality(fullQualityText) {
if (!fullQualityText || fullQualityText === 'Unknown Quality') {
return 'Unknown Quality';
}
const cleanedFullQualityText = fullQualityText.replace(/(\u00a9|\u00ae|[\u2000-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff])/g, '').trim();
const text = cleanedFullQualityText.toLowerCase();
const quality = [];
// Extract resolution
if (text.includes('2160p') || text.includes('4k')) {
quality.push('4K');
} else if (text.includes('1080p')) {
quality.push('1080p');
} else if (text.includes('720p')) {
quality.push('720p');
} else if (text.includes('480p')) {
quality.push('480p');
}
// Extract special features
if (text.includes('hdr')) {
quality.push('HDR');
}
if (text.includes('dolby vision') || text.includes('dovi') || /\bdv\b/.test(text)) {
quality.push('DV');
}
if (text.includes('imax')) {
quality.push('IMAX');
}
if (text.includes('bluray') || text.includes('blu-ray')) {
quality.push('BluRay');
}
// If we found any quality indicators, join them
if (quality.length > 0) {
return quality.join(' | ');
}
// Fallback: try to extract a shorter version of the original text
// Look for patterns like "Movie Name (Year) Resolution ..."
const patterns = [
/(\d{3,4}p.*?(?:x264|x265|hevc).*?)[[(]/i,
/(\d{3,4}p.*?)[[(]/i,
/((?:720p|1080p|2160p|4k).*?)$/i
];
for (const pattern of patterns) {
const match = cleanedFullQualityText.match(pattern);
if (match && match[1].trim().length < 100) {
return match[1].trim().replace(/x265/ig, 'HEVC');
}
}
// Final fallback: truncate if too long
if (cleanedFullQualityText.length > 80) {
return cleanedFullQualityText.substring(0, 77).replace(/x265/ig, 'HEVC') + '...';
}
return cleanedFullQualityText.replace(/x265/ig, 'HEVC');
}
// Function to extract download links for TV shows from a page
async function extractTvShowDownloadLinks(showPageUrl, season, episode) {
try {
console.log(`[UHDMovies] Extracting TV show links from: ${showPageUrl} for S${season}E${episode}`);
const response = await makeRequest(showPageUrl);
const $ = cheerio.load(response.data);
const showTitle = $('h1').first().text().trim();
const downloadLinks = [];
// --- NEW LOGIC TO SCOPE SEARCH TO THE CORRECT SEASON ---
let inTargetSeason = false;
let qualityText = '';
$('.entry-content').find('*').each((index, element) => {
const $el = $(element);
const text = $el.text().trim();
const seasonMatch = text.match(/^SEASON\s+(\d+)/i);
// Check if we are entering a new season block
if (seasonMatch) {
const currentSeasonNum = parseInt(seasonMatch[1], 10);
if (currentSeasonNum === season) {
inTargetSeason = true;
console.log(`[UHDMovies] Entering Season ${season} block.`);
} else if (inTargetSeason) {
// We've hit the next season, so we stop.
console.log(`[UHDMovies] Exiting Season ${season} block, now in Season ${currentSeasonNum}.`);
inTargetSeason = false;
return false; // Exit .each() loop
}
}
if (inTargetSeason) {
// This element is within the correct season's block.
// Is this a quality header? (e.g., a <pre> or a <p> with <strong>)
// It often contains resolution, release group, etc.
const isQualityHeader = $el.is('pre, p:has(strong), p:has(b), h3, h4');
if (isQualityHeader) {
const headerText = $el.text().trim();
// Filter out irrelevant headers. We can be more aggressive here.
if (headerText.length > 5 && !/plot|download|screenshot|trailer|join|powered by|season/i.test(headerText) && !($el.find('a').length > 0)) {
qualityText = headerText; // Store the most recent quality header
}
}
// Is this a paragraph with episode links?
if ($el.is('p') && $el.find('a[href*="tech.unblockedgames.world"], a[href*="tech.examzculture.in"]').length > 0) {
const linksParagraph = $el;
const episodeRegex = new RegExp(`^Episode\\s+0*${episode}(?!\\d)`, 'i');
const targetEpisodeLink = linksParagraph.find('a').filter((i, el) => {
return episodeRegex.test($(el).text().trim());
}).first();
if (targetEpisodeLink.length > 0) {
const link = targetEpisodeLink.attr('href');
if (link && !downloadLinks.some(item => item.link === link)) {
const sizeMatch = qualityText.match(/\[\s*([0-9.,]+\s*[KMGT]B)/i);
const size = sizeMatch ? sizeMatch[1] : 'Unknown';
const cleanQuality = extractCleanQuality(qualityText);
const rawQuality = qualityText.replace(/(\r\n|\n|\r)/gm, " ").replace(/\s+/g, ' ').trim();
console.log(`[UHDMovies] Found match: Quality='${qualityText}', Link='${link}'`);
downloadLinks.push({ quality: cleanQuality, size: size, link: link, rawQuality: rawQuality });
}
}
}
// --- ENHANCED: Check for maxbutton-gdrive-episode structure ---
if ($el.is('p') && $el.find('a.maxbutton-gdrive-episode').length > 0) {
const episodeRegex = new RegExp(`^Episode\\s+0*${episode}(?!\\d)`, 'i');
const targetEpisodeLink = $el.find('a.maxbutton-gdrive-episode').filter((i, el) => {
const episodeText = $(el).find('.mb-text').text().trim();
return episodeRegex.test(episodeText);
}).first();
if (targetEpisodeLink.length > 0) {
const link = targetEpisodeLink.attr('href');
if (link && !downloadLinks.some(item => item.link === link)) {
const sizeMatch = qualityText.match(/\[\s*([0-9.,]+\s*[KMGT]B)/i);
const size = sizeMatch ? sizeMatch[1] : 'Unknown';
const cleanQuality = extractCleanQuality(qualityText);
const rawQuality = qualityText.replace(/(\r\n|\n|\r)/gm, " ").replace(/\s+/g, ' ').trim();
console.log(`[UHDMovies] Found match (maxbutton): Quality='${qualityText}', Link='${link}'`);
downloadLinks.push({ quality: cleanQuality, size: size, link: link, rawQuality: rawQuality });
}
}
}
}
});
if (downloadLinks.length === 0) {
console.log('[UHDMovies] Main extraction logic failed. Checking if requested season exists on page before fallback.');
// Check if the requested season exists on the page at all
let seasonExists = false;
const actualSeasonsOnPage = new Set(); // Track what seasons actually have content
// First pass: Look for actual episode content to see what seasons are available
$('.entry-content').find('a[href*="tech.unblockedgames.world"], a[href*="tech.examzculture.in"], a.maxbutton-gdrive-episode').each((index, element) => {
const $el = $(element);
const linkText = $el.text().trim();
const episodeText = $el.find('.mb-text').text().trim() || linkText;
// Look for season indicators in episode links
const seasonMatches = [
episodeText.match(/S(\d{1,2})/i), // S01, S02, etc.
episodeText.match(/Season\s+(\d+)/i), // Season 1, Season 2, etc.
episodeText.match(/S(\d{1,2})E(\d{1,3})/i) // S01E01 format
];
for (const match of seasonMatches) {
if (match && match[1]) {
const foundSeason = parseInt(match[1], 10);
actualSeasonsOnPage.add(foundSeason);
}
}
});
console.log(`[UHDMovies] Actual seasons found on page: ${Array.from(actualSeasonsOnPage).sort((a,b) => a-b).join(', ')}`);
// Check if requested season is in the actual content
if (actualSeasonsOnPage.has(season)) {
seasonExists = true;
console.log(`[UHDMovies] Season ${season} confirmed to exist in actual episode content`);
} else {
// Fallback: Check page descriptions/titles for season mentions
$('.entry-content').find('*').each((index, element) => {
const $el = $(element);
const text = $el.text().trim();
// Match various season formats: "SEASON 2", "Season 2", "(Season 1 – 2)", "Season 1-2", etc.
const seasonMatches = [
text.match(/^SEASON\s+(\d+)/i),
text.match(/\bSeason\s+(\d+)/i),
text.match(/\(Season\s+\d+\s*[–-]\s*(\d+)\)/i), // Matches "(Season 1 – 2)"
text.match(/Season\s+\d+\s*[–-]\s*(\d+)/i), // Matches "Season 1-2"
text.match(/\bS(\d+)/i) // Matches "S2", "S02", etc.
];
for (const match of seasonMatches) {
if (match) {
const currentSeasonNum = parseInt(match[1], 10);
if (currentSeasonNum === season) {
seasonExists = true;
console.log(`[UHDMovies] Season ${season} found in page description: "${text.substring(0, 100)}..."`);
return false; // Exit .each() loop
}
// For range formats like "Season 1 – 2", check if requested season is in range
if (match[0].includes('–') || match[0].includes('-')) {
const rangeMatch = match[0].match(/Season\s+(\d+)\s*[–-]\s*(\d+)/i);
if (rangeMatch) {
const startSeason = parseInt(rangeMatch[1], 10);
const endSeason = parseInt(rangeMatch[2], 10);
if (season >= startSeason && season <= endSeason) {
seasonExists = true;
console.log(`[UHDMovies] Season ${season} found in range ${startSeason}-${endSeason} in page description`);
return false; // Exit .each() loop
}
}
}
}
}
});
}
if (!seasonExists) {
console.log(`[UHDMovies] Season ${season} not found on page. Available seasons may not include the requested season.`);
// Don't use fallback if the season doesn't exist to avoid wrong episodes
return { title: showTitle, links: [], seasonNotFound: true };
}
console.log(`[UHDMovies] Season ${season} exists on page but episode extraction failed. Trying fallback method with season filtering.`);
// --- ENHANCED FALLBACK LOGIC FOR NEW HTML STRUCTURE ---
// Try the new maxbutton-gdrive-episode structure first
$('.entry-content').find('a.maxbutton-gdrive-episode').each((i, el) => {
const linkElement = $(el);
const episodeText = linkElement.find('.mb-text').text().trim();
const episodeRegex = new RegExp(`^Episode\\s+0*${episode}(?!\\d)`, 'i');
if (episodeRegex.test(episodeText)) {
const link = linkElement.attr('href');
if (link && !downloadLinks.some(item => item.link === link)) {
let qualityText = 'Unknown Quality';
// Look for quality info in the preceding paragraph or heading
const parentP = linkElement.closest('p, div');
const prevElement = parentP.prev();
if (prevElement.length > 0) {
const prevText = prevElement.text().trim();
if (prevText && prevText.length > 5 && !prevText.toLowerCase().includes('download')) {
qualityText = prevText;
}
}
// Check if this episode belongs to the correct season
// Enhanced season check - look for various season formats
const seasonCheckRegexes = [
new RegExp(`\\.S0*${season}[\\.]`, 'i'), // .S01.
new RegExp(`S0*${season}[\\.]`, 'i'), // S01.
new RegExp(`S0*${season}\\b`, 'i'), // S01 (word boundary)
new RegExp(`Season\\s+0*${season}\\b`, 'i'), // Season 1
new RegExp(`S0*${season}`, 'i') // S01 anywhere
];
const seasonMatch = seasonCheckRegexes.some(regex => regex.test(qualityText));
if (!seasonMatch) {
console.log(`[UHDMovies] Skipping episode from different season: Quality='${qualityText}'`);
return; // Skip this episode as it's from a different season
}
const sizeMatch = qualityText.match(/\[([0-9.,]+[KMGT]B[^\]]*)\]/i);
const size = sizeMatch ? sizeMatch[1] : 'Unknown';
const cleanQuality = extractCleanQuality(qualityText);
const rawQuality = qualityText.replace(/(\r\n|\n|\r)/gm, " ").replace(/\s+/g, ' ').trim();
console.log(`[UHDMovies] Found match via enhanced fallback (maxbutton): Quality='${qualityText}', Link='${link}'`);
downloadLinks.push({ quality: cleanQuality, size: size, link: link, rawQuality: rawQuality });
}
}
});
// If still no results, try the original fallback logic
if (downloadLinks.length === 0) {
console.log(`[UHDMovies] Enhanced fallback failed, trying original fallback logic.`);
$('.entry-content').find('a[href*="tech.unblockedgames.world"], a[href*="tech.examzculture.in"]').each((i, el) => {
const linkElement = $(el);
const episodeRegex = new RegExp(`^Episode\\s+0*${episode}(?!\\d)`, 'i');
if (episodeRegex.test(linkElement.text().trim())) {
const link = linkElement.attr('href');
if (link && !downloadLinks.some(item => item.link === link)) {
let qualityText = 'Unknown Quality';
const parentP = linkElement.closest('p, div');
const prevElement = parentP.prev();
if (prevElement.length > 0) {
const prevText = prevElement.text().trim();
if (prevText && prevText.length > 5 && !prevText.toLowerCase().includes('download')) {
qualityText = prevText;
}
}
// Check if this episode belongs to the correct season
// Enhanced season check - look for various season formats
const seasonCheckRegexes = [
new RegExp(`\\.S0*${season}[\\.]`, 'i'), // .S01.
new RegExp(`S0*${season}[\\.]`, 'i'), // S01.
new RegExp(`S0*${season}\\b`, 'i'), // S01 (word boundary)
new RegExp(`Season\\s+0*${season}\\b`, 'i'), // Season 1
new RegExp(`S0*${season}`, 'i') // S01 anywhere
];
const seasonMatch = seasonCheckRegexes.some(regex => regex.test(qualityText));
if (!seasonMatch) {
console.log(`[UHDMovies] Skipping episode from different season: Quality='${qualityText}'`);
return; // Skip this episode as it's from a different season
}
const sizeMatch = qualityText.match(/\[([0-9.,]+[KMGT]B[^\]]*)\]/i);
const size = sizeMatch ? sizeMatch[1] : 'Unknown';
const cleanQuality = extractCleanQuality(qualityText);
const rawQuality = qualityText.replace(/(\r\n|\n|\r)/gm, " ").replace(/\s+/g, ' ').trim();
console.log(`[UHDMovies] Found match via original fallback: Quality='${qualityText}', Link='${link}'`);
downloadLinks.push({ quality: cleanQuality, size: size, link: link, rawQuality: rawQuality });
}
}
});
}
}
if (downloadLinks.length > 0) {
console.log(`[UHDMovies] Found ${downloadLinks.length} links for S${season}E${episode}.`);
} else {
console.log(`[UHDMovies] Could not find links for S${season}E${episode}. It's possible the logic needs adjustment or the links aren't on the page.`);
}
return { title: showTitle, links: downloadLinks };
} catch (error) {
console.error(`[UHDMovies] Error extracting TV show download links: ${error.message}`);
return { title: 'Unknown', links: [] };
}
}
// Function to extract download links from a movie page
async function extractDownloadLinks(moviePageUrl, targetYear = null) {
try {
console.log(`[UHDMovies] Extracting links from: ${moviePageUrl}`);
const response = await makeRequest(moviePageUrl);
const $ = cheerio.load(response.data);
const movieTitle = $('h1').first().text().trim();
const downloadLinks = [];
// Find all download links (the new SID links) and their associated quality information
$('a[href*="tech.unblockedgames.world"], a[href*="tech.examzculture.in"]').each((index, element) => {
const link = $(element).attr('href');
if (link && !downloadLinks.some(item => item.link === link)) {
let quality = 'Unknown Quality';
let size = 'Unknown';
// Method 1: Look for quality in the closest preceding paragraph or heading
const prevElement = $(element).closest('p').prev();
if (prevElement.length > 0) {
const prevText = prevElement.text().trim();
if (prevText && prevText.length > 20 && !prevText.includes('Download')) {
quality = prevText;
}
}
// Method 2: Look for quality in parent's siblings
if (quality === 'Unknown Quality') {
const parentSiblings = $(element).parent().prevAll().first().text().trim();
if (parentSiblings && parentSiblings.length > 20) {
quality = parentSiblings;
}
}
// Method 3: Look for bold/strong text above the link
if (quality === 'Unknown Quality') {
const strongText = $(element).closest('p').prevAll().find('strong, b').last().text().trim();
if (strongText && strongText.length > 20) {
quality = strongText;
}
}
// Method 4: Look for the entire paragraph containing quality info
if (quality === 'Unknown Quality') {
let currentElement = $(element).parent();
for (let i = 0; i < 5; i++) {
currentElement = currentElement.prev();
if (currentElement.length === 0) break;
const text = currentElement.text().trim();
if (text && text.length > 30 &&
(text.includes('1080p') || text.includes('720p') || text.includes('2160p') ||
text.includes('4K') || text.includes('HEVC') || text.includes('x264') || text.includes('x265'))) {
quality = text;
break;
}
}
}
// Year-based filtering for collections
if (targetYear && quality !== 'Unknown Quality') {
// Check for years in quality text
const yearMatches = quality.match(/\((\d{4})\)/g);
let hasMatchingYear = false;
if (yearMatches && yearMatches.length > 0) {
for (const yearMatch of yearMatches) {
const year = parseInt(yearMatch.replace(/[()]/g, ''));
if (year === targetYear) {
hasMatchingYear = true;
break;
}
}
if (!hasMatchingYear) {
console.log(`[UHDMovies] Skipping link due to year mismatch. Target: ${targetYear}, Found: ${yearMatches.join(', ')} in "${quality}"`);
return; // Skip this link
}
} else {
// If no year in quality text, check filename and other indicators
const linkText = $(element).text().trim();
const parentText = $(element).parent().text().trim();
const combinedText = `${quality} ${linkText} ${parentText}`;
// Look for years in combined text
const allYearMatches = combinedText.match(/\((\d{4})\)/g) || combinedText.match(/(\d{4})/g);
if (allYearMatches) {
let foundTargetYear = false;
for (const yearMatch of allYearMatches) {
const year = parseInt(yearMatch.replace(/[()]/g, ''));
if (year >= 1900 && year <= 2030) { // Valid movie year range
if (year === targetYear) {
foundTargetYear = true;
break;
}
}
}
if (!foundTargetYear && allYearMatches.length > 0) {
console.log(`[UHDMovies] Skipping link due to no matching year found. Target: ${targetYear}, Found years: ${allYearMatches.join(', ')} in combined text`);
return; // Skip this link
}
}
// Additional check: if quality contains movie names that don't match target year
const lowerQuality = quality.toLowerCase();
if (targetYear === 2015) {
if (lowerQuality.includes('wasp') || lowerQuality.includes('quantumania')) {
console.log(`[UHDMovies] Skipping link for 2015 target as it contains 'wasp' or 'quantumania': "${quality}"`);
return; // Skip this link
}
}
}
}
// Extract size from quality text if present
const sizeMatch = quality.match(/\[([0-9.,]+\s*[KMGT]B[^\]]*)\]/);
if (sizeMatch) {
size = sizeMatch[1];
}
// Clean up the quality information
const cleanQuality = extractCleanQuality(quality);
downloadLinks.push({
quality: cleanQuality,
size: size,
link: link,
rawQuality: quality.replace(/(\r\n|\n|\r)/gm, " ").replace(/\s+/g, ' ').trim()
});
}
});
return {
title: movieTitle,
links: downloadLinks
};
} catch (error) {
console.error(`[UHDMovies] Error extracting download links: ${error.message}`);
return { title: 'Unknown', links: [] };
}
}
function extractCodecs(rawQuality) {
const codecs = [];
const text = rawQuality.toLowerCase();
if (text.includes('hevc') || text.includes('x265')) {
codecs.push('H.265');
} else if (text.includes('x264')) {
codecs.push('H.264');
}
if (text.includes('10bit') || text.includes('10-bit')) {
codecs.push('10-bit');
}
if (text.includes('atmos')) {
codecs.push('Atmos');
} else if (text.includes('dts-hd')) {
codecs.push('DTS-HD');
} else if (text.includes('dts')) {
codecs.push('DTS');
} else if (text.includes('ddp5.1') || text.includes('dd+ 5.1') || text.includes('eac3')) {
codecs.push('EAC3');
} else if (text.includes('ac3')) {
codecs.push('AC3');
}
if (text.includes('dovi') || text.includes('dolby vision') || /\bdv\b/.test(text)) {
codecs.push('DV');
} else if (text.includes('hdr')) {
codecs.push('HDR');
}
return codecs;
}
// Function to try Instant Download method
async function tryInstantDownload($) {
const instantDownloadLink = $('a:contains("Instant Download")').attr('href');
if (!instantDownloadLink) {
return null;
}
console.log('[UHDMovies] Found "Instant Download" link, attempting to extract final URL...');
try {
const urlParams = new URLSearchParams(new URL(instantDownloadLink).search);
const keys = urlParams.get('url');
if (keys) {
const apiUrl = `${new URL(instantDownloadLink).origin}/api`;
const formData = new FormData();
formData.append('keys', keys);
const apiResponse = await axiosInstance.post(apiUrl, formData, {
headers: {
...formData.getHeaders(),
'x-token': new URL(instantDownloadLink).hostname
}
});
if (apiResponse.data && apiResponse.data.url) {
let finalUrl = apiResponse.data.url;
// Fix spaces in workers.dev URLs by encoding them properly
if (finalUrl.includes('workers.dev')) {
const urlParts = finalUrl.split('/');
const filename = urlParts[urlParts.length - 1];
const encodedFilename = filename.replace(/ /g, '%20');
urlParts[urlParts.length - 1] = encodedFilename;
finalUrl = urlParts.join('/');
}
console.log('[UHDMovies] Extracted final link from API:', finalUrl);
return finalUrl;
}
}
console.log('[UHDMovies] Could not find a valid final download link from Instant Download.');
return null;
} catch (error) {
console.log(`[UHDMovies] Error processing "Instant Download": ${error.message}`);
return null;
}
}
// Function to try Resume Cloud method
async function tryResumeCloud($) {
// Look for both "Resume Cloud" and "Cloud Resume Download" buttons
const resumeCloudButton = $('a:contains("Resume Cloud"), a:contains("Cloud Resume Download")');
if (resumeCloudButton.length === 0) {
return null;
}
const resumeLink = resumeCloudButton.attr('href');
if (!resumeLink) {
return null;
}
// Check if it's already a direct download link (workers.dev)
if (resumeLink.includes('workers.dev') || resumeLink.startsWith('http')) {
let directLink = resumeLink;
// Fix spaces in workers.dev URLs by encoding them properly
if (directLink.includes('workers.dev')) {
const urlParts = directLink.split('/');
const filename = urlParts[urlParts.length - 1];
const encodedFilename = filename.replace(/ /g, '%20');
urlParts[urlParts.length - 1] = encodedFilename;
directLink = urlParts.join('/');
}
console.log(`[UHDMovies] Found direct "Cloud Resume Download" link: ${directLink}`);
return directLink;
}
// Otherwise, follow the link to get the final download
try {
const resumeUrl = new URL(resumeLink, 'https://driveleech.net').href;
console.log(`[UHDMovies] Found 'Resume Cloud' page link. Following to: ${resumeUrl}`);
// "Click" the link by making another request
const finalPageResponse = await makeRequest(resumeUrl, { maxRedirects: 10 });
const $$ = cheerio.load(finalPageResponse.data);
// Look for direct download links
let finalDownloadLink = $$('a.btn-success[href*="workers.dev"], a[href*="driveleech.net/d/"]').attr('href');
if (finalDownloadLink) {
// Fix spaces in workers.dev URLs by encoding them properly
if (finalDownloadLink.includes('workers.dev')) {
// Split the URL at the last slash to separate the base URL from the filename
const urlParts = finalDownloadLink.split('/');
const filename = urlParts[urlParts.length - 1];
// Encode spaces in the filename part only
const encodedFilename = filename.replace(/ /g, '%20');
urlParts[urlParts.length - 1] = encodedFilename;
finalDownloadLink = urlParts.join('/');
}
console.log(`[UHDMovies] Extracted final Resume Cloud link: ${finalDownloadLink}`);
return finalDownloadLink;
} else {
console.log('[UHDMovies] Could not find the final download link on the "Resume Cloud" page.');
return null;
}
} catch (error) {
console.log(`[UHDMovies] Error processing "Resume Cloud": ${error.message}`);
return null;
}
}
// Environment variable to control URL validation
const URL_VALIDATION_ENABLED = process.env.DISABLE_URL_VALIDATION !== 'true';
console.log(`[UHDMovies] URL validation is ${URL_VALIDATION_ENABLED ? 'enabled' : 'disabled'}.`);
// Validate if a video URL is working (not 404 or broken)
async function validateVideoUrl(url, timeout = 10000) {
// Skip validation if disabled via environment variable
if (!URL_VALIDATION_ENABLED) {
console.log(`[UHDMovies] URL validation disabled, skipping validation for: ${url.substring(0, 100)}...`);
return true;
}
try {
console.log(`[UHDMovies] Validating URL: ${url.substring(0, 100)}...`);
const response = await axiosInstance.head(url, {
timeout,
headers: {
'Range': 'bytes=0-1'
}
});
// Check if status is OK (200-299) or partial content (206)
if (response.status >= 200 && response.status < 400) {
console.log(`[UHDMovies] ✓ URL validation successful (${response.status})`);
return true;
} else {
console.log(`[UHDMovies] ✗ URL validation failed with status: ${response.status}`);
return false;
}
} catch (error) {
console.log(`[UHDMovies] ✗ URL validation failed: ${error.message}`);
return false;
}
}
// Compare media to find matching result
function compareMedia(mediaInfo, searchResult) {
const normalizeString = (str) => String(str || '').toLowerCase().replace(/[^a-zA-Z0-9]/g, '');
const titleWithAnd = mediaInfo.title.replace(/\s*&\s*/g, ' and ');
const normalizedMediaTitle = normalizeString(titleWithAnd);
const normalizedResultTitle = normalizeString(searchResult.title);
console.log(`[UHDMovies] Comparing: "${mediaInfo.title}" (${mediaInfo.year}) vs "${searchResult.title}"`);
console.log(`[UHDMovies] Normalized: "${normalizedMediaTitle}" vs "${normalizedResultTitle}"`);
// Check if titles match or result title contains media title
let titleMatches = normalizedResultTitle.includes(normalizedMediaTitle);
// If direct match fails, try checking for franchise/collection matches
if (!titleMatches) {
const mainTitle = normalizedMediaTitle.split('and')[0];
const isCollection = normalizedResultTitle.includes('duology') ||
normalizedResultTitle.includes('trilogy') ||
normalizedResultTitle.includes('quadrilogy') ||
normalizedResultTitle.includes('collection') ||
normalizedResultTitle.includes('saga');
if (isCollection && normalizedResultTitle.includes(mainTitle)) {
console.log(`[UHDMovies] Found collection match: "${mainTitle}" in collection "${searchResult.title}"`);
titleMatches = true;
}
}
if (!titleMatches) {
console.log(`[UHDMovies] Title mismatch: "${normalizedResultTitle}" does not contain "${normalizedMediaTitle}"`);
return false;
}
// NEW: Negative keyword check for spinoffs
const negativeKeywords = ['challenge', 'conversation', 'story', 'in conversation'];
const originalTitleLower = mediaInfo.title.toLowerCase();
for (const keyword of negativeKeywords) {
if (normalizedResultTitle.includes(keyword.replace(/\s/g, '')) && !originalTitleLower.includes(keyword)) {
console.log(`[UHDMovies] Rejecting spinoff due to keyword: "${keyword}"`);
return false; // It's a spinoff, reject it.
}
}
// Check year if both are available
if (mediaInfo.year && searchResult.title) {
const yearRegex = /\b(19[89]\d|20\d{2})\b/g; // Look for years 1980-2099
const yearMatchesInResult = searchResult.title.match(yearRegex);
const yearRangeMatch = searchResult.title.match(/\((\d{4})\s*-\s*(\d{4})\)/);
let hasMatchingYear = false;
if (yearMatchesInResult) {
console.log(`[UHDMovies] Found years in result: ${yearMatchesInResult.join(', ')}`);
if (yearMatchesInResult.some(yearStr => Math.abs(parseInt(yearStr) - mediaInfo.year) <= 1)) {
hasMatchingYear = true;
}
}
if (!hasMatchingYear && yearRangeMatch) {
console.log(`[UHDMovies] Found year range in result: ${yearRangeMatch[0]}`);
const startYear = parseInt(yearRangeMatch[1]);
const endYear = parseInt(yearRangeMatch[2]);
if (mediaInfo.year >= startYear - 1 && mediaInfo.year <= endYear + 1) {
hasMatchingYear = true;
}
}
// If there are any years found in the title, one of them MUST match.
if ((yearMatchesInResult || yearRangeMatch) && !hasMatchingYear) {
console.log(`[UHDMovies] Year mismatch. Target: ${mediaInfo.year}, but no matching year found in result.`);
return false;
}
}
console.log(`[UHDMovies] Match successful!`);
return true;
}
// Function to score search results based on quality keywords and season coverage
function scoreResult(title, requestedSeason = null) {
let score = 0;
const lowerTitle = title.toLowerCase();
// Quality scoring
if (lowerTitle.includes('remux')) score += 10;
if (lowerTitle.includes('bluray') || lowerTitle.includes('blu-ray')) score += 8;
if (lowerTitle.includes('imax')) score += 6;
if (lowerTitle.includes('4k') || lowerTitle.includes('2160p')) score += 5;
if (lowerTitle.includes('dovi') || lowerTitle.includes('dolby vision') || /\\bdv\\b/.test(lowerTitle)) score += 4;
if (lowerTitle.includes('hdr')) score += 3;
if (lowerTitle.includes('1080p')) score += 2;
if (lowerTitle.includes('hevc') || lowerTitle.includes('x265')) score += 1;
// Season coverage scoring (for TV shows)
if (requestedSeason !== null) {
// Check for season range formats like "Season 1 – 2" or "Season 1-2"
const seasonRangeMatch = lowerTitle.match(/season\s+(\d+)\s*[–-]\s*(\d+)/i);
if (seasonRangeMatch) {
const startSeason = parseInt(seasonRangeMatch[1], 10);
const endSeason = parseInt(seasonRangeMatch[2], 10);
if (requestedSeason >= startSeason && requestedSeason <= endSeason) {
score += 50; // High bonus for season range that includes requested season
console.log(`[UHDMovies] Season range bonus (+50): ${startSeason}-${endSeason} includes requested season ${requestedSeason}`);
}
}
// Check for specific season mentions
const specificSeasonMatch = lowerTitle.match(/season\s+(\d+)/i);
if (specificSeasonMatch) {
const mentionedSeason = parseInt(specificSeasonMatch[1], 10);
if (mentionedSeason === requestedSeason) {
score += 30; // Good bonus for exact season match
console.log(`[UHDMovies] Exact season bonus (+30): Season ${mentionedSeason} matches requested season ${requestedSeason}`);
} else if (mentionedSeason < requestedSeason) {
score -= 20; // Penalty for older season when requesting newer season
console.log(`[UHDMovies] Season penalty (-20): Season ${mentionedSeason} is older than requested season ${requestedSeason}`);
}
}
// Check for "Season X Added" or similar indicators
if (lowerTitle.includes('season') && lowerTitle.includes('added')) {
const addedSeasonMatch = lowerTitle.match(/season\s+(\d+)\s+added/i);
if (addedSeasonMatch) {
const addedSeason = parseInt(addedSeasonMatch[1], 10);
if (addedSeason === requestedSeason) {
score += 40; // High bonus for newly added season
console.log(`[UHDMovies] Added season bonus (+40): Season ${addedSeason} was recently added`);
}
}
}
}
return score;
}
// Function to parse size string into MB
function parseSize(sizeString) {
if (!sizeString || typeof sizeString !== 'string') {
return 0;
}
const upperCaseSizeString = sizeString.toUpperCase();
// Regex to find a number (integer or float) followed by GB, MB, or KB
const match = upperCaseSizeString.match(/([0-9.,]+)\s*(GB|MB|KB)/);
if (!match) {
return 0;
}
const sizeValue = parseFloat(match[1].replace(/,/g, ''));
if (isNaN(sizeValue)) {
return 0;
}
const unit = match[2];
if (unit === 'GB') {
return sizeValue * 1024;
} else if (unit === 'MB') {
return sizeValue;
} else if (unit === 'KB') {
return sizeValue / 1024;
}
return 0;
}
// Helper function to extract cookies from jar for a specific URL
const getCookiesForUrl = async (jar, url) => {
try {
const cookies = await jar.getCookies(url);
if (cookies && cookies.length > 0) {
return cookies.map(cookie => cookie.toString()).join('; ');
}
} catch (error) {
console.log(`[UHDMovies] Error extracting cookies for ${url}: ${error.message}`);
}
return null;
};
// Helper function to create a session for SID resolution
const createSession = async (jar) => {
const { wrapper } = await getAxiosCookieJarSupport();
const sessionConfig = {
jar,
headers: {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
'Accept-Language': 'en-US,en;q=0.5',
'Connection': 'keep-alive',
'Upgrade-Insecure-Requests': '1'
}
};
const session = wrapper(axios.create(sessionConfig));
return session;
};
// New function to resolve the tech.unblockedgames.world links
async function resolveSidToDriveleech(sidUrl) {
console.log(`[UHDMovies] Resolving SID link: ${sidUrl}`);
const { origin } = new URL(sidUrl);
const jar = new CookieJar();
// Create session
const session = await createSession(jar);
try {
// Step 0: Get the _wp_http value
console.log(" [SID] Step 0: Fetching initial page...");
const responseStep0 = await session.get(sidUrl);
let $ = cheerio.load(responseStep0.data);
const initialForm = $('#landing');
const wp_http_step1 = initialForm.find('input[name="_wp_http"]').val();
const action_url_step1 = initialForm.attr('action');
if (!wp_http_step1 || !action_url_step1) {
console.error(" [SID] Error: Could not find _wp_http in initial form.");
return null;
}
// Step 1: POST to the first form's action URL
console.log(" [SID] Step 1: Submitting initial form...");
const step1Data = new URLSearchParams({ '_wp_http': wp_http_step1 });
const responseStep1 = await session.post(action_url_step1, step1Data, {
headers: { 'Referer': sidUrl, 'Content-Type': 'application/x-www-form-urlencoded' }
});
// Step 2: Parse verification page for second form
console.log(" [SID] Step 2: Parsing verification page...");
$ = cheerio.load(responseStep1.data);
const verificationForm = $('#landing');
const action_url_step2 = verificationForm.attr('action');
const wp_http2 = verificationForm.find('input[name="_wp_http2"]').val();
const token = verificationForm.find('input[name="token"]').val();
if (!action_url_step2) {
console.error(" [SID] Error: Could not find verification form.");
return null;
}
// Step 3: POST to the verification URL
console.log(" [SID] Step 3: Submitting verification...");
const step2Data = new URLSearchParams({ '_wp_http2': wp_http2, 'token': token });
const responseStep2 = await session.post(action_url_step2, step2Data, {
headers: { 'Referer': responseStep1.request.res.responseUrl, 'Content-Type': 'application/x-www-form-urlencoded' }
});
// Step 4: Find dynamic cookie and link from JavaScript
console.log(" [SID] Step 4: Parsing final page for JS data...");
let finalLinkPath = null;
let cookieName = null;
let cookieValue = null;
const scriptContent = responseStep2.data;
const cookieMatch = scriptContent.match(/s_343\('([^']+)',\s*'([^']+)'/);
const linkMatch = scriptContent.match(/c\.setAttribute\("href",\s*"([^"]+)"\)/);
if (cookieMatch) {
cookieName = cookieMatch[1].trim();
cookieValue = cookieMatch[2].trim();
}
if (linkMatch) {
finalLinkPath = linkMatch[1].trim();
}
if (!finalLinkPath || !cookieName || !cookieValue) {
console.error(" [SID] Error: Could not extract dynamic cookie/link from JS.");
return null;
}
const finalUrl = new URL(finalLinkPath, origin).href;
console.log(` [SID] Dynamic link found: ${finalUrl}`);
console.log(` [SID] Dynamic cookie found: ${cookieName}`);
// Step 5: Set cookie and make final request
console.log(" [SID] Step 5: Setting cookie and making final request...");
await jar.setCookie(`${cookieName}=${cookieValue}`, origin);
const finalResponse = await session.get(finalUrl, {
headers: { 'Referer': responseStep2.request.res.responseUrl }
});
// Step 6: Extract driveleech URL from meta refresh tag
$ = cheerio.load(finalResponse.data);
const metaRefresh = $('meta[http-equiv="refresh"]');
if (metaRefresh.length > 0) {
const content = metaRefresh.attr('content');
const urlMatch = content.match(/url=(.*)/i);
if (urlMatch && urlMatch[1]) {
const driveleechUrl = urlMatch[1].replace(/"/g, "").replace(/'/g, "");
console.log(` [SID] SUCCESS! Resolved Driveleech URL: ${driveleechUrl}`);
return driveleechUrl;
}
}
console.error(" [SID] Error: Could not find meta refresh tag with Driveleech URL.");
return null;
} catch (error) {
console.error(` [SID] Error during SID resolution: ${error.message}`);
if (error.response) {
console.error(` [SID] Status: ${error.response.status}`);
}
return null;
}
}
// Main function to get streams for TMDB content
async function getUHDMoviesStreams(tmdbId, mediaType = 'movie', season = null, episode = null) {
console.log(`[UHDMovies] Attempting to fetch streams for TMDB ID: ${tmdbId}, Type: ${mediaType}${mediaType === 'tv' ? `, S:${season}E:${episode}` : ''}`);
const cacheKey = `uhd_final_v18_${tmdbId}_${mediaType}${season ? `_s${season}e${episode}` : ''}`;
try {
// 1. Check cache first
let cachedLinks = await getFromCache(cacheKey);
if (cachedLinks && cachedLinks.length > 0) {
console.log(`[UHDMovies] Cache HIT for ${cacheKey}. Using ${cachedLinks.length} cached Driveleech links.`);
} else {
if (cachedLinks && cachedLinks.length === 0) {
console.log(`[UHDMovies] Cache contains empty data for ${cacheKey}. Refetching from source.`);
} else {
console.log(`[UHDMovies] Cache MISS for ${cacheKey}. Fetching from source.`);
}
console.log(`[UHDMovies] Cache MISS for ${cacheKey}. Fetching from source.`);
// 2. If cache miss, get TMDB info to perform search
const TMDB_API_KEY_UHDMOVIES = getUhdMoviesKey();
const tmdbUrl = `https://api.themoviedb.org/3/${mediaType === 'tv' ? 'tv' : 'movie'}/${tmdbId}?api_key=${TMDB_API_KEY_UHDMOVIES}`;
const tmdbResponse = await axios.get(tmdbUrl);
const tmdbData = tmdbResponse.data;
const mediaInfo = {
title: mediaType === 'tv' ? tmdbData.name : tmdbData.title,
year: parseInt(((mediaType === 'tv' ? tmdbData.first_air_date : tmdbData.release_date) || '').split('-')[0], 10)
};
if (!mediaInfo.title) throw new Error('Could not extract title from TMDB response.');
console.log(`[UHDMovies] TMDB Info: "${mediaInfo.title}" (${mediaInfo.year || 'N/A'})`);
// 3. Search for the media on UHDMovies
const searchTitle = mediaInfo.title.replace(/:/g, '').replace(/\s*&\s*/g, ' and ');
let searchResults = await searchMovies(searchTitle);
// If no results or only wrong year results, try fallback search with just main title
if (searchResults.length === 0 || !searchResults.some(result => compareMedia(mediaInfo, result))) {
console.log(`[UHDMovies] Primary search failed or no matches. Trying fallback search...`);
// Extract main title (remove subtitles after colon, "and the", etc.)
let fallbackTitle = mediaInfo.title.split(':')[0].trim();
if (fallbackTitle.includes('and the')) {
fallbackTitle = fallbackTitle.split('and the')[0].trim();
}
if (fallbackTitle !== searchTitle) {
console.log(`[UHDMovies] Fallback search with: "${fallbackTitle}"`);
const fallbackResults = await searchMovies(fallbackTitle);
if (fallbackResults.length > 0) {
searchResults = fallbackResults;
}
}
}
if (searchResults.length === 0) {
console.log(`[UHDMovies] No search results found for "${mediaInfo.title}".`);
// Don't cache empty results to allow retrying later
return [];
}
// 4. Find the best matching result
const matchingResults = searchResults.filter(result => compareMedia(mediaInfo, result));
if (matchingResults.length === 0) {
console.log(`[UHDMovies] No matching content found for "${mediaInfo.title}" (${mediaInfo.year}).`);
// Don't cache empty results to allow retrying later
return [];
}
let matchingResult;
let scoredResults = null; // Declare outside the conditional
if (matchingResults.length === 1) {
matchingResult = matchingResults[0];
} else {
console.log(`[UHDMovies] Found ${matchingResults.length} matching results. Scoring to find the best...`);
scoredResults = matchingResults.map(result => {
const score = scoreResult(result.title, mediaType === 'tv' ? season : null);
console.log(` - Score ${score}: ${result.title}`);
return { ...result, score };
}).sort((a, b) => b.score - a.score);
matchingResult = scoredResults[0];
console.log(`[UHDMovies] Best match selected with score ${matchingResult.score}: "${matchingResult.title}"`);
}
console.log(`[UHDMovies] Found matching content: "${matchingResult.title}"`);
// 5. Extract SID links from the movie/show page
let downloadInfo = await (mediaType === 'tv' ? extractTvShowDownloadLinks(matchingResult.link, season, episode) : extractDownloadLinks(matchingResult.link, mediaInfo.year));
// Check if season was not found or episode extraction failed, and we have multiple results to try
if (downloadInfo.links.length === 0 && matchingResults.length > 1 && scoredResults &&
(downloadInfo.seasonNotFound || (mediaType === 'tv' && downloadInfo.title))) {
console.log(`[UHDMovies] Season ${season} not found or episode extraction failed on best match. Trying next best match...`);
// Try the next best match
const nextBestMatch = scoredResults[1];
console.log(`[UHDMovies] Trying next best match: "${nextBestMatch.title}"`);
downloadInfo = await (mediaType === 'tv' ? extractTvShowDownloadLinks(nextBestMatch.link, season, episode) : extractDownloadLinks(nextBestMatch.link, mediaInfo.year));
if (downloadInfo.links.length > 0) {
console.log(`[UHDMovies] Successfully found links on next best match!`);
} else {
console.log(`[UHDMovies] Next best match also failed. No download links found.`);
}
}
if (downloadInfo.links.length === 0) {
console.log('[UHDMovies] No download links found on page.');
// Don't cache empty results to allow retrying later
return [];
}
// 6. Resolve all SID links to driveleech redirect URLs (intermediate step)
console.log(`[UHDMovies] Resolving ${downloadInfo.links.length} SID link(s) to driveleech redirect URLs...`);
const resolutionPromises = downloadInfo.links.map(async (linkInfo) => {
try {
let driveleechUrl = null;
if (linkInfo.link && (linkInfo.link.includes('tech.unblockedgames.world') || linkInfo.link.includes('tech.creativeexpressionsblog.com') || linkInfo.link.includes('tech.examzculture.in'))) {
driveleechUrl = await resolveSidToDriveleech(linkInfo.link);
} else if (linkInfo.link && (linkInfo.link.includes('driveseed.org') || linkInfo.link.includes('driveleech.net'))) {
// If it's already a direct driveseed/driveleech link, use it
driveleechUrl = linkInfo.link;
}
if (!driveleechUrl) return null;
console.log(`[UHDMovies] Caching driveleech redirect URL for ${linkInfo.quality}: ${driveleechUrl}`);
return { ...linkInfo, driveleechRedirectUrl: driveleechUrl };
} catch (error) {
console.error(`[UHDMovies] Error resolving ${linkInfo.quality}: ${error.message}`);
return null;
}
});
cachedLinks = (await Promise.all(resolutionPromises)).filter(Boolean);
// 7. Save the successfully resolved driveleech redirect URLs to the cache
if (cachedLinks.length > 0) {
console.log(`[UHDMovies] Caching ${cachedLinks.length} resolved driveleech redirect URLs for key: ${cacheKey}`);
await saveToCache(cacheKey, cachedLinks);
} else {
console.log(`[UHDMovies] No driveleech redirect URLs could be resolved. Not caching to allow retrying later.`);
return [];
}
}
if (!cachedLinks || cachedLinks.length === 0) {
console.log('[UHDMovies] No final file page URLs found after scraping/cache check.');
return [];
}
// 8. Process all cached driveleech redirect URLs to get streaming links
console.log(`[UHDMovies] Processing ${cachedLinks.length} cached driveleech redirect URL(s) to get streaming links.`);
const streamPromises = cachedLinks.map(async (linkInfo) => {
try {
// First, resolve the driveleech redirect URL to get the final file page URL
const response = await makeRequest(linkInfo.driveleechRedirectUrl, { maxRedirects: 10 });
let $ = cheerio.load(response.data);
// Check for JavaScript redirect (window.location.replace)
const scriptContent = $('script').html();
const redirectMatch = scriptContent && scriptContent.match(/window\.location\.replace\("([^"]+)"\)/);
let finalFilePageUrl = linkInfo.driveleechRedirectUrl;
if (redirectMatch && redirectMatch[1]) {
finalFilePageUrl = new URL(redirectMatch[1], 'https://driveleech.net/').href;
console.log(`[UHDMovies] Resolved redirect to final file page: ${finalFilePageUrl}`);
// Load the final file page
const finalResponse = await makeRequest(finalFilePageUrl, { maxRedirects: 10 });
$ = cheerio.load(finalResponse.data);
}
// Extract file size and name information
let sizeInfo = 'Unknown';
let fileName = null;
const sizeElement = $('li.list-group-item:contains("Size :")').text();
if (sizeElement) {
const sizeMatch = sizeElement.match(/Size\s*:\s*([0-9.,]+\s*[KMGT]B)/);
if (sizeMatch) {
sizeInfo = sizeMatch[1];
}
}
const nameElement = $('li.list-group-item:contains("Name :")');
if (nameElement.length > 0) {
fileName = nameElement.text().replace('Name :', '').trim();
} else {
const h5Title = $('div.card-header h5').clone().children().remove().end().text().trim();
if (h5Title) {
fileName = h5Title.replace(/\[.*\]/, '').trim();
}
}
// Try download methods to get final streaming URL
const downloadMethods = [
{ name: 'Resume Cloud', func: tryResumeCloud },
{ name: 'Instant Download', func: tryInstantDownload }
];
for (const method of downloadMethods) {
try {
const finalUrl = await method.func($);
if (finalUrl) {
const isValid = await validateVideoUrl(finalUrl);
if (isValid) {
const rawQuality = linkInfo.rawQuality || '';
const codecs = extractCodecs(rawQuality);
const cleanFileName = fileName ? fileName.replace(/\.[^/.]+$/, "").replace(/[._]/g, ' ') : (linkInfo.quality || 'Unknown');
return {
name: `UHDMovies`,
title: `${cleanFileName}\n${sizeInfo}`,
url: finalUrl,
quality: linkInfo.quality,
size: sizeInfo,
fileName: fileName,
fullTitle: rawQuality,
codecs: codecs,
behaviorHints: { bingeGroup: `uhdmovies-${linkInfo.quality}` }
};
}
}
} catch (error) {
console.log(`[UHDMovies] ${method.name} failed: ${error.message}`);
}
}
return null;
} catch (error) {
console.error(`[UHDMovies] Error processing cached driveleech redirect ${linkInfo.driveleechRedirectUrl}: ${error.message}`);
return null;
}
});
const streams = (await Promise.all(streamPromises)).filter(Boolean);
console.log(`[UHDMovies] Successfully processed ${streams.length} final stream links.`);
// Sort final streams by size
streams.sort((a, b) => {
const sizeA = parseSize(a.size);
const sizeB = parseSize(b.size);
return sizeB - sizeA;
});
return streams;
} catch (error) {
console.error(`[UHDMovies] A critical error occurred in getUHDMoviesStreams for ${tmdbId}: ${error.message}`);
if (error.stack) console.error(error.stack);
return [];
}
}
module.exports = { getUHDMoviesStreams };