Commit graph

472 commits

Author SHA1 Message Date
Ray
b78f5fcc77
Better support for remote media (HLS/DASH) (#675)
## Description
Check if playback is for a remote source and, if so, play that remote
URL directly. Works for both ExoPlayer & MPV.

Also adds support for direct playback for DASH in ExoPlayer.

### Related issues
Closes #471
Closes #666
2026-01-11 19:43:21 -05:00
Ray
75a98ddaa5
Minor UI changes (#673)
## Description
- Always update home page backdrop
- Use smaller font size for episode names & force single line
- Use smaller cards for episode cards on person page
2026-01-11 17:07:47 -05:00
Justin Caveda
19833a1a03
Add scrim behind season tabs for readability (#657)
## Description

Adds a dark gradient scrim behind the season tabs on the TV Show Details
screen to improve text readability against bright backdrop images. This
follows the same pattern used in PlaybackOverlay.kt for the playback
controls.

  The scrim uses two combined gradients:
  - Vertical: Dark at top (0.80α → 0.5α) fading to transparent at bottom
- Horizontal: Fades in from transparent (left) to full opacity (right),
starting at 15% screen width to avoid overlapping with the nav rail

The gradients are composited using BlendMode.DstIn to create a smooth 2D
fade effect.

### Related issues
Fixes #547

### Screenshots

<img width="1920" height="1084" alt="season_darkened_background"
src="https://github.com/user-attachments/assets/a85237e4-2812-433c-902b-36f9860448c5"
/>

### AI/LLM usage
AI used to draft PR description and documentation
2026-01-11 17:07:40 -05:00
Ray
2377a15611
Disable subtitle download button if user doesn't have permission (#671)
## Description
Just a UI change to disable the Search & Download subtitles button if
the user doesn't have permission to manage subtitles.

This avoids the 403 error if the user attempts to use it.

### Related issues
Closes #483
2026-01-11 13:21:02 -05:00
Justin Caveda
ed67e5575f
Add "Only Forced Subtitles" option to subtitle selection (#589)
## Description

Adds a client-side "Only Forced Subtitles" option when selecting
subtitles, per the discussion in #571.

  ### Changes

  - **TrackIndex.ONLY_FORCED** (`-3`): New constant for the special case
- **StreamChoiceService**: Intercepts `ONLY_FORCED` at the top of
`chooseSubtitleStream()` before server-side `SubtitlePlaybackMode` logic
(which remains untouched)
  - **UI**: Adds "Only Forced Subtitles" option to both:
    - In-player subtitle menu (`PlaybackDialog.kt`)
    - Pre-playback stream selection dialog (`Dialogs.kt`)

  ### Forced track detection

Uses metadata `isForced` flag as primary check, with title-based
fallback ("forced", "signs", "songs" patterns) when language matches
audio.

  ### Related issues

  Closes #571

  ### Screenshots

  N/A - subtitle selection menu only

  ### AI/LLM usage

  Used Claude Code for assistance and to draft PR description.

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Damontecres <damontecres@gmail.com>
2026-01-11 13:11:39 -05:00
Ray
8bdc8a6f8f
Consistent audio/subtitle info across dialogs (#664)
## Description
Makes the labels for audio & subtitle stream consistent across the app

The More->Choose dialogs now highlight which track is currently choosen.

Also uses more of the brand names for audio codecs (eg DD+) and allows
for these to be translated into other languages.

### Related issues
Closes #621 
Fixes #668
Related to
https://github.com/damontecres/Wholphin/issues/528#issuecomment-3678876207,
I adjusted the background & selection colors of the dialogs during
playback

### Screenshots

#### Choose subtitles from More dialog
![subtitle_dialog1
Large](https://github.com/user-attachments/assets/edaf96a0-fea4-4110-b274-e8c57494bc59)

#### Choose subtitles during playback
![subtitle_dialog2
Large](https://github.com/user-attachments/assets/c0dd76ab-bb2c-42a9-bfa7-2d3b6ffe2b35)

#### Choose audio
![audio_tracks
Large](https://github.com/user-attachments/assets/3214879d-9845-48ff-918c-e9cd470ed0bc)
2026-01-11 12:46:38 -05:00
Ray
ee73e7d723
Fix duplicate commands from key presses/MediaSession (#663)
## Description
Fixes duplicate play/pause commands from a remote button press and
`MediaSession`.

This ended up being a bit complicated because Wholphin overrides the
default play/pause behavior for the skip back setting and to show the
controller on pause. This means using a forwarding player which meant
implementing more functionality into `MpvPlayer`.

### Related issues
Fixes #653
2026-01-09 16:59:37 -05:00
Ray
2cd34692e9
Show indicator for multiple versions of media file (#652)
## Description
Adds an indicator to cards on grid pages if there are more than a single
version of the item. Also adds the count to the video stream label, much
like for multiple audio/subtitle tracks.

No behavior changes, just visual changes. You still need to select the
version from More->Choose Version.

### Related issues
Closes #612

### Screenshots
<img width="535" height="476" alt="image"
src="https://github.com/user-attachments/assets/5bf80d36-7abd-4a0e-a14d-062439f024d9"
/>
<img width="958" height="581" alt="image"
src="https://github.com/user-attachments/assets/e3a0ac4e-a283-4bcf-bc16-e61d81401207"
/>
2026-01-09 14:01:37 -05:00
Ray
d2e0d527dd
Fix some track selection bugs (#649)
## Description
Fixes track selection issues with MPV. This was especially focused on
libraries that disable embedded subtitles, but also fixes issues where
the audio streams are listed before video streams.

Also includes test media source JSON and unit tests to verify many
scenarios.

### Related issues
Fixes #494
2026-01-07 17:27:54 -05:00
Damontecres
6906813bbc
Fix mpv error with MediaSession 2026-01-07 14:03:28 -05:00
Ray
4df17e41cd
Fix timing issues with segments (#648)
## Description
Processing segments happens in a separate coroutine which wasn't
cancelled until _after_ playback of the next item begins. So in some
cases the outro from a previous item might be triggered during the very
beginning of the newly starting item.

So this PR instead cancels segment processing immediately when starting
the process for playback of an item. Additionally, the processing also
now checks that the current segment is for the current playback item as
an additional safeguard.

### Related issues
I believe this should fix both of these issues:

Fixes #369
Fixes #647
2026-01-07 13:23:55 -05:00
Ray
49740c47cf
Create media session during playback allowing for external control (#640)
## Description
Creates a `MediaSession` during playback which allows for external
control such as via smart speakers, Google Home app, etc

Note: one limitation is that seeking previous/next items in the playlist
isn't supported. This is because Wholphin manages that independent of
the `Player`, so additional dev work is needed for this.

### Related issues
Closes #622
Might help with #415
2026-01-07 12:49:43 -05:00
Ray
356a93310f
MPV: Handle resolution switch (#635)
## Description
When switching resolution (and possibly refresh rate less frequently),
the initial surface is not always valid. This means, the MPV playback
treated it as detaching the surface and would never update.

This PR instead subscribes to the `SurfaceHolder`'s callbacks which will
provide a new, valid surface once the switch is ready. Then the surface
is attached and queued commands execute to start playback.

Also temporarily disables content scale options for MPV since the
compose implementation conflicts with MPV rendering.

### Related issues
Fixes #626
2026-01-05 15:38:36 -05:00
Ray
4f1c730736
Don't process reqeued MPV commands (#633)
## Description
This is an embarrassing bug... In #619, a change was made to avoid a
race condition and wait for the video output surface to be ready by
re-enqueuing commands. Except I missed cancelling executing the current
command.

This meant the command would both be executed and queued again. So, if
attaching the video surface takes a while, such as needing to wait for a
refresh rate change, _a lot_ of commands could have been added to the
queue and trigger a constant start-stop playback loop.

I think technically it would eventually resolve itself, but can take a
while.

### Related issues
Should fix #626
2026-01-04 17:25:43 -05:00
Ray
02d6a98ba8
More subtitle selection fixes (#630)
## Description
Fixes more subtitle selection issues, primarily fixes the sort order of
subtitle streams. But also prefer default subtitle in some cases

Adds test cases for the described situations below

Also adds an option in the More dialog to clear track selections made on
an item/series.

### Related issues
Addresses
https://github.com/damontecres/Wholphin/issues/570#issuecomment-3707255647
&
https://github.com/damontecres/Wholphin/issues/570#issuecomment-3707292928
2026-01-04 17:06:54 -05:00
joshjryan
3d4b06db44
Guard against navigating to a non-existant tab (#629)
Just make sure we don't crash if the selectedTabIndex isn't a positive
int. Fixes #628.

---------

Co-authored-by: Damontecres <damontecres@gmail.com>
2026-01-03 18:38:07 -05:00
Ray
9345d0a698
Fix home header not updating & row movement (#627)
## Description
Removes an incorrect optimization for showing the home page header

Separates logic for focusing on rows on the home page

### Related issues
Fixes #624 
Fixes #620
2026-01-03 18:09:40 -05:00
Ray
4d9e3cb6de
Fix MPV race condition causing no video output (#619)
## Description
Fixes a race condition where `libmpv` is beginning playback before it
has been attached to the output video surface.

The solution is for the handler to re-enqueue commands if MPV is either
not initialized or not attached yet. Once `libmpv` is ready, the
commands will be processed.

### Related issues
Should fix #576
2026-01-02 14:13:03 -05:00
Ray
0fe8e5d988
Show button for trailers instead of card row (#618)
## Description
On both movie & series detail pages, show a button to play trailers
instead of the row of cards below.

The button works like this:
- If no trailers, the button shows "No trailers" and is
disabled/non-clickable
- If only a single trailer, the button shows "Play trailer" and clicking
it plays the trailer
- Otherwise, shows "Trailers" and clicking displays a dialog to choose
one

Local trailers are shown first in the list. Then there is an attempt to
sort the trailers for the dialog so that names with "Official Trailer"
or "Official Theatrical Trailer" are listed first and "Teaser" is listed
last. This isn't perfect and doesn't work for non-English, but there's
no other metadata to use.

### Related issues
Closes #408
2026-01-02 13:50:45 -05:00
Damontecres
b8e8a1d913
Fix yet another focus problem 2026-01-02 11:50:23 -05:00
Ray
83a543ad7d
Fix some crashes due to bad UI state (#617)
## Description
Fixes two possible crashes:
- When saving view options for a favorite page tab
- When there are no results on a grid page/tab
2026-01-02 00:24:17 -05:00
Ray
0958578082
Fixes websocket subscription, date invalidation, & theme music (#616)
## Description
Makes sure the `ServerEventListener` and `DatePlayedInvalidationService`
are injected so that they run. This was broken in #538.

Also fixes the a delayed stopping of theme music

Also fixes for detecting a non-seamless refresh rate switch

### Related issues
Fixes #615
Fixes #568
2026-01-01 22:19:36 -05:00
Ray
977db0474a
Small bug fixes (#614)
## Description
Fixes the screen showing endless loading when toggling on automatic sign
in

Ports a bug fix to the device profile from the official app
(https://github.com/jellyfin/jellyfin-androidtv/pull/5268)
2026-01-01 15:07:32 -05:00
Ray
3c11d4ba12
Fix some issues with restoring focus between pages (#613)
## Description
Yet more focus issue fixes:
- Restore focus when going back to home page from a later row
- Don't jump to episode row when going back to series overview (such as
from a person page)

This PR also changes how backgrounding the app during playback works.
Now the only goes back to the previous page when the app comes back to
the foreground. This helps with focusing back on the page properly.
There's also a bit more clean up performed.
2026-01-01 14:37:32 -05:00
Ray
26a913b05e
Support resolution switching (#597)
## Description
Adds a settings for automatic resolution switching. When enabled, the
app tries to output content at the video stream's resolution.

For example, if playing 1080p content on a 4K TV, the actual output by
the Android TV device will be 1080p.

This works in hand-in-hand with automatic refresh rate switching. So
enabling both allows for the output to match both refresh rate and
content resolution. Outputting the best refresh rate is preferred over
best resolution.

Also, shows the current display mode in the playback debug info.

### Related issues
Closes #428 
Fixes #531
2025-12-31 17:11:30 -05:00
Ray
38697b011d
Switch from synchronized mutations to copy-on-write (#609)
## Description
Instead of synchronizing all access to event observers, use a
`CopyOnWriteArrayList`. This means sending events doesn't need to lock.
2025-12-31 16:10:29 -05:00
Ray
a5a7ed97b7
A few more UI tweaks (#603)
## Description
- Use series poster for seasons without a poster
- Larger logo on playback overlay
- Fix an issue where corner text on card on the home page would not
properly update

### Related issues
Closes #590
Closes #601
Fixes
https://github.com/damontecres/Wholphin/pull/586#issuecomment-3698613927
2025-12-30 18:39:48 -05:00
Ray
e3fa45d12f
Trigger tv guide scroll animation during key presses (#595)
## Description
Instead of triggering the tv guide scroll animation during composition,
do it during key presses. This fixes an edge case that crashes the main
thread when returning the guide but the underlying UI data structures
haven't been updated.

### Related issues
Fixes #592
2025-12-29 15:39:07 -05:00
Ray
243e08b635
Some minor optimizations to improve UI speed (#593)
## Description
Many tiny changes that improve UI rendering speed and reduces
recompositions

Still plenty of room for improvement though.
2025-12-29 15:36:05 -05:00
Ray
622a99631b
Fix movie page library & collection tabs not updating (#594)
## Description
Ensures the tabs on movie page use separate view models so the data
isn't shared between them.

### Related issues
Fixes #591
2025-12-29 15:35:42 -05:00
Ray
aa194f5a2d
Fix duplicates being added to Android TV watch next channel (#588)
## Description
Fixes the logic for determining which items need to be added to the
watch next channel row

Also adds some code to clean up existing duplicates. This code can be
removed around the next release.

Adds a channel to the home screen for recently added media. This is
needed to ensure full integration with the OS to allow toggling off any
of the Wholphin channels including watch next.

### Related issues
#372 introduced the bug
Fixes #587
2025-12-28 17:14:14 -05:00
Ray
ad64f9a136
Minor UI tweaks (#586)
## Description
- Show unwatched counts on the cards in the latest rows instead of child
count, which is more in line with the web UI & official app
- Show exact runtime on the overview dialog for each version
- Don't show controls after clicking up next

### Related issues
Closes #431
2025-12-27 15:59:51 -05:00
Ray
9ae4965c2a
Add resume/continue watching items to Android TV watch next row (#372)
## Details

Adds resume and continue watching items for the logged in user to the
Android TV OS level watch next "channel"
(https://developer.android.com/training/tv/discovery/watch-next-add-programs).

## Issues
Closes #206
Related to #581
2025-12-27 15:40:45 -05:00
Ray
639ce0de71
Don't flash previous app content when resuming app & auto sign-in is off (#585)
## Description
When the app is put into the background with auto sign-in disabled, it
will remove the current page and show a loading indicator. This way when
the app is resumed, the previous content won't flash on screen for a
split second.

The above should technically fix #584 on its own, but as additional safe
guide, this PR also makes sure the `ApiClient` is configured before
trying to create image URLs.

### Related issues
Fixes #584
2025-12-27 15:13:45 -05:00
Ray
494ff07b72
Fix smart & default subtitle selection logic (#579)
## Description
Fixes the logic for subtitle selection when using `Smart` or `Default`
server modes. Also takes into account unknown languages.

This is heavily inspired by [the server selection
logic](https://github.com/jellyfin/jellyfin/blob/release-10.11.z/Emby.Server.Implementations/Library/MediaStreamSelector.cs).
For better or for worse, Wholphin implements this client side.

### Related issues
Fixes #570
2025-12-27 14:22:40 -05:00
Ray
fd1feddab3
Improvements to overview/media info dialog (#580)
## Description
* Splits video details into two columns
* Show index number if multiple streams of the same type
* Different font color for media section titles
* Adjustments to spacing
* Add hearing impaired flag to & remove AVC from subtitle info

### Related issues
Closes #549
2025-12-27 12:47:01 -05:00
Ray
a797bd8267
Further improvements to resuming the app (#577)
## Description
Fixes issues when the app is resumed, such as after the screensaver is
dismissed.

For example, if you pause during playback and the screensaver starts,
Wholphin will stop playback and go back to the previous page. But with
this PR, instead of focus being lost and defaulting to teh nav drawer,
focus will restore on the play button or episode card.

### Related issues
Related to #552 &
https://github.com/damontecres/Wholphin/issues/552#issuecomment-3690614491
2025-12-26 15:40:52 -05:00
Ray
bdec72752d
Use backdrop images for genre cards (#578)
## Description
Uses backdrop instead of thumb images for the genre cards since the
backdrops tend to have little text to distract from the card title

### Related issues
Closes #574
2025-12-26 15:40:43 -05:00
Damontecres
5d1f4b6154
Merge branch 'release/v0.3.9' 2025-12-25 08:57:20 -05:00
Damontecres
c00c7b8aa9
Catch exceptions during app startup 2025-12-25 08:49:57 -05:00
Damontecres
72f910582f
Only clear backdrop on home for full reloads 2025-12-25 08:49:33 -05:00
Damontecres
13370db48d
Only clear backdrop on home for full reloads 2025-12-24 18:15:17 -05:00
Ray
2ecc3f262d
Optimize series data loading speed (#567)
## Description
Optimizes how both series pages are loaded. If the series has a lot of
seasons and/or lots of episodes per season, the pages load much faster.

This is a combination of reducing queried information, optimizing
finding the right data to display first, and lazy loading seasons.

Note: Series that don't have episode numbers, like daily TV shows, are
not as optimized yet

### Rough speed-ups
These numbers are from my (beefy) server, so it will vary based on your
server

Series details page (one with seasons row) w/ ~50 seasons: 5s->300ms,
~13x faster

Series overview page (one with episode row) w/ ~50 seasons & 25
episodes: 6s->1.1s, ~5x faster

### Related issues
Related to #562
2025-12-24 16:47:17 -05:00
Ray
b671e14826
Better restoration for auto sign in (#566)
## Description
Improves how the app restores state when auto sign in is enabled. If
auto sign in is enabled, the app will restore back to the last page.

#538 altered the app start up logic. This caused the app to reset state
more often when it goes into the background.

### Related issues
Related to #552
2025-12-24 16:44:41 -05:00
Ray
2b53a53155
Prevent quick details from using more veritical space if not enough horizontal space (#544)
## Description
Prevents the quick details (the dot separated details) from using more
vertical space if there is not enough horizontal space. Instead, the row
will be clipped at the total width.

This PR also gives more horizontal space to the details header on grid
pages. This matches the home page now.

### Related issues
Fixes #542
2025-12-22 19:16:12 -05:00
Ray
9a08cf3f25
Don't use saved library info for genre grids (#540)
## Description
The filtering & sorting for the genre results grid is now independent
from the actual library.

This prevents having a filter saved on the actual library that conflicts
with the Genre grid.

Also shows the genre name in the title of the page

### Related issues
Fixes #536
2025-12-22 15:44:08 -05:00
Ray
af54e777dc
Fix settings changes requiring an app restart (#539)
## Description
- Ensures settings changes take effect immediately instead of requiring
an app restart
- Add conditional & catch when checking for app updates

### Related issues
Fixes issues introduced in #538
2025-12-22 15:28:21 -05:00
Ray
eb4e9b93be
Add setting to toggle automatic sign in (#538)
## Description
The major user facing change in this PR is adding back the setting to
toggle automatic sign in on or off. This controls whether to restore the
app to where you left off or go the user selection page.

If enabled: re-opening the app will restore the previous user's session

If disabled: re-opening the app will always start with the user
selection page for the most recent server, or if there isn't a recent
server, the server selection page

This also separate this setting from the PIN protection settings in
previous PRs.

### Dev changes

This PR refactors the "setup" UI (server & user selection) to be
separate from the "app" UI (the actually app content). There is now a
`NavDisplay` for the setup flow which ends with displaying the
`ApplicationContent`'s `NavDisplay`. Most of the logic is moved out of
Compose code and into a `ViewModel`.

This means to switch users/server, the `SetupNavigationManager` must be
used instead of `NavigationManager`.


### Related issues
Closes #396
Fixes #376
2025-12-22 14:52:09 -05:00
Ray
20fe5e2626
Move MPV init & destroy to looper thread (#534)
## Description
No user facing changes in this PR

This is a continuation of #481 to move initializing and tearing down
`libmpv` onto the looper thread to prevent main thread blocking.

~The only function left that runs on the main thread is
`setVideoSurfaceView`. Since this has to directly interact with the UI,
I need to read the docs and ExoPlayer code a bit more to see how this
can safely done multi-threaded.~ It is safe/correct to attach on another
thread.
2025-12-22 10:40:42 -05:00
Ray
60838c2a86
Fixes a few bugs (#535)
## Description

A few minor bug fixes across the app

- Fix the language not showing after search on the subtitle search &
download dialog
- Clear the backdrop whenever the home page is reloading from scratch
- Enable pressing a remote's play (or play/pause) button on the series
page to play the focused episode

### Related issues
Play button follow up from #424
2025-12-21 21:31:01 -05:00