Skip to content

Commit

Permalink
Change DisneyPlusWrapper to use current api
Browse files Browse the repository at this point in the history
  • Loading branch information
Ziedelth committed Jun 21, 2024
1 parent 95c9ec9 commit 111013b
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 65 deletions.
93 changes: 42 additions & 51 deletions src/main/kotlin/fr/shikkanime/platforms/DisneyPlusPlatform.kt
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import java.time.format.DateTimeFormatter
import java.util.logging.Level

class DisneyPlusPlatform :
AbstractPlatform<DisneyPlusConfiguration, CountryCodeDisneyPlusSimulcastKeyCache, List<JsonObject>>() {
AbstractPlatform<DisneyPlusConfiguration, CountryCodeDisneyPlusSimulcastKeyCache, Pair<JsonObject, List<JsonObject>>>() {
@Inject
private lateinit var configCacheService: ConfigCacheService

Expand All @@ -45,22 +45,17 @@ class DisneyPlusPlatform :
}
}

private val seasons = MapCache<CountryCodeDisneyPlusSimulcastKeyCache, List<String>>(Duration.ofDays(1)) {
val accessToken = identifiers[it.countryCode]!!
return@MapCache runBlocking {
DisneyPlusWrapper.getSeasons(
accessToken,
it.countryCode,
it.disneyPlusSimulcast.name
)
}
}

override suspend fun fetchApiContent(
key: CountryCodeDisneyPlusSimulcastKeyCache,
zonedDateTime: ZonedDateTime
) = this.seasons[key]!!.flatMap { season ->
DisneyPlusWrapper.getEpisodes(identifiers[key.countryCode]!!, key.countryCode, season)
): Pair<JsonObject, List<JsonObject>> {
val accessToken = identifiers[key.countryCode]!!
val (animeDetails, seasons) = DisneyPlusWrapper.getAnimeDetailsWithSeasons(
accessToken,
key.disneyPlusSimulcast.name
)
val episodes = seasons.flatMap { DisneyPlusWrapper.getEpisodes(accessToken, it) }
return animeDetails to episodes
}

