Files
2026-07-20 17:28:26 +03:00

742 lines
25 KiB
JavaScript

// flixer - bundled from src/flixer/
var __defProp = Object.defineProperty;
var __defProps = Object.defineProperties;
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp.call(b, prop))
__defNormalProp(a, prop, b[prop]);
if (__getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(b)) {
if (__propIsEnum.call(b, prop))
__defNormalProp(a, prop, b[prop]);
}
return a;
};
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
// src/flixer/http.js
var SITE_URL = "https://flixer.gd";
var API_URL = "https://plsdontscrapemelove.flixer.gd";
var HEADERS = {
"Accept": "text/plain",
"Origin": SITE_URL,
"Referer": `${SITE_URL}/`,
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36"
};
var BASE64_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
var SHA256_CONSTANTS = [
1116352408,
1899447441,
3049323471,
3921009573,
961987163,
1508970993,
2453635748,
2870763221,
3624381080,
310598401,
607225278,
1426881987,
1925078388,
2162078206,
2614888103,
3248222580,
3835390401,
4022224774,
264347078,
604807628,
770255983,
1249150122,
1555081692,
1996064986,
2554220882,
2821834349,
2952996808,
3210313671,
3336571891,
3584528711,
113926993,
338241895,
666307205,
773529912,
1294757372,
1396182291,
1695183700,
1986661051,
2177026350,
2456956037,
2730485921,
2820302411,
3259730800,
3345764771,
3516065817,
3600352804,
4094571909,
275423344,
430227734,
506948616,
659060556,
883997877,
958139571,
1322822218,
1537002063,
1747873779,
1955562222,
2024104815,
2227730452,
2361852424,
2428436474,
2756734187,
3204031479,
3329325298
];
function encodeUtf8(value) {
const bytes = [];
for (let index = 0; index < value.length; index++) {
let codePoint = value.charCodeAt(index);
if (codePoint >= 55296 && codePoint <= 56319 && index + 1 < value.length) {
const trailing = value.charCodeAt(index + 1);
if (trailing >= 56320 && trailing <= 57343) {
codePoint = 65536 + (codePoint - 55296 << 10) + trailing - 56320;
index++;
}
}
if (codePoint < 128)
bytes.push(codePoint);
else if (codePoint < 2048)
bytes.push(192 | codePoint >> 6, 128 | codePoint & 63);
else if (codePoint < 65536)
bytes.push(224 | codePoint >> 12, 128 | codePoint >> 6 & 63, 128 | codePoint & 63);
else
bytes.push(240 | codePoint >> 18, 128 | codePoint >> 12 & 63, 128 | codePoint >> 6 & 63, 128 | codePoint & 63);
}
return new Uint8Array(bytes);
}
function rotateRight(value, amount) {
return value >>> amount | value << 32 - amount;
}
function sha256(input) {
const bitLength = input.length * 8;
const paddedLength = Math.ceil((input.length + 9) / 64) * 64;
const bytes = new Uint8Array(paddedLength);
bytes.set(input);
bytes[input.length] = 128;
const high = Math.floor(bitLength / 4294967296);
const low = bitLength >>> 0;
const end = paddedLength - 8;
bytes[end] = high >>> 24 & 255;
bytes[end + 1] = high >>> 16 & 255;
bytes[end + 2] = high >>> 8 & 255;
bytes[end + 3] = high & 255;
bytes[end + 4] = low >>> 24 & 255;
bytes[end + 5] = low >>> 16 & 255;
bytes[end + 6] = low >>> 8 & 255;
bytes[end + 7] = low & 255;
const hash = [1779033703, 3144134277, 1013904242, 2773480762, 1359893119, 2600822924, 528734635, 1541459225];
const words = new Uint32Array(64);
for (let offset = 0; offset < bytes.length; offset += 64) {
for (let index = 0; index < 16; index++) {
const position = offset + index * 4;
words[index] = (bytes[position] << 24 | bytes[position + 1] << 16 | bytes[position + 2] << 8 | bytes[position + 3]) >>> 0;
}
for (let index = 16; index < 64; index++) {
const first = rotateRight(words[index - 15], 7) ^ rotateRight(words[index - 15], 18) ^ words[index - 15] >>> 3;
const second = rotateRight(words[index - 2], 17) ^ rotateRight(words[index - 2], 19) ^ words[index - 2] >>> 10;
words[index] = words[index - 16] + first + words[index - 7] + second >>> 0;
}
let [a, b, c, d, e, f, g, h] = hash;
for (let index = 0; index < 64; index++) {
const sum1 = rotateRight(e, 6) ^ rotateRight(e, 11) ^ rotateRight(e, 25);
const choice = e & f ^ ~e & g;
const temporary1 = h + sum1 + choice + SHA256_CONSTANTS[index] + words[index] >>> 0;
const sum0 = rotateRight(a, 2) ^ rotateRight(a, 13) ^ rotateRight(a, 22);
const majority = a & b ^ a & c ^ b & c;
const temporary2 = sum0 + majority >>> 0;
h = g;
g = f;
f = e;
e = d + temporary1 >>> 0;
d = c;
c = b;
b = a;
a = temporary1 + temporary2 >>> 0;
}
hash[0] = hash[0] + a >>> 0;
hash[1] = hash[1] + b >>> 0;
hash[2] = hash[2] + c >>> 0;
hash[3] = hash[3] + d >>> 0;
hash[4] = hash[4] + e >>> 0;
hash[5] = hash[5] + f >>> 0;
hash[6] = hash[6] + g >>> 0;
hash[7] = hash[7] + h >>> 0;
}
const output = new Uint8Array(32);
for (let index = 0; index < hash.length; index++) {
output[index * 4] = hash[index] >>> 24 & 255;
output[index * 4 + 1] = hash[index] >>> 16 & 255;
output[index * 4 + 2] = hash[index] >>> 8 & 255;
output[index * 4 + 3] = hash[index] & 255;
}
return output;
}
function hmacSha256(key, message) {
let keyBytes = key instanceof Uint8Array ? key : encodeUtf8(String(key));
if (keyBytes.length > 64)
keyBytes = sha256(keyBytes);
const messageBytes = message instanceof Uint8Array ? message : encodeUtf8(String(message));
const inner = new Uint8Array(64 + messageBytes.length);
const outer = new Uint8Array(96);
for (let index = 0; index < 64; index++) {
const value = index < keyBytes.length ? keyBytes[index] : 0;
inner[index] = value ^ 54;
outer[index] = value ^ 92;
}
inner.set(messageBytes, 64);
outer.set(sha256(inner), 64);
return sha256(outer);
}
function encodeBase64(bytes) {
let output = "";
for (let index = 0; index < bytes.length; index += 3) {
const secondExists = index + 1 < bytes.length;
const thirdExists = index + 2 < bytes.length;
const value = bytes[index] << 16 | (secondExists ? bytes[index + 1] : 0) << 8 | (thirdExists ? bytes[index + 2] : 0);
output += BASE64_ALPHABET[value >>> 18 & 63];
output += BASE64_ALPHABET[value >>> 12 & 63];
output += secondExists ? BASE64_ALPHABET[value >>> 6 & 63] : "=";
output += thirdExists ? BASE64_ALPHABET[value & 63] : "=";
}
return output;
}
function createNonce() {
const bytes = new Uint8Array(16);
for (let index = 0; index < bytes.length; index++)
bytes[index] = Math.floor(Math.random() * 256);
return encodeBase64(bytes).replace(/[/+=]/g, "").slice(0, 22);
}
var serverTimeOffset = 0;
var serverTimeFetchedAt = 0;
async function getServerTimestamp() {
const now = Date.now();
if (serverTimeFetchedAt && now - serverTimeFetchedAt < 3e5) {
return Math.floor((now + serverTimeOffset) / 1e3);
}
try {
const startedAt = Date.now();
const response = await fetch(`${API_URL}/api/time?t=${startedAt}`, {
headers: __spreadProps(__spreadValues({}, HEADERS), { "Cache-Control": "no-cache" })
});
if (!response.ok)
throw new Error(`HTTP ${response.status}`);
const payload = await response.json();
if (!payload || typeof payload.timestamp !== "number")
throw new Error("invalid response");
const finishedAt = Date.now();
serverTimeOffset = payload.timestamp * 1e3 + (finishedAt - startedAt) / 2 - finishedAt;
serverTimeFetchedAt = finishedAt;
return Math.floor((finishedAt + serverTimeOffset) / 1e3);
} catch (_) {
return Math.floor(Date.now() / 1e3);
}
}
async function createSecureHeaders(apiKey, path) {
const timestamp = await getServerTimestamp();
const nonce = createNonce();
const message = `${apiKey}:${timestamp}:${nonce}:${path}`;
return {
"X-Api-Key": apiKey,
"X-Request-Timestamp": String(timestamp),
"X-Request-Nonce": nonce,
"X-Request-Signature": encodeBase64(hmacSha256(apiKey, message)),
"X-Client-Fingerprint": "zerlgt",
"X-Fingerprint-Lite": "e9136c41504646444"
};
}
async function fetchText(url, options = {}) {
const response = await fetch(url, __spreadProps(__spreadValues({}, options), {
headers: __spreadValues(__spreadValues({}, HEADERS), options.headers || {})
}));
if (!response.ok)
throw new Error(`HTTP ${response.status} for ${url}`);
return await response.text();
}
// src/flixer/decoder.js
var CANVAS_FINGERPRINT = "iVBORw0KGgoAAAANSUhEUgAAAMgAAAAyCAYAAAAZUZThAAAQAE";
function concatBytes(...values) {
let length = 0;
for (const value of values)
length += value.length;
const result = new Uint8Array(length);
let offset = 0;
for (const value of values) {
result.set(value, offset);
offset += value.length;
}
return result;
}
function toHex(bytes) {
let result = "";
for (const value of bytes)
result += value.toString(16).padStart(2, "0");
return result;
}
function decodeBase64(value) {
const binary = atob(value);
const bytes = new Uint8Array(binary.length);
for (let index = 0; index < binary.length; index++)
bytes[index] = binary.charCodeAt(index);
return bytes;
}
function decodeUtf8(bytes) {
let result = "";
for (let index = 0; index < bytes.length; ) {
const first = bytes[index++];
let codePoint;
if (first < 128)
codePoint = first;
else if ((first & 224) === 192)
codePoint = (first & 31) << 6 | bytes[index++] & 63;
else if ((first & 240) === 224) {
codePoint = (first & 15) << 12 | (bytes[index++] & 63) << 6 | bytes[index++] & 63;
} else {
codePoint = (first & 7) << 18 | (bytes[index++] & 63) << 12 | (bytes[index++] & 63) << 6 | bytes[index++] & 63;
}
if (codePoint <= 65535)
result += String.fromCharCode(codePoint);
else {
codePoint -= 65536;
result += String.fromCharCode(55296 | codePoint >>> 10, 56320 | codePoint & 1023);
}
}
return result;
}
function multiplyByte(first, second) {
let result = 0;
for (let index = 0; index < 8; index++) {
if (second & 1)
result ^= first;
first = (first << 1 ^ (first & 128 ? 283 : 0)) & 255;
second >>>= 1;
}
return result;
}
function inverseByte(value) {
if (!value)
return 0;
let result = 1;
let base = value;
let power = 254;
while (power) {
if (power & 1)
result = multiplyByte(result, base);
base = multiplyByte(base, base);
power >>>= 1;
}
return result;
}
function rotateByte(value, amount) {
return (value << amount | value >>> 8 - amount) & 255;
}
var AES_SBOX = (() => {
const result = new Uint8Array(256);
for (let index = 0; index < 256; index++) {
const value = inverseByte(index);
result[index] = value ^ rotateByte(value, 1) ^ rotateByte(value, 2) ^ rotateByte(value, 3) ^ rotateByte(value, 4) ^ 99;
}
return result;
})();
function expandAes256Key(key) {
if (key.length !== 32)
throw new Error("Invalid AES-256 key");
const words = new Uint32Array(60);
for (let index = 0; index < 8; index++) {
const offset = index * 4;
words[index] = (key[offset] << 24 | key[offset + 1] << 16 | key[offset + 2] << 8 | key[offset + 3]) >>> 0;
}
let roundConstant = 1;
for (let index = 8; index < words.length; index++) {
let temporary = words[index - 1];
if (index % 8 === 0) {
temporary = (temporary << 8 | temporary >>> 24) >>> 0;
temporary = (AES_SBOX[temporary >>> 24] << 24 | AES_SBOX[temporary >>> 16 & 255] << 16 | AES_SBOX[temporary >>> 8 & 255] << 8 | AES_SBOX[temporary & 255]) >>> 0;
temporary ^= roundConstant << 24;
roundConstant = (roundConstant << 1 ^ (roundConstant & 128 ? 283 : 0)) & 255;
} else if (index % 8 === 4) {
temporary = (AES_SBOX[temporary >>> 24] << 24 | AES_SBOX[temporary >>> 16 & 255] << 16 | AES_SBOX[temporary >>> 8 & 255] << 8 | AES_SBOX[temporary & 255]) >>> 0;
}
words[index] = (words[index - 8] ^ temporary) >>> 0;
}
return words;
}
function addRoundKey(state, words, round) {
for (let column = 0; column < 4; column++) {
const word = words[round * 4 + column];
state[column * 4] ^= word >>> 24;
state[column * 4 + 1] ^= word >>> 16 & 255;
state[column * 4 + 2] ^= word >>> 8 & 255;
state[column * 4 + 3] ^= word & 255;
}
}
function encryptAesBlock(input, words) {
const state = new Uint8Array(input);
const shifted = new Uint8Array(16);
addRoundKey(state, words, 0);
for (let round = 1; round <= 14; round++) {
for (let index = 0; index < 16; index++)
state[index] = AES_SBOX[state[index]];
for (let row = 0; row < 4; row++) {
for (let column = 0; column < 4; column++) {
shifted[row + column * 4] = state[row + (column + row & 3) * 4];
}
}
state.set(shifted);
if (round !== 14) {
for (let column = 0; column < 4; column++) {
const offset = column * 4;
const first = state[offset];
const second = state[offset + 1];
const third = state[offset + 2];
const fourth = state[offset + 3];
const combined = first ^ second ^ third ^ fourth;
state[offset] ^= combined ^ multiplyByte(first ^ second, 2);
state[offset + 1] ^= combined ^ multiplyByte(second ^ third, 2);
state[offset + 2] ^= combined ^ multiplyByte(third ^ fourth, 2);
state[offset + 3] ^= combined ^ multiplyByte(fourth ^ first, 2);
}
}
addRoundKey(state, words, round);
}
return state;
}
function bytesToWords(bytes) {
const result = new Uint32Array(4);
for (let index = 0; index < 4; index++) {
const offset = index * 4;
result[index] = (bytes[offset] << 24 | bytes[offset + 1] << 16 | bytes[offset + 2] << 8 | bytes[offset + 3]) >>> 0;
}
return result;
}
function wordsToBytes(words) {
const result = new Uint8Array(16);
for (let index = 0; index < 4; index++) {
result[index * 4] = words[index] >>> 24;
result[index * 4 + 1] = words[index] >>> 16 & 255;
result[index * 4 + 2] = words[index] >>> 8 & 255;
result[index * 4 + 3] = words[index] & 255;
}
return result;
}
function multiplyGhash(first, second) {
const result = new Uint32Array(4);
const value = new Uint32Array(second);
for (let bit = 0; bit < 128; bit++) {
if (first[bit >>> 5] >>> 31 - (bit & 31) & 1) {
for (let index = 0; index < 4; index++)
result[index] ^= value[index];
}
const lowBit = value[3] & 1;
value[3] = (value[3] >>> 1 | (value[2] & 1) << 31) >>> 0;
value[2] = (value[2] >>> 1 | (value[1] & 1) << 31) >>> 0;
value[1] = (value[1] >>> 1 | (value[0] & 1) << 31) >>> 0;
value[0] >>>= 1;
if (lowBit)
value[0] = (value[0] ^ 3774873600) >>> 0;
}
return result;
}
function calculateGhash(ciphertext, hashKey) {
let state = new Uint32Array(4);
for (let offset = 0; offset < ciphertext.length; offset += 16) {
const block = new Uint8Array(16);
block.set(ciphertext.subarray(offset, Math.min(offset + 16, ciphertext.length)));
const words = bytesToWords(block);
for (let index = 0; index < 4; index++)
state[index] ^= words[index];
state = multiplyGhash(state, hashKey);
}
const lengthBlock = new Uint8Array(16);
const bitLength = ciphertext.length * 8;
const view = new DataView(lengthBlock.buffer);
view.setUint32(12, bitLength >>> 0);
view.setUint32(8, Math.floor(bitLength / 4294967296));
const lengths = bytesToWords(lengthBlock);
for (let index = 0; index < 4; index++)
state[index] ^= lengths[index];
return multiplyGhash(state, hashKey);
}
function incrementCounter(counter) {
for (let index = 15; index >= 12; index--) {
counter[index] = counter[index] + 1 & 255;
if (counter[index])
break;
}
}
function decryptAesGcm(payload, key) {
if (payload.length < 28)
throw new Error("Invalid encrypted payload");
const nonce = payload.subarray(0, 12);
const ciphertext = payload.subarray(12, payload.length - 16);
const expectedTag = payload.subarray(payload.length - 16);
const words = expandAes256Key(key);
const zero = new Uint8Array(16);
const hashKey = bytesToWords(encryptAesBlock(zero, words));
const initialCounter = new Uint8Array(16);
initialCounter.set(nonce);
initialCounter[15] = 1;
const authentication = wordsToBytes(calculateGhash(ciphertext, hashKey));
const encryptedCounter = encryptAesBlock(initialCounter, words);
let mismatch = 0;
for (let index = 0; index < 16; index++)
mismatch |= authentication[index] ^ encryptedCounter[index] ^ expectedTag[index];
if (mismatch)
throw new Error("Invalid encrypted payload tag");
const output = new Uint8Array(ciphertext.length);
const counter = new Uint8Array(initialCounter);
for (let offset = 0; offset < ciphertext.length; offset += 16) {
incrementCounter(counter);
const stream = encryptAesBlock(counter, words);
const length = Math.min(16, ciphertext.length - offset);
for (let index = 0; index < length; index++)
output[offset + index] = ciphertext[offset + index] ^ stream[index];
}
return output;
}
function derivePayloadKey(apiKey, now) {
const hour = Math.floor(now / 36e5);
const dynamic = new Uint8Array(16);
for (let index = 0; index < dynamic.length; index++) {
dynamic[index] = index + 1 ^ Math.floor(hour / 2 ** (index & 7)) & 255;
}
let derived = concatBytes(encodeUtf8(apiKey), dynamic);
for (let iteration = 0; iteration < 600; iteration++)
derived = sha256(derived);
const timeBucket = Math.floor(now / 3e5);
return hmacSha256(derived, `${timeBucket}${apiKey}`);
}
function initDecoder() {
return true;
}
function get_img_key() {
const timestamp = Math.floor(Date.now() / 1e3);
const fingerprint = `1365x768:24:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36:Linux x86_64:en-US:-180:${timestamp}:${CANVAS_FINGERPRINT}`;
return toHex(sha256(encodeUtf8(toHex(sha256(encodeUtf8(fingerprint))))));
}
function process_img_data(value, apiKey) {
const key = derivePayloadKey(apiKey, Date.now());
return decodeUtf8(decryptAesGcm(decodeBase64(value), key));
}
// src/flixer/extractor.js
var NATO_ORDER = [
"alpha",
"bravo",
"charlie",
"delta",
"echo",
"foxtrot",
"golf",
"hotel",
"india",
"juliet",
"kilo",
"lima",
"mike",
"november",
"oscar",
"papa",
"quebec",
"romeo",
"sierra",
"tango",
"uniform",
"victor",
"whiskey",
"xray",
"yankee",
"zulu"
];
var SERVER_LABELS = {
alpha: "Ares",
bravo: "Balder",
charlie: "Circe",
delta: "Dionysus",
echo: "Eros",
foxtrot: "Freya",
golf: "Gaia",
hotel: "Hades",
india: "Isis",
juliet: "Juno",
kilo: "Kronos",
lima: "Loki",
mike: "Medusa",
november: "Nyx",
oscar: "Odin",
papa: "Persephone",
quebec: "Quirinus",
romeo: "Ra",
sierra: "Selene",
tango: "Thor",
uniform: "Uranus",
victor: "Vulcan",
whiskey: "Woden",
xray: "Xolotl",
yankee: "Ymir",
zulu: "Zeus"
};
var TMDB_ID_CACHE = {};
async function resolveTmdbId(id, mediaType) {
if (/^\d+$/.test(id))
return id;
if (!/^tt\d+$/i.test(id))
return null;
const cacheKey = `${mediaType}:${id.toLowerCase()}`;
if (TMDB_ID_CACHE[cacheKey])
return TMDB_ID_CACHE[cacheKey];
const catalogType = mediaType === "movie" ? "movie" : "series";
try {
const raw = await fetchText(`https://v3-cinemeta.strem.io/meta/${catalogType}/${encodeURIComponent(id)}.json`, {
headers: { "Accept": "application/json" }
});
const payload = JSON.parse(raw);
const resolved = payload && payload.meta && payload.meta.moviedb_id;
if (!resolved || !/^\d+$/.test(String(resolved)))
return null;
TMDB_ID_CACHE[cacheKey] = String(resolved);
console.log(`[Flixer] Resolved ${id} to TMDB ${resolved}`);
return TMDB_ID_CACHE[cacheKey];
} catch (error) {
console.warn(`[Flixer] Could not resolve IMDb ID ${id}: ${error && error.message ? error.message : String(error)}`);
return null;
}
}
function buildApiPath(tmdbId, mediaType, season, episode) {
if (mediaType === "movie")
return `/api/tmdb/movie/${encodeURIComponent(tmdbId)}/images`;
return `/api/tmdb/tv/${encodeURIComponent(tmdbId)}/season/${season}/episode/${episode}/images`;
}
async function decryptPayload(encrypted, apiKey) {
const clearText = await process_img_data(encrypted, apiKey);
return JSON.parse(clearText);
}
function getServers(payload) {
const values = [];
if (payload && Array.isArray(payload.sources)) {
for (const source of payload.sources) {
const server = source && String(source.server || "").toLowerCase();
if (server && !values.includes(server))
values.push(server);
}
}
if (payload && payload.servers && typeof payload.servers === "object") {
for (const server of Object.keys(payload.servers)) {
const normalized = server.toLowerCase();
if (!values.includes(normalized))
values.push(normalized);
}
}
return NATO_ORDER.filter((server) => values.includes(server)).concat(values.filter((server) => !NATO_ORDER.includes(server)));
}
function findUrl(payload, server) {
if (payload && Array.isArray(payload.sources)) {
const exact = payload.sources.find((source) => source && String(source.server || "").toLowerCase() === server);
const candidate = exact || payload.sources.find((source) => source && source.url);
return candidate && typeof candidate.url === "string" ? candidate.url.trim() : "";
}
if (payload && payload.sources && typeof payload.sources === "object") {
const value = payload.sources.file || payload.sources.url;
return typeof value === "string" ? value.trim() : "";
}
return "";
}
function getQuality(url) {
const match = String(url).match(/(?:^|[^0-9])(2160|1440|1080|720|480|360)p?(?:[^0-9]|$)/i);
return match ? `${match[1]}p` : "Auto";
}
async function fetchServerPayload(apiUrl, apiPath, apiKey, server) {
const secureHeaders = await createSecureHeaders(apiKey, apiPath);
return await fetchText(apiUrl, {
headers: __spreadProps(__spreadValues({}, secureHeaders), {
"X-Only-Sources": "1",
"X-Server": server
})
});
}
async function extractStreams(tmdbId, mediaType, season, episode) {
const id = String(tmdbId || "").trim();
if (mediaType !== "movie" && mediaType !== "tv")
return [];
if (mediaType === "tv" && (!Number.isInteger(Number(season)) || !Number.isInteger(Number(episode)) || Number(season) < 1 || Number(episode) < 1))
return [];
const resolvedId = await resolveTmdbId(id, mediaType);
if (!resolvedId)
return [];
initDecoder();
const apiKey = get_img_key();
const apiPath = buildApiPath(resolvedId, mediaType, Number(season), Number(episode));
const apiUrl = `${API_URL}${apiPath}`;
const secureHeaders = await createSecureHeaders(apiKey, apiPath);
const serverPayload = await fetchText(apiUrl, {
headers: __spreadProps(__spreadValues({}, secureHeaders), { bW90aGFmYWth: "1" })
});
const servers = getServers(await decryptPayload(serverPayload, apiKey));
const encryptedResponses = await Promise.all(servers.map(async (server) => {
try {
return { server, encrypted: await fetchServerPayload(apiUrl, apiPath, apiKey, server) };
} catch (error) {
console.warn(`[Flixer] ${server} request failed: ${error && error.message ? error.message : String(error)}`);
return { server, encrypted: "" };
}
}));
const streams = [];
const seenUrls = {};
for (const response of encryptedResponses) {
if (!response.encrypted)
continue;
try {
const url = findUrl(await decryptPayload(response.encrypted, apiKey), response.server);
if (!url || seenUrls[url])
continue;
seenUrls[url] = true;
const label = SERVER_LABELS[response.server] || response.server.charAt(0).toUpperCase() + response.server.slice(1);
const quality = getQuality(url);
streams.push({
name: `Flixer \xB7 ${label}`,
title: `${label} \xB7 ${quality}`,
url,
quality,
headers: {
"Referer": `${SITE_URL}/`,
"Origin": SITE_URL,
"User-Agent": HEADERS["User-Agent"]
}
});
} catch (error) {
const message = error && error.message ? error.message : String(error);
if (!/^E5[678]$/.test(message)) {
console.warn(`[Flixer] ${response.server} decode failed: ${message}`);
}
}
}
return streams;
}
// src/flixer/index.js
async function getStreams(tmdbId, mediaType, season, episode) {
try {
console.log(`[Flixer] Request: ${mediaType} ${tmdbId}`);
const streams = await extractStreams(tmdbId, mediaType, season, episode);
console.log(`[Flixer] Found ${streams.length} stream(s)`);
return streams;
} catch (error) {
console.error(`[Flixer] Error: ${error.message}`);
return [];
}
}
module.exports = { getStreams };