- Python 98.1%
- Dockerfile 1.1%
- Shell 0.8%
decide_review()'s one-way guard (ReviewAlreadyDecided) stays untouched -- correct_review() is a separate, deliberately-named function for a human overriding an already-decided review on purpose, and it records the override (ReviewResult.corrected_from/corrected_at) rather than silently rewriting history. SafeArr's new /decisions correction UI calls this in-process; no HTTP route needed for it. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|---|---|---|
| poisonreview | ||
| tests | ||
| .dockerignore | ||
| .gitignore | ||
| docker-entrypoint.sh | ||
| Dockerfile | ||
| pyproject.toml | ||
| README.md | ||
| TODO.md | ||
poisonreview
Generic media-review engine: sample representative screenshots from a video, generate a review session, and return a human approve/reject decision. Built for catching mislabeled/"poisoned" video files in a media library (e.g. kids' shows uploaded under a legit episode name but containing unrelated or inappropriate content), but deliberately ignorant of why a caller wants something reviewed.
This package is deliberately ignorant of Sonarr, Radarr, Plex, or "kids content" — those concepts belong to the consuming project. See SafeArr, the opinionated Sonarr/Radarr quarantine orchestrator that depends on this package for exactly that reason.
from poisonreview import create_review
review = create_review(source="/quarantine/movie.mkv", screenshots=30)
review.id
review.frames # [{"image": "07.jpg", "timestamp_sec": 483.4}, ...]
review.approve()
# or: review.reject(reason="Wrong content")
Requirements
- Python 3
ffmpegandffprobeonPATH
No other dependencies (stdlib only) for the core package.
Status
The core create_review()/approve()/reject() contract above is real
and working, with review state persisted to disk (not just browser
localStorage) so a decision made in one process is visible to another.
poisonreview serve runs the actual review UI/API a human uses:
poisonreview serve --port 8790
poisonreview scan -i <library-dir> -o <output-dir> still does the
original bulk-sweep static-gallery workflow (the original
review_scan.py behavior), for auditing a whole library rather than
reviewing a single quarantined file. A decision can also be corrected
after the fact via correct_review() — a deliberate second entry point
alongside decide_review()'s one-way guard, not a loosening of it; see
TODO.md Phase 10. 66 tests cover all of this — see
TODO.md for exactly what's done vs. still open per phase
(the AI-assisted suspicion-scoring classifier is still unbuilt).
A Dockerfile exists (docker build ., needs ffmpeg/gosu which it
installs itself) and is build-tested and running in production as part
of SafeArr's docker-compose setup, which also verified the
Sonarr/Radarr integration this package feeds against a live instance —
see SafeArr's own README/TODO.md for specifics.
How it works
For each video, ffprobe gets the duration, then a single ffmpeg pass
seeks past an intro margin and decodes forward at a fixed interval to pull
N frames evenly across the episode — one process per video rather than N
separate seeks, which is significantly faster on network-mounted
libraries. See TODO.md for the fingerprint-based cache
invalidation, HTML-injection hardening, disk-backed review state, and
per-frame timestamps built on top of that core loop.