Nouveau formulaire "Recherche YouTube" (mots-cles + limite optionnelle), branche sur la zone de resultats existante (miniatures, bouton "Ajouter" par ligne ; pas de "Tout ajouter", comme demande). - Avec une limite : tous les resultats d'un coup (une seule page). - Sans limite : defilement infini. Un element sentinelle en fin de liste, observe par un IntersectionObserver (racine = la liste, marge 300 px), charge la page suivante ; il est rearme apres chaque page, affiche chargement / erreur avec "Reessayer" / "Fin des resultats", et une page en echec ne fait pas perdre les precedentes. Serveur (GET/POST/DELETE /api/search) : une "session" = un seul yt-dlp (--flat-playlist --lazy-playlist -j -- ytsearch1000:<requete>) servi page par page depuis un tampon. Pourquoi pas un appel yt-dlp par page - mesure avec le vrai yt-dlp : l'ordre des resultats de YouTube n'est pas deterministe meme pour deux appels identiques (5/20 aux memes positions, 69 % de recouvrement sur 100), donc paginer en relancant la recherche donnait 15 a 30 % de doublons des la 3e-4e page et des trous ; YouTube s'arrete vers ~590 resultats ; ~7 % de doublons internes (dedoublonnes a l'ingestion) ; sans --lazy-playlist yt-dlp n'imprime rien avant la fin (~23 s), avec il emet au fil des pages (20 en ~2,3 s). Le parcours n'avance qu'a la demande : quand le tampon a 20 resultats d'avance, la lecture de stdout est suspendue (nouvelle option onSpawn de runYtDlp) ; le tube se remplit et yt-dlp bloque (mesure : plus aucune ligne pendant 10 s de pause). On n'aspire donc pas ~590 resultats, et ~30 requetes vers YouTube, quand l'utilisateur ne defile pas. Cycle de vie : 4 sessions simultanees max (la moins recemment utilisee est fermee), expiration a 10 min d'inactivite / 30 min de vie, fermeture des que la derniere page est servie, sur DELETE (liste remplacee cote client), au pagehide du client, et a l'arret du serveur. Requete validee (1 a 200 caracteres, sans caractere de controle) et transmise en un seul argument ytsearchN:<requete>, jamais interpretable comme une option. Mise en page : ce troisieme formulaire laissait a la liste ~104 px (une ligne) a 1366x650. Une liste non vide garde min-height 13rem et la colonne du formulaire defile au lieu de rogner (la page ne defile toujours pas). Verifie : contre le vrai yt-dlp (page tamponnee en 4 ms, page 200 apres 12 s d'inactivite en ~4 s : la suspension tient ; 29 pages -> 576 videos, 576 uniques ; processus fermes a la fin / sur DELETE / au plafond) et dans le navigateur (580 resultats sans doublon jusqu'a "Fin des resultats", requetes de page uniques malgre deux signaux simultanes, echec + reprise, session expiree, remplacement de la recherche, mode limite, ajout d'un resultat a la file, pagehide, playlist et chaine en non-regression). Le volet IntersectionObserver a ete pilote par un observateur factice : le panneau de navigation n'affichait plus de frames (rAF/IO natifs muets). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
62 lines
3.4 KiB
Markdown
62 lines
3.4 KiB
Markdown
# 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](https://github.com/yt-dlp/yt-dlp) et [ffmpeg](https://ffmpeg.org/).
|
|
|
|
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.
|
|
- **Recherche YouTube** : recherche globale par mots-clés, avec une limite de résultats optionnelle ; sans limite, la liste se prolonge en défilant jusqu'à la fin des résultats de YouTube.
|
|
- **Playlists** : coller un lien de playlist (`youtube.com/playlist?list=...`) affiche toutes ses vidéos, à ajouter une par une ou d'un coup (« Tout ajouter à la file »).
|
|
- **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.
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
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.
|