Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
MediaTracker
Application Dockerisée de recensement de médiathèque. Scanne vos partages NAS en lecture seule, identifie automatiquement films et séries à partir des noms de fichiers, récupère les jaquettes via l'API publique IMDB, et expose une interface web pour rechercher votre catalogue — y compris en plusieurs langues.
Fonctionnalités
- Scan automatique : scan complet au premier démarrage, puis scan incrémental périodique (configurable)
- Détection films/séries : parse-torrent-name reconnaît la grande majorité des conventions de nommage torrent
- Jaquettes automatiques : récupérées via l'API de suggestion IMDB publique (sans clé API)
- Recherche multilingue : cherchez en français ou en anglais — les titres sont croisés avec IMDB en temps réel
- Multi-NAS : autant de sources que nécessaire, montées en lecture seule
- Affiches locales : si un
poster.jpg/folder.jpgexiste à côté du fichier, il est utilisé en priorité - Interface web : thème sombre, cartes avec jaquette, modal de détail, panneau de scan avec historique
Stack technique
| Composant | Technologie |
|---|---|
| Backend | Python 3.12 · FastAPI · SQLAlchemy |
| Base de données | MariaDB 11 |
| Planificateur | APScheduler |
| Parser | parse-torrent-name (PTN) |
| Métadonnées | IMDB suggestion API (public) |
| Frontend | HTML/CSS/JS vanilla · Nginx |
| Conteneurs | Docker Compose v2 |
Prérequis
- Docker ≥ 24 et Docker Compose ≥ v2
- Python 3.x sur l'hôte (pour
generate-compose.py, stdlib uniquement) - Vos partages NAS montés sur le système hôte (voir ci-dessous)
Monter un partage NAS (SMB/CIFS)
Si votre NAS est accessible en SMB, installez cifs-utils puis montez le partage :
sudo apt install cifs-utils # Debian/Ubuntu
sudo mkdir -p /mnt/nas1
# Montage manuel (test)
sudo mount -t cifs //192.168.1.100/Videotheque /mnt/nas1 \
-o username=VOTRE_USER,password=VOTRE_PASS,uid=$(id -u),gid=$(id -g),iocharset=utf8
# Montage permanent via /etc/fstab
//192.168.1.100/Videotheque /mnt/nas1 cifs credentials=/etc/nas-creds,uid=1000,gid=1000,iocharset=utf8,_netdev 0 0
/etc/nas-creds (permissions 600) :
username=VOTRE_USER
password=VOTRE_PASS
MediaTracker ne monte rien lui-même et n'écrit jamais sur le NAS.
Installation
1. Cloner le dépôt
git clone https://github.com/votre-repo/mediatracker.git
cd mediatracker
2. Configurer l'environnement
cp .env.example .env
Éditez .env et adaptez a minima :
DB_ROOT_PASSWORD=un_mot_de_passe_fort
DB_PASSWORD=un_autre_mot_de_passe
NAS_1=NAS Principal|/mnt/nas1
# NAS_2=Séries|/mnt/nas2
3. Générer le fichier Docker Compose override
python3 generate-compose.py
Ce script lit .env, vérifie que les chemins existent, et génère docker-compose.override.yml avec les volumes en lecture seule. Relancez-le à chaque modification des entrées NAS_*.
4. Lancer l'application
docker compose -f docker-compose.yml -f docker-compose.override.yml up -d --build
L'interface est disponible sur http://localhost:8080 (ou le port défini par APP_PORT).
Au premier démarrage, un scan complet est lancé automatiquement.
Ajouter ou modifier un NAS
- Éditez
.env(ajoutez ou modifiez une entréeNAS_X) - Régénérez l'override :
python3 generate-compose.py - Redémarrez le backend :
docker compose -f docker-compose.yml -f docker-compose.override.yml up -d backend
Conventions de nommage supportées
MediaTracker utilise parse-torrent-name pour analyser les noms de fichiers.
Films
The.Dark.Knight.2008.1080p.BluRay.x264.mkv
Inception (2010) 4K HDR.mkv
Parasite.2019.FRENCH.1080p.WEB-DL.mp4
Dune Part Two (2024).mkv
Séries
Breaking.Bad.S01E01.1080p.mkv
Game.of.Thrones.S08E06.The.Iron.Throne.720p.mkv
/Stranger Things/Season 2/Stranger.Things.S02E04.mkv
/The.Wire/Saison 3/S03E01.mkv
Les dossiers nommés Season X, Saison X ou SXX sont automatiquement détectés comme indicateurs de saison.
Recherche multilingue
La recherche fonctionne en français comme en anglais sans configuration supplémentaire.
Mécanisme : lors d'une recherche, la requête est envoyée à l'API de suggestion IMDB (publique, multilingue). Les identifiants IMDB retournés sont croisés avec la colonne imdb_id de la base locale. Ainsi, chercher « chevalier noir » retrouve un film indexé sous son titre anglais « The Dark Knight » si son imdb_id est présent en base.
Les imdb_id sont peuplés automatiquement lors du scan (phase de récupération des jaquettes).
API Reference
| Méthode | Endpoint | Description |
|---|---|---|
| GET | /api/search?q=…&type=all|movie|series |
Recherche (titre + IMDB cross-ref) |
| POST | /api/scan/full |
Déclenche un scan complet |
| POST | /api/scan/incremental |
Déclenche un scan incrémental |
| GET | /api/scan/status/{id} |
Statut d'un scan |
| GET | /api/scan/history |
20 derniers scans |
| GET | /api/stats |
Compteurs globaux |
| GET | /api/nas |
Liste des NAS et leur statut |
| GET | /api/health |
Healthcheck |
| GET | /api/local-poster?path=… |
Sert une jaquette locale depuis le NAS |
Troubleshooting
NAS inaccessible au démarrage
Le backend démarre même si un NAS est inaccessible. Vérifiez les logs :
docker compose logs backend | grep -i nas
Assurez-vous que le point de montage hôte existe avant de lancer generate-compose.py.
Fichiers non reconnus
Les fichiers que PTN ne parvient pas à analyser sont enregistrés dans la table unmatched_files. Consultez-les directement en base :
SELECT file_path, reason FROM unmatched_files ORDER BY scanned_at DESC LIMIT 50;
Ou via les stats de l'interface (compteur « non reconnus »).
Jaquettes manquantes après le scan
Les jaquettes sont récupérées en parallèle après le scan de fichiers (10 workers). Si le réseau est lent ou IMDB indisponible, relancez un scan incrémental :
curl -X POST http://localhost:8080/api/scan/incremental
Réinitialiser complètement la base de données
docker compose down -v
docker compose -f docker-compose.yml -f docker-compose.override.yml up -d --build
Toutes les données sont supprimées. Un scan complet repart automatiquement.
Voir les logs en temps réel
docker compose logs -f backend
Licence
MIT — voir LICENSE.
MediaTracker — English
Dockerized media library scanner. Scans your NAS shares in read-only mode, automatically identifies movies and TV series from filenames, fetches posters via the public IMDB API, and exposes a web UI to browse your catalogue — including multilingual search.
Features
- Automatic scanning: full scan on first start, then periodic incremental scans (configurable interval)
- Movie/series detection: parse-torrent-name handles the vast majority of torrent naming conventions
- Automatic posters: fetched via the public IMDB suggestion API (no API key required)
- Multilingual search: search in French or English — titles are cross-referenced with IMDB at query time
- Multi-NAS: any number of sources, all mounted read-only
- Local artwork: if a
poster.jpg/folder.jpgexists next to the video file, it is used first - Web interface: dark theme, poster cards, detail modal, scan panel with history
Tech stack
| Component | Technology |
|---|---|
| Backend | Python 3.12 · FastAPI · SQLAlchemy |
| Database | MariaDB 11 |
| Scheduler | APScheduler |
| Parser | parse-torrent-name (PTN) |
| Metadata | IMDB suggestion API (public) |
| Frontend | Vanilla HTML/CSS/JS · Nginx |
| Containers | Docker Compose v2 |
Requirements
- Docker ≥ 24 and Docker Compose ≥ v2
- Python 3.x on the host (for
generate-compose.py, stdlib only) - NAS shares mounted on the host system (see below)
Mounting a NAS share (SMB/CIFS)
If your NAS is accessible via SMB, install cifs-utils and mount the share:
sudo apt install cifs-utils # Debian/Ubuntu
sudo mkdir -p /mnt/nas1
# Manual mount (testing)
sudo mount -t cifs //192.168.1.100/Videos /mnt/nas1 \
-o username=YOUR_USER,password=YOUR_PASS,uid=$(id -u),gid=$(id -g),iocharset=utf8
# Permanent mount via /etc/fstab
//192.168.1.100/Videos /mnt/nas1 cifs credentials=/etc/nas-creds,uid=1000,gid=1000,iocharset=utf8,_netdev 0 0
/etc/nas-creds (permissions 600):
username=YOUR_USER
password=YOUR_PASS
MediaTracker never mounts anything itself and never writes to the NAS.
Installation
1. Clone the repository
git clone https://github.com/your-repo/mediatracker.git
cd mediatracker
2. Configure the environment
cp .env.example .env
Edit .env and set at minimum:
DB_ROOT_PASSWORD=a_strong_password
DB_PASSWORD=another_strong_password
NAS_1=Main NAS|/mnt/nas1
# NAS_2=4K Movies|/mnt/nas2
3. Generate the Docker Compose override
python3 generate-compose.py
This script reads .env, checks that paths exist, and generates docker-compose.override.yml with read-only volumes. Re-run it whenever you change NAS_* entries.
4. Start the application
docker compose -f docker-compose.yml -f docker-compose.override.yml up -d --build
The interface is available at http://localhost:8080 (or the port set by APP_PORT).
On first start, a full scan is triggered automatically.
Adding or changing a NAS
- Edit
.env(add or update aNAS_Xentry) - Regenerate the override:
python3 generate-compose.py - Restart the backend:
docker compose -f docker-compose.yml -f docker-compose.override.yml up -d backend
Supported naming conventions
MediaTracker uses parse-torrent-name to parse filenames.
Movies
The.Dark.Knight.2008.1080p.BluRay.x264.mkv
Inception (2010) 4K HDR.mkv
Parasite.2019.FRENCH.1080p.WEB-DL.mp4
Dune Part Two (2024).mkv
TV series
Breaking.Bad.S01E01.1080p.mkv
Game.of.Thrones.S08E06.The.Iron.Throne.720p.mkv
/Stranger Things/Season 2/Stranger.Things.S02E04.mkv
/The.Wire/Season 3/S03E01.mkv
Directories named Season X, Saison X, or SXX are automatically detected as season indicators.
Multilingual search
Search works in any language without additional configuration.
How it works: when a search query is submitted, it is sent to the IMDB suggestion API (public, multilingual). The returned IMDB IDs are cross-referenced against the imdb_id column in the local database. Searching "chevalier noir" (French for "dark knight") will therefore find a film indexed under its English title "The Dark Knight", provided its imdb_id is stored in the database.
imdb_id values are populated automatically during the scan (poster-fetching phase).
API Reference
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/search?q=…&type=all|movie|series |
Search (title + IMDB cross-ref) |
| POST | /api/scan/full |
Trigger a full scan |
| POST | /api/scan/incremental |
Trigger an incremental scan |
| GET | /api/scan/status/{id} |
Scan status |
| GET | /api/scan/history |
Last 20 scans |
| GET | /api/stats |
Global counters |
| GET | /api/nas |
NAS sources and their status |
| GET | /api/health |
Health check |
| GET | /api/local-poster?path=… |
Serve a local poster from the NAS |
Troubleshooting
NAS not accessible at startup
The backend starts even if a NAS is unreachable. Check the logs:
docker compose logs backend | grep -i nas
Make sure the host mount point exists before running generate-compose.py.
Unrecognized files
Files that PTN cannot parse are stored in the unmatched_files table. Query them directly:
SELECT file_path, reason FROM unmatched_files ORDER BY scanned_at DESC LIMIT 50;
Or check the "unmatched" counter in the UI stats panel.
Posters missing after scan
Posters are fetched in parallel after the file walk (10 workers). If the network is slow or IMDB is unavailable, trigger an incremental scan to retry:
curl -X POST http://localhost:8080/api/scan/incremental
Full database reset
docker compose down -v
docker compose -f docker-compose.yml -f docker-compose.override.yml up -d --build
All data is deleted. A full scan will start automatically.
Stream logs in real time
docker compose logs -f backend
License
MIT — see LICENSE.