override fun fetchEpisodes(zonedDateTime: ZonedDateTime, bypassFileContent: File?): List<Episode> {
Expand All @@ -71,11 +66,16 @@ class DisneyPlusPlatform :
it.releaseDay == zonedDateTime.dayOfWeek.value && zonedDateTime.toLocalTime()
.isEqualOrAfter(LocalTime.parse(it.releaseTime))
}.forEach { simulcast ->
val api = getApiContent(CountryCodeDisneyPlusSimulcastKeyCache(countryCode, simulcast), zonedDateTime)
val (animeDetails, episodes) = getApiContent(
CountryCodeDisneyPlusSimulcastKeyCache(
countryCode,
simulcast
), zonedDateTime
)

api.forEach {
episodes.forEach {
try {
list.add(convertEpisode(countryCode, simulcast, it, zonedDateTime))
list.add(convertEpisode(countryCode, simulcast, animeDetails, it, zonedDateTime))
} catch (_: AnimeException) {
// Ignore
} catch (e: Exception) {
Expand All @@ -91,49 +91,40 @@ class DisneyPlusPlatform :
private fun convertEpisode(
countryCode: CountryCode,
simulcast: DisneyPlusConfiguration.DisneyPlusSimulcast,
animeDetails: JsonObject,
jsonObject: JsonObject,
zonedDateTime: ZonedDateTime
): Episode {
val texts = jsonObject.getAsJsonObject("text")
val titles = texts?.getAsJsonObject("title")?.getAsJsonObject("full")
val descriptions = texts.getAsJsonObject("description")?.getAsJsonObject("medium")
val animeName = titles?.getAsJsonObject("series")?.getAsJsonObject("default")?.getAsString("content")
?: throw Exception("Anime name is null")

val animeImage = jsonObject.getAsJsonObject("image")?.getAsJsonObject("tile")?.getAsJsonObject("0.71")
?.getAsJsonObject("series")?.getAsJsonObject("default")?.getAsString("url")
?: throw Exception("Anime image is null")
val animeBanner = jsonObject.getAsJsonObject("image")?.getAsJsonObject("tile")?.getAsJsonObject("1.33")
?.getAsJsonObject("series")?.getAsJsonObject("default")?.getAsString("url")
?: throw Exception("Anime image is null")
val animeDescription = descriptions?.getAsJsonObject("series")
?.getAsJsonObject("default")?.getAsString("content")?.replace('\n', ' ') ?: ""

val season = requireNotNull(jsonObject.getAsInt("seasonSequenceNumber")) { "Season is null" }
val number = jsonObject.getAsInt("episodeSequenceNumber") ?: -1

val id = jsonObject.getAsString("contentId")

val title =
titles.getAsJsonObject("program")?.getAsJsonObject("default")?.getAsString("content")?.ifBlank { null }

val animeName = animeDetails.getAsString("title") ?: throw Exception("Anime name is null")
val tileObject = animeDetails.getAsJsonObject("artwork")?.getAsJsonObject("standard")?.getAsJsonObject("tile")
?: throw Exception("Tile object is null")
val animeImageId =
tileObject.getAsJsonObject("0.71")?.getAsString("imageId") ?: throw Exception("Anime image is null")
val animeImage = DisneyPlusWrapper.getImageUrl(animeImageId)
val animeBannerId =
tileObject.getAsJsonObject("1.33")?.getAsString("imageId") ?: throw Exception("Anime image is null")
val animeBanner = DisneyPlusWrapper.getImageUrl(animeBannerId)
val animeDescription =
animeDetails.getAsJsonObject("description")?.getAsString("full")?.replace('\n', ' ') ?: ""

val season = requireNotNull(jsonObject.getAsInt("seasonNumber")) { "Season is null" }
val number = jsonObject.getAsInt("episodeNumber") ?: -1
val id = jsonObject.getAsString("id")
val title = jsonObject.getAsString("episodeTitle")?.ifBlank { null }
val url = "https://www.disneyplus.com/${countryCode.locale.lowercase()}/video/$id"

val image = jsonObject.getAsJsonObject("image")?.getAsJsonObject("thumbnail")?.getAsJsonObject("1.78")
?.getAsJsonObject("program")?.getAsJsonObject("default")?.getAsString("url")
?: throw Exception("Image is null")

var duration = jsonObject.getAsJsonObject("mediaMetadata")?.getAsLong("runtimeMillis", -1) ?: -1
val imageId = jsonObject.getAsJsonObject("artwork")?.getAsJsonObject("standard")?.getAsJsonObject("thumbnail")
?.getAsJsonObject("1.78")?.getAsString("imageId") ?: throw Exception("Image is null")
val image = DisneyPlusWrapper.getImageUrl(imageId)
var duration = jsonObject.getAsLong("durationMs", -1)

if (duration != -1L) {
duration /= 1000
}

val description = descriptions?.getAsJsonObject("program")
?.getAsJsonObject("default")?.getAsString("content")?.replace('\n', ' ')?.ifBlank { null }

val releaseDateTimeUTC = zonedDateTime.withUTC()
.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")) + "T${simulcast.releaseTime}Z"
val description =
jsonObject.getAsJsonObject("description")?.getAsString("medium")?.replace('\n', ' ')?.ifBlank { null }
val releaseDateTimeUTC =
zonedDateTime.withUTC().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")) + "T${simulcast.releaseTime}Z"
val releaseDateTime = ZonedDateTime.parse(releaseDateTimeUTC)

return Episode(
Expand Down
38 changes: 24 additions & 14 deletions src/main/kotlin/fr/shikkanime/wrappers/DisneyPlusWrapper.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
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
Expand Down Expand Up @@ -38,38 +37,49 @@ object DisneyPlusWrapper {
.getAsString("accessToken")!!
}

suspend fun getSeasons(accessToken: String, countryCode: CountryCode, id: String): List<String> {
suspend fun getAnimeDetailsWithSeasons(accessToken: String, id: String): Pair<JsonObject, List<String>> {
val seasonsResponse = HttpRequest().get(
"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",
"https://disney.api.edge.bamgrid.com/explore/v1.4/page/entity-$id?disableSmartFocus=true&enhancedContainersLimit=15&limit=15",
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") }
val jsonObject = ObjectParser.fromJson(seasonsResponse.bodyAsText(), JsonObject::class.java)
val pageObject = jsonObject.getAsJsonObject("data").getAsJsonObject("page")

val seasons = pageObject.getAsJsonArray("containers")
.filter { it.asJsonObject.getAsString("type") == "episodes" }
.map { it.asJsonObject }
.getOrNull(0)
?.getAsJsonArray("seasons")
?.filter { it.asJsonObject.getAsString("type") == "season" }
?.mapNotNull { it.asJsonObject.getAsString("id") } ?: emptyList()

return pageObject.getAsJsonObject("visuals") to seasons
}

suspend fun getEpisodes(accessToken: String, countryCode: CountryCode, seasonId: String): List<JsonObject> {
suspend fun getEpisodes(accessToken: String, seasonId: String): List<JsonObject> {
val episodes = mutableListOf<JsonObject>()
var page = 1
var hasMore: Boolean

do {
val url =
"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++}"
"https://disney.api.edge.bamgrid.com/explore/v1.4/season/$seasonId?limit=24&offset=${(page++ - 1) * 24}"
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) }
val jsonObject = json.getAsJsonObject("data").getAsJsonObject("season")
hasMore = jsonObject.getAsJsonObject("pagination").getAsBoolean("hasMore") ?: false

jsonObject.getAsJsonArray("items")
.filter { it.asJsonObject.getAsString("type") == "view" }
.forEach { episodes.add(it.asJsonObject.getAsJsonObject("visuals")) }
} while (hasMore)

return episodes
}

fun getImageUrl(id: String) = "https://disney.images.edge.bamgrid.com/ripcut-delivery/v2/variant/disney/$id/compose"
}
18 changes: 18 additions & 0 deletions src/main/resources/db/changelog/2024/06/01-changelog.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.27.xsd"
objectQuotingStrategy="QUOTE_ONLY_RESERVED_WORDS">
<property global="false" name="id" value="1718803306111"/>
<property global="false" name="author" value="Ziedelth"/>

<changeSet id="${id}-1" author="${author}">
<preConditions onFail="MARK_RAN">
<columnExists tableName="config" columnName="property_value"/>
</preConditions>

<modifyDataType tableName="config" columnName="property_value" newDataType="VARCHAR(5000)"/>
</changeSet>
</databaseChangeLog>
2 changes: 2 additions & 0 deletions src/main/resources/db/changelog/db.changelog-master.xml
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,6 @@
<include file="/db/changelog/2024/05/02-changelog.xml"/>
<include file="/db/changelog/2024/05/03-changelog.xml"/>
<include file="/db/changelog/2024/05/04-changelog.xml"/>
<!-- June 2024 -->
<include file="/db/changelog/2024/06/01-changelog.xml"/>
</databaseChangeLog>

0 comments on commit 111013b

Please sign in to comment.