@vyla-entertainment/sdk 1.5.0 → 1.8.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.
@@ -0,0 +1,210 @@
1
+ import crypto from "crypto";
2
+
3
+ export const ID = "cinejoy";
4
+ export const DOMAIN = "https://cinejoy.to";
5
+ export const API_DOMAIN = "https://api.shegu.st";
6
+ export const ENC_DEC_API = "https://enc-dec.app/api";
7
+ export const RETURN_ALL_URLS = true;
8
+
9
+ const UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36";
10
+
11
+ function countLeadingZeroBits(buffer) {
12
+ let count = 0;
13
+ for (const value of buffer) {
14
+ if (value === 0) {
15
+ count += 8;
16
+ continue;
17
+ }
18
+ count += 8 - value.toString(2).length;
19
+ break;
20
+ }
21
+ return count;
22
+ }
23
+
24
+ function solveChallenge(data) {
25
+ const saltStr = `pow2-salt|${data.s}|${data.b}`;
26
+ const salt = crypto.createHash("sha256").update(saltStr).digest();
27
+ const n = data.n;
28
+ const r = data.r;
29
+ const p = data.p;
30
+ const d = data.d;
31
+ const b = data.b;
32
+ const s = data.s;
33
+
34
+ for (let counter = 0; counter < 1000000; counter++) {
35
+ const payload = `pow2|${b}|${s}|${counter}`;
36
+ const result = crypto.scryptSync(payload, salt, 32, {
37
+ N: n,
38
+ r: r,
39
+ p: p,
40
+ maxmem: 128 * n * r * 2
41
+ });
42
+
43
+ if (countLeadingZeroBits(result) >= d) {
44
+ const solved = { ...data, c: counter };
45
+ return Buffer.from(JSON.stringify(solved)).toString("base64");
46
+ }
47
+ }
48
+ throw new Error("Challenge solve failed");
49
+ }
50
+
51
+ async function getTmdbMetadata(tmdbId, isTv) {
52
+ const apiKey = process.env.TMDB_API_KEY;
53
+ if (!apiKey) return null;
54
+ const type = isTv ? "tv" : "movie";
55
+ try {
56
+ const url = `https://api.themoviedb.org/3/${type}/${tmdbId}?api_key=${apiKey}&append_to_response=external_ids`;
57
+ const res = await fetch(url, { signal: AbortSignal.timeout(10000) });
58
+ if (!res.ok) return null;
59
+ const data = await res.json();
60
+ const title = isTv ? data.name : data.title;
61
+ const year = isTv ? (data.first_air_date ? data.first_air_date.split("-")[0] : "") : (data.release_date ? data.release_date.split("-")[0] : "");
62
+ const imdbId = data.external_ids?.imdb_id || "";
63
+ return { title, year, imdbId };
64
+ } catch (err) {
65
+ return null;
66
+ }
67
+ }
68
+
69
+ export async function getStream({ id, s, e, clientIP }) {
70
+ try {
71
+ const isTv = s && e && s !== "null" && e !== "null";
72
+ const meta = await getTmdbMetadata(id, isTv);
73
+ if (!meta) return null;
74
+
75
+ let servers = [];
76
+ try {
77
+ const serverRes = await fetch(`${API_DOMAIN}/servers`, {
78
+ headers: {
79
+ "Origin": DOMAIN,
80
+ "Referer": DOMAIN + "/",
81
+ "User-Agent": UA
82
+ },
83
+ signal: AbortSignal.timeout(15000)
84
+ });
85
+ if (serverRes.ok) {
86
+ const data = await serverRes.json();
87
+ servers = data.servers || [];
88
+ }
89
+ } catch (err) { }
90
+
91
+ const activeServers = servers
92
+ .filter(srv => srv.status === "ok" && srv.name)
93
+ .map(srv => srv.name);
94
+
95
+ if (activeServers.length === 0) return null;
96
+
97
+ const allUrls = [];
98
+
99
+ for (const serverName of activeServers) {
100
+ try {
101
+ const queryParts = [
102
+ `title=${encodeURIComponent(meta.title)}`,
103
+ `type=${isTv ? "series" : "movie"}`,
104
+ `year=${meta.year}`,
105
+ `imdb=${meta.imdbId}`,
106
+ `tmdb=${id}`,
107
+ `server=${serverName}`
108
+ ];
109
+ if (isTv) {
110
+ queryParts.push(`season=${s}`, `episode=${e}`);
111
+ }
112
+
113
+ const plainUrl = `${API_DOMAIN}/?${queryParts.join("&")}`;
114
+
115
+ const encRes = await fetch(`${ENC_DEC_API}/enc-cinejoy?url=${encodeURIComponent(plainUrl)}`, {
116
+ headers: { "User-Agent": UA },
117
+ signal: AbortSignal.timeout(15000)
118
+ });
119
+ if (!encRes.ok) continue;
120
+ const encData = await encRes.json();
121
+ if (encData.status !== 200) continue;
122
+
123
+ const rid = encData.result;
124
+
125
+ const challengeRes = await fetch(`${API_DOMAIN}/challenge?rid=${rid}`, {
126
+ headers: {
127
+ "Origin": DOMAIN,
128
+ "Referer": DOMAIN + "/",
129
+ "User-Agent": UA
130
+ },
131
+ signal: AbortSignal.timeout(30000)
132
+ });
133
+ if (!challengeRes.ok) continue;
134
+
135
+ const challengeData = await challengeRes.json();
136
+
137
+ const solved = solveChallenge(challengeData);
138
+
139
+ const streamRes = await fetch(`${API_DOMAIN}/${rid}`, {
140
+ headers: {
141
+ "Origin": DOMAIN,
142
+ "Referer": DOMAIN + "/",
143
+ "User-Agent": UA,
144
+ "X-At": solved
145
+ },
146
+ signal: AbortSignal.timeout(30000)
147
+ });
148
+
149
+ if (!streamRes.ok) continue;
150
+
151
+ const encryptedText = await streamRes.text();
152
+
153
+ const decRes = await fetch(`${ENC_DEC_API}/dec-cinejoy`, {
154
+ method: "POST",
155
+ headers: {
156
+ "Content-Type": "application/json",
157
+ "User-Agent": UA
158
+ },
159
+ body: JSON.stringify({ text: encryptedText }),
160
+ signal: AbortSignal.timeout(15000)
161
+ });
162
+ if (!decRes.ok) continue;
163
+ const decData = await decRes.json();
164
+ if (decData.status !== 200) continue;
165
+
166
+ let decryptedText = decData.result;
167
+
168
+ if (!decryptedText) continue;
169
+
170
+ if (typeof decryptedText === "string") {
171
+ try {
172
+ decryptedText = JSON.parse(decryptedText);
173
+ } catch (e) { }
174
+ }
175
+
176
+ let streamUrl = "";
177
+ if (decryptedText && typeof decryptedText === "object") {
178
+ if (decryptedText.stream && decryptedText.stream[0]) {
179
+ streamUrl = decryptedText.stream[0].playlist || decryptedText.stream[0].url || "";
180
+ } else {
181
+ streamUrl = decryptedText.url || decryptedText.playlist || decryptedText.file || "";
182
+ }
183
+ } else if (typeof decryptedText === "string") {
184
+ streamUrl = decryptedText.trim();
185
+ }
186
+
187
+ if (streamUrl.startsWith("http")) {
188
+ allUrls.push({
189
+ url: streamUrl,
190
+ headers: {
191
+ "User-Agent": UA,
192
+ "Referer": DOMAIN + "/",
193
+ "Origin": DOMAIN
194
+ },
195
+ server: serverName,
196
+ quality: "Auto",
197
+ type: "hls",
198
+ skipVerify: true,
199
+ skipProxy: true
200
+ });
201
+ }
202
+ } catch (err) { }
203
+ }
204
+
205
+ if (allUrls.length > 0) {
206
+ return { ...allUrls[0], allUrls };
207
+ }
208
+ } catch (err) { }
209
+ return null;
210
+ }
@@ -1,14 +1,26 @@
1
1
  import { fetchJson } from '../utils/helpers.js';
