mirror of
https://github.com/Suwayomi/Suwayomi-Server.git
synced 2026-07-02 18:34:39 -05:00
Add initial testing suit
This commit is contained in:
@@ -39,12 +39,17 @@ import org.jetbrains.exposed.sql.insert
|
||||
import org.jetbrains.exposed.sql.select
|
||||
import org.jetbrains.exposed.sql.transactions.transaction
|
||||
import org.jetbrains.exposed.sql.update
|
||||
import org.kodein.di.DI
|
||||
import org.kodein.di.conf.global
|
||||
import org.kodein.di.instance
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.io.File
|
||||
import java.io.InputStream
|
||||
|
||||
object Extension {
|
||||
private val logger = KotlinLogging.logger {}
|
||||
private val dirs by DI.global.instance<ApplicationDirs>()
|
||||
|
||||
|
||||
data class InstallableAPK(
|
||||
val apkFilePath: String,
|
||||
@@ -58,7 +63,7 @@ object Extension {
|
||||
return installAPK {
|
||||
val apkURL = ExtensionGithubApi.getApkUrl(extensionRecord)
|
||||
val apkName = Uri.parse(apkURL).lastPathSegment!!
|
||||
val apkSavePath = "${ApplicationDirs.extensionsRoot}/$apkName"
|
||||
val apkSavePath = "${dirs.extensionsRoot}/$apkName"
|
||||
// download apk file
|
||||
downloadAPKFile(apkURL, apkSavePath)
|
||||
|
||||
@@ -79,7 +84,7 @@ object Extension {
|
||||
if (!isInstalled) {
|
||||
val fileNameWithoutType = apkName.substringBefore(".apk")
|
||||
|
||||
val dirPathWithoutType = "${ApplicationDirs.extensionsRoot}/$fileNameWithoutType"
|
||||
val dirPathWithoutType = "${dirs.extensionsRoot}/$fileNameWithoutType"
|
||||
val jarFilePath = "$dirPathWithoutType.jar"
|
||||
val dexFilePath = "$dirPathWithoutType.dex"
|
||||
|
||||
@@ -193,7 +198,7 @@ object Extension {
|
||||
|
||||
val extensionRecord = transaction { ExtensionTable.select { ExtensionTable.pkgName eq pkgName }.firstOrNull()!! }
|
||||
val fileNameWithoutType = extensionRecord[ExtensionTable.apkName].substringBefore(".apk")
|
||||
val jarPath = "${ApplicationDirs.extensionsRoot}/$fileNameWithoutType.jar"
|
||||
val jarPath = "${dirs.extensionsRoot}/$fileNameWithoutType.jar"
|
||||
transaction {
|
||||
val extensionId = extensionRecord[ExtensionTable.id].value
|
||||
|
||||
@@ -232,7 +237,7 @@ object Extension {
|
||||
suspend fun getExtensionIcon(apkName: String): Pair<InputStream, String> {
|
||||
val iconUrl = transaction { ExtensionTable.select { ExtensionTable.apkName eq apkName }.firstOrNull()!! }[ExtensionTable.iconUrl]
|
||||
|
||||
val saveDir = "${ApplicationDirs.extensionsRoot}/icon"
|
||||
val saveDir = "${dirs.extensionsRoot}/icon"
|
||||
|
||||
return getCachedImageResponse(saveDir, apkName) {
|
||||
network.client.newCall(
|
||||
|
||||
@@ -22,6 +22,9 @@ import ir.armor.tachidesk.server.ApplicationDirs
|
||||
import org.jetbrains.exposed.sql.select
|
||||
import org.jetbrains.exposed.sql.transactions.transaction
|
||||
import org.jetbrains.exposed.sql.update
|
||||
import org.kodein.di.DI
|
||||
import org.kodein.di.conf.global
|
||||
import org.kodein.di.instance
|
||||
import java.io.InputStream
|
||||
|
||||
object Manga {
|
||||
@@ -95,9 +98,10 @@ object Manga {
|
||||
}
|
||||
}
|
||||
|
||||
private val dirs by DI.global.instance<ApplicationDirs>()
|
||||
suspend fun getMangaThumbnail(mangaId: Int): Pair<InputStream, String> {
|
||||
val mangaEntry = transaction { MangaTable.select { MangaTable.id eq mangaId }.firstOrNull()!! }
|
||||
val saveDir = ApplicationDirs.thumbnailsRoot
|
||||
val saveDir = dirs.thumbnailsRoot
|
||||
val fileName = mangaId.toString()
|
||||
|
||||
return getCachedImageResponse(saveDir, fileName) {
|
||||
|
||||
@@ -21,6 +21,9 @@ import org.jetbrains.exposed.sql.and
|
||||
import org.jetbrains.exposed.sql.select
|
||||
import org.jetbrains.exposed.sql.transactions.transaction
|
||||
import org.jetbrains.exposed.sql.update
|
||||
import org.kodein.di.DI
|
||||
import org.kodein.di.conf.global
|
||||
import org.kodein.di.instance
|
||||
import java.io.File
|
||||
import java.io.InputStream
|
||||
|
||||
@@ -73,6 +76,7 @@ object Page {
|
||||
}
|
||||
|
||||
// TODO: rewrite this to match tachiyomi
|
||||
private val dirs by DI.global.instance<ApplicationDirs>()
|
||||
fun getChapterDir(mangaId: Int, chapterId: Int): String {
|
||||
val mangaEntry = transaction { MangaTable.select { MangaTable.id eq mangaId }.firstOrNull()!! }
|
||||
val sourceId = mangaEntry[MangaTable.sourceReference]
|
||||
@@ -88,7 +92,7 @@ object Page {
|
||||
val mangaTitle = mangaEntry[MangaTable.title]
|
||||
val sourceName = source.toString()
|
||||
|
||||
val mangaDir = "${ApplicationDirs.mangaRoot}/$sourceName/$mangaTitle/$chapterDir"
|
||||
val mangaDir = "${dirs.mangaRoot}/$sourceName/$mangaTitle/$chapterDir"
|
||||
// make sure dirs exist
|
||||
File(mangaDir).mkdirs()
|
||||
return mangaDir
|
||||
|
||||
@@ -24,7 +24,7 @@ object Source {
|
||||
return transaction {
|
||||
SourceTable.selectAll().map {
|
||||
SourceDataClass(
|
||||
it[SourceTable.id].value.toString(),
|
||||
it[SourceTable.id].value,
|
||||
it[SourceTable.name],
|
||||
it[SourceTable.lang],
|
||||
getExtensionIconUrl(ExtensionTable.select { ExtensionTable.id eq it[SourceTable.extension] }.first()[ExtensionTable.apkName]),
|
||||
@@ -39,7 +39,7 @@ object Source {
|
||||
val source = SourceTable.select { SourceTable.id eq sourceId }.firstOrNull()
|
||||
|
||||
SourceDataClass(
|
||||
sourceId.toString(),
|
||||
sourceId,
|
||||
source?.get(SourceTable.name),
|
||||
source?.get(SourceTable.lang),
|
||||
source?.let { ExtensionTable.select { ExtensionTable.id eq source[SourceTable.extension] }.first()[ExtensionTable.iconUrl] },
|
||||
|
||||
@@ -16,10 +16,14 @@ import ir.armor.tachidesk.model.database.SourceTable
|
||||
import ir.armor.tachidesk.server.ApplicationDirs
|
||||
import org.jetbrains.exposed.sql.select
|
||||
import org.jetbrains.exposed.sql.transactions.transaction
|
||||
import org.kodein.di.DI
|
||||
import org.kodein.di.conf.global
|
||||
import org.kodein.di.instance
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
object GetHttpSource {
|
||||
private val sourceCache = ConcurrentHashMap<Long, HttpSource>()
|
||||
private val dirs by DI.global.instance<ApplicationDirs>()
|
||||
|
||||
fun getHttpSource(sourceId: Long): HttpSource {
|
||||
val cachedResult: HttpSource? = sourceCache[sourceId]
|
||||
@@ -39,7 +43,7 @@ object GetHttpSource {
|
||||
val apkName = extensionRecord[ExtensionTable.apkName]
|
||||
val className = extensionRecord[ExtensionTable.classFQName]
|
||||
val jarName = apkName.substringBefore(".apk") + ".jar"
|
||||
val jarPath = "${ApplicationDirs.extensionsRoot}/$jarName"
|
||||
val jarPath = "${dirs.extensionsRoot}/$jarName"
|
||||
|
||||
when (val instance = loadExtensionSources(jarPath, className)) {
|
||||
is Source -> listOf(instance)
|
||||
|
||||
@@ -11,6 +11,9 @@ import ir.armor.tachidesk.server.ApplicationDirs
|
||||
import mu.KotlinLogging
|
||||
import net.dongliu.apk.parser.ApkFile
|
||||
import net.dongliu.apk.parser.ApkParsers
|
||||
import org.kodein.di.DI
|
||||
import org.kodein.di.conf.global
|
||||
import org.kodein.di.instance
|
||||
import org.w3c.dom.Element
|
||||
import org.w3c.dom.Node
|
||||
import xyz.nulldev.androidcompat.pm.InstalledPackage.Companion.toList
|
||||
@@ -31,6 +34,7 @@ import javax.xml.parsers.DocumentBuilderFactory
|
||||
|
||||
object PackageTools {
|
||||
private val logger = KotlinLogging.logger {}
|
||||
private val dirs by DI.global.instance<ApplicationDirs>()
|
||||
|
||||
const val EXTENSION_FEATURE = "tachiyomi.extension"
|
||||
const val METADATA_SOURCE_CLASS = "tachiyomi.extension.class"
|
||||
@@ -65,7 +69,7 @@ object PackageTools {
|
||||
.skipExceptions(false)
|
||||
.to(jarFilePath)
|
||||
if (handler.hasException()) {
|
||||
val errorFile: Path = File(ApplicationDirs.extensionsRoot).toPath().resolve("$fileNameWithoutType-error.txt")
|
||||
val errorFile: Path = File(dirs.extensionsRoot).toPath().resolve("$fileNameWithoutType-error.txt")
|
||||
logger.error(
|
||||
"Detail Error Information in File $errorFile\n" +
|
||||
"Please report this file to one of following link if possible (any one).\n" +
|
||||
|
||||
@@ -18,10 +18,14 @@ import ir.armor.tachidesk.server.ApplicationDirs
|
||||
import org.jetbrains.exposed.sql.Database
|
||||
import org.jetbrains.exposed.sql.SchemaUtils
|
||||
import org.jetbrains.exposed.sql.transactions.transaction
|
||||
import org.kodein.di.DI
|
||||
import org.kodein.di.conf.global
|
||||
import org.kodein.di.instance
|
||||
|
||||
object DBMangaer {
|
||||
val db by lazy {
|
||||
Database.connect("jdbc:h2:${ApplicationDirs.dataRoot}/database", "org.h2.Driver")
|
||||
val dirs by DI.global.instance<ApplicationDirs>()
|
||||
Database.connect("jdbc:h2:${dirs.dataRoot}/database", "org.h2.Driver")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ package ir.armor.tachidesk.model.dataclass
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
data class SourceDataClass(
|
||||
val id: String,
|
||||
val id: Long,
|
||||
val name: String?,
|
||||
val lang: String?,
|
||||
val iconUrl: String?,
|
||||
|
||||
@@ -8,6 +8,7 @@ package ir.armor.tachidesk.server
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import ch.qos.logback.classic.Level
|
||||
import com.typesafe.config.Config
|
||||
import eu.kanade.tachiyomi.App
|
||||
import ir.armor.tachidesk.Main
|
||||
import ir.armor.tachidesk.model.dataclass.makeDataBaseTables
|
||||
@@ -15,7 +16,11 @@ import ir.armor.tachidesk.server.util.systemTray
|
||||
import mu.KotlinLogging
|
||||
import net.harawata.appdirs.AppDirsFactory
|
||||
import org.kodein.di.DI
|
||||
import org.kodein.di.bind
|
||||
import org.kodein.di.conf.global
|
||||
import org.kodein.di.instance
|
||||
import org.kodein.di.singleton
|
||||
import org.slf4j.Logger
|
||||
import xyz.nulldev.androidcompat.AndroidCompat
|
||||
import xyz.nulldev.androidcompat.AndroidCompatInitializer
|
||||
import xyz.nulldev.ts.config.ConfigKodeinModule
|
||||
@@ -24,43 +29,57 @@ import java.io.File
|
||||
|
||||
private val logger = KotlinLogging.logger {}
|
||||
|
||||
object ApplicationDirs {
|
||||
val dataRoot = AppDirsFactory.getInstance().getUserDataDir("Tachidesk", null, null)!!
|
||||
class ApplicationDirs(
|
||||
val dataRoot: String = 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 serverConfig: ServerConfig by DI.global.instance()
|
||||
|
||||
val systemTray by lazy { systemTray() }
|
||||
|
||||
val androidCompat by lazy { AndroidCompat() }
|
||||
|
||||
fun applicationSetup() {
|
||||
// register server config
|
||||
GlobalConfigManager.registerModule(
|
||||
ServerConfig.register(GlobalConfigManager.config)
|
||||
)
|
||||
|
||||
// set application wide logging level
|
||||
if (serverConfig.debugLogsEnabled) {
|
||||
(mu.KotlinLogging.logger(org.slf4j.Logger.ROOT_LOGGER_NAME).underlyingLogger as ch.qos.logback.classic.Logger).level = Level.DEBUG
|
||||
fun applicationSetup(rootDir: String? = null, config: Config = GlobalConfigManager.config) {
|
||||
val dirs = if (rootDir != null) {
|
||||
ApplicationDirs(rootDir)
|
||||
} else {
|
||||
ApplicationDirs()
|
||||
}
|
||||
|
||||
// make dirs we need
|
||||
listOf(
|
||||
ApplicationDirs.dataRoot,
|
||||
ApplicationDirs.extensionsRoot,
|
||||
"${ApplicationDirs.extensionsRoot}/icon",
|
||||
ApplicationDirs.thumbnailsRoot
|
||||
dirs.dataRoot,
|
||||
dirs.extensionsRoot,
|
||||
dirs.extensionsRoot + "/icon",
|
||||
dirs.thumbnailsRoot
|
||||
).forEach {
|
||||
File(it).mkdirs()
|
||||
}
|
||||
|
||||
// Application dirs
|
||||
DI.global.addImport(DI.Module("Server") {
|
||||
bind<ApplicationDirs>() with singleton { dirs }
|
||||
bind<ServerConfig>() with singleton { ServerConfig.register(config) }
|
||||
})
|
||||
// Load config API
|
||||
DI.global.addImport(ConfigKodeinModule().create())
|
||||
// Load Android compatibility dependencies
|
||||
AndroidCompatInitializer().init()
|
||||
// start app
|
||||
androidCompat.startApp(App())
|
||||
|
||||
// set application wide logging level
|
||||
if (serverConfig.debugLogsEnabled) {
|
||||
(KotlinLogging.logger(Logger.ROOT_LOGGER_NAME).underlyingLogger as ch.qos.logback.classic.Logger).level = Level.DEBUG
|
||||
}
|
||||
|
||||
// create conf file if doesn't exist
|
||||
try {
|
||||
val dataConfFile = File("${ApplicationDirs.dataRoot}/server.conf")
|
||||
val dataConfFile = File("${dirs.dataRoot}/server.conf")
|
||||
if (!dataConfFile.exists()) {
|
||||
Main::class.java.getResourceAsStream("/server-reference.conf").use { input ->
|
||||
dataConfFile.outputStream().use { output ->
|
||||
@@ -75,19 +94,13 @@ fun applicationSetup() {
|
||||
makeDataBaseTables()
|
||||
|
||||
// create system tray
|
||||
if (serverConfig.systemTrayEnabled)
|
||||
if (serverConfig.systemTrayEnabled) {
|
||||
try {
|
||||
systemTray
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
// Load config API
|
||||
DI.global.addImport(ConfigKodeinModule().create())
|
||||
// Load Android compatibility dependencies
|
||||
AndroidCompatInitializer().init()
|
||||
// start app
|
||||
androidCompat.startApp(App())
|
||||
}
|
||||
|
||||
// Disable jetty's logging
|
||||
System.setProperty("org.eclipse.jetty.util.log.announce", "false")
|
||||
|
||||
Reference in New Issue
Block a user