@vyla-entertainment/sdk 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/LICENSE +407 -0
  2. package/README.md +44 -0
  3. package/package.json +31 -0
  4. package/src/config.js +519 -0
  5. package/src/downloads/downloads.js +8 -0
  6. package/src/downloads/sources/trendimovies.js +63 -0
  7. package/src/health.js +38 -0
  8. package/src/sdk.js +65 -0
  9. package/src/sources/123anime.js +57 -0
  10. package/src/sources/1embed.js +92 -0
  11. package/src/sources/anihq.js +112 -0
  12. package/src/sources/anineko.js +81 -0
  13. package/src/sources/anipm.js +70 -0
  14. package/src/sources/flaxmovies.js +14 -0
  15. package/src/sources/fsharetv.js +44 -0
  16. package/src/sources/fsonic.js +47 -0
  17. package/src/sources/fsonline.js +46 -0
  18. package/src/sources/goated.js +262 -0
  19. package/src/sources/hexa.js +82 -0
  20. package/src/sources/kisskh.js +60 -0
  21. package/src/sources/lookmovie.js +78 -0
  22. package/src/sources/mapple.js +115 -0
  23. package/src/sources/meowtv.js +111 -0
  24. package/src/sources/nebula.js +62 -0
  25. package/src/sources/nekowatch.js +57 -0
  26. package/src/sources/opstream.js +123 -0
  27. package/src/sources/peachify.js +78 -0
  28. package/src/sources/pengu.js +45 -0
  29. package/src/sources/purstream.js +104 -0
  30. package/src/sources/vidapi.js +115 -0
  31. package/src/sources/vidcore.js +43 -0
  32. package/src/sources/videasy.js +98 -0
  33. package/src/sources/vidfast.js +53 -0
  34. package/src/sources/vidlink.js +28 -0
  35. package/src/sources/vidnest.js +77 -0
  36. package/src/sources/vidrift.js +95 -0
  37. package/src/sources/vidrock.js +145 -0
  38. package/src/sources/vidsync.js +38 -0
  39. package/src/sources/vidup.js +79 -0
  40. package/src/sources/vidzee.js +120 -0
  41. package/src/sources/vixsrc.js +98 -0
  42. package/src/sources/xpass.js +40 -0
  43. package/src/subtitles.js +127 -0
  44. package/src/utils/helpers.js +194 -0
