Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b4b7b5d572 | |||
| 291c2e692d | |||
| 8a9a4f21b1 | |||
| cd31332b39 | |||
| cc8d2162a0 | |||
| e6313cdc67 | |||
| a5578a7ac7 | |||
| fcdda6406e | |||
| d3a6662c60 | |||
| 5474eddf84 | |||
| b666cd47d4 | |||
| 8a986383fe | |||
| 9fa17f617e |
@@ -1,4 +0,0 @@
|
|||||||
dependencies {
|
|
||||||
// Config API, moved to the global build.gradle
|
|
||||||
// implementation("com.typesafe:config:1.4.0")
|
|
||||||
}
|
|
||||||
@@ -20,16 +20,9 @@ dependencies {
|
|||||||
// Android stub library
|
// Android stub library
|
||||||
implementation(fileTree("lib/"))
|
implementation(fileTree("lib/"))
|
||||||
|
|
||||||
|
|
||||||
// Android JAR libs
|
|
||||||
// compileOnly( fileTree(dir: new File(rootProject.rootDir, "libs/other"), include: "*.jar")
|
|
||||||
|
|
||||||
// JSON
|
// JSON
|
||||||
compileOnly("com.google.code.gson:gson:2.8.6")
|
compileOnly("com.google.code.gson:gson:2.8.6")
|
||||||
|
|
||||||
// Javassist
|
|
||||||
compileOnly("org.javassist:javassist:3.27.0-GA")
|
|
||||||
|
|
||||||
// XML
|
// XML
|
||||||
compileOnly(group= "xmlpull", name= "xmlpull", version= "1.1.3.1")
|
compileOnly(group= "xmlpull", name= "xmlpull", version= "1.1.3.1")
|
||||||
|
|
||||||
@@ -43,10 +36,8 @@ dependencies {
|
|||||||
compileOnly("androidx.annotation:annotation:1.2.0-alpha01")
|
compileOnly("androidx.annotation:annotation:1.2.0-alpha01")
|
||||||
|
|
||||||
// substitute for duktape-android
|
// substitute for duktape-android
|
||||||
// 'org.mozilla:rhino' includes some code that we don't need so use 'org.mozilla:rhino-runtime' instead
|
implementation("org.mozilla:rhino-runtime:1.7.13") // slimmer version of 'org.mozilla:rhino'
|
||||||
implementation("org.mozilla:rhino-runtime:1.7.13")
|
implementation("org.mozilla:rhino-engine:1.7.13") // provides the same interface as 'javax.script' a.k.a Nashorn
|
||||||
// 'org.mozilla:rhino-engine' provides the same interface as 'javax.script' a.k.a Nashorn
|
|
||||||
implementation("org.mozilla:rhino-engine:1.7.13")
|
|
||||||
|
|
||||||
// Kotlin wrapper around Java Preferences, makes certain things easier
|
// Kotlin wrapper around Java Preferences, makes certain things easier
|
||||||
val multiplatformSettingsVersion = "0.7.7"
|
val multiplatformSettingsVersion = "0.7.7"
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
package kotlinx.coroutines.experimental.android
|
|
||||||
|
|
||||||
import kotlinx.coroutines.GlobalScope
|
|
||||||
|
|
||||||
val UI = GlobalScope.coroutineContext
|
|
||||||
@@ -2,7 +2,6 @@ package xyz.nulldev.androidcompat
|
|||||||
|
|
||||||
import org.kodein.di.DI
|
import org.kodein.di.DI
|
||||||
import org.kodein.di.conf.global
|
import org.kodein.di.conf.global
|
||||||
import xyz.nulldev.androidcompat.bytecode.ModApplier
|
|
||||||
import xyz.nulldev.androidcompat.config.ApplicationInfoConfigModule
|
import xyz.nulldev.androidcompat.config.ApplicationInfoConfigModule
|
||||||
import xyz.nulldev.androidcompat.config.FilesConfigModule
|
import xyz.nulldev.androidcompat.config.FilesConfigModule
|
||||||
import xyz.nulldev.androidcompat.config.SystemConfigModule
|
import xyz.nulldev.androidcompat.config.SystemConfigModule
|
||||||
@@ -12,12 +11,7 @@ import xyz.nulldev.ts.config.GlobalConfigManager
|
|||||||
* Initializes the Android compatibility module
|
* Initializes the Android compatibility module
|
||||||
*/
|
*/
|
||||||
class AndroidCompatInitializer {
|
class AndroidCompatInitializer {
|
||||||
|
|
||||||
val modApplier by lazy { ModApplier() }
|
|
||||||
|
|
||||||
fun init() {
|
fun init() {
|
||||||
modApplier.apply()
|
|
||||||
|
|
||||||
DI.global.addImport(AndroidCompatModule().create())
|
DI.global.addImport(AndroidCompatModule().create())
|
||||||
|
|
||||||
//Register config modules
|
//Register config modules
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
package xyz.nulldev.androidcompat.bytecode
|
|
||||||
|
|
||||||
import javassist.CtClass
|
|
||||||
import mu.KotlinLogging
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Applies Javassist modifications
|
|
||||||
*/
|
|
||||||
|
|
||||||
class ModApplier {
|
|
||||||
|
|
||||||
val logger = KotlinLogging.logger {}
|
|
||||||
|
|
||||||
fun apply() {
|
|
||||||
logger.info { "Applying Javassist mods..." }
|
|
||||||
val modifiedClasses = mutableListOf<CtClass>()
|
|
||||||
|
|
||||||
modifiedClasses.forEach {
|
|
||||||
it.toClass()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -4,11 +4,21 @@ import java.io.InputStream
|
|||||||
import java.io.Reader
|
import java.io.Reader
|
||||||
import java.math.BigDecimal
|
import java.math.BigDecimal
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
import java.sql.*
|
|
||||||
import java.sql.Array
|
import java.sql.Array
|
||||||
|
import java.sql.Blob
|
||||||
|
import java.sql.Clob
|
||||||
import java.sql.Date
|
import java.sql.Date
|
||||||
import java.util.*
|
import java.sql.NClob
|
||||||
|
import java.sql.Ref
|
||||||
|
import java.sql.ResultSet
|
||||||
|
import java.sql.ResultSetMetaData
|
||||||
|
import java.sql.RowId
|
||||||
|
import java.sql.SQLXML
|
||||||
|
import java.sql.Time
|
||||||
|
import java.sql.Timestamp
|
||||||
|
import java.util.Calendar
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
class ScrollableResultSet(val parent: ResultSet) : ResultSet by parent {
|
class ScrollableResultSet(val parent: ResultSet) : ResultSet by parent {
|
||||||
|
|
||||||
private val cachedContent = mutableListOf<ResultSetEntry>()
|
private val cachedContent = mutableListOf<ResultSetEntry>()
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ class ServiceSupport {
|
|||||||
|
|
||||||
private val logger = KotlinLogging.logger {}
|
private val logger = KotlinLogging.logger {}
|
||||||
|
|
||||||
fun startService(context: Context, intent: Intent) {
|
fun startService(@Suppress("UNUSED_PARAMETER") context: Context, intent: Intent) {
|
||||||
val name = intentToClassName(intent)
|
val name = intentToClassName(intent)
|
||||||
|
|
||||||
logger.debug { "Starting service: $name" }
|
logger.debug { "Starting service: $name" }
|
||||||
@@ -35,7 +35,7 @@ class ServiceSupport {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun stopService(context: Context, intent: Intent) {
|
fun stopService(@Suppress("UNUSED_PARAMETER") context: Context, intent: Intent) {
|
||||||
val name = intentToClassName(intent)
|
val name = intentToClassName(intent)
|
||||||
stopService(name)
|
stopService(name)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ object KodeinGlobalHelper {
|
|||||||
* Get a dependency
|
* Get a dependency
|
||||||
*/
|
*/
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
fun <T : Any> instance(type: Class<T>, kodein: DI? = null): T {
|
fun <T : Any> instance(type: Class<T>, kodein: DI? = null): T {
|
||||||
return when(type) {
|
return when(type) {
|
||||||
AndroidFiles::class.java -> {
|
AndroidFiles::class.java -> {
|
||||||
|
|||||||
+5
-4
@@ -1,8 +1,8 @@
|
|||||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
kotlin("jvm") version "1.4.32"
|
kotlin("jvm") version kotlinVersion
|
||||||
kotlin("plugin.serialization") version "1.4.32" apply false
|
kotlin("plugin.serialization") version kotlinVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
@@ -46,12 +46,12 @@ configure(projects) {
|
|||||||
testImplementation(kotlin("test-junit5"))
|
testImplementation(kotlin("test-junit5"))
|
||||||
|
|
||||||
// coroutines
|
// coroutines
|
||||||
val coroutinesVersion = "1.4.3"
|
val coroutinesVersion = "1.5.0"
|
||||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion")
|
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion")
|
||||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:$coroutinesVersion")
|
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:$coroutinesVersion")
|
||||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutinesVersion")
|
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutinesVersion")
|
||||||
|
|
||||||
val kotlinSerializationVersion = "1.1.0"
|
val kotlinSerializationVersion = "1.2.1"
|
||||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlinSerializationVersion")
|
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlinSerializationVersion")
|
||||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-protobuf:$kotlinSerializationVersion")
|
implementation("org.jetbrains.kotlinx:kotlinx-serialization-protobuf:$kotlinSerializationVersion")
|
||||||
|
|
||||||
@@ -80,6 +80,7 @@ configure(projects) {
|
|||||||
implementation("net.harawata:appdirs:1.2.1")
|
implementation("net.harawata:appdirs:1.2.1")
|
||||||
|
|
||||||
// dex2jar: https://github.com/DexPatcher/dex2jar/releases/tag/v2.1-20190905-lanchon
|
// dex2jar: https://github.com/DexPatcher/dex2jar/releases/tag/v2.1-20190905-lanchon
|
||||||
|
// note: watch https://github.com/ThexXTURBOXx/dex2jar for future development
|
||||||
implementation("com.github.DexPatcher.dex2jar:dex-tools:v2.1-20190905-lanchon")
|
implementation("com.github.DexPatcher.dex2jar:dex-tools:v2.1-20190905-lanchon")
|
||||||
|
|
||||||
// APK parser
|
// APK parser
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
plugins {
|
||||||
|
`kotlin-dsl`
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation("net.lingala.zip4j:zip4j:2.9.0")
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import java.io.BufferedReader
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) Contributors to the Suwayomi project
|
||||||
|
*
|
||||||
|
* 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/. */
|
||||||
|
|
||||||
|
const val kotlinVersion = "1.5.21"
|
||||||
|
|
||||||
|
const val MainClass = "suwayomi.tachidesk.MainKt"
|
||||||
|
|
||||||
|
// should be bumped with each stable release
|
||||||
|
val tachideskVersion = System.getenv("ProductVersion") ?: "v0.4.6"
|
||||||
|
|
||||||
|
val webUIRevisionTag = System.getenv("WebUIRevision") ?: "r24"
|
||||||
|
|
||||||
|
// counts commit count on master
|
||||||
|
val tachideskRevision = runCatching {
|
||||||
|
System.getenv("ProductRevision") ?: Runtime
|
||||||
|
.getRuntime()
|
||||||
|
.exec("git rev-list HEAD --count")
|
||||||
|
.let { process ->
|
||||||
|
process.waitFor()
|
||||||
|
val output = process.inputStream.use {
|
||||||
|
it.bufferedReader().use(BufferedReader::readText)
|
||||||
|
}
|
||||||
|
process.destroy()
|
||||||
|
"r" + output.trim()
|
||||||
|
}
|
||||||
|
}.getOrDefault("r0")
|
||||||
|
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-all.zip
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
jre\bin\javaw "-Dsuwayomi.tachidesk.config.server.webInterface=electron" "-Dsuwayomi.tachidesk.config.server.electronPath=electron/electron.exe" -jar Tachidesk.jar
|
jre\bin\javaw "-Dsuwayomi.tachidesk.config.server.webUIInterface=electron" "-Dsuwayomi.tachidesk.config.server.electronPath=electron/electron.exe" -jar Tachidesk.jar
|
||||||
+49
-47
@@ -1,15 +1,15 @@
|
|||||||
|
|
||||||
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
|
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
|
||||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||||
import org.jmailen.gradle.kotlinter.tasks.FormatTask
|
import org.jmailen.gradle.kotlinter.tasks.FormatTask
|
||||||
import org.jmailen.gradle.kotlinter.tasks.LintTask
|
import org.jmailen.gradle.kotlinter.tasks.LintTask
|
||||||
import java.io.BufferedReader
|
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
application
|
application
|
||||||
id("com.github.johnrengelman.shadow") version "7.0.0"
|
id("com.github.johnrengelman.shadow") version "7.0.0"
|
||||||
id("org.jmailen.kotlinter") version "3.4.3"
|
id("org.jmailen.kotlinter") version "3.4.3"
|
||||||
id("de.fuerstenau.buildconfig") version "1.1.8"
|
id("com.github.gmazzo.buildconfig") version "3.0.2"
|
||||||
}
|
}
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
@@ -53,7 +53,6 @@ dependencies {
|
|||||||
implementation("com.dorkbox:Utilities:1.9")
|
implementation("com.dorkbox:Utilities:1.9")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// dependencies of Tachiyomi extensions, some are duplicate, keeping it here for reference
|
// dependencies of Tachiyomi extensions, some are duplicate, keeping it here for reference
|
||||||
implementation("com.github.inorichi.injekt:injekt-core:65b0440")
|
implementation("com.github.inorichi.injekt:injekt-core:65b0440")
|
||||||
implementation("com.squareup.okhttp3:okhttp:4.9.1")
|
implementation("com.squareup.okhttp3:okhttp:4.9.1")
|
||||||
@@ -81,14 +80,13 @@ dependencies {
|
|||||||
// implementation(fileTree("lib/"))
|
// implementation(fileTree("lib/"))
|
||||||
}
|
}
|
||||||
|
|
||||||
val MainClass = "suwayomi.tachidesk.MainKt"
|
|
||||||
application {
|
application {
|
||||||
mainClass.set(MainClass)
|
mainClass.set(MainClass)
|
||||||
|
|
||||||
// for testing electron
|
// uncomment for testing electron
|
||||||
// applicationDefaultJvmArgs = listOf(
|
// applicationDefaultJvmArgs = listOf(
|
||||||
// "-Dsuwayomi.tachidesk.webInterface=electron",
|
// "-Dsuwayomi.tachidesk.config.server.webUIInterface=electron",
|
||||||
// "-Dsuwayomi.tachidesk.electronPath=/usr/bin/electron"
|
// "-Dsuwayomi.tachidesk.config.server.electronPath=/usr/bin/electron"
|
||||||
// )
|
// )
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,56 +98,40 @@ sourceSets {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// should be bumped with each stable release
|
|
||||||
val tachideskVersion = System.getenv("ProductVersion") ?: "v0.4.5"
|
|
||||||
val webUIRevisionTag = System.getenv("WebUIRevision") ?: "r23"
|
|
||||||
|
|
||||||
// counts commit count on master
|
|
||||||
val tachideskRevision = runCatching {
|
|
||||||
System.getenv("ProductRevision") ?: Runtime
|
|
||||||
.getRuntime()
|
|
||||||
.exec("git rev-list HEAD --count")
|
|
||||||
.let { process ->
|
|
||||||
process.waitFor()
|
|
||||||
val output = process.inputStream.use {
|
|
||||||
it.bufferedReader().use(BufferedReader::readText)
|
|
||||||
}
|
|
||||||
process.destroy()
|
|
||||||
"r" + output.trim()
|
|
||||||
}
|
|
||||||
}.getOrDefault("r0")
|
|
||||||
|
|
||||||
buildConfig {
|
buildConfig {
|
||||||
clsName = "BuildConfig"
|
className("BuildConfig")
|
||||||
packageName = "suwayomi.tachidesk.server"
|
packageName("suwayomi.tachidesk.server")
|
||||||
|
|
||||||
|
useKotlinOutput()
|
||||||
|
|
||||||
buildConfigField("String", "NAME", rootProject.name)
|
fun quoteWrap(obj: Any): String = """"$obj""""
|
||||||
buildConfigField("String", "VERSION", tachideskVersion)
|
|
||||||
buildConfigField("String", "REVISION", tachideskRevision)
|
buildConfigField("String", "NAME", quoteWrap(rootProject.name))
|
||||||
buildConfigField("String", "BUILD_TYPE", if (System.getenv("ProductBuildType") == "Stable") "Stable" else "Preview")
|
buildConfigField("String", "VERSION", quoteWrap(tachideskVersion))
|
||||||
|
buildConfigField("String", "REVISION", quoteWrap(tachideskRevision))
|
||||||
|
buildConfigField("String", "BUILD_TYPE", quoteWrap(if (System.getenv("ProductBuildType") == "Stable") "Stable" else "Preview"))
|
||||||
buildConfigField("long", "BUILD_TIME", Instant.now().epochSecond.toString())
|
buildConfigField("long", "BUILD_TIME", Instant.now().epochSecond.toString())
|
||||||
|
|
||||||
|
|
||||||
buildConfigField("String", "WEBUI_REPO", "https://github.com/Suwayomi/Tachidesk-WebUI-preview")
|
buildConfigField("String", "WEBUI_REPO", quoteWrap("https://github.com/Suwayomi/Tachidesk-WebUI-preview"))
|
||||||
buildConfigField("String", "WEBUI_TAG", webUIRevisionTag)
|
buildConfigField("String", "WEBUI_TAG", quoteWrap(webUIRevisionTag))
|
||||||
|
|
||||||
|
|
||||||
buildConfigField("String", "GITHUB", "https://github.com/Suwayomi/Tachidesk")
|
buildConfigField("String", "GITHUB", quoteWrap("https://github.com/Suwayomi/Tachidesk"))
|
||||||
buildConfigField("String", "DISCORD", "https://discord.gg/DDZdqZWaHA")
|
buildConfigField("String", "DISCORD", quoteWrap("https://discord.gg/DDZdqZWaHA"))
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks {
|
tasks {
|
||||||
shadowJar {
|
shadowJar {
|
||||||
manifest {
|
manifest {
|
||||||
attributes(
|
attributes(
|
||||||
mapOf(
|
mapOf(
|
||||||
"Main-Class" to MainClass,
|
"Main-Class" to MainClass,
|
||||||
"Implementation-Title" to rootProject.name,
|
"Implementation-Title" to rootProject.name,
|
||||||
"Implementation-Vendor" to "The Suwayomi Project",
|
"Implementation-Vendor" to "The Suwayomi Project",
|
||||||
"Specification-Version" to tachideskVersion,
|
"Specification-Version" to tachideskVersion,
|
||||||
"Implementation-Version" to tachideskRevision
|
"Implementation-Version" to tachideskRevision
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
archiveBaseName.set(rootProject.name)
|
archiveBaseName.set(rootProject.name)
|
||||||
@@ -159,9 +141,9 @@ tasks {
|
|||||||
withType<KotlinCompile> {
|
withType<KotlinCompile> {
|
||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
freeCompilerArgs = listOf(
|
freeCompilerArgs = listOf(
|
||||||
"-Xopt-in=kotlin.RequiresOptIn",
|
"-Xopt-in=kotlin.RequiresOptIn",
|
||||||
"-Xopt-in=kotlinx.coroutines.ExperimentalCoroutinesApi",
|
"-Xopt-in=kotlinx.coroutines.ExperimentalCoroutinesApi",
|
||||||
"-Xopt-in=kotlinx.coroutines.InternalCoroutinesApi"
|
"-Xopt-in=kotlinx.coroutines.InternalCoroutinesApi"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -175,7 +157,7 @@ tasks {
|
|||||||
}
|
}
|
||||||
|
|
||||||
named("run") {
|
named("run") {
|
||||||
dependsOn("formatKotlin", "lintKotlin")
|
dependsOn("formatKotlin", "lintKotlin", "downloadWebUI")
|
||||||
}
|
}
|
||||||
|
|
||||||
named<Copy>("processResources") {
|
named<Copy>("processResources") {
|
||||||
@@ -186,6 +168,26 @@ tasks {
|
|||||||
register<de.undercouch.gradle.tasks.download.Download>("downloadWebUI") {
|
register<de.undercouch.gradle.tasks.download.Download>("downloadWebUI") {
|
||||||
src("https://github.com/Suwayomi/Tachidesk-WebUI-preview/releases/download/$webUIRevisionTag/Tachidesk-WebUI-$webUIRevisionTag.zip")
|
src("https://github.com/Suwayomi/Tachidesk-WebUI-preview/releases/download/$webUIRevisionTag/Tachidesk-WebUI-$webUIRevisionTag.zip")
|
||||||
dest("src/main/resources/WebUI.zip")
|
dest("src/main/resources/WebUI.zip")
|
||||||
|
|
||||||
|
|
||||||
|
fun shouldOverwrite(): Boolean {
|
||||||
|
val zipPath = project.projectDir.absolutePath + "/src/main/resources/WebUI.zip"
|
||||||
|
val zipFile = net.lingala.zip4j.ZipFile(zipPath)
|
||||||
|
|
||||||
|
var shouldOverwrite = true
|
||||||
|
if (zipFile.isValidZipFile) {
|
||||||
|
val zipRevision = zipFile.getInputStream(zipFile.getFileHeader("revision")).bufferedReader().use {
|
||||||
|
it.readText().trim()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (zipRevision == webUIRevisionTag)
|
||||||
|
shouldOverwrite = false
|
||||||
|
}
|
||||||
|
|
||||||
|
return shouldOverwrite
|
||||||
|
}
|
||||||
|
|
||||||
|
overwrite(shouldOverwrite())
|
||||||
}
|
}
|
||||||
|
|
||||||
withType<LintTask> {
|
withType<LintTask> {
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ abstract class AnimeHttpSource : AnimeCatalogueSource {
|
|||||||
* Note the generated id sets the sign bit to 0.
|
* Note the generated id sets the sign bit to 0.
|
||||||
*/
|
*/
|
||||||
override val id by lazy {
|
override val id by lazy {
|
||||||
val key = "${name.toLowerCase()}/$lang/$versionId"
|
val key = "${name.lowercase()}/$lang/$versionId"
|
||||||
val bytes = MessageDigest.getInstance("MD5").digest(key.toByteArray())
|
val bytes = MessageDigest.getInstance("MD5").digest(key.toByteArray())
|
||||||
(0..7).map { bytes[it].toLong() and 0xff shl 8 * (7 - it) }.reduce(Long::or) and Long.MAX_VALUE
|
(0..7).map { bytes[it].toLong() and 0xff shl 8 * (7 - it) }.reduce(Long::or) and Long.MAX_VALUE
|
||||||
}
|
}
|
||||||
@@ -80,7 +80,7 @@ abstract class AnimeHttpSource : AnimeCatalogueSource {
|
|||||||
/**
|
/**
|
||||||
* Visible name of the source.
|
* Visible name of the source.
|
||||||
*/
|
*/
|
||||||
override fun toString() = "$name (${lang.toUpperCase()})"
|
override fun toString() = "$name (${lang.uppercase()})"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an observable containing a page with a list of anime. Normally it's not needed to
|
* Returns an observable containing a page with a list of anime. Normally it's not needed to
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import okhttp3.OkHttpClient
|
|||||||
// import uy.kohesive.injekt.injectLazy
|
// import uy.kohesive.injekt.injectLazy
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
@Suppress("UNUSED_PARAMETER")
|
||||||
class NetworkHelper(context: Context) {
|
class NetworkHelper(context: Context) {
|
||||||
|
|
||||||
// private val preferences: PreferencesHelper by injectLazy()
|
// private val preferences: PreferencesHelper by injectLazy()
|
||||||
|
|||||||
@@ -110,6 +110,7 @@ fun Call.asObservableSuccess(): Observable<Response> {
|
|||||||
// return progressClient.newCall(request)
|
// return progressClient.newCall(request)
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
@Suppress("UNUSED_PARAMETER")
|
||||||
fun OkHttpClient.newCallWithProgress(request: Request, listener: ProgressListener): Call {
|
fun OkHttpClient.newCallWithProgress(request: Request, listener: ProgressListener): Call {
|
||||||
val progressClient = newBuilder()
|
val progressClient = newBuilder()
|
||||||
// .cache(null)
|
// .cache(null)
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ abstract class HttpSource : CatalogueSource {
|
|||||||
* Note the generated id sets the sign bit to 0.
|
* Note the generated id sets the sign bit to 0.
|
||||||
*/
|
*/
|
||||||
override val id by lazy {
|
override val id by lazy {
|
||||||
val key = "${name.toLowerCase()}/$lang/$versionId"
|
val key = "${name.lowercase()}/$lang/$versionId"
|
||||||
val bytes = MessageDigest.getInstance("MD5").digest(key.toByteArray())
|
val bytes = MessageDigest.getInstance("MD5").digest(key.toByteArray())
|
||||||
(0..7).map { bytes[it].toLong() and 0xff shl 8 * (7 - it) }.reduce(Long::or) and Long.MAX_VALUE
|
(0..7).map { bytes[it].toLong() and 0xff shl 8 * (7 - it) }.reduce(Long::or) and Long.MAX_VALUE
|
||||||
}
|
}
|
||||||
@@ -81,7 +81,7 @@ abstract class HttpSource : CatalogueSource {
|
|||||||
/**
|
/**
|
||||||
* Visible name of the source.
|
* Visible name of the source.
|
||||||
*/
|
*/
|
||||||
override fun toString() = "$name (${lang.toUpperCase()})"
|
override fun toString() = "$name (${lang.uppercase()})"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an observable containing a page with a list of manga. Normally it's not needed to
|
* Returns an observable containing a page with a list of manga. Normally it's not needed to
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import suwayomi.tachidesk.anime.impl.AnimeList.getAnimeList
|
|||||||
import suwayomi.tachidesk.anime.impl.Episode.getEpisode
|
import suwayomi.tachidesk.anime.impl.Episode.getEpisode
|
||||||
import suwayomi.tachidesk.anime.impl.Episode.getEpisodeList
|
import suwayomi.tachidesk.anime.impl.Episode.getEpisodeList
|
||||||
import suwayomi.tachidesk.anime.impl.Episode.modifyEpisode
|
import suwayomi.tachidesk.anime.impl.Episode.modifyEpisode
|
||||||
|
import suwayomi.tachidesk.anime.impl.Search.sourceSearch
|
||||||
import suwayomi.tachidesk.anime.impl.Source.getAnimeSource
|
import suwayomi.tachidesk.anime.impl.Source.getAnimeSource
|
||||||
import suwayomi.tachidesk.anime.impl.Source.getSourceList
|
import suwayomi.tachidesk.anime.impl.Source.getSourceList
|
||||||
import suwayomi.tachidesk.anime.impl.extension.Extension.getExtensionIcon
|
import suwayomi.tachidesk.anime.impl.extension.Extension.getExtensionIcon
|
||||||
@@ -219,13 +220,13 @@ object AnimeAPI {
|
|||||||
// ctx.json(sourceGlobalSearch(searchTerm))
|
// ctx.json(sourceGlobalSearch(searchTerm))
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// // single source search
|
// single source search
|
||||||
// app.get("/api/v1/source/:sourceId/search/:searchTerm/:pageNum") { ctx ->
|
app.get("/api/v1/anime/source/:sourceId/search/:searchTerm/:pageNum") { ctx ->
|
||||||
// val sourceId = ctx.pathParam("sourceId").toLong()
|
val sourceId = ctx.pathParam("sourceId").toLong()
|
||||||
// val searchTerm = ctx.pathParam("searchTerm")
|
val searchTerm = ctx.pathParam("searchTerm")
|
||||||
// val pageNum = ctx.pathParam("pageNum").toInt()
|
val pageNum = ctx.pathParam("pageNum").toInt()
|
||||||
// ctx.json(JavalinSetup.future { sourceSearch(sourceId, searchTerm, pageNum) })
|
ctx.json(future { sourceSearch(sourceId, searchTerm, pageNum) })
|
||||||
// }
|
}
|
||||||
//
|
//
|
||||||
// // source filter list
|
// // source filter list
|
||||||
// app.get("/api/v1/source/:sourceId/filters/") { ctx ->
|
// app.get("/api/v1/source/:sourceId/filters/") { ctx ->
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package suwayomi.tachidesk.anime.impl
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) Contributors to the Suwayomi project
|
||||||
|
*
|
||||||
|
* 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 suwayomi.tachidesk.anime.impl.AnimeList.processEntries
|
||||||
|
import suwayomi.tachidesk.anime.impl.util.GetAnimeHttpSource.getAnimeHttpSource
|
||||||
|
import suwayomi.tachidesk.anime.model.dataclass.PagedAnimeListDataClass
|
||||||
|
import suwayomi.tachidesk.manga.impl.util.lang.awaitSingle
|
||||||
|
|
||||||
|
object Search {
|
||||||
|
suspend fun sourceSearch(sourceId: Long, searchTerm: String, pageNum: Int): PagedAnimeListDataClass {
|
||||||
|
val source = getAnimeHttpSource(sourceId)
|
||||||
|
val searchManga = source.fetchSearchAnime(pageNum, searchTerm, source.getFilterList()).awaitSingle()
|
||||||
|
return searchManga.processEntries(sourceId)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -138,7 +138,7 @@ object Extension {
|
|||||||
else -> "all"
|
else -> "all"
|
||||||
}
|
}
|
||||||
|
|
||||||
val extensionName = packageInfo.applicationInfo.nonLocalizedLabel.toString().substringAfter("Tachiyomi: ")
|
val extensionName = packageInfo.applicationInfo.nonLocalizedLabel.toString().substringAfter("Aniyomi: ")
|
||||||
|
|
||||||
// update extension info
|
// update extension info
|
||||||
transaction {
|
transaction {
|
||||||
|
|||||||
+1
-1
@@ -32,7 +32,7 @@ object ExtensionGithubApi {
|
|||||||
libVersion in LIB_VERSION_MIN..LIB_VERSION_MAX
|
libVersion in LIB_VERSION_MIN..LIB_VERSION_MAX
|
||||||
}
|
}
|
||||||
.map { element ->
|
.map { element ->
|
||||||
val name = element["name"].string.substringAfter("Tachiyomi: ")
|
val name = element["name"].string.substringAfter("Aniyomi: ")
|
||||||
val pkgName = element["pkg"].string
|
val pkgName = element["pkg"].string
|
||||||
val apkName = element["apk"].string
|
val apkName = element["apk"].string
|
||||||
val versionName = element["version"].string
|
val versionName = element["version"].string
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ package suwayomi.tachidesk.manga
|
|||||||
* 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 io.javalin.Javalin
|
|
||||||
import io.javalin.apibuilder.ApiBuilder.delete
|
import io.javalin.apibuilder.ApiBuilder.delete
|
||||||
import io.javalin.apibuilder.ApiBuilder.get
|
import io.javalin.apibuilder.ApiBuilder.get
|
||||||
import io.javalin.apibuilder.ApiBuilder.patch
|
import io.javalin.apibuilder.ApiBuilder.patch
|
||||||
@@ -22,7 +21,7 @@ import suwayomi.tachidesk.manga.controller.MangaController
|
|||||||
import suwayomi.tachidesk.manga.controller.SourceController
|
import suwayomi.tachidesk.manga.controller.SourceController
|
||||||
|
|
||||||
object MangaAPI {
|
object MangaAPI {
|
||||||
fun defineEndpoints(app: Javalin) {
|
fun defineEndpoints() {
|
||||||
path("extension") {
|
path("extension") {
|
||||||
get("list", ExtensionController::list)
|
get("list", ExtensionController::list)
|
||||||
|
|
||||||
@@ -82,7 +81,7 @@ object MangaAPI {
|
|||||||
patch(":categoryId", LibraryController::categoryModify)
|
patch(":categoryId", LibraryController::categoryModify)
|
||||||
delete(":categoryId", LibraryController::categoryDelete)
|
delete(":categoryId", LibraryController::categoryDelete)
|
||||||
|
|
||||||
patch(":categoryId/reorder", LibraryController::categoryReorder)
|
patch(":categoryId/reorder", LibraryController::categoryReorder) // TODO: the underlying code doesn't need `:categoryId`, remove it
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -54,10 +54,9 @@ object LibraryController {
|
|||||||
|
|
||||||
/** category re-ordering */
|
/** category re-ordering */
|
||||||
fun categoryReorder(ctx: Context) {
|
fun categoryReorder(ctx: Context) {
|
||||||
val categoryId = ctx.pathParam("categoryId").toInt()
|
|
||||||
val from = ctx.formParam("from")!!.toInt()
|
val from = ctx.formParam("from")!!.toInt()
|
||||||
val to = ctx.formParam("to")!!.toInt()
|
val to = ctx.formParam("to")!!.toInt()
|
||||||
Category.reorderCategory(categoryId, from, to)
|
Category.reorderCategory(from, to)
|
||||||
ctx.status(200)
|
ctx.status(200)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ object MangaController {
|
|||||||
fun chapterList(ctx: Context) {
|
fun chapterList(ctx: Context) {
|
||||||
val mangaId = ctx.pathParam("mangaId").toInt()
|
val mangaId = ctx.pathParam("mangaId").toInt()
|
||||||
|
|
||||||
val onlineFetch = ctx.queryParam("onlineFetch")?.toBoolean()
|
val onlineFetch = ctx.queryParam("onlineFetch", "false").toBoolean()
|
||||||
|
|
||||||
ctx.json(future { Chapter.getChapterList(mangaId, onlineFetch) })
|
ctx.json(future { Chapter.getChapterList(mangaId, onlineFetch) })
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ object Category {
|
|||||||
/**
|
/**
|
||||||
* Move the category from position `from` to `to`
|
* Move the category from position `from` to `to`
|
||||||
*/
|
*/
|
||||||
fun reorderCategory(categoryId: Int, from: Int, to: Int) {
|
fun reorderCategory(from: Int, to: Int) {
|
||||||
transaction {
|
transaction {
|
||||||
val categories = CategoryTable.selectAll().orderBy(CategoryTable.order to SortOrder.ASC).toMutableList()
|
val categories = CategoryTable.selectAll().orderBy(CategoryTable.order to SortOrder.ASC).toMutableList()
|
||||||
categories.add(to - 1, categories.removeAt(from - 1))
|
categories.add(to - 1, categories.removeAt(from - 1))
|
||||||
|
|||||||
@@ -30,8 +30,8 @@ import java.time.Instant
|
|||||||
|
|
||||||
object Chapter {
|
object Chapter {
|
||||||
/** get chapter list when showing a manga */
|
/** get chapter list when showing a manga */
|
||||||
suspend fun getChapterList(mangaId: Int, onlineFetch: Boolean?): List<ChapterDataClass> {
|
suspend fun getChapterList(mangaId: Int, onlineFetch: Boolean = false): List<ChapterDataClass> {
|
||||||
return if (onlineFetch == true) {
|
return if (onlineFetch) {
|
||||||
getSourceChapters(mangaId)
|
getSourceChapters(mangaId)
|
||||||
} else {
|
} else {
|
||||||
transaction {
|
transaction {
|
||||||
@@ -40,10 +40,7 @@ object Chapter {
|
|||||||
ChapterTable.toDataClass(it)
|
ChapterTable.toDataClass(it)
|
||||||
}
|
}
|
||||||
}.ifEmpty {
|
}.ifEmpty {
|
||||||
// If it was explicitly set to offline dont grab chapters
|
getSourceChapters(mangaId)
|
||||||
if (onlineFetch == null) {
|
|
||||||
getSourceChapters(mangaId)
|
|
||||||
} else emptyList()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -163,7 +160,10 @@ object Chapter {
|
|||||||
// update page list for this chapter
|
// update page list for this chapter
|
||||||
transaction {
|
transaction {
|
||||||
pageList.forEach { page ->
|
pageList.forEach { page ->
|
||||||
val pageEntry = transaction { PageTable.select { (PageTable.chapter eq chapterId) and (PageTable.index eq page.index) }.firstOrNull() }
|
val pageEntry = transaction {
|
||||||
|
PageTable.select { (PageTable.chapter eq chapterId) and (PageTable.index eq page.index) }
|
||||||
|
.firstOrNull()
|
||||||
|
}
|
||||||
if (pageEntry == null) {
|
if (pageEntry == null) {
|
||||||
PageTable.insert {
|
PageTable.insert {
|
||||||
it[index] = page.index
|
it[index] = page.index
|
||||||
@@ -210,7 +210,14 @@ object Chapter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun modifyChapter(mangaId: Int, chapterIndex: Int, isRead: Boolean?, isBookmarked: Boolean?, markPrevRead: Boolean?, lastPageRead: Int?) {
|
fun modifyChapter(
|
||||||
|
mangaId: Int,
|
||||||
|
chapterIndex: Int,
|
||||||
|
isRead: Boolean?,
|
||||||
|
isBookmarked: Boolean?,
|
||||||
|
markPrevRead: Boolean?,
|
||||||
|
lastPageRead: Int?
|
||||||
|
) {
|
||||||
transaction {
|
transaction {
|
||||||
if (listOf(isRead, isBookmarked, lastPageRead).any { it != null }) {
|
if (listOf(isRead, isBookmarked, lastPageRead).any { it != null }) {
|
||||||
ChapterTable.update({ (ChapterTable.manga eq mangaId) and (ChapterTable.chapterIndex eq chapterIndex) }) { update ->
|
ChapterTable.update({ (ChapterTable.manga eq mangaId) and (ChapterTable.chapterIndex eq chapterIndex) }) { update ->
|
||||||
@@ -244,9 +251,11 @@ object Chapter {
|
|||||||
|
|
||||||
fun modifyChapterMeta(mangaId: Int, chapterIndex: Int, key: String, value: String) {
|
fun modifyChapterMeta(mangaId: Int, chapterIndex: Int, key: String, value: String) {
|
||||||
transaction {
|
transaction {
|
||||||
val chapter = ChapterTable.select { (ChapterTable.manga eq mangaId) and (ChapterTable.chapterIndex eq chapterIndex) }
|
val chapter =
|
||||||
.first()[ChapterTable.id]
|
ChapterTable.select { (ChapterTable.manga eq mangaId) and (ChapterTable.chapterIndex eq chapterIndex) }
|
||||||
val meta = transaction { ChapterMetaTable.select { (ChapterMetaTable.ref eq chapter) and (ChapterMetaTable.key eq key) } }.firstOrNull()
|
.first()[ChapterTable.id]
|
||||||
|
val meta =
|
||||||
|
transaction { ChapterMetaTable.select { (ChapterMetaTable.ref eq chapter) and (ChapterMetaTable.key eq key) } }.firstOrNull()
|
||||||
if (meta == null) {
|
if (meta == null) {
|
||||||
ChapterMetaTable.insert {
|
ChapterMetaTable.insert {
|
||||||
it[ChapterMetaTable.key] = key
|
it[ChapterMetaTable.key] = key
|
||||||
|
|||||||
@@ -13,22 +13,25 @@ import suwayomi.tachidesk.manga.impl.util.lang.awaitSingle
|
|||||||
import suwayomi.tachidesk.manga.model.dataclass.PagedMangaListDataClass
|
import suwayomi.tachidesk.manga.model.dataclass.PagedMangaListDataClass
|
||||||
|
|
||||||
object Search {
|
object Search {
|
||||||
// TODO
|
|
||||||
fun sourceFilters(sourceId: Long) {
|
|
||||||
val source = getHttpSource(sourceId)
|
|
||||||
// source.getFilterList().toItems()
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun sourceSearch(sourceId: Long, searchTerm: String, pageNum: Int): PagedMangaListDataClass {
|
suspend fun sourceSearch(sourceId: Long, searchTerm: String, pageNum: Int): PagedMangaListDataClass {
|
||||||
val source = getHttpSource(sourceId)
|
val source = getHttpSource(sourceId)
|
||||||
val searchManga = source.fetchSearchManga(pageNum, searchTerm, source.getFilterList()).awaitSingle()
|
val searchManga = source.fetchSearchManga(pageNum, searchTerm, source.getFilterList()).awaitSingle()
|
||||||
return searchManga.processEntries(sourceId)
|
return searchManga.processEntries(sourceId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
@Suppress("UNUSED_PARAMETER", "UNUSED_VARIABLE")
|
||||||
|
fun sourceFilters(sourceId: Long) {
|
||||||
|
val source = getHttpSource(sourceId)
|
||||||
|
// source.getFilterList().toItems()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("UNUSED_PARAMETER")
|
||||||
fun sourceGlobalSearch(searchTerm: String) {
|
fun sourceGlobalSearch(searchTerm: String) {
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("unused")
|
||||||
data class FilterWrapper(
|
data class FilterWrapper(
|
||||||
val type: String,
|
val type: String,
|
||||||
val filter: Any
|
val filter: Any
|
||||||
|
|||||||
+2
@@ -141,6 +141,7 @@ object LegacyBackupImport : LegacyBackupBase() {
|
|||||||
* @param history history data from json
|
* @param history history data from json
|
||||||
* @param tracks tracking data from json
|
* @param tracks tracking data from json
|
||||||
*/
|
*/
|
||||||
|
@Suppress("UNUSED_PARAMETER")
|
||||||
private suspend fun restoreMangaData(
|
private suspend fun restoreMangaData(
|
||||||
manga: Manga,
|
manga: Manga,
|
||||||
source: Source,
|
source: Source,
|
||||||
@@ -204,6 +205,7 @@ object LegacyBackupImport : LegacyBackupBase() {
|
|||||||
return fetchedManga
|
return fetchedManga
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("UNUSED_PARAMETER") // TODO: remove this suppress when update Chapters is written
|
||||||
private fun updateChapters(source: Source, fetchedManga: SManga, chapters: List<Chapter>) {
|
private fun updateChapters(source: Source, fetchedManga: SManga, chapters: List<Chapter>) {
|
||||||
// TODO("Not yet implemented")
|
// TODO("Not yet implemented")
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-5
@@ -42,11 +42,11 @@ object LegacyBackupValidator {
|
|||||||
.sorted()
|
.sorted()
|
||||||
}
|
}
|
||||||
|
|
||||||
val trackers = mangas
|
// val trackers = mangas
|
||||||
.filter { it.asJsonObject.has("track") }
|
// .filter { it.asJsonObject.has("track") }
|
||||||
.flatMap { it.asJsonObject["track"].asJsonArray }
|
// .flatMap { it.asJsonObject["track"].asJsonArray }
|
||||||
.map { it.asJsonObject["s"].asInt }
|
// .map { it.asJsonObject["s"].asInt }
|
||||||
.distinct()
|
// .distinct()
|
||||||
|
|
||||||
val missingTrackers = listOf("")
|
val missingTrackers = listOf("")
|
||||||
// val missingTrackers = trackers
|
// val missingTrackers = trackers
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ object BytecodeEditor {
|
|||||||
bytes[2],
|
bytes[2],
|
||||||
bytes[3]
|
bytes[3]
|
||||||
)
|
)
|
||||||
if (cafebabe.toLowerCase() != "cafebabe") {
|
if (cafebabe.lowercase() != "cafebabe") {
|
||||||
// Corrupted class
|
// Corrupted class
|
||||||
return@use null
|
return@use null
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ object JavalinSetup {
|
|||||||
app.routes {
|
app.routes {
|
||||||
path("api/v1/") {
|
path("api/v1/") {
|
||||||
GlobalAPI.defineEndpoints()
|
GlobalAPI.defineEndpoints()
|
||||||
MangaAPI.defineEndpoints(app)
|
MangaAPI.defineEndpoints()
|
||||||
AnimeAPI.defineEndpoints(app) // TODO: migrate Anime endpoints
|
AnimeAPI.defineEndpoints(app) // TODO: migrate Anime endpoints
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ class ServerConfig(config: Config, moduleName: String = "") : ConfigModule(confi
|
|||||||
// webUI
|
// webUI
|
||||||
val webUIEnabled: Boolean by overridableWithSysProperty
|
val webUIEnabled: Boolean by overridableWithSysProperty
|
||||||
val initialOpenInBrowserEnabled: Boolean by overridableWithSysProperty
|
val initialOpenInBrowserEnabled: Boolean by overridableWithSysProperty
|
||||||
val webUIBrowser: String by overridableWithSysProperty
|
val webUIInterface: String by overridableWithSysProperty
|
||||||
val electronPath: String by overridableWithSysProperty
|
val electronPath: String by overridableWithSysProperty
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ object Browser {
|
|||||||
|
|
||||||
fun openInBrowser() {
|
fun openInBrowser() {
|
||||||
if (serverConfig.webUIEnabled) {
|
if (serverConfig.webUIEnabled) {
|
||||||
if (serverConfig.webUIBrowser == ("electron")) {
|
if (serverConfig.webUIInterface == ("electron")) {
|
||||||
try {
|
try {
|
||||||
val electronPath = serverConfig.electronPath
|
val electronPath = serverConfig.electronPath
|
||||||
electronInstances.add(ProcessBuilder(electronPath, appBaseUrl).start())
|
electronInstances.add(ProcessBuilder(electronPath, appBaseUrl).start())
|
||||||
|
|||||||
@@ -14,8 +14,9 @@ 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 java.io.BufferedInputStream
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.io.InputStream
|
||||||
|
import java.net.HttpURLConnection
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
import java.nio.charset.StandardCharsets
|
import java.nio.charset.StandardCharsets
|
||||||
import java.security.MessageDigest
|
import java.security.MessageDigest
|
||||||
@@ -58,9 +59,12 @@ fun setupWebUI() {
|
|||||||
val webUIZipFile = File(webUIZipPath)
|
val webUIZipFile = File(webUIZipPath)
|
||||||
|
|
||||||
// try with resources first
|
// try with resources first
|
||||||
val resourceWebUI = try {
|
val resourceWebUI: InputStream? = try {
|
||||||
BuildConfig::class.java.getResourceAsStream("/WebUI.zip")
|
BuildConfig::class.java.getResourceAsStream("/WebUI.zip")
|
||||||
} catch (e: NullPointerException) { null }
|
} catch (e: NullPointerException) {
|
||||||
|
logger.info { "No bundled WebUI.zip found!" }
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
if (resourceWebUI == null) { // is not bundled
|
if (resourceWebUI == null) { // is not bundled
|
||||||
// download webUI zip
|
// download webUI zip
|
||||||
@@ -71,18 +75,25 @@ fun setupWebUI() {
|
|||||||
val data = ByteArray(1024)
|
val data = ByteArray(1024)
|
||||||
|
|
||||||
webUIZipFile.outputStream().use { webUIZipFileOut ->
|
webUIZipFile.outputStream().use { webUIZipFileOut ->
|
||||||
BufferedInputStream(URL(webUIZipURL).openStream()).use { inp ->
|
|
||||||
|
val connection = URL(webUIZipURL).openConnection() as HttpURLConnection
|
||||||
|
connection.connect()
|
||||||
|
val contentLength = connection.contentLength
|
||||||
|
|
||||||
|
connection.inputStream.buffered().use { inp ->
|
||||||
var totalCount = 0
|
var totalCount = 0
|
||||||
var tresh = 0
|
|
||||||
|
print("Download progress: % 00")
|
||||||
while (true) {
|
while (true) {
|
||||||
val count = inp.read(data, 0, 1024)
|
val count = inp.read(data, 0, 1024)
|
||||||
totalCount += count
|
|
||||||
if (totalCount > tresh + 10 * 1024) {
|
|
||||||
tresh = totalCount
|
|
||||||
print(" *")
|
|
||||||
}
|
|
||||||
if (count == -1)
|
if (count == -1)
|
||||||
break
|
break
|
||||||
|
|
||||||
|
totalCount += count
|
||||||
|
val percentage = (totalCount.toFloat() / contentLength * 100).toInt().toString().padStart(2, '0')
|
||||||
|
print("\b\b$percentage")
|
||||||
|
|
||||||
webUIZipFileOut.write(data, 0, count)
|
webUIZipFileOut.write(data, 0, count)
|
||||||
}
|
}
|
||||||
println()
|
println()
|
||||||
|
|||||||
@@ -14,5 +14,5 @@ server.systemTrayEnabled = true
|
|||||||
# webUI
|
# webUI
|
||||||
server.webUIEnabled = true
|
server.webUIEnabled = true
|
||||||
server.initialOpenInBrowserEnabled = true
|
server.initialOpenInBrowserEnabled = true
|
||||||
server.webUIBrowser = "browser" # "browser" or "electron"
|
server.webUIInterface = "browser" # "browser" or "electron"
|
||||||
server.electronPath = ""
|
server.electronPath = ""
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ class TestExtensions {
|
|||||||
sources = getSourceList().map { getHttpSource(it.id.toLong()) }
|
sources = getSourceList().map { getHttpSource(it.id.toLong()) }
|
||||||
}
|
}
|
||||||
setLoggingEnabled(true)
|
setLoggingEnabled(true)
|
||||||
File("tmp/TestDesk/sources.txt").writeText(sources.joinToString("\n") { "${it.name} - ${it.lang.toUpperCase()} - ${it.id}" })
|
File("tmp/TestDesk/sources.txt").writeText(sources.joinToString("\n") { "${it.name} - ${it.lang.uppercase()} - ${it.id}" })
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -99,7 +99,7 @@ class TestExtensions {
|
|||||||
}.awaitAll()
|
}.awaitAll()
|
||||||
File("tmp/TestDesk/failedToFetch.txt").writeText(
|
File("tmp/TestDesk/failedToFetch.txt").writeText(
|
||||||
failedToFetch.joinToString("\n") { (source, exception) ->
|
failedToFetch.joinToString("\n") { (source, exception) ->
|
||||||
"${source.name} (${source.lang.toUpperCase()}, ${source.id}):" +
|
"${source.name} (${source.lang.uppercase()}, ${source.id}):" +
|
||||||
" ${exception.message}"
|
" ${exception.message}"
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user