Spaces:
Paused
Paused
| const express = require('express'); | |
| const { chromium } = require('playwright-core'); | |
| const axios = require('axios'); | |
| const cheerio = require('cheerio'); | |
| const app = express(); | |
| const PORT = 7860; | |
| // Disable SSL verification for Axios | |
| const axiosInstance = axios.create({ | |
| httpsAgent: new (require('https').Agent)({ rejectUnauthorized: false }) | |
| }); | |
| app.get('/getDownload', async (req, res) => { | |
| try { | |
| const { moviename, episode } = req.query; | |
| if (!moviename) { | |
| return res.status(400).json({ error: "moviename query parameter is required" }); | |
| } | |
| const searchQuery = moviename.trim(); | |
| const episodeFilter = episode ? episode.trim() : null; | |
| const searchUrl = `https://nkiri.com/?s=${encodeURIComponent(searchQuery)}`; | |
| let firstMovieLink = null; | |
| console.log("\n🔍 Searching for:", searchQuery); | |
| try { | |
| // Attempt with Axios | |
| const { data: searchPage } = await axiosInstance.get(searchUrl); | |
| const $search = cheerio.load(searchPage); | |
| firstMovieLink = $search('article.post a').attr('href') || $search('h2.entry-title a').attr('href'); | |
| } catch (error) { | |
| console.log("\n⚠️ Axios failed, switching to Playwright..."); | |
| } | |
| if (!firstMovieLink) { | |
| // Fallback to Playwright if Axios fails | |
| const browser = await chromium.launch({ headless: true, args: ['--ignore-certificate-errors'] }); | |
| const page = await browser.newPage(); | |
| await page.goto(searchUrl, { waitUntil: 'networkidle' }); | |
| await page.waitForSelector('article.post a, h2.entry-title a', { timeout: 10000 }); | |
| firstMovieLink = await page.evaluate(() => { | |
| let linkElement = document.querySelector('article.post a') || document.querySelector('h2.entry-title a'); | |
| return linkElement ? linkElement.href : null; | |
| }); | |
| await browser.close(); | |
| } | |
| if (!firstMovieLink) { | |
| return res.status(404).json({ error: "No movie found" }); | |
| } | |
| console.log("\n✅ First Movie Page Found:", firstMovieLink); | |
| // =========================== | |
| // 2️⃣ GET DOWNLOAD LINKS FROM THE MOVIE PAGE | |
| // =========================== | |
| const { data: moviePage } = await axiosInstance.get(firstMovieLink); | |
| const $movie = cheerio.load(moviePage); | |
| let downloadLinks = []; | |
| const videoExtensions = ['.mkv', '.mp4', '.mov', '.avi']; | |
| $movie('a').each((i, el) => { | |
| const link = $movie(el).attr('href'); | |
| if ( | |
| link && | |
| (link.includes('downloadwella.com') || | |
| link.includes('wetafiles.com') || | |
| videoExtensions.some(ext => link.endsWith(ext))) | |
| ) { | |
| downloadLinks.push(link); | |
| } | |
| }); | |
| if (downloadLinks.length === 0) { | |
| return res.status(404).json({ error: "No valid download links found" }); | |
| } | |
| let selectedLink = downloadLinks[0]; // Default to first link | |
| if (downloadLinks.length > 1 && episodeFilter) { | |
| const filteredLinks = downloadLinks.filter(link => link.includes(`E${episodeFilter}`) || link.includes(`e${episodeFilter}`)); | |
| if (filteredLinks.length > 0) { | |
| selectedLink = filteredLinks[0]; // Use episode-specific link if found | |
| } | |
| } | |
| console.log("\n✅ Selected Download Link:", selectedLink); | |
| // Extract movie name from filename | |
| const filename = selectedLink.split('/').pop(); | |
| const movieTitle = filename.replace(/\.(mkv|mp4|mov|avi).*$/, '').replace(/[\.\-_\(\)]/g, ' ').trim(); | |
| // =========================== | |
| // 3️⃣ HANDLE FINAL DOWNLOAD LINK (WITH PLAYWRIGHT) | |
| // =========================== | |
| if (videoExtensions.some(ext => selectedLink.endsWith(ext))) { | |
| return res.json({ | |
| movie: movieTitle, | |
| finalDownloadUrl: selectedLink | |
| }); | |
| } | |
| // Open Playwright browser | |
| const browser = await chromium.launch({ headless: true, args: ['--ignore-certificate-errors'] }); | |
| const context = await browser.newContext({ ignoreHTTPSErrors: true }); | |
| const page = await context.newPage(); | |
| await page.goto(selectedLink, { waitUntil: 'networkidle' }); | |
| // Wait for the "Create Download Link" button | |
| await page.waitForSelector('#downloadbtn', { timeout: 15000 }); | |
| console.log("\n✅ Download button found, clicking..."); | |
| // Capture final download link | |
| let finalDownloadUrl = null; | |
| page.on('response', async (response) => { | |
| const requestUrl = response.url(); | |
| if (requestUrl.includes('/d/') && videoExtensions.some(ext => requestUrl.endsWith(ext))) { | |
| finalDownloadUrl = requestUrl; | |
| console.log("\n✅ FINAL DOWNLOAD LINK:", finalDownloadUrl); | |
| } | |
| }); | |
| // Click the button to generate final link | |
| await page.evaluate(() => document.querySelector('#downloadbtn').click()); | |
| // Wait for some time to capture responses | |
| await new Promise(resolve => setTimeout(resolve, 10000)); | |
| await browser.close(); | |
| if (!finalDownloadUrl) { | |
| return res.status(404).json({ error: "Failed to extract final download link" }); | |
| } | |
| res.json({ | |
| movie: movieTitle, | |
| finalDownloadUrl | |
| }); | |
| } catch (error) { | |
| console.error("\n❌ Error:", error.message); | |
| res.status(500).json({ error: "Internal server error" }); | |
| } | |
| }); | |
| // Start the API server | |
| app.listen(PORT, () => { | |
| console.log(`✅ API is running on http://localhost:${PORT}`); | |
| }); |