@vyla-entertainment/sdk 1.9.0 → 1.11.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/.github/workflows/publish.yml +38 -38
- package/.gitlab-ci.yml +16 -0
- package/README.md +9 -13
- package/package.json +33 -32
- package/src/config.js +140 -116
- package/src/health.js +2 -2
- package/src/sdk.d.ts +122 -122
- package/src/sdk.js +7 -4
- package/src/sources/anineko.js +3 -1
- package/src/sources/bcine.js +202 -0
- package/src/sources/cinejoy.js +194 -209
- package/src/sources/cinesrc.js +212 -0
- package/src/sources/cinesu.js +147 -93
- package/src/sources/flaxmovies.js +113 -21
- package/src/sources/frame.js +88 -0
- package/src/sources/fsonic.js +3 -1
- package/src/sources/fsonline.js +3 -1
- package/src/sources/lmscript.js +42 -42
- package/src/sources/lookmovie.js +3 -1
- package/src/sources/luna.js +125 -0
- package/src/sources/mapple.js +40 -4
- package/src/sources/megasource.js +47 -0
- package/src/sources/meowtv.js +0 -1
- package/src/sources/nova.js +46 -0
- package/src/sources/peestream.js +122 -0
- package/src/sources/pengu.js +8 -3
- package/src/sources/pstream.js +68 -0
- package/src/sources/rivestream.js +179 -0
- package/src/sources/videasy.js +3 -1
- package/src/sources/vidgod.js +147 -0
- package/src/sources/vidnest.js +3 -1
- package/src/sources/vidvault.js +113 -113
- package/src/sources/vidzee.js +154 -199
- package/src/sources/zxcstream.js +141 -0
- package/src/subtitles.js +18 -0
- package/src/utils/helpers.js +2 -2
- package/src/sources/1embed.js +0 -115
- package/src/sources/anikoto.js +0 -198
- package/src/sources/anizone.js +0 -109
- package/src/sources/kickassanime.js +0 -107
- package/src/sources/nekowatch.js +0 -57
- package/src/sources/opstream.js +0 -123
- package/src/sources/peachify.js +0 -78
- package/src/sources/reanime.js +0 -324
- package/src/sources/vidrift.js +0 -95
- package/src/sources/vidsync.js +0 -38
package/src/sdk.d.ts
CHANGED
|
@@ -1,123 +1,123 @@
|
|
|
1
|
-
export interface SourceConfig {
|
|
2
|
-
key: string;
|
|
3
|
-
label: string;
|
|
4
|
-
sourceFile: string;
|
|
5
|
-
proxyParam: string;
|
|
6
|
-
timeout: number;
|
|
7
|
-
jitter: number;
|
|
8
|
-
retries: number;
|
|
9
|
-
multiUrl: boolean;
|
|
10
|
-
skipProxy?: boolean;
|
|
11
|
-
cdnHeaders?: {
|
|
12
|
-
pattern: RegExp;
|
|
13
|
-
headers: {
|
|
14
|
-
Referer: string;
|
|
15
|
-
Origin: string;
|
|
16
|
-
};
|
|
17
|
-
}[];
|
|
18
|
-
skipVerify?: boolean;
|
|
19
|
-
verifyHeaders?: boolean;
|
|
20
|
-
disabled?: boolean;
|
|
21
|
-
sourcesTimeout?: number;
|
|
22
|
-
}
|
|
23
|
-
export interface ProbeResult {
|
|
24
|
-
ok: boolean;
|
|
25
|
-
ms: number | null;
|
|
26
|
-
}
|
|
27
|
-
export interface StreamResult {
|
|
28
|
-
url: string;
|
|
29
|
-
headers: {
|
|
30
|
-
"User-Agent": string;
|
|
31
|
-
Referer: string;
|
|
32
|
-
Origin: string;
|
|
33
|
-
[key: string]: string;
|
|
34
|
-
};
|
|
35
|
-
server: string;
|
|
36
|
-
quality: string;
|
|
37
|
-
type: "mp4" | "hls";
|
|
38
|
-
skipVerify?: boolean;
|
|
39
|
-
skipProxy?: boolean;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export interface DownloadResult {
|
|
43
|
-
url: string;
|
|
44
|
-
quality: string;
|
|
45
|
-
size: number | null;
|
|
46
|
-
type: "mkv";
|
|
47
|
-
active: boolean;
|
|
48
|
-
}
|
|
49
|
-
export interface SubtitleResult {
|
|
50
|
-
label: string;
|
|
51
|
-
file: string;
|
|
52
|
-
type: "vtt" | "srt";
|
|
53
|
-
source: string;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export type ProbeAllResult = Record<string, ProbeResult>;
|
|
57
|
-
|
|
58
|
-
export interface VylaSDKOptions {
|
|
59
|
-
tmdbApiKey?: string;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// Descriptions written with Claude.
|
|
63
|
-
export default class VylaSDK {
|
|
64
|
-
tmdbApiKey?: string;
|
|
65
|
-
|
|
66
|
-
constructor(options?: VylaSDKOptions);
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Get the list of configured sources.
|
|
70
|
-
* @param excludeDisabled If true, filters out disabled sources.
|
|
71
|
-
*/
|
|
72
|
-
getSources(excludeDisabled?: boolean): SourceConfig[];
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Probe all active (non-disabled) sources for availability.
|
|
76
|
-
*/
|
|
77
|
-
probeAllSources(): Promise<ProbeAllResult>;
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Probe a single source by key.
|
|
81
|
-
*/
|
|
82
|
-
probeSource(key: string): Promise<ProbeResult>;
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Get a playable stream for a given source/media id.
|
|
86
|
-
* @param key Source key
|
|
87
|
-
* @param id Media id (e.g. TMDB id)
|
|
88
|
-
* @param s Season number (for TV), or null for movies
|
|
89
|
-
* @param e Episode number (for TV), or null for movies
|
|
90
|
-
* @param clientIP Optional client IP for source-specific logic
|
|
91
|
-
*/
|
|
92
|
-
getStream(
|
|
93
|
-
key: string,
|
|
94
|
-
id: string | number,
|
|
95
|
-
s?: number | null,
|
|
96
|
-
e?: number | null,
|
|
97
|
-
clientIP?: string | null
|
|
98
|
-
): Promise<StreamResult | { allUrls: StreamResult[] }>;
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Get subtitles for a movie or TV episode.
|
|
102
|
-
* @param id Media id
|
|
103
|
-
* @param s Season number (for TV), or null for movies
|
|
104
|
-
* @param e Episode number (for TV), or null for movies
|
|
105
|
-
*/
|
|
106
|
-
getSubtitles(
|
|
107
|
-
id: string | number,
|
|
108
|
-
s?: number | null,
|
|
109
|
-
e?: number | null
|
|
110
|
-
): Promise<SubtitleResult[]>;
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* Get download links for a movie or TV episode.
|
|
114
|
-
* @param id Media id
|
|
115
|
-
* @param s Season number (for TV), or null for movies
|
|
116
|
-
* @param e Episode number (for TV), or null for movies
|
|
117
|
-
*/
|
|
118
|
-
getDownloads(
|
|
119
|
-
id: string | number,
|
|
120
|
-
s?: number | null,
|
|
121
|
-
e?: number | null
|
|
122
|
-
): Promise<DownloadResult[]>;
|
|
1
|
+
export interface SourceConfig {
|
|
2
|
+
key: string;
|
|
3
|
+
label: string;
|
|
4
|
+
sourceFile: string;
|
|
5
|
+
proxyParam: string;
|
|
6
|
+
timeout: number;
|
|
7
|
+
jitter: number;
|
|
8
|
+
retries: number;
|
|
9
|
+
multiUrl: boolean;
|
|
10
|
+
skipProxy?: boolean;
|
|
11
|
+
cdnHeaders?: {
|
|
12
|
+
pattern: RegExp;
|
|
13
|
+
headers: {
|
|
14
|
+
Referer: string;
|
|
15
|
+
Origin: string;
|
|
16
|
+
};
|
|
17
|
+
}[];
|
|
18
|
+
skipVerify?: boolean;
|
|
19
|
+
verifyHeaders?: boolean;
|
|
20
|
+
disabled?: boolean;
|
|
21
|
+
sourcesTimeout?: number;
|
|
22
|
+
}
|
|
23
|
+
export interface ProbeResult {
|
|
24
|
+
ok: boolean;
|
|
25
|
+
ms: number | null;
|
|
26
|
+
}
|
|
27
|
+
export interface StreamResult {
|
|
28
|
+
url: string;
|
|
29
|
+
headers: {
|
|
30
|
+
"User-Agent": string;
|
|
31
|
+
Referer: string;
|
|
32
|
+
Origin: string;
|
|
33
|
+
[key: string]: string;
|
|
34
|
+
};
|
|
35
|
+
server: string;
|
|
36
|
+
quality: string;
|
|
37
|
+
type: "mp4" | "hls";
|
|
38
|
+
skipVerify?: boolean;
|
|
39
|
+
skipProxy?: boolean;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface DownloadResult {
|
|
43
|
+
url: string;
|
|
44
|
+
quality: string;
|
|
45
|
+
size: number | null;
|
|
46
|
+
type: "mkv";
|
|
47
|
+
active: boolean;
|
|
48
|
+
}
|
|
49
|
+
export interface SubtitleResult {
|
|
50
|
+
label: string;
|
|
51
|
+
file: string;
|
|
52
|
+
type: "vtt" | "srt";
|
|
53
|
+
source: string;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export type ProbeAllResult = Record<string, ProbeResult>;
|
|
57
|
+
|
|
58
|
+
export interface VylaSDKOptions {
|
|
59
|
+
tmdbApiKey?: string;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Descriptions written with Claude.
|
|
63
|
+
export default class VylaSDK {
|
|
64
|
+
tmdbApiKey?: string;
|
|
65
|
+
|
|
66
|
+
constructor(options?: VylaSDKOptions);
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Get the list of configured sources.
|
|
70
|
+
* @param excludeDisabled If true, filters out disabled sources.
|
|
71
|
+
*/
|
|
72
|
+
getSources(excludeDisabled?: boolean): SourceConfig[];
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Probe all active (non-disabled) sources for availability.
|
|
76
|
+
*/
|
|
77
|
+
probeAllSources(): Promise<ProbeAllResult>;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Probe a single source by key.
|
|
81
|
+
*/
|
|
82
|
+
probeSource(key: string): Promise<ProbeResult>;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Get a playable stream for a given source/media id.
|
|
86
|
+
* @param key Source key
|
|
87
|
+
* @param id Media id (e.g. TMDB id)
|
|
88
|
+
* @param s Season number (for TV), or null for movies
|
|
89
|
+
* @param e Episode number (for TV), or null for movies
|
|
90
|
+
* @param clientIP Optional client IP for source-specific logic
|
|
91
|
+
*/
|
|
92
|
+
getStream(
|
|
93
|
+
key: string,
|
|
94
|
+
id: string | number,
|
|
95
|
+
s?: number | null,
|
|
96
|
+
e?: number | null,
|
|
97
|
+
clientIP?: string | null
|
|
98
|
+
): Promise<StreamResult | { allUrls: StreamResult[] }>;
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Get subtitles for a movie or TV episode.
|
|
102
|
+
* @param id Media id
|
|
103
|
+
* @param s Season number (for TV), or null for movies
|
|
104
|
+
* @param e Episode number (for TV), or null for movies
|
|
105
|
+
*/
|
|
106
|
+
getSubtitles(
|
|
107
|
+
id: string | number,
|
|
108
|
+
s?: number | null,
|
|
109
|
+
e?: number | null
|
|
110
|
+
): Promise<SubtitleResult[]>;
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Get download links for a movie or TV episode.
|
|
114
|
+
* @param id Media id
|
|
115
|
+
* @param s Season number (for TV), or null for movies
|
|
116
|
+
* @param e Episode number (for TV), or null for movies
|
|
117
|
+
*/
|
|
118
|
+
getDownloads(
|
|
119
|
+
id: string | number,
|
|
120
|
+
s?: number | null,
|
|
121
|
+
e?: number | null
|
|
122
|
+
): Promise<DownloadResult[]>;
|
|
123
123
|
}
|
package/src/sdk.js
CHANGED
|
@@ -13,8 +13,11 @@ const SOURCE_MODULES = Object.fromEntries(
|
|
|
13
13
|
);
|
|
14
14
|
|
|
15
15
|
export default class VylaSDK {
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
tmdbApiKey = null;
|
|
17
|
+
penguManifest = null;
|
|
18
|
+
constructor({ tmdbApiKey, penguManifest } = {}) {
|
|
19
|
+
this.tmdbApiKey = tmdbApiKey || null;
|
|
20
|
+
this.penguManifest = penguManifest || null;
|
|
18
21
|
}
|
|
19
22
|
getSources(excludeDisabled = false) {
|
|
20
23
|
if (excludeDisabled) {
|
|
@@ -43,14 +46,14 @@ export default class VylaSDK {
|
|
|
43
46
|
if (!cfg) throw new Error(`Source with key "${key}" not found`);
|
|
44
47
|
const mod = SOURCE_MODULES[key];
|
|
45
48
|
if (!mod) throw new Error(`Source module for key "${key}" not found`);
|
|
46
|
-
return await probeSource(this
|
|
49
|
+
return await probeSource(this, cfg, mod);
|
|
47
50
|
}
|
|
48
51
|
async getStream(key, id, s = null, e = null, clientIP = null) {
|
|
49
52
|
const cfg = SOURCES.find(cfg => cfg.key === key);
|
|
50
53
|
if (!cfg) throw new Error(`Source with key "${key}" not found`);
|
|
51
54
|
const mod = SOURCE_MODULES[key];
|
|
52
55
|
if (!mod) throw new Error(`Source module for key "${key}" not found`);
|
|
53
|
-
const streamArgs = await createStreamArgs(cfg, this
|
|
56
|
+
const streamArgs = await createStreamArgs(cfg, this, id, s, e, clientIP);
|
|
54
57
|
return await mod.getStream(streamArgs);
|
|
55
58
|
}
|
|
56
59
|
async getSubtitles(id, s = null, e = null) {
|
package/src/sources/anineko.js
CHANGED
|
@@ -69,7 +69,9 @@ async function extractHls(embedUrl) {
|
|
|
69
69
|
return null;
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
export async function getStream({ id, s, e, audio,
|
|
72
|
+
export async function getStream({ id, s, e, audio, sdk }) {
|
|
73
|
+
const tmdbApiKey = sdk?.tmdbApiKey || null;
|
|
74
|
+
if (!tmdbApiKey) return null;
|
|
73
75
|
try {
|
|
74
76
|
const info = await getTmdbInfo(tmdbApiKey, id, s ? 'tv' : 'movie', s);
|
|
75
77
|
if (!info || !info.isAnime) return null;
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { USER_AGENT } from '../utils/helpers.js';
|
|
2
|
+
|
|
3
|
+
const _sInit = [23, 27, 30, 31, 86, 28, 19, 86, 9, 18, 19, 21, 26, 27, 86, 120, 114, 120, 116, 86, 9, 18, 19, 21, 26, 27, 122, 89, 25, 23];
|
|
4
|
+
const _vParam = `_v=${(_sInit[15] ^ 0x5a)}${(_sInit[16] ^ 0x5a)}${(_sInit[17] ^ 0x5a)}${(_sInit[18] ^ 0x5a)}`;
|
|
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
|
+
const SERVERS = [
|
|
12
|
+
{ id: 'NIGHT', endpoint: '/server/night' },
|
|
13
|
+
{ id: 'EMP', endpoint: '/server/emp' },
|
|
14
|
+
{ id: 'MAIN', endpoint: '/server/vidsrc' }
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
const CORS_PROXY = 'https://eve.pstream.cfd';
|
|
18
|
+
let cachedToken = null;
|
|
19
|
+
let tokenExpiry = 0;
|
|
20
|
+
|
|
21
|
+
function ab(e) {
|
|
22
|
+
let t = e >>> 0;
|
|
23
|
+
t ^= t >>> 16;
|
|
24
|
+
t = Math.imul(t, 2146121005) >>> 0;
|
|
25
|
+
t ^= t >>> 15;
|
|
26
|
+
t = Math.imul(t, 2221713035) >>> 0;
|
|
27
|
+
return (t ^ (t >>> 16)) >>> 0;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function sD(e) {
|
|
31
|
+
const t = new TextEncoder().encode(aD);
|
|
32
|
+
const r = Math.max(32, Math.min(128, e + 17));
|
|
33
|
+
const n = new Uint8Array(r);
|
|
34
|
+
let a = 2166136261;
|
|
35
|
+
for (let s = 0; s < r; s += 1) {
|
|
36
|
+
a ^= t[s % t.length] ?? s;
|
|
37
|
+
a = ab((a + Ls[s % Ls.length] + ((2654435761 * s) >>> 0)) >>> 0);
|
|
38
|
+
n[s] = a & 255;
|
|
39
|
+
}
|
|
40
|
+
return n;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function iD(e) {
|
|
44
|
+
let t = '';
|
|
45
|
+
for (let r = 0; r < e.length; r += 3) {
|
|
46
|
+
const n = e[r];
|
|
47
|
+
const a = e[r + 1];
|
|
48
|
+
const s = e[r + 2];
|
|
49
|
+
t += wa[n >>> 2];
|
|
50
|
+
t += wa[((3 & n) << 4) | ((a ?? 0) >>> 4)];
|
|
51
|
+
if (a === undefined) break;
|
|
52
|
+
t += wa[((15 & a) << 2) | ((s ?? 0) >>> 6)];
|
|
53
|
+
if (s === undefined) break;
|
|
54
|
+
t += wa[63 & s];
|
|
55
|
+
}
|
|
56
|
+
return t;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function generateDirectHlsUrl(id, s, e) {
|
|
60
|
+
const isTv = s != null && e != null;
|
|
61
|
+
const tmdbId = Math.floor(Number(id));
|
|
62
|
+
const season = isTv ? Math.floor(Number(s || 1)) : 0;
|
|
63
|
+
const episode = isTv ? Math.floor(Number(e || 1)) : 0;
|
|
64
|
+
|
|
65
|
+
const str = `${nD}:${isTv ? 's' : 'm'}:${tmdbId}:${season}:${episode}`;
|
|
66
|
+
const a = new TextEncoder().encode(str);
|
|
67
|
+
const sArr = sD(a.length);
|
|
68
|
+
const i = new Uint8Array(a.length + 2);
|
|
69
|
+
i[0] = a.length & 255;
|
|
70
|
+
i[1] = (a.length >>> 8) & 255;
|
|
71
|
+
let o = (2654435769 ^ a.length) >>> 0;
|
|
72
|
+
for (let l = 0; l < a.length; l += 1) {
|
|
73
|
+
o = ab((o + sArr[l % sArr.length] + Ls[l % Ls.length] + l) >>> 0);
|
|
74
|
+
i[l + 2] = (a[l] ^ (255 & o)) ^ sArr[(7 * l + 3) % sArr.length];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return `https://glendale-plumbing.com/c/v1/${iD(i)}/master.m3u8`;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async function fetchInternalToken() {
|
|
81
|
+
if (cachedToken && Date.now() < tokenExpiry) return cachedToken;
|
|
82
|
+
try {
|
|
83
|
+
const res = await fetch('https://1embed.cc/api/token', {
|
|
84
|
+
headers: {
|
|
85
|
+
'User-Agent': USER_AGENT,
|
|
86
|
+
'Referer': 'https://1embed.cc/',
|
|
87
|
+
'Accept': 'application/json, text/plain, */*'
|
|
88
|
+
},
|
|
89
|
+
signal: AbortSignal.timeout(4000)
|
|
90
|
+
});
|
|
91
|
+
if (res.ok) {
|
|
92
|
+
const data = await res.json();
|
|
93
|
+
if (data?.token) {
|
|
94
|
+
cachedToken = data.token;
|
|
95
|
+
tokenExpiry = Date.now() + 1800 * 1000;
|
|
96
|
+
return cachedToken;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
} catch { }
|
|
100
|
+
|
|
101
|
+
try {
|
|
102
|
+
const proxiedUrl = `${CORS_PROXY}/?destination=${encodeURIComponent('https://1embed.cc/api/token')}`;
|
|
103
|
+
const res = await fetch(proxiedUrl, {
|
|
104
|
+
headers: {
|
|
105
|
+
'X-Referer': 'https://1embed.cc/',
|
|
106
|
+
'X-User-Agent': USER_AGENT
|
|
107
|
+
},
|
|
108
|
+
signal: AbortSignal.timeout(4000)
|
|
109
|
+
});
|
|
110
|
+
if (res.ok) {
|
|
111
|
+
const data = await res.json();
|
|
112
|
+
if (data?.token) {
|
|
113
|
+
cachedToken = data.token;
|
|
114
|
+
tokenExpiry = Date.now() + 1800 * 1000;
|
|
115
|
+
return cachedToken;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
} catch { }
|
|
119
|
+
|
|
120
|
+
return '';
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export async function getStream(args) {
|
|
124
|
+
const { id, s, e, clientIP } = args;
|
|
125
|
+
const isTv = s != null && e != null;
|
|
126
|
+
const isMovie = !isTv;
|
|
127
|
+
const allUrls = [];
|
|
128
|
+
|
|
129
|
+
const directHlsUrl = generateDirectHlsUrl(id, s, e);
|
|
130
|
+
const masterUrlWithMark = `${directHlsUrl}?${_vParam}`;
|
|
131
|
+
|
|
132
|
+
allUrls.push({
|
|
133
|
+
url: masterUrlWithMark,
|
|
134
|
+
server: 'Bcine (Direct Master)',
|
|
135
|
+
quality: 'Auto',
|
|
136
|
+
type: 'hls',
|
|
137
|
+
headers: {
|
|
138
|
+
'User-Agent': USER_AGENT,
|
|
139
|
+
'Referer': 'https://bcine.ru/',
|
|
140
|
+
'Origin': 'https://bcine.ru',
|
|
141
|
+
...(clientIP && { 'X-Forwarded-For': clientIP })
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
const token = await fetchInternalToken();
|
|
146
|
+
|
|
147
|
+
await Promise.allSettled(
|
|
148
|
+
SERVERS.map(async (server) => {
|
|
149
|
+
const query = isTv
|
|
150
|
+
? `id=${id}?type=tv&s=${s || 1}&e=${e || 1}`
|
|
151
|
+
: `id=${id}?type=movie`;
|
|
152
|
+
|
|
153
|
+
const stParam = token ? `&_st=${token}` : '';
|
|
154
|
+
const targetUrl = `https://1embed.cc${server.endpoint}/${query}${stParam}`;
|
|
155
|
+
|
|
156
|
+
const headers = {
|
|
157
|
+
'User-Agent': USER_AGENT,
|
|
158
|
+
'Referer': 'https://bcine.ru/',
|
|
159
|
+
'Accept': 'application/json, text/plain, */*',
|
|
160
|
+
...(token && { 'X-Stream-Token': token }),
|
|
161
|
+
...(clientIP && { 'X-Forwarded-For': clientIP })
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
let res = await fetch(targetUrl, { headers, signal: AbortSignal.timeout(5000) }).catch(() => null);
|
|
165
|
+
if (!res || !res.ok) {
|
|
166
|
+
const proxiedUrl = `${CORS_PROXY}/?destination=${encodeURIComponent(targetUrl)}`;
|
|
167
|
+
res = await fetch(proxiedUrl, {
|
|
168
|
+
headers: {
|
|
169
|
+
'X-Referer': 'https://bcine.ru/',
|
|
170
|
+
'X-User-Agent': USER_AGENT
|
|
171
|
+
},
|
|
172
|
+
signal: AbortSignal.timeout(5000)
|
|
173
|
+
}).catch(() => null);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (res && res.ok) {
|
|
177
|
+
try {
|
|
178
|
+
const data = await res.json();
|
|
179
|
+
if (data && data.success !== false) {
|
|
180
|
+
const streamUrl = data.streams?.proxy_m3u8 || data.streams?.raw_m3u8 || data.streams?.m3u8 || data.streamUrl;
|
|
181
|
+
if (streamUrl && typeof streamUrl === 'string') {
|
|
182
|
+
const urlWithMark = streamUrl.includes('?') ? `${streamUrl}&${_vParam}` : `${streamUrl}?${_vParam}`;
|
|
183
|
+
allUrls.push({
|
|
184
|
+
url: urlWithMark,
|
|
185
|
+
server: `Bcine (${data.selectedSource || data.provider || server.id})`,
|
|
186
|
+
quality: 'Auto',
|
|
187
|
+
type: streamUrl.includes('.m3u8') ? 'hls' : 'mp4',
|
|
188
|
+
headers: {
|
|
189
|
+
'User-Agent': USER_AGENT,
|
|
190
|
+
'Referer': 'https://bcine.ru/',
|
|
191
|
+
'Origin': 'https://bcine.ru'
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
} catch { }
|
|
197
|
+
}
|
|
198
|
+
})
|
|
199
|
+
);
|
|
200
|
+
|
|
201
|
+
return allUrls.length ? { allUrls } : null;
|
|
202
|
+
}
|