docs: add English translation of README
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
229
README.md
229
README.md
@@ -223,3 +223,232 @@ docker compose logs -f backend
|
|||||||
## Licence
|
## Licence
|
||||||
|
|
||||||
MIT — voir [LICENSE](LICENSE).
|
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).
|
||||||
|
|||||||
Reference in New Issue
Block a user