mirror of https://github.com/aruppi/aruppi-api.git
Include Schedule endpoints and prepare for Ranking endpoints
parent
1976c82603
commit
dfc1b5a2b8
@ -0,0 +1,27 @@
|
|||||||
|
package com.jeluchu.core.connection
|
||||||
|
|
||||||
|
import io.ktor.client.*
|
||||||
|
import io.ktor.client.engine.cio.*
|
||||||
|
import io.ktor.client.request.*
|
||||||
|
import io.ktor.client.statement.*
|
||||||
|
import io.ktor.http.*
|
||||||
|
import kotlinx.serialization.DeserializationStrategy
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
|
||||||
|
object RestClient {
|
||||||
|
private val client = HttpClient(CIO)
|
||||||
|
private val json = Json { ignoreUnknownKeys = true }
|
||||||
|
|
||||||
|
suspend fun <T> request(
|
||||||
|
url: String,
|
||||||
|
deserializer: DeserializationStrategy<T>
|
||||||
|
): T {
|
||||||
|
return runCatching {
|
||||||
|
val response = client.get(url) {
|
||||||
|
headers { append(HttpHeaders.Accept, ContentType.Application.Json.toString()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
json.decodeFromString(deserializer, response.bodyAsText())
|
||||||
|
}.getOrElse { throwable -> throw throwable }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
package com.jeluchu.core.extensions
|
||||||
|
|
||||||
|
import com.jeluchu.core.utils.TimeUnit
|
||||||
|
import com.jeluchu.core.utils.TimerKey
|
||||||
|
import com.mongodb.client.MongoCollection
|
||||||
|
import com.mongodb.client.model.Filters.eq
|
||||||
|
import com.mongodb.client.model.ReplaceOptions
|
||||||
|
import org.bson.Document
|
||||||
|
import java.time.Duration
|
||||||
|
import java.time.Instant
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
fun MongoCollection<Document>.needsUpdate(
|
||||||
|
key: String,
|
||||||
|
amount: Long = 5,
|
||||||
|
unit: TimeUnit = TimeUnit.HOUR
|
||||||
|
): Boolean {
|
||||||
|
val currentTime = Instant.now()
|
||||||
|
val timestampEntry = find(eq(TimerKey.KEY, key)).firstOrNull()
|
||||||
|
|
||||||
|
return if (timestampEntry == null) true else {
|
||||||
|
val lastUpdatedDate = timestampEntry.getDate(TimerKey.LAST_UPDATED)
|
||||||
|
val lastUpdated = lastUpdatedDate.toInstant()
|
||||||
|
val duration = Duration.between(lastUpdated, currentTime)
|
||||||
|
|
||||||
|
when (unit) {
|
||||||
|
TimeUnit.DAY -> duration.toDays() >= amount
|
||||||
|
TimeUnit.HOUR -> duration.toHours() >= amount
|
||||||
|
TimeUnit.MINUTE -> duration.toMinutes() >= amount
|
||||||
|
TimeUnit.SECOND -> duration.toSeconds() >= amount
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun MongoCollection<Document>.update(key: String) {
|
||||||
|
val currentTime = Instant.now()
|
||||||
|
val newTimestampDocument = Document(TimerKey.KEY, key)
|
||||||
|
.append(TimerKey.LAST_UPDATED, Date.from(currentTime))
|
||||||
|
|
||||||
|
replaceOne(
|
||||||
|
eq(TimerKey.KEY, TimerKey.SCHEDULE),
|
||||||
|
newTimestampDocument,
|
||||||
|
ReplaceOptions().upsert(true)
|
||||||
|
)
|
||||||
|
}
|
@ -1,10 +1,12 @@
|
|||||||
package com.jeluchu.core.messages
|
package com.jeluchu.core.messages
|
||||||
|
|
||||||
|
import com.jeluchu.core.utils.Day
|
||||||
|
|
||||||
sealed class ErrorMessages(val message: String) {
|
sealed class ErrorMessages(val message: String) {
|
||||||
data class Custom(val error: String) : ErrorMessages(error)
|
|
||||||
data object NotFound : ErrorMessages("Nyaaaaaaaan! This request has not been found by our alpaca-neko")
|
data object NotFound : ErrorMessages("Nyaaaaaaaan! This request has not been found by our alpaca-neko")
|
||||||
data object AnimeNotFound : ErrorMessages("This malId is not in our database")
|
data object AnimeNotFound : ErrorMessages("This malId is not in our database")
|
||||||
data object InvalidMalId : ErrorMessages("The provided id of malId is invalid")
|
data object InvalidMalId : ErrorMessages("The provided id of malId is invalid")
|
||||||
|
data object InvalidDay : ErrorMessages("Invalid 'day' parameter. Valid values are: ${Day.entries.joinToString(", ") { it.name.lowercase() }}")
|
||||||
data object InvalidInput : ErrorMessages("Invalid input provided")
|
data object InvalidInput : ErrorMessages("Invalid input provided")
|
||||||
data object UnauthorizedMongo : ErrorMessages("Check the MongoDb Connection String to be able to correctly access this request.")
|
data object UnauthorizedMongo : ErrorMessages("Check the MongoDb Connection String to be able to correctly access this request.")
|
||||||
}
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
package com.jeluchu.core.models
|
||||||
|
|
||||||
|
import java.time.Instant
|
||||||
|
|
||||||
|
data class TimestampEntry(
|
||||||
|
val key: String,
|
||||||
|
val lastUpdated: Instant
|
||||||
|
)
|
@ -0,0 +1,29 @@
|
|||||||
|
package com.jeluchu.core.models.jikan.anime
|
||||||
|
|
||||||
|
import com.jeluchu.core.models.jikan.anime.Prop
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Aired data class.
|
||||||
|
*/
|
||||||
|
@Serializable
|
||||||
|
data class Aired(
|
||||||
|
/**
|
||||||
|
* Start date in ISO8601 format.
|
||||||
|
*/
|
||||||
|
@SerialName("from")
|
||||||
|
val from: String? = "",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see Prop for the detail.
|
||||||
|
*/
|
||||||
|
@SerialName("prop")
|
||||||
|
val prop: Prop? = Prop(),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* End date in ISO8601 format.
|
||||||
|
*/
|
||||||
|
@SerialName("to")
|
||||||
|
val to: String? = ""
|
||||||
|
)
|
@ -0,0 +1,15 @@
|
|||||||
|
package com.jeluchu.core.models.jikan.anime
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Anime data class.
|
||||||
|
*/
|
||||||
|
data class Anime(
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data for anime requested.
|
||||||
|
*/
|
||||||
|
@SerialName("data")
|
||||||
|
val data: AnimeData
|
||||||
|
)
|
@ -0,0 +1,285 @@
|
|||||||
|
package com.jeluchu.core.models.jikan.anime
|
||||||
|
|
||||||
|
import com.jeluchu.core.utils.Day
|
||||||
|
import com.jeluchu.features.schedule.models.DayEntity
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AnimeInfo data class.
|
||||||
|
*/
|
||||||
|
@Serializable
|
||||||
|
data class AnimeData(
|
||||||
|
/**
|
||||||
|
* ID associated with MyAnimeList.
|
||||||
|
*/
|
||||||
|
@SerialName("mal_id")
|
||||||
|
val malId: Int? = 0,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Anime's MyAnimeList link.
|
||||||
|
*/
|
||||||
|
@SerialName("url")
|
||||||
|
val url: String? = "",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Anime's MyAnimeList cover/image link.
|
||||||
|
* @see Images for the detail.
|
||||||
|
*/
|
||||||
|
@SerialName("images")
|
||||||
|
val images: Images? = Images(),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Anime's official trailer URL.
|
||||||
|
* @see Trailer for the detail.
|
||||||
|
*/
|
||||||
|
@SerialName("trailer")
|
||||||
|
val trailer: Trailer? = Trailer(),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When entry is pending approval on MAL.
|
||||||
|
*/
|
||||||
|
@SerialName("approved")
|
||||||
|
val approved: Boolean? = false,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Title of the anime.
|
||||||
|
* @see Title for the detail.
|
||||||
|
*/
|
||||||
|
@SerialName("titles")
|
||||||
|
val titles: List<Title>? = emptyList(),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Title of the anime.
|
||||||
|
*/
|
||||||
|
@Deprecated("Use 'titles: List<Title>' to get the title")
|
||||||
|
@SerialName("title")
|
||||||
|
val title: String? = "",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Title of the anime in English.
|
||||||
|
*/
|
||||||
|
@Deprecated("Use 'titles: List<Title>' to get the title")
|
||||||
|
@SerialName("title_english")
|
||||||
|
val titleEnglish: String? = "",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Title of the anime in Japanese.
|
||||||
|
*/
|
||||||
|
@Deprecated("Use 'titles: List<Title>' to get the title")
|
||||||
|
@SerialName("title_japanese")
|
||||||
|
val titleJapanese: String? = "",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of anime's synonyms.
|
||||||
|
* @return null if there's none.
|
||||||
|
*/
|
||||||
|
@Deprecated("Use 'titles: List<Title>' to get the title")
|
||||||
|
@SerialName("title_synonyms")
|
||||||
|
val titleSynonyms: List<String>? = emptyList(),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type of the anime.
|
||||||
|
* @see AnimeType for the detail.
|
||||||
|
*/
|
||||||
|
@SerialName("type")
|
||||||
|
val type: String? = "",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Source of the anime.
|
||||||
|
*/
|
||||||
|
@SerialName("source")
|
||||||
|
val source : String? = "",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Total episode(s) of the anime.
|
||||||
|
*/
|
||||||
|
@SerialName("episodes")
|
||||||
|
val episodes: Int? = 0,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Status of the anime (e.g "Airing", "Not yet airing", etc).
|
||||||
|
*/
|
||||||
|
@SerialName("status")
|
||||||
|
val status : String? = "",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the anime is currently airing or not.
|
||||||
|
*/
|
||||||
|
@SerialName("airing")
|
||||||
|
val airing: Boolean? = false,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interval of airing time in ISO8601 format.
|
||||||
|
* @see Aired for the detail.
|
||||||
|
* @return null if there's none
|
||||||
|
*/
|
||||||
|
@SerialName("aired")
|
||||||
|
val aired: Aired? = Aired(),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Duration per episode.
|
||||||
|
*/
|
||||||
|
@SerialName("duration")
|
||||||
|
val duration : String? = "",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Age rating of the anime.
|
||||||
|
*/
|
||||||
|
@SerialName("rating")
|
||||||
|
val rating : String? = "",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Score at MyAnimeList. Formatted up to 2 decimal places.
|
||||||
|
*/
|
||||||
|
@SerialName("score")
|
||||||
|
val score: Float? = 0f,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of people/users that scored the anime.
|
||||||
|
*/
|
||||||
|
@SerialName("scored_by")
|
||||||
|
val scoredBy: Int? = 0,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Anime's score rank on MyAnimeList.
|
||||||
|
*/
|
||||||
|
@SerialName("rank")
|
||||||
|
val rank: Int? = 0,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Anime's popularity rank on MyAnimeList.
|
||||||
|
*/
|
||||||
|
@SerialName("popularity")
|
||||||
|
val popularity: Int? = 0,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Anime's members count on MyAnimeList.
|
||||||
|
*/
|
||||||
|
@SerialName("members")
|
||||||
|
val members: Int? = 0,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Anime's favorites count on MyAnimeList.
|
||||||
|
*/
|
||||||
|
@SerialName("favorites")
|
||||||
|
val favorites: Int? = 0,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Synopsis of the anime.
|
||||||
|
*/
|
||||||
|
@SerialName("synopsis")
|
||||||
|
val synopsis : String? = "",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Background info of the anime.
|
||||||
|
*/
|
||||||
|
@SerialName("background")
|
||||||
|
val background : String? = "",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Season where anime premiered.
|
||||||
|
*/
|
||||||
|
@SerialName("season")
|
||||||
|
val season: String? = "",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Year where anime premiered.
|
||||||
|
*/
|
||||||
|
@SerialName("year")
|
||||||
|
val year: Int? = 0,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Broadcast date of the anime (day and time).
|
||||||
|
* @see Broadcast for the detail.
|
||||||
|
*/
|
||||||
|
@SerialName("broadcast")
|
||||||
|
val broadcast: Broadcast? = Broadcast(),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of producers of this anime.
|
||||||
|
* @see Producer for the detail.
|
||||||
|
*/
|
||||||
|
@SerialName("producers")
|
||||||
|
val producers: List<Producer>? = emptyList(),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of licensors of this anime.
|
||||||
|
* @see Licensor for the detail.
|
||||||
|
*/
|
||||||
|
@SerialName("licensors")
|
||||||
|
val licensors: List<Licensor>? = emptyList(),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of studios of this anime.
|
||||||
|
* @see Studio for the detail.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@SerialName("studios")
|
||||||
|
val studios: List<Studio>? = emptyList(),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of genre of this anime.
|
||||||
|
* @see Genre for the detail.
|
||||||
|
*/
|
||||||
|
@SerialName("genres")
|
||||||
|
val genres: List<Genre>? = emptyList(),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of explicit genre of this anime.
|
||||||
|
* @see ExplicitGenre for the detail.
|
||||||
|
*/
|
||||||
|
@SerialName("explicit_genres")
|
||||||
|
val explicitGenres: List<ExplicitGenre>? = emptyList(),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of themes of this anime.
|
||||||
|
* @see Themes for the detail.
|
||||||
|
*/
|
||||||
|
@SerialName("themes")
|
||||||
|
val themes: List<Themes>? = emptyList(),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Demographic of this anime.
|
||||||
|
* @see Demographic for the detail.
|
||||||
|
*/
|
||||||
|
@SerialName("demographics")
|
||||||
|
val demographics: List<Demographic>? = emptyList(),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Relation of this anime.
|
||||||
|
* @see Relation for the detail.
|
||||||
|
*/
|
||||||
|
@SerialName("relations")
|
||||||
|
val relations: List<Relation>? = emptyList(),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Theme of this anime.
|
||||||
|
* @see Theme for the detail.
|
||||||
|
*/
|
||||||
|
@SerialName("theme")
|
||||||
|
val theme: Theme? = Theme(),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Theme of this anime.
|
||||||
|
* @see External for the detail.
|
||||||
|
*/
|
||||||
|
@SerialName("external")
|
||||||
|
val external: List<External>? = emptyList(),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Theme of this anime.
|
||||||
|
* @see Streaming for the detail.
|
||||||
|
*/
|
||||||
|
@SerialName("streaming")
|
||||||
|
val streaming: List<Streaming>? = emptyList()
|
||||||
|
) {
|
||||||
|
companion object {
|
||||||
|
fun AnimeData.toDayEntity(day: Day) = DayEntity(
|
||||||
|
malId = malId ?: 0,
|
||||||
|
day = day.name.lowercase(),
|
||||||
|
image = images?.webp?.large.orEmpty(),
|
||||||
|
title = titles?.first()?.title.orEmpty()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
package com.jeluchu.core.models.jikan.anime
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
|
||||||
|
data class AnimeStatistics(
|
||||||
|
@SerialName("data")
|
||||||
|
val data: Statistics?
|
||||||
|
) {
|
||||||
|
data class Statistics(
|
||||||
|
@SerialName("completed")
|
||||||
|
val completed: Int?,
|
||||||
|
|
||||||
|
@SerialName("dropped")
|
||||||
|
val dropped: Int?,
|
||||||
|
|
||||||
|
@SerialName("on_hold")
|
||||||
|
val onHold: Int?,
|
||||||
|
|
||||||
|
@SerialName("plan_to_watch")
|
||||||
|
val planToWatch: Int?,
|
||||||
|
|
||||||
|
@SerialName("scores")
|
||||||
|
val scores: List<Score>?,
|
||||||
|
|
||||||
|
@SerialName("total")
|
||||||
|
val total: Int?,
|
||||||
|
|
||||||
|
@SerialName("watching")
|
||||||
|
val watching: Int?
|
||||||
|
)
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
package com.jeluchu.core.models.jikan.anime
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Broadcast data class.
|
||||||
|
*/
|
||||||
|
@Serializable
|
||||||
|
data class Broadcast(
|
||||||
|
/**
|
||||||
|
* Day in broadcast.
|
||||||
|
*/
|
||||||
|
@SerialName("day")
|
||||||
|
val day: String? = "",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* String date in broadcast.
|
||||||
|
*/
|
||||||
|
@SerialName("string")
|
||||||
|
val string: String? = "",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Time date in broadcast.
|
||||||
|
*/
|
||||||
|
@SerialName("time")
|
||||||
|
val time: String? = "",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Timezone in broadcast.
|
||||||
|
*/
|
||||||
|
@SerialName("timezone")
|
||||||
|
val timezone: String? = ""
|
||||||
|
)
|
@ -0,0 +1,28 @@
|
|||||||
|
package com.jeluchu.core.models.jikan.anime
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DateProp data class.
|
||||||
|
*/
|
||||||
|
@Serializable
|
||||||
|
data class DateProp(
|
||||||
|
/**
|
||||||
|
* Day in date.
|
||||||
|
*/
|
||||||
|
@SerialName("day")
|
||||||
|
val day: Int? = 0,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Month in date.
|
||||||
|
*/
|
||||||
|
@SerialName("month")
|
||||||
|
val month: Int? = 0,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Year in date.
|
||||||
|
*/
|
||||||
|
@SerialName("year")
|
||||||
|
val year: Int? = 0
|
||||||
|
)
|
@ -0,0 +1,34 @@
|
|||||||
|
package com.jeluchu.core.models.jikan.anime
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Demographic data class.
|
||||||
|
*/
|
||||||
|
@Serializable
|
||||||
|
data class Demographic(
|
||||||
|
/**
|
||||||
|
* ID associated with MyAnimeList.
|
||||||
|
*/
|
||||||
|
@SerialName("mal_id")
|
||||||
|
val malId: Int?,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name for demographic.
|
||||||
|
*/
|
||||||
|
@SerialName("name")
|
||||||
|
val name: String?,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type for demographic.
|
||||||
|
*/
|
||||||
|
@SerialName("type")
|
||||||
|
val type: String?,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Url for demographic.
|
||||||
|
*/
|
||||||
|
@SerialName("url")
|
||||||
|
val url: String?
|
||||||
|
)
|
@ -0,0 +1,34 @@
|
|||||||
|
package com.jeluchu.core.models.jikan.anime
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entry data class.
|
||||||
|
*/
|
||||||
|
@Serializable
|
||||||
|
data class Entry(
|
||||||
|
/**
|
||||||
|
* ID associated with MyAnimeList.
|
||||||
|
*/
|
||||||
|
@SerialName("mal_id")
|
||||||
|
val malId: Int?,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name for entry.
|
||||||
|
*/
|
||||||
|
@SerialName("name")
|
||||||
|
val name: String?,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type for entry.
|
||||||
|
*/
|
||||||
|
@SerialName("type")
|
||||||
|
val type: String?,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Url for entry.
|
||||||
|
*/
|
||||||
|
@SerialName("url")
|
||||||
|
val url: String?
|
||||||
|
)
|
@ -0,0 +1,34 @@
|
|||||||
|
package com.jeluchu.core.models.jikan.anime
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ExplicitGenre data class.
|
||||||
|
*/
|
||||||
|
@Serializable
|
||||||
|
data class ExplicitGenre(
|
||||||
|
/**
|
||||||
|
* ID associated with MyAnimeList.
|
||||||
|
*/
|
||||||
|
@SerialName("mal_id")
|
||||||
|
val malId: Int?,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name for explicit genre.
|
||||||
|
*/
|
||||||
|
@SerialName("name")
|
||||||
|
val name: String?,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type for explicit genre.
|
||||||
|
*/
|
||||||
|
@SerialName("type")
|
||||||
|
val type: String?,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Url for explicit genre.
|
||||||
|
*/
|
||||||
|
@SerialName("url")
|
||||||
|
val url: String?
|
||||||
|
)
|
@ -0,0 +1,22 @@
|
|||||||
|
package com.jeluchu.core.models.jikan.anime
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
/**
|
||||||
|
* External data class.
|
||||||
|
*/
|
||||||
|
@Serializable
|
||||||
|
data class External(
|
||||||
|
/**
|
||||||
|
* Name of external info.
|
||||||
|
*/
|
||||||
|
@SerialName("name")
|
||||||
|
val name: String?,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Url of external info.
|
||||||
|
*/
|
||||||
|
@SerialName("url")
|
||||||
|
val url: String?
|
||||||
|
)
|
@ -0,0 +1,34 @@
|
|||||||
|
package com.jeluchu.core.models.jikan.anime
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Genre data class.
|
||||||
|
*/
|
||||||
|
@Serializable
|
||||||
|
data class Genre(
|
||||||
|
/**
|
||||||
|
* ID associated with MyAnimeList.
|
||||||
|
*/
|
||||||
|
@SerialName("mal_id")
|
||||||
|
val malId: Int?,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name for genre.
|
||||||
|
*/
|
||||||
|
@SerialName("name")
|
||||||
|
val name: String?,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type for genre.
|
||||||
|
*/
|
||||||
|
@SerialName("type")
|
||||||
|
val type: String?,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Url for genre.
|
||||||
|
*/
|
||||||
|
@SerialName("url")
|
||||||
|
val url: String?
|
||||||
|
)
|
@ -0,0 +1,22 @@
|
|||||||
|
package com.jeluchu.core.models.jikan.anime
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class ImageFormat(
|
||||||
|
@SerialName("image_url")
|
||||||
|
val generic: String? = "",
|
||||||
|
|
||||||
|
@SerialName("small_image_url")
|
||||||
|
val small: String? = "",
|
||||||
|
|
||||||
|
@SerialName("medium_image_url")
|
||||||
|
val medium: String? = "",
|
||||||
|
|
||||||
|
@SerialName("large_image_url")
|
||||||
|
val large: String? = "",
|
||||||
|
|
||||||
|
@SerialName("maximum_image_url")
|
||||||
|
val maximum: String? = ""
|
||||||
|
)
|
@ -0,0 +1,22 @@
|
|||||||
|
package com.jeluchu.core.models.jikan.anime
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Images data class.
|
||||||
|
*/
|
||||||
|
@Serializable
|
||||||
|
data class Images(
|
||||||
|
/**
|
||||||
|
* Images for jpg image type.
|
||||||
|
*/
|
||||||
|
@SerialName("jpg")
|
||||||
|
val jpg: ImageFormat? = null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Images for webp image type.
|
||||||
|
*/
|
||||||
|
@SerialName("webp")
|
||||||
|
val webp: ImageFormat? = null
|
||||||
|
)
|
@ -0,0 +1,34 @@
|
|||||||
|
package com.jeluchu.core.models.jikan.anime
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Licensor data class.
|
||||||
|
*/
|
||||||
|
@Serializable
|
||||||
|
data class Licensor(
|
||||||
|
/**
|
||||||
|
* ID associated with MyAnimeList.
|
||||||
|
*/
|
||||||
|
@SerialName("mal_id")
|
||||||
|
val malId: Int?,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name for licensor.
|
||||||
|
*/
|
||||||
|
@SerialName("name")
|
||||||
|
val name: String?,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type for licensor.
|
||||||
|
*/
|
||||||
|
@SerialName("type")
|
||||||
|
val type: String?,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Url for licensor.
|
||||||
|
*/
|
||||||
|
@SerialName("url")
|
||||||
|
val url: String?
|
||||||
|
)
|
@ -0,0 +1,34 @@
|
|||||||
|
package com.jeluchu.core.models.jikan.anime
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Producer data class.
|
||||||
|
*/
|
||||||
|
@Serializable
|
||||||
|
data class Producer(
|
||||||
|
/**
|
||||||
|
* ID associated with MyAnimeList.
|
||||||
|
*/
|
||||||
|
@SerialName("mal_id")
|
||||||
|
val malId: Int?,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name for producer.
|
||||||
|
*/
|
||||||
|
@SerialName("name")
|
||||||
|
val name: String?,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type for producer.
|
||||||
|
*/
|
||||||
|
@SerialName("type")
|
||||||
|
val type: String?,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Url for producer.
|
||||||
|
*/
|
||||||
|
@SerialName("url")
|
||||||
|
val url: String?
|
||||||
|
)
|
@ -0,0 +1,30 @@
|
|||||||
|
package com.jeluchu.core.models.jikan.anime
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prop data class.
|
||||||
|
*/
|
||||||
|
@Serializable
|
||||||
|
data class Prop(
|
||||||
|
/**
|
||||||
|
* Start date.
|
||||||
|
* @see DateProp for the detail.
|
||||||
|
*/
|
||||||
|
@SerialName("from")
|
||||||
|
val from: DateProp? = DateProp(),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* String with date.
|
||||||
|
*/
|
||||||
|
@SerialName("string")
|
||||||
|
val string: String? = "",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* End date.
|
||||||
|
* @see DateProp for the detail.
|
||||||
|
*/
|
||||||
|
@SerialName("to")
|
||||||
|
val to: DateProp? = DateProp()
|
||||||
|
)
|
@ -0,0 +1,23 @@
|
|||||||
|
package com.jeluchu.core.models.jikan.anime
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Relation data class.
|
||||||
|
*/
|
||||||
|
@Serializable
|
||||||
|
data class Relation(
|
||||||
|
/**
|
||||||
|
* List of entries for relation in anime.
|
||||||
|
* @see Entry for the detail.
|
||||||
|
*/
|
||||||
|
@SerialName("entry")
|
||||||
|
val entry: List<Entry>?,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Relation for anime
|
||||||
|
*/
|
||||||
|
@SerialName("relation")
|
||||||
|
val relation: String?
|
||||||
|
)
|
@ -0,0 +1,14 @@
|
|||||||
|
package com.jeluchu.core.models.jikan.anime
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
|
||||||
|
data class Score(
|
||||||
|
@SerialName("percentage")
|
||||||
|
val percentage: Double,
|
||||||
|
|
||||||
|
@SerialName("score")
|
||||||
|
val score: Int,
|
||||||
|
|
||||||
|
@SerialName("votes")
|
||||||
|
val votes: Int
|
||||||
|
)
|
@ -0,0 +1,22 @@
|
|||||||
|
package com.jeluchu.core.models.jikan.anime
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Streaming data class.
|
||||||
|
*/
|
||||||
|
@Serializable
|
||||||
|
data class Streaming(
|
||||||
|
/**
|
||||||
|
* Name of streaming info.
|
||||||
|
*/
|
||||||
|
@SerialName("name")
|
||||||
|
val name: String?,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Url of streaming info.
|
||||||
|
*/
|
||||||
|
@SerialName("url")
|
||||||
|
val url: String?
|
||||||
|
)
|
@ -0,0 +1,34 @@
|
|||||||
|
package com.jeluchu.core.models.jikan.anime
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Studio data class.
|
||||||
|
*/
|
||||||
|
@Serializable
|
||||||
|
data class Studio(
|
||||||
|
/**
|
||||||
|
* ID associated with MyAnimeList.
|
||||||
|
*/
|
||||||
|
@SerialName("mal_id")
|
||||||
|
val malId: Int?,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name for studio.
|
||||||
|
*/
|
||||||
|
@SerialName("name")
|
||||||
|
val name: String?,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type for studio.
|
||||||
|
*/
|
||||||
|
@SerialName("type")
|
||||||
|
val type: String?,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Url for studio.
|
||||||
|
*/
|
||||||
|
@SerialName("url")
|
||||||
|
val url: String?
|
||||||
|
)
|
@ -0,0 +1,22 @@
|
|||||||
|
package com.jeluchu.core.models.jikan.anime
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Theme data class.
|
||||||
|
*/
|
||||||
|
@Serializable
|
||||||
|
data class Theme(
|
||||||
|
/**
|
||||||
|
* List of endings.
|
||||||
|
*/
|
||||||
|
@SerialName("endings")
|
||||||
|
val endings: List<String>? = emptyList(),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of openings.
|
||||||
|
*/
|
||||||
|
@SerialName("openings")
|
||||||
|
val openings: List<String>? = emptyList()
|
||||||
|
)
|
@ -0,0 +1,34 @@
|
|||||||
|
package com.jeluchu.core.models.jikan.anime
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Themes data class.
|
||||||
|
*/
|
||||||
|
@Serializable
|
||||||
|
data class Themes(
|
||||||
|
/**
|
||||||
|
* ID associated with MyAnimeList.
|
||||||
|
*/
|
||||||
|
@SerialName("mal_id")
|
||||||
|
val malId: Int?,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name for themes.
|
||||||
|
*/
|
||||||
|
@SerialName("name")
|
||||||
|
val name: String?,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type for themes.
|
||||||
|
*/
|
||||||
|
@SerialName("type")
|
||||||
|
val type: String?,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Url for themes.
|
||||||
|
*/
|
||||||
|
@SerialName("url")
|
||||||
|
val url: String?
|
||||||
|
)
|
@ -0,0 +1,22 @@
|
|||||||
|
package com.jeluchu.core.models.jikan.anime
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Title data class.
|
||||||
|
*/
|
||||||
|
@Serializable
|
||||||
|
data class Title(
|
||||||
|
/**
|
||||||
|
* Title for anime.
|
||||||
|
*/
|
||||||
|
@SerialName("title")
|
||||||
|
val title: String?,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Title type for anime.
|
||||||
|
*/
|
||||||
|
@SerialName("type")
|
||||||
|
val type: String?
|
||||||
|
)
|
@ -0,0 +1,34 @@
|
|||||||
|
package com.jeluchu.core.models.jikan.anime
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trailer data class.
|
||||||
|
*/
|
||||||
|
@Serializable
|
||||||
|
data class Trailer(
|
||||||
|
/**
|
||||||
|
* Embed url for trailer.
|
||||||
|
*/
|
||||||
|
@SerialName("embed_url")
|
||||||
|
val embedUrl: String? = "",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Url for trailer.
|
||||||
|
*/
|
||||||
|
@SerialName("url")
|
||||||
|
val url: String? = "",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Youtube id for trailer.
|
||||||
|
*/
|
||||||
|
@SerialName("youtube_id")
|
||||||
|
val youtubeId: String? = "",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Images for trailer.
|
||||||
|
*/
|
||||||
|
@SerialName("images")
|
||||||
|
val images: ImageFormat? = ImageFormat()
|
||||||
|
)
|
@ -0,0 +1,28 @@
|
|||||||
|
package com.jeluchu.core.models.jikan.search
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ItemsPage data class.
|
||||||
|
*/
|
||||||
|
@Serializable
|
||||||
|
data class ItemsPage(
|
||||||
|
/**
|
||||||
|
* Count page.
|
||||||
|
*/
|
||||||
|
@SerialName("count")
|
||||||
|
val count: Int? = 0,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Total items availables.
|
||||||
|
*/
|
||||||
|
@SerialName("total")
|
||||||
|
val total: Int? = 0,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Total items per page.
|
||||||
|
*/
|
||||||
|
@SerialName("per_page")
|
||||||
|
val itemsPerPage: Int? = 0
|
||||||
|
)
|
@ -0,0 +1,34 @@
|
|||||||
|
package com.jeluchu.core.models.jikan.search
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pagination data class.
|
||||||
|
*/
|
||||||
|
@Serializable
|
||||||
|
data class Pagination(
|
||||||
|
/**
|
||||||
|
* Current page available.
|
||||||
|
*/
|
||||||
|
@SerialName("current_page")
|
||||||
|
val currentPage: Int? = 0,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Last page available.
|
||||||
|
*/
|
||||||
|
@SerialName("last_visible_page")
|
||||||
|
val lastPage: Int? = 0,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Items information.
|
||||||
|
*/
|
||||||
|
@SerialName("items")
|
||||||
|
val itemsPage: ItemsPage? = ItemsPage(),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request hast next page or not.
|
||||||
|
*/
|
||||||
|
@SerialName("has_next_page")
|
||||||
|
val hasNextPage: Boolean? = null
|
||||||
|
)
|
@ -0,0 +1,23 @@
|
|||||||
|
package com.jeluchu.core.models.jikan.search
|
||||||
|
|
||||||
|
import com.jeluchu.core.models.jikan.anime.AnimeData
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Search data class.
|
||||||
|
*/
|
||||||
|
@Serializable
|
||||||
|
data class Search(
|
||||||
|
/**
|
||||||
|
* Pagination info for request
|
||||||
|
*/
|
||||||
|
@SerialName("pagination")
|
||||||
|
val pagination: Pagination? = Pagination(),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data list of all anime found.
|
||||||
|
*/
|
||||||
|
@SerialName("data")
|
||||||
|
val data: List<AnimeData>? = emptyList()
|
||||||
|
)
|
@ -1,6 +1,27 @@
|
|||||||
package com.jeluchu.core.utils
|
package com.jeluchu.core.utils
|
||||||
|
|
||||||
|
object BaseUrls {
|
||||||
|
const val JIKAN = "https://api.jikan.moe/v4/"
|
||||||
|
}
|
||||||
|
|
||||||
|
object Endpoints {
|
||||||
|
const val SCHEDULES = "schedules"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
object Routes {
|
object Routes {
|
||||||
|
const val SCHEDULE = "/schedule"
|
||||||
const val DIRECTORY = "/directory"
|
const val DIRECTORY = "/directory"
|
||||||
|
const val TOP_ANIME = "/top/anime"
|
||||||
|
const val TOP_MANGA = "/top/manga"
|
||||||
|
const val TOP_PEOPLE = "/top/people"
|
||||||
const val ANIME_DETAILS = "/anime/{id}"
|
const val ANIME_DETAILS = "/anime/{id}"
|
||||||
|
const val SCHEDULE_DAY = "/schedule/{day}"
|
||||||
|
const val TOP_CHARACTER = "/top/character"
|
||||||
|
}
|
||||||
|
|
||||||
|
object TimerKey {
|
||||||
|
const val KEY = "key"
|
||||||
|
const val SCHEDULE = "schedule"
|
||||||
|
const val LAST_UPDATED = "lastUpdated"
|
||||||
}
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package com.jeluchu.core.utils
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
enum class Day {
|
||||||
|
MONDAY,
|
||||||
|
TUESDAY,
|
||||||
|
WEDNESDAY,
|
||||||
|
THURSDAY,
|
||||||
|
FRIDAY,
|
||||||
|
SATURDAY,
|
||||||
|
SUNDAY,
|
||||||
|
}
|
||||||
|
|
||||||
|
fun parseDay(day: String) = Day.entries.firstOrNull { it.name.equals(day, ignoreCase = true) }
|
@ -0,0 +1,8 @@
|
|||||||
|
package com.jeluchu.core.utils
|
||||||
|
|
||||||
|
enum class TimeUnit {
|
||||||
|
DAY,
|
||||||
|
HOUR,
|
||||||
|
MINUTE,
|
||||||
|
SECOND
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
package com.jeluchu.core.utils
|
||||||
|
|
||||||
|
import com.jeluchu.features.schedule.models.DayEntity
|
||||||
|
import com.jeluchu.features.schedule.models.ScheduleData
|
||||||
|
import kotlinx.serialization.encodeToString
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
import org.bson.Document
|
||||||
|
|
||||||
|
fun parseScheduleDataToDocuments(data: ScheduleData): List<Document> {
|
||||||
|
val documents = mutableListOf<Document>()
|
||||||
|
fun processDay(dayList: List<DayEntity>?) {
|
||||||
|
dayList?.forEach { animeData ->
|
||||||
|
val animeJsonString = Json.encodeToString(animeData)
|
||||||
|
val document = Document.parse(animeJsonString)
|
||||||
|
documents.add(document)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
processDay(data.monday)
|
||||||
|
processDay(data.tuesday)
|
||||||
|
processDay(data.wednesday)
|
||||||
|
processDay(data.thursday)
|
||||||
|
processDay(data.friday)
|
||||||
|
processDay(data.saturday)
|
||||||
|
processDay(data.sunday)
|
||||||
|
|
||||||
|
return documents
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
package com.jeluchu.features.rankings.routes
|
||||||
|
|
||||||
|
import com.jeluchu.core.extensions.getToJson
|
||||||
|
import com.jeluchu.core.utils.Routes
|
||||||
|
import com.jeluchu.features.rankings.services.RankingsService
|
||||||
|
import com.mongodb.client.MongoDatabase
|
||||||
|
import io.ktor.server.routing.*
|
||||||
|
|
||||||
|
fun Route.rankingsEndpoints(
|
||||||
|
mongoDatabase: MongoDatabase,
|
||||||
|
service: RankingsService = RankingsService(mongoDatabase)
|
||||||
|
) {
|
||||||
|
getToJson(Routes.TOP_ANIME) { service.getAnimeByMalId(call) }
|
||||||
|
getToJson(Routes.TOP_MANGA) { service.getDirectory(call) }
|
||||||
|
}
|
@ -0,0 +1,76 @@
|
|||||||
|
package com.jeluchu.features.rankings.services
|
||||||
|
|
||||||
|
import com.jeluchu.core.connection.RestClient
|
||||||
|
import com.jeluchu.core.extensions.needsUpdate
|
||||||
|
import com.jeluchu.core.extensions.update
|
||||||
|
import com.jeluchu.core.messages.ErrorMessages
|
||||||
|
import com.jeluchu.core.models.ErrorResponse
|
||||||
|
import com.jeluchu.core.models.jikan.anime.AnimeData.Companion.toDayEntity
|
||||||
|
import com.jeluchu.core.utils.*
|
||||||
|
import com.jeluchu.features.anime.mappers.documentToAnimeDirectoryEntity
|
||||||
|
import com.jeluchu.features.anime.mappers.documentToMoreInfoEntity
|
||||||
|
import com.jeluchu.features.anime.mappers.documentToScheduleDayEntity
|
||||||
|
import com.jeluchu.features.schedule.models.ScheduleData
|
||||||
|
import com.jeluchu.features.schedule.models.ScheduleEntity
|
||||||
|
import com.mongodb.client.MongoDatabase
|
||||||
|
import com.mongodb.client.model.Filters
|
||||||
|
import io.ktor.http.*
|
||||||
|
import io.ktor.server.response.*
|
||||||
|
import io.ktor.server.routing.*
|
||||||
|
import kotlinx.serialization.encodeToString
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
import org.bson.Document
|
||||||
|
|
||||||
|
class RankingsService(
|
||||||
|
database: MongoDatabase
|
||||||
|
) {
|
||||||
|
private val timers = database.getCollection("timers")
|
||||||
|
private val schedules = database.getCollection("schedule")
|
||||||
|
|
||||||
|
suspend fun getAnimeRanking(call: RoutingCall) {
|
||||||
|
val needsUpdate = timers.needsUpdate(
|
||||||
|
amount = 30,
|
||||||
|
unit = TimeUnit.DAY,
|
||||||
|
key = TimerKey.SCHEDULE
|
||||||
|
)
|
||||||
|
|
||||||
|
if (needsUpdate) {
|
||||||
|
schedules.deleteMany(Document())
|
||||||
|
|
||||||
|
val response = ScheduleData(
|
||||||
|
sunday = getSchedule(Day.SUNDAY).data?.map { it.toDayEntity(Day.SUNDAY) }.orEmpty(),
|
||||||
|
friday = getSchedule(Day.FRIDAY).data?.map { it.toDayEntity(Day.FRIDAY) }.orEmpty(),
|
||||||
|
monday = getSchedule(Day.MONDAY).data?.map { it.toDayEntity(Day.MONDAY) }.orEmpty(),
|
||||||
|
tuesday = getSchedule(Day.TUESDAY).data?.map { it.toDayEntity(Day.TUESDAY) }.orEmpty(),
|
||||||
|
thursday = getSchedule(Day.THURSDAY).data?.map { it.toDayEntity(Day.THURSDAY) }.orEmpty(),
|
||||||
|
saturday = getSchedule(Day.SATURDAY).data?.map { it.toDayEntity(Day.SATURDAY) }.orEmpty(),
|
||||||
|
wednesday = getSchedule(Day.WEDNESDAY).data?.map { it.toDayEntity(Day.WEDNESDAY) }.orEmpty()
|
||||||
|
)
|
||||||
|
|
||||||
|
val documentsToInsert = parseScheduleDataToDocuments(response)
|
||||||
|
if (documentsToInsert.isNotEmpty()) schedules.insertMany(documentsToInsert)
|
||||||
|
timers.update(TimerKey.SCHEDULE)
|
||||||
|
|
||||||
|
call.respond(HttpStatusCode.OK, Json.encodeToString(response))
|
||||||
|
} else {
|
||||||
|
val elements = schedules.find().toList()
|
||||||
|
val directory = elements.map { documentToScheduleDayEntity(it) }
|
||||||
|
val json = Json.encodeToString(directory)
|
||||||
|
call.respond(HttpStatusCode.OK, json)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun getScheduleByDay(call: RoutingCall) {
|
||||||
|
val param = call.parameters["day"] ?: throw IllegalArgumentException(ErrorMessages.InvalidMalId.message)
|
||||||
|
if (parseDay(param) == null) call.respond(HttpStatusCode.BadRequest, ErrorResponse(ErrorMessages.InvalidDay.message))
|
||||||
|
|
||||||
|
val elements = schedules.find(Filters.eq("day", param.lowercase())).toList()
|
||||||
|
val directory = elements.map { documentToScheduleDayEntity(it) }
|
||||||
|
val json = Json.encodeToString(directory)
|
||||||
|
call.respond(HttpStatusCode.OK, json)
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun getSchedule(day: Day) =
|
||||||
|
RestClient.request(BaseUrls.JIKAN + Endpoints.SCHEDULES + "/" + day, ScheduleEntity.serializer())
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
|||||||
|
package com.jeluchu.features.schedule.models
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class DayEntity(
|
||||||
|
val malId: Int,
|
||||||
|
val day: String,
|
||||||
|
val title: String,
|
||||||
|
val image: String,
|
||||||
|
)
|
@ -0,0 +1,49 @@
|
|||||||
|
package com.jeluchu.features.schedule.models
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class ScheduleData(
|
||||||
|
/**
|
||||||
|
* All current season entries scheduled for Monday.
|
||||||
|
*/
|
||||||
|
@SerialName("monday")
|
||||||
|
val monday: List<DayEntity>? = emptyList(),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All current season entries scheduled for Tuesday.
|
||||||
|
*/
|
||||||
|
@SerialName("tuesday")
|
||||||
|
val tuesday: List<DayEntity>? = emptyList(),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All current season entries scheduled for Wednesday.
|
||||||
|
*/
|
||||||
|
@SerialName("wednesday")
|
||||||
|
val wednesday: List<DayEntity>? = emptyList(),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All current season entries scheduled for Thursday.
|
||||||
|
*/
|
||||||
|
@SerialName("thursday")
|
||||||
|
val thursday: List<DayEntity>? = emptyList(),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All current season entries scheduled for Friday.
|
||||||
|
*/
|
||||||
|
@SerialName("friday")
|
||||||
|
val friday: List<DayEntity>? = emptyList(),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All current season entries scheduled for Saturday.
|
||||||
|
*/
|
||||||
|
@SerialName("saturday")
|
||||||
|
val saturday: List<DayEntity>? = emptyList(),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All current season entries scheduled for Sunday.
|
||||||
|
*/
|
||||||
|
@SerialName("sunday")
|
||||||
|
val sunday: List<DayEntity>? = emptyList()
|
||||||
|
)
|
@ -0,0 +1,24 @@
|
|||||||
|
package com.jeluchu.features.schedule.models
|
||||||
|
|
||||||
|
import com.jeluchu.core.models.jikan.search.Pagination
|
||||||
|
import com.jeluchu.core.models.jikan.anime.AnimeData
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schedule data class.
|
||||||
|
*/
|
||||||
|
@Serializable
|
||||||
|
data class ScheduleEntity(
|
||||||
|
/**
|
||||||
|
* Pagination info for request
|
||||||
|
*/
|
||||||
|
@SerialName("pagination")
|
||||||
|
val pagination: Pagination? = Pagination(),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data for anime requested.
|
||||||
|
*/
|
||||||
|
@SerialName("data")
|
||||||
|
val data: List<AnimeData>? = emptyList()
|
||||||
|
)
|
@ -0,0 +1,15 @@
|
|||||||
|
package com.jeluchu.features.schedule.routes
|
||||||
|
|
||||||
|
import com.jeluchu.core.extensions.getToJson
|
||||||
|
import com.jeluchu.core.utils.Routes
|
||||||
|
import com.jeluchu.features.schedule.services.ScheduleService
|
||||||
|
import com.mongodb.client.MongoDatabase
|
||||||
|
import io.ktor.server.routing.*
|
||||||
|
|
||||||
|
fun Route.scheduleEndpoints(
|
||||||
|
mongoDatabase: MongoDatabase,
|
||||||
|
service: ScheduleService = ScheduleService(mongoDatabase)
|
||||||
|
) {
|
||||||
|
getToJson(Routes.SCHEDULE) { service.getSchedule(call) }
|
||||||
|
getToJson(Routes.SCHEDULE_DAY) { service.getScheduleByDay(call) }
|
||||||
|
}
|
@ -0,0 +1,73 @@
|
|||||||
|
package com.jeluchu.features.schedule.services
|
||||||
|
|
||||||
|
import com.jeluchu.core.connection.RestClient
|
||||||
|
import com.jeluchu.core.extensions.needsUpdate
|
||||||
|
import com.jeluchu.core.extensions.update
|
||||||
|
import com.jeluchu.core.messages.ErrorMessages
|
||||||
|
import com.jeluchu.core.models.ErrorResponse
|
||||||
|
import com.jeluchu.core.models.jikan.anime.AnimeData.Companion.toDayEntity
|
||||||
|
import com.jeluchu.core.utils.*
|
||||||
|
import com.jeluchu.features.anime.mappers.documentToScheduleDayEntity
|
||||||
|
import com.jeluchu.features.schedule.models.ScheduleData
|
||||||
|
import com.jeluchu.features.schedule.models.ScheduleEntity
|
||||||
|
import com.mongodb.client.MongoDatabase
|
||||||
|
import com.mongodb.client.model.Filters
|
||||||
|
import io.ktor.http.*
|
||||||
|
import io.ktor.server.response.*
|
||||||
|
import io.ktor.server.routing.*
|
||||||
|
import kotlinx.serialization.encodeToString
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
import org.bson.Document
|
||||||
|
|
||||||
|
class ScheduleService(
|
||||||
|
database: MongoDatabase
|
||||||
|
) {
|
||||||
|
private val timers = database.getCollection("timers")
|
||||||
|
private val schedules = database.getCollection("schedule")
|
||||||
|
|
||||||
|
suspend fun getSchedule(call: RoutingCall) {
|
||||||
|
val needsUpdate = timers.needsUpdate(
|
||||||
|
amount = 7,
|
||||||
|
unit = TimeUnit.DAY,
|
||||||
|
key = TimerKey.SCHEDULE
|
||||||
|
)
|
||||||
|
|
||||||
|
if (needsUpdate) {
|
||||||
|
schedules.deleteMany(Document())
|
||||||
|
|
||||||
|
val response = ScheduleData(
|
||||||
|
sunday = getSchedule(Day.SUNDAY).data?.map { it.toDayEntity(Day.SUNDAY) }.orEmpty(),
|
||||||
|
friday = getSchedule(Day.FRIDAY).data?.map { it.toDayEntity(Day.FRIDAY) }.orEmpty(),
|
||||||
|
monday = getSchedule(Day.MONDAY).data?.map { it.toDayEntity(Day.MONDAY) }.orEmpty(),
|
||||||
|
tuesday = getSchedule(Day.TUESDAY).data?.map { it.toDayEntity(Day.TUESDAY) }.orEmpty(),
|
||||||
|
thursday = getSchedule(Day.THURSDAY).data?.map { it.toDayEntity(Day.THURSDAY) }.orEmpty(),
|
||||||
|
saturday = getSchedule(Day.SATURDAY).data?.map { it.toDayEntity(Day.SATURDAY) }.orEmpty(),
|
||||||
|
wednesday = getSchedule(Day.WEDNESDAY).data?.map { it.toDayEntity(Day.WEDNESDAY) }.orEmpty()
|
||||||
|
)
|
||||||
|
|
||||||
|
val documentsToInsert = parseScheduleDataToDocuments(response)
|
||||||
|
if (documentsToInsert.isNotEmpty()) schedules.insertMany(documentsToInsert)
|
||||||
|
timers.update(TimerKey.SCHEDULE)
|
||||||
|
|
||||||
|
call.respond(HttpStatusCode.OK, Json.encodeToString(response))
|
||||||
|
} else {
|
||||||
|
val elements = schedules.find().toList()
|
||||||
|
val directory = elements.map { documentToScheduleDayEntity(it) }
|
||||||
|
val json = Json.encodeToString(directory)
|
||||||
|
call.respond(HttpStatusCode.OK, json)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun getScheduleByDay(call: RoutingCall) {
|
||||||
|
val param = call.parameters["day"] ?: throw IllegalArgumentException(ErrorMessages.InvalidMalId.message)
|
||||||
|
if (parseDay(param) == null) call.respond(HttpStatusCode.BadRequest, ErrorResponse(ErrorMessages.InvalidDay.message))
|
||||||
|
|
||||||
|
val elements = schedules.find(Filters.eq("day", param.lowercase())).toList()
|
||||||
|
val directory = elements.map { documentToScheduleDayEntity(it) }
|
||||||
|
val json = Json.encodeToString(directory)
|
||||||
|
call.respond(HttpStatusCode.OK, json)
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun getSchedule(day: Day) =
|
||||||
|
RestClient.request(BaseUrls.JIKAN + Endpoints.SCHEDULES + "/" + day, ScheduleEntity.serializer())
|
||||||
|
}
|
Loading…
Reference in New Issue