Add TVmaze as a second, user-selectable TV metadata source for Fetch Data

TV episodes can now resolve against either TMDB (default) or TVmaze - picked
via a segmented source picker in the renamed "Fetch Data Settings" modal.
TVmaze is free and needs no API token at all; movies still always resolve
against TMDB regardless of the choice, since TVmaze has no movie catalog.

- New TvmazeClient (crates/aurora-curator-core/src/web/tvmaze.rs): search +
  season/episode lookup against api.tvmaze.com, filtering out unnumbered
  specials rather than panicking on them (TVmaze returns every season's
  episodes in one flat list, unlike TMDB's per-season endpoint).
- New TvMetadataSource setting (settings.rs), persisted alongside the TMDB
  token, defaulting to Tmdb for schema-evolution safety.
- metadata.rs now branches TV fetches through an AnyTvClient wrapper so the
  existing per-(series, season) caching loop doesn't care which source
  produced a result; the movie-fetch path is untouched.
- Frontend: TMDB/TVmaze picker in Fetch Data Settings, persisted on change;
  Fetch Data's token gating now only requires a TMDB token when it's actually
  needed (movies always, TV only when TMDB is the chosen source) instead of
  unconditionally blocking on it.

cargo test --workspace: 88/88 passing (81 + 7 new TVmaze + 3 new settings).
npm run build passing. Playwright verification: 18/18 checks (picker renders
and persists across reload, TV Fetch Data succeeds on TVmaze with zero TMDB
token configured, movies still correctly demand a token even with TVmaze
selected, switching back to TMDB still works end-to-end).
This commit is contained in:
Renamr Scaffold
2026-08-29 10:44:12 +00:00
parent 7097b1ede7
commit 5763c6313b
7 changed files with 729 additions and 96 deletions
+57 -31
View File
@@ -6,10 +6,13 @@ fork), built from scratch as its own project: new stack, new architecture, new b
**Status: early scaffold, but the core loop works end to end.** The naming-expression
engine is ported and tested, the faithfully-recreated two-pane UI is wired to real
native file/folder loading and drag-and-drop, local filename-based season/episode *and
movie title/year* detection ("Match") is working, real online metadata lookups against
TMDB ("Fetch Data") are working for both TV episodes and movies — including fuzzy
title disambiguation, so a search that returns several similarly-named results doesn't
just take TMDB's top-ranked hit — and the actual on-disk operation is wired up (with a
movie title/year* detection ("Match") is working, real online metadata lookups
("Fetch Data") are working for both TV episodes and movies — including fuzzy title
disambiguation, so a search that returns several similarly-named results doesn't just
take the source's top-ranked hit. TV episodes can resolve against either TMDB or
TVmaze — user-selectable in Fetch Data Settings, TMDB stays the default and TVmaze
needs no API token at all — while movies always resolve against TMDB, since TVmaze has
no movie catalog. The actual on-disk operation is wired up (with a
confirmation step showing the full old-path/new-path plan before anything touches disk,
a per-row ✕ to drop an individual file from that plan at the last step, a Move/Copy/
Symlink selector for what to actually do at each target, and — independently — a Skip/
@@ -129,38 +132,43 @@ crates/aurora-curator-core/ Pure Rust core: naming-expression engine (ported),
the same module (`guess_release_info` — resolution, source, video/
audio codec, release group), text-similarity scoring for
disambiguating search results (`similarity/`, partial
`EpisodeMetrics` port), a TMDB metadata client (`web/tmdb.rs` — TV
search + episode lookup
and movie search + lookup, both disambiguated via `similarity/`,
tested against a mocked HTTP server via `mockito`), the on-disk
`EpisodeMetrics` port), two web metadata clients — `web/tmdb.rs`
(TV search + episode lookup and movie search + lookup) and
`web/tvmaze.rs` (TV search + episode lookup only — TVmaze has no
movie catalog, and no API key/auth at all), both disambiguated via
`similarity/` and tested against a mocked HTTP server via
`mockito`, the on-disk
rename engine (`rename/` — Move/Copy/Symlink actions,
Skip/Auto-number/Override conflict policies, can also organize
into (auto-created) subfolders when
the naming scheme includes `/`) — and a rename history/undo log
(`history/`, a partial `HistoryDialog` port, undo-aware of which
action produced each batch). Not yet ported: full media metadata
bindings, other web datasource clients (TVDB/AniDB/etc).
bindings, other web datasource clients (TheTVDB/AniDB/OMDb/etc).
No Tauri dependency, so it builds and unit-tests standalone.
src-tauri/ Tauri app shell: exposes aurora-curator-core as commands to the frontend
(naming-scheme rendering, filename matching for both TV and
movies, TMDB metadata fetch — `metadata.rs` for TV episodes,
plus a movie-fetch command alongside it — executing a rename
movies, metadata fetch — `metadata.rs` for TV episodes (against
whichever of TMDB/TVmaze is the stored source) plus a
movie-fetch command alongside it (always TMDB) — executing a rename
plan, native file/folder dialogs, drag-and-drop expansion), plus
`settings.rs` (TMDB token), `history.rs` (rename history/undo
`settings.rs` (TMDB token, and which TV metadata source Fetch Data
uses), `history.rs` (rename history/undo
log), and `presets.rs` (up to 9 saved naming schemes) — all three
stored as JSON in the OS app-config directory — app
metadata/icons/window config (tauri.conf.json).
src/ React + TypeScript UI (Vite). Faithful recreation of the original
two-pane rename screen (Aurora theme) wired to real file loading,
drag-and-drop, live naming-scheme preview, local TV/movie
matching, TMDB fetch for both (behind a Settings modal for the
API token), a confirm-before-touching-disk modal for the actual
matching, metadata fetch for both (behind a Fetch Data Settings
modal holding the TMDB/TVmaze source picker and the API token), a
confirm-before-touching-disk modal for the actual
rename, a History panel that can undo a past rename, Align Up/Down
list reordering, and a Presets panel (plus `1`-`9` hotkeys) for
saved naming schemes.
scripts/gen_icons.py Regenerates src-tauri/icons/ (placeholder branding — swap the
colors/glyph in the script, or replace the icons directly, to
change the look).
scripts/gen_icons.py Regenerates src-tauri/icons/ from the real logo mark
(`scripts/logo/icon-source.png`, cropped from the supplied
lockup) — replace that source image to change the look.
```
## Building
@@ -183,24 +191,35 @@ npm run tauri build
```
Verified in the environment this was built in: `cargo test -p aurora-curator-core` (all
passing, including the TMDB client tests — those run against a local mock HTTP server
via `mockito`, no live network or API key needed to build/test), `cargo check -p
passing, including the TMDB and TVmaze client tests — those run against a local mock
HTTP server via `mockito`, no live network or API key needed to build/test), `cargo check -p
aurora-curator` (compiles clean against real Tauri + GTK/WebKit system libraries), and `npm run
build` (TypeScript type-checks, Vite bundles). The actual GUI window has **not** been
visually verified anywhere yet — that sandbox has no display. Run `npm run tauri dev`
on your machine to see and click through it for the first time.
### Setting up TMDB (for "Fetch Data")
### Setting up metadata sources (for "Fetch Data")
Everything else in the app works fully offline; "Fetch Data" is the one feature that
needs a (free) [TMDB](https://www.themoviedb.org/) account:
talks to the network, and it's the only one that needs any setup at all — and even that
setup is optional for TV.
1. Create a TMDB account, then go to Settings → API in your account and generate an
**API Read Access Token** (not the older numeric "API Key" — Aurora Curator uses the Bearer
token method TMDB documents as the default).
2. In the app, click the key icon ("TMDB Settings") next to Fetch Data and paste the
token in. It's saved locally in the OS app-config directory and only ever sent to
`api.themoviedb.org`.
TV episodes can resolve against either of two sources, picked in the app (click the key
icon, "Fetch Data Settings", next to Fetch Data):
- **[TVmaze](https://www.tvmaze.com/)** — free, no account or API token needed at all.
Just pick it and go.
- **[TMDB](https://www.themoviedb.org/)** — the default, and the only option for movies
(TVmaze has no movie catalog). Needs a free account:
1. Create a TMDB account, then go to Settings → API in your account and generate an
**API Read Access Token** (not the older numeric "API Key" — Aurora Curator uses the
Bearer token method TMDB documents as the default).
2. In the app, open "Fetch Data Settings" and paste the token in. It's saved locally
in the OS app-config directory and only ever sent to `api.themoviedb.org`.
A batch of TV-only files can run entirely on TVmaze with no token configured at all; a
batch containing any movies still needs the TMDB token regardless of which TV source is
selected.
## Porting roadmap (not yet done)
@@ -240,13 +259,20 @@ ported from, for anyone picking this up:
4. **Media detection** — `net.filebot.media.MediaDetection` (1356 lines): ties file-name
parsing + matching together to auto-identify what a file is.
5. **Web datasource clients** — `net.filebot.web.*` (~40 files): TheMovieDB, TheTVDB,
AniDB, OMDb, TVmaze, OpenSubtitles, etc. TMDB is done for both TV and movies
AniDB, OMDb, TVmaze, OpenSubtitles, etc. Two are done: TMDB, for both TV and movies
(`crates/aurora-curator-core/src/web/tmdb.rs`, `reqwest` + `serde_json`, Bearer-token auth) —
search-by-name plus per-season episode lookup for TV, search-by-title (optionally
narrowed by release year via TMDB's own `primary_release_year` filter) for movies —
both wired to "Fetch Data", disambiguating multi-result searches via the
similarity-scoring pass described in item 3 above rather than blindly trusting
TMDB's top-ranked hit. All other sources (TheTVDB, AniDB, OMDb, TVmaze,
and TVmaze, for TV only (`crates/aurora-curator-core/src/web/tvmaze.rs`, same `reqwest` +
`serde_json` shape, no auth at all — TVmaze has no movie catalog to search, and its
per-show episode endpoint returns every season in one flat list rather than TMDB's
per-season lookup, so the client fetches once and filters locally, skipping any
unnumbered/special episodes rather than panicking on them). Both are wired to "Fetch
Data" — a user-selectable "TV episode source" picker in Fetch Data Settings chooses
which of the two a batch's TV items resolve against (TMDB stays the default; movies
always use TMDB regardless of that picker) — disambiguating multi-result searches via
the similarity-scoring pass described in item 3 above rather than blindly trusting
either source's top-ranked hit. All other sources (TheTVDB, AniDB, OMDb,
OpenSubtitles) are not yet started.
6. **Rename engine + CLI** — `net.filebot.cli.CmdlineOperations` (1235 lines) and
`ArgumentBean` (415 lines, the full flag surface: `-rename`, `--db`, `--format`,