From 13e859d8b15351609116438cd5c656e7cf0b9b67 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Apr 2024 08:18:38 +0000 Subject: [PATCH 1/9] Bump org.bouncycastle:bcprov-jdk18on from 1.77 to 1.78 Bumps [org.bouncycastle:bcprov-jdk18on](https://github.com/bcgit/bc-java) from 1.77 to 1.78. - [Changelog](https://github.com/bcgit/bc-java/blob/main/docs/releasenotes.html) - [Commits](https://github.com/bcgit/bc-java/commits) --- updated-dependencies: - dependency-name: org.bouncycastle:bcprov-jdk18on dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index a636b476..3c8dc63c 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -15,7 +15,7 @@ val playwrightVersion = "1.42.0" val jsoupVersion = "1.17.2" val gsonVersion = "2.10.1" val openCvVersion = "4.9.0-0" -val bcprovVersion = "1.77" +val bcprovVersion = "1.78" val javaImageScalingVersion = "0.8.6" val firebaseVersion = "9.2.0" From f4f724b93dd06e47d8256e97d6cbac7d00a09821 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Apr 2024 08:18:43 +0000 Subject: [PATCH 2/9] Bump net.dv8tion:JDA from 5.0.0-beta.21 to 5.0.0-beta.22 Bumps [net.dv8tion:JDA](https://github.com/discord-jda/JDA) from 5.0.0-beta.21 to 5.0.0-beta.22. - [Release notes](https://github.com/discord-jda/JDA/releases) - [Commits](https://github.com/discord-jda/JDA/compare/v5.0.0-beta.21...v5.0.0-beta.22) --- updated-dependencies: - dependency-name: net.dv8tion:JDA dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 3c8dc63c..8b07e605 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -19,7 +19,7 @@ val bcprovVersion = "1.78" val javaImageScalingVersion = "0.8.6" val firebaseVersion = "9.2.0" -val jdaVersion = "5.0.0-beta.21" +val jdaVersion = "5.0.0-beta.22" val twitter4jVersion = "4.0.7" val twitter4jV2Version = "1.4.3" From 0db3bfc7583ead37cfbd83ac6f406d705bdee9e7 Mon Sep 17 00:00:00 2001 From: Ziedelth Date: Tue, 9 Apr 2024 10:37:50 +0200 Subject: [PATCH 3/9] Add group dependencies on dependabot.yml --- .github/dependabot.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 113b6b46..af9bc970 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -12,6 +12,10 @@ updates: - "Ziedelth" reviewers: - "Ziedelth" + groups: + ktor: + patterns: + - "*ktor*" - package-ecosystem: "github-actions" directory: "/" From 20b234dcc85eb54d41c5734a869e2f106c87f916 Mon Sep 17 00:00:00 2001 From: Ziedelth Date: Tue, 9 Apr 2024 10:32:59 +0200 Subject: [PATCH 4/9] Refactor Disney+ platform --- .../entities/enums/ConfigPropertyKey.kt | 2 + .../platforms/DisneyPlusPlatform.kt | 98 ++++++------------- .../configuration/DisneyPlusConfiguration.kt | 30 +----- .../shikkanime/wrappers/DisneyPlusWrapper.kt | 77 +++++++++++++++ .../db/changelog/2024/04/02-changelog.xml | 38 +++++++ .../db/changelog/db.changelog-master.xml | 1 + 6 files changed, 151 insertions(+), 95 deletions(-) create mode 100644 src/main/kotlin/fr/shikkanime/wrappers/DisneyPlusWrapper.kt create mode 100644 src/main/resources/db/changelog/2024/04/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 575116f9..c832b580 100644 --- a/src/main/kotlin/fr/shikkanime/entities/enums/ConfigPropertyKey.kt +++ b/src/main/kotlin/fr/shikkanime/entities/enums/ConfigPropertyKey.kt @@ -29,4 +29,6 @@ enum class ConfigPropertyKey(val key: String) { CRUNCHYROLL_FETCH_API_SIZE("crunchyroll_fetch_api_size"), ANIMATION_DITIGAL_NETWORK_SIMULCAST_DETECTION_REGEX("animation_digital_network_simulcast_detection_regex"), ANIME_EPISODES_SIZE_LIMIT("anime_episodes_size_limit"), + DISNEY_PLUS_AUTHORIZATION("disney_plus_authorization"), + DISNEY_PLUS_REFRESH_TOKEN("disney_plus_refresh_token"), } \ No newline at end of file diff --git a/src/main/kotlin/fr/shikkanime/platforms/DisneyPlusPlatform.kt b/src/main/kotlin/fr/shikkanime/platforms/DisneyPlusPlatform.kt index 2cee73d2..507ecb59 100644 --- a/src/main/kotlin/fr/shikkanime/platforms/DisneyPlusPlatform.kt +++ b/src/main/kotlin/fr/shikkanime/platforms/DisneyPlusPlatform.kt @@ -1,93 +1,59 @@ package fr.shikkanime.platforms -import com.google.gson.JsonArray import com.google.gson.JsonObject +import com.google.inject.Inject import fr.shikkanime.caches.CountryCodeDisneyPlusSimulcastKeyCache import fr.shikkanime.entities.Anime +import fr.shikkanime.entities.Config import fr.shikkanime.entities.Episode -import fr.shikkanime.entities.enums.CountryCode -import fr.shikkanime.entities.enums.EpisodeType -import fr.shikkanime.entities.enums.LangType -import fr.shikkanime.entities.enums.Platform +import fr.shikkanime.entities.enums.* import fr.shikkanime.exceptions.AnimeException import fr.shikkanime.platforms.configuration.DisneyPlusConfiguration -import fr.shikkanime.utils.* -import fr.shikkanime.utils.ObjectParser.getAsBoolean +import fr.shikkanime.services.caches.ConfigCacheService +import fr.shikkanime.utils.MapCache import fr.shikkanime.utils.ObjectParser.getAsInt import fr.shikkanime.utils.ObjectParser.getAsLong import fr.shikkanime.utils.ObjectParser.getAsString -import io.ktor.client.statement.* +import fr.shikkanime.utils.StringUtils +import fr.shikkanime.utils.isEqualOrAfter +import fr.shikkanime.utils.withUTC +import fr.shikkanime.wrappers.DisneyPlusWrapper +import kotlinx.coroutines.runBlocking import java.io.File +import java.time.Duration import java.time.LocalTime import java.time.ZonedDateTime import java.time.format.DateTimeFormatter import java.util.logging.Level class DisneyPlusPlatform : - AbstractPlatform() { + AbstractPlatform>() { + @Inject + private lateinit var configCacheService: ConfigCacheService + override fun getPlatform(): Platform = Platform.DISN override fun getConfigurationClass() = DisneyPlusConfiguration::class.java - override suspend fun fetchApiContent( - key: CountryCodeDisneyPlusSimulcastKeyCache, - zonedDateTime: ZonedDateTime - ): JsonArray { - check(configuration!!.authorization.isNotBlank()) { "Authorization is null" } - check(configuration!!.refreshToken.isNotBlank()) { "Refresh token is null" } - val httpRequest = HttpRequest() - - val loginDevice = httpRequest.post( - "https://disney.api.edge.bamgrid.com/graph/v1/device/graphql", - headers = mapOf( - "Authorization" to configuration!!.authorization, - ), - body = ObjectParser.toJson( - mapOf( - "operationName" to "refreshToken", - "query" to "mutation refreshToken(\$input:RefreshTokenInput!){refreshToken(refreshToken:\$input){activeSession{sessionId}}}", - "variables" to mapOf( - "input" to mapOf( - "refreshToken" to configuration!!.refreshToken - ) - ), - ) + private val identifiers = MapCache(Duration.ofHours(3).plusMinutes(30), listOf(Config::class.java)) { + return@MapCache runBlocking { + DisneyPlusWrapper.getAccessToken( + configCacheService.getValueAsString(ConfigPropertyKey.DISNEY_PLUS_AUTHORIZATION), + configCacheService.getValueAsString(ConfigPropertyKey.DISNEY_PLUS_REFRESH_TOKEN) ) - ) - - check(loginDevice.status.value == 200) { "Failed to login to Disney+" } - val loginDeviceJson = ObjectParser.fromJson(loginDevice.bodyAsText(), JsonObject::class.java) - val accessToken = loginDeviceJson.getAsJsonObject("extensions").getAsJsonObject("sdk").getAsJsonObject("token") - .getAsString("accessToken") - - val seasonsResponse = httpRequest.get( - "https://disney.content.edge.bamgrid.com/svc/content/DmcSeriesBundle/version/5.1/region/${key.countryCode.name}/audience/k-false,l-true/maturity/1850/language/${key.countryCode.locale}/encodedSeriesId/${key.disneyPlusSimulcast.name}", - mapOf("Authorization" to "Bearer $accessToken") - ) - check(seasonsResponse.status.value == 200) { "Failed to fetch Disney+ content" } - val seasonsJson = ObjectParser.fromJson(seasonsResponse.bodyAsText(), JsonObject::class.java) - val seasons = seasonsJson.getAsJsonObject("data").getAsJsonObject("DmcSeriesBundle").getAsJsonObject("seasons") - .getAsJsonArray("seasons").mapNotNull { it.asJsonObject.getAsString("seasonId") } - val episodes = JsonArray() - - seasons.forEach { season -> - var page = 1 - var hasMore: Boolean - - do { - val url = - "https://disney.content.edge.bamgrid.com/svc/content/DmcEpisodes/version/5.1/region/${key.countryCode.name}/audience/k-false,l-true/maturity/1850/language/${key.countryCode.locale}/seasonId/${season}/pageSize/15/page/${page++}" - val response = httpRequest.get(url, mapOf("Authorization" to "Bearer $accessToken")) - check(response.status.value == 200) { "Failed to fetch Disney+ content" } - val json = ObjectParser.fromJson(response.bodyAsText(), JsonObject::class.java) - - val dmcEpisodesMeta = json.getAsJsonObject("data").getAsJsonObject("DmcEpisodes") - hasMore = dmcEpisodesMeta.getAsJsonObject("meta").getAsBoolean("hasMore") ?: false - dmcEpisodesMeta.getAsJsonArray("videos").forEach { episodes.add(it) } - } while (hasMore) } + } + + private val seasons = MapCache>(Duration.ofDays(1)) { + val accessToken = identifiers[it.countryCode]!! + return@MapCache runBlocking { DisneyPlusWrapper.getSeasons(accessToken, it.countryCode, it.disneyPlusSimulcast.name) } + } - return episodes + override suspend fun fetchApiContent( + key: CountryCodeDisneyPlusSimulcastKeyCache, + zonedDateTime: ZonedDateTime + ) = this.seasons[key]!!.flatMap { season -> + DisneyPlusWrapper.getEpisodes(identifiers[key.countryCode]!!, key.countryCode, season) } override fun fetchEpisodes(zonedDateTime: ZonedDateTime, bypassFileContent: File?): List { @@ -102,7 +68,7 @@ class DisneyPlusPlatform : api.forEach { try { - list.add(convertEpisode(countryCode, simulcast, it.asJsonObject, zonedDateTime)) + list.add(convertEpisode(countryCode, simulcast, it, zonedDateTime)) } catch (_: AnimeException) { // Ignore } catch (e: Exception) { diff --git a/src/main/kotlin/fr/shikkanime/platforms/configuration/DisneyPlusConfiguration.kt b/src/main/kotlin/fr/shikkanime/platforms/configuration/DisneyPlusConfiguration.kt index eb23d825..ffe5850e 100644 --- a/src/main/kotlin/fr/shikkanime/platforms/configuration/DisneyPlusConfiguration.kt +++ b/src/main/kotlin/fr/shikkanime/platforms/configuration/DisneyPlusConfiguration.kt @@ -2,10 +2,7 @@ package fr.shikkanime.platforms.configuration import io.ktor.http.* -data class DisneyPlusConfiguration( - var authorization: String = "", - var refreshToken: String = "", -) : PlatformConfiguration() { +class DisneyPlusConfiguration : PlatformConfiguration() { data class DisneyPlusSimulcast( var releaseDay: Int = 1, var releaseTime: String = "", @@ -57,29 +54,4 @@ data class DisneyPlusConfiguration( } override fun newPlatformSimulcast() = DisneyPlusSimulcast() - - override fun of(parameters: Parameters) { - super.of(parameters) - parameters["authorization"]?.let { authorization = it } - parameters["refreshToken"]?.let { refreshToken = it } - } - - override fun toConfigurationFields() = super.toConfigurationFields().apply { - add( - ConfigurationField( - label = "Authorization", - name = "authorization", - type = "text", - value = authorization - ) - ) - add( - ConfigurationField( - label = "Refresh token", - name = "refreshToken", - type = "text", - value = refreshToken - ) - ) - } } \ No newline at end of file diff --git a/src/main/kotlin/fr/shikkanime/wrappers/DisneyPlusWrapper.kt b/src/main/kotlin/fr/shikkanime/wrappers/DisneyPlusWrapper.kt new file mode 100644 index 00000000..cb42704d --- /dev/null +++ b/src/main/kotlin/fr/shikkanime/wrappers/DisneyPlusWrapper.kt @@ -0,0 +1,77 @@ +package fr.shikkanime.wrappers + +import com.google.gson.JsonObject +import fr.shikkanime.entities.enums.CountryCode +import fr.shikkanime.utils.HttpRequest +import fr.shikkanime.utils.ObjectParser +import fr.shikkanime.utils.ObjectParser.getAsBoolean +import fr.shikkanime.utils.ObjectParser.getAsString +import io.ktor.client.statement.* + +object DisneyPlusWrapper { + private const val BASE_URL = "https://disney.api.edge.bamgrid.com" + + suspend fun getAccessToken(authorization: String?, refreshToken: String?): String { + require(!authorization.isNullOrBlank() && !refreshToken.isNullOrBlank()) { "Missing Disney+ authorization or refresh token" } + + val loginDevice = HttpRequest().post( + "$BASE_URL/graph/v1/device/graphql", + headers = mapOf( + "Authorization" to authorization, + ), + body = ObjectParser.toJson( + mapOf( + "operationName" to "refreshToken", + "query" to "mutation refreshToken(\$input:RefreshTokenInput!){refreshToken(refreshToken:\$input){activeSession{sessionId}}}", + "variables" to mapOf( + "input" to mapOf( + "refreshToken" to refreshToken + ) + ), + ) + ) + ) + + require(loginDevice.status.value == 200) { "Failed to login to Disney+" } + val loginDeviceJson = ObjectParser.fromJson(loginDevice.bodyAsText(), JsonObject::class.java) + return loginDeviceJson.getAsJsonObject("extensions") + .getAsJsonObject("sdk") + .getAsJsonObject("token") + .getAsString("accessToken")!! + } + + suspend fun getSeasons(accessToken: String, countryCode: CountryCode, id: String): List { + val seasonsResponse = HttpRequest().get( + "${BASE_URL}/svc/content/DmcSeriesBundle/version/5.1/region/${countryCode.name}/audience/k-false,l-true/maturity/1850/language/${countryCode.locale}/encodedSeriesId/$id", + mapOf("Authorization" to "Bearer $accessToken") + ) + + require(seasonsResponse.status.value == 200) { "Failed to fetch Disney+ content" } + val seasonsJson = ObjectParser.fromJson(seasonsResponse.bodyAsText(), JsonObject::class.java) + return seasonsJson.getAsJsonObject("data") + .getAsJsonObject("DmcSeriesBundle") + .getAsJsonObject("seasons") + .getAsJsonArray("seasons") + .mapNotNull { it.asJsonObject.getAsString("seasonId") } + } + + suspend fun getEpisodes(accessToken: String, countryCode: CountryCode, seasonId: String): List { + val episodes = mutableListOf() + var page = 1 + var hasMore: Boolean + + do { + val url = + "${BASE_URL}/svc/content/DmcEpisodes/version/5.1/region/${countryCode.name}/audience/k-false,l-true/maturity/1850/language/${countryCode.locale}/seasonId/$seasonId/pageSize/15/page/${page++}" + val response = HttpRequest().get(url, mapOf("Authorization" to "Bearer $accessToken")) + require(response.status.value == 200) { "Failed to fetch Disney+ content" } + val json = ObjectParser.fromJson(response.bodyAsText(), JsonObject::class.java) + + val dmcEpisodesMeta = json.getAsJsonObject("data").getAsJsonObject("DmcEpisodes") + hasMore = dmcEpisodesMeta.getAsJsonObject("meta").getAsBoolean("hasMore") ?: false + dmcEpisodesMeta.getAsJsonArray("videos").forEach { episodes.add(it.asJsonObject) } + } while (hasMore) + + return episodes + } +} \ No newline at end of file diff --git a/src/main/resources/db/changelog/2024/04/02-changelog.xml b/src/main/resources/db/changelog/2024/04/02-changelog.xml new file mode 100644 index 00000000..bc6381f2 --- /dev/null +++ b/src/main/resources/db/changelog/2024/04/02-changelog.xml @@ -0,0 +1,38 @@ + + + + + + + + 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 75c2b01b..03b1331d 100644 --- a/src/main/resources/db/changelog/db.changelog-master.xml +++ b/src/main/resources/db/changelog/db.changelog-master.xml @@ -40,4 +40,5 @@ + \ No newline at end of file From c771cd5ba032cb4dbc6bf5e418a1062c43c75ef5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Apr 2024 08:33:47 +0000 Subject: [PATCH 5/9] Bump ktorVersion from 2.3.9 to 2.3.10 Bumps `ktorVersion` from 2.3.9 to 2.3.10. Updates `io.ktor:ktor-server-core-jvm` from 2.3.9 to 2.3.10 - [Release notes](https://github.com/ktorio/ktor/releases) - [Changelog](https://github.com/ktorio/ktor/blob/2.3.10/CHANGELOG.md) - [Commits](https://github.com/ktorio/ktor/compare/2.3.9...2.3.10) Updates `io.ktor:ktor-server-auth-jvm` from 2.3.9 to 2.3.10 - [Release notes](https://github.com/ktorio/ktor/releases) - [Changelog](https://github.com/ktorio/ktor/blob/2.3.10/CHANGELOG.md) - [Commits](https://github.com/ktorio/ktor/compare/2.3.9...2.3.10) Updates `io.ktor:ktor-server-auth-jwt-jvm` from 2.3.9 to 2.3.10 - [Release notes](https://github.com/ktorio/ktor/releases) - [Changelog](https://github.com/ktorio/ktor/blob/2.3.10/CHANGELOG.md) - [Commits](https://github.com/ktorio/ktor/compare/2.3.9...2.3.10) Updates `io.ktor:ktor-server-sessions` from 2.3.9 to 2.3.10 - [Release notes](https://github.com/ktorio/ktor/releases) - [Changelog](https://github.com/ktorio/ktor/blob/2.3.10/CHANGELOG.md) - [Commits](https://github.com/ktorio/ktor/compare/2.3.9...2.3.10) Updates `io.ktor:ktor-server-sessions-jvm` from 2.3.9 to 2.3.10 - [Release notes](https://github.com/ktorio/ktor/releases) - [Changelog](https://github.com/ktorio/ktor/blob/2.3.10/CHANGELOG.md) - [Commits](https://github.com/ktorio/ktor/compare/2.3.9...2.3.10) Updates `io.ktor:ktor-server-host-common-jvm` from 2.3.9 to 2.3.10 - [Release notes](https://github.com/ktorio/ktor/releases) - [Changelog](https://github.com/ktorio/ktor/blob/2.3.10/CHANGELOG.md) - [Commits](https://github.com/ktorio/ktor/compare/2.3.9...2.3.10) Updates `io.ktor:ktor-server-status-pages-jvm` from 2.3.9 to 2.3.10 - [Release notes](https://github.com/ktorio/ktor/releases) - [Changelog](https://github.com/ktorio/ktor/blob/2.3.10/CHANGELOG.md) - [Commits](https://github.com/ktorio/ktor/compare/2.3.9...2.3.10) Updates `io.ktor:ktor-server-caching-headers-jvm` from 2.3.9 to 2.3.10 - [Release notes](https://github.com/ktorio/ktor/releases) - [Changelog](https://github.com/ktorio/ktor/blob/2.3.10/CHANGELOG.md) - [Commits](https://github.com/ktorio/ktor/compare/2.3.9...2.3.10) Updates `io.ktor:ktor-server-compression-jvm` from 2.3.9 to 2.3.10 - [Release notes](https://github.com/ktorio/ktor/releases) - [Changelog](https://github.com/ktorio/ktor/blob/2.3.10/CHANGELOG.md) - [Commits](https://github.com/ktorio/ktor/compare/2.3.9...2.3.10) Updates `io.ktor:ktor-server-cors-jvm` from 2.3.9 to 2.3.10 - [Release notes](https://github.com/ktorio/ktor/releases) - [Changelog](https://github.com/ktorio/ktor/blob/2.3.10/CHANGELOG.md) - [Commits](https://github.com/ktorio/ktor/compare/2.3.9...2.3.10) Updates `io.ktor:ktor-server-content-negotiation-jvm` from 2.3.9 to 2.3.10 - [Release notes](https://github.com/ktorio/ktor/releases) - [Changelog](https://github.com/ktorio/ktor/blob/2.3.10/CHANGELOG.md) - [Commits](https://github.com/ktorio/ktor/compare/2.3.9...2.3.10) Updates `io.ktor:ktor-serialization-gson` from 2.3.9 to 2.3.10 - [Release notes](https://github.com/ktorio/ktor/releases) - [Changelog](https://github.com/ktorio/ktor/blob/2.3.10/CHANGELOG.md) - [Commits](https://github.com/ktorio/ktor/compare/2.3.9...2.3.10) Updates `io.ktor:ktor-server-freemarker-jvm` from 2.3.9 to 2.3.10 - [Release notes](https://github.com/ktorio/ktor/releases) - [Changelog](https://github.com/ktorio/ktor/blob/2.3.10/CHANGELOG.md) - [Commits](https://github.com/ktorio/ktor/compare/2.3.9...2.3.10) Updates `io.ktor:ktor-server-netty` from 2.3.9 to 2.3.10 - [Release notes](https://github.com/ktorio/ktor/releases) - [Changelog](https://github.com/ktorio/ktor/blob/2.3.10/CHANGELOG.md) - [Commits](https://github.com/ktorio/ktor/compare/2.3.9...2.3.10) Updates `io.ktor:ktor-client-core` from 2.3.9 to 2.3.10 - [Release notes](https://github.com/ktorio/ktor/releases) - [Changelog](https://github.com/ktorio/ktor/blob/2.3.10/CHANGELOG.md) - [Commits](https://github.com/ktorio/ktor/compare/2.3.9...2.3.10) Updates `io.ktor:ktor-client-okhttp` from 2.3.9 to 2.3.10 - [Release notes](https://github.com/ktorio/ktor/releases) - [Changelog](https://github.com/ktorio/ktor/blob/2.3.10/CHANGELOG.md) - [Commits](https://github.com/ktorio/ktor/compare/2.3.9...2.3.10) Updates `io.ktor:ktor-client-okhttp-jvm` from 2.3.9 to 2.3.10 - [Release notes](https://github.com/ktorio/ktor/releases) - [Changelog](https://github.com/ktorio/ktor/blob/2.3.10/CHANGELOG.md) - [Commits](https://github.com/ktorio/ktor/compare/2.3.9...2.3.10) Updates `io.ktor:ktor-server-tests-jvm` from 2.3.9 to 2.3.10 - [Release notes](https://github.com/ktorio/ktor/releases) - [Changelog](https://github.com/ktorio/ktor/blob/2.3.10/CHANGELOG.md) - [Commits](https://github.com/ktorio/ktor/compare/2.3.9...2.3.10) Updates `io.ktor:ktor-client-mock` from 2.3.9 to 2.3.10 - [Release notes](https://github.com/ktorio/ktor/releases) - [Changelog](https://github.com/ktorio/ktor/blob/2.3.10/CHANGELOG.md) - [Commits](https://github.com/ktorio/ktor/compare/2.3.9...2.3.10) --- updated-dependencies: - dependency-name: io.ktor:ktor-server-core-jvm dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.ktor:ktor-server-auth-jvm dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.ktor:ktor-server-auth-jwt-jvm dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.ktor:ktor-server-sessions dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.ktor:ktor-server-sessions-jvm dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.ktor:ktor-server-host-common-jvm dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.ktor:ktor-server-status-pages-jvm dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.ktor:ktor-server-caching-headers-jvm dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.ktor:ktor-server-compression-jvm dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.ktor:ktor-server-cors-jvm dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.ktor:ktor-server-content-negotiation-jvm dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.ktor:ktor-serialization-gson dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.ktor:ktor-server-freemarker-jvm dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.ktor:ktor-server-netty dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.ktor:ktor-client-core dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.ktor:ktor-client-okhttp dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.ktor:ktor-client-okhttp-jvm dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.ktor:ktor-server-tests-jvm dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.ktor:ktor-client-mock dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 8b07e605..bb92baba 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,4 +1,4 @@ -val ktorVersion = "2.3.9" +val ktorVersion = "2.3.10" val ktorSwaggerUiVersion = "2.8.0" val hibernateCoreVersion = "6.4.4.Final" val ehcacheVersion = "3.10.8" From 9e0bfe45740d726c7ce4205d78e38eb60e57ff86 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Apr 2024 08:34:12 +0000 Subject: [PATCH 6/9] Bump io.ktor.plugin from 2.3.9 to 2.3.10 Bumps io.ktor.plugin from 2.3.9 to 2.3.10. --- updated-dependencies: - dependency-name: io.ktor.plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index bb92baba..fe892299 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -29,7 +29,7 @@ val h2Version = "2.2.224" plugins { kotlin("jvm") version "2.0.0-Beta5" kotlin("kapt") version "1.9.23" - id("io.ktor.plugin") version "2.3.9" + id("io.ktor.plugin") version "2.3.10" jacoco id("org.sonarqube") version "5.0.0.4638" } From 96e61689aaa75f3132fe6f0452133d865703cba1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Apr 2024 08:35:38 +0000 Subject: [PATCH 7/9] Bump jvm from 2.0.0-Beta5 to 2.0.0-RC1 Bumps [jvm](https://github.com/JetBrains/kotlin) from 2.0.0-Beta5 to 2.0.0-RC1. - [Release notes](https://github.com/JetBrains/kotlin/releases) - [Changelog](https://github.com/JetBrains/kotlin/blob/master/ChangeLog.md) - [Commits](https://github.com/JetBrains/kotlin/commits) --- updated-dependencies: - dependency-name: jvm dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index fe892299..6fa7cca2 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -27,7 +27,7 @@ val junitVersion = "5.10.2" val h2Version = "2.2.224" plugins { - kotlin("jvm") version "2.0.0-Beta5" + kotlin("jvm") version "2.0.0-RC1" kotlin("kapt") version "1.9.23" id("io.ktor.plugin") version "2.3.10" jacoco From 2661286f8b905bb86d642c35a3d026ab3e8437fa Mon Sep 17 00:00:00 2001 From: Ziedelth Date: Tue, 9 Apr 2024 11:12:24 +0200 Subject: [PATCH 8/9] Fix Disney+ URLs --- .../kotlin/fr/shikkanime/wrappers/DisneyPlusWrapper.kt | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/main/kotlin/fr/shikkanime/wrappers/DisneyPlusWrapper.kt b/src/main/kotlin/fr/shikkanime/wrappers/DisneyPlusWrapper.kt index cb42704d..faab94d7 100644 --- a/src/main/kotlin/fr/shikkanime/wrappers/DisneyPlusWrapper.kt +++ b/src/main/kotlin/fr/shikkanime/wrappers/DisneyPlusWrapper.kt @@ -9,13 +9,11 @@ import fr.shikkanime.utils.ObjectParser.getAsString import io.ktor.client.statement.* object DisneyPlusWrapper { - private const val BASE_URL = "https://disney.api.edge.bamgrid.com" - suspend fun getAccessToken(authorization: String?, refreshToken: String?): String { require(!authorization.isNullOrBlank() && !refreshToken.isNullOrBlank()) { "Missing Disney+ authorization or refresh token" } val loginDevice = HttpRequest().post( - "$BASE_URL/graph/v1/device/graphql", + "https://disney.api.edge.bamgrid.com/graph/v1/device/graphql", headers = mapOf( "Authorization" to authorization, ), @@ -42,7 +40,7 @@ object DisneyPlusWrapper { suspend fun getSeasons(accessToken: String, countryCode: CountryCode, id: String): List { val seasonsResponse = HttpRequest().get( - "${BASE_URL}/svc/content/DmcSeriesBundle/version/5.1/region/${countryCode.name}/audience/k-false,l-true/maturity/1850/language/${countryCode.locale}/encodedSeriesId/$id", + "https://disney.content.edge.bamgrid.com/svc/content/DmcSeriesBundle/version/5.1/region/${countryCode.name}/audience/k-false,l-true/maturity/1850/language/${countryCode.locale}/encodedSeriesId/$id", mapOf("Authorization" to "Bearer $accessToken") ) @@ -62,7 +60,7 @@ object DisneyPlusWrapper { do { val url = - "${BASE_URL}/svc/content/DmcEpisodes/version/5.1/region/${countryCode.name}/audience/k-false,l-true/maturity/1850/language/${countryCode.locale}/seasonId/$seasonId/pageSize/15/page/${page++}" + "https://disney.content.edge.bamgrid.com/svc/content/DmcEpisodes/version/5.1/region/${countryCode.name}/audience/k-false,l-true/maturity/1850/language/${countryCode.locale}/seasonId/$seasonId/pageSize/15/page/${page++}" val response = HttpRequest().get(url, mapOf("Authorization" to "Bearer $accessToken")) require(response.status.value == 200) { "Failed to fetch Disney+ content" } val json = ObjectParser.fromJson(response.bodyAsText(), JsonObject::class.java) From 7479e0647ff6367edbff0815fe9bce8c6ce84ebd Mon Sep 17 00:00:00 2001 From: Ziedelth Date: Tue, 9 Apr 2024 11:40:24 +0200 Subject: [PATCH 9/9] Add global hash method and migrate old crunchyroll hash --- src/main/kotlin/fr/shikkanime/Application.kt | 18 +++------------- .../jobs/FetchDeprecatedEpisodeJob.kt | 11 ++++++++++ .../AnimationDigitalNetworkPlatform.kt | 2 +- .../platforms/CrunchyrollPlatform.kt | 21 +++---------------- .../platforms/DisneyPlusPlatform.kt | 2 +- .../shikkanime/platforms/NetflixPlatform.kt | 7 +++---- .../platforms/PrimeVideoPlatform.kt | 2 +- .../kotlin/fr/shikkanime/utils/StringUtils.kt | 4 ++++ .../shikkanime/wrappers/PrimeVideoWrapper.kt | 8 +------ .../jobs/FetchDeprecatedEpisodeJobTest.kt | 4 ++-- 10 files changed, 30 insertions(+), 49 deletions(-) diff --git a/src/main/kotlin/fr/shikkanime/Application.kt b/src/main/kotlin/fr/shikkanime/Application.kt index 415f8c8e..dc8aab8f 100644 --- a/src/main/kotlin/fr/shikkanime/Application.kt +++ b/src/main/kotlin/fr/shikkanime/Application.kt @@ -10,7 +10,6 @@ import fr.shikkanime.services.MemberService import fr.shikkanime.utils.Constant import fr.shikkanime.utils.JobManager import fr.shikkanime.utils.LoggerFactory -import fr.shikkanime.utils.StringUtils import io.ktor.server.application.* import io.ktor.server.engine.* import io.ktor.server.netty.* @@ -24,7 +23,10 @@ fun main() { } fun initAll(adminPassword: AtomicReference?, port: Int = 37100, wait: Boolean = true): NettyApplicationEngine { + Constant.injector.getInstance(AnimeService::class.java).preIndex() + ImageService.loadCache() + ImageService.addAll() if (adminPassword != null) { val memberService = Constant.injector.getInstance(MemberService::class.java) @@ -36,20 +38,6 @@ fun initAll(adminPassword: AtomicReference?, port: Int = 37100, wait: Bo } } - val animeService = Constant.injector.getInstance(AnimeService::class.java) - animeService.preIndex() - - animeService.findAll().forEach { - val toSlug = StringUtils.toSlug(StringUtils.getShortName(it.name!!)) - - if (it.slug != toSlug) { - it.slug = toSlug - animeService.update(it) - } - } - - ImageService.addAll() - logger.info("Starting jobs...") // Every 10 seconds JobManager.scheduleJob("*/10 * * * * ?", MetricJob::class.java) diff --git a/src/main/kotlin/fr/shikkanime/jobs/FetchDeprecatedEpisodeJob.kt b/src/main/kotlin/fr/shikkanime/jobs/FetchDeprecatedEpisodeJob.kt index 72678547..a7f1548f 100644 --- a/src/main/kotlin/fr/shikkanime/jobs/FetchDeprecatedEpisodeJob.kt +++ b/src/main/kotlin/fr/shikkanime/jobs/FetchDeprecatedEpisodeJob.kt @@ -13,6 +13,7 @@ import fr.shikkanime.utils.LoggerFactory import fr.shikkanime.utils.MapCache import fr.shikkanime.utils.ObjectParser.getAsInt import fr.shikkanime.utils.ObjectParser.getAsString +import fr.shikkanime.utils.StringUtils import fr.shikkanime.utils.withUTC import fr.shikkanime.wrappers.AnimationDigitalNetworkWrapper import fr.shikkanime.wrappers.CrunchyrollWrapper @@ -126,6 +127,16 @@ class FetchDeprecatedEpisodeJob : AbstractJob { needUpdate = true } + if (episode.platform == Platform.CRUN) { + val id = getCrunchyrollEpisodeId(episode.url!!) ?: return false + val hash = StringUtils.getHash(episode.anime!!.countryCode!!, episode.platform!!, id, episode.langType!!) + + if (hash != episode.hash) { + episode.hash = hash + needUpdate = true + } + } + episode.lastUpdateDateTime = now episodeService.update(episode) } catch (e: Exception) { diff --git a/src/main/kotlin/fr/shikkanime/platforms/AnimationDigitalNetworkPlatform.kt b/src/main/kotlin/fr/shikkanime/platforms/AnimationDigitalNetworkPlatform.kt index 9fbc99ca..10622fcd 100644 --- a/src/main/kotlin/fr/shikkanime/platforms/AnimationDigitalNetworkPlatform.kt +++ b/src/main/kotlin/fr/shikkanime/platforms/AnimationDigitalNetworkPlatform.kt @@ -162,7 +162,7 @@ class AnimationDigitalNetworkPlatform : ), episodeType = episodeType, langType = langType, - hash = "${countryCode}-${getPlatform()}-$id-$langType", + hash = StringUtils.getHash(countryCode, getPlatform(), id.toString(), langType), releaseDateTime = releaseDate, season = season, number = number, diff --git a/src/main/kotlin/fr/shikkanime/platforms/CrunchyrollPlatform.kt b/src/main/kotlin/fr/shikkanime/platforms/CrunchyrollPlatform.kt index 0c22c847..68ce53e9 100644 --- a/src/main/kotlin/fr/shikkanime/platforms/CrunchyrollPlatform.kt +++ b/src/main/kotlin/fr/shikkanime/platforms/CrunchyrollPlatform.kt @@ -170,7 +170,9 @@ class CrunchyrollPlatform : AbstractPlatform { - // @DEPRECATED - val externalId = jsonObject.getAsString("external_id")?.split(".")?.last() ?: "" - val deprecatedHash = "${countryCode}-${getPlatform()}-$externalId-$langType" - if (hashCache.contains(deprecatedHash)) throw EpisodeAlreadyReleasedException() - // @DEPRECATED - - val id = requireNotNull(jsonObject.getAsString("id")) { "Id is null" } - val hash = "${countryCode}-${getPlatform()}-$id-$langType" - if (hashCache.contains(hash)) throw EpisodeAlreadyReleasedException() - return Pair(id, hash) - } } \ No newline at end of file diff --git a/src/main/kotlin/fr/shikkanime/platforms/DisneyPlusPlatform.kt b/src/main/kotlin/fr/shikkanime/platforms/DisneyPlusPlatform.kt index 507ecb59..5bd60ebb 100644 --- a/src/main/kotlin/fr/shikkanime/platforms/DisneyPlusPlatform.kt +++ b/src/main/kotlin/fr/shikkanime/platforms/DisneyPlusPlatform.kt @@ -144,7 +144,7 @@ class DisneyPlusPlatform : ), episodeType = EpisodeType.EPISODE, langType = langType, - hash = "${countryCode}-${getPlatform()}-$id-$langType", + hash = StringUtils.getHash(countryCode, getPlatform(), id.toString(), langType), releaseDateTime = releaseDateTime, season = season, number = number, diff --git a/src/main/kotlin/fr/shikkanime/platforms/NetflixPlatform.kt b/src/main/kotlin/fr/shikkanime/platforms/NetflixPlatform.kt index 2faf958d..025c2b77 100644 --- a/src/main/kotlin/fr/shikkanime/platforms/NetflixPlatform.kt +++ b/src/main/kotlin/fr/shikkanime/platforms/NetflixPlatform.kt @@ -46,6 +46,7 @@ class NetflixPlatform : AbstractPlatform") .replace(""", "\"") + + fun getHash(countryCode: CountryCode, platform: Platform, id: String, langType: LangType) = "${countryCode}-${platform}-$id-$langType" } \ No newline at end of file diff --git a/src/main/kotlin/fr/shikkanime/wrappers/PrimeVideoWrapper.kt b/src/main/kotlin/fr/shikkanime/wrappers/PrimeVideoWrapper.kt index e30dbe30..d85fc6f2 100644 --- a/src/main/kotlin/fr/shikkanime/wrappers/PrimeVideoWrapper.kt +++ b/src/main/kotlin/fr/shikkanime/wrappers/PrimeVideoWrapper.kt @@ -1,14 +1,10 @@ package fr.shikkanime.wrappers import com.google.gson.JsonObject -import fr.shikkanime.entities.enums.LangType -import fr.shikkanime.entities.enums.Platform import fr.shikkanime.utils.EncryptionManager import fr.shikkanime.utils.HttpRequest object PrimeVideoWrapper { - private val platform = Platform.PRIM - fun getShowVideos(countryCode: String, locale: String, id: String): List { val document = HttpRequest().use { it.getBrowser("https://www.primevideo.com/-/${countryCode.lowercase()}/detail/$id?language=$locale") } @@ -36,9 +32,7 @@ object PrimeVideoWrapper { }) addProperty( "id", - "${countryCode}-$platform-${ - EncryptionManager.toSHA512("$id-${season}-$episodeNumber").substring(0..<8) - }-${LangType.SUBTITLES}" + EncryptionManager.toSHA512("$id-${season}-$episodeNumber").substring(0..<8) ) addProperty("season", season) addProperty("number", episodeNumber) diff --git a/src/test/kotlin/fr/shikkanime/jobs/FetchDeprecatedEpisodeJobTest.kt b/src/test/kotlin/fr/shikkanime/jobs/FetchDeprecatedEpisodeJobTest.kt index 9efecb50..4ae1ab6d 100644 --- a/src/test/kotlin/fr/shikkanime/jobs/FetchDeprecatedEpisodeJobTest.kt +++ b/src/test/kotlin/fr/shikkanime/jobs/FetchDeprecatedEpisodeJobTest.kt @@ -170,7 +170,7 @@ class FetchDeprecatedEpisodeJobTest { ) } - val content1 = list.first { it.getAsString("id") == "FR-PRIM-467dd829-SUBTITLES" } + val content1 = list.first { it.getAsString("id") == "467dd829" } assertEquals( "https://m.media-amazon.com/images/S/pv-target-images/3be1307dd8c3e901ca1b97c0f50142657aaa9db169ddb98c899dc8a2b1bcdaa4._AC_SX720_FMjpg_.jpg", fetchDeprecatedEpisodeJob.normalizeImage(Platform.PRIM, content1) @@ -186,7 +186,7 @@ class FetchDeprecatedEpisodeJobTest { fetchDeprecatedEpisodeJob.normalizeDescription(Platform.PRIM, content1) ) - val content2 = list.first { it.getAsString("id") == "FR-PRIM-de79b9d1-SUBTITLES" } + val content2 = list.first { it.getAsString("id") == "de79b9d1" } assertEquals( "https://m.media-amazon.com/images/S/pv-target-images/57471c2ecc25e001050ae0a12acbfa12c3ee4da88eb7d1d142749434c4500596._AC_SX720_FMjpg_.jpg",