2
2
 
3
- const API_BASE = 'https://itjiocunahckqxcnzpoy.supabase.co/functions/v1';
4
- const APIKEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Iml0amlvY3VuYWhja3F4Y256cG95Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3NzczMzM1MjQsImV4cCI6MjA5MjkwOTUyNH0.9x9ykdHAzrv_GSvnawPeQaOxQeh3sZg0QAh4u9VOF4M';
5
- const HEADERS = { 'apikey': APIKEY, 'authorization': `Bearer ${APIKEY}`, 'content-type': 'application/json', 'origin': 'https://flaxmovies.xyz', 'referer': 'https://flaxmovies.xyz/' };
6
-
7
3
  export async function getStream({ id, s, e }) {
8
4
  try {
9
- const isMovie = !s;
10
- const data = await fetchJson(isMovie ? `${API_BASE}/get-movie` : `${API_BASE}/get-tv`, { method: 'POST', headers: HEADERS, body: JSON.stringify(isMovie ? { id: String(id) } : { id: String(id), season: Number(s), episode: Number(e) }), signal: AbortSignal.timeout(15000) });
11
- if (!data?.signed_url) return null;
12
- return { allUrls: [{ url: data.signed_url, headers: { 'Referer': 'https://flaxmovies.xyz/', 'Origin': 'https://flaxmovies.xyz' } }] };
13
- } catch { return null; }
5
+ const url = s && e
6
+ ? `https://sparkling-mode-a1ed.fillatame.workers.dev/?tmdb_id=${id}&season=${s}&episode=${e}`
7
+ : `https://sparkling-mode-a1ed.fillatame.workers.dev/?tmdb_id=${id}`;
8
+ const data = await fetchJson(url, { signal: AbortSignal.timeout(15000) });
9
+ if (!data || !Array.isArray(data.streams)) return null;
10
+ const allUrls = [];
11
+ for (const stream of data.streams) {
12
+ const streamUrl = stream.url || stream.link;
13
+ if (!streamUrl) continue;
14
+ const isHls = stream.format === 'HLS' || stream.isM3U8 === true || streamUrl.includes('m3u8');
15
+ allUrls.push({
16
+ url: streamUrl,
17
+ server: stream.provider || 'FlaxMovies',
18
+ quality: stream.resolution || 'Auto',
19
+ type: isHls ? 'hls' : 'mp4'
20
+ });
21
+ }
22
+ return allUrls.length ? { allUrls } : null;
23
+ } catch {
24
+ return null;
25
+ }
14
26
  }
