feat(server): service de découverte de chaîne (GET /api/channel) #1
Loading…
Reference in a new issue
No description provided.
Delete branch "feature/channel-discovery"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Résumé
Première brique du pipeline décrit pour l'app : lister les vidéos/streams d'une chaîne YouTube, filtrables par mots-clés sur le titre (équivalent généralisé de
streamExtractor.cmd). La file d'attente et le téléchargement suivront dans une PR séparée.Détails
server/src/services/ytDlpRunner.ts: exécution bas niveau de yt-dlp viachild_process.spawn— jamais de shell, arguments toujours en tableau (exclut l'injection de commande).server/src/services/ChannelDiscoveryService.ts: accepte un handle (@nom) ou une URL de chaîne, valide strictement l'entrée (premier caractère forcément alphanumérique) et ajoute un séparateur--avant l'URL passée à yt-dlp, en défense en profondeur contre l'injection d'options. Parseyt-dlp --flat-playlist -j, filtre par mots-clés (ET, insensible à la casse) sur le titre.server/src/routes/channel.ts:GET /api/channel?channel=...§ion=videos|streams&keywords=a,b— validation de schéma Fastify,400si entrée invalide,502si yt-dlp échoue.spec/architecture.mdmis à jour (section API, structure des services).Tests
14 tests (4 fichiers) :
ytDlpRunnertesté via un vrai sous-processus (node -e ..., pas yt-dlp),ChannelDiscoveryServicetesté avecytDlpRunnermocké, route testée viaapp.inject().Un test de route a révélé une regex de validation trop permissive (
--execétait accepté comme handle valide) qu'un test de service, avec un exemple d'entrée moins bien choisi, avait laissée passer — corrigé avant ce commit (voirit.eachdanschannelDiscoveryService.test.ts).Vérifications locales
npm run lint(Biome, racine) : cleannpm run typecheck+npm test+npm run build(server) : clean, 14/14 tests passent/health) lors du PR précédent ; cette PR est backend-only, pas de changement frontend🤖 Generated with Claude Code