@vyla-entertainment/sdk 1.20.0 → 1.22.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 +99 -67
- package/src/health.js +60 -20
- 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/4movies.js +77 -0
- package/src/sources/aether.js +99 -0
- package/src/sources/castle.js +415 -0
- 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/framextv.js +126 -0
- 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/meowtv.js +140 -0
- 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/vidora.js +74 -42
- 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/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
|
}
|