@vyla-entertainment/sdk 1.21.0 → 1.23.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.
package/README.md CHANGED
@@ -1,4 +1,5 @@
1
1
  # vyla-entertainment/sdk
2
+
2
3
  The Vyla SDK (@vyla-entertainment/sdk) is a server-side JavaScript/TypeScript package that provides direct access to Vyla's stream resolvers, health probes, download resolvers, and subtitle providers.
3
4
 
4
5
  ## Installing
@@ -11,7 +12,7 @@ npm install @vyla-entertainment/sdk
11
12
  pnpm install @vyla-entertainment/sdk
12
13
  ```
13
14
 
14
- View our full documentation at https://docs.vyla.cc/sdk
15
+ View our full documentation at https://vyla.cc/sdk
15
16
 
16
17
  # [DMCA](https://vyla.cc/misc/project/DMCA)
17
18
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vyla-entertainment/sdk",
3
- "version": "1.21.0",
3
+ "version": "1.23.0",
4
4
  "scripts": {
5
5
  "test": "node test/index.js",
6
6
  "test:all": "node test/index.js all"
package/src/config.js CHANGED
@@ -18,6 +18,25 @@ export const SOURCES = [
18
18
  }],
19
19
  },
20
20
 
21
+ {
22
+ key: '4movies',
23
+ label: '4Movies',
24
+ sourceFile: '4movies',
25
+ proxyParam: '4m',
26
+ timeout: 25000,
27
+ jitter: 500,
28
+ retries: 2,
29
+ multiUrl: true,
30
+ skipProxy: true,
31
+ cdnHeaders: [{
32
+ pattern: /4movie\.in|aapanel\.devcorp\.me/i,
33
+ headers: {
34
+ Referer: 'https://4movie.in/',
35
+ Origin: 'https://4movie.in',
36
+ },
37
+ }],
38
+ },
39
+
21
40
  {
22
41
  key: '123anime',
23
42
  label: '123Anime',
@@ -56,6 +75,56 @@ export const SOURCES = [
56
75
  }],
57
76
  },
58
77
 
78
+ {
79
+ key: 'aether',
80
+ label: 'Aether',
81
+ sourceFile: 'aether',
82
+ proxyParam: 'aet',
83
+ timeout: 25000,
84
+ jitter: 500,
85
+ retries: 2,
86
+ multiUrl: true,
87
+ skipProxy: true,
88
+ cdnHeaders: [{
89
+ pattern: /raccoonunbutteredbagel\.zip|1x2\.space|kaxate\.fun|mechanicalserenity\.xyz|reelvault\.click|visionaryfounderslab\.site|goldenkite\.top|aether\.ist/i,
90
+ headers: {
91
+ Referer: 'https://aether.st/',
92
+ Origin: 'https://aether.st',
93
+ },
94
+ }],
95
+ },
96
+
97
+ {
98
+ key: 'braflix',
99
+ label: 'Braflix',
100
+ sourceFile: 'braflix',
101
+ proxyParam: 'bf',
102
+ timeout: 25000,
103
+ jitter: 500,
104
+ retries: 2,
105
+ multiUrl: true,
106
+ skipProxy: true,
107
+ cdnHeaders: [{
108
+ pattern: /braflix\.dev/i,
109
+ headers: {
110
+ Referer: 'https://braflix.dev/',
111
+ Origin: 'https://braflix.dev',
112
+ },
113
+ }],
114
+ },
115
+
116
+ {
117
+ key: 'castle',
118
+ label: 'Castle',
119
+ sourceFile: 'castle',
120
+ proxyParam: 'cst',
121
+ timeout: 25000,
122
+ jitter: 500,
123
+ retries: 2,
124
+ multiUrl: true,
125
+ skipProxy: true,
126
+ },
127
+
59
128
  {
60
129
  key: 'cinemaarmy',
61
130
  label: 'CinemaArmy',
@@ -151,6 +220,25 @@ export const SOURCES = [
151
220
  }],
152
221
  },
153
222
 
223
+ {
224
+ key: 'framextv',
225
+ label: 'FrameXTV',
226
+ sourceFile: 'framextv',
227
+ proxyParam: 'fxt',
228
+ timeout: 25000,
229
+ jitter: 500,
230
+ retries: 2,
231
+ multiUrl: true,
232
+ skipProxy: true,
233
+ cdnHeaders: [{
234
+ pattern: /framextv\.cc|streamos\.top|workers\.dev|films365\.org/i,
235
+ headers: {
236
+ Referer: 'https://framextv.cc/',
237
+ Origin: 'https://framextv.cc',
238
+ },
239
+ }],
240
+ },
241
+
154
242
  {
155
243
  key: 'frost',
156
244
  label: 'FrostStream',
@@ -278,6 +366,25 @@ export const SOURCES = [
278
366
  },
279
367
  },
280
368
 
369
+ {
370
+ key: 'meowtv',
371
+ label: 'MeowTV',
372
+ sourceFile: 'meowtv',
373
+ proxyParam: 'mtv',
374
+ timeout: 25000,
375
+ jitter: 500,
376
+ retries: 2,
377
+ multiUrl: true,
378
+ skipProxy: true,
379
+ cdnHeaders: [{
380
+ pattern: /meowtv\.ru/i,
381
+ headers: {
382
+ Referer: 'https://meowtv.ru/',
383
+ Origin: 'https://meowtv.ru',
384
+ },
385
+ }],
386
+ },
387
+
281
388
  {
282
389
  key: 'movenerds',
283
390
  label: 'MoverNerds',
@@ -481,6 +588,25 @@ export const SOURCES = [
481
588
  multiUrl: true,
482
589
  },
483
590
 
591
+ {
592
+ key: 'vidora',
593
+ label: 'Vidora',
594
+ sourceFile: 'vidora',
595
+ proxyParam: 'vd',
596
+ timeout: 25000,
597
+ jitter: 500,
598
+ retries: 2,
599
+ multiUrl: true,
600
+ skipProxy: true,
601
+ cdnHeaders: [{
602
+ pattern: /vidoraplayer\.duckdns\.org/i,
603
+ headers: {
604
+ Referer: 'https://vidoraplayer.duckdns.org/',
605
+ Origin: 'https://vidoraplayer.duckdns.org',
606
+ },
607
+ }],
608
+ },
609
+
484
610
  {
485
611
  key: 'vidup',
486
612
  label: 'VidUp',
@@ -618,6 +744,25 @@ export const SOURCES = [
618
744
  multiUrl: true,
619
745
  },
620
746
 
747
+ {
748
+ key: 'zenox',
749
+ label: 'Zenox',
750
+ sourceFile: 'zenox',
751
+ proxyParam: 'zx',
752
+ timeout: 25000,
753
+ jitter: 500,
754
+ retries: 2,
755
+ multiUrl: true,
756
+ skipProxy: true,
757
+ cdnHeaders: [{
758
+ pattern: /zenox\.lol|hls-m3u8\.lol/i,
759
+ headers: {
760
+ Referer: 'https://zenox.lol/',
761
+ Origin: 'https://zenox.lol',
762
+ },
763
+ }],
764
+ },
765
+
621
766
  ];
622
767
 
623
768
  export const HEALTH_PROBE_ID = '155';
package/src/health.js CHANGED
@@ -1,6 +1,15 @@
1
- import { HEALTH_PROBE_ID } from "./config.js";
2
1
 
3
- const withTimeout = (promise, ms) => Promise.race([promise, new Promise(r => setTimeout(() => r(null), ms))]);
2
+ const MOVIE_PROBE_ID = "936075";
3
+ const TV_PROBE_ID = "37854";
4
+ const TV_PROBE_SEASON = "1";
5
+ const TV_PROBE_EPISODE = "1";
6
+
7
+ const withTimeout = (promise, ms) =>
8
+ Promise.race([
9
+ promise,
10
+ new Promise(resolve => setTimeout(() => resolve(null), ms))
11
+ ]);
12
+
4
13
  async function withRetry(fn, attempts = 2, delay = 300) {
5
14
  for (let i = 0; i < attempts; i++) {
6
15
  try {
@@ -8,31 +17,62 @@ async function withRetry(fn, attempts = 2, delay = 300) {
8
17
  if (result != null) return result;
9
18
  } catch (err) {
10
19
  if (i === attempts - 1) throw err;
11
- await new Promise(r => setTimeout(r, delay + Math.random() * delay * 0.5));
20
+ await new Promise(resolve =>
21
+ setTimeout(resolve, delay + Math.random() * delay * 0.5)
22
+ );
12
23
  }
13
24
  }
14
25
  return null;
15
26
  }
16
27
 
28
+ function hasStream(result) {
29
+ const urls = [
30
+ result?.url,
31
+ ...(result?.allUrls || []).map(item => item?.url)
32
+ ];
33
+
34
+ return urls.some(url =>
35
+ typeof url === "string" && url.startsWith("http")
36
+ );
37
+ }
38
+
17
39
  export async function probeSource(sdk, cfg, mod) {
18
- const audio = /dub$/.test(cfg.key) ? 'dub' : 'sub';
19
- const streamArgs = {
20
- id: HEALTH_PROBE_ID,
21
- s: null,
22
- e: null,
23
- clientIP: null,
24
- absoluteBase: null,
25
- audio,
26
- sdk,
27
- config: cfg,
40
+ const audio = /dub$/.test(cfg.key) ? "dub" : "sub";
41
+ const start = Date.now();
42
+
43
+ const test = async (id, s = null, e = null) => {
44
+ const streamArgs = {
45
+ id,
46
+ s,
47
+ e,
48
+ clientIP: null,
49
+ absoluteBase: null,
50
+ audio,
51
+ sdk,
52
+ config: cfg,
53
+ };
54
+
55
+ const result = await withTimeout(
56
+ withRetry(
57
+ () => mod.getStream(streamArgs),
58
+ cfg.retries,
59
+ 300
60
+ ),
61
+ cfg.timeout
62
+ );
63
+
64
+ return hasStream(result);
28
65
  };
29
66
 
30
- const t = Date.now();
31
- const result = await withTimeout(
32
- withRetry(() => mod.getStream(streamArgs), cfg.retries, 300),
33
- cfg.timeout
34
- );
67
+ const [movie, tv] = await Promise.all([
68
+ test(MOVIE_PROBE_ID),
69
+ test(TV_PROBE_ID, TV_PROBE_SEASON, TV_PROBE_EPISODE)
70
+ ]);
35
71
 
36
- const firstUrl = result?.url ?? result?.allUrls?.[0]?.url;
37
- return { ok: !!(typeof firstUrl === 'string' && firstUrl.startsWith('http')), ms: Date.now() - t };
72
+ return {
73
+ ok: movie || tv,
74
+ movie,
75
+ tv,
76
+ ms: Date.now() - start
77
+ };
38
78
  }
@@ -0,0 +1,77 @@
1
+ const BASE_URL = 'https://4movie.in';
2
+ 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';
3
+
4
+ const HEADERS = {
5
+ 'User-Agent': UA,
6
+ Referer: `${BASE_URL}/`,
7
+ Origin: BASE_URL,
8
+ Accept: 'application/json, text/plain, */*',
9
+ 'Accept-Language': 'en-US,en;q=0.9',
10
+ };
11
+
12
+ const PLAYBACK_HEADERS = {
13
+ 'User-Agent': UA,
14
+ Referer: `${BASE_URL}/`,
15
+ Origin: BASE_URL,
16
+ };
17
+
18
+ export async function getStream(args) {
19
+ const { id, s, e } = args || {};
20
+ const isTv = s != null && e != null;
21
+
22
+ let query = isTv
23
+ ? `tmdb=${id}&type=tv&season=${s}&episode=${e}`
24
+ : `tmdb=${id}&type=movie`;
25
+
26
+ if (args?.title) query += `&title=${encodeURIComponent(args.title)}`;
27
+ if (args?.year) query += `&year=${encodeURIComponent(args.year)}`;
28
+
29
+ const targetUrl = `${BASE_URL}/api/hubcloud?${query}`;
30
+
31
+ const res = await fetch(targetUrl, { headers: HEADERS }).catch(() => null);
32
+ if (!res || !res.ok) return null;
33
+
34
+ const data = await res.json().catch(() => null);
35
+ if (!data?.ok || !Array.isArray(data.streams) || !data.streams.length) return null;
36
+
37
+ const allUrls = [];
38
+ const seen = new Set();
39
+
40
+ for (const stream of data.streams) {
41
+ if (stream.rawUrl && !seen.has(stream.rawUrl)) {
42
+ seen.add(stream.rawUrl);
43
+ allUrls.push({
44
+ url: stream.rawUrl,
45
+ server: `4Movies - ${stream.name || 'Direct'}`,
46
+ quality: stream.quality || 'Auto',
47
+ type: stream.type || (stream.rawUrl.includes('.m3u8') ? 'hls' : 'mp4'),
48
+ headers: PLAYBACK_HEADERS,
49
+ });
50
+ }
51
+
52
+ if (stream.url) {
53
+ const proxyUrl = stream.url.startsWith('http')
54
+ ? stream.url
55
+ : `${BASE_URL}${stream.url.startsWith('/') ? '' : '/'}${stream.url}`;
56
+
57
+ if (!seen.has(proxyUrl)) {
58
+ seen.add(proxyUrl);
59
+ allUrls.push({
60
+ url: proxyUrl,
61
+ server: `4Movies - ${stream.name ? `${stream.name} (Proxy)` : 'Proxy'}`,
62
+ quality: stream.quality || 'Auto',
63
+ type: stream.type || 'hls',
64
+ headers: PLAYBACK_HEADERS,
65
+ });
66
+ }
67
+ }
68
+ }
69
+
70
+ if (!allUrls.length) return null;
71
+
72
+ return {
73
+ url: allUrls[0].url,
74
+ headers: allUrls[0].headers,
75
+ allUrls,
76
+ };
77
+ }
@@ -0,0 +1,99 @@
1
+ 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';
2
+
3
+ const HEADERS = {
4
+ 'User-Agent': UA,
5
+ Origin: 'https://aether.st',
6
+ Referer: 'https://aether.st/',
7
+ Accept: 'application/json, text/plain, */*',
8
+ 'Accept-Language': 'en-US,en;q=0.9',
9
+ };
10
+
11
+ const PLAYBACK_HEADERS = {
12
+ 'User-Agent': UA,
13
+ Referer: 'https://aether.st/',
14
+ Origin: 'https://aether.st',
15
+ };
16
+
17
+ function extractStreamUrls(data, target) {
18
+ const urls = [];
19
+ if (!data) return urls;
20
+
21
+ if (Array.isArray(data.streams)) {
22
+ for (const s of data.streams) {
23
+ if (s?.url) {
24
+ urls.push({
25
+ url: s.url,
26
+ name: `${target.name} (${s.name || s.language || 'Default'})`,
27
+ quality: s.quality || 'Auto',
28
+ type: s.type || (s.url.includes('.m3u8') ? 'hls' : 'mp4'),
29
+ });
30
+ }
31
+ }
32
+ }
33
+
34
+ const singleUrl = data.directUrl || data.url || data.stream;
35
+ if (typeof singleUrl === 'string' && /^https?:\/\//.test(singleUrl)) {
36
+ urls.push({
37
+ url: singleUrl,
38
+ name: `${target.name}${data.server ? ` - ${data.server}` : ''}`,
39
+ quality: data.quality || 'Auto',
40
+ type: data.streamType || data.container || (singleUrl.includes('.m3u8') ? 'hls' : 'mp4'),
41
+ });
42
+ }
43
+
44
+ return urls;
45
+ }
46
+
47
+ export async function getStream(args) {
48
+ const { id, s, e } = args || {};
49
+ const isTv = s != null && e != null;
50
+
51
+ const endpoints = [
52
+ { name: 'Meridian', url: isTv ? `https://meridian.raccoonunbutteredbagel.zip/show/${id}/${s}/${e}` : `https://meridian.raccoonunbutteredbagel.zip/movie/${id}` },
53
+ { name: 'Rock', url: isTv ? `https://rock.raccoonunbutteredbagel.zip/tv/${id}/${s}/${e}` : `https://rock.raccoonunbutteredbagel.zip/movie/${id}` },
54
+ { name: 'Shore', url: isTv ? `https://shore.raccoonunbutteredbagel.zip/show/${id}?s=${s}&e=${e}` : `https://shore.raccoonunbutteredbagel.zip/movie/${id}` },
55
+ { name: 'Filler', url: isTv ? `https://filler.raccoonunbutteredbagel.zip/tv/${id}/${s}/${e}` : `https://filler.raccoonunbutteredbagel.zip/movie/${id}` },
56
+ { name: 'Tiki', url: isTv ? `https://tiki.raccoonunbutteredbagel.zip/tv/${id}/${s}/${e}` : `https://tiki.raccoonunbutteredbagel.zip/movie/${id}` },
57
+ { name: 'Link', url: isTv ? `https://link.raccoonunbutteredbagel.zip/tv/${id}/${s}/${e}` : `https://link.raccoonunbutteredbagel.zip/movie/${id}` },
58
+ { name: 'VFast Rapid', url: isTv ? `https://vfast.raccoonunbutteredbagel.zip/tv/${id}/${s}/${e}?server=vRapid` : `https://vfast.raccoonunbutteredbagel.zip/movie/${id}?server=vRapid` },
59
+ { name: 'VFast Blaze', url: isTv ? `https://vfast.raccoonunbutteredbagel.zip/tv/${id}/${s}/${e}?server=vBlaze` : `https://vfast.raccoonunbutteredbagel.zip/movie/${id}?server=vBlaze` },
60
+ ];
61
+
62
+ const responses = await Promise.allSettled(
63
+ endpoints.map(async target => {
64
+ const res = await fetch(target.url, { headers: HEADERS });
65
+ if (!res.ok) return null;
66
+ const data = await res.json();
67
+ return { target, data };
68
+ })
69
+ );
70
+
71
+ const allUrls = [];
72
+ const seen = new Set();
73
+
74
+ for (const res of responses) {
75
+ if (res.status !== 'fulfilled' || !res.value?.data) continue;
76
+ const { target, data } = res.value;
77
+ const found = extractStreamUrls(data, target);
78
+
79
+ for (const item of found) {
80
+ if (!item?.url || seen.has(item.url)) continue;
81
+ seen.add(item.url);
82
+ allUrls.push({
83
+ url: item.url,
84
+ server: `Aether - ${item.name}`,
85
+ quality: item.quality || 'Auto',
86
+ type: item.type || (item.url.includes('.m3u8') ? 'hls' : 'mp4'),
87
+ headers: PLAYBACK_HEADERS,
88
+ });
89
+ }
90
+ }
91
+
92
+ if (!allUrls.length) return null;
93
+
94
+ return {
95
+ url: allUrls[0].url,
96
+ headers: allUrls[0].headers,
97
+ allUrls,
98
+ };
99
+ }
@@ -0,0 +1,80 @@
1
+ const BASE_URL = 'https://braflix.dev';
2
+ 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';
3
+
4
+ const HEADERS = {
5
+ Origin: BASE_URL,
6
+ Referer: `${BASE_URL}/`,
7
+ 'User-Agent': UA,
8
+ Accept: 'application/json, text/plain, */*',
9
+ };
10
+
11
+ const PLAYBACK_HEADERS = {
12
+ Origin: BASE_URL,
13
+ Referer: `${BASE_URL}/`,
14
+ };
15
+
16
+ export async function getStream(args) {
17
+ const { id, s, e } = args || {};
18
+ const idNum = parseInt(id, 10);
19
+ if (!idNum) return null;
20
+
21
+ const isTv = s != null && e != null;
22
+ const targetSeason = isTv ? (s || 1) : 1;
23
+ const targetEpisode = isTv ? (e || 1) : 1;
24
+
25
+ const path = isTv
26
+ ? `/api/play/tv/${idNum}/${targetSeason}/${targetEpisode}`
27
+ : `/api/play/movie/${idNum}`;
28
+
29
+ try {
30
+ const res = await fetch(`${BASE_URL}${path}`, {
31
+ headers: HEADERS,
32
+ signal: AbortSignal.timeout(10000),
33
+ });
34
+ if (!res.ok) return null;
35
+ const data = await res.json();
36
+
37
+ if (data?.status !== 'ready' || !data.result?.file?.stream) {
38
+ return null;
39
+ }
40
+
41
+ const rawStreamPath = data.result.file.stream;
42
+ const fullStreamUrl = rawStreamPath.startsWith('http')
43
+ ? rawStreamPath
44
+ : `${BASE_URL}${rawStreamPath}`;
45
+
46
+ const qualityRaw = String(data.result.source?.quality || '1080,720,480');
47
+ const qualityParts = qualityRaw.split(',').map(q => q.trim()).filter(Boolean);
48
+ const maxQ = qualityParts.reduce((acc, curr) => {
49
+ const num = parseInt(curr, 10);
50
+ return num > acc ? num : acc;
51
+ }, 0);
52
+
53
+ const quality = maxQ > 0 ? `${maxQ}p` : 'Auto';
54
+ const qualitySummary = qualityParts.length > 0
55
+ ? qualityParts.map(q => `${q}p`).join('/')
56
+ : 'DASH';
57
+
58
+ const streamType = fullStreamUrl.includes('.mpd')
59
+ ? 'dash'
60
+ : fullStreamUrl.includes('.m3u8')
61
+ ? 'hls'
62
+ : 'dash';
63
+
64
+ const allUrls = [{
65
+ url: fullStreamUrl,
66
+ server: `Braflix - DASH (${qualitySummary})`,
67
+ quality,
68
+ type: streamType,
69
+ headers: PLAYBACK_HEADERS,
70
+ }];
71
+
72
+ return {
73
+ url: fullStreamUrl,
74
+ headers: PLAYBACK_HEADERS,
75
+ allUrls,
76
+ };
77
+ } catch {
78
+ return null;
79
+ }
80
+ }