Skip to content

Fix slow series scans + per-episode prompting; add tests, CI, and perf optimizations - #1

Merged
salvadordea merged 4 commits into
masterfrom
claude/determined-pascal-214hgc
Jun 14, 2026
Merged

salvadordea merged 4 commits into
masterfrom
claude/determined-pascal-214hgc

Conversation

@salvadordea

Copy link
Copy Markdown
Owner

Summary

Fixes the two reported bugs (slow/"frozen" scans and per-episode prompting), adds the project's first automated test suite + CI, lands five scan-performance optimizations, and validates the PyInstaller packaging.

Bug fixes

  • Slow series scans: episode metadata was fetched one HTTP request per episode. Added TMDBClient.get_season_details() to fetch a whole season in a single /tv/{id}/season/{n} request, reusing the per-episode cache so repeat scans skip the network entirely.
  • Asked per episode instead of inferring the season: the batch group key was derived from the raw filename and split a series into multiple prompts when filenames were inconsistent (year / 1080p before SxxExx). Now groups by the parser's cleaned title_guess; movies keep their year so remakes are not merged.
  • Language-aware episode cache: the episode cache key did not include the language, returning stale-language titles after switching the episode-title language. The key is now namespaced by the effective language.

Performance

  1. Progressive results — phases 2/3 interleaved per group; the table fills in incrementally instead of staying empty until the whole folder resolves.
  2. Parallel episode prefetch — missing seasons fetched concurrently (bounded pool); ~6x faster on a 6-season series in a latency-simulated benchmark. Rate limiter and cache are now thread-safe.
  3. Lower rate-limit spacing (0.25s → 0.05s).
  4. Batched cache writes — one disk write per scan instead of per lookup.
  5. Duplicate finder — name-matched groups use the cheap quick hash instead of reading whole files; hashing switched from MD5 to BLAKE2b.

Testing & build

  • tests/: first pytest suite (35 tests) covering parser, formatter (incl. filename-safety / path-traversal), cache, TMDB client (mocked), detection state machine, the bug fixes, and a headless GUI smoke test. Network is never hit.
  • .github/workflows/ci.yml: pytest + coverage on Python 3.10–3.12, Qt headless.
  • .github/workflows/build-windows.yml: builds dist/RNMR.exe on windows-latest and uploads it as an artifact (PyInstaller cannot cross-compile).
  • MainWindow(skip_setup=...) so headless runs don't block on the first-run wizard.
  • app.spec: exclude cryptography (unused by RNMR; shrinks the bundle). Packaging verified end-to-end.

https://claude.ai/code/session_01C2HyuCwrqW2iK6D3AQDmBL


Generated by Claude Code

claude added 4 commits June 14, 2026 08:06
Bug 1 (scans hang / take forever on series): episode metadata was
fetched one HTTP request per episode. For a full season/series this
meant dozens or hundreds of serial rate-limited calls, and the results
table only populated after ALL of them finished -- so the UI looked
frozen. Add TMDBClient.get_season_details() to fetch a whole season in
a single /tv/{id}/season/{n} request and reuse the per-episode cache so
repeat scans skip the network entirely.

Bug 2 (asks per episode instead of inferring the season): the batch
group key was derived from the raw filename and only stripped text from
the episode pattern onward. Inconsistent filenames (some with a year or
1080p tag before SxxExx, some without) produced different keys and split
one series into several groups -> multiple identity prompts. Group by the
parser's already-cleaned title_guess instead; movies keep their year so
remakes are not merged.
Implements the QA follow-up actions:

- tests/: pytest suite (parser, formatter incl. filename-safety, cache,
  TMDB client with mocked network, detection state machine, the two scan
  bug fixes, and a headless GUI smoke test). 31 tests, network never hit.
- .github/workflows/ci.yml: runs pytest with coverage on Python
  3.10-3.12, Qt headless (offscreen) with a dummy key.
- pyproject.toml: pytest + coverage configuration.
- requirements-dev.txt: pytest / pytest-cov.

Fixes BUG-03 (language-aware episode cache): the episode cache key did
not include the language, so changing the episode-title language returned
stale titles for already-cached episodes. The key is now namespaced by
the effective language; legacy entries simply miss and re-fetch once.

Adds MainWindow(skip_setup=...) so automated/headless runs can construct
the window without the first-run setup wizard's blocking modal.
…aster dup hashing

Five scan-performance improvements:

1. Progressive results: phases 2 and 3 are now interleaved per title
   group. Each group's files are formatted and emitted as soon as that
   group is identified, so the table fills in incrementally instead of
   staying empty until the whole folder is resolved.

2. Parallel episode prefetch: missing seasons are fetched concurrently
   (bounded thread pool) so their network latencies overlap. ~6x faster
   on a 6-season series in a latency-simulated benchmark. The TMDB client
   rate limiter and the cache are now thread-safe.

3. Lower rate-limit spacing (0.25s -> 0.05s). TMDB tolerates it and still
   returns 429 + Retry-After, which is already handled.

4. Batched cache writes: a whole scan now writes the cache file once
   (begin_batch/end_batch) instead of once per lookup.

5. Duplicate finder: name-matched groups use the cheap quick hash instead
   of reading entire files (the hash there is only informational), and
   hashing switched from MD5 to the faster BLAKE2b.

Adds tests for batched cache writes, language-aware cache, progressive
grouped emission, and the duplicate-hash behavior (35 tests total).
- app.spec: exclude 'cryptography' from the bundle. RNMR has no
  cryptography features (HTTPS to TMDB uses the stdlib ssl module), so it
  was only ever pulled in transitively; excluding it shrinks the bundle
  and avoids an unrelated dependency. Verified the spec builds and the
  frozen app launches (validated on Linux; the binary starts the Qt event
  loop without errors).

- .github/workflows/build-windows.yml: build dist/RNMR.exe with
  PyInstaller on windows-latest and upload it as an artifact. PyInstaller
  cannot cross-compile, so the real Windows .exe must be produced on a
  Windows runner; this makes that reproducible on tags or manual dispatch.
@salvadordea
salvadordea merged commit 09bf18e into master Jun 14, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants