From b99f21efa8ab08a254edfb13170974f616cd631f Mon Sep 17 00:00:00 2001 From: Damontecres Date: Thu, 8 Oct 2026 08:09:20 -0400 Subject: [PATCH] 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 --- .../wholphin/data/model/AudioItem.kt | 2 +- .../wholphin/services/BackdropService.kt | 14 +- .../wholphin/services/UpdateChecker.kt | 15 +- .../wholphin/ui/components/ContextMenu.kt | 13 + .../ui/detail/music/AlbumDetailsPage.kt | 1 + .../ui/detail/music/ArtistDetailsPage.kt | 3 + .../ui/detail/music/NowPlayingPage.kt | 7 + .../ui/detail/music/NowPlayingViewModel.kt | 3 +- .../ui/detail/series/SeriesViewModel.kt | 16 +- .../ui/playback/PlaybackKeyHandler.kt | 6 +- .../wholphin/ui/playback/PlaybackPage.kt | 2 + .../ui/preferences/PreferencesContent.kt | 13 +- .../wholphin/test/TestUpdateChecker.kt | 41 ++- app/src/test/resources/release_v108.json | 344 ++++++++++++++++++ 14 files changed, 453 insertions(+), 27 deletions(-) create mode 100644 app/src/test/resources/release_v108.json diff --git a/app/src/main/java/com/github/damontecres/wholphin/data/model/AudioItem.kt b/app/src/main/java/com/github/damontecres/wholphin/data/model/AudioItem.kt index 9c8009db..cf8ce4d0 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/data/model/AudioItem.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/data/model/AudioItem.kt @@ -42,7 +42,7 @@ data class AudioItem( ?.id, title = item.title, albumTitle = item.data.album, - artistNames = item.data.albumArtist, + artistNames = item.data.artists?.joinToString(", "), runtime = item.data.runTimeTicks?.ticks, imageUrl = imageUrl, hasLyrics = item.data.hasLyrics == true, diff --git a/app/src/main/java/com/github/damontecres/wholphin/services/BackdropService.kt b/app/src/main/java/com/github/damontecres/wholphin/services/BackdropService.kt index 8025a6f6..66ef284c 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/services/BackdropService.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/services/BackdropService.kt @@ -77,7 +77,7 @@ class BackdropService itemId: String, imageUrl: String?, ) = withContext(WholphinDispatchers.IO) { - if (backdropFlow.firstOrNull()?.imageUrl != imageUrl) { + if (backdropFlow.firstOrNull()?.imageUrl != imageUrl || imageUrl == null) { _backdropFlow.update { it.copy( itemId = itemId, @@ -110,7 +110,7 @@ class BackdropService val dynamicEnabled = backdropStyle == BackdropStyle.BACKDROP_DYNAMIC_COLOR || backdropStyle == BackdropStyle.UNRECOGNIZED - val (primaryColor, secondaryColor, tertiaryColor) = + val colors = if (dynamicEnabled) { extractColorsFromBackdrop(imageUrl) } else { @@ -121,9 +121,9 @@ class BackdropService BackdropResult( itemId = itemId, imageUrl = imageUrl, - primaryColor = primaryColor, - secondaryColor = secondaryColor, - tertiaryColor = tertiaryColor, + primaryColor = colors?.primary ?: it.primaryColor, + secondaryColor = colors?.secondary ?: it.secondaryColor, + tertiaryColor = colors?.tertiary ?: it.tertiaryColor, ) } else { it @@ -131,10 +131,10 @@ class BackdropService } } - suspend fun extractColorsFromBackdrop(imageUrl: String?): ExtractedColors = + suspend fun extractColorsFromBackdrop(imageUrl: String?): ExtractedColors? = withContext(WholphinDispatchers.IO) { if (imageUrl.isNullOrBlank()) { - return@withContext ExtractedColors.DEFAULT + return@withContext null } extractedColorCache.get(imageUrl)?.let { return@withContext it diff --git a/app/src/main/java/com/github/damontecres/wholphin/services/UpdateChecker.kt b/app/src/main/java/com/github/damontecres/wholphin/services/UpdateChecker.kt index 8c2d84cb..a00de8e4 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/services/UpdateChecker.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/services/UpdateChecker.kt @@ -210,9 +210,7 @@ class UpdateChecker okHttpClient.newCall(request).execute().use { if (it.isSuccessful) { Timber.v("Request successful for ${release.downloadUrl}") - withContext(WholphinDispatchers.Main) { - callback.contentLength(it.body.contentLength()) - } + callback.contentLength(it.body.contentLength()) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { val contentValues = ContentValues().apply { @@ -397,9 +395,7 @@ suspend fun copyTo( while (bytes >= 0) { out.write(buffer, 0, bytes) bytesCopied += bytes - withContext(WholphinDispatchers.Main) { - callback.bytesDownloaded(bytesCopied) - } + callback.bytesDownloaded(bytesCopied) bytes = input.read(buffer) } return@withContext bytesCopied @@ -416,7 +412,12 @@ fun getDownloadUrl( buildList { add("$ASSET_NAME${releaseSuffix}$abiSuffix.apk") add("$ASSET_NAME$releaseSuffix.apk") - if (!debug) add("$ASSET_NAME.apk") + if (!debug) { + if (abiSuffix.isNotNullOrBlank()) { + add("$ASSET_NAME$abiSuffix.apk") + } + add("$ASSET_NAME.apk") + } } var preferredAsset: JsonObject? = null outer@ for (name in preferredNames) { diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/components/ContextMenu.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/components/ContextMenu.kt index 2f39f238..10a41af3 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/components/ContextMenu.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/components/ContextMenu.kt @@ -66,6 +66,7 @@ sealed interface ContextMenu { val canRemoveFromQueue: Boolean, val actions: MusicContextActions, val showRemoveFromPlaylist: Boolean = false, + val showGoTo: Boolean = false, ) : ContextMenu data class ForQueue( @@ -758,6 +759,18 @@ fun buildContextForMusic( buildList { val item = music.item val index = music.index + // Songs should not show Go to + if (music.showGoTo && item.type != BaseItemKind.AUDIO) { + add( + DialogItem( + resources.getString(R.string.go_to), + Icons.Default.ArrowForward, + dismissOnClick = true, + ) { + actions.navigateTo(item.destination()) + }, + ) + } add( DialogItem( resources.getString(R.string.play), diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/music/AlbumDetailsPage.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/music/AlbumDetailsPage.kt index f6a5d715..8f873bcd 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/music/AlbumDetailsPage.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/music/AlbumDetailsPage.kt @@ -609,6 +609,7 @@ fun AlbumDetailsPage( ), canRemoveFromQueue = false, actions = moreDialogActions, + showGoTo = true, ) }, cardContent = { index: Int, item: BaseItem?, mod: Modifier, onClick: () -> Unit, onLongClick: () -> Unit -> diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/music/ArtistDetailsPage.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/music/ArtistDetailsPage.kt index 12238441..20a39e0f 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/music/ArtistDetailsPage.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/music/ArtistDetailsPage.kt @@ -568,6 +568,7 @@ fun ArtistDetailsPage( ), canRemoveFromQueue = false, actions = moreDialogActions, + showGoTo = true, ) }, cardContent = { index: Int, album: BaseItem?, mod: Modifier, onClick: () -> Unit, onLongClick: () -> Unit -> @@ -606,6 +607,7 @@ fun ArtistDetailsPage( ), canRemoveFromQueue = false, actions = moreDialogActions, + showGoTo = true, ) }, cardContent = { index: Int, album: BaseItem?, mod: Modifier, onClick: () -> Unit, onLongClick: () -> Unit -> @@ -704,6 +706,7 @@ fun ArtistDetailsPage( ), canRemoveFromQueue = false, actions = moreDialogActions, + showGoTo = true, ) }, cardContent = { index: Int, item: BaseItem?, mod: Modifier, onClick: () -> Unit, onLongClick: () -> Unit -> diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/music/NowPlayingPage.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/music/NowPlayingPage.kt index e37c7ac1..5b22e6d2 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/music/NowPlayingPage.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/music/NowPlayingPage.kt @@ -48,6 +48,7 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel +import androidx.media3.common.Player import androidx.media3.common.util.UnstableApi import androidx.media3.ui.compose.state.rememberCurrentMediaItemState import androidx.tv.material3.Button @@ -127,6 +128,12 @@ fun NowPlayingPage( onPlaybackDialogTypeClick = { }, getDurationMs = { player.duration }, dpadSeekMode = preferences.playbackPreferences.dpadSeekMode, + onSeekToNext = { + if (player.isCommandAvailable(Player.COMMAND_SEEK_TO_NEXT)) player.seekToNext() + }, + onPSeekToPrevious = { + if (player.isCommandAvailable(Player.COMMAND_SEEK_TO_PREVIOUS)) player.seekToPrevious() + }, ) } diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/music/NowPlayingViewModel.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/music/NowPlayingViewModel.kt index 7e4b7025..af14ff70 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/music/NowPlayingViewModel.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/music/NowPlayingViewModel.kt @@ -17,6 +17,7 @@ import com.github.damontecres.wholphin.preferences.AppPreferences import com.github.damontecres.wholphin.preferences.updateMusicPreferences import com.github.damontecres.wholphin.services.BackdropResult import com.github.damontecres.wholphin.services.BackdropService +import com.github.damontecres.wholphin.services.ExtractedColors import com.github.damontecres.wholphin.services.ImageUrlService import com.github.damontecres.wholphin.services.MusicService import com.github.damontecres.wholphin.services.NavigationManager @@ -278,7 +279,7 @@ class NowPlayingViewModel val (primaryColor, secondaryColor, tertiaryColor) = backdropService.extractColorsFromBackdrop( imageUrl, - ) + ) ?: ExtractedColors.DEFAULT val backdropResult = BackdropResult( itemId = itemId.toString(), diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/series/SeriesViewModel.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/series/SeriesViewModel.kt index cb2146df..2b92f71b 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/series/SeriesViewModel.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/series/SeriesViewModel.kt @@ -124,10 +124,18 @@ class SeriesViewModel Timber.v("Start") addCloseable { themeSongPlayer.stop() } val series = - api.userLibraryApi - .getItem(seriesId) - .content - .let { BaseItem(it) } + try { + api.userLibraryApi + .getItem(seriesId) + .content + .let { BaseItem(it) } + } catch (ex: CancellationException) { + throw ex + } catch (ex: Exception) { + Timber.e(ex, "Error fetching series %s", seriesId) + _state.update { it.copy(series = DataLoadingState.Error(ex)) } + return@launchIO + } viewModelScope.launchDefault { mediaManagementService.collectCanDelete(flowOf(series)) { canDelete -> _state.update { it.copy(canDeleteSeries = canDelete) } diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackKeyHandler.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackKeyHandler.kt index 29bd30b2..1659d4a7 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackKeyHandler.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackKeyHandler.kt @@ -33,6 +33,8 @@ class PlaybackKeyHandler( private val isDpadSeekVisible: () -> Boolean = { false }, private val onDpadSeek: (Long) -> Unit = { }, private val dpadSeekMode: DpadSeekMode, + private val onSeekToNext: () -> Unit, + private val onPSeekToPrevious: () -> Unit, ) { private var leftHandledByRepeat = false private var rightHandledByRepeat = false @@ -89,11 +91,11 @@ class PlaybackKeyHandler( } Key.MediaNext -> { - if (player.isCommandAvailable(Player.COMMAND_SEEK_TO_NEXT)) player.seekToNext() + onSeekToNext.invoke() } Key.MediaPrevious -> { - if (player.isCommandAvailable(Player.COMMAND_SEEK_TO_PREVIOUS)) player.seekToPrevious() + onPSeekToPrevious.invoke() } Key.Captions -> { diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackPage.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackPage.kt index 6ed210a2..483083f2 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackPage.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackPage.kt @@ -269,6 +269,8 @@ fun PlaybackPageContent( }, onDpadSeek = onDpadSeek, dpadSeekMode = prefs.dpadSeekMode, + onSeekToNext = viewModel::playNextUp, + onPSeekToPrevious = viewModel::playPrevious, ) } diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/preferences/PreferencesContent.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/preferences/PreferencesContent.kt index c97117b7..d95d5aba 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/preferences/PreferencesContent.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/preferences/PreferencesContent.kt @@ -226,6 +226,8 @@ fun PreferencesContent( ) { if (showUpdate) { item { + val interactionSource = remember { MutableInteractionSource() } + val focused = interactionSource.collectIsFocusedAsState().value val updateFocusRequester = remember { FocusRequester() } LaunchedEffect(Unit) { if (focusedIndex.first == 0 && focusedIndex.second == 0) { @@ -240,11 +242,20 @@ fun PreferencesContent( viewModel.navigationManager.navigateTo(Destination.UpdateApp) }, summary = release?.version?.toString(), + interactionSource = interactionSource, modifier = Modifier .focusRequester(updateFocusRequester) .focusRequester(firstFocusRequester) - .playSoundOnFocus(movementSounds), + .playSoundOnFocus(movementSounds) + .lazyListWrapScrolling( + state = state, + focused = focused, + isFirst = true, + isLast = false, + firstFocusRequester = firstFocusRequester, + lastFocusRequester = lastFocusRequester, + ), ) } } diff --git a/app/src/test/java/com/github/damontecres/wholphin/test/TestUpdateChecker.kt b/app/src/test/java/com/github/damontecres/wholphin/test/TestUpdateChecker.kt index ca8ef324..4cae61ba 100644 --- a/app/src/test/java/com/github/damontecres/wholphin/test/TestUpdateChecker.kt +++ b/app/src/test/java/com/github/damontecres/wholphin/test/TestUpdateChecker.kt @@ -16,12 +16,19 @@ class TestUpdateChecker { lateinit var releaseJson: JsonObject val assetsJson: JsonArray by lazy { releaseJson["assets"]!!.jsonArray } - @Before - fun setup() { - val resource = javaClass.classLoader?.getResource("release_develop.json") + lateinit var releaseV108Json: JsonObject + val assetsV108Json: JsonArray by lazy { releaseV108Json["assets"]!!.jsonArray } + + private fun read(filename: String): JsonObject { + val resource = javaClass.classLoader?.getResource(filename) Assert.assertNotNull(resource) val fileContents = Paths.get(resource!!.toURI()).readText() - releaseJson = Json.parseToJsonElement(fileContents).jsonObject + return Json.parseToJsonElement(fileContents).jsonObject + } + + @Before + fun setup() { + releaseJson = read("release_develop.json") } @Test @@ -53,4 +60,30 @@ class TestUpdateChecker { val url = getDownloadUrl(assetsJson, true, listOf("arm64-v8a")) Assert.assertEquals("https://github.com/damontecres/Wholphin/releases/download/develop/Wholphin-debug-arm64-v8a.apk", url) } + + @Test + fun `Test regular release`() { + releaseV108Json = read("release_v108.json") + getDownloadUrl(assetsV108Json, false, listOf("arm64-v8a")).let { url -> + Assert.assertEquals( + "https://github.com/damontecres/Wholphin/releases/download/v1.0.8/Wholphin-arm64-v8a.apk", + url, + ) + } + getDownloadUrl(assetsV108Json, false, listOf("armeabi-v7a")).let { url -> + Assert.assertEquals( + "https://github.com/damontecres/Wholphin/releases/download/v1.0.8/Wholphin-armeabi-v7a.apk", + url, + ) + } + getDownloadUrl(assetsV108Json, false, emptyList()).let { url -> + Assert.assertEquals( + "https://github.com/damontecres/Wholphin/releases/download/v1.0.8/Wholphin.apk", + url, + ) + } + getDownloadUrl(assetsV108Json, true, listOf("arm64-v8a")).let { url -> + Assert.assertNull(url) + } + } } diff --git a/app/src/test/resources/release_v108.json b/app/src/test/resources/release_v108.json new file mode 100644 index 00000000..1a64aad8 --- /dev/null +++ b/app/src/test/resources/release_v108.json @@ -0,0 +1,344 @@ +{ + "url": "https://api.github.com/repos/damontecres/Wholphin/releases/388459926", + "assets_url": "https://api.github.com/repos/damontecres/Wholphin/releases/388459926/assets", + "upload_url": "https://uploads.github.com/repos/damontecres/Wholphin/releases/388459926/assets{?name,label}", + "html_url": "https://github.com/damontecres/Wholphin/releases/tag/v1.0.8", + "id": 388459926, + "author": { + "login": "github-actions[bot]", + "id": 41898282, + "node_id": "MDM6Qm90NDE4OTgyODI=", + "avatar_url": "https://avatars.githubusercontent.com/in/15368?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/github-actions%5Bbot%5D", + "html_url": "https://github.com/apps/github-actions", + "followers_url": "https://api.github.com/users/github-actions%5Bbot%5D/followers", + "following_url": "https://api.github.com/users/github-actions%5Bbot%5D/following{/other_user}", + "gists_url": "https://api.github.com/users/github-actions%5Bbot%5D/gists{/gist_id}", + "starred_url": "https://api.github.com/users/github-actions%5Bbot%5D/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/github-actions%5Bbot%5D/subscriptions", + "organizations_url": "https://api.github.com/users/github-actions%5Bbot%5D/orgs", + "repos_url": "https://api.github.com/users/github-actions%5Bbot%5D/repos", + "events_url": "https://api.github.com/users/github-actions%5Bbot%5D/events{/privacy}", + "received_events_url": "https://api.github.com/users/github-actions%5Bbot%5D/received_events", + "type": "Bot", + "user_view_type": "public", + "site_admin": false + }, + "node_id": "RE_kwDOPzwRps4XJ22W", + "tag_name": "v1.0.8", + "target_commitish": "main", + "name": "v1.0.8", + "draft": false, + "immutable": false, + "prerelease": false, + "created_at": "2026-09-14T14:04:10Z", + "updated_at": "2026-09-14T14:28:03Z", + "published_at": "2026-09-14T14:28:03Z", + "assets": [ + { + "url": "https://api.github.com/repos/damontecres/Wholphin/releases/assets/563552435", + "id": 563552435, + "node_id": "RA_kwDOPzwRps4hlyCz", + "name": "Wholphin-arm64-v8a.apk", + "label": "", + "uploader": { + "login": "github-actions[bot]", + "id": 41898282, + "node_id": "MDM6Qm90NDE4OTgyODI=", + "avatar_url": "https://avatars.githubusercontent.com/in/15368?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/github-actions%5Bbot%5D", + "html_url": "https://github.com/apps/github-actions", + "followers_url": "https://api.github.com/users/github-actions%5Bbot%5D/followers", + "following_url": "https://api.github.com/users/github-actions%5Bbot%5D/following{/other_user}", + "gists_url": "https://api.github.com/users/github-actions%5Bbot%5D/gists{/gist_id}", + "starred_url": "https://api.github.com/users/github-actions%5Bbot%5D/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/github-actions%5Bbot%5D/subscriptions", + "organizations_url": "https://api.github.com/users/github-actions%5Bbot%5D/orgs", + "repos_url": "https://api.github.com/users/github-actions%5Bbot%5D/repos", + "events_url": "https://api.github.com/users/github-actions%5Bbot%5D/events{/privacy}", + "received_events_url": "https://api.github.com/users/github-actions%5Bbot%5D/received_events", + "type": "Bot", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/vnd.android.package-archive", + "state": "uploaded", + "size": 46041302, + "digest": "sha256:77504857a15050beed9a8e589b70c29773b5e6a3c6ae76deec79c10702129755", + "download_count": 485, + "created_at": "2026-09-14T14:23:34Z", + "updated_at": "2026-09-14T14:23:39Z", + "browser_download_url": "https://github.com/damontecres/Wholphin/releases/download/v1.0.8/Wholphin-arm64-v8a.apk" + }, + { + "url": "https://api.github.com/repos/damontecres/Wholphin/releases/assets/563552436", + "id": 563552436, + "node_id": "RA_kwDOPzwRps4hlyC0", + "name": "Wholphin-armeabi-v7a.apk", + "label": "", + "uploader": { + "login": "github-actions[bot]", + "id": 41898282, + "node_id": "MDM6Qm90NDE4OTgyODI=", + "avatar_url": "https://avatars.githubusercontent.com/in/15368?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/github-actions%5Bbot%5D", + "html_url": "https://github.com/apps/github-actions", + "followers_url": "https://api.github.com/users/github-actions%5Bbot%5D/followers", + "following_url": "https://api.github.com/users/github-actions%5Bbot%5D/following{/other_user}", + "gists_url": "https://api.github.com/users/github-actions%5Bbot%5D/gists{/gist_id}", + "starred_url": "https://api.github.com/users/github-actions%5Bbot%5D/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/github-actions%5Bbot%5D/subscriptions", + "organizations_url": "https://api.github.com/users/github-actions%5Bbot%5D/orgs", + "repos_url": "https://api.github.com/users/github-actions%5Bbot%5D/repos", + "events_url": "https://api.github.com/users/github-actions%5Bbot%5D/events{/privacy}", + "received_events_url": "https://api.github.com/users/github-actions%5Bbot%5D/received_events", + "type": "Bot", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/vnd.android.package-archive", + "state": "uploaded", + "size": 41771730, + "digest": "sha256:7a7a031104f42a8314e3deed4febb670b515687ac500026f59a997dae772d950", + "download_count": 502, + "created_at": "2026-09-14T14:23:34Z", + "updated_at": "2026-09-14T14:23:39Z", + "browser_download_url": "https://github.com/damontecres/Wholphin/releases/download/v1.0.8/Wholphin-armeabi-v7a.apk" + }, + { + "url": "https://api.github.com/repos/damontecres/Wholphin/releases/assets/563552433", + "id": 563552433, + "node_id": "RA_kwDOPzwRps4hlyCx", + "name": "Wholphin-default-release-1.0.8-0-g7af7bc0a-59-arm64-v8a.apk", + "label": "", + "uploader": { + "login": "github-actions[bot]", + "id": 41898282, + "node_id": "MDM6Qm90NDE4OTgyODI=", + "avatar_url": "https://avatars.githubusercontent.com/in/15368?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/github-actions%5Bbot%5D", + "html_url": "https://github.com/apps/github-actions", + "followers_url": "https://api.github.com/users/github-actions%5Bbot%5D/followers", + "following_url": "https://api.github.com/users/github-actions%5Bbot%5D/following{/other_user}", + "gists_url": "https://api.github.com/users/github-actions%5Bbot%5D/gists{/gist_id}", + "starred_url": "https://api.github.com/users/github-actions%5Bbot%5D/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/github-actions%5Bbot%5D/subscriptions", + "organizations_url": "https://api.github.com/users/github-actions%5Bbot%5D/orgs", + "repos_url": "https://api.github.com/users/github-actions%5Bbot%5D/repos", + "events_url": "https://api.github.com/users/github-actions%5Bbot%5D/events{/privacy}", + "received_events_url": "https://api.github.com/users/github-actions%5Bbot%5D/received_events", + "type": "Bot", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/vnd.android.package-archive", + "state": "uploaded", + "size": 46041302, + "digest": "sha256:77504857a15050beed9a8e589b70c29773b5e6a3c6ae76deec79c10702129755", + "download_count": 170, + "created_at": "2026-09-14T14:23:34Z", + "updated_at": "2026-09-14T14:23:39Z", + "browser_download_url": "https://github.com/damontecres/Wholphin/releases/download/v1.0.8/Wholphin-default-release-1.0.8-0-g7af7bc0a-59-arm64-v8a.apk" + }, + { + "url": "https://api.github.com/repos/damontecres/Wholphin/releases/assets/563552428", + "id": 563552428, + "node_id": "RA_kwDOPzwRps4hlyCs", + "name": "Wholphin-default-release-1.0.8-0-g7af7bc0a-59-armeabi-v7a.apk", + "label": "", + "uploader": { + "login": "github-actions[bot]", + "id": 41898282, + "node_id": "MDM6Qm90NDE4OTgyODI=", + "avatar_url": "https://avatars.githubusercontent.com/in/15368?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/github-actions%5Bbot%5D", + "html_url": "https://github.com/apps/github-actions", + "followers_url": "https://api.github.com/users/github-actions%5Bbot%5D/followers", + "following_url": "https://api.github.com/users/github-actions%5Bbot%5D/following{/other_user}", + "gists_url": "https://api.github.com/users/github-actions%5Bbot%5D/gists{/gist_id}", + "starred_url": "https://api.github.com/users/github-actions%5Bbot%5D/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/github-actions%5Bbot%5D/subscriptions", + "organizations_url": "https://api.github.com/users/github-actions%5Bbot%5D/orgs", + "repos_url": "https://api.github.com/users/github-actions%5Bbot%5D/repos", + "events_url": "https://api.github.com/users/github-actions%5Bbot%5D/events{/privacy}", + "received_events_url": "https://api.github.com/users/github-actions%5Bbot%5D/received_events", + "type": "Bot", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/vnd.android.package-archive", + "state": "uploaded", + "size": 41771730, + "digest": "sha256:7a7a031104f42a8314e3deed4febb670b515687ac500026f59a997dae772d950", + "download_count": 143, + "created_at": "2026-09-14T14:23:34Z", + "updated_at": "2026-09-14T14:23:39Z", + "browser_download_url": "https://github.com/damontecres/Wholphin/releases/download/v1.0.8/Wholphin-default-release-1.0.8-0-g7af7bc0a-59-armeabi-v7a.apk" + }, + { + "url": "https://api.github.com/repos/damontecres/Wholphin/releases/assets/563552432", + "id": 563552432, + "node_id": "RA_kwDOPzwRps4hlyCw", + "name": "Wholphin-default-release-1.0.8-0-g7af7bc0a-59-x86_64.apk", + "label": "", + "uploader": { + "login": "github-actions[bot]", + "id": 41898282, + "node_id": "MDM6Qm90NDE4OTgyODI=", + "avatar_url": "https://avatars.githubusercontent.com/in/15368?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/github-actions%5Bbot%5D", + "html_url": "https://github.com/apps/github-actions", + "followers_url": "https://api.github.com/users/github-actions%5Bbot%5D/followers", + "following_url": "https://api.github.com/users/github-actions%5Bbot%5D/following{/other_user}", + "gists_url": "https://api.github.com/users/github-actions%5Bbot%5D/gists{/gist_id}", + "starred_url": "https://api.github.com/users/github-actions%5Bbot%5D/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/github-actions%5Bbot%5D/subscriptions", + "organizations_url": "https://api.github.com/users/github-actions%5Bbot%5D/orgs", + "repos_url": "https://api.github.com/users/github-actions%5Bbot%5D/repos", + "events_url": "https://api.github.com/users/github-actions%5Bbot%5D/events{/privacy}", + "received_events_url": "https://api.github.com/users/github-actions%5Bbot%5D/received_events", + "type": "Bot", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/vnd.android.package-archive", + "state": "uploaded", + "size": 53184555, + "digest": "sha256:74ba578c1059968c10c0884cc290d74a84793d9b78713beb0805baef7fb0a53f", + "download_count": 29, + "created_at": "2026-09-14T14:23:34Z", + "updated_at": "2026-09-14T14:23:42Z", + "browser_download_url": "https://github.com/damontecres/Wholphin/releases/download/v1.0.8/Wholphin-default-release-1.0.8-0-g7af7bc0a-59-x86_64.apk" + }, + { + "url": "https://api.github.com/repos/damontecres/Wholphin/releases/assets/563552634", + "id": 563552634, + "node_id": "RA_kwDOPzwRps4hlyF6", + "name": "Wholphin-default-release-1.0.8-0-g7af7bc0a-59.apk", + "label": "", + "uploader": { + "login": "github-actions[bot]", + "id": 41898282, + "node_id": "MDM6Qm90NDE4OTgyODI=", + "avatar_url": "https://avatars.githubusercontent.com/in/15368?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/github-actions%5Bbot%5D", + "html_url": "https://github.com/apps/github-actions", + "followers_url": "https://api.github.com/users/github-actions%5Bbot%5D/followers", + "following_url": "https://api.github.com/users/github-actions%5Bbot%5D/following{/other_user}", + "gists_url": "https://api.github.com/users/github-actions%5Bbot%5D/gists{/gist_id}", + "starred_url": "https://api.github.com/users/github-actions%5Bbot%5D/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/github-actions%5Bbot%5D/subscriptions", + "organizations_url": "https://api.github.com/users/github-actions%5Bbot%5D/orgs", + "repos_url": "https://api.github.com/users/github-actions%5Bbot%5D/repos", + "events_url": "https://api.github.com/users/github-actions%5Bbot%5D/events{/privacy}", + "received_events_url": "https://api.github.com/users/github-actions%5Bbot%5D/received_events", + "type": "Bot", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/vnd.android.package-archive", + "state": "uploaded", + "size": 124985861, + "digest": "sha256:9e569dcc4207a7817b777ffa1885cc42d22a85b5a96824a56b8ddc0f34cccd69", + "download_count": 78, + "created_at": "2026-09-14T14:23:39Z", + "updated_at": "2026-09-14T14:23:49Z", + "browser_download_url": "https://github.com/damontecres/Wholphin/releases/download/v1.0.8/Wholphin-default-release-1.0.8-0-g7af7bc0a-59.apk" + }, + { + "url": "https://api.github.com/repos/damontecres/Wholphin/releases/assets/563552644", + "id": 563552644, + "node_id": "RA_kwDOPzwRps4hlyGE", + "name": "Wholphin-x86_64.apk", + "label": "", + "uploader": { + "login": "github-actions[bot]", + "id": 41898282, + "node_id": "MDM6Qm90NDE4OTgyODI=", + "avatar_url": "https://avatars.githubusercontent.com/in/15368?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/github-actions%5Bbot%5D", + "html_url": "https://github.com/apps/github-actions", + "followers_url": "https://api.github.com/users/github-actions%5Bbot%5D/followers", + "following_url": "https://api.github.com/users/github-actions%5Bbot%5D/following{/other_user}", + "gists_url": "https://api.github.com/users/github-actions%5Bbot%5D/gists{/gist_id}", + "starred_url": "https://api.github.com/users/github-actions%5Bbot%5D/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/github-actions%5Bbot%5D/subscriptions", + "organizations_url": "https://api.github.com/users/github-actions%5Bbot%5D/orgs", + "repos_url": "https://api.github.com/users/github-actions%5Bbot%5D/repos", + "events_url": "https://api.github.com/users/github-actions%5Bbot%5D/events{/privacy}", + "received_events_url": "https://api.github.com/users/github-actions%5Bbot%5D/received_events", + "type": "Bot", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/vnd.android.package-archive", + "state": "uploaded", + "size": 53184555, + "digest": "sha256:74ba578c1059968c10c0884cc290d74a84793d9b78713beb0805baef7fb0a53f", + "download_count": 58, + "created_at": "2026-09-14T14:23:39Z", + "updated_at": "2026-09-14T14:23:44Z", + "browser_download_url": "https://github.com/damontecres/Wholphin/releases/download/v1.0.8/Wholphin-x86_64.apk" + }, + { + "url": "https://api.github.com/repos/damontecres/Wholphin/releases/assets/563552645", + "id": 563552645, + "node_id": "RA_kwDOPzwRps4hlyGF", + "name": "Wholphin.apk", + "label": "", + "uploader": { + "login": "github-actions[bot]", + "id": 41898282, + "node_id": "MDM6Qm90NDE4OTgyODI=", + "avatar_url": "https://avatars.githubusercontent.com/in/15368?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/github-actions%5Bbot%5D", + "html_url": "https://github.com/apps/github-actions", + "followers_url": "https://api.github.com/users/github-actions%5Bbot%5D/followers", + "following_url": "https://api.github.com/users/github-actions%5Bbot%5D/following{/other_user}", + "gists_url": "https://api.github.com/users/github-actions%5Bbot%5D/gists{/gist_id}", + "starred_url": "https://api.github.com/users/github-actions%5Bbot%5D/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/github-actions%5Bbot%5D/subscriptions", + "organizations_url": "https://api.github.com/users/github-actions%5Bbot%5D/orgs", + "repos_url": "https://api.github.com/users/github-actions%5Bbot%5D/repos", + "events_url": "https://api.github.com/users/github-actions%5Bbot%5D/events{/privacy}", + "received_events_url": "https://api.github.com/users/github-actions%5Bbot%5D/received_events", + "type": "Bot", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/vnd.android.package-archive", + "state": "uploaded", + "size": 124985861, + "digest": "sha256:9e569dcc4207a7817b777ffa1885cc42d22a85b5a96824a56b8ddc0f34cccd69", + "download_count": 3215, + "created_at": "2026-09-14T14:23:39Z", + "updated_at": "2026-09-14T14:23:47Z", + "browser_download_url": "https://github.com/damontecres/Wholphin/releases/download/v1.0.8/Wholphin.apk" + } + ], + "tarball_url": "https://api.github.com/repos/damontecres/Wholphin/tarball/v1.0.8", + "zipball_url": "https://api.github.com/repos/damontecres/Wholphin/zipball/v1.0.8", + "body": "\r\n\r\n## What's Changed\r\n\r\nThis release adds more media types to the favorites and search pages! There are also many bug fixes.\r\n\r\n### New Features & Enhancements\r\n* Add more searchable types & choose what to search in https://github.com/damontecres/Wholphin/pull/1857\r\n* Update favorites page with more types in https://github.com/damontecres/Wholphin/pull/1864\r\n* Add controls to edit playlists in https://github.com/damontecres/Wholphin/pull/1927\r\n### UI/UX Improvements\r\n* Add button to navigate to random item in https://github.com/damontecres/Wholphin/pull/1916\r\n* Add wrap around scrolling to settings pages in https://github.com/damontecres/Wholphin/pull/1937\r\n### Bug Fixes\r\n* Fix white flash on app start in https://github.com/damontecres/Wholphin/pull/1909\r\n* Fix image loading issues related to VPN and/or Fire OS 6 in https://github.com/damontecres/Wholphin/pull/1910\r\n* Fixes to default home view options for music & videos in https://github.com/damontecres/Wholphin/pull/1926\r\n* Fixes to Now Playing page in https://github.com/damontecres/Wholphin/pull/1915\r\n* Fixes to season/episode search with duplicates in https://github.com/damontecres/Wholphin/pull/1946\r\n* Configure playback controls for RTL in https://github.com/damontecres/Wholphin/pull/1945\r\n* Fix person credits: movie release dates, full filmography, sorted order by @SergeiAK in https://github.com/damontecres/Wholphin/pull/1950\r\n* Fixes to `v1.0.7` in https://github.com/damontecres/Wholphin/pull/1953\r\n* Fix OS screensaver starting during playback with dim enabled in https://github.com/damontecres/Wholphin/pull/1956\r\n* Fix favorites not querying for people & fix restoring focus on search page for discover items in https://github.com/damontecres/Wholphin/pull/1961\r\n### Other changes\r\n* Update API level to Android 17 in https://github.com/damontecres/Wholphin/pull/1908\r\n* Localized formatting for season and episode display by @tal-sarid in https://github.com/damontecres/Wholphin/pull/1884\r\n* Consolidate sending media reports & app logs in https://github.com/damontecres/Wholphin/pull/1936\r\n* Update dependencies in https://github.com/damontecres/Wholphin/pull/1952\r\n* Increase memory for CI builds in https://github.com/damontecres/Wholphin/pull/1954\r\n* Translations 2026-09-12 in https://github.com/damontecres/Wholphin/pull/1957\r\n\r\n## New Contributors\r\n* @SergeiAK made their first contribution in https://github.com/damontecres/Wholphin/pull/1950\r\n\r\n**Full Changelog**: https://github.com/damontecres/Wholphin/compare/v1.0.7...v1.0.8", + "reactions": { + "url": "https://api.github.com/repos/damontecres/Wholphin/releases/388459926/reactions", + "total_count": 34, + "+1": 10, + "-1": 0, + "laugh": 0, + "hooray": 6, + "confused": 0, + "heart": 10, + "rocket": 8, + "eyes": 0 + }, + "mentions_count": 2 +}