From bf05bf2ffd4409f50baa38be2e5c719de1148ba5 Mon Sep 17 00:00:00 2001 From: LuftVerbot <97435834+LuftVerbot@users.noreply.github.com> Date: Tue, 27 Aug 2024 22:14:22 +0200 Subject: [PATCH] Add follow/unfollow artists & trending search --- .../echo/extension/Convertors.kt | 15 ++++--- .../echo/extension/DeezerApi.kt | 28 +++++++++++- .../echo/extension/DeezerExtension.kt | 44 +++++++++++++++++-- gradle.properties | 2 +- 4 files changed, 78 insertions(+), 11 deletions(-) diff --git a/ext/src/main/java/dev/brahmkshatriya/echo/extension/Convertors.kt b/ext/src/main/java/dev/brahmkshatriya/echo/extension/Convertors.kt index 247afa4..8c34529 100644 --- a/ext/src/main/java/dev/brahmkshatriya/echo/extension/Convertors.kt +++ b/ext/src/main/java/dev/brahmkshatriya/echo/extension/Convertors.kt @@ -19,7 +19,7 @@ import kotlinx.serialization.json.jsonPrimitive import java.time.Instant import java.util.Date -fun JsonElement.toMediaItemsContainer( +suspend fun JsonElement.toMediaItemsContainer( name: String? ): MediaItemsContainer { val itemsArray = jsonObject["items"]!!.jsonArray @@ -30,7 +30,7 @@ fun JsonElement.toMediaItemsContainer( } ) } -fun JsonObject.toMediaItemsContainer( +suspend fun JsonObject.toMediaItemsContainer( name: String? ): MediaItemsContainer { return MediaItemsContainer.Category( @@ -39,7 +39,7 @@ fun JsonObject.toMediaItemsContainer( ) } -fun JsonArray.toMediaItemsContainer( +suspend fun JsonArray.toMediaItemsContainer( name: String? ): MediaItemsContainer { val itemsArray = jsonArray @@ -51,7 +51,7 @@ fun JsonArray.toMediaItemsContainer( ) } -fun JsonElement.toEchoMediaItem(): EchoMediaItem? { +suspend fun JsonElement.toEchoMediaItem(): EchoMediaItem? { val data = jsonObject["data"]?.jsonObject ?: jsonObject val type = data["__TYPE__"]!!.jsonPrimitive.content return when { @@ -131,15 +131,18 @@ fun JsonElement.toAlbum(): Album { ) } -fun JsonElement.toArtist(): Artist { +suspend fun JsonElement.toArtist(): Artist { val data = jsonObject["data"]?.jsonObject ?: jsonObject val md5 = data["ART_PICTURE"]?.jsonPrimitive?.content ?: "" + val id = data["ART_ID"]?.jsonPrimitive?.content ?: "" + val isFollowing = DeezerExtension().isFollowingArtist(id) return Artist( - id = data["ART_ID"]?.jsonPrimitive?.content ?: "", + id = id, name = data["ART_NAME"]?.jsonPrimitive?.content ?: "", cover = getCover(md5, "artist"), description = jsonObject["description"]?.jsonPrimitive?.content ?: "", subtitle = jsonObject["subtitle"]?.jsonPrimitive?.content ?: "", + isFollowing = isFollowing ) } diff --git a/ext/src/main/java/dev/brahmkshatriya/echo/extension/DeezerApi.kt b/ext/src/main/java/dev/brahmkshatriya/echo/extension/DeezerApi.kt index a1ee099..1a7890a 100644 --- a/ext/src/main/java/dev/brahmkshatriya/echo/extension/DeezerApi.kt +++ b/ext/src/main/java/dev/brahmkshatriya/echo/extension/DeezerApi.kt @@ -490,13 +490,39 @@ class DeezerApi { method = "deezer.pageProfile", params = buildJsonObject { put("nb", 40) - put ("tab", "artists", ) + put ("tab", "artists") put("user_id", userId) } ) return json.decodeFromString(jsonData) } + suspend fun followArtist(id: String) { + callApi( + method = "artist.addFavorite", + params = buildJsonObject { + put("ART_ID", id) + putJsonObject("CTXT") { + put("id", id) + put("t", "artist_smartradio") + } + } + ) + } + + suspend fun unfollowArtist(id: String) { + callApi( + method = "artist.deleteFavorite", + params = buildJsonObject { + put("ART_ID", id) + putJsonObject("CTXT") { + put("id", id) + put("t", "artist_smartradio") + } + } + ) + } + suspend fun album(album: Album): JsonObject { val jsonData = callApi( method = "deezer.pageAlbum", diff --git a/ext/src/main/java/dev/brahmkshatriya/echo/extension/DeezerExtension.kt b/ext/src/main/java/dev/brahmkshatriya/echo/extension/DeezerExtension.kt index bf01c6b..ca0e58e 100644 --- a/ext/src/main/java/dev/brahmkshatriya/echo/extension/DeezerExtension.kt +++ b/ext/src/main/java/dev/brahmkshatriya/echo/extension/DeezerExtension.kt @@ -2,6 +2,7 @@ package dev.brahmkshatriya.echo.extension import dev.brahmkshatriya.echo.common.clients.AlbumClient import dev.brahmkshatriya.echo.common.clients.ArtistClient +import dev.brahmkshatriya.echo.common.clients.ArtistFollowClient import dev.brahmkshatriya.echo.common.clients.ExtensionClient import dev.brahmkshatriya.echo.common.clients.HomeFeedClient import dev.brahmkshatriya.echo.common.clients.LibraryClient @@ -42,6 +43,7 @@ import kotlinx.coroutines.coroutineScope import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonArray import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.boolean import kotlinx.serialization.json.int import kotlinx.serialization.json.jsonArray import kotlinx.serialization.json.jsonObject @@ -51,8 +53,8 @@ import okhttp3.Request import java.util.Locale class DeezerExtension : ExtensionClient, HomeFeedClient, TrackClient, SearchClient, AlbumClient, ArtistClient, - PlaylistClient, LyricsClient, ShareClient, LoginClient.WebView.Cookie, LoginClient.UsernamePassword, LoginClient.CustomTextInput, - LibraryClient { + ArtistFollowClient, PlaylistClient, LyricsClient, ShareClient, LoginClient.WebView.Cookie, + LoginClient.UsernamePassword, LoginClient.CustomTextInput, LibraryClient { private val json = Json { isLenient = true @@ -340,14 +342,24 @@ class DeezerExtension : ExtensionClient, HomeFeedClient, TrackClient, SearchClie override suspend fun quickSearch(query: String?) = if (query?.isEmpty() == true) { + val queryList = mutableListOf() val jsonObject = api.getSearchHistory() val resultObject = jsonObject["results"]!!.jsonObject val searchObject = resultObject["SEARCH_HISTORY"]?.jsonObject val dataArray = searchObject?.get("data")?.jsonArray - dataArray?.mapNotNull { item -> + val historyList = dataArray?.mapNotNull { item -> val queryItem = item.jsonObject["query"]?.jsonPrimitive?.content queryItem?.let { QuickSearchItem.SearchQueryItem(it, true) } } ?: emptyList() + queryList.addAll(historyList) + val trendingObject = resultObject["TRENDING_QUERIES"]?.jsonObject + val dataTrendingArray = trendingObject?.get("data")?.jsonArray + val trendingList = dataTrendingArray?.mapNotNull { item -> + val queryItem = item.jsonObject["QUERY"]?.jsonPrimitive?.content + queryItem?.let { QuickSearchItem.SearchQueryItem(it, false) } + } ?: emptyList() + queryList.addAll(trendingList) + queryList } else { query?.let { runCatching { @@ -702,6 +714,32 @@ class DeezerExtension : ExtensionClient, HomeFeedClient, TrackClient, SearchClie return resultsObject.toArtist() } + suspend fun isFollowingArtist(id: String): Boolean { + val artObject = api.getArtists() + val resultObject = artObject["results"]!!.jsonObject + val tabObject = resultObject["TAB"]!!.jsonObject + val artistsObject = tabObject["artists"]!!.jsonObject + val dataArray = artistsObject["data"]!!.jsonArray + var isFollowing = false + dataArray.map { item -> + val artistId = item.jsonObject["ART_ID"]?.jsonPrimitive?.content ?: "" + if(artistId.contains(id)) { + isFollowing = true + } + } + return isFollowing + } + + override suspend fun followArtist(artist: Artist): Boolean { + api.followArtist(artist.id) + return true + } + + override suspend fun unfollowArtist(artist: Artist): Boolean { + api.unfollowArtist(artist.id) + return true + } + //<============= Login =============> override suspend fun getCurrentUser(): User { diff --git a/gradle.properties b/gradle.properties index 901209c..648ce6d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -21,4 +21,4 @@ kotlin.code.style=official # resources declared in the library itself and none from the library's dependencies, # thereby reducing the size of the R class for that library android.nonTransitiveRClass=true -libVersion=8c6cb19 \ No newline at end of file +libVersion=2fe748d7c8 \ No newline at end of file