Commit graph

603 commits

Author SHA1 Message Date
Damontecres
6d029086e9
Add detected HDR info to debug page (#2140)
## Description
Adds information to the debug page about detected HDR format for both
the device and the display.

I also wanted to try out the new `Grid` layout composable! It's much
better than the `SimpleTable`/`TableRow` composables I wrote previously.

### Related issues
There's a few issues/PR for improvements to HDR/DV support, so this will
help with debugging

### Testing
Emulator & nvidia shield on HDR TV

## Screenshots
N/A, just tables of info

## AI or LLM usage
None
2026-10-27 18:47:02 -04:00
Damontecres
f66746cf47
Auto-configure Discover from Wholphin server plugin (#2134)
## Description
https://github.com/damontecres/jellyfin-plugin-wholphin/pull/3 added a
new endpoint for Seerr configuration in Wholphin server plugin.

This PR adds support for reading that configuration and either
pre-filling the URL or automatically logging in.

Some code was copied from #1418 (thanks @matschi95!), but that PR worked
by inserting a DB record for the plugin provided server. Since the local
DB was preferred, this meant plugin config changes wouldn't be reflected
in the client. This PR instead attempts the connection and only updates
the in-memory connection state, so user switching and app restarts will
re-fetch from the plugin.

If the server plugin is not installed or no Seerr server is configured,
nothing in Wholphin changes.

### Related issues
#598 

This PR replaces #1418


### Testing
Emulator with different scenarios

## Screenshots
N/A

## AI or LLM usage
None
2026-10-26 14:18:56 -04:00
bobberb
90a2d6d459
Show album artist under album name on album cards (#2117)
## Description
Show album artist under album name on album cards

### Related issues
Fixes #2055

### Testing
Android TV 

## Screenshots
<img width="1920" height="1080" alt="pr1-albums-grid-artist-year"
src="https://github.com/user-attachments/assets/d00a8f78-8bf9-41da-8220-5cc7f6862cf5"
/>

### AI or LLM usage
Claude did the code, I reviewed it, then deployed a -debug.apk to my
device to confirm feature live.

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-26 14:15:29 -04:00
osipovgleb
de67bccb39
Fix: VLC doesn't restart playback from the beginning as expected (#2050)
## Description

When resetting the watch state or choosing to start from the beginning,
the "from_start" flag isn't passed to VLC. Because of that, VLC doesn't
restart playback from the beginning as expected.

This change adds the flag when needed so VLC starts from the correct
position.

## AI or LLM usage

я использовал Codex

Co-authored-by: osipovgleb <19697793+osipovgleb@users.noreply.github.com>
2026-10-26 14:05:37 -04:00
Damontecres
52c26bc0fc
Update playlist details to match library grid (#2113)
## Description
This PR updates the playlist details page to more closely match the look
of a library grid tab. This allows for a few things:
- Customize layout (grid, list, backdrop, etc)
- Show logos
- Random button
- The play all/filter/etc buttons no longer awkwardly show all the time

Basically, a playlist details will default to the list layout with "Show
details" enabled

The library list layout was actually based on the playlist details
layout originally, so this unifies the code. This means a bit less
maintenance and improvements to one page benefits the other.

### Dev note

This PR adds a `CollectionFolderViewScope` to pass down information
about the current collection and layout. This allows for easier
customizing of components. The PR also lifts the card & list item
composable to be parameters of `CollectionFolderViewContent` which,
again, allows for lots of customization.

### Related issues
Related to
https://github.com/damontecres/Wholphin/discussions/2078#discussioncomment-19046988

### Testing
Emulator

## Screenshots

### Before
<img width="1280" height="720" alt="playlist_ui_before Large"
src="https://github.com/user-attachments/assets/1cf8db82-4f53-4f20-a05e-ab937ffa3e3f"
/>

### After
<img width="1280" height="720" alt="playlist_ui_after Large"
src="https://github.com/user-attachments/assets/96ee6c1a-1a20-44dc-b979-0d314539a04a"
/>

## AI or LLM usage
None
2026-10-25 20:56:18 -04:00
Damontecres
6cde8ce8a6
Show warning for future unsupported server version (#2115)
## Description
Now that Jellyfin 12 has been out for over six weeks, it's time to start
considering dropping support for Jellyfin 10 & 11 as part of #1640.

This PR adds a warning message on the switch server, switch user, &
preferences pages if the current server version is <12.

### Related issues
See https://github.com/damontecres/Wholphin/discussions/1640 for further
discussion!

### Testing
Emulator w/ faked data

## Screenshots
N/A, reuses the same error message space

## AI or LLM usage
None
2026-10-25 20:52:20 -04:00
bobberb
9218940a69
Rename music "Top Rated Unwatched" row to "Top Rated" (#2118)
## Description
Rename music "Top Rated Unwatched" row to "Top Rated"

### Related issues
Typo.

### Testing
Android TV

## Screenshots
<!-- Please include screenshots if the PR alters any UI elements -->
<img width="1920" height="1080" alt="pr2-music-recommended-top-rated"
src="https://github.com/user-attachments/assets/3978bc9b-a020-4ee7-ae35-feb19e19ebae"
/>

## AI or LLM usage
Claude wrote the code, I reviewed, deploed a -debug.apk to my device and
tested live.

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-25 20:52:04 -04:00
Damontecres
551501fa75
Add support for server plugin (#1384)
## Description
PR to add support for a Wholphin server plugin:
https://github.com/damontecres/jellyfin-plugin-wholphin

Note: The plugin is not required to use Wholphin. It adds features the
server admin can use to set default settings like the home page or
eventually Seerr connection info.

### Changes
Wholphin will use the home page settings in order of:
1. Saved on the device locally
2. Saved on the server in the user's profile settings (display
preferences)
3. Provided by `jellyfin-plugin-wholphin`
4. Default fallback: combined continue watching & recently added in
libraries

Under customize home page, you can now see the "source" of the home
settings. This also allows to pick a different source

Finally, instead of the home customization being saved in the background
only locally, if there are any changes, a dialog is shown with options
to save locally, server-side user profile, or discard.

So overall, it's more clear where the home page settings are from and
where the user wants to save them.

### Install

[See instructions
here](https://github.com/damontecres/Wholphin/releases/tag/develop-server-plugin)

### Related issues
Related to #598

### Testing
WIP

## Screenshots
N/A

## AI or LLM usage
None

---------

Co-authored-by: Mario Reisinger <marioreisinger95@gmail.com>
2026-10-19 14:41:08 -04:00
Damontecres
e273195e93
Better handling for Seerr request permissions & minor discover UI tweaks (#2084)
## Description
No longer assume that if a user has "Request 4K" then they must also
have regular "Request". Now the requesting dialogs will handle:
- User has only "Request" (including just "Request Movie" vs "Request
TV")
- User has only "Request 4K"
- User has both

Also fixes an issue where the request button would be disabled if a
previous request was declined.

And also because it helped me with testing this and is useful, the
dialog in settings to remove a Seerr server now also shows the username
in addition to URL.

### Related issues

https://github.com/damontecres/Wholphin/issues/702#issuecomment-6132914691

### Testing
Manually on the emulator with the test cases above. I also tested with
and without "Advanced Requests" permission

## Screenshots
N/A, the dialog change is minor

## AI or LLM usage
None
2026-10-19 13:35:51 -04:00
Damontecres
ebf44699ca
Fix experimental settings for AC3 surround sound (#2101)
## Description
The refactor in https://github.com/damontecres/Wholphin/pull/1955
(included in `v1.0.9`) swapped the branches for the experimental "Use
AC3 for surround sound audio" breaking it.

Unfortunately, there isn't a real workaround to get the AC3 behavior
back. With the experimental settings enabled & "Use AC3 for surround
sound audio" _disabled_, surround sound audio will transcode to stereo
AAC. Otherwise if experimental settings are _disabled_ and/or "Use AC3
for surround sound audio" is _enabled_, there's no effect.

### Related issues
Credit to @StefanBS who opened #2090, but closed it before I verified
the bug
Closes #2093

### Testing
Manually via emulator

## Screenshots
N/A

## AI or LLM usage
None
2026-10-19 13:35:00 -04:00
Jake
621686d8e2
Include image tags in item image URLs (#2031)
## Description

Wholphin builds item image URLs without Jellyfin's `tag` query
parameter. `ImageUrlService` already receives the item's `imageTags` and
`backdropTags`, and the low-level `getItemImageUrl` supports `tag`, but
no branch passed it. Today only chapter and now-playing images set it.

Before: `/Items/{id}/Images/Primary?quality=96&fillHeight=229`
After:
`/Items/{id}/Images/Primary?quality=96&fillHeight=229&tag={ImageTags.Primary}`

This is how the official Jellyfin clients request images. jellyfin-web
and the official Jellyfin Android TV app both copy `ImageTags[...]` (and
the parent/series tags) into the image URL.

I also added `ImageUrlServiceTest`, which covers each branch.


### Related issues

I tested each one on the emulator against a stock Jellyfin 12.1 server
(no plugins), comparing `main` with this branch:

- **#366 (Image cache expiration): fixed by this PR.**
- **#1249 (blank tile for a newly added movie) and #1338 (episode cover
never refreshes): already fixed on `main` since v1.0.3, not by this
PR.** 
- **#360 (Option to hide spoilers): partly.**

## AI or LLM usage

This change was made with AI assistance (Claude Code). It was used for:
- the code changes in `ImageUrlService` and the call sites listed above
- the new `ImageUrlServiceTest`
- the emulator testing and benchmarks
- drafting this description

The testing is what's described above: unit tests, an Android TV
emulator against Jellyfin 12.1 servers (with Jellyfin Enhanced and
stock), request logs from a proxy, and a check of every tag against the
server's metadata. I've reviewed the change and can explain it.

I'm also a maintainer on Jellyfin Enhanced, which is how I ran into
this. I'm happy to share examples of my own coding work if that helps
with reviewing this.
2026-10-16 11:28:01 -04:00
Damontecres
3ef221bf91
Improve track persistence for series & episodes (#1802)
## Description
This PR overhauls how audio and subtitle track persistence works for
series! Previously, when you chose an audio or subtitle track for an
episode, only the language was saved and used for subsequent episodes.
This meant aspects about why that choice were lost such as a forced or
hearing impaired track.

This PR changes the persistence to include more details about the chosen
track. Additionally, the persistence is saved at both the season and
series levels.

## How it works

Selecting the track uses the first success option:
1. Episode specific - User has explicitly chosen an audio/subtitle track
for this episode
2. Season specific - User has chosen the track for another episode in
this season
3. Series specific - User has chosen the track for another episode in
this series
4. User preferences - User has _not_ chosen a track for the episode,
season, nor series, so determine track based on the preferred audio
language, preferred subtitle language, and subtitle mode

Additionally, the season or series specific choices use a scoring
algorithm to find the best suited track. For example, if the chosen
tracks for an episode in the season had the forced flag, this will be
preferred for subsequent episodes. Same for SDH/hearing impaired or
title, etc. This means that the common case, where a season has
substantially identical tracks, will use the same ones across all
episodes (after choosing for one, otherwise falling back to the series
or user preferences).

Finally, this also means that users that prefer SDH/hearing impaired
subtitles can be prioritized now, though there is no global preference
for this yet.

The previous track language choices are migrated to the new algorithm.
They lack the additional context, but this makes for a seamless
transition.

## UI changes

The context menu for choosing audio or subtitle tracks now displays why
that track was chosen.

### Related issues
Fixes #1795
Maybe fixes #1783
Related to #1136 & #1798
Closes #1470

### Testing
Previous unit tests for track selection all pass, plus there are a few
additional unit tests. I've done some testing on the emulator and it
seems to work well. But I think real world testing will be needed.

## AI or LLM usage
None
2026-10-16 10:53:44 -04:00
mizuka123
55960c2462
Inherit parent view options and sort for sub-folders (#2045)
## Description

This change applies only to subfolders that do not have their own saved
display settings.

When a subfolder has no saved settings, it now inherits the view type
and sort order from the closest ancestor with saved settings. Filter
settings are not inherited.

If the user changes the settings within a subfolder, those settings are
saved for that subfolder and take precedence over the inherited
settings.

### Related issues

Fixes #1768

### Testing

Tested an App Store flavor debug build on the following setup:

- Device: Xiaomi TV A Pro 43
- Jellyfin server version: 12.1
- Library: A hierarchical recording library stored on a NAS

I changed the view type and sort order at the top level of the library
and confirmed that both settings were inherited by untouched subfolders.

## Screenshots

N/A - no UI changes

## AI or LLM usage

Claude was used to write the changes in `CollectionFolderView.kt`.

I performed the testing on a physical Google TV device and verified the
behavior described above.

The commit also includes a `Co-Authored-By: Claude` trailer.

This description was written in Japanese and translated with an LLM.

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 10:32:12 -04:00
Jeff Whiting
9f557416ea
New user preference to force enable or disable common HDR and Dolby Vision formats (#1644)
Description
Adding per-format HDR override preferences (HDR10, HDR10+, Dolby Vision
Profile 5/7/8) to control device compatibility information sent to the
Jellyfin server, so users can force specific formats on or off
independently instead of disabling Dolby Vision as a whole.

Related issues
This is a common problem across the Jellyfin ecosystem, but there isn't
a specific issue for Wholphin. My experience is the issue is FireTV
(model and generation) + TV dependent + media dependent. I tested videos
from
https://kodi.wiki/view/Samples with the same DOVIWithHDR10 flag that
worked while other movies I have with It is a very frustrating user
experience and the current workaround of setting the bitrate really low
to force a transcode is sub-optimal IMO as it lowers the video quality.
This allows the user to maintain full quality while disabling only the
specific format(s) causing problems.

https://github.com/jellyfin/jellyfin-androidtv/issues/4021
https://github.com/jellyfin/jellyfin-androidtv/issues/4892
https://github.com/nova-video-player/aos-AVP/issues/1503

https://www.reddit.com/r/jellyfin/comments/12jqoxh/dolby_vision_video_not_working_on_fire_stick_4k/

Testing

<!-- Describe how this change was tested and on what device(s) -->
FireTV 4K (gen 1) + Vizio
FireTV 4K Max (gen 1) + LG
FireTV 4K Max (gen 2) + Vizio
FireTV (gen 1) + Olevia


AI or LLM usage
Claude code assisted and wrote much of the code in this PR. I've
reviewed it all and run the pre-commit linting and formatting.

---------

Co-authored-by: Damontecres <damontecres@gmail.com>
2026-10-13 15:41:53 -04:00
Damontecres
f01c5d367c
Updates to session restoration (#1905)
## Description
This PR reworks some of the internal handling of changing users and auto
sign in.

1. Most recently used server/user is migrated from `AppPreferences` to
`MostRecentServerProvider`
2. Checking if a user profile is protected occurs at a lower level in
`ServerRepository` so fewer services need to check for this
3. Now always defaults to the most recent server's user list in cases
where the most recent user can't be switched to such as if the profile
is protected, auto signin is disabled, or and error occurred

The default implementation for `MostRecentServerProvider` uses Android's
`SharedPreferences`. `SharedPreferences` was already was being used to
track the most recent server for crash reporting (the crash reporting
process cannot use the Hilt DI). This PR enhances this and adds a better
API for saving/retrieving.

This also removes the last bit of "user specific" data from
`AppPreferences`.

### Related issues
None specific, but there have been a few related to auto sign-in &
intents that were recently fixed. This PR is a more detailed approach to
those same problems.

### Testing
Manually via the emulator. There are also unit tests for most (all?) of
the different settings and state combinations.

## Screenshots
N/A

## AI or LLM usage
None
2026-10-11 20:11:09 -04:00
Damontecres
5bfbba193a
Fix issue with home reloading on user switch (#2064)
## Description
When switching users, the current user's home page would start a reload
during the switch. This PR fixes that by comparing the user switch.

The underlying cause is that Room's flow is blunt and emits whenever the
table updates. So [during the user
switch](9b02804075/app/src/main/java/com/github/damontecres/wholphin/data/ServerRepository.kt (L117-L118))
the table is updated causing [current user to
emit](9b02804075/app/src/main/java/com/github/damontecres/wholphin/data/ServerRepository.kt (L71))
and the current user flow is updated causing the new user to emit.

### Related issues
N/A

### Testing
Emulator, switching users and switching locales

Can observe that `UserSwitchListener` only trigger once per user switch
instead of twice

## Screenshots
N/A

## AI or LLM usage
None
2026-10-11 09:59:50 -04:00
Damontecres
d6523ce856
Fixes restoring focus on the correct episode (#2051)
## Description
On the series overview page, if you play the second or third episode,
then return to the page, focus will move the first episode.

This did not happen in `v1.0.7` and the code for that page was minimally
changed, so I think this was caused by updating the compose version,
maybe the ordering on focus resolution or something.

This small change seems to reliably fix the issue though.

### Related issues
Fixes #2043

### Testing
Emulator

## Screenshots
N/A

## AI or LLM usage
None
2026-10-09 17:58:12 -04:00
Damontecres
e23c446bb7
Fix issue when scrolling on collection details page (#2048)
## Description
If a collection is using separated types and there were 2+ empty rows
between types, then the forward composition wouldn't trigger and the
next row would not appear. In practice this means if you have a
Collection that contained Movies and Videos, you might not be able to
scroll down from Movies to Videos.

The fix is to filter out the empty rows before composing.

### Related issues
Fixes #2046

### Testing
Emulator

## Screenshots
N/A

## AI or LLM usage
None
2026-10-08 09:51:26 -04:00
Damontecres
b99f21efa8
Various bug fixes (#2010)
## Description
Collecting minor bug fixes in one PR:
- If error occurs fetching a series, show the error on the UI instead of
loading forever
- Use song's artists on Now Playing page
- Fixes settings wrap around scrolling when an update is available
- Fix backdrop not clearing for items without backdrop
- Fix not picking an ABI-specific APK when updating a regular release
(maybe related to #1966)
- Add "Go To" for album context menus
- Fix handling of next/previous media remote button presses during video
playback

### Related issues
Fixes #1990 
Fixes #1965

### Testing
Emulator mostly

## Screenshots
N/A

## AI or LLM usage
None
2026-10-08 08:09:20 -04:00
Damontecres
a38eb3e3d8
Fix possible crash on a few pages due to color space (#2036)
## Description
Fixes a potential crash on any page that uses `HomePageContent`, such as
home page, recommended tab, & customize home page.

I think this is actually a bug in compose because it shouldn't pass
`Color.Unspecified` into the native color code. But similarly, using
`Color.Unspecified` in `animateColorAsState` doesn't make sense either.

### Related issues
Fixes #1995

### Testing
I was able to reproduce this consistently using the Purple theme on
customize home page by focusing on an empty row. This change doesn't
cause the crash.

## Screenshots
N/A

## AI or LLM usage
None
2026-10-07 19:46:14 -04:00
Ayaz Patel
f5dedeab81
Fix baseline profile never being installed (#1984)
## Description

Wholphin already ships a baseline profile. AGP merges the profiles from the AndroidX libraries into `assets/dexopt/baseline.prof` on every release build, so a release APK built from `main` already has one at around 15 KB. It just never gets installed on the device.

The reason is in `app/src/main/AndroidManifest.xml`, which removes `androidx.startup.InitializationProvider` completely:

That was added in #372 so WorkManager could be set up on demand through `Configuration.Provider` and `HiltWorkerFactory`. The problem is that `androidx.profileinstaller` registers `ProfileInstallerInitializer` inside the same provider, so removing the provider removes that as well. 

### Related issues

#553

### Testing

API 34 AOSP emulator, `defaultRelease` signed with a debug key, clean install each time. With this change, logcat shows the profile being installed.

Not tested on a physical Fire TV device.

## Screenshots

None, there are no UI changes.

## AI or LLM usage

I used Claude for this one.

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Damontecres <damontecres@gmail.com>
2026-10-04 18:18:08 -04:00
Damontecres
559abe2458
Add setting to force transcoding above a max resolution (#1955)
## Description
Adds a new setting to pick a maximum resolution (by height). Any
playback that has a larger resolution will be transcoded down to the
maximum resolution.

Playback equal or less than the maximum resolution will not be affected
and will direct play if otherwise able. This setting is also independent
of the maximum bitrate (ie if max resolution is 4K and max bitrate is
2mbps, playing 4K will transcode).

This setting is pretty much equivalent to the Web UI setting "Maximum
Allowed Video Transcoding Resolution" with "Limit maximum supported
video resolution" enabled.

Note: this setting does not affect which version is chosen by default

### Related issues
Closes #756
Closes #1594

### Testing
Manual emulator testing

## Screenshots
N/A

## AI or LLM usage
None
2026-10-03 18:41:18 -04:00
Damontecres
b0d270380d
Better home page header for Seasons (#2016)
## Description
Updates the home page header & card text when a Season type is shown,
such as in recently added for a TV Show library.

The title or logo for the series is shown with the season name as the
title. The "quick details" has the year of the season. The card shows
the unplayed count of episodes.

### Related issues
Closes #1958

### Testing
Emulator over a few days to see different seasons

## Screenshots
<img width="313" height="153" alt="image"
src="https://github.com/user-attachments/assets/c41e9edd-9f2a-4f62-b76d-e452e83dd8bf"
/>

## AI or LLM usage
None
2026-09-30 17:35:29 -04:00
Damontecres
cf74736579
Listen for user config changes and improved websocket error handling (#2012)
## Description
Add better error handling for server web socket messages that are
(technically) invalid.

For example, I talked to Niels and some third party plugins don't always
have the required fields. Since the server isn't as strict as the client
SDK, it's fine on the server but will generate an invalid message sent
to the client.

Also listens for server-side user configuration changes via web socket.

### Related issues
Fixes #1979

### Testing
Valid server messages are handled as normal and I did some manual
testing to push invalid JSON into the webSocketApi, but the code is
gnarly and not viable as an actual unit test

## Screenshots
N/A

## AI or LLM usage
None
2026-09-29 12:43:13 -04:00
Jycreyn
a577ae9f1a
Add option to prefer Dolby Vision over HDR10+ on hybrid videos (#1876)
## Description

Adds a "Prefer Dolby Vision over HDR10+" switch (off by default) under
Experimental settings. That screen only shows up once "Experimental
settings" is enabled under Advanced, and until then the switch is read
as off: it goes through `experimentalPreferences.get {}`, so nothing is
wrapped and the playback path is untouched.

Most current 4K web releases carry both Dolby Vision (profile 8.1) RPUs
and HDR10+ dynamic metadata in the same HEVC stream. Some MediaTek based
devices (Philips and TCL TVs, some Fire TV models) latch onto the HDR10+
metadata on those files and never engage Dolby Vision, even though a
Dolby Vision decoder is selected.

I isolated this on my Philips 55OLED810 by playing the same episode
three ways, direct play in all three cases:

| | Stream | TV shows |
|---|---|---|
| A | MKV with DV 8.1 + HDR10+ | HDR10+ |
| B | Same MKV with the HDR10+ metadata removed using
[hdr10plus_tool](https://github.com/quietvoid/hdr10plus_tool), DV
untouched | Dolby Vision |
| C | Same stream remuxed to MP4, both kinds of metadata present |
HDR10+ |

The container doesn't matter and the Dolby Vision signaling is picked up
correctly. The only thing the app can do is keep the HDR10+ metadata
away from the decoder.

When the switch is on, and only when a Dolby Vision decoder was actually
selected, the HDR10+ SEI messages (SMPTE ST 2094-40, recognized by their
ITU-T T.35 header `B5 003C 0001`) are masked in each access unit before
it is queued to MediaCodec. The SEI payload type byte is overwritten
with an unused value (254), so the decoder skips the message. That is
one byte rewritten in place per message: the masking filter returns the
size it was given, so the access unit is queued exactly as long as it
came out of the extractor, which is what makes it safe with both the
synchronous and asynchronous MediaCodec adapters. media3 does the same
thing for HAGC metadata in `HevcSeiUtil`; this filter only targets ST
2094-40, so other T.35 SEI such as CEA-708 captions are not affected.
The filter was written from the H.265 spec, no Kodi or media3 code was
copied.

The hook is generic rather than HDR10+ specific, as asked in the thread.
`BitstreamFilteringCodecAdapterFactory` wraps the codec adapter with a
`List<BitstreamFilter>`, and a filter is `(ByteBuffer, offset, size) ->
Int` where the returned `Int` is the new size of the access unit: the
adapter queues the size the chain reports, and hands each filter the
size the previous one reported. A filter which only overwrites bytes
returns the size unchanged, which is what the HDR10+ masking does; a
filter which drops NAL units compacts what it keeps and reports the
shorter size. A reported size which is negative or larger than the one
the filter was given is ignored rather than queued. That is what lets
the Dolby Vision profile 7 to 8.1 conversion of #244 arrive later as one
more filter instead of a second copy of the adapter plumbing.

When the switch is off, the playback path is unchanged. On a device
without a Dolby Vision decoder (or a display without DV support) the
wrapper is never installed, so HDR10+ only devices keep their metadata.
Encrypted samples, codec config buffers and empty buffers are passed
through untouched.

Kodi has an equivalent option for the same reason: xbmc/xbmc@032cbfeb
and xbmc/xbmc@e2c54e7f.

### Related issues

Implements what was requested in #1855. The filter list is what #244
(Dolby Vision profile 7 direct play) needs, so that conversion can be
added as another filter. #1895 implemented the same masking
independently and was closed in favour of this PR; the device profile
part of it was not carried over, see the note under Testing. Upstream:
androidx/media#1895, where the maintainers say the bug is in the device
codecs and that they don't plan a workaround in ExoPlayer itself.

## AI or LLM usage

The implementation (bitstream filter, MediaCodecAdapter wiring, unit
tests) were written with AI assistance (Claude). I reviewed the changes
and validated the behavior myself on a real MediaTek TV (Philips
55OLED810), with the setting on and off, on hybrid and DV-only content.

---------

Co-authored-by: Jycreyn <github.2ilp7@passmail.com>
2026-09-29 12:41:40 -04:00
Damontecres
65954a99eb
Fix unnecessary home page reloads (#2008)
## Description
Fixes the home page reloading from scratch when the app is resumed

This happened because the `userDto` is updated on app resume and since
it has a last accessed timestamp, it would always different and trigger
a reload.

### Related issues
Bug introduced by #1981

### Testing
Emulator

## Screenshots
N/A

## AI or LLM usage
None
2026-09-28 13:18:41 -04:00
Damontecres
170989c31e
Guard against crash if episode has seasonId but no seriesId (#1964)
## Description
When clicking on an episode, the app assumes if there is a season ID for
the episode, then there must be a series ID. However, on my JF 12.0
server, an episode (with no metadata) appeared on my Continue Watching
and it has a season ID (which in turn has a series ID) but no series ID.

I'm not sure if this really a valid situation or if it's a server bug,
but Wholphin shouldn't crash at least. So this PR checks both `seasonId`
and `seriesId` and if either is null, falls back to the generic "Episode
Page". Similarly, if a season has no `seriesId` (again, not sure if a
valid situation), a crash won't occur, however there is no generic
"Season Page", so an error page is shown.

### Related issues
TODO, check JF server issues, maybe fixed in 12.1?

### Testing
Emulator

## Screenshots
N/a

## AI or LLM usage
None
2026-09-17 14:41:45 -04:00
Damontecres
32a56e8387
Wait for switched user's home settings before fetching data (#1981)
## Description
There is a race condition when switching users between
`HomeViewModel.init` and `HomeSetttingsService.loadCurrentSettings`.
This happens more often if the new user doesn't have a customized home
page. The result is that the previous user's home page settings are used
for the initial load of the home page.

This PR fixes this by collecting the flows for current user & home
settings, waiting until both are valid and refer to the same user, then
fetch the data.

### Related issues
Fixes #1976
Maybe related (and fixes) #1980, but need to investigate more

### Testing
Emulator. It's easy to reproduce by adding a manual `delay(2.seconds)`
at the start of `HomeSetttingsService.loadCurrentSettings`.

## Screenshots
N/A

## AI or LLM usage
None
2026-09-17 14:41:36 -04:00
Damontecres
ffdebd43c3
Update intent parsing to allow for user switching to home page (#1962)
## Description
Makes the `itemId` parameter optional allowing just passing
`serverId`/`userId` to switch the user and load the app at the home page
for that user.

Dev note: I added a new assert function `assertIs` which asserts that an
object `is` of a type. It also has a contract so the compiler will
smart-cast usages after the `assertIs`. Checking a result type is a very
common pattern in the unit tests, so this assert will simplify a lot of
current & future tests.

### Related issues
Closes https://github.com/damontecres/Wholphin/discussions/1824

### Testing
Emulator and added unit tests for `parseIntent`

## Screenshots
N/A

## AI or LLM usage
None
2026-09-15 13:07:08 -04:00
Damontecres
45c1ceca27
Fix favorites not querying for people & fix restoring focus on search page for discover items (#1961)
## Description
Fix two bugs:
- Favorites page didn't query for favorite people, introduced by #1864
- Fixes restoring focus on the search page after clicking a discover
item and going back

### Related issues
N/A

### Testing
Emulator

## Screenshots
N/A

## AI or LLM usage
None
2026-09-13 20:09:08 -04:00
Damontecres
98fba1340f
Fix OS screensaver starting during playback with dim enabled (#1956)
## Description
Fixes some devices activating the OS screensaver during playback when
the in-app dim was enabled.

I was not able to reproduce this on Shield 2017/2019, but could easily
on a Fire TV Stick. #1834 added the dim feature and, when enabled, would
not pass the keep screen on flag to the OS during playback. It seems
maybe regular Android TV's screensaver also listened to active media
session to prevent starting but maybe Fire TV OS doesn't. I'm not 100%
sure. This PR changes the logic slightly so that the keep screen on flag
is always set during playback.

### Related issues
Fixes #1894
Related to dim feature from
https://github.com/damontecres/Wholphin/pull/1834

### Testing
Emulator, shield 2019, & fire tv stick 4k

## Screenshots
N/A

## AI or LLM usage
None
2026-09-12 18:38:54 -04:00
Damontecres
616565f671
Fixes to v1.0.7 (#1953)
## Description
Collection of minor bug fixes for `v1.0.7`

- Fixes a possible race condition crash when navigating to the search
page
- Uses friendlier error message when login fails due to parental
restrictions (based on
[`jellyfin-web`](https://github.com/jellyfin/jellyfin-web/blob/v10.11.11/src/controllers/session/login/index.js#L38-L41))
- Don't re-sort search results by name, just by relevance scoring
- Consume the key event when dim is active (ie if the screen is dimmed,
pressing a key will un-dim and not perform another action)

### Related issues
Fixes #1922 
Fixes #1951
Related to #1848 (search sorting)

### Testing
Emulator & nvidia shield

## Screenshots
N/A

## AI or LLM usage
None
2026-09-11 15:40:11 -04:00
SergeiAK
6486bd19ed
Fix person credits: movie release dates, full filmography, sorted order (#1950)
<!-- By submitting this pull request, you acknowledge that you have read
the [contributing
guide](https://github.com/damontecres/Wholphin/blob/main/CONTRIBUTING.md,
including the AI/LLM policy, and [developer's
guide](https://github.com/damontecres/Wholphin/blob/main/DEVELOPMENT.md)
-->

## Description

Person pages that get a filmography from Seerr had three problems, all
in the same place.

The release date was taken from `firstAirDate` alone — the field TMDB
fills for series — so
movie cards showed no year at all. The library person page capped the
row at 25 cast + 25 crew while
`DiscoverPersonPage` had no cap, because each screen carried its own
copy of the same logic.
And `cast + crew` left the row in no order a viewer can read, with a
title appearing twice when
a person is both cast and crew on it.

This PR:

* maps credit dates as `releaseDate ?: firstAirDate` — the expression
the search result mapping
  already uses;
* moves the credits logic into a single `SeerrService.personCredits()`
used by both screens, so
  they cannot drift apart again;
* drops the 25 + 25 cap, de-duplicates by TMDB id and sorts by release
date descending, with
  undated entries last.

Rows on movie and series pages are untouched: only the
`BaseItemKind.PERSON` branch of
`similar()` changed.

Two things worth your opinion:

* Without the cap, the row for a person with a long filmography is long
— 135 cards for Cameron
Diaz, for example. If you would rather keep a cap, the row could keep
the newest 25 and gain a
`ViewMoreCard` opening the full grid — `Destination.DiscoveredItem` with
a `PERSON` item
already routes to `DiscoverPersonPage`. I am happy to add that in a
second commit.
* The sort is fixed to release date descending. It now lives in one
function, so a different key
  or a user-facing choice would be cheap to add later.

### Related issues

Fixes #1873

### Testing

CI in my fork ran the repository's own PR workflow on this branch:
`pre-commit` (ktlint) and
`assembleDefaultDebug` with `testDefaultDebugUnitTest` are both green.

I then installed a debug build of the same code on an NVIDIA Shield TV
Pro 2019 (Android 11),
against Jellyfin 10.11.11 with Jellyseerr, and opened Cameron Diaz from
the cast row of
*Charlie's Angels* before and after the change:

* movie cards show a year now; before, the only two cards in the row
with a year were the two
  TV entries;
* the row is ordered by release date descending, movies and series
interleaved, instead of the
  API order of all cast followed by all crew;
* the row is no longer cut at 25 + 25 — it now runs back to her 1952
credit, and the entries
  TMDB has no date for sit at the very end of the row.

Not tested on any other device; nothing in the change is device
specific.

## Screenshots

Person page of Cameron Diaz, reached from the cast row of *Charlie's
Angels*. The library rows
above the Discover row are the same in every shot and are useful as a
reference: they always had
their years.

Before, start of the Discover row — no year under any card:
<img width="1920" height="1080" alt="pr1873-1-before-start"
src="https://github.com/user-attachments/assets/585d0670-ae39-4214-9004-0c92262991da"
/>

Before, end of the Discover row — the row stops here, and the only two
years in it belong to the
two TV entries:
<img width="1920" height="1080" alt="pr1873-2-before-end"
src="https://github.com/user-attachments/assets/85c58575-2ad0-4369-a103-60f04c8d2350"
/>

After, start of the row — years on the movie cards, ordered by date
descending:
<img width="1920" height="1080" alt="pr1873-3-after-start"
src="https://github.com/user-attachments/assets/804745c5-e1a6-4fe4-93bd-dc6c97a7a876"
/>

After, end of the row — the list now reaches 1952, with the undated
entries last:
<img width="1920" height="1080" alt="pr1873-4-after-end"
src="https://github.com/user-attachments/assets/2c32389c-ec0b-4df5-b9d1-f564ef10d8b3"
/>

## AI or LLM usage

The code was written with Claude Opus 5 (Claude Code): the two mapping
lines, the extracted
`personCredits()` function and the two call sites. I reviewed every line
and can explain it.
This description was written by me in Russian and translated into
English with the same
assistant.

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Damontecres <damontecres@gmail.com>
2026-09-11 15:22:02 -04:00
Damontecres
9c56965c82
Add controls to edit playlists (#1927)
## Description
Adds support to remove items from a playlist and move items within a
playlist

The remove option is in the context menu. Moving has buttons on the
right side. The buttons are available if the user has edit permissions
and the playlist is sorted by "Default" (the playlist order). Remove
from playlist option is available if the user has edit permissions.

Also, thumb images are now preferred instead of primary/poster images
since the layout is much wider than tall.

### Related issues
Closes #1881

### Testing
Emulator with both a user with & without permissions to edit

## Screenshots
### With move buttons
<img width="1280" height="720" alt="playlist_buttons Large"
src="https://github.com/user-attachments/assets/ce7880c3-b823-4b69-9ad4-cfc9e7ee5fd5"
/>

### Without move buttons
<img width="1280" height="720" alt="playlist_no_buttons Large"
src="https://github.com/user-attachments/assets/f2027052-4628-4d44-8257-6c2a5e8c3af4"
/>


## AI or LLM usage
None
2026-09-10 17:18:26 -04:00
Damontecres
0b995b5404
Configure playback controls for RTL (#1945)
## Description
Reverts/fixes parts of #1404 for the playback UI. Generally the playback
UI always uses left-to-right for seek bar & media controls even on RTL.
Other buttons or texts will be RTL.

### Related issues
Fixes #1397 

### Testing
Emulator w/ forced RTL English

## Screenshots
See
https://github.com/damontecres/Wholphin/issues/1397#issuecomment-5553711593

## AI or LLM usage
None
2026-09-08 22:51:54 -04:00
Damontecres
4a567cbcf4
Fixes to season/episode search with duplicates (#1946)
## Description
Fixes cases where the server has duplicate season IDs causing the season
index search to fail and default to the first season in the list.

### Related issues
Fixes #1837

### Testing
Emulator & unit tests

## Screenshots
N/A

## AI or LLM usage
None
2026-09-08 22:51:46 -04:00
Damontecres
1778bdb34c
Consolidate sending media reports & app logs (#1936)
## Description
Consolidates sending reports/logs to the server into
`ServerReportService` (renamed from `MediaReportService`)

Also ensures a consistent header is used including the build flavor.

### Related issues
N/A

### Testing
Emulator

## Screenshots
N/A

## AI or LLM usage
None
2026-09-05 12:11:38 -04:00
Damontecres
39239dd444
Add wrap around scrolling to settings pages (#1937)
## Description
Add scrolling from top to bottom and vice versa. This makes it quicker
to get to Advanced Settings for example.

### Related issues
N/A

### Testing
Emulator

## Screenshots
N/A

## AI or LLM usage
None
2026-09-05 12:11:30 -04:00
Tal Sarid
1f3a861c47
Localized formatting for season and episode display (#1884)
## Description
Added localized formatting for season/episode numbers across the UI
because it was in English-only in every UI language.

### Related issues
None

### Testing
Tested on a physical Google TV Streamer 4K device. Checked manually
relevant screens while browsing and during playback.

## Screenshots
No frontend changes are visible in English and new translations will be
contributed through Weblate for other languages later, as usual.

## AI or LLM usage
Generated initial code with AI, then manually passed over it while
cleaning and refactoring where needed.

---------

Co-authored-by: Damontecres <damontecres@gmail.com>
2026-09-04 12:47:06 -04:00
Damontecres
826bbad49c
Fixes to Now Playing page (#1915)
## Description
Fixes several issues on the Now Playing page

- Keep controller focus after lyrics are focused
- Fix the queue not visually updating until recomposition
- The first focused queue shown/focused is now what's currently playing

### Related issues
Fixes #1821

### Testing
Emulator

## Screenshots
N/A, just behavior fixes

## AI or LLM usage
None
2026-09-02 02:50:42 -04:00
Damontecres
6fbf6209a1
Fixes to default home view options for music & videos (#1926)
## Description
This PR fixes how cards are displayed initially when creating the
default home page or loading it from the web config:
- Ensure view options are selected based on the library type (this is
how it's done already when manually adding a row)
- Support more home row types such as photos and music

### Related issues
Fixes https://github.com/damontecres/Wholphin/issues/1838

### Testing
Emulator, resetting to default and loading from web config

## Screenshots
N/A, music cards will be square instead of poster sized

## AI or LLM usage
None
2026-09-01 17:52:47 -04:00
Damontecres
cedca9b2b1
Add button to navigate to random item (#1916)
## Description
Adds a random button on library tab/grid pages which navigates to a
random item in the list. This goes to the item's detail page.

The random item is chosen with the filters applied. So you could filter
by unplayed Action movies with 7+ stars and the random button will
select from those movies.

Pressing back restores focus on the random button so it's easy to
quickly retry.

### Related issues
Closes #838

### Testing
Emulator

## Screenshots
<img width="935" height="105" alt="image"
src="https://github.com/user-attachments/assets/170b495c-b47d-41ce-93b5-99831f2064c7"
/>
<img width="936" height="114" alt="image"
src="https://github.com/user-attachments/assets/3efa6a11-ebe8-42d7-b023-354b1e6eda37"
/>



## AI or LLM usage
None
2026-09-01 16:07:26 -04:00
Damontecres
5363db0b80
Update API level to Android 17 (#1908)
## Description
Updates the compile & target SDKs to 37 (Android 17).

The only required change is to support the new `ACCESS_LOCAL_NETWORK`
permission. This is required for Android 17 devices to auto discover
Jellyfin servers on the local network. Wholphin will prompt for
permission and if granted, use the discover servers feature. If
permission is not granted, the user must enter the server URL manually.

### Related issues
N/A, but several dependency renovate PRs are blocked by this

### Testing
I tested with a regular Android 17 emulator. There are no Android TV 17
images (or probably even devices) available yet.

## Screenshots
N/A

## AI or LLM usage
None
2026-08-29 21:35:58 -04:00
Damontecres
cc2e7dfdda
Fix image loading issues related to VPN and/or Fire OS 6 (#1910)
## Description
This PR override Coil's built-in network connectivity checker with one
that allows returns true. The built-in one seems to be unreliable on
devices running Fire OS 6 (maybe other versions too) and/or devices
using a VPN such as Tailscale.

See more details here:
https://github.com/damontecres/Wholphin/issues/1800#issuecomment-5432941761

### Related issues
Should fix #1156
Should fix #1751
Should fix #1800

### Testing
Unfortunately, I've never been able to reproduce the original issue on
any of my devices, but hopefully someone who is affected can try this
branch out!

This change doesn't break anything on some emulators (tried Android 7.0
& Android TV 14) or NVIDIA shield

## Screenshots
N/A

## AI or LLM usage
None

## Try it

See instructions here:
https://github.com/damontecres/Wholphin/releases/tag/develop-image-fix
2026-08-29 16:07:09 -04:00
Damontecres
fdde986029
Update favorites page with more types (#1864)
## Description
This PR adds many more data types as tabs to the favorites page.
Additionally, only tabs for the types the user has favorites for will
appear. For example, if you have no favorited music videos, that tab
will not show.

Added types:
- Collections
- TV Channels
- Music albums
- Music artists
- Music videos
- Songs
- Home videos
- Photos
- Photo albums

Dev note: The tabs are implemented using keys instead of indexes which
could be useful for the series overview season tabs. Plus it maybe even
be adapted for the episode list to eliminate the terrible index search
logic. A major difference is that the possible favorites tabs are
known/static list where seasons/episodes are queried & paginated.

### Related issues
Closes #1041
Closes #1844

### Testing
Manually on emulator, plus unit tests

## Screenshots
N/A

## AI or LLM usage
None
2026-08-26 21:50:13 -04:00
Damontecres
786b95a393
Fix white flash on app start (#1909)
## Description
This fixes the brief full screen white flash when the app starts or
reloads.

I bisected to find the cause which was #1653. The newly added `Surface`
uses `MaterialTheme` to set its colors. `MaterialTheme` defaults to a
generic _light_ color scheme. So this PR applies the Wholphin's default
purple theme, which will then be overridden once the app preferences are
loaded.

### Related issues
Mentioned in
https://github.com/damontecres/Wholphin/issues/1576#issuecomment-5376373039

### Testing
Used emulator with "Don't keep activities" and repeatedly opened &
closed the app to see if the white flash visually occurred

## Screenshots
N/A

## AI or LLM usage
None
2026-08-26 21:46:48 -04:00
Damontecres
f91bca18ff
Add more searchable types & choose what to search (#1857)
## Description
This PR adds several more data types to search. It also adds a setting
(per use profile) to choose which types to include/exclude when
searching. The combined results now uses the same types instead of a
separate list.

A user can only search for types that they have access to. For example,
they need Live TV access for TV channels/programs or need access to a
movies-type library to search movies.

Added types to search:
- Photos & Photo albums
- Playlists
- People
- TV channels
- Live TV programs

Clicking a TV channel will play it. Clicking a TV program shows the
program dialog allowing for recording or watching live if it's currently
airing.

On the main search page you can also toggle whether to search Seerr or
not. This does not apply to the discover search tab.

Dev note: Some minor refactoring to move setting up/canceling live tv
recordings into a new service so it can be shared between with the live
tv & search pages. Also search related files are moved into the same
package now.

### Related issues
Closes #409
Closes #646 
Closes #1668
Closes #1750

### Testing
Emulator using users with different permissions and library access

## Screenshots
<img width="475" height="584" alt="image"
src="https://github.com/user-attachments/assets/ebcff697-07ba-4ddd-8c26-57f147cfa02a"
/>


## AI or LLM usage
None
2026-08-26 14:39:02 -04:00
Damontecres
4b927e6b7b
Fix Next Up channel launch sign in (#1886)
## Description
When parsing intents, not every path for authentication was checked, so
launching via the "Next Up" OS channel wouldn't check for a profile PIN.
This PR fixes that.

Additionally, the "Next Up" OS channel launch wasn't checking the
correct parameter to ensure the back stack was written properly.

### Related issues
Fixes #1883

### Testing
I manually test on the emulator with these test cases:
- No profile PIN, cold start
- No profile PIN, hot start
- Profile PIN, cold start
- Profile PIN, hot start
- No profile PIN, launch via "Next Up" channel
- No profile PIN, launch via intent
- Profile PIN, launch via "Next Up" channel
- Profile PIN, launch via intent

Also added unit tests for intent-based and regular launching which
covers those cases and more.

## Screenshots
N/A

## AI or LLM usage
None
2026-08-21 15:04:07 -04:00
Damontecres
39523aa6e2
Several minor bug fixes (#1866)
## Description
Another PR to gather small bug fixes:
- Fix aspect ratio for episodes on person page
- Use the song's artist instead of the album's artist on album page
- Fix how the dim percentage is applied to the OS screensaver dim
percentage (#1834)

### Related issues
Fixes #1851 
Fixes #1863

### Testing
<!-- Describe how this change was tested and on what device(s) -->

## Screenshots
<!-- Please include screenshots if the PR alters any UI elements -->

## AI or LLM usage
<!-- If you used any AI or LLM assistance, please list where in the code
and how you tested it -->
2026-08-20 17:09:39 -04:00
Damontecres
ed204ef7e9
Fix experimental AC3 setting being used by default (#1879)
## Description
There were two problems with the experimental "Use AC3 for surround
sound audio" setting (#947):
1. Defaulted to true
2. Access wasn't guarded by enabling experimental settings

This caused unintentional audio transcoding

### Related issues
Fixes #1878

### Testing
Emulator

## Screenshots
N/A

## AI or LLM usage
None
2026-08-20 17:08:31 -04:00