From 6602d948a58c1b20233f8a359f3535d254c438e9 Mon Sep 17 00:00:00 2001 From: Ziedelth Date: Mon, 19 Oct 2026 15:17:27 +0200 Subject: [PATCH] Add changelog for Disney Plus configuration updates and access token management --- .../entities/enums/ConfigPropertyKey.kt | 3 +- .../factories/AbstractDisneyPlusWrapper.kt | 48 ++++++++++++++++++- .../db/changelog/2026/10/02-changelog.xml | 48 +++++++++++++++++++ .../db/changelog/db.changelog-master.xml | 1 + 4 files changed, 97 insertions(+), 3 deletions(-) create mode 100644 src/main/resources/db/changelog/2026/10/02-changelog.xml diff --git a/src/main/kotlin/fr/shikkanime/entities/enums/ConfigPropertyKey.kt b/src/main/kotlin/fr/shikkanime/entities/enums/ConfigPropertyKey.kt index e905a1c2..4c3b5442 100644 --- a/src/main/kotlin/fr/shikkanime/entities/enums/ConfigPropertyKey.kt +++ b/src/main/kotlin/fr/shikkanime/entities/enums/ConfigPropertyKey.kt @@ -21,7 +21,8 @@ enum class ConfigPropertyKey(val key: String) { CRUNCHYROLL_FETCH_API_SIZE("crunchyroll_fetch_api_size"), DISABLE_BOT_DETECTION("disable_bot_detection"), DISCORD_TOKEN("discord_token"), - DISNEY_PLUS_ACCESS_TOKEN("disney_plus_access_token"), + DISNEY_PLUS_AUTHORIZATION("disney_plus_authorization"), + DISNEY_PLUS_REFRESH_TOKEN("disney_plus_refresh_token"), EMAIL_HOST("email_host"), EMAIL_PASSWORD("email_password"), EMAIL_PORT("email_port"), diff --git a/src/main/kotlin/fr/shikkanime/wrappers/factories/AbstractDisneyPlusWrapper.kt b/src/main/kotlin/fr/shikkanime/wrappers/factories/AbstractDisneyPlusWrapper.kt index fcd8d7c4..916da38e 100644 --- a/src/main/kotlin/fr/shikkanime/wrappers/factories/AbstractDisneyPlusWrapper.kt +++ b/src/main/kotlin/fr/shikkanime/wrappers/factories/AbstractDisneyPlusWrapper.kt @@ -1,11 +1,22 @@ package fr.shikkanime.wrappers.factories +import com.google.gson.reflect.TypeToken +import fr.shikkanime.entities.Config import fr.shikkanime.entities.enums.ConfigPropertyKey +import fr.shikkanime.services.ConfigService import fr.shikkanime.services.caches.ConfigCacheService import fr.shikkanime.utils.Constant import fr.shikkanime.utils.HttpRequest +import fr.shikkanime.utils.MapCache +import fr.shikkanime.utils.MapCacheValue +import fr.shikkanime.utils.ObjectParser +import fr.shikkanime.utils.ObjectParser.getAsString +import fr.shikkanime.utils.StringUtils +import io.ktor.client.statement.bodyAsText import io.ktor.http.* +import kotlinx.coroutines.runBlocking import java.io.Serializable +import java.time.Duration abstract class AbstractDisneyPlusWrapper : IStreamingPlatformWrapper { data class Show( @@ -78,9 +89,42 @@ abstract class AbstractDisneyPlusWrapper : IStreamingPlatformWrapper, body: String) = post(url, headers = mapOf(HttpHeaders.Authorization to "Bearer ${configCacheService.getValueAsString(ConfigPropertyKey.DISNEY_PLUS_ACCESS_TOKEN)}").plus(headers), body = body) + @Synchronized + private fun getAccessToken() = MapCache.getOrCompute( + "AbstractDisneyPlusWrapper.getAccessToken", + duration = Duration.ofHours(2), + classes = listOf(Config::class.java), + typeToken = object : TypeToken>() {}, + key = StringUtils.EMPTY_STRING + ) { + runBlocking { + val refreshTokenConfig = configService.findByName(ConfigPropertyKey.DISNEY_PLUS_REFRESH_TOKEN.name) + if (refreshTokenConfig == null || refreshTokenConfig.propertyValue.isNullOrBlank()) + throw IllegalStateException("Disney Plus refresh token is not set") + + val response = HttpRequest.post( + "https://login.disney.com/token", + headers = mapOf( + HttpHeaders.ContentType to ContentType.Application.FormUrlEncoded.toString(), + "X-Dss-Client-Api-Key" to (configCacheService.getValueAsString(ConfigPropertyKey.DISNEY_PLUS_AUTHORIZATION) ?: StringUtils.EMPTY_STRING) + ), + body = "grant_type=refresh_token&client_id=DTCI-DISNEYPLUS.WEB&scope=openid streaming api:identity:user.write&refresh_token=${refreshTokenConfig.propertyValue}" + ) + require(response.status == HttpStatusCode.OK) { "Failed to get access token (${response.status.value})" } + val json = ObjectParser.fromJson(response.bodyAsText()) + + // Change refresh token + refreshTokenConfig.propertyValue = requireNotNull(json.getAsString("refresh_token")) { "Refresh token is null or empty"} + configService.update(refreshTokenConfig) + + requireNotNull(json.getAsString("access_token")) { "Access token is null or empty"} + } + } + + protected suspend fun HttpRequest.getWithAccessToken(url: String) = get(url, headers = mapOf(HttpHeaders.Authorization to "Bearer ${getAccessToken()}")) + protected suspend fun HttpRequest.postWithAccessToken(url: String, headers: Map, body: String) = post(url, headers = mapOf(HttpHeaders.Authorization to "Bearer ${getAccessToken()}").plus(headers), body = body) abstract suspend fun getLatestShowIds(): Array diff --git a/src/main/resources/db/changelog/2026/10/02-changelog.xml b/src/main/resources/db/changelog/2026/10/02-changelog.xml new file mode 100644 index 00000000..33758929 --- /dev/null +++ b/src/main/resources/db/changelog/2026/10/02-changelog.xml @@ -0,0 +1,48 @@ + + + + + + + + SELECT COUNT(*) + FROM config + WHERE property_key = 'disney_plus_access_token' + + + + property_key = 'disney_plus_access_token' + + + + + + SELECT COUNT(*) + FROM config + WHERE property_key = 'disney_plus_authorization' + + + + + + + + + + + + SELECT COUNT(*) + FROM config + WHERE property_key = 'disney_plus_refresh_token' + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/db/changelog/db.changelog-master.xml b/src/main/resources/db/changelog/db.changelog-master.xml index 443ae754..087722d6 100644 --- a/src/main/resources/db/changelog/db.changelog-master.xml +++ b/src/main/resources/db/changelog/db.changelog-master.xml @@ -147,4 +147,5 @@ + \ No newline at end of file