Application web self-hosted pour lister, mettre en file d'attente et extraire des vidéos/audios YouTube (yt-dlp + ffmpeg), avec suivi en temps réel.
Find a file
Nicolas 725c5a5a7f feat(client): frontend (formulaire d'ajout + file d'attente)
Interface web complète : formulaire d'ajout (URL directe ou recherche de
chaîne) et panneau de file d'attente avec sondage de la progression.

- views/downloadForm/ : sélecteur de mode (vidéo/audio/miniature) partagé,
  ajout direct par URL, recherche de chaîne (GET /api/channel) avec ajout
  par résultat. Construction DOM via createElement/textContent (jamais
  d'innerHTML avec du texte venant de YouTube), pas juste par prudence :
  ça évite aussi tout risque d'injection depuis un titre de vidéo.
- views/queuePanel/ : sonde GET /api/queue toutes les 1,5s, affiche statut/
  progression/erreur par élément, annulation et lien de téléchargement
  natif (<a download>, pas de fetch+blob).
- api/ : clients fetch typés (channelApi, queueApi), chaque await dans son
  propre try/catch avec message d'erreur adapté (réseau vs HTTP vs JSON).
- QueueItem gagne un champ title optionnel (purement informatif, jamais
  utilisé pour construire la commande yt-dlp) pour un affichage plus
  parlant qu'une URL brute.
- client/tsconfig.json + build.mjs : cible ES2022 (nécessaire pour
  Error.cause, jusque-là ES2020).
- Vitest ajouté côté client (fonctions pures de src/format.ts ; le câblage
  DOM est vérifié manuellement, pas de jsdom pour l'instant).

Deux bugs réels trouvés et corrigés en testant dans un vrai navigateur
(pas seulement en lisant le code) :
- CSS : un attribut `hidden` sur un conteneur `display: flex` se faisait
  écraser par cette règle (même spécificité, la feuille de l'auteur gagne)
  - les deux panneaux d'options restaient visibles en même temps.
- server/src/routes/channel.ts : ne mappait vers 502 que les YtDlpError
  (code de sortie non nul), pas les erreurs brutes de spawn (ex. binaire
  introuvable - ENOENT), qui remontaient donc en 500 générique. Corrigé +
  test de non-régression.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-16 09:28:49 +02:00
.forgejo/workflows feat(client): frontend (formulaire d'ajout + file d'attente) 2026-09-16 09:28:49 +02:00
client feat(client): frontend (formulaire d'ajout + file d'attente) 2026-09-16 09:28:49 +02:00
server feat(client): frontend (formulaire d'ajout + file d'attente) 2026-09-16 09:28:49 +02:00
spec feat(client): frontend (formulaire d'ajout + file d'attente) 2026-09-16 09:28:49 +02:00
.gitignore chore: init .gitignore 2026-09-16 07:33:38 +02:00
biome.json feat: squelette serveur/client + Docker + CI de build/release 2026-09-16 07:55:43 +02:00
package-lock.json feat: squelette serveur/client + Docker + CI de build/release 2026-09-16 07:55:43 +02:00
package.json feat: squelette serveur/client + Docker + CI de build/release 2026-09-16 07:55:43 +02:00
README.md feat: squelette serveur/client + Docker + CI de build/release 2026-09-16 07:55:43 +02:00

youtubeDownloader

Application web self-hosted pour parcourir, mettre en file d'attente et extraire des vidéos/audios YouTube, en s'appuyant sur yt-dlp et ffmpeg.

Ce projet reprend et remplace une série de scripts .cmd (téléchargement vidéo, récupération de miniatures, recherche de streams par chaîne) par une interface web unique.

Fonctionnalités prévues

  • Parcourir une chaîne : recherche par chaîne (URL ou @handle), liste de ses vidéos/streams avec filtre par mots-clés dans le titre.
  • Ajout par URL : ajout direct d'une ou plusieurs URLs YouTube.
  • File d'attente : chaque élément ajouté est configurable individuellement :
    • Vidéo : qualité, sous-titres (fr/en), miniature intégrée, métadonnées.
    • Audio seul : extraction dans un format courant (mp3/m4a/opus).
    • Miniature seule : récupération du poster uniquement.
  • Exécution en parallèle : plusieurs téléchargements simultanés (concurrence configurable), avec suivi de progression en temps réel.
  • Livraison au navigateur : les fichiers terminés sont téléchargés directement par l'utilisateur (pas de dépôt sur une bibliothèque partagée type Emby).
  • Accès : aucune authentification, usage LAN uniquement.

Stack technique (prévue)

  • Backend : TypeScript / Fastify, organisé en services modulaires (découverte de chaîne, gestion de la file d'attente, exécution des téléchargements, notifications temps réel).
  • Frontend : TypeScript vanilla, vues séparées en .ts / .html / .scss.
  • Moteur : yt-dlp + ffmpeg (installés dans l'image Docker, non versionnés).
  • Déploiement : Docker / docker-compose.
  • Linting : Biome.js.

Développement

Squelette actuel : serveur Fastify (server/) + client minimal (client/), sans encore la logique de découverte/file d'attente/téléchargement.

# Racine : lint (Biome) sur tout le repo
npm install && npm run lint

# Client : build (esbuild + sass) -> client/dist
cd client && npm install && npm run build

# Serveur : typecheck, tests, dev (sert client/dist)
cd server && npm install
npm run typecheck
npm test
npm run dev

Le serveur écoute par défaut sur http://localhost:3000 (/health pour la vérification de santé) et sert les fichiers statiques de client/dist (variable CLIENT_DIST_PATH).

Docker

docker build -f server/Dockerfile -t youtubedownloader .
docker run -p 3000:3000 youtubedownloader

CI/CD

.forgejo/workflows/publish-docker.yml teste (lint + typecheck + tests + build) puis publie l'image sur git.dev.kyuno.fr/kyuno/youtubedownloader (push sur main -> latest + sha court, tag vX.Y.Z -> version). Nécessite un secret REGISTRY_TOKEN sur le dépôt (voir l'en-tête du workflow).

Statut

Squelette d'infrastructure en place (serveur/client minimaux, Docker, CI). Fonctionnalités listées ci-dessus pas encore implémentées. Voir les issues et PR pour le suivi du développement.