## Description
Adds a setting to enable "Media management" which adds a context menu
item to delete media. This is accessible using either the More button or
long clicking.
You can delete episodes, seasons, series and movies/videos.
If order for the option to appear the current user must have server-side
settings for "Allow media deletion from" enabled for the library and the
in-app setting under Settings->Advanced Settings->"Show media management
options".
### Related issues
Closes#104
### Testing
Emulator
## Screenshots
### Context menu

### Confirmation

## AI or LLM usage
None
## Description
- Restores corner text for episode cards
- Always show end time on playback overlay instead of it being
controlled by the "Show Clock" setting
- Better logic to determine person's role in media
### Related issues
Fixes#1010Fixes#1004Fixes#975
### Testing
Emulator
## Screenshots
N/A
## AI or LLM usage
None
## Description
Adds both an optional in-app and Android TV OS (DreamService)
screensaver
Has settings for:
- Starting delay, options from 30s to 1 hour
- Duration to show each image, 30s to 2 minutes
- Show clock (separate from app-wide clock)
- Toggle animated zooming
- Set a max age rating to limit what content is shown
- Included media types: movies, tv shows, and/or photos
By default only Movies & TV Shows are included. But if you have like
family albums on your server, you could enable Photos too.
There's also an button to start the screensaver so you can see what it
looks like.
### Related issues
Closes#230
### Testing
Emulator, Onn 4k pro, nvidia shield using both in-app and OS
screensavers
## Screenshots

