Add support for music (#1059)

## Description
Adds support for music playback

### Features
- Adds a "Now Playing" page which is accessible from the nav drawer
while music is playing
- Manage the playback queue, add/remove/re-order songs
- Supports synced & non-synced lyrics
- Scroll through lyrics
- Click on line for synced lyrics to seek to that position

### User interface
- Customize what's shown on the "Now Playing" page
- Show album cover art, backdrops, and lyrics
- Show a basic bar visualizer
- Search for albums, artists, & songs
- Links between albums, artists, playlists, & music videos when metadata
is available
- Throughout the app, see which song is playing and which ones are in
the queue

Note: lyrics are synced by line. `10.11` added support for syncing by
word, but Wholphin still supports `10.10`

### Related issues
Closes #2 
Closes #267 

### Testing
Emulator & shield testing

## Screenshots
<details><summary>Click to see screenshots</summary>
<p>

### Album grid
![music_album_grid
Large](https://github.com/user-attachments/assets/4573ad32-0cd7-49db-94db-de37ceb6f641)

### Artist page
![music_artist
Large](https://github.com/user-attachments/assets/fdf3b7b9-5c40-434d-867d-7d56e0b3430e)

### Album details
![music_album_details
Large](https://github.com/user-attachments/assets/494d1a76-9581-4a07-a8ee-5c0957f542e0)

### Album is playing/queued
![music_album_queued
Large](https://github.com/user-attachments/assets/55c72cd2-10a9-411d-8bae-b232150db506)

### Now playing page
![now_playing
Large](https://github.com/user-attachments/assets/b773b1bc-71fd-4789-8509-cebfc0d0ffe5)

### Now playing queue
![now_playing_queue
Large](https://github.com/user-attachments/assets/db244462-e33d-452a-93dc-dd2123a4862d)

</p>
</details> 

## AI or LLM usage
None

## Try it out

See instructions at
https://github.com/damontecres/Wholphin/releases/tag/develop-music
This commit is contained in:
Ray 2026-03-24 13:42:18 -04:00 committed by GitHub
parent 8a37d63d09
commit f2570d4ab0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
46 changed files with 6342 additions and 436 deletions

View file

@ -0,0 +1,43 @@
package com.github.damontecres.wholphin.data.model
import androidx.compose.runtime.Stable
import org.jellyfin.sdk.model.extensions.ticks
import java.util.UUID
import kotlin.time.Duration
@Stable
data class AudioItem(
val key: Long = keyTracker++,
val id: UUID,
val albumId: UUID?,
val artistId: UUID?,
val title: String?,
val albumTitle: String?,
val artistNames: String?,
val runtime: Duration?,
val imageUrl: String?,
val hasLyrics: Boolean,
) {
companion object {
private var keyTracker = 0L
fun from(
item: BaseItem,
imageUrl: String?,
): AudioItem =
AudioItem(
id = item.id,
albumId = item.data.albumId,
artistId =
item.data.artistItems
?.firstOrNull()
?.id,
title = item.title,
albumTitle = item.data.album,
artistNames = item.data.albumArtist,
runtime = item.data.runTimeTicks?.ticks,
imageUrl = imageUrl,
hasLyrics = item.data.hasLyrics == true,
)
}
}

View file

@ -8,6 +8,7 @@ import androidx.compose.ui.text.buildAnnotatedString
import com.github.damontecres.wholphin.ui.DateFormatter
import com.github.damontecres.wholphin.ui.abbreviateNumber
import com.github.damontecres.wholphin.ui.detail.CardGridItem
import com.github.damontecres.wholphin.ui.detail.music.artistsString
import com.github.damontecres.wholphin.ui.detail.series.SeasonEpisodeIds
import com.github.damontecres.wholphin.ui.dot
import com.github.damontecres.wholphin.ui.formatDateTime
@ -32,7 +33,7 @@ import kotlin.time.Duration
@Stable
data class BaseItem(
val data: BaseItemDto,
val useSeriesForPrimary: Boolean,
val useSeriesForPrimary: Boolean = false,
val imageUrlOverride: String? = null,
val destinationOverride: Destination? = null,
) : CardGridItem {
@ -57,6 +58,7 @@ data class BaseItem(
when (type) {
BaseItemKind.EPISODE -> data.seasonEpisode + " - " + name
BaseItemKind.SERIES -> data.seriesProductionYears
BaseItemKind.AUDIO -> listOfNotNull(data.album, artistsString).joinToString(" - ")
else -> data.productionYear?.toString()
}