From a8f7ff2a19b5f183da7542b625bcfd50415abe25 Mon Sep 17 00:00:00 2001 From: aayush262 Date: Sun, 21 Jul 2024 01:05:43 +0530 Subject: [PATCH] fix(rpc): no images --- .../connections/anilist/AnilistQueries.kt | 28 ++++----- .../ani/dantotsu/connections/discord/RPC.kt | 33 ++++------- .../connections/discord/RpcExternalAsset.kt | 59 +++++++++++++++++++ .../java/ani/dantotsu/home/status/Stories.kt | 5 +- .../settings/SettingsAddonActivity.kt | 6 +- 5 files changed, 93 insertions(+), 38 deletions(-) create mode 100644 app/src/main/java/ani/dantotsu/connections/discord/RpcExternalAsset.kt diff --git a/app/src/main/java/ani/dantotsu/connections/anilist/AnilistQueries.kt b/app/src/main/java/ani/dantotsu/connections/anilist/AnilistQueries.kt index dc77be30..df4f276e 100644 --- a/app/src/main/java/ani/dantotsu/connections/anilist/AnilistQueries.kt +++ b/app/src/main/java/ani/dantotsu/connections/anilist/AnilistQueries.kt @@ -400,9 +400,7 @@ class AnilistQueries { return media } - private fun continueMediaQuery(type: String, status: String): String { - return """ MediaListCollection(userId: ${Anilist.userid}, type: $type, status: $status , sort: UPDATED_TIME ) { lists { entries { progress private score(format:POINT_100) status media { id idMal type isAdult status chapters episodes nextAiringEpisode {episode} meanScore isFavourite format bannerImage coverImage{large} title { english romaji userPreferred } } } } } """ - } + private suspend fun favMedia(anime: Boolean, id: Int? = Anilist.userid): ArrayList { var hasNextPage = true @@ -428,24 +426,14 @@ class AnilistQueries { return responseArray } - private fun favMediaQuery(anime: Boolean, page: Int, id: Int? = Anilist.userid): String { - return """User(id:${id}){id favourites{${if (anime) "anime" else "manga"}(page:$page){pageInfo{hasNextPage}edges{favouriteOrder node{id idMal isAdult mediaListEntry{ progress private score(format:POINT_100) status } chapters isFavourite format episodes nextAiringEpisode{episode}meanScore isFavourite format startDate{year month day} title{english romaji userPreferred}type status(version:2)bannerImage coverImage{large}}}}}}""" - } - private fun recommendationQuery(): String { - return """ Page(page: 1, perPage:30) { pageInfo { total currentPage hasNextPage } recommendations(sort: RATING_DESC, onList: true) { rating userRating mediaRecommendation { id idMal isAdult mediaListEntry { progress private score(format:POINT_100) status } chapters isFavourite format episodes nextAiringEpisode {episode} popularity meanScore isFavourite format title {english romaji userPreferred } type status(version: 2) bannerImage coverImage { large } } } } """ - } - - private fun recommendationPlannedQuery(type: String): String { - return """ MediaListCollection(userId: ${Anilist.userid}, type: $type, status: PLANNING${if (type == "ANIME") ", sort: MEDIA_POPULARITY_DESC" else ""} ) { lists { entries { media { id mediaListEntry { progress private score(format:POINT_100) status } idMal type isAdult popularity status(version: 2) chapters episodes nextAiringEpisode {episode} meanScore isFavourite format bannerImage coverImage{large} title { english romaji userPreferred } } } } }""" - } suspend fun getUserStatus(): ArrayList? { val toShow: List = PrefManager.getVal(PrefName.HomeLayout) if (toShow.getOrNull(7) != true) return null val query = """{Page1:${status(1)}Page2:${status(2)}}""" - val response = executeQuery(query, show = true) + val response = executeQuery(query) val list = mutableListOf() val threeDaysAgo = Calendar.getInstance().apply { add(Calendar.DAY_OF_MONTH, -3) @@ -497,7 +485,19 @@ class AnilistQueries { return list.toCollection(ArrayList()) } else return null } + private fun favMediaQuery(anime: Boolean, page: Int, id: Int? = Anilist.userid): String { + return """User(id:${id}){id favourites{${if (anime) "anime" else "manga"}(page:$page){pageInfo{hasNextPage}edges{favouriteOrder node{id idMal isAdult mediaListEntry{ progress private score(format:POINT_100) status } chapters isFavourite format episodes nextAiringEpisode{episode}meanScore isFavourite format startDate{year month day} title{english romaji userPreferred}type status(version:2)bannerImage coverImage{large}}}}}}""" + } + private fun recommendationQuery(): String { + return """ Page(page: 1, perPage:30) { pageInfo { total currentPage hasNextPage } recommendations(sort: RATING_DESC, onList: true) { rating userRating mediaRecommendation { id idMal isAdult mediaListEntry { progress private score(format:POINT_100) status } chapters isFavourite format episodes nextAiringEpisode {episode} popularity meanScore isFavourite format title {english romaji userPreferred } type status(version: 2) bannerImage coverImage { large } } } } """ + } + private fun recommendationPlannedQuery(type: String): String { + return """ MediaListCollection(userId: ${Anilist.userid}, type: $type, status: PLANNING${if (type == "ANIME") ", sort: MEDIA_POPULARITY_DESC" else ""} ) { lists { entries { media { id mediaListEntry { progress private score(format:POINT_100) status } idMal type isAdult popularity status(version: 2) chapters episodes nextAiringEpisode {episode} meanScore isFavourite format bannerImage coverImage{large} title { english romaji userPreferred } } } } }""" + } + private fun continueMediaQuery(type: String, status: String): String { + return """ MediaListCollection(userId: ${Anilist.userid}, type: $type, status: $status , sort: UPDATED_TIME ) { lists { entries { progress private score(format:POINT_100) status media { id idMal type isAdult status chapters episodes nextAiringEpisode {episode} meanScore isFavourite format bannerImage coverImage{large} title { english romaji userPreferred } } } } } """ + } suspend fun initHomePage(): Map> { val removeList = PrefManager.getCustomVal("removeList", setOf()) val hidePrivate = PrefManager.getVal(PrefName.HidePrivate) diff --git a/app/src/main/java/ani/dantotsu/connections/discord/RPC.kt b/app/src/main/java/ani/dantotsu/connections/discord/RPC.kt index f46dd63d..468e75cf 100644 --- a/app/src/main/java/ani/dantotsu/connections/discord/RPC.kt +++ b/app/src/main/java/ani/dantotsu/connections/discord/RPC.kt @@ -1,24 +1,19 @@ package ani.dantotsu.connections.discord +import ani.dantotsu.connections.discord.Discord.token import ani.dantotsu.connections.discord.serializers.Activity import ani.dantotsu.connections.discord.serializers.Presence import ani.dantotsu.settings.saving.PrefManager import ani.dantotsu.settings.saving.PrefName -import kotlinx.serialization.Serializable import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json +import okhttp3.OkHttpClient import kotlin.coroutines.CoroutineContext -import ani.dantotsu.client as app +import java.util.concurrent.TimeUnit.SECONDS @Suppress("MemberVisibilityCanBePrivate") open class RPC(val token: String, val coroutineContext: CoroutineContext) { - private val json = Json { - encodeDefaults = true - allowStructuredMapKeys = true - ignoreUnknownKeys = true - } - enum class Type { PLAYING, STREAMING, LISTENING, WATCHING, COMPETING } @@ -27,7 +22,7 @@ open class RPC(val token: String, val coroutineContext: CoroutineContext) { companion object { data class RPCData( - val applicationId: String? = null, + val applicationId: String, val type: Type? = null, val activityName: String? = null, val details: String? = null, @@ -39,23 +34,21 @@ open class RPC(val token: String, val coroutineContext: CoroutineContext) { val stopTimestamp: Long? = null, val buttons: MutableList = mutableListOf() ) - - @Serializable - data class KizzyApi(val id: String) - - val api = "https://kizzy-api.vercel.app/image?url=" - private suspend fun String.discordUrl(): String? { - if (startsWith("mp:")) return this - val json = app.get("$api$this").parsedSafe() - return json?.id - } - suspend fun createPresence(data: RPCData): String { val json = Json { encodeDefaults = true allowStructuredMapKeys = true ignoreUnknownKeys = true } + val client = OkHttpClient.Builder() + .connectTimeout(10, SECONDS) + .readTimeout(10, SECONDS) + .writeTimeout(10, SECONDS) + .build() + + val assetApi = RPCExternalAsset(data.applicationId, token!!, client, json) + suspend fun String.discordUrl() = assetApi.getDiscordUri(this) + return json.encodeToString(Presence.Response( 3, Presence( diff --git a/app/src/main/java/ani/dantotsu/connections/discord/RpcExternalAsset.kt b/app/src/main/java/ani/dantotsu/connections/discord/RpcExternalAsset.kt new file mode 100644 index 00000000..c16f4b82 --- /dev/null +++ b/app/src/main/java/ani/dantotsu/connections/discord/RpcExternalAsset.kt @@ -0,0 +1,59 @@ +package ani.dantotsu.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) + } + }) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/ani/dantotsu/home/status/Stories.kt b/app/src/main/java/ani/dantotsu/home/status/Stories.kt index a141a5d6..09158aae 100644 --- a/app/src/main/java/ani/dantotsu/home/status/Stories.kt +++ b/app/src/main/java/ani/dantotsu/home/status/Stories.kt @@ -507,6 +507,8 @@ class Stories @JvmOverloads constructor( leftPanelTouch() } else if (event.x > rightQuarter) { rightPanelTouch() + } else { + resume() } } else { resume() @@ -523,7 +525,8 @@ class Stories @JvmOverloads constructor( } } val deltaX = event.x - startX - if (abs(deltaX) > swipeThreshold) { + val deltaY = event.y - startY + if (abs(deltaX) > swipeThreshold && !(abs(deltaY) > 10)) { if (deltaX > 0) onStoriesPrevious() else onStoriesCompleted() } diff --git a/app/src/main/java/ani/dantotsu/settings/SettingsAddonActivity.kt b/app/src/main/java/ani/dantotsu/settings/SettingsAddonActivity.kt index 664a8b05..55dacb07 100644 --- a/app/src/main/java/ani/dantotsu/settings/SettingsAddonActivity.kt +++ b/app/src/main/java/ani/dantotsu/settings/SettingsAddonActivity.kt @@ -53,9 +53,9 @@ class SettingsAddonActivity : AppCompatActivity() { bottomMargin = navBarHeight } - binding.addonSettingsBack.setOnClickListener { onBackPressedDispatcher.onBackPressed() } + addonSettingsBack.setOnClickListener { onBackPressedDispatcher.onBackPressed() } - binding.settingsRecyclerView.adapter = SettingsAdapter( + settingsRecyclerView.adapter = SettingsAdapter( arrayListOf( Settings( type = 1, @@ -207,7 +207,7 @@ class SettingsAddonActivity : AppCompatActivity() { ) ) ) - binding.settingsRecyclerView.layoutManager = + settingsRecyclerView.layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false) }