diff --git a/AndroidCompat/Config/build.gradle b/AndroidCompat/Config/build.gradle index de646f6..de1b585 100644 --- a/AndroidCompat/Config/build.gradle +++ b/AndroidCompat/Config/build.gradle @@ -1,4 +1,4 @@ dependencies { - // Config API + // Config API, moved to the global build.gradle // implementation("com.typesafe:config:1.4.0") } \ No newline at end of file diff --git a/AndroidCompat/Config/src/main/java/xyz/nulldev/ts/config/ConfigManager.kt b/AndroidCompat/Config/src/main/java/xyz/nulldev/ts/config/ConfigManager.kt index f346fdc..b9d3f54 100644 --- a/AndroidCompat/Config/src/main/java/xyz/nulldev/ts/config/ConfigManager.kt +++ b/AndroidCompat/Config/src/main/java/xyz/nulldev/ts/config/ConfigManager.kt @@ -4,54 +4,55 @@ import com.typesafe.config.Config import com.typesafe.config.ConfigFactory import com.typesafe.config.ConfigRenderOptions import mu.KotlinLogging +import net.harawata.appdirs.AppDirsFactory import java.io.File /** * Manages app config. */ open class ConfigManager { - private val generatedModules - = mutableMapOf, ConfigModule>() + private val dataRoot by lazy { AppDirsFactory.getInstance().getUserDataDir("Tachidesk", null, null)!! } + + private val generatedModules = mutableMapOf, ConfigModule>() val config by lazy { loadConfigs() } //Public read-only view of modules val loadedModules: Map, ConfigModule> get() = generatedModules - open val configFolder: String - get() = System.getProperty("compat-configdirs") ?: "tachiserver-data/config" + open val appConfigFile: String = "$dataRoot/server.conf" val logger = KotlinLogging.logger {} /** * Get a config module */ - inline fun module(): T - = loadedModules[T::class.java] as T + inline fun module(): T = loadedModules[T::class.java] as T /** * Get a config module (Java API) */ - fun module(type: Class): T - = loadedModules[type] as T + fun module(type: Class): T = loadedModules[type] as T /** * Load configs */ fun loadConfigs(): Config { - val configs = mutableListOf() + //Load reference configs + val compatConfig = ConfigFactory.parseResources("compat-reference.conf") + val serverConfig = ConfigFactory.parseResources("server-reference.conf") - //Load reference config - configs += ConfigFactory.parseResources("reference.conf") + //Load user config + val userConfig = + File(appConfigFile).let{ + ConfigFactory.parseFile(it) + } - //Load custom configs from dir - File(configFolder).listFiles()?.map { - ConfigFactory.parseFile(it) - }?.filterNotNull()?.forEach { - configs += it.withFallback(configs.last()) - } - - val config = configs.last().resolve() + val config = ConfigFactory.empty() + .withFallback(userConfig) + .withFallback(compatConfig) + .withFallback(serverConfig) + .resolve() logger.debug { "Loaded config:\n" + config.root().render(ConfigRenderOptions.concise().setFormatted(true)) diff --git a/AndroidCompat/Config/src/main/java/xyz/nulldev/ts/config/ServerConfig.kt b/AndroidCompat/Config/src/main/java/xyz/nulldev/ts/config/ServerConfig.kt deleted file mode 100644 index 804f280..0000000 --- a/AndroidCompat/Config/src/main/java/xyz/nulldev/ts/config/ServerConfig.kt +++ /dev/null @@ -1,35 +0,0 @@ -package xyz.nulldev.ts.config - -import com.typesafe.config.Config -import java.io.File - -class ServerConfig(config: Config) : ConfigModule(config) { - val ip = config.getString("ip") - val port = config.getInt("port") - - val allowConfigChanges = config.getBoolean("allowConfigChanges") - val enableWebUi = config.getBoolean("enableWebUi") - val useOldWebUi = config.getBoolean("useOldWebUi") - val prettyPrintApi = config.getBoolean("prettyPrintApi") - // TODO Apply to operation IDs - val disabledApiEndpoints = config.getStringList("disabledApiEndpoints").map(String::toLowerCase) - val enabledApiEndpoints = config.getStringList("enabledApiEndpoints").map(String::toLowerCase) - val httpInitializedPrintMessage = config.getString("httpInitializedPrintMessage") - - val useExternalStaticFiles = config.getBoolean("useExternalStaticFiles") - val externalStaticFilesFolder = config.getString("externalStaticFilesFolder") - - val rootDir = registerFile(config.getString("rootDir")) - val patchesDir = registerFile(config.getString("patchesDir")) - - fun registerFile(file: String): File { - return File(file).apply { - mkdirs() - } - } - - companion object { - fun register(config: Config) - = ServerConfig(config.getConfig("ts.server")) - } -} \ No newline at end of file diff --git a/AndroidCompat/Config/src/main/resources/reference.conf b/AndroidCompat/src/main/resources/compat-reference.conf similarity index 97% rename from AndroidCompat/Config/src/main/resources/reference.conf rename to AndroidCompat/src/main/resources/compat-reference.conf index 1990801..556463a 100644 --- a/AndroidCompat/Config/src/main/resources/reference.conf +++ b/AndroidCompat/src/main/resources/compat-reference.conf @@ -1,6 +1,3 @@ -# Server ip and port bindings -ts.server.ip = 0.0.0.0 -ts.server.port = 4567 # Allow/disallow preference changes (useful for demos) ts.server.allowConfigChanges = true diff --git a/build.gradle.kts b/build.gradle.kts index 07800cf..909a457 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -76,5 +76,8 @@ configure(listOf( // dependency of :AndroidCompat:Config implementation("com.typesafe:config:1.4.0") + + // to get application content root + implementation("net.harawata:appdirs:1.2.0") } } \ No newline at end of file diff --git a/server/build.gradle.kts b/server/build.gradle.kts index 6f3c202..202ee9f 100644 --- a/server/build.gradle.kts +++ b/server/build.gradle.kts @@ -72,9 +72,6 @@ dependencies { implementation("org.slf4j:slf4j-api:1.8.0-beta4") implementation("com.fasterxml.jackson.core:jackson-databind:2.10.3") - // to get application content root - implementation("net.harawata:appdirs:1.2.0") - // Exposed ORM val exposed_version = "0.28.1" implementation("org.jetbrains.exposed:exposed-core:$exposed_version") diff --git a/server/src/main/kotlin/ir/armor/tachidesk/Config.kt b/server/src/main/kotlin/ir/armor/tachidesk/Config.kt deleted file mode 100644 index ce0d1be..0000000 --- a/server/src/main/kotlin/ir/armor/tachidesk/Config.kt +++ /dev/null @@ -1,15 +0,0 @@ -package ir.armor.tachidesk - -/* 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 net.harawata.appdirs.AppDirsFactory - -object Config { - val dataRoot = AppDirsFactory.getInstance().getUserDataDir("Tachidesk", null, null) - val extensionsRoot = "$dataRoot/extensions" - val thumbnailsRoot = "$dataRoot/thumbnails" - val mangaRoot = "$dataRoot/manga" - val serverPort = 4567 -} diff --git a/server/src/main/kotlin/ir/armor/tachidesk/Main.kt b/server/src/main/kotlin/ir/armor/tachidesk/Main.kt index a262f20..8206f8f 100644 --- a/server/src/main/kotlin/ir/armor/tachidesk/Main.kt +++ b/server/src/main/kotlin/ir/armor/tachidesk/Main.kt @@ -4,11 +4,9 @@ package ir.armor.tachidesk * 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 import io.javalin.Javalin import ir.armor.tachidesk.util.addMangaToCategory import ir.armor.tachidesk.util.addMangaToLibrary -import ir.armor.tachidesk.util.applicationSetup import ir.armor.tachidesk.util.createCategory import ir.armor.tachidesk.util.getCategoryList import ir.armor.tachidesk.util.getCategoryMangaList @@ -34,44 +32,13 @@ import ir.armor.tachidesk.util.reorderCategory import ir.armor.tachidesk.util.sourceFilters import ir.armor.tachidesk.util.sourceGlobalSearch import ir.armor.tachidesk.util.sourceSearch -import ir.armor.tachidesk.util.systemTray 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 class Main { companion object { - val androidCompat by lazy { AndroidCompat() } - - fun registerConfigModules() { - GlobalConfigManager.registerModules( -// ServerConfig.register(GlobalConfigManager.config), -// SyncConfigModule.register(GlobalConfigManager.config) - ) - } - @JvmStatic fun main(args: Array) { -// System.getProperties()["proxySet"] = "true" -// System.getProperties()["socksProxyHost"] = "127.0.0.1" -// System.getProperties()["socksProxyPort"] = "2020" - - // make sure everything we need exists - applicationSetup() - val tray = systemTray() // assign it to a variable so it's kept in the memory and not garbage collected - - registerConfigModules() - - // Load config API - DI.global.addImport(ConfigKodeinModule().create()) - // Load Android compatibility dependencies - AndroidCompatInitializer().init() - // start app - androidCompat.startApp(App()) + serverSetup() var hasWebUiBundled: Boolean = false @@ -86,16 +53,11 @@ class Main { hasWebUiBundled = false } config.enableCorsForAllOrigins() - }.start(4567) + }.start(serverConfig.ip, serverConfig.port) if (hasWebUiBundled) { openInBrowser() } -// app.before() { ctx -> -// // allow the client which is running on another port -// ctx.header("Access-Control-Allow-Origin", "*") -// } - app.get("/api/v1/extension/list") { ctx -> ctx.json(getExtensionList()) } diff --git a/server/src/main/kotlin/ir/armor/tachidesk/ServerConfig.kt b/server/src/main/kotlin/ir/armor/tachidesk/ServerConfig.kt new file mode 100644 index 0000000..26dc6ec --- /dev/null +++ b/server/src/main/kotlin/ir/armor/tachidesk/ServerConfig.kt @@ -0,0 +1,25 @@ +package ir.armor.tachidesk + +import com.typesafe.config.Config +import xyz.nulldev.ts.config.ConfigModule +import java.io.File + +class ServerConfig(config: Config) : ConfigModule(config) { + val ip = config.getString("ip") + val port = config.getInt("port") + + // proxy + val socksProxy = config.getBoolean("socksProxy") + val socksProxyHost = config.getString("socksProxyHost") + val socksProxyPort = config.getString("socksProxyPort") + + fun registerFile(file: String): File { + return File(file).apply { + mkdirs() + } + } + + companion object { + fun register(config: Config) = ServerConfig(config.getConfig("server")) + } +} diff --git a/server/src/main/kotlin/ir/armor/tachidesk/ServerSetup.kt b/server/src/main/kotlin/ir/armor/tachidesk/ServerSetup.kt new file mode 100644 index 0000000..40aa6f5 --- /dev/null +++ b/server/src/main/kotlin/ir/armor/tachidesk/ServerSetup.kt @@ -0,0 +1,60 @@ +package ir.armor.tachidesk + +import eu.kanade.tachiyomi.App +import ir.armor.tachidesk.database.makeDataBaseTables +import ir.armor.tachidesk.util.systemTray +import net.harawata.appdirs.AppDirsFactory +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 +import java.io.File + +object applicationDirs { + val dataRoot = AppDirsFactory.getInstance().getUserDataDir("Tachidesk", null, null)!! + val extensionsRoot = "$dataRoot/extensions" + val thumbnailsRoot = "$dataRoot/thumbnails" + val mangaRoot = "$dataRoot/manga" +} + +val serverConfig: ServerConfig by lazy { GlobalConfigManager.module() } + +val systemTray by lazy { systemTray() } + +val androidCompat by lazy { AndroidCompat() } + +fun serverSetup() { + // register server config + GlobalConfigManager.registerModule( + ServerConfig.register(GlobalConfigManager.config) + ) + + // make dirs we need + listOf( + applicationDirs.dataRoot, + applicationDirs.extensionsRoot, + "${applicationDirs.extensionsRoot}/icon", + applicationDirs.thumbnailsRoot + ).forEach { + File(it).mkdirs() + } + + makeDataBaseTables() + + // create system tray + systemTray + + // Load config API + DI.global.addImport(ConfigKodeinModule().create()) + // Load Android compatibility dependencies + AndroidCompatInitializer().init() + // start app + androidCompat.startApp(App()) + + // socks proxy settings + System.getProperties()["proxySet"] = serverConfig.socksProxy.toString() + System.getProperties()["socksProxyHost"] = serverConfig.socksProxyHost + System.getProperties()["socksProxyPort"] = serverConfig.socksProxyPort +} diff --git a/server/src/main/kotlin/ir/armor/tachidesk/database/DBMangaer.kt b/server/src/main/kotlin/ir/armor/tachidesk/database/DBMangaer.kt index d12efb2..8f16197 100644 --- a/server/src/main/kotlin/ir/armor/tachidesk/database/DBMangaer.kt +++ b/server/src/main/kotlin/ir/armor/tachidesk/database/DBMangaer.kt @@ -4,7 +4,7 @@ package ir.armor.tachidesk.database * 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 ir.armor.tachidesk.Config +import ir.armor.tachidesk.applicationDirs import ir.armor.tachidesk.database.table.CategoryMangaTable import ir.armor.tachidesk.database.table.CategoryTable import ir.armor.tachidesk.database.table.ChapterTable @@ -18,7 +18,7 @@ import org.jetbrains.exposed.sql.transactions.transaction object DBMangaer { val db by lazy { - Database.connect("jdbc:h2:${Config.dataRoot}/database", "org.h2.Driver") + Database.connect("jdbc:h2:${applicationDirs.dataRoot}/database", "org.h2.Driver") } } diff --git a/server/src/main/kotlin/ir/armor/tachidesk/util/Extension.kt b/server/src/main/kotlin/ir/armor/tachidesk/util/Extension.kt index 319afcc..48f1f71 100644 --- a/server/src/main/kotlin/ir/armor/tachidesk/util/Extension.kt +++ b/server/src/main/kotlin/ir/armor/tachidesk/util/Extension.kt @@ -11,7 +11,7 @@ import eu.kanade.tachiyomi.network.NetworkHelper import eu.kanade.tachiyomi.source.SourceFactory import eu.kanade.tachiyomi.source.online.HttpSource import ir.armor.tachidesk.APKExtractor -import ir.armor.tachidesk.Config +import ir.armor.tachidesk.applicationDirs import ir.armor.tachidesk.database.table.ExtensionTable import ir.armor.tachidesk.database.table.SourceTable import kotlinx.coroutines.runBlocking @@ -32,10 +32,10 @@ import java.net.URLClassLoader fun installAPK(apkName: String): Int { val extensionRecord = getExtensionList(true).first { it.apkName == apkName } val fileNameWithoutType = apkName.substringBefore(".apk") - val dirPathWithoutType = "${Config.extensionsRoot}/$fileNameWithoutType" + val dirPathWithoutType = "${applicationDirs.extensionsRoot}/$fileNameWithoutType" // check if we don't have the dex file already downloaded - val jarPath = "${Config.extensionsRoot}/$fileNameWithoutType.jar" + val jarPath = "${applicationDirs.extensionsRoot}/$fileNameWithoutType.jar" if (!File(jarPath).exists()) { runBlocking { val api = ExtensionGithubApi() @@ -137,7 +137,7 @@ private fun downloadAPKFile(url: String, apkPath: String) { fun removeExtension(pkgName: String) { val extensionRecord = getExtensionList(true).first { it.apkName == pkgName } val fileNameWithoutType = pkgName.substringBefore(".apk") - val jarPath = "${Config.extensionsRoot}/$fileNameWithoutType.jar" + val jarPath = "${applicationDirs.extensionsRoot}/$fileNameWithoutType.jar" transaction { val extensionId = ExtensionTable.select { ExtensionTable.name eq extensionRecord.name }.first()[ExtensionTable.id] @@ -157,7 +157,7 @@ val network: NetworkHelper by injectLazy() fun getExtensionIcon(apkName: String): Pair { val iconUrl = transaction { ExtensionTable.select { ExtensionTable.apkName eq apkName }.firstOrNull()!! }[ExtensionTable.iconUrl] - val saveDir = "${Config.extensionsRoot}/icon" + val saveDir = "${applicationDirs.extensionsRoot}/icon" val fileName = apkName return getCachedResponse(saveDir, fileName) { diff --git a/server/src/main/kotlin/ir/armor/tachidesk/util/Manga.kt b/server/src/main/kotlin/ir/armor/tachidesk/util/Manga.kt index 81e2c3b..929d891 100644 --- a/server/src/main/kotlin/ir/armor/tachidesk/util/Manga.kt +++ b/server/src/main/kotlin/ir/armor/tachidesk/util/Manga.kt @@ -6,7 +6,7 @@ package ir.armor.tachidesk.util import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.source.model.SManga -import ir.armor.tachidesk.Config +import ir.armor.tachidesk.applicationDirs import ir.armor.tachidesk.database.dataclass.MangaDataClass import ir.armor.tachidesk.database.table.MangaStatus import ir.armor.tachidesk.database.table.MangaTable @@ -85,7 +85,7 @@ fun getManga(mangaId: Int, proxyThumbnail: Boolean = true): MangaDataClass { fun getThumbnail(mangaId: Int): Pair { val mangaEntry = transaction { MangaTable.select { MangaTable.id eq mangaId }.firstOrNull()!! } - val saveDir = Config.thumbnailsRoot + val saveDir = applicationDirs.thumbnailsRoot val fileName = mangaId.toString() return getCachedResponse(saveDir, fileName) { diff --git a/server/src/main/kotlin/ir/armor/tachidesk/util/Page.kt b/server/src/main/kotlin/ir/armor/tachidesk/util/Page.kt index e8bc198..c34f732 100644 --- a/server/src/main/kotlin/ir/armor/tachidesk/util/Page.kt +++ b/server/src/main/kotlin/ir/armor/tachidesk/util/Page.kt @@ -6,12 +6,11 @@ package ir.armor.tachidesk.util import eu.kanade.tachiyomi.source.model.Page import eu.kanade.tachiyomi.source.online.HttpSource -import ir.armor.tachidesk.Config +import ir.armor.tachidesk.applicationDirs import ir.armor.tachidesk.database.table.ChapterTable import ir.armor.tachidesk.database.table.MangaTable import ir.armor.tachidesk.database.table.PageTable import ir.armor.tachidesk.database.table.SourceTable -import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq import org.jetbrains.exposed.sql.and import org.jetbrains.exposed.sql.select import org.jetbrains.exposed.sql.transactions.transaction @@ -70,7 +69,7 @@ fun getChapterDir(mangaId: Int, chapterId: Int): String { val mangaTitle = mangaEntry[MangaTable.title] val sourceName = source.toString() - val mangaDir = "${Config.mangaRoot}/$sourceName/$mangaTitle/$chapterDir" + val mangaDir = "${applicationDirs.mangaRoot}/$sourceName/$mangaTitle/$chapterDir" // make sure dirs exist File(mangaDir).mkdirs() return mangaDir diff --git a/server/src/main/kotlin/ir/armor/tachidesk/util/SourceList.kt b/server/src/main/kotlin/ir/armor/tachidesk/util/SourceList.kt index 8687d07..54ae52b 100644 --- a/server/src/main/kotlin/ir/armor/tachidesk/util/SourceList.kt +++ b/server/src/main/kotlin/ir/armor/tachidesk/util/SourceList.kt @@ -6,7 +6,7 @@ package ir.armor.tachidesk.util import eu.kanade.tachiyomi.source.SourceFactory import eu.kanade.tachiyomi.source.online.HttpSource -import ir.armor.tachidesk.Config +import ir.armor.tachidesk.applicationDirs import ir.armor.tachidesk.database.dataclass.SourceDataClass import ir.armor.tachidesk.database.entity.ExtensionEntity import ir.armor.tachidesk.database.entity.SourceEntity @@ -36,7 +36,7 @@ fun getHttpSource(sourceId: Long): HttpSource { val apkName = extensionRecord.apkName val className = extensionRecord.classFQName val jarName = apkName.substringBefore(".apk") + ".jar" - val jarPath = "${Config.extensionsRoot}/$jarName" + val jarPath = "${applicationDirs.extensionsRoot}/$jarName" println(jarName) diff --git a/server/src/main/kotlin/ir/armor/tachidesk/util/Util.kt b/server/src/main/kotlin/ir/armor/tachidesk/util/Util.kt index d4695db..0e62037 100644 --- a/server/src/main/kotlin/ir/armor/tachidesk/util/Util.kt +++ b/server/src/main/kotlin/ir/armor/tachidesk/util/Util.kt @@ -9,23 +9,10 @@ import dorkbox.systemTray.SystemTray import dorkbox.systemTray.SystemTray.TrayType import dorkbox.util.CacheUtil import dorkbox.util.Desktop -import ir.armor.tachidesk.Config import ir.armor.tachidesk.Main -import ir.armor.tachidesk.database.makeDataBaseTables import java.awt.event.ActionListener -import java.io.File import java.io.IOException -fun applicationSetup() { - // make dirs we need - File(Config.dataRoot).mkdirs() - File(Config.extensionsRoot).mkdirs() - File("${Config.extensionsRoot}/icon").mkdirs() - File(Config.thumbnailsRoot).mkdirs() - - makeDataBaseTables() -} - fun openInBrowser() { try { Desktop.browseURL("http://127.0.0.1:4567") @@ -34,8 +21,6 @@ fun openInBrowser() { } } -val icon = Main::class.java.getResource("/icon/faviconlogo.png") - fun systemTray(): SystemTray? { try { // ref: https://github.com/dorkbox/SystemTray/blob/master/test/dorkbox/TestTray.java @@ -61,6 +46,8 @@ fun systemTray(): SystemTray? { ) ) + val icon = Main::class.java.getResource("/icon/faviconlogo.png") + // systemTray.setTooltip("Tachidesk") systemTray.setImage(icon) // systemTray.status = "No Mail" diff --git a/server/src/main/resources/server-reference.conf b/server/src/main/resources/server-reference.conf new file mode 100644 index 0000000..b7761fa --- /dev/null +++ b/server/src/main/resources/server-reference.conf @@ -0,0 +1,8 @@ +# Server ip and port bindings +server.ip = 0.0.0.0 +server.port = 4567 + +# Socks5 proxy +server.socksProxy = false +server.socksProxyHost = "" +server.socksProxyPort = "" \ No newline at end of file