diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml
index 08f1428..572e2e0 100644
--- a/.github/workflows/push.yml
+++ b/.github/workflows/push.yml
@@ -98,4 +98,4 @@ jobs:
- name: SSH Commands
run: |
- ssh -C -p 2222 ${{ secrets.SSH_DESTINATION }} "docker pull localhost:5000/jais-api:latest && cd ${{ secrets.SSH_FOLDER }} && docker compose down jais-api && docker compose up jais-api -d"
+ ssh -C -p 2222 ${{ secrets.SSH_DESTINATION }} "docker pull localhost:5000/jais-api:latest && cd ${{ secrets.SSH_FOLDER }} && docker compose down jais-api && docker compose up -d"
diff --git a/pom.xml b/pom.xml
index 61f0e05..60d33e0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -142,6 +142,11 @@
guava
32.1.2-jre
+
+ com.google.inject
+ guice
+ 7.0.0
+
diff --git a/src/main/kotlin/fr/ziedelth/controllers/AbstractController.kt b/src/main/kotlin/fr/ziedelth/controllers/AbstractController.kt
index 87a87f0..adc2807 100644
--- a/src/main/kotlin/fr/ziedelth/controllers/AbstractController.kt
+++ b/src/main/kotlin/fr/ziedelth/controllers/AbstractController.kt
@@ -2,11 +2,9 @@ package fr.ziedelth.controllers
import fr.ziedelth.utils.Constant
import fr.ziedelth.utils.Decoder
-import fr.ziedelth.utils.ImageCache
import io.ktor.http.*
import io.ktor.server.application.*
import io.ktor.server.response.*
-import io.ktor.server.routing.*
import io.ktor.util.pipeline.*
import java.io.Serializable
import java.lang.reflect.ParameterizedType
@@ -15,7 +13,7 @@ import java.util.*
const val UNKNOWN_MESSAGE_ERROR = "Unknown error"
const val MISSING_PARAMETERS_MESSAGE_ERROR = "Missing parameters"
-open class IController(val prefix: String) {
+open class AbstractController(open val prefix: String) {
data class FilterData(
val animes: List = listOf(),
val episodes: List = listOf(),
@@ -27,7 +25,8 @@ open class IController(val prefix: String) {
((javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0] as Class<*>).simpleName
val uuidRequest: UUID = UUID.randomUUID()
- fun decode(watchlist: String) = Constant.gson.fromJson(Decoder.fromGzip(watchlist), FilterData::class.java)
+ fun decode(watchlist: String): FilterData =
+ Constant.gson.fromJson(Decoder.fromGzip(watchlist), FilterData::class.java)
fun PipelineContext.getPageAndLimit(): Pair {
val page = call.parameters["page"]!!.toIntOrNull() ?: throw IllegalArgumentException("Page is not valid")
@@ -43,30 +42,4 @@ open class IController(val prefix: String) {
e.printStackTrace()
call.respond(HttpStatusCode.InternalServerError, e.message ?: UNKNOWN_MESSAGE_ERROR)
}
-
- fun Route.getAttachment() {
- get("/attachment/{uuid}") {
- val string = call.parameters["uuid"]!!
- val uuidRegex =
- "^[0-9(a-f|A-F)]{8}-[0-9(a-f|A-F)]{4}-4[0-9(a-f|A-F)]{3}-[89ab][0-9(a-f|A-F)]{3}-[0-9(a-f|A-F)]{12}\$".toRegex()
-
- if (!uuidRegex.matches(string)) {
- println("GET $prefix/attachment/$string : Invalid UUID")
- return@get call.respond(HttpStatusCode.BadRequest)
- }
-
- val uuid = UUID.fromString(string)
- println("GET ${prefix}/attachment/$uuid")
-
- if (!ImageCache.contains(uuid)) {
- println("Attachment $uuid not found")
- call.respond(HttpStatusCode.NoContent)
- return@get
- }
-
- val image = ImageCache.get(uuid)!!
- println("Attachment $uuid found (${image.bytes.size} bytes)")
- call.respondBytes(image.bytes, ContentType("image", image.type))
- }
- }
}
diff --git a/src/main/kotlin/fr/ziedelth/controllers/AnimeController.kt b/src/main/kotlin/fr/ziedelth/controllers/AnimeController.kt
index d39dd24..398a1ac 100644
--- a/src/main/kotlin/fr/ziedelth/controllers/AnimeController.kt
+++ b/src/main/kotlin/fr/ziedelth/controllers/AnimeController.kt
@@ -1,11 +1,15 @@
package fr.ziedelth.controllers
+import com.google.inject.Inject
import fr.ziedelth.entities.Anime
import fr.ziedelth.entities.isNullOrNotValid
+import fr.ziedelth.repositories.AnimeRepository
import fr.ziedelth.repositories.CountryRepository
+import fr.ziedelth.repositories.EpisodeRepository
import fr.ziedelth.services.AnimeService
import fr.ziedelth.services.EpisodeService
import fr.ziedelth.utils.ImageCache
+import fr.ziedelth.utils.routes.APIRoute
import io.ktor.http.*
import io.ktor.server.application.*
import io.ktor.server.request.*
@@ -13,77 +17,80 @@ import io.ktor.server.response.*
import io.ktor.server.routing.*
import java.util.*
-class AnimeController(
- private val countryRepository: CountryRepository,
- private val service: AnimeService,
- private val episodeService: EpisodeService
-) :
- IController("/animes") {
- fun getRoutes(routing: Routing) {
- routing.route(prefix) {
- search()
- getByPage()
- getAttachment()
- getMissing()
- create()
- merge()
- diary()
+class AnimeController : AttachmentController("/animes") {
+ @Inject
+ private lateinit var countryRepository: CountryRepository
+
+ @Inject
+ private lateinit var episodeRepository: EpisodeRepository
+
+ @Inject
+ private lateinit var episodeService: EpisodeService
+
+ @Inject
+ private lateinit var animeRepository: AnimeRepository
+
+ @Inject
+ private lateinit var animeService: AnimeService
+
+ @APIRoute
+ private fun Route.searchByCountryAndHash() {
+ get("/country/{country}/search/hash/{hash}") {
+ val country = call.parameters["country"]!!
+ val hash = call.parameters["hash"]!!
+ println("GET $prefix/country/$country/search/hash/$hash")
+ val anime = animeRepository.findByHash(country, hash)
+ call.respond(if (anime != null) mapOf("uuid" to anime) else HttpStatusCode.NotFound)
}
}
- private fun Route.search() {
- route("/country/{country}/search") {
- get("/hash/{hash}") {
- val country = call.parameters["country"]!!
- val hash = call.parameters["hash"]!!
- println("GET $prefix/country/$country/search/hash/$hash")
- val anime = service.repository.findByHash(country, hash)
- call.respond(if (anime != null) mapOf("uuid" to anime) else HttpStatusCode.NotFound)
- }
-
- get("/name/{name}") {
- val country = call.parameters["country"]!!
- val name = call.parameters["name"]!!
- println("GET $prefix/country/$country/search/name/$name")
+ @APIRoute
+ private fun Route.searchByCountryAndName() {
+ get("/country/{country}/search/name/{name}") {
+ val country = call.parameters["country"]!!
+ val name = call.parameters["name"]!!
+ println("GET $prefix/country/$country/search/name/$name")
- try {
- call.respond(service.findByName(country, name))
- } catch (e: Exception) {
- e.printStackTrace()
- }
+ try {
+ call.respond(animeService.findByName(country, name))
+ } catch (e: Exception) {
+ e.printStackTrace()
}
}
}
- private fun Route.getByPage() {
+ @APIRoute
+ private fun Route.paginationByCountryAndSimulcast() {
get("/country/{country}/simulcast/{simulcast}/page/{page}/limit/{limit}") {
try {
val country = call.parameters["country"]!!
val simulcast = call.parameters["simulcast"]!!
val (page, limit) = getPageAndLimit()
println("GET $prefix/country/$country/simulcast/$simulcast/page/$page/limit/$limit")
- call.respond(service.getByPage(country, UUID.fromString(simulcast), page, limit))
+ call.respond(animeService.getByPage(country, UUID.fromString(simulcast), page, limit))
} catch (e: Exception) {
printError(call, e)
}
}
}
- private fun Route.getMissing() {
+ @APIRoute
+ private fun Route.paginationMissing() {
post("/missing/page/{page}/limit/{limit}") {
try {
val watchlist = call.receive()
val (page, limit) = getPageAndLimit()
println("POST $prefix/missing/page/$page/limit/$limit")
val filterData = decode(watchlist)
- call.respond(service.repository.getMissingAnimes(filterData, page, limit))
+ call.respond(animeRepository.getMissingAnimes(filterData, page, limit))
} catch (e: Exception) {
printError(call, e)
}
}
}
- private fun Route.create() {
+ @APIRoute
+ private fun Route.save() {
post {
println("POST $prefix")
@@ -106,7 +113,7 @@ class AnimeController(
return@post
}
- if (service.repository.findOneByName(
+ if (animeRepository.findOneByName(
anime.country!!.tag!!,
anime.name!!
)?.country?.uuid == anime.country!!.uuid
@@ -118,17 +125,17 @@ class AnimeController(
val hash = anime.hash()
- if (service.repository.findByHash(anime.country!!.tag!!, hash) != null) {
+ if (animeRepository.findByHash(anime.country!!.tag!!, hash) != null) {
println("$entityName already exists")
call.respond(HttpStatusCode.Conflict, "$entityName already exists")
return@post
}
anime.hashes.add(hash)
- val savedAnime = service.repository.save(anime)
- ImageCache.cachingNetworkImage(savedAnime.uuid, savedAnime.image!!)
+ val savedAnime = animeRepository.save(anime)
+ ImageCache.cache(savedAnime.uuid, savedAnime.image!!)
- service.invalidateAll()
+ animeService.invalidateAll()
call.respond(HttpStatusCode.Created, savedAnime)
} catch (e: Exception) {
printError(call, e)
@@ -136,13 +143,14 @@ class AnimeController(
}
}
+ @APIRoute
private fun Route.merge() {
put("/merge") {
// Get list of uuids
val uuids = call.receive>().map { UUID.fromString(it) }
println("PUT $prefix/merge")
// Get anime
- val animes = uuids.mapNotNull { service.repository.find(it) }
+ val animes = uuids.mapNotNull { animeRepository.find(it) }
if (animes.isEmpty()) {
println("Anime not found")
@@ -167,14 +175,14 @@ class AnimeController(
val simulcasts = animes.map { it.simulcasts }.flatten().distinctBy { it.uuid }.toMutableSet()
// Get all episodes
val episodes =
- animes.map { episodeService.repository.getAllBy("anime.uuid", it.uuid) }.flatten()
+ animes.map { episodeRepository.getAllBy("anime.uuid", it.uuid) }.flatten()
.distinctBy { it.uuid }
.toMutableSet()
val firstAnime = animes.first()
- val savedAnime = service.repository.find(
- service.repository.save(
+ val savedAnime = animeRepository.find(
+ animeRepository.save(
Anime(
country = countries.first(),
name = "${animes.first().name} (${animes.size})",
@@ -188,26 +196,27 @@ class AnimeController(
).uuid
)!!
- ImageCache.cachingNetworkImage(savedAnime.uuid, savedAnime.image!!)
- episodeService.repository.saveAll(episodes.map { it.copy(anime = savedAnime) })
+ ImageCache.cache(savedAnime.uuid, savedAnime.image!!)
+ episodeRepository.saveAll(episodes.map { it.copy(anime = savedAnime) })
// Delete animes
- service.repository.deleteAll(animes)
+ animeRepository.deleteAll(animes)
- service.invalidateAll()
+ animeService.invalidateAll()
episodeService.invalidateAll()
call.respond(HttpStatusCode.OK, savedAnime)
}
}
- private fun Route.diary() {
+ @APIRoute
+ private fun Route.diaryByCountryAndDay() {
get("/diary/country/{country}/day/{day}") {
val country = call.parameters["country"]!!
var day = call.parameters["day"]!!.toIntOrNull() ?: return@get call.respond(HttpStatusCode.BadRequest)
if (day == 0) day = 7
if (day > 7) day = 1
println("GET $prefix/diary/country/$country/day/$day")
- call.respond(service.getDiary(country, day))
+ call.respond(animeService.getDiary(country, day))
}
}
}
diff --git a/src/main/kotlin/fr/ziedelth/controllers/AttachmentController.kt b/src/main/kotlin/fr/ziedelth/controllers/AttachmentController.kt
new file mode 100644
index 0000000..e43d5ec
--- /dev/null
+++ b/src/main/kotlin/fr/ziedelth/controllers/AttachmentController.kt
@@ -0,0 +1,39 @@
+package fr.ziedelth.controllers
+
+import fr.ziedelth.utils.ImageCache
+import fr.ziedelth.utils.routes.APIIgnore
+import io.ktor.http.*
+import io.ktor.server.application.*
+import io.ktor.server.response.*
+import io.ktor.server.routing.*
+import java.io.Serializable
+import java.util.*
+
+@APIIgnore
+open class AttachmentController(override val prefix: String) : AbstractController(prefix) {
+ fun Route.attachmentByUUID() {
+ get("/attachment/{uuid}") {
+ val string = call.parameters["uuid"]!!
+ val uuidRegex =
+ "^[0-9(a-f|A-F)]{8}-[0-9(a-f|A-F)]{4}-4[0-9(a-f|A-F)]{3}-[89ab][0-9(a-f|A-F)]{3}-[0-9(a-f|A-F)]{12}\$".toRegex()
+
+ if (!uuidRegex.matches(string)) {
+ println("GET $prefix/attachment/$string : Invalid UUID")
+ return@get call.respond(HttpStatusCode.BadRequest)
+ }
+
+ val uuid = UUID.fromString(string)
+ println("GET ${prefix}/attachment/$uuid")
+
+ if (!ImageCache.contains(uuid)) {
+ println("Attachment $uuid not found")
+ call.respond(HttpStatusCode.NoContent)
+ return@get
+ }
+
+ val image = ImageCache.get(uuid)!!
+ println("Attachment $uuid found (${image.bytes.size} bytes)")
+ call.respondBytes(image.bytes, ContentType("image", image.type))
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/fr/ziedelth/controllers/AyaneController.kt b/src/main/kotlin/fr/ziedelth/controllers/AyaneController.kt
index 190f4af..5857c7c 100644
--- a/src/main/kotlin/fr/ziedelth/controllers/AyaneController.kt
+++ b/src/main/kotlin/fr/ziedelth/controllers/AyaneController.kt
@@ -3,34 +3,34 @@ package fr.ziedelth.controllers
import fr.ziedelth.dtos.Ayane
import fr.ziedelth.events.AyaneReleaseEvent
import fr.ziedelth.utils.plugins.PluginManager
+import fr.ziedelth.utils.routes.APIRoute
import io.ktor.http.*
import io.ktor.server.application.*
import io.ktor.server.request.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
-class AyaneController : IController("/ayane") {
- fun getRoutes(routing: Routing) {
- routing.route(prefix) {
- post {
- println("POST $prefix")
+class AyaneController : AbstractController("/ayane") {
+ @APIRoute
+ private fun Route.save() {
+ post {
+ println("POST $prefix")
- try {
- val ayane = call.receive()
+ try {
+ val ayane = call.receive()
- if (ayane.message.isBlank() || ayane.images.isEmpty()) {
- call.respond(HttpStatusCode.BadRequest, MISSING_PARAMETERS_MESSAGE_ERROR)
- return@post
- }
+ if (ayane.message.isBlank() || ayane.images.isEmpty()) {
+ call.respond(HttpStatusCode.BadRequest, MISSING_PARAMETERS_MESSAGE_ERROR)
+ return@post
+ }
- call.respond(HttpStatusCode.Created, "OK")
+ call.respond(HttpStatusCode.Created, "OK")
- Thread {
- PluginManager.callEvent(AyaneReleaseEvent(ayane))
- }.start()
- } catch (e: Exception) {
- printError(call, e)
- }
+ Thread {
+ PluginManager.callEvent(AyaneReleaseEvent(ayane))
+ }.start()
+ } catch (e: Exception) {
+ printError(call, e)
}
}
}
diff --git a/src/main/kotlin/fr/ziedelth/controllers/CountryController.kt b/src/main/kotlin/fr/ziedelth/controllers/CountryController.kt
index 125c50e..dc7ee02 100644
--- a/src/main/kotlin/fr/ziedelth/controllers/CountryController.kt
+++ b/src/main/kotlin/fr/ziedelth/controllers/CountryController.kt
@@ -1,30 +1,34 @@
package fr.ziedelth.controllers
+import com.google.inject.Inject
import fr.ziedelth.entities.Country
import fr.ziedelth.entities.isNullOrNotValid
+import fr.ziedelth.repositories.CountryRepository
import fr.ziedelth.services.CountryService
+import fr.ziedelth.utils.routes.APIRoute
import io.ktor.http.*
import io.ktor.server.application.*
import io.ktor.server.request.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
-class CountryController(private val service: CountryService) : IController("/countries") {
- fun getRoutes(routing: Routing) {
- routing.route(prefix) {
- getAll()
- create()
- }
- }
+class CountryController : AbstractController("/countries") {
+ @Inject
+ private lateinit var countryRepository: CountryRepository
+
+ @Inject
+ private lateinit var countryService: CountryService
- fun Route.getAll() {
+ @APIRoute
+ private fun Route.getAll() {
get {
println("GET $prefix")
- call.respond(service.getAll())
+ call.respond(countryService.getAll())
}
}
- private fun Route.create() {
+ @APIRoute
+ private fun Route.save() {
post {
println("POST $prefix")
@@ -36,18 +40,18 @@ class CountryController(private val service: CountryService) : IController("/episodes") {
- fun getRoutes(routing: Routing) {
- routing.route(prefix) {
- getWithPage()
- getAnimeWithPage()
- getWatchlist()
- getWatchlistFilter()
- getAttachment()
- create()
- }
- }
+class EpisodeController : AttachmentController("/episodes") {
+ @Inject
+ private lateinit var platformRepository: PlatformRepository
+
+ @Inject
+ private lateinit var animeRepository: AnimeRepository
+
+ @Inject
+ private lateinit var animeService: AnimeService
+
+ @Inject
+ private lateinit var simulcastRepository: SimulcastRepository
+
+ @Inject
+ private lateinit var simulcastService: SimulcastService
+
+ @Inject
+ private lateinit var episodeTypeRepository: EpisodeTypeRepository
+
+ @Inject
+ private lateinit var langTypeRepository: LangTypeRepository
+
+ @Inject
+ private lateinit var episodeRepository: EpisodeRepository
+
+ @Inject
+ private lateinit var episodeService: EpisodeService
- private fun Route.getWithPage() {
+ @APIRoute
+ private fun Route.paginationByCountry() {
get("/country/{country}/page/{page}/limit/{limit}") {
try {
val country = call.parameters["country"]!!
val (page, limit) = getPageAndLimit()
println("GET $prefix/country/$country/page/$page/limit/$limit")
- call.respond(service.getByPage(country, page, limit))
+ call.respond(episodeService.getByPage(country, page, limit))
} catch (e: Exception) {
printError(call, e)
}
}
}
- private fun Route.getAnimeWithPage() {
+ @APIRoute
+ private fun Route.paginationAnime() {
get("/anime/{uuid}/page/{page}/limit/{limit}") {
try {
val animeUuid = call.parameters["uuid"]!!
val (page, limit) = getPageAndLimit()
println("GET $prefix/anime/$animeUuid/page/$page/limit/$limit")
- call.respond(service.getByPageWithAnime(UUID.fromString(animeUuid), page, limit))
+ call.respond(episodeService.getByPageWithAnime(UUID.fromString(animeUuid), page, limit))
} catch (e: Exception) {
printError(call, e)
}
@@ -76,20 +87,22 @@ class EpisodeController(
println("POST $prefix/${routePrefix}/page/$page/limit/$limit")
val filterData = decode(watchlist)
- pipelineContext.call.respond(service.repository.getByPageWithListFilter(filterData, page, limit))
+ pipelineContext.call.respond(episodeRepository.getByPageWithListFilter(filterData, page, limit))
} catch (e: Exception) {
episodeController.printError(pipelineContext.call, e)
}
}
- private fun Route.getWatchlist() {
+ @APIRoute
+ private fun Route.paginationWatchlist() {
post("/watchlist/page/{page}/limit/{limit}") {
filterWatchlistByPageAndLimit(this, this@EpisodeController, "watchlist")
}
}
+ @APIRoute
@Deprecated(message = "Use /watchlist as replace")
- private fun Route.getWatchlistFilter() {
+ private fun Route.paginationWatchlistFilter() {
post("/watchlist_filter/page/{page}/limit/{limit}") {
filterWatchlistByPageAndLimit(this, this@EpisodeController, "watchlist_filter")
}
@@ -97,7 +110,7 @@ class EpisodeController(
private fun merge(episode: Episode) {
episode.platform = platformRepository.find(episode.platform!!.uuid) ?: throw Exception("Platform not found")
- episode.anime = animeService.repository.find(episode.anime!!.uuid) ?: throw Exception("Anime not found")
+ episode.anime = animeRepository.find(episode.anime!!.uuid) ?: throw Exception("Anime not found")
episode.episodeType =
episodeTypeRepository.find(episode.episodeType!!.uuid) ?: throw Exception("EpisodeType not found")
episode.langType = langTypeRepository.find(episode.langType!!.uuid) ?: throw Exception("LangType not found")
@@ -107,25 +120,26 @@ class EpisodeController(
}
if (episode.number == -1) {
- episode.number = service.repository.getLastNumber(episode) + 1
+ episode.number = episodeRepository.getLastNumber(episode) + 1
}
val tmpSimulcast =
Simulcast.getSimulcast(episode.releaseDate.split("-")[0].toInt(), episode.releaseDate.split("-")[1].toInt())
val simulcast =
- simulcastService.repository.findBySeasonAndYear(tmpSimulcast.season!!, tmpSimulcast.year!!) ?: tmpSimulcast
+ simulcastRepository.findBySeasonAndYear(tmpSimulcast.season!!, tmpSimulcast.year!!) ?: tmpSimulcast
if (episode.anime!!.simulcasts.isEmpty() || episode.anime!!.simulcasts.none { it.uuid == simulcast.uuid }) {
episode.anime!!.simulcasts.add(simulcast)
}
}
- private fun Route.create() {
+ @APIRoute
+ private fun Route.saveMultiple() {
post("/multiple") {
println("POST $prefix/multiple")
try {
- val episodes = call.receive>().filter { !service.repository.exists("hash", it.hash!!) }
+ val episodes = call.receive>().filter { !episodeRepository.exists("hash", it.hash!!) }
if (episodes.isEmpty()) {
call.respond(HttpStatusCode.NoContent, "All requested episodes already exists!")
@@ -136,12 +150,12 @@ class EpisodeController(
episodes.forEach {
merge(it)
- val savedEpisode = service.repository.save(it)
+ val savedEpisode = episodeRepository.save(it)
savedEpisodes.add(savedEpisode)
- ImageCache.cachingNetworkImage(savedEpisode.uuid, savedEpisode.image!!)
+ ImageCache.cache(savedEpisode.uuid, savedEpisode.image!!)
}
- service.invalidateAll()
+ episodeService.invalidateAll()
animeService.invalidateAll()
simulcastService.invalidateAll()
call.respond(HttpStatusCode.Created, savedEpisodes)
diff --git a/src/main/kotlin/fr/ziedelth/controllers/EpisodeTypeController.kt b/src/main/kotlin/fr/ziedelth/controllers/EpisodeTypeController.kt
index 165708c..41e8cfe 100644
--- a/src/main/kotlin/fr/ziedelth/controllers/EpisodeTypeController.kt
+++ b/src/main/kotlin/fr/ziedelth/controllers/EpisodeTypeController.kt
@@ -1,31 +1,34 @@
package fr.ziedelth.controllers
+import com.google.inject.Inject
import fr.ziedelth.entities.EpisodeType
import fr.ziedelth.entities.isNullOrNotValid
+import fr.ziedelth.repositories.EpisodeTypeRepository
import fr.ziedelth.services.EpisodeTypeService
+import fr.ziedelth.utils.routes.APIRoute
import io.ktor.http.*
import io.ktor.server.application.*
import io.ktor.server.request.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
-class EpisodeTypeController(private val service: EpisodeTypeService) :
- IController("/episodetypes") {
- fun getRoutes(routing: Routing) {
- routing.route(prefix) {
- getAll()
- create()
- }
- }
+class EpisodeTypeController : AbstractController("/episodetypes") {
+ @Inject
+ private lateinit var episodeTypeRepository: EpisodeTypeRepository
+
+ @Inject
+ private lateinit var episodeTypeService: EpisodeTypeService
- fun Route.getAll() {
+ @APIRoute
+ private fun Route.getAll() {
get {
println("GET $prefix")
- call.respond(service.getAll())
+ call.respond(episodeTypeService.getAll())
}
}
- private fun Route.create() {
+ @APIRoute
+ private fun Route.save() {
post {
println("POST $prefix")
@@ -37,13 +40,13 @@ class EpisodeTypeController(private val service: EpisodeTypeService) :
return@post
}
- if (service.repository.exists("name", episodeType.name)) {
+ if (episodeTypeRepository.exists("name", episodeType.name)) {
call.respond(HttpStatusCode.Conflict, "$entityName already exists")
return@post
}
- call.respond(HttpStatusCode.Created, service.repository.save(episodeType))
- service.invalidateAll()
+ call.respond(HttpStatusCode.Created, episodeTypeRepository.save(episodeType))
+ episodeTypeService.invalidateAll()
} catch (e: Exception) {
printError(call, e)
}
diff --git a/src/main/kotlin/fr/ziedelth/controllers/GenreController.kt b/src/main/kotlin/fr/ziedelth/controllers/GenreController.kt
index 24cfcb4..3751ac1 100644
--- a/src/main/kotlin/fr/ziedelth/controllers/GenreController.kt
+++ b/src/main/kotlin/fr/ziedelth/controllers/GenreController.kt
@@ -1,30 +1,30 @@
package fr.ziedelth.controllers
+import com.google.inject.Inject
import fr.ziedelth.entities.Genre
import fr.ziedelth.entities.isNullOrNotValid
import fr.ziedelth.repositories.GenreRepository
+import fr.ziedelth.utils.routes.APIRoute
import io.ktor.http.*
import io.ktor.server.application.*
import io.ktor.server.request.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
-class GenreController(private val genreRepository: GenreRepository) : IController("/genres") {
- fun getRoutes(routing: Routing) {
- routing.route(prefix) {
- getAll()
- create()
- }
- }
+class GenreController : AbstractController("/genres") {
+ @Inject
+ private lateinit var genreRepository: GenreRepository
- fun Route.getAll() {
+ @APIRoute
+ private fun Route.getAll() {
get {
println("GET $prefix")
call.respond(genreRepository.getAll())
}
}
- private fun Route.create() {
+ @APIRoute
+ private fun Route.save() {
post {
println("POST $prefix")
diff --git a/src/main/kotlin/fr/ziedelth/controllers/LangTypeController.kt b/src/main/kotlin/fr/ziedelth/controllers/LangTypeController.kt
index b03980b..c299fb1 100644
--- a/src/main/kotlin/fr/ziedelth/controllers/LangTypeController.kt
+++ b/src/main/kotlin/fr/ziedelth/controllers/LangTypeController.kt
@@ -1,30 +1,34 @@
package fr.ziedelth.controllers
+import com.google.inject.Inject
import fr.ziedelth.entities.LangType
import fr.ziedelth.entities.isNullOrNotValid
+import fr.ziedelth.repositories.LangTypeRepository
import fr.ziedelth.services.LangTypeService
+import fr.ziedelth.utils.routes.APIRoute
import io.ktor.http.*
import io.ktor.server.application.*
import io.ktor.server.request.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
-class LangTypeController(private val service: LangTypeService) : IController("/langtypes") {
- fun getRoutes(routing: Routing) {
- routing.route(prefix) {
- getAll()
- create()
- }
- }
+class LangTypeController : AbstractController("/langtypes") {
+ @Inject
+ private lateinit var langTypeRepository: LangTypeRepository
+
+ @Inject
+ private lateinit var langTypeService: LangTypeService
- fun Route.getAll() {
+ @APIRoute
+ private fun Route.getAll() {
get {
println("GET $prefix")
- call.respond(service.getAll())
+ call.respond(langTypeService.getAll())
}
}
- private fun Route.create() {
+ @APIRoute
+ private fun Route.save() {
post {
println("POST $prefix")
@@ -36,13 +40,13 @@ class LangTypeController(private val service: LangTypeService) : IController("/platforms") {
- fun getRoutes(routing: Routing) {
- routing.route(prefix) {
- getAll()
- getAttachment()
- create()
- }
- }
+class PlatformController : AttachmentController("/platforms") {
+ @Inject
+ private lateinit var platformRepository: PlatformRepository
- fun Route.getAll() {
+ @APIRoute
+ private fun Route.getAll() {
get {
println("GET $prefix")
call.respond(platformRepository.getAll())
}
}
- private fun Route.create() {
+ @APIRoute
+ private fun Route.save() {
post {
println("POST $prefix")
@@ -43,6 +43,7 @@ class PlatformController(private val platformRepository: PlatformRepository) : I
}
call.respond(HttpStatusCode.Created, platformRepository.save(platform))
+ ImageCache.cache(platform.uuid, platform.image!!)
} catch (e: Exception) {
printError(call, e)
}
diff --git a/src/main/kotlin/fr/ziedelth/controllers/ProfileController.kt b/src/main/kotlin/fr/ziedelth/controllers/ProfileController.kt
index 2197a44..19a94fa 100644
--- a/src/main/kotlin/fr/ziedelth/controllers/ProfileController.kt
+++ b/src/main/kotlin/fr/ziedelth/controllers/ProfileController.kt
@@ -1,6 +1,8 @@
package fr.ziedelth.controllers
+import com.google.inject.Inject
import fr.ziedelth.repositories.EpisodeRepository
+import fr.ziedelth.utils.routes.APIRoute
import io.ktor.http.*
import io.ktor.server.application.*
import io.ktor.server.request.*
@@ -8,19 +10,21 @@ import io.ktor.server.response.*
import io.ktor.server.routing.*
import java.io.Serializable
-class ProfileController(private val episodeRepository: EpisodeRepository) : IController("/profile") {
- fun getRoutes(routing: Routing) {
- routing.route(prefix) {
- post("/total-duration") {
- try {
- val watchlist = call.receive()
- println("GET $prefix/total-duration")
- val filterData = decode(watchlist)
- call.respond(mapOf("total-duration" to episodeRepository.getTotalDurationSeen(filterData.episodes)))
- } catch (e: Exception) {
- e.printStackTrace()
- call.respond(HttpStatusCode.InternalServerError, e)
- }
+class ProfileController : AbstractController("/profile") {
+ @Inject
+ private lateinit var episodeRepository: EpisodeRepository
+
+ @APIRoute
+ private fun Route.totalDuration() {
+ post("/total-duration") {
+ try {
+ val watchlist = call.receive()
+ println("GET $prefix/total-duration")
+ val filterData = decode(watchlist)
+ call.respond(mapOf("total-duration" to episodeRepository.getTotalDurationSeen(filterData.episodes)))
+ } catch (e: Exception) {
+ e.printStackTrace()
+ call.respond(HttpStatusCode.InternalServerError, e)
}
}
}
diff --git a/src/main/kotlin/fr/ziedelth/controllers/SimulcastController.kt b/src/main/kotlin/fr/ziedelth/controllers/SimulcastController.kt
index 1ed5712..cd5e46f 100644
--- a/src/main/kotlin/fr/ziedelth/controllers/SimulcastController.kt
+++ b/src/main/kotlin/fr/ziedelth/controllers/SimulcastController.kt
@@ -1,25 +1,28 @@
package fr.ziedelth.controllers
+import com.google.inject.Inject
import fr.ziedelth.entities.Simulcast
import fr.ziedelth.services.SimulcastService
+import fr.ziedelth.utils.routes.APIRoute
import io.ktor.http.*
import io.ktor.server.application.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
-class SimulcastController(private val service: SimulcastService) :
- IController("/simulcasts") {
- fun getRoutes(routing: Routing) {
- routing.route(prefix) {
- get("/country/{country}") {
- try {
- val country = call.parameters["country"]!!
- println("GET $prefix/country/$country")
- call.respond(service.getAll(country))
- } catch (e: Exception) {
- e.printStackTrace()
- call.respond(HttpStatusCode.InternalServerError, e)
- }
+class SimulcastController : AbstractController("/simulcasts") {
+ @Inject
+ private lateinit var simulcastService: SimulcastService
+
+ @APIRoute
+ private fun Route.getByCountry() {
+ get("/country/{country}") {
+ try {
+ val country = call.parameters["country"]!!
+ println("GET $prefix/country/$country")
+ call.respond(simulcastService.getAll(country))
+ } catch (e: Exception) {
+ e.printStackTrace()
+ call.respond(HttpStatusCode.InternalServerError, e)
}
}
}
diff --git a/src/main/kotlin/fr/ziedelth/listeners/EpisodesRelease.kt b/src/main/kotlin/fr/ziedelth/listeners/EpisodesRelease.kt
index 0223fdc..0ac90fc 100644
--- a/src/main/kotlin/fr/ziedelth/listeners/EpisodesRelease.kt
+++ b/src/main/kotlin/fr/ziedelth/listeners/EpisodesRelease.kt
@@ -12,7 +12,7 @@ class EpisodesRelease : Listener {
private var lastDaySend = 0
private var lastSend = mutableListOf()
- fun toString(triple: Triple): String {
+ fun toString(triple: Triple): String {
val etName = when (triple.first.name) {
"EPISODE" -> "Épisode"
"SPECIAL" -> "Spécial"
@@ -38,7 +38,8 @@ class EpisodesRelease : Listener {
lastSend.clear()
}
- val animes = event.episodes.map { it.anime to toString(Triple(it.episodeType!!, it.number!!, it.langType!!)) }.distinctBy { it.first?.uuid }.filter { !lastSend.contains(it.first?.uuid) }
+ val animes = event.episodes.map { it.anime to toString(Triple(it.episodeType!!, it.number!!, it.langType!!)) }
+ .distinctBy { it.first?.uuid }.filter { !lastSend.contains(it.first?.uuid) }
if (animes.isEmpty()) return
lastSend.addAll(animes.map { it.first!!.uuid })
diff --git a/src/main/kotlin/fr/ziedelth/plugins/Routing.kt b/src/main/kotlin/fr/ziedelth/plugins/Routing.kt
index 51458cb..6c918af 100644
--- a/src/main/kotlin/fr/ziedelth/plugins/Routing.kt
+++ b/src/main/kotlin/fr/ziedelth/plugins/Routing.kt
@@ -1,46 +1,63 @@
package fr.ziedelth.plugins
-import fr.ziedelth.controllers.*
-import fr.ziedelth.repositories.*
-import fr.ziedelth.services.*
+import com.google.inject.AbstractModule
+import com.google.inject.Guice
+import fr.ziedelth.controllers.AbstractController
+import fr.ziedelth.controllers.AttachmentController
+import fr.ziedelth.repositories.AbstractRepository
+import fr.ziedelth.services.AbstractService
import fr.ziedelth.utils.Database
+import fr.ziedelth.utils.routes.APIIgnore
+import fr.ziedelth.utils.routes.APIRoute
import io.ktor.server.application.*
import io.ktor.server.routing.*
+import org.reflections.Reflections
+import kotlin.reflect.full.findAnnotations
+import kotlin.reflect.full.memberExtensionFunctions
+import kotlin.reflect.jvm.javaMethod
+
+class DatabaseModule(private val reflections: Reflections, private val database: Database) : AbstractModule() {
+ override fun configure() {
+ bind(Database::class.java).toInstance(database)
+
+ reflections.getSubTypesOf(AbstractRepository::class.java).forEach {
+ bind(it).asEagerSingleton()
+ }
+
+ reflections.getSubTypesOf(AbstractService::class.java).forEach {
+ bind(it).asEagerSingleton()
+ }
+ }
+}
fun Application.configureRouting(database: Database) {
+ val reflections = Reflections("fr.ziedelth")
+ val injector = Guice.createInjector(DatabaseModule(reflections, database))
+
routing {
- val countryRepository = CountryRepository(database)
- val platformRepository = PlatformRepository(database)
- val simulcastRepository = SimulcastRepository(database)
- val genreRepository = GenreRepository(database)
- val animeRepository = AnimeRepository(database)
- val episodeTypeRepository = EpisodeTypeRepository(database)
- val langTypeRepository = LangTypeRepository(database)
- val episodeRepository = EpisodeRepository(database)
-
- val countryService = CountryService(countryRepository)
- val episodeTypeService = EpisodeTypeService(episodeTypeRepository)
- val langTypeService = LangTypeService(langTypeRepository)
- val simulcastService = SimulcastService(simulcastRepository)
- val animeService = AnimeService(animeRepository)
- val episodeService = EpisodeService(episodeRepository)
-
- CountryController(countryService).getRoutes(this)
- PlatformController(platformRepository).getRoutes(this)
- SimulcastController(simulcastService).getRoutes(this)
- GenreController(genreRepository).getRoutes(this)
- AnimeController(countryRepository, animeService, episodeService).getRoutes(this)
- EpisodeTypeController(episodeTypeService).getRoutes(this)
- LangTypeController(langTypeService).getRoutes(this)
- EpisodeController(
- platformRepository,
- animeService,
- simulcastService,
- episodeTypeRepository,
- langTypeRepository,
- episodeService
- ).getRoutes(this)
- AyaneController().getRoutes(this)
- ProfileController(episodeRepository).getRoutes(this)
+ reflections.getSubTypesOf(AbstractController::class.java).forEach {
+ if (it.isAnnotationPresent(APIIgnore::class.java)) {
+ return@forEach
+ }
+
+ val controller = injector.getInstance(it)
+ val isAttachmentController = controller::class.java.superclass == AttachmentController::class.java
+
+ val kFunctions = controller::class.memberExtensionFunctions.filter { kFunction ->
+ kFunction.findAnnotations(APIRoute::class).isNotEmpty()
+ }.toMutableList()
+
+ route(controller.prefix) {
+ kFunctions.forEach { kFunction ->
+ val javaMethod = kFunction.javaMethod!!
+ javaMethod.isAccessible = true
+ javaMethod.invoke(controller, this)
+ }
+
+ if (isAttachmentController) {
+ controller.javaClass.getMethod("attachmentByUUID", Route::class.java).invoke(controller, this)
+ }
+ }
+ }
}
}
diff --git a/src/main/kotlin/fr/ziedelth/repositories/AbstractRepository.kt b/src/main/kotlin/fr/ziedelth/repositories/AbstractRepository.kt
index 696452d..a74797c 100644
--- a/src/main/kotlin/fr/ziedelth/repositories/AbstractRepository.kt
+++ b/src/main/kotlin/fr/ziedelth/repositories/AbstractRepository.kt
@@ -1,10 +1,14 @@
package fr.ziedelth.repositories
+import com.google.inject.Inject
import fr.ziedelth.utils.Database
import java.lang.reflect.ParameterizedType
import java.util.*
-open class AbstractRepository(val database: Database) {
+open class AbstractRepository {
+ @Inject
+ protected lateinit var database: Database
+
private val entityClass: Class =
(javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0] as Class
private val entityName: String = entityClass.simpleName
diff --git a/src/main/kotlin/fr/ziedelth/repositories/AnimeRepository.kt b/src/main/kotlin/fr/ziedelth/repositories/AnimeRepository.kt
index 9bb67d5..d0c7450 100644
--- a/src/main/kotlin/fr/ziedelth/repositories/AnimeRepository.kt
+++ b/src/main/kotlin/fr/ziedelth/repositories/AnimeRepository.kt
@@ -1,17 +1,16 @@
package fr.ziedelth.repositories
-import fr.ziedelth.controllers.IController
+import fr.ziedelth.controllers.AbstractController
import fr.ziedelth.dtos.MissingAnime
import fr.ziedelth.entities.Anime
import fr.ziedelth.entities.Episode
-import fr.ziedelth.utils.Database
import fr.ziedelth.utils.unaccent
import java.time.DayOfWeek
import java.time.OffsetDateTime
import java.time.format.DateTimeFormatter
import java.util.*
-class AnimeRepository(database: Database) : AbstractRepository(database),
+class AnimeRepository : AbstractRepository(),
IPageRepository {
fun findByHash(tag: String, hash: String): UUID? {
return database.inTransaction {
@@ -95,7 +94,7 @@ class AnimeRepository(database: Database) : AbstractRepository(database),
}
fun getMissingAnimes(
- filterData: IController.FilterData,
+ filterData: AbstractController.FilterData,
page: Int,
limit: Int
): List {
diff --git a/src/main/kotlin/fr/ziedelth/repositories/CountryRepository.kt b/src/main/kotlin/fr/ziedelth/repositories/CountryRepository.kt
index 533514e..3e142f8 100644
--- a/src/main/kotlin/fr/ziedelth/repositories/CountryRepository.kt
+++ b/src/main/kotlin/fr/ziedelth/repositories/CountryRepository.kt
@@ -1,6 +1,5 @@
package fr.ziedelth.repositories
import fr.ziedelth.entities.Country
-import fr.ziedelth.utils.Database
-class CountryRepository(database: Database) : AbstractRepository(database)
\ No newline at end of file
+class CountryRepository : AbstractRepository()
\ No newline at end of file
diff --git a/src/main/kotlin/fr/ziedelth/repositories/EpisodeRepository.kt b/src/main/kotlin/fr/ziedelth/repositories/EpisodeRepository.kt
index 76568bc..b563874 100644
--- a/src/main/kotlin/fr/ziedelth/repositories/EpisodeRepository.kt
+++ b/src/main/kotlin/fr/ziedelth/repositories/EpisodeRepository.kt
@@ -1,14 +1,13 @@
package fr.ziedelth.repositories
-import fr.ziedelth.controllers.IController
+import fr.ziedelth.controllers.AbstractController
import fr.ziedelth.entities.Episode
-import fr.ziedelth.utils.Database
import java.util.*
private const val ORDER =
"ORDER BY releaseDate DESC, anime.name, season DESC, number DESC, episodeType.name, langType.name"
-class EpisodeRepository(database: Database) : AbstractRepository(database),
+class EpisodeRepository : AbstractRepository(),
IPageRepository {
override fun getByPage(tag: String, page: Int, limit: Int): List {
return super.getByPage(
@@ -38,7 +37,7 @@ class EpisodeRepository(database: Database) : AbstractRepository(databa
}
fun getByPageWithListFilter(
- filterData: IController.FilterData,
+ filterData: AbstractController.FilterData,
page: Int,
limit: Int
): List {
diff --git a/src/main/kotlin/fr/ziedelth/repositories/EpisodeTypeRepository.kt b/src/main/kotlin/fr/ziedelth/repositories/EpisodeTypeRepository.kt
index e04e00a..9f3f560 100644
--- a/src/main/kotlin/fr/ziedelth/repositories/EpisodeTypeRepository.kt
+++ b/src/main/kotlin/fr/ziedelth/repositories/EpisodeTypeRepository.kt
@@ -1,6 +1,5 @@
package fr.ziedelth.repositories
import fr.ziedelth.entities.EpisodeType
-import fr.ziedelth.utils.Database
-class EpisodeTypeRepository(database: Database) : AbstractRepository(database)
+class EpisodeTypeRepository : AbstractRepository()
diff --git a/src/main/kotlin/fr/ziedelth/repositories/GenreRepository.kt b/src/main/kotlin/fr/ziedelth/repositories/GenreRepository.kt
index 46cf8cf..e67d958 100644
--- a/src/main/kotlin/fr/ziedelth/repositories/GenreRepository.kt
+++ b/src/main/kotlin/fr/ziedelth/repositories/GenreRepository.kt
@@ -1,6 +1,5 @@
package fr.ziedelth.repositories
import fr.ziedelth.entities.Genre
-import fr.ziedelth.utils.Database
-class GenreRepository(database: Database) : AbstractRepository(database)
\ No newline at end of file
+class GenreRepository : AbstractRepository()
\ No newline at end of file
diff --git a/src/main/kotlin/fr/ziedelth/repositories/LangTypeRepository.kt b/src/main/kotlin/fr/ziedelth/repositories/LangTypeRepository.kt
index 62415e0..60ceb84 100644
--- a/src/main/kotlin/fr/ziedelth/repositories/LangTypeRepository.kt
+++ b/src/main/kotlin/fr/ziedelth/repositories/LangTypeRepository.kt
@@ -1,6 +1,5 @@
package fr.ziedelth.repositories
import fr.ziedelth.entities.LangType
-import fr.ziedelth.utils.Database
-class LangTypeRepository(database: Database) : AbstractRepository(database)
+class LangTypeRepository : AbstractRepository()
diff --git a/src/main/kotlin/fr/ziedelth/repositories/PlatformRepository.kt b/src/main/kotlin/fr/ziedelth/repositories/PlatformRepository.kt
index be58351..77b0df5 100644
--- a/src/main/kotlin/fr/ziedelth/repositories/PlatformRepository.kt
+++ b/src/main/kotlin/fr/ziedelth/repositories/PlatformRepository.kt
@@ -1,6 +1,5 @@
package fr.ziedelth.repositories
import fr.ziedelth.entities.Platform
-import fr.ziedelth.utils.Database
-class PlatformRepository(database: Database) : AbstractRepository(database)
\ No newline at end of file
+class PlatformRepository : AbstractRepository()
\ No newline at end of file
diff --git a/src/main/kotlin/fr/ziedelth/repositories/SimulcastRepository.kt b/src/main/kotlin/fr/ziedelth/repositories/SimulcastRepository.kt
index 02dffda..4baa041 100644
--- a/src/main/kotlin/fr/ziedelth/repositories/SimulcastRepository.kt
+++ b/src/main/kotlin/fr/ziedelth/repositories/SimulcastRepository.kt
@@ -2,9 +2,8 @@ package fr.ziedelth.repositories
import fr.ziedelth.entities.Simulcast
import fr.ziedelth.utils.Constant
-import fr.ziedelth.utils.Database
-class SimulcastRepository(database: Database) : AbstractRepository(database) {
+class SimulcastRepository : AbstractRepository() {
fun getAll(tag: String?): List {
val list = database.inTransaction {
val query = it.createQuery("SELECT simulcasts FROM Anime WHERE country.tag = :tag", Simulcast::class.java)
diff --git a/src/main/kotlin/fr/ziedelth/services/AbstractService.kt b/src/main/kotlin/fr/ziedelth/services/AbstractService.kt
new file mode 100644
index 0000000..309c0ef
--- /dev/null
+++ b/src/main/kotlin/fr/ziedelth/services/AbstractService.kt
@@ -0,0 +1,3 @@
+package fr.ziedelth.services
+
+abstract class AbstractService
\ No newline at end of file
diff --git a/src/main/kotlin/fr/ziedelth/services/AnimeService.kt b/src/main/kotlin/fr/ziedelth/services/AnimeService.kt
index 1e02b55..7e163df 100644
--- a/src/main/kotlin/fr/ziedelth/services/AnimeService.kt
+++ b/src/main/kotlin/fr/ziedelth/services/AnimeService.kt
@@ -2,6 +2,7 @@ package fr.ziedelth.services
import com.google.common.cache.CacheBuilder
import com.google.common.cache.CacheLoader
+import com.google.inject.Inject
import fr.ziedelth.caches.DayCountryCacheKey
import fr.ziedelth.caches.PaginationSimulcastCountryCacheKey
import fr.ziedelth.caches.SearchCountryCacheKey
@@ -10,7 +11,10 @@ import fr.ziedelth.repositories.AnimeRepository
import fr.ziedelth.utils.unaccent
import java.util.*
-class AnimeService(val repository: AnimeRepository) {
+class AnimeService : AbstractService() {
+ @Inject
+ private lateinit var repository: AnimeRepository
+
private val paginationSimulcastCountryCache = CacheBuilder.newBuilder()
.build(object : CacheLoader>() {
override fun load(key: PaginationSimulcastCountryCacheKey): List {
diff --git a/src/main/kotlin/fr/ziedelth/services/CountryService.kt b/src/main/kotlin/fr/ziedelth/services/CountryService.kt
index 8b76621..211fb01 100644
--- a/src/main/kotlin/fr/ziedelth/services/CountryService.kt
+++ b/src/main/kotlin/fr/ziedelth/services/CountryService.kt
@@ -2,10 +2,14 @@ package fr.ziedelth.services
import com.google.common.cache.CacheBuilder
import com.google.common.cache.CacheLoader
+import com.google.inject.Inject
import fr.ziedelth.entities.Country
import fr.ziedelth.repositories.CountryRepository
-class CountryService(val repository: CountryRepository) {
+class CountryService : AbstractService() {
+ @Inject
+ private lateinit var repository: CountryRepository
+
private val loadingCache = CacheBuilder.newBuilder()
.build(object : CacheLoader>() {
override fun load(key: String): List {
diff --git a/src/main/kotlin/fr/ziedelth/services/EpisodeService.kt b/src/main/kotlin/fr/ziedelth/services/EpisodeService.kt
index 60310b1..dc6017e 100644
--- a/src/main/kotlin/fr/ziedelth/services/EpisodeService.kt
+++ b/src/main/kotlin/fr/ziedelth/services/EpisodeService.kt
@@ -2,13 +2,17 @@ package fr.ziedelth.services
import com.google.common.cache.CacheBuilder
import com.google.common.cache.CacheLoader
+import com.google.inject.Inject
import fr.ziedelth.caches.PaginationAnimeCacheKey
import fr.ziedelth.caches.PaginationCountryCacheKey
import fr.ziedelth.entities.Episode
import fr.ziedelth.repositories.EpisodeRepository
import java.util.*
-class EpisodeService(val repository: EpisodeRepository) {
+class EpisodeService : AbstractService() {
+ @Inject
+ private lateinit var repository: EpisodeRepository
+
private val paginationCountryCache = CacheBuilder.newBuilder()
.build(object : CacheLoader>() {
override fun load(key: PaginationCountryCacheKey): List {
diff --git a/src/main/kotlin/fr/ziedelth/services/EpisodeTypeService.kt b/src/main/kotlin/fr/ziedelth/services/EpisodeTypeService.kt
index cbfd938..b629275 100644
--- a/src/main/kotlin/fr/ziedelth/services/EpisodeTypeService.kt
+++ b/src/main/kotlin/fr/ziedelth/services/EpisodeTypeService.kt
@@ -2,10 +2,14 @@ package fr.ziedelth.services
import com.google.common.cache.CacheBuilder
import com.google.common.cache.CacheLoader
+import com.google.inject.Inject
import fr.ziedelth.entities.EpisodeType
import fr.ziedelth.repositories.EpisodeTypeRepository
-class EpisodeTypeService(val repository: EpisodeTypeRepository) {
+class EpisodeTypeService : AbstractService() {
+ @Inject
+ private lateinit var repository: EpisodeTypeRepository
+
private val loadingCache = CacheBuilder.newBuilder()
.build(object : CacheLoader>() {
override fun load(key: String): List {
diff --git a/src/main/kotlin/fr/ziedelth/services/LangTypeService.kt b/src/main/kotlin/fr/ziedelth/services/LangTypeService.kt
index 6b47dfb..d5c74a4 100644
--- a/src/main/kotlin/fr/ziedelth/services/LangTypeService.kt
+++ b/src/main/kotlin/fr/ziedelth/services/LangTypeService.kt
@@ -2,10 +2,14 @@ package fr.ziedelth.services
import com.google.common.cache.CacheBuilder
import com.google.common.cache.CacheLoader
+import com.google.inject.Inject
import fr.ziedelth.entities.LangType
import fr.ziedelth.repositories.LangTypeRepository
-class LangTypeService(val repository: LangTypeRepository) {
+class LangTypeService : AbstractService() {
+ @Inject
+ private lateinit var repository: LangTypeRepository
+
private val loadingCache = CacheBuilder.newBuilder()
.build(object : CacheLoader>() {
override fun load(key: String): List {
diff --git a/src/main/kotlin/fr/ziedelth/services/SimulcastService.kt b/src/main/kotlin/fr/ziedelth/services/SimulcastService.kt
index e09db7b..ac4be8a 100644
--- a/src/main/kotlin/fr/ziedelth/services/SimulcastService.kt
+++ b/src/main/kotlin/fr/ziedelth/services/SimulcastService.kt
@@ -2,11 +2,15 @@ package fr.ziedelth.services
import com.google.common.cache.CacheBuilder
import com.google.common.cache.CacheLoader
+import com.google.inject.Inject
import fr.ziedelth.caches.CountryCacheKey
import fr.ziedelth.entities.Simulcast
import fr.ziedelth.repositories.SimulcastRepository
-class SimulcastService(val repository: SimulcastRepository) {
+class SimulcastService : AbstractService() {
+ @Inject
+ private lateinit var repository: SimulcastRepository
+
private val loadingCache = CacheBuilder.newBuilder()
.build(object : CacheLoader>() {
override fun load(key: CountryCacheKey): List {
diff --git a/src/main/kotlin/fr/ziedelth/utils/ImageCache.kt b/src/main/kotlin/fr/ziedelth/utils/ImageCache.kt
index e196aea..3ebae2a 100644
--- a/src/main/kotlin/fr/ziedelth/utils/ImageCache.kt
+++ b/src/main/kotlin/fr/ziedelth/utils/ImageCache.kt
@@ -10,7 +10,7 @@ import java.nio.file.Files
import java.util.*
object ImageCache {
- data class Image(val bytes: ByteArray, val type: String) {
+ data class Image(val url: String, val bytes: ByteArray = byteArrayOf(), val type: String = "jpg") {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
@@ -25,11 +25,35 @@ object ImageCache {
}
}
- private val cache = mutableMapOf()
- private var totalSize = 0
+ private val cache = mutableMapOf>()
fun contains(uuid: UUID) = cache.containsKey(uuid)
- fun get(uuid: UUID) = cache[uuid]
+
+ fun get(uuid: UUID): Image? {
+ val pair = cache[uuid] ?: return null
+
+ if (pair.second) {
+ return pair.first
+ }
+
+ println("Encoding image to WebP")
+ val url = pair.first.url
+ var bytes: ByteArray? = null
+
+ try {
+ bytes = saveImage(url).readBytes()
+ val webp = encodeToWebP(bytes)
+ cache[uuid] = Image(url, webp, "webp") to true
+ } catch (e: Exception) {
+ if (bytes != null) {
+ cache[uuid] = Image(url, bytes, "jpg") to true
+ } else {
+ println("Failed to load image $url : ${e.message}")
+ }
+ }
+
+ return cache[uuid]?.first
+ }
private fun encodeToWebP(image: ByteArray): ByteArray {
val matImage = Imgcodecs.imdecode(MatOfByte(*image), Imgcodecs.IMREAD_UNCHANGED)
@@ -51,46 +75,12 @@ object ImageCache {
return tmpFile.inputStream()
}
- fun cachingNetworkImage(uuid: UUID, url: String) {
- if (contains(uuid)) return
- var bytes: ByteArray? = null
-
- try {
- bytes = saveImage(url).readBytes()
- val webp = encodeToWebP(bytes)
- cache[uuid] = Image(webp, "webp")
- } catch (e: Exception) {
- if (bytes != null) {
- cache[uuid] = Image(bytes, "jpg")
- } else {
- println("Failed to load image $url : ${e.message}")
- this.totalSize--
- }
- }
- }
-
- private fun startPrintProgressThread() {
- val thread = Thread {
- val marginError = 5 // In percent
- var totalSize: Double
- var isRunning = true
-
- while (isRunning) {
- totalSize = this.totalSize * (1 - marginError / 100.0)
- isRunning = cache.size < totalSize
- println("Progress : ${cache.size}/${this.totalSize} (${totalSize.toInt()} with $marginError% margin error)")
- if (!isRunning) println("Done")
- Thread.sleep(5000)
- }
- }
-
- thread.isDaemon = true
- thread.start()
+ fun cache(uuid: UUID, url: String) {
+ cache[uuid] = Image(url) to false
}
fun invalidCache(database: Database) {
cache.clear()
- totalSize = 0
try {
database.inTransaction { session ->
@@ -108,14 +98,12 @@ object ImageCache {
println("Episodes : ${episodes.size}")
val combinedImages = platforms + animes + episodes
- totalSize = combinedImages.size
- startPrintProgressThread()
-
- Thread {
- combinedImages.parallelStream().forEach {
- cachingNetworkImage(it[0] as UUID, it[1] as String)
- }
- }.start()
+
+ combinedImages.parallelStream().forEach {
+ val uuid = it[0] as UUID
+ val url = it[1] as String
+ cache(uuid, url)
+ }
}
} catch (e: Exception) {
e.printStackTrace()
diff --git a/src/main/kotlin/fr/ziedelth/utils/routes/APIIgnore.kt b/src/main/kotlin/fr/ziedelth/utils/routes/APIIgnore.kt
new file mode 100644
index 0000000..f962c6d
--- /dev/null
+++ b/src/main/kotlin/fr/ziedelth/utils/routes/APIIgnore.kt
@@ -0,0 +1,5 @@
+package fr.ziedelth.utils.routes
+
+@Retention(AnnotationRetention.RUNTIME)
+@Target(AnnotationTarget.CLASS)
+annotation class APIIgnore
diff --git a/src/main/kotlin/fr/ziedelth/utils/routes/APIRoute.kt b/src/main/kotlin/fr/ziedelth/utils/routes/APIRoute.kt
new file mode 100644
index 0000000..d80f3a5
--- /dev/null
+++ b/src/main/kotlin/fr/ziedelth/utils/routes/APIRoute.kt
@@ -0,0 +1,5 @@
+package fr.ziedelth.utils.routes
+
+@Retention(AnnotationRetention.RUNTIME)
+@Target(AnnotationTarget.FUNCTION)
+annotation class APIRoute
diff --git a/src/test/kotlin/fr/ziedelth/plugins/RoutingTest.kt b/src/test/kotlin/fr/ziedelth/plugins/RoutingTest.kt
index 9c45684..91bf712 100644
--- a/src/test/kotlin/fr/ziedelth/plugins/RoutingTest.kt
+++ b/src/test/kotlin/fr/ziedelth/plugins/RoutingTest.kt
@@ -1,46 +1,57 @@
package fr.ziedelth.plugins
-import fr.ziedelth.controllers.*
+import com.google.inject.Guice
+import fr.ziedelth.controllers.AbstractController
+import fr.ziedelth.controllers.AttachmentController
import fr.ziedelth.repositories.*
-import fr.ziedelth.services.*
import fr.ziedelth.utils.DatabaseTest
+import fr.ziedelth.utils.routes.APIIgnore
+import fr.ziedelth.utils.routes.APIRoute
import io.ktor.server.application.*
import io.ktor.server.routing.*
+import org.reflections.Reflections
+import kotlin.reflect.full.findAnnotations
+import kotlin.reflect.full.memberExtensionFunctions
+import kotlin.reflect.jvm.javaMethod
val databaseTest = DatabaseTest()
+private val reflections = Reflections("fr.ziedelth")
+private val injector = Guice.createInjector(DatabaseModule(reflections, databaseTest))
-val countryRepository = CountryRepository(databaseTest)
-val platformRepository = PlatformRepository(databaseTest)
-val simulcastRepository = SimulcastRepository(databaseTest)
-val genreRepository = GenreRepository(databaseTest)
-val animeRepository = AnimeRepository(databaseTest)
-val episodeTypeRepository = EpisodeTypeRepository(databaseTest)
-val langTypeRepository = LangTypeRepository(databaseTest)
-val episodeRepository = EpisodeRepository(databaseTest)
-
-val countryService = CountryService(countryRepository)
-val episodeTypeService = EpisodeTypeService(episodeTypeRepository)
-val langTypeService = LangTypeService(langTypeRepository)
-val simulcastService = SimulcastService(simulcastRepository)
-val animeService = AnimeService(animeRepository)
-val episodeService = EpisodeService(episodeRepository)
+val countryRepository: CountryRepository = injector.getInstance(CountryRepository::class.java)
+val platformRepository: PlatformRepository = injector.getInstance(PlatformRepository::class.java)
+val simulcastRepository: SimulcastRepository = injector.getInstance(SimulcastRepository::class.java)
+val genreRepository: GenreRepository = injector.getInstance(GenreRepository::class.java)
+val animeRepository: AnimeRepository = injector.getInstance(AnimeRepository::class.java)
+val episodeTypeRepository: EpisodeTypeRepository = injector.getInstance(EpisodeTypeRepository::class.java)
+val langTypeRepository: LangTypeRepository = injector.getInstance(LangTypeRepository::class.java)
+val episodeRepository: EpisodeRepository = injector.getInstance(EpisodeRepository::class.java)
fun Application.configureRoutingTest() {
routing {
- CountryController(countryService).getRoutes(this)
- PlatformController(platformRepository).getRoutes(this)
- SimulcastController(simulcastService).getRoutes(this)
- GenreController(genreRepository).getRoutes(this)
- AnimeController(countryRepository, animeService, episodeService).getRoutes(this)
- EpisodeTypeController(episodeTypeService).getRoutes(this)
- LangTypeController(langTypeService).getRoutes(this)
- EpisodeController(
- platformRepository,
- animeService,
- simulcastService,
- episodeTypeRepository,
- langTypeRepository,
- episodeService
- ).getRoutes(this)
+ reflections.getSubTypesOf(AbstractController::class.java).forEach {
+ if (it.isAnnotationPresent(APIIgnore::class.java)) {
+ return@forEach
+ }
+
+ val controller = injector.getInstance(it)
+ val isAttachmentController = controller::class.java.superclass == AttachmentController::class.java
+
+ val kFunctions = controller::class.memberExtensionFunctions.filter { kFunction ->
+ kFunction.findAnnotations(APIRoute::class).isNotEmpty()
+ }.toMutableList()
+
+ route(controller.prefix) {
+ kFunctions.forEach { kFunction ->
+ val javaMethod = kFunction.javaMethod!!
+ javaMethod.isAccessible = true
+ javaMethod.invoke(controller, this)
+ }
+
+ if (isAttachmentController) {
+ controller.javaClass.getMethod("attachmentByUUID", Route::class.java).invoke(controller, this)
+ }
+ }
+ }
}
}
\ No newline at end of file