import xml2js from 'xml2js'; import readTorrent from 'read-torrent'; import { promisify } from 'util'; const readTorrentPromise = promisify(readTorrent); const RSS_FEEDS = [ { name: 'IPT', url: 'https://ipt.beelyrics.net/t.rss?u=2181360;tp=aa51b88f9fa0d5abdbb925b10c0d9d59;48;20;7;100;101;90;89;68;6;62;54;22;99;4;5;65;23;26;79;25;24;download' } ]; const parser = new xml2js.Parser({ explicitArray: false, ignoreAttrs: true }); async function downloadAndParseTorrent(url) { try { console.log('Downloading torrent from:', url); const options = { headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36', 'Accept': '*/*', 'Cookie': 'uid=2105434; pass=82acec029bda7c69257905656252be36; login=1', 'Referer': 'https://ipt.beelyrics.net/', 'Origin': 'https://ipt.beelyrics.net' } }; const torrentInfo = await readTorrentPromise(url, options); console.log('Parsed torrent info:', { name: torrentInfo.name, length: torrentInfo.length, files: torrentInfo.files?.length || 0, announce: torrentInfo.announce }); if (!torrentInfo?.infoHash) { console.error('No info hash found'); return null; } const videoFiles = torrentInfo.files?.filter(file => { const filePath = Array.isArray(file.path) ? file.path.join('/') : file.path; return /\.(mp4|mkv|avi|mov|wmv)$/i.test(filePath); }) || []; if (videoFiles.length === 0) { console.log('No video files found'); return null; } videoFiles.sort((a, b) => b.length - a.length); const mainFile = videoFiles[0]; const mainFilePath = Array.isArray(mainFile.path) ? mainFile.path.join('/') : mainFile.path; const magnetUri = `magnet:?xt=urn:btih:${torrentInfo.infoHash}` + `&dn=${encodeURIComponent(torrentInfo.name)}` + (torrentInfo.announce ? torrentInfo.announce.map(tr => `&tr=${encodeURIComponent(tr)}`).join('') : ''); return { magnetLink: magnetUri, files: videoFiles, infoHash: torrentInfo.infoHash, mainFile: { path: mainFilePath, length: mainFile.length } }; } catch (error) { console.error('Error:', error); return null; } } function formatFileSize(bytes) { const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB']; if (bytes === 0) return '0 Bytes'; const i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024))); return Math.round(bytes / Math.pow(1024, i) * 100) / 100 + ' ' + sizes[i]; } function parseTorrentInfo(item) { let size = 'Unknown'; let category = 'Unknown'; let sizeInMB = 0; const parts = (item.description || '').split(/[;|]/); if (parts.length >= 1) { const sizeInfo = formatSize(parts[0].trim()); size = sizeInfo.size; sizeInMB = sizeInfo.sizeInMB; } if (parts.length >= 2) { category = parts[1].trim(); } return { size, category, sizeInMB }; } function formatSize(sizeStr) { if (!sizeStr) return { size: 'Unknown', sizeInMB: 0 }; const match = sizeStr.match(/([\d.]+)\s*(GB|MB|KB|B)/i); if (!match) return { size: sizeStr, sizeInMB: 0 }; const [, value, unit] = match; const numValue = parseFloat(value); let sizeInMB = numValue; switch (unit.toUpperCase()) { case 'GB': sizeInMB *= 1024; break; case 'KB': sizeInMB /= 1024; break; case 'B': sizeInMB /= (1024 * 1024); break; } return { size: sizeStr.trim(), sizeInMB: Math.round(sizeInMB * 100) / 100 }; } function extractQuality(title) { const qualityMatch = title.match(/\b(2160p|1080p|720p|4k|uhd)\b/i); return qualityMatch ? qualityMatch[1].toLowerCase() : ''; } async function fetchRSSFeeds(imdbId) { console.log('\nšŸ”„ Fetching RSS feeds for:', imdbId); let allStreams = []; for (const feed of RSS_FEEDS) { try { console.log(`\nFetching from ${feed.name}...`); const rssUrl = `${feed.url};download;q=${imdbId}`; const response = await fetch(rssUrl, { headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36', 'Accept': 'application/rss+xml,application/xml,text/xml', 'Cookie': 'uid=2105434; pass=82acec029bda7c69257905656252be36; login=1', 'Referer': 'https://ipt.beelyrics.net/', 'Origin': 'https://ipt.beelyrics.net' } }); if (!response.ok) { console.error(`āŒ Failed to fetch from ${feed.name}:`, response.status); continue; } const rssData = await response.text(); const result = await parser.parseStringPromise(rssData); if (!result?.rss?.channel?.item) { console.log(`No items found in ${feed.name}`); continue; } const items = Array.isArray(result.rss.channel.item) ? result.rss.channel.item : [result.rss.channel.item]; console.log(`Found ${items.length} items in ${feed.name}`); const streams = await Promise.all(items.map(async (item, index) => { try { console.log(`\nProcessing item ${index + 1}/${items.length}:`, item.title); const torrentInfo = await downloadAndParseTorrent(item.link); if (!torrentInfo) return null; const { size, category } = parseTorrentInfo(item); const quality = extractQuality(item.title); return { magnetLink: torrentInfo.magnetLink, filename: torrentInfo.mainFile.path, websiteTitle: item.title, quality, size, source: feed.name, infoHash: torrentInfo.infoHash, mainFileSize: torrentInfo.mainFile.length }; } catch (error) { console.error(`Error processing item ${index + 1}:`, error); return null; } })); const validStreams = streams.filter(Boolean); console.log(`āœ… Processed ${validStreams.length} valid streams from ${feed.name}`); allStreams = [...allStreams, ...validStreams]; } catch (error) { console.error(`āŒ Error fetching ${feed.name}:`, error); } } allStreams.sort((a, b) => { const qualityOrder = { '2160p': 4, '4k': 4, '1080p': 3, '720p': 2 }; return (qualityOrder[b.quality] || 0) - (qualityOrder[a.quality] || 0); }); return allStreams; } export { fetchRSSFeeds };