mirror of https://github.com/aruppi/aruppi-api.git
parent
08caaa60fc
commit
f53ed50bb2
@ -0,0 +1,47 @@
|
||||
package com.jeluchu.features.news.mappers
|
||||
|
||||
import com.jeluchu.core.extensions.getBooleanSafe
|
||||
import com.jeluchu.core.extensions.getDocumentSafe
|
||||
import com.jeluchu.core.extensions.getFloatSafe
|
||||
import com.jeluchu.core.extensions.getIntSafe
|
||||
import com.jeluchu.core.extensions.getListSafe
|
||||
import com.jeluchu.core.extensions.getStringSafe
|
||||
import com.jeluchu.core.extensions.parseRssDate
|
||||
import com.jeluchu.features.anime.mappers.documentToVideoPromo
|
||||
import com.jeluchu.features.anime.models.anime.VideoPromo
|
||||
import com.jeluchu.features.news.models.NewEntity
|
||||
import com.prof18.rssparser.model.RssChannel
|
||||
import org.bson.Document
|
||||
|
||||
fun RssChannel.toNews(
|
||||
source: String,
|
||||
list: MutableList<NewEntity>
|
||||
) = list.apply{
|
||||
items.forEach { item ->
|
||||
add(
|
||||
NewEntity(
|
||||
source = source,
|
||||
sourceDescription = description.orEmpty(),
|
||||
link = item.link.orEmpty(),
|
||||
title = item.title.orEmpty(),
|
||||
date = item.pubDate?.parseRssDate().orEmpty(),
|
||||
description = item.description.orEmpty(),
|
||||
content = item.content.orEmpty(),
|
||||
image = item.image.orEmpty(),
|
||||
categories = item.categories
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun documentToNewsEntity(doc: Document) = NewEntity(
|
||||
source = doc.getStringSafe("source"),
|
||||
sourceDescription = doc.getStringSafe("sourceDescription"),
|
||||
link = doc.getStringSafe("link"),
|
||||
title = doc.getStringSafe("title"),
|
||||
date = doc.getStringSafe("date"),
|
||||
description = doc.getStringSafe("description"),
|
||||
content = doc.getStringSafe("content"),
|
||||
image = doc.getStringSafe("image"),
|
||||
categories = doc.getListSafe<String>("categories")
|
||||
)
|
@ -0,0 +1,16 @@
|
||||
package com.jeluchu.features.news.models
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class NewEntity(
|
||||
val source: String,
|
||||
val sourceDescription: String,
|
||||
val link: String,
|
||||
val title: String,
|
||||
val date: String,
|
||||
val description: String,
|
||||
val content: String,
|
||||
val image: String,
|
||||
val categories: List<String>
|
||||
)
|
@ -0,0 +1,20 @@
|
||||
package com.jeluchu.features.news.routes
|
||||
|
||||
import com.jeluchu.core.extensions.getToJson
|
||||
import com.jeluchu.core.utils.Routes
|
||||
import com.jeluchu.features.news.services.NewsService
|
||||
import com.mongodb.client.MongoDatabase
|
||||
import io.ktor.server.routing.*
|
||||
|
||||
fun Route.newsEndpoints(
|
||||
mongoDatabase: MongoDatabase,
|
||||
service: NewsService = NewsService(mongoDatabase)
|
||||
) = route(Routes.NEWS) {
|
||||
route(Routes.ES) {
|
||||
getToJson { service.getSpanishNews(call) }
|
||||
}
|
||||
|
||||
route(Routes.EN) {
|
||||
getToJson { service.getEnglishNews(call) }
|
||||
}
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
package com.jeluchu.features.news.services
|
||||
|
||||
import com.jeluchu.core.enums.TimeUnit
|
||||
import com.jeluchu.core.extensions.needsUpdate
|
||||
import com.jeluchu.core.extensions.update
|
||||
import com.jeluchu.core.utils.Collections
|
||||
import com.jeluchu.core.utils.RssSources
|
||||
import com.jeluchu.core.utils.RssUrls
|
||||
import com.jeluchu.core.utils.parseDataToDocuments
|
||||
import com.jeluchu.features.anime.mappers.documentToAnimeTopEntity
|
||||
import com.jeluchu.features.news.mappers.documentToNewsEntity
|
||||
import com.jeluchu.features.news.mappers.toNews
|
||||
import com.jeluchu.features.news.models.NewEntity
|
||||
import com.mongodb.client.MongoDatabase
|
||||
import com.prof18.rssparser.RssParser
|
||||
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 NewsService(
|
||||
database: MongoDatabase
|
||||
) {
|
||||
private val timers = database.getCollection(Collections.TIMERS)
|
||||
private val spanishNews = database.getCollection(Collections.NEWS_ES)
|
||||
private val englishNews = database.getCollection(Collections.NEWS_EN)
|
||||
|
||||
suspend fun getSpanishNews(call: RoutingCall) {
|
||||
val needsUpdate = timers.needsUpdate(
|
||||
amount = 1,
|
||||
key = Collections.NEWS_ES,
|
||||
unit = TimeUnit.DAY
|
||||
)
|
||||
|
||||
if (needsUpdate) {
|
||||
spanishNews.deleteMany(Document())
|
||||
|
||||
val response = mutableListOf<NewEntity>().apply {
|
||||
with(RssParser()) {
|
||||
getRssChannel(RssUrls.MANGALATAM).toNews(RssSources.MANGALATAM, this@apply)
|
||||
getRssChannel(RssUrls.SOMOSKUDASAI).toNews(RssSources.SOMOSKUDASAI, this@apply)
|
||||
getRssChannel(RssUrls.CRUNCHYROLL).toNews(RssSources.CRUNCHYROLL, this@apply)
|
||||
getRssChannel(RssUrls.RAMENPARADOS).toNews(RssSources.RAMENPARADOS, this@apply)
|
||||
getRssChannel(RssUrls.ANMOSUGOI).toNews(RssSources.ANMOSUGOI, this@apply)
|
||||
}
|
||||
}.shuffled()
|
||||
|
||||
val documentsToInsert = parseDataToDocuments(response, NewEntity.serializer())
|
||||
if (documentsToInsert.isNotEmpty()) spanishNews.insertMany(documentsToInsert)
|
||||
timers.update(Collections.NEWS_ES)
|
||||
|
||||
val elements = documentsToInsert.map { documentToNewsEntity(it) }
|
||||
call.respond(HttpStatusCode.OK, Json.encodeToString(elements))
|
||||
} else {
|
||||
val animes = spanishNews
|
||||
.find()
|
||||
.toList()
|
||||
|
||||
val elements = animes.map { documentToAnimeTopEntity(it) }
|
||||
call.respond(HttpStatusCode.OK, Json.encodeToString(elements))
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getEnglishNews(call: RoutingCall) {
|
||||
val needsUpdate = timers.needsUpdate(
|
||||
amount = 1,
|
||||
key = Collections.NEWS_EN,
|
||||
unit = TimeUnit.DAY
|
||||
)
|
||||
|
||||
if (needsUpdate) {
|
||||
englishNews.deleteMany(Document())
|
||||
|
||||
val response = mutableListOf<NewEntity>().apply {
|
||||
with(RssParser()) {
|
||||
getRssChannel(RssUrls.OTAKUMODE).toNews(RssSources.OTAKUMODE, this@apply)
|
||||
getRssChannel(RssUrls.MYANIMELIST).toNews(RssSources.MYANIMELIST, this@apply)
|
||||
getRssChannel(RssUrls.HONEYSANIME).toNews(RssSources.HONEYSANIME, this@apply)
|
||||
getRssChannel(RssUrls.ANIMEHUNCH).toNews(RssSources.ANIMEHUNCH, this@apply)
|
||||
}
|
||||
}.shuffled()
|
||||
|
||||
val documentsToInsert = parseDataToDocuments(response, NewEntity.serializer())
|
||||
if (documentsToInsert.isNotEmpty()) englishNews.insertMany(documentsToInsert)
|
||||
timers.update(Collections.NEWS_EN)
|
||||
|
||||
val elements = documentsToInsert.map { documentToNewsEntity(it) }
|
||||
call.respond(HttpStatusCode.OK, Json.encodeToString(elements))
|
||||
} else {
|
||||
val animes = englishNews
|
||||
.find()
|
||||
.toList()
|
||||
|
||||
val elements = animes.map { documentToAnimeTopEntity(it) }
|
||||
call.respond(HttpStatusCode.OK, Json.encodeToString(elements))
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package com.jeluchu.features.themes.models.anime
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class Anime(
|
||||
val id: Int? = 0,
|
||||
val image: String? = "",
|
||||
val name: String? = "",
|
||||
val season: String? = "",
|
||||
val slug: String? = "",
|
||||
val synopsis: String? = "",
|
||||
val year: Int? = 0,
|
||||
val themes: List<AnimeVideoTheme>? = emptyList()
|
||||
)
|
@ -0,0 +1,14 @@
|
||||
package com.jeluchu.features.themes.models.anime
|
||||
|
||||
import com.jeluchu.features.themes.models.anime.Video
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class AnimeThemeEntry(
|
||||
val episodes: String?,
|
||||
val id: Int?,
|
||||
val notes: String?,
|
||||
val nsfw: Boolean?,
|
||||
val spoiler: Boolean?,
|
||||
val videos: List<Video>?
|
||||
)
|
@ -0,0 +1,12 @@
|
||||
package com.jeluchu.features.themes.models.anime
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class AnimeVideoTheme(
|
||||
val id: Int? = 0,
|
||||
val type: String? = "",
|
||||
val slug: String? = "",
|
||||
val sequence: Int? = 0,
|
||||
val entries: List<AnimeThemeEntry>? = emptyList(),
|
||||
)
|
@ -0,0 +1,12 @@
|
||||
package com.jeluchu.features.themes.models.anime
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class AnimesEntity(
|
||||
val year: Int? = null,
|
||||
val slug: String? = null,
|
||||
val name: String? = null,
|
||||
val image: String? = null,
|
||||
val season: String? = null,
|
||||
)
|
@ -0,0 +1,11 @@
|
||||
package com.jeluchu.features.themes.models.anime
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class Image(
|
||||
val id: Int?,
|
||||
val facet: String?,
|
||||
val link: String?,
|
||||
val path: String?
|
||||
)
|
@ -0,0 +1,17 @@
|
||||
package com.jeluchu.features.themes.models.anime
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class Video(
|
||||
val size: Int? = 0,
|
||||
val link: String? = "",
|
||||
val resolution: Int? = 0,
|
||||
val source: String? = "",
|
||||
val nc: Boolean? = false,
|
||||
val overlap: String? = "",
|
||||
val filename: String? = "",
|
||||
val uncen: Boolean? = false,
|
||||
val lyrics: Boolean? = false,
|
||||
val subbed: Boolean? = false
|
||||
)
|
@ -0,0 +1,15 @@
|
||||
package com.jeluchu.features.themes.routes
|
||||
|
||||
import com.jeluchu.core.extensions.getToJson
|
||||
import com.jeluchu.core.utils.Routes
|
||||
import com.jeluchu.features.schedule.services.ScheduleService
|
||||
import com.jeluchu.features.themes.services.AnimeThemesService
|
||||
import com.mongodb.client.MongoDatabase
|
||||
import io.ktor.server.routing.*
|
||||
|
||||
fun Route.themesEndpoints(
|
||||
mongoDatabase: MongoDatabase,
|
||||
service: AnimeThemesService = AnimeThemesService(mongoDatabase)
|
||||
) = route(Routes.THEMES) {
|
||||
getToJson(Routes.ANIME) { service.getAnimeThemes(call) }
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
package com.jeluchu.features.themes.services
|
||||
|
||||
import com.jeluchu.core.extensions.badRequestError
|
||||
import com.jeluchu.core.extensions.getIntSafeQueryParam
|
||||
import com.jeluchu.core.messages.ErrorMessages
|
||||
import com.jeluchu.core.models.PaginationResponse
|
||||
import com.jeluchu.core.utils.Collections
|
||||
import com.jeluchu.features.anime.mappers.documentToAnimesEntity
|
||||
import com.jeluchu.features.anime.mappers.documentToAnimesThemeEntity
|
||||
import com.mongodb.client.MongoDatabase
|
||||
import io.ktor.http.*
|
||||
import io.ktor.server.response.*
|
||||
import io.ktor.server.routing.*
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
class AnimeThemesService(
|
||||
private val database: MongoDatabase
|
||||
) {
|
||||
private val themesDirectory = database.getCollection(Collections.ANIME_THEMES)
|
||||
private val artistsDirectory = database.getCollection(Collections.ARTISTS_INDEX)
|
||||
|
||||
suspend fun getAnimeThemes(call: RoutingCall) {
|
||||
val page = call.getIntSafeQueryParam("page", 1)
|
||||
val size = call.getIntSafeQueryParam("size", 25)
|
||||
|
||||
val skipCount = (page - 1) * size
|
||||
if (page < 1 || size < 1) call.badRequestError(ErrorMessages.InvalidSizeAndPage.message)
|
||||
|
||||
val query = themesDirectory
|
||||
.find()
|
||||
.skip(skipCount)
|
||||
.limit(size)
|
||||
.toList()
|
||||
.map { documentToAnimesThemeEntity(it) }
|
||||
|
||||
val paginate = PaginationResponse(
|
||||
page = page,
|
||||
data = query,
|
||||
size = query.size
|
||||
)
|
||||
|
||||
call.respond(HttpStatusCode.OK, Json.encodeToString(paginate))
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue