Previously only ~17 IDs were extracted from initial HTML per genre page
(before the "voir plus" button). The EMAC API at api.arte.tv exposes all
concerts with full pagination (e.g. 131 Metal, 187 Pop Rock).
Also reuses metadata from EMAC response (title, subtitle, thumbnail,
expiry) — skipping redundant player API calls for genre concerts.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
embedsubtitles:True is a CLI-only option — it registers FFmpegEmbedSubtitlePP
only via __init__.py's opts processing, not when using YoutubeDL() directly.
Must explicitly declare the postprocessor via the 'postprocessors' key.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
postprocessor_args keys must be lowercase — cli_configuration_args does
key.lower() for lookup but the dict is case-sensitive, so "ffmpeg_o" and
"EmbedSubtitle+ffmpeg_o" never matched. Use "merger+ffmpeg_o" for title
during merge, "embedsubtitle+ffmpeg_o" for title+disposition during embed.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace disabled "Déjà téléchargé" with active "Re-télécharger" button
(ghost style to distinguish from first download).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Poll /api/cache-ts every 30s; silently reload concerts if the
cache timestamp increased (background scrape finished).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
If DB has any concerts data (even expired), return it immediately and
refresh in background. Start pre-warming at container startup so the
scrape runs before the first user request.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Store subtitle/year/category in downloads table. On startup, re-queue
any download still in queued/downloading state (reset downloading → queued).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Query Arte Player API before each download to determine available stream
versions. Select lang tag (VOSTFR > VO, FRENCH if audio is fr). Embed
French subtitles as default MKV track when VOSTFR. All output now .mkv.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ALTER TABLE ADD COLUMN appends at the end of existing tables, but CREATE TABLE
defines year before cached_at — positional VALUES mapped year→cached_at (NOT NULL).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- tmdb.py: store release_date year in cache, expose as tmdb_year
- main.py + app.js: use tmdb_year when subtitle has no year
- Dockerfile: add gosu + abc user for PUID/PGID runtime privilege drop
- entrypoint.sh: new entrypoint handling PUID/PGID ownership of /app/data
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
asyncio.Queue dans DownloadManager + worker unique démarré dans le lifespan.
Les téléchargements s'exécutent un par un dans l'ordre d'arrivée.
Suppression de BackgroundTasks (plus nécessaire).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- DB_PATH → data/arte_dl.db (mappé sur /mnt/user/appdata/arte-dl)
- mkdir data/ au démarrage dans downloader.py et arte_api.py
- asyncio.Lock sur get_all_concerts() : une seule scrape à la fois,
les requêtes concurrentes attendent le résultat au lieu de relancer
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Le cache en mémoire (6h TTL) est désormais sauvegardé dans concerts_cache.
Au redémarrage, si le cache SQLite est récent, aucune requête réseau n'est faite.
Le bouton Rafraîchir vide aussi le cache SQLite pour forcer un re-scrape.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Bouton ⬇ sur chaque pill de catégorie pour activer/désactiver l'auto-DL
- Souscriptions sauvegardées en SQLite (table auto_dl_categories)
- Boucle background toutes les AUTO_DL_INTERVAL secondes (défaut 1h)
- Déduplication via already_enqueued() (évite re-queue si déjà queued/done)
- POST /api/auto-dl/check pour déclencher un check immédiat
- GET/POST/DELETE /api/auto-dl/{category} pour gérer les souscriptions
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Format : Title.Event.Year.FRENCH.Resolution.WEBRip.x264|HEVC.AAC-ReMoRa.mp4
- build_release_name() : slugify avec strip accents, apostrophe→point,
déduplique l'année si présente dans le titre ET passée séparément,
détecte la résolution et le codec depuis les infos yt-dlp
- enqueue() : reçoit subtitle + year depuis l'API
- _run() : renomme le fichier après download, met à jour le filename en DB
- DownloadRequest : subtitle + year ajoutés
- app.js : extrait l'année du subtitle via regex avant d'envoyer la requête
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- tmdb.py : recherche TMDB par title+subtitle, matching fuzzy,
cache SQLite 30 jours (table tmdb_cache dans arte_dl.db)
- arte_api.py : enrichissement concurrent (5 workers) après résolution
des IDs ; ajoute tmdb_id, tmdb_poster, tmdb_backdrop au concert
- app.js : backdrop TMDB utilisé comme thumbnail de carte quand dispo ;
subtitle affiché sous le titre de carte ; poster dans la modal ;
lien direct vers la fiche TMDB
- docker-compose.yml : passage de TMDB_API_KEY au container
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- arte_api.py : GENRE_PAGES devient une liste de (nom, url), chaque
concert reçoit un champ "categories" avec ses genres d'appartenance
- main.py : endpoint /api/categories + param ?category= sur /api/concerts
- index.html : barre de pills catégories (Tout + 10 genres)
- style.css : styles .cat-bar / .cat-pill avec pill active en or
- app.js : chargement dynamique des pills, filtre catégorie dans le state
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remplace les pages arte-concert par les pages /fr/p/ qui couvrent
toutes les catégories demandées. Passe de 97 à 208 concerts indexés.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Format yt-dlp corrigé : Arte sert l'audio en mp4 pas m4a, l'ancien
sélecteur échouait immédiatement avec ExtractorError
- Progression basée sur downloaded_bytes/total_bytes_estimate (plus
fiable pour HLS que _percent_str)
- finished_once : empêche le flux audio de remettre la progression à 0%
après que le flux vidéo soit terminé
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Quand la recherche ne trouve rien en local (ex: rock-pop chargé
côté client), interroge l'API search d'Arte, récupère les IDs
manquants et les résout via le player API en parallèle.
Permet de trouver n'importe quel concert présent sur arte-concert.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Abandon de l'approche yt-dlp playlist (URL non supportée).
Scrape les pages genre Arte Concert en RSC pour extraire les
programme IDs, puis fetch les métadonnées (titre, thumbnail,
durée, expiry) via l'API player v2 en parallèle (10 workers).
96 concerts disponibles.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>