import { create } from 'youtube-dl-exec'; import { env } from '$env/dynamic/private'; import { spawn } from 'node:child_process'; import supportedFormats from '$lib/common/supportedFormats.json'; import { mimeTypeMap } from '$lib/server/helpers'; const YTDLP_PATH: string = env.YTDLP_PATH as string; export const ytdl = create(YTDLP_PATH); /** * Fetch YouTube metadata (title, uploader/artist) */ export async function getYouTubeMetadata(link: string) { return await ytdl(link, { dumpSingleJson: true, noCheckCertificates: true, noWarnings: true, preferFreeFormats: true }); } /** * Streams the YouTube video/audio using youtube-dl-exec */ export function streamYouTube(link: string, format: string): ReadableStream { const mimeType: string | undefined = mimeTypeMap.get(format) if (!mimeType) { throw new Error("Unsupported format"); } return new ReadableStream({ start(controller) { const args = [ '-o', '-', ].filter(Boolean); if(mimeType?.includes('audio')) { args.push(...['--extract-audio', '--embed-metadata', '--embed-thumbnail', '--audio-format', format]) } else if (mimeType.includes('video')) { args.push(...['--embed-metadata', '--embed-thumbnail', '--format', format]) } console.info(`yt-dlp ${args.join(' ')} ${link}`) const process = spawn('yt-dlp', [...args, link], { stdio: ['ignore', 'pipe', 'ignore'] }); process.stdout.on('data', (chunk) => controller.enqueue(chunk)); process.stdout.on('end', () => controller.close()); process.stdout.on('error', (err) => { console.error('Stream error:', err); controller.error(err); }); } }); }