- Extract track lifecycle logic from VideoPlayerScreen (3248→2928 lines) into TrackManager
- Parse isDefault/isForced for subtitle tracks in parseTrackList
- Emit forced flag from ExoPlayer's emitTrackList
- Fix detectSubtitleMimeType failing on URLs with query params
- Add missing external_ ID prefix in ExoPlayer addSubtitleTrack
- Replace polling loop with stream in selectAndApplyTracks
- Handle play() failure in resumeAfterSubtitleLoad
- Handle addExternalSubtitles failure in onBackendSwitched
Synchronously null surface fields in dispose() before deferred view
removal, add session generation counter to cancel stale MPV fallbacks,
and use postAtFrontOfQueue for defense-in-depth message ordering.
- Lower OkHttp readTimeout from 30s to 10s so stalled Range requests retry faster
- Reduce bufferForPlaybackMs from 2500 to 1000 for quicker playback start
- Add HTTP transfer timing logs (TTFB, bytes, duration) to diagnose startup delays
- ExoPlayerPlugin: move all MPV JNI calls off main thread via runOnExecutor
- WatchNextPlugin: run ContentProvider ops on IO executor with error handling
- MpvPlayerCore: guard executor methods against dispose race (RejectedExecutionException)
- MainActivity: fix PiP null engine NPE with safe flutterEngine?.let
Catch COMMAND_FAILED/NOT_INITIALIZED in PlayerNative.seek() and
PlayerAndroid.seek() directly, preventing unhandled PlatformException
crashes on macOS app resume. Remove the ~200-line
_PendingSeekCoordinator system and revert all callsites to direct
player.seek(clampSeekPosition(...)). Keep seekable property/stream
and media controls gating. Add ExoPlayer seekable emission.
Scale raw AudioTrack position by playback speed to convert from real
time to media time. Captures reference points on speed changes for
correct mid-playback transitions.