diff --git a/README.md b/README.md index 8994262..0dd5c6d 100644 --- a/README.md +++ b/README.md @@ -223,3 +223,232 @@ docker compose logs -f backend ## Licence MIT — voir [LICENSE](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.jpg` exists 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: + +```bash +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 + +```bash +git clone https://github.com/your-repo/mediatracker.git +cd mediatracker +``` + +### 2. Configure the environment + +```bash +cp .env.example .env +``` + +Edit `.env` and set at minimum: + +```env +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 + +```bash +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 + +```bash +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 + +1. Edit `.env` (add or update a `NAS_X` entry) +2. Regenerate the override: `python3 generate-compose.py` +3. Restart the backend: + +```bash +docker compose -f docker-compose.yml -f docker-compose.override.yml up -d backend +``` + +--- + +## Supported naming conventions + +MediaTracker uses [parse-torrent-name](https://github.com/platelminto/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: + +```bash +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: + +```sql +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: + +```bash +curl -X POST http://localhost:8080/api/scan/incremental +``` + +### Full database reset + +```bash +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 + +```bash +docker compose logs -f backend +``` + +--- + +## License + +MIT — see [LICENSE](LICENSE).