Compare commits

...

537 commits
v1.0.4 ... main

Author SHA1 Message Date
f4fb6e22c9 Merge pull request 'Fix TV episode Back navigation and live Resume freshness' (#48) from fm/tv-fb2-fix into main 2026-11-06 22:59:33 +01:00
5bd2affc1a Preserve title authority reset during watch refresh
All checks were successful
review/code-gpt Firstmate read the PR evidence and diff stat: TV navigation, live resume read at click, stop-ack refresh, season focus; 83 targeted cases pass, apk-debug green; full suite has six PersonPickerSessionTest timeouts (disclosed, cause unisolated; bisect on main follows); person switching is verified on the real box before it ships
review/design-claude Firstmate read the PR evidence and diff stat: TV navigation, live resume read at click, stop-ack refresh, season focus; 83 targeted cases pass, apk-debug green; full suite has six PersonPickerSessionTest timeouts (disclosed, cause unisolated; bisect on main follows); person switching is verified on the real box before it ships
2026-11-06 22:49:43 +01:00
8e40ac0869 Fix TV episode navigation and live resume freshness 2026-11-06 22:41:16 +01:00
54c23e076a Merge pull request 'Fix TV artwork, episode layout and focus visibility' (#47) from fm/tv-fb1-visual into main 2026-11-06 22:04:17 +01:00
12fd12f754 Merge remote-tracking branch 'origin/main' into fm/tv-fb1-visual
All checks were successful
review/code-gpt Firstmate read the diff and evidence (native before/after frames, hero decode proof, episode art chain, gear centered per owner answer); apk-debug green; full serial suite NOT green (4 PersonPickerSessionTest timeouts, cause unisolated, disclosed in the PR body), accepted by firstmate with real-box person-switch verification before anything ships to the owner
review/design-claude Firstmate read the diff and evidence (native before/after frames, hero decode proof, episode art chain, gear centered per owner answer); apk-debug green; full serial suite NOT green (4 PersonPickerSessionTest timeouts, cause unisolated, disclosed in the PR body), accepted by firstmate with real-box person-switch verification before anything ships to the owner
2026-11-06 20:39:32 +01:00
7b88f9b54b Remove obsolete episode header position assertion 2026-11-06 20:39:32 +01:00
5162c299db Merge pull request 'Ground Discover watch claims and request history in evidence' (#46) from fm/tv-fb1-truth into main 2026-11-06 20:37:47 +01:00
9d2471c5b1 Fix TV artwork, episode layout and focus visibility 2026-11-06 20:25:50 +01:00
278335f009 Present watched recommendation seeds and request history truthfully
All checks were successful
review/code-gpt Firstmate read the PR evidence: TV-only labels and seed grouping, recorded-wire acceptance matrix, fixtures contain no secrets (checked), native before/after frames, full serial suite 697/190/17 green plus apk-debug; no tokens, ring or spacing changes; device check follows
review/design-claude Firstmate read the PR evidence: TV-only labels and seed grouping, recorded-wire acceptance matrix, fixtures contain no secrets (checked), native before/after frames, full serial suite 697/190/17 green plus apk-debug; no tokens, ring or spacing changes; device check follows
2026-11-06 20:12:06 +01:00
deb24e3c9f Merge pull request 'Persist the debug signing key across container builds' (#45) from fm/tv-stable-key into main 2026-11-06 19:54:26 +01:00
556d633e88 Persist the debug signing key across container builds
All checks were successful
review/code-gpt Build-script only (docker/gradle.sh + README): persistent debug keystore outside the checkout, readonly bind-mount, fails loudly; firstmate read the diff; lane showed identical signer SHA-256 across two optimized builds and the debug build
2026-11-06 17:37:36 +01:00
34087d8eb5 Merge pull request 'Unify TV control focus rings with the approved card style' (#44) from fm/tv-focus-style into main 2026-11-06 15:58:25 +01:00
33dc65bf18 Merge remote-tracking branch 'origin/main' into fm/tv-focus-style
All checks were successful
review/code-gpt Firstmate read the PR evidence and viewed the before/after pairs and native captures against the approved card ring (4 px straddle, no gap); measured ring bounds, inventory with unchanged fill surfaces listed; 20+ targeted native captures and key/session tests; device verification follows on the optimized build
review/design-claude Firstmate read the PR evidence and viewed the before/after pairs and native captures against the approved card ring (4 px straddle, no gap); measured ring bounds, inventory with unchanged fill surfaces listed; 20+ targeted native captures and key/session tests; device verification follows on the optimized build
2026-11-06 15:52:02 +01:00
ef3ae3f21b Unify focus rings on the approved accent straddle style 2026-11-06 15:52:02 +01:00
d0e38306b3 Merge pull request 'Add a release-derived optimized TV comparison build' (#43) from fm/tv-opt-build into main 2026-11-06 15:45:03 +01:00
5306f8ddc4 Keep optimized versions compatible with upgrade and update parsing
All checks were successful
review/code-gpt Build-only change (new optimized build type, own package, baseline seed, version parser test) read by firstmate; release and debug unchanged; the optimized APK was installed and run on the real box (sign-in, picker, Home, Movies work under R8; 0.4 s cold start, 14x lower p99 frame time than debug); version-suffix defect found on the box and fixed in this head
2026-11-06 15:36:20 +01:00
59f4a06815 Register the optimized baseline profile source explicitly 2026-11-06 15:21:19 +01:00
427b18cdc5 Add a release-derived optimized TV comparison variant 2026-11-06 15:12:01 +01:00
93a41ea2d3 Merge pull request 'Keep the person picker closed after switching users' (#42) from fm/tv-picker-ok into main 2026-11-06 15:01:46 +01:00
1c21f50acb Keep the person picker closed after switching users
All checks were successful
review/code-gpt Picker double-OK fix verified on the real box (B9): three single-OK person switches justin/mindel/shared, no crash, logcat clean; 45 targeted tests, final-head apk build
2026-11-06 14:48:36 +01:00
e8d0c52088 Merge pull request 'Keep TV person switches off the main-thread socket close path' (#41) from fm/tv-person-switch-fix into main 2026-11-06 14:18:51 +01:00
db2541feff Move person-switch client disposal off the main thread
All checks were successful
review/code-gpt Person-switch crash fix verified on the real box (B8: justin/mindel/shared switched via the picker three times, no crash, logcat clean); firstmate read the ConductarrSession disposal-scope delta (generation-guarded, IO disposal, no double close); 53 targeted tests
2026-11-06 14:05:01 +01:00
f37ad0f0fe Merge pull request 'Give TV cards roomy spacing and edge-straddling focus rings' (#40) from fm/tv-spacing-b7 into main 2026-11-06 13:24:16 +01:00
92c5661be0 Preserve poster progress and focus across library rail changes
All checks were successful
review/code-gpt GPT review blockers fixed and read by firstmate: poster progress inset back to Title.cardProgressInset (220 px track) with test tag + regression; library focus-follow effect keyed on columns/focusedRow/header/rowHeight with a 199<->200 regression; token values/ring bounds/toolbar gap passed review on c17447c5; walked on the real box
2026-11-06 13:21:06 +01:00
b9ea593735 Merge remote-tracking branch 'origin/main' into fm/tv-spacing-b7 2026-11-06 13:17:37 +01:00
711dbebf28 Merge pull request 'Fix TV startup navigation and complete title pages' (#39) from fm/tv-walk-fix1 into main 2026-11-06 13:16:43 +01:00
6e0f9952cf Reconcile removed Anime roots without discarding pushed pages
All checks were successful
review/code-gpt GPT review blocker B1 (Anime root removal strands Back) fixed: delta read by firstmate (ShellState reconciles route/root to Home, preservePushed replaces stack root, 111-line regression, 16 targeted tests green); all other review areas cleared on 9e15dbee
2026-11-06 13:11:08 +01:00
c17447c528 Give TV cards roomy spacing and edge-straddling focus rings
Some checks failed
review/code-gpt Spacing review: progress-bar inset regression; rail transition focus invalidation
2026-11-06 12:53:51 +01:00
9e15dbee8c Preserve navigation focus when Anime availability changes
Some checks failed
review/code-gpt Anime removal leaves active root invalid; Back pops a singleton stack (B1).
2026-11-06 12:33:10 +01:00
53b8358317 Hide Anime destinations without visible library titles 2026-11-06 12:25:51 +01:00
5a84666074 Synchronize fresh-sign-in navigation and restore test globals 2026-11-06 12:11:42 +01:00
22850632ec Restrict shell route and Back handling to the current entry 2026-11-06 12:03:20 +01:00
afff383b75 Read live shell state inside cached navigation entries 2026-11-06 11:52:48 +01:00
d401ebc355 Fix TV startup navigation and complete title pages 2026-11-06 11:27:35 +01:00
e794dec253 Merge pull request 'Fix post-sign-in crash from snapshot state writes' (#38) from fm/tv-hotfix-snapshot-write into main 2026-11-06 11:09:51 +01:00
4e6377b628 Keep shell state reads safe in read-only snapshots
All checks were successful
review/code-claude Hotfix verified on the real Xiaomi box (B3 runs, no crash across Home/Discover/Movies/Shows/title/Settings/Requests); 5-file delta read by firstmate: ShellState.rememberedView no longer writes on read, 3 regression tests incl. snapshotFlow and an audit
2026-11-06 10:50:56 +01:00
e9a92eba49 Merge pull request 'Align TV fidelity and recovery behavior' (#37) from fm/tv-fidelity-followups into main 2026-11-06 02:35:14 +01:00
81073c410d Synchronize progressive focus assertions with UI publication
All checks were successful
review/design-claude Claude review: PASS, no blocking finding (head 81073c41)
2026-11-06 02:20:13 +01:00
04b1bdd6aa Align TV layouts and close recovery gaps 2026-11-06 02:15:09 +01:00
bfe3dbbb16 Merge pull request 'Wire real Conductarr data into Wolfskin TV' (#36) from fm/tv-conductarr-wiring into main 2026-11-06 01:41:47 +01:00
ec32346c71 Isolate the artwork test singleton lifecycle
All checks were successful
review/code-claude B1 (artwork credential scoped to the exact Jellyfin scheme/host/port by a network interceptor, fresh ImageLoader, redirect-safe, 2-host test) and B2 (audiences null keeps the name rule, foreground recovery, test) verified by firstmate reading the 9-file delta; final gates green
2026-11-06 01:32:59 +01:00
34ea983a51 Scope artwork credentials and preserve library recovery 2026-11-06 01:25:47 +01:00
09f1d72f30 Keep Home responsive and resolve authorized request recipients
Some checks failed
review/code-claude Block: token sent to image hosts via Coil auth client; failed audiences read hides Jellyfin libraries
2026-11-06 00:31:48 +01:00
78322f588a Integrate real Conductarr TV title and recovery providers 2026-11-06 00:10:27 +01:00
a00db96dc8 Merge current TV recovery states into Conductarr wiring 2026-11-05 23:24:21 +01:00
71a055987c Merge pull request 'Build the Wolfskin TV title, episode and person pages' (#34) from fm/tv-slice5-titles into main 2026-11-05 23:21:03 +01:00
844530404d Integrate shared offline recovery and saved-state isolation
All checks were successful
review/design-claude 13 fixes passed Sonnet re-review at cd625b42; merged head 84453040 = main merge + shared RecoveryToast reuse: 33/34 pairs byte-identical, st-048 adopts the shared toast, 830 tests green (firstmate check)
2026-11-05 22:59:45 +01:00
59c2728d9c Wire selected Jellyfin users to Conductarr TV data 2026-11-05 22:55:54 +01:00
f53defad90 Update Conductarr TV contracts and ratings reads 2026-11-05 22:55:25 +01:00
abec496305 Merge pull request 'Add TV offline recovery and per-person saved-state isolation' (#35) from fm/tv-slice8-states into main 2026-11-05 22:43:13 +01:00
a01c0a78fb Add TV offline recovery and per-person state isolation
All checks were successful
review/design-claude Claude Sonnet cross-family review: pass, no blockers
2026-11-05 22:11:00 +01:00
cd625b4227 Remove unreachable duplicate glyph branches and assets
All checks were successful
review/design-claude Round 2: 13/13 round-1 blockers fixed, no blockers on cd625b42
2026-11-05 21:55:04 +01:00
fc02ce8646 Integrate native Home and replay full title launch paths 2026-11-05 21:49:34 +01:00
2fdd459037 Match title CSS geometry and fix modal focus and subtitle choices 2026-11-05 21:38:46 +01:00
9dd321f07e Merge pull request 'Build the Wolfskin TV Home feed' (#31) from fm/tv-slice3-home into main 2026-11-05 21:34:29 +01:00
061670848f Keep overlapping screen captures in separate namespaces
All checks were successful
review/design-claude Design re-review: B1-B3 fixed, no blocking findings (head 06167084)
2026-11-05 21:07:22 +01:00
575103ce98 Integrate Discover with canonical shared UI 2026-11-05 20:57:57 +01:00
e243894a20 Integrate reviewed Requests and Discover surfaces
Some checks failed
review/design-claude Changes requested: 13 blocking design/behaviour findings (see PR comment)
2026-11-05 20:46:58 +01:00
86d3432fb0 Merge pull request 'Build Discover TV picks, hidden titles and request flows' (#33) from fm/tv-slice6-discover into main 2026-11-05 20:35:19 +01:00
43ae716157 Preserve native title line boxes and async focus 2026-11-05 20:26:43 +01:00
5033c171cb Preserve Requests recovery button activation 2026-11-05 20:24:10 +01:00
130697c2eb Clamp Discover text boxes and preserve recovery button height
All checks were successful
review/design-claude B1-B3 re-measured by firstmate from the lane measurement file against the locked numbers (all within 2 px); delta is the three scoped fixes plus an additive main merge; N1/N2 3-4 px offsets remain as listed follow-ups
2026-11-05 20:22:47 +01:00
4cd75cfa26 Integrate Requests with the shared image cache 2026-11-05 20:20:06 +01:00
bfd4002dd1 Merge Requests screens from main 2026-11-05 20:11:00 +01:00
1c77f21df3 Merge pull request 'Build TV Requests under Settings' (#32) from fm/tv-slice7-requests into main 2026-11-05 20:06:36 +01:00
a8951827ba Reuse shared artwork and correct title focus edges 2026-11-05 19:58:36 +01:00
e99ed2d394 Use the locked Home See all spacing 2026-11-05 19:53:51 +01:00
924c90a9e0 Align readiness glyphs to inline text baselines
All checks were successful
review/design-claude B1-B5/B7 verified fixed by Sonnet re-review at b8d5d8a1; B8 readiness block-line replication checked by firstmate: 6-file delta, baseline/no-gap code only, st-086 pair viewed, two-line wrap is font-caused and recorded; B6 approved by Justin
2026-11-05 19:53:32 +01:00
1299034991 Match Discover shadows, text rhythm and asynchronous focus
Some checks failed
review/design-claude Changes requested: 3 blocking design deviations (st-032 sheet rhythm, st-036 button squeeze, hero stack offset)
2026-11-05 19:39:13 +01:00
9c8fceb18c Restore Home viewport across See all navigation 2026-11-05 19:28:09 +01:00
b8d5d8a124 Preserve contained rating marks inside dark chips
Some checks failed
review/design-claude B1-B5,B7 fixed; B8 readiness item glyph/gap geometry deviates from locked st-086
2026-11-05 19:10:25 +01:00
14a74ac43b Integrate libraries and correct Home review blockers 2026-11-05 19:03:33 +01:00
d9578ac405 Match Requests sheets to locked design frames 2026-11-05 18:58:06 +01:00
4e62aad638 Reuse baseline-aligned headers with source subtitle typography 2026-11-05 18:37:58 +01:00
b1b15b384b Keep catalogue outcomes and recovery consistent across views 2026-11-05 18:32:09 +01:00
c1559e2513 Merge Libraries and reuse the shared catalogue surface 2026-11-05 17:55:49 +01:00
3bfb8cd779 Merge shared library surfaces and connect title navigation 2026-11-05 17:54:34 +01:00
439eea3ff8 Merge library slice and reuse shared image policy
Some checks failed
review/design-claude Changes requested: 7 design-parity findings (separator opacity, line-box rhythm, stage gap, mark chips, avatar, count, thumb fringe)
2026-11-05 17:41:43 +01:00
fc7eb94cc1 Record native title metrics and reuse SDK fixtures 2026-11-05 17:40:55 +01:00
03ff22ea86 Preserve request outcomes and align Discover shelf windows 2026-11-05 17:37:39 +01:00
5b0703aec5 Build household requests under Settings 2026-11-05 17:35:42 +01:00
96538f3c7a Merge pull request 'Build TV libraries and continuous See all grids' (#30) from fm/tv-slice4-libraries into main 2026-11-05 17:35:12 +01:00
b54bcc148c Follow visible card centers and remember Home tracks
Some checks failed
review/design-claude Request changes: separator dot colour, vertical rhythm, focus entry after load
2026-11-05 17:16:06 +01:00
0ca13e684f Merge main after TV shell lands 2026-11-05 17:14:09 +01:00
6d7df0fb19 Preserve title data and focus across updates 2026-11-05 17:13:53 +01:00
321f2d41bb Match library header initials to the locked muted colour
All checks were successful
review/design-claude B1/B2 passed Sonnet re-review at 60a0da13; B3 (header avatar initial muted) checked by firstmate: 3 files, default-preserving letterColor param, only LibraryHeader passes muted
2026-11-05 17:13:47 +01:00
90e956b157 Measure native Discover typography and focus boundaries 2026-11-05 17:04:45 +01:00
2b65ee7b53 Preserve the person identity guard on Home 2026-11-05 16:57:20 +01:00
60a0da13a2 Document visible tail navigation and library typography
Some checks failed
review/design-claude Header avatar initial must be muted like the locked frames; tail Down and separator dot fixed
2026-11-05 16:55:12 +01:00
5a0497c9ec Merge the reviewed shell from main 2026-11-05 16:50:59 +01:00
6f430439a6 Merge the shipped TV shell into Discover 2026-11-05 16:50:52 +01:00
4b28b4f044 Match Discover captions and catalogue collection states 2026-11-05 16:50:38 +01:00
3b7249888f Match Home focus and recovery details 2026-11-05 16:50:32 +01:00
e5bb4ec47f Merge remote-tracking branch 'origin/main' into fm/tv-slice4-libraries 2026-11-05 16:50:24 +01:00
7a878b2d81 Merge pull request 'Build the Wolfskin TV shell and navigation' (#29) from fm/tv-slice2-shell into main 2026-11-05 16:49:28 +01:00
b24c404cc8 Merge the reviewed settings pill border correction
# Conflicts:
#	wolfskin-design/tokens.sha256
2026-11-05 16:44:52 +01:00
a6dd04f390 Keep library focus on visible rows and match caption facts 2026-11-05 16:44:21 +01:00
74033ee1da Match the settings pill border to the prototype
All checks were successful
review/design-claude B1/B2/N1/N4 passed Sonnet re-review at 2ea93010; B3 pill border one-frame re-check by firstmate: dash rhythm and 1dp stroke match, delta additive (6 files, pill only)
2026-11-05 16:28:09 +01:00
7e8e232d47 Merge the corrected TV shell into Discover 2026-11-05 16:19:00 +01:00
c534ea75c2 Use resolved weights for episode rating labels 2026-11-05 16:18:40 +01:00
6a02887dc9 Build the Discover catalogue and request flow 2026-11-05 16:18:19 +01:00
0c94e8f910 Merge reviewed TV shell focus and text fixes 2026-11-05 16:17:42 +01:00
c07bb2ca1d Merge the reviewed shell updates 2026-11-05 16:17:38 +01:00
0db05174b1 Build native title and person surfaces 2026-11-05 16:16:02 +01:00
0fd0ec035d Build the Wolfskin Home feed 2026-11-05 16:15:40 +01:00
3da635b4cb Merge reviewed TV shell changes into libraries
Some checks failed
review/design-claude Changes requested: tail-card Down focus bug and caption separator opacity
2026-11-05 16:11:29 +01:00
27fd174aed Preserve full line boxes in library recovery panels 2026-11-05 16:05:25 +01:00
2ea9301069 Assert the declared owned-screen background colour
Some checks failed
review/design-claude B1/B2 fixed; settings pill dashed stroke 2x spec (blocking)
2026-11-05 15:52:12 +01:00
380c423376 Build TV libraries and continuous See all grids 2026-11-05 15:51:24 +01:00
4b89a73908 Restore upstream content focus and deterministic shell typography 2026-11-05 15:39:56 +01:00
9be55c570a Integrate the Conductarr client with the Wolfskin shell
Some checks failed
review/design-claude Changes requested: switch-off path loses backdrop/Up focus; font weight deviation in captures
2026-11-05 14:50:04 +01:00
f60a22e435 Build the Wolfskin TV shell and navigation 2026-11-05 14:38:38 +01:00
2be4e30826 Merge pull request 'Add the pinned Conductarr TV client and disk-backed saved data' (#28) from fm/tv-conductarr-client into main 2026-11-05 13:18:47 +01:00
adbfe5d0e7 Add the pinned Conductarr TV client and disk cache
All checks were successful
review/code-claude Claude cross-family review: clean, no blocking findings
2026-11-05 12:56:06 +01:00
de452448ba Merge pull request 'Merge Wholphin v1.1.0 while preserving Wolfskin features' (#27) from fm/wolfskin-upstream-1-1-0 into main 2026-11-05 01:49:35 +01:00
670e95f2fa v1.1.0
All checks were successful
review/code-claude Claude cross-family review: approve, no blocking findings
-----BEGIN SSH SIGNATURE-----
 U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgrqffh93Kw9xITbVISXK/jkih9K
 Q1NSQeC6TBqiLCg2oAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5
 AAAAQOwlHRfQqaoMZESsY18BqmXMIMwtJzU8cAEB2FWHNv5x2j/ZsGi8ES7VNW+rYtgV/B
 KF9ctdqeDoocL8r8da+AY=
 -----END SSH SIGNATURE-----

Merge upstream v1.1.0 while preserving Wolfskin customizations
2026-11-05 01:39:09 +01:00
Damontecres
2bb662fd60
Release v1.1.0 2026-11-03 17:55:49 -05:00
Damontecres
1fdc7f7d84
Translations 2026-11-03 (#2169)
Update translations as of 2026-11-03

A big thank you to all of the contributors!
2026-11-03 16:45:35 -05:00
Damontecres
a3bd0137b3
Fix style 2026-11-03 16:35:02 -05:00
Damontecres
1d880c9562
Release v1.1.0 2026-11-03 15:28:48 -05:00
Damontecres
d711760dbe
Minor bug fix (#2167)
## Description
- Fixes typo that could prevent restoring a page with artists or album
artists
- Clarified some javadocs

### Related issues
N/A

### Testing
Emulator

## Screenshots
N/A

## AI or LLM usage
None
2026-11-03 14:52:56 -05:00
coulterj
06c1d622bb
Fix HDHomeRun Live TV direct playback by including the live stream ID (#2163)
## Description

I was having trouble playing HDHomeRun channels through Jellyfin in
Wholphin. They started quickly in the official Jellyfin app, but
Wholphin would sometimes spin or fall back when switching channels.

This change includes the live stream ID returned by Jellyfin when
building the Direct Play URL. It also adds a regression test.

### Related issues

Related to #2014 and possibly #1903. My testing was with an HDHomeRun; I
haven’t verified the TVHeadend setups in those reports.

### Testing

Tested on a Google TV Streamer with multiple local channels, FAST
channels, and movie playback. The tested content used Direct Play, and
the HDHomeRun tuners were released after stopping.

All 18 playback tests and the formatting check passed after the
requested test cleanup.

## Screenshots

No UI changes.

## AI or LLM usage

I used OpenAI Codex to help investigate the issue, implement the change
in PlaybackViewModel.kt, add the regression test in
PlaybackViewModelTests.kt, and run validation. Codex also helped draft
this description.
2026-11-03 11:18:41 -05:00
TheMatrixan
e53e8b7c67
Translated using Weblate (Polish)
Currently translated at 100.0% (696 of 696 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/pl/
2026-11-03 07:27:18 +00:00
ymir
c5a07f1ab8
Translated using Weblate (French)
Currently translated at 100.0% (696 of 696 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/fr/
2026-11-03 07:27:16 +00:00
Priit Jõerüüt
b04cba4d6e
Translated using Weblate (Estonian)
Currently translated at 100.0% (696 of 696 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/et/
2026-11-03 07:27:16 +00:00
idezentas
3a8fa272f4
Translated using Weblate (Turkish)
Currently translated at 100.0% (696 of 696 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/tr/
2026-11-02 06:27:17 +00:00
American_Jesus
5dd30ea93f
Translated using Weblate (Portuguese)
Currently translated at 99.8% (695 of 696 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/pt/
2026-11-02 06:27:16 +00:00
North-DaCoder
66ca418261
Translated using Weblate (German)
Currently translated at 100.0% (696 of 696 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/de/
2026-11-02 06:27:15 +00:00
SimonHung
4b2c64dcb5
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 99.1% (689 of 695 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/zh_Hant/
2026-10-31 19:35:01 +00:00
Priit Jõerüüt
7fbee0dff7
Translated using Weblate (Estonian)
Currently translated at 100.0% (695 of 695 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/et/
2026-10-31 19:35:01 +00:00
idezentas
509f566514
Translated using Weblate (Turkish)
Currently translated at 100.0% (693 of 693 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/tr/
2026-10-31 19:35:01 +00:00
arcker95
45392b0563
Translated using Weblate (Italian)
Currently translated at 100.0% (693 of 693 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/it/
2026-10-31 19:35:01 +00:00
North-DaCoder
1208699b6e
Translated using Weblate (German)
Currently translated at 99.5% (690 of 693 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/de/
2026-10-31 19:35:01 +00:00
Greeg0ry
78c18b09aa
Translated using Weblate (Russian)
Currently translated at 100.0% (693 of 693 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/ru/
2026-10-31 19:35:01 +00:00
Priit Jõerüüt
3a6d75618e
Translated using Weblate (Estonian)
Currently translated at 100.0% (693 of 693 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/et/
2026-10-31 19:35:01 +00:00
PreAcc
0cbcfd9269
Translated using Weblate (Hungarian)
Currently translated at 82.9% (573 of 691 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/hu/
2026-10-31 19:35:01 +00:00
TheMatrixan
53de7073d4
Translated using Weblate (Polish)
Currently translated at 100.0% (691 of 691 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/pl/
2026-10-31 19:35:01 +00:00
SimonHung
b918055b34
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 99.4% (687 of 691 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/zh_Hant/
2026-10-31 19:35:01 +00:00
ymir
6d37c36c1c
Translated using Weblate (French)
Currently translated at 100.0% (691 of 691 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/fr/
2026-10-31 19:35:01 +00:00
Priit Jõerüüt
03c6c78903
Translated using Weblate (Estonian)
Currently translated at 100.0% (691 of 691 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/et/
2026-10-31 19:35:01 +00:00
Prahlis
b25aa56277
Translated using Weblate (Swedish)
Currently translated at 91.0% (629 of 691 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/sv/
2026-10-31 19:35:01 +00:00
harupong
43a4e6d296
Added translation using Weblate (Japanese) 2026-10-31 19:35:01 +00:00
tal_sarid
ecbf1e68df
Translated using Weblate (Hebrew)
Currently translated at 100.0% (670 of 670 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/he/
2026-10-31 19:35:01 +00:00
danpergal84
6ba2d8ced5
Translated using Weblate (Spanish)
Currently translated at 100.0% (670 of 670 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/es/
2026-10-31 19:35:01 +00:00
PreAcc
02261f3993
Translated using Weblate (Hungarian)
Currently translated at 72.9% (489 of 670 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/hu/
2026-10-31 19:35:01 +00:00
filippvl
546c00ba1a
Translated using Weblate (Serbian)
Currently translated at 20.4% (137 of 670 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/sr/
2026-10-31 19:35:01 +00:00
opakholis
a272cea6a0
Translated using Weblate (Indonesian)
Currently translated at 100.0% (670 of 670 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/id/
2026-10-31 19:35:01 +00:00
TheMatrixan
a4abd56274
Translated using Weblate (Polish)
Currently translated at 100.0% (670 of 670 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/pl/
2026-10-31 19:35:01 +00:00
ymir
545ef636ff
Translated using Weblate (French)
Currently translated at 100.0% (670 of 670 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/fr/
2026-10-31 19:35:01 +00:00
n8llcaster
b4c5697755
Translated using Weblate (Slovak)
Currently translated at 100.0% (670 of 670 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/sk/
2026-10-31 19:35:01 +00:00
Priit Jõerüüt
f4178ce803
Translated using Weblate (Estonian)
Currently translated at 100.0% (670 of 670 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/et/
2026-10-31 19:35:00 +00:00
North-DaCoder
3fe6054813
Translated using Weblate (German)
Currently translated at 100.0% (670 of 670 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/de/
2026-10-31 19:35:00 +00:00
idezentas
e9c8f8483d
Translated using Weblate (Turkish)
Currently translated at 100.0% (670 of 670 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/tr/
2026-10-31 19:35:00 +00:00
arcker95
ffc4d2fd5e
Translated using Weblate (Italian)
Currently translated at 100.0% (670 of 670 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/it/
2026-10-31 19:35:00 +00:00
SimonHung
d03538c8bb
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (670 of 670 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/zh_Hant/
2026-10-31 19:35:00 +00:00
Priit Jõerüüt
6b3a0872b1
Translated using Weblate (Estonian)
Currently translated at 99.8% (669 of 670 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/et/
2026-10-31 19:35:00 +00:00
Damontecres
38bd690c85
Update dependencies (#2157)
Updates dependencies to max versions still supporting API level 23

#2152 will allow for further updates
2026-10-31 15:34:57 -04:00
Ali Alaei
46bf78aac4
Allow play/pause from untrusted media controllers (#2145)
## Description
- From media3 1.11, controllers that aren't trusted get read-only player
commands by default.
- Google Home sends its commands through
com.google.android.apps.mediashell (Google's Cast service on the TV),
which isn't trusted, so play/pause from it was dropped.
- Logcat showed: MediaSessionLegacyStub: Calling play() omitted due to
COMMAND_PLAY_PAUSE not being available
- The change: a MediaSession.Callback (TrustAllControllersCallback in
PlayerFactory.kt) that gives every controller all player commands again.
It uses onConnectAsync and AcceptedResultBuilder(session, controller),
so untrusted controllers keep the restricted session commands.
- It's applied to the video session (createMediaSession) and the music
session (MusicService).
- It probably started with the media3 1.11 bump in #1814.

### Related issues
<!-- If this is a new feature or a change, there must be a discussion in
an issue first, reference the issue here -->
<!-- If fixing a bug, reference the bug issue here, or describe the bug,
including steps to reproduce -->
- Fixes #2087 

### Testing
- JMGO N1S 4K, Google TV, Android 14, ExoPlayer.
- Before the fix: play/pause from Google Home did nothing, and logcat
showed the "omitted" warning.
- After the fix: pause and play from Google Home work. Logcat shows each
command reaching handleSetPlayWhenReady, and the warning is gone.
- The TV remote still works.
- I didn't test music playback; leave that out or test it first.

## Screenshots
- None; no UI changes.

## AI or LLM usage
- Claude Code read the logcat output, found the media3 1.11
untrusted-controller change, and wrote TrustAllControllersCallback plus
the two setCallback(...) calls.
2026-10-31 15:24:07 -04:00
Clint Bird
d2713ff2f5
Can Select Artist or Album Artist to be displayed on Music > Artists Page (#2127)
## Description
The Music / Artists view currently appears to use the artist metadata
from individual tracks. While at a track level this makes perfect sense,
it can result in a very noisy and fragmented artists view.

For example, an album by Eminem might contain tracks with artists such
as:
- Eminem
- Eminem feat. 50 Cent
- Eminem ft. Rihanna
- Eminem & Dr. Dre

Each of these seem to appear as a separate artist entry (even though
they are all tracks from the same album by Eminem)

This becomes particularly noticeable in large music libraries, where
featured artists, collaborations, remixes, and slightly different artist
metadata ends up resulting in a large number of sparsely populated or
duplicate / strange looking artist entries.

This PR adds an option / toggle to determine which metadata field is
used to populate the artists view. This option sits neatly within the
current artist view settings e.g. Music > Artists > View options >
Artist source
- Artist (current behavior)
- Album Artist (use the album artist metadata instead)

That Artist setting stays as the default choice (so nobody sees a change
unless they pick it) but now gives the option to filter down only to
Album Artists if desired - this choice is saved per library and applies
immediately.

### Related issues
Closes #1868

### Testing
I've tested it extensively on an Amazon Fire TV Cube Gen 2 (using the
firetv debug variant) the following manual tests were performed:
- The list changes when you pick Album artist and importantly the
selection survives a full app restart
- It was tested on a large library and can confirm only the Album
Artists remained (e.g. only one Eminem entry remained)

Automated checks were run (testFiretvDebugUnitTest & pre-commit) As well
as two new tests being added to the CollectionFolderViewModelTest.kt:
- For letter counting its checking via the album artist endpoint (and
not the standard one) when the source is set as ALBUM_ARTIST
- When the source is changed via the saveViewOptions its triggering a
load from the album artist endpoint

## Screenshots
Please see the screenshots below showing the UI impact / modification:
<img width="4624" height="3472" alt="1"
src="https://github.com/user-attachments/assets/6b53575e-ad15-4f66-b9c0-074657128a1d"
/>
<img width="4624" height="3472" alt="2"
src="https://github.com/user-attachments/assets/528c5766-44d8-43d3-8519-778f5aab7441"
/>
<img width="4624" height="3472" alt="3"
src="https://github.com/user-attachments/assets/5de2fb6d-173d-4ac3-ad1b-e08f27f4dafd"
/>

## AI or LLM usage
The code was written / supported with Claude - the approach (e.g. design
/ storing the choice in ViewOptions) endpoint research etc was done by
myself - I reviewed the approaches / refactoring and than deployed a
debug.apk to my local device to confirm everything was working as
expected.

I've reviewed each line and can explain it / the thinking to approaches
/ logic etc and am comfortable submitting the PR.

---------

Co-authored-by: Damontecres <damontecres@gmail.com>
2026-10-31 14:21:41 -04:00
hawkinslabdev
c45c662a96
Request audio focus for video playback so background music pauses (#2151)
## Description
The video player passes false to setAudioAttributes (since #1258 I
think), as ExoPlayer never requests audio focus. This will pass `true`.

### Related issues
#447, #1258.

### Testing
Not tested on a device.

### Screenshots
Not applicable

### AI or LLM usage
None.

---------

Co-authored-by: Damontecres <damontecres@gmail.com>
2026-10-31 13:56:06 -04:00
6bb382a126 Merge pull request 'Show PWA source ratings on every surface through one shared rating row' (#26) from fm/wolfskin-25-ratings-everywhere into main 2026-10-29 21:51:24 +01:00
85365aa3c6 Show each episode's own TMDB score next to the series ratings
All checks were successful
review/code-claude Claude code review: pass, no blocking findings (episode TMDB badge)
2026-10-29 21:35:13 +01:00
2ccce98dc1 Show PWA source ratings on every surface through one shared rating row
All checks were successful
review/code-claude Claude code review: pass, no blocking findings
2026-10-29 21:04:39 +01:00
853a3989b2 Merge pull request 'Show PWA source ratings (RT, IMDb, TMDB from Seerr) on the TV' (#24) from fm/wolfskin-23-ratings into main 2026-10-29 20:29:43 +01:00
04d659b115 Tolerate unknown RT labels, expire cached ratings, avoid duplicate collectors and Jellyfin flash
All checks were successful
review/code-claude Reviewed c54acc9c (PASS); review-fix delta re-checked by firstmate
2026-10-29 20:28:51 +01:00
c54acc9c1d Show Rotten Tomatoes before IMDb like the PWA
All checks were successful
review/code-claude Claude code review: pass, no blocking findings
2026-10-29 20:15:08 +01:00
38db9e5127 Show Seerr source ratings on Jellyfin movie and series details 2026-10-29 20:00:31 +01:00
15b082ccd8 Show PWA source ratings on Discover screens 2026-10-29 20:00:31 +01:00
e92ade99df Add source ratings model and Seerr ratings service matching the PWA 2026-10-29 20:00:31 +01:00
Damontecres
5f2f9a8106
Fixes to v1.0.9 (#2072)
## Description
As usual, a PR to fix various smaller bugs in the latest release.

- Fixes not showing the Videos tab on favorites page
- Fixes the Random button not working for photos
- Long nav drawer item names use a marquee scroll if needed
- Fixes a crash when clicking "View More" on a studios rows on the home
page

### Related issues
Fixes #2070
Fixes #2069
Fixes #2135

### Testing
Emulator

## Screenshots
N/A

## AI or LLM usage
None
2026-10-28 15:17:24 -04:00
Damontecres
811eaed87e
Change max bitrate during playback (#2097)
## Description
Adds an option to the change the max bitrate during playback. It
defaults to the global setting and can be changed in the settings (gear
icon) on the playback controls.

It is applied for the entire playback session. So if you start an
episode and change it, will be used for each next up episode. If you
back out of playback and start again, it will reset back to the global
default.

### Related issues
Closes #1382

### Testing
Testing on the emulator

## Screenshots
N/A

## AI or LLM usage
None
2026-10-28 15:17:02 -04:00
SergeiAK
2f7804fd5e
Convert Dolby Vision profile 7 to 8.1 on devices without a profile 7 decoder (#2017)
## Description

**On Amlogic boxes (S905X4 and similar) Dolby Vision Profile 7 does not
play as Dolby Vision.**
The server transcodes it, or, with "Direct play Dolby Vision Profile 7"
switched on by hand, the
decoder answers `NoSupport` and fallback ends in HDR10. Devices with a
native Profile 7 decoder,
such as the Shield, are not affected and nothing changes for them.

This PR converts Profile 7 to 8.1 on the fly. It has two halves and one
decision.

The preference `convertDolbyVisionProfile7` is proto field 6 in the
experimental settings, off by
default. In `WholphinRenderersFactory` the filter comes first in the
list, followed by the HDR10+
masking from #1876.

**What this PR does not do.** The enhancement layer is dropped; that is
the price of the
conversion, which is why devices with a native Profile 7 decoder are
left alone.
`BlockAdditional` (an enhancement layer outside the stream) is not read
— like the rest of
Wholphin today — so such a file stays HDR10, as it is now.

### Related issues

Closes #244

Builds on #1876 (the `BitstreamFilter` list). Related to #1540. @fanni42
asked for exactly this on
an S905X4 in #1876.

### Testing

**Hardware** — a debug build of this branch, Homatics box (Amlogic
S905X4, Android 14) + LG BX,
Jellyfin 12.1.0, a Profile 7 FEL remux with the enhancement layer in
band, played from the start
for 39 seconds. Only the new preference was switched on; manual "Direct
play Dolby Vision
Profile 7" was **off**:

* `DolbyVisionProfile7FilterTest` (14) — a fake rewriter on a direct
buffer: offset ≠ 0,
position/limit untouched, every "bytes stay as they were" branch,
three-byte start codes,
  `UnsatisfiedLinkError` tried once;
* `DolbyVisionProfile7ExtractorsFactoryTest` (5, mockk) — only the video
track is rewritten;
* `DolbyVisionProfile7ConversionTest` (6) — codec strings, DRM, `dvh1`.

CI in my fork ran on this branch plus a debug signing commit:
`pre-commit`,
`testDefaultDebugUnitTest` and `assembleDefaultDebug` are all green. The
hardware measurement
above is that build.

## Screenshots

The only UI change is one toggle in the experimental settings.

## AI or LLM usage

The code was written with Claude (Claude Code): the filter, the
extractor wrapper, the condition
and the tests. I reviewed every line and can explain it. It was tested
with the unit tests and
the hardware measurement above. This description was written by me in
Russian and translated
into English with the same assistant.

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: Damontecres <damontecres@gmail.com>
2026-10-28 15:16:42 -04:00
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
d78a23a80a Merge pull request 'Serialize Gradle containers sharing a cache volume' (#22) from fm/wolfskin-14-gradle-lock into main 2026-10-27 17:03:03 +01:00
221f623c87 Serialize Gradle containers sharing a cache volume
All checks were successful
review/code-claude Approve: lock held across container, no deadlock, releases on all exits
2026-10-27 15:30:44 +01:00
Damontecres
cecfdaeba9
Fix unit tests after merge 2026-10-26 16:45:42 -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
Gabelschnabler
962a14d5db
Add Fire OS voice command permission for MediaSession (#2076)
## Description
Just a small change to AndroidManifest.xml so that Alexa voice commands
work in Wholphin.

"To enable voice command and control to work with your application, add
the permission com.amazon.permission.media.session.voicecommandcontrol
to your application manifest"
See
https://developer.amazon.com/docs/fire-tv/mediasession-api-integration.html

This is required only for Fire OS <14.

### Related issues
I couldn't find any related issues.

Steps to reproduce: Start some media -> Tell Alexa to pause/play
("Alexa, pause", "Alexa, play")
Expected behavior: Media pauses/resumes almost immediately.
Actual behavior: Pausing takes ~10 seconds, resuming doesn't work at all
Environment: 
- FireTV Cube Gen 3 running Fire OS 7.7.1.7 (PS7717/5741)
- Wholphin 1.0.9-0-g2d87d526
- Jellyfin server 12.2

### Testing
See environment above.
After the change pause/play works immediately.

## Screenshots
N/A

## AI or LLM usage
I used Claude to analyze the issue and Claude Code to build a debug app
for testing.

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Damontecres <damontecres@gmail.com>
2026-10-26 11:45:59 -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
renovate[bot]
0aab839852
Update Gradle to v9.8.2 (#2103) 2026-10-22 18:53:26 -04:00
renovate[bot]
f2a76a962a
Update serialization to v1.12.0 (#2104) 2026-10-22 18:53:02 -04:00
renovate[bot]
766269da98
Update Github Actions (#2083) 2026-10-22 18:46:53 -04:00
761a5a6145 Merge pull request 'Use Forgejo releases for Wolfskin updates and match installed versions consistently' (#20) from fm/wolfskin-5-updater-gpt into main 2026-10-22 16:13:20 +02:00
1715041df3 Match updater versions by ordering and cover Wolfskin asset selection
All checks were successful
review/code-claude Approved: no blocking findings
2026-10-22 16:06:09 +02:00
be7268cc96 Merge pull request 'Default Seerr login to Jellyfin and prefill the Wolfskin Seerr URL' (#19) from fm/wolfskin-6-seerr-default into main 2026-10-22 16:00:23 +02:00
4ae2171061 Merge pull request 'Change application id to org.justinvisser.wolfskin.tv' (#18) from fm/wolfskin-3-package-id into main 2026-10-22 15:58:32 +02:00
bc220021a8 Merge pull request 'Rebrand the Android TV app as Wolfskin' (#16) from fm/wolfskin-2-rebrand into main 2026-10-22 15:23:03 +02:00
df8614bf8b Merge pull request 'Focus the active profile in the Select User list' (#15) from fm/wolfskin-7-profile-focus into main 2026-10-22 15:11:45 +02:00
c98a9756ac Integrate Wolfskin into theme-specific controls
All checks were successful
review/design-claude Approved at c98a9756; no blockers, see PR comment
review/code-claude Approved at c98a9756; no blockers, see PR comment
2026-10-22 15:07:58 +02:00
e499c3f118 Rebrand the TV app as Wolfskin 2026-10-22 15:05:37 +02:00
0f7a23faa8 Point updater at Forgejo releases and Wolfskin assets
Some checks failed
review/code-gpt Request changes: version equivalence and lost positive asset-selection coverage
2026-10-22 14:47:50 +02:00
af885eae58 Default Seerr login to Jellyfin and prefill Wolfskin Seerr URL
All checks were successful
review/firstmate Exact-diff check: JELLYFIN first, API key last; URL prefill from one constant; unit test; apk-debug+test green
2026-10-22 14:46:41 +02:00
06c783a44a Change application id to org.justinvisser.wolfskin.tv
All checks were successful
review/firstmate Exact-diff check: only applicationId line + Intents.md adb examples; aapt2 badging proof org.justinvisser.wolfskin.tv.debug; apk-debug+test green
2026-10-22 14:46:18 +02:00
344aa9990d Focus the active profile in the user selector
All checks were successful
review/firstmate Diff byte-identical to Justin's upstream commit f816ef03 (Wholphin#2003); worker ran make test + apk-debug green
2026-10-22 14:46:05 +02:00
7d6f041b55 Merge pull request 'Add Wolfskin fork header to README' (#12) from fm/wolfskin-1-readme into main 2026-10-22 14:44:39 +02:00
f312138a75 Merge pull request 'Add pinned Docker APK builds and release signing' (#13) from fm/wolfskin-4-build into main 2026-10-22 14:44:21 +02:00
19adf54c23 Pin platform tools and use the upstream debug unit task
All checks were successful
review/security-claude Carried from reviewed head: identical tree (re-pushed only to shed stale Actions statuses)
review/code-claude Carried from reviewed head: identical tree (re-pushed only to shed stale Actions statuses)
2026-10-22 14:43:07 +02:00
1db83e98d4 Add Wolfskin fork header to README
All checks were successful
review/firstmate Carried from reviewed head: identical tree (re-pushed only to shed stale Actions statuses)
2026-10-22 14:42:47 +02:00
3d6f8bae1a Add pinned container builds and Wolfskin release signing 2026-10-22 12:45:29 +02: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
renovate[bot]
a11cd9fb74
Update Gradle to v9.8.1 (#1818) 2026-10-11 20:10:35 -04:00
renovate[bot]
26659b3faf
Update dependency org.openapi.generator to v7.26.0 (#2058) 2026-10-11 20:09:39 -04:00
renovate[bot]
56836f6203
Update actions/upload-artifact digest to cf430e0 (#2056) 2026-10-11 20:09:26 -04:00
renovate[bot]
d0640f148c
Update Kotlin to v2.4.21 (#2057) 2026-10-11 20:08:51 -04:00
Damontecres
2d87d526db
Release v1.0.9
Some checks failed
Development build / build (push) Has been cancelled
Create release / publish (push) Has been cancelled
2026-10-11 17:15:01 -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
9b02804075
Translations 2026-10 -10 (#2054)
Updates translations as of 2026-10-10

Thanks to everyone who contributed!

---------

Co-authored-by: n8llcaster <n8llcaster@noreply.codeberg.org>
Co-authored-by: SimonHung <simonhung@noreply.codeberg.org>
Co-authored-by: Sk4hnt42 <sk4hnt42@noreply.codeberg.org>
Co-authored-by: Priit Jõerüüt <jrtcdbrg@noreply.codeberg.org>
Co-authored-by: American_Jesus <american_jesus@noreply.codeberg.org>
Co-authored-by: idezentas <idezentas@noreply.codeberg.org>
Co-authored-by: Greeg0ry <greeg0ry@noreply.codeberg.org>
Co-authored-by: MrGegaz <mrgegaz@noreply.codeberg.org>
Co-authored-by: Andi Chandler <andi@gowling.com>
Co-authored-by: Prahlis <prahlis@noreply.codeberg.org>
Co-authored-by: SergeiAK <sergeiak@noreply.codeberg.org>
Co-authored-by: Outbreak2096 <outbreak2096@noreply.codeberg.org>
Co-authored-by: danpergal84 <danpergal84@noreply.codeberg.org>
Co-authored-by: TheMatrixan <thematrixan@noreply.codeberg.org>
2026-10-10 20:39:02 -04:00
Prahlis
1571591a12
Translated using Weblate (Swedish)
Currently translated at 94.9% (626 of 659 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/sv/
2026-10-10 10:52:06 +00:00
TheMatrixan
db77aaa3a4
Translated using Weblate (Polish)
Currently translated at 100.0% (659 of 659 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/pl/
2026-10-10 10:52:06 +00:00
Prahlis
55d3254b1e
Translated using Weblate (Swedish)
Currently translated at 94.8% (625 of 659 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/sv/
2026-10-10 10:52:06 +00:00
danpergal84
f14e5a5756
Translated using Weblate (Spanish)
Currently translated at 100.0% (659 of 659 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/es/
2026-10-10 10:52:06 +00:00
danpergal84
68c48f154c
Translated using Weblate (Spanish)
Currently translated at 100.0% (659 of 659 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/es/
2026-10-10 10:52:06 +00:00
Outbreak2096
c879a5713f
Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (659 of 659 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/zh_Hans/
2026-10-10 10:52:06 +00:00
SergeiAK
6308ad85a9
Translated using Weblate (Russian)
Currently translated at 100.0% (659 of 659 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/ru/
2026-10-10 10:52:06 +00:00
Prahlis
ba5351f8dc
Translated using Weblate (Swedish)
Currently translated at 94.6% (624 of 659 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/sv/
2026-10-10 10:52:06 +00:00
Prahlis
4502a12dcb
Translated using Weblate (Swedish)
Currently translated at 92.7% (611 of 659 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/sv/
2026-10-10 10:52:06 +00:00
Andi Chandler
b03325accb
Translated using Weblate (English (United Kingdom))
Currently translated at 9.4% (62 of 659 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/en_GB/
2026-10-10 10:52:06 +00:00
MrGegaz
e4c3257c13
Translated using Weblate (Croatian)
Currently translated at 100.0% (659 of 659 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/hr/
2026-10-10 10:52:06 +00:00
Greeg0ry
26d3e5b6fc
Translated using Weblate (Russian)
Currently translated at 100.0% (659 of 659 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/ru/
2026-10-10 10:52:06 +00:00
idezentas
121208e021
Translated using Weblate (Turkish)
Currently translated at 99.8% (658 of 659 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/tr/
2026-10-10 10:52:05 +00:00
American_Jesus
0e0d50753b
Translated using Weblate (Portuguese)
Currently translated at 100.0% (659 of 659 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/pt/
2026-10-10 10:52:05 +00:00
Priit Jõerüüt
29e235ffa5
Translated using Weblate (Estonian)
Currently translated at 100.0% (659 of 659 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/et/
2026-10-10 10:52:05 +00:00
Sk4hnt42
c0eceba16c
Translated using Weblate (German)
Currently translated at 100.0% (659 of 659 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/de/
2026-10-10 10:52:05 +00:00
SimonHung
22254bac32
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (659 of 659 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/zh_Hant/
2026-10-10 10:52:05 +00:00
n8llcaster
0e11b8ff6f
Translated using Weblate (Slovak)
Currently translated at 100.0% (659 of 659 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/sk/
2026-10-10 10:52:05 +00: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
renovate[bot]
365f8f8ada
Update android-actions/setup-android digest to be39fa8 (#1986) 2026-09-18 11:16:50 -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
renovate[bot]
8effd2b1e7
Update actions/setup-java action to v6 (#1907) 2026-09-15 12:46:02 -04:00
renovate[bot]
61f7f70d36
Update dependency org.robolectric:robolectric to v4.17 (#1446) 2026-09-15 12:45:06 -04:00
Damontecres
62965eae48
Fix CI setup step (#1974)
## Description
Looks like `tools` was replaced by `cmdline-tools`
(https://developer.android.com/tools#tools-sdk), so updating the setup
action for this.

### Related issues
https://github.com/android-actions/setup-android/issues/537

### Testing
N/A

## Screenshots
N/A

## AI or LLM usage
None
2026-09-15 10:53:14 -04:00
Damontecres
7af7bc0aa7
Release v1.0.8
Some checks failed
Create release / publish (push) Has been cancelled
2026-09-14 10:04:09 -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
2fb295cbed
Translations 2026-09-12 (#1957)
Updates translations as of 2026-09-12

Thanks again to all of the contributors!
2026-09-12 18:53:43 -04:00
Damontecres
190c6be41a
Run pre-commit 2026-09-12 18:43:14 -04:00
Prahlis
af6a3b9916
Translated using Weblate (Swedish)
Currently translated at 92.2% (608 of 659 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/sv/
2026-09-12 22:39:03 +00:00
TheMatrixan
a60433dbbf
Translated using Weblate (Polish)
Currently translated at 99.6% (657 of 659 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/pl/
2026-09-12 22:39:03 +00:00
arcker95
f181770870
Translated using Weblate (Italian)
Currently translated at 100.0% (659 of 659 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/it/
2026-09-12 22:39:03 +00:00
SimonHung
923f0b7ea3
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (659 of 659 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/zh_Hant/
2026-09-12 22:39:03 +00:00
TheMatrixan
391a38e777
Translated using Weblate (Polish)
Currently translated at 98.6% (648 of 657 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/pl/
2026-09-12 22:39:03 +00:00
SimonHung
cd0128e1db
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (657 of 657 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/zh_Hant/
2026-09-12 22:39:03 +00:00
Priit Jõerüüt
0db4d45dbc
Translated using Weblate (Estonian)
Currently translated at 100.0% (657 of 657 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/et/
2026-09-12 22:39:02 +00:00
Prahlis
584c3566d6
Translated using Weblate (Swedish)
Currently translated at 90.7% (595 of 656 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/sv/
2026-09-12 22:39:02 +00:00
American_Jesus
f79c0bdfe7
Translated using Weblate (Portuguese)
Currently translated at 100.0% (656 of 656 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/pt/
2026-09-12 22:39:02 +00:00
MrGegaz
bad47eb638
Translated using Weblate (Croatian)
Currently translated at 100.0% (656 of 656 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/hr/
2026-09-12 22:39:02 +00:00
Andi Chandler
8a570b89fb
Translated using Weblate (English (United Kingdom))
Currently translated at 8.6% (57 of 656 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/en_GB/
2026-09-12 22:39:02 +00:00
opakholis
7bd1e993d0
Translated using Weblate (Indonesian)
Currently translated at 100.0% (656 of 656 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/id/
2026-09-12 22:39:02 +00:00
n8llcaster
c0f6293ea7
Translated using Weblate (Slovak)
Currently translated at 100.0% (656 of 656 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/sk/
2026-09-12 22:39:02 +00:00
Prahlis
6647cf338c
Translated using Weblate (Swedish)
Currently translated at 90.3% (593 of 656 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/sv/
2026-09-12 22:39:02 +00:00
marinosGR
3598e3010b
Translated using Weblate (Greek)
Currently translated at 51.0% (335 of 656 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/el/
2026-09-12 22:39:02 +00:00
Priit Jõerüüt
60a0d633bd
Translated using Weblate (Estonian)
Currently translated at 100.0% (656 of 656 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/et/
2026-09-12 22:39:02 +00:00
danpergal84
5ee6b31018
Translated using Weblate (Spanish)
Currently translated at 100.0% (656 of 656 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/es/
2026-09-12 22:39:02 +00:00
idezentas
1e86616d2a
Translated using Weblate (Turkish)
Currently translated at 99.8% (655 of 656 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/tr/
2026-09-12 22:39:02 +00:00
tal_sarid
7b39854621
Translated using Weblate (Hebrew)
Currently translated at 100.0% (656 of 656 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/he/
2026-09-12 22:39:02 +00:00
lednurb
8e050a0830
Translated using Weblate (Dutch)
Currently translated at 91.6% (601 of 656 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/nl/
2026-09-12 22:39:02 +00:00
SimonHung
114df65de3
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (656 of 656 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/zh_Hant/
2026-09-12 22:39:02 +00:00
North-DaCoder
d6b1d77c28
Translated using Weblate (German)
Currently translated at 100.0% (656 of 656 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/de/
2026-09-12 22:39:02 +00:00
lednurb
6e12b0c776
Translated using Weblate (Dutch)
Currently translated at 92.6% (601 of 649 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/nl/
2026-09-12 22:39:02 +00:00
Bone NI
026f8c7592
Added translation using Weblate (Lao) 2026-09-12 22:39:02 +00:00
alexkahler
2ade8173ff
Translated using Weblate (Danish)
Currently translated at 99.8% (648 of 649 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/da/
2026-09-12 22:39:02 +00:00
Andi Chandler
8c2cbcb7b2
Translated using Weblate (English (United Kingdom))
Currently translated at 7.8% (51 of 649 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/en_GB/
2026-09-12 22:39:02 +00:00
American_Jesus
de6cf7fb59
Translated using Weblate (Portuguese)
Currently translated at 100.0% (649 of 649 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/pt/
2026-09-12 22:39:02 +00:00
TheMatrixan
c8d202c3fa
Translated using Weblate (Polish)
Currently translated at 99.6% (647 of 649 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/pl/
2026-09-12 22:39:02 +00:00
brdaustra
7f587b9f50
Translated using Weblate (Norwegian Bokmål)
Currently translated at 99.3% (645 of 649 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/nb_NO/
2026-09-12 22:39:01 +00:00
Prahlis
cf83266e4a
Translated using Weblate (Swedish)
Currently translated at 90.4% (587 of 649 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/sv/
2026-09-12 22:39:01 +00:00
n8llcaster
0398f3f689
Translated using Weblate (Slovak)
Currently translated at 100.0% (649 of 649 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/sk/
2026-09-12 22:39:01 +00:00
tal_sarid
cbebc9e63c
Translated using Weblate (Hebrew)
Currently translated at 100.0% (649 of 649 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/he/
2026-09-12 22:39:01 +00:00
arcker95
e73d0961ab
Translated using Weblate (Italian)
Currently translated at 100.0% (649 of 649 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/it/
2026-09-12 22:39:01 +00:00
Outbreak2096
5a9e5c406f
Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (649 of 649 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/zh_Hans/
2026-09-12 22:39:01 +00:00
SimonHung
c0401914a7
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (649 of 649 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/zh_Hant/
2026-09-12 22:39:01 +00:00
Priit Jõerüüt
0b275a2daa
Translated using Weblate (Estonian)
Currently translated at 100.0% (649 of 649 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/et/
2026-09-12 22:39:01 +00:00
danpergal84
8931bf5d7a
Translated using Weblate (Spanish)
Currently translated at 100.0% (649 of 649 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/es/
2026-09-12 22:39:01 +00:00
Priit Jõerüüt
4f4e13723c
Translated using Weblate (Estonian)
Currently translated at 100.0% (647 of 647 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/et/
2026-09-12 22:39:01 +00:00
tal_sarid
db7cfaee9b
Translated using Weblate (Hebrew)
Currently translated at 100.0% (647 of 647 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/he/
2026-09-12 22:39:01 +00:00
arcker95
048a5f35b6
Translated using Weblate (Italian)
Currently translated at 100.0% (647 of 647 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/it/
2026-09-12 22:39:01 +00:00
Prahlis
9602b4f3f0
Translated using Weblate (Swedish)
Currently translated at 90.5% (586 of 647 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/sv/
2026-09-12 22:39:01 +00:00
olliveiraanderson
d6eb23d29f
Translated using Weblate (Portuguese (Brazil))
Currently translated at 96.1% (622 of 647 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/pt_BR/
2026-09-12 22:39:01 +00:00
true-seeker
f3239c7b15
Translated using Weblate (Russian)
Currently translated at 65.0% (421 of 647 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/ru/
2026-09-12 22:39:01 +00:00
jatag41526
f7c391ad54
Translated using Weblate (Russian)
Currently translated at 65.0% (421 of 647 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/ru/
2026-09-12 22:39:01 +00:00
SergeiAK
02163ba47c
Translated using Weblate (Russian)
Currently translated at 65.0% (421 of 647 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/ru/
2026-09-12 22:39:01 +00: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
074eab22f3
Increase memory for CI builds (#1954)
## Description
Increases the memory available for CI builds and splits up builds a bit
more

There are no user facing changes

### Related issues
Recently dev builds failed due to OOM

### Testing
https://github.com/damontecres/Wholphin/actions/runs/34710759629

## Screenshots
N/A

## AI or LLM usage
None
2026-09-12 15:14:14 -04:00
Damontecres
4a118b6ddb
Update dependencies (#1952)
## Description
Now that the SDK level is updated, many dependencies can be updated as
well.

This includes a fix from `wholphin-extensions` for a TLS timeout issue
on some devices using MPV
(https://github.com/damontecres/wholphin-extensions/pull/13).

### Related issues
Fixes #1932

### Testing
Just basics on emulator & nvidia shield

## Screenshots
N/A

## AI or LLM usage
None
2026-09-11 15:40:38 -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
2b9af1e8bc
Release v1.0.7
Some checks failed
Create release / publish (push) Has been cancelled
2026-08-21 18:04:09 -04:00
Damontecres
088c276129
Translation 2026-08-21 (#1887)
Updates translations as of 2026-08-21

Thank you to all of the contributors! There is a large update to Danish
and a complete translation for Croatian, so special thanks to the
contributors for these languages!
2026-08-21 17:39:41 -04:00
alexkahler
bdef33c973
Translated using Weblate (Danish)
Currently translated at 99.5% (644 of 647 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/da/
2026-08-21 19:04:21 +00:00
SimonHung
ec67d51936
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (647 of 647 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/zh_Hant/
2026-08-21 19:04:21 +00:00
Majkic666
adf299e1ee
Translated using Weblate (Danish)
Currently translated at 85.4% (553 of 647 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/da/
2026-08-21 19:04:21 +00:00
alexkahler
f84ea0e758
Translated using Weblate (Danish)
Currently translated at 85.4% (553 of 647 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/da/
2026-08-21 19:04:21 +00:00
Majkic666
f00622be13
Translated using Weblate (Danish)
Currently translated at 85.4% (553 of 647 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/da/
2026-08-21 19:04:21 +00:00
Majkic666
18174b6e91
Translated using Weblate (Danish)
Currently translated at 85.4% (553 of 647 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/da/
2026-08-21 19:04:21 +00:00
Majkic666
e1a6fcc2f5
Translated using Weblate (Danish)
Currently translated at 85.4% (553 of 647 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/da/
2026-08-21 19:04:21 +00:00
alexkahler
6ab1f96aca
Translated using Weblate (Danish)
Currently translated at 85.4% (553 of 647 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/da/
2026-08-21 19:04:20 +00:00
MrGegaz
7cef2204ea
Translated using Weblate (Croatian)
Currently translated at 100.0% (647 of 647 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/hr/
2026-08-21 19:04:20 +00:00
idezentas
28d38258b4
Translated using Weblate (Turkish)
Currently translated at 99.8% (646 of 647 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/tr/
2026-08-21 19:04:20 +00:00
m_ber
97b8c1f2e6
Translated using Weblate (Czech)
Currently translated at 78.9% (511 of 647 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/cs/
2026-08-21 19:04:20 +00:00
TheMatrixan
797170d758
Translated using Weblate (Polish)
Currently translated at 99.6% (645 of 647 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/pl/
2026-08-21 19:04:20 +00:00
Jaeensson
41443dd85d
Translated using Weblate (Swedish)
Currently translated at 90.5% (586 of 647 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/sv/
2026-08-21 19:04:20 +00:00
Outbreak2096
1978947b25
Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (647 of 647 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/zh_Hans/
2026-08-21 19:04:20 +00:00
rgabbo
f06dba281d
Translated using Weblate (Italian)
Currently translated at 99.5% (644 of 647 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/it/
2026-08-21 19:04:20 +00:00
n8llcaster
9acc8251e2
Translated using Weblate (Slovak)
Currently translated at 100.0% (647 of 647 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/sk/
2026-08-21 19:04:20 +00:00
m4st3r-0day
df3d6e2a78
Translated using Weblate (Albanian)
Currently translated at 6.0% (39 of 644 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/sq/
2026-08-21 19:04:20 +00:00
m4st3r-0day
78a3f3b929
Added translation using Weblate (Albanian) 2026-08-21 19:04:20 +00:00
MrGegaz
4882ff87e1
Translated using Weblate (Croatian)
Currently translated at 100.0% (644 of 644 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/hr/
2026-08-21 19:04:20 +00:00
tal_sarid
ad2a7109f7
Translated using Weblate (Hebrew)
Currently translated at 100.0% (644 of 644 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/he/
2026-08-21 19:04:20 +00:00
American_Jesus
e48a8e089f
Translated using Weblate (Portuguese)
Currently translated at 100.0% (644 of 644 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/pt/
2026-08-21 19:04:20 +00:00
MrGegaz
c26fa32aa9
Translated using Weblate (Croatian)
Currently translated at 91.7% (591 of 644 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/hr/
2026-08-21 19:04:20 +00:00
MrGegaz
7d0dd26f42
Translated using Weblate (Croatian)
Currently translated at 81.8% (527 of 644 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/hr/
2026-08-21 19:04:20 +00: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
Damontecres
b064af7c4e
Update item fields queried & expand usage of primary aspect ratio (#1852)
## Description
Slight optimization to remove "child count" for grid pages. Adds back
"primary image aspect ratio" for several queries where its necessary.

Also updates extras cards to use the "primary image aspect ratio"
instead of a hard coded value.

Dev note: some light refactoring is also in this PR including renaming
the item fields lists to better reflect the intended usage in code

### Related issues
Fixes #1843

### Testing
Emulator, I tested many pages and views, but probably need to do "real
world" testing to see if I missed anything

## Screenshots
N/A

## AI or LLM usage
None
2026-08-17 22:54:15 -04:00
Damontecres
c4264a3263
Adds option to dim the screensaver (#1834)
## Description
Adds a new sceensaver setting to add dimming. A larger value is darker

This works with or without the in-app screensaver. If dimming is
enabled, the screen be will be dimmed after inactivity. If both dimming
and the in-app screensaver are enabled, the screensaver will show dimmed
after inactivity.

### Related issues
Closes #1179

### Testing
Emulator

## Screenshots
N/A, it's just darker

## AI or LLM usage
None
2026-08-17 22:53:40 -04:00
Stefan Bullones
197af604d6
Pause music playback when another app takes audio focus (#1842)
## Description
The audio player passed handleAudioFocus = false when setting its audio
attributes, so ExoPlayer never requested audio focus. Music kept playing
and mixed with other audio when a call arrived, another app started
playback, or voice search took focus.

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

### Testing
1. Play a music track
2. Open YouTube and play a video

## AI or LLM usage
Cursor and Claude Code
2026-08-17 22:51:51 -04:00
Damontecres
f89d752d2c
Updates & fixes to discover pages (#1836)
## Description
Fixes several issues on the discover pages:
- Fixes sorting by release date for tv shows
- Fixes automatic go-to for movie & tv show grid
- Fixes tv show discover page's go-to using a movie detail page
- Updates the alignment & padding for the headers on different discover
pages to match the reset of the app
- Use media's logo image if available and the setting is enabled

### Related issues
N/A

### Testing
Emulator mostly

## Screenshots
N/A, headers and logos are unchanged, just moved slightly to match
regular content

## AI or LLM usage
None
2026-08-16 10:29:03 -04:00
Damontecres
4e53cbaa7f
Preload next image during slideshow (#1847)
## Description
When viewing images in a slideshow, this PR enqueues the next image so
it will likely be cached and ready to display when the slideshow
advances.

This works for both automatic and manual scrolling as well as advancing
next or previous images.

### Related issues
Closes #1835 

### Testing
Emulator with large photos

## Screenshots
N/A

## AI or LLM usage
None
2026-08-16 10:20:46 -04:00
Damontecres
22a949bc76
Fixes slideshow images not being full screen (#1849)
## Description
I accidentally removed the original fix/workaround from #1089 during a
merge in #1052, so this PR restores the fix.

### Related issues
Fixes #1736
Related to the original fix #1089

### Testing
Emulator with portrait and landscape images

## Screenshots
N/A

## AI or LLM usage
None
2026-08-16 10:20:33 -04:00
Damontecres
007ac4801c
Release v1.0.6
Some checks failed
Create release / publish (push) Has been cancelled
2026-08-13 18:36:38 -04:00
Damontecres
4b5d44ef1c
Translations 2026-08-13 (#1833)
Updates translations as of 2026-08-13

Thanks to all of the contributions!
2026-08-13 18:15:21 -04:00
MrGegaz
8ea73b6f3a
Translated using Weblate (Croatian)
Currently translated at 32.4% (209 of 644 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/hr/
2026-08-13 17:57:57 +00:00
MrGegaz
40d01b54ef
Translated using Weblate (Croatian)
Currently translated at 17.7% (114 of 644 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/hr/
2026-08-13 17:57:57 +00:00
arcker95
2033f1857a
Translated using Weblate (Italian)
Currently translated at 100.0% (644 of 644 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/it/
2026-08-13 17:57:57 +00:00
n8llcaster
894e0db459
Translated using Weblate (Slovak)
Currently translated at 100.0% (644 of 644 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/sk/
2026-08-13 17:57:57 +00:00
Priit Jõerüüt
14a1f2e110
Translated using Weblate (Estonian)
Currently translated at 100.0% (644 of 644 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/et/
2026-08-13 17:57:57 +00:00
MrGegaz
84185530c9
Translated using Weblate (Croatian)
Currently translated at 15.2% (98 of 644 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/hr/
2026-08-13 17:57:57 +00:00
MrGegaz
ea28a2d58f
Added translation using Weblate (Croatian) 2026-08-13 17:57:57 +00:00
North-DaCoder
d463dbf876
Translated using Weblate (German)
Currently translated at 100.0% (644 of 644 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/de/
2026-08-13 17:57:57 +00:00
Outbreak2096
0e70fe030a
Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (644 of 644 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/zh_Hans/
2026-08-13 17:57:57 +00:00
SimonHung
e2a5f30ed5
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (644 of 644 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/zh_Hant/
2026-08-13 17:57:56 +00:00
danpergal84
3cbb738af8
Translated using Weblate (Spanish)
Currently translated at 100.0% (644 of 644 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/es/
2026-08-13 17:57:56 +00:00
addisonv
88fbae9867
Translated using Weblate (Portuguese (Brazil))
Currently translated at 87.8% (564 of 642 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/pt_BR/
2026-08-13 17:57:56 +00:00
lednurb
8144b674e2
Translated using Weblate (Dutch)
Currently translated at 93.3% (599 of 642 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/nl/
2026-08-13 17:57:56 +00:00
Priit Jõerüüt
a0ee9ce45c
Translated using Weblate (Estonian)
Currently translated at 100.0% (642 of 642 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/et/
2026-08-13 17:57:56 +00:00
American_Jesus
0cb2d10455
Translated using Weblate (Portuguese)
Currently translated at 100.0% (642 of 642 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/pt/
2026-08-13 17:57:56 +00:00
SimonHung
486cf527bd
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (642 of 642 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/zh_Hant/
2026-08-13 17:57:56 +00:00
danpergal84
9def1b964b
Translated using Weblate (Spanish)
Currently translated at 100.0% (642 of 642 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/es/
2026-08-13 17:57:56 +00:00
SimonHung
e6f93cd809
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (642 of 642 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/zh_Hant/
2026-08-13 17:57:56 +00:00
TheMatrixan
c10e410fd3
Translated using Weblate (Polish)
Currently translated at 100.0% (642 of 642 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/pl/
2026-08-13 17:57:56 +00:00
tal_sarid
884735df60
Translated using Weblate (Hebrew)
Currently translated at 100.0% (642 of 642 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/he/
2026-08-13 17:57:56 +00:00
outopik
f7509767b0
Translated using Weblate (French)
Currently translated at 100.0% (642 of 642 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/fr/
2026-08-13 17:57:56 +00:00
ymir
fc9d2287d7
Translated using Weblate (French)
Currently translated at 100.0% (642 of 642 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/fr/
2026-08-13 17:57:56 +00:00
n8llcaster
b12b078293
Translated using Weblate (Slovak)
Currently translated at 100.0% (642 of 642 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/sk/
2026-08-13 17:57:56 +00:00
nofkclue
fe943fef4e
Translated using Weblate (German)
Currently translated at 100.0% (642 of 642 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/de/
2026-08-13 17:57:56 +00:00
Damontecres
2110d846c1
Fix some bugs on discover pages (#1832)
## Description
Fix some bugs on discover pages:
- UI fixes for available seasons
- Fix toggle not updating when removing a season from a pending request
- Don't request images if the path is null
- Better error handling when fetching ratings

### Related issues
Follow up to #1816

### Testing
Emulator

## Screenshots
N/A

## AI or LLM usage
None
2026-08-13 13:57:51 -04:00
renovate[bot]
ba52915cf0
Update actions/setup-python action to v7 (#1822) 2026-08-13 13:40:22 -04:00
Damontecres
51ab39ed3b
Several minor bug fixes (#1811)
## Description
Fixes several small bugs and does some minor refactoring:
- Use "Recently Added in XYZ" instead of "Recently recorded" for
recorded tv libraries
- Improve home page query performance by using fewer fields in the query
- When an error occurs connecting to discovered servers, show the error
instead of only logging
- Fix headers sometimes appearing briefly on some pages when navigating
back
- Catch exceptions in socket connections
- Use a larger buffer when downloading updates
- Split up ADB logging for media info

### Related issues
Related to
https://github.com/damontecres/Wholphin/issues/1517#issuecomment-5184316086
Maybe the larger download buffer will help with
https://github.com/damontecres/Wholphin/issues/1696
Will help show the error in #1801
Prevents the crash in #1786

### Testing
Emulator & nvidia shield

## Screenshots
N/A

## AI or LLM usage
None
2026-08-13 12:36:20 -04:00
Damontecres
54966f9124
Handle density configuration changes to prevent unnecessary app restarts (#1828)
## Description
Add `density` to `configChanges` and handle any changes to density that
occur. Thankfully, Compose handles density changes itself, so only
changes where a density calculation is "remembered" needed to be
updated.

Without this, some devices will recreate `MainActivity` when switching
resolutions for playback. That recreation would cause playback to end
immediately.

### Related issues
Fixes #1809

### Testing
Tested on Onn 4k Pro & nvidia shield

I was able to reproduce on the Onn, but not the Shield, so this might be
device and/or API level specific

## Screenshots
N/A

## AI or LLM usage
None
2026-08-12 21:01:28 -04:00
Damontecres
e6304f79a2
Fix requesting new seasons after approval (#1816)
## Description
Fixes requesting additional seasons of a show if a previous request has
already been approved

Now if the previous request is already approved/completed/etc, a new
request will be created instead of trying to update the previous one.
Pending requests will still be updated as before instead of requesting a
new one.

### Related issues
Fixes #1702

### Testing
Emulator

## Screenshots
N/A

## AI or LLM usage
None
2026-08-12 16:47:08 -04:00
Damontecres
548ec09af3
Fix issue with scrolling to the right episode if there are specials in the season (#1827)
## Description
Fixes an edge case where clicking on an episode to go to Series Overview
wouldn't scroll to the episode if there is a special (season 0) episodes
in the episode list.

Dev note: to simplify things, if the entire dataset is cached, then just
search with `indexOf`. Often the data is cached because 20 seasons or
100 episodes are fetched initially which covers many shows.

### Related issues
Follow up to #1708 

### Testing
Emulator and unit tests

## Screenshots
N/A

## AI or LLM usage
None
2026-08-12 16:25:30 -04:00
Damontecres
c6d81dada8
Fix playlist & collection random sorting on home page (#1820)
## Description
Ensure that a playlist or collection's items are random sorted on the
home page, if applicable.

Previously, the request did sort by random then by sort name resulting
in only sorting by sort name.

However, there are still issues with random sorting in general, see
#1819

### Related issues
Technically fixes #1806
Further bugs in #1819

### Testing
Emulator

## Screenshots
N/A

## AI or LLM usage
None
2026-08-12 14:04:19 -04:00
Nehereus
1c0e9a5853
Add a preference option to disable hardware audio offloading (#1564)
## Description
By default, Wholphin plays music with hardware audio offloading enabled.
This delegates audio decoding to the device's hardware DSP, making
playback stability highly dependent on the manufacturer's system audio
implementation. On certain hardware (such as my TCL TVs, e.g., the
Chinese Model Q9L Pro), this implementation causes music playback to
hang indefinitely at 0 seconds.

### Related issues
#1372

### Testing
Tested on a TCL TV (Q9L Pro):
- Some musics playback hangs at 0s with offloading enabled.
- Disabling audio offloading fixes the issues for all medias.

## Screenshots
<!-- Please include screenshots if the PR alters any UI elements -->
<img width="4284" height="5712" alt="IMG_9486"
src="https://github.com/user-attachments/assets/ddf95e68-6ebd-42f9-9565-568de4fbfc42"
/>

## AI or LLM usage
Developed in pair with Gemini and human-reviewed, tested.

---------

Co-authored-by: Damontecres <damontecres@gmail.com>
2026-08-11 13:36:03 -04:00
Damontecres
de30c2ccac
Improvements to Now Playing page, including artist backdrops (#1782)
## Description
This PR has updates the Now Playing page.

Now only the song's backdrops and the song's artists' backdrops will
show. First, if the song has any backdrops (probably pretty uncommon),
they will be shuffled and shown, then if the song's artists have
backdrop, those are shuffled and shown. The backdrop changes every 2
minutes unless there's <15s left in the song to prevent rapid changes.
Note: album backdrops and album artists not directly linked to the
specific song are not included.

If a song has a lyrics and the user is scrolling through them, if the
user doesn't scroll for 5 seconds, the focus leaves the lyrics and they
scroll to the current line if available.

Dev note: Both backdrop & lyric updates are refactored to use `Flow`s to
trigger lookups

### Related issues
Fixes #1170

### Testing
Emulator, I need to test it longer term

## Screenshots
N/A

## AI or LLM usage
None
2026-08-11 13:35:20 -04:00
Damontecres
5219b22fc7
Update wholphin-extensions & media3 (#1814)
Updates playback dependencies:
- `wholphin-extensions` to `v0.2.2`
- `media3` to `1.11.0`
- `libass-android` to `0.5.1`
2026-08-11 13:35:11 -04:00
Damontecres
bd1a6c44ee
Add shuffle parameter to playback intent (#1813)
## Description
Adds an optional boolean parameter `shuffle` that is read for the
playback intent. When true, it will cause the resulting media to be
shuffled if applicable.

Something can be shuffled if the `itemId` is a grouping on media such as
a playlist, series, season, or even library.

### Related issues
Depends on #1756

### Testing
Emulator with the documented command

## Screenshots
N/A

## AI or LLM usage
None
2026-08-11 13:33:49 -04:00
renovate[bot]
e94e82479b
Update dependency org.openapi.generator to v7.24.0 (#1731) 2026-08-11 13:00:33 -04:00
renovate[bot]
5f44f870df
Update Kotlin to v2.4.10 (#1697) 2026-08-11 13:00:15 -04:00
renovate[bot]
2745e76b82
Update Github Actions (#1672) 2026-08-11 12:59:55 -04:00
calebvetter
c1abb57cd2
Add back stack for deep link navigation (#1756)
## Description
When testing the new deep link feature from this PR
[#1688](https://github.com/damontecres/Wholphin/pull/1688)
I noticed that the back button would close the app. As in, all routes
are cleared and only the playback is in the nav stack.

I figured a more desirable behavior would be to create a nav stack,
always starting with the home screen, then also inserting the media
item's details page, if available.

To achieve this, I made the return Target.destinations a list of
destinations, and updated the other two uses in IntentService.

Open to implementation tweaks, or scrap it if this isn't how it should
work, haha.

### Testing

Tested deep links, which produced the following nav stacks:
- Movie view
  - Home → Movie details
- Movie playback (with and without position)
  - Home → Movie details → Playback
- Series view
  - Home → Series details
- Season view
  - Home → Season details
- Episode view
  - Home → Episode details
- Episode playback (with and without position)
  - Home → Episode details → Playback
- Trailer/extras playback (no details page available)
  - Home → Playback
- TV channel view
  - Home → Playback
- TV channel playback
  - Home → Playback

## AI or LLM usage
AI was used to generate the initial code, debug and test, then manual
refactoring and cleanup was done.

---------

Co-authored-by: Damontecres <damontecres@gmail.com>
2026-08-11 10:59:20 -04:00
Stefan Bullones
a0966dd05a
Fix alphabet highlight for names starting with "The " (#1788)
## Description
The alphabet scroll bar highlighted the letter of an item's *display*
name while the grid sorted by the server's article-stripped `SortName`,
so "The Beatles" sat under **B** but highlighted **T**.

- **Artists:** the Artists tab never requested `SortName`, so the
highlight silently fell back to `Name`. It now asks for `SlimItemFields`
(which already includes `SORT_NAME`), matching the sibling `/Items`
branch. The count-only query used for letter positions passes `fields =
null`, since a `limit = 0` request has no use for them.
- **Genres and studios:** these grids bucketed on the display name
unconditionally. The sort-name fallback is extracted as
`BaseItemDto.alphabetSortName` (`sortName ?: name ?: ""`) and carried
onto the `Genre` and `Studio` grid items, so all three grids now derive
the letter from one value.

### Related issues
https://github.com/damontecres/Wholphin/issues/1787

### Testing
Two unit tests added:
- `CollectionFolderViewModelTest` pins that the artist pager actually
requests `SORT_NAME` — the field whose absence caused the bug.
- `AlphabetSortNameTest` covers both branches of the `alphabetSortName`
fallback.

Manually: select a music library → Artists tab → put the cursor on an
artist starting with "The " and confirm the highlighted letter matches
the grid position. Same check on the genre and studio grids.

## AI or LLM usage
I used Cursor for debugging and implementing the fix, and Claude Code
for a follow-up cleanup pass over the diff.
2026-08-10 21:52:43 -04:00
Damontecres
454c0212b6
Fix issues with external subtitles & transcoding (#1790)
## Description
Fixes a bug where the external subtitle track would not be activated if
playback is transcoded

Also fixes a bug where external subtitles would cause MPV to incorrectly
switch to transcoding

### Related issues
Fixes #1778

### Testing
Emulator with files that have a variety of external SRT, embedded SRT &
ASS, & embedded PGS

## Screenshots
N/A

## AI or LLM usage
None
2026-08-10 20:17:42 -04:00
Damontecres
7581b189aa
Fix preference text overflow/clipping (#1785)
## Description
Removes the max height constraints for slider preferences and navigation
drawer preferences so that longer text (possibly in other languages or a
long library name) won't cut off any content

### Related issues
Fixes #1784 

### Testing
Emulator with manual long text

## Screenshots
N/A, no significant change except sliders can be slightly taller if
needed

## AI or LLM usage
None
2026-08-04 11:01:19 -04:00
Damontecres
fceb5f81a7
Release v1.0.5
Some checks failed
Create release / publish (push) Has been cancelled
2026-08-03 11:10:07 -04:00
Stefan Bullones
d7d63f52c3
Fix the alphabet buttons scroll bar on the Artists tab (#1775)
## Description
positionOfLetter counted through /Items no matter which endpoint the
grid was actually paging. A music library's Artists tab pages /Artists,
so the index it returned had counted every album and song before the
letter - an order of magnitude more rows than the artist grid holds -
and every letter jumped to the last row.

Count through the same endpoint createPager builds its pager from:
/Artists for the ARTIST override, /Items for NONE. The artist request is
now built once in createGetArtistsRequest and shared by both, so the two
cannot drift apart.

GetPersonsRequest has neither nameLessThan nor startIndex, so /Persons
cannot be counted up to a letter at all; the PERSON override returns
null, which the call sites already map to the "no jump" sentinel. That
path is unreachable today - the only PERSON tab sorts by
ItemSortBy.DEFAULT, so showLetterButtons is never true there and
AlphabetButtons is never composed.

### Related issues
https://github.com/damontecres/Wholphin/issues/1774

### Testing
Select a music library -> Go to Artist tab -> Select a letter on the
right side alphabet scroll bar

## AI or LLM usage
I used Cursor and Claude Code for planning, implementation and code
review.

---------

Co-authored-by: Damontecres <damontecres@gmail.com>
2026-08-03 09:54:03 -04:00
Damontecres
6ad96865e7
Fix live tv & recorded tv playback (#1770)
## Description
#1654 broke playback for both live TV and recorded programs in `.ts`
format.

This PR fixes both issues! Jellyfin returns `NoCompatibleStream` for
live tv if the source ID is passed in, so that is now skipped for live
tv. `.ts` files may have IDs formatted with a slash instead of colon, so
the logic is updated to handle that plus fallbacks for potentially
unknown future formats.

### Related issues
Fixes #1767

### Testing
Emulator & nvidia shield, plus unit tests

## Screenshots
N/A

## AI or LLM usage
None
2026-08-02 11:11:32 -04:00
Damontecres
7c6ab39436
Fix translations again (#1776)
## Description
Another follow up to https://github.com/damontecres/Wholphin/pull/1764 &
#1772

Also adds `lint.xml` to mark the extra translations as just a warning
since they don't cause a problem in the final build.

### Related issues
#1764
#1772

### Testing
N/A

## Screenshots
N/A

## AI or LLM usage
None
2026-08-02 10:31:56 -04:00
Damontecres
1874b5babe
Merge remote-tracking branch 'origin/main' into github-main 2026-07-30 20:48:57 -04:00
Damontecres
89933c83f9
Fix incorrect translation merge (#1772)
Fixes the squash merge from #1764
2026-07-30 20:32:50 -04:00
Damontecres
c1b055db3a
Remove outdated dpad_seek_mode_skip_time entries 2026-07-30 20:14:13 -04:00
arcker95
145f716da4
Translated using Weblate (Italian)
Currently translated at 100.0% (642 of 642 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/it/
2026-07-30 20:10:01 -04:00
Outbreak2096
836706fffa
Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (642 of 642 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/zh_Hans/
2026-07-30 20:10:01 -04:00
opakholis
2ac7a3d83f
Translated using Weblate (Indonesian)
Currently translated at 97.5% (626 of 642 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/id/
2026-07-30 20:10:01 -04:00
n8llcaster
e24ef7783e
Translated using Weblate (Slovak)
Currently translated at 98.9% (634 of 641 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/sk/
2026-07-30 20:10:01 -04:00
idezentas
45f3cc7665
Translated using Weblate (Turkish)
Currently translated at 100.0% (641 of 641 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/tr/
2026-07-30 20:10:01 -04:00
Outbreak2096
99c5ce2fdf
Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (641 of 641 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/zh_Hans/
2026-07-30 20:10:01 -04:00
TheMatrixan
ab400fd7fb
Translated using Weblate (Polish)
Currently translated at 100.0% (641 of 641 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/pl/
2026-07-30 20:10:01 -04:00
tal_sarid
708ba9dfab
Translated using Weblate (Hebrew)
Currently translated at 100.0% (641 of 641 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/he/
2026-07-30 20:10:01 -04:00
ymir
712fbcc9b8
Translated using Weblate (French)
Currently translated at 100.0% (641 of 641 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/fr/
2026-07-30 20:10:00 -04:00
American_Jesus
e3afc3c583
Translated using Weblate (Portuguese)
Currently translated at 100.0% (641 of 641 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/pt/
2026-07-30 20:10:00 -04:00
arcker95
d73cf5e9e8
Translated using Weblate (Italian)
Currently translated at 100.0% (641 of 641 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/it/
2026-07-30 20:10:00 -04:00
SimonHung
46347abbc7
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 99.8% (640 of 641 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/zh_Hant/
2026-07-30 20:10:00 -04:00
Priit Jõerüüt
45f05fbc69
Translated using Weblate (Estonian)
Currently translated at 98.7% (633 of 641 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/et/
2026-07-30 20:10:00 -04:00
danpergal84
24792279cc
Translated using Weblate (Spanish)
Currently translated at 100.0% (641 of 641 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/es/
2026-07-30 20:10:00 -04:00
idezentas
fe39318e04
Translated using Weblate (Turkish)
Currently translated at 100.0% (639 of 639 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/tr/
2026-07-30 20:10:00 -04:00
danpergal84
ea13c5c5ad
Translated using Weblate (Spanish)
Currently translated at 100.0% (639 of 639 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/es/
2026-07-30 20:10:00 -04:00
Prahlis
50e306baa1
Translated using Weblate (Swedish)
Currently translated at 87.8% (559 of 636 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/sv/
2026-07-30 20:10:00 -04:00
Prahlis
0b94cdb509
Translated using Weblate (Swedish)
Currently translated at 87.7% (558 of 636 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/sv/
2026-07-30 20:10:00 -04:00
North-DaCoder
3830a9eb01
Translated using Weblate (German)
Currently translated at 100.0% (636 of 636 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/de/
2026-07-30 20:10:00 -04:00
Codeberg Translate
a26d0932b5
Update translation files
Updated by "Remove blank strings" add-on in Weblate.

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/
2026-07-30 20:10:00 -04:00
idezentas
291ac6c50c
Translated using Weblate (Turkish)
Currently translated at 100.0% (636 of 636 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/tr/
2026-07-30 20:10:00 -04:00
Outbreak2096
22b04ff855
Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (636 of 636 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/zh_Hans/
2026-07-30 20:09:59 -04:00
n8llcaster
ec97a52ffc
Translated using Weblate (Slovak)
Currently translated at 100.0% (636 of 636 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/sk/
2026-07-30 20:09:59 -04:00
Prahlis
05560697a3
Translated using Weblate (Swedish)
Currently translated at 87.4% (556 of 636 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/sv/
2026-07-30 20:09:59 -04:00
danpergal84
10a7008ad2
Translated using Weblate (Spanish)
Currently translated at 100.0% (636 of 636 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/es/
2026-07-30 20:09:59 -04:00
Prahlis
c4ac8b6a65
Translated using Weblate (Swedish)
Currently translated at 85.7% (543 of 633 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/sv/
2026-07-30 20:09:59 -04:00
TheMatrixan
1c3e269718
Translated using Weblate (Polish)
Currently translated at 100.0% (625 of 625 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/pl/
2026-07-30 20:09:59 -04:00
ymir
9988974001
Translated using Weblate (French)
Currently translated at 99.8% (624 of 625 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/fr/
2026-07-30 20:09:59 -04:00
opakholis
43e86e4769
Translated using Weblate (Indonesian)
Currently translated at 99.8% (624 of 625 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/id/
2026-07-30 20:09:59 -04:00
nofkclue
c393bc9697
Translated using Weblate (German)
Currently translated at 100.0% (625 of 625 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/de/
2026-07-30 20:09:59 -04:00
arcker95
a6887c0826
Translated using Weblate (Italian)
Currently translated at 100.0% (625 of 625 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/it/
2026-07-30 20:09:59 -04:00
outopik
a335dbcbc5
Translated using Weblate (French)
Currently translated at 98.5% (616 of 625 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/fr/
2026-07-30 20:09:59 -04:00
SimonHung
4d7ac8f759
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (625 of 625 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/zh_Hant/
2026-07-30 20:09:59 -04:00
unikitty
327a49f1d7
Translated using Weblate (English (United Kingdom))
Currently translated at 6.7% (42 of 625 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/en_GB/
2026-07-30 20:09:59 -04:00
damontecres
e7efe473c8
Added translation using Weblate (English (United Kingdom)) 2026-07-30 20:09:59 -04:00
idezentas
aa5c65b4a2
Translated using Weblate (Turkish)
Currently translated at 100.0% (625 of 625 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/tr/
2026-07-30 20:09:58 -04:00
Outbreak2096
857d1505ed
Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (625 of 625 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/zh_Hans/
2026-07-30 20:09:58 -04:00
n8llcaster
2807c92a35
Translated using Weblate (Slovak)
Currently translated at 100.0% (625 of 625 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/sk/
2026-07-30 20:09:58 -04:00
Priit Jõerüüt
00d37eb726
Translated using Weblate (Estonian)
Currently translated at 100.0% (625 of 625 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/et/
2026-07-30 20:09:58 -04:00
American_Jesus
4eba026541
Translated using Weblate (Portuguese)
Currently translated at 100.0% (625 of 625 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/pt/
2026-07-30 20:09:58 -04:00
danpergal84
fbe0458dad
Translated using Weblate (Spanish)
Currently translated at 100.0% (625 of 625 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/es/
2026-07-30 20:09:58 -04:00
ymir
a959049c77
Translated using Weblate (French)
Currently translated at 100.0% (612 of 612 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/fr/
2026-07-30 20:09:58 -04:00
opakholis
f80bfdc886
Translated using Weblate (Indonesian)
Currently translated at 99.8% (611 of 612 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/id/
2026-07-30 20:09:58 -04:00
viretius
28cf4c6443
Translated using Weblate (German)
Currently translated at 100.0% (612 of 612 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/de/
2026-07-30 20:09:58 -04:00
idezentas
5eddaacf4e
Translated using Weblate (Turkish)
Currently translated at 100.0% (612 of 612 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/tr/
2026-07-30 20:09:58 -04:00
streamyfinchris
28b909ed79
Translated using Weblate (Swedish)
Currently translated at 86.6% (530 of 612 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/sv/
2026-07-30 20:09:58 -04:00
tal_sarid
912551e74b
Translated using Weblate (Hebrew)
Currently translated at 100.0% (612 of 612 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/he/
2026-07-30 20:09:58 -04:00
danpergal84
964b3b5068
Translated using Weblate (Spanish)
Currently translated at 100.0% (612 of 612 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/es/
2026-07-30 20:09:58 -04:00
North-DaCoder
e539551e70
Translated using Weblate (German)
Currently translated at 100.0% (612 of 612 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/de/
2026-07-30 20:09:58 -04:00
Outbreak2096
d61cba4101
Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (612 of 612 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/zh_Hans/
2026-07-30 20:09:57 -04:00
TheMatrixan
ad241ca7e8
Translated using Weblate (Polish)
Currently translated at 100.0% (612 of 612 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/pl/
2026-07-30 20:09:57 -04:00
arcker95
0d2524b359
Translated using Weblate (Italian)
Currently translated at 100.0% (612 of 612 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/it/
2026-07-30 20:09:57 -04:00
SimonHung
76b5aa12ab
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (612 of 612 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/zh_Hant/
2026-07-30 20:09:57 -04:00
n8llcaster
ca27e94d33
Translated using Weblate (Slovak)
Currently translated at 100.0% (612 of 612 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/sk/
2026-07-30 20:09:57 -04:00
Priit Jõerüüt
8ac955c44d
Translated using Weblate (Estonian)
Currently translated at 100.0% (612 of 612 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/et/
2026-07-30 20:09:57 -04:00
Outbreak2096
7e837b4d45
Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (610 of 610 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/zh_Hans/
2026-07-30 20:09:57 -04:00
idezentas
12640a9fd1
Translated using Weblate (Turkish)
Currently translated at 100.0% (610 of 610 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/tr/
2026-07-30 20:09:57 -04:00
TheMatrixan
48455bc13f
Translated using Weblate (Polish)
Currently translated at 100.0% (610 of 610 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/pl/
2026-07-30 20:09:57 -04:00
SimonHung
b86e454db6
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (610 of 610 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/zh_Hant/
2026-07-30 20:09:57 -04:00
n8llcaster
c03abe4511
Translated using Weblate (Slovak)
Currently translated at 100.0% (610 of 610 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/sk/
2026-07-30 20:09:57 -04:00
Priit Jõerüüt
8747dd30b7
Translated using Weblate (Estonian)
Currently translated at 100.0% (610 of 610 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/et/
2026-07-30 20:09:57 -04:00
arcker95
b98dab8945
Translated using Weblate (Italian)
Currently translated at 100.0% (642 of 642 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/it/
2026-07-29 20:57:55 +00:00
Outbreak2096
fbeb192ad7
Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (642 of 642 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/zh_Hans/
2026-07-29 14:21:55 +00:00
opakholis
d0d996fda7
Translated using Weblate (Indonesian)
Currently translated at 97.5% (626 of 642 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/id/
2026-07-29 14:21:55 +00:00
n8llcaster
42155bdab0
Translated using Weblate (Slovak)
Currently translated at 98.9% (634 of 641 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/sk/
2026-07-29 14:21:55 +00:00
idezentas
05f8456177
Translated using Weblate (Turkish)
Currently translated at 100.0% (641 of 641 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/tr/
2026-07-29 14:21:55 +00:00
Outbreak2096
4f05b6ffab
Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (641 of 641 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/zh_Hans/
2026-07-29 14:21:55 +00:00
TheMatrixan
477e4c921d
Translated using Weblate (Polish)
Currently translated at 100.0% (641 of 641 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/pl/
2026-07-29 14:21:55 +00:00
tal_sarid
4ed689064e
Translated using Weblate (Hebrew)
Currently translated at 100.0% (641 of 641 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/he/
2026-07-29 14:21:55 +00:00
ymir
dcb304641d
Translated using Weblate (French)
Currently translated at 100.0% (641 of 641 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/fr/
2026-07-29 14:21:55 +00:00
American_Jesus
d969e73bd0
Translated using Weblate (Portuguese)
Currently translated at 100.0% (641 of 641 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/pt/
2026-07-29 14:21:55 +00:00
arcker95
4633209fb3
Translated using Weblate (Italian)
Currently translated at 100.0% (641 of 641 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/it/
2026-07-29 14:21:55 +00:00
SimonHung
a1b5182e6a
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 99.8% (640 of 641 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/zh_Hant/
2026-07-29 14:21:55 +00:00
Priit Jõerüüt
e41d0032f5
Translated using Weblate (Estonian)
Currently translated at 98.7% (633 of 641 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/et/
2026-07-29 14:21:55 +00:00
danpergal84
36369afb70
Translated using Weblate (Spanish)
Currently translated at 100.0% (641 of 641 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/es/
2026-07-29 14:21:55 +00:00
idezentas
4dde8b80cc
Translated using Weblate (Turkish)
Currently translated at 100.0% (639 of 639 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/tr/
2026-07-29 14:21:55 +00:00
danpergal84
50f2afc5c4
Translated using Weblate (Spanish)
Currently translated at 100.0% (639 of 639 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/es/
2026-07-29 14:21:55 +00:00
Prahlis
9a6749a0d3
Translated using Weblate (Swedish)
Currently translated at 87.8% (559 of 636 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/sv/
2026-07-29 14:21:55 +00:00
Prahlis
5820398b4a
Translated using Weblate (Swedish)
Currently translated at 87.7% (558 of 636 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/sv/
2026-07-29 14:21:55 +00:00
North-DaCoder
6c8be55c29
Translated using Weblate (German)
Currently translated at 100.0% (636 of 636 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/de/
2026-07-29 14:21:55 +00:00
Codeberg Translate
25bbc7c418
Update translation files
Updated by "Remove blank strings" add-on in Weblate.

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/
2026-07-29 14:21:55 +00:00
idezentas
eedca7331a
Translated using Weblate (Turkish)
Currently translated at 100.0% (636 of 636 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/tr/
2026-07-29 14:21:55 +00:00
Outbreak2096
09e835a374
Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (636 of 636 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/zh_Hans/
2026-07-29 14:21:55 +00:00
n8llcaster
e7a54c8012
Translated using Weblate (Slovak)
Currently translated at 100.0% (636 of 636 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/sk/
2026-07-29 14:21:55 +00:00
Prahlis
0964322ab9
Translated using Weblate (Swedish)
Currently translated at 87.4% (556 of 636 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/sv/
2026-07-29 14:21:54 +00:00
danpergal84
a4e62fb532
Translated using Weblate (Spanish)
Currently translated at 100.0% (636 of 636 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/es/
2026-07-29 14:21:54 +00:00
Prahlis
b3cc7c424d
Translated using Weblate (Swedish)
Currently translated at 85.7% (543 of 633 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/sv/
2026-07-29 14:21:54 +00:00
TheMatrixan
6827201bdc
Translated using Weblate (Polish)
Currently translated at 100.0% (625 of 625 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/pl/
2026-07-29 14:21:54 +00:00
n8llcaster
c198f5c2b6
Translated using Weblate (Slovak)
Currently translated at 100.0% (625 of 625 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/sk/
2026-07-29 14:21:54 +00:00
idezentas
043dfb61bd
Translated using Weblate (Turkish)
Currently translated at 100.0% (625 of 625 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/tr/
2026-07-29 14:21:54 +00:00
nofkclue
c7a5ec61a3
Translated using Weblate (German)
Currently translated at 100.0% (625 of 625 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/de/
2026-07-29 14:21:54 +00:00
ymir
b96d50d166
Translated using Weblate (French)
Currently translated at 99.8% (624 of 625 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/fr/
2026-07-29 14:21:54 +00:00
opakholis
08444c2509
Translated using Weblate (Indonesian)
Currently translated at 99.8% (624 of 625 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/id/
2026-07-29 14:21:54 +00:00
nofkclue
aa83ee1382
Translated using Weblate (German)
Currently translated at 100.0% (625 of 625 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/de/
2026-07-29 14:21:54 +00:00
Outbreak2096
320c9acc8a
Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (625 of 625 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/zh_Hans/
2026-07-29 14:21:54 +00:00
arcker95
63893894d0
Translated using Weblate (Italian)
Currently translated at 100.0% (625 of 625 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/it/
2026-07-29 14:21:54 +00:00
SimonHung
8abbbabcd5
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (625 of 625 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/zh_Hant/
2026-07-29 14:21:54 +00:00
Codeberg Translate
f7348a6c7a
Update translation files
Updated by "Remove blank strings" add-on in Weblate.

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/
2026-07-29 14:21:54 +00:00
outopik
75f1f06345
Translated using Weblate (French)
Currently translated at 98.5% (616 of 625 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/fr/
2026-07-29 14:21:54 +00:00
n8llcaster
7ba5c83f33
Translated using Weblate (Slovak)
Currently translated at 100.0% (625 of 625 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/sk/
2026-07-29 14:21:54 +00:00
SimonHung
ab993b0d96
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (625 of 625 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/zh_Hant/
2026-07-29 14:21:54 +00:00
unikitty
920af648be
Translated using Weblate (English (United Kingdom))
Currently translated at 6.7% (42 of 625 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/en_GB/
2026-07-29 14:21:54 +00:00
damontecres
07592b15b4
Added translation using Weblate (English (United Kingdom)) 2026-07-29 14:21:54 +00:00
idezentas
d301cde016
Translated using Weblate (Turkish)
Currently translated at 100.0% (625 of 625 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/tr/
2026-07-29 14:21:54 +00:00
Outbreak2096
527c9e3705
Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (625 of 625 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/zh_Hans/
2026-07-29 14:21:54 +00:00
n8llcaster
f0ab44be88
Translated using Weblate (Slovak)
Currently translated at 100.0% (625 of 625 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/sk/
2026-07-29 14:21:54 +00:00
Priit Jõerüüt
a71b40feab
Translated using Weblate (Estonian)
Currently translated at 100.0% (625 of 625 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/et/
2026-07-29 14:21:54 +00:00
American_Jesus
49c14aaa6c
Translated using Weblate (Portuguese)
Currently translated at 100.0% (625 of 625 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/pt/
2026-07-29 14:21:53 +00:00
danpergal84
c906431b0d
Translated using Weblate (Spanish)
Currently translated at 100.0% (625 of 625 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/es/
2026-07-29 14:21:53 +00:00
ymir
0cacb4e4ed
Translated using Weblate (French)
Currently translated at 100.0% (612 of 612 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/fr/
2026-07-29 14:21:53 +00:00
opakholis
92a17f2b84
Translated using Weblate (Indonesian)
Currently translated at 99.8% (611 of 612 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/id/
2026-07-29 14:21:53 +00:00
viretius
15592f87aa
Translated using Weblate (German)
Currently translated at 100.0% (612 of 612 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/de/
2026-07-29 14:21:53 +00:00
idezentas
ea96feca74
Translated using Weblate (Turkish)
Currently translated at 100.0% (612 of 612 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/tr/
2026-07-29 14:21:53 +00:00
SimonHung
7c22ce7ce7
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (612 of 612 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/zh_Hant/
2026-07-29 14:21:53 +00:00
streamyfinchris
171371fb54
Translated using Weblate (Swedish)
Currently translated at 86.6% (530 of 612 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/sv/
2026-07-29 14:21:53 +00:00
tal_sarid
7a44d2c553
Translated using Weblate (Hebrew)
Currently translated at 100.0% (612 of 612 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/he/
2026-07-29 14:21:53 +00:00
danpergal84
96dceefcd8
Translated using Weblate (Spanish)
Currently translated at 100.0% (612 of 612 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/es/
2026-07-29 14:21:53 +00:00
North-DaCoder
dc1e74fc84
Translated using Weblate (German)
Currently translated at 100.0% (612 of 612 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/de/
2026-07-29 14:21:53 +00:00
Outbreak2096
78291b6dd9
Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (612 of 612 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/zh_Hans/
2026-07-29 14:21:53 +00:00
TheMatrixan
b841f5d021
Translated using Weblate (Polish)
Currently translated at 100.0% (612 of 612 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/pl/
2026-07-29 14:21:53 +00:00
arcker95
4c557f3ced
Translated using Weblate (Italian)
Currently translated at 100.0% (612 of 612 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/it/
2026-07-29 14:21:53 +00:00
SimonHung
15f8398610
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (612 of 612 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/zh_Hant/
2026-07-29 14:21:53 +00:00
n8llcaster
4739ab73eb
Translated using Weblate (Slovak)
Currently translated at 100.0% (612 of 612 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/sk/
2026-07-29 14:21:53 +00:00
Priit Jõerüüt
7da1b0b510
Translated using Weblate (Estonian)
Currently translated at 100.0% (612 of 612 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/et/
2026-07-29 14:21:53 +00:00
Outbreak2096
1f214ebf87
Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (610 of 610 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/zh_Hans/
2026-07-29 14:21:53 +00:00
idezentas
1459ac7b77
Translated using Weblate (Turkish)
Currently translated at 100.0% (610 of 610 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/tr/
2026-07-29 14:21:53 +00:00
butterflyoffire
35a0804e73
Translated using Weblate (Kabyle)
Currently translated at 9.6% (59 of 610 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/kab/
2026-07-29 14:21:53 +00:00
TheMatrixan
781efcbb8d
Translated using Weblate (Polish)
Currently translated at 100.0% (610 of 610 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/pl/
2026-07-29 14:21:53 +00:00
SimonHung
613032ebfe
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (610 of 610 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/zh_Hant/
2026-07-29 14:21:53 +00:00
n8llcaster
2de2746f77
Translated using Weblate (Slovak)
Currently translated at 100.0% (610 of 610 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/sk/
2026-07-29 14:21:53 +00:00
Priit Jõerüüt
124b587285
Translated using Weblate (Estonian)
Currently translated at 100.0% (610 of 610 strings)

Translation: Wholphin/Wholphin
Translate-URL: https://translate.codeberg.org/projects/wholphin/wholphin/et/
2026-07-29 14:21:53 +00:00
3041 changed files with 84902 additions and 7047 deletions

View file

@ -6,11 +6,11 @@ runs:
steps: steps:
# Setup the SDKs # Setup the SDKs
- name: Set up Python - name: Set up Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6 uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7
with: with:
python-version: '3.14' python-version: '3.14'
- name: Setup JDK - name: Setup JDK
uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5 uses: actions/setup-java@b843ebf9b913146b38da2eaa7aeddf76074ae1ad # v6
with: with:
distribution: zulu distribution: zulu
java-version: '21' java-version: '21'
@ -21,9 +21,9 @@ runs:
echo "BUILD_TOOLS_VERSION=36.0.0" >> $GITHUB_ENV echo "BUILD_TOOLS_VERSION=36.0.0" >> $GITHUB_ENV
echo "NDK_VERSION=29.0.14206865" >> $GITHUB_ENV echo "NDK_VERSION=29.0.14206865" >> $GITHUB_ENV
- name: Setup Android SDK - name: Setup Android SDK
uses: android-actions/setup-android@40fd30fb8d7440372e1316f5d1809ec01dcd3699 # v4 uses: android-actions/setup-android@be39fa834029ff78f1a44aa3bb0819b8fc2bd8fd # v4
with: with:
packages: "tools platform-tools build-tools;${{ env.BUILD_TOOLS_VERSION }} ndk;${{ env.NDK_VERSION }}" packages: "platform-tools build-tools;${{ env.BUILD_TOOLS_VERSION }} ndk;${{ env.NDK_VERSION }}"
- name: Add NDK to path - name: Add NDK to path
shell: bash shell: bash
run: | run: |

View file

@ -16,7 +16,7 @@ concurrency:
env: env:
BRANCH_NAME: ${{ github.ref_name }} BRANCH_NAME: ${{ github.ref_name }}
GRADLE_OPTS: "-Dorg.gradle.jvmargs='-Xmx8g -XX:MaxMetaspaceSize=512m'" GRADLE_OPTS: "-Dorg.gradle.jvmargs='-Xmx12g -XX:MaxMetaspaceSize=1024m'"
jobs: jobs:
build: build:
@ -25,7 +25,7 @@ jobs:
contents: write contents: write
steps: steps:
- name: Checkout the code - name: Checkout the code
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with: with:
fetch-depth: 0 # Need the tags to build fetch-depth: 0 # Need the tags to build
- name: Setup - name: Setup
@ -54,7 +54,8 @@ jobs:
ORG_GRADLE_PROJECT_WholphinExtensionsUsername: "${{ secrets.EXTENSIONS_USERNAME }}" ORG_GRADLE_PROJECT_WholphinExtensionsUsername: "${{ secrets.EXTENSIONS_USERNAME }}"
ORG_GRADLE_PROJECT_WholphinExtensionsPassword: "${{ secrets.EXTENSIONS_PASSWORD }}" ORG_GRADLE_PROJECT_WholphinExtensionsPassword: "${{ secrets.EXTENSIONS_PASSWORD }}"
run: | run: |
./gradlew clean assembleDefaultRelease assembleDefaultDebug --no-daemon ./gradlew clean assembleDefaultDebug
./gradlew assembleDefaultRelease
- name: Verify signatures - name: Verify signatures
run: | run: |
@ -76,7 +77,7 @@ jobs:
echo "SHA256 checksums:" echo "SHA256 checksums:"
find app/build/outputs/apk -name '*.apk' -print0 | xargs -0 sha256sum find app/build/outputs/apk -name '*.apk' -print0 | xargs -0 sha256sum
- name: Upload mapping files - name: Upload mapping files
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
with: with:
name: mapping name: mapping
path: | path: |

View file

@ -9,18 +9,18 @@ defaults:
env: env:
BUILD_DIRS_ARTIFACT: build-dirs BUILD_DIRS_ARTIFACT: build-dirs
GRADLE_OPTS: "-Dorg.gradle.jvmargs='-Xmx8g -XX:MaxMetaspaceSize=512m'" GRADLE_OPTS: "-Dorg.gradle.jvmargs='-Xmx12g -XX:MaxMetaspaceSize=1024m'"
jobs: jobs:
pre-commit: pre-commit:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout the code - name: Checkout the code
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with: with:
fetch-depth: 0 # Need the tags to build fetch-depth: 0 # Need the tags to build
- name: Setup Python - name: Setup Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6 uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7
with: with:
python-version: '3.14' python-version: '3.14'
- name: Run pre-commit - name: Run pre-commit
@ -31,7 +31,7 @@ jobs:
needs: pre-commit needs: pre-commit
steps: steps:
- name: Checkout the code - name: Checkout the code
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with: with:
fetch-depth: 0 # Need the tags to build fetch-depth: 0 # Need the tags to build
- name: Setup - name: Setup

View file

@ -11,7 +11,7 @@ defaults:
env: env:
APK_SHORT_NAME: Wholphin.apk APK_SHORT_NAME: Wholphin.apk
GRADLE_OPTS: "-Dorg.gradle.jvmargs='-Xmx8g -XX:MaxMetaspaceSize=512m'" GRADLE_OPTS: "-Dorg.gradle.jvmargs='-Xmx12g -XX:MaxMetaspaceSize=1024m'"
TAG_NAME: ${{ github.ref_name }} TAG_NAME: ${{ github.ref_name }}
jobs: jobs:
@ -21,7 +21,7 @@ jobs:
contents: write contents: write
steps: steps:
- name: Checkout the code - name: Checkout the code
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with: with:
fetch-depth: 0 # Need the tags to build fetch-depth: 0 # Need the tags to build
- name: Setup - name: Setup
@ -36,7 +36,8 @@ jobs:
ORG_GRADLE_PROJECT_WholphinExtensionsUsername: "${{ secrets.EXTENSIONS_USERNAME }}" ORG_GRADLE_PROJECT_WholphinExtensionsUsername: "${{ secrets.EXTENSIONS_USERNAME }}"
ORG_GRADLE_PROJECT_WholphinExtensionsPassword: "${{ secrets.EXTENSIONS_PASSWORD }}" ORG_GRADLE_PROJECT_WholphinExtensionsPassword: "${{ secrets.EXTENSIONS_PASSWORD }}"
run: | run: |
./gradlew clean bundleAppstoreRelease bundleFiretvRelease ./gradlew clean bundleAppstoreRelease
./gradlew bundleFiretvRelease
./gradlew assembleDefaultRelease ./gradlew assembleDefaultRelease
- name: Verify signatures - name: Verify signatures
run: | run: |
@ -58,14 +59,14 @@ jobs:
echo "SHA256 checksums:" echo "SHA256 checksums:"
find app/build/outputs \( -name '*.apk' -or -name '*.aab' \) -print0 | xargs -0 sha256sum find app/build/outputs \( -name '*.apk' -or -name '*.aab' \) -print0 | xargs -0 sha256sum
- name: Upload AAB - name: Upload AAB
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
with: with:
name: AAB name: AAB
path: | path: |
app/build/outputs/bundle/**/*.aab app/build/outputs/bundle/**/*.aab
compression-level: 0 compression-level: 0
- name: Upload mapping files - name: Upload mapping files
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
with: with:
name: mapping name: mapping
path: | path: |

View file

@ -1,8 +1,5 @@
# Intents # Intents
> [!WARNING]
> This feature is only available in the develop builds until the next release!
> [!IMPORTANT] > [!IMPORTANT]
> This feature is experimental and the exact behaviors and/or parameters may change at any time > This feature is experimental and the exact behaviors and/or parameters may change at any time
@ -36,7 +33,7 @@ Full format
```bash ```bash
adb shell am start \ adb shell am start \
-a android.intent.action.SEARCH \ -a android.intent.action.SEARCH \
-n 'com.github.damontecres.wholphin/.MainActivity' \ -n 'org.justinvisser.wolfskin.tv/com.github.damontecres.wholphin.MainActivity' \
--es query "Avengers" --es query "Avengers"
``` ```
@ -50,7 +47,7 @@ Multi-word query:
# Whole shell command is wrapped in double quotes # Whole shell command is wrapped in double quotes
adb shell "am start \ adb shell "am start \
-a android.intent.action.SEARCH \ -a android.intent.action.SEARCH \
-n 'com.github.damontecres.wholphin/.MainActivity' \ -n 'org.justinvisser.wolfskin.tv/com.github.damontecres.wholphin.MainActivity' \
--es query 'Avengers Endgame'" --es query 'Avengers Endgame'"
adb shell am start -d 'wholphin://search?query=Avengers+Endgame' adb shell am start -d 'wholphin://search?query=Avengers+Endgame'
@ -66,7 +63,7 @@ Action: `android.intent.action.VIEW`
Shorthand action: `view` Shorthand action: `view`
Parameters: Parameters:
- `itemId` - Required, the UUID of the media item - `itemId` - Optional, the UUID of the media item, if not set, goes to home screen
### Examples ### Examples
@ -75,7 +72,7 @@ Full format
```bash ```bash
adb shell am start \ adb shell am start \
-a android.intent.action.VIEW \ -a android.intent.action.VIEW \
-n 'com.github.damontecres.wholphin/.MainActivity' \ -n 'org.justinvisser.wolfskin.tv/com.github.damontecres.wholphin.MainActivity' \
--es itemId "5cf8f8e7-2a5f-4aa9-8c12-ddf63d42ee6d" --es itemId "5cf8f8e7-2a5f-4aa9-8c12-ddf63d42ee6d"
``` ```
@ -93,6 +90,7 @@ Shorthand action: `play`
Parameters: Parameters:
- `itemId` - Required, the UUID of the media item - `itemId` - Required, the UUID of the media item
- `position` - Optional, the start position for playback in milliseconds - `position` - Optional, the start position for playback in milliseconds
- `shuffle` - Optional, whether to shuffle the resulting items
### Examples ### Examples
@ -100,7 +98,7 @@ Full format
```bash ```bash
adb shell am start \ adb shell am start \
-a com.github.damontecres.wholphin.PLAYBACK \ -a com.github.damontecres.wholphin.PLAYBACK \
-n 'com.github.damontecres.wholphin/.MainActivity' \ -n 'org.justinvisser.wolfskin.tv/com.github.damontecres.wholphin.MainActivity' \
--es itemId "5cf8f8e7-2a5f-4aa9-8c12-ddf63d42ee6d" --es itemId "5cf8f8e7-2a5f-4aa9-8c12-ddf63d42ee6d"
``` ```
@ -113,25 +111,44 @@ Start at 4m30s:
```bash ```bash
adb shell am start \ adb shell am start \
-a com.github.damontecres.wholphin.PLAYBACK \ -a com.github.damontecres.wholphin.PLAYBACK \
-n 'com.github.damontecres.wholphin/.MainActivity' \ -n 'org.justinvisser.wolfskin.tv/com.github.damontecres.wholphin.MainActivity' \
--es itemId "5cf8f8e7-2a5f-4aa9-8c12-ddf63d42ee6d" \ --es itemId "5cf8f8e7-2a5f-4aa9-8c12-ddf63d42ee6d" \
--el position 270000 --el position 270000
adb shell am start -d 'wholphin://play?itemId=5cf8f8e7-2a5f-4aa9-8c12-ddf63d42ee6d\&position=270000' adb shell am start -d 'wholphin://play?itemId=5cf8f8e7-2a5f-4aa9-8c12-ddf63d42ee6d\&position=270000'
``` ```
Shuffle a series (`itemId` is the Series ID):
```bash
adb shell am start \
-a com.github.damontecres.wholphin.PLAYBACK \
-n 'org.justinvisser.wolfskin.tv/com.github.damontecres.wholphin.MainActivity' \
--es itemId "5cf8f8e7-2a5f-4aa9-8c12-ddf63d42ee6d" \
--ez shuffle true
adb shell am start -d 'wholphin://play?itemId=5cf8f8e7-2a5f-4aa9-8c12-ddf63d42ee6d\&shuffle=true'
```
## More examples ## More examples
### Switch user ### Switch user
Full format Full format
```bash ```bash
# Switch user, go to item
adb shell am start \ adb shell am start \
-a android.intent.action.VIEW \ -a android.intent.action.VIEW \
-n 'com.github.damontecres.wholphin/.MainActivity' \ -n 'org.justinvisser.wolfskin.tv/com.github.damontecres.wholphin.MainActivity' \
--es itemId "5cf8f8e7-2a5f-4aa9-8c12-ddf63d42ee6d" \ --es itemId "5cf8f8e7-2a5f-4aa9-8c12-ddf63d42ee6d" \
--es serverId "341880f9-ca88-4038-8718-f6b2407950b1" \ --es serverId "341880f9-ca88-4038-8718-f6b2407950b1" \
--es userId "5c8575e0-468d-44fb-8c70-00aa79160587" --es userId "5c8575e0-468d-44fb-8c70-00aa79160587"
# Switch user, go to home screen
adb shell am start \
-a android.intent.action.VIEW \
-n 'org.justinvisser.wolfskin.tv/com.github.damontecres.wholphin.MainActivity' \
--es serverId "341880f9-ca88-4038-8718-f6b2407950b1" \
--es userId "5c8575e0-468d-44fb-8c70-00aa79160587"
``` ```
URI based URI based
@ -146,6 +163,6 @@ Debug builds have a different package, so you must specify the component by its
```bash ```bash
adb shell am start \ adb shell am start \
-a android.intent.action.VIEW \ -a android.intent.action.VIEW \
-n 'com.github.damontecres.wholphin.debug/com.github.damontecres.wholphin.MainActivity' \ -n 'org.justinvisser.wolfskin.tv.debug/com.github.damontecres.wholphin.MainActivity' \
--es itemId "5cf8f8e7-2a5f-4aa9-8c12-ddf63d42ee6d" --es itemId "5cf8f8e7-2a5f-4aa9-8c12-ddf63d42ee6d"
``` ```

21
Makefile Normal file
View file

@ -0,0 +1,21 @@
.DEFAULT_GOAL := apk
WOLFSKIN_BUILD_IMAGE ?= wolfskin-build:sdk37-jdk21
WOLFSKIN_GRADLE_VOLUME ?= wolfskin-gradle
WOLFSKIN_SECRETS_DIR ?= /opt/stacks/ventoy/machine-parity/manifest-tank/secrets/wolfskin
export WOLFSKIN_BUILD_IMAGE WOLFSKIN_GRADLE_VOLUME WOLFSKIN_SECRETS_DIR
.PHONY: build-image apk apk-debug test release-tag
build-image:
docker build --platform linux/amd64 --tag "$(WOLFSKIN_BUILD_IMAGE)" docker
apk: build-image
@bash docker/gradle.sh release clean assembleDefaultRelease
apk-debug: build-image
@bash docker/gradle.sh debug assembleDefaultDebug
test: build-image
@bash docker/gradle.sh debug testDefaultDebugUnitTest
release-tag:
@bash docker/release-tag.sh

View file

@ -1,3 +1,15 @@
# Wolfskin
Wolfskin is a personal fork of [Wholphin](https://github.com/damontecres/Wholphin) by damontecres.
Licensed under GPL-2.0, the same licence as upstream (see [LICENSE](LICENSE)).
Wolfskin is an Android TV client for one household. It is released through Forgejo releases on this repo, and it tracks upstream by merging each upstream release tag.
The app uses Wolfskin launcher artwork and a lilac-on-`#07070a` theme by default on a fresh install. Existing theme choices and all upstream colour themes remain available under Settings → App theme. Settings → About credits and links to Wholphin by damontecres.
---
# Wholphin - an OSS Android TV client for Jellyfin # Wholphin - an OSS Android TV client for Jellyfin
> "Never half-phin two jellies. Always wholphin one jelly." > "Never half-phin two jellies. Always wholphin one jelly."
@ -103,7 +115,7 @@ Requires Android 6+ (or Fire TV OS 6+) and Jellyfin server `10.10.x` or `10.11.x
The app is tested on a variety of Android TV/Fire TV OS devices, but if you encounter issues, please file an issue! The app is tested on a variety of Android TV/Fire TV OS devices, but if you encounter issues, please file an issue!
Seerr integration is tested with `v3.3.0`. Older versions may not work. Seerr integration is generally tested with the latest stable version. Older versions may not work as expected. The Seerr server should configured with integration to your Jellyfin server for full compatibility.
## Contributions ## Contributions

View file

@ -1,3 +1,4 @@
import com.android.build.api.artifact.SingleArtifact
import com.android.build.api.dsl.ApplicationExtension import com.android.build.api.dsl.ApplicationExtension
import com.android.build.api.dsl.ProductFlavor import com.android.build.api.dsl.ProductFlavor
import com.android.build.api.variant.FilterConfiguration import com.android.build.api.variant.FilterConfiguration
@ -5,6 +6,7 @@ import com.google.protobuf.gradle.id
import com.mikepenz.aboutlibraries.plugin.DuplicateMode import com.mikepenz.aboutlibraries.plugin.DuplicateMode
import com.mikepenz.aboutlibraries.plugin.DuplicateRule import com.mikepenz.aboutlibraries.plugin.DuplicateRule
import org.jetbrains.kotlin.gradle.dsl.JvmTarget import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import java.io.File
import java.util.Base64 import java.util.Base64
import java.util.Properties import java.util.Properties
@ -65,19 +67,22 @@ kotlin {
} }
} }
private fun Provider<String>.getInt() = get().toInt()
configure<ApplicationExtension> { configure<ApplicationExtension> {
namespace = "com.github.damontecres.wholphin" namespace = "com.github.damontecres.wholphin"
compileSdk = 36 compileSdk = libs.versions.compileSdk.getInt()
defaultConfig { defaultConfig {
applicationId = "com.github.damontecres.wholphin" applicationId = "org.justinvisser.wolfskin.tv"
minSdk = 23 minSdk = libs.versions.minSdk.getInt()
targetSdk = 36 targetSdk = libs.versions.targetSdk.getInt()
versionCode = gitTags.trim().lines().size versionCode = gitTags.trim().lines().size
versionName = gitDescribe.trim().removePrefix("v").ifBlank { "0.0.0" } versionName = gitDescribe.trim().removePrefix("v").ifBlank { "0.0.0" }
testInstrumentationRunner = "com.github.damontecres.wholphin.test.WholphinTestRunner" testInstrumentationRunner = "com.github.damontecres.wholphin.test.WholphinTestRunner"
buildConfigField("long", "BUILD_TIME", System.currentTimeMillis().toString()) buildConfigField("long", "BUILD_TIME", System.currentTimeMillis().toString())
buildConfigField("String", "CONDUCTARR_BASE_URL", "\"https://wolfskin-tv.justinvisser.org\"")
} }
signingConfigs { signingConfigs {
@ -128,6 +133,13 @@ configure<ApplicationExtension> {
isDebuggable = true isDebuggable = true
applicationIdSuffix = ".debug" applicationIdSuffix = ".debug"
} }
create("optimized") {
initWith(getByName("release"))
signingConfig = signingConfigs.getByName("debug")
applicationIdSuffix = ".opt"
matchingFallbacks += "release"
}
} }
flavorDimensions += "version" flavorDimensions += "version"
productFlavors { productFlavors {
@ -178,7 +190,7 @@ configure<ApplicationExtension> {
isEnable = !isBuildingBundle.get() isEnable = !isBuildingBundle.get()
reset() reset()
include("armeabi-v7a", "arm64-v8a") include("armeabi-v7a", "arm64-v8a", "x86_64")
isUniversalApk = true isUniversalApk = true
} }
} }
@ -192,6 +204,11 @@ configure<ApplicationExtension> {
sourceSets { sourceSets {
getByName("main") { getByName("main") {
kotlin.directories += "$buildDir/generated/seerr_api/src/main/kotlin" kotlin.directories += "$buildDir/generated/seerr_api/src/main/kotlin"
kotlin.directories += "src/wolfskin/java"
}
getByName("optimized") {
kotlin.directories += "src/release/java"
baselineProfiles.directories += "src/optimized/baselineProfiles"
} }
} }
@ -222,6 +239,52 @@ androidComponents {
"Wholphin-${variant.flavorName}-${variant.buildType}-${output.versionName.get()}-${output.versionCode.get()}$abi.apk" "Wholphin-${variant.flavorName}-${variant.buildType}-${output.versionName.get()}-${output.versionCode.get()}$abi.apk"
output.outputFileName = outputFileName output.outputFileName = outputFileName
} }
if (variant.name == "defaultOptimized") {
tasks.withType<Test>().configureEach {
systemProperty("wolfskin.optimizedVersionName", variant.outputs.first().versionName.get())
}
}
if (variant.name == "defaultDebug") {
val packagedApks = variant.artifacts.get(SingleArtifact.APK)
val artifactLoader = variant.artifacts.getBuiltArtifactsLoader()
val aapt2 = sdkComponents.aapt2.flatMap { it.executable }
val checkWolfskinBranding = tasks.register("checkWolfskinBranding") {
inputs.dir(packagedApks)
inputs.file(aapt2)
doLast {
val artifacts = checkNotNull(artifactLoader.load(packagedApks.get())) {
"Packaged default/debug APK metadata was not found; branding is unverified"
}.elements
check(artifacts.isNotEmpty()) { "No default/debug APKs were found; branding is unverified" }
val header = Regex("""^\s*resource 0x[\da-fA-F]+ (?:[^\s:]+:)?([^\s/]+)/([^\s]+)""")
val visibleTypes = setOf("string", "plurals", "array")
// Upstream legal attribution and its project URL must survive the branding cutover.
val legalNames = setOf("wolfskin_upstream_credit", "wolfskin_upstream_url")
val violations = sortedSetOf<String>()
artifacts.forEach { artifact ->
val dump = providers.exec {
commandLine(aapt2.get().asFile, "dump", "resources", artifact.outputFile)
}.standardOutput.asText.get()
var currentName: String? = null
var inspected = 0
dump.lineSequence().forEach { line ->
val resource = header.find(line)
if (resource != null) {
currentName = resource.groupValues[2].takeIf { resource.groupValues[1] in visibleTypes }
if (currentName != null) inspected++
} else if (currentName != null && currentName !in legalNames && line.contains("Wholphin", ignoreCase = true)) {
violations += "${File(artifact.outputFile).name}:$currentName"
}
}
check(inspected > 0) { "No packaged string resources were decoded; branding is unverified" }
logger.lifecycle("Inspected $inspected string/plural/array resources in ${File(artifact.outputFile).name}")
}
check(violations.isEmpty()) { "User-visible upstream branding remains: ${violations.joinToString()}" }
logger.lifecycle("Wolfskin branding check passed (${artifacts.size} packaged debug APKs; legal attribution preserved)")
}
}
tasks.matching { it.name == "assembleDefaultDebug" }.configureEach { dependsOn(checkWolfskinBranding) }
}
} }
} }
@ -286,6 +349,8 @@ tasks.named("preBuild") {
} }
dependencies { dependencies {
implementation(project(":wolfskin-design"))
implementation(project(":conductarr-client"))
implementation(libs.androidx.core.ktx) implementation(libs.androidx.core.ktx)
implementation(libs.androidx.appcompat) implementation(libs.androidx.appcompat)
implementation(platform(libs.androidx.compose.bom)) implementation(platform(libs.androidx.compose.bom))
@ -303,6 +368,7 @@ dependencies {
implementation(libs.androidx.tvprovider) implementation(libs.androidx.tvprovider)
implementation(libs.androidx.work.runtime.ktx) implementation(libs.androidx.work.runtime.ktx)
implementation(libs.androidx.hilt.work) implementation(libs.androidx.hilt.work)
implementation(libs.androidx.profileinstaller)
implementation(libs.androidx.media3.exoplayer) implementation(libs.androidx.media3.exoplayer)
implementation(libs.androidx.media3.session) implementation(libs.androidx.media3.session)
@ -312,6 +378,7 @@ dependencies {
implementation(libs.androidx.media3.ui) implementation(libs.androidx.media3.ui)
implementation(libs.androidx.media3.ui.compose) implementation(libs.androidx.media3.ui.compose)
implementation(libs.ass.media) implementation(libs.ass.media)
implementation(libs.exoplayerhdrutils)
implementation(libs.coil.core) implementation(libs.coil.core)
implementation(libs.coil.compose) implementation(libs.coil.compose)
@ -398,12 +465,23 @@ dependencies {
testImplementation(libs.mockk.android) testImplementation(libs.mockk.android)
testImplementation(libs.mockk.agent) testImplementation(libs.mockk.agent)
testImplementation(libs.kotlinx.coroutines.test) testImplementation(libs.kotlinx.coroutines.test)
testImplementation("com.squareup.okhttp3:mockwebserver3")
testImplementation(libs.androidx.core.testing) testImplementation(libs.androidx.core.testing)
testImplementation(libs.robolectric) testImplementation(libs.robolectric)
testImplementation(libs.hilt.android.testing) testImplementation(libs.hilt.android.testing)
testImplementation(libs.androidx.compose.ui.test.junit4) testImplementation(libs.androidx.compose.ui.test.junit4)
testImplementation("io.github.takahirom.roborazzi:roborazzi:1.77.0")
testImplementation("io.github.takahirom.roborazzi:roborazzi-compose:1.77.0")
androidTestImplementation(platform(libs.androidx.compose.bom)) androidTestImplementation(platform(libs.androidx.compose.bom))
androidTestImplementation(libs.mockk.android) androidTestImplementation(libs.mockk.android)
androidTestImplementation(libs.hilt.android.testing) androidTestImplementation(libs.hilt.android.testing)
androidTestImplementation(libs.androidx.compose.ui.test.manifest) androidTestImplementation(libs.androidx.compose.ui.test.manifest)
} }
tasks.withType<Test>().configureEach {
dependsOn(":wolfskin-design:testDebugUnitTest")
systemProperty("robolectric.dependency.dir", project(":wolfskin-design").layout.buildDirectory.dir("robolectric-sdk").get().asFile.absolutePath)
systemProperty("robolectric.offline", "true")
systemProperty("roborazzi.test.record", "true")
systemProperty("wolfskin.captureDirectory", rootProject.layout.buildDirectory.dir("wolfskin-captures").get().asFile.absolutePath)
}

View file

@ -22,3 +22,6 @@
-keep class androidx.media3.ui.SubtitlePainter { -keep class androidx.media3.ui.SubtitlePainter {
private final float outlineWidth; private final float outlineWidth;
} }
# Keep external/native functions
-keep class com.suyashbelekar.exoplayerhdrutils.libdovi.LibDovi { *; }

View file

@ -0,0 +1,834 @@
{
"formatVersion": 1,
"database": {
"version": 40,
"identityHash": "b297c087485321c3ee8282ad1ff675a0",
"entities": [
{
"tableName": "servers",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `name` TEXT, `url` TEXT NOT NULL, `version` TEXT, `lastUsed` TEXT, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT"
},
{
"fieldPath": "url",
"columnName": "url",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "version",
"columnName": "version",
"affinity": "TEXT"
},
{
"fieldPath": "lastUsed",
"columnName": "lastUsed",
"affinity": "TEXT"
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"id"
]
}
},
{
"tableName": "users",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`rowId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `id` TEXT NOT NULL, `name` TEXT, `serverId` TEXT NOT NULL, `accessToken` TEXT, `pin` TEXT, `requireLogin` INTEGER NOT NULL DEFAULT false, `lastUsed` TEXT, `uiLanguage` TEXT, `preferredAudioLanguage` TEXT NOT NULL DEFAULT '', `preferredSubtitleLanguage` TEXT NOT NULL DEFAULT '', `subtitleMode` TEXT NOT NULL DEFAULT 'USE_USER_PROFILE', FOREIGN KEY(`serverId`) REFERENCES `servers`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "rowId",
"columnName": "rowId",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "id",
"columnName": "id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT"
},
{
"fieldPath": "serverId",
"columnName": "serverId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "accessToken",
"columnName": "accessToken",
"affinity": "TEXT"
},
{
"fieldPath": "pin",
"columnName": "pin",
"affinity": "TEXT"
},
{
"fieldPath": "requireLogin",
"columnName": "requireLogin",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "false"
},
{
"fieldPath": "lastUsed",
"columnName": "lastUsed",
"affinity": "TEXT"
},
{
"fieldPath": "uiLanguage",
"columnName": "uiLanguage",
"affinity": "TEXT"
},
{
"fieldPath": "appPreferences.preferredAudioLanguage",
"columnName": "preferredAudioLanguage",
"affinity": "TEXT",
"notNull": true,
"defaultValue": "''"
},
{
"fieldPath": "appPreferences.preferredSubtitleLanguage",
"columnName": "preferredSubtitleLanguage",
"affinity": "TEXT",
"notNull": true,
"defaultValue": "''"
},
{
"fieldPath": "appPreferences.subtitleMode",
"columnName": "subtitleMode",
"affinity": "TEXT",
"notNull": true,
"defaultValue": "'USE_USER_PROFILE'"
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"rowId"
]
},
"indices": [
{
"name": "index_users_id_serverId",
"unique": true,
"columnNames": [
"id",
"serverId"
],
"orders": [],
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_users_id_serverId` ON `${TABLE_NAME}` (`id`, `serverId`)"
},
{
"name": "index_users_id",
"unique": false,
"columnNames": [
"id"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_users_id` ON `${TABLE_NAME}` (`id`)"
},
{
"name": "index_users_serverId",
"unique": false,
"columnNames": [
"serverId"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_users_serverId` ON `${TABLE_NAME}` (`serverId`)"
}
],
"foreignKeys": [
{
"table": "servers",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"serverId"
],
"referencedColumns": [
"id"
]
}
]
},
{
"tableName": "ItemPlayback",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`rowId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `userId` INTEGER NOT NULL, `itemId` TEXT NOT NULL, `sourceId` TEXT, `audioIndex` INTEGER NOT NULL, `subtitleIndex` INTEGER NOT NULL, FOREIGN KEY(`userId`) REFERENCES `users`(`rowId`) ON UPDATE CASCADE ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "rowId",
"columnName": "rowId",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "userId",
"columnName": "userId",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "itemId",
"columnName": "itemId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "sourceId",
"columnName": "sourceId",
"affinity": "TEXT"
},
{
"fieldPath": "audioIndex",
"columnName": "audioIndex",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "subtitleIndex",
"columnName": "subtitleIndex",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"rowId"
]
},
"indices": [
{
"name": "index_ItemPlayback_userId_itemId",
"unique": true,
"columnNames": [
"userId",
"itemId"
],
"orders": [],
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_ItemPlayback_userId_itemId` ON `${TABLE_NAME}` (`userId`, `itemId`)"
}
],
"foreignKeys": [
{
"table": "users",
"onDelete": "CASCADE",
"onUpdate": "CASCADE",
"columns": [
"userId"
],
"referencedColumns": [
"rowId"
]
}
]
},
{
"tableName": "NavDrawerPinnedItem",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`userId` INTEGER NOT NULL, `itemId` TEXT NOT NULL, `type` TEXT NOT NULL, `order` INTEGER NOT NULL DEFAULT -1, PRIMARY KEY(`userId`, `itemId`), FOREIGN KEY(`userId`) REFERENCES `users`(`rowId`) ON UPDATE CASCADE ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "userId",
"columnName": "userId",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "itemId",
"columnName": "itemId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "type",
"columnName": "type",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "order",
"columnName": "order",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "-1"
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"userId",
"itemId"
]
},
"foreignKeys": [
{
"table": "users",
"onDelete": "CASCADE",
"onUpdate": "CASCADE",
"columns": [
"userId"
],
"referencedColumns": [
"rowId"
]
}
]
},
{
"tableName": "LibraryDisplayInfo",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`userId` INTEGER NOT NULL, `itemId` TEXT NOT NULL, `sort` TEXT NOT NULL, `direction` TEXT NOT NULL, `filter` TEXT NOT NULL DEFAULT '{}', `viewOptions` TEXT, PRIMARY KEY(`userId`, `itemId`), FOREIGN KEY(`userId`) REFERENCES `users`(`rowId`) ON UPDATE CASCADE ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "userId",
"columnName": "userId",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "itemId",
"columnName": "itemId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "sort",
"columnName": "sort",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "direction",
"columnName": "direction",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "filter",
"columnName": "filter",
"affinity": "TEXT",
"notNull": true,
"defaultValue": "'{}'"
},
{
"fieldPath": "viewOptions",
"columnName": "viewOptions",
"affinity": "TEXT"
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"userId",
"itemId"
]
},
"indices": [
{
"name": "index_LibraryDisplayInfo_userId_itemId",
"unique": true,
"columnNames": [
"userId",
"itemId"
],
"orders": [],
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_LibraryDisplayInfo_userId_itemId` ON `${TABLE_NAME}` (`userId`, `itemId`)"
}
],
"foreignKeys": [
{
"table": "users",
"onDelete": "CASCADE",
"onUpdate": "CASCADE",
"columns": [
"userId"
],
"referencedColumns": [
"rowId"
]
}
]
},
{
"tableName": "playback_effects",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`jellyfinUserRowId` INTEGER NOT NULL, `itemId` TEXT NOT NULL, `type` TEXT NOT NULL, `rotation` INTEGER NOT NULL, `brightness` INTEGER NOT NULL, `contrast` INTEGER NOT NULL, `saturation` INTEGER NOT NULL, `hue` INTEGER NOT NULL, `red` INTEGER NOT NULL, `green` INTEGER NOT NULL, `blue` INTEGER NOT NULL, `blur` INTEGER NOT NULL, PRIMARY KEY(`jellyfinUserRowId`, `itemId`, `type`))",
"fields": [
{
"fieldPath": "jellyfinUserRowId",
"columnName": "jellyfinUserRowId",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "itemId",
"columnName": "itemId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "type",
"columnName": "type",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "videoFilter.rotation",
"columnName": "rotation",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "videoFilter.brightness",
"columnName": "brightness",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "videoFilter.contrast",
"columnName": "contrast",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "videoFilter.saturation",
"columnName": "saturation",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "videoFilter.hue",
"columnName": "hue",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "videoFilter.red",
"columnName": "red",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "videoFilter.green",
"columnName": "green",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "videoFilter.blue",
"columnName": "blue",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "videoFilter.blur",
"columnName": "blur",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"jellyfinUserRowId",
"itemId",
"type"
]
}
},
{
"tableName": "PlaybackLanguageChoice",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`userId` INTEGER NOT NULL, `seriesId` TEXT NOT NULL, `itemId` TEXT, `audioLanguage` TEXT, `subtitleLanguage` TEXT, `subtitlesDisabled` INTEGER, PRIMARY KEY(`userId`, `seriesId`), FOREIGN KEY(`userId`) REFERENCES `users`(`rowId`) ON UPDATE CASCADE ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "userId",
"columnName": "userId",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "seriesId",
"columnName": "seriesId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "itemId",
"columnName": "itemId",
"affinity": "TEXT"
},
{
"fieldPath": "audioLanguage",
"columnName": "audioLanguage",
"affinity": "TEXT"
},
{
"fieldPath": "subtitleLanguage",
"columnName": "subtitleLanguage",
"affinity": "TEXT"
},
{
"fieldPath": "subtitlesDisabled",
"columnName": "subtitlesDisabled",
"affinity": "INTEGER"
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"userId",
"seriesId"
]
},
"foreignKeys": [
{
"table": "users",
"onDelete": "CASCADE",
"onUpdate": "CASCADE",
"columns": [
"userId"
],
"referencedColumns": [
"rowId"
]
}
]
},
{
"tableName": "ItemTrackModification",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`userId` INTEGER NOT NULL, `itemId` TEXT NOT NULL, `trackIndex` INTEGER NOT NULL, `delayMs` INTEGER NOT NULL, PRIMARY KEY(`userId`, `itemId`, `trackIndex`), FOREIGN KEY(`userId`) REFERENCES `users`(`rowId`) ON UPDATE CASCADE ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "userId",
"columnName": "userId",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "itemId",
"columnName": "itemId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "trackIndex",
"columnName": "trackIndex",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "delayMs",
"columnName": "delayMs",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"userId",
"itemId",
"trackIndex"
]
},
"foreignKeys": [
{
"table": "users",
"onDelete": "CASCADE",
"onUpdate": "CASCADE",
"columns": [
"userId"
],
"referencedColumns": [
"rowId"
]
}
]
},
{
"tableName": "seerr_servers",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `url` TEXT NOT NULL, `name` TEXT, `version` TEXT)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "url",
"columnName": "url",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT"
},
{
"fieldPath": "version",
"columnName": "version",
"affinity": "TEXT"
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
},
"indices": [
{
"name": "index_seerr_servers_url",
"unique": true,
"columnNames": [
"url"
],
"orders": [],
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_seerr_servers_url` ON `${TABLE_NAME}` (`url`)"
}
]
},
{
"tableName": "seerr_users",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`jellyfinUserRowId` INTEGER NOT NULL, `serverId` INTEGER NOT NULL, `authMethod` TEXT NOT NULL, `username` TEXT, `password` TEXT, `credential` TEXT, PRIMARY KEY(`jellyfinUserRowId`, `serverId`), FOREIGN KEY(`serverId`) REFERENCES `seerr_servers`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`jellyfinUserRowId`) REFERENCES `users`(`rowId`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "jellyfinUserRowId",
"columnName": "jellyfinUserRowId",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "serverId",
"columnName": "serverId",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "authMethod",
"columnName": "authMethod",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "username",
"columnName": "username",
"affinity": "TEXT"
},
{
"fieldPath": "password",
"columnName": "password",
"affinity": "TEXT"
},
{
"fieldPath": "credential",
"columnName": "credential",
"affinity": "TEXT"
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"jellyfinUserRowId",
"serverId"
]
},
"foreignKeys": [
{
"table": "seerr_servers",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"serverId"
],
"referencedColumns": [
"id"
]
},
{
"table": "users",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"jellyfinUserRowId"
],
"referencedColumns": [
"rowId"
]
}
]
},
{
"tableName": "RememberedTab",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`userId` INTEGER NOT NULL, `itemId` TEXT NOT NULL, `index` INTEGER NOT NULL, PRIMARY KEY(`userId`, `itemId`), FOREIGN KEY(`userId`) REFERENCES `users`(`rowId`) ON UPDATE CASCADE ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "userId",
"columnName": "userId",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "itemId",
"columnName": "itemId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "index",
"columnName": "index",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"userId",
"itemId"
]
},
"indices": [
{
"name": "index_RememberedTab_userId_itemId",
"unique": true,
"columnNames": [
"userId",
"itemId"
],
"orders": [],
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_RememberedTab_userId_itemId` ON `${TABLE_NAME}` (`userId`, `itemId`)"
}
],
"foreignKeys": [
{
"table": "users",
"onDelete": "CASCADE",
"onUpdate": "CASCADE",
"columns": [
"userId"
],
"referencedColumns": [
"rowId"
]
}
]
},
{
"tableName": "SeriesTrackChoice",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`userId` INTEGER NOT NULL, `parentId` TEXT NOT NULL, `type` TEXT NOT NULL, `parentType` TEXT NOT NULL, `itemId` TEXT, `language` TEXT, `activation` TEXT NOT NULL, `trackFlags` INTEGER NOT NULL, `codec` TEXT, `relativeTrackIndex` INTEGER, `title` TEXT, `audioChannels` INTEGER, PRIMARY KEY(`userId`, `parentId`, `type`), FOREIGN KEY(`userId`) REFERENCES `users`(`rowId`) ON UPDATE CASCADE ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "userId",
"columnName": "userId",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "parentId",
"columnName": "parentId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "type",
"columnName": "type",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "parentType",
"columnName": "parentType",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "itemId",
"columnName": "itemId",
"affinity": "TEXT"
},
{
"fieldPath": "language",
"columnName": "language",
"affinity": "TEXT"
},
{
"fieldPath": "activation",
"columnName": "activation",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "trackFlags",
"columnName": "trackFlags",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "codec",
"columnName": "codec",
"affinity": "TEXT"
},
{
"fieldPath": "relativeTrackIndex",
"columnName": "relativeTrackIndex",
"affinity": "INTEGER"
},
{
"fieldPath": "title",
"columnName": "title",
"affinity": "TEXT"
},
{
"fieldPath": "audioChannels",
"columnName": "audioChannels",
"affinity": "INTEGER"
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"userId",
"parentId",
"type"
]
},
"foreignKeys": [
{
"table": "users",
"onDelete": "CASCADE",
"onUpdate": "CASCADE",
"columns": [
"userId"
],
"referencedColumns": [
"rowId"
]
}
]
}
],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'b297c087485321c3ee8282ad1ff675a0')"
]
}
}

View file

@ -0,0 +1,841 @@
{
"formatVersion": 1,
"database": {
"version": 41,
"identityHash": "1f2fe7912f9e3ab83b77029e07488e84",
"entities": [
{
"tableName": "servers",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `name` TEXT, `url` TEXT NOT NULL, `version` TEXT, `lastUsed` TEXT, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT"
},
{
"fieldPath": "url",
"columnName": "url",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "version",
"columnName": "version",
"affinity": "TEXT"
},
{
"fieldPath": "lastUsed",
"columnName": "lastUsed",
"affinity": "TEXT"
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"id"
]
}
},
{
"tableName": "users",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`rowId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `id` TEXT NOT NULL, `name` TEXT, `serverId` TEXT NOT NULL, `accessToken` TEXT, `pin` TEXT, `requireLogin` INTEGER NOT NULL DEFAULT false, `lastUsed` TEXT, `uiLanguage` TEXT, `preferredAudioLanguage` TEXT NOT NULL DEFAULT '', `preferredSubtitleLanguage` TEXT NOT NULL DEFAULT '', `subtitleMode` TEXT NOT NULL DEFAULT 'USE_USER_PROFILE', `c_homeSettingsSource` TEXT NOT NULL DEFAULT 'UNSET', FOREIGN KEY(`serverId`) REFERENCES `servers`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "rowId",
"columnName": "rowId",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "id",
"columnName": "id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT"
},
{
"fieldPath": "serverId",
"columnName": "serverId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "accessToken",
"columnName": "accessToken",
"affinity": "TEXT"
},
{
"fieldPath": "pin",
"columnName": "pin",
"affinity": "TEXT"
},
{
"fieldPath": "requireLogin",
"columnName": "requireLogin",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "false"
},
{
"fieldPath": "lastUsed",
"columnName": "lastUsed",
"affinity": "TEXT"
},
{
"fieldPath": "uiLanguage",
"columnName": "uiLanguage",
"affinity": "TEXT"
},
{
"fieldPath": "appPreferences.preferredAudioLanguage",
"columnName": "preferredAudioLanguage",
"affinity": "TEXT",
"notNull": true,
"defaultValue": "''"
},
{
"fieldPath": "appPreferences.preferredSubtitleLanguage",
"columnName": "preferredSubtitleLanguage",
"affinity": "TEXT",
"notNull": true,
"defaultValue": "''"
},
{
"fieldPath": "appPreferences.subtitleMode",
"columnName": "subtitleMode",
"affinity": "TEXT",
"notNull": true,
"defaultValue": "'USE_USER_PROFILE'"
},
{
"fieldPath": "config.homeSettingsSource",
"columnName": "c_homeSettingsSource",
"affinity": "TEXT",
"notNull": true,
"defaultValue": "'UNSET'"
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"rowId"
]
},
"indices": [
{
"name": "index_users_id_serverId",
"unique": true,
"columnNames": [
"id",
"serverId"
],
"orders": [],
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_users_id_serverId` ON `${TABLE_NAME}` (`id`, `serverId`)"
},
{
"name": "index_users_id",
"unique": false,
"columnNames": [
"id"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_users_id` ON `${TABLE_NAME}` (`id`)"
},
{
"name": "index_users_serverId",
"unique": false,
"columnNames": [
"serverId"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_users_serverId` ON `${TABLE_NAME}` (`serverId`)"
}
],
"foreignKeys": [
{
"table": "servers",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"serverId"
],
"referencedColumns": [
"id"
]
}
]
},
{
"tableName": "ItemPlayback",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`rowId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `userId` INTEGER NOT NULL, `itemId` TEXT NOT NULL, `sourceId` TEXT, `audioIndex` INTEGER NOT NULL, `subtitleIndex` INTEGER NOT NULL, FOREIGN KEY(`userId`) REFERENCES `users`(`rowId`) ON UPDATE CASCADE ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "rowId",
"columnName": "rowId",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "userId",
"columnName": "userId",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "itemId",
"columnName": "itemId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "sourceId",
"columnName": "sourceId",
"affinity": "TEXT"
},
{
"fieldPath": "audioIndex",
"columnName": "audioIndex",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "subtitleIndex",
"columnName": "subtitleIndex",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"rowId"
]
},
"indices": [
{
"name": "index_ItemPlayback_userId_itemId",
"unique": true,
"columnNames": [
"userId",
"itemId"
],
"orders": [],
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_ItemPlayback_userId_itemId` ON `${TABLE_NAME}` (`userId`, `itemId`)"
}
],
"foreignKeys": [
{
"table": "users",
"onDelete": "CASCADE",
"onUpdate": "CASCADE",
"columns": [
"userId"
],
"referencedColumns": [
"rowId"
]
}
]
},
{
"tableName": "NavDrawerPinnedItem",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`userId` INTEGER NOT NULL, `itemId` TEXT NOT NULL, `type` TEXT NOT NULL, `order` INTEGER NOT NULL DEFAULT -1, PRIMARY KEY(`userId`, `itemId`), FOREIGN KEY(`userId`) REFERENCES `users`(`rowId`) ON UPDATE CASCADE ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "userId",
"columnName": "userId",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "itemId",
"columnName": "itemId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "type",
"columnName": "type",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "order",
"columnName": "order",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "-1"
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"userId",
"itemId"
]
},
"foreignKeys": [
{
"table": "users",
"onDelete": "CASCADE",
"onUpdate": "CASCADE",
"columns": [
"userId"
],
"referencedColumns": [
"rowId"
]
}
]
},
{
"tableName": "LibraryDisplayInfo",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`userId` INTEGER NOT NULL, `itemId` TEXT NOT NULL, `sort` TEXT NOT NULL, `direction` TEXT NOT NULL, `filter` TEXT NOT NULL DEFAULT '{}', `viewOptions` TEXT, PRIMARY KEY(`userId`, `itemId`), FOREIGN KEY(`userId`) REFERENCES `users`(`rowId`) ON UPDATE CASCADE ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "userId",
"columnName": "userId",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "itemId",
"columnName": "itemId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "sort",
"columnName": "sort",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "direction",
"columnName": "direction",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "filter",
"columnName": "filter",
"affinity": "TEXT",
"notNull": true,
"defaultValue": "'{}'"
},
{
"fieldPath": "viewOptions",
"columnName": "viewOptions",
"affinity": "TEXT"
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"userId",
"itemId"
]
},
"indices": [
{
"name": "index_LibraryDisplayInfo_userId_itemId",
"unique": true,
"columnNames": [
"userId",
"itemId"
],
"orders": [],
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_LibraryDisplayInfo_userId_itemId` ON `${TABLE_NAME}` (`userId`, `itemId`)"
}
],
"foreignKeys": [
{
"table": "users",
"onDelete": "CASCADE",
"onUpdate": "CASCADE",
"columns": [
"userId"
],
"referencedColumns": [
"rowId"
]
}
]
},
{
"tableName": "playback_effects",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`jellyfinUserRowId` INTEGER NOT NULL, `itemId` TEXT NOT NULL, `type` TEXT NOT NULL, `rotation` INTEGER NOT NULL, `brightness` INTEGER NOT NULL, `contrast` INTEGER NOT NULL, `saturation` INTEGER NOT NULL, `hue` INTEGER NOT NULL, `red` INTEGER NOT NULL, `green` INTEGER NOT NULL, `blue` INTEGER NOT NULL, `blur` INTEGER NOT NULL, PRIMARY KEY(`jellyfinUserRowId`, `itemId`, `type`))",
"fields": [
{
"fieldPath": "jellyfinUserRowId",
"columnName": "jellyfinUserRowId",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "itemId",
"columnName": "itemId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "type",
"columnName": "type",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "videoFilter.rotation",
"columnName": "rotation",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "videoFilter.brightness",
"columnName": "brightness",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "videoFilter.contrast",
"columnName": "contrast",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "videoFilter.saturation",
"columnName": "saturation",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "videoFilter.hue",
"columnName": "hue",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "videoFilter.red",
"columnName": "red",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "videoFilter.green",
"columnName": "green",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "videoFilter.blue",
"columnName": "blue",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "videoFilter.blur",
"columnName": "blur",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"jellyfinUserRowId",
"itemId",
"type"
]
}
},
{
"tableName": "PlaybackLanguageChoice",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`userId` INTEGER NOT NULL, `seriesId` TEXT NOT NULL, `itemId` TEXT, `audioLanguage` TEXT, `subtitleLanguage` TEXT, `subtitlesDisabled` INTEGER, PRIMARY KEY(`userId`, `seriesId`), FOREIGN KEY(`userId`) REFERENCES `users`(`rowId`) ON UPDATE CASCADE ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "userId",
"columnName": "userId",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "seriesId",
"columnName": "seriesId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "itemId",
"columnName": "itemId",
"affinity": "TEXT"
},
{
"fieldPath": "audioLanguage",
"columnName": "audioLanguage",
"affinity": "TEXT"
},
{
"fieldPath": "subtitleLanguage",
"columnName": "subtitleLanguage",
"affinity": "TEXT"
},
{
"fieldPath": "subtitlesDisabled",
"columnName": "subtitlesDisabled",
"affinity": "INTEGER"
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"userId",
"seriesId"
]
},
"foreignKeys": [
{
"table": "users",
"onDelete": "CASCADE",
"onUpdate": "CASCADE",
"columns": [
"userId"
],
"referencedColumns": [
"rowId"
]
}
]
},
{
"tableName": "ItemTrackModification",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`userId` INTEGER NOT NULL, `itemId` TEXT NOT NULL, `trackIndex` INTEGER NOT NULL, `delayMs` INTEGER NOT NULL, PRIMARY KEY(`userId`, `itemId`, `trackIndex`), FOREIGN KEY(`userId`) REFERENCES `users`(`rowId`) ON UPDATE CASCADE ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "userId",
"columnName": "userId",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "itemId",
"columnName": "itemId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "trackIndex",
"columnName": "trackIndex",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "delayMs",
"columnName": "delayMs",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"userId",
"itemId",
"trackIndex"
]
},
"foreignKeys": [
{
"table": "users",
"onDelete": "CASCADE",
"onUpdate": "CASCADE",
"columns": [
"userId"
],
"referencedColumns": [
"rowId"
]
}
]
},
{
"tableName": "seerr_servers",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `url` TEXT NOT NULL, `name` TEXT, `version` TEXT)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "url",
"columnName": "url",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT"
},
{
"fieldPath": "version",
"columnName": "version",
"affinity": "TEXT"
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
},
"indices": [
{
"name": "index_seerr_servers_url",
"unique": true,
"columnNames": [
"url"
],
"orders": [],
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_seerr_servers_url` ON `${TABLE_NAME}` (`url`)"
}
]
},
{
"tableName": "seerr_users",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`jellyfinUserRowId` INTEGER NOT NULL, `serverId` INTEGER NOT NULL, `authMethod` TEXT NOT NULL, `username` TEXT, `password` TEXT, `credential` TEXT, PRIMARY KEY(`jellyfinUserRowId`, `serverId`), FOREIGN KEY(`serverId`) REFERENCES `seerr_servers`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`jellyfinUserRowId`) REFERENCES `users`(`rowId`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "jellyfinUserRowId",
"columnName": "jellyfinUserRowId",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "serverId",
"columnName": "serverId",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "authMethod",
"columnName": "authMethod",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "username",
"columnName": "username",
"affinity": "TEXT"
},
{
"fieldPath": "password",
"columnName": "password",
"affinity": "TEXT"
},
{
"fieldPath": "credential",
"columnName": "credential",
"affinity": "TEXT"
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"jellyfinUserRowId",
"serverId"
]
},
"foreignKeys": [
{
"table": "seerr_servers",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"serverId"
],
"referencedColumns": [
"id"
]
},
{
"table": "users",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"jellyfinUserRowId"
],
"referencedColumns": [
"rowId"
]
}
]
},
{
"tableName": "RememberedTab",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`userId` INTEGER NOT NULL, `itemId` TEXT NOT NULL, `index` INTEGER NOT NULL, PRIMARY KEY(`userId`, `itemId`), FOREIGN KEY(`userId`) REFERENCES `users`(`rowId`) ON UPDATE CASCADE ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "userId",
"columnName": "userId",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "itemId",
"columnName": "itemId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "index",
"columnName": "index",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"userId",
"itemId"
]
},
"indices": [
{
"name": "index_RememberedTab_userId_itemId",
"unique": true,
"columnNames": [
"userId",
"itemId"
],
"orders": [],
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_RememberedTab_userId_itemId` ON `${TABLE_NAME}` (`userId`, `itemId`)"
}
],
"foreignKeys": [
{
"table": "users",
"onDelete": "CASCADE",
"onUpdate": "CASCADE",
"columns": [
"userId"
],
"referencedColumns": [
"rowId"
]
}
]
},
{
"tableName": "SeriesTrackChoice",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`userId` INTEGER NOT NULL, `parentId` TEXT NOT NULL, `type` TEXT NOT NULL, `parentType` TEXT NOT NULL, `itemId` TEXT, `language` TEXT, `activation` TEXT NOT NULL, `trackFlags` INTEGER NOT NULL, `codec` TEXT, `relativeTrackIndex` INTEGER, `title` TEXT, `audioChannels` INTEGER, PRIMARY KEY(`userId`, `parentId`, `type`), FOREIGN KEY(`userId`) REFERENCES `users`(`rowId`) ON UPDATE CASCADE ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "userId",
"columnName": "userId",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "parentId",
"columnName": "parentId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "type",
"columnName": "type",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "parentType",
"columnName": "parentType",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "itemId",
"columnName": "itemId",
"affinity": "TEXT"
},
{
"fieldPath": "language",
"columnName": "language",
"affinity": "TEXT"
},
{
"fieldPath": "activation",
"columnName": "activation",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "trackFlags",
"columnName": "trackFlags",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "codec",
"columnName": "codec",
"affinity": "TEXT"
},
{
"fieldPath": "relativeTrackIndex",
"columnName": "relativeTrackIndex",
"affinity": "INTEGER"
},
{
"fieldPath": "title",
"columnName": "title",
"affinity": "TEXT"
},
{
"fieldPath": "audioChannels",
"columnName": "audioChannels",
"affinity": "INTEGER"
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"userId",
"parentId",
"type"
]
},
"foreignKeys": [
{
"table": "users",
"onDelete": "CASCADE",
"onUpdate": "CASCADE",
"columns": [
"userId"
],
"referencedColumns": [
"rowId"
]
}
]
}
],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '1f2fe7912f9e3ab83b77029e07488e84')"
]
}
}

View file

@ -3,5 +3,8 @@
xmlns:tools="http://schemas.android.com/tools"> xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" tools:node="remove" /> <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" tools:node="remove" />
<uses-permission
android:name="com.amazon.permission.media.session.voicecommandcontrol"
tools:node="remove" />
</manifest> </manifest>

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Some files were not shown because too many files have changed in this diff Show more