## AI or LLM usage
None
## Acknowledgements
Some of the skeleton code for setting up the `DreamService` with the
right lifecycle was copied and modified from the [official app's
implementation](https://github.com/jellyfin/jellyfin-androidtv/blob/master/app/src/main/java/org/jellyfin/androidtv/integration/dream/DreamServiceCompat.kt).
## Description
Play theme songs for collections if available
### Related issues
Closes#711
### Testing
Emulator
## Screenshots
N/A
## AI or LLM usage
None
## Description
Weblate's Android string parser (aka
https://translate.codeberg.org/projects/wholphin/) doesn't support
direct translations of string arrays.
Many of Wholphin's preference options are defined in string arrays and
therefore could not be translated. So this PR implements the [suggested
workaround](https://docs.weblate.org/en/latest/formats/android.html) to
move the string into individual entries and reference them in arrays.
Also moves some hardcoded strings into `strings.xml` so they can be
translated. Note: virtually all error messages are still hardcoded, but
they are only for exceptional cases, so it's probably not a huge
problem.
A minor bug where the backdrop would show briefly after switching users
is fixed.
### Related issues
Fixes#957
### Testing
Emulator
## Screenshots
N/A
## AI or LLM usage
None
## Description
Adds a preset for "Episode thumbnails" which shows episodes using their
Primary image (ie a thumbnail or screenshot of the episode).
The previous "Thumbnails" preset is renamed "Series Thumbs" because it
uses the episode's Series Thumb image.
Also fixes a bug where toggling "Use series" might not update the home
page preview automatically.
### Related issues
Fixes#940
### Testing
Emulator
## Screenshots
N/A
## AI or LLM usage
None
## Description
Hopefully this is the last round of bug fixes for customizing the home
page!
Fixes a possible crash when scrolling after adding a row after resetting
to default or loading remote settings that have more rows than the
original settings
Fixes some incorrect titles
### Related issues
Related to #399 & #803
### Testing
Emulator & nvidia shield
## Screenshots
N/A
## AI or LLM usage
None
## Description
Improves home page customization for Live TV & Recordings
- Add row for live tv channels
- Add row for "on now" programs
- Clicking on a TV channel or TV program starts playback
- Better name for "Recently recorded" instead of "Recently added in
Recordings"
Also fixes a back stack issue after adding rows
### Related issues
Follow up from #803
### Testing
Emulator
## Screenshots
<img width="663" height="190" alt="image"
src="https://github.com/user-attachments/assets/49d41953-42ab-4621-92f1-b7936aab7e97"
/>
## AI or LLM usage
None
## Description
This PR adds the ability to customize the home page in-app
### Features
- Add, remove, & reorder rows
- Persist the configuration locally
- Save the configuration to the server, allowing to pull down on other
devices
- Adjust view options for rows such as card height, image type,
preferring series images, or aspect ratio (similar to libraries)
- Pull down the web client's home rows (no plugins are supported yet!)
- Preview of the home page which is usable & updated as changes are made
### Row options
These are row types that can be added in-app via the UI:
- Continue watching
- Next up
- Combined continue waiting & next up
- Recently added in a library
- Recently released in a library
- Genres in a library
- Suggestions for a library (movie & TV show libraries only)
- Favorite movies, tv shows, episodes, etc
Additionally, there are more row types that don't have a UI to add them
(yet):
- Simple query to get items from a parent ID such as a collection or
playlist
- Complex query to get arbitrary items via the `/Items` API endpoint
### Dev notes
Settings are loaded in order:
1. Locally saved
2. Remote saved
3. Fallback to default similar to Wholphin's original home rows
The remote saved settings are stored via the display preferences API.
I know some server admins would prefer to push a default setup to their
clients. This PR does not have that ability, but it does define a
straightforward API for defining the settings. Something like the
potential server plugin work started in #625 could be slimmed down to
expose a URL to be added in the load order.
I'm also investigating integration with popular home page plugins to
allow for further customization, but will take more time.
### Related issues
Closes#399Closes#361Closes#282
Related to #340
## Description
- Adding `Quick Connect` drawer to the Settings under the Seer
integration, and before Additional options.
- When interacted with, A inline-dialog appears (after internally
resetting itself), with gutter options Cancel / OK, like existing
dialogs, and when that is completed, where it completes the other side
of `Quick Connect`, e.g. login to your phone Jellyfin app by using
Wholphin.
- Failure and success both are indicated to the user and if success, it
closes the window.
### Related issues
Related to #819Closes#819
### Testing
Tested on development build from my repo on a Nvidia Shield 2019.
Performed several logout/login, both success and fail to observe dialog
state and function.
## AI or LLM usage
Used Claude Sonnet 4.5 for most of the code, ChatGPT, reviewed it, then
I reviewed it, made a few tweaks.
## Description
Add a settings to set the maximum amount of time items can appear in
Next Up.
Options range from 7 days to a year, or no limit (current & default
behavior)
### Related issues
Closes#662
### Testing
Tested on the emulator and verified URLs, added unit tests
## Screenshots
N/A, just a new slider bar setting
## AI or LLM usage
None
## Description
Adds a item in the More menu to send information about the media item to
the server (and app logs).
This includes the "media sources" which is info about the files and
stream/tracks in the files. It also includes device info, the playback
preferences, and the device's transcoding profile. All of this info is
useful for debugging playback issues.
### Related issues
N/A
### Testing
Emulator testing
## Screenshots
N/A
## AI or LLM usage
None
## Description
Add support for viewing photos in photo albums
### Features
- Browse and view albums & photos
- View an album as a slideshow
- Show overlay with photo details and controls
- Rotate, zoom, & pan photos
- Apply basic filters to photos or albums such as contrast, saturation,
red/green/blue, etc
- Setting to include video clips during slideshows
### Controls
- D-Pad left or right: scroll between photos in album
- Hold D-Pad up or down: zoom in or out of the current photo
- D-Pad left/right/up/down, while zoomed: pan around photo
- Back, while zoomed: revert the zoom
- Otherwise: show photo overlay
### Related issues
Closes#458Closes#634
### Screenshots
#### Overlay

#### Applying filters

## Description
Can now configure a different subtitle style for HDR playback.
There is also a new setting to change the opacity/dim image based
subtitles. This is primarily for HDR to dim very bright PGS subtitles,
but the setting is available for SDR too.
Please remember that the styles only apply to unstyled text formats like
SRT.
I haven't been able to consistently get the preview to switch the
display into HDR mode, so the preview is not 100% accurate.
### Related issues
Closes#583
### Testing
Shield pro 2019 w/ LG C2
## AI or LLM usage
None
## Description
The MPV backend is no longer considered experimental. This PR adds a
setting for player backend "Prefer MPV" which uses MPV for all playback
unless the video is HDR which then uses ExoPlayer.
Switching occurs per video. So if there's a playlist with both SDR &
HDR, the player will switch back and forth as needed.
### Related issues
Closes#253
Related to #235
## Description
Adds the [`dav1d` decoder
module](https://github.com/androidx/media/tree/release/libraries/decoder_av1)
for ExoPlayer as an option. It can be enabled in advanced settings.
Performance will vary between devices.
### Related issues
Closes#103
### Dev notes
As with the ffmpeg module, this one is not required to build the entire
app so it's easier for developers to get started.
This also introduces a customized `DefaultRenderersFactory` for
ExoPlayer, but its largely copied from the super class's implementation.
## Description
This PR is a rewrite of a previously submitted PR for this same feature.
It implements native Voice Search for Android TV using Android's
SpeechRecognizer API.
Key Changes
New Files:
- VoiceInputManager.kt - Handles SpeechRecognizer lifecycle, permission
management, and audio level normalization
- VoiceSearchButton.kt - Composable button with audio-reactive pulse and
full-screen listening dialog
UI/UX:
- Audio-reactive microphone button that pulses based on input volume
- Full-screen listening overlay with animated states:
- Listening - Pulsing bubble with ripple rings, shows partial
transcription
- Processing - Animated dots while waiting for final result
- Error - Red bubble with localized error message, auto-dismisses after
3s
### Related issues
Resolves https://github.com/damontecres/Wholphin/issues/515
### AI/LLM usage
The initial draft of this change from the prior PR was created with the
assistance of Claude Code, which was heavily leaned on for the overlay.
I have taken the initial draft, gone through it, and re-implemented by
hand to clean it up, narrow the scope (AI loves to touch and change
things unrelated to what you're working on) and make it more readable.
AI was used in the last stage to assist with finding any logic
errors/bugs I may have missed (by looking through code and also by
looking over ADB logs from testing on Nvidia Shield).. AI was also used
to create the tests found in TestVoiceInputManager.kt. Lastly, I fed the
diffs to an AI to help summarize the changes for this PR in an easy to
read manner.
---------
Co-authored-by: Damontecres <damontecres@gmail.com>
**Description**
Fixes a race condition in the Seerr integration.
When you added a new Seerr server and logged in successfully, the app
would immediately show the "Disable Seerr?" dialog instead of a success
message. The state was getting mixed up during recomposition and
thinking you wanted to remove the server you just added.
Fixed by being more explicit about what mode the dialog is in (adding vs
removing) so it can't get confused by background state changes. Also
added a success toast when login works.
**AI/LLM usage**
Used Claude Code to analyze the issue.
## Description
This PR add the ability to integrate with a [Jellyseerr/Seerr
server](https://github.com/seerr-team/seerr).
### Features
- Login to the Seerr server using API Key, Jellyfin credentials, or
local Seerr credentials
- Separate Seerr logins per user profile
- Search Seerr from the search page
- Discover media from Seerr on the nav drawer `Discover` page
- Also from movie, series, or person pages
- Seamless integration with existing media, i.e. selecting media found
from Seerr that already exists on the Jellyfin server, will go directly
to the regular media page
- Mostly consistent UI between Jellyfin media & Seerr media
- Submit requests to Seerr
- Cancel submitted requests
### Screenshots

### Related issues
Closes#54
## Acknowledgements
The `app/src/main/seerr/seerr-api.yml` file is copied & modified from
https://github.com/seerr-team/seerr/blob/develop/seerr-api.yml. I hope
to try to upstream some of the changes in the future.
## Description
A few devices, like the Nvidia Shield Pro 2019, are able to correctly
handle Dolby Vision Profile 7. However, when a Full Enhancement Layer
(FEL) is present, these devices effectively ignore the enhancement layer
and only apply the RPU metadata.
Due to this behavior, device capabilities are reported as not supporting
`DOVIWithEL`, which causes the Jellyfin server to strip the DV layer
entirely with a remux.
This commit adds an option to force direct play of Dolby Vision Profile
7 content, preventing the server from stripping the Dolby Vision layer
and allowing compatible devices to handle playback as intended.
### Related issues
Fixes https://github.com/damontecres/Wholphin/issues/449
### Screenshots
<img width="1280" height="720" alt="dovi7"
src="https://github.com/user-attachments/assets/849e9897-93b6-419f-a1fb-7f361f9c88dd"
/>
### AI/LLM usage
None
Co-authored-by: Ray <154766448+damontecres@users.noreply.github.com>
## 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>
## 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
## 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#428Fixes#531
Redesign Select Server and Select User screens with horizontal card
layout, similar to traditional streaming services
- Replace vertical lists with horizontal list of icons
- Center align text in Quick Connect and Username/Password modals
- Display Jellyfin profile images
- Fallback to first letter of username if no image is available
- Filter out duplicate server entries in the auto-discovery list
---------
Co-authored-by: Damontecres <damontecres@gmail.com>
**This is for MPV playback backend only!** Since this only works in MPV
for now, the option is not shown if using ExoPlayer.
Adds a setting (the gear icon during playback) to adjust the subtitle
delay.
A negative delay shows subtitles sooner. A positive delay shows them
later. For example, if a subtitle is supposed to show between
1000ms-2000ms, a negative 250ms delay will show it at 750ms-1750ms
instead.
The delay is persisted between plays of the same media & subtitle track.
Ref: #12

Adds a view options button for the TV guide to allow some basic
customization:
* Show details header
* Adjust how channels are sorted
* Toggle color coding for programs
Related to #250Closes#288Fixes#439
Adds an advanced playback setting to enable automatic refresh rate
switching during playback
When enabled, the app looks at the available display modes, chooses the
best candidate, and attempts to switch to it. After playback ends, the
display is switched back to the original mode.
Closes#62Closes#379
Adds a new button implementation which allows for icon buttons to be
circular. Overall the buttons are reduced in size.
Also, the playback controls are are reduced in size, buttons are smaller
and vertical padding is reduced.

Adds a settings allowing for adjusting the thickness of unstyled
subtitle outlines, if outline is enabled.
This is applied for both ExoPlayer & MPV
Closes#179

Dev note: the ExoPlayer implementation is bad code, don't write code
like this. It works though
Allows for setting a per-user profile PIN that must be entered to switch
to the user. The PIN is a sequence of directional buttons, ie D-Pad
left/right/up/down.
This PIN is per device per user per server. The PIN is stored locally
and not sent nor shared with the server. If you forget your PIN, can
still access the app using server credentials which also removes the
PIN.
Additionally, there is another setting to disable automatically sign in.
When enabled (default) the last user is automatically restored, even if
there is a PIN. If disabled, a server & user must always be selected
when opening the app.
Closes#268Closes#321
## Details
Adds options to customize how grid pages are displayed. Every grid page
can be individually customized.
The options are saved per user on the device and restored when
navigating back to the page. The pages that support it have a new button
next to the sort/filter buttons and changes are updated live.
The options are:
* Primary or Thumb image
* Aspect ratio
* Show details header w/ backdrop (similar to the one on the home page)
* Number of columns
* Spacing between cards
* Card image content scale (eg Fit, Fill, Crop, etc)
Note: the Genre tabs' grids cannot be customized yet
### Other changes
- Nav drawer now opens over top of content instead of pushing it
- Images for most cards are fetched with actual fill size
### Possible future work
* Customize Genre grids
* Add more image types, banners?
* Add similar customization options to pages with rows, eg Home page and
Recommended tabs
## Example
For example, this is a movie library using thumb images with 8 columns
and reduced spacing. It also shows the details header
## Issues
Closes#186
Related to #72
## Details
This PR contains a number of optimizations
### Images
Updates to request images with maximum sizes
The max sizes are estimates on the maximum number of pixels that will be
actually displayed. This means the server is downscaling large images
which means 1) better quality downscaling and 2) smaller images sent
over the network and cached
This should mean slightly better quality images and more images that can
be cached locally
### Paging
Reduces network calls when fetching paginated data, ie grid pages and
some rows. This PR combines the total record count & first page queries
which slightly reduces total time to load paginated data.
Additionally, on movies/tv show recommended pages, the rows now only
fetch a limited number of items (same as number on home page). While
they previously fetched using pagination, there is an overhead required
to paginate requests, so this is slightly faster.
### Async recommended fetching
On movies/tv show recommended pages, the rows are now fetched completely
separately from each other. Previously, the rows were requested
separtely, but each was only added to the UI in order as each completed.
Now they will add as the data arrived.
Note: Top unwatched TV shows is still very slow on `10.11.x`, see #204
### Image cache
The local, on-disk image cache size is increased from 100mb to 200mb.
Combined with the smaller images, this covers about 1500-2000 poster
images, but will vary by server.
The cache size is now also configurable in advanced settings from 25mb
to 1000mb. Additionally, you can see how much of both the disk and
memory caches are in use.
## Issues
Closes#330
Related to #120
Adds a toggle to increase the verbosity of the app logs for
release/production builds
Most users won't need to use this, but it can be helpful when [gathering
app
logs](https://github.com/damontecres/Wholphin/wiki/Gathering-app-logs)
to report an issue.
Adds a subtitle style option to set the margin below unstyled subtitles.
This is roughly the percent of the screen below the subtitles. It
applies to both ExoPlayer & MPV.
Also fixes font & background opacity not being applied in some cases.
Fixes#225Closes#178
## Details
This PR updates the detail pages for Movies & TV Shows.
- Increase backdrop image size & brightness (now matches home page)
- Increase max width for titles
- Decrease max width for detail text
- Switch to using a customized display labels for video, audio, &
subtitle streams
Additional change for movie pages:
- Don't dim movie details text
- Move video stream details below play buttons
- Move first row up higher
### Labels
Instead of using the server provided `DisplayTitle`, create display
labels in-app. In general, this shortens the text without losing
significant detail. It is similar to the official app.
Some of the changes:
- Don't show "SDR", only "HDR"
- Simplify audio channel info, eg "Surround 5.1" => "5.1"
- Show chosen subtitle language
- Show chosen subtitle codec
- Show "(+#)" if there are additional audio or subtitle tracks
- Use gray background slightly tinted by the theme color
## Issues
Closes#239
Adds a button to filter contents next to the sort button on grid pages
The filters are saved and restored you return to the page. It works with
#278, playing the filtered items in the sorted order.
The drop down menus for both sorting & filtering are updated to closer
match the overall look.
Filters for:
- Played or unplayed
- Favorite or not
- Genres
- Community (star) rating
- Parental rating
- Video type (HD vs SD, etc)
- Release year and/or decade
Changes the skip segment button text to use a single phrase instead of
concatenating two strings. This allows correct context when translating.
Follow up from #292
Use the server scoring API when adding a new server. This allows just
entering a hostname or IP address without the scheme (`http`/`https`) or
port in most cases.
Note: non-standard ports would still need to be provided
Closes#5Closes#296
Adds "Bold Blue" and Black/OLED themes
Also tweaks Orange & Green a bit to make the borders stronger and
backgrounds darker/less colored
Related to #91
## Description
Shows local extras (clips, interviews, etc) for movies and tv shows
Extras are grouped by type and clicking on the type will go to a grid
page listing all of the items. However, if there is just one of that
type, it is shown in-line.
Trailers still have on their own row. And theme songs & theme videos are
not shown.
## Issues
Closes#123