CLI that audits a Plex movie+TV library against the Plex naming standard and suggests/optionally fixes corrected names. Reuses avatarr's TMDB/IMDB resolver + naming.
Find a file
Alan Gaudet 3ed313aabd
Some checks are pending
CI / Test & Clippy (push) Waiting to run
docs: state §8's next milestone in the form the loop reads
M1-M25 are shipped and the submission is closed, but §8 said so only in prose.
Without the terminal marker the loop would hard-pause here as an ambiguous §8
instead of exiting clean.

milestone-cycle v1.12.0 writes one canonical marker and re-parses it before
committing, so this file is now round-trip clean against the loop's own parser.
2026-07-25 13:49:41 -04:00
.github/workflows v0.14.0 feat: add Slint design-system foundation (#3) 2026-07-17 02:31:38 +02:00
crates fix: surface AI reviews in Findings for v0.23.2 2026-07-21 16:37:08 -04:00
docs docs: state §8's next milestone in the form the loop reads 2026-07-25 13:49:41 -04:00
evals fix: close M11 pre-landing findings 2026-07-16 08:46:29 -04:00
fixtures/fake-library WIP: package M11 AppImage and judge demo 2026-07-16 00:48:31 -04:00
packaging feat: ship M23 GUI dogfood fixes 2026-07-19 00:40:05 -04:00
.gitignore WIP: package M11 AppImage and judge demo 2026-07-16 00:48:31 -04:00
AGENTS.md docs: make AGENTS.md the real context file, symlink CLAUDE.md and GEMINI.md 2026-07-25 03:08:56 -04:00
Cargo.lock fix: surface AI reviews in Findings for v0.23.2 2026-07-21 16:37:08 -04:00
Cargo.toml fix: surface AI reviews in Findings for v0.23.2 2026-07-21 16:37:08 -04:00
CHANGELOG.md fix: surface AI reviews in Findings for v0.23.2 2026-07-21 16:37:08 -04:00
CLAUDE.md docs: make AGENTS.md the real context file, symlink CLAUDE.md and GEMINI.md 2026-07-25 03:08:56 -04:00
GEMINI.md docs: make AGENTS.md the real context file, symlink CLAUDE.md and GEMINI.md 2026-07-25 03:08:56 -04:00
LICENSE M2: Cargo workspace scaffold + avatarr config shim 2026-06-17 09:53:13 -04:00
README.md docs: finalize Build Week submission package 2026-07-21 19:37:16 -04:00
ROADMAP.md docs: finalize Build Week submission package 2026-07-21 19:37:16 -04:00
rust-toolchain.toml M2: Cargo workspace scaffold + avatarr config shim 2026-06-17 09:53:13 -04:00

MediaLint

MediaLint audits movie and TV libraries for Plex naming problems. It emits terminal, JSON, or self-contained HTML reports. Fixes are dry-run by default; applying a fix requires an explicit command and produces an undo journal.

The source workspace is version 0.23.2. Its reusable core supplies the scan pipeline, an SQLite history store, and tracked multi-batch undo. The GUI crate opens a frameless desktop shell with a custom titlebar and five-item navigation rail. Its Dashboard shows scoped severity deltas, distinct-file library health, the healthy-file count, a green percentage/progress bar, and up to 30 complete scans of trend history. Re-scan reports live progress and supports cancellation through a bounded Tokio worker bridge; the footer retains the latest scan's date, file count, and finding count and shows TMDB/AI configuration readiness. Slint remains on the main thread. The Findings view combines Rule, Library, severity, and search filters; Approve all approves every fixable row currently shown by those filters. It also records deterministic alternatives. Dividers resize all five data columns. Optional GPT-5.6 advice appears in the Suggested column and finding detail, but never feeds model output into the fix planner.

The Fix view rebuilds approved moves against the current filesystem, shows unsafe rows before apply, confirms one journaled batch, reports progress, and offers immediate undo or a fresh plan for remaining approvals. A prepared plan can be cleared without applying it; no-op suggestions are labeled already correct.

History lists saved scans and applied batches below a fixed tab strip. Rows show date and time with semantic error, warning, and unverifiable colors. Its Snapshot action opens a saved report read-only; the Findings banner explains that approvals are disabled and can replace it with a live scan. Saved reports also export to private JSON and HTML files. Scan deletion is confirmed, and batches with a current valid journal can be restored against the active library paths.

Settings shows each Movie, UHD movie, and TV location as command-line, MediaLint-owned, or inherited. It supports multiple locations per media kind, native folder selection, explicit inherit/remove actions, and unknown TOML preservation. Stored TMDB and AI service keys are never projected into the UI. The GUI can select hosted OpenAI or a local Responses-compatible endpoint, change the review model, replace credentials, verify TMDB, change saved-scan retention, and open the data folder.

Version 0.23.2 is the selected OpenAI Build Week submission release. The scanner, deterministic rules, metadata resolver, reports, fix planner, apply, and undo predate the event baseline commit 08b0868. The Build Week range ends at the v0.23.2 tag. It adds structured partial-scan issues, optional GPT-5.6 review for parser edge cases, compatibility and AI-isolation tests, a local Gemma quality evaluation, Linux AppImages, a reusable scan pipeline, SQLite history, and the desktop GUI. Version 0.17.0 added the first complete view and connected it to the scan pipeline and history store; version 0.18.0 shipped the Findings review workbench at 6c90259; version 0.19.0 shipped staged Fix and Undo at 27edaf0. Version 0.20.0 shipped the History view at 12d9426. Version 0.21.0 shipped provenance-aware Settings, private atomic config persistence, and immediate configurable retention at 3980a54. Version 0.22.0 shipped the production-bridge workflow, cancellation, and history-degraded hardening at e817a9b. Version 0.23.0 incorporates the owner-driven GUI dogfood fixes and the safe 500-title mock-library cycle at 3dad528. Version 0.23.1 at 9a5b734 fixes individual approval toggles in Findings and local Responses compatibility. Version 0.23.2 shows returned AI advice in the Suggested column and selects a reviewed row so its rationale is immediately visible. The v0.23.2 source tag and generated archives are available on Codeberg and GitHub. The public 2:19 Build Week demonstration shows the desktop workflow, AI review, and configuration.

The custom milestone-cycle v1.10.0 skill used to execute most of the roadmap is available as a judge archive. It contains the source template, Claude and Codex renders, host scripts, resume hook, 152-check test suite, and MediaLint usage notes.

Install

Download the current Linux x86_64 AppImage and checksum, then run:

sha256sum -c MediaLint-0.23.2-x86_64.AppImage.sha256
chmod +x MediaLint-0.23.2-x86_64.AppImage
./MediaLint-0.23.2-x86_64.AppImage

The default entry point opens the GUI. Pass --cli before normal CLI arguments, or run the bundled credential-free fixture with:

./MediaLint-0.23.2-x86_64.AppImage --demo --format terminal --no-history

If FUSE is unavailable, add --appimage-extract-and-run before the MediaLint arguments. The AppImage SHA-256 is 1e02cf6c54ab2326706ed6a21a6cc819275c7a2ce03ad070153c0644fec7834c.

Build the CLI from source

MediaLint v0.23.2 uses two crates from avatarr, so clone both repositories into the same parent directory. The avatarr commit below matches the release build.

mkdir medialint-build
cd medialint-build
git clone https://codeberg.org/alan090/avatarr.git
git -C avatarr checkout a00ff54e9da46369fceaaa9f0d5c35c8d0cd6ee4
git clone --branch v0.23.2 https://codeberg.org/alan090/medialint.git
cd medialint
rustup toolchain install 1.96 --profile minimal
cargo +1.96 build --release --locked -p medialint
./target/release/medialint --help

Run the included fixture without credentials:

./target/release/medialint \
  --movie-dir fixtures/fake-library/Movies \
  --uhd-movie-dir "fixtures/fake-library/UHD Movies" \
  --tv-dir fixtures/fake-library/TV \
  --format terminal --no-history

Build the GUI from the same checkout with cargo +1.96 build --release --locked -p medialint-gui.

packaging/build-appimage.sh requires Docker, mksquashfs, and curl. It is the reproducible builder for the earlier v0.11 CLI-only artifact; the v0.23.2 GUI artifact's build and smoke-test record is in docs/qa/v0.23.2-appimage-smoke.md.

Usage

Audit configured roots or pass them directly:

medialint --format terminal
medialint --movie-dir /media/Movies --tv-dir /media/TV --format json > report.json
medialint --format html > report.html
medialint history list
medialint history show 1 --format json
medialint history prune --keep 30

Completed scans are saved under $XDG_DATA_HOME/medialint/medialint.db. Pass --no-history to skip one scan. History failures produce a warning but do not discard the report.

Desktop GUI

Build and launch the desktop application from the source checkout:

cargo run -p medialint-gui
cargo build --release -p medialint-gui
./target/release/medialint-gui

The navigation rail opens Dashboard for library health and scan progress, Findings for review and approval, Fix for the apply/undo workflow, History for saved scans and batches, and Settings for library paths, credentials, and retention. Library locations can be typed or selected with Browse…. Add Movie/UHD movie/TV location keeps existing locations and adds another scan root.

Settings also configures advisory AI review. OpenAI uses the hosted Responses API and requires a stored key or OPENAI_API_KEY. Local accepts an OpenAI-compatible Responses API URL and model name; its API key is optional. MediaLint writes stored credentials to its owner-only config and never displays their values after entry. The footer lights are green when the corresponding TMDB or AI configuration is usable; they are configuration indicators, not continuous network probes.

Without a TMDB key, deterministic filename parses appear as ParsedLocal suggestions. Rows that need metadata stay unavailable for approval and explain that a key can expand lookup. Completed scans live at $XDG_DATA_HOME/medialint/medialint.db; each applied batch gets a private journal under $XDG_DATA_HOME/medialint/journals/.

If the history database cannot open, Dashboard and History show the storage error. Scanning remains available, and approved moves can be applied and undone through their journal. Cancelling a scan discards its partial report and writes no history row; a new scan can start after cancellation completes.

Review qualifying parser edge cases with GPT-5.6:

OPENAI_API_KEY=... medialint --ai-review --format json

--ai-review is explicit opt-in. It sends media kind, deterministic rules/messages, any deterministic suggestion, and paths relative to configured library paths. Requests use gpt-5.6, store: false, strict Structured Outputs, and sequential batches of at most 20. Keys, absolute roots, prompts, and raw responses are not logged. Model advice is stored separately from Resolution; the fix planner does not turn it into a move.

Preview, apply, and undo a report:

medialint fix report.json
medialint fix report.json --apply --trusted-root /media/Movies
medialint undo --trusted-root /media/Movies

Configured medialint and avatarr library paths are trusted automatically. Use repeatable --trusted-root arguments for roots supplied only through scan directory overrides. Apply and undo reject paths outside those current roots, and never replace an occupied destination. Default apply runs create separate private journals. medialint undo selects the newest existing journal; use --journal to choose one explicitly.

The AppImage demo library contains tiny placeholder .mkv files and exercises filenames only.

Contributing

Run the pinned workspace gate before submitting changes:

cargo test --workspace
cargo clippy --workspace --all-targets -- -D warnings

Commits use Alan <alan.c.gaudet@gmail.com> through the global Git config.

License

GPL-3.0-or-later. See LICENSE.