calculus / src /iptorrents.js
no1b4me's picture
Update src/iptorrents.js
984b721 verified
raw
history blame
7.34 kB
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 };