Skip to content

Commit

Permalink
Add episode page
Browse files Browse the repository at this point in the history
  • Loading branch information
Ziedelth committed Jun 24, 2024
1 parent c816c88 commit 9754b23
Show file tree
Hide file tree
Showing 36 changed files with 475 additions and 151 deletions.
27 changes: 26 additions & 1 deletion .github/workflows/global_workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -121,13 +121,38 @@ jobs:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Cache Docker layers
if: github.actor != 'dependabot[bot]' && github.event_name == 'push'
uses: actions/cache@v4
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-docker-staging-${{ hashFiles('Dockerfile') }}
restore-keys: |
${{ runner.os }}-docker-staging-
- name: Login to GitHub Container Registry
if: github.actor != 'dependabot[bot]' && github.event_name == 'push'
uses: docker/login-action@v3
with:
registry: registry.shikkanime.fr:5000
username: ziedelth
password: ${{ secrets.REGISTRY_PASSWORD }}

- name: Build docker file
uses: docker/build-push-action@v6
with:
context: .
push: false
push: github.event_name == 'push'
tags: registry.shikkanime.fr:5000/shikkanime-core:dev
platforms: ${{ matrix.platform }}
cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,dest=/tmp/.buildx-cache-new

- name: Move cache
if: github.actor != 'dependabot[bot]' && github.event_name == 'push'
run: |
rm -rf /tmp/.buildx-cache
mv /tmp/.buildx-cache-new /tmp/.buildx-cache
clear_cache:
runs-on: ubuntu-latest
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package fr.shikkanime.caches

import fr.shikkanime.entities.enums.CountryCode
import fr.shikkanime.entities.enums.EpisodeType

data class CountryCodeSlugSeasonEpisodeTypeNumberKeyCache(
val countryCode: CountryCode,
val slug: String,
val season: Int,
val episodeType: EpisodeType,
val number: Int
)
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ package fr.shikkanime.controllers.api

