bruno df53445efe feat(oauth): import favoris/abos Google (YouTube) et Twitch vers abonnements/likes
- Backend: server/oauth.mjs (auth URL, echange code, refresh, fetch
  subscriptions/likes Google, follows Twitch), table oauth_connections
  + migration, routes /api/oauth/:provider/{url,callback,preview,import},
  /api/oauth/{status,connections}
- Front: /library/import (connect, preview, import), service
  oauth-import, lien depuis Abonnements
- Config: GOOGLE_CLIENT_ID/SECRET/REDIRECT_URI, TWITCH_REDIRECT_URI,
  OAUTH_APP_BASE_URL documentes (.env.example, docker-compose),
  passthrough docker-compose.local.yml, roadmap README cochee
2026-09-26 18:47:02 -04:00
2025-09-14 23:05:30 -04:00
2025-09-14 23:05:30 -04:00
2025-09-14 23:05:30 -04:00

NewTube — Votre hub vidéo multi-plateformes 🎬🌐

Agrégez, explorez et regardez des vidéos depuis

  • YouTube 🔴
  • Dailymotion 🔵
  • Twitch 🟣
  • PeerTube 🟢 (multi-instances)
  • Odysee 🟡
  • Rumble 🟠

✨ Pourquoi NewTube ? (Objectifs clés)

  • 🔎 Recherche unifiée & tendances : un seul champ de recherche, des sections par fournisseur, filtres cohérents.
  • 🧭 Navigation claire : thèmes (Trending, Live, Gaming, News…), onglets Shorts, pages Playlists/History/Liked.
  • 👥 Multi-utilisateur : playlists publiques/privées, préférences, région/qualité par défaut.
  • ⚙️ Prod-ready : API Node/Express, SQLite intégré, rate-limit, logs, tests ciblés.
  • 📦 Ops friendly : image Docker, script maj.sh, variables d’env, astuces daemon.json pour registres HTTP.

🧩 Stack

  • 🅰️ Angular 20 (standalone), RxJS, TailwindCSS
  • 🟩 Node/Express (sert dist/ + API)
  • 🐳 Docker/Compose (déploiement)
  • 💾 SQLite (par défaut) – simple, portable

🎥 Fournisseurs supportés

Plateforme Recherche Lecture Shorts Live Playlists*
YouTube 🔴 ✅ ✅ ✅ ✅ ✅
Dailymotion 🔵 ✅ ✅ ⏳ ✅ ⏳
Twitch 🟣 ✅ ✅ N/A ✅ ⏳
PeerTube 🟢 (multi-instances) ✅ ✅ ⏳ ⏳ ⏳
Odysee 🟡 ✅ ✅ ⏳ ⏳ ⏳
Rumble 🟠 ✅ ✅ ⏳ ⏳ ⏳

* Playlists = intégration locale NewTube (création/gestion); la synchro native dépend de l’API publique de chaque fournisseur.


🔎 Recherche unifiée (multi-providers)

Un seul champ, tous les fournisseurs — avec filtres, raccourcis et deep-links :

  • Chips providers dans la barre : All / YT / DM / TW / PT / OD / RU (raccourcis Alt+1..6)
  • Autocomplete @ : tapez @yt dans le champ pour filtrer sur YouTube (flèches + Enter, Esc pour fermer)
  • Provider picker : bouton @ ou Ctrl/⌘+K — modal avec filtre texte, sélection multiple et option « Remember as default » (persistée dans vos préférences utilisateur)
  • Quick menu Ctrl/⌘+K : historique des recherches + toggles providers en un écran
  • Deep-links : /#/search?q=…&providers=yt,ru relance la recherche filtrée — partageable
  • Fallback préférence : URL sans providers → préférence defaultProviders de l’utilisateur → provider actif
  • Accessibilité : focus trap dans les modals, Esc pour fermer, aria-combobox sur le champ, focus restauré à la fermeture
  • Typeahead requête : sous l’input, suggestions de requêtes (recherches récentes 🕘 + groupes par provider YT/DM/…, sous-chaîne surlignée) — GET /api/search/suggest?q=…&providers=…&limit=… (min 2 caractères, debounce 250 ms, cache 5 min, dégradation [] par provider) ; ↑/↓/Enter/Tab/Esc, priorité au popover @

