Skip to content

Commit

Permalink
Merge pull request #261 from Shikkanime/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
Ziedelth committed Mar 8, 2024
2 parents 1112957 + 1bea6f3 commit 254ec25
Show file tree
Hide file tree
Showing 21 changed files with 159 additions and 33 deletions.
14 changes: 14 additions & 0 deletions src/main/kotlin/fr/shikkanime/controllers/site/SiteController.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import fr.shikkanime.utils.routes.Path
import fr.shikkanime.utils.routes.Response
import fr.shikkanime.utils.routes.method.Get
import fr.shikkanime.utils.routes.param.PathParam
import fr.shikkanime.utils.routes.param.QueryParam
import io.ktor.http.*

@Controller("/")
Expand Down Expand Up @@ -115,6 +116,19 @@ class SiteController {
)
}

@Path("search")
@Get
private fun search(
@QueryParam("q") query: String?,
): Response {
return Response.template(
Link.SEARCH,
mutableMapOf(
"query" to query
)
)
}

@Path("presentation")
@Get
private fun presentation(): Response {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import fr.shikkanime.converters.AbstractConverter
import fr.shikkanime.dtos.AnimeDto
import fr.shikkanime.entities.Anime
import fr.shikkanime.entities.Simulcast
import fr.shikkanime.entities.enums.CountryCode
import fr.shikkanime.services.AnimeService
import java.time.ZonedDateTime

Expand All @@ -19,7 +18,7 @@ class AnimeDtoToAnimeConverter : AbstractConverter<AnimeDto, Anime>() {
if (findByUuid != null)
return findByUuid

val findByName = animeService.findAllByLikeName(CountryCode.FR, from.name)
val findByName = animeService.findAllByLikeName(from.countryCode, from.name)

if (findByName.isNotEmpty())
return findByName.first()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,28 @@
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.enums.Status
import fr.shikkanime.entities.Anime
import fr.shikkanime.services.caches.LanguageCacheService
import fr.shikkanime.utils.StringUtils
import fr.shikkanime.utils.withUTC
import org.apache.tika.language.detect.LanguageDetector
import org.hibernate.Hibernate
import java.time.format.DateTimeFormatter

class AnimeToAnimeDtoConverter : AbstractConverter<Anime, AnimeDto>() {
private val languageDetector: LanguageDetector = LanguageDetector.getDefaultLanguageDetector().loadModels()
@Inject
private lateinit var languageCacheService: LanguageCacheService

override fun convert(from: Anime): AnimeDto {
val status = if (
from.image.isNullOrBlank() ||
from.banner.isNullOrBlank() ||
from.description.isNullOrBlank() ||
from.description?.startsWith("(") == true ||
languageDetector.detect(from.description).language.lowercase() != from.countryCode!!.name.lowercase()
languageCacheService.detectLanguage(from.description) != from.countryCode!!.name.lowercase()
) Status.INVALID else Status.VALID

return AnimeDto(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,25 @@
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.enums.Status
import fr.shikkanime.entities.Episode
import fr.shikkanime.services.caches.LanguageCacheService
import fr.shikkanime.utils.withUTC
import org.apache.tika.language.detect.LanguageDetector
import java.time.format.DateTimeFormatter

class EpisodeToEpisodeDtoConverter : AbstractConverter<Episode, EpisodeDto>() {
private val languageDetector: LanguageDetector = LanguageDetector.getDefaultLanguageDetector().loadModels()
@Inject
private lateinit var languageCacheService: LanguageCacheService

override fun convert(from: Episode): EpisodeDto {
val status = if (
from.image.isNullOrBlank() ||
from.description.isNullOrBlank() ||
from.description?.startsWith("(") == true ||
languageDetector.detect(from.description).language.lowercase() != from.anime!!.countryCode!!.name.lowercase() ||
languageCacheService.detectLanguage(from.description) != from.anime!!.countryCode!!.name.lowercase() ||
from.url?.contains("media-", true) == true
) Status.INVALID else Status.VALID

Expand Down
1 change: 1 addition & 0 deletions src/main/kotlin/fr/shikkanime/entities/enums/Link.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ enum class Link(
// Site
HOME("/", "/site/home.ftl", "", "Accueil", "${Constant.NAME} : Ne manquez plus jamais un épisode d'animé !"),
CATALOG("/catalog/{currentSimulcast}", "/site/catalog.ftl", "", "Catalogue"),
SEARCH("/search", "/site/search.ftl", "", "Recherche"),
PRESENTATION("/presentation", "/site/presentation.ftl", "", "Présentation", footer = true),
;
}
32 changes: 15 additions & 17 deletions src/main/kotlin/fr/shikkanime/jobs/FetchEpisodesJob.kt
Original file line number Diff line number Diff line change
Expand Up @@ -98,23 +98,21 @@ class FetchEpisodesJob : AbstractJob {
return
}

Constant.abstractSocialNetworks.forEach { socialNetwork ->
Thread {
try {
socialNetwork.sendEpisodeRelease(dto, mediaImage)
} catch (e: Exception) {
logger.log(
Level.SEVERE,
"Error while sending episode release for ${
socialNetwork.javaClass.simpleName.replace(
"SocialNetwork",
""
)
}",
e
)
}
}.start()
Constant.abstractSocialNetworks.parallelStream().forEach { socialNetwork ->
try {
socialNetwork.sendEpisodeRelease(dto, mediaImage)
} catch (e: Exception) {
logger.log(
Level.SEVERE,
"Error while sending episode release for ${
socialNetwork.javaClass.simpleName.replace(
"SocialNetwork",
""
)
}",
e
)
}
}
}
}
3 changes: 1 addition & 2 deletions src/main/kotlin/fr/shikkanime/modules/Security.kt
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,7 @@ fun Application.configureSecurity() {
return@validate validationSession(jwtVerifier, session, memberCacheService)
}
challenge {
// If content type is json, then respond with json
if (call.request.contentType() == ContentType.Application.Json) {
if (call.request.contentType() != ContentType.Text.Html) {
call.respond(
HttpStatusCode.Unauthorized,
MessageDto(MessageDto.Type.ERROR, "You are not authorized to access this page")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ class AnimeRepository : AbstractRepository<Anime>() {
override fun getEntityClass() = Anime::class.java

private fun Anime.initialize(): Anime {
Hibernate.initialize(this.simulcasts)
if (!Hibernate.isInitialized(this.simulcasts)) {
Hibernate.initialize(this.simulcasts)
}

return this
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ class EpisodeRepository : AbstractRepository<Episode>() {
override fun getEntityClass() = Episode::class.java

private fun Episode.initialize(): Episode {
Hibernate.initialize(this.anime?.simulcasts)
if (!Hibernate.isInitialized(this.anime?.simulcasts)) {
Hibernate.initialize(this.anime?.simulcasts)
}

return this
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ class MemberRepository : AbstractRepository<Member>() {
override fun getEntityClass() = Member::class.java

private fun Member.initialize(): Member {
Hibernate.initialize(this.roles)
if (!Hibernate.isInitialized(this.roles)) {
Hibernate.initialize(this.roles)
}

return this
}

Expand Down
4 changes: 3 additions & 1 deletion src/main/kotlin/fr/shikkanime/services/ImageService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -495,7 +495,9 @@ object ImageService {
ImageIO.read(URI(episode.anime.image!!).toURL()).resize((480 / scale).toInt(), (720 / scale).toInt())

val platformImage = try {
ImageIO.read(URI("http://localhost:37100/assets/img/platforms/${episode.platform.image}").toURL())
ImageIO.read(
ClassLoader.getSystemClassLoader().getResourceAsStream("assets/img/platforms/${episode.platform.image}")
)
.resize(32, 32)
} catch (e: Exception) {
e.printStackTrace()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package fr.shikkanime.services.caches

import fr.shikkanime.utils.MapCache
import org.apache.tika.language.detect.LanguageDetector

class LanguageCacheService : AbstractCacheService {
private val languageDetector: LanguageDetector = LanguageDetector.getDefaultLanguageDetector().loadModels()

private val detectCache = MapCache<String, String>(log = false) {
languageDetector.detect(it).language.lowercase()
}

fun detectLanguage(text: String?) = text?.let { detectCache[it] }
}
6 changes: 5 additions & 1 deletion src/main/kotlin/fr/shikkanime/utils/MapCache.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import java.time.Duration
class MapCache<K : Any, V>(
private var duration: Duration? = null,
private val classes: List<Class<*>> = listOf(),
private val log: Boolean = true,
private val block: (K) -> V,
) {
private lateinit var cache: LoadingCache<K, V>
Expand All @@ -27,7 +28,10 @@ class MapCache<K : Any, V>(
cache = builder
.build(object : CacheLoader<K, V & Any>() {
override fun load(key: K): V & Any {
logger.info("Loading $key")
if (log) {
logger.info("Loading $key")
}

return block(key)!!
}
})
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/assets/css/purged/bootstrap.min.css

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions src/main/resources/templates/_freemarker_implicit.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@
[#-- @ftlvariable name="currentSimulcast" type="fr.shikkanime.dtos.SimulcastDto" --]
[#-- @ftlvariable name="footerLinks" type="kotlin.collections.AbstractList<fr.shikkanime.entities.LinkObject>" --]
[#-- @ftlvariable name="seoLinks" type="kotlin.collections.AbstractList<fr.shikkanime.entities.enums.Link>" --]
[#-- @ftlvariable name="query" type="java.lang.String" --]
69 changes: 69 additions & 0 deletions src/main/resources/templates/site/search.ftl
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<#import "_navigation.ftl" as navigation />

<@navigation.display>
<div class="container my-3">
<input type="text" id="search" class="form-control-lg w-100 bg-dark text-white"
placeholder="Rechercher" value="<#if query??>${query}</#if>">
</div>

<div class="row justify-content-center" id="result-list" style="min-height: 50vh;">

</div>

<script src="/assets/js/main.js"></script>
<script>
<#if query??>
search('${query}');
</#if>
document.getElementById('search').addEventListener('input', function () {
if (this.value.length > 0) {
window.history.pushState({}, '', '/search?q=' + encodeURIComponent(this.value));
} else {
window.history.pushState({}, '', '/search');
}
search(this.value);
});
async function search(query) {
const trimmedQuery = query.trim();
if (trimmedQuery.length === 0) {
document.getElementById('result-list').innerHTML = '';
return;
}
const animes = await callApi('/api/v1/animes?name=' + trimmedQuery + '&limit=12');
document.getElementById('result-list').innerHTML = animes.data.map(anime => template(anime)).join('');
}
function template(anime) {
return `<div class="col-md-2 col-6 mt-0">
<article x-data="{ hover: false }">
<a href="/animes/` + anime.slug + `" class="text-decoration-none text-white" @mouseenter="hover = true"
@mouseleave="hover = false">
<div class="position-relative">
<img src="https://api.shikkanime.fr/v1/attachments?uuid=` + anime.uuid + `&type=image"
alt="` + anime.shortName.replace("\"", "'") + ` anime image" class="img-fluid" width="480"
height="720">
<span class="h6 mt-2 text-truncate-2">` + anime.shortName + `</span>
<div class="bg-black bg-opacity-75 position-absolute top-0 start-0 w-100 h-100 mh-100 p-3"
x-show="hover">
<div class="h6 text-truncate-2">
` + anime.name.toUpperCase() + `
</div>
<hr>
` + (anime.description != null ? `<div class="text-truncate-6">` + anime.description + `</div>` : ``) + `
</div>
</div>
</a>
</article>
</div>`;
}
</script>
</@navigation.display>
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,13 @@ class EpisodeControllerTest {
fun setUp() {
Constant.injector.injectMembers(this)

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
Expand All @@ -67,6 +74,7 @@ class EpisodeControllerTest {
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
Expand Down
1 change: 1 addition & 0 deletions src/test/resources/animes/dragon-ball.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"name": "Dragon Ball Z",
"releaseDateTime": "2024-01-01T00:00:00Z",
"image": "https://cdn.myanimelist.net/images/anime/1607/117271.jpg",
"banner": "https://cdn.myanimelist.net/images/anime/1607/117271.jpg",
"description": "Dragon Ball Z is a Japanese animated television series produced by Toei Animation. Dragon Ball Z is the sequel to the Dragon Ball anime and adapts the last 26 volumes of the original 42 volume Dragon Ball manga series created by Akira Toriyama The series Debut in 1988-1995 on Weekly Shounen Jump. Dragon Ball Z depicts the continuing adventures of Goku and his companions to defend against an assortment of villains which seek to destroy or rule the Earth.",
"simulcasts": [
{
Expand Down
1 change: 1 addition & 0 deletions src/test/resources/animes/naruto.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"name": "Naruto",
"releaseDateTime": "2024-01-01T00:00:00Z",
"image": "https://cdn.myanimelist.net/images/anime/13/17405.jpg",
"banner": "https://cdn.myanimelist.net/images/anime/13/17405.jpg",
"description": "Naruto Uzumaki, a mischievous adolescent ninja, struggles as he searches for recognition and dreams of becoming the Hokage, the village's leader and strongest ninja.",
"simulcasts": [
{
Expand Down
1 change: 1 addition & 0 deletions src/test/resources/animes/one-piece.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"name": "One Piece",
"releaseDateTime": "2024-01-01T00:00:00Z",
"image": "https://cdn.myanimelist.net/images/anime/1244/138851.jpg",
"banner": "https://cdn.myanimelist.net/images/anime/1244/138851.jpg",
"description": "Luffy et son équipage naviguent sur les mers à la recherche du légendaire trésor appelé « One Piece » et doivent faire face à de nombreuses aventures. Celui qui s'en emparera deviendra le roi des pirates !",
"simulcasts": [
{
Expand Down
1 change: 1 addition & 0 deletions src/test/resources/animes/two-piece.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"name": "Two Piece",
"releaseDateTime": "2024-01-01T00:00:00Z",
"image": "https://cdn.myanimelist.net/images/anime/1244/138851.jpg",
"banner": "https://cdn.myanimelist.net/images/anime/1244/138851.jpg",
"description": "Joke",
"simulcasts": [
{
Expand Down

0 comments on commit 254ec25

Please sign in to comment.