Skip to content

Commit

Permalink
Merge pull request #273 from Shikkanime/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
Ziedelth authored Mar 11, 2024
2 parents 8f5543d + eccd89f commit d3f1801
Show file tree
Hide file tree
Showing 13 changed files with 365 additions and 32 deletions.
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ val guiceVersion = "7.0.0"
val liquibaseCoreVersion = "4.26.0"
val quartzVersion = "2.5.0-rc1"
val guavaVersion = "33.0.0-jre"
val jacksonVersion = "2.16.1"
val jacksonVersion = "2.16.2"
val playwrightVersion = "1.41.2"
val jsoupVersion = "1.17.2"
val gsonVersion = "2.10.1"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,9 +121,10 @@ class AdminController {

episodeService.findAll()
.filter { it.langType == LangType.SUBTITLES && it.episodeType != EpisodeType.FILM }
.sortedBy { it.releaseDateTime }
.forEach { episode ->
val anime = animeService.find(episode.anime!!.uuid!!)!!
episodeService.addSimulcastToAnime(anime, episodeService.getSimulcast(episode))
episodeService.addSimulcastToAnime(anime, episodeService.getSimulcast(anime, episode))

if (episode.anime != anime) {
animeService.update(anime)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import fr.shikkanime.dtos.AnimeDto
import fr.shikkanime.dtos.SimulcastDto
import fr.shikkanime.dtos.enums.Status
import fr.shikkanime.entities.Anime
import fr.shikkanime.services.SimulcastService.Companion.sortBySeasonAndYear
import fr.shikkanime.services.caches.LanguageCacheService
import fr.shikkanime.utils.StringUtils
import fr.shikkanime.utils.withUTC
Expand Down Expand Up @@ -36,7 +37,7 @@ class AnimeToAnimeDtoConverter : AbstractConverter<Anime, AnimeDto>() {
shortName = StringUtils.getShortName(from.name!!),
description = from.description,
simulcasts = if (Hibernate.isInitialized(from.simulcasts)) convert(
from.simulcasts,
from.simulcasts.sortBySeasonAndYear(),
SimulcastDto::class.java
) else null,
status = status,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,5 @@ enum class ConfigPropertyKey(val key: String) {
BSKY_MESSAGE("bsky_message"),
BSKY_SESSION_TIMEOUT("bsky_session_timeout"),
THREADS_SESSION_TIMEOUT("threads_session_timeout"),
SIMULCAST_RANGE_DELAY("simulcast_range_delay"),
}
4 changes: 2 additions & 2 deletions src/main/kotlin/fr/shikkanime/modules/HTTP.kt
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,11 @@ fun Application.configureHTTP() {
}
info {
title = "${Constant.NAME} API"
version = "1.0"
version = "1.0.0"
description = "API for testing and demonstration purposes"
}
server {
url = "http://localhost:37100"
url = Constant.BASE_URL
}
}
}
10 changes: 1 addition & 9 deletions src/main/kotlin/fr/shikkanime/repositories/EpisodeRepository.kt
Original file line number Diff line number Diff line change
Expand Up @@ -102,15 +102,7 @@ class EpisodeRepository : AbstractRepository<Episode>() {
createReadOnlyQuery(it, "FROM Episode WHERE anime.uuid = :uuid", getEntityClass())
.setParameter("uuid", uuid)
.resultList
}
}

fun findByHash(hash: String?): Episode? {
return inTransaction {
createReadOnlyQuery(it, "FROM Episode WHERE LOWER(hash) LIKE :hash", getEntityClass())
.setParameter("hash", "%${hash?.lowercase()}%")
.resultList
.firstOrNull()
.initialize()
}
}

Expand Down
22 changes: 15 additions & 7 deletions src/main/kotlin/fr/shikkanime/services/EpisodeService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import fr.shikkanime.utils.Constant
import fr.shikkanime.utils.MapCache
import io.ktor.http.*
import java.time.ZonedDateTime
import java.time.temporal.ChronoUnit
import java.util.*

class EpisodeService : AbstractService<Episode, EpisodeRepository>() {
Expand Down Expand Up @@ -41,8 +42,6 @@ class EpisodeService : AbstractService<Episode, EpisodeRepository>() {

fun findAllByAnime(uuid: UUID) = episodeRepository.findAllByAnime(uuid)

fun findByHash(hash: String?) = episodeRepository.findByHash(hash)

fun findAllUUIDAndImage() = episodeRepository.findAllUUIDAndImage()

fun findAllByPlatformDeprecatedEpisodes(
Expand All @@ -56,7 +55,7 @@ class EpisodeService : AbstractService<Episode, EpisodeRepository>() {
ImageService.add(uuid, ImageService.Type.IMAGE, image, 640, 360)
}

fun getSimulcast(entity: Episode): Simulcast {
fun getSimulcast(anime: Anime, entity: Episode): Simulcast {
val simulcastRange = configCacheService.getValueAsInt(ConfigPropertyKey.SIMULCAST_RANGE, 1)

val adjustedDates = listOf(-simulcastRange, 0, simulcastRange).map { days ->
Expand All @@ -71,10 +70,19 @@ class EpisodeService : AbstractService<Episode, EpisodeRepository>() {
val currentSimulcast = simulcasts[1]
val nextSimulcast = simulcasts[2]

val isAnimeReleaseDateTimeBeforeMinusXDays = entity.anime!!.releaseDateTime.isBefore(adjustedDates[0])
val isAnimeReleaseDateTimeBeforeMinusXDays = anime.releaseDateTime.isBefore(adjustedDates[0])
val animeEpisodes = anime.uuid?.let { episodeRepository.findAllByAnime(it).sortedBy { it.releaseDateTime } }
val previousEpisode =
animeEpisodes?.lastOrNull { it.releaseDateTime.isBefore(entity.releaseDateTime) && it.episodeType == entity.episodeType && it.langType == entity.langType }
val diff = previousEpisode?.releaseDateTime?.until(entity.releaseDateTime, ChronoUnit.MONTHS) ?: -1

val choosenSimulcast = when {
anime.simulcasts.any { it.year == nextSimulcast.year && it.season == nextSimulcast.season } -> nextSimulcast
entity.number!! <= 1 && currentSimulcast != nextSimulcast -> nextSimulcast
entity.number!! > 1 && isAnimeReleaseDateTimeBeforeMinusXDays && (diff == -1L || diff >= configCacheService.getValueAsInt(
ConfigPropertyKey.SIMULCAST_RANGE_DELAY,
3
)) -> nextSimulcast
entity.number!! > 1 && isAnimeReleaseDateTimeBeforeMinusXDays && currentSimulcast != previousSimulcast -> previousSimulcast
else -> currentSimulcast
}
Expand All @@ -95,8 +103,8 @@ class EpisodeService : AbstractService<Episode, EpisodeRepository>() {

override fun save(entity: Episode): Episode {
val copy = entity.anime!!.copy()
val anime =
animeService.findAllByLikeName(copy.countryCode!!, copy.name!!).firstOrNull() ?: animeService.save(copy)
val anime = animeService.findAllByLikeName(copy.countryCode!!, copy.name!!).firstOrNull() ?: animeService.save(copy)
entity.anime = anime.copy()

if (anime.banner.isNullOrBlank() && !copy.banner.isNullOrBlank()) {
anime.banner = copy.banner
Expand All @@ -113,7 +121,7 @@ class EpisodeService : AbstractService<Episode, EpisodeRepository>() {
}

if (entity.langType == LangType.SUBTITLES && entity.episodeType != EpisodeType.FILM) {
val simulcast = getSimulcast(entity)
val simulcast = getSimulcast(anime, entity)
addSimulcastToAnime(anime, simulcast)
}

Expand Down
10 changes: 9 additions & 1 deletion src/main/kotlin/fr/shikkanime/services/SimulcastService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class SimulcastService : AbstractService<Simulcast, SimulcastRepository>() {
override fun getRepository() = simulcastRepository

override fun findAll() =
super.findAll().sortedWith(compareBy({ it.year }, { Constant.seasons.indexOf(it.season) })).reversed()
super.findAll().sortBySeasonAndYear()

fun findBySeasonAndYear(season: String, year: Int) = simulcastRepository.findBySeasonAndYear(season, year)

Expand All @@ -27,4 +27,12 @@ class SimulcastService : AbstractService<Simulcast, SimulcastRepository>() {
super.delete(entity)
MapCache.invalidate(Simulcast::class.java)
}

companion object {
fun List<Simulcast>.sortBySeasonAndYear() =
this.sortedWith(compareBy({ it.year }, { Constant.seasons.indexOf(it.season) })).reversed()

fun Set<Simulcast>.sortBySeasonAndYear() =
this.toList().sortBySeasonAndYear().toSet()
}
}
23 changes: 23 additions & 0 deletions src/main/resources/db/changelog/2024/03/03-changelog.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?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.26.xsd" objectQuotingStrategy="QUOTE_ONLY_RESERVED_WORDS">
<property global="false" name="id" value="1710164378809"/>
<property global="false" name="author" value="Ziedelth"/>

<changeSet id="${id}-1" author="${author}" dbms="postgresql">
<preConditions onFail="MARK_RAN">
<sqlCheck expectedResult="0">SELECT COUNT(*)
FROM config
WHERE property_key = 'simulcast_range_delay'</sqlCheck>
</preConditions>

<insert tableName="config">
<column name="uuid" valueComputed="gen_random_uuid()"/>
<column name="property_key" value="simulcast_range_delay"/>
<column name="property_value" value="3"/>
</insert>
</changeSet>
</databaseChangeLog>
3 changes: 2 additions & 1 deletion src/main/resources/db/changelog/db.changelog-master.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,6 @@
<include file="/db/changelog/2024/02/11-changelog.xml"/>
<!-- March 2024 -->
<include file="/db/changelog/2024/03/01-changelog.xml"/>
<include file="db/changelog/2024/03/02-changelog.xml"/>
<include file="/db/changelog/2024/03/02-changelog.xml"/>
<include file="/db/changelog/2024/03/03-changelog.xml"/>
</databaseChangeLog>
2 changes: 1 addition & 1 deletion src/main/resources/templates/admin/dashboard.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
<div class="card p-3">
<div class="d-flex mb-4">
<h4 class="card-title">Simulcasts</h4>
<a href="/admin/simulcasts-invalidate" class="btn btn-danger ms-auto me-0">Invalidate</a>
<a id="simulcasts-invalidate" href="/admin/simulcasts-invalidate" class="btn btn-danger ms-auto me-0">Invalidate</a>
</div>

<ul class="list-group list-group-numbered">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,30 @@ package fr.shikkanime.controllers.admin

import com.google.inject.Inject
import com.microsoft.playwright.Playwright
import fr.shikkanime.converters.AbstractConverter
import fr.shikkanime.dtos.AnimeDto
import fr.shikkanime.entities.Anime
import fr.shikkanime.entities.Episode
import fr.shikkanime.entities.enums.EpisodeType
import fr.shikkanime.entities.enums.LangType
import fr.shikkanime.entities.enums.Link
import fr.shikkanime.entities.enums.Platform
import fr.shikkanime.initAll
import fr.shikkanime.services.AnimeService
import fr.shikkanime.services.EpisodeService
import fr.shikkanime.services.MemberService
import fr.shikkanime.utils.Constant
import fr.shikkanime.utils.JobManager
import fr.shikkanime.utils.ObjectParser
import io.ktor.server.engine.*
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import java.io.File
import java.net.BindException
import java.net.ServerSocket
import java.util.*
import java.util.concurrent.atomic.AtomicReference

class AdminControllerTest {
Expand All @@ -25,6 +36,12 @@ class AdminControllerTest {
@Inject
private lateinit var memberService: MemberService

@Inject
private lateinit var animeService: AnimeService

@Inject
private lateinit var episodeService: EpisodeService

private fun isPortInUse(port: Int): Boolean {
try {
val socket = ServerSocket(port)
Expand All @@ -44,12 +61,56 @@ class AdminControllerTest {
Constant.injector.injectMembers(this)
server = initAll(password, port, false)
JobManager.invalidate()

val descriptions = listOf(
"The story of the Saiyan Goku and his friends continues after the defeat of Majin Buu.",
"C'est l'histoire de la suite de Dragon Ball Z. L'histoire se passe 10 ans après la défaite de Majin Buu.",
"(Test) - The story of the Saiyan Goku and his friends continues after the defeat of Majin Buu.",
"(Test) - C'est l'histoire de la suite de Dragon Ball Z. L'histoire se passe 10 ans après la défaite de Majin Buu."
)

val listFiles = File(ClassLoader.getSystemClassLoader().getResource("animes")?.file).listFiles()

listFiles
?.sortedBy { it.name.lowercase() }
?.forEach {
val anime = animeService.save(
AbstractConverter.convert(
ObjectParser.fromJson(
it.readText(),
AnimeDto::class.java
), Anime::class.java
)
)

(1..10).forEach { number ->
episodeService.save(
Episode(
platform = Platform.entries.random(),
anime = anime,
episodeType = EpisodeType.entries.random(),
langType = LangType.entries.random(),
hash = UUID.randomUUID().toString(),
releaseDateTime = anime.releaseDateTime,
season = 1,
number = number,
title = "Episode $number",
description = descriptions[number % descriptions.size],
url = "https://www.google.com",
image = "https://pbs.twimg.com/profile_banners/1726908281640091649/1700562801/1500x500",
duration = 1420
)
)
}
}
}

@AfterEach
fun tearDown() {
memberService.deleteAll()
server?.stop(1000, 10000)
episodeService.deleteAll()
animeService.deleteAll()
}

@Test
Expand Down Expand Up @@ -138,4 +199,23 @@ class AdminControllerTest {
browser.close()
playwright.close()
}

@Test
fun `invalidate simulcasts`() {
val playwright = Playwright.create()
val browser = playwright.chromium().launch()
val page = browser.newPage()

page.navigate("http://localhost:$port/admin")
assertEquals("Login - Shikkanime", page.title())
page.fill("input[name=username]", "admin")
page.fill("input[name=password]", password.get())
page.click("button[type=submit]")

page.click("#simulcasts-invalidate")

page.close()
browser.close()
playwright.close()
}
}
Loading

0 comments on commit d3f1801

Please sign in to comment.