Endpoints API concernés

  • GET /api/search?q=…&providers=yt,dm — fan-out parallèle, réponse groupée par provider (page/pageSize/sort ; YT sans quota via InnerTube + continuations)
  • GET /api/search/suggest?q=…&providers=yt,dm&limit=10 — typeahead { q, groups: { yt: string[], … } } (cache 5 min, rate-limit)
  • GET /api/details/youtube/:videoId — métadonnées + related[] (watch-next InnerTube, ?related=0 pour désactiver)
  • GET /api/trending?provider=yt&limit=… — tendances YT sans clé
  • GET /healthz (alias /api/healthz) — mode YT, binaire yt-dlp binOk, cache, métriques quota/jour, clés
  • GET /api/transcript/:provider/:videoId?lang=&instance=&slug=&sourceUrl= — transcript { lang, available, languages, lines: [{ t, dur, text }] } (cache 24 h, rate-limit 10/min ; absent → 200 { available: false }, échec → 502 ; YouTube : découverte des pistes via InnerTube, YT_TRANSCRIPT_SOURCE)
  • GET/PATCH /api/user/preferences — defaultProviders (tableau JSON, sanitizé serveur)
  • POST /api/telemetry/events — événements UX anonymes (whitelist : search_submit, provider_picker_open, provider_apply, at_autocomplete_use, quick_menu_open, suggest_shown, suggest_used)

Tests

npm run test:search        # unitaires SearchService + parsing @ + picker
npm run test:search-e2e    # scénarios e2e (serveur réel isolé)
npm run test:suggest        # typeahead : parsing/dédup + contrat /api/search/suggest
npm run test:transcript     # transcripts : parseurs json3/vtt + contrat /api/transcript
npm run test:preferences   # persistance defaultProviders
npm run test:telemetry     # télémétrie minimale

🖥️ Fonctionnalités (vue d’ensemble)

  • 🧭 Accueil “Tendances & Viral” par fournisseurs
  • 🧩 Thèmes : Trending, Live, Gaming, Sports, News, Finance, Tech, Science, Health, Music, Podcasts, Movies/TV, Education, Travel, Food, DIY, Auto…
  • 🎯 Shorts : affichage dédié (séparé des vidéos longues)
  • ❤️ Liked videos avec recherche serveur
  • 🕘 History (recherches + visionnage)
  • 📚 Playlists publiques/privées (CRUD, compteurs, dates MAJ)
  • 🔐 Auth légère (JWT), rate-limit API
  • ⚙️ Préférences : langue, thème (système / dark / light / blue / black), région, qualité par défaut
  • 🧩 PeerTube multi-instances : activer/désactiver, choisir l’instance active

🗂️ Structure du repo

  • docker-compose/

    • docker-compose.yml — service newtube (image, ports, env, volumes, restart)
    • .env.example — modèle d’environnement
    • maj.sh — pull image + restart stack
    • init.sh — init des dossiers/volumes & .env
  • docker/

    • Dockerfile — build Node/Express (sert dist/ + API)
    • scripts/env-dump.sh — génère assets/config.js depuis l’env (option NGINX)
    • config/nginx.conf — exemple (si variante NGINX)
  • server/

    • index.mjs — routes API, statiques dist/, downloads
    • db.mjs — SQLite + migrations légères
    • tests/playlist_visibility.test.mjs — tests playlists
  • db/ — schema.sql + migrations/

  • assets/ — config.local.example.js

  • src/, app/, public/ — front Angular

  • package.json — scripts (dev, build, api, api:watch, test:playlists)


🧱 Prérequis

  • 🐧 Linux (recommandé) / macOS / Windows (WSL2 ok)
  • 🐳 Docker Engine ≥ 24, Compose v2
  • 🟩 Node.js ≥ 20 (dev local)
  • 🔐 Accès au registre d’images (ex. docker-registry.dev.home:5000)

🚀 Installation

Option A — Docker (recommandé)

cp docker-compose/.env.example docker-compose/.env
# Éditez docker-compose/.env (hostnames, clés API, secrets…)
cd docker-compose
docker compose up -d

Application : http://localhost:8080 (mappage 8080:4000)

Option B — Dev local

npm install
cp assets/config.local.example.js assets/config.local.js   # (optionnel)
npm run dev                  # front + api dev proxy
# API seule :
npm run api
npm run api:watch
# Build prod :
npm run build

🔁 Déploiement & mises à jour (maj.sh)

chmod +x docker-compose/maj.sh
./docker-compose/maj.sh

Ce script fait :

  1. docker image pull <registre>/newtube-angular:latest
  2. docker compose down
  3. docker compose up -d

Vérifications : docker compose ps, docker logs newtube --tail=200, curl -I http://localhost:8080


🧰 Astuce Ops — Docker /etc/docker/daemon.json (registres HTTP/insecure)

