Skip to content

Commit

Permalink
add Disney+ support for anime fetching and episode mapping
Browse files Browse the repository at this point in the history
  • Loading branch information
Ziedelth committed Feb 19, 2025
1 parent 7c7dfe2 commit b4a4bbd
Show file tree
Hide file tree
Showing 14 changed files with 352 additions and 5,654 deletions.
24 changes: 19 additions & 5 deletions src/main/kotlin/fr/shikkanime/jobs/UpdateAnimeJob.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,7 @@ import fr.shikkanime.utils.LoggerFactory
import fr.shikkanime.utils.MapCache
import fr.shikkanime.utils.StringUtils
import fr.shikkanime.utils.normalize
import fr.shikkanime.wrappers.impl.caches.AnimationDigitalNetworkCachedWrapper
import fr.shikkanime.wrappers.impl.caches.CrunchyrollCachedWrapper
import fr.shikkanime.wrappers.impl.caches.NetflixCachedWrapper
import fr.shikkanime.wrappers.impl.caches.PrimeVideoCachedWrapper
import fr.shikkanime.wrappers.impl.caches.*
import kotlinx.coroutines.runBlocking
import java.time.ZonedDateTime

Expand Down Expand Up @@ -146,9 +143,9 @@ class UpdateAnimeJob : AbstractJob {
when (it.platform!!) {
Platform.ANIM -> list.add(fetchADNAnime(it))
Platform.CRUN -> list.add(fetchCrunchyrollAnime(it))
Platform.DISN -> list.add(fetchDisneyPlusAnime(it))
Platform.NETF -> list.add(fetchNetflixAnime(it))
Platform.PRIM -> list.add(fetchPrimeVideoAnime(it))
else -> logger.warning("Platform ${it.platform} not supported")
}
}.onFailure { e ->
logger.warning("Error while fetching anime ${anime.name} on platform ${it.platform}: ${e.message}")
Expand Down Expand Up @@ -206,6 +203,23 @@ class UpdateAnimeJob : AbstractJob {
)
}

private suspend fun fetchDisneyPlusAnime(animePlatform: AnimePlatform): UpdatableAnime {
val show = DisneyPlusCachedWrapper.getShow(animePlatform.platformId!!)
val episodes = DisneyPlusCachedWrapper.getEpisodesByShowId(animePlatform.anime!!.countryCode!!.locale, animePlatform.platformId!!)

if (episodes.isEmpty())
throw Exception("No episode found for Disney+ anime ${animePlatform.anime!!.name}")

return UpdatableAnime(
platform = Platform.DISN,
lastReleaseDateTime = animePlatform.anime!!.lastReleaseDateTime,
image = show.image,
banner = show.banner,
description = show.description,
episodeSize = episodes.size
)
}

