From cbbff41f99235a90385c05f8ccd5ebc01a115114 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Mon, 15 Jun 2026 13:10:46 -0600 Subject: [PATCH 1/3] AuthAPI: use unixTime from APIHolder --- .../cloudstream3/syncproviders/AuthAPI.kt | 63 +++++++------------ .../syncproviders/providers/AniListApi.kt | 5 +- .../syncproviders/providers/KitsuApi.kt | 5 +- .../syncproviders/providers/MALApi.kt | 5 +- .../providers/OpenSubtitlesApi.kt | 12 ++-- .../syncproviders/providers/SimklApi.kt | 17 ++--- 6 files changed, 47 insertions(+), 60 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/AuthAPI.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/AuthAPI.kt index 184a9fbcc64..26fece78c14 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/AuthAPI.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/AuthAPI.kt @@ -1,48 +1,12 @@ package com.lagradost.cloudstream3.syncproviders import android.util.Base64 -import androidx.annotation.WorkerThread import com.fasterxml.jackson.annotation.JsonProperty import com.lagradost.cloudstream3.APIHolder.unixTime -import com.lagradost.cloudstream3.ActorData -import com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey -import com.lagradost.cloudstream3.CloudStreamApp.Companion.openBrowser -import com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey -import com.lagradost.cloudstream3.CommonActivity.showToast -import com.lagradost.cloudstream3.ErrorLoadingException -import com.lagradost.cloudstream3.LoadResponse -import com.lagradost.cloudstream3.NextAiring -import com.lagradost.cloudstream3.R -import com.lagradost.cloudstream3.Score -import com.lagradost.cloudstream3.SearchQuality -import com.lagradost.cloudstream3.SearchResponse -import com.lagradost.cloudstream3.ShowStatus -import com.lagradost.cloudstream3.TvType -import com.lagradost.cloudstream3.mvvm.Resource -import com.lagradost.cloudstream3.mvvm.logError -import com.lagradost.cloudstream3.mvvm.safe -import com.lagradost.cloudstream3.mvvm.safeApiCall import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.APP_STRING -import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.NONE_ID -import com.lagradost.cloudstream3.syncproviders.providers.Addic7ed -import com.lagradost.cloudstream3.syncproviders.providers.AniListApi -import com.lagradost.cloudstream3.syncproviders.providers.LocalList -import com.lagradost.cloudstream3.syncproviders.providers.MALApi -import com.lagradost.cloudstream3.syncproviders.providers.KitsuApi -import com.lagradost.cloudstream3.syncproviders.providers.OpenSubtitlesApi -import com.lagradost.cloudstream3.syncproviders.providers.SimklApi -import com.lagradost.cloudstream3.syncproviders.providers.SubDlApi -import com.lagradost.cloudstream3.syncproviders.providers.SubSourceApi -import com.lagradost.cloudstream3.ui.SyncWatchType -import com.lagradost.cloudstream3.ui.library.ListSorting import com.lagradost.cloudstream3.utils.AppContextUtils.splitQuery -import com.lagradost.cloudstream3.utils.DataStoreHelper -import com.lagradost.cloudstream3.utils.UiText -import com.lagradost.cloudstream3.utils.txt -import java.net.URL +import java.net.URI import java.security.SecureRandom -import java.util.Date -import java.util.concurrent.TimeUnit data class AuthLoginPage( /** The website to open to authenticate */ @@ -79,10 +43,10 @@ data class AuthToken( val payload: String? = null, ) { fun isAccessTokenExpired(marginSec: Long = 10L) = - accessTokenLifetime != null && (System.currentTimeMillis() / 1000) + marginSec >= accessTokenLifetime + accessTokenLifetime != null && unixTime + marginSec >= accessTokenLifetime fun isRefreshTokenExpired(marginSec: Long = 10L) = - refreshTokenLifetime != null && (System.currentTimeMillis() / 1000) + marginSec >= refreshTokenLifetime + refreshTokenLifetime != null && unixTime + marginSec >= refreshTokenLifetime } data class AuthUser( @@ -177,16 +141,33 @@ abstract class AuthAPI { open val inAppLoginRequirement: AuthLoginRequirement? = null companion object { + @Deprecated( + message = "Use APIHolder.unixTime instead", + replaceWith = ReplaceWith( + expression = "APIHolder.unixTime", + imports = ["com.lagradost.cloudstream3.APIHolder"] + ), + level = DeprecationLevel.WARNING, + ) val unixTime: Long get() = System.currentTimeMillis() / 1000L + + @Deprecated( + message = "Use APIHolder.unixTimeMS instead", + replaceWith = ReplaceWith( + expression = "unixTimeMS", + imports = ["com.lagradost.cloudstream3.APIHolder.unixTimeMS"] + ), + level = DeprecationLevel.WARNING, + ) val unixTimeMs: Long get() = System.currentTimeMillis() fun splitRedirectUrl(redirectUrl: String): Map { return splitQuery( - URL( + URI( redirectUrl.replace(APP_STRING, "https").replace("/#", "?") - ) + ).toURL() ) } diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/AniListApi.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/AniListApi.kt index 7a46b411376..58746a44469 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/AniListApi.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/AniListApi.kt @@ -5,6 +5,7 @@ import com.fasterxml.jackson.annotation.JsonProperty import com.lagradost.cloudstream3.Actor import com.lagradost.cloudstream3.ActorData import com.lagradost.cloudstream3.ActorRole +import com.lagradost.cloudstream3.APIHolder import com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey import com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey import com.lagradost.cloudstream3.ErrorLoadingException @@ -52,7 +53,7 @@ class AniListApi : SyncAPI() { val token = AuthToken( accessToken = sanitizer["access_token"] ?: throw ErrorLoadingException("No access token"), //refreshToken = sanitizer["refresh_token"], - accessTokenLifetime = unixTime + sanitizer["expires_in"]!!.toLong(), + accessTokenLifetime = APIHolder.unixTime + sanitizer["expires_in"]!!.toLong(), ) return token } @@ -106,7 +107,7 @@ class AniListApi : SyncAPI() { nextAiring = season.nextAiringEpisode?.let { NextAiring( it.episode ?: return@let null, - (it.timeUntilAiring ?: return@let null) + unixTime + (it.timeUntilAiring ?: return@let null) + APIHolder.unixTime ) }, title = season.title?.userPreferred, diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/KitsuApi.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/KitsuApi.kt index e15a77c6442..9eb49b4bd08 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/KitsuApi.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/KitsuApi.kt @@ -3,6 +3,7 @@ package com.lagradost.cloudstream3.syncproviders.providers import androidx.annotation.StringRes import com.fasterxml.jackson.annotation.JsonProperty +import com.lagradost.cloudstream3.APIHolder import com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey import com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey import com.lagradost.cloudstream3.R @@ -106,7 +107,7 @@ class KitsuApi: SyncAPI() { ).parsed() return AuthToken( - accessTokenLifetime = unixTime + token.expiresIn.toLong(), + accessTokenLifetime = APIHolder.unixTime + token.expiresIn.toLong(), refreshToken = token.refreshToken, accessToken = token.accessToken, ) @@ -125,7 +126,7 @@ class KitsuApi: SyncAPI() { return AuthToken( accessToken = res.accessToken, refreshToken = res.refreshToken, - accessTokenLifetime = unixTime + res.expiresIn.toLong() + accessTokenLifetime = APIHolder.unixTime + res.expiresIn.toLong() ) } diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/MALApi.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/MALApi.kt index ba0195be6b8..356854359ca 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/MALApi.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/MALApi.kt @@ -2,6 +2,7 @@ package com.lagradost.cloudstream3.syncproviders.providers import androidx.annotation.StringRes import com.fasterxml.jackson.annotation.JsonProperty +import com.lagradost.cloudstream3.APIHolder import com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey import com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey import com.lagradost.cloudstream3.R @@ -78,7 +79,7 @@ class MALApi : SyncAPI() { ) ).parsed() return AuthToken( - accessTokenLifetime = unixTime + token.expiresIn.toLong(), + accessTokenLifetime = APIHolder.unixTime + token.expiresIn.toLong(), refreshToken = token.refreshToken, accessToken = token.accessToken ) @@ -366,7 +367,7 @@ class MALApi : SyncAPI() { return AuthToken( accessToken = res.accessToken, refreshToken = res.refreshToken, - accessTokenLifetime = unixTime + res.expiresIn.toLong() + accessTokenLifetime = APIHolder.unixTime + res.expiresIn.toLong() ) } diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/OpenSubtitlesApi.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/OpenSubtitlesApi.kt index 4b17fdb2920..15ef6bfabe3 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/OpenSubtitlesApi.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/OpenSubtitlesApi.kt @@ -2,9 +2,11 @@ package com.lagradost.cloudstream3.syncproviders.providers import android.util.Log import com.fasterxml.jackson.annotation.JsonProperty -import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.APIHolder +import com.lagradost.cloudstream3.APIHolder.unixTimeMS import com.lagradost.cloudstream3.ErrorLoadingException import com.lagradost.cloudstream3.R +import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.subtitles.AbstractSubtitleEntities import com.lagradost.cloudstream3.syncproviders.AuthData import com.lagradost.cloudstream3.syncproviders.AuthLoginRequirement @@ -43,17 +45,17 @@ class OpenSubtitlesApi : SubtitleAPI() { } private fun canDoRequest(): Boolean { - return unixTimeMs > currentCoolDown + return unixTimeMS > currentCoolDown } private fun throwIfCantDoRequest() { if (!canDoRequest()) { - throw ErrorLoadingException("Too many requests wait for ${(currentCoolDown - unixTimeMs) / 1000L}s") + throw ErrorLoadingException("Too many requests wait for ${(currentCoolDown - unixTimeMS) / 1000L}s") } } private fun throwGotTooManyRequests() { - currentCoolDown = unixTimeMs + COOLDOWN_DURATION + currentCoolDown = unixTimeMS + COOLDOWN_DURATION throw ErrorLoadingException("Too many requests") } @@ -89,7 +91,7 @@ class OpenSubtitlesApi : SubtitleAPI() { accessToken = response.token ?: throw ErrorLoadingException("Invalid password or username"), /// JWT token is valid 24 hours after successfully authentication of user - accessTokenLifetime = unixTime + 60 * 60 * 24, + accessTokenLifetime = APIHolder.unixTime + 60 * 60 * 24, payload = form.toJson() ) } diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SimklApi.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SimklApi.kt index 84a498bb005..a0eb6229371 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SimklApi.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SimklApi.kt @@ -4,6 +4,7 @@ import androidx.annotation.StringRes import androidx.core.net.toUri import com.fasterxml.jackson.annotation.JsonInclude import com.fasterxml.jackson.annotation.JsonProperty +import com.lagradost.cloudstream3.APIHolder import com.lagradost.cloudstream3.BuildConfig import com.lagradost.cloudstream3.CloudStreamApp import com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey @@ -77,15 +78,15 @@ class SimklApi : SyncAPI() { private class SimklCacheWrapper( @JsonProperty("obj") val obj: T?, @JsonProperty("validUntil") val validUntil: Long, - @JsonProperty("cacheTime") val cacheTime: Long = unixTime, + @JsonProperty("cacheTime") val cacheTime: Long = APIHolder.unixTime, ) { /** Returns true if cache is newer than cacheDays */ fun isFresh(): Boolean { - return validUntil > unixTime + return validUntil > APIHolder.unixTime } fun remainingTime(): Duration { - val unixTime = unixTime + val unixTime = APIHolder.unixTime return if (validUntil > unixTime) { (validUntil - unixTime).toDuration(DurationUnit.SECONDS) } else { @@ -109,7 +110,7 @@ class SimklApi : SyncAPI() { SIMKL_CACHE_KEY, path, // Storing as plain sting is required to make generics work. - SimklCacheWrapper(value, unixTime + cacheTime.inWholeSeconds).toJson() + SimklCacheWrapper(value, APIHolder.unixTime + cacheTime.inWholeSeconds).toJson() ) } @@ -418,7 +419,7 @@ class SimklApi : SyncAPI() { } suspend fun execute(): Boolean { - val time = getDateTime(unixTime) + val time = getDateTime(APIHolder.unixTime) val headers = this.headers ?: emptyMap() return if (this.status == SimklListStatusType.None.value) { app.post( @@ -568,7 +569,7 @@ class SimklApi : SyncAPI() { @JsonProperty("year") year: Int?, @JsonProperty("ids") ids: Ids?, @JsonProperty("rating") val rating: Int, - @JsonProperty("rated_at") val ratedAt: String? = getDateTime(unixTime) + @JsonProperty("rated_at") val ratedAt: String? = getDateTime(APIHolder.unixTime) ) : MediaObject(title, year, ids) @JsonInclude(JsonInclude.Include.NON_EMPTY) @@ -577,7 +578,7 @@ class SimklApi : SyncAPI() { @JsonProperty("year") year: Int?, @JsonProperty("ids") ids: Ids?, @JsonProperty("to") val to: String, - @JsonProperty("watched_at") val watchedAt: String? = getDateTime(unixTime) + @JsonProperty("watched_at") val watchedAt: String? = getDateTime(APIHolder.unixTime) ) : MediaObject(title, year, ids) @JsonInclude(JsonInclude.Include.NON_EMPTY) @@ -862,7 +863,7 @@ class SimklApi : SyncAPI() { newStatus: AbstractSyncStatus ): Boolean { val parsedId = readIdFromString(id) - lastScoreTime = unixTime + lastScoreTime = APIHolder.unixTime val simklStatus = newStatus as? SimklSyncStatus val builder = SimklScoreBuilder.Builder() From 41601724cb10222ac8aa00efadac88e026855383 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Mon, 15 Jun 2026 15:56:40 -0600 Subject: [PATCH 2/3] Use APIHolder here also --- .../com/lagradost/cloudstream3/syncproviders/AuthAPI.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/AuthAPI.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/AuthAPI.kt index 26fece78c14..21ad555b562 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/AuthAPI.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/AuthAPI.kt @@ -2,7 +2,9 @@ package com.lagradost.cloudstream3.syncproviders import android.util.Base64 import com.fasterxml.jackson.annotation.JsonProperty +import com.lagradost.cloudstream3.APIHolder import com.lagradost.cloudstream3.APIHolder.unixTime +import com.lagradost.cloudstream3.APIHolder.unixTimeMS import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.APP_STRING import com.lagradost.cloudstream3.utils.AppContextUtils.splitQuery import java.net.URI @@ -150,7 +152,7 @@ abstract class AuthAPI { level = DeprecationLevel.WARNING, ) val unixTime: Long - get() = System.currentTimeMillis() / 1000L + get() = APIHolder.unixTime @Deprecated( message = "Use APIHolder.unixTimeMS instead", @@ -161,7 +163,7 @@ abstract class AuthAPI { level = DeprecationLevel.WARNING, ) val unixTimeMs: Long - get() = System.currentTimeMillis() + get() = unixTimeMS fun splitRedirectUrl(redirectUrl: String): Map { return splitQuery( From 752464c7e6cde8b13222a2ff9ceb62b51cb620e0 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Tue, 16 Jun 2026 10:28:16 -0600 Subject: [PATCH 3/3] Use base64Encode --- .../com/lagradost/cloudstream3/syncproviders/AuthAPI.kt | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/AuthAPI.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/AuthAPI.kt index 21ad555b562..b6997d4943d 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/AuthAPI.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/AuthAPI.kt @@ -1,10 +1,10 @@ package com.lagradost.cloudstream3.syncproviders -import android.util.Base64 import com.fasterxml.jackson.annotation.JsonProperty import com.lagradost.cloudstream3.APIHolder import com.lagradost.cloudstream3.APIHolder.unixTime import com.lagradost.cloudstream3.APIHolder.unixTimeMS +import com.lagradost.cloudstream3.base64Encode import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.APP_STRING import com.lagradost.cloudstream3.utils.AppContextUtils.splitQuery import java.net.URI @@ -179,9 +179,8 @@ abstract class AuthAPI { val secureRandom = SecureRandom() val codeVerifierBytes = ByteArray(96) // base64 has 6bit per char; (8/6)*96 = 128 secureRandom.nextBytes(codeVerifierBytes) - return Base64.encodeToString(codeVerifierBytes, Base64.DEFAULT).trimEnd('=') - .replace("+", "-") - .replace("/", "_").replace("\n", "") + return base64Encode(codeVerifierBytes).trimEnd('=') + .replace("+", "-").replace("/", "_").replace("\n", "") } }