À configurer sur la machine qui exécute docker compose / maj.sh.

sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json >/dev/null <<'JSON'
{
  "insecure-registries": ["docker-registry.dev.home:5000"],
  "registry-mirrors": [],
  "debug": false
}
JSON
# debian linux
sudo systemctl daemon-reload
sudo systemctl restart docker
# Alpine linux
sudo rc-service docker restart
sudo rc-update add docker

docker info | grep -i registry

Ajoutez au besoin log-driver, log-opts, default-address-pools, etc.


🔐 Variables d’environnement (exemples)

Service / compose

  • NGINX_HOSTNAME, DIR_NEWTUBE, TZ

App / serveur

  • PORT (4000), NODE_ENV, JWT_SECRET
  • ACCESS_TTL_MIN, REFRESH_TTL_DAYS, REMEMBER_TTL_DAYS
  • YT_CACHE_TTL_MS
  • Clés API : GEMINI_API_KEY, YOUTUBE_API_KEY ou YOUTUBE_API_KEYS (CSV), VIMEO_ACCESS_TOKEN, TWITCH_CLIENT_ID, TWITCH_CLIENT_SECRET
  • NEWTUBE_DB_FILE (chemin SQLite alternatif)

Voir docker-compose/.env.example pour un point de départ.


🩺 Troubleshooting (rapide)

  • 🧾 Certif/registre : x509… unknown authority → configurez daemon.json (ci-dessus) puis systemctl restart docker
  • 🔌 Port 8080 occupé : changez le mappage dans docker-compose.yml
  • 🗄️ Permissions volumes : vérifiez que DIR_NEWTUBE existe et est accessible par Docker
  • 🧩 Variables manquantes : complétez .env (clés API, JWT_SECRET, etc.)
  • 🌐 CORS en dev : utilisez le proxy.conf.json et npm run dev

🗺️ Roadmap

  • ✅ Dist statique + API Node/Express
  • ✅ Playlists publiques/privées (tests de visibilité)
  • ✅ Barre de recherche Liked videos (filtrage serveur)
  • ✅ PeerTube multi-instances (activer/désactiver, set active)
  • ✅ Thème (système / dark / light / blue / black)
  • ✅ Préférences (langue, thème, région, qualité par défaut)
  • ✅ Auth légère (JWT), rate-limit API
  • ✅ Recherche unifiée multi-providers — chips + autocomplete @, picker Ctrl/⌘+K, deep-links ?providers=…, préférence defaultProviders persistée, télémétrie minimale, a11y (focus trap, Esc)
  • ✅ Recherche unifiée multi-providers — chips + autocomplete @, picker Ctrl/⌘+K, deep-links ?providers=…, préférence defaultProviders persistée, télémétrie minimale, a11y (focus trap, Esc)
  • ✅ Navigation par thèmes (Trending, Live, Gaming, News, Finance, Tech, Science, Health, Music, Podcasts, Movies/TV, Education, Travel, Food, DIY, Auto…)
  • ⏳ Abonnements (routes + DB)
  • ⏳ Tags & recherche par tags
  • ⏳ Page “Shorts” unifiée (tous fournisseurs) + badges de durée
  • ✅ Téléchargements intégrés — file d'attente persistée en SQLite (survit aux redémarrages API), jobs par utilisateur (répertoires isolés, ownership sur status/fichier/cancel), quota de stockage configurable (DOWNLOAD_STORAGE_QUOTA_BYTES, fenêtre DOWNLOAD_QUOTA_WINDOW_MS), reprise des jobs échoués/interrrompus (bouton Réessayer), page Bibliothèque > Téléchargements (filtres par état, progression live, quota), nettoyage auto des fichiers orphelins au boot
  • 🔧 Variables : DOWNLOAD_MAX_CONCURRENT (2), DOWNLOAD_STORAGE_QUOTA_BYTES (5 GiB), DOWNLOAD_QUOTA_WINDOW_MS (30 j), DOWNLOAD_PROVIDERS (peertube,odysee)
  • ⏳ Import/Export playlists (JSON / OPML-like)
  • ✅ Sous-titres & transcripts — GET /api/transcript/:provider/:videoId (yt-dlp subtitles/automatic_captions, parsing json3/vtt, cache 24 h, rate-limit), panneau Transcript sur la page Watch (sélecteur de langue, dégradation propre si indisponible)
  • ✅ YouTube sans quota (InnerTube façon SmartTube) — youtubei.js pinné, chaîne innertube → scrape yt-dlp → API officielle (YT_SEARCH_MODE, défaut innertube-first), pagination illimitée via continuations (scroll infini, page=2,3…), vidéos connexes watch-next dans GET /api/details/youtube/:videoId → sidebar Watch, GET /api/trending?provider=yt, cache mémoire + SQLite, anti-ban (YT_COOKIES_FILE, YT_PO_TOKEN, YT_EGRESS_PROXY), observabilité /healthz (mode, binaire binOk, cache, quota jour, clés)
  • ⏳ PWA (installable, offline cache des métadonnées)
  • ⏳ Chromecast / AirPlay
  • ⏳ Mode “TV”
  • ⏳ Observabilité : healthcheck /healthz, métriques, page Admin (clés OK/KO, logs, versions)
  • ✅ OAuth (Google/Twitch) pour import favoris/abonnements — /library/import : abonnements + likes YouTube (lecture seule), follows Twitch → abonnements, preview + import, GET /api/oauth/status|connections|preview, POST /api/oauth/:provider/import
  • ⏳ Cache serveur configurable (TTL par provider)
  • ⏳ Qualité vidéo : sélecteur et “auto” intelligent
  • ⏳ Traduction UI (i18n) élargie
  • ⏳ Theming avancé (polices, densité, accents)

