@vyla-entertainment/sdk 1.12.0 → 1.14.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/package.json +1 -1
- package/src/config.js +13 -215
- package/src/sources/dulo.js +150 -0
- package/src/sources/streamaggregator.js +5 -3
- package/src/sources/vidcore.js +115 -35
- package/src/sources/vidfast.js +118 -48
- package/src/sources/vidup.js +102 -58
- package/src/sources/4khdhub.js +0 -324
- package/src/sources/cinejoy.js +0 -195
- package/src/sources/cinesrc.js +0 -212
- package/src/sources/cinesu.js +0 -148
- package/src/sources/downloadeverything.js +0 -338
- package/src/sources/frame.js +0 -88
- package/src/sources/fsharetv.js +0 -44
- package/src/sources/fsonic.js +0 -49
- package/src/sources/hexa.js +0 -82
- package/src/sources/luna.js +0 -125
- package/src/sources/meowtv.js +0 -142
- package/src/sources/peestream.js +0 -122
- package/src/sources/vadapav.js +0 -85
- package/src/sources/vuflix.js +0 -249
package/src/sources/cinesu.js
DELETED
|
@@ -1,148 +0,0 @@
|
|
|
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
|
-
};
|
|
148
|
-
}
|
|
@@ -1,338 +0,0 @@
|
|
|
1
|
-
import { getUA } from '../utils/helpers.js';
|
|
2
|
-
|
|
3
|
-
const SLAVE_URL = 'https://slave.downloadeverythingfromeverywhere.com/';
|
|
4
|
-
const REFERER = 'https://downloadeverythingfromeverywhere.com/';
|
|
5
|
-
const ORIGIN = 'https://downloadeverythingfromeverywhere.com';
|
|
6
|
-
const USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36';
|
|
7
|
-
|
|
8
|
-
function extractJsonObjects(text) {
|
|
9
|
-
const objects = [];
|
|
10
|
-
let depth = 0;
|
|
11
|
-
let start = -1;
|
|
12
|
-
let inString = false;
|
|
13
|
-
let escape = false;
|
|
14
|
-
|
|
15
|
-
for (let i = 0; i < text.length; i++) {
|
|
16
|
-
const char = text[i];
|
|
17
|
-
if (escape) {
|
|
18
|
-
escape = false;
|
|
19
|
-
continue;
|
|
20
|
-
}
|
|
21
|
-
if (char === '\\') {
|
|
22
|
-
escape = true;
|
|
23
|
-
continue;
|
|
24
|
-
}
|
|
25
|
-
if (char === '"') {
|
|
26
|
-
inString = !inString;
|
|
27
|
-
continue;
|
|
28
|
-
}
|
|
29
|
-
if (!inString) {
|
|
30
|
-
if (char === '{') {
|
|
31
|
-
if (depth === 0) start = i;
|
|
32
|
-
depth++;
|
|
33
|
-
} else if (char === '}') {
|
|
34
|
-
depth--;
|
|
35
|
-
if (depth === 0 && start !== -1) {
|
|
36
|
-
const jsonStr = text.substring(start, i + 1);
|
|
37
|
-
try {
|
|
38
|
-
objects.push(JSON.parse(jsonStr));
|
|
39
|
-
} catch { }
|
|
40
|
-
start = -1;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
return objects;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
async function resolveDetails(sdk, id, isTv) {
|
|
49
|
-
const apiKey = sdk?.tmdbApiKey || process.env.TMDB_API_KEY;
|
|
50
|
-
if (!apiKey) return null;
|
|
51
|
-
const type = isTv ? 'tv' : 'movie';
|
|
52
|
-
try {
|
|
53
|
-
const res = await fetch(`https://api.themoviedb.org/3/${type}/${id}?api_key=${apiKey}&append_to_response=external_ids`, {
|
|
54
|
-
signal: AbortSignal.timeout(6000),
|
|
55
|
-
});
|
|
56
|
-
if (!res.ok) return null;
|
|
57
|
-
const data = await res.json();
|
|
58
|
-
const title = isTv ? data.name : data.title;
|
|
59
|
-
const releaseDate = isTv ? data.first_air_date : data.release_date;
|
|
60
|
-
const year = releaseDate ? parseInt(releaseDate.split('-')[0], 10) : null;
|
|
61
|
-
const imdbId = data.imdb_id || data.external_ids?.imdb_id || null;
|
|
62
|
-
return { title, year, imdbId };
|
|
63
|
-
} catch {
|
|
64
|
-
return null;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
async function resolveHubCloud(hubUrl, ua) {
|
|
69
|
-
try {
|
|
70
|
-
const res1 = await fetch(hubUrl, {
|
|
71
|
-
headers: {
|
|
72
|
-
'User-Agent': ua,
|
|
73
|
-
Referer: REFERER,
|
|
74
|
-
},
|
|
75
|
-
signal: AbortSignal.timeout(8000),
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
const html = await res1.text();
|
|
79
|
-
const hubPhpMatch = html.match(/https?:\/\/[^\s"<>]+\/hubcloud\.php\?[^\s"<>]+/i);
|
|
80
|
-
if (!hubPhpMatch) return null;
|
|
81
|
-
|
|
82
|
-
const phpUrl = hubPhpMatch[0];
|
|
83
|
-
const phpRes = await fetch(phpUrl, {
|
|
84
|
-
headers: {
|
|
85
|
-
'User-Agent': ua,
|
|
86
|
-
Referer: hubUrl,
|
|
87
|
-
},
|
|
88
|
-
signal: AbortSignal.timeout(8000),
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
const phpBody = await phpRes.text();
|
|
92
|
-
|
|
93
|
-
const r2Match = phpBody.match(/https?:\/\/[a-zA-Z0-9.\-_]+\.r2\.cloudflarestorage\.com\/[^\s"<>]+/i);
|
|
94
|
-
if (r2Match) {
|
|
95
|
-
return r2Match[0].replaceAll('&', '&');
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
const pixelMatch = phpBody.match(/https?:\/\/pixel\.hubcloud\.[a-z]+\/\?id=[^\s"<>]+/i);
|
|
99
|
-
if (pixelMatch) {
|
|
100
|
-
return pixelMatch[0];
|
|
101
|
-
}
|
|
102
|
-
} catch { }
|
|
103
|
-
return null;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
async function resolveClicknUpload(clicknUrl, ua) {
|
|
107
|
-
try {
|
|
108
|
-
const res1 = await fetch(clicknUrl, {
|
|
109
|
-
headers: {
|
|
110
|
-
'User-Agent': ua,
|
|
111
|
-
Referer: REFERER,
|
|
112
|
-
},
|
|
113
|
-
signal: AbortSignal.timeout(8000),
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
const body1 = await res1.text();
|
|
117
|
-
const formMatch1 = body1.match(/<form[^>]+method=["']POST["'][^>]*>([\s\S]*?)<\/form>/i);
|
|
118
|
-
if (!formMatch1) return null;
|
|
119
|
-
|
|
120
|
-
const inputMatches1 = [...formMatch1[1].matchAll(/<input[^>]+name=["']([^"']+)["'][^>]+value=["']([^"']*)["']/gi)];
|
|
121
|
-
const params1 = new URLSearchParams();
|
|
122
|
-
for (const m of inputMatches1) {
|
|
123
|
-
params1.set(m[1], m[2]);
|
|
124
|
-
}
|
|
125
|
-
params1.set('method_free', 'Slow Download');
|
|
126
|
-
|
|
127
|
-
const rawCookies = res1.headers.getSetCookie?.() || [res1.headers.get('set-cookie')].filter(Boolean);
|
|
128
|
-
const cookieHeader = rawCookies.join('; ');
|
|
129
|
-
|
|
130
|
-
const res2 = await fetch(clicknUrl, {
|
|
131
|
-
method: 'POST',
|
|
132
|
-
headers: {
|
|
133
|
-
'User-Agent': ua,
|
|
134
|
-
Referer: clicknUrl,
|
|
135
|
-
'Content-Type': 'application/x-www-form-urlencoded',
|
|
136
|
-
...(cookieHeader ? { Cookie: cookieHeader } : {}),
|
|
137
|
-
},
|
|
138
|
-
body: params1.toString(),
|
|
139
|
-
signal: AbortSignal.timeout(8000),
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
const body2 = await res2.text();
|
|
143
|
-
const formMatch2 = body2.match(/<form[^>]+method=["']POST["'][^>]*>([\s\S]*?)<\/form>/i);
|
|
144
|
-
if (!formMatch2) return null;
|
|
145
|
-
|
|
146
|
-
const inputMatches2 = [...formMatch2[1].matchAll(/<input[^>]+name=["']([^"']+)["'][^>]+value=["']([^"']*)["']/gi)];
|
|
147
|
-
const params2 = new URLSearchParams();
|
|
148
|
-
for (const m of inputMatches2) {
|
|
149
|
-
params2.set(m[1], m[2]);
|
|
150
|
-
}
|
|
151
|
-
params2.set('down_script', '1');
|
|
152
|
-
|
|
153
|
-
await new Promise(r => setTimeout(r, 4500));
|
|
154
|
-
|
|
155
|
-
const res3 = await fetch(clicknUrl, {
|
|
156
|
-
method: 'POST',
|
|
157
|
-
headers: {
|
|
158
|
-
'User-Agent': ua,
|
|
159
|
-
Referer: clicknUrl,
|
|
160
|
-
'Content-Type': 'application/x-www-form-urlencoded',
|
|
161
|
-
...(cookieHeader ? { Cookie: cookieHeader } : {}),
|
|
162
|
-
},
|
|
163
|
-
body: params2.toString(),
|
|
164
|
-
signal: AbortSignal.timeout(8000),
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
const body3 = await res3.text();
|
|
168
|
-
const directMatch = body3.match(/https?:\/\/[a-zA-Z0-9.\-_:]+\/d\/[a-zA-Z0-9_\-\/]+/i) ||
|
|
169
|
-
body3.match(/window\.open\(["'](https?:\/\/[^"']+)["']\)/i);
|
|
170
|
-
|
|
171
|
-
if (directMatch) {
|
|
172
|
-
const found = directMatch[1] || directMatch[0];
|
|
173
|
-
if (found.includes('clicknupload.') && !found.includes('/d/')) {
|
|
174
|
-
return null;
|
|
175
|
-
}
|
|
176
|
-
return found;
|
|
177
|
-
}
|
|
178
|
-
} catch { }
|
|
179
|
-
return null;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
async function resolveItem(item, fallbackTitle, ua) {
|
|
183
|
-
const rawUrl = String(item.url || '').trim();
|
|
184
|
-
if (!rawUrl) return null;
|
|
185
|
-
|
|
186
|
-
if (
|
|
187
|
-
rawUrl.includes('111477.xyz') ||
|
|
188
|
-
rawUrl.includes('vadapav.mov') ||
|
|
189
|
-
rawUrl.includes('driveseed.org') ||
|
|
190
|
-
rawUrl.includes('new3.gdflix.io') ||
|
|
191
|
-
rawUrl.includes('rapidrar.cr') ||
|
|
192
|
-
rawUrl.includes('megaup.net') ||
|
|
193
|
-
rawUrl.includes('telegram.dog') ||
|
|
194
|
-
rawUrl.includes('t.me')
|
|
195
|
-
) {
|
|
196
|
-
return null;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
let directStreamUrl = null;
|
|
200
|
-
let provider = item.site || 'DownloadEverything';
|
|
201
|
-
let streamHeaders = { 'User-Agent': ua };
|
|
202
|
-
|
|
203
|
-
try {
|
|
204
|
-
if (rawUrl.includes('hakunaymatata.com')) {
|
|
205
|
-
directStreamUrl = rawUrl;
|
|
206
|
-
provider = 'Moviebox';
|
|
207
|
-
streamHeaders = { 'User-Agent': 'Lavf/60.16.100' };
|
|
208
|
-
} else if (rawUrl.includes('pixeldrain.dev') || rawUrl.includes('pixeldrain.com')) {
|
|
209
|
-
const m = rawUrl.match(/pixeldrain\.(?:dev|com)\/(?:u|l)\/([a-zA-Z0-9_-]+)/);
|
|
210
|
-
if (m) {
|
|
211
|
-
directStreamUrl = `https://pixeldrain.com/api/file/${m[1]}`;
|
|
212
|
-
provider = 'Pixeldrain';
|
|
213
|
-
}
|
|
214
|
-
} else if (rawUrl.includes('hubcloud.') || rawUrl.includes('vcloud.zip')) {
|
|
215
|
-
directStreamUrl = await resolveHubCloud(rawUrl, ua);
|
|
216
|
-
if (directStreamUrl) {
|
|
217
|
-
provider = 'HubCloud';
|
|
218
|
-
}
|
|
219
|
-
} else if (rawUrl.includes('clicknupload.')) {
|
|
220
|
-
directStreamUrl = await resolveClicknUpload(rawUrl, ua);
|
|
221
|
-
if (directStreamUrl) {
|
|
222
|
-
provider = 'ClicknUpload';
|
|
223
|
-
}
|
|
224
|
-
} else if (
|
|
225
|
-
/\.(?:mp4|mkv)(?:\?|$)/i.test(rawUrl) &&
|
|
226
|
-
!rawUrl.includes('111477.xyz') &&
|
|
227
|
-
!rawUrl.includes('vadapav.mov') &&
|
|
228
|
-
!rawUrl.includes('.cyou/res/')
|
|
229
|
-
) {
|
|
230
|
-
try {
|
|
231
|
-
const check = await fetch(rawUrl, {
|
|
232
|
-
method: 'HEAD',
|
|
233
|
-
headers: { 'User-Agent': ua },
|
|
234
|
-
signal: AbortSignal.timeout(2000),
|
|
235
|
-
});
|
|
236
|
-
if (check.status === 200 || check.status === 206 || (check.status >= 300 && check.status < 400)) {
|
|
237
|
-
directStreamUrl = rawUrl;
|
|
238
|
-
provider = item.site || 'DirectStream';
|
|
239
|
-
}
|
|
240
|
-
} catch { }
|
|
241
|
-
}
|
|
242
|
-
} catch { }
|
|
243
|
-
|
|
244
|
-
if (!directStreamUrl) return null;
|
|
245
|
-
|
|
246
|
-
const tags = Array.isArray(item.tags) ? item.tags.map(String) : [];
|
|
247
|
-
const qualityMatch = tags.find(t => /2160p|4k|1080p|720p|480p/i.test(t)) || '1080p';
|
|
248
|
-
const rawTitle = item.name || item.release || fallbackTitle;
|
|
249
|
-
|
|
250
|
-
return {
|
|
251
|
-
url: directStreamUrl,
|
|
252
|
-
label: `[${provider}] ${rawTitle} (${qualityMatch})`,
|
|
253
|
-
headers: streamHeaders,
|
|
254
|
-
};
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
export async function getStream({ id, s, e, sdk }) {
|
|
258
|
-
const isTv = Boolean(s && e);
|
|
259
|
-
const mediaType = isTv ? 'series' : 'movie';
|
|
260
|
-
const ua = USER_AGENT;
|
|
261
|
-
|
|
262
|
-
const details = await resolveDetails(sdk, id, isTv);
|
|
263
|
-
const title = details?.title || String(id);
|
|
264
|
-
const tmdbId = parseInt(id, 10);
|
|
265
|
-
|
|
266
|
-
const payload = {
|
|
267
|
-
mode: mediaType,
|
|
268
|
-
title,
|
|
269
|
-
...(details?.year ? { year: String(details.year) } : {}),
|
|
270
|
-
...(tmdbId ? { tmdb_id: tmdbId } : {}),
|
|
271
|
-
...(details?.imdbId ? { imdb_id: details.imdbId } : {}),
|
|
272
|
-
...(isTv && s != null ? { season: Number(s) } : {}),
|
|
273
|
-
...(isTv && e != null ? { episode: Number(e) } : {}),
|
|
274
|
-
};
|
|
275
|
-
|
|
276
|
-
const res = await fetch(SLAVE_URL, {
|
|
277
|
-
method: 'POST',
|
|
278
|
-
headers: {
|
|
279
|
-
'User-Agent': ua,
|
|
280
|
-
Origin: ORIGIN,
|
|
281
|
-
Referer: REFERER,
|
|
282
|
-
'Content-Type': 'application/json',
|
|
283
|
-
Accept: 'application/x-ndjson',
|
|
284
|
-
'x-defe-manual': '1',
|
|
285
|
-
'sec-ch-ua': '"Microsoft Edge";v="153", "Not_A Brand";v="8", "Chromium";v="153"',
|
|
286
|
-
'sec-ch-ua-mobile': '?0',
|
|
287
|
-
'sec-ch-ua-platform': '"Windows"',
|
|
288
|
-
'sec-fetch-dest': 'empty',
|
|
289
|
-
'sec-fetch-mode': 'cors',
|
|
290
|
-
'sec-fetch-site': 'same-site',
|
|
291
|
-
},
|
|
292
|
-
body: JSON.stringify(payload),
|
|
293
|
-
signal: AbortSignal.timeout(16000),
|
|
294
|
-
});
|
|
295
|
-
|
|
296
|
-
if (!res.ok) return null;
|
|
297
|
-
|
|
298
|
-
let fullText = '';
|
|
299
|
-
if (res.body?.getReader) {
|
|
300
|
-
const reader = res.body.getReader();
|
|
301
|
-
const decoder = new TextDecoder();
|
|
302
|
-
|
|
303
|
-
try {
|
|
304
|
-
while (true) {
|
|
305
|
-
const { done, value } = await reader.read();
|
|
306
|
-
if (done) break;
|
|
307
|
-
fullText += decoder.decode(value, { stream: true });
|
|
308
|
-
}
|
|
309
|
-
} catch { }
|
|
310
|
-
} else {
|
|
311
|
-
fullText = await res.text();
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
const objects = extractJsonObjects(fullText);
|
|
315
|
-
const candidateItems = [];
|
|
316
|
-
|
|
317
|
-
for (const parsed of objects) {
|
|
318
|
-
if (parsed?.t === 'hit' && Array.isArray(parsed.links)) {
|
|
319
|
-
const site = parsed.site || 'DownloadEverything';
|
|
320
|
-
for (const l of parsed.links) {
|
|
321
|
-
if (l && typeof l === 'object') {
|
|
322
|
-
candidateItems.push({ site, ...l });
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
const resolved = await Promise.all(candidateItems.map(item => resolveItem(item, title, ua)));
|
|
329
|
-
const allUrls = resolved.filter(Boolean);
|
|
330
|
-
|
|
331
|
-
if (allUrls.length === 0) return null;
|
|
332
|
-
|
|
333
|
-
return {
|
|
334
|
-
url: allUrls[0].url,
|
|
335
|
-
allUrls,
|
|
336
|
-
headers: allUrls[0].headers,
|
|
337
|
-
};
|
|
338
|
-
}
|
package/src/sources/frame.js
DELETED
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import { USER_AGENT, fetchJson } from '../utils/helpers.js';
|
|
2
|
-
|
|
3
|
-
const BASE_URL = 'https://api.peestream.in';
|
|
4
|
-
|
|
5
|
-
const PROVIDERS = [
|
|
6
|
-
{ id: 'vaplayer', name: 'FRAME Zephyr' },
|
|
7
|
-
{ id: 'castle', name: 'FRAME Atlas' },
|
|
8
|
-
{ id: 'hera', name: 'FRAME Luna' },
|
|
9
|
-
{ id: 'multivid', name: 'FRAME Volt' },
|
|
10
|
-
{ id: 'netmirror', name: 'FRAME Echo' },
|
|
11
|
-
{ id: 'vidsuper-castle', name: 'FRAME Rift' },
|
|
12
|
-
{ id: 'vidsuper-vixsrc', name: 'FRAME Quill' }
|
|
13
|
-
];
|
|
14
|
-
|
|
15
|
-
async function fetchProviderStreams(provider, type, id, s, e) {
|
|
16
|
-
try {
|
|
17
|
-
const queryParams = new URLSearchParams({
|
|
18
|
-
q: String(id),
|
|
19
|
-
type,
|
|
20
|
-
provider: provider.id
|
|
21
|
-
});
|
|
22
|
-
if (type === 'tv') {
|
|
23
|
-
queryParams.set('season', String(s));
|
|
24
|
-
queryParams.set('episode', String(e));
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const url = `${BASE_URL}/api/search?${queryParams.toString()}`;
|
|
28
|
-
const data = await fetchJson(url, {
|
|
29
|
-
headers: {
|
|
30
|
-
'User-Agent': USER_AGENT,
|
|
31
|
-
'Accept': 'application/json',
|
|
32
|
-
'Referer': 'https://peestream.in/'
|
|
33
|
-
},
|
|
34
|
-
signal: AbortSignal.timeout(12000)
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
if (!data || !Array.isArray(data.results) || !data.results.length) return [];
|
|
38
|
-
|
|
39
|
-
const streams = [];
|
|
40
|
-
for (const result of data.results) {
|
|
41
|
-
for (const stream of result.streams || []) {
|
|
42
|
-
if (!stream || !stream.url) continue;
|
|
43
|
-
streams.push({
|
|
44
|
-
url: stream.url,
|
|
45
|
-
server: provider.name,
|
|
46
|
-
quality: stream.quality || 'Auto',
|
|
47
|
-
type: stream.type === 'm3u8' || stream.url.includes('.m3u8') ? 'hls' : 'mp4',
|
|
48
|
-
headers: stream.headers || {
|
|
49
|
-
'User-Agent': USER_AGENT
|
|
50
|
-
}
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
return streams;
|
|
55
|
-
} catch {
|
|
56
|
-
return [];
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
export async function getStream(args) {
|
|
61
|
-
const { id, s, e, server } = args;
|
|
62
|
-
const isTv = s != null && e != null;
|
|
63
|
-
const type = isTv ? 'tv' : 'movie';
|
|
64
|
-
|
|
65
|
-
let targets = PROVIDERS;
|
|
66
|
-
if (server && server !== 'all') {
|
|
67
|
-
const clean = server.toLowerCase().replace('frame ', '').trim();
|
|
68
|
-
targets = PROVIDERS.filter(p => p.id.toLowerCase() === clean || p.name.toLowerCase().includes(clean));
|
|
69
|
-
if (!targets.length) targets = PROVIDERS;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
const settled = await Promise.allSettled(
|
|
73
|
-
targets.map(p => fetchProviderStreams(p, type, id, s, e))
|
|
74
|
-
);
|
|
75
|
-
|
|
76
|
-
const allUrls = [];
|
|
77
|
-
for (const r of settled) {
|
|
78
|
-
if (r.status === 'fulfilled' && Array.isArray(r.value)) {
|
|
79
|
-
allUrls.push(...r.value);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
return allUrls.length ? { allUrls } : null;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
export async function getSources() {
|
|
87
|
-
return PROVIDERS.map(p => p.name);
|
|
88
|
-
}
|
package/src/sources/fsharetv.js
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { fetchText, fetchJson, USER_AGENT, getTmdbInfo } from '../utils/helpers.js';
|
|
2
|
-
|
|
3
|
-
const BASE_URL = 'https://fsharetv.cc';
|
|
4
|
-
const HEADERS = { 'User-Agent': USER_AGENT, 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'Accept-Language': 'en-US,en;q=0.9', 'Referer': `${BASE_URL}/` };
|
|
5
|
-
const API_HEADERS = { ...HEADERS, 'Accept': 'application/json, */*; q=0.01', 'X-Requested-With': 'XMLHttpRequest' };
|
|
6
|
-
|
|
7
|
-
export async function getStream({ id, s }) {
|
|
8
|
-
if (s != null) return null;
|
|
9
|
-
try {
|
|
10
|
-
const info = await getTmdbInfo(id, 'movie');
|
|
11
|
-
if (!info?.imdbId) return null;
|
|
12
|
-
const html = await fetchText(`${BASE_URL}/movie/${info.imdbId}`, { headers: HEADERS, signal: AbortSignal.timeout(8000) });
|
|
13
|
-
let watchPath = null;
|
|
14
|
-
const match = html.match(/href="(\/w\/[^"]+)"/);
|
|
15
|
-
if (match) watchPath = match[1];
|
|
16
|
-
if (!watchPath) return null;
|
|
17
|
-
const watchHtml = await fetchText(`${BASE_URL}${watchPath}`, { headers: HEADERS, signal: AbortSignal.timeout(8000) });
|
|
18
|
-
let sourceId = null;
|
|
19
|
-
const sidMatch = watchHtml.match(/(?:source_id|file_id|setSource)[\s=:\('"]+([^'"\)]+)/i);
|
|
20
|
-
if (sidMatch) sourceId = sidMatch[1];
|
|
21
|
-
if (!sourceId) return null;
|
|
22
|
-
const json = await fetchJson(`${BASE_URL}/api/file/${sourceId}/source?trailer=Png81APqcxU&type=watch`, { headers: { ...API_HEADERS, 'Referer': `${BASE_URL}${watchPath}` }, signal: AbortSignal.timeout(8000) });
|
|
23
|
-
if (json.status !== 'ok') return null;
|
|
24
|
-
const groups = [];
|
|
25
|
-
if (Array.isArray(json.data?.file?.sources)) groups.push(json.data.file.sources);
|
|
26
|
-
if (Array.isArray(json.data?.file?.alternatives)) json.data.file.alternatives.forEach(g => Array.isArray(g) && groups.push(g));
|
|
27
|
-
const out = [], seen = new Set();
|
|
28
|
-
for (const group of groups) {
|
|
29
|
-
for (const item of group.filter(st => st?.src).sort((a, b) => parseInt(b.quality) - parseInt(a.quality))) {
|
|
30
|
-
const url = item.src.startsWith('http') ? item.src : `${BASE_URL}${item.src}`;
|
|
31
|
-
if (seen.has(url)) continue;
|
|
32
|
-
seen.add(url);
|
|
33
|
-
out.push({ url, quality: parseInt(item.quality) || 0, label: item.label || null });
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
out.sort((a, b) => b.quality - a.quality);
|
|
37
|
-
return out.length ? { allUrls: out.map(u => ({ url: u.url, headers: HEADERS, skipProxy: false })) } : null;
|
|
38
|
-
} catch { return null; }
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export async function getSources(args) {
|
|
42
|
-
const stream = await getStream(args);
|
|
43
|
-
return stream?.allUrls ? stream.allUrls.map(u => u.url) : [];
|
|
44
|
-
}
|
package/src/sources/fsonic.js
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import { fetchText, fetchJson, USER_AGENT, getTmdbInfo } from '../utils/helpers.js';
|
|
2
|
-
|
|
3
|
-
const BASE_URL = 'https://www.fsonic.net';
|
|
4
|
-
const FSHARE_BASE = 'https://fsharetv.co';
|
|
5
|
-
const HEADERS = { 'User-Agent': USER_AGENT, 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'Accept-Language': 'en-US,en;q=0.9' };
|
|
6
|
-
|
|
7
|
-
export async function getStream({ id, s, sdk }) {
|
|
8
|
-
const tmdbApiKey = sdk?.tmdbApiKey || null;
|
|
9
|
-
if (!tmdbApiKey) return null;
|
|
10
|
-
if (s != null) return null;
|
|
11
|
-
try {
|
|
12
|
-
const info = await getTmdbInfo(tmdbApiKey, id, 'movie');
|
|
13
|
-
if (!info?.titles?.length) return null;
|
|
14
|
-
let watchSlug = null;
|
|
15
|
-
for (const title of info.titles) {
|
|
16
|
-
try {
|
|
17
|
-
const html = await fetchText(`${BASE_URL}/movie/search/${encodeURIComponent(title)}`, { headers: HEADERS, signal: AbortSignal.timeout(8000) });
|
|
18
|
-
let idx = 0, found = null;
|
|
19
|
-
const yearStr = String(info.year);
|
|
20
|
-
while ((idx = html.indexOf('href="/watch/', idx)) !== -1) {
|
|
21
|
-
const start = idx + 6;
|
|
22
|
-
const end = html.indexOf('"', start);
|
|
23
|
-
const link = html.slice(start, end);
|
|
24
|
-
if (!found) found = link;
|
|
25
|
-
if (link.includes(yearStr)) { found = link; break; }
|
|
26
|
-
idx = end;
|
|
27
|
-
}
|
|
28
|
-
if (found) { watchSlug = found; break; }
|
|
29
|
-
} catch { }
|
|
30
|
-
}
|
|
31
|
-
if (!watchSlug) return null;
|
|
32
|
-
const wHtml = await fetchText(`${BASE_URL}${watchSlug}`, { headers: HEADERS, signal: AbortSignal.timeout(8000) });
|
|
33
|
-
let token = null, trailer = null;
|
|
34
|
-
const match = wHtml.match(/init\('([^']+)',\s*(?:'[^']*',\s*)?'([^']+)'/);
|
|
35
|
-
if (match) { token = match[1]; trailer = match[2]; }
|
|
36
|
-
if (!token) return null;
|
|
37
|
-
const json = await fetchJson(`${BASE_URL}/api/source/${token}?trailer=${trailer}&type=watch`, { headers: { ...HEADERS, 'Accept': 'application/json, text/plain, */*', 'Referer': `${BASE_URL}${watchSlug}` }, signal: AbortSignal.timeout(8000) });
|
|
38
|
-
if (json.status !== 'ok') return null;
|
|
39
|
-
const allGroups = [];
|
|
40
|
-
if (json.data?.file?.sources?.length) allGroups.push(json.data.file.sources);
|
|
41
|
-
if (json.data?.file?.alternatives) for (const g of json.data.file.alternatives) if (g?.length) allGroups.push(g);
|
|
42
|
-
const urls = new Set();
|
|
43
|
-
for (const group of allGroups) {
|
|
44
|
-
const best = [...group].filter(st => st?.src).sort((a, b) => parseInt(b.quality) - parseInt(a.quality))[0];
|
|
45
|
-
if (best) urls.add(best.src.startsWith('http') ? best.src : `${FSHARE_BASE}${best.src}`);
|
|
46
|
-
}
|
|
47
|
-
return urls.size ? { allUrls: [...urls].map(url => ({ url, headers: { ...HEADERS, 'Referer': `${FSHARE_BASE}/` }, skipProxy: false })) } : null;
|
|
48
|
-
} catch { return null; }
|
|
49
|
-
}
|