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