{"id":49742332,"url":"https://github.com/binhex/movarr","last_synced_at":"2026-06-04T21:00:51.007Z","repository":{"id":355456005,"uuid":"1226568456","full_name":"binhex/movarr","owner":"binhex","description":"Automated movie downloader based on IMDb criteria filtering.","archived":false,"fork":false,"pushed_at":"2026-05-26T14:35:11.000Z","size":986,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-26T16:25:58.751Z","etag":null,"topics":["automatic","automation","cli","imdb","jackett","movies","prowlarr","python","qbittorrent","quality"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/binhex.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-01T15:09:07.000Z","updated_at":"2026-05-26T14:54:16.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/binhex/movarr","commit_stats":null,"previous_names":["binhex/movarr"],"tags_count":20,"template":false,"template_full_name":null,"purl":"pkg:github/binhex/movarr","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/binhex%2Fmovarr","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/binhex%2Fmovarr/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/binhex%2Fmovarr/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/binhex%2Fmovarr/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/binhex","download_url":"https://codeload.github.com/binhex/movarr/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/binhex%2Fmovarr/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33917202,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-04T02:00:06.755Z","response_time":64,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["automatic","automation","cli","imdb","jackett","movies","prowlarr","python","qbittorrent","quality"],"created_at":"2026-05-09T20:20:23.879Z","updated_at":"2026-06-04T21:00:50.995Z","avatar_url":"https://github.com/binhex.png","language":"Python","funding_links":["https://www.paypal.com/en_US/i/btn/btn_donate_SM.gif","https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick\u0026hosted_button_id=MM5E27UX6AUU4"],"categories":[],"sub_categories":[],"readme":"# movarr\n\nAutomated movie downloader based on IMDb criteria filtering.\n\n## Features\n\n- **Jackett and Prowlarr integration** — polls any Jackett-configured indexer (or all indexers at once) or a\n  Prowlarr instance for movie torrents across configurable quality tiers (1080p, 2160p, 2160p remux, etc.).\n- **Deep IMDb filtering** — every candidate is resolved to an IMDb ID and evaluated against rating, vote count,\n  year, runtime, language, country, title type, and genre before anything is queued.\n- **Override lists** — bypass the standard filters for specific directors, cast members, writers, movie titles, or\n  characters (e.g. force-accept all James Bond films regardless of rating).\n- **Genre threshold overrides** — relax rating and vote minimums on a per-genre basis (e.g. accept Animation\n  titles at a lower rating floor than live-action).\n- **Library deduplication** — resolves candidate titles to IMDb IDs and checks against all configured library\n  paths before queuing, preventing duplicate downloads.\n- **Database deduplication** — records every evaluated title in SQLite; previously passed, failed, or stalled\n  titles are skipped on subsequent runs.\n- **Configurable TTL expiry** — failed, stalled, and passed records are automatically pruned after configurable\n  retention windows so titles can be re-evaluated over time.\n- **Queue management** — monitors qBittorrent for torrents stuck in stalled or metadata-fetching states and\n  removes them after configurable grace periods.\n- **qBittorrent-aware queue management** — stalled torrent removal is paused when qBittorrent reports\n  it is disconnected from the internet, preventing false positives from transient outages.\n- **Post-processing** — detects completed downloads in qBittorrent, copies qualifying files to your media\n  library, and removes source files if configured.\n- **Genre/certification routing** — routes completed movies to different library paths per viewer profile based\n  on genre and age-rating rules.\n- **Notifications** — sends alerts via any [apprise](https://github.com/caronc/apprise)-compatible service\n  (ntfy, Discord, Telegram, email, and more).\n- **Three independent schedulers** — acquisition, queue management, and post-processing each run on their own\n  configurable interval.\n- **Daemon mode** — runs as a background process with PID file management, or in foreground mode for direct\n  invocation.\n- **Automatic config migration** — upgrades the YAML config schema automatically on startup, backing up the\n  previous version before applying changes.\n\n## Prerequisites\n\n- [Python 3.12+](https://www.python.org/downloads/)\n- [Astral uv](https://github.com/astral-sh/uv#installation) (optional)\n- [Jackett](https://github.com/Jackett/Jackett) or [Prowlarr](https://github.com/Prowlarr/Prowlarr) — torrent indexer proxy\n- [qBittorrent](https://www.qbittorrent.org/) with Web UI enabled\n\n## Quick start\n\n### Installation using uv (recommended)\n\n```bash\ngit clone https://github.com/binhex/movarr\ncd movarr\nuv venv --quiet\nuv sync\n```\n\n### Installation using pip\n\n```bash\ngit clone https://github.com/binhex/movarr\ncd movarr\npython -m venv .venv\nsource .venv/bin/activate\npip install .\n```\n\n### Usage\n\n```bash\nmovarr --help\n```\n\n## Options\n\nAll options are optional overrides. When an option is omitted, the value from `movarr.yml` is used.\n\n### General\n\n| Option | Description | Default |\n| ------ | ----------- | ------- |\n| `--config-path \u003cdir\u003e` | Directory containing `movarr.yml`. | `configs` |\n| `--log-path \u003cdir\u003e` | Override the log directory from config. The file `movarr.log` is created inside. | *(from config)* |\n| `--log-level \u003clevel\u003e` | Override the console log level. Choices: `DEBUG`, `INFO`, `SUCCESS`, `WARNING`, `ERROR`. Useful for temporary debugging without editing the config file. | *(from config)* |\n| `--db-path \u003cdir\u003e` | Override the database directory from config. The file `movarr.db` is created inside. | *(from config)* |\n| `--library-path-list \u003cpath[,path...]\u003e` | Comma-separated list of library root paths, overrides `general.library_path_list` in config. Example: `/media/movies,/media/4k`. | *(from config)* |\n| `--daemon` | Run in background daemon mode. Without this flag movarr runs a single pass and exits. | `false` |\n| `--test` | Validate configuration and exit without running any tasks. | `false` |\n| `--version` | Print the version and exit. | — |\n\n### qBittorrent\n\n| Option | Description | Default |\n| ------ | ----------- | ------- |\n| `--qbt-host \u003chost\u003e` | Override qBittorrent WebUI host from config. | *(from config)* |\n| `--qbt-port \u003cport\u003e` | Override qBittorrent WebUI port from config. | *(from config)* |\n| `--qbt-username \u003cuser\u003e` | Override qBittorrent username from config. | *(from config)* |\n| `--qbt-password \u003cpass\u003e` | Override qBittorrent password from config. | *(from config)* |\n\n### Index Proxy\n\n| Option | Description | Default |\n| ------ | ----------- | ------- |\n| `--index-proxy \u003cproxy\u003e` | Override index proxy selection. Choices: `jackett`, `prowlarr`. | *(from config)* |\n| `--jackett-host \u003chost\u003e` | Override Jackett host from config. | *(from config)* |\n| `--jackett-port \u003cport\u003e` | Override Jackett port from config. | *(from config)* |\n| `--jackett-api-key \u003ckey\u003e` | Override Jackett API key from config. | *(from config)* |\n| `--prowlarr-host \u003chost\u003e` | Override Prowlarr host from config. | *(from config)* |\n| `--prowlarr-port \u003cport\u003e` | Override Prowlarr port from config. | *(from config)* |\n| `--prowlarr-api-key \u003ckey\u003e` | Override Prowlarr API key from config. | *(from config)* |\n\n\u003e **Unraid users:** map container environment variables directly to these flags so a working\n\u003e deployment requires no manual config file editing.\n\n## Configuration\n\nAll behaviour is controlled by a YAML file inside the config directory (`configs/movarr.yml` by default). A default config is created\nautomatically on first run. The file is divided into the sections below.\n\n### `general`\n\n| Key | Description | Default |\n| --- | ----------- | ------- |\n| `config_version` | Schema version — managed automatically; do not edit. | *(current)* |\n| `daemon_mode` | `foreground` or `background`. Overridden by `--daemon` CLI flag. | `foreground` |\n| `log_level_console` | Console logging level (`debug`, `info`, `success`, `warning`, `error`). Overridden by `--log-level`. | `info` |\n| `log_level_file` | File logging level. | `info` |\n| `log_path` | Directory for the log file (`movarr.log` is created inside). Empty string disables file logging. Overridden by `--log-path`. | `\"logs\"` |\n| `library_path_list` | Root paths to scan when checking whether a movie already exists in the library. Overridden by `--library-path-list`. | `[]` |\n| `db_path` | Directory for the SQLite history database (`movarr.db` is created inside). Overridden by `--db-path`. | `\"db\"` |\n| `pid_path` | Directory for the PID file (`movarr.pid` is created inside). Empty string disables PID file creation. Overridden by `--pid-path`. | `\"pids\"` |\n\n### `schedule`\n\nEach of the three background tasks has its own schedule block with the same keys:\n\n| Key | Description | Default |\n| --- | ----------- | ------- |\n| `enabled` | Enable or disable this task. | `true` |\n| `schedule_time_mins` | Interval in minutes between runs. | `30` (acquisition), `5` (queue_management / post_processing) |\n| `run_on_start` | Run this task immediately when movarr starts, before the first interval elapses. | `true` |\n\nTasks: `acquisition`, `queue_management`, `post_processing`.\n\n### `filters`\n\nControls which torrents pass the IMDb quality gate.\n\n| Key | Description | Default |\n| --- | ----------- | ------- |\n| `minimum_year` | Reject movies released before this year. | `1970` |\n| `minimum_runtime_mins` | Reject movies shorter than this many minutes. | `60` |\n| `minimum_rating` | Minimum IMDb rating (0–10). | `7.0` |\n| `minimum_votes` | Minimum IMDb vote count. | `5000` |\n| `override_genre` | Map of genre → `{minimum_rating, minimum_votes}` to relax thresholds for specific genres. | `{}` |\n| `allow_imdb_title_type_list` | Allowed IMDb title types. | `[movie, video, tvmovie]` |\n| `allow_country_list` | Allowed production country codes (ISO 3166-1 alpha-2). Empty = allow all. | `[]` |\n| `allow_language_list` | Allowed spoken language codes (ISO 639-1). Empty = allow all. | `[]` |\n| `reject_index_title_list` | Index titles containing any of these keywords (case-insensitive) are rejected before IMDb lookup. | *(see default config)* |\n| `reject_genre_list` | Reject any movie whose IMDb genres include one of these values. | `[]` |\n| `reject_genre_exclusive_list` | Reject a movie only when ALL of its IMDb genres are in this list (e.g. add `Horror` to reject pure horror, keep horror/sci-fi hybrids). | `[]` |\n| `reject_movie_title_list` | Reject movies whose resolved title exactly matches any entry. | `[]` |\n| `reject_index_group_list` | Reject torrents from these release groups (case-insensitive). | `[]` |\n| `override_cast_list` | Force-accept any movie featuring one of these cast members, bypassing all other filters. | `[]` |\n| `override_writer_list` | Force-accept any movie written by one of these writers. | `[]` |\n| `override_director_list` | Force-accept any movie directed by one of these directors. | `[]` |\n| `override_movie_title_list` | Force-accept any movie whose title contains one of these strings. | `[]` |\n| `override_character_list` | Force-accept any movie featuring one of these characters. | `[]` |\n| `preferred_index_group_list` | Preferred release group names. Matching torrents sort higher. | `[]` |\n\n### `torrent_client`\n\n| Key | Description | Default |\n| --- | ----------- | ------- |\n| `selected` | Torrent client to use. Currently only `qbittorrent` is supported. | `qbittorrent` |\n| `qbittorrent.host` | qBittorrent Web UI hostname or IP address. | `localhost` |\n| `qbittorrent.port` | qBittorrent Web UI port. | `8080` |\n| `qbittorrent.username` | Web UI username. | `admin` |\n| `qbittorrent.password` | Web UI password. | `adminadmin` |\n| `qbittorrent.add_paused` | Add torrents in paused state. | `false` |\n| `qbittorrent.category` | Category tag applied to all movarr-managed torrents. | `movies-movarr` |\n\n### `notification`\n\n| Key | Description | Default |\n| --- | ----------- | ------- |\n| `apprise_urls` | List of [apprise](https://github.com/caronc/apprise) service URLs. Leave empty to disable. | `[]` |\n| `index_proxy_alert_hours` | Send an alert if the index proxy returns no results or is unreachable for this many consecutive hours. Set to `0` to disable. | `0` |\n| `torrent_client_alert_hours` | Send an alert if the torrent client has been unreachable for this many consecutive hours. Set to `0` to disable. | `0` |\n\nApprise supports ntfy, Discord, Telegram, email, Slack, and many other services. Example:\n`ntfy://my-topic`, `discord://webhook-id/webhook-token`.\n\n### `index_proxy`\n\n| Key | Description | Default |\n| --- | ----------- | ------- |\n| `selected` | Index proxy to use: `jackett` or `prowlarr`. | `jackett` |\n| `jackett.host` | Jackett hostname or IP address. | `localhost` |\n| `jackett.port` | Jackett port. | `9117` |\n| `jackett.api_key` | Jackett API key (found in the Jackett dashboard). | `\"\"` |\n| `jackett.read_timeout` | HTTP read timeout in seconds. | `60.0` |\n| `jackett.limit` | Maximum number of results to request per search query. | `500` |\n| `jackett.offset` | Result offset for pagination. | `0` |\n| `jackett.ignore_list` | Jackett indexer names to skip when querying with `jackett_indexer: all`. Case-insensitive. | `[]` |\n| `prowlarr.host` | Prowlarr hostname or IP address. | `localhost` |\n| `prowlarr.port` | Prowlarr port. | `9696` |\n| `prowlarr.api_key` | Prowlarr API key (found in *Settings → General*). | `\"\"` |\n| `prowlarr.read_timeout` | HTTP read timeout in seconds. | `60.0` |\n| `prowlarr.ignore_list` | Prowlarr indexer names to skip when querying with `prowlarr_indexer: all`. Case-insensitive. | `[]` |\n\n### `credentials`\n\n| Key | Description | Default |\n| --- | ----------- | ------- |\n| `tmdb.api_key` | [TMDb](https://www.themoviedb.org/settings/api) API key (IMDb ID resolution fallback). | `\"\"` |\n| `omdb.api_key` | [OMDb](https://www.omdbapi.com/apikey.aspx) API key (IMDb ID resolution fallback). | `\"\"` |\n\n### `index_site`\n\nControls what is searched and which indexers are used.\n\n| Key | Description | Default |\n| --- | ----------- | ------- |\n| `jackett_indexer` | Jackett indexer to query. Use `all` to query every configured indexer simultaneously. | `all` |\n| `prowlarr_indexer` | Prowlarr indexer ID to query. Use `all` (maps to `-1`) or a numeric indexer ID from Prowlarr. | `all` |\n| `search` | List of search criteria blocks (see below). | *(1080p only)* |\n| `override_search` | Per-indexer overrides for search parameters, keyed by indexer name. | `{}` |\n\nEach entry in `search`:\n\n| Key | Description | Default |\n| --- | ----------- | ------- |\n| `criteria` | Search string passed to the index proxy (e.g. `1080p`, `2160p remux`). | — |\n| `category` | Torrent category codes, comma-separated (Torznab format). | `2000,5000` |\n| `minimum_size_mb` | Minimum torrent size in MB. | `3000` (1080p), `7000` (2160p) |\n| `maximum_size_mb` | Maximum torrent size in MB. | `20000` (1080p), `170000` (2160p) |\n| `minimum_bitrate_mb` | Minimum video bitrate in MB/min. Set `0` to disable. | `50` (1080p), `115` (2160p) |\n\n### `queue_management`\n\n| Key | Description | Default |\n| --- | ----------- | ------- |\n| `queue_management_enabled` | Master switch for the queue management pipeline. | `true` |\n| `stalled_monitor_enabled` | Remove torrents that have stalled (no peers, no download progress). | `true` |\n| `metadata_monitor_enabled` | Remove torrents stuck in metadata-fetching state. | `true` |\n| `stalled_delete_torrent_data` | Also delete downloaded data when removing a stalled torrent. | `true` |\n| `metadata_delete_torrent_data` | Also delete downloaded data when removing a metadata-stuck torrent. | `true` |\n| `stalled_delete_torrent_max_mins` | Minutes a torrent must be continuously stalled before it is removed. | `120` |\n| `metadata_delete_torrent_max_mins` | Minutes a torrent must be stuck in metadata-fetching state before removal. | `30` |\n\n### `post_process`\n\n| Key | Description | Default |\n| --- | ----------- | ------- |\n| `post_process_enabled` | Master switch for the post-processing pipeline. | `true` |\n| `copy_completed` | Copy completed files to the media library. | `true` |\n| `remove_completed` | Remove source files after a successful copy. | `true` |\n| `exclude_file_min_kb` | Files smaller than this size (kilobytes) are not copied (skips small extras and samples). | `1500000` |\n| `exclude_file_regex_list` | Regex patterns matched against file names — matching files are skipped. | `[]` |\n| `exclude_folder_regex_list` | Regex patterns matched against folder names — matching folders and their contents are skipped. | `[]` |\n| `copy_library_rules` | Ordered list of routing rules (see below). | `[]` |\n| `default_copy_library.hd_path` | Fallback destination for HD movies when no rule matches. | `\"\"` |\n| `default_copy_library.uhd_path` | Fallback destination for UHD/4K movies when no rule matches. | `\"\"` |\n| `delete_lower_quality` | Auto-delete lower-quality library files when a better version is copied. Defaults to `false`. Permanent deletion — use with care. | `false` |\n\nEach entry in `copy_library_rules`:\n\n| Key | Description |\n| --- | ----------- |\n| `name` | Human-readable label for this rule (e.g. a viewer's name). |\n| `genres` | List of IMDb genres that match this rule. |\n| `max_certification` | Optional age-rating ceiling (e.g. `12A`). Movies rated above this are skipped for this rule. |\n| `hd_path` | Destination directory for 1080p / HD movies. |\n| `uhd_path` | Destination directory for 2160p / UHD movies. |\n\n### `post_process.hooks`\n\n| Key | Description | Default |\n| --- | ----------- | ------- |\n| `pre_copy` | Shell command to run before each copy. Failure aborts the copy. `{dir}` is substituted with the absolute destination directory. `{leaf}` is substituted with the last path component (e.g. movie folder name). | `\"\"` (disabled) |\n| `post_copy` | Shell command to run after each successful copy. `{dir}` is substituted with the absolute destination directory. `{leaf}` substituted likewise. | `\"\"` (disabled) |\n| `pre_delete` | Shell command to run before the deletion pass. Failure aborts deletion. `{dir}` and `{leaf}` substituted. | `\"\"` (disabled) |\n| `post_delete` | Shell command to run after the deletion pass. Failure is non-fatal. `{dir}` and `{leaf}` substituted. | `\"\"` (disabled) |\n\nHooks must not rename or move the target files. Use only in-place operations (e.g. `chattr -i`, `trimarr`).\n\n### `database`\n\n| Key | Description | Default |\n| --- | ----------- | ------- |\n| `stalled_expiry_days` | Delete stalled history records older than this many days, allowing the title to be retried. | `7` |\n| `failed_expiry_days` | Delete failed history records older than this many days, allowing the title to be re-evaluated. | `7` |\n| `passed_expiry_days` | Delete passed history records older than this many days. Allows re-queuing if qBittorrent was reset externally. Set `0` to disable. | `30` |\n\n## How it works\n\nmovarr runs three independent pipelines on configurable schedules.\n\n### Acquisition pipeline\n\n```mermaid\nflowchart TD\n    A([Start]) --\u003e B[Query Jackett/Prowlarr for each search criteria]\n    B --\u003e C[For each result]\n    C --\u003e D{Bad keyword\\nin title?}\n    D -- Yes --\u003e SKIP1([⛔ Skip])\n    D -- No --\u003e E{Size within\\nlimits?}\n    E -- No --\u003e SKIP2([⛔ Skip])\n    E -- Yes --\u003e F{Already\\nin library?}\n    F -- Yes --\u003e SKIP3([⛔ Skip])\n    F -- No --\u003e G{Already in\\ndatabase?}\n    G -- Yes --\u003e SKIP4([⛔ Skip])\n    G -- No --\u003e H[Resolve IMDb ID]\n    H --\u003e I{Title type\\nallowed?}\n    I -- No --\u003e FAIL1([❌ Fail])\n    I -- Yes --\u003e J{Bad genre?}\n    J -- Yes --\u003e FAIL2([❌ Fail])\n    J -- No --\u003e K{Pass rating, votes,\\nyear, runtime,\\nlanguage, country?}\n    K -- No --\u003e FAIL3([❌ Fail])\n    K -- Yes --\u003e L{Override list\\nmatch?}\n    L -- Yes --\u003e PASS([✅ Add to qBittorrent])\n    L -- No --\u003e M{All standard\\nfilters pass?}\n    M -- No --\u003e FAIL4([❌ Fail])\n    M -- Yes --\u003e PASS\n```\n\n### Queue management pipeline\n\nRuns on its own interval and inspects all movarr-managed torrents in qBittorrent:\n\n- **Stalled torrents** — torrents with no peers and no download progress for longer than\n  `stalled_delete_torrent_max_mins` are removed. The history record is updated to `Stalled` and\n  `stalled_expiry_days` controls when the title can be retried.\n- **Metadata-stuck torrents** — torrents that have been fetching metadata for longer than\n  `metadata_delete_torrent_max_mins` are removed.\n- **Connectivity guard** — if qBittorrent reports it is disconnected from the internet, queue management\n  is paused until connectivity returns (so stalled torrents are not incorrectly deleted during an outage).\n\n### Post-processing pipeline\n\nRuns on its own interval and inspects all movarr-managed torrents in qBittorrent:\n\n1. Detects torrents with a completed status.\n2. Scans the download directory, skipping files and folders that match the exclude rules.\n3. Evaluates `copy_library_rules` in order — the first matching rule determines the destination.\n4. Falls back to `default_copy_library` if no rule matches.\n5. Copies qualifying files to the destination; removes source files if `remove_completed` is enabled.\n6. Marks the history record as `Completed`.\n\n## Scheduler\n\nmovarr runs three schedulers concurrently. Each uses a **run-then-sleep** strategy: the interval is measured\nfrom the *start* of the previous run, so drift does not accumulate over time.\n\n| Task | Default interval | Config key |\n| ---- | ---------------- | ---------- |\n| Acquisition | 30 min | `schedule.acquisition` |\n| Queue management | 5 min | `schedule.queue_management` |\n| Post-processing | 5 min | `schedule.post_processing` |\n\nAny task can be disabled independently by setting `enabled: false` in its schedule block.\n\n## Development\n\n```bash\ngit clone https://github.com/binhex/movarr\ncd movarr\nuv venv --quiet\nuv sync --extra dev\n```\n\nIf you wish to perform linting on all files before committing (PR will not be\naccepted if it does not pass all linting) then run `pre-commit run --all-files`.\n\n### Running tests\n\n```bash\nuv run pytest\n```\n\n## FAQ\n\n**Q: movarr queued a movie I already have. Why?**\n\nLibrary matching works by extracting the movie title and year from the torrent's index title and scanning your `library_path_list` for video files whose sanitised filename contains the same title and year. If the filename does not match (e.g. it contains a garbled release-group string), the **parent folder name** is checked as a fallback. Ensure your media files include the release year in their filename (e.g. `The Matrix 1999 1080p BluRay.mkv`) or organise movies into folders whose names contain the full movie title and year. movarr also attempts an IMDb ID lookup as a secondary match when the index title can be resolved.\n\n**Q: How do I prevent movarr from downloading non-English movies?**\n\nSet `filters.allow_language_list` to `[en]`. movarr will reject any title where the primary IMDb language is\nnot English.\n\n**Q: Can I force-accept a specific director's entire filmography?**\n\nYes — add the director's name to `filters.override_director_list`. All filter checks (rating, votes, genre,\nyear, etc.) are bypassed for matching titles. The same pattern applies to `override_cast_list`,\n`override_writer_list`, `override_movie_title_list`, and `override_character_list`.\n\n**Q: What happens if qBittorrent is not reachable?**\n\nThe acquisition pipeline skips the search entirely if qBittorrent is unreachable. The post-processing and queue\nmanagement pipelines also log a warning and skip their cycles when qBittorrent is unavailable.\n\n**Q: How do I disable passed record expiry?**\n\nSet `database.passed_expiry_days: 0`. This prevents movarr from ever re-queuing a title that was previously\nsent to qBittorrent, even if qBittorrent is reset externally.\n\n**Q: I am using no_ransom script to secure my media, is it possible to use the 'pre_delete' hook to unlock existing media before deletion?**\n\nYes - however there are thee additional changes you will need to make to the movarr container for this to work with the no_ransom script:\n\n- Grant chattr additional permissions inside the container\nThis is done by adding in the following to the extra parameters field for the container: `--cap-add LINUX_IMMUTABLE`.\n\n- Pass through the 'diskX' shares to the container, this is required for no_ransom as chattr cannot traverse FUSE shares (/mnt/user/...)\nThis is done by creating an additional path and setting the container path and host path to `/mnt`.\n\n- chattr MUST be run as root, so in order for no_ransom to operate you either need to switch to root account or use sudo.\n\n___\nIf you appreciate my work, then please consider buying me a beer  :D\n\n[![PayPal donation](https://www.paypal.com/en_US/i/btn/btn_donate_SM.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick\u0026hosted_button_id=MM5E27UX6AUU4)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbinhex%2Fmovarr","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbinhex%2Fmovarr","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbinhex%2Fmovarr/lists"}