Update index.js
Browse files
index.js
CHANGED
|
@@ -15,6 +15,7 @@ app.use((req, res, next) => {
|
|
| 15 |
});
|
| 16 |
|
| 17 |
const TMDB_KEY = '83d364331c40bfbe29858aeed82f45cc';
|
|
|
|
| 18 |
const UA = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36';
|
| 19 |
const TORRENTIO_BASE = 'https://torrentio.strem.fun';
|
| 20 |
|
|
@@ -32,11 +33,12 @@ const QUALITY_RANK = {
|
|
| 32 |
'4k': 5, '2160p': 5, 'webrip': 6, 'webdl': 6,
|
| 33 |
};
|
| 34 |
|
| 35 |
-
const PRIORITY_PROVIDERS = ['yts', 'knaben', 'torrentsdb', 'eztv', 'nyaasi', 'thepiratebay'];
|
| 36 |
|
| 37 |
const ALLOWED_PROVIDERS = [
|
| 38 |
'yts',
|
| 39 |
'knaben',
|
|
|
|
| 40 |
'thepiratesbay',
|
| 41 |
'thepiratebay',
|
| 42 |
'eztv',
|
|
@@ -258,6 +260,53 @@ async function scrapeYTS(imdbId) {
|
|
| 258 |
} catch (e) { console.error('[YTS]', e.message); return []; }
|
| 259 |
}
|
| 260 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 261 |
async function scrapeKnaben(title, year, isSeries, season, episode) {
|
| 262 |
if (!title) return [];
|
| 263 |
try {
|
|
@@ -356,19 +405,21 @@ app.get('/stream/:type/:id.json', async (req, res) => {
|
|
| 356 |
const title = meta?.title || '';
|
| 357 |
const year = meta?.year || '';
|
| 358 |
|
| 359 |
-
const [ytsR, knabenR, torrentioR] = await Promise.allSettled([
|
| 360 |
isSeries ? Promise.resolve([]) : scrapeYTS(imdbId),
|
|
|
|
| 361 |
scrapeKnaben(title, year, isSeries, season, episode),
|
| 362 |
fetchTorrentio(type, id, title, year),
|
| 363 |
]);
|
| 364 |
|
| 365 |
const yts = ytsR.status === 'fulfilled' ? (ytsR.value || []) : [];
|
|
|
|
| 366 |
const knaben = knabenR.status === 'fulfilled' ? (knabenR.value || []) : [];
|
| 367 |
const torrentio = torrentioR.status === 'fulfilled' ? (torrentioR.value || []) : [];
|
| 368 |
|
| 369 |
-
const streams = processStreams([...yts, ...knaben, ...torrentio], type);
|
| 370 |
|
| 371 |
-
console.log(`[stream] ${type}/${id} β yts:${yts.length} knaben:${knaben.length} torrentio:${torrentio.length} final:${streams.length}`);
|
| 372 |
res.json({ streams });
|
| 373 |
});
|
| 374 |
|
|
@@ -378,8 +429,9 @@ app.get('/diag/:type/:id', async (req, res) => {
|
|
| 378 |
const isSeries = type === 'series';
|
| 379 |
const [imdbId, season = '', episode = ''] = id.split(':');
|
| 380 |
const meta = await tmdbLookup(imdbId);
|
| 381 |
-
const [ytsR, knabenR, torrentioR] = await Promise.allSettled([
|
| 382 |
isSeries ? Promise.resolve([]) : scrapeYTS(imdbId),
|
|
|
|
| 383 |
scrapeKnaben(meta?.title || '', meta?.year || '', isSeries, season, episode),
|
| 384 |
fetchTorrentio(type, id, meta?.title || '', meta?.year || ''),
|
| 385 |
]);
|
|
@@ -387,6 +439,7 @@ app.get('/diag/:type/:id', async (req, res) => {
|
|
| 387 |
imdbId, title: meta?.title, year: meta?.year, isSeries,
|
| 388 |
tmdb: meta ? `OK: ${meta.title} (${meta.year})` : 'FAILED',
|
| 389 |
yts: { count: (ytsR.value || []).length, err: ytsR.reason?.message || null },
|
|
|
|
| 390 |
knaben: { count: (knabenR.value || []).length, err: knabenR.reason?.message || null },
|
| 391 |
torrentio: { count: (torrentioR.value || []).length, err: torrentioR.reason?.message || null },
|
| 392 |
});
|
|
@@ -497,14 +550,18 @@ app.get('/', (req, res) => {
|
|
| 497 |
</div>
|
| 498 |
</div>
|
| 499 |
<div class="stats">
|
| 500 |
-
<div class="stat"><div class="stat-val">100K+</div><div class="stat-lbl">
|
| 501 |
-
<div class="stat"><div class="stat-val">
|
| 502 |
-
<div class="stat"><div class="stat-val">
|
| 503 |
</div>
|
| 504 |
-
<div class="made-by">Made
|
| 505 |
</div>
|
| 506 |
</body>
|
| 507 |
</html>`);
|
| 508 |
});
|
| 509 |
|
| 510 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
});
|
| 16 |
|
| 17 |
const TMDB_KEY = '83d364331c40bfbe29858aeed82f45cc';
|
| 18 |
+
const TORBOX_KEY = process.env.TORBOX_KEY || '424b91b9-a79f-4817-96c1-d4c720b95983';
|
| 19 |
const UA = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36';
|
| 20 |
const TORRENTIO_BASE = 'https://torrentio.strem.fun';
|
| 21 |
|
|
|
|
| 33 |
'4k': 5, '2160p': 5, 'webrip': 6, 'webdl': 6,
|
| 34 |
};
|
| 35 |
|
| 36 |
+
const PRIORITY_PROVIDERS = ['yts', 'knaben', 'torbox', 'torrentsdb', 'eztv', 'nyaasi', 'thepiratebay'];
|
| 37 |
|
| 38 |
const ALLOWED_PROVIDERS = [
|
| 39 |
'yts',
|
| 40 |
'knaben',
|
| 41 |
+
'torbox',
|
| 42 |
'thepiratesbay',
|
| 43 |
'thepiratebay',
|
| 44 |
'eztv',
|
|
|
|
| 260 |
} catch (e) { console.error('[YTS]', e.message); return []; }
|
| 261 |
}
|
| 262 |
|
| 263 |
+
async function scrapeTorbox(title, year, isSeries, season, episode) {
|
| 264 |
+
if (!title || !TORBOX_KEY) return [];
|
| 265 |
+
try {
|
| 266 |
+
let query = title;
|
| 267 |
+
if (year && !isSeries) query += ' ' + year;
|
| 268 |
+
if (isSeries && season && episode)
|
| 269 |
+
query += ` S${String(season).padStart(2, '0')}E${String(episode).padStart(2, '0')}`;
|
| 270 |
+
|
| 271 |
+
const { data } = await axios.get(
|
| 272 |
+
`https://api.torbox.app/v1/api/search`,
|
| 273 |
+
{
|
| 274 |
+
params: { query, token: TORBOX_KEY, limit: 40 },
|
| 275 |
+
timeout: 14000,
|
| 276 |
+
headers: { 'User-Agent': UA }
|
| 277 |
+
}
|
| 278 |
+
);
|
| 279 |
+
|
| 280 |
+
if (!data?.data?.length) return [];
|
| 281 |
+
const streams = [];
|
| 282 |
+
|
| 283 |
+
for (const result of data.data) {
|
| 284 |
+
if (!result.hash) continue;
|
| 285 |
+
|
| 286 |
+
const name = result.title || result.name || '';
|
| 287 |
+
const sizeGB = result.size ? result.size / 1073741824 : null;
|
| 288 |
+
const sizeStr = sizeGB ? sizeGB.toFixed(2) + ' GB' : '';
|
| 289 |
+
const seeders = result.seeders || 0;
|
| 290 |
+
const langLine = getLangLine(name);
|
| 291 |
+
|
| 292 |
+
streams.push({
|
| 293 |
+
infoHash: result.hash.toLowerCase(),
|
| 294 |
+
name: name,
|
| 295 |
+
title: `βοΈ ${title}${year ? ' (' + year + ')' : ''}\nπ± ${seeders}\nπΎ ${sizeStr}\nπ
Torbox${langLine ? '\nπ ' + langLine : ''}`,
|
| 296 |
+
sources: [],
|
| 297 |
+
_quality: getQuality(name),
|
| 298 |
+
_seeders: seeders,
|
| 299 |
+
_sizeGB: sizeGB,
|
| 300 |
+
_source: 'torbox',
|
| 301 |
+
_provider: 'torbox',
|
| 302 |
+
});
|
| 303 |
+
}
|
| 304 |
+
|
| 305 |
+
console.log(`[Torbox] ${streams.length} for "${query}"`);
|
| 306 |
+
return streams;
|
| 307 |
+
} catch (e) { console.error('[Torbox]', e.message); return []; }
|
| 308 |
+
}
|
| 309 |
+
|
| 310 |
async function scrapeKnaben(title, year, isSeries, season, episode) {
|
| 311 |
if (!title) return [];
|
| 312 |
try {
|
|
|
|
| 405 |
const title = meta?.title || '';
|
| 406 |
const year = meta?.year || '';
|
| 407 |
|
| 408 |
+
const [ytsR, torboxR, knabenR, torrentioR] = await Promise.allSettled([
|
| 409 |
isSeries ? Promise.resolve([]) : scrapeYTS(imdbId),
|
| 410 |
+
scrapeTorbox(title, year, isSeries, season, episode),
|
| 411 |
scrapeKnaben(title, year, isSeries, season, episode),
|
| 412 |
fetchTorrentio(type, id, title, year),
|
| 413 |
]);
|
| 414 |
|
| 415 |
const yts = ytsR.status === 'fulfilled' ? (ytsR.value || []) : [];
|
| 416 |
+
const torbox = torboxR.status === 'fulfilled' ? (torboxR.value || []) : [];
|
| 417 |
const knaben = knabenR.status === 'fulfilled' ? (knabenR.value || []) : [];
|
| 418 |
const torrentio = torrentioR.status === 'fulfilled' ? (torrentioR.value || []) : [];
|
| 419 |
|
| 420 |
+
const streams = processStreams([...yts, ...torbox, ...knaben, ...torrentio], type);
|
| 421 |
|
| 422 |
+
console.log(`[stream] ${type}/${id} β yts:${yts.length} torbox:${torbox.length} knaben:${knaben.length} torrentio:${torrentio.length} final:${streams.length}`);
|
| 423 |
res.json({ streams });
|
| 424 |
});
|
| 425 |
|
|
|
|
| 429 |
const isSeries = type === 'series';
|
| 430 |
const [imdbId, season = '', episode = ''] = id.split(':');
|
| 431 |
const meta = await tmdbLookup(imdbId);
|
| 432 |
+
const [ytsR, torboxR, knabenR, torrentioR] = await Promise.allSettled([
|
| 433 |
isSeries ? Promise.resolve([]) : scrapeYTS(imdbId),
|
| 434 |
+
scrapeTorbox(meta?.title || '', meta?.year || '', isSeries, season, episode),
|
| 435 |
scrapeKnaben(meta?.title || '', meta?.year || '', isSeries, season, episode),
|
| 436 |
fetchTorrentio(type, id, meta?.title || '', meta?.year || ''),
|
| 437 |
]);
|
|
|
|
| 439 |
imdbId, title: meta?.title, year: meta?.year, isSeries,
|
| 440 |
tmdb: meta ? `OK: ${meta.title} (${meta.year})` : 'FAILED',
|
| 441 |
yts: { count: (ytsR.value || []).length, err: ytsR.reason?.message || null },
|
| 442 |
+
torbox: { count: (torboxR.value || []).length, err: torboxR.reason?.message || null },
|
| 443 |
knaben: { count: (knabenR.value || []).length, err: knabenR.reason?.message || null },
|
| 444 |
torrentio: { count: (torrentioR.value || []).length, err: torrentioR.reason?.message || null },
|
| 445 |
});
|
|
|
|
| 550 |
</div>
|
| 551 |
</div>
|
| 552 |
<div class="stats">
|
| 553 |
+
<div class="stat"><div class="stat-val">100K+</div><div class="stat-lbl">Torrents</div></div>
|
| 554 |
+
<div class="stat"><div class="stat-val">4</div><div class="stat-lbl">Sources</div></div>
|
| 555 |
+
<div class="stat"><div class="stat-val">24/7</div><div class="stat-lbl">Online</div></div>
|
| 556 |
</div>
|
| 557 |
+
<div class="made-by">Made with π€ by Van</div>
|
| 558 |
</div>
|
| 559 |
</body>
|
| 560 |
</html>`);
|
| 561 |
});
|
| 562 |
|
| 563 |
+
// βββ Server startup ββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 564 |
+
app.listen(PORT, () => {
|
| 565 |
+
console.log(`π¬ VanStreams+ running on port ${PORT}`);
|
| 566 |
+
console.log(`API Key configured: ${TORBOX_KEY ? 'YES' : 'NO'}`);
|
| 567 |
+
});
|