mirror of
https://github.com/Suwayomi/Tachidesk.git
synced 2025-12-10 23:02:06 +01:00
add support for alternative web interfaces (#342)
* add support for alternative web interfaces * fix naming * won't bundle sorayomi zip * clean diff
This commit is contained in:
@@ -15,6 +15,7 @@ const val MainClass = "suwayomi.tachidesk.MainKt"
|
|||||||
val tachideskVersion = System.getenv("ProductVersion") ?: "v0.6.3"
|
val tachideskVersion = System.getenv("ProductVersion") ?: "v0.6.3"
|
||||||
|
|
||||||
val webUIRevisionTag = System.getenv("WebUIRevision") ?: "r942"
|
val webUIRevisionTag = System.getenv("WebUIRevision") ?: "r942"
|
||||||
|
val sorayomiRevisionTag = System.getenv("SorayomiRevision") ?: "0.1.5"
|
||||||
|
|
||||||
// counts commits on the master branch
|
// counts commits on the master branch
|
||||||
val tachideskRevision = runCatching {
|
val tachideskRevision = runCatching {
|
||||||
|
|||||||
@@ -107,6 +107,9 @@ buildConfig {
|
|||||||
buildConfigField("String", "WEBUI_REPO", quoteWrap("https://github.com/Suwayomi/Tachidesk-WebUI-preview"))
|
buildConfigField("String", "WEBUI_REPO", quoteWrap("https://github.com/Suwayomi/Tachidesk-WebUI-preview"))
|
||||||
buildConfigField("String", "WEBUI_TAG", quoteWrap(webUIRevisionTag))
|
buildConfigField("String", "WEBUI_TAG", quoteWrap(webUIRevisionTag))
|
||||||
|
|
||||||
|
buildConfigField("String", "SORAYOMI_REPO", quoteWrap("https://github.com/Suwayomi/Tachidesk-Sorayomi"))
|
||||||
|
buildConfigField("String", "SORAYOMI_TAG", quoteWrap(sorayomiRevisionTag))
|
||||||
|
|
||||||
|
|
||||||
buildConfigField("String", "GITHUB", quoteWrap("https://github.com/Suwayomi/Tachidesk-Server"))
|
buildConfigField("String", "GITHUB", quoteWrap("https://github.com/Suwayomi/Tachidesk-Server"))
|
||||||
buildConfigField("String", "DISCORD", quoteWrap("https://discord.gg/DDZdqZWaHA"))
|
buildConfigField("String", "DISCORD", quoteWrap("https://discord.gg/DDZdqZWaHA"))
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import org.kodein.di.instance
|
|||||||
import suwayomi.tachidesk.global.GlobalAPI
|
import suwayomi.tachidesk.global.GlobalAPI
|
||||||
import suwayomi.tachidesk.manga.MangaAPI
|
import suwayomi.tachidesk.manga.MangaAPI
|
||||||
import suwayomi.tachidesk.server.util.Browser
|
import suwayomi.tachidesk.server.util.Browser
|
||||||
import suwayomi.tachidesk.server.util.setupWebUI
|
import suwayomi.tachidesk.server.util.setupWebInterface
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.util.concurrent.CompletableFuture
|
import java.util.concurrent.CompletableFuture
|
||||||
import kotlin.concurrent.thread
|
import kotlin.concurrent.thread
|
||||||
@@ -45,9 +45,9 @@ object JavalinSetup {
|
|||||||
fun javalinSetup() {
|
fun javalinSetup() {
|
||||||
val app = Javalin.create { config ->
|
val app = Javalin.create { config ->
|
||||||
if (serverConfig.webUIEnabled) {
|
if (serverConfig.webUIEnabled) {
|
||||||
setupWebUI()
|
setupWebInterface()
|
||||||
|
|
||||||
logger.info { "Serving webUI static files" }
|
logger.info { "Serving web static files for ${serverConfig.webUIFlavor}" }
|
||||||
config.addStaticFiles(applicationDirs.webUIRoot, Location.EXTERNAL)
|
config.addStaticFiles(applicationDirs.webUIRoot, Location.EXTERNAL)
|
||||||
config.addSinglePageRoot("/", applicationDirs.webUIRoot + "/index.html", Location.EXTERNAL)
|
config.addSinglePageRoot("/", applicationDirs.webUIRoot + "/index.html", Location.EXTERNAL)
|
||||||
config.registerPlugin(OpenApiPlugin(getOpenApiOptions()))
|
config.registerPlugin(OpenApiPlugin(getOpenApiOptions()))
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ class ServerConfig(config: Config, moduleName: String = MODULE_NAME) : SystemPro
|
|||||||
|
|
||||||
// webUI
|
// webUI
|
||||||
val webUIEnabled: Boolean by overridableConfig
|
val webUIEnabled: Boolean by overridableConfig
|
||||||
|
val webUIFlavor: String by overridableConfig
|
||||||
val initialOpenInBrowserEnabled: Boolean by overridableConfig
|
val initialOpenInBrowserEnabled: Boolean by overridableConfig
|
||||||
val webUIInterface: String by overridableConfig
|
val webUIInterface: String by overridableConfig
|
||||||
val electronPath: String by overridableConfig
|
val electronPath: String by overridableConfig
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ package suwayomi.tachidesk.server.util
|
|||||||
* 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 kotlinx.serialization.json.Json
|
||||||
|
import kotlinx.serialization.json.jsonObject
|
||||||
|
import kotlinx.serialization.json.jsonPrimitive
|
||||||
import mu.KotlinLogging
|
import mu.KotlinLogging
|
||||||
import net.lingala.zip4j.ZipFile
|
import net.lingala.zip4j.ZipFile
|
||||||
import org.kodein.di.DI
|
import org.kodein.di.DI
|
||||||
@@ -14,6 +17,8 @@ import org.kodein.di.conf.global
|
|||||||
import org.kodein.di.instance
|
import org.kodein.di.instance
|
||||||
import suwayomi.tachidesk.server.ApplicationDirs
|
import suwayomi.tachidesk.server.ApplicationDirs
|
||||||
import suwayomi.tachidesk.server.BuildConfig
|
import suwayomi.tachidesk.server.BuildConfig
|
||||||
|
import suwayomi.tachidesk.server.serverConfig
|
||||||
|
import uy.kohesive.injekt.injectLazy
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.net.HttpURLConnection
|
import java.net.HttpURLConnection
|
||||||
@@ -23,6 +28,7 @@ import java.security.MessageDigest
|
|||||||
|
|
||||||
private val logger = KotlinLogging.logger {}
|
private val logger = KotlinLogging.logger {}
|
||||||
private val applicationDirs by DI.global.instance<ApplicationDirs>()
|
private val applicationDirs by DI.global.instance<ApplicationDirs>()
|
||||||
|
private val json: Json by injectLazy()
|
||||||
private val tmpDir = System.getProperty("java.io.tmpdir")
|
private val tmpDir = System.getProperty("java.io.tmpdir")
|
||||||
|
|
||||||
private fun ByteArray.toHex(): String = joinToString(separator = "") { eachByte -> "%02x".format(eachByte) }
|
private fun ByteArray.toHex(): String = joinToString(separator = "") { eachByte -> "%02x".format(eachByte) }
|
||||||
@@ -44,6 +50,19 @@ private fun directoryMD5(fileDir: String): String {
|
|||||||
return digest.toHex()
|
return digest.toHex()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Make sure a valid web interface installation is available */
|
||||||
|
fun setupWebInterface() {
|
||||||
|
when (serverConfig.webUIFlavor) {
|
||||||
|
"WebUI" -> setupWebUI()
|
||||||
|
"Sorayomi" -> setupSorayomi()
|
||||||
|
"Custom" -> {
|
||||||
|
/* do nothing */
|
||||||
|
}
|
||||||
|
else -> setupWebUI()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Make sure a valid copy of WebUI is available */
|
||||||
fun setupWebUI() {
|
fun setupWebUI() {
|
||||||
// check if we have webUI installed and is correct version
|
// check if we have webUI installed and is correct version
|
||||||
val webUIRevisionFile = File(applicationDirs.webUIRoot + "/revision")
|
val webUIRevisionFile = File(applicationDirs.webUIRoot + "/revision")
|
||||||
@@ -117,3 +136,63 @@ fun setupWebUI() {
|
|||||||
logger.info { "Extracting WebUI zip Done." }
|
logger.info { "Extracting WebUI zip Done." }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Make sure a valid copy of Sorayomi is available */
|
||||||
|
fun setupSorayomi() {
|
||||||
|
// check if we have Sorayomi installed and is correct version
|
||||||
|
val sorayomiVersionFile = File(applicationDirs.webUIRoot + "/version.json")
|
||||||
|
if (sorayomiVersionFile.exists() && json.parseToJsonElement(
|
||||||
|
sorayomiVersionFile.readText()
|
||||||
|
).jsonObject["version"]!!.jsonPrimitive.content == BuildConfig.SORAYOMI_TAG
|
||||||
|
) {
|
||||||
|
logger.info { "Sorayomi Static files exists and is the correct revision" }
|
||||||
|
logger.info { "Verifying Sorayomi Static files..." }
|
||||||
|
logger.info { "md5: " + directoryMD5(applicationDirs.webUIRoot) }
|
||||||
|
} else {
|
||||||
|
File(applicationDirs.webUIRoot).deleteRecursively()
|
||||||
|
|
||||||
|
val sorayomiZip = "tachidesk-sorayomi-${BuildConfig.SORAYOMI_TAG}-web.zip"
|
||||||
|
val sorayomiZipPath = "$tmpDir/$sorayomiZip"
|
||||||
|
val sorayomiZipFile = File(sorayomiZipPath)
|
||||||
|
|
||||||
|
// download sorayomi zip
|
||||||
|
val sorayomiZipURL = "${BuildConfig.SORAYOMI_REPO}/releases/download/${BuildConfig.SORAYOMI_TAG}/$sorayomiZip"
|
||||||
|
sorayomiZipFile.delete()
|
||||||
|
|
||||||
|
logger.info { "Downloading Sorayomi zip from the Internet..." }
|
||||||
|
val data = ByteArray(1024)
|
||||||
|
|
||||||
|
sorayomiZipFile.outputStream().use { sorayomiZipFileOut ->
|
||||||
|
|
||||||
|
val connection = URL(sorayomiZipURL).openConnection() as HttpURLConnection
|
||||||
|
connection.connect()
|
||||||
|
val contentLength = connection.contentLength
|
||||||
|
|
||||||
|
connection.inputStream.buffered().use { inp ->
|
||||||
|
var totalCount = 0
|
||||||
|
|
||||||
|
print("Download progress: % 00")
|
||||||
|
while (true) {
|
||||||
|
val count = inp.read(data, 0, 1024)
|
||||||
|
|
||||||
|
if (count == -1)
|
||||||
|
break
|
||||||
|
|
||||||
|
totalCount += count
|
||||||
|
val percentage = (totalCount.toFloat() / contentLength * 100).toInt().toString().padStart(2, '0')
|
||||||
|
print("\b\b$percentage")
|
||||||
|
|
||||||
|
sorayomiZipFileOut.write(data, 0, count)
|
||||||
|
}
|
||||||
|
println()
|
||||||
|
logger.info { "Downloading Sorayomi Done." }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// extract Sorayomi zip
|
||||||
|
logger.info { "Extracting Sorayomi zip..." }
|
||||||
|
File(applicationDirs.webUIRoot).mkdirs()
|
||||||
|
ZipFile(sorayomiZipPath).extractAll(applicationDirs.webUIRoot)
|
||||||
|
logger.info { "Extracting Sorayomi zip Done." }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@ server.socksProxyPort = ""
|
|||||||
|
|
||||||
# webUI
|
# webUI
|
||||||
server.webUIEnabled = true
|
server.webUIEnabled = true
|
||||||
|
server.webUIFlavor = "WebUI" # "WebUI" or "Sorayomi" or "Custom"
|
||||||
server.initialOpenInBrowserEnabled = true
|
server.initialOpenInBrowserEnabled = true
|
||||||
server.webUIInterface = "browser" # "browser" or "electron"
|
server.webUIInterface = "browser" # "browser" or "electron"
|
||||||
server.electronPath = ""
|
server.electronPath = ""
|
||||||
|
|||||||
Reference in New Issue
Block a user