{"id":48600710,"url":"https://github.com/adocampo/clutch","last_synced_at":"2026-05-13T19:01:00.407Z","repository":{"id":264720926,"uuid":"894202328","full_name":"adocampo/clutch","owner":"adocampo","description":"Convert videos in batch with a CLI tool, or via web UI, or even automatically with a watchdog daemon using HandBrake CLI. Ready to drift!!","archived":false,"fork":false,"pushed_at":"2026-05-05T23:16:56.000Z","size":2548,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-05-06T01:23:46.393Z","etag":null,"topics":["encoding","handbrakecli","video-encoding","video-processing"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/adocampo.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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":"2024-11-25T23:55:10.000Z","updated_at":"2026-05-05T23:17:00.000Z","dependencies_parsed_at":"2025-01-09T14:26:17.537Z","dependency_job_id":"47fd8906-c113-47d3-8dad-2ecebf2593f9","html_url":"https://github.com/adocampo/clutch","commit_stats":null,"previous_names":["adocampo/convert-video","adocampo/clutch"],"tags_count":68,"template":false,"template_full_name":null,"purl":"pkg:github/adocampo/clutch","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adocampo%2Fclutch","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adocampo%2Fclutch/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adocampo%2Fclutch/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adocampo%2Fclutch/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/adocampo","download_url":"https://codeload.github.com/adocampo/clutch/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adocampo%2Fclutch/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32995915,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-13T13:14:54.681Z","status":"ssl_error","status_checked_at":"2026-05-13T13:14:51.610Z","response_time":115,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["encoding","handbrakecli","video-encoding","video-processing"],"created_at":"2026-04-08T22:00:46.972Z","updated_at":"2026-05-13T19:01:00.397Z","avatar_url":"https://github.com/adocampo.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n\u003cimg src=\"https://github.com/adocampo/clutch/blob/master/docs/images/clutch.png?raw=true\" alt=\"Sublime's custom image\"/\n\u003c/p\u003e\n\nClutch manages video transcodes through HandBrakeCLI from the command line or from a browser dashboard. `clutch` handles single files, recursive libraries, watched folders, and a shared LAN service with a persistent queue.\n\n![clutch service dashboard](docs/images/service-dashboard.png)\n\n## Features at a glance\n\n- Convert single files, whole folders, recursive trees, file globs, and ISO images.\n- Encode with `nvenc_h265`, `nvenc_h264`, `x265`, or `av1`.\n- Preserve audio and subtitle tracks, with optional audio passthrough.\n- Run several local workers in parallel for faster batch processing.\n- Rotate NVENC jobs across selected NVIDIA GPUs with `--gpus 0,1`.\n- Skip wasteful re-encodes using codec-aware and muxer-aware detection.\n- Check for updates and upgrade in place with the built-in `--update` and `--upgrade` commands, plus daily release reminders in the CLI.\n- Expose an HTTP service with a built-in dashboard to inspect the queue and submit jobs remotely.\n- Upload local files directly to a remote clutch server with `--remote-server` from CLI or browser.\n- Stream-convert files in one step with `--stream` (upload + remote convert + immediate download).\n- Download completed remote jobs with `--download`.\n- Pause and resume running conversions from the dashboard or the HTTP API.\n- Survive service restarts: active conversions are detached on shutdown and automatically reattached on the next start when the encoder process is still alive.\n- Show a dashboard release icon with a badge when the service detects a newer version, including one-click upgrade and restart.\n- Persist service configuration, worker count, GPU list, and watched folders in SQLite.\n- Watch folders and auto-enqueue new videos once they stop changing on disk.\n- Include a `change-title` helper to sync MKV title metadata with the file name.\n- **Native Windows support**: runs on Windows 10/11 with a dedicated PowerShell installer, automatic drive enumeration, mapped network drive detection, and system monitor using native Win32 APIs.\n\n## Requirements\n\nYou only need [HandBrakeCLI](https://handbrake.fr/downloads2.php) to run the main converter.\n\nFor the full feature set, install these tools as well:\n\n- `mediainfo`\n- `mkvpropedit`\n- `pv` (optional, Linux/macOS only — used by the shell helpers)\n\n\u003e **Windows note:** The PowerShell installer automatically installs all required runtime dependencies (HandBrakeCLI, mediainfo, MKVToolNix) via your package manager (winget, Chocolatey, or Scoop) and adds them to your user PATH.\n\n## Installation\n\n### Linux / macOS\n\n#### One-liner install (no manual clone needed)\n\nThe GitHub repository now lives at `adocampo/clutch`, and the installer and self-update commands below use the renamed repo.\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/adocampo/clutch/master/install.sh | bash\n```\n\nThe installer detects your OS and package manager, ensures Python 3.9+, venv, and pipx are available, clones the repo to a temporary directory when needed, installs `clutch` via pipx, checks runtime dependencies, and places the systemd user unit on Linux.\n\n#### Install from a local clone\n\n```bash\ngit clone https://github.com/adocampo/clutch.git clutch\ncd clutch\nbash install.sh\n```\n\n#### Direct install with pipx from GitHub\n\n```bash\npipx install git+https://github.com/adocampo/clutch.git\n```\n\n### Windows\n\n#### One-liner install (PowerShell)\n\nOpen a PowerShell terminal (no admin required) and run:\n\n```powershell\nSet-ExecutionPolicy Bypass -Scope Process -Force\nirm https://raw.githubusercontent.com/adocampo/clutch/master/install.ps1 | iex\n```\n\nThe installer will:\n\n1. Detect your package manager (winget, Chocolatey, or Scoop).\n2. Install Python 3.12+ if not found (skipping Microsoft Store stubs).\n3. Install pipx via pip.\n4. Clone the repo to a temporary directory and install `clutch` via pipx.\n5. Install runtime dependencies (HandBrakeCLI, mediainfo, MKVToolNix) and add them to your user PATH.\n6. Offer to register `clutch` as a Windows scheduled task that starts the service at system startup (before any user logs in).\n\nThe scheduled task step asks for your Windows password so the Task Scheduler can run the service without requiring an interactive logon session. A UAC elevation prompt will appear briefly to register the task with administrator privileges. The password is stored only by the Windows Task Scheduler; the installer does not keep it.\n\n#### Install from a local clone\n\n```powershell\ngit clone https://github.com/adocampo/clutch.git clutch\ncd clutch\n.\\install.ps1\n```\n\n#### Direct install with pipx from GitHub\n\n```powershell\npipx install git+https://github.com/adocampo/clutch.git\n```\n\n\u003e **Tip:** If HandBrakeCLI, mediainfo, or mkvpropedit are not in your PATH after a manual install, you can configure their locations from the clutch web dashboard under **Settings → Binary Paths**.\n\n### Docker\n\nClutch is available as two Docker images:\n\n| Image | Size | Best for |\n|-------|------|----------|\n| `ghcr.io/adocampo/clutch` | ~1.5 GB | Full Arch image — shell access, in-place upgrades |\n| `ghcr.io/adocampo/clutch-minimal` | ~280 MB | Scratch image — minimal footprint, no shell |\n\nPull and run:\n\n```bash\ndocker run -d \\\n  --name clutch \\\n  -p 8765:8765 \\\n  -v clutch-config:/config \\\n  -v /path/to/media:/media \\\n  ghcr.io/adocampo/clutch:latest\n```\n\nOr use the provided `docker-compose.yml` (edit to pick full or minimal):\n\n```bash\ndocker compose up -d\n```\n\nTo build locally from source:\n\n```bash\n# Full image\ndocker build -t clutch .\n\n# Minimal image\ndocker build -f Dockerfile.minimal -t clutch-minimal .\n```\n\nFor NVIDIA GPU passthrough, environment variables, watch directories, and scheduling options, see the [Docker wiki page](docs/wiki/Docker.md).\n\n### Verify installation\n\n```bash\nclutch --version\n```\n\n## Why this exists\n\nUsually, when you download movies and TV shows, you end up with plenty of formats and codecs. Older codecs such as AVC waste a lot of disk space compared to newer ones such as AV1, but not every player can handle AV1 smoothly yet.\n\nI have plenty of space in my home server, but I realized I could save a huge part of it just by re-encoding my video library.\n\nAt first, I used ffmpeg. Converting AVC (H.264) to HEVC (H.265) saved a lot of space, but I wanted better results.\n\nThen I tried AV1. Compression was excellent, but with an NVIDIA RTX 3070 I still had to encode AV1 on the CPU instead of the GPU, which is far too slow when you have hundreds of videos.\n\nSo I started automating the workflow. After comparing outputs, HandBrake consistently produced much better compression for my media than the presets I had tuned manually in ffmpeg.\n\n### The good\n\nWith the right HandBrake presets, I was able to shrink some 60 GB H.264 BDRips to around 2 GB in AV1 while keeping very good quality.\n\n### The bad\n\nIf you do not have NVIDIA 40-series hardware, AV1 encoding on the GPU is not available, so large AV1 jobs can still take a long time.\n\n### The ugly\n\nHandBrake H.265 was good enough that it often got close to AV1 compression while still letting me use NVENC, which means a one-hour video can finish in just a few minutes on the GPU. That is the workflow this project is built around.\n\n## Development setup\n\nIf you want to contribute or test the latest development version:\n\n```bash\ngit clone https://github.com/adocampo/clutch.git clutch\ncd clutch\npython3 -m venv .venv\nsource .venv/bin/activate\npip install -e .\n```\n\nInside the virtual environment, use the regular `clutch` command:\n\n```bash\nclutch --version\nclutch -r ~/Videos/\n```\n\nIf your system also has `clutch` installed through `pipx`, activate `.venv` before running it so the virtual environment version takes priority in `PATH`.\n\n## Updating\n\n### Self-update from the tool itself\n\nOn the first normal CLI run of each day, `clutch` also performs a lightweight cached release check and prints a reminder when a newer version is available.\n\n```bash\n# Check if a new version is available\nclutch --update\n\n# Upgrade to the latest version\nclutch --upgrade\n```\n\n### Manual update with pipx\n\n```bash\npipx install git+https://github.com/adocampo/clutch.git --force\n```\n\n## Uninstalling\n\n```bash\npipx uninstall clutch\n```\n\n## Smart codec detection\n\n`clutch` automatically detects the current video codec and muxer before converting, avoiding unnecessary re-encodes:\n\n### Codec quality hierarchy\n\nThe script understands that some codecs produce better compression than others:\n\n```text\nAVC (H.264) \u003c HEVC (H.265) \u003c AV1\n```\n\n- If the source is in a **worse** codec than the target (e.g. AVC → HEVC), it **converts** normally.\n- If the source is already in a **better** codec than the target (e.g. AV1 → HEVC), it **skips** the file and warns you.\n- If the source is in the **same** codec as the target, it checks the muxer (see below).\n\n### Why HandBrake gets special treatment\n\nI have experimented extensively with ffmpeg, mkvmerge, and HandBrake for video encoding. While all three can produce valid H.265/AV1 output, I have consistently achieved significantly better compression results using HandBrake's built-in presets compared to anything I could configure with ffmpeg or mkvmerge. The HandBrake team clearly knows a lot about encoding tuning and their presets are incredibly well optimized.\n\nBecause of this, the script treats the muxer as a quality signal:\n\n- **Same codec + muxed by HandBrake** → The file is already optimally compressed. The script **skips** it with a message: `[SKIP] 'file.mkv' is already HEVC encoded by HandBrake. Use --force to override.`\n- **Same codec + muxed by ffmpeg/mkvmerge/other** → The compression is likely suboptimal. The script shows a **warning** but **converts it anyway**: `[WARN] 'file.mkv' is already HEVC but was muxed by 'mkvmerge v88.0'. Converting anyway.`\n\nUse `--force` to override this behavior and convert everything regardless.\n\n## change-title\n\n`change-title` is a quick script to change metadata title and make it match with its filename, so, intead of see something like\n![image](https://github.com/user-attachments/assets/8d1019f0-e931-49cc-8770-2195a7e9ad17)\nyou will see this\n![image](https://github.com/user-attachments/assets/ead048a4-79ae-47a6-a64f-60e8571709a5)\n\n`change-title` can be used standalone as\n\n```bash\nchange-title \u003cvideo_name\u003e\n```\n\nor recursively for all Matroska files like this\n\n```bash\nfind . -type f -name \"*.mkv\" -print0 | xargs -0 -I {} change-title \"{}\"\n```\n\n## Usage\n\n### Basic usage\n\nConvert a single file:\n\n```bash\nclutch movie.mp4\n```\n\nConvert and place output in a directory:\n\n```bash\nclutch -o ~/converted/ movie.mp4\n```\n\n### Batch conversion\n\nConvert all videos in a directory recursively:\n\n```bash\nclutch -r ~/Videos/\n```\n\nConvert all `.mp4` files in a pattern (without subdirectories):\n\n```bash\nclutch ~/Videos/*.mp4\n```\n\nConvert all videos and auto-find them:\n\n```bash\nclutch --find  # Searches current directory\nclutch --find ~/Videos  # Searches ~/Videos directory pattern\n```\n\nConvert several files in parallel with local CLI workers:\n\n```bash\nclutch --workers 3 -r ~/Videos/\n```\n\nDistribute NVENC jobs across two GPUs:\n\n```bash\nclutch --workers 2 --gpus 0,1 -r ~/Videos/\n```\n\nWith more than one local worker, the CLI switches to a combined progress display that keeps all active conversions in one coordinated terminal view. Raw verbose HandBrake output is disabled in that mode so the progress view stays readable.\n\nWhen you pass `--gpus`, `clutch` routes NVENC jobs through those GPU indices in round-robin order by passing `gpu=\u003cindex\u003e` to HandBrake's NVENC encoder options. Leave it empty to let HandBrake choose the GPU automatically.\n\n\u003e **Note:** Multi-GPU support is implemented and ready to use, but has not been tested with actual multi-GPU hardware. If you have more than one NVENC-capable GPU, please report any issues you find.\n\n### Service mode over the LAN\n\nYou can now run `clutch` as a service on machine A and submit jobs from another machine in the LAN.\n\nYou can use two remote workflows:\n\n- **Path-based submission** with `--server-url`: machine A must already see the source/destination paths (for example SMB/NFS mounted on the server).\n- **Upload-based submission** with `--remote-server`: machine B uploads files to machine A directly, then polls for completion and can optionally download results back.\n\n#### Running as a systemd service (Linux)\n\nThe installer automatically places a systemd user unit file. To enable and start the service:\n\n```bash\nsystemctl --user enable --now clutch.service\nsystemctl --user status clutch.service\n```\n\nBy default the unit runs `clutch --serve` on `127.0.0.1:8765`. To customize options (bind address, allowed roots, watchers, GPUs, etc.), edit `~/.config/systemd/user/clutch.service` and reload:\n\n```bash\nsystemctl --user daemon-reload\nsystemctl --user restart clutch.service\n```\n\nTo keep the service running after you log out:\n\n```bash\nloginctl enable-linger $USER\n```\n\n#### Running on Windows\n\nThe PowerShell installer (`install.ps1`) can register `clutch` as a Windows scheduled task that starts automatically at system startup -- before any user logs in. When you run the installer, it will ask whether you want to register the service. If you accept:\n\n1. You enter your Windows password in the installer window (stored only by Task Scheduler).\n2. A brief UAC prompt appears to grant the necessary privileges.\n3. The task is registered silently and the installer offers to start it immediately.\n\nThe service listens on `0.0.0.0:8765` by default. After the task is registered, the dashboard is available at `http://localhost:8765` on every boot.\n\nTo manage the scheduled task manually:\n\n```powershell\n# Check task status\nGet-ScheduledTask -TaskName clutch\n\n# Start / stop\nStart-ScheduledTask -TaskName clutch\nStop-ScheduledTask -TaskName clutch\n\n# Remove the task entirely\nUnregister-ScheduledTask -TaskName clutch -Confirm:$false\n```\n\nIf you prefer not to use the installer, you can also register the task by hand:\n\n```powershell\nschtasks /create /tn \"clutch\" /tr \"clutch --serve --listen-host 0.0.0.0 --listen-port 8765\" /sc onstart /ru %USERNAME% /rp\n```\n\nOr simply start the service manually from PowerShell:\n\n```powershell\nclutch --serve --listen-host 0.0.0.0 --listen-port 8765 --allow-root D:\\Videos\n```\n\nThe dashboard and all features (file browser, system monitor, one-click upgrade, watched directories) work the same on Windows. The system monitor uses native Win32 APIs to report CPU, memory, and disk usage, and the file browser enumerates drive letters and mapped network drives automatically.\n\n#### Manual service launch\n\nStart the service on machine A:\n\n```bash\nclutch --serve \\\n  --workers 2 \\\n  --gpus 0,1 \\\n  --listen-host 0.0.0.0 \\\n  --listen-port 8765 \\\n  --allow-root /mnt/media-b \\\n  --allow-root /srv/convert-output\n```\n\nThen open the browser from machine B and use the built-in dashboard:\n\n```text\nhttp://machine-a:8765/\n```\n\nThe dashboard lets you:\n\n- submit conversion jobs without using the CLI\n- inspect queued, running, paused, completed, skipped, and failed jobs\n- pause and resume running conversions instantly\n- cancel queued or running jobs\n- check for new releases from the dashboard and install them with confirmation when an update is available\n- review the service roots and watched directories exposed by machine A\n- change how many workers run in parallel on the shared queue\n- change which NVENC GPU indices the service rotates across\n- change the default conversion settings used by the service and future watched files\n- add and remove watched directories without restarting the service\n\nWhen the service is stopped (e.g. `Ctrl+C` or `systemctl --user stop clutch`), active conversions are paused and detached instead of killed. On the next start, the service reattaches to any encoder process that is still alive and resumes from where it left off. If the process is gone, the job is re-queued from the beginning automatically.\n\nThe service also performs its own cached GitHub release check once per day. When a newer version is available, the dashboard release icon shows a badge and its tooltip changes to the changelog delta between the installed version and the latest release.\n\nSubmit a job from machine B to be executed by machine A:\n\n```bash\nclutch \\\n  --server-url http://machine-a:8765 \\\n  -o /mnt/media-b/converted \\\n  /mnt/media-b/incoming/movie.mkv\n```\n\nIf you omit `-o`, the service keeps the current behavior and writes the converted output next to the source file.\n\n#### Remote upload and stream workflows (2.0)\n\nUpload local files to a remote server and queue remote jobs:\n\n```bash\nclutch \\\n  --remote-server machine-a:8765 \\\n  --token YOUR_TOKEN \\\n  --upload-workers 4 \\\n  --download \\\n  -o ./converted \\\n  ./input/*.mkv\n```\n\nRun single-step stream conversion (upload + convert + download in one request):\n\n```bash\nclutch \\\n  --remote-server machine-a:8765 \\\n  --token YOUR_TOKEN \\\n  --stream \\\n  -o ./converted \\\n  ./movie.mkv\n```\n\nUse `--server-url` and `--remote-server` as separate modes. They are mutually exclusive by design.\n\nRuntime service configuration is persisted in the service database (`--service-db`). This includes allowed roots, worker count, configured NVENC GPU indices, default job settings, and watched directories configured through the dashboard, so they survive service restarts. On first start, CLI service options seed that state; after that, the persisted state is restored from the database.\n\nService HTTP endpoints:\n\n```text\nGET    /\nGET    /health\nGET    /config\nGET    /watchers\nGET    /jobs\nGET    /jobs/\u003cjob_id\u003e\nPOST   /config\nPOST   /watchers\nPOST   /jobs\nPOST   /jobs/\u003cjob_id\u003e/pause\nPOST   /jobs/\u003cjob_id\u003e/resume\nPOST   /jobs/\u003cjob_id\u003e/retry\nDELETE /watchers/\u003cwatcher_id\u003e\nDELETE /jobs/\u003cjob_id\u003e\n```\n\nThe service starts with 1 worker by default. You can raise the worker count from the dashboard to process several jobs in parallel; all workers share the same queue. If you configure NVENC GPU indices, the service assigns NVENC jobs to those GPUs in round-robin order.\n\n### Automatic watched-directory mode\n\nMachine A can also watch one or more directories and automatically enqueue any new video file that becomes stable on disk.\n\nWatch a directory and convert everything that appears there:\n\n```bash\nclutch --serve \\\n  --listen-host 0.0.0.0 \\\n  --watch-dir /mnt/media-b/watch \\\n  --watch-recursive \\\n  --watch-settle-time 60 \\\n  --allow-root /mnt/media-b\n```\n\nThe watcher uses a polling strategy and waits until the file stops changing before queueing it, which helps avoid starting a conversion while a large file is still being copied.\n\nWhen you use `--workers` in normal CLI mode, `clutch` runs that many local conversions in parallel. In `--serve` mode, the same option seeds the service worker pool on first start for that service database; after that, the persisted worker count from the database takes precedence. When you use `--gpus`, local NVENC jobs rotate across those GPU indices, and `--serve --gpus ...` seeds the service's persisted NVENC GPU list on first start for that service database.\n\nThe configured GPU indices must be visible to the process running `clutch`. If the service only sees GPU `0`, configuring `0,1` will not make GPU `1` usable until that second GPU is also exposed to HandBrake and NVENC on that machine.\n\n### qBittorrent integration\n\nThe repository includes `qbt-hardlink-to-watch.sh`, a standalone script that bridges qBittorrent downloads with clutch watchers. When a torrent finishes, the script creates hardlinks of the downloaded video files into the appropriate watch directory so clutch picks them up for conversion automatically.\n\nUsing hardlinks instead of copies means:\n\n- No extra disk space is consumed.\n- qBittorrent keeps seeding normally from its own download path.\n- clutch can be configured with `--watch-dir` and `delete_source` so the hardlink is removed after conversion, without affecting the original seeding file.\n\n#### How it works\n\n1. qBittorrent calls the script when a torrent completes.\n2. The script classifies the torrent as **series** or **movie** based on the qBittorrent category and torrent name:\n   - **Series** — the category is `sonarr`, or the name contains `PACK`, `serie`, or an `S01`..`S99` season pattern (case-insensitive).\n   - **Movies** — the category is `radarr`, or everything else that does not match a series pattern.\n3. Video files (`mp4`, `mkv`, `avi`, `mov`, `ts`, `iso`, `mpg`, `mpeg`) are hardlinked into the matching watch directory.\n4. For multi-file torrents, a subfolder named after the torrent is created inside the watch directory and the files are linked there, preserving the original structure.\n\n#### Setup\n\n1. **Configure watch directories** in clutch (via the dashboard or CLI). For example:\n\n   | Watch directory        | Purpose |\n   |------------------------|---------|\n   | `/data/Downloads/Movies` | Incoming movies for conversion |\n   | `/data/Downloads/Series` | Incoming series for conversion |\n\n   Enable `delete_source` on those watchers so the hardlinks are cleaned up after conversion.\n\n2. **Edit the script variables** at the top of `qbt-hardlink-to-watch.sh` to match your paths:\n\n   ```bash\n   MOVIES_WATCH=\"/data/Downloads/Movies\"\n   SERIES_WATCH=\"/data/Downloads/Series\"\n   LOG_FILE=\"/config/qbt-hardlink-to-watch.log\"   # optional, set empty to disable\n   ```\n\n3. **Register the script in qBittorrent.** Go to *Options → Downloads → Run external program on torrent finished* and enter:\n\n   ```text\n   /path/to/qbt-hardlink-to-watch.sh \"%N\" \"%L\" \"%F\"\n   ```\n\n   | Parameter | Meaning |\n   |-----------|---------|\n   | `%N` | Torrent name |\n   | `%L` | Category (e.g. `radarr`, `sonarr`) |\n   | `%F` | Content path (root path for multi-file torrents) |\n\n4. Make the script executable:\n\n   ```bash\n   chmod +x /path/to/qbt-hardlink-to-watch.sh\n   ```\n\n#### Typical workflow (Sonarr / Radarr → qBittorrent → clutch)\n\n```text\nSonarr/Radarr sends download to qBittorrent\n        │\n        ▼\nqBittorrent finishes download\n        │\n        ▼\nqbt-hardlink-to-watch.sh creates hardlinks in watch dir\n        │\n        ▼\nclutch watcher detects new files and enqueues conversion\n        │\n        ▼\nConversion completes → hardlinks removed (delete_source)\nqBittorrent originals untouched → seeding continues\n```\n\n### Full option reference and wiki\n\nThe README focuses on practical workflows. The complete option-by-option reference is available in `docs/wiki/`:\n\n- [docs/wiki/Home.md](docs/wiki/Home.md)\n- [docs/wiki/CLI-Options-Reference.md](docs/wiki/CLI-Options-Reference.md)\n- [docs/wiki/Service-and-API.md](docs/wiki/Service-and-API.md)\n- [docs/wiki/Remote-Upload-and-Stream-Mode.md](docs/wiki/Remote-Upload-and-Stream-Mode.md)\n- [docs/wiki/Scheduling-and-Energy-Rules.md](docs/wiki/Scheduling-and-Energy-Rules.md)\n\nYou can mirror these pages to GitHub Wiki at any time by enabling Wiki in repository settings and pushing to the `.wiki` repository.\n\n### Advanced options\n\nConvert with audio passthrough (no re-encoding audio):\n\n```bash\nclutch -ap movie.mp4\n```\n\nConvert using AV1 codec with maximum compression (slow):\n\n```bash\nclutch -c av1 -s movie.mp4\n```\n\nAuto-accept without prompts and delete source on success:\n\n```bash\nclutch -y -ds movie.mkv\n```\n\nPower off after conversion completes:\n\n```bash\nclutch -po movie.mp4\n```\n\nForce re-conversion even if file is already in target codec:\n\n```bash\nclutch --force movie.mkv\n```\n\nShow source file information (codec, resolution, audio tracks, etc.):\n\n```bash\nclutch -si movie.mkv\n```\n\n### ISO disc images\n\nConvert a DVD/Blu-ray ISO image (automatically selects the main feature):\n\n```bash\nclutch movie.iso\n```\n\n### Help\n\n```bash\nclutch --help\n```\n\nFull help output:\n\n```text\nusage: clutch [-h] [-o OUTPUT] [--find [PATTERN]] [-r] [-ds] [-c CODEC]\n                     [-s] [-f] [-n] [-ap] [--force] [--gpus GPUS] [-y] [--verbose]\n                     [-w WORKERS] [-po]\n                     [--server-url SERVER_URL] [--serve]\n                     [--listen-host LISTEN_HOST] [--listen-port LISTEN_PORT]\n                     [--service-db SERVICE_DB] [--allow-root ALLOW_ROOT]\n                     [--watch-dir WATCH_DIR] [--watch-recursive]\n                     [--watch-poll-interval WATCH_POLL_INTERVAL]\n                     [--watch-settle-time WATCH_SETTLE_TIME] [-si] [-v]\n                     [--update] [--upgrade]\n                     [input_files ...]\n\nConvert video files using HandBrakeCLI and preserve all audio and subtitle\ntracks.\n\noptions:\n  -h, --help            show this help message and exit\n\ninput/output:\n  input_files           Video files or directories to convert.\n  -o, --output OUTPUT   Output directory for converted files.\n  --find [PATTERN]      Recursively search for video files in directories\n                        matching the pattern, or current directory if no\n                        pattern is given.\n  -r, --recursive       Recursively search directories for video files\n                        matching the given patterns.\n  -ds, --delete-source  Delete the original source file after a successful\n                        conversion.\n\nencoding:\n  -c, --codec CODEC     Video codec: nvenc_h265 (default), nvenc_h264, av1,\n                        x265.\n  -s, --slow            Use slow encoding speed.\n  -f, --fast            Use fast encoding speed.\n  -n, --normal          Use normal encoding speed (default).\n  -ap, --audio-passthrough\n                        Pass through original audio tracks.\n  --force               Force conversion even if file is already in the target\n                        codec.\n  --gpus GPUS           Comma-separated NVENC GPU indices to use. Example:\n                        0,1 rotates jobs across GPU 0 and GPU 1.\n\nbehaviour:\n  -y, --yes             Automatically accept transcoding without prompts.\n  --verbose             Show verbose output from HandBrakeCLI.\n  -w, --workers WORKERS\n                        Number of local conversion workers to run in\n                        parallel (default: 1).\n  -po, --poweroff       Power off the system after conversion.\n  --server-url SERVER_URL\n                        Submit matching jobs to a remote clutch\n                        service instead of converting locally.\n\nservice:\n  --serve               Run the HTTP conversion service on this machine.\n  --listen-host LISTEN_HOST\n                        Bind host for the service (default: 127.0.0.1).\n  --listen-port LISTEN_PORT\n                        Bind port for the service (default: 8765).\n  --service-db SERVICE_DB\n                        SQLite database path for the service queue.\n  --allow-root ALLOW_ROOT\n                        Allowed filesystem root for service input/output\n                        paths. Repeat as needed.\n  --watch-dir WATCH_DIR\n                        Directory to watch and enqueue automatically when\n                        running with --serve.\n  --watch-recursive     Watch directories recursively when using --watch-dir.\n  --watch-poll-interval WATCH_POLL_INTERVAL\n                        Polling interval in seconds for watched directories.\n  --watch-settle-time WATCH_SETTLE_TIME\n                        Seconds a watched file must remain unchanged before\n                        enqueueing.\n\ninfo:\n  -si, --source-info    Show source information about a single video file.\n  -v, --version         show program's version number and exit\n  --update              Check if a newer version is available on GitHub.\n  --upgrade             Upgrade to the latest version from GitHub.\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadocampo%2Fclutch","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fadocampo%2Fclutch","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadocampo%2Fclutch/lists"}