From 44a2146c1211841ec5662e76eab00bff1014d30f Mon Sep 17 00:00:00 2001 From: Cloudburst <18114966+C10udburst@users.noreply.github.com> Date: Wed, 9 Aug 2023 23:44:17 +0200 Subject: [PATCH] fix voting api (#544) --- .../cloudstream3/plugins/VotingApi.kt | 101 ++++++++---------- .../extensions/PluginDetailsFragment.kt | 49 ++------- .../res/layout/fragment_plugin_details.xml | 15 +-- app/src/main/res/values/strings.xml | 1 + 4 files changed, 54 insertions(+), 112 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/plugins/VotingApi.kt b/app/src/main/java/com/lagradost/cloudstream3/plugins/VotingApi.kt index f099ad1a..a45ab5f0 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/plugins/VotingApi.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/plugins/VotingApi.kt @@ -8,22 +8,14 @@ import com.lagradost.cloudstream3.AcraApplication.Companion.setKey import com.lagradost.cloudstream3.R import java.security.MessageDigest import com.lagradost.cloudstream3.app -import com.lagradost.cloudstream3.utils.Coroutines.ioSafe import com.lagradost.cloudstream3.utils.Coroutines.main -import kotlinx.coroutines.delay import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock object VotingApi { // please do not cheat the votes lol private const val LOGKEY = "VotingApi" - enum class VoteType(val value: Int) { - UPVOTE(1), - DOWNVOTE(-1), - NONE(0) - } - - private val apiDomain = "https://api.countapi.xyz" + private const val apiDomain = "https://counterapi.com/api" private fun transformUrl(url: String): String = // dont touch or all votes get reset MessageDigest @@ -35,12 +27,12 @@ object VotingApi { // please do not cheat the votes lol return getVotes(url) } - suspend fun SitePlugin.vote(requestType: VoteType): Int { - return vote(url, requestType) + fun SitePlugin.hasVoted(): Boolean { + return hasVoted(url) } - fun SitePlugin.getVoteType(): VoteType { - return getVoteType(url) + suspend fun SitePlugin.vote(): Int { + return vote(url) } fun SitePlugin.canVote(): Boolean { @@ -50,28 +42,31 @@ object VotingApi { // please do not cheat the votes lol // Plugin url to Int private val votesCache = mutableMapOf() - suspend fun getVotes(pluginUrl: String): Int { - val url = "${apiDomain}/get/cs3-votes/${transformUrl(pluginUrl)}" + private fun getRepository(pluginUrl: String) = pluginUrl + .split("/") + .drop(2) + .take(3) + .joinToString("-") + + private suspend fun readVote(pluginUrl: String): Int { + var url = "${apiDomain}/cs-${getRepository(pluginUrl)}/vote/${transformUrl(pluginUrl)}?readOnly=true" Log.d(LOGKEY, "Requesting: $url") - return votesCache[pluginUrl] ?: app.get(url).parsedSafe()?.value?.also { - votesCache[pluginUrl] = it - } ?: (0.also { - ioSafe { - createBucket(pluginUrl) + return app.get(url).parsedSafe()?.value ?: 0 + } + + private suspend fun writeVote(pluginUrl: String): Boolean { + var url = "${apiDomain}/cs-${getRepository(pluginUrl)}/vote/${transformUrl(pluginUrl)}" + Log.d(LOGKEY, "Requesting: $url") + return app.get(url).parsedSafe()?.value != null + } + + suspend fun getVotes(pluginUrl: String): Int = + votesCache[pluginUrl] ?: readVote(pluginUrl).also { + votesCache[pluginUrl] = it } - }) - } - fun getVoteType(pluginUrl: String): VoteType { - return getKey("cs3-votes/${transformUrl(pluginUrl)}") ?: VoteType.NONE - } - - private suspend fun createBucket(pluginUrl: String) { - val url = - "${apiDomain}/create?namespace=cs3-votes&key=${transformUrl(pluginUrl)}&value=0&update_lowerbound=-2&update_upperbound=2&enable_reset=0" - Log.d(LOGKEY, "Requesting: $url") - app.get(url) - } + fun hasVoted(pluginUrl: String) = + getKey("cs3-votes/${transformUrl(pluginUrl)}") ?: false fun canVote(pluginUrl: String): Boolean { if (!PluginManager.urlPlugins.contains(pluginUrl)) return false @@ -79,7 +74,7 @@ object VotingApi { // please do not cheat the votes lol } private val voteLock = Mutex() - suspend fun vote(pluginUrl: String, requestType: VoteType): Int { + suspend fun vote(pluginUrl: String): Int { // Prevent multiple requests at the same time. voteLock.withLock { if (!canVote(pluginUrl)) { @@ -90,33 +85,21 @@ object VotingApi { // please do not cheat the votes lol return getVotes(pluginUrl) } - val savedType: VoteType = - getKey("cs3-votes/${transformUrl(pluginUrl)}") ?: VoteType.NONE - - val newType = if (requestType == savedType) VoteType.NONE else requestType - val changeValue = if (requestType == savedType) { - -requestType.value - } else if (savedType == VoteType.NONE) { - requestType.value - } else if (savedType != requestType) { - -savedType.value + requestType.value - } else 0 - - // Pre-emptively set vote key - setKey("cs3-votes/${transformUrl(pluginUrl)}", newType) - - val url = - "${apiDomain}/update/cs3-votes/${transformUrl(pluginUrl)}?amount=${changeValue}" - Log.d(LOGKEY, "Requesting: $url") - val res = app.get(url).parsedSafe()?.value - - if (res == null) { - // "Refund" key if the response is invalid - setKey("cs3-votes/${transformUrl(pluginUrl)}", savedType) - } else { - votesCache[pluginUrl] = res + if (hasVoted(pluginUrl)) { + main { + Toast.makeText(context, R.string.already_voted, Toast.LENGTH_SHORT) + .show() + } + return getVotes(pluginUrl) } - return res ?: 0 + + + if (writeVote(pluginUrl)) { + setKey("cs3-votes/${transformUrl(pluginUrl)}", true) + votesCache[pluginUrl] = votesCache[pluginUrl]?.plus(1) ?: 1 + } + + return getVotes(pluginUrl) } } diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/extensions/PluginDetailsFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/extensions/PluginDetailsFragment.kt index d8047c11..7d733be0 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/extensions/PluginDetailsFragment.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/extensions/PluginDetailsFragment.kt @@ -13,10 +13,9 @@ import com.lagradost.cloudstream3.AcraApplication.Companion.openBrowser import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.databinding.FragmentPluginDetailsBinding import com.lagradost.cloudstream3.plugins.PluginManager -import com.lagradost.cloudstream3.plugins.VotingApi import com.lagradost.cloudstream3.plugins.VotingApi.canVote -import com.lagradost.cloudstream3.plugins.VotingApi.getVoteType import com.lagradost.cloudstream3.plugins.VotingApi.getVotes +import com.lagradost.cloudstream3.plugins.VotingApi.hasVoted import com.lagradost.cloudstream3.plugins.VotingApi.vote import com.lagradost.cloudstream3.utils.Coroutines.ioSafe import com.lagradost.cloudstream3.utils.Coroutines.main @@ -106,7 +105,6 @@ class PluginDetailsFragment(val data: PluginViewData) : BottomSheetDialogFragmen } if (!metadata.canVote()) { - downvote.alpha = .6f upvote.alpha = .6f } @@ -137,19 +135,11 @@ class PluginDetailsFragment(val data: PluginViewData) : BottomSheetDialogFragmen upvote.setOnClickListener { ioSafe { - metadata.vote(VotingApi.VoteType.UPVOTE).main { + metadata.vote().main { updateVoting(it) } } } - downvote.setOnClickListener { - ioSafe { - metadata.vote(VotingApi.VoteType.DOWNVOTE).main { - updateVoting(it) - } - - } - } ioSafe { metadata.getVotes().main { @@ -163,33 +153,14 @@ class PluginDetailsFragment(val data: PluginViewData) : BottomSheetDialogFragmen val metadata = data.plugin.second binding?.apply { pluginVotes.text = value.toString() - when (metadata.getVoteType()) { - VotingApi.VoteType.UPVOTE -> { - upvote.imageTintList = ColorStateList.valueOf( - context?.colorFromAttribute(R.attr.colorPrimary) ?: R.color.colorPrimary - ) - downvote.imageTintList = ColorStateList.valueOf( - context?.colorFromAttribute(R.attr.white) ?: R.color.white - ) - } - - VotingApi.VoteType.DOWNVOTE -> { - downvote.imageTintList = ColorStateList.valueOf( - context?.colorFromAttribute(R.attr.colorPrimary) ?: R.color.colorPrimary - ) - upvote.imageTintList = ColorStateList.valueOf( - context?.colorFromAttribute(R.attr.white) ?: R.color.white - ) - } - - VotingApi.VoteType.NONE -> { - upvote.imageTintList = ColorStateList.valueOf( - context?.colorFromAttribute(R.attr.white) ?: R.color.white - ) - downvote.imageTintList = ColorStateList.valueOf( - context?.colorFromAttribute(R.attr.white) ?: R.color.white - ) - } + if (metadata.hasVoted()) { + upvote.imageTintList = ColorStateList.valueOf( + context?.colorFromAttribute(R.attr.colorPrimary) ?: R.color.colorPrimary + ) + } else { + upvote.imageTintList = ColorStateList.valueOf( + context?.colorFromAttribute(R.attr.colorOnSurface) ?: R.color.white + ) } } } diff --git a/app/src/main/res/layout/fragment_plugin_details.xml b/app/src/main/res/layout/fragment_plugin_details.xml index 35ab9216..7a8f85e4 100644 --- a/app/src/main/res/layout/fragment_plugin_details.xml +++ b/app/src/main/res/layout/fragment_plugin_details.xml @@ -284,23 +284,10 @@ android:layout_gravity="center" android:gravity="center_horizontal|center_vertical"> - - tv_no_focus_tag + You have already voted