From 05227eca80943fee031743347907cd263104dbc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9luchu?= Date: Mon, 7 Jul 2025 13:43:11 +0200 Subject: [PATCH] Include random endpoint --- .../com/jeluchu/core/utils/Constants.kt | 1 + .../features/anime/routes/AnimeRoutes.kt | 1 + .../features/anime/services/AnimeService.kt | 36 +++++++++++++++++++ .../features/anime/services/TagsService.kt | 29 +++++++++------ 4 files changed, 56 insertions(+), 11 deletions(-) diff --git a/src/main/kotlin/com/jeluchu/core/utils/Constants.kt b/src/main/kotlin/com/jeluchu/core/utils/Constants.kt index 73892c7..b804682 100644 --- a/src/main/kotlin/com/jeluchu/core/utils/Constants.kt +++ b/src/main/kotlin/com/jeluchu/core/utils/Constants.kt @@ -76,6 +76,7 @@ object Routes { const val THEMES = "/themes" const val SUGGESTIONS = "/suggestions" const val YEAR_INDEX = "/yearIndex" + const val RANDOM = "/random" } object TimerKey { diff --git a/src/main/kotlin/com/jeluchu/features/anime/routes/AnimeRoutes.kt b/src/main/kotlin/com/jeluchu/features/anime/routes/AnimeRoutes.kt index d54767e..98eee49 100644 --- a/src/main/kotlin/com/jeluchu/features/anime/routes/AnimeRoutes.kt +++ b/src/main/kotlin/com/jeluchu/features/anime/routes/AnimeRoutes.kt @@ -18,6 +18,7 @@ fun Route.animeEndpoints( ) = route(Routes.ANIME) { getToJson { service.getAnimeByType(call) } getToJson(Routes.ID) { service.getAnimeByMalId(call) } + getToJson(Routes.RANDOM) { service.getRandomAnime(call) } getToJson(Routes.LAST_EPISODES) { service.getLastEpisodes(call) } route(Routes.SUGGESTIONS) { diff --git a/src/main/kotlin/com/jeluchu/features/anime/services/AnimeService.kt b/src/main/kotlin/com/jeluchu/features/anime/services/AnimeService.kt index 6279394..4d2dcb9 100644 --- a/src/main/kotlin/com/jeluchu/features/anime/services/AnimeService.kt +++ b/src/main/kotlin/com/jeluchu/features/anime/services/AnimeService.kt @@ -1,6 +1,8 @@ package com.jeluchu.features.anime.services import com.jeluchu.core.connection.RestClient +import com.jeluchu.core.enums.AnimeStatusTypes +import com.jeluchu.core.enums.AnimeTypes import com.jeluchu.core.enums.TimeUnit import com.jeluchu.core.enums.parseAnimeStatusType import com.jeluchu.core.enums.parseAnimeType @@ -21,6 +23,7 @@ import com.jeluchu.features.anime.mappers.documentToAnimeLastEpisodeEntity import com.jeluchu.features.anime.mappers.documentToAnimeTypeEntity import com.jeluchu.features.anime.mappers.documentToMoreInfoEntity import com.mongodb.client.MongoDatabase +import com.mongodb.client.model.Aggregates import com.mongodb.client.model.Filters import com.mongodb.client.model.Sorts import io.ktor.http.* @@ -95,6 +98,39 @@ class AnimeService( call.respond(HttpStatusCode.NotFound, ErrorResponse(ErrorMessages.InvalidInput.message)) } + suspend fun getRandomAnime(call: RoutingCall) = try { + val nsfw = call.request.queryParameters["nsfw"]?.toBoolean() ?: false + + val filters = mutableListOf().apply { + add(Filters.`in`("type", listOf( + AnimeTypes.TV, + AnimeTypes.MOVIE, + AnimeTypes.OVA, + AnimeTypes.SPECIAL, + AnimeTypes.ONA, + AnimeTypes.TV_SPECIAL + ))) + + add(Filters.nin("status", listOf( + AnimeStatusTypes.UPCOMING + ))) + + if (!nsfw) add(Filters.eq("nsfw", false)) + } + + val aggregates = listOf( + Aggregates.match(Filters.and(filters)), + Aggregates.sample(1) + ) + + directoryCollection.aggregate(aggregates).firstOrNull()?.let { anime -> + val info = documentToMoreInfoEntity(anime) + call.respond(HttpStatusCode.OK, Json.encodeToString(info)) + } ?: call.respond(HttpStatusCode.NotFound, ErrorResponse(ErrorMessages.AnimeNotFound.message)) + } catch (ex: Exception) { + call.respond(HttpStatusCode.NotFound, ErrorResponse(ErrorMessages.InvalidInput.message)) + } + suspend fun getLastEpisodes(call: RoutingCall) = try { val dayOfWeek = LocalDate.now() .dayOfWeek diff --git a/src/main/kotlin/com/jeluchu/features/anime/services/TagsService.kt b/src/main/kotlin/com/jeluchu/features/anime/services/TagsService.kt index f427a4b..e15dca3 100644 --- a/src/main/kotlin/com/jeluchu/features/anime/services/TagsService.kt +++ b/src/main/kotlin/com/jeluchu/features/anime/services/TagsService.kt @@ -1,6 +1,7 @@ package com.jeluchu.features.anime.services import com.jeluchu.core.enums.AnimeStatusTypes +import com.jeluchu.core.enums.AnimeTypes import com.jeluchu.core.models.documentToSimpleAnimeEntity import com.jeluchu.core.utils.Collections import com.mongodb.client.MongoCollection @@ -19,6 +20,7 @@ class TagsService( ) { suspend fun getAnimeByAnyTag(call: RoutingCall) { val tags = call.request.queryParameters["tags"].orEmpty() + val nsfw = call.request.queryParameters["nsfw"].toBoolean() val tagsList = if (tags.isNotEmpty()) { tags.split(",").map { it.trim() } @@ -29,17 +31,22 @@ class TagsService( return } - val query = directory.find( - Filters.and( - Filters.or( - Filters.`in`("tags.es", tagsList), - Filters.`in`("tags.en", tagsList) - ), - Filters.`in`("status", listOf(AnimeStatusTypes.FINISHED, AnimeStatusTypes.ONGOING)), - Filters.ne("type", "MUSIC"), - Filters.ne("type", "PV") - ) - ) + val filters = mutableListOf().apply { + add(Filters.or( + Filters.`in`("tags.es", tagsList), + Filters.`in`("tags.en", tagsList) + )) + + add(Filters.`in`("status", listOf(AnimeStatusTypes.FINISHED, AnimeStatusTypes.ONGOING))) + + add(Filters.ne("type", AnimeTypes.MUSIC)) + add(Filters.ne("type", AnimeTypes.PV)) + add(Filters.ne("type", AnimeTypes.CM)) + + if (!nsfw) add(Filters.eq("nsfw", false)) + } + + val query = directory.find(Filters.and(filters)) .toList() .map { documentToSimpleAnimeEntity(it) }