mirror of
https://github.com/Suwayomi/Suwayomi-Server.git
synced 2026-07-04 11:24:35 -05:00
refactor endpoints to the new styles
This commit is contained in:
@@ -7,18 +7,15 @@ package suwayomi.tachidesk.global
|
|||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
import io.javalin.Javalin
|
|
||||||
import io.javalin.apibuilder.ApiBuilder.get
|
import io.javalin.apibuilder.ApiBuilder.get
|
||||||
import io.javalin.apibuilder.ApiBuilder.path
|
import io.javalin.apibuilder.ApiBuilder.path
|
||||||
import suwayomi.tachidesk.global.controller.SettingsController
|
import suwayomi.tachidesk.global.controller.SettingsController
|
||||||
|
|
||||||
object GlobalAPI {
|
object GlobalAPI {
|
||||||
fun defineEndpoints(app: Javalin) {
|
fun defineEndpoints() {
|
||||||
app.routes {
|
path("settings") {
|
||||||
path("api/v1/settings") {
|
get("about", SettingsController::about)
|
||||||
get("about", SettingsController::about)
|
get("check-update", SettingsController::checkUpdate)
|
||||||
get("check-update", SettingsController::checkUpdate)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,19 +10,19 @@ package suwayomi.tachidesk.global.controller
|
|||||||
import io.javalin.http.Context
|
import io.javalin.http.Context
|
||||||
import suwayomi.tachidesk.global.impl.About
|
import suwayomi.tachidesk.global.impl.About
|
||||||
import suwayomi.tachidesk.global.impl.AppUpdate
|
import suwayomi.tachidesk.global.impl.AppUpdate
|
||||||
import suwayomi.tachidesk.server.JavalinSetup
|
import suwayomi.tachidesk.server.JavalinSetup.future
|
||||||
|
|
||||||
/** Settings Page/Screen */
|
/** Settings Page/Screen */
|
||||||
object SettingsController {
|
object SettingsController {
|
||||||
/** returns some static info about the current app build */
|
/** returns some static info about the current app build */
|
||||||
fun about(ctx: Context): Context {
|
fun about(ctx: Context) {
|
||||||
return ctx.json(About.getAbout())
|
ctx.json(About.getAbout())
|
||||||
}
|
}
|
||||||
|
|
||||||
/** check for app updates */
|
/** check for app updates */
|
||||||
fun checkUpdate(ctx: Context): Context {
|
fun checkUpdate(ctx: Context) {
|
||||||
return ctx.json(
|
ctx.json(
|
||||||
JavalinSetup.future { AppUpdate.checkUpdate() }
|
future { AppUpdate.checkUpdate() }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,469 +8,103 @@ package suwayomi.tachidesk.manga
|
|||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
import io.javalin.Javalin
|
import io.javalin.Javalin
|
||||||
import suwayomi.tachidesk.manga.impl.Category
|
import io.javalin.apibuilder.ApiBuilder.delete
|
||||||
import suwayomi.tachidesk.manga.impl.CategoryManga.addMangaToCategory
|
import io.javalin.apibuilder.ApiBuilder.get
|
||||||
import suwayomi.tachidesk.manga.impl.CategoryManga.getCategoryMangaList
|
import io.javalin.apibuilder.ApiBuilder.patch
|
||||||
import suwayomi.tachidesk.manga.impl.CategoryManga.getMangaCategories
|
import io.javalin.apibuilder.ApiBuilder.path
|
||||||
import suwayomi.tachidesk.manga.impl.CategoryManga.removeMangaFromCategory
|
import io.javalin.apibuilder.ApiBuilder.post
|
||||||
import suwayomi.tachidesk.manga.impl.Chapter.getChapter
|
import io.javalin.apibuilder.ApiBuilder.ws
|
||||||
import suwayomi.tachidesk.manga.impl.Chapter.getChapterList
|
import suwayomi.tachidesk.manga.controller.BackupController
|
||||||
import suwayomi.tachidesk.manga.impl.Chapter.modifyChapter
|
import suwayomi.tachidesk.manga.controller.DownloadController
|
||||||
import suwayomi.tachidesk.manga.impl.Chapter.modifyChapterMeta
|
import suwayomi.tachidesk.manga.controller.ExtensionController
|
||||||
import suwayomi.tachidesk.manga.impl.Library.addMangaToLibrary
|
import suwayomi.tachidesk.manga.controller.LibraryController
|
||||||
import suwayomi.tachidesk.manga.impl.Library.getLibraryMangas
|
import suwayomi.tachidesk.manga.controller.MangaController
|
||||||
import suwayomi.tachidesk.manga.impl.Library.removeMangaFromLibrary
|
import suwayomi.tachidesk.manga.controller.SourceController
|
||||||
import suwayomi.tachidesk.manga.impl.Manga.getManga
|
|
||||||
import suwayomi.tachidesk.manga.impl.Manga.getMangaThumbnail
|
|
||||||
import suwayomi.tachidesk.manga.impl.Manga.modifyMangaMeta
|
|
||||||
import suwayomi.tachidesk.manga.impl.MangaList.getMangaList
|
|
||||||
import suwayomi.tachidesk.manga.impl.Page.getPageImage
|
|
||||||
import suwayomi.tachidesk.manga.impl.Search.sourceFilters
|
|
||||||
import suwayomi.tachidesk.manga.impl.Search.sourceGlobalSearch
|
|
||||||
import suwayomi.tachidesk.manga.impl.Search.sourceSearch
|
|
||||||
import suwayomi.tachidesk.manga.impl.Source.SourcePreferenceChange
|
|
||||||
import suwayomi.tachidesk.manga.impl.Source.getSource
|
|
||||||
import suwayomi.tachidesk.manga.impl.Source.getSourceList
|
|
||||||
import suwayomi.tachidesk.manga.impl.Source.getSourcePreferences
|
|
||||||
import suwayomi.tachidesk.manga.impl.Source.setSourcePreference
|
|
||||||
import suwayomi.tachidesk.manga.impl.backup.BackupFlags
|
|
||||||
import suwayomi.tachidesk.manga.impl.backup.legacy.LegacyBackupExport.createLegacyBackup
|
|
||||||
import suwayomi.tachidesk.manga.impl.backup.legacy.LegacyBackupImport.restoreLegacyBackup
|
|
||||||
import suwayomi.tachidesk.manga.impl.download.DownloadManager
|
|
||||||
import suwayomi.tachidesk.manga.impl.extension.Extension.getExtensionIcon
|
|
||||||
import suwayomi.tachidesk.manga.impl.extension.Extension.installExtension
|
|
||||||
import suwayomi.tachidesk.manga.impl.extension.Extension.uninstallExtension
|
|
||||||
import suwayomi.tachidesk.manga.impl.extension.Extension.updateExtension
|
|
||||||
import suwayomi.tachidesk.manga.impl.extension.ExtensionsList.getExtensionList
|
|
||||||
import suwayomi.tachidesk.server.JavalinSetup.future
|
|
||||||
import java.text.SimpleDateFormat
|
|
||||||
import java.util.Date
|
|
||||||
|
|
||||||
object MangaAPI {
|
object MangaAPI {
|
||||||
fun defineEndpoints(app: Javalin) {
|
fun defineEndpoints(app: Javalin) {
|
||||||
// list all extensions
|
path("extension") {
|
||||||
app.get("/api/v1/extension/list") { ctx ->
|
get("list", ExtensionController::list)
|
||||||
ctx.json(
|
|
||||||
future {
|
get("install/:pkgName", ExtensionController::install)
|
||||||
getExtensionList()
|
get("update/:pkgName", ExtensionController::update)
|
||||||
}
|
get("uninstall/:pkgName", ExtensionController::uninstall)
|
||||||
)
|
|
||||||
|
get("icon/:apkName", ExtensionController::icon)
|
||||||
}
|
}
|
||||||
|
|
||||||
// install extension identified with "pkgName"
|
path("source") {
|
||||||
app.get("/api/v1/extension/install/:pkgName") { ctx ->
|
get("list", SourceController::list)
|
||||||
val pkgName = ctx.pathParam("pkgName")
|
get(":sourceId", SourceController::retrieve)
|
||||||
|
|
||||||
ctx.json(
|
get(":sourceId/popular/:pageNum", SourceController::popular)
|
||||||
future {
|
get(":sourceId/latest/:pageNum", SourceController::latest)
|
||||||
installExtension(pkgName)
|
|
||||||
}
|
get(":sourceId/preferences", SourceController::getPreferences)
|
||||||
)
|
post(":sourceId/preferences", SourceController::setPreference)
|
||||||
|
|
||||||
|
post(":sourceId/filters", SourceController::filters) // TODO
|
||||||
|
|
||||||
|
get(":sourceId/search/:searchTerm/:pageNum", SourceController::searchSingle)
|
||||||
|
get("search/:searchTerm/:pageNum", SourceController::searchSingle) // TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
// update extension identified with "pkgName"
|
path("manga") {
|
||||||
app.get("/api/v1/extension/update/:pkgName") { ctx ->
|
get(":mangaId", MangaController::retrieve)
|
||||||
val pkgName = ctx.pathParam("pkgName")
|
get(":mangaId/thumbnail", MangaController::thumbnail)
|
||||||
|
|
||||||
ctx.json(
|
get(":mangaId/category", MangaController::categoryList)
|
||||||
future {
|
get(":mangaId/category/:categoryId", MangaController::addToCategory)
|
||||||
updateExtension(pkgName)
|
delete(":mangaId/category/:categoryId", MangaController::removeFromCategory)
|
||||||
}
|
|
||||||
)
|
get(":mangaId/library", MangaController::addToLibrary)
|
||||||
|
delete(":mangaId/library", MangaController::removeFromLibrary)
|
||||||
|
|
||||||
|
patch(":mangaId/meta", MangaController::meta)
|
||||||
|
|
||||||
|
get(":mangaId/chapters", MangaController::chapterList)
|
||||||
|
get(":mangaId/chapter/:chapterIndex", MangaController::chapterRetrieve)
|
||||||
|
patch(":mangaId/chapter/:chapterIndex", MangaController::chapterModify)
|
||||||
|
|
||||||
|
patch(":mangaId/chapter/:chapterIndex/meta", MangaController::chapterMeta)
|
||||||
|
|
||||||
|
get(":mangaId/chapter/:chapterIndex/page/:index", MangaController::chapterList)
|
||||||
}
|
}
|
||||||
|
|
||||||
// uninstall extension identified with "pkgName"
|
path("") {
|
||||||
app.get("/api/v1/extension/uninstall/:pkgName") { ctx ->
|
get("library", LibraryController::list)
|
||||||
val pkgName = ctx.pathParam("pkgName")
|
|
||||||
|
|
||||||
uninstallExtension(pkgName)
|
path("category") {
|
||||||
ctx.status(200)
|
get("", LibraryController::categoryList)
|
||||||
}
|
post("", LibraryController::categoryCreate)
|
||||||
|
|
||||||
// icon for extension named `apkName`
|
get(":categoryId", LibraryController::categoryMangas)
|
||||||
app.get("/api/v1/extension/icon/:apkName") { ctx ->
|
patch(":categoryId", LibraryController::categoryModify)
|
||||||
val apkName = ctx.pathParam("apkName")
|
delete(":categoryId", LibraryController::categoryDelete)
|
||||||
|
|
||||||
ctx.result(
|
patch(":categoryId/reorder", LibraryController::categoryReorder)
|
||||||
future { getExtensionIcon(apkName) }
|
|
||||||
.thenApply {
|
|
||||||
ctx.header("content-type", it.second)
|
|
||||||
it.first
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// list of sources
|
|
||||||
app.get("/api/v1/source/list") { ctx ->
|
|
||||||
ctx.json(getSourceList())
|
|
||||||
}
|
|
||||||
|
|
||||||
// fetch source with id `sourceId`
|
|
||||||
app.get("/api/v1/source/:sourceId") { ctx ->
|
|
||||||
val sourceId = ctx.pathParam("sourceId").toLong()
|
|
||||||
ctx.json(getSource(sourceId))
|
|
||||||
}
|
|
||||||
|
|
||||||
// fetch preferences of source with id `sourceId`
|
|
||||||
app.get("/api/v1/source/:sourceId/preferences") { ctx ->
|
|
||||||
val sourceId = ctx.pathParam("sourceId").toLong()
|
|
||||||
ctx.json(getSourcePreferences(sourceId))
|
|
||||||
}
|
|
||||||
|
|
||||||
// fetch preferences of source with id `sourceId`
|
|
||||||
app.post("/api/v1/source/:sourceId/preferences") { ctx ->
|
|
||||||
val sourceId = ctx.pathParam("sourceId").toLong()
|
|
||||||
val preferenceChange = ctx.bodyAsClass(SourcePreferenceChange::class.java)
|
|
||||||
ctx.json(setSourcePreference(sourceId, preferenceChange))
|
|
||||||
}
|
|
||||||
|
|
||||||
// popular mangas from source with id `sourceId`
|
|
||||||
app.get("/api/v1/source/:sourceId/popular/:pageNum") { ctx ->
|
|
||||||
val sourceId = ctx.pathParam("sourceId").toLong()
|
|
||||||
val pageNum = ctx.pathParam("pageNum").toInt()
|
|
||||||
ctx.json(
|
|
||||||
future {
|
|
||||||
getMangaList(sourceId, pageNum, popular = true)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// latest mangas from source with id `sourceId`
|
|
||||||
app.get("/api/v1/source/:sourceId/latest/:pageNum") { ctx ->
|
|
||||||
val sourceId = ctx.pathParam("sourceId").toLong()
|
|
||||||
val pageNum = ctx.pathParam("pageNum").toInt()
|
|
||||||
ctx.json(
|
|
||||||
future {
|
|
||||||
getMangaList(sourceId, pageNum, popular = false)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// get manga info
|
|
||||||
app.get("/api/v1/manga/:mangaId/") { ctx ->
|
|
||||||
val mangaId = ctx.pathParam("mangaId").toInt()
|
|
||||||
val onlineFetch = ctx.queryParam("onlineFetch", "false").toBoolean()
|
|
||||||
|
|
||||||
ctx.json(
|
|
||||||
future {
|
|
||||||
getManga(mangaId, onlineFetch)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// manga thumbnail
|
|
||||||
app.get("api/v1/manga/:mangaId/thumbnail") { ctx ->
|
|
||||||
val mangaId = ctx.pathParam("mangaId").toInt()
|
|
||||||
|
|
||||||
ctx.result(
|
|
||||||
future { getMangaThumbnail(mangaId) }
|
|
||||||
.thenApply {
|
|
||||||
ctx.header("content-type", it.second)
|
|
||||||
it.first
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// list manga's categories
|
|
||||||
app.get("api/v1/manga/:mangaId/category/") { ctx ->
|
|
||||||
val mangaId = ctx.pathParam("mangaId").toInt()
|
|
||||||
ctx.json(getMangaCategories(mangaId))
|
|
||||||
}
|
|
||||||
|
|
||||||
// adds the manga to category
|
|
||||||
app.get("api/v1/manga/:mangaId/category/:categoryId") { ctx ->
|
|
||||||
val mangaId = ctx.pathParam("mangaId").toInt()
|
|
||||||
val categoryId = ctx.pathParam("categoryId").toInt()
|
|
||||||
addMangaToCategory(mangaId, categoryId)
|
|
||||||
ctx.status(200)
|
|
||||||
}
|
|
||||||
|
|
||||||
// removes the manga from the category
|
|
||||||
app.delete("api/v1/manga/:mangaId/category/:categoryId") { ctx ->
|
|
||||||
val mangaId = ctx.pathParam("mangaId").toInt()
|
|
||||||
val categoryId = ctx.pathParam("categoryId").toInt()
|
|
||||||
removeMangaFromCategory(mangaId, categoryId)
|
|
||||||
ctx.status(200)
|
|
||||||
}
|
|
||||||
|
|
||||||
// get chapter list when showing a manga
|
|
||||||
app.get("/api/v1/manga/:mangaId/chapters") { ctx ->
|
|
||||||
val mangaId = ctx.pathParam("mangaId").toInt()
|
|
||||||
|
|
||||||
val onlineFetch = ctx.queryParam("onlineFetch")?.toBoolean()
|
|
||||||
|
|
||||||
ctx.json(future { getChapterList(mangaId, onlineFetch) })
|
|
||||||
}
|
|
||||||
|
|
||||||
// used to modify a manga's meta parameters
|
|
||||||
app.patch("/api/v1/manga/:mangaId/meta") { ctx ->
|
|
||||||
val mangaId = ctx.pathParam("mangaId").toInt()
|
|
||||||
|
|
||||||
val key = ctx.formParam("key")!!
|
|
||||||
val value = ctx.formParam("value")!!
|
|
||||||
|
|
||||||
modifyMangaMeta(mangaId, key, value)
|
|
||||||
|
|
||||||
ctx.status(200)
|
|
||||||
}
|
|
||||||
|
|
||||||
// used to display a chapter, get a chapter in order to show it's pages
|
|
||||||
app.get("/api/v1/manga/:mangaId/chapter/:chapterIndex") { ctx ->
|
|
||||||
val chapterIndex = ctx.pathParam("chapterIndex").toInt()
|
|
||||||
val mangaId = ctx.pathParam("mangaId").toInt()
|
|
||||||
ctx.json(future { getChapter(chapterIndex, mangaId) })
|
|
||||||
}
|
|
||||||
|
|
||||||
// used to modify a chapter's parameters
|
|
||||||
app.patch("/api/v1/manga/:mangaId/chapter/:chapterIndex") { ctx ->
|
|
||||||
val chapterIndex = ctx.pathParam("chapterIndex").toInt()
|
|
||||||
val mangaId = ctx.pathParam("mangaId").toInt()
|
|
||||||
|
|
||||||
val read = ctx.formParam("read")?.toBoolean()
|
|
||||||
val bookmarked = ctx.formParam("bookmarked")?.toBoolean()
|
|
||||||
val markPrevRead = ctx.formParam("markPrevRead")?.toBoolean()
|
|
||||||
val lastPageRead = ctx.formParam("lastPageRead")?.toInt()
|
|
||||||
|
|
||||||
modifyChapter(mangaId, chapterIndex, read, bookmarked, markPrevRead, lastPageRead)
|
|
||||||
|
|
||||||
ctx.status(200)
|
|
||||||
}
|
|
||||||
|
|
||||||
// used to modify a chapter's meta parameters
|
|
||||||
app.patch("/api/v1/manga/:mangaId/chapter/:chapterIndex/meta") { ctx ->
|
|
||||||
val chapterIndex = ctx.pathParam("chapterIndex").toInt()
|
|
||||||
val mangaId = ctx.pathParam("mangaId").toInt()
|
|
||||||
|
|
||||||
val key = ctx.formParam("key")!!
|
|
||||||
val value = ctx.formParam("value")!!
|
|
||||||
|
|
||||||
modifyChapterMeta(mangaId, chapterIndex, key, value)
|
|
||||||
|
|
||||||
ctx.status(200)
|
|
||||||
}
|
|
||||||
|
|
||||||
// get page at index "index"
|
|
||||||
app.get("/api/v1/manga/:mangaId/chapter/:chapterIndex/page/:index") { ctx ->
|
|
||||||
val mangaId = ctx.pathParam("mangaId").toInt()
|
|
||||||
val chapterIndex = ctx.pathParam("chapterIndex").toInt()
|
|
||||||
val index = ctx.pathParam("index").toInt()
|
|
||||||
|
|
||||||
ctx.result(
|
|
||||||
future { getPageImage(mangaId, chapterIndex, index) }
|
|
||||||
.thenApply {
|
|
||||||
ctx.header("content-type", it.second)
|
|
||||||
it.first
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// submit a chapter for download
|
|
||||||
app.put("/api/v1/manga/:mangaId/chapter/:chapterIndex/download") { ctx ->
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
// cancel a chapter download
|
|
||||||
app.delete("/api/v1/manga/:mangaId/chapter/:chapterIndex/download") { ctx ->
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
// global search, Not implemented yet
|
|
||||||
app.get("/api/v1/search/:searchTerm") { ctx ->
|
|
||||||
val searchTerm = ctx.pathParam("searchTerm")
|
|
||||||
ctx.json(sourceGlobalSearch(searchTerm))
|
|
||||||
}
|
|
||||||
|
|
||||||
// single source search
|
|
||||||
app.get("/api/v1/source/:sourceId/search/:searchTerm/:pageNum") { ctx ->
|
|
||||||
val sourceId = ctx.pathParam("sourceId").toLong()
|
|
||||||
val searchTerm = ctx.pathParam("searchTerm")
|
|
||||||
val pageNum = ctx.pathParam("pageNum").toInt()
|
|
||||||
ctx.json(future { sourceSearch(sourceId, searchTerm, pageNum) })
|
|
||||||
}
|
|
||||||
|
|
||||||
// source filter list
|
|
||||||
app.get("/api/v1/source/:sourceId/filters/") { ctx ->
|
|
||||||
val sourceId = ctx.pathParam("sourceId").toLong()
|
|
||||||
ctx.json(sourceFilters(sourceId))
|
|
||||||
}
|
|
||||||
|
|
||||||
// adds the manga to library
|
|
||||||
app.get("api/v1/manga/:mangaId/library") { ctx ->
|
|
||||||
val mangaId = ctx.pathParam("mangaId").toInt()
|
|
||||||
|
|
||||||
ctx.result(
|
|
||||||
future { addMangaToLibrary(mangaId) }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// removes the manga from the library
|
|
||||||
app.delete("api/v1/manga/:mangaId/library") { ctx ->
|
|
||||||
val mangaId = ctx.pathParam("mangaId").toInt()
|
|
||||||
|
|
||||||
ctx.result(
|
|
||||||
future { removeMangaFromLibrary(mangaId) }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// lists mangas that have no category assigned
|
|
||||||
app.get("/api/v1/library/") { ctx ->
|
|
||||||
ctx.json(getLibraryMangas())
|
|
||||||
}
|
|
||||||
|
|
||||||
// category list
|
|
||||||
app.get("/api/v1/category/") { ctx ->
|
|
||||||
ctx.json(Category.getCategoryList())
|
|
||||||
}
|
|
||||||
|
|
||||||
// category create
|
|
||||||
app.post("/api/v1/category/") { ctx ->
|
|
||||||
val name = ctx.formParam("name")!!
|
|
||||||
Category.createCategory(name)
|
|
||||||
ctx.status(200)
|
|
||||||
}
|
|
||||||
|
|
||||||
// category modification
|
|
||||||
app.patch("/api/v1/category/:categoryId") { ctx ->
|
|
||||||
val categoryId = ctx.pathParam("categoryId").toInt()
|
|
||||||
val name = ctx.formParam("name")
|
|
||||||
val isDefault = ctx.formParam("default")?.toBoolean()
|
|
||||||
Category.updateCategory(categoryId, name, isDefault)
|
|
||||||
ctx.status(200)
|
|
||||||
}
|
|
||||||
|
|
||||||
// category re-ordering
|
|
||||||
app.patch("/api/v1/category/:categoryId/reorder") { ctx ->
|
|
||||||
val categoryId = ctx.pathParam("categoryId").toInt()
|
|
||||||
val from = ctx.formParam("from")!!.toInt()
|
|
||||||
val to = ctx.formParam("to")!!.toInt()
|
|
||||||
Category.reorderCategory(categoryId, from, to)
|
|
||||||
ctx.status(200)
|
|
||||||
}
|
|
||||||
|
|
||||||
// category delete
|
|
||||||
app.delete("/api/v1/category/:categoryId") { ctx ->
|
|
||||||
val categoryId = ctx.pathParam("categoryId").toInt()
|
|
||||||
Category.removeCategory(categoryId)
|
|
||||||
ctx.status(200)
|
|
||||||
}
|
|
||||||
|
|
||||||
// returns the manga list associated with a category
|
|
||||||
app.get("/api/v1/category/:categoryId") { ctx ->
|
|
||||||
val categoryId = ctx.pathParam("categoryId").toInt()
|
|
||||||
ctx.json(getCategoryMangaList(categoryId))
|
|
||||||
}
|
|
||||||
|
|
||||||
// expects a Tachiyomi legacy backup json in the body
|
|
||||||
app.post("/api/v1/backup/legacy/import") { ctx ->
|
|
||||||
ctx.result(
|
|
||||||
future {
|
|
||||||
restoreLegacyBackup(ctx.bodyAsInputStream())
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// expects a Tachiyomi legacy backup json as a file upload, the file must be named "backup.json"
|
|
||||||
app.post("/api/v1/backup/legacy/import/file") { ctx ->
|
|
||||||
ctx.result(
|
|
||||||
future {
|
|
||||||
restoreLegacyBackup(ctx.uploadedFile("backup.json")!!.content)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// returns a Tachiyomi legacy backup json created from the current database as a json body
|
|
||||||
app.get("/api/v1/backup/legacy/export") { ctx ->
|
|
||||||
ctx.contentType("application/json")
|
|
||||||
ctx.result(
|
|
||||||
future {
|
|
||||||
createLegacyBackup(
|
|
||||||
BackupFlags(
|
|
||||||
includeManga = true,
|
|
||||||
includeCategories = true,
|
|
||||||
includeChapters = true,
|
|
||||||
includeTracking = true,
|
|
||||||
includeHistory = true,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// returns a Tachiyomi legacy backup json created from the current database as a file
|
|
||||||
app.get("/api/v1/backup/legacy/export/file") { ctx ->
|
|
||||||
ctx.contentType("application/json")
|
|
||||||
val sdf = SimpleDateFormat("yyyy-MM-dd_HH-mm")
|
|
||||||
val currentDate = sdf.format(Date())
|
|
||||||
|
|
||||||
ctx.header("Content-Disposition", "attachment; filename=\"tachidesk_$currentDate.json\"")
|
|
||||||
ctx.result(
|
|
||||||
future {
|
|
||||||
createLegacyBackup(
|
|
||||||
BackupFlags(
|
|
||||||
includeManga = true,
|
|
||||||
includeCategories = true,
|
|
||||||
includeChapters = true,
|
|
||||||
includeTracking = true,
|
|
||||||
includeHistory = true,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Download queue stats
|
|
||||||
app.ws("/api/v1/downloads") { ws ->
|
|
||||||
ws.onConnect { ctx ->
|
|
||||||
DownloadManager.addClient(ctx)
|
|
||||||
DownloadManager.notifyClient(ctx)
|
|
||||||
}
|
|
||||||
ws.onMessage { ctx ->
|
|
||||||
DownloadManager.handleRequest(ctx)
|
|
||||||
}
|
|
||||||
ws.onClose { ctx ->
|
|
||||||
DownloadManager.removeClient(ctx)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start the downloader
|
path("backup") {
|
||||||
app.get("/api/v1/downloads/start") { ctx ->
|
post("legacy/import", BackupController::legacyImport)
|
||||||
DownloadManager.start()
|
post("legacy/import/file", BackupController::legacyImportFile)
|
||||||
|
|
||||||
ctx.status(200)
|
get("legacy/export", BackupController::legacyExport)
|
||||||
|
get("legacy/export/file", BackupController::legacyExportFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop the downloader
|
path("downloads") {
|
||||||
app.get("/api/v1/downloads/stop") { ctx ->
|
ws("", DownloadController::downloadsWS)
|
||||||
DownloadManager.stop()
|
|
||||||
|
|
||||||
ctx.status(200)
|
get("start", DownloadController::start)
|
||||||
|
get("stop", DownloadController::stop)
|
||||||
|
get("clear", DownloadController::stop)
|
||||||
}
|
}
|
||||||
|
|
||||||
// clear download queue
|
path("download") {
|
||||||
app.get("/api/v1/downloads/clear") { ctx ->
|
get(":mangaId/chapter/:chapterIndex", DownloadController::queueChapter)
|
||||||
DownloadManager.clear()
|
delete(":mangaId/chapter/:chapterIndex", DownloadController::unqueueChapter)
|
||||||
|
|
||||||
ctx.status(200)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Queue chapter for download
|
|
||||||
app.get("/api/v1/download/:mangaId/chapter/:chapterIndex") { ctx ->
|
|
||||||
val chapterIndex = ctx.pathParam("chapterIndex").toInt()
|
|
||||||
val mangaId = ctx.pathParam("mangaId").toInt()
|
|
||||||
|
|
||||||
DownloadManager.enqueue(chapterIndex, mangaId)
|
|
||||||
|
|
||||||
ctx.status(200)
|
|
||||||
}
|
|
||||||
|
|
||||||
// delete chapter from download queue
|
|
||||||
app.delete("/api/v1/download/:mangaId/chapter/:chapterIndex") { ctx ->
|
|
||||||
val chapterIndex = ctx.pathParam("chapterIndex").toInt()
|
|
||||||
val mangaId = ctx.pathParam("mangaId").toInt()
|
|
||||||
|
|
||||||
DownloadManager.unqueue(chapterIndex, mangaId)
|
|
||||||
|
|
||||||
ctx.status(200)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,76 @@
|
|||||||
|
package suwayomi.tachidesk.manga.controller
|
||||||
|
|
||||||
|
import io.javalin.http.Context
|
||||||
|
import suwayomi.tachidesk.manga.impl.backup.BackupFlags
|
||||||
|
import suwayomi.tachidesk.manga.impl.backup.legacy.LegacyBackupExport
|
||||||
|
import suwayomi.tachidesk.manga.impl.backup.legacy.LegacyBackupImport
|
||||||
|
import suwayomi.tachidesk.server.JavalinSetup
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.Date
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) Contributors to the Suwayomi project
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
object BackupController {
|
||||||
|
/** expects a Tachiyomi legacy backup json in the body */
|
||||||
|
fun legacyImport(ctx: Context) {
|
||||||
|
ctx.result(
|
||||||
|
JavalinSetup.future {
|
||||||
|
LegacyBackupImport.restoreLegacyBackup(ctx.bodyAsInputStream())
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** expects a Tachiyomi legacy backup json as a file upload, the file must be named "backup.json" */
|
||||||
|
fun legacyImportFile(ctx: Context) {
|
||||||
|
ctx.result(
|
||||||
|
JavalinSetup.future {
|
||||||
|
LegacyBackupImport.restoreLegacyBackup(ctx.uploadedFile("backup.json")!!.content)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** returns a Tachiyomi legacy backup json created from the current database as a json body */
|
||||||
|
fun legacyExport(ctx: Context) {
|
||||||
|
ctx.contentType("application/json")
|
||||||
|
ctx.result(
|
||||||
|
JavalinSetup.future {
|
||||||
|
LegacyBackupExport.createLegacyBackup(
|
||||||
|
BackupFlags(
|
||||||
|
includeManga = true,
|
||||||
|
includeCategories = true,
|
||||||
|
includeChapters = true,
|
||||||
|
includeTracking = true,
|
||||||
|
includeHistory = true,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** returns a Tachiyomi legacy backup json created from the current database as a file */
|
||||||
|
fun legacyExportFile(ctx: Context) {
|
||||||
|
ctx.contentType("application/json")
|
||||||
|
val sdf = SimpleDateFormat("yyyy-MM-dd_HH-mm")
|
||||||
|
val currentDate = sdf.format(Date())
|
||||||
|
|
||||||
|
ctx.header("Content-Disposition", "attachment; filename=\"tachidesk_$currentDate.json\"")
|
||||||
|
ctx.result(
|
||||||
|
JavalinSetup.future {
|
||||||
|
LegacyBackupExport.createLegacyBackup(
|
||||||
|
BackupFlags(
|
||||||
|
includeManga = true,
|
||||||
|
includeCategories = true,
|
||||||
|
includeChapters = true,
|
||||||
|
includeTracking = true,
|
||||||
|
includeHistory = true,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
package suwayomi.tachidesk.manga.controller
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) Contributors to the Suwayomi project
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
import io.javalin.http.Context
|
||||||
|
import io.javalin.websocket.WsHandler
|
||||||
|
import suwayomi.tachidesk.manga.impl.download.DownloadManager
|
||||||
|
|
||||||
|
object DownloadController {
|
||||||
|
/** Download queue stats */
|
||||||
|
fun downloadsWS(ws: WsHandler) {
|
||||||
|
ws.onConnect { ctx ->
|
||||||
|
DownloadManager.addClient(ctx)
|
||||||
|
DownloadManager.notifyClient(ctx)
|
||||||
|
}
|
||||||
|
ws.onMessage { ctx ->
|
||||||
|
DownloadManager.handleRequest(ctx)
|
||||||
|
}
|
||||||
|
ws.onClose { ctx ->
|
||||||
|
DownloadManager.removeClient(ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Start the downloader */
|
||||||
|
fun start(ctx: Context) {
|
||||||
|
DownloadManager.start()
|
||||||
|
|
||||||
|
ctx.status(200)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Stop the downloader */
|
||||||
|
fun stop(ctx: Context) {
|
||||||
|
DownloadManager.stop()
|
||||||
|
|
||||||
|
ctx.status(200)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** clear download queue */
|
||||||
|
fun clear(ctx: Context) {
|
||||||
|
DownloadManager.clear()
|
||||||
|
|
||||||
|
ctx.status(200)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Queue chapter for download */
|
||||||
|
fun queueChapter(ctx: Context) {
|
||||||
|
val chapterIndex = ctx.pathParam("chapterIndex").toInt()
|
||||||
|
val mangaId = ctx.pathParam("mangaId").toInt()
|
||||||
|
|
||||||
|
DownloadManager.enqueue(chapterIndex, mangaId)
|
||||||
|
|
||||||
|
ctx.status(200)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** delete chapter from download queue */
|
||||||
|
fun unqueueChapter(ctx: Context) {
|
||||||
|
val chapterIndex = ctx.pathParam("chapterIndex").toInt()
|
||||||
|
val mangaId = ctx.pathParam("mangaId").toInt()
|
||||||
|
|
||||||
|
DownloadManager.unqueue(chapterIndex, mangaId)
|
||||||
|
|
||||||
|
ctx.status(200)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
package suwayomi.tachidesk.manga.controller
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) Contributors to the Suwayomi project
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
import io.javalin.http.Context
|
||||||
|
import suwayomi.tachidesk.manga.impl.extension.Extension
|
||||||
|
import suwayomi.tachidesk.manga.impl.extension.ExtensionsList
|
||||||
|
import suwayomi.tachidesk.server.JavalinSetup.future
|
||||||
|
|
||||||
|
object ExtensionController {
|
||||||
|
/** list all extensions */
|
||||||
|
fun list(ctx: Context) {
|
||||||
|
ctx.json(
|
||||||
|
future {
|
||||||
|
ExtensionsList.getExtensionList()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** install extension identified with "pkgName" */
|
||||||
|
fun install(ctx: Context) {
|
||||||
|
val pkgName = ctx.pathParam("pkgName")
|
||||||
|
|
||||||
|
ctx.json(
|
||||||
|
future {
|
||||||
|
Extension.installExtension(pkgName)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** update extension identified with "pkgName" */
|
||||||
|
fun update(ctx: Context) {
|
||||||
|
val pkgName = ctx.pathParam("pkgName")
|
||||||
|
|
||||||
|
ctx.json(
|
||||||
|
future {
|
||||||
|
Extension.updateExtension(pkgName)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** uninstall extension identified with "pkgName" */
|
||||||
|
fun uninstall(ctx: Context) {
|
||||||
|
val pkgName = ctx.pathParam("pkgName")
|
||||||
|
|
||||||
|
Extension.uninstallExtension(pkgName)
|
||||||
|
ctx.status(200)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** icon for extension named `apkName` */
|
||||||
|
fun icon(ctx: Context) {
|
||||||
|
val apkName = ctx.pathParam("apkName")
|
||||||
|
|
||||||
|
ctx.result(
|
||||||
|
future { Extension.getExtensionIcon(apkName) }
|
||||||
|
.thenApply {
|
||||||
|
ctx.header("content-type", it.second)
|
||||||
|
it.first
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
package suwayomi.tachidesk.manga.controller
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) Contributors to the Suwayomi project
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
import io.javalin.http.Context
|
||||||
|
import suwayomi.tachidesk.manga.impl.Category
|
||||||
|
import suwayomi.tachidesk.manga.impl.CategoryManga
|
||||||
|
import suwayomi.tachidesk.manga.impl.Library
|
||||||
|
|
||||||
|
object LibraryController {
|
||||||
|
/** lists mangas that have no category assigned */
|
||||||
|
fun list(ctx: Context) {
|
||||||
|
ctx.json(Library.getLibraryMangas())
|
||||||
|
}
|
||||||
|
|
||||||
|
/** category list */
|
||||||
|
fun categoryList(ctx: Context) {
|
||||||
|
ctx.json(Category.getCategoryList())
|
||||||
|
}
|
||||||
|
|
||||||
|
/** category create */
|
||||||
|
fun categoryCreate(ctx: Context) {
|
||||||
|
val name = ctx.formParam("name")!!
|
||||||
|
Category.createCategory(name)
|
||||||
|
ctx.status(200)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** category modification */
|
||||||
|
fun categoryModify(ctx: Context) {
|
||||||
|
val categoryId = ctx.pathParam("categoryId").toInt()
|
||||||
|
val name = ctx.formParam("name")
|
||||||
|
val isDefault = ctx.formParam("default")?.toBoolean()
|
||||||
|
Category.updateCategory(categoryId, name, isDefault)
|
||||||
|
ctx.status(200)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** category delete */
|
||||||
|
fun categoryDelete(ctx: Context) {
|
||||||
|
val categoryId = ctx.pathParam("categoryId").toInt()
|
||||||
|
Category.removeCategory(categoryId)
|
||||||
|
ctx.status(200)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** returns the manga list associated with a category */
|
||||||
|
fun categoryMangas(ctx: Context) {
|
||||||
|
val categoryId = ctx.pathParam("categoryId").toInt()
|
||||||
|
ctx.json(CategoryManga.getCategoryMangaList(categoryId))
|
||||||
|
}
|
||||||
|
|
||||||
|
/** category re-ordering */
|
||||||
|
fun categoryReorder(ctx: Context) {
|
||||||
|
val categoryId = ctx.pathParam("categoryId").toInt()
|
||||||
|
val from = ctx.formParam("from")!!.toInt()
|
||||||
|
val to = ctx.formParam("to")!!.toInt()
|
||||||
|
Category.reorderCategory(categoryId, from, to)
|
||||||
|
ctx.status(200)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,154 @@
|
|||||||
|
package suwayomi.tachidesk.manga.controller
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) Contributors to the Suwayomi project
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
import io.javalin.http.Context
|
||||||
|
import suwayomi.tachidesk.manga.impl.CategoryManga
|
||||||
|
import suwayomi.tachidesk.manga.impl.Chapter
|
||||||
|
import suwayomi.tachidesk.manga.impl.Library
|
||||||
|
import suwayomi.tachidesk.manga.impl.Manga
|
||||||
|
import suwayomi.tachidesk.manga.impl.Page
|
||||||
|
import suwayomi.tachidesk.server.JavalinSetup.future
|
||||||
|
|
||||||
|
object MangaController {
|
||||||
|
/** get manga info */
|
||||||
|
fun retrieve(ctx: Context) {
|
||||||
|
val mangaId = ctx.pathParam("mangaId").toInt()
|
||||||
|
val onlineFetch = ctx.queryParam("onlineFetch", "false").toBoolean()
|
||||||
|
|
||||||
|
ctx.json(
|
||||||
|
future {
|
||||||
|
Manga.getManga(mangaId, onlineFetch)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** manga thumbnail */
|
||||||
|
fun thumbnail(ctx: Context) {
|
||||||
|
val mangaId = ctx.pathParam("mangaId").toInt()
|
||||||
|
|
||||||
|
ctx.result(
|
||||||
|
future { Manga.getMangaThumbnail(mangaId) }
|
||||||
|
.thenApply {
|
||||||
|
ctx.header("content-type", it.second)
|
||||||
|
it.first
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** adds the manga to library */
|
||||||
|
fun addToLibrary(ctx: Context) {
|
||||||
|
val mangaId = ctx.pathParam("mangaId").toInt()
|
||||||
|
|
||||||
|
ctx.result(
|
||||||
|
future { Library.addMangaToLibrary(mangaId) }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** removes the manga from the library */
|
||||||
|
fun removeFromLibrary(ctx: Context) {
|
||||||
|
val mangaId = ctx.pathParam("mangaId").toInt()
|
||||||
|
|
||||||
|
ctx.result(
|
||||||
|
future { Library.removeMangaFromLibrary(mangaId) }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** list manga's categories */
|
||||||
|
fun categoryList(ctx: Context) {
|
||||||
|
val mangaId = ctx.pathParam("mangaId").toInt()
|
||||||
|
ctx.json(CategoryManga.getMangaCategories(mangaId))
|
||||||
|
}
|
||||||
|
|
||||||
|
/** adds the manga to category */
|
||||||
|
fun addToCategory(ctx: Context) {
|
||||||
|
val mangaId = ctx.pathParam("mangaId").toInt()
|
||||||
|
val categoryId = ctx.pathParam("categoryId").toInt()
|
||||||
|
CategoryManga.addMangaToCategory(mangaId, categoryId)
|
||||||
|
ctx.status(200)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** removes the manga from the category */
|
||||||
|
fun removeFromCategory(ctx: Context) {
|
||||||
|
val mangaId = ctx.pathParam("mangaId").toInt()
|
||||||
|
val categoryId = ctx.pathParam("categoryId").toInt()
|
||||||
|
CategoryManga.removeMangaFromCategory(mangaId, categoryId)
|
||||||
|
ctx.status(200)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** used to modify a manga's meta parameters */
|
||||||
|
fun meta(ctx: Context) {
|
||||||
|
val mangaId = ctx.pathParam("mangaId").toInt()
|
||||||
|
|
||||||
|
val key = ctx.formParam("key")!!
|
||||||
|
val value = ctx.formParam("value")!!
|
||||||
|
|
||||||
|
Manga.modifyMangaMeta(mangaId, key, value)
|
||||||
|
|
||||||
|
ctx.status(200)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** get chapter list when showing a manga */
|
||||||
|
fun chapterList(ctx: Context) {
|
||||||
|
val mangaId = ctx.pathParam("mangaId").toInt()
|
||||||
|
|
||||||
|
val onlineFetch = ctx.queryParam("onlineFetch")?.toBoolean()
|
||||||
|
|
||||||
|
ctx.json(future { Chapter.getChapterList(mangaId, onlineFetch) })
|
||||||
|
}
|
||||||
|
|
||||||
|
/** used to display a chapter, get a chapter in order to show its pages */
|
||||||
|
fun chapterRetrieve(ctx: Context) {
|
||||||
|
val chapterIndex = ctx.pathParam("chapterIndex").toInt()
|
||||||
|
val mangaId = ctx.pathParam("mangaId").toInt()
|
||||||
|
ctx.json(future { Chapter.getChapter(chapterIndex, mangaId) })
|
||||||
|
}
|
||||||
|
|
||||||
|
/** used to modify a chapter's parameters */
|
||||||
|
fun chapterModify(ctx: Context) {
|
||||||
|
val chapterIndex = ctx.pathParam("chapterIndex").toInt()
|
||||||
|
val mangaId = ctx.pathParam("mangaId").toInt()
|
||||||
|
|
||||||
|
val read = ctx.formParam("read")?.toBoolean()
|
||||||
|
val bookmarked = ctx.formParam("bookmarked")?.toBoolean()
|
||||||
|
val markPrevRead = ctx.formParam("markPrevRead")?.toBoolean()
|
||||||
|
val lastPageRead = ctx.formParam("lastPageRead")?.toInt()
|
||||||
|
|
||||||
|
Chapter.modifyChapter(mangaId, chapterIndex, read, bookmarked, markPrevRead, lastPageRead)
|
||||||
|
|
||||||
|
ctx.status(200)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** used to modify a chapter's meta parameters */
|
||||||
|
fun chapterMeta(ctx: Context) {
|
||||||
|
val chapterIndex = ctx.pathParam("chapterIndex").toInt()
|
||||||
|
val mangaId = ctx.pathParam("mangaId").toInt()
|
||||||
|
|
||||||
|
val key = ctx.formParam("key")!!
|
||||||
|
val value = ctx.formParam("value")!!
|
||||||
|
|
||||||
|
Chapter.modifyChapterMeta(mangaId, chapterIndex, key, value)
|
||||||
|
|
||||||
|
ctx.status(200)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** get page at index "index" */
|
||||||
|
fun pageRetrieve(ctx: Context) {
|
||||||
|
val mangaId = ctx.pathParam("mangaId").toInt()
|
||||||
|
val chapterIndex = ctx.pathParam("chapterIndex").toInt()
|
||||||
|
val index = ctx.pathParam("index").toInt()
|
||||||
|
|
||||||
|
ctx.result(
|
||||||
|
future { Page.getPageImage(mangaId, chapterIndex, index) }
|
||||||
|
.thenApply {
|
||||||
|
ctx.header("content-type", it.second)
|
||||||
|
it.first
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
package suwayomi.tachidesk.manga.controller
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) Contributors to the Suwayomi project
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
import io.javalin.http.Context
|
||||||
|
import suwayomi.tachidesk.manga.impl.MangaList
|
||||||
|
import suwayomi.tachidesk.manga.impl.Search
|
||||||
|
import suwayomi.tachidesk.manga.impl.Source
|
||||||
|
import suwayomi.tachidesk.manga.impl.Source.SourcePreferenceChange
|
||||||
|
import suwayomi.tachidesk.server.JavalinSetup
|
||||||
|
import suwayomi.tachidesk.server.JavalinSetup.future
|
||||||
|
|
||||||
|
object SourceController {
|
||||||
|
/** list of sources */
|
||||||
|
fun list(ctx: Context) {
|
||||||
|
ctx.json(Source.getSourceList())
|
||||||
|
}
|
||||||
|
|
||||||
|
/** fetch source with id `sourceId` */
|
||||||
|
fun retrieve(ctx: Context) {
|
||||||
|
val sourceId = ctx.pathParam("sourceId").toLong()
|
||||||
|
ctx.json(Source.getSource(sourceId))
|
||||||
|
}
|
||||||
|
|
||||||
|
/** popular mangas from source with id `sourceId` */
|
||||||
|
fun popular(ctx: Context) {
|
||||||
|
val sourceId = ctx.pathParam("sourceId").toLong()
|
||||||
|
val pageNum = ctx.pathParam("pageNum").toInt()
|
||||||
|
ctx.json(
|
||||||
|
future {
|
||||||
|
MangaList.getMangaList(sourceId, pageNum, popular = true)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** latest mangas from source with id `sourceId` */
|
||||||
|
fun latest(ctx: Context) {
|
||||||
|
val sourceId = ctx.pathParam("sourceId").toLong()
|
||||||
|
val pageNum = ctx.pathParam("pageNum").toInt()
|
||||||
|
ctx.json(
|
||||||
|
future {
|
||||||
|
MangaList.getMangaList(sourceId, pageNum, popular = false)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** fetch preferences of source with id `sourceId` */
|
||||||
|
fun getPreferences(ctx: Context) {
|
||||||
|
val sourceId = ctx.pathParam("sourceId").toLong()
|
||||||
|
ctx.json(Source.getSourcePreferences(sourceId))
|
||||||
|
}
|
||||||
|
|
||||||
|
/** fetch preferences of source with id `sourceId` */
|
||||||
|
fun setPreference(ctx: Context) {
|
||||||
|
val sourceId = ctx.pathParam("sourceId").toLong()
|
||||||
|
val preferenceChange = ctx.bodyAsClass(SourcePreferenceChange::class.java)
|
||||||
|
ctx.json(Source.setSourcePreference(sourceId, preferenceChange))
|
||||||
|
}
|
||||||
|
|
||||||
|
/** fetch filters of source with id `sourceId` */
|
||||||
|
fun filters(ctx: Context) { // TODO
|
||||||
|
val sourceId = ctx.pathParam("sourceId").toLong()
|
||||||
|
ctx.json(Search.sourceFilters(sourceId))
|
||||||
|
}
|
||||||
|
|
||||||
|
/** single source search */
|
||||||
|
fun searchSingle(ctx: Context) {
|
||||||
|
val sourceId = ctx.pathParam("sourceId").toLong()
|
||||||
|
val searchTerm = ctx.pathParam("searchTerm")
|
||||||
|
val pageNum = ctx.pathParam("pageNum").toInt()
|
||||||
|
ctx.json(JavalinSetup.future { Search.sourceSearch(sourceId, searchTerm, pageNum) })
|
||||||
|
}
|
||||||
|
|
||||||
|
/** all source search */
|
||||||
|
fun searchAll(ctx: Context) { // TODO
|
||||||
|
val searchTerm = ctx.pathParam("searchTerm")
|
||||||
|
ctx.json(Search.sourceGlobalSearch(searchTerm))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@ package suwayomi.tachidesk.server
|
|||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
import io.javalin.Javalin
|
import io.javalin.Javalin
|
||||||
|
import io.javalin.apibuilder.ApiBuilder.path
|
||||||
import io.javalin.http.staticfiles.Location
|
import io.javalin.http.staticfiles.Location
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
@@ -77,8 +78,12 @@ object JavalinSetup {
|
|||||||
ctx.result(e.message ?: "Internal Server Error")
|
ctx.result(e.message ?: "Internal Server Error")
|
||||||
}
|
}
|
||||||
|
|
||||||
GlobalAPI.defineEndpoints(app)
|
app.routes {
|
||||||
MangaAPI.defineEndpoints(app)
|
path("api/v1/") {
|
||||||
AnimeAPI.defineEndpoints(app)
|
GlobalAPI.defineEndpoints()
|
||||||
|
MangaAPI.defineEndpoints(app)
|
||||||
|
AnimeAPI.defineEndpoints(app) // TODO: migrate Anime endpoints
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user