diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/connections/discord/DiscordRPCService.kt b/app/src/main/java/eu/kanade/tachiyomi/data/connections/discord/DiscordRPCService.kt index 5f768ffe2c..6033ce9a60 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/connections/discord/DiscordRPCService.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/connections/discord/DiscordRPCService.kt @@ -19,7 +19,6 @@ import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.connections.ConnectionsManager import eu.kanade.tachiyomi.data.notification.NotificationReceiver import eu.kanade.tachiyomi.data.notification.Notifications -import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.NetworkHelper import eu.kanade.tachiyomi.ui.player.viewer.PipState import eu.kanade.tachiyomi.util.system.notificationBuilder @@ -33,6 +32,7 @@ import uy.kohesive.injekt.api.get import uy.kohesive.injekt.injectLazy import kotlin.math.ceil import kotlin.math.floor +import kotlinx.serialization.json.Json class DiscordRPCService : Service() { @@ -239,24 +239,27 @@ class DiscordRPCService : Service() { } withIOContext { + val connectionsManager: ConnectionsManager by injectLazy() val networkService: NetworkHelper by injectLazy() val client = networkService.client - val response = if (!discordIncognito) { + val json = Json { + encodeDefaults = true + allowStructuredMapKeys = true + ignoreUnknownKeys = true + } + val rpcExternalAsset = RPCExternalAsset(applicationId = RICH_PRESENCE_APPLICATION_ID, token = connectionsPreferences.connectionsToken(connectionsManager.discord).get(), client = client, json = json) + + val discordUri = if (!discordIncognito) { try { - client.newCall( - GET("https://kizzy-api.vercel.app/image?url=${playerData.thumbnailUrl}"), - ).execute() + rpcExternalAsset.getDiscordUri(playerData.thumbnailUrl) } catch (e: Throwable) { null } } else { null } - - val animeThumbnail = response?.body?.string() - ?.takeIf { !it.contains("external/Not Found") }?.substringAfter("\"id\": \"")?.substringBefore( - "\"}", - ) + val animeThumbnail = discordUri?.takeIf { !it.contains("external/Not Found") } + ?.substringAfter("\"id\": \"")?.substringBefore("\"}") ?.split("external/")?.getOrNull(1)?.let { "external/$it" } setAnimeScreen( @@ -271,6 +274,7 @@ class DiscordRPCService : Service() { } } + @Suppress("SwallowedException", "TooGenericExceptionCaught", "CyclomaticComplexMethod") internal suspend fun setReaderActivity( context: Context, @@ -306,24 +310,23 @@ class DiscordRPCService : Service() { } withIOContext { + val connectionsManager: ConnectionsManager by injectLazy() val networkService: NetworkHelper by injectLazy() val client = networkService.client - val response = if (!discordIncognito) { + val json = Json { ignoreUnknownKeys = true } // Configura el JSON parser si es necesario + val rpcExternalAsset = RPCExternalAsset(applicationId = RICH_PRESENCE_APPLICATION_ID , token = connectionsPreferences.connectionsToken(connectionsManager.discord).get(), client = client, json = json) + + val discordUri = if (!discordIncognito) { try { - client.newCall( - GET("https://kizzy-api.vercel.app/image?url=${readerData.thumbnailUrl}"), - ).execute() + rpcExternalAsset.getDiscordUri(readerData.thumbnailUrl) } catch (e: Throwable) { null } } else { null } - - val mangaThumbnail = response?.body?.string() - ?.takeIf { !it.contains("external/Not Found") }?.substringAfter("\"id\": \"")?.substringBefore( - "\"}", - ) + val mangaThumbnail = discordUri?.takeIf { !it.contains("external/Not Found") } + ?.substringAfter("\"id\": \"")?.substringBefore("\"}") ?.split("external/")?.getOrNull(1)?.let { "external/$it" } setMangaScreen( @@ -337,6 +340,8 @@ class DiscordRPCService : Service() { ) } } + + private const val RICH_PRESENCE_APPLICATION_ID = "952899285983326208" } } // <-- AM (DISCORD) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/connections/discord/RPCExternalAsset.kt b/app/src/main/java/eu/kanade/tachiyomi/data/connections/discord/RPCExternalAsset.kt new file mode 100644 index 0000000000..2007544545 --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/data/connections/discord/RPCExternalAsset.kt @@ -0,0 +1,58 @@ +package eu.kanade.tachiyomi.data.connections.discord + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.Json +import okhttp3.Call +import okhttp3.Callback +import okhttp3.MediaType.Companion.toMediaType +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.RequestBody.Companion.toRequestBody +import okhttp3.Response +import okio.IOException +import kotlin.coroutines.resume +import kotlin.coroutines.resumeWithException +import kotlin.coroutines.suspendCoroutine + +class RPCExternalAsset( + applicationId: String, + private val token: String, + private val client: OkHttpClient, + private val json: Json +) { + + @Serializable + data class ExternalAsset( + val url: String? = null, + @SerialName("external_asset_path") + val externalAssetPath: String? = null + ) + + private val api = "https://discord.com/api/v9/applications/$applicationId/external-assets" + suspend fun getDiscordUri(imageUrl: String): String? { + if (imageUrl.startsWith("mp:")) return imageUrl + val request = Request.Builder().url(api).header("Authorization", token) + .post("{\"urls\":[\"$imageUrl\"]}".toRequestBody("application/json".toMediaType())) + .build() + return runCatching { + val res = client.newCall(request).await() + json.decodeFromString>(res.body.string()) + .firstOrNull()?.externalAssetPath?.let { "mp:$it" } + }.getOrNull() + } + + private suspend inline fun Call.await(): Response { + return suspendCoroutine { + enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + it.resumeWithException(e) + } + + override fun onResponse(call: Call, response: Response) { + it.resume(response) + } + }) + } + } +}