@vyla-entertainment/sdk 1.20.0 → 1.22.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 (58) hide show
  1. package/package.json +3 -2
  2. package/src/config.js +99 -67
  3. package/src/health.js +60 -20
  4. package/src/sdk.d.ts +94 -121
  5. package/src/sdk.js +82 -78
  6. package/src/sources/111477.js +88 -100
  7. package/src/sources/123anime.js +120 -56
  8. package/src/sources/3eyedraven.js +82 -135
  9. package/src/sources/4movies.js +77 -0
  10. package/src/sources/aether.js +99 -0
  11. package/src/sources/castle.js +415 -0
  12. package/src/sources/cinecat.js +37 -18
  13. package/src/sources/cinemaarmy.js +179 -180
  14. package/src/sources/cinesrc.js +401 -397
  15. package/src/sources/cno.js +101 -94
  16. package/src/sources/dulo.js +134 -149
  17. package/src/sources/flaxmovies.js +114 -105
  18. package/src/sources/framextv.js +126 -0
  19. package/src/sources/frost.js +38 -29
  20. package/src/sources/fsonline.js +95 -47
  21. package/src/sources/hdhub.js +43 -36
  22. package/src/sources/hexa.js +60 -53
  23. package/src/sources/hyper.js +42 -35
  24. package/src/sources/kickassanime.js +117 -124
  25. package/src/sources/kisskh.js +114 -59
  26. package/src/sources/lmscript.js +72 -70
  27. package/src/sources/lookmovie.js +80 -79
  28. package/src/sources/meowtv.js +140 -0
  29. package/src/sources/movenerds.js +74 -124
  30. package/src/sources/movy.js +197 -209
  31. package/src/sources/net79.js +59 -55
  32. package/src/sources/peestream.js +126 -138
  33. package/src/sources/pengu.js +46 -49
  34. package/src/sources/pstream.js +73 -67
  35. package/src/sources/purstream.js +96 -104
  36. package/src/sources/rivestream.js +182 -176
  37. package/src/sources/rivo.js +58 -53
  38. package/src/sources/streamaggregator.js +114 -128
  39. package/src/sources/thugtv.js +70 -62
  40. package/src/sources/vidapi.js +122 -114
  41. package/src/sources/vidcore.js +14 -122
  42. package/src/sources/vidfast.js +14 -122
  43. package/src/sources/vidlink.js +78 -27
  44. package/src/sources/vidora.js +74 -42
  45. package/src/sources/vidup.js +14 -122
  46. package/src/sources/vidvault.js +133 -187
  47. package/src/sources/vidy.js +192 -187
  48. package/src/sources/vidzee.js +189 -183
  49. package/src/sources/vixsrc.js +123 -113
  50. package/src/sources/watchout.js +60 -46
  51. package/src/sources/xdownloader.js +127 -128
  52. package/src/sources/yapgrid.js +68 -62
  53. package/src/sources/yastream.js +35 -29
  54. package/src/subtitles.js +105 -122
  55. package/src/utils/helpers.js +586 -247
  56. package/src/sources/bcine.js +0 -202
  57. package/src/sources/cinezo.js +0 -55
  58. package/src/sources/vidrock.js +0 -145
