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
|
||||
implementation(fileTree("lib/"))
|
||||
|
||||
|
||||
// Android JAR libs
|
||||
// compileOnly( fileTree(dir: new File(rootProject.rootDir, "libs/other"), include: "*.jar")
|
||||
|
||||
// JSON
|
||||
compileOnly("com.google.code.gson:gson:2.8.6")
|
||||
|
||||
// Javassist
|
||||
compileOnly("org.javassist:javassist:3.27.0-GA")
|
||||
|
||||
// XML
|
||||
compileOnly(group= "xmlpull", name= "xmlpull", version= "1.1.3.1")
|
||||
|
||||
@@ -43,10 +36,8 @@ dependencies {
|
||||
compileOnly("androidx.annotation:annotation:1.2.0-alpha01")
|
||||
|
||||
// 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")
|
||||
// 'org.mozilla:rhino-engine' provides the same interface as 'javax.script' a.k.a Nashorn
|
||||
implementation("org.mozilla:rhino-engine:1.7.13")
|
||||
implementation("org.mozilla:rhino-runtime:1.7.13") // slimmer version of 'org.mozilla:rhino'
|
||||
implementation("org.mozilla:rhino-engine:1.7.13") // provides the same interface as 'javax.script' a.k.a Nashorn
|
||||
|
||||
// Kotlin wrapper around Java Preferences, makes certain things easier
|
||||
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.conf.global
|
||||
import xyz.nulldev.androidcompat.bytecode.ModApplier
|
||||
import xyz.nulldev.androidcompat.config.ApplicationInfoConfigModule
|
||||
import xyz.nulldev.androidcompat.config.FilesConfigModule
|
||||
import xyz.nulldev.androidcompat.config.SystemConfigModule
|
||||
@@ -12,12 +11,7 @@ import xyz.nulldev.ts.config.GlobalConfigManager
|
||||
* Initializes the Android compatibility module
|
||||
*/
|
||||
class AndroidCompatInitializer {
|
||||
|
||||
val modApplier by lazy { ModApplier() }
|
||||
|
||||
fun init() {
|
||||
modApplier.apply()
|
||||
|
||||
DI.global.addImport(AndroidCompatModule().create())
|
||||
|
||||
//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.math.BigDecimal
|
||||
import java.net.URL
|
||||
import java.sql.*
|
||||
import java.sql.Array
|
||||
import java.sql.Blob
|
||||
import java.sql.Clob
|
||||
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 {
|
||||
|
||||
private val cachedContent = mutableListOf<ResultSetEntry>()
|
||||
|
||||
@@ -18,7 +18,7 @@ class ServiceSupport {
|
||||
|
||||
private val logger = KotlinLogging.logger {}
|
||||
|
||||
fun startService(context: Context, intent: Intent) {
|
||||
fun startService(@Suppress("UNUSED_PARAMETER") context: Context, intent: Intent) {
|
||||
val name = intentToClassName(intent)
|
||||
|
||||
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)
|
||||
stopService(name)
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ object KodeinGlobalHelper {
|
||||
* Get a dependency
|
||||
*/
|
||||
@JvmStatic
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <T : Any> instance(type: Class<T>, kodein: DI? = null): T {
|
||||
return when(type) {
|
||||
AndroidFiles::class.java -> {
|
||||
|
||||
+5
-4
@@ -1,8 +1,8 @@
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||
|
||||
plugins {
|
||||
kotlin("jvm") version "1.4.32"
|
||||
kotlin("plugin.serialization") version "1.4.32" apply false
|
||||
kotlin("jvm") version kotlinVersion
|
||||
kotlin("plugin.serialization") version kotlinVersion
|
||||
}
|
||||
|
||||
allprojects {
|
||||
@@ -46,12 +46,12 @@ configure(projects) {
|
||||
testImplementation(kotlin("test-junit5"))
|
||||
|
||||
// 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-jdk8:$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-protobuf:$kotlinSerializationVersion")
|
||||
|
||||
@@ -80,6 +80,7 @@ configure(projects) {
|
||||
implementation("net.harawata:appdirs:1.2.1")
|
||||
|
||||
// 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")
|
||||
|
||||
// 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
|
||||
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
|
||||
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 org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||
import org.jmailen.gradle.kotlinter.tasks.FormatTask
|
||||
import org.jmailen.gradle.kotlinter.tasks.LintTask
|
||||
import java.io.BufferedReader
|
||||
import java.time.Instant
|
||||
|
||||
plugins {
|
||||
application
|
||||
id("com.github.johnrengelman.shadow") version "7.0.0"
|
||||
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 {
|
||||
@@ -53,7 +53,6 @@ dependencies {
|
||||
implementation("com.dorkbox:Utilities:1.9")
|
||||
|
||||
|
||||
|
||||
// dependencies of Tachiyomi extensions, some are duplicate, keeping it here for reference
|
||||
implementation("com.github.inorichi.injekt:injekt-core:65b0440")
|
||||
implementation("com.squareup.okhttp3:okhttp:4.9.1")
|
||||
@@ -81,14 +80,13 @@ dependencies {
|
||||
// implementation(fileTree("lib/"))
|
||||
}
|
||||
|
||||
val MainClass = "suwayomi.tachidesk.MainKt"
|
||||
application {
|
||||
mainClass.set(MainClass)
|
||||
|
||||
// for testing electron
|
||||
// uncomment for testing electron
|
||||
// applicationDefaultJvmArgs = listOf(
|
||||
// "-Dsuwayomi.tachidesk.webInterface=electron",
|
||||
// "-Dsuwayomi.tachidesk.electronPath=/usr/bin/electron"
|
||||
// "-Dsuwayomi.tachidesk.config.server.webUIInterface=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 {
|
||||
clsName = "BuildConfig"
|
||||
packageName = "suwayomi.tachidesk.server"
|
||||
className("BuildConfig")
|
||||
packageName("suwayomi.tachidesk.server")
|
||||
|
||||
useKotlinOutput()
|
||||
|
||||
buildConfigField("String", "NAME", rootProject.name)
|
||||
buildConfigField("String", "VERSION", tachideskVersion)
|
||||
buildConfigField("String", "REVISION", tachideskRevision)
|
||||
buildConfigField("String", "BUILD_TYPE", if (System.getenv("ProductBuildType") == "Stable") "Stable" else "Preview")
|
||||
fun quoteWrap(obj: Any): String = """"$obj""""
|
||||
|
||||
buildConfigField("String", "NAME", quoteWrap(rootProject.name))
|
||||
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("String", "WEBUI_REPO", "https://github.com/Suwayomi/Tachidesk-WebUI-preview")
|
||||
buildConfigField("String", "WEBUI_TAG", webUIRevisionTag)
|
||||
buildConfigField("String", "WEBUI_REPO", quoteWrap("https://github.com/Suwayomi/Tachidesk-WebUI-preview"))
|
||||
buildConfigField("String", "WEBUI_TAG", quoteWrap(webUIRevisionTag))
|
||||
|
||||
|
||||
buildConfigField("String", "GITHUB", "https://github.com/Suwayomi/Tachidesk")
|
||||
buildConfigField("String", "DISCORD", "https://discord.gg/DDZdqZWaHA")
|
||||
buildConfigField("String", "GITHUB", quoteWrap("https://github.com/Suwayomi/Tachidesk"))
|
||||
buildConfigField("String", "DISCORD", quoteWrap("https://discord.gg/DDZdqZWaHA"))
|
||||
}
|
||||
|
||||
tasks {
|
||||
shadowJar {
|
||||
manifest {
|
||||
attributes(
|
||||
mapOf(
|
||||
"Main-Class" to MainClass,
|
||||
"Implementation-Title" to rootProject.name,
|
||||
"Implementation-Vendor" to "The Suwayomi Project",
|
||||
"Specification-Version" to tachideskVersion,
|
||||
"Implementation-Version" to tachideskRevision
|
||||
)
|
||||
mapOf(
|
||||
"Main-Class" to MainClass,
|
||||
"Implementation-Title" to rootProject.name,
|
||||
"Implementation-Vendor" to "The Suwayomi Project",
|
||||
"Specification-Version" to tachideskVersion,
|
||||
"Implementation-Version" to tachideskRevision
|
||||
)
|
||||
)
|
||||
}
|
||||
archiveBaseName.set(rootProject.name)
|
||||
@@ -159,9 +141,9 @@ tasks {
|
||||
withType<KotlinCompile> {
|
||||
kotlinOptions {
|
||||
freeCompilerArgs = listOf(
|
||||
"-Xopt-in=kotlin.RequiresOptIn",
|
||||
"-Xopt-in=kotlinx.coroutines.ExperimentalCoroutinesApi",
|
||||
"-Xopt-in=kotlinx.coroutines.InternalCoroutinesApi"
|
||||
"-Xopt-in=kotlin.RequiresOptIn",
|
||||
"-Xopt-in=kotlinx.coroutines.ExperimentalCoroutinesApi",
|
||||
"-Xopt-in=kotlinx.coroutines.InternalCoroutinesApi"
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -175,7 +157,7 @@ tasks {
|
||||
}
|
||||
|
||||
named("run") {
|
||||
dependsOn("formatKotlin", "lintKotlin")
|
||||
dependsOn("formatKotlin", "lintKotlin", "downloadWebUI")
|
||||
}
|
||||
|
||||
named<Copy>("processResources") {
|
||||
@@ -186,6 +168,26 @@ tasks {
|
||||
register<de.undercouch.gradle.tasks.download.Download>("downloadWebUI") {
|
||||
src("https://github.com/Suwayomi/Tachidesk-WebUI-preview/releases/download/$webUIRevisionTag/Tachidesk-WebUI-$webUIRevisionTag.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> {
|
||||
|
||||
@@ -54,7 +54,7 @@ abstract class AnimeHttpSource : AnimeCatalogueSource {
|
||||
* Note the generated id sets the sign bit to 0.
|
||||
*/
|
||||
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())
|
||||
(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.
|
||||
*/
|
||||
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
|
||||
|
||||
@@ -18,6 +18,7 @@ import okhttp3.OkHttpClient
|
||||
// import uy.kohesive.injekt.injectLazy
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
class NetworkHelper(context: Context) {
|
||||
|
||||
// private val preferences: PreferencesHelper by injectLazy()
|
||||
|
||||
@@ -110,6 +110,7 @@ fun Call.asObservableSuccess(): Observable<Response> {
|
||||
// return progressClient.newCall(request)
|
||||
// }
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
fun OkHttpClient.newCallWithProgress(request: Request, listener: ProgressListener): Call {
|
||||
val progressClient = newBuilder()
|
||||
// .cache(null)
|
||||
|
||||
@@ -55,7 +55,7 @@ abstract class HttpSource : CatalogueSource {
|
||||
* Note the generated id sets the sign bit to 0.
|
||||
*/
|
||||
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())
|
||||
(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.
|
||||
*/
|
||||
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
|
||||
|
||||
@@ -14,6 +14,7 @@ import suwayomi.tachidesk.anime.impl.AnimeList.getAnimeList
|
||||
import suwayomi.tachidesk.anime.impl.Episode.getEpisode
|
||||
import suwayomi.tachidesk.anime.impl.Episode.getEpisodeList
|
||||
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.getSourceList
|
||||
import suwayomi.tachidesk.anime.impl.extension.Extension.getExtensionIcon
|
||||
@@ -219,13 +220,13 @@ object AnimeAPI {
|
||||
// ctx.json(sourceGlobalSearch(searchTerm))
|
||||
// }
|
||||
//
|
||||
// // single source search
|
||||
// app.get("/api/v1/source/:sourceId/search/:searchTerm/:pageNum") { ctx ->
|
||||
// val sourceId = ctx.pathParam("sourceId").toLong()
|
||||
// val searchTerm = ctx.pathParam("searchTerm")
|
||||
// val pageNum = ctx.pathParam("pageNum").toInt()
|
||||
// ctx.json(JavalinSetup.future { sourceSearch(sourceId, searchTerm, pageNum) })
|
||||
// }
|
||||
// single source search
|
||||
app.get("/api/v1/anime/source/:sourceId/search/:searchTerm/:pageNum") { ctx ->
|
||||
val sourceId = ctx.pathParam("sourceId").toLong()
|
||||
val searchTerm = ctx.pathParam("searchTerm")
|
||||
val pageNum = ctx.pathParam("pageNum").toInt()
|
||||
ctx.json(future { sourceSearch(sourceId, searchTerm, pageNum) })
|
||||
}
|
||||
//
|
||||
// // source filter list
|
||||
// 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"
|
||||
}
|
||||
|
||||
val extensionName = packageInfo.applicationInfo.nonLocalizedLabel.toString().substringAfter("Tachiyomi: ")
|
||||
val extensionName = packageInfo.applicationInfo.nonLocalizedLabel.toString().substringAfter("Aniyomi: ")
|
||||
|
||||
// update extension info
|
||||
transaction {
|
||||
|
||||
+1
-1
@@ -32,7 +32,7 @@ object ExtensionGithubApi {
|
||||
libVersion in LIB_VERSION_MIN..LIB_VERSION_MAX
|
||||
}
|
||||
.map { element ->
|
||||
val name = element["name"].string.substringAfter("Tachiyomi: ")
|
||||
val name = element["name"].string.substringAfter("Aniyomi: ")
|
||||
val pkgName = element["pkg"].string
|
||||
val apkName = element["apk"].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
|
||||
* 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.get
|
||||
import io.javalin.apibuilder.ApiBuilder.patch
|
||||
@@ -22,7 +21,7 @@ import suwayomi.tachidesk.manga.controller.MangaController
|
||||
import suwayomi.tachidesk.manga.controller.SourceController
|
||||
|
||||
object MangaAPI {
|
||||
fun defineEndpoints(app: Javalin) {
|
||||
fun defineEndpoints() {
|
||||
path("extension") {
|
||||
get("list", ExtensionController::list)
|
||||
|
||||
@@ -82,7 +81,7 @@ object MangaAPI {
|
||||
patch(":categoryId", LibraryController::categoryModify)
|
||||
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 */
|
||||
fun categoryReorder(ctx: Context) {
|
||||
val categoryId = ctx.pathParam("categoryId").toInt()
|
||||
val from = ctx.formParam("from")!!.toInt()
|
||||
val to = ctx.formParam("to")!!.toInt()
|
||||
Category.reorderCategory(categoryId, from, to)
|
||||
Category.reorderCategory(from, to)
|
||||
ctx.status(200)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ object MangaController {
|
||||
fun chapterList(ctx: Context) {
|
||||
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) })
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ object Category {
|
||||
/**
|
||||
* Move the category from position `from` to `to`
|
||||
*/
|
||||
fun reorderCategory(categoryId: Int, from: Int, to: Int) {
|
||||
fun reorderCategory(from: Int, to: Int) {
|
||||
transaction {
|
||||
val categories = CategoryTable.selectAll().orderBy(CategoryTable.order to SortOrder.ASC).toMutableList()
|
||||
categories.add(to - 1, categories.removeAt(from - 1))
|
||||
|
||||
@@ -30,8 +30,8 @@ import java.time.Instant
|
||||
|
||||
object Chapter {
|
||||
/** get chapter list when showing a manga */
|
||||
suspend fun getChapterList(mangaId: Int, onlineFetch: Boolean?): List<ChapterDataClass> {
|
||||
return if (onlineFetch == true) {
|
||||
suspend fun getChapterList(mangaId: Int, onlineFetch: Boolean = false): List<ChapterDataClass> {
|
||||
return if (onlineFetch) {
|
||||
getSourceChapters(mangaId)
|
||||
} else {
|
||||
transaction {
|
||||
@@ -40,10 +40,7 @@ object Chapter {
|
||||
ChapterTable.toDataClass(it)
|
||||
}
|
||||
}.ifEmpty {
|
||||
// If it was explicitly set to offline dont grab chapters
|
||||
if (onlineFetch == null) {
|
||||
getSourceChapters(mangaId)
|
||||
} else emptyList()
|
||||
getSourceChapters(mangaId)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -163,7 +160,10 @@ object Chapter {
|
||||
// update page list for this chapter
|
||||
transaction {
|
||||
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) {
|
||||
PageTable.insert {
|
||||
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 {
|
||||
if (listOf(isRead, isBookmarked, lastPageRead).any { it != null }) {
|
||||
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) {
|
||||
transaction {
|
||||
val chapter = ChapterTable.select { (ChapterTable.manga eq mangaId) and (ChapterTable.chapterIndex eq chapterIndex) }
|
||||
.first()[ChapterTable.id]
|
||||
val meta = transaction { ChapterMetaTable.select { (ChapterMetaTable.ref eq chapter) and (ChapterMetaTable.key eq key) } }.firstOrNull()
|
||||
val chapter =
|
||||
ChapterTable.select { (ChapterTable.manga eq mangaId) and (ChapterTable.chapterIndex eq chapterIndex) }
|
||||
.first()[ChapterTable.id]
|
||||
val meta =
|
||||
transaction { ChapterMetaTable.select { (ChapterMetaTable.ref eq chapter) and (ChapterMetaTable.key eq key) } }.firstOrNull()
|
||||
if (meta == null) {
|
||||
ChapterMetaTable.insert {
|
||||
it[ChapterMetaTable.key] = key
|
||||
|
||||
@@ -13,22 +13,25 @@ import suwayomi.tachidesk.manga.impl.util.lang.awaitSingle
|
||||
import suwayomi.tachidesk.manga.model.dataclass.PagedMangaListDataClass
|
||||
|
||||
object Search {
|
||||
// TODO
|
||||
fun sourceFilters(sourceId: Long) {
|
||||
val source = getHttpSource(sourceId)
|
||||
// source.getFilterList().toItems()
|
||||
}
|
||||
|
||||
suspend fun sourceSearch(sourceId: Long, searchTerm: String, pageNum: Int): PagedMangaListDataClass {
|
||||
val source = getHttpSource(sourceId)
|
||||
val searchManga = source.fetchSearchManga(pageNum, searchTerm, source.getFilterList()).awaitSingle()
|
||||
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) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
data class FilterWrapper(
|
||||
val type: String,
|
||||
val filter: Any
|
||||
|
||||
+2
@@ -141,6 +141,7 @@ object LegacyBackupImport : LegacyBackupBase() {
|
||||
* @param history history data from json
|
||||
* @param tracks tracking data from json
|
||||
*/
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
private suspend fun restoreMangaData(
|
||||
manga: Manga,
|
||||
source: Source,
|
||||
@@ -204,6 +205,7 @@ object LegacyBackupImport : LegacyBackupBase() {
|
||||
return fetchedManga
|
||||
}
|
||||
|
||||
@Suppress("UNUSED_PARAMETER") // TODO: remove this suppress when update Chapters is written
|
||||
private fun updateChapters(source: Source, fetchedManga: SManga, chapters: List<Chapter>) {
|
||||
// TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
+5
-5
@@ -42,11 +42,11 @@ object LegacyBackupValidator {
|
||||
.sorted()
|
||||
}
|
||||
|
||||
val trackers = mangas
|
||||
.filter { it.asJsonObject.has("track") }
|
||||
.flatMap { it.asJsonObject["track"].asJsonArray }
|
||||
.map { it.asJsonObject["s"].asInt }
|
||||
.distinct()
|
||||
// val trackers = mangas
|
||||
// .filter { it.asJsonObject.has("track") }
|
||||
// .flatMap { it.asJsonObject["track"].asJsonArray }
|
||||
// .map { it.asJsonObject["s"].asInt }
|
||||
// .distinct()
|
||||
|
||||
val missingTrackers = listOf("")
|
||||
// val missingTrackers = trackers
|
||||
|
||||
@@ -85,7 +85,7 @@ object BytecodeEditor {
|
||||
bytes[2],
|
||||
bytes[3]
|
||||
)
|
||||
if (cafebabe.toLowerCase() != "cafebabe") {
|
||||
if (cafebabe.lowercase() != "cafebabe") {
|
||||
// Corrupted class
|
||||
return@use null
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ object JavalinSetup {
|
||||
app.routes {
|
||||
path("api/v1/") {
|
||||
GlobalAPI.defineEndpoints()
|
||||
MangaAPI.defineEndpoints(app)
|
||||
MangaAPI.defineEndpoints()
|
||||
AnimeAPI.defineEndpoints(app) // TODO: migrate Anime endpoints
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ class ServerConfig(config: Config, moduleName: String = "") : ConfigModule(confi
|
||||
// webUI
|
||||
val webUIEnabled: Boolean by overridableWithSysProperty
|
||||
val initialOpenInBrowserEnabled: Boolean by overridableWithSysProperty
|
||||
val webUIBrowser: String by overridableWithSysProperty
|
||||
val webUIInterface: String by overridableWithSysProperty
|
||||
val electronPath: String by overridableWithSysProperty
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -18,7 +18,7 @@ object Browser {
|
||||
|
||||
fun openInBrowser() {
|
||||
if (serverConfig.webUIEnabled) {
|
||||
if (serverConfig.webUIBrowser == ("electron")) {
|
||||
if (serverConfig.webUIInterface == ("electron")) {
|
||||
try {
|
||||
val electronPath = serverConfig.electronPath
|
||||
electronInstances.add(ProcessBuilder(electronPath, appBaseUrl).start())
|
||||
|
||||
@@ -14,8 +14,9 @@ import org.kodein.di.conf.global
|
||||
import org.kodein.di.instance
|
||||
import suwayomi.tachidesk.server.ApplicationDirs
|
||||
import suwayomi.tachidesk.server.BuildConfig
|
||||
import java.io.BufferedInputStream
|
||||
import java.io.File
|
||||
import java.io.InputStream
|
||||
import java.net.HttpURLConnection
|
||||
import java.net.URL
|
||||
import java.nio.charset.StandardCharsets
|
||||
import java.security.MessageDigest
|
||||
@@ -58,9 +59,12 @@ fun setupWebUI() {
|
||||
val webUIZipFile = File(webUIZipPath)
|
||||
|
||||
// try with resources first
|
||||
val resourceWebUI = try {
|
||||
val resourceWebUI: InputStream? = try {
|
||||
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
|
||||
// download webUI zip
|
||||
@@ -71,18 +75,25 @@ fun setupWebUI() {
|
||||
val data = ByteArray(1024)
|
||||
|
||||
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 tresh = 0
|
||||
|
||||
print("Download progress: % 00")
|
||||
while (true) {
|
||||
val count = inp.read(data, 0, 1024)
|
||||
totalCount += count
|
||||
if (totalCount > tresh + 10 * 1024) {
|
||||
tresh = totalCount
|
||||
print(" *")
|
||||
}
|
||||
|
||||
if (count == -1)
|
||||
break
|
||||
|
||||
totalCount += count
|
||||
val percentage = (totalCount.toFloat() / contentLength * 100).toInt().toString().padStart(2, '0')
|
||||
print("\b\b$percentage")
|
||||
|
||||
webUIZipFileOut.write(data, 0, count)
|
||||
}
|
||||
println()
|
||||
|
||||
@@ -14,5 +14,5 @@ server.systemTrayEnabled = true
|
||||
# webUI
|
||||
server.webUIEnabled = true
|
||||
server.initialOpenInBrowserEnabled = true
|
||||
server.webUIBrowser = "browser" # "browser" or "electron"
|
||||
server.webUIInterface = "browser" # "browser" or "electron"
|
||||
server.electronPath = ""
|
||||
|
||||
@@ -72,7 +72,7 @@ class TestExtensions {
|
||||
sources = getSourceList().map { getHttpSource(it.id.toLong()) }
|
||||
}
|
||||
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
|
||||
@@ -99,7 +99,7 @@ class TestExtensions {
|
||||
}.awaitAll()
|
||||
File("tmp/TestDesk/failedToFetch.txt").writeText(
|
||||
failedToFetch.joinToString("\n") { (source, exception) ->
|
||||
"${source.name} (${source.lang.toUpperCase()}, ${source.id}):" +
|
||||
"${source.name} (${source.lang.uppercase()}, ${source.id}):" +
|
||||
" ${exception.message}"
|
||||
}
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user