@vyla-entertainment/sdk 1.10.0 → 1.11.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 +1 -1
- package/src/config.js +82 -26
- package/src/sources/bcine.js +202 -0
- package/src/sources/cinesrc.js +212 -0
- package/src/sources/cinesu.js +148 -0
- package/src/sources/pstream.js +68 -0
- package/src/sources/zxcstream.js +141 -0
- package/src/sources/vidrift.js +0 -95
- package/src/sources/vidsync.js +0 -38
package/package.json
CHANGED
package/src/config.js
CHANGED
|
@@ -103,6 +103,24 @@ export const SOURCES = [
|
|
|
103
103
|
},
|
|
104
104
|
},
|
|
105
105
|
|
|
106
|
+
{
|
|
107
|
+
key: 'bcine',
|
|
108
|
+
label: 'Bcine',
|
|
109
|
+
sourceFile: 'bcine',
|
|
110
|
+
proxyParam: 'bc',
|
|
111
|
+
timeout: 25000,
|
|
112
|
+
jitter: 500,
|
|
113
|
+
retries: 2,
|
|
114
|
+
multiUrl: true,
|
|
115
|
+
cdnHeaders: [{
|
|
116
|
+
pattern: /1embed\.cc|videasy\.to/i,
|
|
117
|
+
headers: {
|
|
118
|
+
Referer: 'https://bcine.ru/',
|
|
119
|
+
Origin: 'https://bcine.ru',
|
|
120
|
+
},
|
|
121
|
+
}],
|
|
122
|
+
},
|
|
123
|
+
|
|
106
124
|
{
|
|
107
125
|
key: 'cinejoy',
|
|
108
126
|
label: 'Cinejoy',
|
|
@@ -115,6 +133,46 @@ export const SOURCES = [
|
|
|
115
133
|
skipProxy: true,
|
|
116
134
|
},
|
|
117
135
|
|
|
136
|
+
{
|
|
137
|
+
key: 'cinesrc',
|
|
138
|
+
label: 'CineSrc',
|
|
139
|
+
sourceFile: 'cinesrc',
|
|
140
|
+
proxyParam: 'csr',
|
|
141
|
+
timeout: 25000,
|
|
142
|
+
jitter: 500,
|
|
143
|
+
retries: 2,
|
|
144
|
+
multiUrl: true,
|
|
145
|
+
skipProxy: true,
|
|
146
|
+
skipVerify: true,
|
|
147
|
+
cdnHeaders: [{
|
|
148
|
+
pattern: /glendale-plumbing\.com|1embed\.cc|bright\d+\.online/i,
|
|
149
|
+
headers: {
|
|
150
|
+
Referer: 'https://cinesrc.st/',
|
|
151
|
+
Origin: 'https://cinesrc.st',
|
|
152
|
+
},
|
|
153
|
+
}],
|
|
154
|
+
},
|
|
155
|
+
|
|
156
|
+
{
|
|
157
|
+
key: 'cinesu',
|
|
158
|
+
label: 'CineSu',
|
|
159
|
+
sourceFile: 'cinesu',
|
|
160
|
+
proxyParam: 'cs',
|
|
161
|
+
timeout: 25000,
|
|
162
|
+
jitter: 500,
|
|
163
|
+
retries: 2,
|
|
164
|
+
multiUrl: true,
|
|
165
|
+
skipProxy: true,
|
|
166
|
+
skipVerify: true,
|
|
167
|
+
cdnHeaders: [{
|
|
168
|
+
pattern: /glendale-plumbing\.com/i,
|
|
169
|
+
headers: {
|
|
170
|
+
Referer: 'https://cine.su/',
|
|
171
|
+
Origin: 'https://cine.su',
|
|
172
|
+
},
|
|
173
|
+
}],
|
|
174
|
+
},
|
|
175
|
+
|
|
118
176
|
{
|
|
119
177
|
key: 'flaxmovies',
|
|
120
178
|
label: 'FlaxMovies',
|
|
@@ -302,7 +360,18 @@ export const SOURCES = [
|
|
|
302
360
|
skipProxy: true,
|
|
303
361
|
disabled: false, // Enabled, but only returns streams when a manifest is provided
|
|
304
362
|
},
|
|
305
|
-
|
|
363
|
+
|
|
364
|
+
{
|
|
365
|
+
key: 'pstream',
|
|
366
|
+
label: 'PStream',
|
|
367
|
+
sourceFile: 'pstream',
|
|
368
|
+
proxyParam: 'ps',
|
|
369
|
+
timeout: 35000,
|
|
370
|
+
jitter: 500,
|
|
371
|
+
retries: 1,
|
|
372
|
+
multiUrl: true,
|
|
373
|
+
},
|
|
374
|
+
|
|
306
375
|
{
|
|
307
376
|
key: 'nova',
|
|
308
377
|
label: 'Nova',
|
|
@@ -313,7 +382,7 @@ export const SOURCES = [
|
|
|
313
382
|
retries: 1,
|
|
314
383
|
multiUrl: true,
|
|
315
384
|
},
|
|
316
|
-
|
|
385
|
+
|
|
317
386
|
{
|
|
318
387
|
key: 'megasource',
|
|
319
388
|
label: 'MegaSource',
|
|
@@ -456,19 +525,6 @@ export const SOURCES = [
|
|
|
456
525
|
skipProxy: true,
|
|
457
526
|
},
|
|
458
527
|
|
|
459
|
-
{
|
|
460
|
-
key: 'vidrift',
|
|
461
|
-
label: 'VidRift',
|
|
462
|
-
sourceFile: 'vidrift',
|
|
463
|
-
proxyParam: 'vr',
|
|
464
|
-
timeout: 20000,
|
|
465
|
-
jitter: 500,
|
|
466
|
-
retries: 2,
|
|
467
|
-
multiUrl: true,
|
|
468
|
-
skipProxy: true,
|
|
469
|
-
disabled: true, // Temporarily disabled because their site is down, embed website does not load
|
|
470
|
-
},
|
|
471
|
-
|
|
472
528
|
{
|
|
473
529
|
key: 'vidrock',
|
|
474
530
|
label: 'VidRock',
|
|
@@ -489,17 +545,6 @@ export const SOURCES = [
|
|
|
489
545
|
},],
|
|
490
546
|
},
|
|
491
547
|
|
|
492
|
-
{
|
|
493
|
-
key: 'vidsync',
|
|
494
|
-
label: 'VidSync',
|
|
495
|
-
sourceFile: 'vidsync',
|
|
496
|
-
proxyParam: 'vs',
|
|
497
|
-
timeout: 20000,
|
|
498
|
-
retries: 2,
|
|
499
|
-
multiUrl: true,
|
|
500
|
-
disabled: true, // Temporarily disabled due to enc dec issues
|
|
501
|
-
},
|
|
502
|
-
|
|
503
548
|
{
|
|
504
549
|
key: 'vidup',
|
|
505
550
|
label: 'VidUp',
|
|
@@ -568,6 +613,17 @@ export const SOURCES = [
|
|
|
568
613
|
skipProxy: true,
|
|
569
614
|
},
|
|
570
615
|
|
|
616
|
+
{
|
|
617
|
+
key: 'zxcstream',
|
|
618
|
+
label: 'ZxcStream',
|
|
619
|
+
sourceFile: 'zxcstream',
|
|
620
|
+
proxyParam: 'zxc',
|
|
621
|
+
timeout: 25000,
|
|
622
|
+
jitter: 500,
|
|
623
|
+
retries: 2,
|
|
624
|
+
multiUrl: true,
|
|
625
|
+
},
|
|
626
|
+
|
|
571
627
|
];
|
|
572
628
|
|
|
573
629
|
export const HEALTH_PROBE_ID = '155';
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { USER_AGENT } from '../utils/helpers.js';
|
|
2
|
+
|
|
3
|
+
const _sInit = [23, 27, 30, 31, 86, 28, 19, 86, 9, 18, 19, 21, 26, 27, 86, 120, 114, 120, 116, 86, 9, 18, 19, 21, 26, 27, 122, 89, 25, 23];
|
|
4
|
+
const _vParam = `_v=${(_sInit[15] ^ 0x5a)}${(_sInit[16] ^ 0x5a)}${(_sInit[17] ^ 0x5a)}${(_sInit[18] ^ 0x5a)}`;
|
|
5
|
+
|
|
6
|
+
const nD = '4860ac8bfddb';
|
|
7
|
+
const aD = '224eff10e662e9635c9f671cf46351dcd69af42b1edd56f5e5fa21751f44b9c8';
|
|
8
|
+
const Ls = [17, 91, 203, 44, 8, 177, 62, 239, 119, 3, 154, 81, 28, 210, 101, 7];
|
|
9
|
+
const wa = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
|
|
10
|
+
|
|
11
|
+
const SERVERS = [
|
|
12
|
+
{ id: 'NIGHT', endpoint: '/server/night' },
|
|
13
|
+
{ id: 'EMP', endpoint: '/server/emp' },
|
|
14
|
+
{ id: 'MAIN', endpoint: '/server/vidsrc' }
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
const CORS_PROXY = 'https://eve.pstream.cfd';
|
|
18
|
+
let cachedToken = null;
|
|
19
|
+
let tokenExpiry = 0;
|
|
20
|
+
|
|
21
|
+
function ab(e) {
|
|
22
|
+
let t = e >>> 0;
|
|
23
|
+
t ^= t >>> 16;
|
|
24
|
+
t = Math.imul(t, 2146121005) >>> 0;
|
|
25
|
+
t ^= t >>> 15;
|
|
26
|
+
t = Math.imul(t, 2221713035) >>> 0;
|
|
27
|
+
return (t ^ (t >>> 16)) >>> 0;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function sD(e) {
|
|
31
|
+
const t = new TextEncoder().encode(aD);
|
|
32
|
+
const r = Math.max(32, Math.min(128, e + 17));
|
|
33
|
+
const n = new Uint8Array(r);
|
|
34
|
+
let a = 2166136261;
|
|
35
|
+
for (let s = 0; s < r; s += 1) {
|
|
36
|
+
a ^= t[s % t.length] ?? s;
|
|
37
|
+
a = ab((a + Ls[s % Ls.length] + ((2654435761 * s) >>> 0)) >>> 0);
|
|
38
|
+
n[s] = a & 255;
|
|
39
|
+
}
|
|
40
|
+
return n;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function iD(e) {
|
|
44
|
+
let t = '';
|
|
45
|
+
for (let r = 0; r < e.length; r += 3) {
|
|
46
|
+
const n = e[r];
|
|
47
|
+
const a = e[r + 1];
|
|
48
|
+
const s = e[r + 2];
|
|
49
|
+
t += wa[n >>> 2];
|
|
50
|
+
t += wa[((3 & n) << 4) | ((a ?? 0) >>> 4)];
|
|
51
|
+
if (a === undefined) break;
|
|
52
|
+
t += wa[((15 & a) << 2) | ((s ?? 0) >>> 6)];
|
|
53
|
+
if (s === undefined) break;
|
|
54
|
+
t += wa[63 & s];
|
|
55
|
+
}
|
|
56
|
+
return t;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function generateDirectHlsUrl(id, s, e) {
|
|
60
|
+
const isTv = s != null && e != null;
|
|
61
|
+
const tmdbId = Math.floor(Number(id));
|
|
62
|
+
const season = isTv ? Math.floor(Number(s || 1)) : 0;
|
|
63
|
+
const episode = isTv ? Math.floor(Number(e || 1)) : 0;
|
|
64
|
+
|
|
65
|
+
const str = `${nD}:${isTv ? 's' : 'm'}:${tmdbId}:${season}:${episode}`;
|
|
66
|
+
const a = new TextEncoder().encode(str);
|
|
67
|
+
const sArr = sD(a.length);
|
|
68
|
+
const i = new Uint8Array(a.length + 2);
|
|
69
|
+
i[0] = a.length & 255;
|
|
70
|
+
i[1] = (a.length >>> 8) & 255;
|
|
71
|
+
let o = (2654435769 ^ a.length) >>> 0;
|
|
72
|
+
for (let l = 0; l < a.length; l += 1) {
|
|
73
|
+
o = ab((o + sArr[l % sArr.length] + Ls[l % Ls.length] + l) >>> 0);
|
|
74
|
+
i[l + 2] = (a[l] ^ (255 & o)) ^ sArr[(7 * l + 3) % sArr.length];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return `https://glendale-plumbing.com/c/v1/${iD(i)}/master.m3u8`;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async function fetchInternalToken() {
|
|
81
|
+
if (cachedToken && Date.now() < tokenExpiry) return cachedToken;
|
|
82
|
+
try {
|
|
83
|
+
const res = await fetch('https://1embed.cc/api/token', {
|
|
84
|
+
headers: {
|
|
85
|
+
'User-Agent': USER_AGENT,
|
|
86
|
+
'Referer': 'https://1embed.cc/',
|
|
87
|
+
'Accept': 'application/json, text/plain, */*'
|
|
88
|
+
},
|
|
89
|
+
signal: AbortSignal.timeout(4000)
|
|
90
|
+
});
|
|
91
|
+
if (res.ok) {
|
|
92
|
+
const data = await res.json();
|
|
93
|
+
if (data?.token) {
|
|
94
|
+
cachedToken = data.token;
|
|
95
|
+
tokenExpiry = Date.now() + 1800 * 1000;
|
|
96
|
+
return cachedToken;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
} catch { }
|
|
100
|
+
|
|
101
|
+
try {
|
|
102
|
+
const proxiedUrl = `${CORS_PROXY}/?destination=${encodeURIComponent('https://1embed.cc/api/token')}`;
|
|
103
|
+
const res = await fetch(proxiedUrl, {
|
|
104
|
+
headers: {
|
|
105
|
+
'X-Referer': 'https://1embed.cc/',
|
|
106
|
+
'X-User-Agent': USER_AGENT
|
|
107
|
+
},
|
|
108
|
+
signal: AbortSignal.timeout(4000)
|
|
109
|
+
});
|
|
110
|
+
if (res.ok) {
|
|
111
|
+
const data = await res.json();
|
|
112
|
+
if (data?.token) {
|
|
113
|
+
cachedToken = data.token;
|
|
114
|
+
tokenExpiry = Date.now() + 1800 * 1000;
|
|
115
|
+
return cachedToken;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
} catch { }
|
|
119
|
+
|
|
120
|
+
return '';
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export async function getStream(args) {
|
|
124
|
+
const { id, s, e, clientIP } = args;
|
|
125
|
+
const isTv = s != null && e != null;
|
|
126
|
+
const isMovie = !isTv;
|
|
127
|
+
const allUrls = [];
|
|
128
|
+
|
|
129
|
+
const directHlsUrl = generateDirectHlsUrl(id, s, e);
|
|
130
|
+
const masterUrlWithMark = `${directHlsUrl}?${_vParam}`;
|
|
131
|
+
|
|
132
|
+
allUrls.push({
|
|
133
|
+
url: masterUrlWithMark,
|
|
134
|
+
server: 'Bcine (Direct Master)',
|
|
135
|
+
quality: 'Auto',
|
|
136
|
+
type: 'hls',
|
|
137
|
+
headers: {
|
|
138
|
+
'User-Agent': USER_AGENT,
|
|
139
|
+
'Referer': 'https://bcine.ru/',
|
|
140
|
+
'Origin': 'https://bcine.ru',
|
|
141
|
+
...(clientIP && { 'X-Forwarded-For': clientIP })
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
const token = await fetchInternalToken();
|
|
146
|
+
|
|
147
|
+
await Promise.allSettled(
|
|
148
|
+
SERVERS.map(async (server) => {
|
|
149
|
+
const query = isTv
|
|
150
|
+
? `id=${id}?type=tv&s=${s || 1}&e=${e || 1}`
|
|
151
|
+
: `id=${id}?type=movie`;
|
|
152
|
+
|
|
153
|
+
const stParam = token ? `&_st=${token}` : '';
|
|
154
|
+
const targetUrl = `https://1embed.cc${server.endpoint}/${query}${stParam}`;
|
|
155
|
+
|
|
156
|
+
const headers = {
|
|
157
|
+
'User-Agent': USER_AGENT,
|
|
158
|
+
'Referer': 'https://bcine.ru/',
|
|
159
|
+
'Accept': 'application/json, text/plain, */*',
|
|
160
|
+
...(token && { 'X-Stream-Token': token }),
|
|
161
|
+
...(clientIP && { 'X-Forwarded-For': clientIP })
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
let res = await fetch(targetUrl, { headers, signal: AbortSignal.timeout(5000) }).catch(() => null);
|
|
165
|
+
if (!res || !res.ok) {
|
|
166
|
+
const proxiedUrl = `${CORS_PROXY}/?destination=${encodeURIComponent(targetUrl)}`;
|
|
167
|
+
res = await fetch(proxiedUrl, {
|
|
168
|
+
headers: {
|
|
169
|
+
'X-Referer': 'https://bcine.ru/',
|
|
170
|
+
'X-User-Agent': USER_AGENT
|
|
171
|
+
},
|
|
172
|
+
signal: AbortSignal.timeout(5000)
|
|
173
|
+
}).catch(() => null);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (res && res.ok) {
|
|
177
|
+
try {
|
|
178
|
+
const data = await res.json();
|
|
179
|
+
if (data && data.success !== false) {
|
|
180
|
+
const streamUrl = data.streams?.proxy_m3u8 || data.streams?.raw_m3u8 || data.streams?.m3u8 || data.streamUrl;
|
|
181
|
+
if (streamUrl && typeof streamUrl === 'string') {
|
|
182
|
+
const urlWithMark = streamUrl.includes('?') ? `${streamUrl}&${_vParam}` : `${streamUrl}?${_vParam}`;
|
|
183
|
+
allUrls.push({
|
|
184
|
+
url: urlWithMark,
|
|
185
|
+
server: `Bcine (${data.selectedSource || data.provider || server.id})`,
|
|
186
|
+
quality: 'Auto',
|
|
187
|
+
type: streamUrl.includes('.m3u8') ? 'hls' : 'mp4',
|
|
188
|
+
headers: {
|
|
189
|
+
'User-Agent': USER_AGENT,
|
|
190
|
+
'Referer': 'https://bcine.ru/',
|
|
191
|
+
'Origin': 'https://bcine.ru'
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
} catch { }
|
|
197
|
+
}
|
|
198
|
+
})
|
|
199
|
+
);
|
|
200
|
+
|
|
201
|
+
return allUrls.length ? { allUrls } : null;
|
|
202
|
+
}
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { USER_AGENT } from '../utils/helpers.js';
|
|
2
|
+
|
|
3
|
+
const _sInit = [23, 27, 30, 31, 86, 28, 19, 86, 9, 18, 19, 21, 26, 27, 86, 120, 114, 120, 116, 86, 9, 18, 19, 21, 26, 27, 122, 89, 25, 23];
|
|
4
|
+
const _vParam = `_v=${(_sInit[15] ^ 0x5a)}${(_sInit[16] ^ 0x5a)}${(_sInit[17] ^ 0x5a)}${(_sInit[18] ^ 0x5a)}`;
|
|
5
|
+
|
|
6
|
+
const nD = '4860ac8bfddb';
|
|
7
|
+
const aD = '224eff10e662e9635c9f671cf46351dcd69af42b1edd56f5e5fa21751f44b9c8';
|
|
8
|
+
const Ls = [17, 91, 203, 44, 8, 177, 62, 239, 119, 3, 154, 81, 28, 210, 101, 7];
|
|
9
|
+
const wa = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
|
|
10
|
+
|
|
11
|
+
const SERVERS = [
|
|
12
|
+
{ id: 'NIGHT', endpoint: '/server/night' },
|
|
13
|
+
{ id: 'EMP', endpoint: '/server/emp' },
|
|
14
|
+
{ id: 'MAIN', endpoint: '/server/vidsrc' }
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
let cachedToken = null;
|
|
18
|
+
let tokenExpiry = 0;
|
|
19
|
+
|
|
20
|
+
function ab(e) {
|
|
21
|
+
let t = e >>> 0;
|
|
22
|
+
t ^= t >>> 16;
|
|
23
|
+
t = Math.imul(t, 2146121005) >>> 0;
|
|
24
|
+
t ^= t >>> 15;
|
|
25
|
+
t = Math.imul(t, 2221713035) >>> 0;
|
|
26
|
+
return (t ^ (t >>> 16)) >>> 0;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function sD(e) {
|
|
30
|
+
const t = new TextEncoder().encode(aD);
|
|
31
|
+
const r = Math.max(32, Math.min(128, e + 17));
|
|
32
|
+
const n = new Uint8Array(r);
|
|
33
|
+
let a = 2166136261;
|
|
34
|
+
for (let s = 0; s < r; s += 1) {
|
|
35
|
+
a ^= t[s % t.length] ?? s;
|
|
36
|
+
a = ab((a + Ls[s % Ls.length] + ((2654435761 * s) >>> 0)) >>> 0);
|
|
37
|
+
n[s] = a & 255;
|
|
38
|
+
}
|
|
39
|
+
return n;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function iD(e) {
|
|
43
|
+
let t = '';
|
|
44
|
+
for (let r = 0; r < e.length; r += 3) {
|
|
45
|
+
const n = e[r];
|
|
46
|
+
const a = e[r + 1];
|
|
47
|
+
const s = e[r + 2];
|
|
48
|
+
t += wa[n >>> 2];
|
|
49
|
+
t += wa[((3 & n) << 4) | ((a ?? 0) >>> 4)];
|
|
50
|
+
if (a === undefined) break;
|
|
51
|
+
t += wa[((15 & a) << 2) | ((s ?? 0) >>> 6)];
|
|
52
|
+
if (s === undefined) break;
|
|
53
|
+
t += wa[63 & s];
|
|
54
|
+
}
|
|
55
|
+
return t;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function generateCinesrcDirectHlsUrl(id, s, e) {
|
|
59
|
+
const isTv = s != null && e != null;
|
|
60
|
+
const tmdbId = Math.floor(Number(id));
|
|
61
|
+
const season = isTv ? Math.floor(Number(s || 1)) : 0;
|
|
62
|
+
const episode = isTv ? Math.floor(Number(e || 1)) : 0;
|
|
63
|
+
|
|
64
|
+
const str = `${nD}:${isTv ? 's' : 'm'}:${tmdbId}:${season}:${episode}`;
|
|
65
|
+
const a = new TextEncoder().encode(str);
|
|
66
|
+
const sArr = sD(a.length);
|
|
67
|
+
const i = new Uint8Array(a.length + 2);
|
|
68
|
+
i[0] = a.length & 255;
|
|
69
|
+
i[1] = (a.length >>> 8) & 255;
|
|
70
|
+
let o = (2654435769 ^ a.length) >>> 0;
|
|
71
|
+
for (let l = 0; l < a.length; l += 1) {
|
|
72
|
+
o = ab((o + sArr[l % sArr.length] + Ls[l % Ls.length] + l) >>> 0);
|
|
73
|
+
i[l + 2] = (a[l] ^ (255 & o)) ^ sArr[(7 * l + 3) % sArr.length];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return `https://glendale-plumbing.com/c/v1/${iD(i)}/master.m3u8`;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async function fetchBright67Subtitles(id, season, episode) {
|
|
80
|
+
let url = `https://subs.bright67.online/search?id=${id}`;
|
|
81
|
+
if (season != null && episode != null) {
|
|
82
|
+
url += `&season=${season}&episode=${episode}`;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
try {
|
|
86
|
+
const res = await fetch(url, {
|
|
87
|
+
headers: {
|
|
88
|
+
'User-Agent': USER_AGENT,
|
|
89
|
+
'Referer': 'https://cinesrc.st/'
|
|
90
|
+
},
|
|
91
|
+
signal: AbortSignal.timeout(4000)
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
if (!res.ok) return [];
|
|
95
|
+
const data = await res.json();
|
|
96
|
+
if (!Array.isArray(data)) return [];
|
|
97
|
+
|
|
98
|
+
return data.slice(0, 15).map(s => ({
|
|
99
|
+
label: s.display || s.languageName || s.language || 'English',
|
|
100
|
+
language: s.language || 'en',
|
|
101
|
+
file: s.url || s.r2Url,
|
|
102
|
+
type: (s.url || s.r2Url || '').endsWith('.vtt') ? 'vtt' : 'srt'
|
|
103
|
+
}));
|
|
104
|
+
} catch {
|
|
105
|
+
return [];
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
async function fetchInternalToken() {
|
|
110
|
+
if (cachedToken && Date.now() < tokenExpiry) return cachedToken;
|
|
111
|
+
try {
|
|
112
|
+
const res = await fetch('https://1embed.cc/api/token', {
|
|
113
|
+
headers: {
|
|
114
|
+
'User-Agent': USER_AGENT,
|
|
115
|
+
'Referer': 'https://1embed.cc/',
|
|
116
|
+
'Accept': 'application/json, text/plain, */*'
|
|
117
|
+
},
|
|
118
|
+
signal: AbortSignal.timeout(4000)
|
|
119
|
+
});
|
|
120
|
+
if (res.ok) {
|
|
121
|
+
const data = await res.json();
|
|
122
|
+
if (data?.token) {
|
|
123
|
+
cachedToken = data.token;
|
|
124
|
+
tokenExpiry = Date.now() + 1800 * 1000;
|
|
125
|
+
return cachedToken;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
} catch { }
|
|
129
|
+
|
|
130
|
+
return '';
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export async function getStream(args) {
|
|
134
|
+
const { id, s, e, clientIP } = args;
|
|
135
|
+
const isTv = s != null && e != null;
|
|
136
|
+
const isMovie = !isTv;
|
|
137
|
+
const allUrls = [];
|
|
138
|
+
|
|
139
|
+
const [subtitles, directHlsUrl] = await Promise.all([
|
|
140
|
+
fetchBright67Subtitles(id, isMovie ? undefined : s, isMovie ? undefined : e),
|
|
141
|
+
Promise.resolve(generateCinesrcDirectHlsUrl(id, s, e))
|
|
142
|
+
]);
|
|
143
|
+
|
|
144
|
+
const masterUrlWithMark = `${directHlsUrl}?${_vParam}`;
|
|
145
|
+
|
|
146
|
+
allUrls.push({
|
|
147
|
+
url: masterUrlWithMark,
|
|
148
|
+
server: 'CineSrc (Direct Master)',
|
|
149
|
+
quality: 'Auto',
|
|
150
|
+
type: 'hls',
|
|
151
|
+
headers: {
|
|
152
|
+
'User-Agent': USER_AGENT,
|
|
153
|
+
'Referer': 'https://cinesrc.st/',
|
|
154
|
+
'Origin': 'https://cinesrc.st',
|
|
155
|
+
...(clientIP && { 'X-Forwarded-For': clientIP })
|
|
156
|
+
},
|
|
157
|
+
subtitles: subtitles.length ? subtitles : undefined
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
const token = await fetchInternalToken();
|
|
161
|
+
|
|
162
|
+
await Promise.allSettled(
|
|
163
|
+
SERVERS.map(async (server) => {
|
|
164
|
+
const query = isTv
|
|
165
|
+
? `id=${id}?type=tv&s=${s || 1}&e=${e || 1}`
|
|
166
|
+
: `id=${id}?type=movie`;
|
|
167
|
+
|
|
168
|
+
const stParam = token ? `&_st=${token}` : '';
|
|
169
|
+
const targetUrl = `https://1embed.cc${server.endpoint}/${query}${stParam}`;
|
|
170
|
+
|
|
171
|
+
const headers = {
|
|
172
|
+
'User-Agent': USER_AGENT,
|
|
173
|
+
'Referer': 'https://cinesrc.st/',
|
|
174
|
+
'Accept': 'application/json, text/plain, */*',
|
|
175
|
+
...(token && { 'X-Stream-Token': token }),
|
|
176
|
+
...(clientIP && { 'X-Forwarded-For': clientIP })
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
const res = await fetch(targetUrl, { headers, signal: AbortSignal.timeout(5000) }).catch(() => null);
|
|
180
|
+
|
|
181
|
+
if (res && res.ok) {
|
|
182
|
+
try {
|
|
183
|
+
const data = await res.json();
|
|
184
|
+
if (data && data.success !== false) {
|
|
185
|
+
const streamUrl = data.streams?.proxy_m3u8 || data.streams?.raw_m3u8 || data.streams?.m3u8 || data.streamUrl;
|
|
186
|
+
if (streamUrl && typeof streamUrl === 'string') {
|
|
187
|
+
const urlWithMark = streamUrl.includes('?') ? `${streamUrl}&${_vParam}` : `${streamUrl}?${_vParam}`;
|
|
188
|
+
allUrls.push({
|
|
189
|
+
url: urlWithMark,
|
|
190
|
+
server: `CineSrc (${data.selectedSource || data.provider || server.id})`,
|
|
191
|
+
quality: 'Auto',
|
|
192
|
+
type: streamUrl.includes('.m3u8') ? 'hls' : 'mp4',
|
|
193
|
+
headers: {
|
|
194
|
+
'User-Agent': USER_AGENT,
|
|
195
|
+
'Referer': 'https://cinesrc.st/',
|
|
196
|
+
'Origin': 'https://cinesrc.st'
|
|
197
|
+
},
|
|
198
|
+
subtitles: subtitles.length ? subtitles : undefined
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
} catch { }
|
|
203
|
+
}
|
|
204
|
+
})
|
|
205
|
+
);
|
|
206
|
+
|
|
207
|
+
return allUrls.length ? { allUrls } : null;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export async function getSources() {
|
|
211
|
+
return ['CineSrc (Direct Master)', 'CineSrc (NIGHT)', 'CineSrc (EMP)', 'CineSrc (MAIN)'];
|
|
212
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { USER_AGENT } from '../utils/helpers.js';
|
|
2
|
+
|
|
3
|
+
const BASE_DOMAIN = 'https://glendale-plumbing.com';
|
|
4
|
+
const REFERER = 'https://cine.su/';
|
|
5
|
+
|
|
6
|
+
const nD = '4860ac8bfddb';
|
|
7
|
+
const aD = '224eff10e662e9635c9f671cf46351dcd69af42b1edd56f5e5fa21751f44b9c8';
|
|
8
|
+
const Ls = [17, 91, 203, 44, 8, 177, 62, 239, 119, 3, 154, 81, 28, 210, 101, 7];
|
|
9
|
+
const wa = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
|
|
10
|
+
|
|
11
|
+
function ab(e) {
|
|
12
|
+
let t = e >>> 0;
|
|
13
|
+
t ^= t >>> 16;
|
|
14
|
+
t = Math.imul(t, 2146121005) >>> 0;
|
|
15
|
+
t ^= t >>> 15;
|
|
16
|
+
t = Math.imul(t, 2221713035) >>> 0;
|
|
17
|
+
return (t ^ (t >>> 16)) >>> 0;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function sD(e) {
|
|
21
|
+
const t = new TextEncoder().encode(aD);
|
|
22
|
+
const r = Math.max(32, Math.min(128, e + 17));
|
|
23
|
+
const n = new Uint8Array(r);
|
|
24
|
+
let a = 2166136261;
|
|
25
|
+
for (let s = 0; s < r; s += 1) {
|
|
26
|
+
a ^= t[s % t.length] ?? s;
|
|
27
|
+
a = ab((a + Ls[s % Ls.length] + ((2654435761 * s) >>> 0)) >>> 0);
|
|
28
|
+
n[s] = a & 255;
|
|
29
|
+
}
|
|
30
|
+
return n;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function iD(e) {
|
|
34
|
+
let t = '';
|
|
35
|
+
for (let r = 0; r < e.length; r += 3) {
|
|
36
|
+
const n = e[r];
|
|
37
|
+
const a = e[r + 1];
|
|
38
|
+
const s = e[r + 2];
|
|
39
|
+
t += wa[n >>> 2];
|
|
40
|
+
t += wa[((3 & n) << 4) | ((a ?? 0) >>> 4)];
|
|
41
|
+
if (a === undefined) break;
|
|
42
|
+
t += wa[((15 & a) << 2) | ((s ?? 0) >>> 6)];
|
|
43
|
+
if (s === undefined) break;
|
|
44
|
+
t += wa[63 & s];
|
|
45
|
+
}
|
|
46
|
+
return t;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function generateMasterUrl(id, s, e) {
|
|
50
|
+
const isTv = s != null && e != null;
|
|
51
|
+
const tmdbId = Math.floor(Number(id));
|
|
52
|
+
const season = isTv ? Math.floor(Number(s || 1)) : 0;
|
|
53
|
+
const episode = isTv ? Math.floor(Number(e || 1)) : 0;
|
|
54
|
+
|
|
55
|
+
const str = `${nD}:${isTv ? 's' : 'm'}:${tmdbId}:${season}:${episode}`;
|
|
56
|
+
const a = new TextEncoder().encode(str);
|
|
57
|
+
const sArr = sD(a.length);
|
|
58
|
+
const i = new Uint8Array(a.length + 2);
|
|
59
|
+
i[0] = a.length & 255;
|
|
60
|
+
i[1] = (a.length >>> 8) & 255;
|
|
61
|
+
let o = (2654435769 ^ a.length) >>> 0;
|
|
62
|
+
for (let l = 0; l < a.length; l += 1) {
|
|
63
|
+
o = ab((o + sArr[l % sArr.length] + Ls[l % Ls.length] + l) >>> 0);
|
|
64
|
+
i[l + 2] = (a[l] ^ (255 & o)) ^ sArr[(7 * l + 3) % sArr.length];
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return `${BASE_DOMAIN}/c/v1/${iD(i)}/master.m3u8`;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function parsePlaylist(m3u8Text) {
|
|
71
|
+
const qualities = [];
|
|
72
|
+
const subtitles = [];
|
|
73
|
+
|
|
74
|
+
const subRegex = /#EXT-X-MEDIA:TYPE=SUBTITLES,[^\n]*NAME="([^"]*)"[^\n]*LANGUAGE="([^"]*)"[^\n]*URI="([^"]*)"/g;
|
|
75
|
+
let match;
|
|
76
|
+
while ((match = subRegex.exec(m3u8Text)) !== null) {
|
|
77
|
+
let uri = match[3];
|
|
78
|
+
if (uri.startsWith('/')) uri = `${BASE_DOMAIN}${uri}`;
|
|
79
|
+
subtitles.push({ label: match[1], language: match[2], file: uri, type: 'vtt' });
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const streamRegex = /#EXT-X-STREAM-INF:[^\n]*RESOLUTION=\d+x(\d+)[^\n]*\r?\n([^\n#][^\n]*)/g;
|
|
83
|
+
while ((match = streamRegex.exec(m3u8Text)) !== null) {
|
|
84
|
+
let streamPath = match[2].trim();
|
|
85
|
+
if (streamPath.startsWith('/')) streamPath = `${BASE_DOMAIN}${streamPath}`;
|
|
86
|
+
qualities.push({ quality: `${match[1]}p`, url: streamPath });
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return { qualities, subtitles };
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export async function getStream(args) {
|
|
93
|
+
const { id, s, e, clientIP } = args;
|
|
94
|
+
const rawMasterUrl = generateMasterUrl(id, s, e);
|
|
95
|
+
|
|
96
|
+
const headers = {
|
|
97
|
+
'User-Agent': USER_AGENT,
|
|
98
|
+
'Referer': REFERER,
|
|
99
|
+
'Origin': 'https://cine.su',
|
|
100
|
+
...(clientIP && { 'X-Forwarded-For': clientIP })
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
try {
|
|
104
|
+
const res = await fetch(rawMasterUrl, {
|
|
105
|
+
headers,
|
|
106
|
+
signal: AbortSignal.timeout(5000)
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
if (res.ok) {
|
|
110
|
+
const text = await res.text();
|
|
111
|
+
const { qualities, subtitles } = parsePlaylist(text);
|
|
112
|
+
|
|
113
|
+
if (qualities.length) {
|
|
114
|
+
const allUrls = [{
|
|
115
|
+
url: rawMasterUrl,
|
|
116
|
+
server: 'CineSu (Auto)',
|
|
117
|
+
quality: 'Auto',
|
|
118
|
+
type: 'hls',
|
|
119
|
+
headers,
|
|
120
|
+
subtitles: subtitles.length ? subtitles : undefined
|
|
121
|
+
}];
|
|
122
|
+
|
|
123
|
+
for (const q of qualities) {
|
|
124
|
+
allUrls.push({
|
|
125
|
+
url: q.url,
|
|
126
|
+
server: `CineSu (${q.quality})`,
|
|
127
|
+
quality: q.quality,
|
|
128
|
+
type: 'hls',
|
|
129
|
+
headers,
|
|
130
|
+
subtitles: subtitles.length ? subtitles : undefined
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return { allUrls };
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
} catch { }
|
|
138
|
+
|
|
139
|
+
return {
|
|
140
|
+
allUrls: [{
|
|
141
|
+
url: rawMasterUrl,
|
|
142
|
+
server: 'CineSu',
|
|
143
|
+
quality: 'Auto',
|
|
144
|
+
type: 'hls',
|
|
145
|
+
headers
|
|
146
|
+
}]
|
|
147
|
+
};
|
|
148
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { USER_AGENT } from '../utils/helpers.js';
|
|
2
|
+
|
|
3
|
+
async function safeImport(moduleName) {
|
|
4
|
+
try {
|
|
5
|
+
return await import(`./${moduleName}.js`);
|
|
6
|
+
} catch {
|
|
7
|
+
return null;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export async function getStream(args) {
|
|
12
|
+
const { id, s, e, clientIP, sdk } = args;
|
|
13
|
+
const isTv = s != null && e != null;
|
|
14
|
+
const type = isTv ? 'tv' : 'movie';
|
|
15
|
+
const allUrls = [];
|
|
16
|
+
|
|
17
|
+
const providers = [
|
|
18
|
+
{ name: 'CineSu', key: 'cinesu', fnName: 'fetchCineSuStreams' },
|
|
19
|
+
{ name: 'ZxcStream', key: 'zxcstream', fnName: 'fetchZxcStreams' },
|
|
20
|
+
{ name: 'VidFast', key: 'vidfast', fnName: 'fetchVidFastStreams' },
|
|
21
|
+
{ name: '1Embed', key: '1embed', fnName: 'fetchOneEmbedStreams' },
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
await Promise.all(
|
|
25
|
+
providers.map(async ({ name, key, fnName }) => {
|
|
26
|
+
try {
|
|
27
|
+
let streamResult = null;
|
|
28
|
+
|
|
29
|
+
if (sdk) {
|
|
30
|
+
try {
|
|
31
|
+
streamResult = await sdk.getStream(key, id, s, e, clientIP);
|
|
32
|
+
} catch { }
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (!streamResult) {
|
|
36
|
+
const mod = await safeImport(key);
|
|
37
|
+
if (mod) {
|
|
38
|
+
if (typeof mod.getStream === 'function') {
|
|
39
|
+
streamResult = await mod.getStream(args);
|
|
40
|
+
} else if (typeof mod[fnName] === 'function') {
|
|
41
|
+
const raw = await mod[fnName]({ type, id, season: s, episode: e });
|
|
42
|
+
if (Array.isArray(raw)) {
|
|
43
|
+
streamResult = { allUrls: raw };
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (!streamResult) return;
|
|
50
|
+
|
|
51
|
+
const streams = streamResult.allUrls || (streamResult.url ? [streamResult] : []);
|
|
52
|
+
for (const item of streams) {
|
|
53
|
+
allUrls.push({
|
|
54
|
+
url: item.url,
|
|
55
|
+
server: `FlyStream (${item.source || item.server || name})`,
|
|
56
|
+
quality: item.quality || 'Auto',
|
|
57
|
+
type: item.type || item.format || (item.url?.includes('.m3u8') ? 'hls' : 'mp4'),
|
|
58
|
+
headers: item.headers || {
|
|
59
|
+
'User-Agent': USER_AGENT,
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
} catch { }
|
|
64
|
+
})
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
return allUrls.length ? { allUrls } : null;
|
|
68
|
+
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import crypto from 'crypto';
|
|
2
|
+
import { getTmdbInfo, getUA } from '../utils/helpers.js';
|
|
3
|
+
|
|
4
|
+
const BASE_URL = 'https://player.zxcstream.xyz';
|
|
5
|
+
const AES_KEY = '7f4c9e2a81d63b05c4f7a9e8126d3b50e1a8c7f23d9465ab0c6e9f1d4a7b832c';
|
|
6
|
+
const SERVERS = ['berkas', 'orion', 'aquarius', 'resshin'];
|
|
7
|
+
|
|
8
|
+
function decryptCryptoJS(ciphertextB64, passphrase) {
|
|
9
|
+
try {
|
|
10
|
+
const buf = Buffer.from(ciphertextB64, 'base64');
|
|
11
|
+
if (buf.slice(0, 8).toString('utf8') !== 'Salted__') {
|
|
12
|
+
const key = crypto.createHash('md5').update(passphrase).digest();
|
|
13
|
+
const iv = Buffer.alloc(16, 0);
|
|
14
|
+
const decipher = crypto.createDecipheriv('aes-128-cbc', key, iv);
|
|
15
|
+
return Buffer.concat([decipher.update(buf), decipher.final()]).toString('utf8');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const salt = buf.slice(8, 16);
|
|
19
|
+
const cipherBytes = buf.slice(16);
|
|
20
|
+
|
|
21
|
+
let hash = Buffer.alloc(0);
|
|
22
|
+
let keyAndIv = Buffer.alloc(0);
|
|
23
|
+
while (keyAndIv.length < 48) {
|
|
24
|
+
hash = crypto.createHash('md5').update(Buffer.concat([hash, Buffer.from(passphrase), salt])).digest();
|
|
25
|
+
keyAndIv = Buffer.concat([keyAndIv, hash]);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const key = keyAndIv.slice(0, 32);
|
|
29
|
+
const iv = keyAndIv.slice(32, 48);
|
|
30
|
+
|
|
31
|
+
const decipher = crypto.createDecipheriv('aes-256-cbc', key, iv);
|
|
32
|
+
return Buffer.concat([decipher.update(cipherBytes), decipher.final()]).toString('utf8');
|
|
33
|
+
} catch {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export async function getStream({ id, s, e }) {
|
|
39
|
+
try {
|
|
40
|
+
const isTv = Boolean(s && e);
|
|
41
|
+
const mediaType = isTv ? 'tv' : 'movie';
|
|
42
|
+
|
|
43
|
+
let title = 'Media';
|
|
44
|
+
let year = '2024';
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
const info = await getTmdbInfo(id, mediaType, s);
|
|
48
|
+
if (info?.title) title = info.title;
|
|
49
|
+
if (info?.year) year = String(info.year);
|
|
50
|
+
} catch { }
|
|
51
|
+
|
|
52
|
+
const headers = {
|
|
53
|
+
'User-Agent': getUA(),
|
|
54
|
+
Referer: `${BASE_URL}/`,
|
|
55
|
+
Origin: BASE_URL,
|
|
56
|
+
Accept: 'application/json, text/plain, */*',
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const serverResults = await Promise.all(
|
|
60
|
+
SERVERS.map(async (server) => {
|
|
61
|
+
try {
|
|
62
|
+
const tokenRes = await fetch(`${BASE_URL}/backend/you-are-gay`, {
|
|
63
|
+
method: 'POST',
|
|
64
|
+
headers: { ...headers, 'Content-Type': 'application/json' },
|
|
65
|
+
body: JSON.stringify({
|
|
66
|
+
id,
|
|
67
|
+
media_type: mediaType,
|
|
68
|
+
path: server,
|
|
69
|
+
...(isTv ? { season: Number(s || 1), episode: Number(e || 1) } : {}),
|
|
70
|
+
}),
|
|
71
|
+
signal: AbortSignal.timeout(8000),
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
if (!tokenRes.ok) return [];
|
|
75
|
+
const tokenData = await tokenRes.json();
|
|
76
|
+
if (!tokenData?.token) return [];
|
|
77
|
+
|
|
78
|
+
const params = new URLSearchParams({
|
|
79
|
+
id,
|
|
80
|
+
b: mediaType,
|
|
81
|
+
ts: String(tokenData.ts),
|
|
82
|
+
token: tokenData.token,
|
|
83
|
+
title,
|
|
84
|
+
year,
|
|
85
|
+
date: year,
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
if (isTv) {
|
|
89
|
+
params.append('season', String(s || 1));
|
|
90
|
+
params.append('episode', String(e || 1));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const sourcesRes = await fetch(`${BASE_URL}/backend_/sources/${server}?${params.toString()}`, {
|
|
94
|
+
headers,
|
|
95
|
+
signal: AbortSignal.timeout(8000),
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
if (!sourcesRes.ok) return [];
|
|
99
|
+
const sourcesData = await sourcesRes.json();
|
|
100
|
+
|
|
101
|
+
const links = [];
|
|
102
|
+
if (Array.isArray(sourcesData?.links)) {
|
|
103
|
+
for (const item of sourcesData.links) {
|
|
104
|
+
if (!item.link) continue;
|
|
105
|
+
const decryptedUrl = decryptCryptoJS(item.link, AES_KEY);
|
|
106
|
+
if (decryptedUrl && decryptedUrl.startsWith('http')) {
|
|
107
|
+
links.push({
|
|
108
|
+
url: decryptedUrl,
|
|
109
|
+
type: decryptedUrl.includes('.m3u8') ? 'hls' : decryptedUrl.includes('.mpd') ? 'dash' : 'mp4',
|
|
110
|
+
quality: item.resolution || 'Auto',
|
|
111
|
+
server: `ZxcStream-${server.toUpperCase()}`,
|
|
112
|
+
headers: {
|
|
113
|
+
Referer: `${BASE_URL}/`,
|
|
114
|
+
Origin: BASE_URL,
|
|
115
|
+
},
|
|
116
|
+
skipProxy: true,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return links;
|
|
123
|
+
} catch {
|
|
124
|
+
return [];
|
|
125
|
+
}
|
|
126
|
+
})
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
const allUrls = serverResults.flat();
|
|
130
|
+
if (!allUrls.length) return null;
|
|
131
|
+
|
|
132
|
+
return { allUrls };
|
|
133
|
+
} catch {
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export async function getSources(args) {
|
|
139
|
+
const stream = await getStream(args);
|
|
140
|
+
return stream?.allUrls ? [...new Set(stream.allUrls.map(u => u.server))] : [];
|
|
141
|
+
}
|
package/src/sources/vidrift.js
DELETED
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const BASE = "https://embed.vidrift.in";
|
|
4
|
-
|
|
5
|
-
const DEFAULT_HEADERS = {
|
|
6
|
-
"Accept": "*/*",
|
|
7
|
-
"Accept-Language": "en-US,en;q=0.9",
|
|
8
|
-
"Cache-Control": "no-cache",
|
|
9
|
-
"Pragma": "no-cache",
|
|
10
|
-
"Referer": `${BASE}/`,
|
|
11
|
-
"Origin": BASE,
|
|
12
|
-
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36 Edg/150.0.0.0"
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
function decodeStreams(encodedStr) {
|
|
16
|
-
try {
|
|
17
|
-
const base64Str = encodedStr.replace(/-/g, '+').replace(/_/g, '/');
|
|
18
|
-
|
|
19
|
-
const binaryStr = typeof atob === 'function'
|
|
20
|
-
? atob(base64Str)
|
|
21
|
-
: Buffer.from(base64Str, 'base64').toString('binary');
|
|
22
|
-
|
|
23
|
-
const bytes = new Uint8Array(binaryStr.length);
|
|
24
|
-
for (let i = 0; i < binaryStr.length; i++) {
|
|
25
|
-
bytes[i] = binaryStr.charCodeAt(i);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const key = bytes[0];
|
|
29
|
-
let decodedStr = '';
|
|
30
|
-
for (let i = 1; i < bytes.length; i++) {
|
|
31
|
-
decodedStr += String.fromCharCode(bytes[i] ^ key);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
return JSON.parse(decodedStr);
|
|
35
|
-
} catch (e) {
|
|
36
|
-
return [];
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export async function getStream(args) {
|
|
41
|
-
const { id, s, e, server: serverName } = args;
|
|
42
|
-
const type = s != null && e != null ? "tv" : "movie";
|
|
43
|
-
|
|
44
|
-
const endpoint = type === "tv"
|
|
45
|
-
? `${BASE}/embed/tv/${id}/${s}/${e}`
|
|
46
|
-
: `${BASE}/embed/movie/${id}`;
|
|
47
|
-
|
|
48
|
-
try {
|
|
49
|
-
const res = await fetch(endpoint, {
|
|
50
|
-
headers: {
|
|
51
|
-
...DEFAULT_HEADERS,
|
|
52
|
-
"Accept": "text/html",
|
|
53
|
-
},
|
|
54
|
-
signal: AbortSignal.timeout(10000)
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
if (!res.ok) return null;
|
|
58
|
-
|
|
59
|
-
const html = await res.text();
|
|
60
|
-
|
|
61
|
-
const match = html.match(/var\s+_s\s*=\s*['"]([^'"]+)['"]/);
|
|
62
|
-
if (!match) return null;
|
|
63
|
-
|
|
64
|
-
const encodedStreams = match[1];
|
|
65
|
-
const streamsData = decodeStreams(encodedStreams);
|
|
66
|
-
|
|
67
|
-
if (!Array.isArray(streamsData) || !streamsData.length) {
|
|
68
|
-
return null;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
const allUrls = streamsData.map((stream, index) => ({
|
|
72
|
-
url: stream.url.startsWith("http")
|
|
73
|
-
? stream.url
|
|
74
|
-
: `${BASE}${stream.url}`,
|
|
75
|
-
server: stream.label || `VidRift - Server ${index + 1}`,
|
|
76
|
-
type: "hls",
|
|
77
|
-
headers: DEFAULT_HEADERS
|
|
78
|
-
}));
|
|
79
|
-
|
|
80
|
-
if (serverName && serverName !== "all") {
|
|
81
|
-
const filtered = allUrls.filter(x => x.server === serverName);
|
|
82
|
-
return filtered.length ? { allUrls: filtered } : null;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
return { allUrls };
|
|
86
|
-
} catch (err) {
|
|
87
|
-
return null;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
export async function getSources(args) {
|
|
92
|
-
const res = await getStream(args);
|
|
93
|
-
if (!res?.allUrls) return ["VidRift - Server 1"];
|
|
94
|
-
return res.allUrls.map(x => x.server);
|
|
95
|
-
}
|
package/src/sources/vidsync.js
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { fetchJson, fetchText, USER_AGENT, getTmdbInfo } from '../utils/helpers.js';
|
|
2
|
-
|
|
3
|
-
const API_BASE = "https://enc-dec.app/api";
|
|
4
|
-
const DOMAIN = "https://vidsync.xyz";
|
|
5
|
-
const HEADERS = { "Accept": "*/*", "Origin": DOMAIN, "Referer": `${DOMAIN}/`, "User-Agent": USER_AGENT, "X-Requested-With": "XMLHttpRequest" };
|
|
6
|
-
const SERVERS = ["cinevault", "cinedub", "cinebox", "cineflix", "cinevip", "cinecloud", "cine4k"];
|
|
7
|
-
|
|
8
|
-
export async function getStream({ id, s, e, server }) {
|
|
9
|
-
try {
|
|
10
|
-
const isTv = s != null && e != null;
|
|
11
|
-
const type = isTv ? 'tv' : 'movie';
|
|
12
|
-
const info = await getTmdbInfo(id, type);
|
|
13
|
-
if (!info?.titles?.length) return null;
|
|
14
|
-
const turnstileJson = await fetchJson(`${API_BASE}/enc-vidsync`, { signal: AbortSignal.timeout(5000) });
|
|
15
|
-
if (turnstileJson.status !== 200 || !turnstileJson.result?.token) return null;
|
|
16
|
-
const turnstileToken = turnstileJson.result.token;
|
|
17
|
-
let targets = SERVERS;
|
|
18
|
-
if (server && server !== 'all') {
|
|
19
|
-
const clean = server.replace('VidSync - ', '');
|
|
20
|
-
targets = SERVERS.includes(clean) ? [clean] : SERVERS;
|
|
21
|
-
}
|
|
22
|
-
const encTitle = encodeURIComponent(info.titles[0]).replace(/%20/g, '+');
|
|
23
|
-
const results = await Promise.allSettled(targets.map(async srv => {
|
|
24
|
-
let url = `${DOMAIN}/api/stream/fetch?title=${encTitle}&type=${type}&releaseYear=${info.year}&mediaId=${id}&serverName=${srv}`;
|
|
25
|
-
if (isTv) url += `&season=${s}&episode=${e}`;
|
|
26
|
-
const encryptedText = await fetchText(url, { headers: { ...HEADERS, "X-Cf-Turnstile": turnstileToken }, signal: AbortSignal.timeout(10000) });
|
|
27
|
-
const decJson = await fetchJson(`${API_BASE}/dec-vidsync`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ text: encryptedText, id: String(id) }), signal: AbortSignal.timeout(10000) });
|
|
28
|
-
if (decJson.status !== 200 || !decJson.result) throw new Error();
|
|
29
|
-
const streams = Array.isArray(decJson.result) ? decJson.result : [decJson.result];
|
|
30
|
-
return streams.map(st => ({ url: st.url || st.file, server: `VidSync - ${srv}`, quality: st.quality || "Auto", type: (st.url || st.file || "").includes(".m3u8") ? "hls" : "mp4", headers: { ...HEADERS, "Origin": DOMAIN }, skipProxy: false, skipVerify: true, skipHlsCheck: true }));
|
|
31
|
-
}));
|
|
32
|
-
const allUrls = [];
|
|
33
|
-
for (const r of results) if (r.status === 'fulfilled') allUrls.push(...r.value);
|
|
34
|
-
return allUrls.length ? { allUrls } : null;
|
|
35
|
-
} catch { return null; }
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export async function getSources() { return SERVERS.map(s => `VidSync - ${s}`); }
|