@vyla-entertainment/sdk 1.20.0 → 1.21.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 (52) hide show
  1. package/package.json +3 -2
  2. package/src/config.js +10 -85
  3. package/src/sdk.d.ts +94 -121
  4. package/src/sdk.js +82 -78
  5. package/src/sources/111477.js +88 -100
  6. package/src/sources/123anime.js +120 -56
  7. package/src/sources/3eyedraven.js +82 -135
  8. package/src/sources/cinecat.js +37 -18
  9. package/src/sources/cinemaarmy.js +179 -180
  10. package/src/sources/cinesrc.js +401 -397
  11. package/src/sources/cno.js +101 -94
  12. package/src/sources/dulo.js +134 -149
  13. package/src/sources/flaxmovies.js +114 -105
  14. package/src/sources/frost.js +38 -29
  15. package/src/sources/fsonline.js +95 -47
  16. package/src/sources/hdhub.js +43 -36
  17. package/src/sources/hexa.js +60 -53
  18. package/src/sources/hyper.js +42 -35
  19. package/src/sources/kickassanime.js +117 -124
  20. package/src/sources/kisskh.js +114 -59
  21. package/src/sources/lmscript.js +72 -70
  22. package/src/sources/lookmovie.js +80 -79
  23. package/src/sources/movenerds.js +74 -124
  24. package/src/sources/movy.js +197 -209
  25. package/src/sources/net79.js +59 -55
  26. package/src/sources/peestream.js +126 -138
  27. package/src/sources/pengu.js +46 -49
  28. package/src/sources/pstream.js +73 -67
  29. package/src/sources/purstream.js +96 -104
  30. package/src/sources/rivestream.js +182 -176
  31. package/src/sources/rivo.js +58 -53
  32. package/src/sources/streamaggregator.js +114 -128
  33. package/src/sources/thugtv.js +70 -62
  34. package/src/sources/vidapi.js +122 -114
  35. package/src/sources/vidcore.js +14 -122
  36. package/src/sources/vidfast.js +14 -122
  37. package/src/sources/vidlink.js +78 -27
  38. package/src/sources/vidup.js +14 -122
  39. package/src/sources/vidvault.js +133 -187
  40. package/src/sources/vidy.js +192 -187
  41. package/src/sources/vidzee.js +189 -183
  42. package/src/sources/vixsrc.js +123 -113
  43. package/src/sources/watchout.js +60 -46
  44. package/src/sources/xdownloader.js +127 -128
  45. package/src/sources/yapgrid.js +68 -62
  46. package/src/sources/yastream.js +35 -29
  47. package/src/subtitles.js +105 -122
  48. package/src/utils/helpers.js +586 -247
  49. package/src/sources/bcine.js +0 -202
  50. package/src/sources/cinezo.js +0 -55
  51. package/src/sources/vidora.js +0 -62
  52. package/src/sources/vidrock.js +0 -145
