docs: refresh CLAUDE.md and README with current project state, drop dead legacy pages

Both docs still described a frontend/-subfolder Vite/react-router-dom
setup that never existed in this repo's history, and were missing the
yt-dlp probe gating, SEO landing pages, sitemap, and 4-locale i18n
shipped in recent commits. Also removes src/app/page.tsx and
src/app/status/[uuid]/page.tsx, superseded by the [locale]-based
routes and unreachable since the next-intl middleware redirects all
non-API traffic into [locale]/...

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-11 15:02:37 +02:00
co-authored by Claude Sonnet 5
parent d2e491c762
commit 1f51ec7a2b
4 changed files with 63 additions and 61 deletions
+55 -27
View File
@@ -4,12 +4,13 @@ Interface web de téléchargement de vidéos via [yt-dlp](https://github.com/yt-
## Fonctionnement
1. L'utilisateur soumet une URL depuis l'interface web.
2. La demande est enregistrée en base (statut `PENDING`).
3. Le worker (Node.js, arrière-plan, supervisé par pm2) dépile les jobs et exécute `yt-dlp` en parallèle (concurrence configurable).
4. Le fichier téléchargé est stocké localement ; un token signé (24h) est généré.
5. L'utilisateur est redirigé vers une page de statut qui se rafraîchit jusqu'à ce que le fichier soit prêt.
6. Un cron quotidien supprime les fichiers expirés et marque les entrées `FILE_DELETED` — la DB conserve l'historique complet.
1. L'utilisateur colle une URL dans l'interface web. Elle est immédiatement analysée via un probe `yt-dlp -J` (`POST /api/probe`), qui détermine les qualités, sous-titres et durée réellement disponibles pour cette vidéo.
2. Les options de téléchargement (format, qualité, sous-titres, découpe, qualité audio MP3) affichées à l'utilisateur sont dérivées de ce probe — la soumission est bloquée tant qu'il n'a pas réussi.
3. La demande est enregistrée en base (statut `PENDING`).
4. Le worker (Node.js, arrière-plan, supervisé par pm2) dépile les jobs et exécute `yt-dlp` en parallèle (concurrence configurable).
5. Le fichier téléchargé est stocké localement ; un token signé (24h) est généré.
6. L'utilisateur est redirigé vers une page de statut qui se rafraîchit jusqu'à ce que le fichier soit prêt.
7. Un cron quotidien supprime les fichiers expirés et marque les entrées `FILE_DELETED` — la DB conserve l'historique complet.
## Stack technique
@@ -17,7 +18,10 @@ Interface web de téléchargement de vidéos via [yt-dlp](https://github.com/yt-
|--------|-------------|
| Framework | Next.js 16 (App Router) |
| Base de données | MariaDB 11 via Prisma 7 |
| Frontend | React 19, TypeScript |
| Frontend | React 19, TypeScript, Tailwind CSS v4 |
| i18n | next-intl (EN, FR, ES, IT), routing par `[locale]` |
| Thème | next-themes (clair/sombre) |
| Analytics | PostHog (cookieless) |
| Worker | Node.js (tsx), supervisé par pm2 |
| Conteneur (dev) | Docker Compose |
@@ -25,7 +29,7 @@ Interface web de téléchargement de vidéos via [yt-dlp](https://github.com/yt-
- Node.js 20+
- Docker & Docker Compose (pour MariaDB en développement)
- `yt-dlp` et `ffmpeg` (binaires précompilés dans `./bin/` ou dans le `PATH`)
- `yt-dlp`, `ffmpeg` et `ffprobe` (binaires précompilés dans `./bin/` ou dans le `PATH`)
## Démarrage rapide
@@ -60,7 +64,8 @@ L'interface est accessible sur [http://localhost:3000](http://localhost:3000).
|----------|--------|---------|-------------|
| `DATABASE_URL` | oui | `mysql://ombrora:ombrora@localhost:3306/ombrora` | Connexion MariaDB |
| `STORAGE_PATH` | oui | `/var/www/ombrora/storage` | Répertoire de stockage des fichiers téléchargés |
| `BIN_DIR` | non | `./bin` | Répertoire contenant `yt-dlp` et `ffmpeg` (défaut : `./bin`) |
| `NEXT_PUBLIC_BASE_URL` | oui | `https://example.com` | URL publique du site, utilisée pour le SEO (canonical, OpenGraph, JSON-LD, sitemap) |
| `BIN_DIR` | non | `./bin` | Répertoire contenant `yt-dlp`, `ffmpeg` et `ffprobe` (défaut : `./bin`) — absent de `.env.example`, à ajouter manuellement si le défaut ne convient pas |
## Scripts npm
@@ -87,18 +92,22 @@ L'interface est accessible sur [http://localhost:3000](http://localhost:3000).
Les paramètres applicatifs sont centralisés dans `config/app.config.ts` :
```typescript
DOWNLOAD_LINK_TTL_HOURS: 24 // Durée de validité du token de téléchargement
WORKER_CONCURRENCY: 3 // Téléchargements parallèles maximum
WORKER_POLL_INTERVAL_MS: 10000 // Intervalle de polling du worker (ms)
RATE_LIMIT_MAX: 5 // Soumissions max par IP par fenêtre
RATE_LIMIT_WINDOW_MS: 3600000 // Fenêtre de rate-limit (1h)
DOWNLOAD_LINK_TTL_HOURS: 24 // Durée de validité du token de téléchargement
WORKER_CONCURRENCY: 3 // Téléchargements parallèles maximum
WORKER_POLL_INTERVAL_MS: 10000 // Intervalle de polling du worker (ms)
RATE_LIMIT_MAX: 5 // Soumissions max par IP par fenêtre
RATE_LIMIT_WINDOW_MS: 3600000 // Fenêtre de rate-limit des soumissions (1h)
PROBE_RATE_LIMIT_MAX: 20 // Analyses (probe) max par IP par fenêtre
PROBE_RATE_LIMIT_WINDOW_MS: 3600000 // Fenêtre de rate-limit du probe (1h)
PROBE_TIMEOUT_MS: 20000 // Timeout du probe yt-dlp -J (ms)
```
## API
| Méthode | Endpoint | Description |
|---------|----------|-------------|
| `POST` | `/api/downloads` | Soumet une URL. Corps JSON : `{ url, format?, quality?, subtitles?, extraArgs? }`. Retourne `{ uuid }`. |
| `POST` | `/api/probe` | Analyse une URL via `yt-dlp -J`. Corps JSON : `{ url }`. Retourne les qualités, sous-titres et durée réellement disponibles pour la vidéo, ou une erreur (`422` si l'analyse échoue, `429` si rate-limit dépassé). |
| `POST` | `/api/downloads` | Soumet une URL. Corps JSON : `{ url, format, quality, subtitles, subtitleLangs?, clipStart?, clipEnd?, audioQuality?, extraArgs? }`. Retourne `{ uuid }`. |
| `GET` | `/api/downloads/:uuid` | Statut d'un téléchargement. Retourne `{ status, fileName, fileSize, downloadToken?, tokenExpiresAt?, errorMsg? }`. |
| `GET` | `/api/download/:token` | Téléchargement du fichier (token à usage unique, 24h). |
@@ -107,26 +116,45 @@ RATE_LIMIT_WINDOW_MS: 3600000 // Fenêtre de rate-limit (1h)
```
src/
├── app/
│ ├── page.tsx # Page d'accueil (formulaire de soumission)
│ ├── status/[uuid]/page.tsx # Page de suivi
│ ├── [locale]/
│ ├── layout.tsx # Header, thème, next-intl, JSON-LD, PostHog
│ │ ├── page.tsx # Accueil (hero, formulaire, sections SEO)
│ │ ├── [slug]/page.tsx # Pages SEO par plateforme (youtube-downloader, etc.)
│ │ ├── status/[uuid]/page.tsx # Page de suivi
│ │ └── supported-sites/page.tsx # Liste des sites supportés par yt-dlp
│ ├── sitemap.ts # Génération du sitemap.xml
│ └── api/
│ ├── downloads/route.ts # POST — création
│ ├── downloads/route.ts # POST — création
│ ├── downloads/[uuid]/route.ts # GET — statut
── download/[token]/route.ts # GET — téléchargement
── download/[token]/route.ts # GET — téléchargement
│ └── probe/route.ts # POST — analyse yt-dlp -J
├── components/
│ ├── SubmitForm.tsx # Formulaire de soumission
── StatusView.tsx # Vue de suivi (polling)
│ ├── SubmitForm.tsx # Formulaire de soumission (options dérivées du probe)
── StatusView.tsx # Vue de suivi (polling)
│ ├── Header.tsx, LanguageSwitcher.tsx, ThemeToggle.tsx
│ ├── HowItWorksSection.tsx, ReassuranceSection.tsx, SupportedPlatformsSection.tsx
│ └── FaqSection.tsx, FaqAccordion.tsx, SupportedSitesBrowser.tsx
├── i18n/
│ ├── routing.ts # Locales, préfixes d'URL
│ └── request.ts # Config next-intl côté serveur
├── proxy.ts # Middleware next-intl (détection/routage locale)
└── lib/
├── prisma.ts # Client Prisma (singleton)
├── rate-limit.ts # Rate limiting par IP
├── token.ts # Génération/validation de tokens
── ytdlp.ts # Construction des arguments yt-dlp
├── prisma.ts # Client Prisma (singleton)
├── rate-limit.ts # Factory createRateLimiter (downloads + probe)
├── token.ts # Génération/validation de tokens
── ytdlp.ts # Construction des arguments/commande yt-dlp
├── ytdlp-options.ts # Formats/qualités/langues proposés
├── ytdlp-probe.ts # Analyse yt-dlp -J d'une URL
├── downloader-platforms.ts # Données des pages SEO par plateforme
└── supported-sites.ts # Liste des sites supportés par yt-dlp
worker/
├── index.ts # Boucle de polling principale
├── processor.ts # Exécution de yt-dlp, mise à jour DB
└── cron-cleanup.ts # Nettoyage des fichiers expirés
messages/ # Traductions (en.json, fr.json, es.json, it.json)
ecosystem.config.cjs # Config pm2 du process "ombrora-worker"
prisma/
@@ -137,8 +165,8 @@ prisma/
### Contraintes spécifiques à l'hébergement mutualisé
- **Pas de compilation sur le serveur** : `yt-dlp` et `ffmpeg` doivent être des binaires précompilés pour la plateforme cible, placés dans `BIN_DIR`.
- **`node_modules` unique** : Passenger ne crée qu'un seul `node_modules` à la racine. Toute dépendance runtime importée par le frontend doit figurer dans le `dependencies` du `package.json` racine (en plus de `frontend/package.json`).
- **Pas de compilation sur le serveur** : `yt-dlp`, `ffmpeg` et `ffprobe` doivent être des binaires précompilés pour la plateforme cible, placés dans `BIN_DIR`.
- **`node_modules` unique** : Passenger ne crée qu'un seul `node_modules` à la racine. Le projet n'a qu'un seul `package.json` (pas de sous-dossier frontend séparé à synchroniser).
- **Worker** : Passenger ne supervise que l'app Next.js. Le worker est un process à part, maintenu vivant par **pm2** (auto-restart en cas de crash), à la manière de Passenger pour l'app web.
### Étapes de déploiement