mirror of
https://github.com/JustinZeus/Wholphin.git
synced 2026-11-05 18:30:59 +01:00
Fix music artist listing & show music in collections (#1739)
## Description Switches to use the Artists API instead of Items API when fetching the list of artists in a library. Enables fetching artists, albums, and music videos in a collection. Also adds titles for the remaining `BaseItemKind` types for future proofing even if they aren't used anywhere in the app. ### Related issues Fixes #1733 Fixes #1734 Fixes #1735 ### Testing Emulator, created a new collection with the above. Also verified the artist query against the web UI ## Screenshots N/A ## AI or LLM usage None
This commit is contained in:
parent
00490b14ec
commit
5bc874a9ff
9 changed files with 134 additions and 35 deletions
|
|
@ -9,6 +9,7 @@ import kotlinx.serialization.Serializable
|
|||
import kotlinx.serialization.UseSerializers
|
||||
import org.jellyfin.sdk.model.api.BaseItemKind
|
||||
import org.jellyfin.sdk.model.api.VideoType
|
||||
import org.jellyfin.sdk.model.api.request.GetArtistsRequest
|
||||
import org.jellyfin.sdk.model.api.request.GetItemsRequest
|
||||
import org.jellyfin.sdk.model.api.request.GetPersonsRequest
|
||||
import org.jellyfin.sdk.model.serializer.UUIDSerializer
|
||||
|
|
@ -138,6 +139,22 @@ data class GetItemsFilter(
|
|||
isFavorite = favorite,
|
||||
)
|
||||
|
||||
fun applyTo(req: GetArtistsRequest) =
|
||||
req.copy(
|
||||
minCommunityRating = minCommunityRating,
|
||||
isFavorite = favorite,
|
||||
genreIds = genres,
|
||||
personIds = persons,
|
||||
studioIds = studios,
|
||||
tags = tags,
|
||||
officialRatings = officialRatings,
|
||||
years =
|
||||
buildSet {
|
||||
years?.letNotEmpty(::addAll)
|
||||
decades?.forEach { addAll(it..<(it + 10)) }
|
||||
},
|
||||
)
|
||||
|
||||
/**
|
||||
* Merge another [GetItemsFilter] onto this one, replacing only unset values
|
||||
*/
|
||||
|
|
@ -162,4 +179,5 @@ data class GetItemsFilter(
|
|||
enum class GetItemsFilterOverride {
|
||||
NONE,
|
||||
PERSON,
|
||||
ARTIST,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -230,36 +230,36 @@ fun formatTypeName(type: BaseItemKind): Int =
|
|||
BaseItemKind.PLAYLIST -> R.string.playlists
|
||||
BaseItemKind.PERSON -> R.string.people_title
|
||||
BaseItemKind.BOX_SET -> R.string.collections
|
||||
BaseItemKind.AUDIO -> TODO()
|
||||
BaseItemKind.AUDIO -> R.string.songs
|
||||
BaseItemKind.CHANNEL -> R.string.channels
|
||||
BaseItemKind.GENRE -> R.string.genres
|
||||
BaseItemKind.LIVE_TV_CHANNEL -> R.string.channels
|
||||
BaseItemKind.MUSIC_ALBUM -> TODO()
|
||||
BaseItemKind.MUSIC_ARTIST -> TODO()
|
||||
BaseItemKind.MUSIC_GENRE -> TODO()
|
||||
BaseItemKind.MUSIC_VIDEO -> TODO()
|
||||
BaseItemKind.MUSIC_ALBUM -> R.string.albums
|
||||
BaseItemKind.MUSIC_ARTIST -> R.string.artists
|
||||
BaseItemKind.MUSIC_GENRE -> R.string.genres
|
||||
BaseItemKind.MUSIC_VIDEO -> R.string.music_videos
|
||||
BaseItemKind.PHOTO -> R.string.photos
|
||||
BaseItemKind.PHOTO_ALBUM -> TODO()
|
||||
BaseItemKind.PROGRAM -> TODO()
|
||||
BaseItemKind.RECORDING -> TODO()
|
||||
BaseItemKind.PHOTO_ALBUM -> R.string.photos
|
||||
BaseItemKind.PROGRAM -> R.string.programs
|
||||
BaseItemKind.RECORDING -> R.string.recordings
|
||||
BaseItemKind.SEASON -> R.string.tv_seasons
|
||||
BaseItemKind.STUDIO -> R.string.studios
|
||||
BaseItemKind.TRAILER -> R.string.trailers_title
|
||||
BaseItemKind.TV_CHANNEL -> R.string.channels
|
||||
BaseItemKind.TV_PROGRAM -> TODO()
|
||||
BaseItemKind.USER_ROOT_FOLDER -> TODO()
|
||||
BaseItemKind.USER_VIEW -> TODO()
|
||||
BaseItemKind.YEAR -> TODO()
|
||||
BaseItemKind.AGGREGATE_FOLDER -> TODO()
|
||||
BaseItemKind.AUDIO_BOOK -> TODO()
|
||||
BaseItemKind.BASE_PLUGIN_FOLDER -> TODO()
|
||||
BaseItemKind.BOOK -> TODO()
|
||||
BaseItemKind.CHANNEL_FOLDER_ITEM -> TODO()
|
||||
BaseItemKind.COLLECTION_FOLDER -> TODO()
|
||||
BaseItemKind.FOLDER -> TODO()
|
||||
BaseItemKind.MANUAL_PLAYLISTS_FOLDER -> TODO()
|
||||
BaseItemKind.LIVE_TV_PROGRAM -> TODO()
|
||||
BaseItemKind.PLAYLISTS_FOLDER -> TODO()
|
||||
BaseItemKind.TV_PROGRAM -> R.string.programs
|
||||
BaseItemKind.USER_ROOT_FOLDER -> R.string.folders_title
|
||||
BaseItemKind.USER_VIEW -> R.string.user_views
|
||||
BaseItemKind.YEAR -> R.string.year
|
||||
BaseItemKind.AGGREGATE_FOLDER -> R.string.folders_title
|
||||
BaseItemKind.AUDIO_BOOK -> R.string.audio_books
|
||||
BaseItemKind.BASE_PLUGIN_FOLDER -> R.string.folders_title
|
||||
BaseItemKind.BOOK -> R.string.books
|
||||
BaseItemKind.CHANNEL_FOLDER_ITEM -> R.string.folders_title
|
||||
BaseItemKind.COLLECTION_FOLDER -> R.string.library
|
||||
BaseItemKind.FOLDER -> R.string.folders_title
|
||||
BaseItemKind.MANUAL_PLAYLISTS_FOLDER -> R.string.playlists
|
||||
BaseItemKind.LIVE_TV_PROGRAM -> R.string.programs
|
||||
BaseItemKind.PLAYLISTS_FOLDER -> R.string.playlists
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ import com.github.damontecres.wholphin.ui.tryRequestFocus
|
|||
import com.github.damontecres.wholphin.util.ApiRequestPager
|
||||
import com.github.damontecres.wholphin.util.DataLoadingState
|
||||
import com.github.damontecres.wholphin.util.ExceptionHandler
|
||||
import com.github.damontecres.wholphin.util.GetArtistsHandler
|
||||
import com.github.damontecres.wholphin.util.GetItemsRequestHandler
|
||||
import com.github.damontecres.wholphin.util.GetPersonsHandler
|
||||
import com.github.damontecres.wholphin.util.LoadingState
|
||||
|
|
@ -92,6 +93,7 @@ import org.jellyfin.sdk.model.api.CollectionType
|
|||
import org.jellyfin.sdk.model.api.ImageType
|
||||
import org.jellyfin.sdk.model.api.ItemSortBy
|
||||
import org.jellyfin.sdk.model.api.SortOrder
|
||||
import org.jellyfin.sdk.model.api.request.GetArtistsRequest
|
||||
import org.jellyfin.sdk.model.api.request.GetItemsRequest
|
||||
import org.jellyfin.sdk.model.api.request.GetPersonsRequest
|
||||
import org.jellyfin.sdk.model.serializer.toUUID
|
||||
|
|
@ -373,6 +375,26 @@ class CollectionFolderViewModel
|
|||
)
|
||||
newPager
|
||||
}
|
||||
|
||||
GetItemsFilterOverride.ARTIST -> {
|
||||
val item = state.value.item.successValue
|
||||
val request =
|
||||
filter.applyTo(
|
||||
GetArtistsRequest(
|
||||
parentId = item?.id,
|
||||
enableImageTypes = listOf(ImageType.PRIMARY, ImageType.THUMB),
|
||||
),
|
||||
)
|
||||
val newPager =
|
||||
ApiRequestPager(
|
||||
api,
|
||||
request,
|
||||
GetArtistsHandler,
|
||||
viewModelScope,
|
||||
useSeriesForPrimary = useSeriesForPrimary,
|
||||
)
|
||||
newPager
|
||||
}
|
||||
}
|
||||
|
||||
private fun createGetItemsRequest(
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import com.github.damontecres.wholphin.data.ServerRepository
|
|||
import com.github.damontecres.wholphin.data.model.BaseItem
|
||||
import com.github.damontecres.wholphin.data.model.CollectionFolderFilter
|
||||
import com.github.damontecres.wholphin.data.model.GetItemsFilter
|
||||
import com.github.damontecres.wholphin.data.model.GetItemsFilterOverride
|
||||
import com.github.damontecres.wholphin.preferences.UserPreferences
|
||||
import com.github.damontecres.wholphin.services.BackdropService
|
||||
import com.github.damontecres.wholphin.services.MusicService
|
||||
|
|
@ -203,7 +204,7 @@ fun CollectionFolderMusic(
|
|||
CollectionFolderFilter(
|
||||
filter =
|
||||
GetItemsFilter(
|
||||
includeItemTypes = listOf(BaseItemKind.MUSIC_ARTIST),
|
||||
override = GetItemsFilterOverride.ARTIST,
|
||||
),
|
||||
),
|
||||
showTitle = false,
|
||||
|
|
|
|||
|
|
@ -425,7 +425,7 @@ fun CollectionDetailsContent(
|
|||
onClickPlay = onClickPlay,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
onFocusPosition = { position ->
|
||||
Timber.v("onFocusPosition=%s", position)
|
||||
// Timber.v("onFocusPosition=%s", position)
|
||||
focusedItem =
|
||||
position.let {
|
||||
val key =
|
||||
|
|
|
|||
|
|
@ -51,18 +51,45 @@ fun CollectionRows(
|
|||
if (row is HomeRowLoadingState.Success) {
|
||||
// TODO not great to do this in the UI
|
||||
val viewOptions =
|
||||
if (type == BaseItemKind.EPISODE) {
|
||||
HomeRowViewOptions(
|
||||
heightDp = Cards.HEIGHT_EPISODE,
|
||||
episodeAspectRatio = AspectRatio.WIDE,
|
||||
showTitles = cardViewOptions.showTitles,
|
||||
useSeries = false,
|
||||
)
|
||||
} else {
|
||||
HomeRowViewOptions(
|
||||
showTitles = cardViewOptions.showTitles,
|
||||
)
|
||||
when (type) {
|
||||
BaseItemKind.EPISODE -> {
|
||||
HomeRowViewOptions(
|
||||
heightDp = Cards.HEIGHT_EPISODE,
|
||||
episodeAspectRatio = AspectRatio.WIDE,
|
||||
showTitles = cardViewOptions.showTitles,
|
||||
useSeries = false,
|
||||
)
|
||||
}
|
||||
|
||||
BaseItemKind.MUSIC_ARTIST,
|
||||
BaseItemKind.MUSIC_ALBUM,
|
||||
BaseItemKind.PLAYLIST,
|
||||
BaseItemKind.AUDIO,
|
||||
-> {
|
||||
HomeRowViewOptions(
|
||||
heightDp = Cards.HEIGHT_EPISODE,
|
||||
aspectRatio = AspectRatio.SQUARE,
|
||||
showTitles = cardViewOptions.showTitles,
|
||||
)
|
||||
}
|
||||
|
||||
BaseItemKind.VIDEO,
|
||||
BaseItemKind.MUSIC_VIDEO,
|
||||
-> {
|
||||
HomeRowViewOptions(
|
||||
heightDp = Cards.HEIGHT_EPISODE,
|
||||
aspectRatio = AspectRatio.WIDE,
|
||||
showTitles = cardViewOptions.showTitles,
|
||||
)
|
||||
}
|
||||
|
||||
else -> {
|
||||
HomeRowViewOptions(
|
||||
showTitles = cardViewOptions.showTitles,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
row.copy(viewOptions = viewOptions)
|
||||
} else {
|
||||
row
|
||||
|
|
|
|||
|
|
@ -489,6 +489,9 @@ class CollectionViewModel
|
|||
BaseItemKind.EPISODE,
|
||||
BaseItemKind.VIDEO,
|
||||
BaseItemKind.BOX_SET,
|
||||
BaseItemKind.MUSIC_ARTIST,
|
||||
BaseItemKind.MUSIC_ALBUM,
|
||||
BaseItemKind.MUSIC_VIDEO,
|
||||
)
|
||||
|
||||
const val VIEW_OPTIONS_KEY = "CollectionViewOptions"
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import kotlinx.serialization.modules.polymorphic
|
|||
import kotlinx.serialization.modules.subclass
|
||||
import org.jellyfin.sdk.api.client.ApiClient
|
||||
import org.jellyfin.sdk.api.client.Response
|
||||
import org.jellyfin.sdk.api.client.extensions.artistsApi
|
||||
import org.jellyfin.sdk.api.client.extensions.genresApi
|
||||
import org.jellyfin.sdk.api.client.extensions.itemsApi
|
||||
import org.jellyfin.sdk.api.client.extensions.liveTvApi
|
||||
|
|
@ -21,6 +22,7 @@ import org.jellyfin.sdk.api.client.extensions.tvShowsApi
|
|||
import org.jellyfin.sdk.api.client.extensions.userLibraryApi
|
||||
import org.jellyfin.sdk.model.api.BaseItemDtoQueryResult
|
||||
import org.jellyfin.sdk.model.api.GetProgramsDto
|
||||
import org.jellyfin.sdk.model.api.request.GetArtistsRequest
|
||||
import org.jellyfin.sdk.model.api.request.GetEpisodesRequest
|
||||
import org.jellyfin.sdk.model.api.request.GetGenresRequest
|
||||
import org.jellyfin.sdk.model.api.request.GetItemsRequest
|
||||
|
|
@ -367,6 +369,25 @@ object GetLiveTvChannelsRequestHandler : RequestHandler<GetLiveTvChannelsRequest
|
|||
): Response<BaseItemDtoQueryResult> = api.liveTvApi.getLiveTvChannels(request)
|
||||
}
|
||||
|
||||
@Serializable
|
||||
object GetArtistsHandler : RequestHandler<GetArtistsRequest> {
|
||||
override fun prepare(
|
||||
request: GetArtistsRequest,
|
||||
startIndex: Int,
|
||||
limit: Int,
|
||||
enableTotalRecordCount: Boolean,
|
||||
): GetArtistsRequest =
|
||||
request.copy(
|
||||
startIndex = startIndex,
|
||||
limit = limit,
|
||||
)
|
||||
|
||||
override suspend fun execute(
|
||||
api: ApiClient,
|
||||
request: GetArtistsRequest,
|
||||
): Response<BaseItemDtoQueryResult> = api.artistsApi.getArtists((request))
|
||||
}
|
||||
|
||||
val requestSerializersModule =
|
||||
SerializersModule {
|
||||
polymorphic(Any::class) {
|
||||
|
|
@ -382,5 +403,6 @@ val requestSerializersModule =
|
|||
subclass(GetStudiosRequest::class)
|
||||
subclass(GetRecordingsRequest::class)
|
||||
subclass(GetLiveTvChannelsRequest::class)
|
||||
subclass(GetArtistsHandler::class)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -874,4 +874,10 @@
|
|||
<string name="any_language">Any language</string>
|
||||
<string name="hash_matches">Hash matches</string>
|
||||
<string name="subtitles_hearing_impaired">SDH</string>
|
||||
<string name="programs">TV programs</string>
|
||||
<string name="recordings">Recordings</string>
|
||||
<string name="folders_title">Folders</string>
|
||||
<string name="user_views">User views</string>
|
||||
<string name="books">Books</string>
|
||||
<string name="audio_books">Audio books</string>
|
||||
</resources>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue