feat(probe): ffprobe wrapper #59
Merged
naps62-yolo
merged 4 commits from 2026-08-22 20:52:10 +01:00
issue/19-ffprobe into main
Labels
Clear labels
area/api
area/ci
area/compat
area/core
area/daemon
area/db
area/dl
area/indexer
area/infra
area/meta
area/parse
area/probe
area/subs
area/web
difficulty/easy
difficulty/hard
difficulty/moderate
difficulty/trivial
phase/1-skeleton
phase/2-logic
phase/3-sourcing
phase/4-movies
phase/5-ui
phase/6-tv
phase/7-people
phase/8-compat
phase/9-subtitles
type/bug
type/chore
type/feature
type/test
arr-api
CI and test harness
arr-compat
arr-core
arr-daemon
arr-db
arr-dl
arr-indexer
workspace and tooling
arr-meta
arr-parse
arr-probe
arr-subs crate: providers, extraction, translation, sync
web/
bounded, obvious approach, few files
subtle correctness or cross-cutting
multiple files, judgement, an interface to design
one file, mechanical, no design decisions
workspace, CI, config, database, empty API and SPA
parsing and policy engine, pure, no network
TMDB and Prowlarr, read-only
movies end to end
search, buckets, library views, queues
seasons, episodes, tracking, derived status
owner tags and notifications
Jellyseerr shim
build order: subtitles, DESIGN.md §15
No labels
Milestone
No items
No Milestone
Projects
Clear projects
No projects
No Assignees
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: yolo/arr#59
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Closes #19.
arr-proberunsffprobeand returns aProbedFile: resolution, videocodec, HDR format with the Dolby Vision profile as a number, per-track audio
language with the
titleandhandler_namestrings §5.2 needs, subtitletracks, duration and size. Source stays
None— no file knows where it camefrom.
Portuguese resolution uses the two file-visible signals from §5.2 (BCP-47
region tags, then the track's own description) and falls back to
por-unverifiedrather than guessing. Track languages are normalised toISO-639-1 so they compare against TMDB's
original_language.select_featurepicks the feature out of a multi-file torrent: largest videofile, then a runtime check against TMDB's runtime at 15% tolerance. When
nothing matches it still returns the largest and marks the result
Mismatched, leaving the decision to import.Nothing returns a default-valued struct. Unreadable files, text files ffmpeg's
ttydemuxer happily reads as ANSI art, and files without a duration are allerrors.
Fixtures and CI
scripts/make-probe-fixtures.shregenerates the six committed clips (~120 KBtotal). The Dolby Vision pair splices a
dvcC/dvvCconfiguration box into areal HEVC clip — x265 refuses to encode DV without an RPU file, and profile 5
is the rule from §5.3 worth proving.
CI gains
ffmpegin its build deps soffprobeexists for those tests. TheNix dev shell already had it.
just ci: 80 tests, all passing.@@ -95,5 +95,5 @@policy,overrides,candidate,};let rules: [&dyn PolicyRule; 2] = [&ResolutionRule, &SourceRule];Removing
DubBlacklistRuleandRequiredAudioRuleleavesrequired_audio,dub_blacklist, and the title original language unexamined, so a pt-BR-only dub or download without original audio is eligible. Keep these rules and the original-language input in the built-in pipeline;arr-probeshould supply evidence, not remove enforcement.@@ -2,0 +140,4 @@let path = path.into();match self.probe(path.clone()).await {Ok(file) => candidates.push(file),Err(error) => {select_featureswallowsSpawn,Timeout,Io, andDecodeand returnsNoCandidates, hiding a broken or unavailable prober even when valid media exists. Skip only per-file content failures and propagate probe/runtime failures.@@ -0,0 +50,4 @@let video = output.streams.iter().find(|stream| stream.is_kind("video"))An audio file with embedded cover art has an
attached_picvideo stream, so this selects it as importable video. Deserializedisposition.attached_picand choose only a non-attached video stream.Two fixed in
4e88041, one I think is about a different change.This branch does not touch
arr-core.git diff --stat origin/main...HEADlists onlyarr-probe,scripts/,.gitea/workflows/ci.ymlandCargo.lock;DubBlacklistRuleandRequiredAudioRuleare as they were on main. Audio enforcement is a separate issue andarr-probeonly supplies the evidence for it.Fixed.
Error::is_about_the_filenow splits per-file content failures (Rejected,NotVideo,NoVideoStream,NoDuration) from prober failures (Spawn,Timeout,Io,Decode); only the first kind is skipped, the rest propagate. Test:a_broken_prober_fails_the_selection.Fixed. The video stream is now chosen with
disposition.attached_pic == 0, so an audio file with embedded artwork isNoVideoStreamrather than importable video. New fixtureaudio-with-cover.m4aand testan_audio_file_with_artwork_is_not_video.Reviewed
4e880413ae3f2280f2ba2456b50eb42ea97061f7. No new findings; the audio-policy finding in review 55 remains unresolved.The audio-policy finding was my branch being behind main, not a removal. #57 merged
DubBlacklistRuleandRequiredAudioRulewhile this PR was open; main is now merged in (14fa9e4) and both rules are in the pipeline untouched.That merge also made this branch's own Portuguese detection a second copy of
arr-core::lang, so60f7ddddeletes it:arr-probenow callsresolve_portuguesewith the two signals a file carries — the streamtitle/handler_namestrings and the container BCP-47 tag — and leaves signal 1, release-name markers, to the release.just cigreen on60f7ddd: 111 tests.Reviewed
60f7ddda2acf55309578e6f51be7753fe29c53f8. No findings.