import com.google.inject.Inject
import fr.shikkanime.converters.AbstractConverter
import fr.shikkanime.dtos.EpisodeMappingDto
import fr.shikkanime.dtos.PageableDto
import fr.shikkanime.dtos.enums.Status
import fr.shikkanime.dtos.mappings.EpisodeMappingDto
import fr.shikkanime.dtos.variants.EpisodeVariantDto
import fr.shikkanime.entities.enums.CountryCode
import fr.shikkanime.services.EpisodeMappingService
Expand Down
28 changes: 0 additions & 28 deletions src/main/kotlin/fr/shikkanime/controllers/api/MemberController.kt
Original file line number Diff line number Diff line change
Expand Up @@ -37,20 +37,6 @@ class MemberController {
@Inject
private lateinit var memberFollowEpisodeService: MemberFollowEpisodeService

@Path("/private-register")
@Post
@OpenAPI(
description = "Register a private member",
responses = [
OpenAPIResponse(201, "Private member registered", Map::class),
],
deprecated = true
)
@Deprecated("You should use /register instead", ReplaceWith("/register"))
private fun registerPrivateMember(): Response {
return registerMember()
}

@Path("/register")
@Post
@OpenAPI(
Expand All @@ -70,20 +56,6 @@ class MemberController {
return Response.created(mapOf("identifier" to identifier))
}

@Path("/private-login")
@Post
@OpenAPI(
description = "Login a private member",
responses = [
OpenAPIResponse(200, "Private member logged in"),
],
deprecated = true
)
@Deprecated("You should use /login instead", ReplaceWith("/login"))
private fun loginPrivateMember(@BodyParam identifier: String): Response {
return loginMember(identifier)
}

@Path("/login")
@Post
@OpenAPI(
Expand Down
115 changes: 47 additions & 68 deletions src/main/kotlin/fr/shikkanime/controllers/site/SiteController.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import fr.shikkanime.dtos.AnimeDto
import fr.shikkanime.entities.SortParameter
import fr.shikkanime.entities.enums.ConfigPropertyKey
import fr.shikkanime.entities.enums.CountryCode
import fr.shikkanime.entities.enums.EpisodeType
import fr.shikkanime.entities.enums.Link
import fr.shikkanime.services.caches.AnimeCacheService
import fr.shikkanime.services.caches.ConfigCacheService
Expand Down Expand Up @@ -120,14 +121,10 @@ class SiteController {
)
}

@Path("animes/{slug}")
@Get
private fun animeDetail(@PathParam("slug") slug: String): Response {
private fun getAnimeDetail(slug: String, season: Int? = null, page: Int? = null): Response {
val dto = animeCacheService.findBySlug(CountryCode.FR, slug) ?: return Response.notFound()
val seasonDto = dto.seasons.firstOrNull() ?: return Response.notFound()

val seasonDto = dto.seasons.firstOrNull { it.number == (season ?: it.number) } ?: return Response.notFound()
val limit = configCacheService.getValueAsInt(ConfigPropertyKey.ANIME_EPISODES_SIZE_LIMIT, 24)

val findAllBy = episodeMappingCacheService.findAllBy(
CountryCode.FR,
dto.uuid,
Expand All @@ -138,98 +135,80 @@ class SiteController {
SortParameter("episodeType", SortParameter.Order.ASC),
SortParameter("number", SortParameter.Order.ASC),
),
1,
page ?: 1,
limit
)
)!!

val title = dto.shortName + (season?.let { " - Saison $it" } ?: "")
val showMore = ((((page ?: 1) - 1) * limit) + findAllBy.data.size < findAllBy.total.toInt())

return Response.template(
"/site/anime.ftl",
dto.shortName,
title,
mutableMapOf(
"description" to dto.description?.let { StringUtils.sanitizeXSS(it) },
"anime" to dto,
"episodeMappings" to findAllBy!!.data,
"showMore" to (findAllBy.data.size < findAllBy.total.toInt()),
"showLess" to false,
"season" to if (season != null) seasonDto else null,
"episodeMappings" to findAllBy.data,
"showMore" to showMore,
"showLess" to ((page ?: 1) > 1),
"page" to page,
)
)
}

@Path("animes/{slug}")
@Get
private fun animeDetail(
@PathParam("slug") slug: String
) = getAnimeDetail(slug)

@Path("animes/{slug}/season-{season}")
@Get
private fun animeDetailBySeason(
@PathParam("slug") slug: String,
@PathParam("season") season: Int
): Response {
val dto = animeCacheService.findBySlug(CountryCode.FR, slug) ?: return Response.notFound()
val seasonDto = dto.seasons.firstOrNull { it.number == season } ?: return Response.notFound()

val limit = configCacheService.getValueAsInt(ConfigPropertyKey.ANIME_EPISODES_SIZE_LIMIT, 24)

val findAllBy = episodeMappingCacheService.findAllBy(
CountryCode.FR,
dto.uuid,
season,
listOf(
SortParameter("releaseDateTime", SortParameter.Order.ASC),
SortParameter("season", SortParameter.Order.ASC),
SortParameter("episodeType", SortParameter.Order.ASC),
SortParameter("number", SortParameter.Order.ASC),
),
1,
limit
)

return Response.template(
"/site/anime.ftl",
"${dto.shortName} - Saison $season",
mutableMapOf(
"description" to dto.description?.let { StringUtils.sanitizeXSS(it) },
"anime" to dto,
"season" to seasonDto,
"episodeMappings" to findAllBy!!.data,
"showMore" to (findAllBy.data.size < findAllBy.total.toInt()),
"showLess" to false,
)
)
}
) = getAnimeDetail(slug, season)

@Path("animes/{slug}/season-{season}/page-{page}")
@Get
private fun animeDetailBySeasonAndPage(
@PathParam("slug") slug: String,
@PathParam("season") season: Int,
@PathParam("page") page: Int
) = getAnimeDetail(slug, season, page)

@Path("animes/{slug}/season-{season}/{episodeSlug}")
@Get
private fun episodeDetails(
@PathParam("slug") slug: String,
@PathParam("season") season: Int,
@PathParam("episodeSlug") episodeSlug: String
): Response {
val dto = animeCacheService.findBySlug(CountryCode.FR, slug) ?: return Response.notFound()
val seasonDto = dto.seasons.firstOrNull { it.number == season } ?: return Response.notFound()
val regex = Regex("(${EpisodeType.entries.joinToString("|") { it.slug }})-(\\d+)")
val match = regex.find(episodeSlug) ?: return Response.notFound()
val episodeType = EpisodeType.fromSlug(match.groupValues[1])
val episodeNumber = match.groupValues[2].toInt()

val limit = configCacheService.getValueAsInt(ConfigPropertyKey.ANIME_EPISODES_SIZE_LIMIT, 24)
val findAllBy = episodeMappingCacheService.findAllBy(
val (previousDto, currentDto, nextDto) = episodeMappingCacheService.findByAnimeSeasonEpisodeTypeNumber(
CountryCode.FR,
dto.uuid,
slug,
season,
listOf(
SortParameter("releaseDateTime", SortParameter.Order.ASC),
SortParameter("season", SortParameter.Order.ASC),
SortParameter("episodeType", SortParameter.Order.ASC),
SortParameter("number", SortParameter.Order.ASC),
),
page,
limit
)
episodeType,
episodeNumber
) ?: return Response.notFound()

val title =
currentDto.anime.shortName + " - Saison $season ${StringUtils.getEpisodeTypeLabel(episodeType)} ${currentDto.number}"

return Response.template(
"/site/anime.ftl",
"${dto.shortName} - Saison $season",
"/site/episodeDetails.ftl",
title,
mutableMapOf(
"description" to dto.description?.let { StringUtils.sanitizeXSS(it) },
"anime" to dto,
"season" to seasonDto,
"episodeMappings" to findAllBy!!.data,
"showMore" to (((page - 1) * limit) + findAllBy.data.size < findAllBy.total.toInt()),
"showLess" to (page > 1),
"page" to page,
"description" to currentDto.description?.let { StringUtils.sanitizeXSS(it) },
"episodeMapping" to currentDto,
"previousEpisode" to previousDto,
"nextEpisode" to nextDto,
)
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ import fr.shikkanime.converters.AbstractConverter
import fr.shikkanime.dtos.AnimeDto
import fr.shikkanime.dtos.SeasonDto
import fr.shikkanime.dtos.SimulcastDto
import fr.shikkanime.dtos.mappings.EpisodeMappingWithoutAnimeDto
import fr.shikkanime.entities.Anime
import fr.shikkanime.entities.enums.LangType
import fr.shikkanime.services.EpisodeMappingService
import fr.shikkanime.services.SimulcastService.Companion.sortBySeasonAndYear
import fr.shikkanime.services.caches.EpisodeVariantCacheService
import fr.shikkanime.utils.StringUtils
import fr.shikkanime.utils.withUTCString
import org.hibernate.Hibernate
import java.time.ZonedDateTime

class AnimeToAnimeDtoConverter : AbstractConverter<Anime, AnimeDto>() {
Expand Down Expand Up @@ -43,6 +45,13 @@ class AnimeToAnimeDtoConverter : AbstractConverter<Anime, AnimeDto>() {
langTypes = audioLocales.map { LangType.fromAudioLocale(from.countryCode, it) }.distinct().sorted(),
seasons = episodeMappingService.findAllSeasonsByAnime(from)
.map { SeasonDto(it[0] as Int, (it[1] as ZonedDateTime).withUTCString()) },
episodes = if (Hibernate.isInitialized(from.mappings))
convert(
from.mappings.sortedBy { it.releaseDateTime },
EpisodeMappingWithoutAnimeDto::class.java
)?.toList()
else
null,
status = from.status,
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ package fr.shikkanime.converters.episode_mapping
import com.google.inject.Inject
import fr.shikkanime.converters.AbstractConverter
import fr.shikkanime.dtos.AnimeDto
import fr.shikkanime.dtos.EpisodeMappingDto
import fr.shikkanime.dtos.PlatformDto
import fr.shikkanime.dtos.mappings.EpisodeMappingDto
import fr.shikkanime.dtos.variants.EpisodeVariantWithoutMappingDto
import fr.shikkanime.entities.EpisodeMapping
import fr.shikkanime.entities.enums.LangType
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package fr.shikkanime.converters.episode_mapping

import fr.shikkanime.converters.AbstractConverter
import fr.shikkanime.dtos.mappings.EpisodeMappingWithoutAnimeDto
import fr.shikkanime.entities.EpisodeMapping
import fr.shikkanime.utils.withUTCString

class EpisodeMappingToEpisodeMappingWithoutAnimeDtoConverter :
AbstractConverter<EpisodeMapping, EpisodeMappingWithoutAnimeDto>() {
override fun convert(from: EpisodeMapping): EpisodeMappingWithoutAnimeDto {
return EpisodeMappingWithoutAnimeDto(
uuid = from.uuid!!,
releaseDateTime = from.releaseDateTime.withUTCString(),
lastReleaseDateTime = from.lastReleaseDateTime.withUTCString(),
lastUpdateDateTime = from.lastUpdateDateTime.withUTCString(),
episodeType = from.episodeType!!,
season = from.season!!,
number = from.number!!,
duration = from.duration,
title = from.title,
description = from.description,
image = from.image!!,
status = from.status
)
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package fr.shikkanime.converters.episode_variant

import fr.shikkanime.converters.AbstractConverter
import fr.shikkanime.dtos.EpisodeMappingDto
import fr.shikkanime.dtos.PlatformDto
import fr.shikkanime.dtos.mappings.EpisodeMappingDto
import fr.shikkanime.dtos.variants.EpisodeVariantDto
import fr.shikkanime.entities.EpisodeVariant
import fr.shikkanime.utils.withUTCString
Expand Down
2 changes: 2 additions & 0 deletions src/main/kotlin/fr/shikkanime/dtos/AnimeDto.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package fr.shikkanime.dtos

import fr.shikkanime.dtos.enums.Status
import fr.shikkanime.dtos.mappings.EpisodeMappingWithoutAnimeDto
import fr.shikkanime.entities.enums.CountryCode
import fr.shikkanime.entities.enums.LangType
import java.util.*
Expand All @@ -20,5 +21,6 @@ data class AnimeDto(
val audioLocales: List<String>? = null,
val langTypes: List<LangType>? = null,
val seasons: List<SeasonDto> = emptyList(),
var episodes: List<EpisodeMappingWithoutAnimeDto>? = null,
val status: Status? = null,
)
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package fr.shikkanime.dtos
package fr.shikkanime.dtos.mappings

import fr.shikkanime.dtos.AnimeDto
import fr.shikkanime.dtos.PlatformDto
import fr.shikkanime.dtos.enums.Status
import fr.shikkanime.dtos.variants.EpisodeVariantWithoutMappingDto
import fr.shikkanime.entities.enums.EpisodeType
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package fr.shikkanime.dtos.mappings

import fr.shikkanime.dtos.enums.Status
import fr.shikkanime.entities.enums.EpisodeType
import java.util.*

data class EpisodeMappingWithoutAnimeDto(
val uuid: UUID,
val releaseDateTime: String,
val lastReleaseDateTime: String,
val lastUpdateDateTime: String,
var episodeType: EpisodeType,
val season: Int,
val number: Int,
val duration: Long,
val title: String?,
val description: String?,
val image: String,
val status: Status,
)
Loading

0 comments on commit 9754b23

Please sign in to comment.