import express from 'express'; import axios from 'axios'; import * as cheerio from 'cheerio'; const app = express(); app.use(express.json()); const VIDEO_EXTENSIONS = ['.mkv', '.mp4', '.mov', '.avi', '.webm', '.flv', '.wmv', '.m4v', '.ts']; /** * Extract final download link from downloadwella/wetafiles pages */ async function extractDownloadLink(url) { const capturedLinks = new Set(); const navigationLog = []; let finalDownloadUrl = null; // Create axios client with standard headers const client = axios.create({ 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': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', 'Accept-Language': 'en-US,en;q=0.5', 'Accept-Encoding': 'gzip, deflate, br', 'Connection': 'keep-alive', 'Upgrade-Insecure-Requests': '1' }, maxRedirects: 0, validateStatus: (status) => status < 500, timeout: 30000 }); try { console.log(`\nšŸ” Fetching: ${url}`); navigationLog.push({ time: new Date().toISOString(), url, step: 'initial' }); // FIRST REQUEST - Get the initial page let response = await client.get(url); console.log(`āœ… Initial page status: ${response.status}`); let $ = cheerio.load(response.data); const pageUrl = response.request.res.responseUrl || url; // Extract form data from the page const form = $('form[name="F1"]'); if (form.length === 0) { throw new Error('Could not find form[name="F1"] on page'); } const formData = {}; form.find('input[type="hidden"]').each((i, elem) => { const name = $(elem).attr('name'); const value = $(elem).attr('value') || ''; if (name) { formData[name] = value; } }); console.log('\nšŸ“ Extracted form data:'); Object.keys(formData).forEach(key => { console.log(` ${key}: ${formData[key]}`); }); // Wait a bit to simulate human behavior await new Promise(resolve => setTimeout(resolve, 2000)); // FIRST FORM SUBMISSION console.log('\nšŸ–±ļø FIRST FORM SUBMIT...'); navigationLog.push({ time: new Date().toISOString(), url: pageUrl, step: 'first_submit' }); const submitUrl = pageUrl; const postData = new URLSearchParams(formData).toString(); let submitResponse; try { submitResponse = await client.post(submitUrl, postData, { headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Origin': new URL(url).origin, 'Referer': pageUrl }, maxRedirects: 0, validateStatus: (status) => status < 500 }); } catch (error) { if (error.response) { submitResponse = error.response; } else { throw error; } } console.log(`āœ… First submit status: ${submitResponse.status}`); // Handle redirect let currentUrl = submitResponse.request.res.responseUrl || submitUrl; if (submitResponse.status === 302 || submitResponse.status === 301) { const redirectUrl = submitResponse.headers.location; currentUrl = redirectUrl.startsWith('http') ? redirectUrl : new URL(redirectUrl, submitUrl).href; console.log(`šŸ”„ Redirected to: ${currentUrl}`); navigationLog.push({ time: new Date().toISOString(), url: currentUrl, step: 'after_first_redirect' }); // Check if this redirect URL is already a download link if (currentUrl.includes('/d/') && VIDEO_EXTENSIONS.some(ext => currentUrl.includes(ext))) { finalDownloadUrl = currentUrl; capturedLinks.add(currentUrl); console.log(`āœ… āœ… āœ… DOWNLOAD LINK FOUND IN FIRST REDIRECT: ${currentUrl}`); // Return immediately - no need to continue return { success: true, downloadUrl: finalDownloadUrl, alternativeLinks: [], totalFound: 1, navigationLog: navigationLog, allCapturedLinks: Array.from(capturedLinks) }; } // Follow the redirect only if we didn't find the download link submitResponse = await client.get(currentUrl, { headers: { 'Referer': submitUrl } }); } $ = cheerio.load(submitResponse.data); // Check if we need second submission (look for download button) const downloadBtn = $('#downloadbtn'); const secondForm = $('form[name="F1"]'); if (downloadBtn.length > 0 && secondForm.length > 0) { console.log('\nšŸ–±ļø SECOND FORM SUBMIT (triggering download)...'); // Wait before second submit await new Promise(resolve => setTimeout(resolve, 3000)); // Extract updated form data const secondFormData = {}; secondForm.find('input[type="hidden"]').each((i, elem) => { const name = $(elem).attr('name'); const value = $(elem).attr('value') || ''; if (name) { secondFormData[name] = value; } }); console.log(' Second form data:', secondFormData); const secondSubmitUrl = currentUrl; const secondPostData = new URLSearchParams(secondFormData).toString(); navigationLog.push({ time: new Date().toISOString(), url: secondSubmitUrl, step: 'second_submit' }); try { const secondSubmit = await client.post(secondSubmitUrl, secondPostData, { headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Origin': new URL(url).origin, 'Referer': currentUrl }, maxRedirects: 0, validateStatus: (status) => status < 500 }); console.log(`āœ… Second submit status: ${secondSubmit.status}`); // Check for download URL in redirect if (secondSubmit.status === 302 || secondSubmit.status === 301) { const downloadRedirect = secondSubmit.headers.location; const fullDownloadUrl = downloadRedirect.startsWith('http') ? downloadRedirect : new URL(downloadRedirect, secondSubmitUrl).href; console.log(`šŸ”„ Download redirect: ${fullDownloadUrl}`); navigationLog.push({ time: new Date().toISOString(), url: fullDownloadUrl, step: 'download_redirect' }); if (fullDownloadUrl.includes('/d/') && VIDEO_EXTENSIONS.some(ext => fullDownloadUrl.includes(ext))) { finalDownloadUrl = fullDownloadUrl; capturedLinks.add(fullDownloadUrl); console.log(`āœ… āœ… āœ… DOWNLOAD LINK FOUND: ${fullDownloadUrl}`); } } else { // Check response body for download links $ = cheerio.load(secondSubmit.data); $('a').each((i, elem) => { const href = $(elem).attr('href'); if (href && href.includes('/d/')) { const fullHref = href.startsWith('http') ? href : new URL(href, secondSubmitUrl).href; if (VIDEO_EXTENSIONS.some(ext => fullHref.includes(ext))) { capturedLinks.add(fullHref); if (!finalDownloadUrl) finalDownloadUrl = fullHref; console.log(` Found in HTML: ${fullHref}`); } } }); } } catch (error) { if (error.response && (error.response.status === 302 || error.response.status === 301)) { const downloadRedirect = error.response.headers.location; const fullDownloadUrl = downloadRedirect.startsWith('http') ? downloadRedirect : new URL(downloadRedirect, secondSubmitUrl).href; if (fullDownloadUrl.includes('/d/') && VIDEO_EXTENSIONS.some(ext => fullDownloadUrl.includes(ext))) { finalDownloadUrl = fullDownloadUrl; capturedLinks.add(fullDownloadUrl); console.log(`āœ… āœ… āœ… DOWNLOAD LINK FOUND: ${fullDownloadUrl}`); } navigationLog.push({ time: new Date().toISOString(), url: fullDownloadUrl, step: 'download_redirect' }); } else { console.error('Error in second submit:', error.message); } } } // Final scan for any missed download links if (!finalDownloadUrl) { console.log('\nšŸ” Scanning page for download links...'); $('a').each((i, elem) => { const href = $(elem).attr('href'); if (href && href.includes('/d/')) { const fullHref = href.startsWith('http') ? href : new URL(href, currentUrl).href; if (VIDEO_EXTENSIONS.some(ext => fullHref.includes(ext))) { capturedLinks.add(fullHref); if (!finalDownloadUrl) finalDownloadUrl = fullHref; console.log(` Found: ${fullHref}`); } } }); } } catch (error) { console.error('āŒ Error:', error.message); if (error.response) { console.error(` Status: ${error.response.status}`); } } const allLinks = Array.from(capturedLinks); return { success: finalDownloadUrl !== null || allLinks.length > 0, downloadUrl: finalDownloadUrl || allLinks[0], alternativeLinks: allLinks.slice(1, 5), totalFound: allLinks.length, navigationLog: navigationLog, allCapturedLinks: allLinks }; } /** * API Endpoint */ app.get('/extract', async (req, res) => { const { url } = req.query; if (!url) { return res.status(400).json({ error: 'URL parameter is required', usage: '/extract?url=YOUR_DOWNLOAD_PAGE_URL' }); } try { console.log('\nšŸš€ Starting download link extraction...'); console.log(`šŸ“ Target: ${url}\n`); const result = await extractDownloadLink(url); if (!result.success || !result.downloadUrl) { return res.status(404).json({ error: 'No download link found', navigationLog: result.navigationLog, capturedLinks: result.allCapturedLinks, message: 'Could not extract download link. Check logs for navigation history.' }); } // Extract movie title const urlPath = result.downloadUrl.split('/').pop().split('?')[0]; const movieTitle = urlPath .replace(/\.(mkv|mp4|mov|avi|webm|flv|wmv|m4v|ts)$/i, '') .replace(/[\.\-_\(\)]/g, ' ') .replace(/\s+/g, ' ') .trim(); console.log('\nāœ… EXTRACTION SUCCESSFUL!'); console.log(`šŸŽ¬ Title: ${movieTitle}`); console.log(`šŸ”— Download URL: ${result.downloadUrl}\n`); res.json({ success: true, movie: movieTitle || 'Unknown', downloadUrl: result.downloadUrl, alternativeLinks: result.alternativeLinks, totalLinksFound: result.totalFound, navigationLog: result.navigationLog }); } catch (error) { console.error('\nāŒ Fatal Error:', error); res.status(500).json({ error: 'Internal server error', message: error.message }); } }); app.get('/health', (req, res) => { res.json({ status: 'ok', timestamp: new Date().toISOString() }); }); const PORT = process.env.PORT || 7860; app.listen(PORT, () => { console.log('\n' + '='.repeat(50)); console.log('šŸš€ Downloadwella Axios-Based Extractor'); console.log('='.repeat(50)); console.log(`šŸ“” Server: http://localhost:${PORT}`); console.log(`šŸ“ Usage: http://localhost:${PORT}/extract?url=YOUR_URL`); console.log(`šŸ’š Health: http://localhost:${PORT}/health`); console.log('='.repeat(50) + '\n'); }); export default app;