media-gate
Fail-closed media QC for content pipelines: catches black video, silent audio, and duplicate/near-duplicate images before they go out the door.
$ media-gate check output/final_render.mp4
FAIL: final_render.mp4
FAIL: SILENT_AUDIO — mean_volume -61.2 dB (at/below -50.0 dB threshold)
PASS: no black intervals detected
Why this exists
If you run any kind of automated content pipeline — video generation, faceless-channel automation, bulk image export, TTS narration — you will, eventually, publish something broken. Not because the pipeline is bad, but because silent failures are the default failure mode of media processing:
- A TTS/rendering step silently drops the audio track and the video looks fine in a file browser (correct duration, correct thumbnail) right up until someone presses play.
- A render step crashes partway through and produces a video that is technically valid (openable, correct container) but is just black frames.
- A "new" asset is actually the same image re-exported, resized, or re-encoded from something already published — byte-different, but visually identical. A checksum won't catch it; a platform's spam/dedup detection will.
Each of these is invisible to a naive if file exists and file size > 0
check, and each one is exactly the kind of thing that erodes trust with an
audience or gets an account flagged. media-gate gives you a small,
dependency-light, scriptable tool to run as a pre-publish gate so these
never make it out silently.
Fail-closed by design: if a check can't produce a confident answer (e.g. ffmpeg is missing, or a video's duration can't be read), the result leans toward failure/warning rather than a silent pass. The entire point of a QC gate is defeated if "I couldn't check" is treated the same as "it's fine."
Install
pip install media-gate
This installs the Python dependencies (Pillow, imagehash). The video
checks additionally require ffmpeg and ffprobe on your PATH:
- Windows: https://ffmpeg.org/download.html or
winget install Gyan.FFmpeg - macOS:
brew install ffmpeg - Debian/Ubuntu:
apt install ffmpeg
CLI usage
# Video: checks for black frames + silent/missing audio
media-gate check my_video.mp4
# Image: computes a perceptual hash, and (optionally) compares it against
# already-published images to catch near-duplicates
media-gate check new_thumbnail.png --compare-against published/*.png
# Machine-readable output for use in scripts/CI
media-gate check my_video.mp4 --json
echo $? # 0 = PASS, 1 = FAIL, 2 = error (file not found, bad args, ...)
Useful flags (see media-gate check --help for the full list):
| Flag | Default | Meaning |
|---|---|---|
--silence-threshold-db |
-50.0 |
mean_volume at/below this dB counts as silent |
--max-black-fraction |
0.20 |
fail if more than this fraction of the video is black |
--hash-algorithm |
phash |
perceptual hash algorithm (phash, dhash, ahash, whash) |
--max-hamming-distance |
6 |
bit distance at/below which two images count as near-duplicates |
Exit codes are designed for shell/CI gating: 0 = PASS, non-zero = do not
publish.
Library usage
from media_gate import dedup, video_qc
# --- video ---
audio = video_qc.check_silent_audio("clip.mp4")
black = video_qc.check_black_frames("clip.mp4")
if not audio.passed or not black.passed:
raise RuntimeError(f"QC failed: {audio.reason} / {black.reason}")
# --- images ---
known = dedup.build_registry(["published/a.png", "published/b.png"])
matches = dedup.find_duplicates("new/candidate.png", known)
if matches:
fp, distance = matches[0]
print(f"near-duplicate of {fp.path} (hamming distance {distance})")
How the checks work
Black video — runs ffmpeg's blackdetect video filter
(-vf blackdetect=d=...:pic_th=...:pix_th=...) and parses the
black_start/black_end/black_duration lines it writes to stderr. Fails
if the total black duration exceeds --max-black-fraction of the video's
total length.
Silent audio — first checks (via ffprobe) that the file has an audio
stream at all (a missing stream is NO_AUDIO_TRACK, a distinct and common
failure mode from a present-but-silent track). Then runs ffmpeg's
volumedetect audio filter and parses mean_volume/max_volume from
stderr; a mean volume at or below the threshold is SILENT_AUDIO.
Duplicate images — computes a perceptual hash (default: phash, via the
imagehash library) for each image and compares hashes by Hamming distance.
Unlike a checksum, this catches the same image re-encoded, resized, or
lightly edited — the actual failure mode automated pipelines produce, since
two independent generations are almost never byte-identical but are often
visually identical.
Development
git clone https://github.com/luandv92/media-gate
cd media-gate
pip install -e ".[dev]"
pytest
License
MIT — see LICENSE.
Metadata
Release files for media-gate 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| media_gate-0.1.0.tar.gz | 18.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| media_gate-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 31.9 kB
Release files / media_gate-0.1.0.tar.gz
| Download URL | media_gate-0.1.0.tar.gz |
|---|---|
| Size | 18.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
707cf1a65cd06d8e1703e7a8012f9e28d5397252b1d481d4992cab5fdae5dd92
|
|
BLAKE2b-256 checksum How to use checksums |
5585716ab99ef2fd89a6a88a537ecd91506cdbc8358a0c164917bcb29e2a953c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 19, 2026.
Transparency logRelease files / media_gate-0.1.0-py3-none-any.whl
| Download URL | media_gate-0.1.0-py3-none-any.whl |
|---|---|
| Size | 13.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
fc76f861f939f57d8a195ce0f162cb227c7c7b3ec5e0bf79235cbcb3b6f668c7
|
|
BLAKE2b-256 checksum How to use checksums |
3f654abd0a6328194618f0c6187ce2c7e14b95f5f1391bba3f0d10217e510eb9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 19, 2026.
Transparency log