# Media Sorter A reliable, high-performance media classification and organization engine engineered with defensive data safety, atomic operations, dry-run simulation, operation journaling, transactional rollback, and review quarantine. Supported media types: - **Movies** (Feature films, scene releases, REMUX, UHD/4K, multi-part) - **TV Shows** (Episodic series, multi-episode files, season packages) - **Anime** (Fansub groups, absolute numbering, season/episode mapping) - **Music** (Multi-disc albums, flac/mp3, ID3v2/Vorbis tags, track/artist tokens) - **Audiobooks** (M4B, chapter tags, narrator metadata, multi-part) - **Podcasts** (Dated releases, show prefixes, episode titles) - **Documentaries** (Documentary flags, broadcast tags) - **Home Videos & Photos** (EXIF datetime, camera models, smartphone naming schemes) - **Sidecars & Companions** (Subtitles `.srt/.ass`, Artwork `poster/cover`, Metadata `.nfo`, Extras `-trailer/-sample`) - **Archives & Unknowns** (Zip, rar, 7z, and unclassified files isolated safely) --- ## Key Safety Guarantees 1. **Zero Silent Data Loss**: Files are never deleted by default. 2. **Dry-Run by Default**: Operations always default to dry-run preview unless explicitly launched with `--live` or configured otherwise. 3. **No Guessing / Quarantine Queue**: If classification confidence falls below the configured threshold (default `0.75`), the file is placed into the Quarantine queue for human inspection. 4. **Collision & Conflict Prevention**: Destination paths are validated beforehand. If a collision is detected, the configurable policy (`rename_unique`, `replace_if_higher_quality`, `quarantine`, `skip`, or `error`) is triggered safely. 5. **Atomic Moves**: Moves on the same filesystem use `os.replace`. Moves across filesystems write to hidden temporary files (`.tmp_media_sorter_*`), verify integrity/size, atomically replace into destination, and only then remove source files. 6. **Transactional Journaling & Instant Rollback**: All operations are recorded in a SQLite WAL database (`OperationStatus.PLANNED` -> `IN_PROGRESS` -> `COMMITTED`). Any batch can be cleanly inverted with `media-sorter rollback --batch-id `. 7. **Active Download / Lock Protection**: Automatically ignores files modified within the minimum file age (default 300s) or locked by downloading torrent/browser clients. --- ## Architecture ``` +-----------------------+ | Source Directories | +-----------+-----------+ | v +-----------------------+ | Scanner (Lock/Age) | +-----------+-----------+ | +------------------------+------------------------+ | | | v v v +--------------------+ +-------------------+ +-------------------+ | Filename Tokenizer | | Media Analyzer | | External Provider | | (Regex / Patterns) | | (Headers/Atoms) | | (TMDB/MusicBrainz)| +----------+---------+ +---------+---------+ +---------+---------+ | | | +------------------------+------------------------+ | v +-----------------------+ | Multi-Signal | | Classifier & Scorer | +-----------+-----------+ | +---------------------+---------------------+ | (Confidence >= 0.75)| | (Confidence < 0.75) v v +-----------------------+ +-----------------------+ | Namer & Path Sanitizer| | Quarantine Manager | +-----------+-----------+ +-----------------------+ | v +-----------------------+ | Executor & Journal | <==== SQLite WAL Database (media_sorter.db) +-----------+-----------+ | +-----------+-----------+ | Organized Destination | +-----------------------+ ``` --- ## Quickstart ### 1. Installation ```bash # Clone repository git clone https://github.com/example/media-sorter.git cd media-sorter # Create virtual environment and install python3 -m venv .venv source .venv/bin/activate pip install -e . ``` ### 2. Configuration (.env) Media Sorter supports simple, editable settings directly in a `.env` file in the project root: ```ini # .env DOWNLOADS_DIR=./downloads # Source folder where downloads arrive MOVIES_DIR=./movies # Destination for Movies SHOWS_DIR=./shows # Destination for TV Series DRY_RUN=false # false = move files live; true = simulation preview ACTION=move # move | copy | link | hardlink CONFIDENCE_THRESHOLD=0.75 # Minimum classification confidence (0.0 - 1.0) MIN_FILE_AGE_SECONDS=0 # Ignore files modified within N seconds SERVER_HOST=0.0.0.0 SERVER_PORT=8085 DATABASE_PATH=media_sorter.db ``` Check your active configuration at any time: ```bash media-sorter config show ``` ### 3. Web Dashboard & Management UI Start the responsive, modern Web Management Dashboard: ```bash media-sorter server ``` **Using the Antigravity Bot in Direct Messages** You can also interact with the Media Sorter assistant bot via direct messages (DMs). Send commands such as `scan`, `organize`, `rollback`, or `config show` directly to the bot, and it will reply with results, status updates, or interactive prompts. This provides a convenient way to manage your media library without opening the web UI. **Bot Owner Configuration** Set the Discord bot owner ID in `config.example.yaml` (or your own config file) under the `owner` field. The value should be the numeric Discord user ID of the bot’s owner. The bot will treat this user as having owner‑only privileges. Open `http://localhost:8085` (or `http://:8085`) in your browser. The web UI includes: - **Dashboard & Activity**: Live metrics, mode badge, 1-click Dry-Run Preview & Live Sort buttons, 1-click Server Restart button, and past batch history. - **Folder Explorer**: Live view of files in `downloads/`, `movies/`, and `shows/` with file sizes and timestamps. - **Quarantine Review**: Visual approval queue for ambiguous media with 1-click "Approve as Movie" or "Approve as Show". - **Settings & .env**: Interactive settings form where you can update directory paths, toggle dry-run mode, and save directly to `.env`. ### 4. Running with PM2 (Production Process Manager) Media Sorter includes an [`ecosystem.config.js`](file:///md0/media-sorter/ecosystem.config.js) file for daemonizing under PM2: ```bash # Start Media Sorter with PM2 pm2 start ecosystem.config.js # View status pm2 status # View live stream logs pm2 logs media-sorter # Restart or reload pm2 restart media-sorter # Enable PM2 to auto-start on machine boot pm2 save pm2 startup ``` The web dashboard's **🔄 Restart Server** button connects natively with PM2: clicking it restarts the process and automatically refreshes the web page once back online. ### 5. Scan & Preview (Dry-Run) Preview classification without touching any files: ```bash media-sorter scan ``` Generate a dry-run batch preview: ```bash media-sorter organize --dry-run ``` ### 5. Execute Live Organization Sort files from `downloads/` into `movies/` or `shows/`: ```bash media-sorter organize --live ``` ### 6. Instant Rollback If you ever need to undo an organization run: ```bash # Revert latest batch media-sorter rollback # Revert specific batch media-sorter rollback --batch-id ``` ### 7. Review Quarantine Queue List and resolve files requiring manual verification via CLI: ```bash media-sorter quarantine list media-sorter quarantine resolve 1 --category movie ``` --- ## CLI Reference | Command | Description | |---|---| | `media-sorter scan` | Discover and analyze source media, displaying classification table | | `media-sorter organize` | Execute organization or dry-run preview (`--dry-run` or `--live`) | | `media-sorter rollback` | Roll back a batch and restore files to source paths | | `media-sorter history` | View audit trail of past batches and metrics | | `media-sorter quarantine list` | List items pending manual human review | | `media-sorter quarantine resolve` | Approve or reclassify a quarantined item | | `media-sorter server` | Start FastAPI REST API and web management dashboard | | `media-sorter config show` | Display active configuration settings in YAML | | `media-sorter config init` | Generate a starter configuration file | --- ## Database & State Tracking The system utilizes SQLite in **Write-Ahead Logging (WAL)** mode with `PRAGMA synchronous=NORMAL` and `PRAGMA foreign_keys=ON`: - `batches`: High-level run records with status (`IN_PROGRESS`, `COMPLETED`, `ROLLED_BACK`), dry-run indicator, counts of moved, skipped, failed, and quarantined files. - `operations`: Fine-grained journal entries tracking `src`, `dst`, `action` (`move`, `copy`, `link`, `hardlink`), `src_hash`, `dst_hash`, `backup_path`, diagnostic details, and timestamps. - `files`: File fingerprint cache (`path`, `size`, `mtime`, `hash`) to avoid redundant metadata probing on unchanged files. - `quarantine`: Audit log for low-confidence or conflicting files holding reason, signals, and resolution states. ### Migrations with Alembic Run database migrations: ```bash alembic upgrade head ``` Create a new migration: ```bash alembic revision --autogenerate -m "Add custom column" ``` --- ## Deployment ### Docker Build and run with Docker Compose: ```bash docker-compose up -d ``` Check health status: ```bash curl -f http://localhost:8080/api/status ``` ### Systemd Service 1. Copy repository to `/opt/media-sorter`. 2. Copy `media-sorter.service` to `/etc/systemd/system/media-sorter.service`. 3. Enable and start: ```bash sudo systemctl daemon-reload sudo systemctl enable --now media-sorter sudo systemctl status media-sorter ``` --- ## Backup & Upgrade Instructions ### Database Backup Because SQLite uses WAL mode, use the standard SQLite online backup or VACUUM INTO command: ```bash # Safe hot-backup of live database sqlite3 media_sorter.db ".backup 'media_sorter.backup.db'" ``` Or backup directory before upgrading: ```bash cp media_sorter.db media_sorter.db.bak ``` ### Upgrading 1. Pull latest release: ```bash git pull origin main ``` 2. Update dependencies: ```bash pip install -e . ``` 3. Run Alembic schema migrations: ```bash alembic upgrade head ``` 4. Restart service: ```bash sudo systemctl restart media-sorter ``` --- ## Testing Run the full test suite (unit tests, integration tests, and Hypothesis property-based fuzz tests): ```bash pytest -v ```