@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.
Files changed (46) hide show
  1. package/.github/workflows/publish.yml +38 -38
  2. package/.gitlab-ci.yml +16 -0
  3. package/README.md +9 -13
  4. package/package.json +33 -32
  5. package/src/config.js +140 -116
  6. package/src/health.js +2 -2
  7. package/src/sdk.d.ts +122 -122
  8. package/src/sdk.js +7 -4
  9. package/src/sources/anineko.js +3 -1
  10. package/src/sources/bcine.js +202 -0
  11. package/src/sources/cinejoy.js +194 -209
  12. package/src/sources/cinesrc.js +212 -0
  13. package/src/sources/cinesu.js +147 -93
  14. package/src/sources/flaxmovies.js +113 -21
  15. package/src/sources/frame.js +88 -0
  16. package/src/sources/fsonic.js +3 -1
  17. package/src/sources/fsonline.js +3 -1
  18. package/src/sources/lmscript.js +42 -42
  19. package/src/sources/lookmovie.js +3 -1
  20. package/src/sources/luna.js +125 -0
  21. package/src/sources/mapple.js +40 -4
  22. package/src/sources/megasource.js +47 -0
  23. package/src/sources/meowtv.js +0 -1
  24. package/src/sources/nova.js +46 -0
  25. package/src/sources/peestream.js +122 -0
  26. package/src/sources/pengu.js +8 -3
  27. package/src/sources/pstream.js +68 -0
  28. package/src/sources/rivestream.js +179 -0
  29. package/src/sources/videasy.js +3 -1
  30. package/src/sources/vidgod.js +147 -0
  31. package/src/sources/vidnest.js +3 -1
  32. package/src/sources/vidvault.js +113 -113
  33. package/src/sources/vidzee.js +154 -199
  34. package/src/sources/zxcstream.js +141 -0
  35. package/src/subtitles.js +18 -0
  36. package/src/utils/helpers.js +2 -2
  37. package/src/sources/1embed.js +0 -115
  38. package/src/sources/anikoto.js +0 -198
  39. package/src/sources/anizone.js +0 -109
  40. package/src/sources/kickassanime.js +0 -107
  41. package/src/sources/nekowatch.js +0 -57
  42. package/src/sources/opstream.js +0 -123
  43. package/src/sources/peachify.js +0 -78
  44. package/src/sources/reanime.js +0 -324
  45. package/src/sources/vidrift.js +0 -95
  46. 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
+ }
@@ -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, tmdbApiKey }) {
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
+ }
@@ -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, tmdbApiKey, audio }) {
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;
@@ -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
  }