private fun fetchNetflixAnime(animePlatform: AnimePlatform): UpdatableAnime {
val episodes = runCatching {
NetflixCachedWrapper.getShowVideos(
Expand Down
62 changes: 45 additions & 17 deletions src/main/kotlin/fr/shikkanime/jobs/UpdateEpisodeMappingJob.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,23 @@ import fr.shikkanime.entities.enums.ConfigPropertyKey
import fr.shikkanime.entities.enums.CountryCode
import fr.shikkanime.entities.enums.EpisodeType
import fr.shikkanime.entities.enums.Platform
import fr.shikkanime.platforms.*
import fr.shikkanime.platforms.AbstractPlatform.Episode
import fr.shikkanime.platforms.AnimationDigitalNetworkPlatform
import fr.shikkanime.platforms.CrunchyrollPlatform
import fr.shikkanime.platforms.NetflixPlatform
import fr.shikkanime.platforms.PrimeVideoPlatform
import fr.shikkanime.services.*
import fr.shikkanime.services.caches.ConfigCacheService
import fr.shikkanime.services.caches.LanguageCacheService
import fr.shikkanime.utils.*
import fr.shikkanime.wrappers.factories.AbstractCrunchyrollWrapper
import fr.shikkanime.wrappers.factories.AbstractCrunchyrollWrapper.BrowseObject
import fr.shikkanime.wrappers.impl.CrunchyrollWrapper
import fr.shikkanime.wrappers.impl.caches.AnimationDigitalNetworkCachedWrapper
import fr.shikkanime.wrappers.impl.caches.CrunchyrollCachedWrapper
import fr.shikkanime.wrappers.impl.caches.NetflixCachedWrapper
import fr.shikkanime.wrappers.impl.caches.PrimeVideoCachedWrapper
import fr.shikkanime.wrappers.impl.caches.*
import kotlinx.coroutines.runBlocking
import java.time.ZonedDateTime
import java.util.concurrent.atomic.AtomicBoolean

class UpdateEpisodeMappingJob : AbstractJob {
private val logger = LoggerFactory.getLogger(javaClass)
private val availableUpdatePlatforms = listOf(Platform.ANIM, Platform.CRUN, Platform.NETF, Platform.PRIM)
private val availableUpdatePlatforms = listOf(Platform.ANIM, Platform.CRUN, Platform.DISN, Platform.NETF, Platform.PRIM)

@Inject
private lateinit var animeService: AnimeService
Expand All @@ -50,6 +44,9 @@ class UpdateEpisodeMappingJob : AbstractJob {
@Inject
private lateinit var crunchyrollPlatform: CrunchyrollPlatform

@Inject
private lateinit var disneyPlusPlatform: DisneyPlusPlatform

@Inject
private lateinit var netflixPlatform: NetflixPlatform

Expand All @@ -71,10 +68,10 @@ class UpdateEpisodeMappingJob : AbstractJob {
override fun run() {
val lastDateTime = ZonedDateTime.now().minusDays(configCacheService.getValueAsInt(ConfigPropertyKey.UPDATE_EPISODE_DELAY, 30).toLong())

val allPlatformEpisodes = availableUpdatePlatforms.flatMap { episodeMappingService.findAllNeedUpdateByPlatform(it, lastDateTime) }.distinctBy { it.uuid }
val allPlatformEpisodes = episodeMappingService.findAllNeedUpdateByPlatforms(availableUpdatePlatforms, lastDateTime)
logger.info("Found ${allPlatformEpisodes.size} episodes to update")

val needUpdateEpisodes = allPlatformEpisodes.distinctBy { it.uuid }
val needUpdateEpisodes = allPlatformEpisodes
.shuffled()
.take(configCacheService.getValueAsInt(ConfigPropertyKey.UPDATE_EPISODE_SIZE, 15))

Expand All @@ -94,7 +91,7 @@ class UpdateEpisodeMappingJob : AbstractJob {
val mappingIdentifier = "${StringUtils.getShortName(mapping.anime!!.name!!)} - S${mapping.season} ${mapping.episodeType} ${mapping.number}"
logger.info("Updating episode $mappingIdentifier...")

val episodes = variants.flatMap { variant -> runBlocking { retrievePlatformEpisode(mapping, variant, lastDateTime) } }
val episodes = variants.flatMap { variant -> runBlocking { retrievePlatformEpisode(mapping, variant, lastDateTime, identifiers) } }
.sortedBy { it.platform.sortIndex }

allPreviousAndNext.addAll(checkPreviousAndNextEpisodes(mapping.anime!!, variants))
Expand Down Expand Up @@ -339,7 +336,8 @@ class UpdateEpisodeMappingJob : AbstractJob {
private suspend fun retrievePlatformEpisode(
episodeMapping: EpisodeMapping,
episodeVariant: EpisodeVariant,
lastDateTime: ZonedDateTime
lastDateTime: ZonedDateTime,
identifiers: MutableSet<String>
): List<Episode> {
val countryCode = episodeMapping.anime!!.countryCode!!
val episodes = mutableListOf<Episode>()
Expand Down Expand Up @@ -374,12 +372,42 @@ class UpdateEpisodeMappingJob : AbstractJob {
}
}

Platform.DISN -> {
runCatching {
val disneyPlusId = disneyPlusPlatform.getDisneyPlusId(episodeVariant.identifier!!)!!
val (currentId, showId) = DisneyPlusCachedWrapper.getShowIdByEpisodeId(disneyPlusId)

if (currentId != disneyPlusId) {
val oldIdentifier = episodeVariant.identifier!!
logger.warning("Updating Disney+ episode $disneyPlusId to $currentId")
episodeVariant.identifier = oldIdentifier.replace(disneyPlusId, currentId)
episodeVariant.url = episodeVariant.url!!.replace(disneyPlusId, currentId)
episodeVariantService.update(episodeVariant)

identifiers.remove(oldIdentifier)
identifiers.add(episodeVariant.identifier!!)
}

val disneyPlusEpisodes = DisneyPlusCachedWrapper.getEpisodesByShowId(countryCode.locale, showId)

disneyPlusEpisodes.map { episode ->
disneyPlusPlatform.convertEpisode(
countryCode,
episode,
ZonedDateTime.now(),
false,
)
}.find { it.getIdentifier() == episodeVariant.identifier }
?.also { episodes.add(it) }
}
}

Platform.NETF -> {
runCatching {
val showId = netflixPlatform.getShowId(episodeVariant.url!!) ?: return emptyList()
val netflixEpisodes = NetflixCachedWrapper.getShowVideos(countryCode, showId)

netflixEpisodes?.map { episode ->
netflixEpisodes.map { episode ->
netflixPlatform.convertEpisode(
countryCode,
episodeMapping.anime!!.image!!,
Expand All @@ -388,7 +416,7 @@ class UpdateEpisodeMappingJob : AbstractJob {
episodeMapping.episodeType!!,
episodeVariant.audioLocale!!,
)
}?.find { it.getIdentifier() == episodeVariant.identifier }
}.find { it.getIdentifier() == episodeVariant.identifier }
?.also { episodes.add(it) }
}
}
Expand All @@ -398,14 +426,14 @@ class UpdateEpisodeMappingJob : AbstractJob {
val showId = primeVideoPlatform.getShowId(episodeVariant.url!!) ?: return emptyList()
val primeVideoEpisodes = PrimeVideoCachedWrapper.getShowVideos(countryCode, showId)

primeVideoEpisodes?.map { episode ->
primeVideoEpisodes.map { episode ->
primeVideoPlatform.convertEpisode(
countryCode,
episodeMapping.anime!!.image!!,
episode,
ZonedDateTime.now(),
)
}?.find { it.getIdentifier() == episodeVariant.identifier }
}.find { it.getIdentifier() == episodeVariant.identifier }
?.also { episodes.add(it) }
}
}
Expand Down
Loading

0 comments on commit b4a4bbd

Please sign in to comment.