@@ -1,106 +1,115 @@
1
- import { fetchJson } from '../utils/helpers.js';
2
-
3
- export async function getStream({ id, s, e }) {
4
- const isTv = s != null && e != null;
5
- const allUrls = [];
6
-
7
- const endpoints = [
8
- async () => {
9
- const url = isTv
10
- ? `https://themoviebox.uk/api/resolve?type=tv&id=${id}&season=${s}&episode=${e}`
11
- : `https://themoviebox.uk/api/resolve?type=movie&id=${id}`;
12
- const res = await fetchJson(url);
13
- if (res?.success && Array.isArray(res.sources)) {
14
- for (const item of res.sources) {
15
- const streamUrl = item.url || item.original_url;
16
- if (streamUrl) {
17
- allUrls.push({
18
- url: streamUrl,
19
- server: `TheMovieBox - ${item.server || item.provider || 'Server'}`,
20
- headers: {
21
- Referer: 'https://themoviebox.uk/',
22
- Origin: 'https://themoviebox.uk'
23
- }
24
- });
25
- }
26
- }
27
- }
28
- },
29
-
30
- async () => {
31
- const url = isTv
32
- ? `https://pro2.nabilekson.workers.dev/tv/${id}/${s}/${e}`
33
- : `https://pro2.nabilekson.workers.dev/movie/${id}`;
34
- const res = await fetchJson(url);
35
- if (res?.success && Array.isArray(res.primarySources)) {
36
- for (const item of res.primarySources) {
37
- const streamUrl = item.url || item.originalUrl;
38
- if (streamUrl) {
39
- allUrls.push({
40
- url: streamUrl,
41
- server: `CineBros - ${item.name || item.quality || 'Server'}`,
42
- headers: item.headers || {
43
- Referer: 'https://pro2.nabilekson.workers.dev/',
44
- Origin: 'https://pro2.nabilekson.workers.dev'
45
- }
46
- });
47
- }
48
- }
49
- }
50
- },
51
-
52
- async () => {
53
- const url = isTv
54
- ? `https://praxi.nabilekson.workers.dev/tv/${id}/${s}/${e}`
55
- : `https://praxi.nabilekson.workers.dev/movie/${id}`;
56
- const res = await fetchJson(url);
57
- if (res?.success && Array.isArray(res.primarySources)) {
58
- for (const item of res.primarySources) {
59
- const streamUrl = item.url || item.originalUrl;
60
- if (streamUrl) {
61
- allUrls.push({
62
- url: streamUrl,
63
- server: `Praxi - ${item.name || item.providerName || 'Server'}`,
64
- headers: item.headers || {
65
- Referer: 'https://praxi.nabilekson.workers.dev/',
66
- Origin: 'https://praxi.nabilekson.workers.dev'
67
- }
68
- });
69
- }
70
- }
71
- }
72
- },
73
-
74
- async () => {
75
- const url = isTv
76
- ? `https://freakyniki.elaxo.lol/?tmdb_id=${id}&season=${s}&episode=${e}`
77
- : `https://freakyniki.elaxo.lol/?tmdb_id=${id}`;
78
- const res = await fetchJson(url);
79
- if (Array.isArray(res?.streams)) {
80
- for (const item of res.streams) {
81
- const streamUrl = item.url || item.raw_url;
82
- if (streamUrl) {
83
- allUrls.push({
84
- url: streamUrl,
85
- server: `FreakyNiki - ${item.server || item.provider || 'Server'}`,
86
- headers: {
87
- Referer: 'https://freakyniki.elaxo.lol/',
88
- Origin: 'https://freakyniki.elaxo.lol'
89
- }
90
- });
91
- }
92
- }
93
- }
94
- }
95
- ];
96
-
97
- await Promise.allSettled(endpoints.map(fn => fn().catch(() => { })));
98
-
99
- if (!allUrls.length) return null;
100
-
101
- return {
102
- url: allUrls[0].url,
103
- headers: allUrls[0].headers,
104
- allUrls
105
- };
1
+ import { fetchJson } from '../utils/helpers.js';
2
+
3
+ export async function getStream(args) {
4
+ const { id, s, e } = args || {};
5
+ const isTv = s != null && e != null;
6
+ const allUrls = [];
7
+
8
+ const endpoints = [
9
+ async () => {
10
+ const url = isTv
11
+ ? `https://themoviebox.uk/api/resolve?type=tv&id=${id}&season=${s}&episode=${e}`
12
+ : `https://themoviebox.uk/api/resolve?type=movie&id=${id}`;
13
+ const res = await fetchJson(url);
14
+ if (res?.success && Array.isArray(res.sources)) {
15
+ for (const item of res.sources) {
16
+ const streamUrl = item.url || item.original_url;
17
+ if (streamUrl) {
18
+ allUrls.push({
19
+ url: streamUrl,
20
+ server: `TheMovieBox - ${item.server || item.provider || 'Server'}`,
21
+ quality: 'Auto',
22
+ type: streamUrl.includes('.m3u8') ? 'hls' : 'mp4',
23
+ headers: {
24
+ Referer: 'https://themoviebox.uk/',
25
+ Origin: 'https://themoviebox.uk',
26
+ },
27
+ });
28
+ }
29
+ }
30
+ }
31
+ },
32
+
33
+ async () => {
34
+ const url = isTv
35
+ ? `https://pro2.nabilekson.workers.dev/tv/${id}/${s}/${e}`
36
+ : `https://pro2.nabilekson.workers.dev/movie/${id}`;
37
+ const res = await fetchJson(url);
38
+ if (res?.success && Array.isArray(res.primarySources)) {
39
+ for (const item of res.primarySources) {
40
+ const streamUrl = item.url || item.originalUrl;
41
+ if (streamUrl) {
42
+ allUrls.push({
43
+ url: streamUrl,
44
+ server: `CineBros - ${item.name || item.quality || 'Server'}`,
45
+ quality: item.quality || 'Auto',
46
+ type: streamUrl.includes('.m3u8') ? 'hls' : 'mp4',
47
+ headers: item.headers || {
48
+ Referer: 'https://pro2.nabilekson.workers.dev/',
49
+ Origin: 'https://pro2.nabilekson.workers.dev',
50
+ },
51
+ });
52
+ }
53
+ }
54
+ }
55
+ },
56
+
57
+ async () => {
58
+ const url = isTv
59
+ ? `https://praxi.nabilekson.workers.dev/tv/${id}/${s}/${e}`
60
+ : `https://praxi.nabilekson.workers.dev/movie/${id}`;
61
+ const res = await fetchJson(url);
62
+ if (res?.success && Array.isArray(res.primarySources)) {
63
+ for (const item of res.primarySources) {
64
+ const streamUrl = item.url || item.originalUrl;
65
+ if (streamUrl) {
66
+ allUrls.push({
67
+ url: streamUrl,
68
+ server: `Praxi - ${item.name || item.providerName || 'Server'}`,
69
+ quality: 'Auto',
70
+ type: streamUrl.includes('.m3u8') ? 'hls' : 'mp4',
71
+ headers: item.headers || {
72
+ Referer: 'https://praxi.nabilekson.workers.dev/',
73
+ Origin: 'https://praxi.nabilekson.workers.dev',
74
+ },
75
+ });
76
+ }
77
+ }
78
+ }
79
+ },
80
+
81
+ async () => {
82
+ const url = isTv
83
+ ? `https://freakyniki.elaxo.lol/?tmdb_id=${id}&season=${s}&episode=${e}`
84
+ : `https://freakyniki.elaxo.lol/?tmdb_id=${id}`;
85
+ const res = await fetchJson(url);
86
+ if (Array.isArray(res?.streams)) {
87
+ for (const item of res.streams) {
88
+ const streamUrl = item.url || item.raw_url;
89
+ if (streamUrl) {
90
+ allUrls.push({
91
+ url: streamUrl,
92
+ server: `FreakyNiki - ${item.server || item.provider || 'Server'}`,
93
+ quality: 'Auto',
94
+ type: streamUrl.includes('.m3u8') ? 'hls' : 'mp4',
95
+ headers: {
96
+ Referer: 'https://freakyniki.elaxo.lol/',
97
+ Origin: 'https://freakyniki.elaxo.lol',
98
+ },
99
+ });
100
+ }
101
+ }
102
+ }
103
+ },
104
+ ];
105
+
106
+ await Promise.allSettled(endpoints.map(fn => fn().catch(() => { })));
107
+
108
+ if (!allUrls.length) return null;
109
+
110
+ return {
111
+ url: allUrls[0].url,
112
+ headers: allUrls[0].headers,
113
+ allUrls,
114
+ };
106
115
  }
@@ -0,0 +1,126 @@
1
+ const FRAMEX_BASE = 'https://api.framextv.cc';
2
+ const STREAMOS_BASE = 'https://api.streamos.top';
3
+ 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';
4
+
5
+ const FRAMEX_HEADERS = {
6
+ 'User-Agent': UA,
7
+ Referer: 'https://framextv.cc/',
8
+ Origin: 'https://framextv.cc',
9
+ Accept: 'application/json, text/plain, */*',
10
+ 'Accept-Language': 'en-US,en;q=0.9',
11
+ };
12
+
13
+ const STREAMOS_HEADERS = {
14
+ 'User-Agent': UA,
15
+ Referer: 'https://streamos.top/',
16
+ Origin: 'https://streamos.top',
17
+ };
18
+
19
+ const STREAMOS_SERVERS = [
20
+ 'auto',
21
+ 'miami',
22
+ 'boise',
23
+ 'vegas',
24
+ 'reno',
25
+ 'oakland',
26
+ 'seattle',
27
+ 'phoenix',
28
+ 'atlanta',
29
+ 'portland',
30
+ 'austin',
31
+ 'dallas',
32
+ 'tampa',
33
+ 'orlando',
34
+ 'munich',
35
+ 'berlin',
36
+ 'france',
37
+ 'india',
38
+ 'mexico',
39
+ 'delhi',
40
+ ];
41
+
42
+ export async function getStream(args) {
43
+ const { id, s, e } = args || {};
44
+ const isTv = s != null && e != null;
45
+
46
+ const framexQuery = isTv
47
+ ? `type=tv&id=${id}&season=${s}&episode=${e}&codecs=hevc`
48
+ : `type=movie&id=${id}&codecs=hevc`;
49
+
50
+ const framexUrls = [
51
+ `${FRAMEX_BASE}/api/stream?${framexQuery}`,
52
+ `${FRAMEX_BASE}/api/stream?${framexQuery}&provider=sparky`,
53
+ `${FRAMEX_BASE}/api/stream?${framexQuery}&provider=titan`,
54
+ ];
55
+
56
+ const streamOsBaseQuery = isTv
57
+ ? `id=${id}&season=${s}&episode=${e}&kind=tv`
58
+ : `id=${id}&kind=movie`;
59
+
60
+ const allUrls = [];
61
+ const seen = new Set();
62
+
63
+ const framexPromises = Promise.all(
64
+ framexUrls.map(url =>
65
+ fetch(url, { headers: FRAMEX_HEADERS })
66
+ .then(r => (r.ok ? r.json() : null))
67
+ .catch(() => null)
68
+ )
69
+ );
70
+
71
+ const streamOsChecks = Promise.all(
72
+ STREAMOS_SERVERS.slice(0, 8).map(async server => {
73
+ const serverParam = server === 'auto' ? '' : `&server=${server}`;
74
+ const url = `${STREAMOS_BASE}/api/relay/hls?${streamOsBaseQuery}${serverParam}`;
75
+ try {
76
+ const res = await fetch(url, { method: 'HEAD', headers: STREAMOS_HEADERS });
77
+ if (res.ok) {
78
+ return {
79
+ url,
80
+ server: `StreamOS - ${server.toUpperCase()}`,
81
+ quality: '1080p',
82
+ type: 'hls',
83
+ headers: STREAMOS_HEADERS,
84
+ };
85
+ }
86
+ } catch { }
87
+ return null;
88
+ })
89
+ );
90
+
91
+ const [framexResults, streamOsResults] = await Promise.all([framexPromises, streamOsChecks]);
92
+
93
+ for (const data of framexResults) {
94
+ if (!data?.success || !Array.isArray(data.sources)) continue;
95
+ for (const src of data.sources) {
96
+ if (!src?.url || seen.has(src.url)) continue;
97
+ seen.add(src.url);
98
+ allUrls.push({
99
+ url: src.url,
100
+ server: `FrameX - ${src.server || data.provider || 'Direct'}`,
101
+ quality: src.quality || 'Auto',
102
+ type: src.type || (src.url.includes('.m3u8') ? 'hls' : 'mp4'),
103
+ headers: {
104
+ 'User-Agent': UA,
105
+ Referer: 'https://framextv.cc/',
106
+ Origin: 'https://framextv.cc',
107
+ },
108
+ });
109
+ }
110
+ }
111
+
112
+ for (const stream of streamOsResults) {
113
+ if (stream && !seen.has(stream.url)) {
114
+ seen.add(stream.url);
115
+ allUrls.push(stream);
116
+ }
117
+ }
118
+
119
+ if (!allUrls.length) return null;
120
+
121
+ return {
122
+ url: allUrls[0].url,
123
+ headers: allUrls[0].headers,
124
+ allUrls,
125
+ };
126
+ }
@@ -1,30 +1,39 @@
1
- import { fetchJson, resolveImdbId } from '../utils/helpers.js';
2
-
3
- export async function getStream({ id, s, e, tmdbApiKey, sdk }) {
4
- const isTv = s != null && e != null;
5
- const type = isTv ? 'series' : 'movie';
6
- const imdb = await resolveImdbId(id, isTv, tmdbApiKey || sdk?.tmdbApiKey);
7
- if (!imdb) return null;
8
-
9
- const url = isTv
10
- ? `https://froststream.cloutteam.com/stream/series/${imdb}:${s}:${e}.json`
11
- : `https://froststream.cloutteam.com/stream/movie/${imdb}.json`;
12
-
13
- const res = await fetchJson(url).catch(() => null);
14
- if (!res || !Array.isArray(res.streams) || !res.streams.length) return null;
15
-
16
- const allUrls = res.streams.filter(st => st.url).map(st => ({
17
- url: st.url,
18
- server: `Frost - ${st.name || 'Server'} ${st.title ? `- ${st.title}` : ''}`,
19
- headers: st.behaviorHints?.proxyHeaders?.request || undefined,
20
- skipProxy: st.behaviorHints?.notWebReady === false
21
- }));
22
-
23
- if (!allUrls.length) return null;
24
-
25
- return {
26
- url: allUrls[0].url,
27
- headers: allUrls[0].headers,
28
- allUrls
29
- };
1
+ import { fetchJson, resolveImdbId, resolveTmdbKey } from '../utils/helpers.js';
2
+
3
+ const BASE_URL = 'https://froststream.cloutteam.com';
4
+
5
+ export async function getStream(args) {
6
+ const { id, s, e, sdk } = args || {};
7
+ const isTv = s != null && e != null;
8
+ const type = isTv ? 'series' : 'movie';
9
+ const apiKey = resolveTmdbKey(args, sdk);
10
+
11
+ const imdb = await resolveImdbId(id, isTv, apiKey);
12
+ if (!imdb) return null;
13
+
14
+ const url = isTv
15
+ ? `${BASE_URL}/stream/series/${imdb}:${s}:${e}.json`
16
+ : `${BASE_URL}/stream/movie/${imdb}.json`;
17
+
18
+ const res = await fetchJson(url).catch(() => null);
19
+ if (!res || !Array.isArray(res.streams) || !res.streams.length) return null;
20
+
21
+ const allUrls = res.streams
22
+ .filter(st => st.url)
23
+ .map(st => ({
24
+ url: st.url,
25
+ server: `Frost - ${st.name || 'Server'}${st.title ? ` - ${st.title}` : ''}`,
26
+ quality: 'Auto',
27
+ type: st.url.includes('.m3u8') ? 'hls' : 'mp4',
28
+ headers: st.behaviorHints?.proxyHeaders?.request || undefined,
29
+ skipProxy: st.behaviorHints?.notWebReady === false,
30
+ }));
31
+
32
+ if (!allUrls.length) return null;
33
+
34
+ return {
35
+ url: allUrls[0].url,
36
+ headers: allUrls[0].headers,
37
+ allUrls,
38
+ };
30
39
  }
@@ -1,48 +1,96 @@
1
- import { fetchText, USER_AGENT, getTmdbInfo } from '../utils/helpers.js';
2
-
3
- const ORIGIN = 'https://www3.fsonline.app';
4
- const AJAX_URL = `${ORIGIN}/wp-admin/admin-ajax.php`;
5
- const HEADERS = { 'User-Agent': USER_AGENT, 'Origin': ORIGIN, 'Referer': `${ORIGIN}/` };
6
-
7
- export async function getStream({ id, s, e, sdk }) {
8
- const tmdbApiKey = sdk?.tmdbApiKey || null;
9
- if (!tmdbApiKey) return null;
10
- try {
11
- const isTv = s != null && e != null;
12
- const info = await getTmdbInfo(tmdbApiKey, id, isTv ? 'tv' : 'movie');
13
- if (!info?.titles?.length) return null;
14
- const searchHtml = await fetchText(`${ORIGIN}/?s=${encodeURIComponent(info.titles[0] + (info.year ? ' ' + info.year : ''))}`, { headers: HEADERS });
15
- const typeFolder = isTv ? 'seriale' : 'film';
16
- const linkMatch = searchHtml.match(new RegExp(`href=["'](https?://www3\\.fsonline\\.app/${typeFolder}/([^"'/]+)/)["']`, 'i'));
17
- if (!linkMatch) return null;
18
- const targetPageUrl = isTv ? `${ORIGIN}/episoade/${linkMatch[2].replace(/-\d{4}$/, '')}-sezonul-${s}-episodul-${e}/` : linkMatch[1];
19
- const pageHtml = await fetchText(targetPageUrl, { headers: HEADERS });
20
- const movieId = (pageHtml.match(/movie-id=['"]([^'"]+)['"]/) || pageHtml.match(/movie-id=([^ >]+)/))?.[1];
21
- if (!movieId) return null;
22
- const ajaxHtml = await fetchText(AJAX_URL, { method: 'POST', headers: { ...HEADERS, 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', 'X-Requested-With': 'XMLHttpRequest', 'Referer': targetPageUrl }, body: `action=lazy_player&movieID=${movieId}` });
23
- const results = [];
24
- let idx = 0;
25
- while ((idx = ajaxHtml.indexOf('data-vs="', idx)) !== -1) {
26
- const embedStart = idx + 9;
27
- const embedEnd = ajaxHtml.indexOf('"', embedStart);
28
- const embedUrl = ajaxHtml.slice(embedStart, embedEnd);
29
- const spanStart = ajaxHtml.indexOf('<span>', embedEnd);
30
- const spanEnd = ajaxHtml.indexOf('</span>', spanStart);
31
- const serverLabel = ajaxHtml.slice(spanStart + 6, spanEnd).trim().toLowerCase();
32
- if (serverLabel.includes('filesun')) {
33
- try {
34
- const rHtml = await fetchText(embedUrl, { headers: { 'Referer': ORIGIN, 'User-Agent': USER_AGENT } });
35
- const m3u8Match = rHtml.match(/file:\s*["'](https?:\/\/[^"']+\.m3u8[^"']*)["']/) || rHtml.match(/["']?file["']?:\s*["'](https?:\/\/[^"']+)["']/);
36
- if (m3u8Match) results.push({ url: m3u8Match[1].replace(/\\\//g, '/'), server: 'FSOnline - FileSuN', headers: { 'Referer': embedUrl, 'Origin': 'https://player.fsonline.app', 'User-Agent': USER_AGENT } });
37
- } catch { }
38
- }
39
- idx = spanEnd;
40
- }
41
- return results.length ? { allUrls: results } : null;
42
- } catch { return null; }
43
- }
44
-
45
- export async function getSources(args) {
46
- const res = await getStream(args);
47
- return res?.allUrls ? [...new Set(res.allUrls.map(u => u.server))] : [];
1
+ import { fetchText, getTmdbMetadata, resolveTmdbKey, USER_AGENT } from '../utils/helpers.js';
2
+
3
+ const ORIGIN = 'https://www3.fsonline.app';
4
+ const AJAX_URL = `${ORIGIN}/wp-admin/admin-ajax.php`;
5
+ const HEADERS = {
6
+ 'User-Agent': USER_AGENT,
7
+ Origin: ORIGIN,
8
+ Referer: `${ORIGIN}/`,
9
+ };
10
+
11
+ export async function getStream(args) {
12
+ const { id, s, e, sdk } = args || {};
13
+ const isTv = s != null && e != null;
14
+ const apiKey = resolveTmdbKey(args, sdk);
15
+ if (!apiKey) return null;
16
+
17
+ try {
18
+ const meta = await getTmdbMetadata(id, isTv, apiKey);
19
+ if (!meta?.titles?.length) return null;
20
+
21
+ const query = meta.titles[0] + (meta.year ? ` ${meta.year}` : '');
22
+ const searchHtml = await fetchText(`${ORIGIN}/?s=${encodeURIComponent(query)}`, { headers: HEADERS });
23
+ const typeFolder = isTv ? 'seriale' : 'film';
24
+ const linkMatch = searchHtml.match(new RegExp(`href=["'](https?://www3\\.fsonline\\.app/${typeFolder}/([^"'/]+)/)["']`, 'i'));
25
+ if (!linkMatch) return null;
26
+
27
+ const targetPageUrl = isTv
28
+ ? `${ORIGIN}/episoade/${linkMatch[2].replace(/-\d{4}$/, '')}-sezonul-${s}-episodul-${e}/`
29
+ : linkMatch[1];
30
+
31
+ const pageHtml = await fetchText(targetPageUrl, { headers: HEADERS });
32
+ const movieId = (pageHtml.match(/movie-id=['"]([^'"]+)['"]/) || pageHtml.match(/movie-id=([^ >]+)/))?.[1];
33
+ if (!movieId) return null;
34
+
35
+ const ajaxHtml = await fetchText(AJAX_URL, {
36
+ method: 'POST',
37
+ headers: {
38
+ ...HEADERS,
39
+ 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
40
+ 'X-Requested-With': 'XMLHttpRequest',
41
+ Referer: targetPageUrl,
42
+ },
43
+ body: `action=lazy_player&movieID=${movieId}`,
44
+ });
45
+
46
+ const allUrls = [];
47
+ let idx = 0;
48
+ while ((idx = ajaxHtml.indexOf('data-vs="', idx)) !== -1) {
49
+ const embedStart = idx + 9;
50
+ const embedEnd = ajaxHtml.indexOf('"', embedStart);
51
+ const embedUrl = ajaxHtml.slice(embedStart, embedEnd);
52
+ const spanStart = ajaxHtml.indexOf('<span>', embedEnd);
53
+ const spanEnd = ajaxHtml.indexOf('</span>', spanStart);
54
+ const serverLabel = ajaxHtml.slice(spanStart + 6, spanEnd).trim().toLowerCase();
55
+
56
+ if (serverLabel.includes('filesun')) {
57
+ try {
58
+ const rHtml = await fetchText(embedUrl, {
59
+ headers: { Referer: ORIGIN, 'User-Agent': USER_AGENT },
60
+ });
61
+ const m3u8Match = rHtml.match(/file:\s*["'](https?:\/\/[^"']+\.m3u8[^"']*)["']/) || rHtml.match(/["']?file["']?:\s*["'](https?:\/\/[^"']+)["']/);
62
+ if (m3u8Match) {
63
+ const streamUrl = m3u8Match[1].replace(/\\\//g, '/');
64
+ allUrls.push({
65
+ url: streamUrl,
66
+ server: 'FSOnline - FileSuN',
67
+ quality: 'Auto',
68
+ type: 'hls',
69
+ headers: {
70
+ Referer: embedUrl,
71
+ Origin: 'https://player.fsonline.app',
72
+ 'User-Agent': USER_AGENT,
73
+ },
74
+ });
75
+ }
76
+ } catch { }
77
+ }
78
+ idx = spanEnd;
79
+ }
80
+
81
+ if (!allUrls.length) return null;
82
+
83
+ return {
84
+ url: allUrls[0].url,
85
+ headers: allUrls[0].headers,
86
+ allUrls,
87
+ };
88
+ } catch {
89
+ return null;
90
+ }
91
+ }
92
+
93
+ export async function getSources(args) {
94
+ const stream = await getStream(args);
95
+ return stream?.allUrls ? [...new Set(stream.allUrls.map(u => u.server))] : [];
48
96
  }