package/src/config.js ADDED
@@ -0,0 +1,519 @@
1
+ export const SOURCES = [
2
+ {
3
+ key: '1embed',
4
+ label: '1Embed',
5
+ sourceFile: '1embed',
6
+ proxyParam: '1e',
7
+ timeout: 20000,
8
+ jitter: 500,
9
+ retries: 2,
10
+ multiUrl: true,
11
+ },
12
+
13
+ {
14
+ key: '123anime',
15
+ label: '123Anime',
16
+ sourceFile: '123anime',
17
+ proxyParam: 'a1',
18
+ timeout: 25000,
19
+ jitter: 500,
20
+ retries: 2,
21
+ multiUrl: false,
22
+ skipProxy: true,
23
+ cdnHeaders: [{
24
+ pattern: /hlsx\d+cdn\.|burntburst\d+\.store|echovideo\.ru/i,
25
+ headers: {
26
+ Referer: 'https://play2.echovideo.ru/',
27
+ Origin: 'https://play2.echovideo.ru',
28
+ },
29
+ },],
30
+ },
31
+
32
+ {
33
+ key: 'anihq-sub',
34
+ label: 'AniHQ (Sub)',
35
+ sourceFile: 'anihq',
36
+ proxyParam: 'ahsub',
37
+ timeout: 25000,
38
+ jitter: 500,
39
+ retries: 2,
40
+ multiUrl: true,
41
+ skipProxy: true
42
+ },
43
+
44
+ {
45
+ key: 'anihq-dub',
46
+ label: 'AniHQ (Dub)',
47
+ sourceFile: 'anihq',
48
+ proxyParam: 'ahdub',
49
+ timeout: 25000,
50
+ jitter: 500,
51
+ retries: 2,
52
+ multiUrl: true,
53
+ skipProxy: true
54
+ },
55
+
56
+ {
57
+ key: 'anineko-sub',
58
+ sourceFile: 'anineko',
59
+ label: 'AniNeko (Sub)',
60
+ proxyParam: 'anksub',
61
+ timeout: 25000,
62
+ jitter: 500,
63
+ retries: 2
64
+ },
65
+
66
+ {
67
+ key: 'anineko-dub',
68
+ sourceFile: 'anineko',
69
+ label: 'AniNeko (Dub)',
70
+ proxyParam: 'ankdub',
71
+ timeout: 25000,
72
+ jitter: 500,
73
+ retries: 2
74
+ },
75
+
76
+ {
77
+ key: 'anipm-sub',
78
+ sourceFile: 'anipm',
79
+ label: 'AniPM (Sub)',
80
+ proxyParam: 'apsub',
81
+ timeout: 25000,
82
+ jitter: 500,
83
+ retries: 2,
84
+ skipProxy: true,
85
+ skipVerify: true,
86
+ multiUrl: true,
87
+ verifyHeaders: {
88
+ Referer: 'https://ani.pm/',
89
+ Origin: 'https://ani.pm',
90
+ },
91
+ },
92
+
93
+ {
94
+ key: 'anipm-dub',
95
+ sourceFile: 'anipm',
96
+ label: 'AniPM (Dub)',
97
+ proxyParam: 'apdub',
98
+ timeout: 25000,
99
+ jitter: 500,
100
+ retries: 2,
101
+ skipProxy: true,
102
+ skipVerify: true,
103
+ multiUrl: true,
104
+ verifyHeaders: {
105
+ Referer: 'https://ani.pm/',
106
+ Origin: 'https://ani.pm',
107
+ },
108
+ },
109
+
110
+ {
111
+ key: 'flaxmovies',
112
+ label: 'FlaxMovies',
113
+ sourceFile: 'flaxmovies',
114
+ proxyParam: 'fx',
115
+ timeout: 20000,
116
+ jitter: 500,
117
+ retries: 2,
118
+ multiUrl: true,
119
+ disabled: true, // Temporarily disabled because their site is down, all streams are returning 403's
120
+ cdnHeaders: [{
121
+ pattern: /flix2watch\.pro/i,
122
+ headers: {
123
+ Referer: 'https://flaxmovies.xyz/',
124
+ Origin: 'https://flaxmovies.xyz',
125
+ },
126
+ },],
127
+ },
128
+
129
+ {
130
+ key: 'fsharetv',
131
+ label: 'FShareTV',
132
+ sourceFile: 'fsharetv',
133
+ proxyParam: 'fs',
134
+ timeout: 25000,
135
+ jitter: 600,
136
+ retries: 2,
137
+ multiUrl: false,
138
+ verifyHeaders: {
139
+ Accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8',
140
+ 'Accept-Language': 'en-US,en;q=0.9',
141
+ Referer: 'https://fsharetv.cc',
142
+ },
143
+ },
144
+
145
+ {
146
+ key: 'goated',
147
+ label: 'Goated',
148
+ sourceFile: 'goated',
149
+ proxyParam: 'gt',
150
+ timeout: 25000,
151
+ jitter: 500,
152
+ retries: 2,
153
+ multiUrl: true,
154
+ skipProxy: true,
155
+ },
156
+
157
+ {
158
+ key: 'fsonic',
159
+ label: 'Fsonic',
160
+ sourceFile: 'fsonic',
161
+ proxyParam: 'fn',
162
+ timeout: 35000,
163
+ jitter: 600,
164
+ retries: 1,
165
+ multiUrl: true,
166
+ },
167
+
168
+ {
169
+ key: 'fsonline',
170
+ label: 'FSOnline',
171
+ sourceFile: 'fsonline',
172
+ proxyParam: 'fo',
173
+ timeout: 20000,
174
+ retries: 1,
175
+ jitter: 0,
176
+ multiUrl: true,
177
+ skipProxy: true,
178
+ },
179
+
180
+ {
181
+ key: 'hexa',
182
+ label: 'Hexa',
183
+ sourceFile: 'hexa',
184
+ proxyParam: 'hx',
185
+ timeout: 20000,
186
+ jitter: 500,
187
+ retries: 2,
188
+ },
189
+
190
+ {
191
+ key: 'kisskh',
192
+ label: 'KissKH',
193
+ sourceFile: 'kisskh',
194
+ proxyParam: 'kk',
195
+ timeout: 30000,
196
+ jitter: 500,
197
+ retries: 1,
198
+ },
199
+
200
+ {
201
+ key: 'lookmovie',
202
+ label: 'LookMovie',
203
+ sourceFile: 'lookmovie',
204
+ proxyParam: 'lm',
205
+ timeout: 20000,
206
+ jitter: 500,
207
+ retries: 2,
208
+ multiUrl: true,
209
+ verifyHeaders: {
210
+ 'Accept-Language': 'en-US,en;q=0.9',
211
+ },
212
+ },
213
+
214
+ {
215
+ key: 'mapple',
216
+ label: 'Mapple',
217
+ sourceFile: 'mapple',
218
+ proxyParam: 'mp',
219
+ timeout: 15000,
220
+ retries: 1,
221
+ jitter: 0
222
+ },
223
+
224
+ {
225
+ key: 'meowtv',
226
+ label: 'MeowTV',
227
+ sourceFile: 'meowtv',
228
+ proxyParam: 'mt',
229
+ timeout: 20000,
230
+ jitter: 500,
231
+ retries: 2,
232
+ multiUrl: true,
233
+ skipProxy: true
234
+ },
235
+
236
+ {
237
+ key: 'nebula',
238
+ label: 'Nebula',
239
+ sourceFile: 'nebula',
240
+ proxyParam: 'nb',
241
+ timeout: 25000,
242
+ jitter: 500,
243
+ retries: 1,
244
+ multiUrl: true,
245
+ skipProxy: true,
246
+ },
247
+
248
+ {
249
+ key: 'nekowatch-sub',
250
+ sourceFile: 'nekowatch',
251
+ label: 'NekoWatch (Sub)',
252
+ proxyParam: 'nwsub',
253
+ timeout: 30000,
254
+ jitter: 500,
255
+ retries: 2
256
+ },
257
+
258
+ {
259
+ key: 'nekowatch-dub',
260
+ sourceFile: 'nekowatch',
261
+ label: 'NekoWatch (Dub)',
262
+ proxyParam: 'nwdub',
263
+ timeout: 30000,
264
+ jitter: 500,
265
+ retries: 2
266
+ },
267
+
268
+ {
269
+ key: 'opstream',
270
+ label: 'OpStream',
271
+ sourceFile: 'opstream',
272
+ proxyParam: 'op',
273
+ timeout: 35000,
274
+ jitter: 500,
275
+ retries: 2,
276
+ multiUrl: true,
277
+ skipProxy: true,
278
+ verifyHeaders: {
279
+ Referer: 'https://opstream.fun/',
280
+ Origin: 'https://opstream.fun',
281
+ },
282
+ },
283
+
284
+ {
285
+ key: 'peachify',
286
+ label: 'Peachify',
287
+ sourceFile: 'peachify',
288
+ proxyParam: 'pf',
289
+ timeout: 30000,
290
+ jitter: 500,
291
+ retries: 1,
292
+ multiUrl: true
293
+ },
294
+
295
+ {
296
+ key: 'pengu',
297
+ label: 'Pengu',
298
+ sourceFile: 'pengu',
299
+ proxyParam: 'pg',
300
+ timeout: 25000,
301
+ jitter: 500,
302
+ retries: 1,
303
+ multiUrl: true,
304
+ skipProxy: true,
305
+ disabled: true, // Temporarily disabled because they now require google auth
306
+ },
307
+
308
+ {
309
+ key: 'purstream',
310
+ sourceFile: 'purstream',
311
+ label: 'Purstream',
312
+ proxyParam: 'ps',
313
+ timeout: 20000,
314
+ jitter: 500,
315
+ retries: 2,
316
+ },
317
+
318
+ {
319
+ key: 'vidapi',
320
+ label: 'VidAPI',
321
+ sourceFile: 'vidapi',
322
+ proxyParam: 'va',
323
+ timeout: 25000,
324
+ jitter: 500,
325
+ retries: 1,
326
+ multiUrl: true
327
+ },
328
+
329
+ {
330
+ key: 'vidcore',
331
+ sourceFile: 'vidcore',
332
+ label: 'Vidcore',
333
+ proxyParam: 'vc',
334
+ timeout: 30000,
335
+ jitter: 500,
336
+ retries: 2,
337
+ sourcesTimeout: 10000,
338
+ },
339
+
340
+ {
341
+ key: 'videasy',
342
+ label: 'Videasy',
343
+ sourceFile: 'videasy',
344
+ proxyParam: 'vy',
345
+ timeout: 40000,
346
+ sourcesTimeout: 10000,
347
+ jitter: 900,
348
+ retries: 3,
349
+ multiUrl: true,
350
+ verifyHeaders: {
351
+ Accept: 'application/json, /; q=0.01',
352
+ Referer: 'https://player.videasy.net/',
353
+ Origin: 'https://player.videasy.net',
354
+ },
355
+ },
356
+
357
+ {
358
+ key: 'vidfast',
359
+ label: 'Vidfast',
360
+ sourceFile: 'vidfast',
361
+ proxyParam: 'vf',
362
+ timeout: 35000,
363
+ jitter: 500,
364
+ retries: 1,
365
+ },
366
+
367
+ {
368
+ key: 'vidlink',
369
+ label: 'Vidlink',
370
+ sourceFile: 'vidlink',
371
+ proxyParam: 'vl',
372
+ timeout: 20000,
373
+ jitter: 500,
374
+ retries: 2,
375
+ skipProxy: true,
376
+ multiUrl: true,
377
+ disabled: true, // Temporarily disabled because their site is down, all streams are returning 403's
378
+ },
379
+
380
+ {
381
+ key: 'vidnest',
382
+ label: 'VidNest',
383
+ sourceFile: 'vidnest',
384
+ proxyParam: 'vdn',
385
+ timeout: 20000,
386
+ retries: 1,
387
+ jitter: 0,
388
+ multiUrl: true,
389
+ },
390
+
391
+ {
392
+ key: 'vidnest-sub',
393
+ label: 'VidNest (Sub)',
394
+ sourceFile: 'vidnest',
395
+ proxyParam: 'vdn',
396
+ timeout: 20000,
397
+ retries: 1,
398
+ jitter: 0,
399
+ multiUrl: true,
400
+ skipProxy: true,
401
+ },
402
+
403
+ {
404
+ key: 'vidnest-dub',
405
+ label: 'VidNest (Dub)',
406
+ sourceFile: 'vidnest',
407
+ proxyParam: 'vdn',
408
+ timeout: 20000,
409
+ retries: 1,
410
+ jitter: 0,
411
+ multiUrl: true,
412
+ skipProxy: true,
413
+ },
414
+
415
+ {
416
+ key: 'vidrift',
417
+ label: 'VidRift',
418
+ sourceFile: 'vidrift',
419
+ proxyParam: 'vr',
420
+ timeout: 20000,
421
+ jitter: 500,
422
+ retries: 2,
423
+ multiUrl: true,
424
+ skipProxy: true
425
+ },
426
+
427
+ {
428
+ key: 'vidrock',
429
+ label: 'VidRock',
430
+ sourceFile: 'vidrock',
431
+ proxyParam: 'vr',
432
+ timeout: 20000,
433
+ jitter: 800,
434
+ retries: 3,
435
+ multiUrl: true,
436
+ cdnHeaders: [{
437
+ pattern: /./,
438
+ headers: {
439
+ Accept: '/',
440
+ 'Accept-Language': 'en-US,en;q=0.9',
441
+ Referer: 'https://vidrock.ru/',
442
+ Origin: 'https://vidrock.ru',
443
+ },
444
+ },],
445
+ },
446
+
447
+ {
448
+ key: 'vidsync',
449
+ label: 'VidSync',
450
+ sourceFile: 'vidsync',
451
+ proxyParam: 'vs',
452
+ timeout: 20000,
453
+ retries: 2,
454
+ multiUrl: true,
455
+ disabled: true, // Temporarily disabled due to enc dec issues
456
+ },
457
+
458
+ {
459
+ key: 'vidup',
460
+ label: 'VidUp',
461
+ sourceFile: 'vidup',
462
+ proxyParam: 'vu',
463
+ timeout: 35000,
464
+ jitter: 500,
465
+ retries: 1,
466
+ multiUrl: true
467
+ },
468
+
469
+ {
470
+ key: 'vidzee',
471
+ label: 'VidZee',
472
+ sourceFile: 'vidzee',
473
+ proxyParam: 'vz',
474
+ timeout: 20000,
475
+ sourcesTimeout: 10000,
476
+ jitter: 400,
477
+ retries: 3,
478
+ disabled: true, // Temporarily disabled because their site is down, all streams are returning 403's
479
+ verifyHeaders: {
480
+ Accept: '/',
481
+ 'Accept-Language': 'en-US,en;q=0.9',
482
+ Referer: 'https://player.vidzee.wtf',
483
+ Origin: 'https://player.vidzee.wtf',
484
+ },
485
+ },
486
+
487
+ {
488
+ key: 'vixsrc',
489
+ label: 'VixSrc',
490
+ sourceFile: 'vixsrc',
491
+ proxyParam: 'vx',
492
+ timeout: 35000,
493
+ jitter: 0,
494
+ retries: 2,
495
+ multiUrl: false,
496
+ skipProxy: true,
497
+ verifyHeaders: {
498
+ Accept: 'application/json, text/javascript, /; q=0.01',
499
+ 'Accept-Language': 'en-US,en;q=0.9',
500
+ Referer: 'https://vixsrc.to/',
501
+ Origin: 'https://vixsrc.to',
502
+ },
503
+ },
504
+
505
+ {
506
+ key: 'xpass',
507
+ sourceFile: 'xpass',
508
+ label: 'XPass',
509
+ proxyParam: 'xp',
510
+ timeout: 20000,
511
+ jitter: 500,
512
+ retries: 2,
513
+ skipProxy: true,
514
+ },
515
+ ];
516
+
517
+ export const HEALTH_PROBE_ID = '155';
518
+ export const SOURCE_MAP = Object.fromEntries(SOURCES.map(s => [s.key, s]));
519
+ export default SOURCES;
@@ -0,0 +1,8 @@
1
+ import { getDownloads, getDownloadsTv } from "./sources/trendimovies.js";
2
+
3
+ export async function fetchDownloads(id, s = null, e = null) {
4
+ const res = s != null && e != null
5
+ ? await getDownloadsTv(id, s, e)
6
+ : await getDownloads(id);
7
+ return res;
8
+ }
@@ -0,0 +1,63 @@
1
+ const BASE = "https://trendimovies.com";
2
+
3
+ const HEADERS = {
4
+ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
5
+ Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
6
+ "Accept-Language": "en-US,en;q=0.9",
7
+ "Referer": "https://trendimovies.com/",
8
+ };
9
+
10
+ async function fetchPage(path) {
11
+ const res = await fetch(`${BASE}${path}`, { headers: HEADERS });
12
+ if (!res.ok) throw new Error(`trendimovies ${res.status}`);
13
+ return res.text();
14
+ }
15
+
16
+ function parseLinks(html) {
17
+ const m = html.match(/DownloadSection[^>]*props="([^"]+)"/s) ||
18
+ html.match(/props="([^"]+)"[^>]*ssr[^>]*client="load"[^>]*opts="[^"]*DownloadSection/s);
19
+ if (!m) {
20
+ const alt = html.match(/"DownloadSection"/);
21
+ if (!alt) return [];
22
+ const propsMatch = html.match(/props="({[^"]*DownloadSection[^"]*})"/s);
23
+ if (!propsMatch) return [];
24
+ return extractLinks(propsMatch[1].replace(/"/g, '"').replace(/'/g, "'"));
25
+ }
26
+ return extractLinks(m[1].replace(/"/g, '"').replace(/'/g, "'"));
27
+ }
28
+
29
+ function extractLinks(propsJson) {
30
+ try {
31
+ const parsed = JSON.parse(propsJson);
32
+ const rawLinks = parsed?.links?.[1];
33
+ if (!Array.isArray(rawLinks)) return [];
34
+ return rawLinks
35
+ .map(item => item?.[1])
36
+ .filter(l => l && typeof l === "object")
37
+ .map(l => ({
38
+ url: unwrap(l.url),
39
+ quality: unwrap(l.quality) || "HD",
40
+ size: unwrap(l.file_size) || null,
41
+ type: "mkv",
42
+ active: unwrap(l.is_active) !== false,
43
+ }))
44
+ .filter(l => l.url && l.active);
45
+ } catch {
46
+ return [];
47
+ }
48
+ }
49
+
50
+ function unwrap(v) {
51
+ if (Array.isArray(v) && v.length === 2 && (v[0] === 0 || v[0] === 1)) return v[1];
52
+ return v;
53
+ }
54
+
55
+ export async function getDownloads(tmdbId) {
56
+ const html = await fetchPage(`/movie/${tmdbId}`);
57
+ return parseLinks(html);
58
+ }
59
+
60
+ export async function getDownloadsTv(tmdbId, season, episode) {
61
+ const html = await fetchPage(`/tv/${tmdbId}/season/${season}/episode/${episode}`);
62
+ return parseLinks(html);
63
+ }
package/src/health.js ADDED
@@ -0,0 +1,38 @@
1
+ import { HEALTH_PROBE_ID } from "./config.js";
2
+
3
+ const withTimeout = (promise, ms) => Promise.race([promise, new Promise(r => setTimeout(() => r(null), ms))]);
4
+ async function withRetry(fn, attempts = 2, delay = 300) {
5
+ for (let i = 0; i < attempts; i++) {
6
+ try {
7
+ const result = await fn();
8
+ if (result != null) return result;
9
+ } catch (err) {
10
+ if (i === attempts - 1) throw err;
11
+ await new Promise(r => setTimeout(r, delay + Math.random() * delay * 0.5));
12
+ }
13
+ }
14
+ return null;
15
+ }
16
+
17
+ export async function probeSource(tmdbApiKey, cfg, mod) {
18
+ const audio = /dub$/.test(cfg.key) ? 'dub' : 'sub';
19
+ const streamArgs = {
20
+ id: HEALTH_PROBE_ID,
21
+ s: null,
22
+ e: null,
23
+ clientIP: null,
24
+ absoluteBase: null,
25
+ audio,
26
+ tmdbApiKey,
27
+ config: cfg,
28
+ };
29
+
30
+ const t = Date.now();
31
+ const result = await withTimeout(
32
+ withRetry(() => mod.getStream(streamArgs), cfg.retries, 300),
33
+ cfg.timeout
34
+ );
35
+
36
+ const firstUrl = result?.url ?? result?.allUrls?.[0]?.url;
37
+ return { ok: !!(typeof firstUrl === 'string' && firstUrl.startsWith('http')), ms: Date.now() - t };
38
+ }
package/src/sdk.js ADDED
@@ -0,0 +1,65 @@
1
+ import SOURCES, { SOURCE_MAP } from "./config.js";
2
+ import { fetchDownloads } from "./downloads/downloads.js";
3
+ import { probeSource } from "./health.js";
4
+ import { fetchSubtitles, getSubPathsMovie, getSubPathsTv } from "./subtitles.js";
5
+ import { createStreamArgs } from "./utils/helpers.js";
6
+
7
+ const ALL_SOURCE_MODULES = Object.fromEntries(
8
+ await Promise.all(SOURCES.map(async cfg => [cfg.key, await import(`./sources/${cfg.sourceFile}.js`)]))
9
+ );
10
+
11
+ const SOURCE_MODULES = Object.fromEntries(
12
+ Object.entries(ALL_SOURCE_MODULES).filter(([key]) => !SOURCE_MAP[key]?.disabled)
13
+ );
14
+
15
+ export default class VylaSDK {
16
+ constructor({ tmdbApiKey } = {}) {
17
+ this.tmdbApiKey = tmdbApiKey;
18
+ }
19
+ getSources(excludeDisabled = false) {
20
+ if (excludeDisabled) {
21
+ return SOURCES.filter(cfg => !cfg.disabled);
22
+ }
23
+ return SOURCES;
24
+ }
25
+ async probeAllSources() {
26
+ const active = SOURCES.filter(cfg => !cfg.disabled);
27
+
28
+ const results = await Promise.allSettled(
29
+ active.map(async cfg => await probeSource(cfg, SOURCE_MODULES[cfg.key]))
30
+ );
31
+
32
+ const sources = Object.fromEntries(
33
+ active.map((cfg, i) => [
34
+ cfg.key,
35
+ results[i].status === 'fulfilled' ? results[i].value : { ok: false, ms: null },
36
+ ])
37
+ );
38
+
39
+ return sources;
40
+ }
41
+ async probeSource(key) {
42
+ const cfg = SOURCES.find(cfg => cfg.key === key);
43
+ if (!cfg) throw new Error(`Source with key "${key}" not found`);
44
+ const mod = SOURCE_MODULES[key];
45
+ if (!mod) throw new Error(`Source module for key "${key}" not found`);
46
+ return await probeSource(this.tmdbApiKey, cfg, mod);
47
+ }
48
+ async getStream(key, id, s = null, e = null, clientIP = null) {
49
+ const cfg = SOURCES.find(cfg => cfg.key === key);
50
+ if (!cfg) throw new Error(`Source with key "${key}" not found`);
51
+ const mod = SOURCE_MODULES[key];
52
+ if (!mod) throw new Error(`Source module for key "${key}" not found`);
53
+ const streamArgs = await createStreamArgs(cfg, this.tmdbApiKey, id, s, e, clientIP);
54
+ return await mod.getStream(streamArgs);
55
+ }
56
+ async getSubtitles(id, s = null, e = null) {
57
+ const paths = s != null && e != null
58
+ ? await getSubPathsTv(id, s, e)
59
+ : await getSubPathsMovie(id);
60
+ return await fetchSubtitles(paths);
61
+ }
62
+ async getDownloads(id, s = null, e = null) {
63
+ return await fetchDownloads(id, s, e);
64
+ }
65
+ }