@vyla-entertainment/sdk 1.19.0 → 1.21.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 (52) hide show
  1. package/package.json +3 -2
  2. package/src/config.js +46 -85
  3. package/src/sdk.d.ts +94 -121
  4. package/src/sdk.js +82 -78
  5. package/src/sources/111477.js +88 -100
  6. package/src/sources/123anime.js +120 -56
  7. package/src/sources/3eyedraven.js +82 -135
  8. package/src/sources/cinecat.js +37 -18
  9. package/src/sources/cinemaarmy.js +179 -180
  10. package/src/sources/cinesrc.js +401 -397
  11. package/src/sources/cno.js +101 -94
  12. package/src/sources/dulo.js +134 -149
  13. package/src/sources/flaxmovies.js +114 -105
  14. package/src/sources/frost.js +39 -0
  15. package/src/sources/fsonline.js +95 -47
  16. package/src/sources/hdhub.js +43 -0
  17. package/src/sources/hexa.js +60 -53
  18. package/src/sources/hyper.js +42 -35
  19. package/src/sources/kickassanime.js +117 -124
  20. package/src/sources/kisskh.js +114 -59
  21. package/src/sources/lmscript.js +72 -70
  22. package/src/sources/lookmovie.js +80 -79
  23. package/src/sources/movenerds.js +74 -124
  24. package/src/sources/movy.js +197 -209
  25. package/src/sources/net79.js +59 -55
  26. package/src/sources/peestream.js +126 -138
  27. package/src/sources/pengu.js +46 -49
  28. package/src/sources/pstream.js +73 -67
  29. package/src/sources/purstream.js +96 -104
  30. package/src/sources/rivestream.js +182 -176
  31. package/src/sources/rivo.js +58 -53
  32. package/src/sources/streamaggregator.js +114 -128
  33. package/src/sources/thugtv.js +70 -62
  34. package/src/sources/vidapi.js +122 -114
  35. package/src/sources/vidcore.js +14 -122
  36. package/src/sources/vidfast.js +14 -122
  37. package/src/sources/vidlink.js +78 -27
  38. package/src/sources/vidup.js +14 -122
  39. package/src/sources/vidvault.js +133 -187
  40. package/src/sources/vidy.js +192 -187
  41. package/src/sources/vidzee.js +189 -183
  42. package/src/sources/vixsrc.js +123 -113
  43. package/src/sources/watchout.js +60 -0
  44. package/src/sources/xdownloader.js +127 -128
  45. package/src/sources/yapgrid.js +68 -62
  46. package/src/sources/yastream.js +35 -29
  47. package/src/subtitles.js +105 -122
  48. package/src/utils/helpers.js +586 -230
  49. package/src/sources/bcine.js +0 -202
  50. package/src/sources/cinezo.js +0 -55
  51. package/src/sources/vidora.js +0 -62
  52. package/src/sources/vidrock.js +0 -145
