Bump deps

This commit is contained in:
0d0 2025-02-05 13:12:58 +01:00
parent 6ca85079fa
commit ebf8d8e67d
5 changed files with 217 additions and 210 deletions

View file

@ -1,80 +0,0 @@
import { DOWNLOAD_PATH } from '$env/static/private';
import { redirect } from '@sveltejs/kit';
import youtubedl from 'youtube-dl-exec';
const isAudioFormat = (format: string) => {
let isAudio = false;
switch (format) {
case 'mp3':
isAudio = true;
break;
default:
isAudio = false;
break;
}
return isAudio;
};
const isVideoFormat = (format: string) => {
let isVideo = false;
switch (format) {
case 'mp4':
isVideo = true;
break;
default:
isVideo = false;
break;
}
return isVideo;
}
export const actions = {
download: async ({ request, cookies }) => {
const data = await request.formData();
const obj = {};
for (const element of data) {
obj[element[0]] = element[1];
}
const { format, source, link } = obj;
if (!(format && source && link)) {
throw redirect(307, '/');
}
console.info(`Asked ${source} download of ${link}`);
switch (source) {
case 'youtube':
const options = {
output: `${DOWNLOAD_PATH}/%(artist)s-%(title)s.%(ext)s`,
embedThumbnail: true
}
if (isAudioFormat(format)) {
options.extractAudio = true;
options.audioFormat = format;
}
isVideoFormat(format) ? options.format = format : ''
const output = await youtubedl(link);
console.log(output);
console.info(`Downloaded ${link} to ${output}`);
break;
case 'spotify':
break;
default:
console.error('ops');
}
return { success: true };
}
};

View file

@ -1,7 +1,4 @@
<script>
import { enhance } from '$app/forms';
let { form } = $props();
let source = $state('youtube');
let link = $state('');
let format = $state('mp3');
@ -13,29 +10,27 @@
showModal = !showModal;
};
const handleSubmit = (e) => {
const handleSubmit = async (e) => {
e.preventDefault();
console.log({
source,
link,
format
});
};
const onFormSubmit = ({ formElement, formData, action, cancel, submitter }) => {
loading = true;
// `formElement` is this `<form>` element
// `formData` is its `FormData` object that's about to be submitted
// `action` is the URL to which the form is posted
// calling `cancel()` will prevent the submission
// `submitter` is the `HTMLElement` that caused the form to be submitted
const searchParams = new URLSearchParams();
searchParams.append('source', source);
searchParams.append('link', link);
searchParams.append('format', format);
return async ({ result, update }) => {
loading = false;
error = result.type !== 'success';
// `result` is an `ActionResult` object
// `update` is a function which triggers the default logic that would be triggered if this callback wasn't set
};
const response = await fetch(`/download?${searchParams.toString()}`);
const file = window.URL.createObjectURL(await response.blob());
const anchor = document.createElement('a');
anchor.setAttribute('download', true);
anchor.href = file;
anchor.click();
};
$effect(() => {
@ -66,7 +61,7 @@
</button>
<h1 class="mb-6 text-center text-xl">🐙 Scaricatore 🐙</h1>
<form method="POST" action="?/download" class="space-y-6" use:enhance={onFormSubmit}>
<form class="space-y-6" onsubmit={handleSubmit}>
<!-- Source Selection -->
<fieldset class="space-y-4">
<legend class="text-green-400">Choose Source:</legend>
@ -125,8 +120,8 @@
</div>
<!-- Submit Button -->
<button
type="submit"
<a
{href}
class="w-full rounded-lg border-4 border-pink-700 bg-pink-500 px-4 py-3 text-black transition hover:bg-pink-600 active:border-yellow-500"
>
Start Download!

View file

@ -0,0 +1,92 @@
import { DOWNLOAD_PATH } from '$env/static/private';
import { redirect } from '@sveltejs/kit';
import ytdl from 'youtube-dl-exec';
import { json, error } from '@sveltejs/kit';
import type { RequestHandler } from './$types';
import { spawn } from 'child_process';
/**
* Fetch YouTube metadata (title, uploader/artist)
*/
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
*/
function streamYouTube(link: string, format: string): ReadableStream<Uint8Array> {
return new ReadableStream({
start(controller) {
const args = [
'-o',
'-',
format === 'mp3' ? '--embed-metadata' : '',
format === 'mp3' ? '--embed-thumbnail' : '',
'--format',
format === 'mp3' ? 'bestaudio' : 'best',
'--audio-format',
format === 'mp3' ? 'mp3' : '',
'--no-playlist'
].filter(Boolean);
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);
});
}
});
}
/**
* Sanitize filename by removing unsafe characters
*/
function sanitizeFilename(name: string): string {
return name.replace(/[\/:*?"<>|]/g, '').trim();
}
export const GET: RequestHandler = async ({ 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
// Validate input
if (!link || !format || !source) {
throw error(400, 'Missing required query parameters: link, format, or source');
}
if (source !== 'youtube') {
throw error(400, 'Currently, only YouTube is supported');
}
try {
// Fetch metadata for filename
const metadata = await getYouTubeMetadata(link);
const { title, uploader } = metadata;
const safeTitle = sanitizeFilename(`${uploader} - ${title}`);
const filename = `${safeTitle}.${format}`;
console.log(filename)
// Stream video/audio
return new Response(streamYouTube(link, format), {
headers: {
'Content-Type': format === 'mp3' ? 'audio/mpeg' : 'video/mp4',
'Content-Disposition': `attachment; filename="${filename}"`
}
});
} catch (err) {
console.error('Error fetching metadata:', err);
throw error(500, 'Failed to fetch video metadata');
}
};