Files
suwayomi-material-you-webui/server/src/main/kotlin/ir/armor/tachidesk/Main.kt

280 lines
11 KiB
Kotlin
Raw Normal View History

package ir.armor.tachidesk
2021-01-26 23:32:12 +03:30
/* 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 eu.kanade.tachiyomi.App
2020-12-24 02:08:03 +03:30
import io.javalin.Javalin
2021-02-14 01:10:43 +03:30
import ir.armor.tachidesk.util.addMangaToCategory
2021-02-13 21:12:18 +03:30
import ir.armor.tachidesk.util.addMangaToLibrary
2021-01-22 12:34:03 +03:30
import ir.armor.tachidesk.util.applicationSetup
2021-02-14 01:10:43 +03:30
import ir.armor.tachidesk.util.createCategory
import ir.armor.tachidesk.util.getCategoryList
import ir.armor.tachidesk.util.getCategoryMangaList
2021-02-04 03:42:30 +03:30
import ir.armor.tachidesk.util.getChapter
2021-01-22 12:34:03 +03:30
import ir.armor.tachidesk.util.getChapterList
2021-02-04 14:47:27 +03:30
import ir.armor.tachidesk.util.getExtensionIcon
2021-01-22 12:34:03 +03:30
import ir.armor.tachidesk.util.getExtensionList
2021-02-13 21:12:18 +03:30
import ir.armor.tachidesk.util.getLibraryMangas
2021-01-22 12:34:03 +03:30
import ir.armor.tachidesk.util.getManga
import ir.armor.tachidesk.util.getMangaList
2021-02-04 03:42:30 +03:30
import ir.armor.tachidesk.util.getPageImage
2021-01-22 17:00:33 +03:30
import ir.armor.tachidesk.util.getSource
2021-01-22 12:34:03 +03:30
import ir.armor.tachidesk.util.getSourceList
2021-01-29 14:19:24 +03:30
import ir.armor.tachidesk.util.getThumbnail
2021-01-22 12:34:03 +03:30
import ir.armor.tachidesk.util.installAPK
2021-02-04 18:02:46 +03:30
import ir.armor.tachidesk.util.openInBrowser
2021-02-14 01:10:43 +03:30
import ir.armor.tachidesk.util.removeCategory
2021-01-29 15:23:29 +03:30
import ir.armor.tachidesk.util.removeExtension
2021-02-14 01:10:43 +03:30
import ir.armor.tachidesk.util.removeMangaFromCategory
2021-02-13 21:12:18 +03:30
import ir.armor.tachidesk.util.removeMangaFromLibrary
2021-02-20 01:23:52 +03:30
import ir.armor.tachidesk.util.reorderCategory
2021-01-22 12:34:03 +03:30
import ir.armor.tachidesk.util.sourceFilters
import ir.armor.tachidesk.util.sourceGlobalSearch
import ir.armor.tachidesk.util.sourceSearch
2021-02-04 18:02:46 +03:30
import ir.armor.tachidesk.util.systemTray
2021-02-14 01:10:43 +03:30
import ir.armor.tachidesk.util.updateCategory
import org.kodein.di.DI
import org.kodein.di.conf.global
import xyz.nulldev.androidcompat.AndroidCompat
import xyz.nulldev.androidcompat.AndroidCompatInitializer
import xyz.nulldev.ts.config.ConfigKodeinModule
import xyz.nulldev.ts.config.GlobalConfigManager
2020-12-24 02:08:03 +03:30
2020-12-23 19:52:16 +03:30
class Main {
companion object {
val androidCompat by lazy { AndroidCompat() }
fun registerConfigModules() {
GlobalConfigManager.registerModules(
// ServerConfig.register(GlobalConfigManager.config),
// SyncConfigModule.register(GlobalConfigManager.config)
)
}
2020-12-24 02:08:03 +03:30
@JvmStatic
fun main(args: Array<String>) {
// System.getProperties()["proxySet"] = "true"
// System.getProperties()["socksProxyHost"] = "127.0.0.1"
// System.getProperties()["socksProxyPort"] = "2020"
2021-01-22 17:00:33 +03:30
2020-12-25 02:39:30 +03:30
// make sure everything we need exists
2020-12-25 13:17:41 +03:30
applicationSetup()
2021-02-20 01:23:52 +03:30
val tray = systemTray() // assign it to a variable so it's kept in the memory and not garbage collected
2020-12-24 19:37:27 +03:30
registerConfigModules()
2021-01-22 12:34:03 +03:30
// Load config API
DI.global.addImport(ConfigKodeinModule().create())
2021-01-22 12:34:03 +03:30
// Load Android compatibility dependencies
AndroidCompatInitializer().init()
// start app
androidCompat.startApp(App())
2021-02-04 18:02:46 +03:30
var hasWebUiBundled: Boolean = false
2021-01-29 14:19:24 +03:30
2021-01-20 03:05:40 +03:30
val app = Javalin.create { config ->
2021-01-20 15:26:52 +03:30
try {
this::class.java.classLoader.getResource("/react/index.html")
2021-02-04 18:02:46 +03:30
hasWebUiBundled = true
2021-01-20 15:26:52 +03:30
config.addStaticFiles("/react")
2021-01-22 12:34:03 +03:30
config.addSinglePageRoot("/", "/react/index.html")
2021-01-20 15:26:52 +03:30
} catch (e: RuntimeException) {
println("Warning: react build files are missing.")
2021-02-04 18:02:46 +03:30
hasWebUiBundled = false
2021-01-20 15:26:52 +03:30
}
2021-02-13 21:12:18 +03:30
config.enableCorsForAllOrigins()
2021-01-20 03:05:40 +03:30
}.start(4567)
2021-02-04 18:02:46 +03:30
if (hasWebUiBundled) {
openInBrowser()
}
2021-01-20 03:05:40 +03:30
2021-02-13 21:12:18 +03:30
// app.before() { ctx ->
// // allow the client which is running on another port
// ctx.header("Access-Control-Allow-Origin", "*")
// }
2020-12-25 02:39:30 +03:30
app.get("/api/v1/extension/list") { ctx ->
2020-12-25 02:39:30 +03:30
ctx.json(getExtensionList())
}
app.get("/api/v1/extension/install/:apkName") { ctx ->
2020-12-25 02:39:30 +03:30
val apkName = ctx.pathParam("apkName")
2021-01-29 15:23:29 +03:30
println("installing $apkName")
2020-12-25 02:39:30 +03:30
ctx.status(
2021-01-22 12:34:03 +03:30
installAPK(apkName)
2020-12-25 02:39:30 +03:30
)
}
2021-01-29 15:23:29 +03:30
app.get("/api/v1/extension/uninstall/:apkName") { ctx ->
val apkName = ctx.pathParam("apkName")
println("uninstalling $apkName")
removeExtension(apkName)
ctx.status(200)
}
2021-02-04 14:47:27 +03:30
app.get("/api/v1/extension/icon/:apkName") { ctx ->
val apkName = ctx.pathParam("apkName")
val result = getExtensionIcon(apkName)
ctx.result(result.first)
ctx.header("content-type", result.second)
}
app.get("/api/v1/source/list") { ctx ->
2020-12-25 06:15:52 +03:30
ctx.json(getSourceList())
}
2021-01-22 17:00:33 +03:30
app.get("/api/v1/source/:sourceId") { ctx ->
val sourceId = ctx.pathParam("sourceId").toLong()
ctx.json(getSource(sourceId))
}
2021-01-19 20:20:28 +03:30
app.get("/api/v1/source/:sourceId/popular/:pageNum") { ctx ->
val sourceId = ctx.pathParam("sourceId").toLong()
2021-01-19 15:07:20 +03:30
val pageNum = ctx.pathParam("pageNum").toInt()
2021-01-20 15:26:52 +03:30
ctx.json(getMangaList(sourceId, pageNum, popular = true))
}
2021-01-19 20:20:28 +03:30
app.get("/api/v1/source/:sourceId/latest/:pageNum") { ctx ->
val sourceId = ctx.pathParam("sourceId").toLong()
2021-01-19 15:07:20 +03:30
val pageNum = ctx.pathParam("pageNum").toInt()
2021-01-20 15:26:52 +03:30
ctx.json(getMangaList(sourceId, pageNum, popular = false))
2021-01-19 14:47:25 +03:30
}
2021-01-19 20:20:28 +03:30
app.get("/api/v1/manga/:mangaId/") { ctx ->
val mangaId = ctx.pathParam("mangaId").toInt()
ctx.json(getManga(mangaId))
}
2021-02-04 03:42:30 +03:30
app.get("api/v1/manga/:mangaId/thumbnail") { ctx ->
val mangaId = ctx.pathParam("mangaId").toInt()
val result = getThumbnail(mangaId)
ctx.result(result.first)
ctx.header("content-type", result.second)
}
// adds the manga to library
app.get("api/v1/manga/:mangaId/library") { ctx ->
2021-02-13 21:12:18 +03:30
val mangaId = ctx.pathParam("mangaId").toInt()
addMangaToLibrary(mangaId)
ctx.status(200)
}
// removes the manga from the library
app.delete("api/v1/manga/:mangaId/library") { ctx ->
2021-02-13 21:12:18 +03:30
val mangaId = ctx.pathParam("mangaId").toInt()
removeMangaFromLibrary(mangaId)
ctx.status(200)
}
// adds the manga to category
app.get("api/v1/manga/:mangaId/category/:categoryId") { ctx ->
2021-02-14 01:10:43 +03:30
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 ->
2021-02-14 01:10:43 +03:30
val mangaId = ctx.pathParam("mangaId").toInt()
val categoryId = ctx.pathParam("categoryId").toInt()
removeMangaFromCategory(mangaId, categoryId)
ctx.status(200)
}
2021-01-20 00:04:12 +03:30
app.get("/api/v1/manga/:mangaId/chapters") { ctx ->
2021-01-19 21:02:57 +03:30
val mangaId = ctx.pathParam("mangaId").toInt()
ctx.json(getChapterList(mangaId))
}
2021-01-20 01:05:24 +03:30
app.get("/api/v1/manga/:mangaId/chapter/:chapterId") { ctx ->
2021-01-20 00:04:12 +03:30
val chapterId = ctx.pathParam("chapterId").toInt()
2021-01-20 01:05:24 +03:30
val mangaId = ctx.pathParam("mangaId").toInt()
2021-02-04 03:42:30 +03:30
ctx.json(getChapter(chapterId, mangaId))
2021-01-20 00:04:12 +03:30
}
2021-01-21 14:15:05 +03:30
2021-02-04 03:42:30 +03:30
app.get("/api/v1/manga/:mangaId/chapter/:chapterId/page/:index") { ctx ->
val chapterId = ctx.pathParam("chapterId").toInt()
2021-01-29 14:19:24 +03:30
val mangaId = ctx.pathParam("mangaId").toInt()
2021-02-04 03:42:30 +03:30
val index = ctx.pathParam("index").toInt()
val result = getPageImage(mangaId, chapterId, index)
2021-01-29 14:19:24 +03:30
ctx.result(result.first)
ctx.header("content-type", result.second)
}
2021-01-21 14:15:05 +03:30
// global search
app.get("/api/v1/search/:searchTerm") { ctx ->
val searchTerm = ctx.pathParam("searchTerm")
ctx.json(sourceGlobalSearch(searchTerm))
}
// single source search
2021-01-22 18:07:31 +03:30
app.get("/api/v1/source/:sourceId/search/:searchTerm/:pageNum") { ctx ->
2021-01-21 14:15:05 +03:30
val sourceId = ctx.pathParam("sourceId").toLong()
val searchTerm = ctx.pathParam("searchTerm")
2021-01-22 18:07:31 +03:30
val pageNum = ctx.pathParam("pageNum").toInt()
ctx.json(sourceSearch(sourceId, searchTerm, pageNum))
2021-01-21 14:15:05 +03:30
}
// source filter list
app.get("/api/v1/source/:sourceId/filters/") { ctx ->
val sourceId = ctx.pathParam("sourceId").toLong()
ctx.json(sourceFilters(sourceId))
}
2021-02-20 01:23:52 +03:30
// lists mangas that have no category assigned
app.get("/api/v1/library/") { ctx ->
2021-02-13 21:12:18 +03:30
ctx.json(getLibraryMangas())
}
// category list
app.get("/api/v1/category/") { ctx ->
2021-02-14 01:10:43 +03:30
ctx.json(getCategoryList())
}
// category create
app.post("/api/v1/category/") { ctx ->
2021-02-14 01:10:43 +03:30
val name = ctx.formParam("name")!!
2021-02-20 01:23:52 +03:30
createCategory(name)
2021-02-14 01:10:43 +03:30
ctx.status(200)
}
// category modification
2021-02-20 01:23:52 +03:30
app.patch("/api/v1/category/:categoryId") { ctx ->
val categoryId = ctx.pathParam("categoryId")!!.toInt()
val name = ctx.formParam("name")
val isLanding = if (ctx.formParam("isLanding") != null) ctx.formParam("isLanding")?.toBoolean() else null
2021-02-14 01:10:43 +03:30
updateCategory(categoryId, name, isLanding)
ctx.status(200)
}
2021-02-20 01:23:52 +03:30
// 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()
reorderCategory(categoryId, from, to)
ctx.status(200)
}
2021-02-14 01:10:43 +03:30
// category delete
app.delete("/api/v1/category/:categoryId") { ctx ->
val categoryId = ctx.pathParam("categoryId").toInt()
removeCategory(categoryId)
ctx.status(200)
}
// returns the manga list associated with a category
app.get("/api/v1/category/:categoryId") { ctx ->
2021-02-14 01:10:43 +03:30
val categoryId = ctx.pathParam("categoryId").toInt()
ctx.json(getCategoryMangaList(categoryId))
}
2021-01-21 14:15:05 +03:30
}
}
}