@vyla-entertainment/sdk 1.9.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/.github/workflows/publish.yml +38 -38
- package/.gitlab-ci.yml +16 -0
- package/README.md +9 -13
- package/package.json +33 -32
- package/src/config.js +140 -116
- package/src/health.js +2 -2
- package/src/sdk.d.ts +122 -122
- package/src/sdk.js +7 -4
- package/src/sources/anineko.js +3 -1
- package/src/sources/bcine.js +202 -0
- package/src/sources/cinejoy.js +194 -209
- package/src/sources/cinesrc.js +212 -0
- package/src/sources/cinesu.js +147 -93
- package/src/sources/flaxmovies.js +113 -21
- package/src/sources/frame.js +88 -0
- package/src/sources/fsonic.js +3 -1
- package/src/sources/fsonline.js +3 -1
- package/src/sources/lmscript.js +42 -42
- package/src/sources/lookmovie.js +3 -1
- package/src/sources/luna.js +125 -0
- package/src/sources/mapple.js +40 -4
- package/src/sources/megasource.js +47 -0
- package/src/sources/meowtv.js +0 -1
- package/src/sources/nova.js +46 -0
- package/src/sources/peestream.js +122 -0
- package/src/sources/pengu.js +8 -3
- package/src/sources/pstream.js +68 -0
- package/src/sources/rivestream.js +179 -0
- package/src/sources/videasy.js +3 -1
- package/src/sources/vidgod.js +147 -0
- package/src/sources/vidnest.js +3 -1
- package/src/sources/vidvault.js +113 -113
- package/src/sources/vidzee.js +154 -199
- package/src/sources/zxcstream.js +141 -0
- package/src/subtitles.js +18 -0
- package/src/utils/helpers.js +2 -2
- package/src/sources/1embed.js +0 -115
- package/src/sources/anikoto.js +0 -198
- package/src/sources/anizone.js +0 -109
- package/src/sources/kickassanime.js +0 -107
- package/src/sources/nekowatch.js +0 -57
- package/src/sources/opstream.js +0 -123
- package/src/sources/peachify.js +0 -78
- package/src/sources/reanime.js +0 -324
- package/src/sources/vidrift.js +0 -95
- package/src/sources/vidsync.js +0 -38
|
@@ -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,179 @@
|
|
|
1
|
+
// im being salty
|
|
2
|
+
|
|
3
|
+
import { USER_AGENT, fetchJson } from '../utils/helpers.js';
|
|
4
|
+
|
|
5
|
+
const C_ARRAY = [
|
|
6
|
+
'4Z7lUo', 'gwIVSMD', 'PLmz2elE2v', 'Z4OFV0', 'SZ6RZq6Zc', 'zhJEFYxrz8', 'FOm7b0', 'axHS3q4KDq', 'o9zuXQ', '4Aebt',
|
|
7
|
+
'wgjjWwKKx', 'rY4VIxqSN', 'kfjbnSo', '2DyrFA1M', 'YUixDM9B', 'JQvgEj0', 'mcuFx6JIek', 'eoTKe26gL', 'qaI9EVO1rB', '0xl33btZL',
|
|
8
|
+
'1fszuAU', 'a7jnHzst6P', 'wQuJkX', 'cBNhTJlEOf', 'KNcFWhDvgT', 'XipDGjST', 'PCZJlbHoyt', '2AYnMZkqd', 'HIpJh', 'KH0C3iztrG',
|
|
9
|
+
'W81hjts92', 'rJhAT', 'NON7LKoMQ', 'NMdY3nsKzI', 't4En5v', 'Qq5cOQ9H', 'Y9nwrp', 'VX5FYVfsf', 'cE5SJG', 'x1vj1',
|
|
10
|
+
'HegbLe', 'zJ3nmt4OA', 'gt7rxW57dq', 'clIE9b', 'jyJ9g', 'B5jXjMCSx', 'cOzZBZTV', 'FTXGy', 'Dfh1q1', 'ny9jqZ2POI',
|
|
11
|
+
'X2NnMn', 'MBtoyD', 'qz4Ilys7wB', '68lbOMye', '3YUJnmxp', '1fv5Imona', 'PlfvvXD7mA', 'ZarKfHCaPR', 'owORnX', 'dQP1YU',
|
|
12
|
+
'dVdkx', 'qgiK0E', 'cx9wQ', '5F9bGa', '7UjkKrp', 'Yvhrj', 'wYXez5Dg3', 'pG4GMU', 'MwMAu', 'rFRD5wlM'
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
const DEFAULT_SERVICES = [
|
|
16
|
+
'apex', 'pulse', 'solstice', 'quasar', 'horizon', 'primevids',
|
|
17
|
+
'flowcast', 'asiacloud', 'citadel', 'hindicast', 'guru'
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
function generateRiveSecretKey(e) {
|
|
21
|
+
if (e === undefined || e === null) return 'rive';
|
|
22
|
+
try {
|
|
23
|
+
let t, n;
|
|
24
|
+
const r = String(e);
|
|
25
|
+
if (isNaN(Number(e))) {
|
|
26
|
+
const sum = r.split('').reduce((acc, ch) => acc + ch.charCodeAt(0), 0);
|
|
27
|
+
t = C_ARRAY[sum % C_ARRAY.length] || Buffer.from(r).toString('base64');
|
|
28
|
+
n = Math.floor((sum % r.length) / 2);
|
|
29
|
+
} else {
|
|
30
|
+
const i = Number(e);
|
|
31
|
+
t = C_ARRAY[i % C_ARRAY.length] || Buffer.from(r).toString('base64');
|
|
32
|
+
n = Math.floor((i % r.length) / 2);
|
|
33
|
+
}
|
|
34
|
+
const i = r.slice(0, n) + t + r.slice(n);
|
|
35
|
+
const o = (function (str) {
|
|
36
|
+
const t = String(str);
|
|
37
|
+
let n = 3735928559 ^ t.length;
|
|
38
|
+
for (let e = 0; e < t.length; e++) {
|
|
39
|
+
const r = t.charCodeAt(e);
|
|
40
|
+
const rXor = (131 * e + 89 ^ (r << (e % 5))) & 255;
|
|
41
|
+
const r2 = r ^ rXor;
|
|
42
|
+
n = (((n << 7) | (n >>> 25)) >>> 0) ^ r2;
|
|
43
|
+
const idx = (65535 & n) * 60205;
|
|
44
|
+
const o2 = ((n >>> 16) * 60205) << 16;
|
|
45
|
+
n = (idx + o2) >>> 0;
|
|
46
|
+
n ^= n >>> 11;
|
|
47
|
+
}
|
|
48
|
+
n ^= n >>> 15;
|
|
49
|
+
n = ((65535 & n) * 49842 + (((n >>> 16) * 49842) << 16)) >>> 0;
|
|
50
|
+
n ^= n >>> 13;
|
|
51
|
+
n = ((65535 & n) * 40503 + (((n >>> 16) * 40503) << 16)) >>> 0;
|
|
52
|
+
n ^= n >>> 16;
|
|
53
|
+
n = ((65535 & n) * 10196 + (((n >>> 16) * 10196) << 16)) >>> 0;
|
|
54
|
+
return ((n ^= n >>> 15)).toString(16).padStart(8, '0');
|
|
55
|
+
})(
|
|
56
|
+
(function (str) {
|
|
57
|
+
const s = String(str);
|
|
58
|
+
let t = 0;
|
|
59
|
+
for (let n = 0; n < s.length; n++) {
|
|
60
|
+
const r = s.charCodeAt(n);
|
|
61
|
+
const i = (((t = (r + (t << 6) + (t << 16) - t) >>> 0) << (n % 5)) | (t >>> (32 - (n % 5)))) >>> 0;
|
|
62
|
+
t ^= (i ^ ((r << (n % 7)) | (r >>> (8 - (n % 7))))) >>> 0;
|
|
63
|
+
t = (t + ((t >>> 11) ^ (t << 3))) >>> 0;
|
|
64
|
+
}
|
|
65
|
+
t ^= t >>> 15;
|
|
66
|
+
t = ((65535 & t) * 49842 + ((((t >>> 16) * 49842) & 65535) << 16)) >>> 0;
|
|
67
|
+
t ^= t >>> 13;
|
|
68
|
+
t = ((65535 & t) * 40503 + ((((t >>> 16) * 40503) & 65535) << 16)) >>> 0;
|
|
69
|
+
return ((t ^= t >>> 16)).toString(16).padStart(8, '0');
|
|
70
|
+
})(i)
|
|
71
|
+
);
|
|
72
|
+
return Buffer.from(o, 'utf-8').toString('base64');
|
|
73
|
+
} catch {
|
|
74
|
+
return 'topSecret';
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async function fetchRiveServices() {
|
|
79
|
+
try {
|
|
80
|
+
const secretKey = generateRiveSecretKey();
|
|
81
|
+
const url = `https://www.rivestream.app/api/backendfetch?requestID=VideoProviderServices&secretKey=${encodeURIComponent(secretKey)}`;
|
|
82
|
+
const res = await fetchJson(url, {
|
|
83
|
+
headers: {
|
|
84
|
+
'User-Agent': USER_AGENT,
|
|
85
|
+
'Referer': 'https://www.rivestream.app/',
|
|
86
|
+
'Accept': 'application/json, text/plain, */*'
|
|
87
|
+
},
|
|
88
|
+
signal: AbortSignal.timeout(6000)
|
|
89
|
+
});
|
|
90
|
+
return Array.isArray(res?.data) && res.data.length ? res.data : DEFAULT_SERVICES;
|
|
91
|
+
} catch {
|
|
92
|
+
return DEFAULT_SERVICES;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
async function fetchServiceStreams(service, isMovie, id, s, e, secretKey, referer) {
|
|
97
|
+
try {
|
|
98
|
+
const cb = (service === 'primevids' || service === 'citadel')
|
|
99
|
+
? `&cb=${Math.floor(Date.now() / 3e6)}`
|
|
100
|
+
: '';
|
|
101
|
+
|
|
102
|
+
const reqID = isMovie ? 'movieVideoProvider' : 'tvVideoProvider';
|
|
103
|
+
const params = isMovie
|
|
104
|
+
? `requestID=${reqID}&id=${encodeURIComponent(id)}&service=${service}${cb}&secretKey=${encodeURIComponent(secretKey)}`
|
|
105
|
+
: `requestID=${reqID}&id=${encodeURIComponent(id)}&season=${encodeURIComponent(s)}&episode=${encodeURIComponent(e)}&service=${service}${cb}&secretKey=${encodeURIComponent(secretKey)}`;
|
|
106
|
+
|
|
107
|
+
const url = `https://www.rivestream.app/api/backendfetch?${params}`;
|
|
108
|
+
const res = await fetchJson(url, {
|
|
109
|
+
headers: {
|
|
110
|
+
'User-Agent': USER_AGENT,
|
|
111
|
+
'Referer': referer,
|
|
112
|
+
'Accept': 'application/json, text/plain, */*'
|
|
113
|
+
},
|
|
114
|
+
signal: AbortSignal.timeout(10000)
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
if (!res?.data?.sources || !Array.isArray(res.data.sources)) return [];
|
|
118
|
+
|
|
119
|
+
const streams = [];
|
|
120
|
+
for (const item of res.data.sources) {
|
|
121
|
+
if (!item || !item.url) continue;
|
|
122
|
+
|
|
123
|
+
const format = String(item.format || '').toLowerCase();
|
|
124
|
+
const urlStr = String(item.url || '').toLowerCase();
|
|
125
|
+
const isM3U8 = format === 'hls' || format === 'm3u8' || urlStr.includes('.m3u8') || urlStr.includes('.txt');
|
|
126
|
+
|
|
127
|
+
streams.push({
|
|
128
|
+
url: item.url,
|
|
129
|
+
server: `Rive (${item.source || service})`,
|
|
130
|
+
quality: String(item.quality || 'Auto'),
|
|
131
|
+
type: isM3U8 ? 'hls' : 'mp4',
|
|
132
|
+
headers: {
|
|
133
|
+
'User-Agent': USER_AGENT,
|
|
134
|
+
'Referer': referer
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
return streams;
|
|
139
|
+
} catch {
|
|
140
|
+
return [];
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export async function getStream(args) {
|
|
145
|
+
const { id, s, e, server } = args;
|
|
146
|
+
const isTv = s != null && e != null;
|
|
147
|
+
const isMovie = !isTv;
|
|
148
|
+
|
|
149
|
+
const secretKey = generateRiveSecretKey(id);
|
|
150
|
+
const referer = isMovie
|
|
151
|
+
? `https://www.rivestream.app/watch?type=movie&id=${id}`
|
|
152
|
+
: `https://www.rivestream.app/watch?type=tv&id=${id}&season=${s}&episode=${e}`;
|
|
153
|
+
|
|
154
|
+
let services = await fetchRiveServices();
|
|
155
|
+
|
|
156
|
+
if (server && server !== 'all') {
|
|
157
|
+
const clean = server.toLowerCase().replace('rive (', '').replace(')', '').replace('rive', '').trim();
|
|
158
|
+
services = services.filter(srv => srv.toLowerCase().includes(clean));
|
|
159
|
+
if (!services.length) services = await fetchRiveServices();
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const settled = await Promise.allSettled(
|
|
163
|
+
services.map(srv => fetchServiceStreams(srv, isMovie, id, s, e, secretKey, referer))
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
const allUrls = [];
|
|
167
|
+
for (const r of settled) {
|
|
168
|
+
if (r.status === 'fulfilled' && Array.isArray(r.value)) {
|
|
169
|
+
allUrls.push(...r.value);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return allUrls.length ? { allUrls } : null;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export async function getSources() {
|
|
177
|
+
const services = await fetchRiveServices();
|
|
178
|
+
return services.map(s => `Rive (${s})`);
|
|
179
|
+
}
|
package/src/sources/videasy.js
CHANGED
|
@@ -12,7 +12,9 @@ const SERVERS = [
|
|
|
12
12
|
{ id: 'superflix', name: 'Raze' }
|
|
13
13
|
];
|
|
14
14
|
|
|
15
|
-
export async function getStream({ id, s, e, server,
|
|
15
|
+
export async function getStream({ id, s, e, server, sdk }) {
|
|
16
|
+
const tmdbApiKey = sdk?.tmdbApiKey || null;
|
|
17
|
+
if (!tmdbApiKey) return null;
|
|
16
18
|
try {
|
|
17
19
|
const isTv = s != null && e != null;
|
|
18
20
|
const info = await getTmdbInfo(tmdbApiKey, id, isTv ? 'tv' : 'movie');
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { USER_AGENT } from '../utils/helpers.js';
|
|
2
|
+
|
|
3
|
+
const REDIS_URL = 'https://vidnest-redis-fell-prism-rest.cloud.layerbase.dev/';
|
|
4
|
+
const REDIS_AUTH = 'Bearer ve8z9XSKatu74M7FjLU8eQ29';
|
|
5
|
+
const ORIGIN = 'https://vidgod.space';
|
|
6
|
+
|
|
7
|
+
const SERVERS = [
|
|
8
|
+
{
|
|
9
|
+
name: 'Pulsar',
|
|
10
|
+
key: 'pulsar',
|
|
11
|
+
base: 'https://vidnest-extractor.vividdubbing.workers.dev/api',
|
|
12
|
+
serverParam: 'prime'
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
name: 'Orion',
|
|
16
|
+
key: 'orion',
|
|
17
|
+
base: 'https://404-vidnest.lofiserver.workers.dev/api',
|
|
18
|
+
serverParam: 'gama'
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
name: 'Stellar',
|
|
22
|
+
key: 'stellar',
|
|
23
|
+
base: 'https://404-vidnest.lofiserver.workers.dev/api',
|
|
24
|
+
serverParam: 'sigma'
|
|
25
|
+
}
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
function buildCacheKey(serverKey, type, id, s, e) {
|
|
29
|
+
const parts = [serverKey, type, id];
|
|
30
|
+
if (type === 'tv') {
|
|
31
|
+
parts.push(s || '1', e || '1');
|
|
32
|
+
}
|
|
33
|
+
return parts.join(':');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async function getFromCache(key) {
|
|
37
|
+
try {
|
|
38
|
+
const res = await fetch(REDIS_URL, {
|
|
39
|
+
method: 'POST',
|
|
40
|
+
headers: {
|
|
41
|
+
'Authorization': REDIS_AUTH,
|
|
42
|
+
'Content-Type': 'application/json',
|
|
43
|
+
'Accept': '*/*',
|
|
44
|
+
'Origin': ORIGIN,
|
|
45
|
+
'Referer': `${ORIGIN}/`,
|
|
46
|
+
'User-Agent': USER_AGENT
|
|
47
|
+
},
|
|
48
|
+
body: JSON.stringify(['GET', key]),
|
|
49
|
+
signal: AbortSignal.timeout(6000)
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
if (!res.ok) return null;
|
|
53
|
+
const data = await res.json();
|
|
54
|
+
if (!data || !data.result) return null;
|
|
55
|
+
|
|
56
|
+
const parsed = typeof data.result === 'string' ? JSON.parse(data.result) : data.result;
|
|
57
|
+
return parsed?.streams?.length ? parsed : null;
|
|
58
|
+
} catch {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async function fetchFromWorker(srv, type, id, s, e) {
|
|
64
|
+
try {
|
|
65
|
+
const endpoint = type === 'movie'
|
|
66
|
+
? `${srv.base}/movie/${id}?server=${srv.serverParam}`
|
|
67
|
+
: `${srv.base}/tv/${id}/${s || '1'}/${e || '1'}?server=${srv.serverParam}`;
|
|
68
|
+
|
|
69
|
+
const res = await fetch(endpoint, {
|
|
70
|
+
headers: {
|
|
71
|
+
'Accept': 'application/json',
|
|
72
|
+
'Origin': ORIGIN,
|
|
73
|
+
'Referer': `${ORIGIN}/`,
|
|
74
|
+
'User-Agent': USER_AGENT
|
|
75
|
+
},
|
|
76
|
+
signal: AbortSignal.timeout(8000)
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
if (!res.ok) return null;
|
|
80
|
+
const data = await res.json();
|
|
81
|
+
return data?.streams?.length ? data : null;
|
|
82
|
+
} catch {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async function resolveServer(srv, type, id, s, e) {
|
|
88
|
+
const cacheKey = buildCacheKey(srv.key, type, id, s, e);
|
|
89
|
+
const cached = await getFromCache(cacheKey);
|
|
90
|
+
if (cached) return { server: srv.name, data: cached };
|
|
91
|
+
|
|
92
|
+
const live = await fetchFromWorker(srv, type, id, s, e);
|
|
93
|
+
if (live) return { server: srv.name, data: live };
|
|
94
|
+
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export async function getStream(args) {
|
|
99
|
+
const { id, s, e, server } = args;
|
|
100
|
+
const isTv = s != null && e != null;
|
|
101
|
+
const type = isTv ? 'tv' : 'movie';
|
|
102
|
+
|
|
103
|
+
let targets = SERVERS;
|
|
104
|
+
if (server && server !== 'all') {
|
|
105
|
+
const clean = server.toLowerCase().trim();
|
|
106
|
+
targets = SERVERS.filter(srv => srv.name.toLowerCase() === clean || srv.key.toLowerCase() === clean);
|
|
107
|
+
if (!targets.length) targets = SERVERS;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const settled = await Promise.allSettled(
|
|
111
|
+
targets.map(srv => resolveServer(srv, type, id, s, e))
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
const allUrls = [];
|
|
115
|
+
|
|
116
|
+
for (const r of settled) {
|
|
117
|
+
if (r.status !== 'fulfilled' || !r.value) continue;
|
|
118
|
+
const { server: serverName, data } = r.value;
|
|
119
|
+
|
|
120
|
+
for (const item of data.streams || []) {
|
|
121
|
+
if (!item || !item.url) continue;
|
|
122
|
+
|
|
123
|
+
const typeStr = String(item.type || '').toLowerCase();
|
|
124
|
+
const urlStr = String(item.url || '').toLowerCase();
|
|
125
|
+
const isM3U8 =
|
|
126
|
+
typeStr === 'hls' ||
|
|
127
|
+
typeStr === 'application/vnd.apple.mpegurl' ||
|
|
128
|
+
typeStr === 'cloudflare' ||
|
|
129
|
+
typeStr === 'tiktok' ||
|
|
130
|
+
urlStr.includes('.m3u8') ||
|
|
131
|
+
urlStr.includes('.txt');
|
|
132
|
+
|
|
133
|
+
allUrls.push({
|
|
134
|
+
url: item.url,
|
|
135
|
+
server: serverName,
|
|
136
|
+
quality: item.quality || 'Auto',
|
|
137
|
+
type: isM3U8 ? 'hls' : 'mp4',
|
|
138
|
+
headers: item.headers || {
|
|
139
|
+
'User-Agent': USER_AGENT,
|
|
140
|
+
'Referer': `${ORIGIN}/`
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return allUrls.length ? { allUrls } : null;
|
|
147
|
+
}
|
package/src/sources/vidnest.js
CHANGED
|
@@ -39,7 +39,9 @@ async function tmdbToAnilist(tmdbId, season) {
|
|
|
39
39
|
|
|
40
40
|
const SERVER_KEYS = ['hollymoviehd', 'allmovies', 'catflix', 'purstream', 'lamda', 'vidlink', 'klikxxi'];
|
|
41
41
|
|
|
42
|
-
export async function getStream({ id, s, e,
|
|
42
|
+
export async function getStream({ id, s, e, sdk, audio }) {
|
|
43
|
+
const tmdbApiKey = sdk?.tmdbApiKey || null;
|
|
44
|
+
if (!tmdbApiKey) return null;
|
|
43
45
|
if (s) {
|
|
44
46
|
const k = tmdbApiKey;
|
|
45
47
|
const showData = k ? await fetchJson(`https://api.themoviedb.org/3/tv/${id}?api_key=${k}`, { signal: AbortSignal.timeout(5000) }).catch(() => null) : null;
|
package/src/sources/vidvault.js
CHANGED
|
@@ -1,114 +1,114 @@
|
|
|
1
|
-
import { USER_AGENT } from '../utils/helpers.js';
|
|
2
|
-
|
|
3
|
-
const BASE_URL = "https://vidvault.ru";
|
|
4
|
-
const HEADERS = {
|
|
5
|
-
"Referer": `${BASE_URL}/`,
|
|
6
|
-
"Origin": BASE_URL,
|
|
7
|
-
"User-Agent": USER_AGENT,
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
async function getToken() {
|
|
11
|
-
const res = await fetch(`${BASE_URL}/api/get-token`, {
|
|
12
|
-
method: "GET",
|
|
13
|
-
headers: HEADERS
|
|
14
|
-
});
|
|
15
|
-
const data = await res.json();
|
|
16
|
-
return data.t;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function getCaptionType(url) {
|
|
20
|
-
return url.toLowerCase().includes(".vtt") ? "vtt" : "srt";
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export async function getStream(args) {
|
|
24
|
-
const { id, s, e } = args;
|
|
25
|
-
const type = (s != null && e != null) ? "tv" : "movie";
|
|
26
|
-
|
|
27
|
-
try {
|
|
28
|
-
const token = await getToken();
|
|
29
|
-
|
|
30
|
-
const payload = { type, tmdbId: String(id) };
|
|
31
|
-
if (type === "tv") {
|
|
32
|
-
payload.season = String(s);
|
|
33
|
-
payload.episode = String(e);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const res = await fetch(`${BASE_URL}/api/download-proxy`, {
|
|
37
|
-
method: "POST",
|
|
38
|
-
headers: {
|
|
39
|
-
...HEADERS,
|
|
40
|
-
"Content-Type": "application/json",
|
|
41
|
-
"x-request-token": token
|
|
42
|
-
},
|
|
43
|
-
body: JSON.stringify(payload)
|
|
44
|
-
});
|
|
45
|
-
const data = await res.json();
|
|
46
|
-
|
|
47
|
-
const allUrls = [];
|
|
48
|
-
const subtitles = [];
|
|
49
|
-
|
|
50
|
-
const mp4 = data?.mp4Data;
|
|
51
|
-
if (mp4) {
|
|
52
|
-
const country = mp4.country || "";
|
|
53
|
-
const lanName = mp4.lanName || "";
|
|
54
|
-
const detailPath = mp4.detailPath || "";
|
|
55
|
-
|
|
56
|
-
const downloads = mp4.downloadInfo?.data?.downloads || [];
|
|
57
|
-
for (const d of downloads) {
|
|
58
|
-
if (!d?.url) continue;
|
|
59
|
-
allUrls.push({
|
|
60
|
-
quality: `${d.resolution}p ${detailPath} ${country} ${lanName}`.trim(),
|
|
61
|
-
url: d.url,
|
|
62
|
-
type: "mp4",
|
|
63
|
-
headers: HEADERS
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
const srtCaptions = mp4.downloadInfo?.data?.captions || [];
|
|
68
|
-
for (const c of srtCaptions) {
|
|
69
|
-
if (!c?.url) continue;
|
|
70
|
-
subtitles.push({
|
|
71
|
-
label: c.lanName || c.lan || "Unknown",
|
|
72
|
-
type: getCaptionType(c.url),
|
|
73
|
-
language: c.lan || "",
|
|
74
|
-
url: c.url
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
const mkvFiles = data?.mkvData?.files || [];
|
|
80
|
-
for (const f of mkvFiles) {
|
|
81
|
-
if (!f?.url) continue;
|
|
82
|
-
allUrls.push({
|
|
83
|
-
quality: `MKV ${f.size || ""}`.trim(),
|
|
84
|
-
url: f.url,
|
|
85
|
-
type: "mp4",
|
|
86
|
-
headers: HEADERS
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
const mkvV2 = data?.mkvV2Data;
|
|
91
|
-
if (mkvV2?.url) {
|
|
92
|
-
allUrls.push({
|
|
93
|
-
quality: `${mkvV2.quality || ""} ${mkvV2.language || ""} ${mkvV2.country || ""} (${mkvV2.size || ""})`.trim(),
|
|
94
|
-
url: mkvV2.url,
|
|
95
|
-
type: "mp4",
|
|
96
|
-
headers: HEADERS
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
const mkvV3 = data?.mkvV3Data;
|
|
101
|
-
if (mkvV3?.url) {
|
|
102
|
-
allUrls.push({
|
|
103
|
-
quality: `${mkvV3.quality || ""} ${mkvV3.language || ""} ${mkvV3.country || ""} (${mkvV3.size || ""})`.trim(),
|
|
104
|
-
url: mkvV3.url,
|
|
105
|
-
type: "mp4",
|
|
106
|
-
headers: HEADERS
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
return allUrls.length ? { allUrls, subtitles } : null;
|
|
111
|
-
} catch (err) {
|
|
112
|
-
return null;
|
|
113
|
-
}
|
|
1
|
+
import { USER_AGENT } from '../utils/helpers.js';
|
|
2
|
+
|
|
3
|
+
const BASE_URL = "https://vidvault.ru";
|
|
4
|
+
const HEADERS = {
|
|
5
|
+
"Referer": `${BASE_URL}/`,
|
|
6
|
+
"Origin": BASE_URL,
|
|
7
|
+
"User-Agent": USER_AGENT,
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
async function getToken() {
|
|
11
|
+
const res = await fetch(`${BASE_URL}/api/get-token`, {
|
|
12
|
+
method: "GET",
|
|
13
|
+
headers: HEADERS
|
|
14
|
+
});
|
|
15
|
+
const data = await res.json();
|
|
16
|
+
return data.t;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function getCaptionType(url) {
|
|
20
|
+
return url.toLowerCase().includes(".vtt") ? "vtt" : "srt";
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export async function getStream(args) {
|
|
24
|
+
const { id, s, e } = args;
|
|
25
|
+
const type = (s != null && e != null) ? "tv" : "movie";
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
const token = await getToken();
|
|
29
|
+
|
|
30
|
+
const payload = { type, tmdbId: String(id) };
|
|
31
|
+
if (type === "tv") {
|
|
32
|
+
payload.season = String(s);
|
|
33
|
+
payload.episode = String(e);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const res = await fetch(`${BASE_URL}/api/download-proxy`, {
|
|
37
|
+
method: "POST",
|
|
38
|
+
headers: {
|
|
39
|
+
...HEADERS,
|
|
40
|
+
"Content-Type": "application/json",
|
|
41
|
+
"x-request-token": token
|
|
42
|
+
},
|
|
43
|
+
body: JSON.stringify(payload)
|
|
44
|
+
});
|
|
45
|
+
const data = await res.json();
|
|
46
|
+
|
|
47
|
+
const allUrls = [];
|
|
48
|
+
const subtitles = [];
|
|
49
|
+
|
|
50
|
+
const mp4 = data?.mp4Data;
|
|
51
|
+
if (mp4) {
|
|
52
|
+
const country = mp4.country || "";
|
|
53
|
+
const lanName = mp4.lanName || "";
|
|
54
|
+
const detailPath = mp4.detailPath || "";
|
|
55
|
+
|
|
56
|
+
const downloads = mp4.downloadInfo?.data?.downloads || [];
|
|
57
|
+
for (const d of downloads) {
|
|
58
|
+
if (!d?.url) continue;
|
|
59
|
+
allUrls.push({
|
|
60
|
+
quality: `${d.resolution}p ${detailPath} ${country} ${lanName}`.trim(),
|
|
61
|
+
url: d.url,
|
|
62
|
+
type: "mp4",
|
|
63
|
+
headers: HEADERS
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const srtCaptions = mp4.downloadInfo?.data?.captions || [];
|
|
68
|
+
for (const c of srtCaptions) {
|
|
69
|
+
if (!c?.url) continue;
|
|
70
|
+
subtitles.push({
|
|
71
|
+
label: c.lanName || c.lan || "Unknown",
|
|
72
|
+
type: getCaptionType(c.url),
|
|
73
|
+
language: c.lan || "",
|
|
74
|
+
url: c.url
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const mkvFiles = data?.mkvData?.files || [];
|
|
80
|
+
for (const f of mkvFiles) {
|
|
81
|
+
if (!f?.url) continue;
|
|
82
|
+
allUrls.push({
|
|
83
|
+
quality: `MKV ${f.size || ""}`.trim(),
|
|
84
|
+
url: f.url,
|
|
85
|
+
type: "mp4",
|
|
86
|
+
headers: HEADERS
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const mkvV2 = data?.mkvV2Data;
|
|
91
|
+
if (mkvV2?.url) {
|
|
92
|
+
allUrls.push({
|
|
93
|
+
quality: `${mkvV2.quality || ""} ${mkvV2.language || ""} ${mkvV2.country || ""} (${mkvV2.size || ""})`.trim(),
|
|
94
|
+
url: mkvV2.url,
|
|
95
|
+
type: "mp4",
|
|
96
|
+
headers: HEADERS
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const mkvV3 = data?.mkvV3Data;
|
|
101
|
+
if (mkvV3?.url) {
|
|
102
|
+
allUrls.push({
|
|
103
|
+
quality: `${mkvV3.quality || ""} ${mkvV3.language || ""} ${mkvV3.country || ""} (${mkvV3.size || ""})`.trim(),
|
|
104
|
+
url: mkvV3.url,
|
|
105
|
+
type: "mp4",
|
|
106
|
+
headers: HEADERS
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return allUrls.length ? { allUrls, subtitles } : null;
|
|
111
|
+
} catch (err) {
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
114
|
}
|