@@ -1,104 +1,96 @@
1
- import { fetchJson, USER_AGENT, getTmdbInfo } from '../utils/helpers.js';
2
-
3
- const DOMAIN = 'https://purstream.ad';
4
- const API_BASE = 'https://api.purstream.ad/api/v1';
5
-
6
- const HEADERS = {
7
- 'User-Agent': USER_AGENT,
8
- 'Accept': 'application/json, text/plain, */*',
9
- 'Referer': `${DOMAIN}/`,
10
- 'Origin': DOMAIN,
11
- 'X-Requested-With': 'XMLHttpRequest',
12
- 'Sec-Fetch-Dest': 'empty',
13
- 'Sec-Fetch-Mode': 'cors',
14
- 'Sec-Fetch-Site': 'same-site'
15
- };
16
-
17
- export async function getStream({ id, s, e }) {
18
- try {
19
- const isTv = s != null;
20
-
21
- const info = await getTmdbInfo(id, isTv ? 'tv' : 'movie');
22
-
23
-
24
- if (!info?.titles?.length) {
25
- return null;
26
- }
27
-
28
- const title = info.titles[0];
29
-
30
- const searchUrl = `${API_BASE}/search-bar/search/${encodeURIComponent(title)}`;
31
-
32
- const searchData = await fetchJson(searchUrl, {
33
- headers: HEADERS,
34
- signal: AbortSignal.timeout(10000)
35
- });
36
-
37
- const items = searchData?.data?.items?.movies?.items || [];
38
-
39
- const type = isTv ? 'tv' : 'movie';
40
- const lowerTitle = title.toLowerCase();
41
-
42
- let match = items.find(item =>
43
- item.type === type &&
44
- item.title?.toLowerCase() === lowerTitle &&
45
- (!info.year || item.release_date?.startsWith(String(info.year)))
46
- );
47
-
48
- if (!match) {
49
- match = items.find(item => item.type === type);
50
- }
51
-
52
- if (!match?.id) {
53
- return null;
54
- }
55
-
56
- const streamUrl = isTv
57
- ? `${API_BASE}/stream/${match.id}/episode?season=${s}&episode=${e}`
58
- : `${API_BASE}/stream/${match.id}`;
59
-
60
- const json = await fetchJson(streamUrl, {
61
- headers: HEADERS,
62
- signal: AbortSignal.timeout(10000)
63
- });
64
-
65
- const sources = json?.data?.items?.sources;
66
-
67
- if (json?.type !== 'success' || !Array.isArray(sources) || !sources.length) {
68
- return null;
69
- }
70
-
71
- const chosen = sources.find(src => src.stream_url);
72
-
73
- if (!chosen?.stream_url) {
74
- return null;
75
- }
76
-
77
- const result = {
78
- url: chosen.stream_url,
79
- headers: {
80
- 'User-Agent': USER_AGENT,
81
- 'Referer': `${DOMAIN}/`
82
- },
83
- server: 'purstream',
84
- quality: chosen.source_name || 'Auto',
85
- type: chosen.format || 'hls',
86
- skipProxy: true
87
- };
88
-
89
- return result;
90
-
91
- } catch (err) {
92
- return null;
93
- }
94
- }
95
-
96
- export async function getSources(args) {
97
- const stream = await getStream(args);
98
-
99
- return stream ? [stream] : [];
100
- }
101
-
102
- export const VERIFY_HEADERS = {
103
- ...HEADERS
104
- };
1
+ import { fetchJson, getTmdbMetadata, resolveTmdbKey, USER_AGENT } from '../utils/helpers.js';
2
+
3
+ const DOMAIN = 'https://purstream.ad';
4
+ const API_BASE = 'https://api.purstream.ad/api/v1';
5
+
6
+ const HEADERS = {
7
+ 'User-Agent': USER_AGENT,
8
+ Accept: 'application/json, text/plain, */*',
9
+ Referer: `${DOMAIN}/`,
10
+ Origin: DOMAIN,
11
+ 'X-Requested-With': 'XMLHttpRequest',
12
+ 'Sec-Fetch-Dest': 'empty',
13
+ 'Sec-Fetch-Mode': 'cors',
14
+ 'Sec-Fetch-Site': 'same-site',
15
+ };
16
+
17
+ export async function getStream(args) {
18
+ const { id, s, e, sdk } = args || {};
19
+ const isTv = s != null && e != null;
20
+ const type = isTv ? 'tv' : 'movie';
21
+ const apiKey = resolveTmdbKey(args, sdk);
22
+
23
+ try {
24
+ const meta = await getTmdbMetadata(id, isTv, apiKey);
25
+ if (!meta?.titles?.length) return null;
26
+
27
+ const title = meta.titles[0];
28
+ const searchUrl = `${API_BASE}/search-bar/search/${encodeURIComponent(title)}`;
29
+
30
+ const searchData = await fetchJson(searchUrl, {
31
+ headers: HEADERS,
32
+ signal: AbortSignal.timeout(10000),
33
+ });
34
+
35
+ const items = searchData?.data?.items?.movies?.items || [];
36
+ const lowerTitle = title.toLowerCase();
37
+
38
+ let match = items.find(item =>
39
+ item.type === type &&
40
+ item.title?.toLowerCase() === lowerTitle &&
41
+ (!meta.year || item.release_date?.startsWith(String(meta.year)))
42
+ );
43
+
44
+ if (!match) {
45
+ match = items.find(item => item.type === type);
46
+ }
47
+
48
+ if (!match?.id) return null;
49
+
50
+ const streamUrl = isTv
51
+ ? `${API_BASE}/stream/${match.id}/episode?season=${s}&episode=${e}`
52
+ : `${API_BASE}/stream/${match.id}`;
53
+
54
+ const json = await fetchJson(streamUrl, {
55
+ headers: HEADERS,
56
+ signal: AbortSignal.timeout(10000),
57
+ });
58
+
59
+ const sources = json?.data?.items?.sources;
60
+ if (json?.type !== 'success' || !Array.isArray(sources) || !sources.length) return null;
61
+
62
+ const chosen = sources.find(src => src.stream_url);
63
+ if (!chosen?.stream_url) return null;
64
+
65
+ const streamHeaders = {
66
+ 'User-Agent': USER_AGENT,
67
+ Referer: `${DOMAIN}/`,
68
+ };
69
+
70
+ const allUrls = [{
71
+ url: chosen.stream_url,
72
+ headers: streamHeaders,
73
+ server: 'purstream',
74
+ quality: chosen.source_name || 'Auto',
75
+ type: chosen.format || 'hls',
76
+ skipProxy: true,
77
+ }];
78
+
79
+ return {
80
+ url: chosen.stream_url,
81
+ headers: streamHeaders,
82
+ server: 'purstream',
83
+ quality: chosen.source_name || 'Auto',
84
+ type: chosen.format || 'hls',
85
+ skipProxy: true,
86
+ allUrls,
87
+ };
88
+ } catch {
89
+ return null;
90
+ }
91
+ }
92
+
93
+ export async function getSources(args) {
94
+ const stream = await getStream(args);
95
+ return stream?.allUrls ? stream.allUrls.map(u => u.server) : ['purstream'];
96
+ }
@@ -1,177 +1,183 @@
1
- import { USER_AGENT, fetchJson } from '../utils/helpers.js';
2
-
3
- const C_ARRAY = [
4
- '4Z7lUo', 'gwIVSMD', 'PLmz2elE2v', 'Z4OFV0', 'SZ6RZq6Zc', 'zhJEFYxrz8', 'FOm7b0', 'axHS3q4KDq', 'o9zuXQ', '4Aebt',
5
- 'wgjjWwKKx', 'rY4VIxqSN', 'kfjbnSo', '2DyrFA1M', 'YUixDM9B', 'JQvgEj0', 'mcuFx6JIek', 'eoTKe26gL', 'qaI9EVO1rB', '0xl33btZL',
6
- '1fszuAU', 'a7jnHzst6P', 'wQuJkX', 'cBNhTJlEOf', 'KNcFWhDvgT', 'XipDGjST', 'PCZJlbHoyt', '2AYnMZkqd', 'HIpJh', 'KH0C3iztrG',
7
- 'W81hjts92', 'rJhAT', 'NON7LKoMQ', 'NMdY3nsKzI', 't4En5v', 'Qq5cOQ9H', 'Y9nwrp', 'VX5FYVfsf', 'cE5SJG', 'x1vj1',
8
- 'HegbLe', 'zJ3nmt4OA', 'gt7rxW57dq', 'clIE9b', 'jyJ9g', 'B5jXjMCSx', 'cOzZBZTV', 'FTXGy', 'Dfh1q1', 'ny9jqZ2POI',
9
- 'X2NnMn', 'MBtoyD', 'qz4Ilys7wB', '68lbOMye', '3YUJnmxp', '1fv5Imona', 'PlfvvXD7mA', 'ZarKfHCaPR', 'owORnX', 'dQP1YU',
10
- 'dVdkx', 'qgiK0E', 'cx9wQ', '5F9bGa', '7UjkKrp', 'Yvhrj', 'wYXez5Dg3', 'pG4GMU', 'MwMAu', 'rFRD5wlM'
11
- ];
12
-
13
- const DEFAULT_SERVICES = [
14
- 'apex', 'pulse', 'solstice', 'quasar', 'horizon', 'primevids',
15
- 'flowcast', 'asiacloud', 'citadel', 'hindicast', 'guru'
16
- ];
17
-
18
- function generateRiveSecretKey(e) {
19
- if (e === undefined || e === null) return 'rive';
20
- try {
21
- let t, n;
22
- const r = String(e);
23
- if (isNaN(Number(e))) {
24
- const sum = r.split('').reduce((acc, ch) => acc + ch.charCodeAt(0), 0);
25
- t = C_ARRAY[sum % C_ARRAY.length] || Buffer.from(r).toString('base64');
26
- n = Math.floor((sum % r.length) / 2);
27
- } else {
28
- const i = Number(e);
29
- t = C_ARRAY[i % C_ARRAY.length] || Buffer.from(r).toString('base64');
30
- n = Math.floor((i % r.length) / 2);
31
- }
32
- const i = r.slice(0, n) + t + r.slice(n);
33
- const o = (function (str) {
34
- const t = String(str);
35
- let n = 3735928559 ^ t.length;
36
- for (let e = 0; e < t.length; e++) {
37
- const r = t.charCodeAt(e);
38
- const rXor = (131 * e + 89 ^ (r << (e % 5))) & 255;
39
- const r2 = r ^ rXor;
40
- n = (((n << 7) | (n >>> 25)) >>> 0) ^ r2;
41
- const idx = (65535 & n) * 60205;
42
- const o2 = ((n >>> 16) * 60205) << 16;
43
- n = (idx + o2) >>> 0;
44
- n ^= n >>> 11;
45
- }
46
- n ^= n >>> 15;
47
- n = ((65535 & n) * 49842 + (((n >>> 16) * 49842) << 16)) >>> 0;
48
- n ^= n >>> 13;
49
- n = ((65535 & n) * 40503 + (((n >>> 16) * 40503) << 16)) >>> 0;
50
- n ^= n >>> 16;
51
- n = ((65535 & n) * 10196 + (((n >>> 16) * 10196) << 16)) >>> 0;
52
- return ((n ^= n >>> 15)).toString(16).padStart(8, '0');
53
- })(
54
- (function (str) {
55
- const s = String(str);
56
- let t = 0;
57
- for (let n = 0; n < s.length; n++) {
58
- const r = s.charCodeAt(n);
59
- const i = (((t = (r + (t << 6) + (t << 16) - t) >>> 0) << (n % 5)) | (t >>> (32 - (n % 5)))) >>> 0;
60
- t ^= (i ^ ((r << (n % 7)) | (r >>> (8 - (n % 7))))) >>> 0;
61
- t = (t + ((t >>> 11) ^ (t << 3))) >>> 0;
62
- }
63
- t ^= t >>> 15;
64
- t = ((65535 & t) * 49842 + ((((t >>> 16) * 49842) & 65535) << 16)) >>> 0;
65
- t ^= t >>> 13;
66
- t = ((65535 & t) * 40503 + ((((t >>> 16) * 40503) & 65535) << 16)) >>> 0;
67
- return ((t ^= t >>> 16)).toString(16).padStart(8, '0');
68
- })(i)
69
- );
70
- return Buffer.from(o, 'utf-8').toString('base64');
71
- } catch {
72
- return 'topSecret';
73
- }
74
- }
75
-
76
- async function fetchRiveServices() {
77
- try {
78
- const secretKey = generateRiveSecretKey();
79
- const url = `https://www.rivestream.app/api/backendfetch?requestID=VideoProviderServices&secretKey=${encodeURIComponent(secretKey)}`;
80
- const res = await fetchJson(url, {
81
- headers: {
82
- 'User-Agent': USER_AGENT,
83
- 'Referer': 'https://www.rivestream.app/',
84
- 'Accept': 'application/json, text/plain, */*'
85
- },
86
- signal: AbortSignal.timeout(6000)
87
- });
88
- return Array.isArray(res?.data) && res.data.length ? res.data : DEFAULT_SERVICES;
89
- } catch {
90
- return DEFAULT_SERVICES;
91
- }
92
- }
93
-
94
- async function fetchServiceStreams(service, isMovie, id, s, e, secretKey, referer) {
95
- try {
96
- const cb = (service === 'primevids' || service === 'citadel')
97
- ? `&cb=${Math.floor(Date.now() / 3e6)}`
98
- : '';
99
-
100
- const reqID = isMovie ? 'movieVideoProvider' : 'tvVideoProvider';
101
- const params = isMovie
102
- ? `requestID=${reqID}&id=${encodeURIComponent(id)}&service=${service}${cb}&secretKey=${encodeURIComponent(secretKey)}`
103
- : `requestID=${reqID}&id=${encodeURIComponent(id)}&season=${encodeURIComponent(s)}&episode=${encodeURIComponent(e)}&service=${service}${cb}&secretKey=${encodeURIComponent(secretKey)}`;
104
-
105
- const url = `https://www.rivestream.app/api/backendfetch?${params}`;
106
- const res = await fetchJson(url, {
107
- headers: {
108
- 'User-Agent': USER_AGENT,
109
- 'Referer': referer,
110
- 'Accept': 'application/json, text/plain, */*'
111
- },
112
- signal: AbortSignal.timeout(10000)
113
- });
114
-
115
- if (!res?.data?.sources || !Array.isArray(res.data.sources)) return [];
116
-
117
- const streams = [];
118
- for (const item of res.data.sources) {
119
- if (!item || !item.url) continue;
120
-
121
- const format = String(item.format || '').toLowerCase();
122
- const urlStr = String(item.url || '').toLowerCase();
123
- const isM3U8 = format === 'hls' || format === 'm3u8' || urlStr.includes('.m3u8') || urlStr.includes('.txt');
124
-
125
- streams.push({
126
- url: item.url,
127
- server: `Rive (${item.source || service})`,
128
- quality: String(item.quality || 'Auto'),
129
- type: isM3U8 ? 'hls' : 'mp4',
130
- headers: {
131
- 'User-Agent': USER_AGENT,
132
- 'Referer': referer
133
- }
134
- });
135
- }
136
- return streams;
137
- } catch {
138
- return [];
139
- }
140
- }
141
-
142
- export async function getStream(args) {
143
- const { id, s, e, server } = args;
144
- const isTv = s != null && e != null;
145
- const isMovie = !isTv;
146
-
147
- const secretKey = generateRiveSecretKey(id);
148
- const referer = isMovie
149
- ? `https://www.rivestream.app/watch?type=movie&id=${id}`
150
- : `https://www.rivestream.app/watch?type=tv&id=${id}&season=${s}&episode=${e}`;
151
-
152
- let services = await fetchRiveServices();
153
-
154
- if (server && server !== 'all') {
155
- const clean = server.toLowerCase().replace('rive (', '').replace(')', '').replace('rive', '').trim();
156
- services = services.filter(srv => srv.toLowerCase().includes(clean));
157
- if (!services.length) services = await fetchRiveServices();
158
- }
159
-
160
- const settled = await Promise.allSettled(
161
- services.map(srv => fetchServiceStreams(srv, isMovie, id, s, e, secretKey, referer))
162
- );
163
-
164
- const allUrls = [];
165
- for (const r of settled) {
166
- if (r.status === 'fulfilled' && Array.isArray(r.value)) {
167
- allUrls.push(...r.value);
168
- }
169
- }
170
-
171
- return allUrls.length ? { allUrls } : null;
172
- }
173
-
174
- export async function getSources() {
175
- const services = await fetchRiveServices();
176
- return services.map(s => `Rive (${s})`);
1
+ import { fetchJson, USER_AGENT } from '../utils/helpers.js';
2
+
3
+ const C_ARRAY = [
4
+ '4Z7lUo', 'gwIVSMD', 'PLmz2elE2v', 'Z4OFV0', 'SZ6RZq6Zc', 'zhJEFYxrz8', 'FOm7b0', 'axHS3q4KDq', 'o9zuXQ', '4Aebt',
5
+ 'wgjjWwKKx', 'rY4VIxqSN', 'kfjbnSo', '2DyrFA1M', 'YUixDM9B', 'JQvgEj0', 'mcuFx6JIek', 'eoTKe26gL', 'qaI9EVO1rB', '0xl33btZL',
6
+ '1fszuAU', 'a7jnHzst6P', 'wQuJkX', 'cBNhTJlEOf', 'KNcFWhDvgT', 'XipDGjST', 'PCZJlbHoyt', '2AYnMZkqd', 'HIpJh', 'KH0C3iztrG',
7
+ 'W81hjts92', 'rJhAT', 'NON7LKoMQ', 'NMdY3nsKzI', 't4En5v', 'Qq5cOQ9H', 'Y9nwrp', 'VX5FYVfsf', 'cE5SJG', 'x1vj1',
8
+ 'HegbLe', 'zJ3nmt4OA', 'gt7rxW57dq', 'clIE9b', 'jyJ9g', 'B5jXjMCSx', 'cOzZBZTV', 'FTXGy', 'Dfh1q1', 'ny9jqZ2POI',
9
+ 'X2NnMn', 'MBtoyD', 'qz4Ilys7wB', '68lbOMye', '3YUJnmxp', '1fv5Imona', 'PlfvvXD7mA', 'ZarKfHCaPR', 'owORnX', 'dQP1YU',
10
+ 'dVdkx', 'qgiK0E', 'cx9wQ', '5F9bGa', '7UjkKrp', 'Yvhrj', 'wYXez5Dg3', 'pG4GMU', 'MwMAu', 'rFRD5wlM',
11
+ ];
12
+
13
+ const DEFAULT_SERVICES = [
14
+ 'apex', 'pulse', 'solstice', 'quasar', 'horizon', 'primevids',
15
+ 'flowcast', 'asiacloud', 'citadel', 'hindicast', 'guru',
16
+ ];
17
+
18
+ function generateRiveSecretKey(e) {
19
+ if (e === undefined || e === null) return 'rive';
20
+ try {
21
+ let t, n;
22
+ const r = String(e);
23
+ if (isNaN(Number(e))) {
24
+ const sum = r.split('').reduce((acc, ch) => acc + ch.charCodeAt(0), 0);
25
+ t = C_ARRAY[sum % C_ARRAY.length] || Buffer.from(r).toString('base64');
26
+ n = Math.floor((sum % r.length) / 2);
27
+ } else {
28
+ const i = Number(e);
29
+ t = C_ARRAY[i % C_ARRAY.length] || Buffer.from(r).toString('base64');
30
+ n = Math.floor((i % r.length) / 2);
31
+ }
32
+ const i = r.slice(0, n) + t + r.slice(n);
33
+ const o = (function (str) {
34
+ const t = String(str);
35
+ let n = 3735928559 ^ t.length;
36
+ for (let e = 0; e < t.length; e++) {
37
+ const r = t.charCodeAt(e);
38
+ const rXor = (131 * e + 89 ^ (r << (e % 5))) & 255;
39
+ const r2 = r ^ rXor;
40
+ n = (((n << 7) | (n >>> 25)) >>> 0) ^ r2;
41
+ const idx = (65535 & n) * 60205;
42
+ const o2 = ((n >>> 16) * 60205) << 16;
43
+ n = (idx + o2) >>> 0;
44
+ n ^= n >>> 11;
45
+ }
46
+ n ^= n >>> 15;
47
+ n = ((65535 & n) * 49842 + (((n >>> 16) * 49842) << 16)) >>> 0;
48
+ n ^= n >>> 13;
49
+ n = ((65535 & n) * 40503 + (((n >>> 16) * 40503) << 16)) >>> 0;
50
+ n ^= n >>> 16;
51
+ n = ((65535 & n) * 10196 + (((n >>> 16) * 10196) << 16)) >>> 0;
52
+ return ((n ^= n >>> 15)).toString(16).padStart(8, '0');
53
+ })(
54
+ (function (str) {
55
+ const s = String(str);
56
+ let t = 0;
57
+ for (let n = 0; n < s.length; n++) {
58
+ const r = s.charCodeAt(n);
59
+ const i = (((t = (r + (t << 6) + (t << 16) - t) >>> 0) << (n % 5)) | (t >>> (32 - (n % 5)))) >>> 0;
60
+ t ^= (i ^ ((r << (n % 7)) | (r >>> (8 - (n % 7))))) >>> 0;
61
+ t = (t + ((t >>> 11) ^ (t << 3))) >>> 0;
62
+ }
63
+ t ^= t >>> 15;
64
+ t = ((65535 & t) * 49842 + ((((t >>> 16) * 49842) & 65535) << 16)) >>> 0;
65
+ t ^= t >>> 13;
66
+ t = ((65535 & t) * 40503 + ((((t >>> 16) * 40503) & 65535) << 16)) >>> 0;
67
+ return ((t ^= t >>> 16)).toString(16).padStart(8, '0');
68
+ })(i)
69
+ );
70
+ return Buffer.from(o, 'utf-8').toString('base64');
71
+ } catch {
72
+ return 'topSecret';
73
+ }
74
+ }
75
+
76
+ async function fetchRiveServices() {
77
+ try {
78
+ const secretKey = generateRiveSecretKey();
79
+ const url = `https://www.rivestream.app/api/backendfetch?requestID=VideoProviderServices&secretKey=${encodeURIComponent(secretKey)}`;
80
+ const res = await fetchJson(url, {
81
+ headers: {
82
+ 'User-Agent': USER_AGENT,
83
+ Referer: 'https://www.rivestream.app/',
84
+ Accept: 'application/json, text/plain, */*',
85
+ },
86
+ signal: AbortSignal.timeout(6000),
87
+ });
88
+ return Array.isArray(res?.data) && res.data.length ? res.data : DEFAULT_SERVICES;
89
+ } catch {
90
+ return DEFAULT_SERVICES;
91
+ }
92
+ }
93
+
94
+ async function fetchServiceStreams(service, isMovie, id, s, e, secretKey, referer) {
95
+ try {
96
+ const cb = (service === 'primevids' || service === 'citadel')
97
+ ? `&cb=${Math.floor(Date.now() / 3e6)}`
98
+ : '';
99
+
100
+ const reqID = isMovie ? 'movieVideoProvider' : 'tvVideoProvider';
101
+ const params = isMovie
102
+ ? `requestID=${reqID}&id=${encodeURIComponent(id)}&service=${service}${cb}&secretKey=${encodeURIComponent(secretKey)}`
103
+ : `requestID=${reqID}&id=${encodeURIComponent(id)}&season=${encodeURIComponent(s)}&episode=${encodeURIComponent(e)}&service=${service}${cb}&secretKey=${encodeURIComponent(secretKey)}`;
104
+
105
+ const url = `https://www.rivestream.app/api/backendfetch?${params}`;
106
+ const res = await fetchJson(url, {
107
+ headers: {
108
+ 'User-Agent': USER_AGENT,
109
+ Referer: referer,
110
+ Accept: 'application/json, text/plain, */*',
111
+ },
112
+ signal: AbortSignal.timeout(10000),
113
+ });
114
+
115
+ if (!res?.data?.sources || !Array.isArray(res.data.sources)) return [];
116
+
117
+ const streams = [];
118
+ for (const item of res.data.sources) {
119
+ if (!item || !item.url) continue;
120
+
121
+ const format = String(item.format || '').toLowerCase();
122
+ const urlStr = String(item.url || '').toLowerCase();
123
+ const isM3U8 = format === 'hls' || format === 'm3u8' || urlStr.includes('.m3u8') || urlStr.includes('.txt');
124
+
125
+ streams.push({
126
+ url: item.url,
127
+ server: `Rive (${item.source || service})`,
128
+ quality: String(item.quality || 'Auto'),
129
+ type: isM3U8 ? 'hls' : 'mp4',
130
+ headers: {
131
+ 'User-Agent': USER_AGENT,
132
+ Referer: referer,
133
+ },
134
+ });
135
+ }
136
+ return streams;
137
+ } catch {
138
+ return [];
139
+ }
140
+ }
141
+
142
+ export async function getStream(args) {
143
+ const { id, s, e, server } = args || {};
144
+ const isTv = s != null && e != null;
145
+ const isMovie = !isTv;
146
+
147
+ const secretKey = generateRiveSecretKey(id);
148
+ const referer = isMovie
149
+ ? `https://www.rivestream.app/watch?type=movie&id=${id}`
150
+ : `https://www.rivestream.app/watch?type=tv&id=${id}&season=${s}&episode=${e}`;
151
+
152
+ let services = await fetchRiveServices();
153
+
154
+ if (server && server !== 'all') {
155
+ const clean = server.toLowerCase().replace('rive (', '').replace(')', '').replace('rive', '').trim();
156
+ services = services.filter(srv => srv.toLowerCase().includes(clean));
157
+ if (!services.length) services = await fetchRiveServices();
158
+ }
159
+
160
+ const settled = await Promise.allSettled(
161
+ services.map(srv => fetchServiceStreams(srv, isMovie, id, s, e, secretKey, referer))
162
+ );
163
+
164
+ const allUrls = [];
165
+ for (const r of settled) {
166
+ if (r.status === 'fulfilled' && Array.isArray(r.value)) {
167
+ allUrls.push(...r.value);
168
+ }
169
+ }
170
+
171
+ if (!allUrls.length) return null;
172
+
173
+ return {
174
+ url: allUrls[0].url,
175
+ headers: allUrls[0].headers,
176
+ allUrls,
177
+ };
178
+ }
179
+
180
+ export async function getSources() {
181
+ const services = await fetchRiveServices();
182
+ return services.map(s => `Rive (${s})`);
177
183
  }