@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.
- package/package.json +3 -2
- package/src/config.js +10 -85
- package/src/sdk.d.ts +94 -121
- package/src/sdk.js +82 -78
- package/src/sources/111477.js +88 -100
- package/src/sources/123anime.js +120 -56
- package/src/sources/3eyedraven.js +82 -135
- package/src/sources/cinecat.js +37 -18
- package/src/sources/cinemaarmy.js +179 -180
- package/src/sources/cinesrc.js +401 -397
- package/src/sources/cno.js +101 -94
- package/src/sources/dulo.js +134 -149
- package/src/sources/flaxmovies.js +114 -105
- package/src/sources/frost.js +38 -29
- package/src/sources/fsonline.js +95 -47
- package/src/sources/hdhub.js +43 -36
- package/src/sources/hexa.js +60 -53
- package/src/sources/hyper.js +42 -35
- package/src/sources/kickassanime.js +117 -124
- package/src/sources/kisskh.js +114 -59
- package/src/sources/lmscript.js +72 -70
- package/src/sources/lookmovie.js +80 -79
- package/src/sources/movenerds.js +74 -124
- package/src/sources/movy.js +197 -209
- package/src/sources/net79.js +59 -55
- package/src/sources/peestream.js +126 -138
- package/src/sources/pengu.js +46 -49
- package/src/sources/pstream.js +73 -67
- package/src/sources/purstream.js +96 -104
- package/src/sources/rivestream.js +182 -176
- package/src/sources/rivo.js +58 -53
- package/src/sources/streamaggregator.js +114 -128
- package/src/sources/thugtv.js +70 -62
- package/src/sources/vidapi.js +122 -114
- package/src/sources/vidcore.js +14 -122
- package/src/sources/vidfast.js +14 -122
- package/src/sources/vidlink.js +78 -27
- package/src/sources/vidup.js +14 -122
- package/src/sources/vidvault.js +133 -187
- package/src/sources/vidy.js +192 -187
- package/src/sources/vidzee.js +189 -183
- package/src/sources/vixsrc.js +123 -113
- package/src/sources/watchout.js +60 -46
- package/src/sources/xdownloader.js +127 -128
- package/src/sources/yapgrid.js +68 -62
- package/src/sources/yastream.js +35 -29
- package/src/subtitles.js +105 -122
- package/src/utils/helpers.js +586 -247
- package/src/sources/bcine.js +0 -202
- package/src/sources/cinezo.js +0 -55
- package/src/sources/vidora.js +0 -62
- package/src/sources/vidrock.js +0 -145
package/src/sources/purstream.js
CHANGED
|
@@ -1,104 +1,96 @@
|
|
|
1
|
-
import { fetchJson,
|
|
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
|
-
|
|
9
|
-
|
|
10
|
-
|
|
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(
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
(
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
if (!match)
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
return
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
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 {
|
|
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
|
-
|
|
84
|
-
|
|
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
|
-
|
|
110
|
-
|
|
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
|
-
|
|
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
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
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
|
}
|