feat: gate download options on real-time yt-dlp video analysis
Options (quality, subtitles) are now derived from a yt-dlp -J probe of the submitted URL instead of a static list, so users can't pick combinations the source video doesn't actually support. Submission is blocked until the probe succeeds. - New /api/probe endpoint + src/lib/ytdlp-probe.ts, with its own rate limiter (rate-limit.ts refactored into a createRateLimiter factory). - New options: subtitle language selection, clip start/end trim, MP3 audio quality. - Fixed buildYtdlpArgs: format=mp3 never triggered audio extraction (-x/--audio-format), and quality=best never applied --merge-output-format, so the chosen container had no real effect. - Cross-platform yt-dlp invocation: the bundled bin/yt-dlp is a Python zipapp relying on a shebang, which Windows' spawn() can't run directly. buildYtdlpCommand() runs it through `python` on Windows and execs it directly on Linux/o2switch, where the shebang works natively. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
+12
-2
@@ -9,13 +9,23 @@
|
||||
"urlLabel": "Video URL",
|
||||
"format": "Format",
|
||||
"quality": "Quality",
|
||||
"subtitles": "Subtitles (fr, en)",
|
||||
"subtitles": "Subtitles",
|
||||
"subtitleLanguages": "Subtitle languages",
|
||||
"advanced": "Advanced options",
|
||||
"formats": "mp4 · mp3 · webm · mkv",
|
||||
"submit": "Download",
|
||||
"submitting": "Sending...",
|
||||
"errorRateLimit": "Too many submissions. Try again in an hour.",
|
||||
"errorGeneric": "Submission error."
|
||||
"errorGeneric": "Submission error.",
|
||||
"analyzing": "Analyzing video...",
|
||||
"probeError": "Couldn't analyze this video. Check the link or try again.",
|
||||
"retry": "Retry",
|
||||
"audioOnlySource": "Audio-only source",
|
||||
"clipRange": "Clip (optional)",
|
||||
"clipStart": "Start (s)",
|
||||
"clipEnd": "End (s)",
|
||||
"audioQuality": "Audio quality",
|
||||
"videoLength": "Length: {duration}"
|
||||
},
|
||||
"status": {
|
||||
"heading": "Download status",
|
||||
|
||||
+12
-2
@@ -9,13 +9,23 @@
|
||||
"urlLabel": "URL del vídeo",
|
||||
"format": "Formato",
|
||||
"quality": "Calidad",
|
||||
"subtitles": "Subtítulos (fr, en)",
|
||||
"subtitles": "Subtítulos",
|
||||
"subtitleLanguages": "Idiomas de los subtítulos",
|
||||
"advanced": "Opciones avanzadas",
|
||||
"formats": "mp4 · mp3 · webm · mkv",
|
||||
"submit": "Descargar",
|
||||
"submitting": "Enviando...",
|
||||
"errorRateLimit": "Demasiadas peticiones. Inténtalo de nuevo en una hora.",
|
||||
"errorGeneric": "Error al enviar."
|
||||
"errorGeneric": "Error al enviar.",
|
||||
"analyzing": "Analizando el vídeo...",
|
||||
"probeError": "No se pudo analizar este vídeo. Comprueba el enlace o inténtalo de nuevo.",
|
||||
"retry": "Reintentar",
|
||||
"audioOnlySource": "Fuente solo de audio",
|
||||
"clipRange": "Fragmento (opcional)",
|
||||
"clipStart": "Inicio (s)",
|
||||
"clipEnd": "Fin (s)",
|
||||
"audioQuality": "Calidad de audio",
|
||||
"videoLength": "Duración: {duration}"
|
||||
},
|
||||
"status": {
|
||||
"heading": "Estado de la descarga",
|
||||
|
||||
+12
-2
@@ -9,13 +9,23 @@
|
||||
"urlLabel": "URL de la vidéo",
|
||||
"format": "Format",
|
||||
"quality": "Qualité",
|
||||
"subtitles": "Sous-titres (fr, en)",
|
||||
"subtitles": "Sous-titres",
|
||||
"subtitleLanguages": "Langues des sous-titres",
|
||||
"advanced": "Options avancées",
|
||||
"formats": "mp4 · mp3 · webm · mkv",
|
||||
"submit": "Télécharger",
|
||||
"submitting": "Envoi en cours...",
|
||||
"errorRateLimit": "Trop de soumissions. Réessayez dans une heure.",
|
||||
"errorGeneric": "Erreur lors de la soumission."
|
||||
"errorGeneric": "Erreur lors de la soumission.",
|
||||
"analyzing": "Analyse de la vidéo...",
|
||||
"probeError": "Impossible d'analyser cette vidéo. Vérifiez le lien ou réessayez.",
|
||||
"retry": "Réessayer",
|
||||
"audioOnlySource": "Source audio uniquement",
|
||||
"clipRange": "Extrait (optionnel)",
|
||||
"clipStart": "Début (s)",
|
||||
"clipEnd": "Fin (s)",
|
||||
"audioQuality": "Qualité audio",
|
||||
"videoLength": "Durée : {duration}"
|
||||
},
|
||||
"status": {
|
||||
"heading": "Statut du téléchargement",
|
||||
|
||||
+12
-2
@@ -9,13 +9,23 @@
|
||||
"urlLabel": "URL del video",
|
||||
"format": "Formato",
|
||||
"quality": "Qualità",
|
||||
"subtitles": "Sottotitoli (fr, en)",
|
||||
"subtitles": "Sottotitoli",
|
||||
"subtitleLanguages": "Lingue dei sottotitoli",
|
||||
"advanced": "Opzioni avanzate",
|
||||
"formats": "mp4 · mp3 · webm · mkv",
|
||||
"submit": "Scarica",
|
||||
"submitting": "Invio in corso...",
|
||||
"errorRateLimit": "Troppe richieste. Riprova tra un'ora.",
|
||||
"errorGeneric": "Errore durante l'invio."
|
||||
"errorGeneric": "Errore durante l'invio.",
|
||||
"analyzing": "Analisi del video...",
|
||||
"probeError": "Impossibile analizzare questo video. Controlla il link o riprova.",
|
||||
"retry": "Riprova",
|
||||
"audioOnlySource": "Sorgente solo audio",
|
||||
"clipRange": "Estratto (opzionale)",
|
||||
"clipStart": "Inizio (s)",
|
||||
"clipEnd": "Fine (s)",
|
||||
"audioQuality": "Qualità audio",
|
||||
"videoLength": "Durata: {duration}"
|
||||
},
|
||||
"status": {
|
||||
"heading": "Stato del download",
|
||||
|
||||
Reference in New Issue
Block a user