Wire real media probing into Filter and List panels
Extends the sixteenth delivery's container-header probing
(probe_media_files) beyond the Rename panel: Filter and List now run the
same batched probe alongside their existing local scan, using the same
override rule everywhere - a filename tag wins when present, otherwise a
real probed value fills in.
List: {width}/{height}/{fps}/{duration}/{file size} are now available in
naming-scheme-style expressions (no filename-tag equivalent exists), and a
probed {resolution}/{video codec}/{audio codec} fills in when the filename
didn't already carry that tag.
Filter: gained Resolution and Video codec chip rows (populated from the
same merged filename-tag-or-probed value, with an Unknown bucket for files
with neither) so a batch can be narrowed by either. Each result row's
subtitle now also shows the resolved resolution when one exists.
Verified via cargo check/test --workspace (unaffected, frontend-only
change) + npm run build (clean) + a 15-check Playwright script against
npm run dev covering both panels: filename-tag resolution winning over a
conflicting probed value, probed fields filling in for an otherwise-
unmatched file, the new Filter chip rows narrowing results correctly.
Updated README (status paragraph, Filter section, List section, Real
media-file probing section, roadmap item 1).
This commit is contained in:
@@ -64,7 +64,9 @@ file via a native Save dialog — this closes out the full original panel set (R
|
||||
Episodes/Subtitles/SFV/Filter/List); see "List" below. Real media-file probing (real
|
||||
resolution, frame rate, duration, and codecs read straight from a video file's own
|
||||
container header, not guessed from its filename) is wired into the Rename panel's
|
||||
"Match" step — see "Real media-file probing" below. The naming-expression engine's Rhai
|
||||
"Match" step, and now the Filter and List panels' own local scans too — Filter gained
|
||||
Resolution/Video codec filter chips from it, and List's expressions can reference the
|
||||
same probed fields — see "Real media-file probing" below. The naming-expression engine's Rhai
|
||||
scripting layer also gained a batch of FileBot-style string helpers — `.pad()`,
|
||||
`.sort_name()`/`.sort_initial()`, `.upper_initial()`/`.lower_initial()`, `.acronym()`,
|
||||
`.validate_file_name()`, `.space()`/`.space_with()`, `.colon()`/`.colon_with()` — callable
|
||||
@@ -500,21 +502,29 @@ write hex digests in uppercase and others in lowercase.
|
||||
|
||||
The Filter sidebar panel loads a batch of files (independent of whatever's loaded in the
|
||||
Rename panel) and narrows it down before you decide what to do with it elsewhere — copy
|
||||
the matching paths out, or just get a sense of what's actually in a folder. Unlike SFV,
|
||||
it adds no new Rust/Tauri code at all: it scans every loaded file with the exact same
|
||||
local, filename-only matchers "Match" uses (`guess_episode`/`guess_movie`/
|
||||
`guess_release_info`) and turns the results into filter criteria instead of a rename
|
||||
preview — no network calls, so scanning even a large batch is effectively instant.
|
||||
the matching paths out, or just get a sense of what's actually in a folder. It scans every
|
||||
loaded file with the exact same local, filename-only matchers "Match" uses
|
||||
(`guess_episode`/`guess_movie`/`guess_release_info`) and turns the results into filter
|
||||
criteria instead of a rename preview — no network calls, so scanning even a large batch is
|
||||
effectively instant. It also runs the same batched `probe_media_files` real container-header
|
||||
probe "Match" and List do (see "Real media-file probing" below), so a file's resolution/
|
||||
video codec can come from real probing even when nothing in its filename says so.
|
||||
|
||||
**Load Files…** loads and scans a batch in one step. Toggleable chips then appear for
|
||||
every **extension** actually present (e.g. MKV/MP4/TXT) and every **kind** Aurora Curator
|
||||
locally recognized (TV/Movies/Unmatched) — click a chip to exclude that group, click it
|
||||
again to bring it back. A **filename contains** field does a live, case-insensitive
|
||||
again to bring it back. **Resolution** and **Video codec** chip rows appear the same way
|
||||
whenever at least one loaded file actually has a value for either (a filename tag wins
|
||||
when present, otherwise a real probed value fills in — same override rule as everywhere
|
||||
else this delivery touches; files with neither fall into their own "Unknown" chip rather
|
||||
than being silently excluded). A **filename contains** field does a live, case-insensitive
|
||||
substring search, and a **season** field (shown only while the TV chip is enabled) narrows
|
||||
to a single season number, automatically excluding anything that isn't a TV episode in
|
||||
that season. The results list updates live with an "N of M files match" count, and
|
||||
**Copy File Paths** writes every currently-matching file's full path, one per line, to the
|
||||
clipboard.
|
||||
that season. Each result row's subtitle also shows a resolved resolution when one exists
|
||||
(e.g. `Unmatched · 480p` for a file Match couldn't identify as TV or a movie but still got
|
||||
a real probed resolution for). The results list updates live with an "N of M files match"
|
||||
count, and **Copy File Paths** writes every currently-matching file's full path, one per
|
||||
line, to the clipboard.
|
||||
|
||||
## List
|
||||
|
||||
@@ -530,26 +540,31 @@ native Save dialog and writes whatever text the frontend hands it to a `.txt` fi
|
||||
everything else (matching, and rendering each file's line) reuses commands that already
|
||||
existed.
|
||||
|
||||
**Load Files…** loads a batch and scans it locally, the same way Filter does. The
|
||||
**Format** field holds the expression rendered against each file — the exact same `{ }`
|
||||
syntax the naming scheme uses, run through the same `render_expression` command the
|
||||
Rename panel's live preview calls. `{name}`/`{ext}` always work (they're the file's own
|
||||
name/extension); `{show name}`/`{season number}`/`{episode number}`, `{movie name}`/
|
||||
`{year}`, and the release-tag fields (`{resolution}`/`{source}`/`{video codec}`/
|
||||
`{audio codec}`/`{release group}`) fill in once the local scan recognizes a file — there's
|
||||
no Fetch Data step here, List stays local-only like Filter. A file whose rendered line
|
||||
comes out empty (e.g. an expression that only references a field this particular file
|
||||
never matched) shows an "(empty)" placeholder rather than blocking the rest of the list,
|
||||
and the results header tracks "N of M lines rendered" live as the expression changes.
|
||||
**Copy List** copies every line, in file order, newline-joined, to the clipboard; **Export
|
||||
to File…** opens a native Save dialog (defaulted to `list.txt`) and writes the same text
|
||||
to disk.
|
||||
**Load Files…** loads a batch and scans it locally, the same way Filter does — including
|
||||
the same batched real container-header probe (see "Real media-file probing" below), so
|
||||
List's expressions get real probed values too, not just filename-tag ones. The **Format**
|
||||
field holds the expression rendered against each file — the exact same `{ }` syntax the
|
||||
naming scheme uses, run through the same `render_expression` command the Rename panel's
|
||||
live preview calls. `{name}`/`{ext}` always work (they're the file's own name/extension);
|
||||
`{show name}`/`{season number}`/`{episode number}`, `{movie name}`/`{year}`, and the
|
||||
release-tag fields (`{resolution}`/`{source}`/`{video codec}`/`{audio codec}`/`{release
|
||||
group}`) fill in once the local scan recognizes a file; `{width}`/`{height}`/`{fps}`/
|
||||
`{duration}`/`{file size}` come straight from real probing (no filename-tag equivalent
|
||||
exists), and a probed `{resolution}`/`{video codec}`/`{audio codec}` fills in whenever the
|
||||
filename didn't already carry that tag — there's no Fetch Data step here, List stays
|
||||
local-only like Filter. A file whose rendered line comes out empty (e.g. an expression
|
||||
that only references a field this particular file never matched) shows an "(empty)"
|
||||
placeholder rather than blocking the rest of the list, and the results header tracks
|
||||
"N of M lines rendered" live as the expression changes. **Copy List** copies every line, in
|
||||
file order, newline-joined, to the clipboard; **Export to File…** opens a native Save
|
||||
dialog (defaulted to `list.txt`) and writes the same text to disk.
|
||||
|
||||
## Real media-file probing
|
||||
|
||||
Unlike every panel above, this isn't a new sidebar screen — it's a naming-scheme
|
||||
binding source wired into the Rename panel's existing "Match" step, closing (part of)
|
||||
the gap the porting roadmap has called out since the beginning: FileBot's
|
||||
binding source wired into the Rename panel's "Match" step, the Filter panel's scan, and
|
||||
the List panel's scan alike, closing (part of) the gap the porting roadmap has called out
|
||||
since the beginning: FileBot's
|
||||
`MediaBindingBean` doesn't just parse tags out of a release name, it also reads a
|
||||
video file's own container header for its real resolution, frame rate, duration, and
|
||||
codecs — a naming scheme can reference those even when the filename itself doesn't
|
||||
@@ -562,19 +577,24 @@ values — probing is always a best-effort enrichment layered on top of filename
|
||||
matching, never a hard requirement, so an unsupported or corrupt file can't break
|
||||
Match.
|
||||
|
||||
Clicking **Match** now also probes every loaded file's real container header
|
||||
(`probe_media_files`, one batched Tauri round trip off the main thread) alongside the
|
||||
existing filename-based guessing. The result feeds the same bindings the release-tag
|
||||
parser already populates — `{resolution}`/`{vf}`, `{video codec}`/`{vc}`,
|
||||
`{audio codec}`/`{ac}` — but only when the filename itself didn't already carry that
|
||||
tag; an explicit release-group tag always wins over a probed value, since a release
|
||||
group's own tag is usually deliberate. Five bindings have no filename-tag equivalent
|
||||
at all, so they're only ever available this way: `{width}`, `{height}`, `{fps}`,
|
||||
`{duration}` (`h:mm:ss`, or `m:ss` under an hour), and `{file size}` (human-readable,
|
||||
e.g. `1.4 GB`) — all formatted once on the Rust side so the UI never reimplements that
|
||||
logic. The Match status line reports how many loaded files were actually probed
|
||||
(`"N probed from file"`), and the naming-scheme editor's field-reference list has a
|
||||
new "Real file probing" group listing all five.
|
||||
Clicking **Match** (Rename), or loading a batch into **Filter** or **List**, now also
|
||||
probes every loaded file's real container header (`probe_media_files`, one batched Tauri
|
||||
round trip off the main thread) alongside the existing filename-based guessing — all
|
||||
three panels call the exact same command the exact same way. The result feeds the same
|
||||
bindings the release-tag parser already populates — `{resolution}`/`{vf}`, `{video
|
||||
codec}`/`{vc}`, `{audio codec}`/`{ac}` — but only when the filename itself didn't already
|
||||
carry that tag; an explicit release-group tag always wins over a probed value, since a
|
||||
release group's own tag is usually deliberate. Five bindings have no filename-tag
|
||||
equivalent at all, so they're only ever available this way: `{width}`, `{height}`,
|
||||
`{fps}`, `{duration}` (`h:mm:ss`, or `m:ss` under an hour), and `{file size}`
|
||||
(human-readable, e.g. `1.4 GB`) — all formatted once on the Rust side so the UI never
|
||||
reimplements that logic. Rename's Match status line, List's scan status, and Filter's
|
||||
scan status all report how many loaded files were actually probed (`"N probed from
|
||||
file"`), the naming-scheme editor's field-reference list has a "Real file probing" group
|
||||
listing all five width/height/fps/duration/file-size bindings, and the Filter panel adds
|
||||
its own **Resolution**/**Video codec** chip rows (populated from the same merged
|
||||
filename-tag-or-probed value) so a batch can be narrowed by either, not just by
|
||||
extension/kind/name/season.
|
||||
|
||||
## Porting roadmap (not yet done)
|
||||
|
||||
@@ -591,11 +611,13 @@ ported from, for anyone picking this up:
|
||||
actually reading the file — real resolution/video codec/audio codec fill in
|
||||
whenever the filename didn't already carry that tag, plus `{width}`/`{height}`/
|
||||
`{fps}`/`{duration}`/`{file size}`, which have no filename-tag equivalent at all —
|
||||
for the two container families it supports (MP4/M4V/MOV and MKV/WebM). Still
|
||||
missing: probing for other containers (.avi, .wmv, ...), audio-only metadata
|
||||
(bitrate, sample rate, channel layout), file hashing (`{crc32}` reuses the SFV
|
||||
panel's own hasher today but isn't wired into naming-scheme bindings yet), and
|
||||
wiring probed bindings into the List/Filter panels (currently Rename-panel-only).
|
||||
for the two container families it supports (MP4/M4V/MOV and MKV/WebM). Probed
|
||||
bindings are now wired into all three panels that do local matching — Rename's
|
||||
Match step, and the Filter and List panels' own scans (Filter also gained
|
||||
Resolution/Video codec filter chips from it). Still missing: probing for other
|
||||
containers (.avi, .wmv, ...), audio-only metadata (bitrate, sample rate, channel
|
||||
layout), and file hashing (`{crc32}` reuses the SFV panel's own hasher today but
|
||||
isn't wired into naming-scheme bindings yet).
|
||||
2. **String/expression helper methods** — `net.filebot.format.ExpressionFormatMethods`
|
||||
(636 lines): FileBot-specific Groovy string extensions like `.pad()`, `.sortName()`.
|
||||
Ported so far (`crates/aurora-curator-core/src/format/functions.rs`): `any`, `all_of`,
|
||||
|
||||
Reference in New Issue
Block a user