@@ -4,10 +4,10 @@ const BASE_URL = 'https://www.fsonic.net';
4
4
  const FSHARE_BASE = 'https://fsharetv.co';
5
5
  const HEADERS = { 'User-Agent': USER_AGENT, 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'Accept-Language': 'en-US,en;q=0.9' };
6
6
 
7
- export async function getStream({ id, s }) {
7
+ export async function getStream({ id, s, tmdbApiKey }) {
8
8
  if (s != null) return null;
9
9
  try {
10
- const info = await getTmdbInfo(id, 'movie');
10
+ const info = await getTmdbInfo(tmdbApiKey, id, 'movie');
11
11
  if (!info?.titles?.length) return null;
12
12
  let watchSlug = null;
13
13
  for (const title of info.titles) {
@@ -4,10 +4,10 @@ const ORIGIN = 'https://www3.fsonline.app';
4
4
  const AJAX_URL = `${ORIGIN}/wp-admin/admin-ajax.php`;
5
5
  const HEADERS = { 'User-Agent': USER_AGENT, 'Origin': ORIGIN, 'Referer': `${ORIGIN}/` };
6
6
 
7
- export async function getStream({ id, s, e }) {
7
+ export async function getStream({ id, s, e, tmdbApiKey }) {
8
8
  try {
9
9
  const isTv = s != null && e != null;
10
- const info = await getTmdbInfo(id, isTv ? 'tv' : 'movie');
10
+ const info = await getTmdbInfo(tmdbApiKey, id, isTv ? 'tv' : 'movie');
11
11
  if (!info?.titles?.length) return null;
12
12
  const searchHtml = await fetchText(`${ORIGIN}/?s=${encodeURIComponent(info.titles[0] + (info.year ? ' ' + info.year : ''))}`, { headers: HEADERS });
13
13
  const typeFolder = isTv ? 'seriale' : 'film';
@@ -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
+ }
@@ -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) });
@@ -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
  }