🔒 Notes de sécurité

  • ❌ Ne jamais versionner de secrets réels
  • 🔑 Utiliser .env hors VCS + restrictions par referer côté fournisseurs
  • 🚧 Limiter l’exposition publique de l’API, activer rate-limit (déjà en place)
  • 🧪 Ajouter des tests e2e/units pour les zones critiques (auth, playlists, downloads)

🤝 Contribuer

Issues & PR bienvenues ! Proposez des connecteurs, des règles de parsing plus robustes ou des idées d’UX. Astuce : ouvrez une PR “Draft” tôt pour discussion/feedback.


📜 Licence

MIT (voir LICENSE)


💡 Tip produit : gardez l’UX simple — Thèmes fixes sous le header, Shorts séparés, CTA clairs (“View All”, “Add to playlist”), et utilisez les états vides (empty states) sur History/Liked/Playlists pour guider l’utilisateur.


🧩 Ajouter un provider en 5 minutes

  1. Front — Registry
  • Éditez src/app/core/providers/provider-registry.ts et ajoutez une entrée ProviderSpec avec:
    • id (ex. "yt"), displayName, shortLabel, icon, colorClass
    • supports (search/shorts/live/playlists)
    • buildSearchUrl(q) (facultatif côté front)
  1. Back — Handler
  • Créez un fichier server/providers/<provider>.mjs qui exporte default avec:
    • id, label
    • async search(q, { limit, page }) → Promise<Suggestion[]>
  • Enregistrez-le dans server/providers/registry.mjs pour être éligible au fan‑out /api/search.
  1. API — Recherche multi‑providers
  • L’endpoint GET /api/search?q=...&providers=yt,dm,ru&limit=... valide les providers et déclenche les recherches en parallèle (timeouts), puis retourne:
{
  "q": "documentary",
  "providers": ["yt","dm","ru"],
  "groups": {
    "yt": [{ "title": "...", "id": "...", "duration": 192, "isShort": false }],
    "dm": [],
    "ru": [{ "title": "...", "id": "...", "isShort": true }]
  }
}
  1. UI — Sélecteur & Chips
  • Le SearchBoxComponent (standalone) rend les chips All / YT / DM / TW / PT / OD / RU + menu rapide @ (ProviderPicker).
  • Le composant émet (submitted) avec { q, providers } et met à jour SearchService (RxJS state) pour l’appel API.
  1. Deep‑link
  • Les URLs du type ?q=…&providers=yt,ru relancent la même recherche. Assurez-vous de propager le paramètre providers lors des navigations.
  1. Tests
  • Unit (npm run test:search) : parsing @yt dans l’input, toggles ProviderPicker, composition et fan-out de SearchService.
  • e2e (npm run test:search-e2e) : providers=yt,dm → réponse ciblée sur [yt,dm]; deep-link providers=pt; fallback registry complet; préférence persistée; route SPA.

Astuce: l’ajout d’un provider ne nécessite pas de modifier les composants — il suffit d’ajouter une entrée dans le registry front + un handler API.

S
Description
Site Web permettant de centraliser les accès à plusieurs platformes de streaming.
Readme
10 MiB
Languages
TypeScript 44.6%
JavaScript 37.9%
HTML 14.7%
CSS 1.7%
Shell 0.7%
Other 0.2%