Skip to content

Commit

Permalink
Implement generic 'view more' page (closes #52)
Browse files Browse the repository at this point in the history
Kind of fix long press menu positioning (again)
  • Loading branch information
toasterofbread committed Jun 11, 2023
1 parent dbbc3fd commit 13104c9
Show file tree
Hide file tree
Showing 19 changed files with 272 additions and 155 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ actual class PlatformContext(private val context: Context) {

@Composable
actual fun getScreenHeight(): Dp {
return LocalConfiguration.current.screenHeightDp.dp + getStatusBarHeight()
return LocalConfiguration.current.screenHeightDp.dp// + getStatusBarHeight()
}

@Composable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ actual fun PlatformDialog(
) {
Dialog(
onDismissRequest,
DialogProperties(usePlatformDefaultWidth = use_platform_default_width)
DialogProperties(usePlatformDefaultWidth = use_platform_default_width, decorFitsSystemWindows = false)
) {
if (!dim_behind) {
val dialog = LocalView.current.parent as DialogWindowProvider
Expand Down
11 changes: 11 additions & 0 deletions shared/src/commonMain/kotlin/SpMp.kt
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,17 @@ object SpMp {
low_memory_listeners.forEach { it.invoke() }
}

fun reportActionError(exception: Throwable?) {
// TODO add option to disable
context.sendToast(exception.toString())
}

@Composable
fun ErrorDisplay(exception: Throwable?, modifier: Modifier = Modifier) {
// TODO
Text(exception.toString())
}

private fun getFontFamily(context: PlatformContext): FontFamily {
val locale = ui_language
val font_dirs = context.listResourceFiles("")!!.filter { it.length > 4 && it.startsWith("font") }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.spectre7.spmp.api

import com.spectre7.spmp.api.Api.Companion.addYtHeaders
import com.spectre7.spmp.api.Api.Companion.getStream
import com.spectre7.spmp.api.Api.Companion.ytUrl
import com.spectre7.spmp.model.mediaitem.MediaItem
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import okhttp3.Request

suspend fun getGenericFeedViewMorePage(browse_id: String): Result<List<MediaItem>> = withContext(Dispatchers.IO) {

val hl = SpMp.data_language
val request = Request.Builder()
.ytUrl("/youtubei/v1/browse")
.addYtHeaders()
.post(Api.getYoutubeiRequestBody(
mapOf("browseId" to browse_id)
))
.build()

val result = Api.request(request)
val stream = result.getOrNull()?.getStream() ?: return@withContext result.cast()

val parsed: YoutubeiBrowseResponse = Api.klaxon.parse(stream)!!
stream.close()

val items = parsed
.contents!!
.singleColumnBrowseResultsRenderer
.tabs
.first()
.tabRenderer
.content!!
.sectionListRenderer
.contents!!
.first()
.getMediaItems(hl)

return@withContext Result.success(items)
}
79 changes: 21 additions & 58 deletions shared/src/commonMain/kotlin/com/spectre7/spmp/api/HomeFeed.kt
Original file line number Diff line number Diff line change
Expand Up @@ -164,66 +164,29 @@ private fun processRows(rows: List<YoutubeiShelf>, hl: String): List<MediaItemLa
continue
}

when (browse_endpoint.browseId) {
"FEmusic_listen_again" -> {
if (Settings.get(Settings.KEY_FEED_SHOW_LISTEN_ROW)) {
add(
LocalisedYoutubeString.app("home_feed_listen_again"),
null,
thumbnail_source = null,
view_more = MediaItemLayout.ViewMore(list_page_url = "https://music.youtube.com/listen_again")
)
}
continue
}
"FEmusic_mixed_for_you" -> {
if (Settings.get(Settings.KEY_FEED_SHOW_MIX_ROW)) {
add(
LocalisedYoutubeString.app("home_feed_mixed_for_you"),
null,
view_more = MediaItemLayout.ViewMore(list_page_url = "https://music.youtube.com/mixed_for_you")
)
}
continue
}
"FEmusic_new_releases_albums" -> {
if (Settings.get(Settings.KEY_FEED_SHOW_NEW_ROW)) {
add(
LocalisedYoutubeString.app("home_feed_new_releases"),
null,
view_more = MediaItemLayout.ViewMore(list_page_url = "https://music.youtube.com/new_releases/albums")
)
}
continue
}
"FEmusic_moods_and_genres" -> {
if (Settings.get(Settings.KEY_FEED_SHOW_MOODS_ROW)) {
add(
LocalisedYoutubeString.app("home_feed_moods_and_genres"),
null,
view_more = MediaItemLayout.ViewMore(list_page_url = "https://music.youtube.com/moods_and_genres")
)
}
continue
}
"FEmusic_charts" -> {
if (Settings.get(Settings.KEY_FEED_SHOW_CHARTS_ROW)) {
add(
LocalisedYoutubeString.app("home_feed_charts"),
null,
view_more = MediaItemLayout.ViewMore(list_page_url = "https://music.youtube.com/charts")
)
}
continue
}
val view_more_page_title_key = when (browse_endpoint.browseId) {
"FEmusic_listen_again" -> if (Settings.KEY_FEED_SHOW_LISTEN_ROW.get()) "home_feed_listen_again" else null
"FEmusic_mixed_for_you" -> if (Settings.KEY_FEED_SHOW_MIX_ROW.get()) "home_feed_mixed_for_you" else null
"FEmusic_new_releases_albums" -> if (Settings.KEY_FEED_SHOW_NEW_ROW.get()) "home_feed_new_releases" else null
"FEmusic_moods_and_genres" -> if (Settings.KEY_FEED_SHOW_MOODS_ROW.get()) "home_feed_moods_and_genres" else null
"FEmusic_charts" -> if (Settings.KEY_FEED_SHOW_CHARTS_ROW.get()) "home_feed_charts" else null
else -> null
}

if (view_more_page_title_key != null) {
add(
LocalisedYoutubeString.app(view_more_page_title_key),
null,
view_more = MediaItemLayout.ViewMore(list_page_browse_id = browse_endpoint.browseId)
)
continue
}

val page_type = browse_endpoint.browseEndpointContextSupportedConfigs?.browseEndpointContextMusicConfig?.pageType
val media_item: MediaItem

when (page_type) {
"MUSIC_PAGE_TYPE_ARTIST", "MUSIC_PAGE_TYPE_USER_CHANNEL" -> media_item = Artist.fromId(browse_endpoint.browseId)
"MUSIC_PAGE_TYPE_PLAYLIST" -> media_item = AccountPlaylist.fromId(browse_endpoint.browseId).editPlaylistData { supplyTitle(header.title.first_text) }
val media_item: MediaItem = when (page_type) {
"MUSIC_PAGE_TYPE_ARTIST", "MUSIC_PAGE_TYPE_USER_CHANNEL" -> Artist.fromId(browse_endpoint.browseId)
"MUSIC_PAGE_TYPE_PLAYLIST" -> AccountPlaylist.fromId(browse_endpoint.browseId).editPlaylistData { supplyTitle(header.title.first_text) }
else -> throw NotImplementedError(browse_endpoint.toString())
}

Expand Down Expand Up @@ -507,7 +470,7 @@ data class MusicTwoRowItemRenderer(
val menu: YoutubeiNextResponse.Menu? = null
) {
fun getArtist(host_item: MediaItem): Artist? {
for (run in subtitle!!.runs!!) {
for (run in subtitle?.runs ?: emptyList()) {
val browse_endpoint = run.navigationEndpoint?.browseEndpoint

val endpoint_type = browse_endpoint?.getMediaItemType()
Expand All @@ -518,7 +481,7 @@ data class MusicTwoRowItemRenderer(

if (host_item is Song) {
val index = if (host_item.song_type == SongType.VIDEO) 0 else 1
subtitle.runs?.getOrNull(index)?.also {
subtitle?.runs?.getOrNull(index)?.also {
return Artist.createForItem(host_item).editArtistData { supplyTitle(it.text) }
}
}
Expand Down
35 changes: 18 additions & 17 deletions shared/src/commonMain/kotlin/com/spectre7/spmp/api/Lyrics.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,29 +16,30 @@ import org.xmlpull.v1.XmlPullParserFactory
import java.nio.channels.ClosedByInterruptException
import java.util.*

suspend fun getSongLyrics(song: Song, data: Pair<Int, SongLyrics.Source>?): SongLyrics? {
suspend fun getSongLyrics(song: Song, data: Pair<Int, SongLyrics.Source>?): Result<SongLyrics> {
if (song.title == null) {
return null
return Result.failure(RuntimeException("Song has no title"))
}

val ret: SongLyrics =
if (data != null)
getLyrics(data.first, data.second).getOrReport("getSongLyrics")
?: return null
val result: Result<SongLyrics> =
if (data != null) getLyrics(data.first, data.second)
else {
val results = searchForLyrics(song.title!!, song.artist?.title).getOrReport("getSongLyrics")
?: return null
if (results.isEmpty()) {
return null
}

val lyrics = results.first()
getLyrics(lyrics.id, lyrics.source).getOrReport("getSongLyrics")
?: return null
searchForLyrics(song.title!!, song.artist?.title).fold(
{ results ->
if (results.isEmpty()) Result.failure(RuntimeException("No lyrics found"))
else getLyrics(results.first().id, results.first().source)
},
{
Result.failure(it)
}
)
}

song.song_reg_entry.updateLyrics(ret.id, ret.source)
return ret
result.getOrNull()?.also { lyrics ->
song.song_reg_entry.updateLyrics(lyrics.id, lyrics.source)
}

return result
}

fun getLyricsData(lyrics_id: Int, sync_type: SongLyrics.SyncType): Result<String> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,30 +14,28 @@ class SongLyricsHolder(private val song: Song) {

private val load_lock = Object()

suspend fun loadAndGet(): SongLyrics? {
withContext(Dispatchers.IO) {
synchronized(load_lock) {
if (loading) {
load_lock.wait()
return@withContext lyrics
}
loading = true
}

coroutineContext.job.invokeOnCompletion {
synchronized(load_lock) {
loading = false
load_lock.notifyAll()
}
suspend fun loadAndGet(): Result<SongLyrics> = withContext(Dispatchers.IO) {
synchronized(load_lock) {
if (loading) {
load_lock.wait()
return@withContext lyrics?.let { Result.success(it) } ?: Result.failure(RuntimeException("Lyrics not loaded"))
}
loading = true
}

val result = getSongLyrics(song, song.song_reg_entry.getLyricsData())
coroutineContext.job.invokeOnCompletion {
synchronized(load_lock) {
loaded = true
lyrics = result
loading = false
load_lock.notifyAll()
}
}

return lyrics
val result = getSongLyrics(song, song.song_reg_entry.getLyricsData())
synchronized(load_lock) {
loaded = true
lyrics = result.getOrNull()
}

return@withContext result
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -144,17 +144,16 @@ fun getArtistLongPressMenuData(
@Composable
private fun LongPressMenuActionProvider.ArtistLongPressPopupActions(artist: MediaItem) {
require(artist is Artist)

// TODO | Should radio actions be replaced with shuffle?
val player = LocalPlayerState.current

ActionButton(
Icons.Default.PlayArrow,
getString("lpm_action_play"),
onClick = {
TODO() // Play songs
player.playMediaItem(artist)
},
onLongClick = {
TODO() // Play radio
player.playMediaItem(artist, shuffle = true)
}
)

Expand All @@ -170,7 +169,6 @@ private fun LongPressMenuActionProvider.ArtistLongPressPopupActions(artist: Medi
}
)

val player = LocalPlayerState.current
ActionButton(Icons.Default.Person, getString("lpm_action_open_artist"), onClick = {
player.openMediaItem(artist)
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ private fun MenuContent(

Box(
Modifier
.requiredHeight(SpMp.context.getScreenHeight() + 1.dp)
.requiredHeight(SpMp.context.getScreenHeight() + SpMp.context.getNavigationBarHeight())
.offset(y = -SpMp.context.getStatusBarHeight())
.background(Color.Black.setAlpha(0.5f))
) {
Expand All @@ -186,6 +186,7 @@ private fun MenuContent(
Column(
modifier
.background(Theme.current.background, shape)
.padding(bottom = SpMp.context.getNavigationBarHeight())
.fillMaxWidth()
.onSizeChanged {
if (show_info || !main_actions_showing) {
Expand Down
Loading

0 comments on commit 13104c9

Please sign in to comment.