@vyla-entertainment/sdk 1.0.0 → 1.2.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 (53) hide show
  1. package/.env.example +1 -0
  2. package/.github/workflows/publish.yml +38 -0
  3. package/.gitlab-ci.yml +22 -0
  4. package/LICENSE +0 -0
  5. package/README.md +13 -26
  6. package/package.json +5 -3
  7. package/src/config.js +63 -77
  8. package/src/downloads/downloads.js +8 -4
  9. package/src/downloads/sources/trendimovies.js +0 -0
  10. package/src/health.js +0 -0
  11. package/src/sdk.d.ts +123 -0
  12. package/src/sdk.js +0 -0
  13. package/src/sources/123anime.js +0 -0
  14. package/src/sources/anihq.js +14 -2
  15. package/src/sources/anineko.js +122 -15
  16. package/src/sources/anipm.js +0 -0
  17. package/src/sources/cinejoy.js +210 -0
  18. package/src/sources/flaxmovies.js +114 -10
  19. package/src/sources/frame.js +88 -0
  20. package/src/sources/fsharetv.js +0 -0
  21. package/src/sources/fsonic.js +2 -2
  22. package/src/sources/fsonline.js +2 -2
  23. package/src/sources/hexa.js +0 -0
  24. package/src/sources/kisskh.js +0 -0
  25. package/src/sources/lmscript.js +43 -0
  26. package/src/sources/lookmovie.js +0 -0
  27. package/src/sources/mapple.js +40 -4
  28. package/src/sources/meowtv.js +1 -9
  29. package/src/sources/peestream.js +122 -0
  30. package/src/sources/pengu.js +0 -0
  31. package/src/sources/purstream.js +0 -0
  32. package/src/sources/vidapi.js +0 -0
  33. package/src/sources/vidcore.js +0 -0
  34. package/src/sources/videasy.js +6 -12
  35. package/src/sources/vidfast.js +0 -0
  36. package/src/sources/vidlink.js +0 -0
  37. package/src/sources/vidnest.js +0 -0
  38. package/src/sources/vidrift.js +0 -0
  39. package/src/sources/vidrock.js +0 -0
  40. package/src/sources/vidsync.js +0 -0
  41. package/src/sources/vidup.js +0 -0
  42. package/src/sources/vidvault.js +114 -0
  43. package/src/sources/vidzee.js +73 -87
  44. package/src/sources/vixsrc.js +28 -14
  45. package/src/sources/xpass.js +0 -0
  46. package/src/subtitles.js +0 -0
  47. package/src/utils/helpers.js +56 -20
  48. package/src/sources/1embed.js +0 -92
  49. package/src/sources/goated.js +0 -262
  50. package/src/sources/nebula.js +0 -62
  51. package/src/sources/nekowatch.js +0 -57
  52. package/src/sources/opstream.js +0 -123
  53. package/src/sources/peachify.js +0 -78
@@ -0,0 +1,43 @@
1
+ import { getTmdbInfo } from '../utils/helpers.js';
2
+
3
+ export async function getStream(args) {
4
+ const { id, s, e, tmdbApiKey } = args;
5
+ const type = (s != null && e != null) ? 'tv' : 'movie';
6
+
7
+ try {
8
+ const tmdbInfo = await getTmdbInfo(tmdbApiKey, id, type, s);
9
+ const name = tmdbInfo.titles[0] || '';
10
+ if (!name) return null;
11
+
12
+ if (type === 'tv') {
13
+ return null;
14
+ } else {
15
+ const url = `https://lmscript.xyz/v1/movies?filters[q]=${encodeURIComponent(name)}&expand=streams`;
16
+ const response = await fetch(url);
17
+ const data = await response.json();
18
+
19
+ const movie = data.items?.find(item => `${item.tmdb_prefix}` === `${id}` || `${item.tmdb_id}` === `${id}`);
20
+ if (!movie) return null;
21
+
22
+ const streams = movie.streams || {};
23
+ const SOURCE_ORDER = ["1080p", "720p", "480p", "360p"];
24
+ const sortedStreams = Object.keys(streams).sort((a, b) => SOURCE_ORDER.indexOf(a) - SOURCE_ORDER.indexOf(b));
25
+
26
+ if (!sortedStreams.length) return null;
27
+
28
+ const allUrls = sortedStreams.map(quality => {
29
+ const streamUrl = streams[quality];
30
+ return {
31
+ url: streamUrl,
32
+ quality,
33
+ type: streamUrl.includes('.m3u8') ? 'hls' : 'mp4',
34
+ headers: {}
35
+ };
36
+ });
37
+
38
+ return { allUrls };
39
+ }
40
+ } catch (err) {
41
+ return null;
42
+ }
43
+ }
File without changes
@@ -76,13 +76,29 @@ export async function getStream(args) {
76
76
  const reqMatch = html.match(/window\.__REQUEST_TOKEN__\s*=\s*"([^"]+)"/);
