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.
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.
The decode clamp was height-only, so ultra-wide originals could decode
far past the display budget, and two small-slot fallbacks skipped
server-side resizing entirely — handing multi-megapixel originals to
the decoder behind tiny slots. The TV spotlight background's offline
branch had no decode bound at all. All artwork now flows through a
shared both-axes bound (ResizeImagePolicy.fit: aspect-preserving,
scale-down only), and the reduced tier gets matching thumb/poster
decode caps.
Ref #1349
Initialize TvDetectionService on every platform so the existing
force_tv_mode setting drives the 10-foot TV interface on Windows,
macOS, and Linux, and surface the toggle in appearance settings there.
Desktop keeps real-mouse behavior in TV mode: InputModeTracker still
flips between pointer and keyboard modes (cursor hidden while
keyboard-driven), segmented controls keep their hover affordance, and
the settings backup section stays available (only Android TV lacks a
document picker).
Adds PlatformDetector.debugSetIsDesktopOSOverride so TV-device
simulations in widget tests don't inherit the desktop test host's
platform.
close#1409
Around July 3 plex.tv started returning the profile language-list fields
(defaultAudioLanguages, defaultSubtitleLanguages, mediaReviewsLanguages)
as comma-separated strings instead of arrays. The generated cast threw on
the successful 201 /switch response, dropping the freshly minted Home
user token: every rebind failed, the binder retried a /switch mint every
1-2s, and the app sat permanently in offline mode even after re-signing
in. Accounts without language prefs set were unaffected, which is why
the breakage looked sporadic.
Parse the language lists with a CSV-aware coercion, and make
UserSwitchResponse.fromJson strict only about authToken: decorative
fields now coerce tolerantly and a broken profile blob falls back to
defaults, so account-API drift can never brick token minting again.
close#1488
Resolve platform, hardware model, and friendly device name once via a
shared DeviceIdentityService and send them to both backends: Plex gets
a real X-Plex-Platform plus X-Plex-Device/X-Plex-Device-Name (shown as
Player in dashboards/Tautulli), Jellyfin gets the device name in the
MediaBrowser auth header. Transcode and live-TV decision requests keep
their pinned platform names, which Plex validates server-side.
close#1270
FFmpeg's protocol lookup is case-sensitive, so a stored "Https://" base
URL reaches mpv verbatim through the direct-play string concat and fails
with "Protocol not found" (API calls survive because Dart's Uri
lowercases the scheme). Canonicalize at Jellyfin URL intake and in the
connection constructor so persisted configs self-heal on load, and
register mpv-escaped (https\://) redaction variants so option-value
logs stop leaking the server host.
close#1465
Plain Play requests the default media version (index 0 or the saved
preference), but the offline resolvers rejected the single downloaded
row when a non-default version was downloaded, then threw "No video
URL available" with no client to fall back to.
Three-part fix sharing one matcher (downloadedVersionMatches):
- getPlaybackData falls back to the downloaded version when there is no
client to stream from; the result now carries the effective
mediaIndex/mediaSourceId so cached media info and the committed
session describe the file actually played.
- navigateToVideoPlayer seeds the selection from the download record
for isOffline plays with no explicit version, covering the external
player branch and offline-library plays with a reachable server.
- PlaybackSession.fromContext prefers the result source id over the
requested one, keeping in-player state in sync after a fallback.
Online pinning is untouched: with a live client an explicitly requested
non-downloaded version still streams from the server.
Re-enables Audio Passthrough on Apple TV against the MPVKit EAC3-JOC
AVPlayer sink (pin bump to v1.0.8 follows), adds an AVPlayer test
harness + diagnostics screen for #1300, and makes loudnorm yield while
passthrough is active (fixes a latent spdif conflict on desktop too).
Guest switch dispatch pre-marked its dedup key and fired-and-forgot, so
any failure (fetch error, reload busy with an auto-advance, navigation
race with the host exiting) silently stranded the guest on the old media.
A CurrentPlaybackDispatcher now marks a key handled only after the sink
reports success against the committed identity, with a serialized
in-flight slot, timeout, and generation reset; the reconciler re-offers
unattached media on every host heartbeat, making the heartbeat the retry
channel. Fetches that outlive their dispatch are re-validated against the
current snapshot so a stale switch can't override the live one.
hostExitedPlayer now rides the controller's ordered message queue with
host authentication instead of racing state handling in the provider.
The aired-order rework can sweep correctly-placed Specials into "download
next N"; this toggle lets users opt out. Shown only for whole shows
(reusing FocusableSwitchListTile via an optional toggle on the shared
option-picker dialog), remembered across opens via a BoolPref
(default on = unchanged behavior). Filters Specials at the single
collect choke point (_collectPlayable), with a guard so explicitly
downloading the Specials season still queues its episodes.
* fix(plex): show PGS subtitles when transcoding
Bitmap subtitles (PGS/VOBSUB) disappeared from the menu while transcoding on Plex, leaving only "Off". The MKV transcode already supports them, so embed them in the stream like text subs. Now they show up and can be turned on.
* fix(plex): give bitmap subtitle codecs the right sidecar extension
getSubtitleExtension fell back to .srt for vobsub, pgssub and dvb subs. Map them to .sub/.sup so it stays consistent with isImageSubtitleCodec and any sidecar URL or download uses the correct extension.
- start binder before navigating from auth, mark isBinding synchronously
- overlap plex.tv resource refresh with optimistic cached-metadata connect,
reconcile tokens/membership in background once it lands
- cached endpoint probe gets a head start on the race instead of serially
blocking it
- defer phase-1 HTTPS upgrade off the splash critical path
- per-server connect progress stream for incremental splash checkmarks
- startup timing instrumentation (bind/fetch/race/connect elapsedMs)
Adds context.withFreshWatchState/readFreshWatchState and sweeps the
remaining session-critical readers: context menu actions, folder tree
rows, discover hero, and TV spotlight minutes-left.
Cards consult the hierarchy-aware store so container marks flip episode
rows instantly and a stale per-episode patch can no longer shadow a newer
show/season mark; playback opens with the session-fresh resume offset.