* 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.
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>
The platforms advertise stop, skip forward/backward, and playback-rate
commands by default, but both the music and video handlers silently
dropped them (Android Auto/Bluetooth stop and FF/rewind did nothing;
iOS/macOS showed a dead rate control). setControlsEnabled now manages
those controls: music handles Stop and in-track skips and stops
advertising a speed control; video handles Stop (exit, matching the
companion remote), skips via a shared relative-seek helper, and rate
changes through player.setRate. Skip commands stay off on iOS/macOS
where they would displace the next/previous lock-screen buttons.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Shared TabChipStrip replaces the plain Rows in libraries/downloads/live
TV app bars (and live TV's hand-rolled scroll wrapper); chips center
themselves on focus so d-pad reaches off-screen tabs.
Queue sheet/panel now renders the whole playback order — dimmed played
tracks above the current one — instead of only up-next. Opens scrolled
to the current track and follows advancement while parked on it.
Wide layouts put the circular portrait beside a left-aligned
name/genre/bio/actions block (mirroring the album header) instead of
a centered mobile column floating over the left-hugging albums grid.
Album/artist downloads expand to tracks with pinned parent metadata,
aggregate progress, container deletes with reference-counted album
covers, and a Music tab on the downloads screen with fully offline
album playback. Home rows include music libraries (fixes plex hub
items being filtered to video types) and audio playlists join
download/sync rules.
Audio-only mpv core on every platform (dedicated
com.plezy/mpv_audio_player channels): parameterized android/windows/
linux mpv plugins and a new apple MpvAudioPlayerCore, all skipping
video/window paths (vid=no, audio-display=no, gapless-audio=weak).
MusicPlaybackService drives an in-memory queue with shuffle/repeat,
file-loaded-event gapless arming (property edges coalesce and the
android bridge drops them), per-track progress reporting, OS media
controls, audio focus, sleep timer, and error auto-skip.
PlaybackCoordinator enforces one live native player: starting video
disposes the audio core first.
Un-gates music libraries; adds CardShape.square plumbing (circular
artists), artists/albums/tracks browse groupings with per-grouping
sorts, audio playlists tab, artist + album detail screens with dpad
track rows, music context-menu actions, and a stub MusicPlaybackService
seam for the upcoming engine.
_ensureFallbackOnDeckEpisode is reached through unawaited fetch
continuations and reads providers through State.context — leaving the
screen before the season fetch settled crashed on the null-check in
the context getter.
Visited seasons' 200-item pages were retained for the screen's
lifetime — irrelevant for a 3-season show, tens of MB of Dart heap for
a 30-season one. Low-end TV now keeps the prefetch window (selected
season plus/minus one); evicted seasons transparently refetch through the
existing unloaded-hub path.
Ref #1349