Passenger runs a literal JS entry file, not the next start CLI or an npm script, so a custom server was needed for cPanel's Node.js App startup file field.
202 lines
11 KiB
Markdown
202 lines
11 KiB
Markdown
# Ombrora YTDLP
|
|
|
|
Interface web de téléchargement de vidéos via [yt-dlp](https://github.com/yt-dlp/yt-dlp), avec file d'attente persistante, suivi en base de données et liens de téléchargement sécurisés.
|
|
|
|
## Fonctionnement
|
|
|
|
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
|
|
|
|
| Couche | Technologie |
|
|
|--------|-------------|
|
|
| Framework | Next.js 16 (App Router) |
|
|
| Base de données | MariaDB 11 via Prisma 7 |
|
|
| 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 |
|
|
|
|
## Prérequis
|
|
|
|
- Node.js 20+
|
|
- Docker & Docker Compose (pour MariaDB en développement)
|
|
- `yt-dlp`, `ffmpeg` et `ffprobe` (binaires précompilés dans `./bin/` ou dans le `PATH`)
|
|
|
|
## Démarrage rapide
|
|
|
|
```bash
|
|
# 1. Cloner le dépôt
|
|
git clone <url> ombrora-ytdlp && cd ombrora-ytdlp
|
|
|
|
# 2. Copier et remplir les variables d'environnement
|
|
cp .env.example .env
|
|
|
|
# 3. Démarrer MariaDB
|
|
docker-compose up -d
|
|
|
|
# 4. Installer les dépendances
|
|
npm install
|
|
|
|
# 5. Appliquer les migrations Prisma
|
|
npm run db:migrate
|
|
|
|
# 6. Lancer le serveur Next.js
|
|
npm run dev
|
|
|
|
# 7. Dans un autre terminal, lancer le worker
|
|
npm run worker
|
|
```
|
|
|
|
L'interface est accessible sur [http://localhost:3000](http://localhost:3000).
|
|
|
|
## Variables d'environnement
|
|
|
|
| Variable | Requis | Exemple | Description |
|
|
|----------|--------|---------|-------------|
|
|
| `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 |
|
|
| `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
|
|
|
|
| Script | Description |
|
|
|--------|-------------|
|
|
| `npm run dev` | Serveur de développement Next.js |
|
|
| `npm run build` | Build de production |
|
|
| `npm start` | Serveur de production (`server.js`, requis par Passenger sur o2switch — `next start` seul n'est pas utilisable comme fichier de démarrage) |
|
|
| `npm test` | Tests Jest |
|
|
| `npm run worker` | Worker de téléchargement (boucle de polling, exécution directe/dev) |
|
|
| `npm run worker:pm2:start` | Démarre le worker sous pm2 (`ecosystem.config.cjs`), avec auto-restart |
|
|
| `npm run worker:pm2:stop` | Arrête le worker géré par pm2 |
|
|
| `npm run worker:pm2:restart` | Redémarre le worker géré par pm2 |
|
|
| `npm run worker:pm2:status` | Affiche l'état du process `ombrora-worker` |
|
|
| `npm run worker:pm2:logs` | Affiche les logs du worker géré par pm2 |
|
|
| `npm run worker:cleanup` | Expire et supprime les fichiers anciens (usage cron) |
|
|
| `npm run db:migrate` | Crée et applique les migrations Prisma (dev, interactif) |
|
|
| `npm run db:migrate:deploy` | Applique les migrations en attente (production, non interactif) |
|
|
| `npm run db:generate` | Régénère le client Prisma |
|
|
| `npm run deploy` | Déploiement complet sur o2switch (voir section ci-dessous) |
|
|
|
|
## Configuration
|
|
|
|
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 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/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). |
|
|
|
|
## Architecture
|
|
|
|
```
|
|
src/
|
|
├── app/
|
|
│ ├── [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/[uuid]/route.ts # GET — statut
|
|
│ ├── download/[token]/route.ts # GET — téléchargement
|
|
│ └── probe/route.ts # POST — analyse yt-dlp -J
|
|
├── components/
|
|
│ ├── 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 # 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)
|
|
|
|
server.js # Serveur HTTP custom (fichier de démarrage Passenger sur o2switch)
|
|
ecosystem.config.cjs # Config pm2 du process "ombrora-worker"
|
|
|
|
prisma/
|
|
└── schema.prisma # Modèles : Download, DownloadToken
|
|
```
|
|
|
|
## Déploiement (o2switch / Passenger)
|
|
|
|
### Contraintes spécifiques à l'hébergement mutualisé
|
|
|
|
- **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.
|
|
- **Fichier de démarrage (Passenger)** : Passenger exécute directement `node <fichier>` — il ne peut pas lancer une commande CLI (`next start`) ni un script npm. Le dépôt fournit donc `server.js` à la racine (serveur HTTP custom minimal, cf. [doc Next.js](https://nextjs.org/docs/app/guides/custom-server)), qui appelle l'API programmatique de Next.js et écoute sur `process.env.PORT` (port fourni par Passenger).
|
|
|
|
### Étapes de déploiement
|
|
|
|
1. Uploader les sources (hors `node_modules`, `.env`, `storage/`).
|
|
2. Déposer `yt-dlp` et `ffmpeg` dans `BIN_DIR`.
|
|
3. Remplir `.env.prod` avec les valeurs de production (non versionné, à créer/mettre à jour manuellement sur le serveur).
|
|
4. Via cPanel > "Setup Node.js App" : créer l'app Node une première fois pour que Passenger et le nodevenv soient configurés (pointer sur le dépôt). Dans le champ **"Application startup file"**, indiquer `server.js`.
|
|
5. En SSH, dans l'environnement Node fourni par cPanel (celui activé par le lien "Enter to the virtual environment" de cPanel) :
|
|
```bash
|
|
npm run deploy
|
|
```
|
|
Ce script (`scripts/deploy.sh`) enchaîne : copie de `.env.prod` vers `.env`, `npm install`, génération du client Prisma, application des migrations en attente (`prisma migrate deploy`), `npm run build`, puis démarrage/redémarrage du worker sous pm2 (`pm2 startOrRestart` + `pm2 save`, pour persister la liste des process en vue d'un `pm2 resurrect` après reboot).
|
|
6. Redémarrer l'app Next.js via le bouton "Restart" de cPanel > "Setup Node.js App" pour que Passenger recharge le nouveau build (le script ne pilote pas Passenger, qui est géré en dehors du SSH/nodevenv).
|
|
7. Configurer un cron cPanel pour `npm run worker:cleanup` une fois par jour (suppression des fichiers expirés). pm2 gère lui-même le redémarrage du worker en cas de crash ; il n'y a donc plus besoin de cron de supervision dédié.
|
|
8. Si l'hébergeur redémarre le serveur, relancer `pm2 resurrect` (ou `npm run worker:pm2:start` si la sauvegarde `pm2 save` n'a pas été faite) pour reprendre le worker.
|
|
|
|
Pour les déploiements suivants, seule l'étape 5 (`npm run deploy`) et l'étape 6 (redémarrage Passenger) sont nécessaires.
|
|
|
|
## Tests
|
|
|
|
```bash
|
|
npm test
|
|
```
|
|
|
|
Tests Jest (environnement Node, transpilation SWC). Les fichiers de test sont dans `**/__tests__/**/*.test.ts`.
|
|
|
|
## Licence
|
|
|
|
Usage interne — non distribué.
|