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:
Aria Moradi
2022-04-16 21:09:36 +04:30
committed by GitHub
parent a8892143a2
commit 320d1ae9d8
6 changed files with 88 additions and 3 deletions

View File

@@ -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 {

View File

@@ -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"))

View File

@@ -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()))

View File

@@ -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

View File

@@ -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." }
}
}

View File

@@ -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 = ""