* fix(player): preserve volume when toggling mute
Muting now keeps the last volume level memorized. Unmuting restores that level, including amplified values allowed by the configured maximum.
* fix(player): preserve volume for companion remote mute
Route the companion remote through the shared mute transition so it no longer overwrites the persisted volume or restores to 100%. Also correct the Dartdoc formatting for the transition record fields.
Report the paused timeline every tick (~10s, matching official clients)
instead of every ~60s, and ping the Plex transcoder keepalive endpoint
alongside it while transcoding — PMS reaps idle transcode sessions that
timeline reports alone historically have not kept alive. Prevents the
transcode-variant of the #1520 stream death; the reporter's direct-play
case is covered by EOF classification and reconnect.
close#1520
Classify player EOF signals against the best-known duration: a mid-file
EOF means the stream died (transcode reaped or idle connection closed
during a long pause), not that the media ended — it must never mark the
item watched, prompt Play Next, or exit a movie. Recover with a bounded
in-place reload at the parked position; if the server is still refusing,
park on the old frame and rebuild the stream on user play/seek or when
the server-status monitor sees it come back online.
ffmpeg's reconnect gave up on the first HTTP-error response, so a PMS
answering 503 (startup maintenance) after an idle-pause disconnect
surfaced as a clean mid-file EOF instead of riding through the outage.
The old bool meant "attempt was current and handled", so callers could
not distinguish a real pre-open failure (old stream still loaded) from
success — the distinction the #1520 recovery needs.
close#1514
A query submitted from the companion remote now behaves like a submit
instead of focus-to-type: TvKeyboardController closes an already-open
OSK and lands focus on the input without reopening it, then the shared
handleSearchSubmit path runs the search and focuses the first result.
Also guard DebouncedMediaSearch against selection-only controller
notifications re-arming the debounce into a duplicate fetch.
Co-authored-by: l3gitpanda <12003346+l3gitpanda@users.noreply.github.com>
A paused-but-alive player keeps its MediaCodec decoders and tunneled
passthrough AudioTrack while Plezy sits in the background, which can
degrade playback in every other app on shared-pipeline TV SoCs until
force-stop. After a 30s grace on Android TV the player is stopped
(retaining session state); returning reloads in place, or re-tunes the
channel for live TV.
When the display/system sleeps with a video paused, the window server
stops completing CAMetalLayer presents and mpv's MoltenVK swapchain wedges,
pinning one core at 100% until the app exits. occlusionState does not
reliably change on display sleep, so observe NSWorkspace screensDidSleep/
Wake to hide the metal layer (and drop the playback activity) while dark,
restoring on wake with a forced redraw when paused to avoid a stale frame.
Pairs with MPVKit v1.0.10, which gates libmpv presentation on the layer's
hidden state (check_visible) so presents actually stop while hidden.
The non-mixing playback session was activated in didFinishLaunching,
so merely opening the app stopped other apps' audio. Keep the category
configuration; playback start activates the session.
close#1496
Bumps os_media_controls so the audio session is only activated on
playing-state pushes; paused/metadata pushes no longer re-interrupt
other apps' audio (which caused the 1-2 Hz play/pause loop).
Pulls edde746/media_controls@71b96f8: iOS/macOS guard async artwork
downloads against track changes (slow art no longer lands on the next
track) and clear stale artwork when a track has none.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
TrackRow compared bare ids (server-scoped rating keys), so a track on
another server with the same id lit up as currently playing. Compare
globalKey (serverId:id) like the rest of the queue engine.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
All timed presets shared one 'timed' bool, so arming any of 15/30/60
minutes checkmarked all three. The service now retains the armed
duration (sleepTimerDuration) and the menu marks the matching preset.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>