$ amuxify scan ~/incoming
PASS /home/me/incoming/Show.S01E01.mkv
WARN /home/me/incoming/Movie.2019.mkv
WARN LINK_IN_TAG 1 link(s) in metadata: tag COMMENT: http://tracker.example/x
BLOCK /home/me/incoming/Movie.2019.Sub.mkv
BLOCK ATTACH_EXEC attachment #1 "font.ttf" (font/ttf, 71 KiB) contains executable PE/DOS executable
BLOCK: 3 file(s) BLOCK=1 PASS=1 WARN=1
The third file has a Windows program packed inside it as a subtitle font. A media server would import it without complaint.
What it catches
- Programs disguised as fonts or images inside an MKV, and files that are a valid video but also carry a ZIP, RAR or 7z archive or a Windows or Linux executable.
- Tracker and release-group links in tags, titles, chapter names and subtitles; a warning with the default profile.
- Your own account details in purchased files: account name, purchase date and store IDs in MP4 metadata; a warning with the default profile, and stripped by every profile.
- Dangerous files next to the video:
.lnk,.url,.exe,.scr,.bat,.ps1and similar. - Broken or mislabeled files: wrong extension, truncated, does not decode. A file that reports no duration gets a warning.
- Filenames with hidden characters such as right-to-left override or zero-width spaces. A double
extension like
x.exe.mkvgets a warning.
The profile decides what gets fixed. The default one strips titles, tags and purchase details, keeps every audio and subtitle track, and drops font attachments only when the file has no text subtitle track that could use them. The other profiles also drop commentary tracks, languages you did not ask for, chapters or attachments. Before a rebuilt file is placed, each stream it kept is hashed and compared with the source. amuxify does not transcode, rename or organise your library; Sonarr and Radarr still do that.
Where it fits
- Your own machine: download or buy the file, run
amuxify scanon it, thencleanorremux, and copy the result to the NAS. Nothing else needs to be installed or configured. The hooks below are the same commands wired to a download client so they run without you. - SABnzbd and NZBGet: run the hook here if you can. It runs before Sonarr or Radarr import,
so a failed job keeps the file out of the library. SABnzbd only fails a job on a script's exit code when
script_can_failis on (Config, Special). Both clients report a failed job to Sonarr and Radarr, which blocklist the release and search for another one; on aBLOCKthe NZBGet script also tells NZBGet to mark the download as bad. If a damaged or noisy file should not cost you the release, pass--fail-on blockso that only aBLOCKfails the job. - Sonarr and Radarr: the hook runs after import and cleans the file already in the library,
the same way the download-client hooks do. With the default profile it also makes the audio track in the series
or movie's original language the default. It cannot stop an import. Torrent imports are usually hard links,
which the hook leaves alone unless you pass
--hardlinks break. - qBittorrent, Transmission, Deluge: they ignore a script's exit code. Use the Sonarr and
Radarr hooks with
--hardlinks break, or runamuxify scan --quarantine=/srv/quarantine "$DIR"from the completion script to moveBLOCKfiles out of the download folder. - Storage: TrueNAS, Unraid, Synology, NFS and SMB shares. When amuxify rebuilds a file in place, which is how the hooks work, the rebuilt file keeps the owner, mode and modification time of the original. A hard-linked file you are still seeding is never edited in place, so the copy your torrent client holds is never changed.
The SABnzbd script is one line:
exec amuxify --profile "${AMUXIFY_PROFILE:-homelab}" hook sabnzbd "$@"
Scripts for each tool ship in contrib/hooks/ and the Docker image. Setup steps are in
docs/hooks.md.
Install
amuxify needs MKVToolNix 50 or newer and ffmpeg 4.4 or newer on the
same machine. exiftool and clamscan are optional. amuxify doctor tells you what is missing.
# release binary, Linux and macOS (verifies the SHA-256 checksum)
curl -fsSL https://raw.githubusercontent.com/amuxify/amuxify/main/install.sh | sh
# Homebrew
brew install --cask amuxify/tap/amuxify
# Docker, run as the uid that owns the library, never root
docker run --rm -u 1000:1000 -v /srv/media/incoming:/data ghcr.io/amuxify/amuxify scan /data
The install guide covers package names per distro, pinning a version and the Docker image.
Safety
A rebuilt file is written beside the destination and only takes its place once every kept stream's hash matches
the source; if one does not, the rebuilt file is deleted and the original stays. amuxify will not write over some
other file that already sits at the destination, and it skips symlinks. It refuses to modify files as root
unless told to, and no flag overrides a BLOCK.
docs/safety.md lists all ten
guarantees, each with a test.
Reference
Commands
| Command | What it does | Writes |
|---|---|---|
scan | Report findings and a verdict per file | nothing, unless --quarantine moves BLOCK files into a mirrored tree under that directory |
ingest | Scan, then rebuild into a verified MKV or clean in place | the file in place; a rebuild is hash-verified before it replaces the original |
hook | Run ingest from SABnzbd, NZBGet, Sonarr or Radarr and exit the way that program expects | as ingest |
watch | Poll a directory and run ingest on each file once it has stopped changing; for a sidecar container or a drop folder | as ingest |
remux | Rebuild into a sanitized MKV in a mirrored tree beside the input root, or replace the original with --in-place | <root>__remuxed/, --output or --in-place |
clean | Strip metadata in place, tracks untouched | the file; MP4, MOV, AVI and FLV are rewritten to a temp file and hash-verified before they replace the original, MKV and WebM headers are edited in place by mkvpropedit |
doctor | Check tools, version floors, profile and environment | nothing |
profile | List the built-in profiles or print one | nothing |
Reads MKV, WebM, MP4, M4V, MOV, AVI, MPEG-TS, M2TS, MPG, VOB and FLV. A rebuilt file is always MKV, written
by mkvmerge; clean keeps MP4-family and AVI files in their own container.
Verdicts
| Verdict | Exit | Meaning |
|---|---|---|
| PASS | 0 | Nothing to report |
| WARN | 1 | Worth knowing; the file is usable |
| FAIL | 3 | The file failed a check and nothing is written for it: truncated, unparseable, mislabeled, a rebuilt copy whose hashes did not match, a destination that already exists, or a finding such as a tracker link that the profile treats as a failure |
| BLOCK | 4 | Dangerous: executable payload, polyglot, hidden characters in the filename or blocked sidecar |
The worst verdict of the run is the exit code; 2 means a usage error and 130 an interruption.
--json prints the full report, described in
docs/report.md.
Profiles
| Profile | Languages | Chapters | Fonts | Commentary | Links / provenance | Verify |
|---|---|---|---|---|---|---|
homelab (default) | keep all, prefer original | keep | keep if text subs | keep | warn | quick |
anime | keep all, prefer original | keep | keep | drop | warn | quick |
archive | English only | drop | drop | drop | fail | quick |
strict | English only | drop | drop | drop | fail | full + ClamAV |
A profile is a TOML file; amuxify profile show homelab prints one to start from. Unknown keys
are rejected, so a typo cannot loosen a policy. All keys are in
docs/profiles.md.