Skip to content

Refactoring review fixes: DB off the async runtime, typed kinds, module splits - #12

Merged
df49b9cd merged 1 commit into
mainfrom
refactor/review-fixes
Nov 4, 2026
Merged

df49b9cd merged 1 commit into
mainfrom
refactor/review-fixes

Conversation

@df49b9cd

@df49b9cd df49b9cd commented Nov 4, 2026

Copy link
Copy Markdown
Owner

Fixes every finding from the whole-repo refactoring review (31 smells across backend, frontend, build and tests).

Backend

  • DB locks off the async runtime. Async Tauri commands used to take the parking_lot database locks directly on tokio workers, and the writer is held for a whole catalog sync, so e.g. a favorite toggle during a sync blocked a runtime worker. They now go through read_blocking / write_blocking (state.rs), which also replaces seven copy-pasted spawn_blocking(...).map_err(...) tails. This covers tmdb.rs, secrets.rs and sources, which held locks across .await.
  • Typed kinds. kind.rs adds ItemKind / WorkKind / PlayKind (serde lowercase, ToSql / FromSql). They replace about 87 string literals and tmdb::Kind. Unknown kinds are now rejected at the IPC boundary (unknown variant 'bogus') instead of silently picking the wrong table.
  • Module splits.
    • catalog.rs (2,820 lines) is now catalog/{categories,channels,works,details,guide,search}.
    • sources/, works/ and cast/ move their code into leaf modules.
    • The movie and series detail commands share one work_context setup.
  • Smaller fixes.
    • probe.rs statics become a managed Probe.
    • playback::resolve uses a named ItemRow and has unit tests.
    • XtreamLists has named fields.
    • Error::TmdbRejected replaces matching on the error message.
    • write_m3u propagates a failed category insert instead of dropping it.
  • unsafe / FFI.
    • Every unsafe block has a // SAFETY: comment, and Mpv's Sync is documented separately.
    • Linux and macOS share player/render.rs, and the mpv_sys imports are explicit.
    • The player commands return the crate Result with the same message strings.
    • No unchecked Instant subtraction; named timeouts; expect() with the invariant instead of bare unwrap().
  • check.sh now runs cargo fmt --check and denies clippy::undocumented_unsafe_blocks.

Frontend

  • vitest only runs src/. It had also been running stale suite copies under .deps/, reporting 209 tests when only 46 were real.
  • The Player page's hooks move into pages/player/ with a key-binding table; I checked it key for key against the old if/else chain. The zap and next-episode logic is now pure functions with tests.
  • One useChannelEpg hook. Player and Live used the same cache key for different time windows (+6 h vs +12 h).
  • playerWrite replaces the .catch(() => {}) calls and covers player writes that had no catch at all.
  • writeSetting rolls back on failure; settings are typed; MAX_VOLUME_* constants.
  • Shared storage, item and route helpers; dead exports removed; the app version comes from package.json; the zustand store is reset between tests.

Behavior changes

  • The volume slider now goes to 150, matching the keyboard and mpv's volume-max; it stopped at 130 before.
  • Volume, mute and subtitle messages appear only when the change actually took effect.
  • A failed write on the Settings page resets the control and shows an error.

Testing

  • scripts/check.sh passes: fmt, clippy -D warnings plus the unsafe lint, 92 Rust tests (2 ignored), tsc, 65 vitest tests, third-party notices.
  • Headless app (scripts/headless.sh) with a local M3U playlist:
    • Sync, categories, series grouping, search, favorites, history and continue-watching, and both detail pages work.
    • play resolves and starts mpv, and the version check fails cleanly on a dead URL.
    • Invalid kinds and non-http player_load URLs are rejected.
  • Not verified:
    • The macOS player code was not compiled locally (Linux host), so CI's macOS job is its first build.
    • scripts/smoke.sh against the real provider did not run, because .env.local with the test-account credentials was missing.

…le splits

Backend
- Async commands reach SQLite through read_blocking/write_blocking
  (state.rs): the database locks are plain mutexes and the writer is held
  for a whole catalog sync, so locking on the runtime stalled its workers.
- kind.rs: ItemKind/WorkKind/PlayKind replace the "live"/"movie"/
  "series"/"episode" strings (and tmdb::Kind); Tauri rejects unknown
  kinds at the IPC boundary.
- Split catalog.rs into catalog/{categories,channels,works,details,guide,
  search}; sources/, works/ and cast/ get leaf modules for commands,
  sync, store, grouping, channels, discovery and session. Shared
  movie/series detail prelude (work_context).
- probe.rs statics become a managed Probe; playback::resolve uses a named
  ItemRow and gets unit tests; XtreamLists has named fields.
- Error::TmdbRejected instead of matching the error message; write_m3u
  propagates a failed category insert.
- SAFETY comments on every unsafe block; linux/macos share
  player/render.rs; explicit mpv_sys imports; player commands return the
  crate Result; no unchecked Instant subtraction; named timeouts; expect()
  with the invariant instead of bare unwrap().
- Cast TLS verifier documents why it accepts any certificate; fixed two
  spliced comment pairs (lib.rs, works/mod.rs).
- check.sh runs cargo fmt --check and denies undocumented unsafe blocks.

Frontend
- vitest only runs src/ (it also picked up stale copies under .deps/).
- Player page split into pages/player/ hooks and a key-binding table;
  pure zap/next-episode logic with tests.
- One useChannelEpg hook (Player and Live shared a cache key with
  different windows); playerWrite instead of swallowed errors;
  writeSetting with rollback; typed Settings; MAX_VOLUME constants.
- Shared storage/item/routes helpers; dead exports removed; app version
  from package.json; store reset between tests.
@df49b9cd
df49b9cd merged commit efcaaab into main Nov 4, 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.

1 participant