- 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
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.
ExoPlayerCore emitLog() forwards native diagnostics (init, tracks,
tunneling, watchdog, errors, framerate, audio focus) to Dart via the
existing log-message event when debug logging is enabled. URIs are
redacted before forwarding. setLogLevel method channel wires into the
existing debug toggle in video_player_screen.
Logs screen now shows a device info header (app version, OS, model,
TV mode) and includes it in copy/upload output.
Adds a user-facing toggle for MediaCodec tunneling (Android/ExoPlayer)
and a rendered-frame watchdog that auto-falls back to MPV when ExoPlayer
produces 0 video frames after 8 seconds of audio playback.