77
77
  if (!reqMatch) return null;
78
78
  const requestToken = reqMatch[1];
79
- const initRes = await fetch(`${BASE_URL}/api/playback-init`, { method: "POST", headers: { "Content-Type": "application/json", ...PROXY_HEADERS, Referer: pageUrl }, body: JSON.stringify({ mediaId: Number(id), mediaType, requestToken }), signal: AbortSignal.timeout(10000) });
79
+ const cookies = pageRes.headers.getSetCookie();
80
+ const cookieHeader = cookies.map(c => c.split(';')[0]).join('; ');
81
+
82
+ const initHeaders = { "Content-Type": "application/json", ...PROXY_HEADERS, Referer: pageUrl };
83
+ if (cookieHeader) initHeaders.Cookie = cookieHeader;
84
+
85
+ const initRes = await fetch(`${BASE_URL}/api/playback-init`, {
86
+ method: "POST",
87
+ headers: initHeaders,
88
+ body: JSON.stringify({ mediaId: Number(id), mediaType, requestToken }),
89
+ signal: AbortSignal.timeout(10000)
90
+ });
80
91
  const initData = await initRes.json();
81
92
  let streamToken = initData.token;
82
93
  if (initData.requiresPow && initData.pow) {
83
94
  const powRes = solvePoW(initData.pow.challenge, initData.pow.difficulty);
84
95
  if (powRes.found) {
85
- const solveRes = await fetch(`${BASE_URL}/api/playback-init`, { method: "POST", headers: { "Content-Type": "application/json", ...PROXY_HEADERS, Referer: pageUrl }, body: JSON.stringify({ mediaId: Number(id), mediaType, requestToken, pow: { challengeId: initData.pow.challengeId, nonce: powRes.nonce } }), signal: AbortSignal.timeout(10000) });
96
+ const solveRes = await fetch(`${BASE_URL}/api/playback-init`, {
97
+ method: "POST",
98
+ headers: initHeaders,
99
+ body: JSON.stringify({ mediaId: Number(id), mediaType, requestToken, pow: { challengeId: initData.pow.challengeId, nonce: powRes.nonce } }),
100
+ signal: AbortSignal.timeout(10000)
101
+ });
86
102
  streamToken = (await solveRes.json()).token;
87
103
  }
88
104
  }
