@vyla-entertainment/sdk 1.17.0 → 1.19.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 +5 -5
- package/package.json +1 -1
- package/src/config.js +187 -118
- package/src/sources/cinecat.js +19 -0
- package/src/sources/cinesrc.js +398 -0
- package/src/sources/cinezo.js +55 -0
- package/src/sources/cno.js +95 -0
- package/src/sources/flaxmovies.js +91 -103
- package/src/sources/hexa.js +54 -0
- package/src/sources/hyper.js +36 -0
- package/src/sources/kickassanime.js +125 -0
- package/src/sources/lmscript.js +53 -25
- package/src/sources/movy.js +161 -233
- package/src/sources/net79.js +56 -0
- package/src/sources/rivo.js +54 -0
- package/src/sources/thugtv.js +56 -55
- package/src/sources/vidora.js +62 -0
- package/src/sources/yapgrid.js +63 -0
- package/src/sources/yastream.js +30 -0
- package/src/sources/anihq.js +0 -124
- package/src/sources/anineko.js +0 -190
- package/src/sources/movienight.js +0 -117
- package/src/sources/vidgod.js +0 -147
- package/src/sources/vidnest.js +0 -79
|
@@ -1,118 +1,106 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { fetchJson } from '../utils/helpers.js';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
export async function getStream({ id, s, e }) {
|
|
4
|
+
const isTv = s != null && e != null;
|
|
5
|
+
const allUrls = [];
|
|
4
6
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
+
}
|
|
21
27
|
}
|
|
28
|
+
},
|
|
22
29
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
if (m && m[1]) {
|
|
41
|
-
const wUrl = m[1].replace(/\/+$/, '');
|
|
42
|
-
if (!foundUrls.includes(wUrl)) foundUrls.push(wUrl);
|
|
43
|
-
}
|
|
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
|
+
});
|
|
44
47
|
}
|
|
45
|
-
}
|
|
48
|
+
}
|
|
46
49
|
}
|
|
47
|
-
}
|
|
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
|
-
});
|
|
50
|
+
},
|
|
81
51
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
'
|
|
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'
|
|
96
67
|
}
|
|
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;
|
|
68
|
+
});
|
|
69
|
+
}
|
|
104
70
|
}
|
|
71
|
+
}
|
|
72
|
+
},
|
|
105
73
|
|
|
106
|
-
|
|
107
|
-
|
|
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
|
+
}
|
|
108
92
|
}
|
|
109
93
|
}
|
|
110
|
-
}
|
|
111
|
-
|
|
94
|
+
}
|
|
95
|
+
];
|
|
96
|
+
|
|
97
|
+
await Promise.allSettled(endpoints.map(fn => fn().catch(() => { })));
|
|
112
98
|
|
|
113
|
-
return null;
|
|
114
|
-
}
|
|
99
|
+
if (!allUrls.length) return null;
|
|
115
100
|
|
|
116
|
-
|
|
117
|
-
|
|
101
|
+
return {
|
|
102
|
+
url: allUrls[0].url,
|
|
103
|
+
headers: allUrls[0].headers,
|
|
104
|
+
allUrls
|
|
105
|
+
};
|
|
118
106
|
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { fetchJson, fetchText } from '../utils/helpers.js';
|
|
2
|
+
|
|
3
|
+
const API = "https://enc-dec.app/api";
|
|
4
|
+
|
|
5
|
+
function getRandomHex(size = 32) {
|
|
6
|
+
const array = new Uint8Array(size);
|
|
7
|
+
crypto.getRandomValues(array);
|
|
8
|
+
return Array.from(array).map(b => b.toString(16).padStart(2, '0')).join('');
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export async function getStream({ id, s, e }) {
|
|
12
|
+
const isTv = s != null && e != null;
|
|
13
|
+
const key = getRandomHex(32);
|
|
14
|
+
|
|
15
|
+
const headers = {
|
|
16
|
+
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36",
|
|
17
|
+
"Referer": "https://hexa.su/",
|
|
18
|
+
"Accept": "text/plain",
|
|
19
|
+
"X-Fingerprint-Lite": "e9136c41504646444",
|
|
20
|
+
"X-Api-Key": key
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const encHexaRes = await fetchJson(`${API}/enc-hexa`);
|
|
24
|
+
if (!encHexaRes || encHexaRes.status !== 200) return null;
|
|
25
|
+
headers["X-Cap-Token"] = encHexaRes.result.token;
|
|
26
|
+
|
|
27
|
+
const url = isTv
|
|
28
|
+
? `https://theemoviedb.hexa.su/api/tmdb/tv/${id}/season/${s}/episode/${e}/images`
|
|
29
|
+
: `https://theemoviedb.hexa.su/api/tmdb/movie/${id}/images`;
|
|
30
|
+
|
|
31
|
+
const encrypted = await fetchText(url, { headers });
|
|
32
|
+
if (!encrypted) return null;
|
|
33
|
+
|
|
34
|
+
const decRes = await fetchJson(`${API}/dec-hexa`, {
|
|
35
|
+
method: "POST",
|
|
36
|
+
headers: { "Content-Type": "application/json" },
|
|
37
|
+
body: JSON.stringify({ text: encrypted, key })
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
if (!decRes || decRes.status !== 200 || !decRes.result) return null;
|
|
41
|
+
|
|
42
|
+
const data = decRes.result;
|
|
43
|
+
const streamUrl = data.url || data.file || (Array.isArray(data.sources) ? data.sources[0]?.url : null);
|
|
44
|
+
|
|
45
|
+
if (!streamUrl) return null;
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
url: streamUrl,
|
|
49
|
+
headers: {
|
|
50
|
+
Referer: "https://hexa.su/",
|
|
51
|
+
Origin: "https://hexa.su"
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
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 path = isTv
|
|
6
|
+
? `/local/stream/series/tmdb:${id}:${s}:${e}.json`
|
|
7
|
+
: `/local/stream/movie/tmdb:${id}.json`;
|
|
8
|
+
|
|
9
|
+
const url = `https://hyper.stravo.site${path}`;
|
|
10
|
+
const res = await fetchJson(url);
|
|
11
|
+
if (!res || !Array.isArray(res.streams)) return null;
|
|
12
|
+
|
|
13
|
+
const validStreams = res.streams.filter(item => {
|
|
14
|
+
if (!item.url || item.externalUrl) return false;
|
|
15
|
+
if (typeof item.title === 'string' && item.title.includes('🔒')) return false;
|
|
16
|
+
return true;
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
if (!validStreams.length) return null;
|
|
20
|
+
|
|
21
|
+
const allUrls = validStreams.map(item => ({
|
|
22
|
+
url: item.url,
|
|
23
|
+
server: `Hyper - ${item.title?.replace(/[^\x20-\x7E]+/g, '').trim() || 'Server'}`,
|
|
24
|
+
headers: item.behaviorHints?.proxyHeaders?.request || {
|
|
25
|
+
Referer: 'https://mzfi.me/',
|
|
26
|
+
Accept: '*/*'
|
|
27
|
+
},
|
|
28
|
+
skipProxy: item.behaviorHints?.notWebReady === false
|
|
29
|
+
}));
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
url: allUrls[0].url,
|
|
33
|
+
headers: allUrls[0].headers,
|
|
34
|
+
allUrls
|
|
35
|
+
};
|
|
36
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { fetchJson, USER_AGENT } from '../utils/helpers.js';
|
|
2
|
+
|
|
3
|
+
const BASE = "https://kaa.lt";
|
|
4
|
+
const HLS_BASE = "https://hls.krussdomi.com/manifest";
|
|
5
|
+
const HEADERS = { "User-Agent": USER_AGENT, Accept: "application/json" };
|
|
6
|
+
|
|
7
|
+
async function kaaSearch(query) {
|
|
8
|
+
const res = await fetchJson(`${BASE}/api/fsearch`, {
|
|
9
|
+
method: "POST",
|
|
10
|
+
headers: { ...HEADERS, "Content-Type": "application/json" },
|
|
11
|
+
body: JSON.stringify({ page: 1, query }),
|
|
12
|
+
}).catch(() => null);
|
|
13
|
+
return Array.isArray(res?.result) ? res.result : [];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async function kaaShowInfo(showSlug) {
|
|
17
|
+
return fetchJson(`${BASE}/api/show/${showSlug}`, { headers: HEADERS }).catch(() => null);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async function kaaEpisodePage(showSlug, ep) {
|
|
21
|
+
return fetchJson(`${BASE}/api/show/${showSlug}/episodes?ep=${ep}&lang=ja-JP`, { headers: HEADERS }).catch(() => null);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async function kaaAllEpisodes(showSlug) {
|
|
25
|
+
const first = await kaaEpisodePage(showSlug, 1);
|
|
26
|
+
if (!first) return [];
|
|
27
|
+
const pages = Array.isArray(first.pages) ? first.pages : [];
|
|
28
|
+
const all = Array.isArray(first.result) ? [...first.result] : [];
|
|
29
|
+
|
|
30
|
+
if (pages.length > 1) {
|
|
31
|
+
const rest = await Promise.all(
|
|
32
|
+
pages.slice(1).map(async (pg) => {
|
|
33
|
+
const startEp = pg.eps?.[0];
|
|
34
|
+
if (!startEp) return [];
|
|
35
|
+
const d = await kaaEpisodePage(showSlug, startEp);
|
|
36
|
+
return Array.isArray(d?.result) ? d.result : [];
|
|
37
|
+
})
|
|
38
|
+
);
|
|
39
|
+
for (const batch of rest) all.push(...batch);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return all;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async function kaaEpisodeServers(showSlug, fullEpSlug) {
|
|
46
|
+
return fetchJson(`${BASE}/api/show/${showSlug}/episode/${fullEpSlug}`, { headers: HEADERS }).catch(() => null);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export async function getStream({ id, s, e, tmdbApiKey, sdk }) {
|
|
50
|
+
try {
|
|
51
|
+
const apiKey = tmdbApiKey || sdk?.tmdbApiKey || process.env.TMDB_API_KEY || '45dbdd5e714da212424bda0336167447';
|
|
52
|
+
const isTv = !!s;
|
|
53
|
+
const mediaType = isTv ? 'tv' : 'movie';
|
|
54
|
+
const epNum = e ? Number(e) : 1;
|
|
55
|
+
|
|
56
|
+
let titles = [];
|
|
57
|
+
try {
|
|
58
|
+
const tmdbRes = await fetchJson(`https://api.themoviedb.org/3/${mediaType}/${id}?api_key=${apiKey}&append_to_response=alternative_titles`);
|
|
59
|
+
if (tmdbRes) {
|
|
60
|
+
const primary = tmdbRes.title || tmdbRes.name;
|
|
61
|
+
const original = tmdbRes.original_title || tmdbRes.original_name;
|
|
62
|
+
if (primary) titles.push(primary);
|
|
63
|
+
if (original && !titles.includes(original)) titles.push(original);
|
|
64
|
+
|
|
65
|
+
const alts = tmdbRes.alternative_titles?.titles || tmdbRes.alternative_titles?.results || [];
|
|
66
|
+
for (const alt of alts) {
|
|
67
|
+
const candidate = alt.title || alt.name;
|
|
68
|
+
if (candidate && !titles.includes(candidate)) {
|
|
69
|
+
titles.push(candidate);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
} catch { }
|
|
74
|
+
|
|
75
|
+
if (!titles.length) return null;
|
|
76
|
+
|
|
77
|
+
let showSlug = null;
|
|
78
|
+
for (const title of titles) {
|
|
79
|
+
const results = await kaaSearch(title);
|
|
80
|
+
if (results.length) {
|
|
81
|
+
showSlug = results[0].slug;
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (!showSlug) return null;
|
|
87
|
+
|
|
88
|
+
const showInfo = await kaaShowInfo(showSlug);
|
|
89
|
+
let fullEpSlug = null;
|
|
90
|
+
|
|
91
|
+
if (showInfo?.type === "movie") {
|
|
92
|
+
const m = (showInfo.watch_uri || "").match(/\/(ep-(\d+)-([a-f0-9]+))$/i);
|
|
93
|
+
if (m) fullEpSlug = m[1];
|
|
94
|
+
} else {
|
|
95
|
+
const episodes = await kaaAllEpisodes(showSlug);
|
|
96
|
+
const epItem = episodes.find((item) => item.episode_number === epNum);
|
|
97
|
+
if (epItem) fullEpSlug = `ep-${epItem.episode_number}-${epItem.slug}`;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (!fullEpSlug) return null;
|
|
101
|
+
|
|
102
|
+
const episodeData = await kaaEpisodeServers(showSlug, fullEpSlug);
|
|
103
|
+
const servers = Array.isArray(episodeData?.servers) ? episodeData.servers : [];
|
|
104
|
+
|
|
105
|
+
const urls = [];
|
|
106
|
+
for (const srv of servers) {
|
|
107
|
+
if (!srv.src) continue;
|
|
108
|
+
const m = srv.src.match(/[?&]id=([^&]+)/);
|
|
109
|
+
if (m) {
|
|
110
|
+
urls.push({
|
|
111
|
+
url: `${HLS_BASE}/${m[1]}/master.m3u8`,
|
|
112
|
+
server: `KickAssAnime (${srv.name || 'Server'})`,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return urls.length ? { allUrls: urls } : null;
|
|
118
|
+
} catch (err) {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export async function getSources() {
|
|
124
|
+
return ['KickAssAnime'];
|
|
125
|
+
}
|
package/src/sources/lmscript.js
CHANGED
|
@@ -1,43 +1,71 @@
|
|
|
1
1
|
import { getTmdbInfo } from '../utils/helpers.js';
|
|
2
2
|
|
|
3
3
|
export async function getStream(args) {
|
|
4
|
-
const { id, s, e, tmdbApiKey } = args;
|
|
4
|
+
const { id, s, e, tmdbApiKey, sdk } = args;
|
|
5
5
|
const type = (s != null && e != null) ? 'tv' : 'movie';
|
|
6
|
+
const apiKey = tmdbApiKey || sdk?.tmdbApiKey || process.env.TMDB_API_KEY || '45dbdd5e714da212424bda0336167447';
|
|
6
7
|
|
|
7
8
|
try {
|
|
8
|
-
const tmdbInfo = await getTmdbInfo(tmdbApiKey, id, type, s);
|
|
9
|
-
const name = tmdbInfo.titles[0] || '';
|
|
10
|
-
if (!name) return null;
|
|
11
|
-
|
|
12
9
|
if (type === 'tv') {
|
|
13
10
|
return null;
|
|
14
|
-
}
|
|
15
|
-
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const tmdbInfo = await getTmdbInfo(apiKey, id, type, s);
|
|
14
|
+
const titles = tmdbInfo?.titles || [];
|
|
15
|
+
if (!titles.length) return null;
|
|
16
|
+
|
|
17
|
+
let movie = null;
|
|
18
|
+
for (const title of titles) {
|
|
19
|
+
const url = `https://lmscript.xyz/v1/movies?filters[q]=${encodeURIComponent(title)}&expand=streams`;
|
|
16
20
|
const response = await fetch(url);
|
|
21
|
+
if (!response.ok) continue;
|
|
17
22
|
const data = await response.json();
|
|
18
23
|
|
|
19
|
-
const
|
|
20
|
-
|
|
24
|
+
const found = data.items?.find(item => {
|
|
25
|
+
const tmdbPrefixMatch = `${item.tmdb_prefix}` === `${id}`;
|
|
26
|
+
const tmdbIdMatch = `${item.tmdb_id}` === `${id}`;
|
|
27
|
+
const titleMatch = item.title?.toLowerCase() === title.toLowerCase();
|
|
28
|
+
return tmdbPrefixMatch || tmdbIdMatch || titleMatch;
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
if (found) {
|
|
32
|
+
movie = found;
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
21
36
|
|
|
22
|
-
|
|
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));
|
|
37
|
+
if (!movie) return null;
|
|
25
38
|
|
|
26
|
-
|
|
39
|
+
const streams = movie.streams || {};
|
|
40
|
+
const SOURCE_ORDER = ["1080p", "720p", "480p", "360p"];
|
|
41
|
+
const sortedStreams = Object.keys(streams).sort((a, b) => {
|
|
42
|
+
const indexA = SOURCE_ORDER.indexOf(a);
|
|
43
|
+
const indexB = SOURCE_ORDER.indexOf(b);
|
|
44
|
+
return (indexA === -1 ? 99 : indexA) - (indexB === -1 ? 99 : indexB);
|
|
45
|
+
});
|
|
27
46
|
|
|
28
|
-
|
|
29
|
-
const streamUrl = streams[quality];
|
|
30
|
-
return {
|
|
31
|
-
url: streamUrl,
|
|
32
|
-
quality,
|
|
33
|
-
type: streamUrl.includes('.m3u8') ? 'hls' : 'mp4',
|
|
34
|
-
headers: {}
|
|
35
|
-
};
|
|
36
|
-
});
|
|
47
|
+
if (!sortedStreams.length) return null;
|
|
37
48
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
49
|
+
const allUrls = sortedStreams.map(quality => {
|
|
50
|
+
const streamUrl = streams[quality];
|
|
51
|
+
return {
|
|
52
|
+
url: streamUrl,
|
|
53
|
+
quality,
|
|
54
|
+
server: `LMScript - ${quality}`,
|
|
55
|
+
type: streamUrl.includes('.m3u8') ? 'hls' : 'mp4',
|
|
56
|
+
headers: {
|
|
57
|
+
Referer: 'https://lookmovie2.to/',
|
|
58
|
+
Origin: 'https://lookmovie2.to'
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
return {
|
|
64
|
+
url: allUrls[0].url,
|
|
65
|
+
headers: allUrls[0].headers,
|
|
66
|
+
allUrls
|
|
67
|
+
};
|
|
68
|
+
} catch {
|
|
41
69
|
return null;
|
|
42
70
|
}
|
|
43
71
|
}
|