diff --git a/build.gradle.kts b/build.gradle.kts index 075f25ae..a636b476 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -28,6 +28,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" jacoco id("org.sonarqube") version "5.0.0.4638" @@ -95,6 +96,9 @@ dependencies { implementation("org.twitter4j:twitter4j-core:$twitter4jVersion") implementation("io.github.takke:jp.takke.twitter4j-v2:$twitter4jV2Version") + kapt("org.hibernate.orm:hibernate-jpamodelgen:$hibernateCoreVersion") + compileOnly("org.hibernate.orm:hibernate-jpamodelgen:$hibernateCoreVersion") + testImplementation("io.ktor:ktor-server-tests-jvm:$ktorVersion") testImplementation("io.ktor:ktor-client-mock:$ktorVersion") testImplementation("org.junit.jupiter:junit-jupiter-api:$junitVersion") diff --git a/src/main/kotlin/fr/shikkanime/controllers/admin/AdminAnimeController.kt b/src/main/kotlin/fr/shikkanime/controllers/admin/AdminAnimeController.kt index a947c9a6..10804f51 100644 --- a/src/main/kotlin/fr/shikkanime/controllers/admin/AdminAnimeController.kt +++ b/src/main/kotlin/fr/shikkanime/controllers/admin/AdminAnimeController.kt @@ -2,7 +2,7 @@ package fr.shikkanime.controllers.admin import com.google.inject.Inject import fr.shikkanime.converters.AbstractConverter -import fr.shikkanime.dtos.AnimeDto +import fr.shikkanime.dtos.animes.AnimeDto import fr.shikkanime.entities.enums.Link import fr.shikkanime.services.AnimeService import fr.shikkanime.utils.routes.AdminSessionAuthenticated diff --git a/src/main/kotlin/fr/shikkanime/controllers/site/SiteController.kt b/src/main/kotlin/fr/shikkanime/controllers/site/SiteController.kt index b2827145..8a12d316 100644 --- a/src/main/kotlin/fr/shikkanime/controllers/site/SiteController.kt +++ b/src/main/kotlin/fr/shikkanime/controllers/site/SiteController.kt @@ -1,7 +1,7 @@ package fr.shikkanime.controllers.site import com.google.inject.Inject -import fr.shikkanime.dtos.AnimeDto +import fr.shikkanime.dtos.animes.AnimeDto import fr.shikkanime.entities.SortParameter import fr.shikkanime.entities.enums.ConfigPropertyKey import fr.shikkanime.entities.enums.CountryCode diff --git a/src/main/kotlin/fr/shikkanime/converters/anime/AnimeDtoToAnimeConverter.kt b/src/main/kotlin/fr/shikkanime/converters/anime/AnimeDtoToAnimeConverter.kt index 5276e80a..343d6174 100644 --- a/src/main/kotlin/fr/shikkanime/converters/anime/AnimeDtoToAnimeConverter.kt +++ b/src/main/kotlin/fr/shikkanime/converters/anime/AnimeDtoToAnimeConverter.kt @@ -2,7 +2,7 @@ package fr.shikkanime.converters.anime import com.google.inject.Inject import fr.shikkanime.converters.AbstractConverter -import fr.shikkanime.dtos.AnimeDto +import fr.shikkanime.dtos.animes.AnimeDto import fr.shikkanime.entities.Anime import fr.shikkanime.entities.Simulcast import fr.shikkanime.services.AnimeService diff --git a/src/main/kotlin/fr/shikkanime/converters/anime/AnimeToAnimeDtoConverter.kt b/src/main/kotlin/fr/shikkanime/converters/anime/AnimeToAnimeDtoConverter.kt index 4f45f155..2614e5fd 100644 --- a/src/main/kotlin/fr/shikkanime/converters/anime/AnimeToAnimeDtoConverter.kt +++ b/src/main/kotlin/fr/shikkanime/converters/anime/AnimeToAnimeDtoConverter.kt @@ -2,16 +2,11 @@ package fr.shikkanime.converters.anime import com.google.inject.Inject import fr.shikkanime.converters.AbstractConverter -import fr.shikkanime.dtos.AnimeDto -import fr.shikkanime.dtos.SimulcastDto +import fr.shikkanime.dtos.animes.AnimeDto +import fr.shikkanime.dtos.animes.AnimeNoStatusDto 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 -import org.hibernate.Hibernate -import java.time.format.DateTimeFormatter class AnimeToAnimeDtoConverter : AbstractConverter() { @Inject @@ -26,24 +21,10 @@ class AnimeToAnimeDtoConverter : AbstractConverter() { languageCacheService.detectLanguage(from.description) != from.countryCode!!.name.lowercase() ) Status.INVALID else Status.VALID - return AnimeDto( - uuid = from.uuid, - releaseDateTime = from.releaseDateTime.withUTC() - .format(DateTimeFormatter.ISO_OFFSET_DATE_TIME), - image = from.image, - banner = from.banner, - countryCode = from.countryCode!!, - name = from.name!!, - shortName = StringUtils.getShortName(from.name!!), - description = from.description, - simulcasts = if (Hibernate.isInitialized(from.simulcasts)) convert( - from.simulcasts.sortBySeasonAndYear(), - SimulcastDto::class.java - ) else null, - status = status, - slug = from.slug, - lastReleaseDateTime = from.lastReleaseDateTime.withUTC() - .format(DateTimeFormatter.ISO_OFFSET_DATE_TIME) + + return AnimeDto.from( + convert(from, AnimeNoStatusDto::class.java), + status ) } } \ No newline at end of file diff --git a/src/main/kotlin/fr/shikkanime/converters/anime/AnimeToAnimeNoStatusDtoConverter.kt b/src/main/kotlin/fr/shikkanime/converters/anime/AnimeToAnimeNoStatusDtoConverter.kt new file mode 100644 index 00000000..30e5cbbd --- /dev/null +++ b/src/main/kotlin/fr/shikkanime/converters/anime/AnimeToAnimeNoStatusDtoConverter.kt @@ -0,0 +1,34 @@ +package fr.shikkanime.converters.anime + +import fr.shikkanime.converters.AbstractConverter +import fr.shikkanime.dtos.SimulcastDto +import fr.shikkanime.dtos.animes.AnimeNoStatusDto +import fr.shikkanime.entities.Anime +import fr.shikkanime.services.SimulcastService.Companion.sortBySeasonAndYear +import fr.shikkanime.utils.StringUtils +import fr.shikkanime.utils.withUTC +import org.hibernate.Hibernate +import java.time.format.DateTimeFormatter + +class AnimeToAnimeNoStatusDtoConverter : AbstractConverter() { + override fun convert(from: Anime): AnimeNoStatusDto { + return AnimeNoStatusDto( + uuid = from.uuid, + releaseDateTime = from.releaseDateTime.withUTC() + .format(DateTimeFormatter.ISO_OFFSET_DATE_TIME), + image = from.image, + banner = from.banner, + countryCode = from.countryCode!!, + name = from.name!!, + shortName = StringUtils.getShortName(from.name!!), + description = from.description, + simulcasts = if (Hibernate.isInitialized(from.simulcasts)) convert( + from.simulcasts.sortBySeasonAndYear(), + SimulcastDto::class.java + ) else null, + slug = from.slug, + lastReleaseDateTime = from.lastReleaseDateTime.withUTC() + .format(DateTimeFormatter.ISO_OFFSET_DATE_TIME) + ) + } +} \ No newline at end of file diff --git a/src/main/kotlin/fr/shikkanime/converters/episode/EpisodeToEpisodeDtoConverter.kt b/src/main/kotlin/fr/shikkanime/converters/episode/EpisodeToEpisodeDtoConverter.kt index d7aa6473..32e19bdb 100644 --- a/src/main/kotlin/fr/shikkanime/converters/episode/EpisodeToEpisodeDtoConverter.kt +++ b/src/main/kotlin/fr/shikkanime/converters/episode/EpisodeToEpisodeDtoConverter.kt @@ -2,9 +2,9 @@ package fr.shikkanime.converters.episode import com.google.inject.Inject import fr.shikkanime.converters.AbstractConverter -import fr.shikkanime.dtos.AnimeDto import fr.shikkanime.dtos.EpisodeDto import fr.shikkanime.dtos.PlatformDto +import fr.shikkanime.dtos.animes.AnimeDto import fr.shikkanime.dtos.enums.Status import fr.shikkanime.entities.Episode import fr.shikkanime.services.caches.LanguageCacheService diff --git a/src/main/kotlin/fr/shikkanime/dtos/AnimeDto.kt b/src/main/kotlin/fr/shikkanime/dtos/AnimeDto.kt deleted file mode 100644 index e8b60ac8..00000000 --- a/src/main/kotlin/fr/shikkanime/dtos/AnimeDto.kt +++ /dev/null @@ -1,20 +0,0 @@ -package fr.shikkanime.dtos - -import fr.shikkanime.dtos.enums.Status -import fr.shikkanime.entities.enums.CountryCode -import java.util.* - -data class AnimeDto( - val uuid: UUID?, - val countryCode: CountryCode, - var name: String, - var shortName: String, - var releaseDateTime: String, - val image: String? = null, - val banner: String? = null, - val description: String?, - val simulcasts: List?, - val status: Status? = null, - val slug: String? = null, - val lastReleaseDateTime: String? = null -) diff --git a/src/main/kotlin/fr/shikkanime/dtos/EpisodeDto.kt b/src/main/kotlin/fr/shikkanime/dtos/EpisodeDto.kt index 1ff7f94b..34be4fb8 100644 --- a/src/main/kotlin/fr/shikkanime/dtos/EpisodeDto.kt +++ b/src/main/kotlin/fr/shikkanime/dtos/EpisodeDto.kt @@ -1,5 +1,6 @@ package fr.shikkanime.dtos +import fr.shikkanime.dtos.animes.AnimeDto import fr.shikkanime.dtos.enums.Status import fr.shikkanime.entities.enums.EpisodeType import fr.shikkanime.entities.enums.LangType diff --git a/src/main/kotlin/fr/shikkanime/dtos/WeeklyAnimeDto.kt b/src/main/kotlin/fr/shikkanime/dtos/WeeklyAnimeDto.kt index a84270f9..b4115d47 100644 --- a/src/main/kotlin/fr/shikkanime/dtos/WeeklyAnimeDto.kt +++ b/src/main/kotlin/fr/shikkanime/dtos/WeeklyAnimeDto.kt @@ -1,5 +1,7 @@ package fr.shikkanime.dtos +import fr.shikkanime.dtos.animes.AnimeDto + data class WeeklyAnimeDto( val anime: AnimeDto, val releaseDateTime: String, diff --git a/src/main/kotlin/fr/shikkanime/dtos/animes/AnimeDto.kt b/src/main/kotlin/fr/shikkanime/dtos/animes/AnimeDto.kt new file mode 100644 index 00000000..6fc4d281 --- /dev/null +++ b/src/main/kotlin/fr/shikkanime/dtos/animes/AnimeDto.kt @@ -0,0 +1,52 @@ +package fr.shikkanime.dtos.animes + +import fr.shikkanime.dtos.SimulcastDto +import fr.shikkanime.dtos.enums.Status +import fr.shikkanime.entities.enums.CountryCode +import java.util.* + +data class AnimeDto( + override val uuid: UUID?, + override val countryCode: CountryCode, + override var name: String, + override var shortName: String, + override var releaseDateTime: String, + override val image: String? = null, + override val banner: String? = null, + override val description: String?, + override val simulcasts: List?, + override val slug: String? = null, + override val lastReleaseDateTime: String? = null, + val status: Status? = null, +) : AnimeNoStatusDto( + uuid, + countryCode, + name, + shortName, + releaseDateTime, + image, + banner, + description, + simulcasts, + slug, + lastReleaseDateTime +) { + companion object { + fun from(animeNoStatusDto: AnimeNoStatusDto, status: Status?): AnimeDto { + return AnimeDto( + animeNoStatusDto.uuid, + animeNoStatusDto.countryCode, + animeNoStatusDto.name, + animeNoStatusDto.shortName, + animeNoStatusDto.releaseDateTime, + animeNoStatusDto.image, + animeNoStatusDto.banner, + animeNoStatusDto.description, + animeNoStatusDto.simulcasts, + animeNoStatusDto.slug, + animeNoStatusDto.lastReleaseDateTime, + status, + ) + } + } +} diff --git a/src/main/kotlin/fr/shikkanime/dtos/animes/AnimeNoStatusDto.kt b/src/main/kotlin/fr/shikkanime/dtos/animes/AnimeNoStatusDto.kt new file mode 100644 index 00000000..44fa45bf --- /dev/null +++ b/src/main/kotlin/fr/shikkanime/dtos/animes/AnimeNoStatusDto.kt @@ -0,0 +1,32 @@ +package fr.shikkanime.dtos.animes + +import fr.shikkanime.dtos.SimulcastDto +import fr.shikkanime.entities.enums.CountryCode +import java.util.* + +open class AnimeNoStatusDto( + @Transient + open val uuid: UUID?, + @Transient + open val countryCode: CountryCode, + @Transient + open var name: String, + @Transient + open var shortName: String, + @Transient + open var releaseDateTime: String, + @Transient + open val image: String? = null, + @Transient + open val banner: String? = null, + @Transient + open val description: String?, + @Transient + open val simulcasts: List?, + @Transient + open val slug: String? = null, + @Transient + open val lastReleaseDateTime: String? = null +) { + fun toAnimeDto() = AnimeDto.from(this, null) +} \ No newline at end of file diff --git a/src/main/kotlin/fr/shikkanime/entities/Anime.kt b/src/main/kotlin/fr/shikkanime/entities/Anime.kt index 407d0429..e794ede7 100644 --- a/src/main/kotlin/fr/shikkanime/entities/Anime.kt +++ b/src/main/kotlin/fr/shikkanime/entities/Anime.kt @@ -14,6 +14,7 @@ import java.util.* name = "anime", indexes = [ Index(name = "idx_anime_country_code", columnList = "country_code"), + Index(name = "idx_anime_slug", columnList = "slug"), ] ) @Indexed @@ -44,7 +45,7 @@ class Anime( ) @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) var simulcasts: MutableSet = mutableSetOf(), - @Column(nullable = true) + @Column(nullable = false, unique = true) var slug: String? = null, @Column(nullable = false, name = "last_release_date_time") var lastReleaseDateTime: ZonedDateTime = releaseDateTime, diff --git a/src/main/kotlin/fr/shikkanime/repositories/AbstractRepository.kt b/src/main/kotlin/fr/shikkanime/repositories/AbstractRepository.kt index 6809168a..6711c623 100644 --- a/src/main/kotlin/fr/shikkanime/repositories/AbstractRepository.kt +++ b/src/main/kotlin/fr/shikkanime/repositories/AbstractRepository.kt @@ -6,6 +6,7 @@ import fr.shikkanime.entities.ShikkEntity import fr.shikkanime.utils.Database import jakarta.persistence.EntityManager import jakarta.persistence.TypedQuery +import jakarta.persistence.criteria.CriteriaQuery import org.hibernate.ScrollMode import org.hibernate.jpa.AvailableHints import org.hibernate.query.Query @@ -41,6 +42,11 @@ abstract class AbstractRepository { .setHint(AvailableHints.HINT_READ_ONLY, true) } + fun createReadOnlyQuery(entityManager: EntityManager, criteriaQuery: CriteriaQuery): TypedQuery { + return entityManager.createQuery(criteriaQuery) + .setHint(AvailableHints.HINT_READ_ONLY, true) + } + fun buildPageableQuery(query: TypedQuery, page: Int, limit: Int): Pageable { val scrollableResults = query.unwrap(Query::class.java) .setReadOnly(true) diff --git a/src/main/kotlin/fr/shikkanime/repositories/AnimeRepository.kt b/src/main/kotlin/fr/shikkanime/repositories/AnimeRepository.kt index fb894bf6..e5a9516d 100644 --- a/src/main/kotlin/fr/shikkanime/repositories/AnimeRepository.kt +++ b/src/main/kotlin/fr/shikkanime/repositories/AnimeRepository.kt @@ -1,6 +1,7 @@ package fr.shikkanime.repositories import fr.shikkanime.entities.Anime +import fr.shikkanime.entities.Anime_ import fr.shikkanime.entities.Pageable import fr.shikkanime.entities.SortParameter import fr.shikkanime.entities.enums.CountryCode @@ -139,9 +140,15 @@ class AnimeRepository : AbstractRepository() { } fun findBySlug(slug: String): Anime? { - return inTransaction { - createReadOnlyQuery(it, "FROM Anime WHERE slug = :slug", getEntityClass()) - .setParameter("slug", slug) + return inTransaction { entityManager -> + val cb = entityManager.criteriaBuilder + val query = cb.createQuery(getEntityClass()) + val root = query.from(getEntityClass()) + + query.select(root) + .where(cb.equal(root[Anime_.slug], slug)) + + createReadOnlyQuery(entityManager, query) .resultList .firstOrNull() ?.initialize() diff --git a/src/main/kotlin/fr/shikkanime/repositories/EpisodeRepository.kt b/src/main/kotlin/fr/shikkanime/repositories/EpisodeRepository.kt index 7136f18a..319a39d2 100644 --- a/src/main/kotlin/fr/shikkanime/repositories/EpisodeRepository.kt +++ b/src/main/kotlin/fr/shikkanime/repositories/EpisodeRepository.kt @@ -1,8 +1,6 @@ package fr.shikkanime.repositories -import fr.shikkanime.entities.Episode -import fr.shikkanime.entities.Pageable -import fr.shikkanime.entities.SortParameter +import fr.shikkanime.entities.* import fr.shikkanime.entities.enums.CountryCode import fr.shikkanime.entities.enums.EpisodeType import fr.shikkanime.entities.enums.LangType @@ -164,19 +162,17 @@ class EpisodeRepository : AbstractRepository() { end: ZonedDateTime, ): List { return inTransaction { entityManager -> - createReadOnlyQuery( - entityManager, - """ - FROM Episode e - WHERE e.anime.countryCode = :countryCode AND e.releaseDateTime BETWEEN :start AND :end - """.trimIndent(), - getEntityClass() - ) - .setParameter("countryCode", countryCode) - .setParameter("start", start) - .setParameter("end", end) + val cb = entityManager.criteriaBuilder + val query = cb.createQuery(getEntityClass()) + val root = query.from(getEntityClass()) + + val countryPredicate = cb.equal(root[Episode_.anime][Anime_.countryCode], countryCode) + val datePredicate = cb.between(root[Episode_.releaseDateTime], start, end) + + query.select(root).where(cb.and(countryPredicate, datePredicate)) + + createReadOnlyQuery(entityManager, query) .resultList - .initialize() } } } \ No newline at end of file diff --git a/src/main/kotlin/fr/shikkanime/services/AnimeService.kt b/src/main/kotlin/fr/shikkanime/services/AnimeService.kt index 599190f6..8e0fec95 100644 --- a/src/main/kotlin/fr/shikkanime/services/AnimeService.kt +++ b/src/main/kotlin/fr/shikkanime/services/AnimeService.kt @@ -2,16 +2,17 @@ package fr.shikkanime.services import com.google.inject.Inject import fr.shikkanime.converters.AbstractConverter -import fr.shikkanime.dtos.EpisodeDto import fr.shikkanime.dtos.PlatformDto import fr.shikkanime.dtos.WeeklyAnimeDto import fr.shikkanime.dtos.WeeklyAnimesDto +import fr.shikkanime.dtos.animes.AnimeNoStatusDto import fr.shikkanime.entities.Anime import fr.shikkanime.entities.SortParameter import fr.shikkanime.entities.enums.CountryCode import fr.shikkanime.repositories.AnimeRepository import fr.shikkanime.utils.MapCache import fr.shikkanime.utils.StringUtils.capitalizeWords +import fr.shikkanime.utils.withUTC import io.ktor.http.* import java.time.LocalDate import java.time.ZonedDateTime @@ -53,34 +54,31 @@ class AnimeService : AbstractService() { fun getWeeklyAnimes(startOfWeekDay: LocalDate, countryCode: CountryCode): List { val start = ZonedDateTime.parse("${startOfWeekDay.minusDays(7)}T00:00:00Z") val end = ZonedDateTime.parse("${startOfWeekDay.plusDays(7)}T23:59:59Z") - val list = episodeService.findAllByDateRange(countryCode, start, end).toMutableList() - - return startOfWeekDay.datesUntil(startOfWeekDay.plusDays(7)).map { date -> - val dateTitle = date.format( - DateTimeFormatter.ofPattern( - "EEEE", - Locale.of(countryCode.locale.split("-")[0], countryCode.locale.split("-")[1]) - ) - ).capitalizeWords() + val list = episodeService.findAllByDateRange(countryCode, start, end) + val pattern = DateTimeFormatter.ofPattern("EEEE", Locale.of(countryCode.locale.split("-")[0], countryCode.locale.split("-")[1])) + + return startOfWeekDay.datesUntil(startOfWeekDay.plusDays(7)).toList().map { date -> + val dateTitle = date.format(pattern).capitalizeWords() val episodes = list.filter { it.releaseDateTime.dayOfWeek == date.dayOfWeek } .sortedWith(compareBy({ it.releaseDateTime.toLocalTime() }, { it.anime?.name?.lowercase() })) WeeklyAnimesDto( dateTitle, - AbstractConverter.convert( - episodes.distinctBy { episode -> episode.anime?.uuid }, - EpisodeDto::class.java - ).map { episodeDto -> + episodes.distinctBy { episode -> episode.anime?.uuid }.map { distinctEpisode -> + val platforms = episodes.mapNotNull { episode -> + if (episode.anime?.uuid == distinctEpisode.anime?.uuid) + episode.platform!! + else null + }.distinct() + WeeklyAnimeDto( - episodeDto.anime, - episodeDto.releaseDateTime, - AbstractConverter.convert(episodes.filter { episode -> episode.anime?.uuid == episodeDto.anime.uuid } - .map { episode -> episode.platform!! } - .distinct(), PlatformDto::class.java) + AbstractConverter.convert(distinctEpisode.anime, AnimeNoStatusDto::class.java).toAnimeDto(), + distinctEpisode.releaseDateTime.withUTC().format(DateTimeFormatter.ISO_OFFSET_DATE_TIME), + AbstractConverter.convert(platforms, PlatformDto::class.java) ) } ) - }.toList() + } } fun addImage(uuid: UUID, image: String, bypass: Boolean = false) { diff --git a/src/main/kotlin/fr/shikkanime/services/caches/AnimeCacheService.kt b/src/main/kotlin/fr/shikkanime/services/caches/AnimeCacheService.kt index ae67ca44..fb33f200 100644 --- a/src/main/kotlin/fr/shikkanime/services/caches/AnimeCacheService.kt +++ b/src/main/kotlin/fr/shikkanime/services/caches/AnimeCacheService.kt @@ -5,9 +5,9 @@ import fr.shikkanime.caches.CountryCodeLocalDateKeyCache import fr.shikkanime.caches.CountryCodeNamePaginationKeyCache import fr.shikkanime.caches.CountryCodeUUIDSortPaginationKeyCache import fr.shikkanime.converters.AbstractConverter -import fr.shikkanime.dtos.AnimeDto import fr.shikkanime.dtos.PageableDto import fr.shikkanime.dtos.WeeklyAnimesDto +import fr.shikkanime.dtos.animes.AnimeDto import fr.shikkanime.entities.Anime import fr.shikkanime.entities.Episode import fr.shikkanime.entities.SortParameter diff --git a/src/main/kotlin/fr/shikkanime/utils/StringUtils.kt b/src/main/kotlin/fr/shikkanime/utils/StringUtils.kt index 6a443d09..d4a36ee3 100644 --- a/src/main/kotlin/fr/shikkanime/utils/StringUtils.kt +++ b/src/main/kotlin/fr/shikkanime/utils/StringUtils.kt @@ -10,15 +10,11 @@ import java.util.regex.Pattern object StringUtils { private val NONLATIN: Pattern = Pattern.compile("[^\\w-]") private val WHITESPACE: Pattern = Pattern.compile("\\s") + private val regex = "([-|!].*[-|!])|(Saison \\d*)|\\(\\d*\\)".toRegex() + private val separators = listOf(":", ",", "!", "–", " so ") fun getShortName(fullName: String): String { - val regexs = listOf("[-|!].*[-|!]".toRegex(), "Saison \\d*".toRegex(), "\\(\\d*\\)".toRegex()) - val separators = listOf(":", ",", "!", " so ") - var shortName = fullName - - regexs.forEach { regex -> - shortName = regex.replace(shortName, "") - } + var shortName = regex.replace(fullName, "") separators.forEach { separator -> if (shortName.contains(separator)) { @@ -32,8 +28,7 @@ object StringUtils { } } - shortName = shortName.replace(" +".toRegex(), " ") - return shortName.trim() + return shortName.replace(" +".toRegex(), " ").trim() } fun getHashtag(fullName: String) = getShortName(fullName).capitalizeWords().filter { it.isLetterOrDigit() } diff --git a/src/main/resources/db/changelog/2024/04/01-changelog.xml b/src/main/resources/db/changelog/2024/04/01-changelog.xml new file mode 100644 index 00000000..b1c88f80 --- /dev/null +++ b/src/main/resources/db/changelog/2024/04/01-changelog.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 7ec47419..75c2b01b 100644 --- a/src/main/resources/db/changelog/db.changelog-master.xml +++ b/src/main/resources/db/changelog/db.changelog-master.xml @@ -38,4 +38,6 @@ + + \ No newline at end of file diff --git a/src/main/resources/templates/_freemarker_implicit.ftl b/src/main/resources/templates/_freemarker_implicit.ftl index 7c02e5fe..a24584c4 100644 --- a/src/main/resources/templates/_freemarker_implicit.ftl +++ b/src/main/resources/templates/_freemarker_implicit.ftl @@ -7,13 +7,13 @@ [#-- @ftlvariable name="platforms" type="kotlin.collections.AbstractList" --] [#-- @ftlvariable name="platform" type="fr.shikkanime.entities.enums.Platform" --] [#-- @ftlvariable name="error" type="kotlin.NumbersKt" --] -[#-- @ftlvariable name="anime" type="fr.shikkanime.dtos.AnimeDto" --] +[#-- @ftlvariable name="anime" type="fr.shikkanime.dtos.animes.AnimeDto" --] [#-- @ftlvariable name="simulcast_config" type="fr.shikkanime.platforms.configuration.PlatformSimulcast" --] [#-- @ftlvariable name="episode" type="fr.shikkanime.dtos.EpisodeDto" --] [#-- @ftlvariable name="episodeTypes" type="kotlin.collections.AbstractList" --] [#-- @ftlvariable name="langTypes" type="kotlin.collections.AbstractList" --] [#-- @ftlvariable name="config" type="fr.shikkanime.dtos.ConfigDto" --] -[#-- @ftlvariable name="animes" type="kotlin.collections.AbstractList" --] +[#-- @ftlvariable name="animes" type="kotlin.collections.AbstractList" --] [#-- @ftlvariable name="episodes" type="kotlin.collections.AbstractList" --] [#-- @ftlvariable name="size" type="java.lang.Integer" --] [#-- @ftlvariable name="originalSize" type="java.lang.String" --] diff --git a/src/test/kotlin/fr/shikkanime/controllers/admin/AdminControllerTest.kt b/src/test/kotlin/fr/shikkanime/controllers/admin/AdminControllerTest.kt index 108d2896..eaaad67a 100644 --- a/src/test/kotlin/fr/shikkanime/controllers/admin/AdminControllerTest.kt +++ b/src/test/kotlin/fr/shikkanime/controllers/admin/AdminControllerTest.kt @@ -4,7 +4,7 @@ import com.google.inject.Inject import com.microsoft.playwright.Page import com.microsoft.playwright.junit.UsePlaywright import fr.shikkanime.converters.AbstractConverter -import fr.shikkanime.dtos.AnimeDto +import fr.shikkanime.dtos.animes.AnimeDto import fr.shikkanime.entities.Anime import fr.shikkanime.entities.Episode import fr.shikkanime.entities.enums.EpisodeType diff --git a/src/test/kotlin/fr/shikkanime/controllers/api/AnimeControllerTest.kt b/src/test/kotlin/fr/shikkanime/controllers/api/AnimeControllerTest.kt index d82a4556..5aa4b6cf 100644 --- a/src/test/kotlin/fr/shikkanime/controllers/api/AnimeControllerTest.kt +++ b/src/test/kotlin/fr/shikkanime/controllers/api/AnimeControllerTest.kt @@ -3,10 +3,10 @@ package fr.shikkanime.controllers.api import com.google.gson.reflect.TypeToken import com.google.inject.Inject import fr.shikkanime.converters.AbstractConverter -import fr.shikkanime.dtos.AnimeDto import fr.shikkanime.dtos.MessageDto import fr.shikkanime.dtos.PageableDto import fr.shikkanime.dtos.WeeklyAnimesDto +import fr.shikkanime.dtos.animes.AnimeDto import fr.shikkanime.entities.Anime import fr.shikkanime.entities.Episode import fr.shikkanime.entities.enums.CountryCode diff --git a/src/test/kotlin/fr/shikkanime/controllers/api/AttachmentControllerTest.kt b/src/test/kotlin/fr/shikkanime/controllers/api/AttachmentControllerTest.kt index a6d1ff0d..e7cde950 100644 --- a/src/test/kotlin/fr/shikkanime/controllers/api/AttachmentControllerTest.kt +++ b/src/test/kotlin/fr/shikkanime/controllers/api/AttachmentControllerTest.kt @@ -2,7 +2,7 @@ package fr.shikkanime.controllers.api import com.google.inject.Inject import fr.shikkanime.converters.AbstractConverter -import fr.shikkanime.dtos.AnimeDto +import fr.shikkanime.dtos.animes.AnimeDto import fr.shikkanime.entities.Anime import fr.shikkanime.module import fr.shikkanime.services.AnimeService diff --git a/src/test/kotlin/fr/shikkanime/controllers/api/EpisodeControllerTest.kt b/src/test/kotlin/fr/shikkanime/controllers/api/EpisodeControllerTest.kt index 63b6b91d..881dd740 100644 --- a/src/test/kotlin/fr/shikkanime/controllers/api/EpisodeControllerTest.kt +++ b/src/test/kotlin/fr/shikkanime/controllers/api/EpisodeControllerTest.kt @@ -3,9 +3,9 @@ package fr.shikkanime.controllers.api import com.google.gson.reflect.TypeToken import com.google.inject.Inject import fr.shikkanime.converters.AbstractConverter -import fr.shikkanime.dtos.AnimeDto import fr.shikkanime.dtos.EpisodeDto import fr.shikkanime.dtos.PageableDto +import fr.shikkanime.dtos.animes.AnimeDto import fr.shikkanime.entities.Anime import fr.shikkanime.entities.Episode import fr.shikkanime.entities.enums.EpisodeType diff --git a/src/test/kotlin/fr/shikkanime/jobs/FetchDeprecatedEpisodeJobTest.kt b/src/test/kotlin/fr/shikkanime/jobs/FetchDeprecatedEpisodeJobTest.kt index cbadd345..9efecb50 100644 --- a/src/test/kotlin/fr/shikkanime/jobs/FetchDeprecatedEpisodeJobTest.kt +++ b/src/test/kotlin/fr/shikkanime/jobs/FetchDeprecatedEpisodeJobTest.kt @@ -2,7 +2,7 @@ package fr.shikkanime.jobs import com.google.inject.Inject import fr.shikkanime.converters.AbstractConverter -import fr.shikkanime.dtos.AnimeDto +import fr.shikkanime.dtos.animes.AnimeDto import fr.shikkanime.entities.Anime import fr.shikkanime.entities.Config import fr.shikkanime.entities.Episode @@ -41,7 +41,7 @@ class FetchDeprecatedEpisodeJobTest { Constant.injector.injectMembers(this) Constant.injector.injectMembers(fetchDeprecatedEpisodeJob) - val listFiles = File(ClassLoader.getSystemClassLoader().getResource("animes")?.file).listFiles() + val listFiles = ClassLoader.getSystemClassLoader().getResource("animes")?.file?.let { File(it).listFiles() } listFiles ?.sortedBy { it.name.lowercase() } diff --git a/src/test/kotlin/fr/shikkanime/services/EpisodeServiceTest.kt b/src/test/kotlin/fr/shikkanime/services/EpisodeServiceTest.kt index a06df5b2..71c34458 100644 --- a/src/test/kotlin/fr/shikkanime/services/EpisodeServiceTest.kt +++ b/src/test/kotlin/fr/shikkanime/services/EpisodeServiceTest.kt @@ -56,6 +56,7 @@ class EpisodeServiceTest { image = "https://www.shikkanime.com/image.png", banner = "https://www.shikkanime.com/image.png", releaseDateTime = releaseDateTime, + slug = "test", ), episodeType = EpisodeType.EPISODE, langType = LangType.SUBTITLES, @@ -90,6 +91,7 @@ class EpisodeServiceTest { image = "https://www.shikkanime.com/image.png", banner = "https://www.shikkanime.com/image.png", releaseDateTime = ZonedDateTime.parse("2023-12-20T00:00:00Z"), + slug = "test", ), episodeType = EpisodeType.EPISODE, langType = LangType.SUBTITLES, @@ -111,6 +113,7 @@ class EpisodeServiceTest { image = "https://www.shikkanime.com/image.png", banner = "https://www.shikkanime.com/image.png", releaseDateTime = ZonedDateTime.parse("2023-12-20T00:00:00Z"), + slug = "test", ), episodeType = EpisodeType.EPISODE, langType = LangType.SUBTITLES, @@ -140,6 +143,7 @@ class EpisodeServiceTest { image = "https://www.shikkanime.com/image.png", banner = "https://www.shikkanime.com/image.png", releaseDateTime = releaseDateTime, + slug = "test", ), episodeType = EpisodeType.EPISODE, langType = LangType.SUBTITLES, @@ -171,6 +175,7 @@ class EpisodeServiceTest { image = "https://www.shikkanime.com/image.png", banner = "https://www.shikkanime.com/image.png", releaseDateTime = releaseDateTime, + slug = "test", ), episodeType = EpisodeType.EPISODE, langType = LangType.SUBTITLES, @@ -195,6 +200,7 @@ class EpisodeServiceTest { image = "https://www.shikkanime.com/image.png", banner = "https://www.shikkanime.com/image.png", releaseDateTime = releaseDateTime, + slug = "test", ), episodeType = EpisodeType.EPISODE, langType = LangType.SUBTITLES, @@ -219,6 +225,7 @@ class EpisodeServiceTest { image = "https://www.shikkanime.com/image.png", banner = "https://www.shikkanime.com/image.png", releaseDateTime = releaseDateTime, + slug = "test", ), episodeType = EpisodeType.EPISODE, langType = LangType.SUBTITLES, @@ -243,6 +250,7 @@ class EpisodeServiceTest { image = "https://www.shikkanime.com/image.png", banner = "https://www.shikkanime.com/image.png", releaseDateTime = releaseDateTime, + slug = "test", ), episodeType = EpisodeType.EPISODE, langType = LangType.SUBTITLES, @@ -274,6 +282,7 @@ class EpisodeServiceTest { image = Constant.DEFAULT_IMAGE_PREVIEW, banner = Constant.DEFAULT_IMAGE_PREVIEW, releaseDateTime = ZonedDateTime.parse("2023-07-10T15:30:00Z"), + slug = "synduality-noir", ), episodeType = EpisodeType.EPISODE, langType = LangType.SUBTITLES, @@ -296,6 +305,7 @@ class EpisodeServiceTest { image = Constant.DEFAULT_IMAGE_PREVIEW, banner = Constant.DEFAULT_IMAGE_PREVIEW, releaseDateTime = ZonedDateTime.parse("2023-07-10T15:30:00Z"), + slug = "synduality-noir", ), episodeType = EpisodeType.EPISODE, langType = LangType.SUBTITLES, @@ -317,6 +327,7 @@ class EpisodeServiceTest { image = Constant.DEFAULT_IMAGE_PREVIEW, banner = Constant.DEFAULT_IMAGE_PREVIEW, releaseDateTime = ZonedDateTime.parse("2023-07-10T15:30:00Z"), + slug = "synduality-noir", ), episodeType = EpisodeType.EPISODE, langType = LangType.SUBTITLES, @@ -342,6 +353,7 @@ class EpisodeServiceTest { image = Constant.DEFAULT_IMAGE_PREVIEW, banner = Constant.DEFAULT_IMAGE_PREVIEW, releaseDateTime = ZonedDateTime.parse("2023-07-10T15:30:00Z"), + slug = "synduality-noir", ), episodeType = EpisodeType.EPISODE, langType = LangType.SUBTITLES, @@ -367,6 +379,7 @@ class EpisodeServiceTest { image = Constant.DEFAULT_IMAGE_PREVIEW, banner = Constant.DEFAULT_IMAGE_PREVIEW, releaseDateTime = ZonedDateTime.parse("2023-07-10T15:30:00Z"), + slug = "synduality-noir", ), episodeType = EpisodeType.EPISODE, langType = LangType.SUBTITLES, @@ -395,6 +408,7 @@ class EpisodeServiceTest { image = Constant.DEFAULT_IMAGE_PREVIEW, banner = Constant.DEFAULT_IMAGE_PREVIEW, releaseDateTime = ZonedDateTime.parse("2023-07-10T15:30:00Z"), + slug = "synduality-noir", ), episodeType = EpisodeType.EPISODE, langType = LangType.SUBTITLES, @@ -417,6 +431,7 @@ class EpisodeServiceTest { image = Constant.DEFAULT_IMAGE_PREVIEW, banner = Constant.DEFAULT_IMAGE_PREVIEW, releaseDateTime = ZonedDateTime.parse("2023-07-10T15:30:00Z"), + slug = "synduality-noir", ), episodeType = EpisodeType.EPISODE, langType = LangType.SUBTITLES, @@ -438,6 +453,7 @@ class EpisodeServiceTest { image = Constant.DEFAULT_IMAGE_PREVIEW, banner = Constant.DEFAULT_IMAGE_PREVIEW, releaseDateTime = ZonedDateTime.parse("2023-07-10T15:30:00Z"), + slug = "synduality-noir", ), episodeType = EpisodeType.EPISODE, langType = LangType.SUBTITLES, diff --git a/src/test/kotlin/fr/shikkanime/services/ImageServiceTest.kt b/src/test/kotlin/fr/shikkanime/services/ImageServiceTest.kt index f9e5f016..4b30ce69 100644 --- a/src/test/kotlin/fr/shikkanime/services/ImageServiceTest.kt +++ b/src/test/kotlin/fr/shikkanime/services/ImageServiceTest.kt @@ -1,10 +1,10 @@ package fr.shikkanime.services import fr.shikkanime.converters.AbstractConverter -import fr.shikkanime.dtos.AnimeDto import fr.shikkanime.dtos.EpisodeDto import fr.shikkanime.dtos.PlatformDto import fr.shikkanime.dtos.SimulcastDto +import fr.shikkanime.dtos.animes.AnimeDto import fr.shikkanime.dtos.enums.Status import fr.shikkanime.entities.enums.CountryCode import fr.shikkanime.entities.enums.EpisodeType diff --git a/src/test/kotlin/fr/shikkanime/utils/StringUtilsTest.kt b/src/test/kotlin/fr/shikkanime/utils/StringUtilsTest.kt index 4d4dfb08..d11172da 100644 --- a/src/test/kotlin/fr/shikkanime/utils/StringUtilsTest.kt +++ b/src/test/kotlin/fr/shikkanime/utils/StringUtilsTest.kt @@ -37,6 +37,7 @@ class StringUtilsTest { "Studio Apartment" to "Studio Apartment, Good Lighting, Angel Included", "I Was Reincarnated as the 7th Prince" to "I Was Reincarnated as the 7th Prince so I Can Take My Time Perfecting My Magical Ability", "Mushoku Tensei: Jobless Reincarnation" to "Mushoku Tensei: Jobless Reincarnation", + "Yuru Camp" to "Yuru Camp – Au grand air", ) list.forEach { (expected, input) -> diff --git a/src/test/resources/animes/dragon-ball.json b/src/test/resources/animes/dragon-ball.json index a3a17544..73793c61 100644 --- a/src/test/resources/animes/dragon-ball.json +++ b/src/test/resources/animes/dragon-ball.json @@ -10,5 +10,6 @@ "season": "WINTER", "year": 2024 } - ] + ], + "slug": "dragon-ball-z" } \ No newline at end of file diff --git a/src/test/resources/animes/naruto.json b/src/test/resources/animes/naruto.json index ba8bd541..047f6855 100644 --- a/src/test/resources/animes/naruto.json +++ b/src/test/resources/animes/naruto.json @@ -10,5 +10,6 @@ "season": "WINTER", "year": 2024 } - ] + ], + "slug": "naruto" } \ No newline at end of file diff --git a/src/test/resources/animes/one-piece.json b/src/test/resources/animes/one-piece.json index 0f4d8d45..894106db 100644 --- a/src/test/resources/animes/one-piece.json +++ b/src/test/resources/animes/one-piece.json @@ -10,5 +10,6 @@ "season": "WINTER", "year": 2024 } - ] + ], + "slug": "one-piece" } \ No newline at end of file diff --git a/src/test/resources/animes/two-piece.json b/src/test/resources/animes/two-piece.json index 5fa47700..74df5bdf 100644 --- a/src/test/resources/animes/two-piece.json +++ b/src/test/resources/animes/two-piece.json @@ -10,5 +10,6 @@ "season": "WINTER", "year": 2024 } - ] + ], + "slug": "two-piece" } \ No newline at end of file