From 5e96861dcbe2382db75d74e663ceded92b3f57cc Mon Sep 17 00:00:00 2001 From: devmil Date: Fri, 31 Jan 2025 18:25:06 +0100 Subject: [PATCH 1/3] adds SongLink as a service to allow sharing the song.link URL --- .../com/prochy/odesliandroid/activity/Main.kt | 16 +------ .../prochy/odesliandroid/activity/Share.kt | 21 +++----- .../odesliandroid/utils/MusicProviders.kt | 1 + .../com/prochy/odesliandroid/utils/Utils.kt | 48 +++++++++++++++++++ 4 files changed, 57 insertions(+), 29 deletions(-) diff --git a/odesli/src/main/java/com/prochy/odesliandroid/activity/Main.kt b/odesli/src/main/java/com/prochy/odesliandroid/activity/Main.kt index 572b22a..ab7502c 100644 --- a/odesli/src/main/java/com/prochy/odesliandroid/activity/Main.kt +++ b/odesli/src/main/java/com/prochy/odesliandroid/activity/Main.kt @@ -339,21 +339,7 @@ fun OdesliLayout() { strokeCap = StrokeCap.Round ) if (receivedLinks) { - val thumbnail = songData.entitiesByUniqueId[outputService]?.thumbnailUrl - val title = songData.entitiesByUniqueId[outputService]?.title - val artist = songData.entitiesByUniqueId[outputService]?.artistName - val service = getLabelFromService(outputService) - val link = songData.linksByPlatform[outputService]?.url - val type = songData.entitiesByUniqueId[songData.entitiesByUniqueId.keys.first()]?.type ?: "" - - Utils.SongInfo( - thumbnail = thumbnail.toString(), - title = title.toString(), - artist = artist.toString(), - service = service.toString(), - link = link.toString(), - odesliType = type - ) + Utils.SongInfoFromData(songData, outputService) } } diff --git a/odesli/src/main/java/com/prochy/odesliandroid/activity/Share.kt b/odesli/src/main/java/com/prochy/odesliandroid/activity/Share.kt index 2b19dec..23a9617 100644 --- a/odesli/src/main/java/com/prochy/odesliandroid/activity/Share.kt +++ b/odesli/src/main/java/com/prochy/odesliandroid/activity/Share.kt @@ -125,7 +125,8 @@ class Share : ComponentActivity() { ).show() finish() } - val platformLink = data.linksByPlatform[service]?.url + + val platformLink = Utils.getLinkForPlatform(data, service) if (!platformLink.isNullOrBlank()) { val clipboard = getSystemService(CLIPBOARD_SERVICE) as ClipboardManager val clip = ClipData.newPlainText("Link", platformLink) @@ -326,19 +327,10 @@ fun ShareActivityLayout(receivedLink: String) { } val musicServices = MusicProviders.entries.map { it.service } - val thumbnail = receivedData.value.entitiesByUniqueId[outputService]?.thumbnailUrl - val title = receivedData.value.entitiesByUniqueId[outputService]?.title - val artist = receivedData.value.entitiesByUniqueId[outputService]?.artistName - val service = getLabelFromService(outputService) - val link = receivedData.value.linksByPlatform[outputService]?.url - val type = receivedData.value.entitiesByUniqueId[receivedData.value.entitiesByUniqueId.keys.first()]?.type ?: "" - Utils.SongInfo( - thumbnail = thumbnail.toString(), - title = title.toString(), - artist = artist.toString(), - service = service.toString(), - link = link.toString(), - odesliType = type, + + Utils.SongInfoFromData( + receivedData.value, + outputService, element = { DynamicSelectTextFieldPopUp( modifier = Modifier.width(350.dp), @@ -351,6 +343,7 @@ fun ShareActivityLayout(receivedLink: String) { ) } ) + } } } diff --git a/odesli/src/main/java/com/prochy/odesliandroid/utils/MusicProviders.kt b/odesli/src/main/java/com/prochy/odesliandroid/utils/MusicProviders.kt index 7d7dba7..60197ee 100644 --- a/odesli/src/main/java/com/prochy/odesliandroid/utils/MusicProviders.kt +++ b/odesli/src/main/java/com/prochy/odesliandroid/utils/MusicProviders.kt @@ -5,6 +5,7 @@ import androidx.annotation.Keep // Enum class representing different music services @Keep enum class MusicProviders(val label: String, val service: String) { + SongLink("SongLink", "SONG_LINK"), AmazonMusic("Amazon Music", "amazonMusic"), AmazonStore("Amazon Appstore", "amazonStore"), Anghami("Anghami", "anghami"), diff --git a/odesli/src/main/java/com/prochy/odesliandroid/utils/Utils.kt b/odesli/src/main/java/com/prochy/odesliandroid/utils/Utils.kt index 529b189..7ea17e2 100644 --- a/odesli/src/main/java/com/prochy/odesliandroid/utils/Utils.kt +++ b/odesli/src/main/java/com/prochy/odesliandroid/utils/Utils.kt @@ -49,9 +49,35 @@ import coil.compose.rememberAsyncImagePainter import coil.request.ImageRequest import coil.size.Size import com.prochy.odesliandroid.R +import com.prochy.odesliandroid.utils.MusicProviders.Companion.getLabelFromService class Utils { companion object { + @Composable + fun SongInfoFromData( + songData: OdesliData, + service: String, + element: @Composable () -> Unit = {}, + ) { + val entriesData = getEntriesDataFor(songData, service) + val thumbnail = entriesData?.thumbnailUrl + val title = entriesData?.title + val artist = entriesData?.artistName + val serviceLabel = getLabelFromService(service) + val link = getLinkForPlatform(songData, service) + val type = songData.entitiesByUniqueId[songData.entitiesByUniqueId.keys.first()]?.type ?: "" + + SongInfo( + thumbnail = thumbnail.toString(), + title = title.toString(), + artist = artist.toString(), + service = serviceLabel.toString(), + link = link.toString(), + odesliType = type, + element = element, + ) + } + @Composable fun SongInfo( thumbnail: String, @@ -261,6 +287,28 @@ class Utils { startActivity(context, browserIntent, null) } + fun getEntriesDataFor(songData: OdesliData, service: String) : EntitiesData? { + val matchingData = songData.entitiesByUniqueId[service] + if(matchingData != null) { + return matchingData + } + if(songData.entitiesByUniqueId.isNotEmpty()) { + return songData.entitiesByUniqueId[songData.entitiesByUniqueId.keys.first()] + } + return null + } + + fun getLinkForPlatform(data: OdesliData, platform: String): String? { + if(platform.equals(MusicProviders.SongLink.service)) { + return data.pageUrl + } + val platformSpecificLink = data.linksByPlatform[platform]; + if(platformSpecificLink == null) { + return null + } + return platformSpecificLink.url + } + fun getMusicData(link: String, context: Context, callback: (OdesliData) -> Unit) { fun retroFitRequest(countryCode: String) { From 6687eda32fe8d39d934ce1d732dfaf6c03012344 Mon Sep 17 00:00:00 2001 From: devmil Date: Fri, 31 Jan 2025 23:06:33 +0100 Subject: [PATCH 2/3] add fallback services by priority for metadata if the actual service is not containing any (can happen for SoundLink) --- .../main/java/com/prochy/odesliandroid/utils/Utils.kt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/odesli/src/main/java/com/prochy/odesliandroid/utils/Utils.kt b/odesli/src/main/java/com/prochy/odesliandroid/utils/Utils.kt index 7ea17e2..83ef9b7 100644 --- a/odesli/src/main/java/com/prochy/odesliandroid/utils/Utils.kt +++ b/odesli/src/main/java/com/prochy/odesliandroid/utils/Utils.kt @@ -53,6 +53,9 @@ import com.prochy.odesliandroid.utils.MusicProviders.Companion.getLabelFromServi class Utils { companion object { + + val fallbackServices = listOf(MusicProviders.Spotify, MusicProviders.AppleMusic, MusicProviders.Deezer) + @Composable fun SongInfoFromData( songData: OdesliData, @@ -292,6 +295,12 @@ class Utils { if(matchingData != null) { return matchingData } + for (fallbackService in fallbackServices) { + val potentialFallbackData = songData.entitiesByUniqueId[fallbackService.service] + if(potentialFallbackData != null) { + return potentialFallbackData + } + } if(songData.entitiesByUniqueId.isNotEmpty()) { return songData.entitiesByUniqueId[songData.entitiesByUniqueId.keys.first()] } From 793dcfe8163f2b27055a93961c958269f98fdc91 Mon Sep 17 00:00:00 2001 From: devmil Date: Sat, 1 Feb 2025 22:21:32 +0100 Subject: [PATCH 3/3] cleanup and comments --- .../prochy/odesliandroid/activity/Share.kt | 6 ++-- .../com/prochy/odesliandroid/utils/Utils.kt | 31 ++++++++++++------- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/odesli/src/main/java/com/prochy/odesliandroid/activity/Share.kt b/odesli/src/main/java/com/prochy/odesliandroid/activity/Share.kt index 23a9617..7151be2 100644 --- a/odesli/src/main/java/com/prochy/odesliandroid/activity/Share.kt +++ b/odesli/src/main/java/com/prochy/odesliandroid/activity/Share.kt @@ -126,10 +126,10 @@ class Share : ComponentActivity() { finish() } - val platformLink = Utils.getLinkForPlatform(data, service) - if (!platformLink.isNullOrBlank()) { + val serviceLink = Utils.getLinkForService(data, service) + if (!serviceLink.isNullOrBlank()) { val clipboard = getSystemService(CLIPBOARD_SERVICE) as ClipboardManager - val clip = ClipData.newPlainText("Link", platformLink) + val clip = ClipData.newPlainText("Link", serviceLink) clipboard.setPrimaryClip(clip) finish() } else { diff --git a/odesli/src/main/java/com/prochy/odesliandroid/utils/Utils.kt b/odesli/src/main/java/com/prochy/odesliandroid/utils/Utils.kt index 83ef9b7..d5d315a 100644 --- a/odesli/src/main/java/com/prochy/odesliandroid/utils/Utils.kt +++ b/odesli/src/main/java/com/prochy/odesliandroid/utils/Utils.kt @@ -54,8 +54,15 @@ import com.prochy.odesliandroid.utils.MusicProviders.Companion.getLabelFromServi class Utils { companion object { - val fallbackServices = listOf(MusicProviders.Spotify, MusicProviders.AppleMusic, MusicProviders.Deezer) + /// prioritized list of music providers that get used if the selected music provider doesn't have any metadata + private val fallbackMusicProviders = listOf( + MusicProviders.Spotify, + MusicProviders.AppleMusic, + MusicProviders.YoutubeMusic, + MusicProviders.Deezer, + ) + /// adds song metadata extracted from the given [songData] for the given [service] @Composable fun SongInfoFromData( songData: OdesliData, @@ -67,7 +74,7 @@ class Utils { val title = entriesData?.title val artist = entriesData?.artistName val serviceLabel = getLabelFromService(service) - val link = getLinkForPlatform(songData, service) + val link = getLinkForService(songData, service) val type = songData.entitiesByUniqueId[songData.entitiesByUniqueId.keys.first()]?.type ?: "" SongInfo( @@ -290,13 +297,15 @@ class Utils { startActivity(context, browserIntent, null) } - fun getEntriesDataFor(songData: OdesliData, service: String) : EntitiesData? { + private fun getEntriesDataFor(songData: OdesliData, service: String) : EntitiesData? { val matchingData = songData.entitiesByUniqueId[service] if(matchingData != null) { return matchingData } - for (fallbackService in fallbackServices) { - val potentialFallbackData = songData.entitiesByUniqueId[fallbackService.service] + // if [service] doesn't have metadata then go through the fallbackMusicProviders + // and use the first one that has metadata + for (fallbackMusicProvider in fallbackMusicProviders) { + val potentialFallbackData = songData.entitiesByUniqueId[fallbackMusicProvider.service] if(potentialFallbackData != null) { return potentialFallbackData } @@ -307,15 +316,13 @@ class Utils { return null } - fun getLinkForPlatform(data: OdesliData, platform: String): String? { - if(platform.equals(MusicProviders.SongLink.service)) { + fun getLinkForService(data: OdesliData, service: String): String? { + // if the selected service is "SongLink" then we return the SongLink URL + if(service == MusicProviders.SongLink.service) { return data.pageUrl } - val platformSpecificLink = data.linksByPlatform[platform]; - if(platformSpecificLink == null) { - return null - } - return platformSpecificLink.url + val serviceSpecificLink = data.linksByPlatform[service] ?: return null + return serviceSpecificLink.url } fun getMusicData(link: String, context: Context, callback: (OdesliData) -> Unit) {