push
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
function qualityToPixels(q) {
|
||||
if (!q) return null;
|
||||
const s = String(q).toLowerCase();
|
||||
if (/2160|4k|uhd/.test(s)) return 2160;
|
||||
const m = s.match(/(\d{3,4})\s*p/);
|
||||
if (m) {
|
||||
const n = parseInt(m[1], 10);
|
||||
return n >= 1440 ? 2160 : n;
|
||||
}
|
||||
if (/1080|full\s?hd|fhd/.test(s)) return 1080;
|
||||
if (/720/.test(s)) return 720;
|
||||
if (/480/.test(s)) return 480;
|
||||
return null;
|
||||
}
|
||||
|
||||
function detectAudio(text) {
|
||||
const t = ` ${String(text || '').toLowerCase()} `;
|
||||
if (/\bdts\b|dts-?hd/.test(t)) return 'dts';
|
||||
if (/e-?ac3|dd\+|ac-?3|dolby digital/.test(t)) return 'ac3';
|
||||
if (/\baac\b/.test(t)) return 'aac';
|
||||
if (/\bopus\b/.test(t)) return 'opus';
|
||||
if (/\bflac\b|lossless/.test(t)) return 'flac';
|
||||
if (/\bmp3\b/.test(t)) return 'mp3';
|
||||
if (/dual-?audio|multi-?audio|original audio|multi audio/.test(t)) return 'multi';
|
||||
return null;
|
||||
}
|
||||
|
||||
function extOf(text) {
|
||||
const m = String(text || '').toLowerCase().split(/[?#]/)[0].match(/\.([a-z0-9]{2,5})$/);
|
||||
return m ? m[1] : '';
|
||||
}
|
||||
|
||||
function streamType(url, name) {
|
||||
const u = String(url || '');
|
||||
const n = String(name || '').toLowerCase();
|
||||
if (/^magnet:/i.test(u)) return 'magnet';
|
||||
if (/m3u8/i.test(u)) return 'm3u8';
|
||||
const ext = extOf(u) || extOf(n);
|
||||
if (ext === 'mkv' || /\.mkv\b/.test(n)) return 'mkv';
|
||||
if (ext === 'mp4' || ext === 'm4v' || ext === 'mov' || /\.mp4\b/.test(n)) return 'mp4';
|
||||
if (ext === 'avi' || /\.avi\b/.test(n)) return 'avi';
|
||||
if (ext === 'webm') return 'webm';
|
||||
if (ext === 'ts' || ext === 'm4a') return 'other';
|
||||
return ext || 'other';
|
||||
}
|
||||
|
||||
function normalizeSubtitles(subs) {
|
||||
if (!Array.isArray(subs)) return [];
|
||||
return subs
|
||||
.filter((s) => s && typeof s.url === 'string' && s.url.length > 0)
|
||||
.map((s) => ({
|
||||
url: s.url,
|
||||
language: s.language || s.id || s.lang || '',
|
||||
name: s.name || '',
|
||||
}));
|
||||
}
|
||||
|
||||
function normalize(raw, providerName) {
|
||||
const text = [raw.name, raw.title, raw.description].filter(Boolean).join(' ');
|
||||
const pixels = qualityToPixels(raw.quality) ?? qualityToPixels(`${raw.name || ''} ${raw.title || ''}`);
|
||||
return {
|
||||
provider: providerName,
|
||||
serverName: raw._serverName || '',
|
||||
name: raw.name || raw.title || 'stream',
|
||||
title: raw.title || '',
|
||||
description: raw.description || '',
|
||||
url: raw.url,
|
||||
quality: raw.quality || (pixels ? `${pixels}p` : ''),
|
||||
pixels,
|
||||
audio: detectAudio(text),
|
||||
type: streamType(raw.url, raw.name || raw.title),
|
||||
subtitles: normalizeSubtitles(raw.subtitles),
|
||||
size: typeof raw.size === 'number' ? raw.size : 0,
|
||||
headers: raw.headers && typeof raw.headers === 'object' ? raw.headers : {},
|
||||
is4k: !!raw._is4k || pixels === 2160,
|
||||
};
|
||||
}
|
||||
|
||||
function formatBytes(n) {
|
||||
if (!n || n <= 0) return '';
|
||||
const units = ['B', 'KB', 'MB', 'GB', 'TB'];
|
||||
let i = 0;
|
||||
let v = n;
|
||||
while (v >= 1024 && i < units.length - 1) {
|
||||
v /= 1024;
|
||||
i++;
|
||||
}
|
||||
return `${v.toFixed(v >= 100 || i === 0 ? 0 : 1)}${units[i]}`;
|
||||
}
|
||||
|
||||
module.exports = { normalize, qualityToPixels, detectAudio, formatBytes };
|
||||
Reference in New Issue
Block a user