From 24ff0a07380655ec99f7a43b4ce14903eec1a970 Mon Sep 17 00:00:00 2001 From: 0d0 <0d0acre@esiliati.org> Date: Tue, 25 Feb 2025 14:26:07 +0100 Subject: [PATCH] Use winston and error management of stream controller --- src/hooks.server.ts | 7 +++++++ src/lib/server/ytdlp.ts | 31 ++++++++++++++++++++++++------- src/routes/download/+server.ts | 8 +++++--- 3 files changed, 36 insertions(+), 10 deletions(-) create mode 100644 src/hooks.server.ts diff --git a/src/hooks.server.ts b/src/hooks.server.ts new file mode 100644 index 0000000..09a01a4 --- /dev/null +++ b/src/hooks.server.ts @@ -0,0 +1,7 @@ +import { logger } from "$lib/server/helpers"; + +export async function handle({ event, resolve }) { + logger.info(`Received request: ${event.url}`); + + return await resolve(event);; +} \ No newline at end of file diff --git a/src/lib/server/ytdlp.ts b/src/lib/server/ytdlp.ts index 5c5beb1..c9ac629 100644 --- a/src/lib/server/ytdlp.ts +++ b/src/lib/server/ytdlp.ts @@ -2,7 +2,7 @@ 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'; +import { logger, mimeTypeMap } from '$lib/server/helpers'; const YTDLP_PATH: string = env.YTDLP_PATH as string; @@ -24,31 +24,48 @@ export async function getYouTubeMetadata(link: string) { * Streams the YouTube video/audio using youtube-dl-exec */ export function streamYouTube(link: string, format: string): ReadableStream { + logger.debug(`Starting to stream: ${link}`); const mimeType: string | undefined = mimeTypeMap.get(format) - + if (!mimeType) { throw new Error("Unsupported format"); } + logger.debug(`Given format is compatible: ${mimeType}`); return new ReadableStream({ start(controller) { const args = [ + '--no-write-thumbnail', '-o', '-', ].filter(Boolean); - if(mimeType?.includes('audio')) { + 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(`${YTDLP_PATH} ${args.join(' ')} ${link}`) + const cmd = `${YTDLP_PATH} ${args.join(' ')} ${link}` + logger.debug(`Running: ${cmd}`); - const process = spawn(YTDLP_PATH, [...args, link], { stdio: ['ignore', 'pipe', 'ignore'] }); + const process = spawn(YTDLP_PATH, [...args, link], { cwd: "/tmp", stdio: ['ignore', 'pipe', 'pipe'] }); - process.stdout.on('data', (chunk) => controller.enqueue(chunk)); - process.stdout.on('end', () => controller.close()); + process.stdout.on('data', (chunk) => { + try { + controller.enqueue(chunk) + } catch (ex) { + process.kill() + } + }); + process.stderr.on('data', (chunk) => logger.debug(chunk.toString())); + process.stdout.on('end', () => { + try { + controller.close() + } catch (ex) { + process.kill() + } + }); process.stdout.on('error', (err) => { console.error('Stream error:', err); controller.error(err); diff --git a/src/routes/download/+server.ts b/src/routes/download/+server.ts index 6369cb5..6280088 100644 --- a/src/routes/download/+server.ts +++ b/src/routes/download/+server.ts @@ -1,14 +1,14 @@ import { error } from '@sveltejs/kit'; import type { RequestHandler } from './$types'; import { getYouTubeMetadata, streamYouTube, ytdl } from '$lib/server/ytdlp'; -import { isURLValid, mimeTypeMap } from '$lib/server/helpers'; +import { isURLValid, logger, mimeTypeMap } from '$lib/server/helpers'; const validateRequest = (url: URL) => { // Get query params const link = url.searchParams.get('link'); const format = url.searchParams.get('format'); // mp3, mp4 const source = url.searchParams.get('source'); // youtube or spotify - const metadata = url.searchParams.get('metadata'); + const metadata = url.searchParams.has('metadata'); // Validate input if (!link || !format || !source) { @@ -32,11 +32,13 @@ const validateRequest = (url: URL) => { } } export const GET: RequestHandler = async ({ url }) => { - const { format, source, metadata, link } = validateRequest(url) + const { format, source, metadata, link } = validateRequest(url); + logger.debug(`Request is valid`); let filename = `you-clicked-no-metadata-so-i-cant-put-a-correct-name.${format}`; if (!!metadata) { try { + logger.debug(`Fetching video data to set filename`); // Fetch metadata for filename const ytMetadata = await getYouTubeMetadata(link); const { title, uploader } = ytMetadata;