Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

This file was deleted.

17 changes: 7 additions & 10 deletions src/main/kotlin/fr/shikkanime/jobs/FetchOldEpisodesJob.kt
Original file line number Diff line number Diff line change
Expand Up @@ -213,16 +213,13 @@ class FetchOldEpisodesJob : AbstractJob {
}.getOrElse { emptyList() }
}
Platform.NETF -> NetflixCachedWrapper.getEpisodesByShowId(countryCode, id.toInt())
.flatMap { episode ->
val audioLocales = episode.audioLocales.ifEmpty { setOf("ja-JP") }
audioLocales.mapNotNull { audioLocale ->
runCatching {
netflixPlatform.convertEpisode(
countryCode, StringUtils.EMPTY_STRING, episode, audioLocale
)
}.getOrNull()
}
}
.mapNotNull { episode ->
runCatching {
netflixPlatform.convertEpisode(
countryCode, episode
)
}.getOrNull()
}.flatten()
Platform.PRIM -> HttpRequest.retry(3) {
PrimeVideoCachedWrapper.getEpisodesByShowId(countryCode, id)
.flatMap { episode ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -466,12 +466,10 @@ class UpdateEpisodeMappingJob : AbstractJob {
updateIdentifier(episodeVariant, id, episode.id.toString(), identifiers)
updateUrl(episodeVariant, episode.url)

episodes.add(
episodes.addAll(
netflixPlatform.convertEpisode(
countryCode,
StringUtils.EMPTY_STRING,
episode,
episodeVariant.audioLocale!!
)
)
}
Expand Down Expand Up @@ -570,7 +568,7 @@ class UpdateEpisodeMappingJob : AbstractJob {

// Fetch episodes by series and find the previous episode
logger.warning("Previous episode not found in season, searching by series...")
return runCatching { CrunchyrollCachedWrapper.getEpisodesBySeriesId(countryCode.locale, episode.seriesId) }.getOrNull()
runCatching { CrunchyrollCachedWrapper.getEpisodesBySeriesId(countryCode.locale, episode.seriesId) }.getOrNull()
?.sortedWith(compareBy({ it.episodeMetadata!!.seasonSequenceNumber }, { it.episodeMetadata!!.sequenceNumber }))
?.lastOrNull { it.episodeMetadata!!.index() < episode.index() }
?.id
Comment on lines +571 to 574
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

With the addition of retrievePreviousEpisode in AbstractCrunchyrollWrapper, the logic here for finding the previous episode for Crunchyroll is now duplicated and overly complex. You can simplify the retrievePreviousEpisodes method in this file to directly call the new wrapper method.

This would make the code much cleaner and easier to maintain, which aligns with the goal of this pull request.

Expand Down Expand Up @@ -619,7 +617,7 @@ class UpdateEpisodeMappingJob : AbstractJob {

// Fetch episodes by series and find the next episode
logger.warning("Next episode not found in season, searching by series...")
return runCatching { CrunchyrollCachedWrapper.getEpisodesBySeriesId(countryCode.locale, episode.seriesId) }.getOrNull()
runCatching { CrunchyrollCachedWrapper.getEpisodesBySeriesId(countryCode.locale, episode.seriesId) }.getOrNull()
?.sortedWith(compareBy({ it.episodeMetadata!!.seasonSequenceNumber }, { it.episodeMetadata!!.sequenceNumber }))
?.firstOrNull { it.episodeMetadata!!.index() > episode.index() }
?.id
Comment on lines +620 to 623
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Similar to my comment on finding the previous episode, the logic here for finding the next episode is now duplicated since retrieveNextEpisode was added to AbstractCrunchyrollWrapper. You should refactor the retrieveNextEpisodes method in this file to use the new wrapper method for the Crunchyroll platform. This will remove redundant code and simplify this job.

Expand Down
11 changes: 4 additions & 7 deletions src/main/kotlin/fr/shikkanime/platforms/CrunchyrollPlatform.kt
Original file line number Diff line number Diff line change
Expand Up @@ -203,9 +203,8 @@ class CrunchyrollPlatform : AbstractPlatform<CrunchyrollConfiguration, CountryCo

val crunchyrollAnimeContent = CrunchyrollCachedWrapper.getObjects(countryCode.locale, browseObject.episodeMetadata.seriesId).first()
val isConfigurationSimulcasted = containsAnimeSimulcastConfiguration(animeName)
val season = CrunchyrollCachedWrapper.getSeason(countryCode.locale, browseObject.episodeMetadata.seasonId)

val (number, episodeType) = getNumberAndEpisodeType(browseObject.episodeMetadata, season)
val (number, episodeType) = getNumberAndEpisodeType(browseObject.episodeMetadata)

val isSimulcasted = crunchyrollAnimeContent.seriesMetadata!!.isSimulcast || isDubbed || episodeType == EpisodeType.FILM

Expand Down Expand Up @@ -247,16 +246,14 @@ class CrunchyrollPlatform : AbstractPlatform<CrunchyrollConfiguration, CountryCo
)
}

private fun getNumberAndEpisodeType(
episode: AbstractCrunchyrollWrapper.Episode,
season: AbstractCrunchyrollWrapper.Season
): Pair<Int, EpisodeType> {
private fun getNumberAndEpisodeType(episode: AbstractCrunchyrollWrapper.Episode): Pair<Int, EpisodeType> {
var number = episode.number ?: -1
val specialEpisodeRegex = "SP(\\d*)".toRegex()

var episodeType = when {
episode.seasonSlugTitle?.contains("movie", true) == true ||
season.keywords.any { it.contains("movie", true) } -> EpisodeType.FILM
episode.seriesSlugTitle?.contains("movie", true) == true ||
(episode.number == null && episode.durationMs > 60_000) -> EpisodeType.FILM
number == -1 -> EpisodeType.SPECIAL
else -> EpisodeType.EPISODE
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class DisneyPlusPlatform : AbstractPlatform<DisneyPlusConfiguration, CountryCode
val list = mutableListOf<Episode>()

configuration!!.availableCountries.forEach { countryCode ->
configuration!!.simulcasts.filter { it.releaseDay == 0 || it.releaseDay == zonedDateTime.dayOfWeek.value }
configuration!!.simulcasts.filter { it.canBeFetch(zonedDateTime) }
.forEach { simulcast ->
runCatching {
list.addAll(
Expand Down
87 changes: 35 additions & 52 deletions src/main/kotlin/fr/shikkanime/platforms/NetflixPlatform.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package fr.shikkanime.platforms

import fr.shikkanime.caches.CountryCodeNetflixSimulcastKeyCache
import fr.shikkanime.caches.CountryCodeReleaseDayPlatformSimulcastKeyCache
import fr.shikkanime.entities.enums.CountryCode
import fr.shikkanime.entities.enums.ImageType
import fr.shikkanime.entities.enums.Platform
Expand All @@ -10,69 +10,52 @@ import fr.shikkanime.wrappers.impl.NetflixWrapper
import java.io.File
import java.time.ZonedDateTime

class NetflixPlatform : AbstractPlatform<NetflixConfiguration, CountryCodeNetflixSimulcastKeyCache, List<AbstractPlatform.Episode>>() {
class NetflixPlatform : AbstractPlatform<NetflixConfiguration, CountryCodeReleaseDayPlatformSimulcastKeyCache, List<AbstractPlatform.Episode>>() {
override fun getPlatform(): Platform = Platform.NETF

override fun getConfigurationClass() = NetflixConfiguration::class.java

override suspend fun fetchApiContent(
key: CountryCodeNetflixSimulcastKeyCache,
key: CountryCodeReleaseDayPlatformSimulcastKeyCache,
zonedDateTime: ZonedDateTime
) = NetflixWrapper.getEpisodesByShowId(key.countryCode, key.netflixSimulcast.name.toInt())
.flatMap { video ->
val audioLocales = video.audioLocales.ifEmpty { key.netflixSimulcast.audioLocales }
audioLocales.map { audioLocale ->
convertEpisode(
key.countryCode,
key.netflixSimulcast.image,
video,
audioLocale
).apply {
if (key.netflixSimulcast.audioLocaleHasDelay.contains(audioLocale)) {
releaseDateTime = zonedDateTime
}
}
}
}
) = NetflixWrapper.getEpisodesByShowId(key.countryCode, key.releaseDayPlatformSimulcast.name.toInt())
.flatMap { video -> convertEpisode(key.countryCode, video) }

override suspend fun fetchEpisodes(zonedDateTime: ZonedDateTime, bypassFileContent: File?) = configuration!!.availableCountries.flatMap { countryCode ->
configuration!!.simulcasts
.filter { it.releaseDay == 0 || it.releaseDay == zonedDateTime.dayOfWeek.value }
.flatMap { simulcast ->
getApiContent(CountryCodeNetflixSimulcastKeyCache(countryCode, simulcast), zonedDateTime)
}
configuration!!.simulcasts.filter { it.canBeFetch(zonedDateTime) }
.flatMap { simulcast -> getApiContent(CountryCodeReleaseDayPlatformSimulcastKeyCache(countryCode, simulcast), zonedDateTime) }
}


fun convertEpisode(
countryCode: CountryCode,
showImage: String,
episode: AbstractNetflixWrapper.Episode,
audioLocale: String,
) = Episode(
countryCode = countryCode,
animeId = episode.show.id.toString(),
anime = episode.show.name,
animeAttachments = mapOf(
ImageType.THUMBNAIL to (episode.show.thumbnail ?: showImage),
ImageType.BANNER to episode.show.banner,
ImageType.CAROUSEL to episode.show.carousel
),
animeDescription = episode.show.description,
releaseDateTime = requireNotNull(episode.releaseDateTime) { "Release date is null" },
episodeType = episode.episodeType,
seasonId = episode.season.toString(),
season = episode.season,
number = episode.number,
duration = episode.duration,
title = episode.title,
description = episode.description,
image = episode.image,
platform = getPlatform(),
audioLocale = audioLocale,
id = episode.id.toString(),
url = episode.url,
uncensored = false,
original = true,
)
): List<Episode> = episode.audioLocales.map {
Episode(
countryCode = countryCode,
animeId = episode.show.id.toString(),
anime = episode.show.name,
animeAttachments = buildMap {
episode.show.thumbnail?.let { image -> put(ImageType.THUMBNAIL, image) }
put(ImageType.BANNER, episode.show.banner)
put(ImageType.CAROUSEL, episode.show.carousel)
},
animeDescription = episode.show.description,
releaseDateTime = requireNotNull(episode.releaseDateTime) { "Release date is null" },
episodeType = episode.episodeType,
seasonId = episode.season.toString(),
season = episode.season,
number = episode.number,
duration = episode.duration,
title = episode.title,
description = episode.description,
image = episode.image,
platform = getPlatform(),
audioLocale = it,
id = episode.id.toString(),
url = episode.url,
uncensored = false,
original = true,
)
}
}
18 changes: 3 additions & 15 deletions src/main/kotlin/fr/shikkanime/platforms/PrimeVideoPlatform.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import fr.shikkanime.utils.HttpRequest
import fr.shikkanime.wrappers.factories.AbstractPrimeVideoWrapper
import fr.shikkanime.wrappers.impl.PrimeVideoWrapper
import java.io.File
import java.time.LocalTime
import java.time.ZonedDateTime
import java.util.logging.Level

Expand Down Expand Up @@ -41,20 +40,9 @@ class PrimeVideoPlatform :
}
}

override suspend fun fetchEpisodes(zonedDateTime: ZonedDateTime, bypassFileContent: File?): List<Episode> {
val list = mutableListOf<Episode>()

configuration!!.availableCountries.forEach { countryCode ->
configuration!!.simulcasts.filter {
(it.releaseDay == 0 || it.releaseDay == zonedDateTime.dayOfWeek.value) &&
(it.releaseTime.isBlank() || zonedDateTime.toLocalTime() >= LocalTime.parse(it.releaseTime))
}
.forEach { simulcast ->
list.addAll(getApiContent(CountryCodePrimeVideoSimulcastKeyCache(countryCode, simulcast), zonedDateTime))
}
}

return list
override suspend fun fetchEpisodes(zonedDateTime: ZonedDateTime, bypassFileContent: File?) = configuration!!.availableCountries.flatMap { countryCode ->
configuration!!.simulcasts.filter { it.canBeFetch(zonedDateTime) }
.flatMap { simulcast -> getApiContent(CountryCodePrimeVideoSimulcastKeyCache(countryCode, simulcast), zonedDateTime) }
}

fun convertEpisode(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,57 +1,5 @@
package fr.shikkanime.platforms.configuration

import fr.shikkanime.utils.StringUtils
import io.ktor.http.*

class NetflixConfiguration : PlatformConfiguration<NetflixConfiguration.NetflixSimulcastDay>() {
data class NetflixSimulcastDay(
var audioLocales: MutableSet<String> = mutableSetOf("ja-JP"),
var audioLocaleHasDelay: MutableSet<String> = mutableSetOf(),
) : ReleaseDayPlatformSimulcast() {
override fun of(parameters: Parameters) {
super.of(parameters)
parameters["audioLocales"]?.let { audioLocales = it.split(StringUtils.COMMA_STRING).toMutableSet() }
parameters["audioLocaleHasDelay"]?.let { audioLocaleHasDelay = it.split(StringUtils.COMMA_STRING).toMutableSet() }
}

override fun toConfigurationFields() = super.toConfigurationFields().apply {
add(
ConfigurationField(
label = "Audio Locales",
name = "audioLocales",
type = "text",
value = audioLocales.joinToString(StringUtils.COMMA_STRING),
)
)
add(
ConfigurationField(
label = "Audio Locale Delays",
caption = "Format: locale (e.g. fr-FR)",
name = "audioLocaleHasDelay",
type = "text",
value = audioLocaleHasDelay.joinToString(StringUtils.COMMA_STRING),
)
)
}

override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is NetflixSimulcastDay) return false
if (!super.equals(other)) return false

if (audioLocales != other.audioLocales) return false
if (audioLocaleHasDelay != other.audioLocaleHasDelay) return false

return true
}

override fun hashCode(): Int {
var result = super.hashCode()
result = 31 * result + audioLocales.hashCode()
result = 31 * result + audioLocaleHasDelay.hashCode()
return result
}
}

override fun newPlatformSimulcast() = NetflixSimulcastDay()
class NetflixConfiguration : PlatformConfiguration<ReleaseDayPlatformSimulcast>() {
override fun newPlatformSimulcast() = ReleaseDayPlatformSimulcast()
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,30 @@ package fr.shikkanime.platforms.configuration

import fr.shikkanime.utils.StringUtils
import io.ktor.http.*
import java.time.LocalTime
import java.time.ZoneId
import java.time.ZonedDateTime

class PrimeVideoConfiguration : PlatformConfiguration<PrimeVideoConfiguration.PrimeVideoSimulcast>() {
data class PrimeVideoSimulcast(var releaseTime: String = StringUtils.EMPTY_STRING) : ReleaseDayPlatformSimulcast() {
data class PrimeVideoSimulcast(
var image: String = StringUtils.EMPTY_STRING,
var releaseTime: String = StringUtils.EMPTY_STRING
) : ReleaseDayPlatformSimulcast() {
override fun of(parameters: Parameters) {
super.of(parameters)
parameters["image"]?.let { image = it }
parameters["releaseTime"]?.let { releaseTime = it }
}

override fun toConfigurationFields() = super.toConfigurationFields().apply {
add(
ConfigurationField(
label = "Image",
name = "image",
type = "text",
value = image
),
)
add(
ConfigurationField(
label = "Release time",
Expand All @@ -27,16 +42,29 @@ class PrimeVideoConfiguration : PlatformConfiguration<PrimeVideoConfiguration.Pr
if (other !is PrimeVideoSimulcast) return false
if (!super.equals(other)) return false

if (image != other.image) return false
if (releaseTime != other.releaseTime) return false

return true
}

override fun hashCode(): Int {
var result = super.hashCode()
result = 31 * result + image.hashCode()
result = 31 * result + releaseTime.hashCode()
return result
}

override fun canBeFetch(zonedDateTime: ZonedDateTime): Boolean {
if (!super.canBeFetch(zonedDateTime)) return false
if (this.releaseTime.isBlank()) return true

val releaseLocalTime = LocalTime.parse(this.releaseTime)
val isAfterInOriginalZone = zonedDateTime.toLocalTime() >= releaseLocalTime
val isAfterInSystemZone = zonedDateTime.withZoneSameInstant(ZoneId.systemDefault()).toLocalTime() >= releaseLocalTime

return isAfterInOriginalZone || isAfterInSystemZone
}
}

override fun newPlatformSimulcast() = PrimeVideoSimulcast()
Expand Down
Loading
Loading