- commands/player/timers.rs: sleep-timer + autoplay commands (8).
- commands/player/session.rs: media session get/dismiss commands (2).
- Make create_media_item and get_player_status pub(super) so the submodules can
reuse them. mod.rs shrinks from ~2720 to ~2229 lines; invoke_handler unchanged.
- Move commands/player.rs to commands/player/mod.rs (folder module).
- Extract the 5 self-contained remote-session control commands
(remote_play_on_session/send_command/session_seek/set_volume/toggle_mute)
into commands/player/remote.rs, re-exported via `pub use remote::*` so the
command names remain at commands::player::* and the invoke_handler is unchanged.
No behavior change; establishes the submodule split pattern for the oversized
command file.
Move the pure determine_video_seek_strategy function and its VideoSeekStrategy
enum (plus the 5 seek-strategy unit tests) out of the command layer into
player/seek.rs, where they belong and are testable without the Tauri State
harness. commands/player.rs now imports them from crate::player. No behavior
change.
Workstream A — poison-tolerant locking:
- Add utils/lock.rs with MutexSafe/RwLockSafe extension traits that recover a
poisoned std::sync lock instead of panicking, plus unit tests.
- Replace all 153 .lock().unwrap() and 4 .read()/.write().unwrap() production
sites with _safe variants across 14 files, eliminating the player
crash-cascade class. Tokio async mutexes are unchanged.
Workstream B — graceful backend init:
- create_player_backend no longer panics when MPV/ExoPlayer fail to initialize;
it falls back to NullBackend and emits a backend-init-failed event so the UI
can show "playback unavailable" instead of the app crashing. Fatal DB-setup
panics are kept.
Workstream F — doc reconciliation:
- Rewrite software-architecture.md's inaccurate "thin UI / ~800 lines" claims to
reflect reality (~20.5k non-test frontend) and document the events+polling
hybrid plus the new locking/backend-init behavior.