@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,212 @@
1
+ import { USER_AGENT } from '../utils/helpers.js';
2
+
3
+ const _sInit = [23, 27, 30, 31, 86, 28, 19, 86, 9, 18, 19, 21, 26, 27, 86, 120, 114, 120, 116, 86, 9, 18, 19, 21, 26, 27, 122, 89, 25, 23];
4
+ const _vParam = `_v=${(_sInit[15] ^ 0x5a)}${(_sInit[16] ^ 0x5a)}${(_sInit[17] ^ 0x5a)}${(_sInit[18] ^ 0x5a)}`;
5
+
6
+ const nD = '4860ac8bfddb';
7
+ const aD = '224eff10e662e9635c9f671cf46351dcd69af42b1edd56f5e5fa21751f44b9c8';
8
+ const Ls = [17, 91, 203, 44, 8, 177, 62, 239, 119, 3, 154, 81, 28, 210, 101, 7];
9
+ const wa = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
10
+
11
+ const SERVERS = [
12
+ { id: 'NIGHT', endpoint: '/server/night' },
13
+ { id: 'EMP', endpoint: '/server/emp' },
14
+ { id: 'MAIN', endpoint: '/server/vidsrc' }
15
+ ];
16
+
17
+ let cachedToken = null;
18
+ let tokenExpiry = 0;
19
+
20
+ function ab(e) {
21
+ let t = e >>> 0;
22
+ t ^= t >>> 16;
23
+ t = Math.imul(t, 2146121005) >>> 0;
24
+ t ^= t >>> 15;
25
+ t = Math.imul(t, 2221713035) >>> 0;
26
+ return (t ^ (t >>> 16)) >>> 0;
27
+ }
28
+
29
+ function sD(e) {
30
+ const t = new TextEncoder().encode(aD);
31
+ const r = Math.max(32, Math.min(128, e + 17));
32
+ const n = new Uint8Array(r);
33
+ let a = 2166136261;
34
+ for (let s = 0; s < r; s += 1) {
35
+ a ^= t[s % t.length] ?? s;
36
+ a = ab((a + Ls[s % Ls.length] + ((2654435761 * s) >>> 0)) >>> 0);
37
+ n[s] = a & 255;
38
+ }
39
+ return n;
40
+ }
41
+
42
+ function iD(e) {
43
+ let t = '';
44
+ for (let r = 0; r < e.length; r += 3) {
45
+ const n = e[r];
46
+ const a = e[r + 1];
47
+ const s = e[r + 2];
48
+ t += wa[n >>> 2];
49
+ t += wa[((3 & n) << 4) | ((a ?? 0) >>> 4)];
50
+ if (a === undefined) break;
51
+ t += wa[((15 & a) << 2) | ((s ?? 0) >>> 6)];
52
+ if (s === undefined) break;
53
+ t += wa[63 & s];
54
+ }
55
+ return t;
56
+ }
57
+
58
+ function generateCinesrcDirectHlsUrl(id, s, e) {
59
+ const isTv = s != null && e != null;
60
+ const tmdbId = Math.floor(Number(id));
61
+ const season = isTv ? Math.floor(Number(s || 1)) : 0;
62
+ const episode = isTv ? Math.floor(Number(e || 1)) : 0;
63
+
64
+ const str = `${nD}:${isTv ? 's' : 'm'}:${tmdbId}:${season}:${episode}`;
65
+ const a = new TextEncoder().encode(str);
66
+ const sArr = sD(a.length);
67
+ const i = new Uint8Array(a.length + 2);
68
+ i[0] = a.length & 255;
69
+ i[1] = (a.length >>> 8) & 255;
70
+ let o = (2654435769 ^ a.length) >>> 0;
71
+ for (let l = 0; l < a.length; l += 1) {
72
+ o = ab((o + sArr[l % sArr.length] + Ls[l % Ls.length] + l) >>> 0);
73
+ i[l + 2] = (a[l] ^ (255 & o)) ^ sArr[(7 * l + 3) % sArr.length];
74
+ }
75
+
76
+ return `https://glendale-plumbing.com/c/v1/${iD(i)}/master.m3u8`;
77
+ }
78
+
79
+ async function fetchBright67Subtitles(id, season, episode) {
80
+ let url = `https://subs.bright67.online/search?id=${id}`;
81
+ if (season != null && episode != null) {
82
+ url += `&season=${season}&episode=${episode}`;
83
+ }
84
+
85
+ try {
86
+ const res = await fetch(url, {
87
+ headers: {
88
+ 'User-Agent': USER_AGENT,
89
+ 'Referer': 'https://cinesrc.st/'
90
+ },
91
+ signal: AbortSignal.timeout(4000)
92
+ });
93
+
94
+ if (!res.ok) return [];
95
+ const data = await res.json();
96
+ if (!Array.isArray(data)) return [];
97
+
98
+ return data.slice(0, 15).map(s => ({
99
+ label: s.display || s.languageName || s.language || 'English',
100
+ language: s.language || 'en',
101
+ file: s.url || s.r2Url,
102
+ type: (s.url || s.r2Url || '').endsWith('.vtt') ? 'vtt' : 'srt'
103
+ }));
104
+ } catch {
105
+ return [];
106
+ }
107
+ }
108
+
109
+ async function fetchInternalToken() {
110
+ if (cachedToken && Date.now() < tokenExpiry) return cachedToken;
111
+ try {
112
+ const res = await fetch('https://1embed.cc/api/token', {
113
+ headers: {
114
+ 'User-Agent': USER_AGENT,
115
+ 'Referer': 'https://1embed.cc/',
116
+ 'Accept': 'application/json, text/plain, */*'
117
+ },
118
+ signal: AbortSignal.timeout(4000)
119
+ });
120
+ if (res.ok) {
121
+ const data = await res.json();
122
+ if (data?.token) {
123
+ cachedToken = data.token;
124
+ tokenExpiry = Date.now() + 1800 * 1000;
125
+ return cachedToken;
126
+ }
127
+ }
128
+ } catch { }
129
+
130
+ return '';
131
+ }
132
+
133
+ export async function getStream(args) {
134
+ const { id, s, e, clientIP } = args;
135
+ const isTv = s != null && e != null;
136
+ const isMovie = !isTv;
137
+ const allUrls = [];
138
+
139
+ const [subtitles, directHlsUrl] = await Promise.all([
140
+ fetchBright67Subtitles(id, isMovie ? undefined : s, isMovie ? undefined : e),
141
+ Promise.resolve(generateCinesrcDirectHlsUrl(id, s, e))
142
+ ]);
143
+
144
+ const masterUrlWithMark = `${directHlsUrl}?${_vParam}`;
145
+
146
+ allUrls.push({
147
+ url: masterUrlWithMark,
148
+ server: 'CineSrc (Direct Master)',
149
+ quality: 'Auto',
150
+ type: 'hls',
151
+ headers: {
152
+ 'User-Agent': USER_AGENT,
153
+ 'Referer': 'https://cinesrc.st/',
154
+ 'Origin': 'https://cinesrc.st',
155
+ ...(clientIP && { 'X-Forwarded-For': clientIP })
156
+ },
157
+ subtitles: subtitles.length ? subtitles : undefined
158
+ });
159
+
160
+ const token = await fetchInternalToken();
161
+
162
+ await Promise.allSettled(
163
+ SERVERS.map(async (server) => {
164
+ const query = isTv
165
+ ? `id=${id}?type=tv&s=${s || 1}&e=${e || 1}`
166
+ : `id=${id}?type=movie`;
167
+
168
+ const stParam = token ? `&_st=${token}` : '';
169
+ const targetUrl = `https://1embed.cc${server.endpoint}/${query}${stParam}`;
170
+
171
+ const headers = {
172
+ 'User-Agent': USER_AGENT,
173
+ 'Referer': 'https://cinesrc.st/',
174
+ 'Accept': 'application/json, text/plain, */*',
175
+ ...(token && { 'X-Stream-Token': token }),
176
+ ...(clientIP && { 'X-Forwarded-For': clientIP })
177
+ };
178
+
179
+ const res = await fetch(targetUrl, { headers, signal: AbortSignal.timeout(5000) }).catch(() => null);
180
+
181
+ if (res && res.ok) {
182
+ try {
183
+ const data = await res.json();
184
+ if (data && data.success !== false) {
185
+ const streamUrl = data.streams?.proxy_m3u8 || data.streams?.raw_m3u8 || data.streams?.m3u8 || data.streamUrl;
186
+ if (streamUrl && typeof streamUrl === 'string') {
187
+ const urlWithMark = streamUrl.includes('?') ? `${streamUrl}&${_vParam}` : `${streamUrl}?${_vParam}`;
188
+ allUrls.push({
189
+ url: urlWithMark,
190
+ server: `CineSrc (${data.selectedSource || data.provider || server.id})`,
191
+ quality: 'Auto',
192
+ type: streamUrl.includes('.m3u8') ? 'hls' : 'mp4',
193
+ headers: {
194
+ 'User-Agent': USER_AGENT,
195
+ 'Referer': 'https://cinesrc.st/',
196
+ 'Origin': 'https://cinesrc.st'
197
+ },
198
+ subtitles: subtitles.length ? subtitles : undefined
199
+ });
200
+ }
201
+ }
202
+ } catch { }
203
+ }
204
+ })
205
+ );
206
+
207
+ return allUrls.length ? { allUrls } : null;
208
+ }
209
+
210
+ export async function getSources() {
211
+ return ['CineSrc (Direct Master)', 'CineSrc (NIGHT)', 'CineSrc (EMP)', 'CineSrc (MAIN)'];
212
+ }
@@ -1,94 +1,148 @@
1
- import { USER_AGENT } from '../utils/helpers.js';
2
-
3
- const lS = [17, 91, 203, 44, 8, 177, 62, 239, 119, 3, 154, 81, 28, 210, 101, 7];
4
-
5
- function lA(e) {
6
- let t = e >>> 0;
7
- t ^= t >>> 16;
8
- t = Math.imul(t, 0x7feb352d) >>> 0;
9
- t ^= t >>> 15;
10
- t = Math.imul(t, 0x846ca68b) >>> 0;
11
- return (t ^ (t >>> 16)) >>> 0;
12
- }
13
-
14
- function lL(keyStr, targetLen) {
15
- const encoder = new TextEncoder();
16
- const i = encoder.encode(keyStr || "dev");
17
- const rLen = Math.max(32, Math.min(128, targetLen + 17));
18
- const r = new Uint8Array(rLen);
19
- let s = 0x811c9dc5;
20
- for (let e = 0; e < rLen; e += 1) {
21
- const a = i[e % i.length] ?? e;
22
- s ^= a;
23
- s = lA((s + lS[e % lS.length] + ((0x9e3779b1 * e) >>> 0)) >>> 0);
24
- r[e] = s & 255;
25
- }
26
- return r;
27
- }
28
-
29
- function base64UrlEncode(bytes) {
30
- const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
31
- let i = "";
32
- for (let r = 0; r < bytes.length; r += 3) {
33
- const s = bytes[r];
34
- const a = bytes[r + 1];
35
- const n = bytes[r + 2];
36
- i += chars[s >>> 2];
37
- i += chars[((3 & s) << 4) | ((a ?? 0) >>> 4)];
38
- if (a === undefined) break;
39
- i += chars[((15 & a) << 2) | ((n ?? 0) >>> 6)];
40
- if (n === undefined) break;
41
- i += chars[63 & n];
42
- }
43
- return i;
44
- }
45
-
46
- export function generateCineSuUrl(type, tmdbId, season = 1, episode = 1) {
47
- const kind = type === "show" || type === "tv" ? "show" : "movie";
48
- const s = kind === "show" ? Math.max(1, Math.floor(season)) : 0;
49
- const ep = kind === "show" ? Math.max(1, Math.floor(episode)) : 0;
50
- const char = kind[0];
51
-
52
- const payloadStr = `4860ac8bfddb:${char}:${Math.floor(Number(tmdbId))}:${s}:${ep}`;
53
- const encoder = new TextEncoder();
54
- const d = encoder.encode(payloadStr);
55
-
56
- const key = "224eff10e662e9635c9f671cf46351dcd69af42b1edd56f5e5fa21751f44b9c8";
57
- const u = lL(key, d.length);
58
-
59
- const h = new Uint8Array(d.length + 2);
60
- h[0] = 255 & d.length;
61
- h[1] = (d.length >>> 8) & 255;
62
-
63
- let c = (0x9e3779b9 ^ d.length) >>> 0;
64
- for (let e = 0; e < d.length; e += 1) {
65
- c = lA((c + u[e % u.length] + lS[e % lS.length] + e) >>> 0);
66
- h[e + 2] = d[e] ^ (255 & c) ^ u[(7 * e + 3) % u.length];
67
- }
68
-
69
- const token = base64UrlEncode(h);
70
- return `https://glendale-plumbing.com/c/v1/${token}/master.m3u8`;
71
- }
72
-
73
- export async function getStream({ id, s, e }) {
74
- try {
75
- const isTv = !!s;
76
- const mediaType = isTv ? 'tv' : 'movie';
77
- const m3u8Url = generateCineSuUrl(mediaType, id, s || 1, e || 1);
78
-
79
- return {
80
- allUrls: [
81
- {
82
- url: m3u8Url,
83
- server: 'CineSu',
84
- }
85
- ]
86
- };
87
- } catch (err) {
88
- return null;
89
- }
90
- }
91
-
92
- export async function getSources() {
93
- return ['CineSu'];
1
+ import { USER_AGENT } from '../utils/helpers.js';
2
+
3
+ const BASE_DOMAIN = 'https://glendale-plumbing.com';
4
+ const REFERER = 'https://cine.su/';
5
+
6
+ const nD = '4860ac8bfddb';
7
+ const aD = '224eff10e662e9635c9f671cf46351dcd69af42b1edd56f5e5fa21751f44b9c8';
8
+ const Ls = [17, 91, 203, 44, 8, 177, 62, 239, 119, 3, 154, 81, 28, 210, 101, 7];
9
+ const wa = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
10
+
11
+ function ab(e) {
12
+ let t = e >>> 0;
13
+ t ^= t >>> 16;
14
+ t = Math.imul(t, 2146121005) >>> 0;
15
+ t ^= t >>> 15;
16
+ t = Math.imul(t, 2221713035) >>> 0;
17
+ return (t ^ (t >>> 16)) >>> 0;
18
+ }
19
+
20
+ function sD(e) {
21
+ const t = new TextEncoder().encode(aD);
22
+ const r = Math.max(32, Math.min(128, e + 17));
23
+ const n = new Uint8Array(r);
24
+ let a = 2166136261;
25
+ for (let s = 0; s < r; s += 1) {
26
+ a ^= t[s % t.length] ?? s;
27
+ a = ab((a + Ls[s % Ls.length] + ((2654435761 * s) >>> 0)) >>> 0);
28
+ n[s] = a & 255;
29
+ }
30
+ return n;
31
+ }
32
+
33
+ function iD(e) {
34
+ let t = '';
35
+ for (let r = 0; r < e.length; r += 3) {
36
+ const n = e[r];
37
+ const a = e[r + 1];
38
+ const s = e[r + 2];
39
+ t += wa[n >>> 2];
40
+ t += wa[((3 & n) << 4) | ((a ?? 0) >>> 4)];
41
+ if (a === undefined) break;
42
+ t += wa[((15 & a) << 2) | ((s ?? 0) >>> 6)];
43
+ if (s === undefined) break;
44
+ t += wa[63 & s];
45
+ }
46
+ return t;
47
+ }
48
+
49
+ function generateMasterUrl(id, s, e) {
50
+ const isTv = s != null && e != null;
51
+ const tmdbId = Math.floor(Number(id));
52
+ const season = isTv ? Math.floor(Number(s || 1)) : 0;
53
+ const episode = isTv ? Math.floor(Number(e || 1)) : 0;
54
+
55
+ const str = `${nD}:${isTv ? 's' : 'm'}:${tmdbId}:${season}:${episode}`;
56
+ const a = new TextEncoder().encode(str);
57
+ const sArr = sD(a.length);
58
+ const i = new Uint8Array(a.length + 2);
59
+ i[0] = a.length & 255;
60
+ i[1] = (a.length >>> 8) & 255;
61
+ let o = (2654435769 ^ a.length) >>> 0;
62
+ for (let l = 0; l < a.length; l += 1) {
63
+ o = ab((o + sArr[l % sArr.length] + Ls[l % Ls.length] + l) >>> 0);
64
+ i[l + 2] = (a[l] ^ (255 & o)) ^ sArr[(7 * l + 3) % sArr.length];
65
+ }
66
+
67
+ return `${BASE_DOMAIN}/c/v1/${iD(i)}/master.m3u8`;
68
+ }
69
+
70
+ function parsePlaylist(m3u8Text) {
71
+ const qualities = [];
72
+ const subtitles = [];
73
+
74
+ const subRegex = /#EXT-X-MEDIA:TYPE=SUBTITLES,[^\n]*NAME="([^"]*)"[^\n]*LANGUAGE="([^"]*)"[^\n]*URI="([^"]*)"/g;
75
+ let match;
76
+ while ((match = subRegex.exec(m3u8Text)) !== null) {
77
+ let uri = match[3];
78
+ if (uri.startsWith('/')) uri = `${BASE_DOMAIN}${uri}`;
79
+ subtitles.push({ label: match[1], language: match[2], file: uri, type: 'vtt' });
80
+ }
81
+
82
+ const streamRegex = /#EXT-X-STREAM-INF:[^\n]*RESOLUTION=\d+x(\d+)[^\n]*\r?\n([^\n#][^\n]*)/g;
83
+ while ((match = streamRegex.exec(m3u8Text)) !== null) {
84
+ let streamPath = match[2].trim();
85
+ if (streamPath.startsWith('/')) streamPath = `${BASE_DOMAIN}${streamPath}`;
86
+ qualities.push({ quality: `${match[1]}p`, url: streamPath });
87
+ }
88
+
89
+ return { qualities, subtitles };
90
+ }
91
+
92
+ export async function getStream(args) {
93
+ const { id, s, e, clientIP } = args;
94
+ const rawMasterUrl = generateMasterUrl(id, s, e);
95
+
96
+ const headers = {
97
+ 'User-Agent': USER_AGENT,
98
+ 'Referer': REFERER,
99
+ 'Origin': 'https://cine.su',
100
+ ...(clientIP && { 'X-Forwarded-For': clientIP })
101
+ };
102
+
103
+ try {
104
+ const res = await fetch(rawMasterUrl, {
105
+ headers,
106
+ signal: AbortSignal.timeout(5000)
107
+ });
108
+
109
+ if (res.ok) {
110
+ const text = await res.text();
111
+ const { qualities, subtitles } = parsePlaylist(text);
112
+
113
+ if (qualities.length) {
114
+ const allUrls = [{
115
+ url: rawMasterUrl,
116
+ server: 'CineSu (Auto)',
117
+ quality: 'Auto',
118
+ type: 'hls',
119
+ headers,
120
+ subtitles: subtitles.length ? subtitles : undefined
121
+ }];
122
+
123
+ for (const q of qualities) {
124
+ allUrls.push({
125
+ url: q.url,
126
+ server: `CineSu (${q.quality})`,
127
+ quality: q.quality,
128
+ type: 'hls',
129
+ headers,
130
+ subtitles: subtitles.length ? subtitles : undefined
131
+ });
132
+ }
133
+
134
+ return { allUrls };
135
+ }
136
+ }
137
+ } catch { }
138
+
139
+ return {
140
+ allUrls: [{
141
+ url: rawMasterUrl,
142
+ server: 'CineSu',
143
+ quality: 'Auto',
144
+ type: 'hls',
145
+ headers
146
+ }]
147
+ };
94
148
  }
@@ -1,26 +1,118 @@
1
- import { fetchJson } from '../utils/helpers.js';
1
+ import { USER_AGENT, fetchJson } from '../utils/helpers.js';
2
2
 
3
- export async function getStream({ id, s, e }) {
3
+ const BASE_URL = 'https://flaxmovies.xyz';
4
+
5
+ async function getWorkerUrls(embedUrl) {
6
+ const foundUrls = [];
4
7
  try {
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
- });
8
+ const res = await fetch(embedUrl, {
9
+ headers: {
10
+ 'User-Agent': USER_AGENT,
11
+ 'Referer': `${BASE_URL}/`,
12
+ 'Origin': BASE_URL
13
+ },
14
+ signal: AbortSignal.timeout(8000)
15
+ });
16
+ if (res.ok) {
17
+ const html = await res.text();
18
+ const directMatch = html.match(/WORKER_URL\s*[:=]\s*["'](https?:\/\/[^"']+)["']/i);
19
+ if (directMatch && directMatch[1]) {
20
+ foundUrls.push(directMatch[1].replace(/\/+$/, ''));
21
+ }
22
+
23
+ const scriptMatches = [...html.matchAll(/<script[^>]+src=["']([^"']+)["']/gi)];
24
+ for (const sm of scriptMatches) {
25
+ let scriptUrl = sm[1];
26
+ if (scriptUrl.startsWith('//')) scriptUrl = `https:${scriptUrl}`;
27
+ else if (scriptUrl.startsWith('/')) scriptUrl = `${BASE_URL}${scriptUrl}`;
28
+ else if (!scriptUrl.startsWith('http')) scriptUrl = `${BASE_URL}/${scriptUrl}`;
29
+
30
+ if (scriptUrl.includes('jsdelivr') || scriptUrl.includes('google') || scriptUrl.includes('cloudflare')) continue;
31
+
32
+ try {
33
+ const sRes = await fetch(scriptUrl, {
34
+ headers: { 'User-Agent': USER_AGENT, 'Referer': embedUrl },
35
+ signal: AbortSignal.timeout(6000)
36
+ });
37
+ if (sRes.ok) {
38
+ const sCode = await sRes.text();
39
+ const m = sCode.match(/WORKER_URL\s*[:=]\s*["'](https?:\/\/[^"']+)["']/i);
40
+ if (m && m[1]) {
41
+ const wUrl = m[1].replace(/\/+$/, '');
42
+ if (!foundUrls.includes(wUrl)) foundUrls.push(wUrl);
43
+ }
44
+ }
45
+ } catch { }
46
+ }
21
47
  }
22
- return allUrls.length ? { allUrls } : null;
23
- } catch {
24
- return null;
48
+ } catch { }
49
+
50
+ const defaults = ['https://freakyniki.elaxo.lol', 'https://vidlove.nabilekson.workers.dev'];
51
+ for (const d of defaults) {
52
+ if (!foundUrls.includes(d)) foundUrls.push(d);
53
+ }
54
+ return foundUrls;
55
+ }
56
+
57
+ export async function getStream(args) {
58
+ const { id, s, e, server } = args;
59
+ const isTv = s != null && e != null;
60
+ const embedUrl = isTv
61
+ ? `${BASE_URL}/embed/tv/${id}/${s}/${e}`
62
+ : `${BASE_URL}/embed/movie/${id}`;
63
+
64
+ const workerUrls = await getWorkerUrls(embedUrl);
65
+ const query = isTv
66
+ ? `tmdb_id=${id}&tmdbId=${id}&season=${s}&episode=${e}`
67
+ : `tmdb_id=${id}&tmdbId=${id}`;
68
+
69
+ for (const worker of workerUrls) {
70
+ try {
71
+ const url = `${worker}/?${query}`;
72
+ const data = await fetchJson(url, {
73
+ headers: {
74
+ 'User-Agent': USER_AGENT,
75
+ 'Referer': `${BASE_URL}/`,
76
+ 'Origin': BASE_URL,
77
+ 'Accept': 'application/json, text/plain, */*'
78
+ },
79
+ signal: AbortSignal.timeout(12000)
80
+ });
81
+
82
+ if (data && Array.isArray(data.streams) && data.streams.length > 0) {
83
+ let allUrls = data.streams
84
+ .filter(st => st && typeof st.url === 'string')
85
+ .map(st => {
86
+ const isHls = (st.format || '').toLowerCase().includes('hls') || st.url.includes('.m3u8');
87
+ return {
88
+ url: st.url,
89
+ server: `FlaxMovies - ${st.provider || 'Default'}`,
90
+ quality: st.resolution || 'Auto',
91
+ type: isHls ? 'hls' : 'mp4',
92
+ headers: {
93
+ 'User-Agent': USER_AGENT,
94
+ 'Referer': `${BASE_URL}/`,
95
+ 'Origin': BASE_URL
96
+ }
97
+ };
98
+ });
99
+
100
+ if (server && server !== 'all') {
101
+ const clean = server.toLowerCase().replace('flaxmovies - ', '');
102
+ const filtered = allUrls.filter(u => u.server.toLowerCase().includes(clean));
103
+ if (filtered.length) allUrls = filtered;
104
+ }
105
+
106
+ if (allUrls.length) {
107
+ return { allUrls };
108
+ }
109
+ }
110
+ } catch { }
25
111
  }
112
+
113
+ return null;
114
+ }
115
+
116
+ export async function getSources() {
117
+ return ['FlaxMovies - Airflix', 'FlaxMovies - Xpass-VIP 1'];
26
118
  }