feat(miruro): attempt to retrieve quality from stream playlist
This commit is contained in:
1 parent
6e86adb0e6
commit
27a87191c3
7 files changed
+928
-42
No files matched your search
+71
-20
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* miruro - Built from src/miruro/
|
||||
* Generated: 2026-07-19T17:01:21.823Z
|
||||
* Generated: 2026-07-19T17:21:26.205Z
|
||||
*/
|
||||
var __defProp = Object.defineProperty;
|
||||
var __defProps = Object.defineProperties;
|
||||
@@ -573,6 +573,7 @@ function secureGet(_0) {
|
||||
// src/miruro/extractor.js
|
||||
var ANIMAP_URL = "https://animap.id/api/map";
|
||||
var ANILIST_URL = "https://graphql.anilist.co";
|
||||
var HLS_QUALITY_TIMEOUT_MS = 4e3;
|
||||
var PROVIDERS = [
|
||||
{ id: "bonk", label: "Bonk", subCategory: "ssub" },
|
||||
{ id: "kiwi", label: "Kiwi", subCategory: "sub" },
|
||||
@@ -762,38 +763,88 @@ function getOrigin(url) {
|
||||
const match = typeof url === "string" ? url.match(/^(https?:\/\/[^/]+)/i) : null;
|
||||
return match ? match[1] : BASE_URL;
|
||||
}
|
||||
function getQuality(stream) {
|
||||
const value = String(stream.quality || stream.server || "HD");
|
||||
function getDeclaredQuality(stream) {
|
||||
const value = `${stream.quality || ""} ${stream.resolution || ""} ${stream.server || ""}`;
|
||||
const resolution = value.match(/(2160|1440|1080|720|480|360)p?/i);
|
||||
if (resolution) {
|
||||
return `${resolution[1]}p`;
|
||||
}
|
||||
return /4k/i.test(value) ? "4K" : "HD";
|
||||
return /4k/i.test(value) ? "4K" : null;
|
||||
}
|
||||
function getHlsQuality(manifest) {
|
||||
const heights = [];
|
||||
const pattern = /\bRESOLUTION\s*=\s*\d+\s*x\s*(\d+)\b/gi;
|
||||
let match;
|
||||
while ((match = pattern.exec(manifest)) !== null) {
|
||||
const height = Number(match[1]);
|
||||
if (height > 0) {
|
||||
heights.push(height);
|
||||
}
|
||||
}
|
||||
return heights.length > 0 ? `${Math.max(...heights)}p` : null;
|
||||
}
|
||||
function isHlsStream(stream) {
|
||||
const type = String(stream && stream.type || "").toLowerCase();
|
||||
return type === "hls" || type === "m3u8" || type === "application/x-mpegurl";
|
||||
}
|
||||
function resolveQuality(stream, headers) {
|
||||
return __async(this, null, function* () {
|
||||
const declaredQuality = getDeclaredQuality(stream);
|
||||
if (declaredQuality) {
|
||||
return declaredQuality;
|
||||
}
|
||||
if (isHlsStream(stream)) {
|
||||
let timeoutId;
|
||||
try {
|
||||
const manifest = yield Promise.race([
|
||||
fetchText(stream.url, { headers }),
|
||||
new Promise((resolve) => {
|
||||
timeoutId = setTimeout(() => resolve(null), HLS_QUALITY_TIMEOUT_MS);
|
||||
})
|
||||
]);
|
||||
const hlsQuality = typeof manifest === "string" ? getHlsQuality(manifest) : null;
|
||||
if (hlsQuality) {
|
||||
return hlsQuality;
|
||||
}
|
||||
} catch (_) {
|
||||
} finally {
|
||||
if (timeoutId != null) {
|
||||
clearTimeout(timeoutId);
|
||||
}
|
||||
}
|
||||
}
|
||||
return "HD";
|
||||
});
|
||||
}
|
||||
function isPlayableStream(stream) {
|
||||
const type = String(stream && stream.type || "").toLowerCase();
|
||||
return !!(stream && stream.url) && (type === "hls" || type === "m3u8" || type === "mp4" || type === "application/x-mpegurl");
|
||||
}
|
||||
function normalizeStreams(sourcePayload, provider, variant) {
|
||||
const subtitleCount = Array.isArray(sourcePayload.subtitles) ? sourcePayload.subtitles.length : 0;
|
||||
const language = variant === "dub" ? "DUB" : "SUB";
|
||||
return (sourcePayload.streams || []).filter(isPlayableStream).map((stream) => {
|
||||
const referer = stream.referer || BASE_URL;
|
||||
const server = stream.server || getQuality(stream);
|
||||
const subtitleLabel = subtitleCount > 0 && variant !== "dub" ? " \xB7 CC" : "";
|
||||
return {
|
||||
// Nuvio's source picker prominently displays `name`, so include the
|
||||
// Miruro server and audio variant here instead of only in `title`.
|
||||
name: `Miruro \xB7 ${provider.label} \xB7 ${language}`,
|
||||
title: `[${language}] ${provider.label} \xB7 ${server}${subtitleLabel}`,
|
||||
url: stream.url,
|
||||
quality: getQuality(stream),
|
||||
headers: {
|
||||
return __async(this, null, function* () {
|
||||
const subtitleCount = Array.isArray(sourcePayload.subtitles) ? sourcePayload.subtitles.length : 0;
|
||||
const language = variant === "dub" ? "DUB" : "SUB";
|
||||
return Promise.all((sourcePayload.streams || []).filter(isPlayableStream).map((stream) => __async(this, null, function* () {
|
||||
const streamHeaders = stream.headers && typeof stream.headers === "object" ? stream.headers : {};
|
||||
const referer = stream.referer || streamHeaders.Referer || streamHeaders.referer || BASE_URL;
|
||||
const subtitleLabel = subtitleCount > 0 && variant !== "dub" ? " \xB7 CC" : "";
|
||||
const headers = __spreadProps(__spreadValues({}, streamHeaders), {
|
||||
"Referer": referer,
|
||||
"Origin": getOrigin(referer),
|
||||
"User-Agent": HEADERS["User-Agent"]
|
||||
}
|
||||
};
|
||||
});
|
||||
const quality = yield resolveQuality(stream, headers);
|
||||
const server = !stream.server || /^(?:HD|auto)$/i.test(stream.server) ? quality : stream.server;
|
||||
return {
|
||||
// Nuvio's source picker prominently displays `name`, so include the
|
||||
// Miruro server and audio variant here instead of only in `title`.
|
||||
name: `Miruro \xB7 ${provider.label} \xB7 ${language}`,
|
||||
title: `[${language}] ${provider.label} \xB7 ${server}${subtitleLabel}`,
|
||||
url: stream.url,
|
||||
quality,
|
||||
headers
|
||||
};
|
||||
})));
|
||||
});
|
||||
}
|
||||
function getProviderStreams(provider, providerPayload, anilistId, episodeNumber) {
|
||||
|
||||
Reference in new issue
Block a user