mikmc5/bitsa
0
1import fetch from 'node-fetch';2import * as cheerio from 'cheerio';3 4// ==============================5// sanitizeTitle: Clean Cyrillic & Noise6// ==============================7function sanitizeTitle(rawTitle) {8 return rawTitle9 .replace(/[\u0400-\u04FF]+/g, '') // Remove Cyrillic10 .replace(/[^\x00-\x7F]+/g, '') // Remove non-ASCII remnants11 .replace(/\[\s*[\u0400-\u04FF\d]+\s*[\u0400-\u04FF]*\]/g, match => {12 const digits = match.match(/\d+/);13 return digits ? `[${digits[0]}]` : '';14 })15 .replace(/^[\s/\\]+/, '') // Remove leading slashes or backslashes16 .replace(/\s{2,}/g, ' ') // Collapse multiple spaces17 .trim();18}19 20// ==============================21// fetchMegapeerTorrents: Main Export Function22// ==============================23async function fetchMegapeerTorrents(searchQuery) {24 console.log(`\n๐ Fetching Megapeer results for: ${searchQuery}`);25 26 const encodedQuery = encodeURIComponent(searchQuery);27 const searchUrl = `https://megapeer.vip/browse.php?search=${encodedQuery}&age=&cat=0&stype=0&sort=0&ascdesc=0`;28 console.log(`๐ก Fetching: ${searchUrl}`);29 30 try {31 const response = await fetch(searchUrl, {32 headers: {33 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/134.0.0.0 Safari/537.36',34 'Accept': 'text/html',35 'Referer': 'https://megapeer.vip/',36 },37 method: 'GET',38 });39 40 if (!response.ok) {41 throw new Error(`Failed to fetch from Megapeer: ${response.status}`);42 }43 44 const pageHtml = await response.text();45 const $ = cheerio.load(pageHtml);46 const torrents = [];47 48 $('tr.table_fon').each((_, element) => {49 const titleElement = $(element).find('a.url');50 const rawTitle = titleElement.text().trim();51 const sanitizedTitle = sanitizeTitle(rawTitle);52 53 const torrentPage = titleElement.attr('href');54 const downloadLink = $(element).find('a[href^="/download/"]').attr('href');55 const size = $(element).find('td[align="right"]').text().trim();56 const dateElement = $(element).find('td').first();57 const date = dateElement.text().trim();58 59 const seedLeechCell = $(element).find('td[align="center"]');60 const seedsMatch = seedLeechCell.html().match(/<font color="#008000"[^>]*>(\d+)<\/font>/i);61 const leechesMatch = seedLeechCell.html().match(/<font color="#8b0000"[^>]*>(\d+)<\/font>/i);62 63 const seeds = seedsMatch ? parseInt(seedsMatch[1]) : 0;64 const leeches = leechesMatch ? parseInt(leechesMatch[1]) : 0;65 66 if (!torrentPage) return;67 68 const torrentPageUrl = `https://megapeer.vip${torrentPage}`;69 const directDownloadUrl = `https://megapeer.vip${downloadLink}`;70 const quality = extractQuality(sanitizedTitle);71 72 torrents.push({73 title: sanitizedTitle,74 quality,75 size,76 date,77 seeds,78 leeches,79 torrentPageUrl,80 directDownloadUrl81 });82 });83 84 const completedTorrents = await Promise.all(85 torrents.map(async (torrent) => {86 try {87 const magnetLink = await extractMagnetLink(torrent.torrentPageUrl);88 return {89 websiteTitle: torrent.title,90 quality: torrent.quality,91 size: torrent.size,92 date: torrent.date,93 seeds: torrent.seeds,94 leeches: torrent.leeches,95 mainFileSize: parseSizeToBytes(torrent.size),96 torrentPageUrl: torrent.torrentPageUrl,97 directDownloadUrl: torrent.directDownloadUrl,98 magnetLink: magnetLink || null,99 };100 } catch (error) {101 console.error(`Error processing torrent ${torrent.title}:`, error);102 return null;103 }104 })105 );106 107 const validTorrents = completedTorrents.filter(Boolean);108 109 validTorrents.sort((a, b) => {110 if (b.seeds !== a.seeds) return b.seeds - a.seeds;111 112 const qualityOrder = { '2160p': 4, '4k': 4, 'uhd': 4, '1080p': 3, '720p': 2 };113 const qualityDiff = (qualityOrder[b.quality] || 0) - (qualityOrder[a.quality] || 0);114 115 return qualityDiff === 0 ? b.mainFileSize - a.mainFileSize : qualityDiff;116 });117 118 console.log(`โ
Processed ${validTorrents.length} valid torrents from Megapeer`);119 return validTorrents;120 } catch (error) {121 console.error('โ Error fetching from Megapeer:', error);122 return [];123 }124}125 126// ==============================127// extractMagnetLink: Try to find magnet links (if available)128// ==============================129async function extractMagnetLink(torrentPageUrl) {130 try {131 await new Promise(resolve => setTimeout(resolve, Math.random() * 2000 + 1000));132 133 const response = await fetch(torrentPageUrl, {134 headers: {135 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/134.0.0.0 Safari/537.36',136 'Accept': 'text/html',137 'Referer': 'https://megapeer.vip/'138 },139 method: 'GET',140 });141 142 if (!response.ok) {143 throw new Error(`Failed to fetch torrent page: ${response.status}`);144 }145 146 const pageHtml = await response.text();147 const magnetMatch = pageHtml.match(/href="(magnet:\?xt=urn:btih:[^"]+)"/);148 return magnetMatch ? magnetMatch[1] : null;149 } catch (error) {150 console.error('โ Error extracting magnet link:', error);151 return null;152 }153}154 155// ==============================156// parseSizeToBytes: Convert Sizes for Sorting157// ==============================158function parseSizeToBytes(size) {159 if (!size) return 0;160 const sizeMatch = size.match(/([\d.]+)\s*(MB|GB|TB)/i);161 if (!sizeMatch) return 0;162 163 const [, value, unit] = sizeMatch;164 const multiplier = unit.toUpperCase() === 'TB' ? 1024 ** 4 :165 unit.toUpperCase() === 'GB' ? 1024 ** 3 :166 1024 ** 2;167 return parseFloat(value) * multiplier;168}169 170// ==============================171// extractQuality: Identify Quality from Title172// ==============================173function extractQuality(title) {174 if (!title) return '';175 const qualityMatch = title.match(/\b(2160p|1080p|720p|4k|uhd)\b/i);176 return qualityMatch ? qualityMatch[1].toLowerCase() : '';177}178 179// ==============================180// Export for Server.js181// ==============================182export { fetchMegapeerTorrents };183 