Files
sdk/src/subtitles.js
2026-07-27 22:10:31 -07:00

127 lines
4.3 KiB
JavaScript

import { getUA } from './utils/helpers.js';
const SUBTITLE_BASES = [
'https://sub.vdrk.site/v1',
'https://sub.vdrk.site/v2',
'https://fed-subs.pstream.mov'
];
const VYLIAN_MESSAGES = [
"Thanks for using Vyla!"
];
function generateVylianVtt() {
let vttContent = 'WEBVTT\n\n';
let currentTime = 1;
while (currentTime <= 7200) {
const duration = Math.floor(Math.random() * 4) + 1;
const message = VYLIAN_MESSAGES[Math.floor(Math.random() * VYLIAN_MESSAGES.length)];
const startTime = formatVttTime(currentTime);
const endTime = formatVttTime(currentTime + duration);
vttContent += `${startTime} --> ${endTime}\n${message}\n\n`;
currentTime += duration + Math.floor(Math.random() * 60) + 30;
}
return vttContent;
}
function formatVttTime(seconds) {
const hours = Math.floor(seconds / 3600);
const minutes = Math.floor((seconds % 3600) / 60);
const secs = seconds % 60;
return `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}:${String(secs).padStart(2, '0')}.000`;
}
export async function fetchSubtitles(paths = []) {
try {
const results = await Promise.all(
paths.map(async ({ base, path }) => {
try {
const res = await fetch(`${base}${path}`, {
headers: { 'User-Agent': getUA() },
signal: AbortSignal.timeout(5000),
});
if (!res.ok) {
res.body?.cancel();
return [];
}
const data = await res.json();
if (base.includes('/v2')) {
return Array.isArray(data)
? data.map(x => ({
label: x.label,
file: x.file || x.url,
type: 'vtt',
source: 'v2'
}))
: [];
}
if (base.includes('fed-subs.pstream.mov')) {
if (!data?.subtitles || typeof data.subtitles !== 'object') return [];
return Object.entries(data.subtitles)
.map(([language, sub]) => {
if (!sub?.subtitle_link) return null;
const ext = sub.subtitle_link.split('.').pop()?.toLowerCase();
return {
label: sub.subtitle_name || language,
file: sub.subtitle_link,
type: ext === 'vtt' ? 'vtt' : 'srt',
source: 'febbox'
};
})
.filter(Boolean);
}
const v1 = Array.isArray(data) ? data : [];
return v1.map(x => ({
label: x.label,
file: x.file || x.url,
type: 'vtt',
source: 'v1'
}));
} catch {
return [];
}
})
);
const val = results.flat();
val.push({
label: 'Vylian',
file: 'data:text/vtt;base64,' + Buffer.from(generateVylianVtt()).toString('base64'),
type: 'vtt',
source: 'easter-egg'
});
return val;
} catch {
return [];
}
}
export async function getSubPathsMovie(id) {
return [
{ base: SUBTITLE_BASES[0], path: `/movie/${id}` },
{ base: SUBTITLE_BASES[1], path: `/movie/${id}` },
{ base: SUBTITLE_BASES[2], path: `/movie/tt${id}` }
];
}
export async function getSubPathsTv(id, season, episode) {
return [
{ base: SUBTITLE_BASES[0], path: `/tv/${id}/${season}/${episode}` },
{ base: SUBTITLE_BASES[1], path: `/tv/${id}/${season}/${episode}` },
{ base: SUBTITLE_BASES[2], path: `/tv/tt${id}/${season}/${episode}` }
];
}
export { SUBTITLE_BASES };