Spaces:
Sleeping
Sleeping
| 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; |