@@ -96,8 +112,28 @@ export async function getStream(args) {
96
112
  const allUrls = [];
97
113
  for (const srv of targets) {
98
114
  try {
99
- const streamUrl = `${BASE_URL}/api/stream?mediaId=${id}&mediaType=${mediaType}&tv_slug=${tvSlug}&source=${srv.id}&apikey=mptv_sk_a8f29c4e7b3d1f&requestToken=${requestToken}&token=${streamToken}`;
100
- const streamRes = await fetch(streamUrl, { headers: { ...PROXY_HEADERS, Referer: pageUrl }, signal: AbortSignal.timeout(8000) });
115
+ const encryptRes = await fetch(`${BASE_URL}/api/encrypt`, {
116
+ method: "POST",
117
+ headers: initHeaders,
118
+ body: JSON.stringify({
119
+ data: {
120
+ mediaId: Number(id),
121
+ mediaType,
122
+ tv_slug: tvSlug,
123
+ source: srv.id,
124
+ apikey: "mptv_sk_a8f29c4e7b3d1f"
125
+ }
126
+ }),
127
+ signal: AbortSignal.timeout(8000)
128
+ });
129
+ const encryptData = await encryptRes.json();
130
+ if (!encryptData.encrypted) continue;
131
+
132
+ const streamUrl = `${BASE_URL}/api/stream-encrypted?data=${encodeURIComponent(encryptData.encrypted)}&requestToken=${encodeURIComponent(requestToken)}&token=${encodeURIComponent(streamToken)}`;
133
+ const streamRes = await fetch(streamUrl, {
134
+ headers: { ...PROXY_HEADERS, Referer: pageUrl, ...(cookieHeader ? { Cookie: cookieHeader } : {}) },
135
+ signal: AbortSignal.timeout(8000)
136
+ });
101
137
  const streamData = await streamRes.json();
102
138
  if (streamData.success && streamData.data?.stream_url) {
103
139
  let fileUrl = streamData.data.stream_url;
@@ -13,15 +13,7 @@ const HEADERS = {
13
13
  };
14
14
 
15
15
  const SERVERS = [
16
- 'pseudo',
17
- 'lynx',
18
- 'tik',
19
- 'ipcloud',
20
- 'v4:English',
21
- 'turkce',
22
- 'v5:Hindi',
23
- 'v4:Hindi',
24
- 'v6:Hindi'
16
+ 'hindiv3'
25
17
  ];
26
18
 
27
19
  const TIMEOUT_MS = 15000;
@@ -0,0 +1,122 @@
1
+ import { USER_AGENT, fetchJson, getTmdbInfo } from '../utils/helpers.js';
2
+
3
+ const BASE_URL = 'https://providers.peestream.in';
4
+
5
+ export async function getStream(args) {
6
+ const { id, s, e, server, tmdbApiKey } = args;
7
+ const isTv = s != null && e != null;
8
+ const type = isTv ? 'tv' : 'movie';
9
+
10
+ let title = args.title || '';
11
+ let releaseYear = args.year || '';
12
+ let imdbId = args.imdbId || '';
13
+
14
+ if (!title) {
15
+ try {
16
+ const info = await getTmdbInfo(id, type, s, tmdbApiKey);
17
+ if (info) {
18
+ title = info.title || '';
19
+ if (info.year) releaseYear = info.year;
20
+ if (info.imdbId) imdbId = info.imdbId;
21
+ }
22
+ } catch { }
23
+ }
24
+
25
+ const queryParams = new URLSearchParams({
26
+ type,
27
+ tmdbId: String(id),
28
+ title: title || String(id)
29
+ });
30
+ if (releaseYear) queryParams.set('releaseYear', String(releaseYear));
31
+ if (imdbId) queryParams.set('imdbId', String(imdbId));
32
+ if (isTv) {
33
+ queryParams.set('season', String(s));
34
+ queryParams.set('episode', String(e));
35
+ }
36
+
37
+ const allUrls = [];
38
+
39
+ try {
40
+ const scrapeUrl = `${BASE_URL}/scrape?${queryParams.toString()}`;
41
+ const res = await fetch(scrapeUrl, {
42
+ headers: {
43
+ 'User-Agent': USER_AGENT,
44
+ 'Accept': 'text/event-stream',
45
+ 'Referer': `${BASE_URL}/`
46
+ },
47
+ signal: AbortSignal.timeout(15000)
48
+ });
49
+
50
+ if (res.ok) {
51
+ const text = await res.text();
52
+ const events = text.split('\n\n');
53
+ for (const ev of events) {
54
+ if (ev.includes('event: completed')) {
55
+ const dataMatch = ev.match(/data:\s*(.+)/);
56
+ if (dataMatch) {
57
+ try {
58
+ const parsed = JSON.parse(dataMatch[1].trim());
59
+ const stream = parsed.stream;
60
+ const streamUrl = stream?.playlist || stream?.url || stream?.file;
61
+ if (streamUrl) {
62
+ allUrls.push({
63
+ url: streamUrl,
64
+ server: `PeeStream - ${parsed.sourceId || 'Poseidon'}`,
65
+ quality: 'Auto',
66
+ type: stream.type === 'hls' || streamUrl.includes('.m3u8') ? 'hls' : 'mp4',
67
+ headers: stream.headers || {
68
+ 'User-Agent': USER_AGENT
69
+ }
70
+ });
71
+ }
72
+ } catch { }
73
+ }
74
+ }
75
+ }
76
+ }
77
+ } catch { }
78
+
79
+ if (!allUrls.length) {
80
+ try {
81
+ const searchUrl = `${BASE_URL}/api/search?q=${encodeURIComponent(title || id)}&type=${type}&tmdbId=${id}${isTv ? `&season=${s}&episode=${e}` : ''}`;
82
+ const data = await fetchJson(searchUrl, {
83
+ headers: {
84
+ 'User-Agent': USER_AGENT,
85
+ 'Accept': 'application/json',
86
+ 'Referer': `${BASE_URL}/`
87
+ },
88
+ signal: AbortSignal.timeout(10000)
89
+ });
90
+
91
+ if (data && Array.isArray(data.results)) {
92
+ for (const result of data.results) {
93
+ const pName = result.providerName || result.provider || 'PeeStream';
94
+ for (const stream of result.streams || []) {
95
+ if (!stream || !stream.url) continue;
96
+ allUrls.push({
97
+ url: stream.url,
98
+ server: `PeeStream - ${stream.name || pName}`,
99
+ quality: stream.quality || 'Auto',
100
+ type: stream.type === 'm3u8' || stream.url.includes('.m3u8') ? 'hls' : 'mp4',
101
+ headers: stream.headers || {
102
+ 'User-Agent': USER_AGENT
103
+ }
104
+ });
105
+ }
106
+ }
107
+ }
108
+ } catch { }
109
+ }
110
+
111
+ if (server && server !== 'all') {
112
+ const clean = server.toLowerCase().replace('peestream - ', '');
113
+ const filtered = allUrls.filter(u => u.server.toLowerCase().includes(clean));
114
+ if (filtered.length) return { allUrls: filtered };
115
+ }
116
+
117
+ return allUrls.length ? { allUrls } : null;
118
+ }
119
+
120
+ export async function getSources() {
121
+ return ['PeeStream - vaplayer'];
122
+ }
File without changes
File without changes
File without changes
File without changes
@@ -1,28 +1,24 @@
1
1
  import { getTmdbInfo, fetchJson, fetchText, USER_AGENT } from '../utils/helpers.js';
2
2
 
3
- const WINGS_BASE = "https://api.wingsdatabase.com";
3
+ const SPEEDRACE_BASE = "https://api.speedracelight.com";
4
4
  const HEADERS = { "Accept": "*/*", "Origin": "https://player.videasy.to", "Referer": "https://player.videasy.to/", "User-Agent": USER_AGENT };
5
5
  const SERVERS = [
6
- { id: 'jett', name: 'Jett' },
7
6
  { id: 'cdn', name: 'Yoru' },
8
- { id: 'tejo', name: 'Tejo' },
9
- { id: 'neon2', name: 'Neon' },
10
- { id: 'ym', name: 'Sage' },
11
- { id: 'downloader2', name: 'Cypher' },
12
7
  { id: 'm4uhd', name: 'Breach' },
8
+ { id: 'vsrc', name: 'Neon' },
13
9
  { id: 'hdmovie', name: 'Vyse' },
14
10
  { id: 'meine', name: 'Killjoy' },
15
11
  { id: 'lamovie', name: 'Omen' },
16
12
  { id: 'superflix', name: 'Raze' }
17
13
  ];
18
14
 
19
- export async function getStream({ id, s, e, server }) {
15
+ export async function getStream({ id, s, e, server, tmdbApiKey }) {
20
16
  try {
21
17
  const isTv = s != null && e != null;
22
- const info = await getTmdbInfo(id, isTv ? 'tv' : 'movie');
18
+ const info = await getTmdbInfo(tmdbApiKey, id, isTv ? 'tv' : 'movie');
23
19
  if (!info?.titles?.length) return null;
24
20
 
25
- const seedData = await fetchJson(`${WINGS_BASE}/seed?mediaId=${id}`, { headers: HEADERS, signal: AbortSignal.timeout(5000) });
21
+ const seedData = await fetchJson(`${SPEEDRACE_BASE}/seed?mediaId=${id}`, { headers: HEADERS, signal: AbortSignal.timeout(5000) });
26
22
  const seed = seedData?.seed;
27
23
  if (!seed) return null;
28
24
 
@@ -36,9 +32,7 @@ export async function getStream({ id, s, e, server }) {
36
32
  }
37
33
 
38
34
  const settled = await Promise.allSettled(targets.map(async srv => {
39
- if (srv.id === 'cdn' && isTv) throw new Error();
40
-
41
- let url = `${WINGS_BASE}/${srv.id}/sources-with-title?title=${encTitle}&mediaType=${isTv ? 'tv' : 'movie'}&year=${info.year || ''}&tmdbId=${id}&imdbId=${info.imdbId || "tt0000000"}&enc=2&seed=${seed}`;
35
+ let url = `${SPEEDRACE_BASE}/${srv.id}/sources-with-title?title=${encTitle}&mediaType=${isTv ? 'tv' : 'movie'}&year=${info.year || ''}&tmdbId=${id}&imdbId=${info.imdbId || "tt0000000"}&enc=2&seed=${seed}`;
42
36
  if (isTv) url += `&episodeId=${e}&seasonId=${s}`;
43
37
 
44
38
  const encText = await fetchText(url, { headers: HEADERS, signal: AbortSignal.timeout(10000) });
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -0,0 +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
+ }
114
+ }
@@ -1,70 +1,47 @@
1
- import { webcrypto } from 'node:crypto';
1
+ // i can't fix this, i'll wait for someone else to fix this lol
2
+
3
+ import crypto from 'node:crypto';
2
4
  import { fetchJson, USER_AGENT } from '../utils/helpers.js';
3
5
 
4
- const PLAYER_URL = 'https://player.vidzee.wtf';
5
6
  const CORE_URL = 'https://core.vidzee.wtf';
7
+ const PLAYER_URL = 'https://player.vidzee.wtf';
8
+ const KEY = 'c4a8f1d7e2b9a6c3d0f5e8a1b7c4d9e2';
6
9
 
7
- let cachedKey = null, cachedKeyTs = 0;
8
-
9
- async function getDecKey(headers) {
10
- const now = Date.now();
11
- if (cachedKey && now - cachedKeyTs < 300000) return cachedKey;
12
-
13
- const res = await fetch(`${CORE_URL}/api-key`, {
14
- headers,
15
- signal: AbortSignal.timeout(7000)
16
- });
17
- if (!res.ok) throw new Error(`API key fetch failed: ${res.status}`);
18
-
19
- const e = await res.text();
20
- const t = Buffer.from(e.replace(/\s+/g, ''), 'base64');
21
-
22
- const s = new Uint8Array(t.length - 28 + 16);
23
- s.set(t.subarray(28), 0);
24
- s.set(t.subarray(12, 28), t.length - 28);
25
-
26
- const keyMat = await webcrypto.subtle.digest('SHA-256', new TextEncoder().encode('c4a8f1d7e2b9a6c3d0f5e8a1b7c4d9e2'));
27
- const key = await webcrypto.subtle.importKey('raw', keyMat, { name: 'AES-GCM' }, false, ['decrypt']);
10
+ function decryptAes(encryptedBase64) {
11
+ const keyBuf = Buffer.from(KEY, 'utf8');
12
+ const ciphertext = Buffer.from(encryptedBase64, 'base64');
28
13
 
29
14
  try {
30
- const decrypted = await webcrypto.subtle.decrypt({
31
- name: 'AES-GCM',
32
- iv: t.subarray(0, 12),
33
- tagLength: 128
34
- }, key, s);
35
-
36
- cachedKey = new TextDecoder().decode(decrypted);
37
- cachedKeyTs = now;
38
- return cachedKey;
39
- } catch (err) {
40
- throw new Error('Failed to decrypt Vidzee master key');
41
- }
42
- }
15
+ const decipher = crypto.createDecipheriv('aes-256-ecb', keyBuf, null);
16
+ decipher.setAutoPadding(true);
17
+ let dec = decipher.update(ciphertext);
18
+ dec = Buffer.concat([dec, decipher.final()]);
19
+ const text = dec.toString('utf8');
20
+ if (text.startsWith('http') || text.includes('{')) return text;
21
+ } catch { }
43
22
 
44
- function decrypt(enc, key) {
45
23
  try {
46
- const dec = Buffer.from(enc, 'base64').toString('utf8');
47
- const sep = dec.indexOf(':');
48
- if (sep === -1) return '';
24
+ const iv = Buffer.alloc(16, 0);
25
+ const decipher = crypto.createDecipheriv('aes-256-cbc', keyBuf, iv);
26
+ decipher.setAutoPadding(true);
27
+ let dec = decipher.update(ciphertext);
28
+ dec = Buffer.concat([dec, decipher.final()]);
29
+ const text = dec.toString('utf8');
30
+ if (text.startsWith('http') || text.includes('{')) return text;
31
+ } catch { }
49
32
 
50
- const ivBase64 = dec.slice(0, sep);
51
- const ciphertext = dec.slice(sep + 1);
52
- const keyPadded = key.padEnd(32, '\0');
53
-
54
- const decrypted = CryptoJS.AES.decrypt(
55
- ciphertext,
56
- CryptoJS.enc.Utf8.parse(keyPadded),
57
- {
58
- iv: CryptoJS.enc.Base64.parse(ivBase64),
59
- mode: CryptoJS.mode.CBC,
60
- padding: CryptoJS.pad.Pkcs7
61
- }
62
- );
63
-
64
- return decrypted.toString(CryptoJS.enc.Utf8) || '';
65
- } catch (err) {
66
- return '';
67
- }
33
+ try {
34
+ const iv = ciphertext.subarray(0, 16);
35
+ const data = ciphertext.subarray(16);
36
+ const decipher = crypto.createDecipheriv('aes-256-cbc', keyBuf, iv);
37
+ decipher.setAutoPadding(true);
38
+ let dec = decipher.update(data);
39
+ dec = Buffer.concat([dec, decipher.final()]);
40
+ const text = dec.toString('utf8');
41
+ if (text.startsWith('http') || text.includes('{')) return text;
42
+ } catch { }
43
+
44
+ return null;
68
45
  }
69
46
 
70
47
  export async function getStream({ id, s, e, clientIP }) {
@@ -77,44 +54,53 @@ export async function getStream({ id, s, e, clientIP }) {
77
54
  };
78
55
 
79
56
  try {
80
- const decKey = await getDecKey(headers);
81
-
82
- const serversToTry = [3, 0, 1, 2, 4, 5, 6, 8];
57
+ const isTv = s != null && e != null;
58
+ const servers = ['tik', 'ipcloud', 'v6:Hindi'];
59
+ const results = [];
83
60
 
84
- for (const sr of serversToTry) {
61
+ for (const sr of servers) {
85
62
  try {
86
- const url = `${PLAYER_URL}/api/server?id=${id}&sr=${sr}${s ? `&ss=${s}&ep=${e || 1}` : ''}`;
87
- const data = await fetchJson(url, { headers, signal: AbortSignal.timeout(5000) });
88
-
89
- if (data?.url?.length) {
90
- for (const entry of data.url) {
91
- if (!entry.link) continue;
92
-
93
- const decrypted = decrypt(entry.link, decKey);
94
- if (decrypted?.startsWith('http')) {
63
+ const url = isTv
64
+ ? `${CORE_URL}/streams/tv/${id}/${s}/${e}?s=${encodeURIComponent(sr)}&e=${e}`
65
+ : `${CORE_URL}/streams/movie/${id}?s=${encodeURIComponent(sr)}&e=1`;
66
+
67
+ const data = await fetchJson(url, { headers, signal: AbortSignal.timeout(6000) });
68
+
69
+ if (data && data.c) {
70
+ const decryptedText = decryptAes(data.c);
71
+ if (decryptedText) {
72
+ let streamUrl = decryptedText;
73
+ let extraHeaders = {};
74
+
75
+ if (decryptedText.startsWith('{')) {
76
+ try {
77
+ const parsed = JSON.parse(decryptedText);
78
+ streamUrl = parsed.url || parsed.link || parsed.file;
79
+ if (parsed.headers) extraHeaders = parsed.headers;
80
+ } catch { }
81
+ }
95
82
 
96
- return {
97
- allUrls: [
98
- {
99
- url: decrypted,
100
- skipHlsCheck: true,
101
- headers: {
102
- 'User-Agent': USER_AGENT,
103
- 'Referer': PLAYER_URL,
104
- 'Origin': PLAYER_URL
105
- }
106
- }
107
- ]
108
- };
83
+ if (streamUrl && streamUrl.startsWith('http')) {
84
+ results.push({
85
+ url: streamUrl,
86
+ server: `VidZee - ${sr}`,
87
+ skipHlsCheck: true,
88
+ headers: {
89
+ 'User-Agent': USER_AGENT,
90
+ 'Referer': PLAYER_URL,
91
+ 'Origin': PLAYER_URL,
92
+ ...extraHeaders
93
+ }
94
+ });
109
95
  }
110
96
  }
111
97
  }
112
98
  } catch (err) {
113
- continue;
114
99
  }
115
100
  }
116
- return null;
117
- } catch (err) {
101
+
102
+ return results.length ? { allUrls: results } : null;
103
+ } catch {
118
104
  return null;
119
105
  }
120
106
  }