- Layout en hauteur pleine (html/body/.shell à 100%/100vh, overflow
hidden sur body) : la page ne défile plus jamais. Seules
download-form__results et queue-panel__list défilent en interne
(flex:1 1 0 + min-height:0 + overflow-y:auto), propagé depuis .shell
via min-height:0 à chaque niveau flex descendant.
- .shell__main : ratio de colonnes 3fr/2fr -> 2fr/1fr et max-width
960px -> 1280px, pour une liste de vidéos plus large.
- Miniatures de résultats agrandies (96x54 -> 144x81, ratio 16:9) et
titre sur 2 lignes (line-clamp) plutôt qu'une troncature sur une seule
ligne, pour mieux différencier les vidéos au premier coup d'œil.
Vérifié en navigateur avec des données de test (16 éléments de file,
12 résultats factices injectés) : bodyScrollHeight reste égal à
windowInnerHeight (page sans overflow) alors que les deux listes ont un
scrollHeight très supérieur à leur clientHeight (défilement interne
réel, pas juste visuel).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- server/Dockerfile : base node:22-bookworm-slim au lieu d'alpine. Le
binaire autonome yt-dlp_linux est lié à la glibc ; sur musl (Alpine),
spawn échouait en prod avec ENOENT bien que le fichier soit présent et
exécutable (interpréteur ELF introuvable). Repéré via un rapport de bug
en conditions réelles. Même choix que mediaDrop pour un souci similaire.
- client/src/styles/base.scss : palette partagée (custom properties CSS),
fond/texte/bordures adoucis, boutons/inputs cohérents, variante
"secondary" pour les actions non-principales (Annuler). Remplace le
rendu par défaut trop contrasté (fond très sombre côté navigateur non
compensé, rouge vif sur les erreurs).
- Placeholders des champs chaîne/mots-clés rendus génériques
(@nomdelachaine, mot-clé1/mot-clé2) au lieu d'un exemple spécifique.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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>
Pose l'infrastructure de base avant l'implémentation des fonctionnalités :
- server/ : Fastify + TypeScript (ESM), route /health, sert client/dist
- client/ : TypeScript vanilla + esbuild/sass, vue placeholder (shell)
- server/Dockerfile : image multi-étapes avec yt-dlp + ffmpeg embarqués
- .forgejo/workflows/publish-docker.yml : test puis publication sur le
registre de conteneurs Forgejo (nécessite le secret REGISTRY_TOKEN)
- biome.json : lint du repo entier (downloader/ exclu)
- spec/architecture.md : documentation de ces choix
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>