@@ -1,80 +1,81 @@
1
- import { USER_AGENT, fetchText, fetchJson } from '../utils/helpers.js';
2
-
3
- const TMDB_BASE = 'https://api.themoviedb.org/3';
4
- const LM_DOMAINS = ['https://www.lookmovie2.to', 'https://lookmovie2.to', 'https://lookmovie.foundation'];
5
- const HEADERS_BASE = { 'User-Agent': USER_AGENT, 'Accept-Language': 'en-US,en;q=0.9' };
6
-
7
- async function searchLookMovie(type, title, year, clientIP) {
8
- for (const base of LM_DOMAINS) {
9
- try {
10
- const headers = { ...HEADERS_BASE, 'Accept': 'application/json', 'Referer': `${base}/`, 'X-Requested-With': 'XMLHttpRequest', ...(clientIP && { 'X-Forwarded-For': clientIP }) };
11
- const data = await fetchJson(`${base}/api/v1/${type}/do-search/?q=${encodeURIComponent(title)}`, { headers, signal: AbortSignal.timeout(4000) });
12
- const results = data?.result;
13
- if (results?.length) {
14
- const match = results.find(r => String(r.year) === String(year)) ?? results.find(r => r.title?.toLowerCase() === title.toLowerCase()) ?? results[0];
15
- if (match) return { match, base };
16
- }
17
- } catch { }
18
- }
19
- return null;
20
- }
21
-
22
- const STORAGE_RE = /window\[['"](?:movie|show)_storage['"]\]\s*=\s*\{([^}]+)\}/s;
23
- const ID_MOVIE_RE = /['"]?(?:id_movie|movieId)['"]?\s*[:=]\s*['"]?(\d+)['"]?/i;
24
- const SEASONS_RE = /seasons\s*:\s*(\[[\s\S]+?\])\s*[,}]/;
25
-
26
- function getEpisodeIdFast(html, s, e) {
27
- const sMatch = html.match(STORAGE_RE);
28
- if (sMatch) {
29
- const block = sMatch[1], sm = block.match(SEASONS_RE);
30
- if (sm) {
31
- try {
32
- const seasons = JSON.parse(sm[1]);
33
- const season = seasons.find(x => String(x?.season ?? x?.meta?.season) === String(s));
34
- if (season) {
35
- const ep = Array.isArray(season.episodes) ? season.episodes.find(x => String(x.episode) === String(e)) : (season.episodes?.[String(e)] || Object.values(season.episodes || {}).find(x => String(x.episode) === String(e)));
36
- if (ep) return String(ep.id_episode ?? ep.id);
37
- }
38
- } catch { }
39
- }
40
- }
41
- const parts = html.split(/id_episode['"]?\s*[:=]\s*['"]?(\d+)['"]?/i);
42
- for (let i = 1; i < parts.length; i += 2) {
43
- const context = parts[i - 1].slice(-300) + parts[i + 1].slice(0, 300);
44
- if (context.match(new RegExp(`['"]?episode['"]?\\s*[:=]\\s*['"]?${e}['"]?`, 'i')) && context.match(new RegExp(`['"]?season['"]?\\s*[:=]\\s*['"]?${s}['"]?`, 'i'))) return parts[i];
45
- }
46
- const am = html.match(new RegExp(`data-season=["']${s}["'][^>]*?data-episode=["']${e}["'][^>]*?data-id=["'](\\d+)["']`, 'i')) || html.match(new RegExp(`data-episode=["']${e}["'][^>]*?data-season=["']${s}["'][^>]*?data-id=["'](\\d+)["']`, 'i'));
47
- return am ? am[1] : null;
48
- }
49
-
50
- export async function getStream({ id, s, e, sdk, clientIP }) {
51
- const tmdbApiKey = sdk?.tmdbApiKey || null;
52
- if (!tmdbApiKey) return null;
53
- try {
54
- const tmdbKey = tmdbApiKey;
55
- if (!tmdbKey) return null;
56
- const isTV = s != null && e != null;
57
- const typeStr = isTV ? 'shows' : 'movies';
58
- const tmdbData = await fetchJson(`${TMDB_BASE}/${isTV ? 'tv' : 'movie'}/${id}?api_key=${tmdbKey}`, { signal: AbortSignal.timeout(3000) });
59
- const title = tmdbData?.title || tmdbData?.name;
60
- const year = (tmdbData?.first_air_date || tmdbData?.release_date || '').slice(0, 4);
61
- if (!title) return null;
62
- const searchRes = await searchLookMovie(typeStr, title, year, clientIP);
63
- if (!searchRes?.match?.slug) return null;
64
- const { match, base } = searchRes;
65
- const headers = { ...HEADERS_BASE, 'Accept': 'text/html', 'Referer': `${base}/`, ...(clientIP && { 'X-Forwarded-For': clientIP }) };
66
- const html = await fetchText(`${base}/${typeStr}/play/${match.slug}`, { headers, signal: AbortSignal.timeout(8000) });
67
- const storageMatch = html.match(STORAGE_RE);
68
- if (!storageMatch) return null;
69
- const hashMatch = storageMatch[1].match(/hash\s*:\s*['"]([^'"]+)['"]/);
70
- const expiresMatch = storageMatch[1].match(/expires\s*:\s*(\d+)/);
71
- if (!hashMatch || !expiresMatch) return null;
72
- const streamId = isTV ? getEpisodeIdFast(html, s, e) : (match.id_movie || match.id || html.match(ID_MOVIE_RE)?.[1]);
73
- if (!streamId) return null;
74
- const accessHeaders = { ...HEADERS_BASE, 'Accept': 'application/json', 'Referer': `${base}/`, 'X-Requested-With': 'XMLHttpRequest', ...(clientIP && { 'X-Forwarded-For': clientIP }) };
75
- const data = await fetchJson(`${base}/api/v1/security/${isTV ? 'episode' : 'movie'}-access?id_${isTV ? 'episode' : 'movie'}=${streamId}&hash=${hashMatch[1]}&expires=${expiresMatch[1]}`, { headers: accessHeaders, signal: AbortSignal.timeout(8000) });
76
- const streams = data?.streams ?? data?.result?.streams ?? data?.data?.streams ?? data;
77
- const allUrls = Object.entries(streams || {}).filter(([, v]) => typeof v === 'string' && v.includes('.m3u8')).map(([quality, url]) => ({ url, quality }));
78
- return allUrls.length ? { allUrls } : null;
79
- } catch { return null; }
1
+ import { USER_AGENT, fetchText, fetchJson } from '../utils/helpers.js';
2
+
3
+ const TMDB_BASE = 'https://api.themoviedb.org/3';
4
+ const LM_DOMAINS = ['https://www.lookmovie2.to', 'https://lookmovie2.to', 'https://lookmovie.foundation'];
5
+
6
+ const HEADERS_BASE = { 'User-Agent': USER_AGENT, 'Accept-Language': 'en-US,en;q=0.9' };
7
+
8
+ async function searchLookMovie(type, title, year, clientIP) {
9
+ for (const base of LM_DOMAINS) {
10
+ try {
11
+ const headers = { ...HEADERS_BASE, 'Accept': 'application/json', 'Referer': `${base}/`, 'X-Requested-With': 'XMLHttpRequest', ...(clientIP && { 'X-Forwarded-For': clientIP }) };
12
+ const data = await fetchJson(`${base}/api/v1/${type}/do-search/?q=${encodeURIComponent(title)}`, { headers, signal: AbortSignal.timeout(4000) });
13
+ const results = data?.result;
14
+ if (results?.length) {
15
+ const match = results.find(r => String(r.year) === String(year)) ?? results.find(r => r.title?.toLowerCase() === title.toLowerCase()) ?? results[0];
16
+ if (match) return { match, base };
17
+ }
18
+ } catch { }
19
+ }
20
+ return null;
21
+ }
22
+
23
+ const STORAGE_RE = /window\[['"](?:movie|show)_storage['"]\]\s*=\s*\{([^}]+)\}/s;
24
+ const ID_MOVIE_RE = /['"]?(?:id_movie|movieId)['"]?\s*[:=]\s*['"]?(\d+)['"]?/i;
25
+ const SEASONS_RE = /seasons\s*:\s*(\[[\s\S]+?\])\s*[,}]/;
26
+
27
+ function getEpisodeIdFast(html, s, e) {
28
+ const sMatch = html.match(STORAGE_RE);
29
+ if (sMatch) {
30
+ const block = sMatch[1], sm = block.match(SEASONS_RE);
31
+ if (sm) {
32
+ try {
33
+ const seasons = JSON.parse(sm[1]);
34
+ const season = seasons.find(x => String(x?.season ?? x?.meta?.season) === String(s));
35
+ if (season) {
36
+ const ep = Array.isArray(season.episodes) ? season.episodes.find(x => String(x.episode) === String(e)) : (season.episodes?.[String(e)] || Object.values(season.episodes || {}).find(x => String(x.episode) === String(e)));
37
+ if (ep) return String(ep.id_episode ?? ep.id);
38
+ }
39
+ } catch { }
40
+ }
41
+ }
42
+ const parts = html.split(/id_episode['"]?\s*[:=]\s*['"]?(\d+)['"]?/i);
43
+ for (let i = 1; i < parts.length; i += 2) {
44
+ const context = parts[i - 1].slice(-300) + parts[i + 1].slice(0, 300);
45
+ if (context.match(new RegExp(`['"]?episode['"]?\\s*[:=]\\s*['"]?${e}['"]?`, 'i')) && context.match(new RegExp(`['"]?season['"]?\\s*[:=]\\s*['"]?${s}['"]?`, 'i'))) return parts[i];
46
+ }
47
+ const am = html.match(new RegExp(`data-season=["']${s}["'][^>]*?data-episode=["']${e}["'][^>]*?data-id=["'](\\d+)["']`, 'i')) || html.match(new RegExp(`data-episode=["']${e}["'][^>]*?data-season=["']${s}["'][^>]*?data-id=["'](\\d+)["']`, 'i'));
48
+ return am ? am[1] : null;
49
+ }
50
+
51
+ export async function getStream({ id, s, e, sdk, clientIP }) {
52
+ const tmdbApiKey = sdk?.tmdbApiKey || null;
53
+ if (!tmdbApiKey) return null;
54
+ try {
55
+ const tmdbKey = tmdbApiKey;
56
+ if (!tmdbKey) return null;
57
+ const isTV = s != null && e != null;
58
+ const typeStr = isTV ? 'shows' : 'movies';
59
+ const tmdbData = await fetchJson(`${TMDB_BASE}/${isTV ? 'tv' : 'movie'}/${id}?api_key=${tmdbKey}`, { signal: AbortSignal.timeout(3000) });
60
+ const title = tmdbData?.title || tmdbData?.name;
61
+ const year = (tmdbData?.first_air_date || tmdbData?.release_date || '').slice(0, 4);
62
+ if (!title) return null;
63
+ const searchRes = await searchLookMovie(typeStr, title, year, clientIP);
64
+ if (!searchRes?.match?.slug) return null;
65
+ const { match, base } = searchRes;
66
+ const headers = { ...HEADERS_BASE, 'Accept': 'text/html', 'Referer': `${base}/`, ...(clientIP && { 'X-Forwarded-For': clientIP }) };
67
+ const html = await fetchText(`${base}/${typeStr}/play/${match.slug}`, { headers, signal: AbortSignal.timeout(8000) });
68
+ const storageMatch = html.match(STORAGE_RE);
69
+ if (!storageMatch) return null;
70
+ const hashMatch = storageMatch[1].match(/hash\s*:\s*['"]([^'"]+)['"]/);
71
+ const expiresMatch = storageMatch[1].match(/expires\s*:\s*(\d+)/);
72
+ if (!hashMatch || !expiresMatch) return null;
73
+ const streamId = isTV ? getEpisodeIdFast(html, s, e) : (match.id_movie || match.id || html.match(ID_MOVIE_RE)?.[1]);
74
+ if (!streamId) return null;
75
+ const accessHeaders = { ...HEADERS_BASE, 'Accept': 'application/json', 'Referer': `${base}/`, 'X-Requested-With': 'XMLHttpRequest', ...(clientIP && { 'X-Forwarded-For': clientIP }) };
76
+ const data = await fetchJson(`${base}/api/v1/security/${isTV ? 'episode' : 'movie'}-access?id_${isTV ? 'episode' : 'movie'}=${streamId}&hash=${hashMatch[1]}&expires=${expiresMatch[1]}`, { headers: accessHeaders, signal: AbortSignal.timeout(8000) });
77
+ const streams = data?.streams ?? data?.result?.streams ?? data?.data?.streams ?? data;
78
+ const allUrls = Object.entries(streams || {}).filter(([, v]) => typeof v === 'string' && v.includes('.m3u8')).map(([quality, url]) => ({ url, quality }));
79
+ return allUrls.length ? { allUrls } : null;
80
+ } catch { return null; }
80
81
  }
@@ -1,125 +1,75 @@
1
- import { getUA } from "../utils/helpers.js";
2
-
3
- const API_BASE = "https://api.movenerds.space/api";
4
-
5
- function getHeaders() {
6
- return {
7
- "User-Agent": getUA(),
8
- Accept: "application/json",
9
- Referer: "https://movenerds.space/",
10
- Origin: "https://movenerds.space",
11
- };
12
- }
13
-
14
- function resolveApiKey(args) {
15
- return (
16
- args?.tmdbApiKey ||
17
- args?.sdk?.tmdbApiKey ||
18
- process.env.TMDB_API_KEY ||
19
- null
20
- );
21
- }
22
-
23
- async function getMeta(id, isTv, apiKey) {
24
- if (!apiKey) return null;
25
- const type = isTv ? "tv" : "movie";
26
- try {
27
- const res = await fetch(
28
- `https://api.themoviedb.org/3/${type}/${id}?api_key=${apiKey}`,
29
- { signal: AbortSignal.timeout(5000) }
30
- );
31
- if (!res.ok) return null;
32
- const data = await res.json();
33
- const title = isTv ? data.name : data.title;
34
- const date = isTv ? data.first_air_date : data.release_date;
35
- const year = date ? parseInt(date.slice(0, 4), 10) : null;
36
- return { title, year };
37
- } catch {
38
- return null;
39
- }
40
- }
41
-
42
- function mapSource(source) {
43
- if (!source || !source.url) return null;
44
- if (source.type !== "hls" && source.type !== "mp4") return null;
45
- if (!/^https?:\/\//.test(source.url)) return null;
46
-
47
- return {
48
- url: source.url,
49
- headers: {
50
- "User-Agent": source.headers?.["User-Agent"] || getUA(),
51
- Referer: source.headers?.Referer || "https://movenerds.space/",
52
- Origin: source.headers?.Origin || "https://movenerds.space",
53
- },
54
- server: source.name || source.providerName || "MoverNerds",
55
- quality: source.quality || "1080p",
56
- type: source.type,
57
- skipProxy: true,
58
- };
59
- }
60
-
61
- export async function getStream(args) {
62
- const { id, s = null, e = null } = args;
63
- const isTv = s != null && e != null;
64
-
65
- const apiKey = resolveApiKey(args);
66
- const meta = await getMeta(id, isTv, apiKey);
67
-
68
- if (!meta?.title) {
69
- if (process.env.DEBUG_CAUSE) {
70
- console.error(
71
- `[movenerds] Could not resolve title for ${isTv ? "tv" : "movie"} ${id} ` +
72
- `(tmdbApiKey ${apiKey ? "present" : "MISSING"})`
73
- );
74
- }
75
- return null;
76
- }
77
-
78
- const params = new URLSearchParams({
79
- tmdbId: String(id),
80
- type: isTv ? "tv" : "movie",
81
- title: meta.title,
82
- });
83
- if (meta.year) params.set("year", String(meta.year));
84
- if (isTv) {
85
- params.set("season", String(s));
86
- params.set("episode", String(e));
87
- params.set("language", "en");
88
- }
89
-
90
- const url = `${API_BASE}/stream?${params.toString()}`;
91
-
92
- try {
93
- const res = await fetch(url, {
94
- headers: getHeaders(),
95
- signal: AbortSignal.timeout(20000),
96
- });
97
-
98
- if (!res.ok) {
99
- if (process.env.DEBUG_CAUSE) {
100
- console.error(`[movenerds] HTTP ${res.status} for ${url}`);
101
- }
102
- return null;
103
- }
104
-
105
- const data = await res.json();
106
- const primary = Array.isArray(data?.primarySources) ? data.primarySources : [];
107
- if (!primary.length) {
108
- if (process.env.DEBUG_CAUSE) {
109
- console.error(`[movenerds] No primarySources in response for ${url}`);
110
- }
111
- return null;
112
- }
113
-
114
- const allUrls = primary.map(mapSource).filter(Boolean);
115
- if (!allUrls.length) return null;
116
-
117
- return { allUrls };
118
- } catch (err) {
119
- if (process.env.DEBUG_CAUSE) {
120
- console.error(`[movenerds] fetch error for ${url}:`, err.message);
121
- if (err.cause) console.error(" cause:", err.cause.code, err.cause.message);
122
- }
123
- return null;
124
- }
1
+ import { getTmdbMetadata, getUA, resolveTmdbKey } from '../utils/helpers.js';
2
+
3
+ const BASE_URL = 'https://movenerds.space';
4
+ const API_BASE = 'https://api.movenerds.space/api';
5
+
6
+ function mapSource(source) {
7
+ if (!source || !source.url) return null;
8
+ if (source.type !== 'hls' && source.type !== 'mp4') return null;
9
+ if (!/^https?:\/\//.test(source.url)) return null;
10
+
11
+ return {
12
+ url: source.url,
13
+ headers: {
14
+ 'User-Agent': source.headers?.['User-Agent'] || getUA(),
15
+ Referer: source.headers?.Referer || `${BASE_URL}/`,
16
+ Origin: source.headers?.Origin || BASE_URL,
17
+ },
18
+ server: source.name || source.providerName || 'MoverNerds',
19
+ quality: source.quality || '1080p',
20
+ type: source.type,
21
+ skipProxy: true,
22
+ };
23
+ }
24
+
25
+ export async function getStream(args) {
26
+ const { id, s, e, sdk } = args || {};
27
+ const isTv = s != null && e != null;
28
+ const apiKey = resolveTmdbKey(args, sdk);
29
+
30
+ const meta = await getTmdbMetadata(id, isTv, apiKey);
31
+ if (!meta?.title) return null;
32
+
33
+ const params = new URLSearchParams({
34
+ tmdbId: String(id),
35
+ type: isTv ? 'tv' : 'movie',
36
+ title: meta.title,
37
+ });
38
+ if (meta.year) params.set('year', String(meta.year));
39
+ if (isTv) {
40
+ params.set('season', String(s));
41
+ params.set('episode', String(e));
42
+ params.set('language', 'en');
43
+ }
44
+
45
+ const url = `${API_BASE}/stream?${params.toString()}`;
46
+ const headers = {
47
+ 'User-Agent': getUA(),
48
+ Accept: 'application/json',
49
+ Referer: `${BASE_URL}/`,
50
+ Origin: BASE_URL,
51
+ };
52
+
53
+ try {
54
+ const res = await fetch(url, {
55
+ headers,
56
+ signal: AbortSignal.timeout(20000),
57
+ });
58
+ if (!res.ok) return null;
59
+
60
+ const data = await res.json();
61
+ const primary = Array.isArray(data?.primarySources) ? data.primarySources : [];
62
+ if (!primary.length) return null;
63
+
64
+ const allUrls = primary.map(mapSource).filter(Boolean);
65
+ if (!allUrls.length) return null;
66
+
67
+ return {
68
+ url: allUrls[0].url,
69
+ headers: allUrls[0].headers,
70
+ allUrls,
71
+ };
72
+ } catch {
73
+ return null;
74
+ }
125
75
  }