Compare commits

..

2 Commits

Author SHA1 Message Date
Aria Moradi
464b9659fe queries 2023-06-10 04:00:49 +03:30
Aria Moradi
7a59d0d4dd it compiles 2023-06-09 22:56:14 +03:30
433 changed files with 8460 additions and 18990 deletions

View File

@@ -1,11 +0,0 @@
[*.{kt,kts}]
indent_size=4
insert_final_newline=true
ij_kotlin_allow_trailing_comma=true
ij_kotlin_allow_trailing_comma_on_call_site=true
ij_kotlin_name_count_to_use_star_import=2147483647
ij_kotlin_name_count_to_use_star_import_for_members=2147483647
ktlint_standard_discouraged-comment-location=disabled
ktlint_standard_if-else-wrapping=disabled
ktlint_standard_no-consecutive-comments=disabled

5
.gitattributes vendored
View File

@@ -25,7 +25,4 @@
*.pyc binary *.pyc binary
*.swp binary *.swp binary
*.pdf binary *.pdf binary
*.exe binary *.exe binary
*.avif binary
*.heif binary
*.jxl binary

View File

@@ -11,7 +11,7 @@ I acknowledge that:
- I have updated to the latest version of the app. - I have updated to the latest version of the app.
- I have tried the troubleshooting guide described in `README.md` - I have tried the troubleshooting guide described in `README.md`
- If this is a request for adding/changing an extension it should be brought up to your extension repo. - If this is a request for adding/changing an extension it should be brought up to Tachiyomi: https://github.com/tachiyomiorg/tachiyomi-extensions/issues/new/choose
- If this is an issue with some extension not working properly, It does work inside Tachiyomi as intended. - If this is an issue with some extension not working properly, It does work inside Tachiyomi as intended.
- I have searched the existing issues and this is a new ticket **NOT** a duplicate or related to another open issue - I have searched the existing issues and this is a new ticket **NOT** a duplicate or related to another open issue
- I will fill out the title and the information in this template - I will fill out the title and the information in this template
@@ -23,7 +23,7 @@ Note that the issue will be automatically closed if you do not fill out the titl
--- ---
## Device information ## Device information
- Suwayomi-Server version: (Example: v1.0.0-r1438-win32) - Tachidesk version: (Example: v0.2.3-r255-win32)
- Server Operating System: (Example: Ubuntu 20.04) - Server Operating System: (Example: Ubuntu 20.04)
- Server Desktop Environment: N/A or (Example: Gnome 40) - Server Desktop Environment: N/A or (Example: Gnome 40)
- Server JVM version: bundled with win32 or (Example: Java 8 Update 281 or OpenJDK 8u281) - Server JVM version: bundled with win32 or (Example: Java 8 Update 281 or OpenJDK 8u281)

View File

@@ -11,7 +11,7 @@ I acknowledge that:
- I have updated to the latest version of the app. - I have updated to the latest version of the app.
- I have tried the troubleshooting guide described in `README.md` - I have tried the troubleshooting guide described in `README.md`
- If this is a request for adding/changing an extension it should be brought up to your extension repo. - If this is a request for adding/changing an extension it should be brought up to Tachiyomi: https://github.com/tachiyomiorg/tachiyomi-extensions/issues/new/choose
- If this is an issue with some extension not working properly, It does work in Tachiyomi application as intended. - If this is an issue with some extension not working properly, It does work in Tachiyomi application as intended.
- I have searched the existing issues and this is a new ticket **NOT** a duplicate or related to another open issue - I have searched the existing issues and this is a new ticket **NOT** a duplicate or related to another open issue
- I will fill out the title and the information in this template - I will fill out the title and the information in this template
@@ -22,7 +22,7 @@ Note that the issue will be automatically closed if you do not fill out the titl
--- ---
## What feature should be added to Suwayomi? ## What feature should be added to Tachidesk?
Explain What the feature is and how it should work in detail. Remove this line after you are done. Explain What the feature is and how it should work in detail. Remove this line after you are done.
## Why/Project's Benefit/Existing Problem ## Why/Project's Benefit/Existing Problem

View File

@@ -3,10 +3,6 @@ name: CI Pull Request
on: on:
pull_request: pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs: jobs:
check_wrapper: check_wrapper:
name: Validate Gradle Wrapper name: Validate Gradle Wrapper
@@ -14,7 +10,7 @@ jobs:
steps: steps:
- name: Clone repo - name: Clone repo
uses: actions/checkout@v4 uses: actions/checkout@v3
- name: Validate Gradle Wrapper - name: Validate Gradle Wrapper
uses: gradle/wrapper-validation-action@v1 uses: gradle/wrapper-validation-action@v1
@@ -22,21 +18,26 @@ jobs:
build: build:
name: Build pull request name: Build pull request
needs: check_wrapper needs: check_wrapper
if: "!startsWith(github.event.head_commit.message, '[SKIP CI]')"
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Cancel previous runs
uses: styfle/cancel-workflow-action@0.10.0
with:
access_token: ${{ github.token }}
- name: Checkout pull request - name: Checkout pull request
uses: actions/checkout@v4 uses: actions/checkout@v2
with: with:
ref: ${{ github.event.pull_request.head.sha }} ref: ${{ github.event.pull_request.head.sha }}
path: master path: master
fetch-depth: 0 fetch-depth: 0
- name: Set up JDK 1.8 - name: Set up JDK 1.8
uses: actions/setup-java@v4 uses: actions/setup-java@v1
with: with:
java-version: 8 java-version: 1.8
distribution: 'temurin'
- name: Copy CI gradle.properties - name: Copy CI gradle.properties
run: | run: |
@@ -48,5 +49,5 @@ jobs:
uses: gradle/gradle-build-action@v2 uses: gradle/gradle-build-action@v2
with: with:
build-root-directory: master build-root-directory: master
arguments: ktlintCheck :server:shadowJar --stacktrace arguments: :server:shadowJar --stacktrace

View File

@@ -5,10 +5,6 @@ on:
branches: branches:
- master - master
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs: jobs:
check_wrapper: check_wrapper:
name: Validate Gradle Wrapper name: Validate Gradle Wrapper
@@ -23,20 +19,25 @@ jobs:
build: build:
name: Build Jar name: Build Jar
needs: check_wrapper needs: check_wrapper
if: "!startsWith(github.event.head_commit.message, '[SKIP CI]')"
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Cancel previous runs
uses: styfle/cancel-workflow-action@0.10.0
with:
access_token: ${{ github.token }}
- name: Checkout master branch - name: Checkout master branch
uses: actions/checkout@v4 uses: actions/checkout@v3
with: with:
ref: master ref: master
path: master path: master
fetch-depth: 0 fetch-depth: 0
- name: Set up JDK 1.8 - name: Set up JDK 1.8
uses: actions/setup-java@v4 uses: actions/setup-java@v1
with: with:
java-version: 8 java-version: 1.8
distribution: 'temurin'
- name: Copy CI gradle.properties - name: Copy CI gradle.properties
run: | run: |
@@ -68,7 +69,6 @@ jobs:
- name: Tar scripts dir to maintain file permissions - name: Tar scripts dir to maintain file permissions
run: tar -cvzf scripts.tar.gz -C master/ scripts/ run: tar -cvzf scripts.tar.gz -C master/ scripts/
- name: Upload scripts.tar.gz - name: Upload scripts.tar.gz
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
with: with:
@@ -163,7 +163,7 @@ jobs:
- name: Checkout Preview branch - name: Checkout Preview branch
uses: actions/checkout@v3 uses: actions/checkout@v3
with: with:
repository: "Suwayomi/Suwayomi-Server-preview" repository: "Suwayomi/Tachidesk-Server-preview"
ref: main ref: main
path: preview path: preview
token: ${{ secrets.DEPLOY_PREVIEW_TOKEN }} token: ${{ secrets.DEPLOY_PREVIEW_TOKEN }}
@@ -172,9 +172,9 @@ jobs:
id: GenTagName id: GenTagName
run: | run: |
cd release cd release
genTag=$(ls *.jar | sed -e's/Suwayomi-Server-\|.jar//g') genTag=$(ls *.jar | sed -e's/Tachidesk-Server-\|.jar//g')
echo "$genTag" echo "$genTag"
echo "value=$genTag" >> $GITHUB_OUTPUT echo "::set-output name=value::$genTag"
- name: Create Tag - name: Create Tag
run: | run: |
@@ -196,7 +196,7 @@ jobs:
uses: softprops/action-gh-release@v1 uses: softprops/action-gh-release@v1
with: with:
token: ${{ secrets.DEPLOY_PREVIEW_TOKEN }} token: ${{ secrets.DEPLOY_PREVIEW_TOKEN }}
repository: "Suwayomi/Suwayomi-Server-preview" repository: "Suwayomi/Tachidesk-Server-preview"
tag_name: ${{ steps.GenTagName.outputs.value }} tag_name: ${{ steps.GenTagName.outputs.value }}
files: release/* files: release/*

View File

@@ -37,7 +37,7 @@ jobs:
}, },
{ {
"type": "body", "type": "body",
"regex": ".*(Suwayomi-Server version|Server Operating System|Server Desktop Environment|Server JVM version|Client Operating System|Client Web Browser):.*(\\(Example:|<usually).*", "regex": ".*(Tachidesk version|Server Operating System|Server Desktop Environment|Server JVM version|Client Operating System|Client Web Browser):.*(\\(Example:|<usually).*",
"message": "The requested information was not filled out" "message": "The requested information was not filled out"
}, },
{ {

View File

@@ -6,17 +6,13 @@ on:
tags: tags:
- "v*" - "v*"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs: jobs:
check_wrapper: check_wrapper:
name: Validate Gradle Wrapper name: Validate Gradle Wrapper
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Clone repo - name: Clone repo
uses: actions/checkout@v4 uses: actions/checkout@v3
- name: Validate Gradle Wrapper - name: Validate Gradle Wrapper
uses: gradle/wrapper-validation-action@v1 uses: gradle/wrapper-validation-action@v1
@@ -26,18 +22,22 @@ jobs:
needs: check_wrapper needs: check_wrapper
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Cancel previous runs
uses: styfle/cancel-workflow-action@0.10.0
with:
access_token: ${{ github.token }}
- name: Checkout ${{ github.ref }} - name: Checkout ${{ github.ref }}
uses: actions/checkout@v4 uses: actions/checkout@v3
with: with:
ref: ${{ github.ref }} ref: ${{ github.ref }}
path: master path: master
fetch-depth: 0 fetch-depth: 0
- name: Set up JDK 1.8 - name: Set up JDK 1.8
uses: actions/setup-java@v4 uses: actions/setup-java@v1
with: with:
java-version: 8 java-version: 1.8
distribution: 'temurin'
- name: Copy CI gradle.properties - name: Copy CI gradle.properties
run: | run: |
@@ -70,7 +70,6 @@ jobs:
- name: Tar scripts dir to maintain file permissions - name: Tar scripts dir to maintain file permissions
run: tar -cvzf scripts.tar.gz -C master/ scripts/ run: tar -cvzf scripts.tar.gz -C master/ scripts/
- name: Upload scripts.tar.gz - name: Upload scripts.tar.gz
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
with: with:

View File

@@ -1,11 +1,12 @@
@Suppress("DSL_SCOPE_VIOLATION")
plugins { plugins {
id(libs.plugins.kotlin.jvm.get().pluginId) id(libs.plugins.kotlin.jvm.get().pluginId)
id(libs.plugins.kotlin.serialization.get().pluginId) id(libs.plugins.kotlin.serialization.get().pluginId)
id(libs.plugins.ktlint.get().pluginId) id(libs.plugins.kotlinter.get().pluginId)
} }
dependencies { dependencies {
// Shared // Shared
implementation(libs.bundles.shared) implementation(libs.bundles.shared)
testImplementation(libs.bundles.sharedTest) testImplementation(libs.bundles.sharedTest)
} }

View File

@@ -15,6 +15,6 @@ val ApplicationRootDir: String
get(): String { get(): String {
return System.getProperty( return System.getProperty(
"$CONFIG_PREFIX.server.rootDir", "$CONFIG_PREFIX.server.rootDir",
AppDirsFactory.getInstance().getUserDataDir("Tachidesk", null, null), AppDirsFactory.getInstance().getUserDataDir("Tachidesk", null, null)
) )
} }

View File

@@ -5,9 +5,8 @@ import org.kodein.di.bind
import org.kodein.di.singleton import org.kodein.di.singleton
class ConfigKodeinModule { class ConfigKodeinModule {
fun create() = fun create() = DI.Module("ConfigManager") {
DI.Module("ConfigManager") { // Config module
// Config module bind<ConfigManager>() with singleton { GlobalConfigManager }
bind<ConfigManager>() with singleton { GlobalConfigManager } }
}
} }

View File

@@ -10,12 +10,10 @@ package xyz.nulldev.ts.config
import ch.qos.logback.classic.Level import ch.qos.logback.classic.Level
import com.typesafe.config.Config import com.typesafe.config.Config
import com.typesafe.config.ConfigFactory import com.typesafe.config.ConfigFactory
import com.typesafe.config.ConfigRenderOptions
import com.typesafe.config.ConfigValue import com.typesafe.config.ConfigValue
import com.typesafe.config.ConfigValueFactory import com.typesafe.config.ConfigValueFactory
import com.typesafe.config.parser.ConfigDocument
import com.typesafe.config.parser.ConfigDocumentFactory import com.typesafe.config.parser.ConfigDocumentFactory
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import mu.KotlinLogging import mu.KotlinLogging
import java.io.File import java.io.File
@@ -34,8 +32,6 @@ open class ConfigManager {
val loadedModules: Map<Class<out ConfigModule>, ConfigModule> val loadedModules: Map<Class<out ConfigModule>, ConfigModule>
get() = generatedModules get() = generatedModules
private val mutex = Mutex()
/** /**
* Get a config module * Get a config module
*/ */
@@ -47,12 +43,6 @@ open class ConfigManager {
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
fun <T : ConfigModule> module(type: Class<T>): T = loadedModules[type] as T fun <T : ConfigModule> module(type: Class<T>): T = loadedModules[type] as T
private fun getUserConfig(): Config {
return userConfigFile.let {
ConfigFactory.parseFile(it)
}
}
/** /**
* Load configs * Load configs
*/ */
@@ -63,25 +53,30 @@ open class ConfigManager {
val baseConfig = val baseConfig =
ConfigFactory.parseMap( ConfigFactory.parseMap(
mapOf( mapOf(
// override AndroidCompat's rootDir "androidcompat.rootDir" to "$ApplicationRootDir/android-compat" // override AndroidCompat's rootDir
"androidcompat.rootDir" to "$ApplicationRootDir/android-compat", )
),
) )
// Load user config // Load user config
val userConfig = getUserConfig() val userConfig =
userConfigFile.let {
ConfigFactory.parseFile(it)
}
val config = val config = ConfigFactory.empty()
ConfigFactory.empty() .withFallback(baseConfig)
.withFallback(baseConfig) .withFallback(userConfig)
.withFallback(userConfig) .withFallback(compatConfig)
.withFallback(compatConfig) .withFallback(serverConfig)
.withFallback(serverConfig) .resolve()
.resolve()
// set log level early // set log level early
if (debugLogsEnabled(config)) { if (debugLogsEnabled(config)) {
setLogLevelFor(BASE_LOGGER_NAME, Level.DEBUG) setLogLevel(Level.DEBUG)
}
logger.debug {
"Loaded config:\n" + config.root().render(ConfigRenderOptions.concise().setFormatted(true))
} }
return config return config
@@ -97,69 +92,18 @@ open class ConfigManager {
} }
} }
private fun updateUserConfigFile( private fun updateUserConfigFile(path: String, value: ConfigValue) {
path: String,
value: ConfigValue,
) {
val userConfigDoc = ConfigDocumentFactory.parseFile(userConfigFile) val userConfigDoc = ConfigDocumentFactory.parseFile(userConfigFile)
val updatedConfigDoc = userConfigDoc.withValue(path, value) val updatedConfigDoc = userConfigDoc.withValue(path, value)
val newFileContent = updatedConfigDoc.render() val newFileContent = updatedConfigDoc.render()
userConfigFile.writeText(newFileContent) userConfigFile.writeText(newFileContent)
} }
suspend fun updateValue( fun updateValue(path: String, value: Any) {
path: String, val configValue = ConfigValueFactory.fromAnyRef(value)
value: Any,
) {
mutex.withLock {
val configValue = ConfigValueFactory.fromAnyRef(value)
updateUserConfigFile(path, configValue) updateUserConfigFile(path, configValue)
internalConfig = internalConfig.withValue(path, configValue) internalConfig = internalConfig.withValue(path, configValue)
}
}
fun resetUserConfig(updateInternalConfig: Boolean = true): ConfigDocument {
val serverConfigFileContent = this::class.java.getResource("/server-reference.conf")?.readText()
val serverConfigDoc = ConfigDocumentFactory.parseString(serverConfigFileContent)
userConfigFile.writeText(serverConfigDoc.render())
if (updateInternalConfig) {
getUserConfig().entrySet().forEach { internalConfig = internalConfig.withValue(it.key, it.value) }
}
return serverConfigDoc
}
/**
* Makes sure the "UserConfig" is up-to-date.
*
* - adds missing settings
* - removes outdated settings
*/
fun updateUserConfig() {
val serverConfig = ConfigFactory.parseResources("server-reference.conf")
val userConfig = getUserConfig()
val hasMissingSettings = serverConfig.entrySet().any { !userConfig.hasPath(it.key) }
val hasOutdatedSettings = userConfig.entrySet().any { !serverConfig.hasPath(it.key) }
val isUserConfigOutdated = hasMissingSettings || hasOutdatedSettings
if (!isUserConfigOutdated) {
return
}
logger.debug {
"user config is out of date, updating... (missingSettings= $hasMissingSettings, outdatedSettings= $hasOutdatedSettings"
}
var newUserConfigDoc: ConfigDocument = resetUserConfig(false)
userConfig.entrySet().filter {
serverConfig.hasPath(
it.key,
)
}.forEach { newUserConfigDoc = newUserConfigDoc.withValue(it.key, it.value) }
userConfigFile.writeText(newUserConfigDoc.render())
} }
} }

View File

@@ -8,8 +8,6 @@ package xyz.nulldev.ts.config
* 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 com.typesafe.config.Config import com.typesafe.config.Config
import com.typesafe.config.ConfigFactory
import com.typesafe.config.ConfigValueFactory
import io.github.config4k.getValue import io.github.config4k.getValue
import kotlin.reflect.KProperty import kotlin.reflect.KProperty
@@ -28,28 +26,21 @@ abstract class SystemPropertyOverridableConfigModule(getConfig: () -> Config, mo
/** Defines a config property that is overridable with jvm `-D` commandline arguments prefixed with [CONFIG_PREFIX] */ /** Defines a config property that is overridable with jvm `-D` commandline arguments prefixed with [CONFIG_PREFIX] */
class SystemPropertyOverrideDelegate(val getConfig: () -> Config, val moduleName: String) { class SystemPropertyOverrideDelegate(val getConfig: () -> Config, val moduleName: String) {
inline operator fun <R, reified T> getValue( operator fun <R> setValue(thisRef: R, property: KProperty<*>, value: Any) {
thisRef: R, GlobalConfigManager.updateValue("$moduleName.${property.name}", value)
property: KProperty<*>, }
): T {
val config = getConfig()
val configValue: T = config.getValue(thisRef, property)
val combined = inline operator fun <R, reified T> getValue(thisRef: R, property: KProperty<*>): T {
System.getProperty( val configValue: T = getConfig().getValue(thisRef, property)
"$CONFIG_PREFIX.$moduleName.${property.name}",
if (T::class.simpleName == "List") { val combined = System.getProperty(
ConfigValueFactory.fromAnyRef(configValue).render() "$CONFIG_PREFIX.$moduleName.${property.name}",
} else { configValue.toString()
configValue.toString() )
},
)
return when (T::class.simpleName) { return when (T::class.simpleName) {
"Int" -> combined.toInt() "Int" -> combined.toInt()
"Boolean" -> combined.toBoolean() "Boolean" -> combined.toBoolean()
"Double" -> combined.toDouble()
"List" -> ConfigFactory.parseString("internal=" + combined).getStringList("internal").orEmpty()
// add more types as needed // add more types as needed
else -> combined // covers String else -> combined // covers String
} as T } as T

View File

@@ -8,88 +8,12 @@ package xyz.nulldev.ts.config
* 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 ch.qos.logback.classic.Level import ch.qos.logback.classic.Level
import ch.qos.logback.classic.LoggerContext
import ch.qos.logback.classic.encoder.PatternLayoutEncoder
import ch.qos.logback.classic.spi.ILoggingEvent
import ch.qos.logback.core.rolling.RollingFileAppender
import ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy
import ch.qos.logback.core.util.FileSize
import com.typesafe.config.Config import com.typesafe.config.Config
import mu.KotlinLogging import mu.KotlinLogging
import org.slf4j.Logger import org.slf4j.Logger
import org.slf4j.LoggerFactory
private fun createRollingFileAppender( fun setLogLevel(level: Level) {
logContext: LoggerContext, (KotlinLogging.logger(Logger.ROOT_LOGGER_NAME).underlyingLogger as ch.qos.logback.classic.Logger).level = level
logDirPath: String,
): RollingFileAppender<ILoggingEvent> {
val logFilename = "application"
val logEncoder =
PatternLayoutEncoder().apply {
pattern = "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n"
context = logContext
start()
}
val appender =
RollingFileAppender<ILoggingEvent>().apply {
name = "FILE"
context = logContext
encoder = logEncoder
file = "$logDirPath/$logFilename.log"
}
val rollingPolicy =
SizeAndTimeBasedRollingPolicy<ILoggingEvent>().apply {
context = logContext
setParent(appender)
fileNamePattern = "$logDirPath/${logFilename}_%d{yyyy-MM-dd}_%i.log.gz"
setMaxFileSize(FileSize.valueOf("10mb"))
maxHistory = 14
setTotalSizeCap(FileSize.valueOf("1gb"))
start()
}
appender.rollingPolicy = rollingPolicy
appender.start()
return appender
}
private fun getBaseLogger(): ch.qos.logback.classic.Logger {
return (KotlinLogging.logger(Logger.ROOT_LOGGER_NAME).underlyingLogger as ch.qos.logback.classic.Logger)
}
private fun getLogger(name: String): ch.qos.logback.classic.Logger {
val context = LoggerFactory.getILoggerFactory() as LoggerContext
return context.getLogger(name)
}
fun initLoggerConfig(appRootPath: String) {
val context = LoggerFactory.getILoggerFactory() as LoggerContext
val logger = getBaseLogger()
// logback logs to the console by default (at least when adding a console appender logs in the console are duplicated)
logger.addAppender(createRollingFileAppender(context, "$appRootPath/logs"))
// set "kotlin exposed" log level
setLogLevelFor("Exposed", Level.ERROR)
}
const val BASE_LOGGER_NAME = "_BaseLogger"
fun setLogLevelFor(
name: String,
level: Level,
) {
val logger =
if (name == BASE_LOGGER_NAME) {
getBaseLogger()
} else {
getLogger(name)
}
logger.level = level
} }
fun debugLogsEnabled(config: Config) = fun debugLogsEnabled(config: Config) =

View File

@@ -2,6 +2,5 @@ package xyz.nulldev.ts.config.util
import com.typesafe.config.Config import com.typesafe.config.Config
operator fun Config.get(key: String) = operator fun Config.get(key: String) = getString(key)
getString(key) ?: throw IllegalStateException("Could not find value for config entry: $key!")
?: throw IllegalStateException("Could not find value for config entry: $key!")

View File

@@ -1,7 +1,8 @@
@Suppress("DSL_SCOPE_VIOLATION")
plugins { plugins {
id(libs.plugins.kotlin.jvm.get().pluginId) id(libs.plugins.kotlin.jvm.get().pluginId)
id(libs.plugins.kotlin.serialization.get().pluginId) id(libs.plugins.kotlin.serialization.get().pluginId)
id(libs.plugins.ktlint.get().pluginId) id(libs.plugins.kotlinter.get().pluginId)
} }
dependencies { dependencies {

View File

@@ -1,23 +1,20 @@
package android.graphics; package android.graphics;
import android.annotation.ColorInt; import java.awt.image.BufferedImage;
import android.annotation.NonNull; import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Iterator;
import javax.imageio.IIOImage; import javax.imageio.IIOImage;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam; import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter; import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageOutputStream; import javax.imageio.stream.ImageOutputStream;
import java.awt.image.BufferedImage;
import java.awt.image.Raster;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Iterator;
public final class Bitmap { public final class Bitmap {
private final int width; private int width;
private final int height; private int height;
private final BufferedImage image; private BufferedImage image;
public Bitmap(BufferedImage image) { public Bitmap(BufferedImage image) {
this.image = image; this.image = image;
@@ -62,8 +59,8 @@ public final class Bitmap {
final int nativeInt; final int nativeInt;
private static final Config[] sConfigs = { private static Config sConfigs[] = {
null, ALPHA_8, null, RGB_565, ARGB_4444, ARGB_8888, RGBA_F16, HARDWARE, RGBA_1010102 null, ALPHA_8, null, RGB_565, ARGB_4444, ARGB_8888, RGBA_F16, HARDWARE, RGBA_1010102
}; };
Config(int ni) { Config(int ni) {
@@ -75,60 +72,11 @@ public final class Bitmap {
} }
} }
/**
* Common code for checking that x and y are >= 0
*
* @param x x coordinate to ensure is >= 0
* @param y y coordinate to ensure is >= 0
*/
private static void checkXYSign(int x, int y) {
if (x < 0) {
throw new IllegalArgumentException("x must be >= 0");
}
if (y < 0) {
throw new IllegalArgumentException("y must be >= 0");
}
}
/**
* Common code for checking that width and height are > 0
*
* @param width width to ensure is > 0
* @param height height to ensure is > 0
*/
private static void checkWidthHeight(int width, int height) {
if (width <= 0) {
throw new IllegalArgumentException("width must be > 0");
}
if (height <= 0) {
throw new IllegalArgumentException("height must be > 0");
}
}
public static Bitmap createBitmap(int width, int height, Config config) { public static Bitmap createBitmap(int width, int height, Config config) {
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
return new Bitmap(image); return new Bitmap(image);
} }
public static Bitmap createBitmap(@NonNull Bitmap source, int x, int y, int width, int height) {
checkXYSign(x, y);
checkWidthHeight(width, height);
if (x + width > source.getWidth()) {
throw new IllegalArgumentException("x + width must be <= bitmap.width()");
}
if (y + height > source.getHeight()) {
throw new IllegalArgumentException("y + height must be <= bitmap.height()");
}
// Android will make a copy when creating a sub image,
// so we do the same here
BufferedImage subImage = source.image.getSubimage(x, y, width, height);
BufferedImage newImage = new BufferedImage(subImage.getWidth(), subImage.getHeight(), subImage.getType());
newImage.setData(subImage.getData());
return new Bitmap(newImage);
}
public boolean compress(CompressFormat format, int quality, OutputStream stream) { public boolean compress(CompressFormat format, int quality, OutputStream stream) {
if (stream == null) { if (stream == null) {
throw new NullPointerException(); throw new NullPointerException();
@@ -139,7 +87,7 @@ public final class Bitmap {
} }
float qualityFloat = ((float) quality) / 100; float qualityFloat = ((float) quality) / 100;
String formatString; String formatString = "";
if (format == Bitmap.CompressFormat.PNG) { if (format == Bitmap.CompressFormat.PNG) {
formatString = "png"; formatString = "png";
} else if (format == Bitmap.CompressFormat.JPEG) { } else if (format == Bitmap.CompressFormat.JPEG) {
@@ -152,7 +100,7 @@ public final class Bitmap {
if (!writers.hasNext()) { if (!writers.hasNext()) {
throw new IllegalStateException("no image writers found for this format!"); throw new IllegalStateException("no image writers found for this format!");
} }
ImageWriter writer = writers.next(); ImageWriter writer = (ImageWriter) writers.next();
ImageOutputStream ios; ImageOutputStream ios;
try { try {
@@ -163,73 +111,19 @@ public final class Bitmap {
writer.setOutput(ios); writer.setOutput(ios);
ImageWriteParam param = writer.getDefaultWriteParam(); ImageWriteParam param = writer.getDefaultWriteParam();
if ("jpg".equals(formatString)) { if (formatString == "jpg") {
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionQuality(qualityFloat); param.setCompressionQuality(qualityFloat);
} }
try { try {
writer.write(null, new IIOImage(image, null, null), param); writer.write(null, new IIOImage(image, null, null), param);
ios.close(); ios.close();
writer.dispose(); writer.dispose();
} catch (IOException ex) { } catch (IOException ex) {
throw new RuntimeException(ex); throw new RuntimeException(ex);
} }
return true; return true;
} }
/**
* Shared code to check for illegal arguments passed to getPixels()
* or setPixels()
*
* @param x left edge of the area of pixels to access
* @param y top edge of the area of pixels to access
* @param width width of the area of pixels to access
* @param height height of the area of pixels to access
* @param offset offset into pixels[] array
* @param stride number of elements in pixels[] between each logical row
* @param pixels array to hold the area of pixels being accessed
*/
private void checkPixelsAccess(int x, int y, int width, int height,
int offset, int stride, int[] pixels) {
checkXYSign(x, y);
if (width < 0) {
throw new IllegalArgumentException("width must be >= 0");
}
if (height < 0) {
throw new IllegalArgumentException("height must be >= 0");
}
if (x + width > getWidth()) {
throw new IllegalArgumentException(
"x + width must be <= bitmap.width()");
}
if (y + height > getHeight()) {
throw new IllegalArgumentException(
"y + height must be <= bitmap.height()");
}
if (Math.abs(stride) < width) {
throw new IllegalArgumentException("abs(stride) must be >= width");
}
int lastScanline = offset + (height - 1) * stride;
int length = pixels.length;
if (offset < 0 || (offset + width > length)
|| lastScanline < 0
|| (lastScanline + width > length)) {
throw new ArrayIndexOutOfBoundsException();
}
}
public void getPixels(@ColorInt int[] pixels, int offset, int stride,
int x, int y, int width, int height) {
checkPixelsAccess(x, y, width, height, offset, stride, pixels);
Raster raster = image.getData();
int[] rasterPixels = raster.getPixels(x, y, width, height, (int[]) null);
for (int ht = 0; ht < height; ht++) {
int rowOffset = offset + stride * ht;
System.arraycopy(rasterPixels, ht * width, pixels, rowOffset, width);
}
}
} }

View File

@@ -12,7 +12,7 @@ class PreferenceManager {
fun getDefaultSharedPreferences(context: Context) = fun getDefaultSharedPreferences(context: Context) =
context.getSharedPreferences( context.getSharedPreferences(
context.applicationInfo.packageName, context.applicationInfo.packageName,
Context.MODE_PRIVATE, Context.MODE_PRIVATE
)!! )!!
} }
} }

View File

@@ -1,247 +0,0 @@
package android.webkit;
import android.annotation.Nullable;
import xyz.nulldev.androidcompat.webkit.CookieManagerImpl;
public abstract class CookieManager {
/**
* @deprecated This class should not be constructed by applications, use {@link #getInstance}
* instead to fetch the singleton instance.
*/
// TODO(ntfschr): mark this as @SystemApi after a year.
@Deprecated
public CookieManager() {}
@Override
protected Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException("doesn't implement Cloneable");
}
private static CookieManager INSTANCE = null;
private static final Object lock = new Object();
/**
* Gets the singleton CookieManager instance.
*
* @return the singleton CookieManager instance
*/
public static CookieManager getInstance() {
if (INSTANCE != null) {
return INSTANCE;
} else {
synchronized (lock) {
if (INSTANCE == null) {
INSTANCE = new CookieManagerImpl();
}
return INSTANCE;
}
}
}
/**
* Sets whether the application's {@link WebView} instances should send and
* accept cookies.
* By default this is set to {@code true} and the WebView accepts cookies.
* <p>
* When this is {@code true}
* {@link CookieManager#setAcceptThirdPartyCookies setAcceptThirdPartyCookies} and
* {@link CookieManager#setAcceptFileSchemeCookies setAcceptFileSchemeCookies}
* can be used to control the policy for those specific types of cookie.
*
* @param accept whether {@link WebView} instances should send and accept
* cookies
*/
public abstract void setAcceptCookie(boolean accept);
/**
* Gets whether the application's {@link WebView} instances send and accept
* cookies.
*
* @return {@code true} if {@link WebView} instances send and accept cookies
*/
public abstract boolean acceptCookie();
/**
* Sets whether the {@link WebView} should allow third party cookies to be set.
* Allowing third party cookies is a per WebView policy and can be set
* differently on different WebView instances.
* <p>
* Apps that target {@link android.os.Build.VERSION_CODES#KITKAT} or below
* default to allowing third party cookies. Apps targeting
* {@link android.os.Build.VERSION_CODES#LOLLIPOP} or later default to disallowing
* third party cookies.
*
* @param webview the {@link WebView} instance to set the cookie policy on
* @param accept whether the {@link WebView} instance should accept
* third party cookies
*/
public abstract void setAcceptThirdPartyCookies(WebView webview, boolean accept);
/**
* Gets whether the {@link WebView} should allow third party cookies to be set.
*
* @param webview the {@link WebView} instance to get the cookie policy for
* @return {@code true} if the {@link WebView} accepts third party cookies
*/
public abstract boolean acceptThirdPartyCookies(WebView webview);
/**
* Sets a single cookie (key-value pair) for the given URL. Any existing cookie with the same
* host, path and name will be replaced with the new cookie. The cookie being set
* will be ignored if it is expired. To set multiple cookies, your application should invoke
* this method multiple times.
*
* <p>The {@code value} parameter must follow the format of the {@code Set-Cookie} HTTP
* response header defined by
* <a href="https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-03">RFC6265bis</a>.
* This is a key-value pair of the form {@code "key=value"}, optionally followed by a list of
* cookie attributes delimited with semicolons (ex. {@code "key=value; Max-Age=123"}). Please
* consult the RFC specification for a list of valid attributes.
*
* <p class="note"><b>Note:</b> if specifying a {@code value} containing the {@code "Secure"}
* attribute, {@code url} must use the {@code "https://"} scheme.
*
* @param url the URL for which the cookie is to be set
* @param value the cookie as a string, using the format of the 'Set-Cookie'
* HTTP response header
*/
public abstract void setCookie(String url, String value);
/**
* Sets a single cookie (key-value pair) for the given URL. Any existing cookie with the same
* host, path and name will be replaced with the new cookie. The cookie being set
* will be ignored if it is expired. To set multiple cookies, your application should invoke
* this method multiple times.
*
* <p>The {@code value} parameter must follow the format of the {@code Set-Cookie} HTTP
* response header defined by
* <a href="https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-03">RFC6265bis</a>.
* This is a key-value pair of the form {@code "key=value"}, optionally followed by a list of
* cookie attributes delimited with semicolons (ex. {@code "key=value; Max-Age=123"}). Please
* consult the RFC specification for a list of valid attributes.
*
* <p>This method is asynchronous. If a {@link ValueCallback} is provided,
* {@link ValueCallback#onReceiveValue} will be called on the current
* thread's {@link android.os.Looper} once the operation is complete.
* The value provided to the callback indicates whether the cookie was set successfully.
* You can pass {@code null} as the callback if you don't need to know when the operation
* completes or whether it succeeded, and in this case it is safe to call the method from a
* thread without a Looper.
*
* <p class="note"><b>Note:</b> if specifying a {@code value} containing the {@code "Secure"}
* attribute, {@code url} must use the {@code "https://"} scheme.
*
* @param url the URL for which the cookie is to be set
* @param value the cookie as a string, using the format of the 'Set-Cookie'
* HTTP response header
* @param callback a callback to be executed when the cookie has been set
*/
public abstract void setCookie(String url, String value, @Nullable ValueCallback<Boolean>
callback);
/**
* Gets all the cookies for the given URL. This may return multiple key-value pairs if multiple
* cookies are associated with this URL, in which case each cookie will be delimited by {@code
* "; "} characters (semicolon followed by a space). Each key-value pair will be of the form
* {@code "key=value"}.
*
* @param url the URL for which the cookies are requested
* @return value the cookies as a string, using the format of the 'Cookie'
* HTTP request header
*/
public abstract String getCookie(String url);
/**
* Removes all session cookies, which are cookies without an expiration
* date.
* @deprecated use {@link #removeSessionCookies(ValueCallback)} instead.
*/
@Deprecated
public abstract void removeSessionCookie();
/**
* Removes all session cookies, which are cookies without an expiration
* date.
* <p>
* This method is asynchronous.
* If a {@link ValueCallback} is provided,
* {@link ValueCallback#onReceiveValue(Object)} will be called on the current
* thread's {@link android.os.Looper} once the operation is complete.
* The value provided to the callback indicates whether any cookies were removed.
* You can pass {@code null} as the callback if you don't need to know when the operation
* completes or whether any cookie were removed, and in this case it is safe to call the
* method from a thread without a Looper.
* @param callback a callback which is executed when the session cookies have been removed
*/
public abstract void removeSessionCookies(@Nullable ValueCallback<Boolean> callback);
/**
* Removes all cookies.
* @deprecated Use {@link #removeAllCookies(ValueCallback)} instead.
*/
@Deprecated
public abstract void removeAllCookie();
/**
* Removes all cookies.
* <p>
* This method is asynchronous.
* If a {@link ValueCallback} is provided,
* {@link ValueCallback#onReceiveValue(Object)} will be called on the current
* thread's {@link android.os.Looper} once the operation is complete.
* The value provided to the callback indicates whether any cookies were removed.
* You can pass {@code null} as the callback if you don't need to know when the operation
* completes or whether any cookies were removed, and in this case it is safe to call the
* method from a thread without a Looper.
* @param callback a callback which is executed when the cookies have been removed
*/
public abstract void removeAllCookies(@Nullable ValueCallback<Boolean> callback);
/**
* Gets whether there are stored cookies.
*
* @return {@code true} if there are stored cookies
*/
public abstract boolean hasCookies();
/**
* Removes all expired cookies.
* @deprecated The WebView handles removing expired cookies automatically.
*/
@Deprecated
public abstract void removeExpiredCookie();
/**
* Ensures all cookies currently accessible through the getCookie API are
* written to persistent storage.
* This call will block the caller until it is done and may perform I/O.
*/
public abstract void flush();
/**
* Gets whether the application's {@link WebView} instances send and accept
* cookies for file scheme URLs.
*
* @return {@code true} if {@link WebView} instances send and accept cookies for
* file scheme URLs
*/
// Static for backward compatibility.
public static boolean allowFileSchemeCookies() {
return getInstance().allowFileSchemeCookiesImpl();
}
public abstract boolean allowFileSchemeCookiesImpl();
/**
* Sets whether the application's {@link WebView} instances should send and accept cookies for
* file scheme URLs.
* <p>
* Use of cookies with file scheme URLs is potentially insecure and turned off by default. All
* {@code file://} URLs share all their cookies, which may lead to leaking private app cookies
* (ex. any malicious file can access cookies previously set by other (trusted) files).
* <p class="note">
* Loading content via {@code file://} URLs is generally discouraged. See the note in
* {@link WebSettings#setAllowFileAccess}.
* Using <a href="{@docRoot}reference/androidx/webkit/WebViewAssetLoader.html">
* androidx.webkit.WebViewAssetLoader</a> to load files over {@code http(s)://} URLs allows
* the standard web security model to be used for setting and sharing cookies for local files.
* <p>
* Note that calls to this method will have no effect if made after calling other
* {@link CookieManager} APIs.
*
* @deprecated This setting is not secure, please use
* <a href="{@docRoot}reference/androidx/webkit/WebViewAssetLoader.html">
* androidx.webkit.WebViewAssetLoader</a> instead.
*/
// Static for backward compatibility.
@Deprecated
public static void setAcceptFileSchemeCookies(boolean accept) {
getInstance().setAcceptFileSchemeCookiesImpl(accept);
}
public abstract void setAcceptFileSchemeCookiesImpl(boolean accept);
}

View File

@@ -1,45 +0,0 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@file:Suppress("NOTHING_TO_INLINE") // Aliases to public API.
package androidx.core.net
import android.net.Uri
import java.io.File
/**
* Creates a Uri from the given encoded URI string.
*
* @see Uri.parse
*/
public inline fun String.toUri(): Uri = Uri.parse(this)
/**
* Creates a Uri from the given file.
*
* @see Uri.fromFile
*/
public inline fun File.toUri(): Uri = Uri.fromFile(this)
/**
* Creates a [File] from the given [Uri]. Note that this will throw an
* [IllegalArgumentException] when invoked on a [Uri] that lacks `file` scheme.
*/
public fun Uri.toFile(): File {
require(scheme == "file") { "Uri lacks 'file' scheme: $this" }
return File(requireNotNull(path) { "Uri path is null: $this" })
}

View File

@@ -22,7 +22,6 @@ public class Preference {
@JsonIgnore @JsonIgnore
protected Context context; protected Context context;
private boolean isVisible;
private String key; private String key;
private CharSequence title; private CharSequence title;
private CharSequence summary; private CharSequence summary;
@@ -101,14 +100,6 @@ public class Preference {
return sharedPreferences; return sharedPreferences;
} }
public void setVisible(boolean visible) {
isVisible = visible;
}
public boolean getVisible() {
return isVisible;
}
/** Tachidesk specific API */ /** Tachidesk specific API */
public void setSharedPreferences(SharedPreferences sharedPreferences) { public void setSharedPreferences(SharedPreferences sharedPreferences) {
this.sharedPreferences = sharedPreferences; this.sharedPreferences = sharedPreferences;

View File

@@ -7,6 +7,7 @@ import org.kodein.di.instance
import xyz.nulldev.androidcompat.androidimpl.CustomContext import xyz.nulldev.androidcompat.androidimpl.CustomContext
class AndroidCompat { class AndroidCompat {
val context: CustomContext by DI.global.instance() val context: CustomContext by DI.global.instance()
fun startApp(application: Application) { fun startApp(application: Application) {

View File

@@ -18,13 +18,10 @@ class AndroidCompatInitializer {
GlobalConfigManager.registerModules( GlobalConfigManager.registerModules(
FilesConfigModule.register(GlobalConfigManager.config), FilesConfigModule.register(GlobalConfigManager.config),
ApplicationInfoConfigModule.register(GlobalConfigManager.config), ApplicationInfoConfigModule.register(GlobalConfigManager.config),
SystemConfigModule.register(GlobalConfigManager.config), SystemConfigModule.register(GlobalConfigManager.config)
) )
// Set some properties extensions use // Set some properties extensions use
System.setProperty( System.setProperty("http.agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36")
"http.agent",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
)
} }
} }

View File

@@ -18,24 +18,22 @@ import xyz.nulldev.androidcompat.service.ServiceSupport
*/ */
class AndroidCompatModule { class AndroidCompatModule {
fun create() = fun create() = DI.Module("AndroidCompat") {
DI.Module("AndroidCompat") { bind<AndroidFiles>() with singleton { AndroidFiles() }
bind<AndroidFiles>() with singleton { AndroidFiles() }
bind<ApplicationInfoImpl>() with singleton { ApplicationInfoImpl() } bind<ApplicationInfoImpl>() with singleton { ApplicationInfoImpl() }
bind<ServiceSupport>() with singleton { ServiceSupport() } bind<ServiceSupport>() with singleton { ServiceSupport() }
bind<FakePackageManager>() with singleton { FakePackageManager() } bind<FakePackageManager>() with singleton { FakePackageManager() }
bind<PackageController>() with singleton { PackageController() } bind<PackageController>() with singleton { PackageController() }
// Context // Context
bind<CustomContext>() with singleton { CustomContext() } bind<CustomContext>() with singleton { CustomContext() }
bind<Context>() with bind<Context>() with singleton {
singleton { val context: Context by DI.global.instance<CustomContext>()
val context: Context by DI.global.instance<CustomContext>() context
context
}
} }
}
} }

View File

@@ -13,6 +13,7 @@ class ApplicationInfoConfigModule(getConfig: () -> Config) : ConfigModule(getCon
val debug: Boolean by getConfig() val debug: Boolean by getConfig()
companion object { companion object {
fun register(config: Config) = ApplicationInfoConfigModule { config.getConfig("android.app") } fun register(config: Config) =
ApplicationInfoConfigModule { config.getConfig("android.app") }
} }
} }

View File

@@ -28,6 +28,7 @@ class FilesConfigModule(getConfig: () -> Config) : ConfigModule(getConfig) {
val packageDir: String by getConfig() val packageDir: String by getConfig()
companion object { companion object {
fun register(config: Config) = FilesConfigModule { config.getConfig("android.files") } fun register(config: Config) =
FilesConfigModule { config.getConfig("android.files") }
} }
} }

View File

@@ -10,16 +10,13 @@ class SystemConfigModule(val getConfig: () -> Config) : ConfigModule(getConfig)
val propertyPrefix = "properties." val propertyPrefix = "properties."
fun getStringProperty(property: String) = getConfig().getString("$propertyPrefix$property")!! fun getStringProperty(property: String) = getConfig().getString("$propertyPrefix$property")!!
fun getIntProperty(property: String) = getConfig().getInt("$propertyPrefix$property") fun getIntProperty(property: String) = getConfig().getInt("$propertyPrefix$property")
fun getLongProperty(property: String) = getConfig().getLong("$propertyPrefix$property") fun getLongProperty(property: String) = getConfig().getLong("$propertyPrefix$property")
fun getBooleanProperty(property: String) = getConfig().getBoolean("$propertyPrefix$property") fun getBooleanProperty(property: String) = getConfig().getBoolean("$propertyPrefix$property")
fun hasProperty(property: String) = getConfig().hasPath("$propertyPrefix$property") fun hasProperty(property: String) = getConfig().hasPath("$propertyPrefix$property")
companion object { companion object {
fun register(config: Config) = SystemConfigModule { config.getConfig("android.system") } fun register(config: Config) =
SystemConfigModule { config.getConfig("android.system") }
} }
} }

View File

@@ -20,6 +20,7 @@ import java.util.Calendar
@Suppress("UNCHECKED_CAST") @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>()
private val columnCache = mutableMapOf<String, Int>() private val columnCache = mutableMapOf<String, Int>()
private var lastReturnWasNull = false private var lastReturnWasNull = false
@@ -28,10 +29,9 @@ class ScrollableResultSet(val parent: ResultSet) : ResultSet by parent {
val parentMetadata = parent.metaData val parentMetadata = parent.metaData
val columnCount = parentMetadata.columnCount val columnCount = parentMetadata.columnCount
val columnLabels = val columnLabels = (1..columnCount).map {
(1..columnCount).map { parentMetadata.getColumnLabel(it)
parentMetadata.getColumnLabel(it) }.toTypedArray()
}.toTypedArray()
init { init {
val columnCount = columnCount val columnCount = columnCount
@@ -43,11 +43,10 @@ class ScrollableResultSet(val parent: ResultSet) : ResultSet by parent {
// Fill cache // Fill cache
while (parent.next()) { while (parent.next()) {
cachedContent += cachedContent += ResultSetEntry().apply {
ResultSetEntry().apply { for (i in 1..columnCount)
for (i in 1..columnCount) data += parent.getObject(i)
data += parent.getObject(i) }
}
resultSetLength++ resultSetLength++
} }
} }
@@ -93,121 +92,67 @@ class ScrollableResultSet(val parent: ResultSet) : ResultSet by parent {
return obj(columnLabel) as NClob return obj(columnLabel) as NClob
} }
override fun updateNString( override fun updateNString(columnIndex: Int, nString: String?) {
columnIndex: Int,
nString: String?,
) {
notImplemented() notImplemented()
} }
override fun updateNString( override fun updateNString(columnLabel: String?, nString: String?) {
columnLabel: String?,
nString: String?,
) {
notImplemented() notImplemented()
} }
override fun updateBinaryStream( override fun updateBinaryStream(columnIndex: Int, x: InputStream?, length: Int) {
columnIndex: Int,
x: InputStream?,
length: Int,
) {
notImplemented() notImplemented()
} }
override fun updateBinaryStream( override fun updateBinaryStream(columnLabel: String?, x: InputStream?, length: Int) {
columnLabel: String?,
x: InputStream?,
length: Int,
) {
notImplemented() notImplemented()
} }
override fun updateBinaryStream( override fun updateBinaryStream(columnIndex: Int, x: InputStream?, length: Long) {
columnIndex: Int,
x: InputStream?,
length: Long,
) {
notImplemented() notImplemented()
} }
override fun updateBinaryStream( override fun updateBinaryStream(columnLabel: String?, x: InputStream?, length: Long) {
columnLabel: String?,
x: InputStream?,
length: Long,
) {
notImplemented() notImplemented()
} }
override fun updateBinaryStream( override fun updateBinaryStream(columnIndex: Int, x: InputStream?) {
columnIndex: Int,
x: InputStream?,
) {
notImplemented() notImplemented()
} }
override fun updateBinaryStream( override fun updateBinaryStream(columnLabel: String?, x: InputStream?) {
columnLabel: String?,
x: InputStream?,
) {
notImplemented() notImplemented()
} }
override fun updateTimestamp( override fun updateTimestamp(columnIndex: Int, x: Timestamp?) {
columnIndex: Int,
x: Timestamp?,
) {
notImplemented() notImplemented()
} }
override fun updateTimestamp( override fun updateTimestamp(columnLabel: String?, x: Timestamp?) {
columnLabel: String?,
x: Timestamp?,
) {
notImplemented() notImplemented()
} }
override fun updateNCharacterStream( override fun updateNCharacterStream(columnIndex: Int, x: Reader?, length: Long) {
columnIndex: Int,
x: Reader?,
length: Long,
) {
notImplemented() notImplemented()
} }
override fun updateNCharacterStream( override fun updateNCharacterStream(columnLabel: String?, reader: Reader?, length: Long) {
columnLabel: String?,
reader: Reader?,
length: Long,
) {
notImplemented() notImplemented()
} }
override fun updateNCharacterStream( override fun updateNCharacterStream(columnIndex: Int, x: Reader?) {
columnIndex: Int,
x: Reader?,
) {
notImplemented() notImplemented()
} }
override fun updateNCharacterStream( override fun updateNCharacterStream(columnLabel: String?, reader: Reader?) {
columnLabel: String?,
reader: Reader?,
) {
notImplemented() notImplemented()
} }
override fun updateInt( override fun updateInt(columnIndex: Int, x: Int) {
columnIndex: Int,
x: Int,
) {
notImplemented() notImplemented()
} }
override fun updateInt( override fun updateInt(columnLabel: String?, x: Int) {
columnLabel: String?,
x: Int,
) {
notImplemented() notImplemented()
} }
@@ -225,18 +170,12 @@ class ScrollableResultSet(val parent: ResultSet) : ResultSet by parent {
notImplemented() notImplemented()
} }
override fun getDate( override fun getDate(columnIndex: Int, cal: Calendar?): Date {
columnIndex: Int,
cal: Calendar?,
): Date {
// TODO Maybe? // TODO Maybe?
notImplemented() notImplemented()
} }
override fun getDate( override fun getDate(columnLabel: String?, cal: Calendar?): Date {
columnLabel: String?,
cal: Calendar?,
): Date {
// TODO Maybe? // TODO Maybe?
notImplemented() notImplemented()
} }
@@ -246,17 +185,11 @@ class ScrollableResultSet(val parent: ResultSet) : ResultSet by parent {
notImplemented() notImplemented()
} }
override fun updateFloat( override fun updateFloat(columnIndex: Int, x: Float) {
columnIndex: Int,
x: Float,
) {
notImplemented() notImplemented()
} }
override fun updateFloat( override fun updateFloat(columnLabel: String?, x: Float) {
columnLabel: String?,
x: Float,
) {
notImplemented() notImplemented()
} }
@@ -272,18 +205,12 @@ class ScrollableResultSet(val parent: ResultSet) : ResultSet by parent {
return cursor - 1 < resultSetLength return cursor - 1 < resultSetLength
} }
override fun getBigDecimal( override fun getBigDecimal(columnIndex: Int, scale: Int): BigDecimal {
columnIndex: Int,
scale: Int,
): BigDecimal {
// TODO Maybe? // TODO Maybe?
notImplemented() notImplemented()
} }
override fun getBigDecimal( override fun getBigDecimal(columnLabel: String?, scale: Int): BigDecimal {
columnLabel: String?,
scale: Int,
): BigDecimal {
// TODO Maybe? // TODO Maybe?
notImplemented() notImplemented()
} }
@@ -296,17 +223,11 @@ class ScrollableResultSet(val parent: ResultSet) : ResultSet by parent {
return obj(columnLabel) as BigDecimal return obj(columnLabel) as BigDecimal
} }
override fun updateBytes( override fun updateBytes(columnIndex: Int, x: ByteArray?) {
columnIndex: Int,
x: ByteArray?,
) {
notImplemented() notImplemented()
} }
override fun updateBytes( override fun updateBytes(columnLabel: String?, x: ByteArray?) {
columnLabel: String?,
x: ByteArray?,
) {
notImplemented() notImplemented()
} }
@@ -328,18 +249,12 @@ class ScrollableResultSet(val parent: ResultSet) : ResultSet by parent {
notImplemented() notImplemented()
} }
override fun getTime( override fun getTime(columnIndex: Int, cal: Calendar?): Time {
columnIndex: Int,
cal: Calendar?,
): Time {
// TODO Maybe? // TODO Maybe?
notImplemented() notImplemented()
} }
override fun getTime( override fun getTime(columnLabel: String?, cal: Calendar?): Time {
columnLabel: String?,
cal: Calendar?,
): Time {
// TODO Maybe? // TODO Maybe?
notImplemented() notImplemented()
} }
@@ -413,49 +328,27 @@ class ScrollableResultSet(val parent: ResultSet) : ResultSet by parent {
return cursorValid() return cursorValid()
} }
override fun updateAsciiStream( override fun updateAsciiStream(columnIndex: Int, x: InputStream?, length: Int) {
columnIndex: Int,
x: InputStream?,
length: Int,
) {
notImplemented() notImplemented()
} }
override fun updateAsciiStream( override fun updateAsciiStream(columnLabel: String?, x: InputStream?, length: Int) {
columnLabel: String?,
x: InputStream?,
length: Int,
) {
notImplemented() notImplemented()
} }
override fun updateAsciiStream( override fun updateAsciiStream(columnIndex: Int, x: InputStream?, length: Long) {
columnIndex: Int,
x: InputStream?,
length: Long,
) {
notImplemented() notImplemented()
} }
override fun updateAsciiStream( override fun updateAsciiStream(columnLabel: String?, x: InputStream?, length: Long) {
columnLabel: String?,
x: InputStream?,
length: Long,
) {
notImplemented() notImplemented()
} }
override fun updateAsciiStream( override fun updateAsciiStream(columnIndex: Int, x: InputStream?) {
columnIndex: Int,
x: InputStream?,
) {
notImplemented() notImplemented()
} }
override fun updateAsciiStream( override fun updateAsciiStream(columnLabel: String?, x: InputStream?) {
columnLabel: String?,
x: InputStream?,
) {
notImplemented() notImplemented()
} }
@@ -467,107 +360,61 @@ class ScrollableResultSet(val parent: ResultSet) : ResultSet by parent {
return obj(columnLabel) as URL return obj(columnLabel) as URL
} }
override fun updateShort( override fun updateShort(columnIndex: Int, x: Short) {
columnIndex: Int,
x: Short,
) {
notImplemented() notImplemented()
} }
override fun updateShort( override fun updateShort(columnLabel: String?, x: Short) {
columnLabel: String?,
x: Short,
) {
notImplemented() notImplemented()
} }
override fun getType() = ResultSet.TYPE_SCROLL_INSENSITIVE override fun getType() = ResultSet.TYPE_SCROLL_INSENSITIVE
override fun updateNClob( override fun updateNClob(columnIndex: Int, nClob: NClob?) {
columnIndex: Int,
nClob: NClob?,
) {
notImplemented() notImplemented()
} }
override fun updateNClob( override fun updateNClob(columnLabel: String?, nClob: NClob?) {
columnLabel: String?,
nClob: NClob?,
) {
notImplemented() notImplemented()
} }
override fun updateNClob( override fun updateNClob(columnIndex: Int, reader: Reader?, length: Long) {
columnIndex: Int,
reader: Reader?,
length: Long,
) {
notImplemented() notImplemented()
} }
override fun updateNClob( override fun updateNClob(columnLabel: String?, reader: Reader?, length: Long) {
columnLabel: String?,
reader: Reader?,
length: Long,
) {
notImplemented() notImplemented()
} }
override fun updateNClob( override fun updateNClob(columnIndex: Int, reader: Reader?) {
columnIndex: Int,
reader: Reader?,
) {
notImplemented() notImplemented()
} }
override fun updateNClob( override fun updateNClob(columnLabel: String?, reader: Reader?) {
columnLabel: String?,
reader: Reader?,
) {
notImplemented() notImplemented()
} }
override fun updateRef( override fun updateRef(columnIndex: Int, x: Ref?) {
columnIndex: Int,
x: Ref?,
) {
notImplemented() notImplemented()
} }
override fun updateRef( override fun updateRef(columnLabel: String?, x: Ref?) {
columnLabel: String?,
x: Ref?,
) {
notImplemented() notImplemented()
} }
override fun updateObject( override fun updateObject(columnIndex: Int, x: Any?, scaleOrLength: Int) {
columnIndex: Int,
x: Any?,
scaleOrLength: Int,
) {
notImplemented() notImplemented()
} }
override fun updateObject( override fun updateObject(columnIndex: Int, x: Any?) {
columnIndex: Int,
x: Any?,
) {
notImplemented() notImplemented()
} }
override fun updateObject( override fun updateObject(columnLabel: String?, x: Any?, scaleOrLength: Int) {
columnLabel: String?,
x: Any?,
scaleOrLength: Int,
) {
notImplemented() notImplemented()
} }
override fun updateObject( override fun updateObject(columnLabel: String?, x: Any?) {
columnLabel: String?,
x: Any?,
) {
notImplemented() notImplemented()
} }
@@ -575,17 +422,11 @@ class ScrollableResultSet(val parent: ResultSet) : ResultSet by parent {
internalMove(resultSetLength + 1) internalMove(resultSetLength + 1)
} }
override fun updateLong( override fun updateLong(columnIndex: Int, x: Long) {
columnIndex: Int,
x: Long,
) {
notImplemented() notImplemented()
} }
override fun updateLong( override fun updateLong(columnLabel: String?, x: Long) {
columnLabel: String?,
x: Long,
) {
notImplemented() notImplemented()
} }
@@ -599,47 +440,27 @@ class ScrollableResultSet(val parent: ResultSet) : ResultSet by parent {
notImplemented() notImplemented()
} }
override fun updateClob( override fun updateClob(columnIndex: Int, x: Clob?) {
columnIndex: Int,
x: Clob?,
) {
notImplemented() notImplemented()
} }
override fun updateClob( override fun updateClob(columnLabel: String?, x: Clob?) {
columnLabel: String?,
x: Clob?,
) {
notImplemented() notImplemented()
} }
override fun updateClob( override fun updateClob(columnIndex: Int, reader: Reader?, length: Long) {
columnIndex: Int,
reader: Reader?,
length: Long,
) {
notImplemented() notImplemented()
} }
override fun updateClob( override fun updateClob(columnLabel: String?, reader: Reader?, length: Long) {
columnLabel: String?,
reader: Reader?,
length: Long,
) {
notImplemented() notImplemented()
} }
override fun updateClob( override fun updateClob(columnIndex: Int, reader: Reader?) {
columnIndex: Int,
reader: Reader?,
) {
notImplemented() notImplemented()
} }
override fun updateClob( override fun updateClob(columnLabel: String?, reader: Reader?) {
columnLabel: String?,
reader: Reader?,
) {
notImplemented() notImplemented()
} }
@@ -659,31 +480,19 @@ class ScrollableResultSet(val parent: ResultSet) : ResultSet by parent {
return obj(columnLabel) as String? return obj(columnLabel) as String?
} }
override fun updateSQLXML( override fun updateSQLXML(columnIndex: Int, xmlObject: SQLXML?) {
columnIndex: Int,
xmlObject: SQLXML?,
) {
notImplemented() notImplemented()
} }
override fun updateSQLXML( override fun updateSQLXML(columnLabel: String?, xmlObject: SQLXML?) {
columnLabel: String?,
xmlObject: SQLXML?,
) {
notImplemented() notImplemented()
} }
override fun updateDate( override fun updateDate(columnIndex: Int, x: Date?) {
columnIndex: Int,
x: Date?,
) {
notImplemented() notImplemented()
} }
override fun updateDate( override fun updateDate(columnLabel: String?, x: Date?) {
columnLabel: String?,
x: Date?,
) {
notImplemented() notImplemented()
} }
@@ -695,33 +504,21 @@ class ScrollableResultSet(val parent: ResultSet) : ResultSet by parent {
return obj(columnLabel) return obj(columnLabel)
} }
override fun getObject( override fun getObject(columnIndex: Int, map: MutableMap<String, Class<*>>?): Any {
columnIndex: Int,
map: MutableMap<String, Class<*>>?,
): Any {
// TODO Maybe? // TODO Maybe?
notImplemented() notImplemented()
} }
override fun getObject( override fun getObject(columnLabel: String?, map: MutableMap<String, Class<*>>?): Any {
columnLabel: String?,
map: MutableMap<String, Class<*>>?,
): Any {
// TODO Maybe? // TODO Maybe?
notImplemented() notImplemented()
} }
override fun <T : Any?> getObject( override fun <T : Any?> getObject(columnIndex: Int, type: Class<T>?): T {
columnIndex: Int,
type: Class<T>?,
): T {
return obj(columnIndex) as T return obj(columnIndex) as T
} }
override fun <T : Any?> getObject( override fun <T : Any?> getObject(columnLabel: String?, type: Class<T>?): T {
columnLabel: String?,
type: Class<T>?,
): T {
return obj(columnLabel) as T return obj(columnLabel) as T
} }
@@ -730,17 +527,11 @@ class ScrollableResultSet(val parent: ResultSet) : ResultSet by parent {
return cursorValid() return cursorValid()
} }
override fun updateDouble( override fun updateDouble(columnIndex: Int, x: Double) {
columnIndex: Int,
x: Double,
) {
notImplemented() notImplemented()
} }
override fun updateDouble( override fun updateDouble(columnLabel: String?, x: Double) {
columnLabel: String?,
x: Double,
) {
notImplemented() notImplemented()
} }
@@ -774,61 +565,35 @@ class ScrollableResultSet(val parent: ResultSet) : ResultSet by parent {
notImplemented() notImplemented()
} }
override fun updateBlob( override fun updateBlob(columnIndex: Int, x: Blob?) {
columnIndex: Int,
x: Blob?,
) {
notImplemented() notImplemented()
} }
override fun updateBlob( override fun updateBlob(columnLabel: String?, x: Blob?) {
columnLabel: String?,
x: Blob?,
) {
notImplemented() notImplemented()
} }
override fun updateBlob( override fun updateBlob(columnIndex: Int, inputStream: InputStream?, length: Long) {
columnIndex: Int,
inputStream: InputStream?,
length: Long,
) {
notImplemented() notImplemented()
} }
override fun updateBlob( override fun updateBlob(columnLabel: String?, inputStream: InputStream?, length: Long) {
columnLabel: String?,
inputStream: InputStream?,
length: Long,
) {
notImplemented() notImplemented()
} }
override fun updateBlob( override fun updateBlob(columnIndex: Int, inputStream: InputStream?) {
columnIndex: Int,
inputStream: InputStream?,
) {
notImplemented() notImplemented()
} }
override fun updateBlob( override fun updateBlob(columnLabel: String?, inputStream: InputStream?) {
columnLabel: String?,
inputStream: InputStream?,
) {
notImplemented() notImplemented()
} }
override fun updateByte( override fun updateByte(columnIndex: Int, x: Byte) {
columnIndex: Int,
x: Byte,
) {
notImplemented() notImplemented()
} }
override fun updateByte( override fun updateByte(columnLabel: String?, x: Byte) {
columnLabel: String?,
x: Byte,
) {
notImplemented() notImplemented()
} }
@@ -862,17 +627,11 @@ class ScrollableResultSet(val parent: ResultSet) : ResultSet by parent {
notImplemented() notImplemented()
} }
override fun updateString( override fun updateString(columnIndex: Int, x: String?) {
columnIndex: Int,
x: String?,
) {
notImplemented() notImplemented()
} }
override fun updateString( override fun updateString(columnLabel: String?, x: String?) {
columnLabel: String?,
x: String?,
) {
notImplemented() notImplemented()
} }
@@ -892,17 +651,11 @@ class ScrollableResultSet(val parent: ResultSet) : ResultSet by parent {
return cursor - 1 < resultSetLength return cursor - 1 < resultSetLength
} }
override fun updateBoolean( override fun updateBoolean(columnIndex: Int, x: Boolean) {
columnIndex: Int,
x: Boolean,
) {
notImplemented() notImplemented()
} }
override fun updateBoolean( override fun updateBoolean(columnLabel: String?, x: Boolean) {
columnLabel: String?,
x: Boolean,
) {
notImplemented() notImplemented()
} }
@@ -912,17 +665,11 @@ class ScrollableResultSet(val parent: ResultSet) : ResultSet by parent {
override fun rowUpdated() = false override fun rowUpdated() = false
override fun updateBigDecimal( override fun updateBigDecimal(columnIndex: Int, x: BigDecimal?) {
columnIndex: Int,
x: BigDecimal?,
) {
notImplemented() notImplemented()
} }
override fun updateBigDecimal( override fun updateBigDecimal(columnLabel: String?, x: BigDecimal?) {
columnLabel: String?,
x: BigDecimal?,
) {
notImplemented() notImplemented()
} }
@@ -942,17 +689,11 @@ class ScrollableResultSet(val parent: ResultSet) : ResultSet by parent {
return getBinaryStream(columnLabel) return getBinaryStream(columnLabel)
} }
override fun updateTime( override fun updateTime(columnIndex: Int, x: Time?) {
columnIndex: Int,
x: Time?,
) {
notImplemented() notImplemented()
} }
override fun updateTime( override fun updateTime(columnLabel: String?, x: Time?) {
columnLabel: String?,
x: Time?,
) {
notImplemented() notImplemented()
} }
@@ -966,18 +707,12 @@ class ScrollableResultSet(val parent: ResultSet) : ResultSet by parent {
notImplemented() notImplemented()
} }
override fun getTimestamp( override fun getTimestamp(columnIndex: Int, cal: Calendar?): Timestamp {
columnIndex: Int,
cal: Calendar?,
): Timestamp {
// TODO Maybe? // TODO Maybe?
notImplemented() notImplemented()
} }
override fun getTimestamp( override fun getTimestamp(columnLabel: String?, cal: Calendar?): Timestamp {
columnLabel: String?,
cal: Calendar?,
): Timestamp {
// TODO Maybe? // TODO Maybe?
notImplemented() notImplemented()
} }
@@ -994,17 +729,11 @@ class ScrollableResultSet(val parent: ResultSet) : ResultSet by parent {
override fun getConcurrency() = ResultSet.CONCUR_READ_ONLY override fun getConcurrency() = ResultSet.CONCUR_READ_ONLY
override fun updateRowId( override fun updateRowId(columnIndex: Int, x: RowId?) {
columnIndex: Int,
x: RowId?,
) {
notImplemented() notImplemented()
} }
override fun updateRowId( override fun updateRowId(columnLabel: String?, x: RowId?) {
columnLabel: String?,
x: RowId?,
) {
notImplemented() notImplemented()
} }
@@ -1016,17 +745,11 @@ class ScrollableResultSet(val parent: ResultSet) : ResultSet by parent {
return getBinaryStream(columnLabel).reader() return getBinaryStream(columnLabel).reader()
} }
override fun updateArray( override fun updateArray(columnIndex: Int, x: Array?) {
columnIndex: Int,
x: Array?,
) {
notImplemented() notImplemented()
} }
override fun updateArray( override fun updateArray(columnLabel: String?, x: Array?) {
columnLabel: String?,
x: Array?,
) {
notImplemented() notImplemented()
} }
@@ -1091,13 +814,9 @@ class ScrollableResultSet(val parent: ResultSet) : ResultSet by parent {
override fun getMetaData(): ResultSetMetaData { override fun getMetaData(): ResultSetMetaData {
return object : ResultSetMetaData by parentMetadata { return object : ResultSetMetaData by parentMetadata {
override fun isReadOnly(column: Int) = true override fun isReadOnly(column: Int) = true
override fun isWritable(column: Int) = false override fun isWritable(column: Int) = false
override fun isDefinitelyWritable(column: Int) = false override fun isDefinitelyWritable(column: Int) = false
override fun getColumnCount() = this@ScrollableResultSet.columnCount override fun getColumnCount() = this@ScrollableResultSet.columnCount
override fun getColumnLabel(column: Int): String { override fun getColumnLabel(column: Int): String {
return columnLabels[column - 1] return columnLabels[column - 1]
} }
@@ -1112,49 +831,27 @@ class ScrollableResultSet(val parent: ResultSet) : ResultSet by parent {
return (obj(columnLabel) as ByteArray).inputStream() return (obj(columnLabel) as ByteArray).inputStream()
} }
override fun updateCharacterStream( override fun updateCharacterStream(columnIndex: Int, x: Reader?, length: Int) {
columnIndex: Int,
x: Reader?,
length: Int,
) {
notImplemented() notImplemented()
} }
override fun updateCharacterStream( override fun updateCharacterStream(columnLabel: String?, reader: Reader?, length: Int) {
columnLabel: String?,
reader: Reader?,
length: Int,
) {
notImplemented() notImplemented()
} }
override fun updateCharacterStream( override fun updateCharacterStream(columnIndex: Int, x: Reader?, length: Long) {
columnIndex: Int,
x: Reader?,
length: Long,
) {
notImplemented() notImplemented()
} }
override fun updateCharacterStream( override fun updateCharacterStream(columnLabel: String?, reader: Reader?, length: Long) {
columnLabel: String?,
reader: Reader?,
length: Long,
) {
notImplemented() notImplemented()
} }
override fun updateCharacterStream( override fun updateCharacterStream(columnIndex: Int, x: Reader?) {
columnIndex: Int,
x: Reader?,
) {
notImplemented() notImplemented()
} }
override fun updateCharacterStream( override fun updateCharacterStream(columnLabel: String?, reader: Reader?) {
columnLabel: String?,
reader: Reader?,
) {
notImplemented() notImplemented()
} }

View File

@@ -9,8 +9,7 @@ package xyz.nulldev.androidcompat.io.sharedprefs
import android.content.SharedPreferences import android.content.SharedPreferences
import com.russhwolf.settings.ExperimentalSettingsApi import com.russhwolf.settings.ExperimentalSettingsApi
import com.russhwolf.settings.PropertiesSettings import com.russhwolf.settings.PreferencesSettings
import com.russhwolf.settings.Settings
import com.russhwolf.settings.serialization.decodeValue import com.russhwolf.settings.serialization.decodeValue
import com.russhwolf.settings.serialization.decodeValueOrNull import com.russhwolf.settings.serialization.decodeValueOrNull
import com.russhwolf.settings.serialization.encodeValue import com.russhwolf.settings.serialization.encodeValue
@@ -18,68 +17,21 @@ import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.SerializationException import kotlinx.serialization.SerializationException
import kotlinx.serialization.builtins.SetSerializer import kotlinx.serialization.builtins.SetSerializer
import kotlinx.serialization.builtins.serializer import kotlinx.serialization.builtins.serializer
import mu.KotlinLogging import java.util.prefs.PreferenceChangeListener
import xyz.nulldev.androidcompat.util.SafePath import java.util.prefs.Preferences
import xyz.nulldev.ts.config.ApplicationRootDir
import java.util.Properties
import kotlin.io.path.Path
import kotlin.io.path.createParentDirectories
import kotlin.io.path.deleteIfExists
import kotlin.io.path.exists
import kotlin.io.path.inputStream
import kotlin.io.path.outputStream
@OptIn(ExperimentalSerializationApi::class, ExperimentalSettingsApi::class) @OptIn(ExperimentalSerializationApi::class, ExperimentalSettingsApi::class)
class JavaSharedPreferences(key: String) : SharedPreferences { class JavaSharedPreferences(key: String) : SharedPreferences {
companion object { private val javaPreferences = Preferences.userRoot().node("suwayomi/tachidesk/$key")
private val logger = KotlinLogging.logger {} private val preferences = PreferencesSettings(javaPreferences)
} private val listeners = mutableMapOf<SharedPreferences.OnSharedPreferenceChangeListener, PreferenceChangeListener>()
private val file =
Path(
ApplicationRootDir,
"settings",
"${SafePath.buildValidFilename(key)}.xml",
)
private val properties =
Properties().also { properties ->
try {
if (file.exists()) {
file.inputStream().use { properties.loadFromXML(it) }
}
} catch (e: Exception) {
logger.error(e) { "Error loading settings from $key" }
}
}
private val preferences =
PropertiesSettings(
properties,
onModify = { properties ->
try {
if (properties.isEmpty) {
file.deleteIfExists()
} else {
file.createParentDirectories()
file.outputStream().use {
properties.storeToXML(it, null)
}
}
} catch (e: Exception) {
logger.error(e) { "Error saving settings in $key" }
}
},
)
private val listeners = mutableMapOf<SharedPreferences.OnSharedPreferenceChangeListener, (String) -> Unit>()
// TODO: 2021-05-29 Need to find a way to get this working with all pref types // TODO: 2021-05-29 Need to find a way to get this working with all pref types
override fun getAll(): MutableMap<String, *> { override fun getAll(): MutableMap<String, *> {
return preferences.keys.associateWith { preferences.getStringOrNull(it) }.toMutableMap() return preferences.keys.associateWith { preferences.getStringOrNull(it) }.toMutableMap()
} }
override fun getString( override fun getString(key: String, defValue: String?): String? {
key: String,
defValue: String?,
): String? {
return if (defValue != null) { return if (defValue != null) {
preferences.getString(key, defValue) preferences.getString(key, defValue)
} else { } else {
@@ -87,10 +39,7 @@ class JavaSharedPreferences(key: String) : SharedPreferences {
} }
} }
override fun getStringSet( override fun getStringSet(key: String, defValues: Set<String>?): Set<String>? {
key: String,
defValues: Set<String>?,
): Set<String>? {
try { try {
return if (defValues != null) { return if (defValues != null) {
preferences.decodeValue(SetSerializer(String.serializer()), key, defValues) preferences.decodeValue(SetSerializer(String.serializer()), key, defValues)
@@ -102,31 +51,19 @@ class JavaSharedPreferences(key: String) : SharedPreferences {
} }
} }
override fun getInt( override fun getInt(key: String, defValue: Int): Int {
key: String,
defValue: Int,
): Int {
return preferences.getInt(key, defValue) return preferences.getInt(key, defValue)
} }
override fun getLong( override fun getLong(key: String, defValue: Long): Long {
key: String,
defValue: Long,
): Long {
return preferences.getLong(key, defValue) return preferences.getLong(key, defValue)
} }
override fun getFloat( override fun getFloat(key: String, defValue: Float): Float {
key: String,
defValue: Float,
): Float {
return preferences.getFloat(key, defValue) return preferences.getFloat(key, defValue)
} }
override fun getBoolean( override fun getBoolean(key: String, defValue: Boolean): Boolean {
key: String,
defValue: Boolean,
): Boolean {
return preferences.getBoolean(key, defValue) return preferences.getBoolean(key, defValue)
} }
@@ -135,27 +72,19 @@ class JavaSharedPreferences(key: String) : SharedPreferences {
} }
override fun edit(): SharedPreferences.Editor { override fun edit(): SharedPreferences.Editor {
return Editor(preferences) { key -> return Editor(preferences)
listeners.forEach { (_, listener) ->
listener(key)
}
}
} }
class Editor(private val preferences: Settings, private val notify: (String) -> Unit) : SharedPreferences.Editor { class Editor(private val preferences: PreferencesSettings) : SharedPreferences.Editor {
private val actions = mutableListOf<Action>() private val actions = mutableListOf<Action>()
private sealed class Action { private sealed class Action {
data class Add(val key: String, val value: Any) : Action() data class Add(val key: String, val value: Any) : Action()
data class Remove(val key: String) : Action() data class Remove(val key: String) : Action()
data object Clear : Action() object Clear : Action()
} }
override fun putString( override fun putString(key: String, value: String?): SharedPreferences.Editor {
key: String,
value: String?,
): SharedPreferences.Editor {
if (value != null) { if (value != null) {
actions += Action.Add(key, value) actions += Action.Add(key, value)
} else { } else {
@@ -166,7 +95,7 @@ class JavaSharedPreferences(key: String) : SharedPreferences {
override fun putStringSet( override fun putStringSet(
key: String, key: String,
values: MutableSet<String>?, values: MutableSet<String>?
): SharedPreferences.Editor { ): SharedPreferences.Editor {
if (values != null) { if (values != null) {
actions += Action.Add(key, values) actions += Action.Add(key, values)
@@ -176,34 +105,22 @@ class JavaSharedPreferences(key: String) : SharedPreferences {
return this return this
} }
override fun putInt( override fun putInt(key: String, value: Int): SharedPreferences.Editor {
key: String,
value: Int,
): SharedPreferences.Editor {
actions += Action.Add(key, value) actions += Action.Add(key, value)
return this return this
} }
override fun putLong( override fun putLong(key: String, value: Long): SharedPreferences.Editor {
key: String,
value: Long,
): SharedPreferences.Editor {
actions += Action.Add(key, value) actions += Action.Add(key, value)
return this return this
} }
override fun putFloat( override fun putFloat(key: String, value: Float): SharedPreferences.Editor {
key: String,
value: Float,
): SharedPreferences.Editor {
actions += Action.Add(key, value) actions += Action.Add(key, value)
return this return this
} }
override fun putBoolean( override fun putBoolean(key: String, value: Boolean): SharedPreferences.Editor {
key: String,
value: Boolean,
): SharedPreferences.Editor {
actions += Action.Add(key, value) actions += Action.Add(key, value)
return this return this
} }
@@ -231,17 +148,14 @@ class JavaSharedPreferences(key: String) : SharedPreferences {
actions.forEach { actions.forEach {
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
when (it) { when (it) {
is Action.Add -> { is Action.Add -> when (val value = it.value) {
when (val value = it.value) { is Set<*> -> preferences.encodeValue(SetSerializer(String.serializer()), it.key, value as Set<String>)
is Set<*> -> preferences.encodeValue(SetSerializer(String.serializer()), it.key, value as Set<String>) is String -> preferences.putString(it.key, value)
is String -> preferences.putString(it.key, value) is Int -> preferences.putInt(it.key, value)
is Int -> preferences.putInt(it.key, value) is Long -> preferences.putLong(it.key, value)
is Long -> preferences.putLong(it.key, value) is Float -> preferences.putFloat(it.key, value)
is Float -> preferences.putFloat(it.key, value) is Double -> preferences.putDouble(it.key, value)
is Double -> preferences.putDouble(it.key, value) is Boolean -> preferences.putBoolean(it.key, value)
is Boolean -> preferences.putBoolean(it.key, value)
}
notify(it.key)
} }
is Action.Remove -> { is Action.Remove -> {
preferences.remove(it.key) preferences.remove(it.key)
@@ -256,8 +170,6 @@ class JavaSharedPreferences(key: String) : SharedPreferences {
preferences.remove(key) preferences.remove(key)
} }
} }
notify(it.key)
} }
Action.Clear -> preferences.clear() Action.Clear -> preferences.clear()
} }
@@ -266,18 +178,22 @@ class JavaSharedPreferences(key: String) : SharedPreferences {
} }
override fun registerOnSharedPreferenceChangeListener(listener: SharedPreferences.OnSharedPreferenceChangeListener) { override fun registerOnSharedPreferenceChangeListener(listener: SharedPreferences.OnSharedPreferenceChangeListener) {
val javaListener: (String) -> Unit = { val javaListener = PreferenceChangeListener {
listener.onSharedPreferenceChanged(this, it) listener.onSharedPreferenceChanged(this, it.key)
} }
listeners[listener] = javaListener listeners[listener] = javaListener
javaPreferences.addPreferenceChangeListener(javaListener)
} }
override fun unregisterOnSharedPreferenceChangeListener(listener: SharedPreferences.OnSharedPreferenceChangeListener) { override fun unregisterOnSharedPreferenceChangeListener(listener: SharedPreferences.OnSharedPreferenceChangeListener) {
listeners.remove(listener) val registeredListener = listeners.remove(listener)
if (registeredListener != null) {
javaPreferences.removePreferenceChangeListener(registeredListener)
}
} }
fun deleteAll(): Boolean { fun deleteAll(): Boolean {
preferences.clear() javaPreferences.removeNode()
return true return true
} }
} }

View File

@@ -20,47 +20,42 @@ data class InstalledPackage(val root: File) {
val icon = File(root, "icon.png") val icon = File(root, "icon.png")
val info: PackageInfo val info: PackageInfo
get() = get() = ApkParsers.getMetaInfo(apk).toPackageInfo(apk).also {
ApkParsers.getMetaInfo(apk).toPackageInfo(apk).also { val parsed = ApkFile(apk)
val parsed = ApkFile(apk) val dbFactory = DocumentBuilderFactory.newInstance()
val dbFactory = DocumentBuilderFactory.newInstance() val dBuilder = dbFactory.newDocumentBuilder()
val dBuilder = dbFactory.newDocumentBuilder() val doc = parsed.manifestXml.byteInputStream().use {
val doc = dBuilder.parse(it)
parsed.manifestXml.byteInputStream().use {
dBuilder.parse(it)
}
it.applicationInfo.metaData =
Bundle().apply {
val appTag = doc.getElementsByTagName("application").item(0)
appTag?.childNodes?.toList()?.filter {
it.nodeType == Node.ELEMENT_NODE
}?.map {
it as Element
}?.filter {
it.tagName == "meta-data"
}?.map {
putString(
it.attributes.getNamedItem("android:name").nodeValue,
it.attributes.getNamedItem("android:value").nodeValue,
)
}
}
it.signatures =
(
parsed.apkSingers.flatMap { it.certificateMetas }
// + parsed.apkV2Singers.flatMap { it.certificateMetas }
) // Blocked by: https://github.com/hsiafan/apk-parser/issues/72
.map { Signature(it.data) }.toTypedArray()
} }
it.applicationInfo.metaData = Bundle().apply {
val appTag = doc.getElementsByTagName("application").item(0)
appTag?.childNodes?.toList()?.filter {
it.nodeType == Node.ELEMENT_NODE
}?.map {
it as Element
}?.filter {
it.tagName == "meta-data"
}?.map {
putString(
it.attributes.getNamedItem("android:name").nodeValue,
it.attributes.getNamedItem("android:value").nodeValue
)
}
}
it.signatures = (
parsed.apkSingers.flatMap { it.certificateMetas }
/*+ parsed.apkV2Singers.flatMap { it.certificateMetas }*/
) // Blocked by: https://github.com/hsiafan/apk-parser/issues/72
.map { Signature(it.data) }.toTypedArray()
}
fun verify(): Boolean { fun verify(): Boolean {
val res = val res = ApkVerifier.Builder(apk)
ApkVerifier.Builder(apk) .build()
.build() .verify()
.verify()
return res.isVerified return res.isVerified
} }
@@ -69,12 +64,11 @@ data class InstalledPackage(val root: File) {
try { try {
val icons = ApkFile(apk).allIcons val icons = ApkFile(apk).allIcons
val read = val read = icons.filter { it.isFile }.map {
icons.filter { it.isFile }.map { it.data.inputStream().use {
it.data.inputStream().use { ImageIO.read(it)
ImageIO.read(it) }
} }.sortedByDescending { it.width * it.height }.firstOrNull() ?: return
}.sortedByDescending { it.width * it.height }.firstOrNull() ?: return
ImageIO.write(read, "png", icon) ImageIO.write(read, "png", icon)
} catch (e: Exception) { } catch (e: Exception) {

View File

@@ -25,10 +25,7 @@ class PackageController {
return File(androidFiles.packagesDir, pn) return File(androidFiles.packagesDir, pn)
} }
fun installPackage( fun installPackage(apk: File, allowReinstall: Boolean) {
apk: File,
allowReinstall: Boolean,
) {
val root = findRoot(apk) val root = findRoot(apk)
if (root.exists()) { if (root.exists()) {

View File

@@ -12,18 +12,16 @@ fun ApkMeta.toPackageInfo(apk: File): PackageInfo {
it.versionCode = versionCode.toInt() it.versionCode = versionCode.toInt()
it.versionName = versionName it.versionName = versionName
it.reqFeatures = it.reqFeatures = usesFeatures.map {
usesFeatures.map { FeatureInfo().apply {
FeatureInfo().apply { name = it.name
name = it.name
}
}.toTypedArray()
it.applicationInfo =
ApplicationInfo().apply {
packageName = it.packageName
nonLocalizedLabel = label
sourceDir = apk.absolutePath
} }
}.toTypedArray()
it.applicationInfo = ApplicationInfo().apply {
packageName = it.packageName
nonLocalizedLabel = label
sourceDir = apk.absolutePath
}
} }
} }

View File

@@ -18,10 +18,7 @@ class ServiceSupport {
private val logger = KotlinLogging.logger {} private val logger = KotlinLogging.logger {}
fun startService( fun startService(@Suppress("UNUSED_PARAMETER") context: Context, intent: Intent) {
@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" }
@@ -38,10 +35,7 @@ class ServiceSupport {
} }
} }
fun stopService( fun stopService(@Suppress("UNUSED_PARAMETER") context: Context, intent: Intent) {
@Suppress("UNUSED_PARAMETER") context: Context,
intent: Intent,
) {
val name = intentToClassName(intent) val name = intentToClassName(intent)
stopService(name) stopService(name)
} }

View File

@@ -26,10 +26,7 @@ object KodeinGlobalHelper {
*/ */
@JvmStatic @JvmStatic
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
fun <T : Any> instance( fun <T : Any> instance(type: Class<T>, kodein: DI? = null): T {
type: Class<T>,
kodein: DI? = null,
): T {
return when (type) { return when (type) {
AndroidFiles::class.java -> { AndroidFiles::class.java -> {
val instance: AndroidFiles by (kodein ?: kodein()).instance() val instance: AndroidFiles by (kodein ?: kodein()).instance()

View File

@@ -24,7 +24,5 @@ import java.net.URI
* Utilites to convert between Java and Android Uris. * Utilites to convert between Java and Android Uris.
*/ */
fun Uri.java() = URI(this.toString()) fun Uri.java() = URI(this.toString())
fun Uri.file() = File(this.path) fun Uri.file() = File(this.path)
fun URI.android() = Uri.parse(this.toString())!! fun URI.android() = Uri.parse(this.toString())!!

View File

@@ -1,103 +0,0 @@
package xyz.nulldev.androidcompat.webkit
import android.webkit.CookieManager
import android.webkit.ValueCallback
import android.webkit.WebView
import java.net.CookieHandler
import java.net.HttpCookie
import java.net.URI
@Suppress("DEPRECATION")
class CookieManagerImpl : CookieManager() {
private val cookieHandler = CookieHandler.getDefault() as java.net.CookieManager
private var acceptCookie = true
private var acceptThirdPartyCookies = true
private var allowFileSchemeCookies = false
override fun setAcceptCookie(accept: Boolean) {
acceptCookie = accept
}
override fun acceptCookie(): Boolean {
return acceptCookie
}
override fun setAcceptThirdPartyCookies(
webview: WebView?,
accept: Boolean,
) {
acceptThirdPartyCookies = accept
}
override fun acceptThirdPartyCookies(webview: WebView?): Boolean {
return acceptThirdPartyCookies
}
override fun setCookie(
url: String,
value: String?,
) {
val uri =
if (url.startsWith("http")) {
URI(url)
} else {
URI("http://$url")
}
HttpCookie.parse(value).forEach {
cookieHandler.cookieStore.add(uri, it)
}
}
override fun setCookie(
url: String,
value: String?,
callback: ValueCallback<Boolean>?,
) {
setCookie(url, value)
callback?.onReceiveValue(true)
}
override fun getCookie(url: String): String {
val uri =
if (url.startsWith("http")) {
URI(url)
} else {
URI("http://$url")
}
return cookieHandler.cookieStore.get(uri)
.joinToString("; ") { "${it.name}=${it.value}" }
}
@Deprecated("Deprecated in Java")
override fun removeSessionCookie() {}
override fun removeSessionCookies(callback: ValueCallback<Boolean>?) {}
@Deprecated("Deprecated in Java")
override fun removeExpiredCookie() {}
@Deprecated("Deprecated in Java")
override fun removeAllCookie() {
cookieHandler.cookieStore.removeAll()
}
override fun removeAllCookies(callback: ValueCallback<Boolean>?) {
val removedCookies = cookieHandler.cookieStore.removeAll()
callback?.onReceiveValue(removedCookies)
}
override fun hasCookies(): Boolean {
return cookieHandler.cookieStore.cookies.isNotEmpty()
}
override fun flush() {}
override fun allowFileSchemeCookiesImpl(): Boolean {
return allowFileSchemeCookies
}
override fun setAcceptFileSchemeCookiesImpl(accept: Boolean) {
allowFileSchemeCookies = acceptCookie
}
}

View File

@@ -2,10 +2,10 @@
## TL;DR ## TL;DR
- N/A - N/A
## Suwayomi-Server Changelog ## Tachidesk-Server Changelog
- N/A - N/A
## Suwayomi-WebUI Changelog ## Tachidesk-WebUI Changelog
- N/A - N/A

View File

@@ -7,67 +7,67 @@
- WebUI changes: - WebUI changes:
- Uhh, idk, find out yourself... - Uhh, idk, find out yourself...
## Suwayomi-Server Changelog ## Tachidesk-Server Changelog
- (r1159) v0.6.6 (by @AriaMoradi) - (r1159) v0.6.6 (by @AriaMoradi)
- (r1160) add Chagelog TL;DR (by @AriaMoradi) - (r1160) add Chagelog TL;DR (by @AriaMoradi)
- (r1161) fix Changelog typos (by @AriaMoradi) - (r1161) fix Changelog typos (by @AriaMoradi)
- (r1162) WebView based cloudflare interceptor ([#456](https://github.com/Suwayomi/Suwayomi-Server/pull/456) by @AriaMoradi) - (r1162) WebView based cloudflare interceptor ([#456](https://github.com/Suwayomi/Tachidesk-Server/pull/456) by @AriaMoradi)
- (r1163) update issue mod (by @AriaMoradi) - (r1163) update issue mod (by @AriaMoradi)
- (r1164) better description (by @AriaMoradi) - (r1164) better description (by @AriaMoradi)
- (r1165) fix regex (by @AriaMoradi) - (r1165) fix regex (by @AriaMoradi)
- (r1166) get default User Agent from WebView ([#457](https://github.com/Suwayomi/Suwayomi-Server/pull/457) by @AriaMoradi) - (r1166) get default User Agent from WebView ([#457](https://github.com/Suwayomi/Tachidesk-Server/pull/457) by @AriaMoradi)
- (r1167) implementation of android.graphics.BitmapFactory ([#460](https://github.com/Suwayomi/Suwayomi-Server/pull/460) by @animeavi) - (r1167) implementation of android.graphics.BitmapFactory ([#460](https://github.com/Suwayomi/Tachidesk-Server/pull/460) by @animeavi)
- (r1168) Basic android.graphics Rect and Canvas implementation ([#461](https://github.com/Suwayomi/Suwayomi-Server/pull/461) by @animeavi) - (r1168) Basic android.graphics Rect and Canvas implementation ([#461](https://github.com/Suwayomi/Tachidesk-Server/pull/461) by @animeavi)
- (r1169) Get Playwright working ([#462](https://github.com/Suwayomi/Suwayomi-Server/pull/462) by @Syer10) - (r1169) Get Playwright working ([#462](https://github.com/Suwayomi/Tachidesk-Server/pull/462) by @Syer10)
- (r1170) disable deb release (by @AriaMoradi) - (r1170) disable deb release (by @AriaMoradi)
- (r1171) Fix debian release ([#463](https://github.com/Suwayomi/Suwayomi-Server/pull/463) by @mahor1221) - (r1171) Fix debian release ([#463](https://github.com/Suwayomi/Tachidesk-Server/pull/463) by @mahor1221)
- (r1172) Add better manga thumbnail handling ([#465](https://github.com/Suwayomi/Suwayomi-Server/pull/465) by @Syer10) - (r1172) Add better manga thumbnail handling ([#465](https://github.com/Suwayomi/Tachidesk-Server/pull/465) by @Syer10)
- (r1173) Use extension list fallback if extensions fail to fetch ([#469](https://github.com/Suwayomi/Suwayomi-Server/pull/469) by @Syer10) - (r1173) Use extension list fallback if extensions fail to fetch ([#469](https://github.com/Suwayomi/Tachidesk-Server/pull/469) by @Syer10)
- (r1174) fix when playwright fails on providing a UA (by @AriaMoradi) - (r1174) fix when playwright fails on providing a UA (by @AriaMoradi)
- (r1175) Update CategoryMetaTable.kt (by @AriaMoradi) - (r1175) Update CategoryMetaTable.kt (by @AriaMoradi)
- (r1176) fix CategoryMetaTable reference to CategoryTable ([#473](https://github.com/Suwayomi/Suwayomi-Server/pull/473) by @AriaMoradi) - (r1176) fix CategoryMetaTable reference to CategoryTable ([#473](https://github.com/Suwayomi/Tachidesk-Server/pull/473) by @AriaMoradi)
- (r1177) remove possibly misleading sentence (by @AriaMoradi) - (r1177) remove possibly misleading sentence (by @AriaMoradi)
- (r1178) Clarify and Update (by @AriaMoradi) - (r1178) Clarify and Update (by @AriaMoradi)
- (r1179) Clarify and Update (by @AriaMoradi) - (r1179) Clarify and Update (by @AriaMoradi)
- (r1180) link to Tachiyomi section (by @AriaMoradi) - (r1180) link to Tachiyomi section (by @AriaMoradi)
- (r1181) fix typo (by @AriaMoradi) - (r1181) fix typo (by @AriaMoradi)
- (r1182) Improve Gradle Configuration ([#478](https://github.com/Suwayomi/Suwayomi-Server/pull/478) by @Syer10) - (r1182) Improve Gradle Configuration ([#478](https://github.com/Suwayomi/Tachidesk-Server/pull/478) by @Syer10)
- (r1183) Improve Playwright handling ([#479](https://github.com/Suwayomi/Suwayomi-Server/pull/479) by @Syer10) - (r1183) Improve Playwright handling ([#479](https://github.com/Suwayomi/Tachidesk-Server/pull/479) by @Syer10)
- (r1184) fix ambiguous reference issue on JDK 13+ (by @AriaMoradi) - (r1184) fix ambiguous reference issue on JDK 13+ (by @AriaMoradi)
- (r1185) update gradle version (by @AriaMoradi) - (r1185) update gradle version (by @AriaMoradi)
- (r1186) upgrade dorkbox stuff (by @AriaMoradi) - (r1186) upgrade dorkbox stuff (by @AriaMoradi)
- (r1187) Fixe Dex2Jar and dorkbox dependency issues ([#487](https://github.com/Suwayomi/Suwayomi-Server/pull/487) by @akabhirav) - (r1187) Fixe Dex2Jar and dorkbox dependency issues ([#487](https://github.com/Suwayomi/Tachidesk-Server/pull/487) by @akabhirav)
- (r1188) Fix logging and update system try ([#488](https://github.com/Suwayomi/Suwayomi-Server/pull/488) by @Syer10) - (r1188) Fix logging and update system try ([#488](https://github.com/Suwayomi/Tachidesk-Server/pull/488) by @Syer10)
- (r1189) add support for Extensions Lib 1.4 ([#496](https://github.com/Suwayomi/Suwayomi-Server/pull/496) by @Syer10) - (r1189) add support for Extensions Lib 1.4 ([#496](https://github.com/Suwayomi/Tachidesk-Server/pull/496) by @Syer10)
- (r1190) disable playwright for v0.6.7 (by @AriaMoradi) - (r1190) disable playwright for v0.6.7 (by @AriaMoradi)
- (r1191) Decouple Cache and Download behaviour ([#493](https://github.com/Suwayomi/Suwayomi-Server/pull/493) by @akabhirav) - (r1191) Decouple Cache and Download behaviour ([#493](https://github.com/Suwayomi/Tachidesk-Server/pull/493) by @akabhirav)
- (r1192) rethink image cache ([#498](https://github.com/Suwayomi/Suwayomi-Server/pull/498) by @AriaMoradi) - (r1192) rethink image cache ([#498](https://github.com/Suwayomi/Tachidesk-Server/pull/498) by @AriaMoradi)
- (r1193) fix Page index issues for some providers ([#491](https://github.com/Suwayomi/Suwayomi-Server/pull/491) by @akabhirav) - (r1193) fix Page index issues for some providers ([#491](https://github.com/Suwayomi/Tachidesk-Server/pull/491) by @akabhirav)
- (r1194) Download as CBZ ([#490](https://github.com/Suwayomi/Suwayomi-Server/pull/490) by @akabhirav) - (r1194) Download as CBZ ([#490](https://github.com/Suwayomi/Tachidesk-Server/pull/490) by @akabhirav)
- (r1195) re-order config options (by @AriaMoradi) - (r1195) re-order config options (by @AriaMoradi)
- (r1196) stop using depricated API (by @AriaMoradi) - (r1196) stop using depricated API (by @AriaMoradi)
## Suwayomi-WebUI Changelog ## Tachidesk-WebUI Changelog
- (r964) Created a GridLayout enum and updated all locations to use it. ([#208](https://github.com/Suwayomi/Suwayomi-WebUI/pull/208) by @infix) - (r964) Created a GridLayout enum and updated all locations to use it. ([#208](https://github.com/Suwayomi/Tachidesk-WebUI/pull/208) by @infix)
- (r965) fix library update progress rendering ([#210](https://github.com/Suwayomi/Suwayomi-WebUI/pull/210) by @schroda) - (r965) fix library update progress rendering ([#210](https://github.com/Suwayomi/Tachidesk-WebUI/pull/210) by @schroda)
- (r966) Save reader settings per manga in Meta ([#216](https://github.com/Suwayomi/Suwayomi-WebUI/pull/216) by @schroda) - (r966) Save reader settings per manga in Meta ([#216](https://github.com/Suwayomi/Tachidesk-WebUI/pull/216) by @schroda)
- (r967) make default reader settings changeable ([#217](https://github.com/Suwayomi/Suwayomi-WebUI/pull/217) by @schroda) - (r967) make default reader settings changeable ([#217](https://github.com/Suwayomi/Tachidesk-WebUI/pull/217) by @schroda)
- (r968) [#211] Refresh Library after a update ([#212](https://github.com/Suwayomi/Suwayomi-WebUI/pull/212) by @schroda) - (r968) [#211] Refresh Library after a update ([#212](https://github.com/Suwayomi/Tachidesk-WebUI/pull/212) by @schroda)
- (r969) add logic for metadata migration ([#218](https://github.com/Suwayomi/Suwayomi-WebUI/pull/218) by @schroda) - (r969) add logic for metadata migration ([#218](https://github.com/Suwayomi/Tachidesk-WebUI/pull/218) by @schroda)
- (r970) set browser tab title ([#220](https://github.com/Suwayomi/Suwayomi-WebUI/pull/220) by @schroda) - (r970) set browser tab title ([#220](https://github.com/Suwayomi/Tachidesk-WebUI/pull/220) by @schroda)
- (r971) Add tooltip containing full manga title to title of manga ([#221](https://github.com/Suwayomi/Suwayomi-WebUI/pull/221) by @schroda) - (r971) Add tooltip containing full manga title to title of manga ([#221](https://github.com/Suwayomi/Tachidesk-WebUI/pull/221) by @schroda)
- (r972) show more detailed upload dates for today and yesterday ([#222](https://github.com/Suwayomi/Suwayomi-WebUI/pull/222) by @schroda) - (r972) show more detailed upload dates for today and yesterday ([#222](https://github.com/Suwayomi/Tachidesk-WebUI/pull/222) by @schroda)
- (r973) add GitHub action on pushing to run lint ([#224](https://github.com/Suwayomi/Suwayomi-WebUI/pull/224) by @schroda) - (r973) add GitHub action on pushing to run lint ([#224](https://github.com/Suwayomi/Tachidesk-WebUI/pull/224) by @schroda)
- (r974) Ignore filters while searching ([#226](https://github.com/Suwayomi/Suwayomi-WebUI/pull/226) by @schroda) - (r974) Ignore filters while searching ([#226](https://github.com/Suwayomi/Tachidesk-WebUI/pull/226) by @schroda)
- (r975) force absolute import path ([#223](https://github.com/Suwayomi/Suwayomi-WebUI/pull/223) by @schroda) - (r975) force absolute import path ([#223](https://github.com/Suwayomi/Tachidesk-WebUI/pull/223) by @schroda)
- (r976) add prettier for auto formatting ([#231](https://github.com/Suwayomi/Suwayomi-WebUI/pull/231) by @schroda) - (r976) add prettier for auto formatting ([#231](https://github.com/Suwayomi/Tachidesk-WebUI/pull/231) by @schroda)
- (r977) Fix import path ([#228](https://github.com/Suwayomi/Suwayomi-WebUI/pull/228) by @schroda) - (r977) Fix import path ([#228](https://github.com/Suwayomi/Tachidesk-WebUI/pull/228) by @schroda)
- (r978) increase prettier line length to 120 ([#233](https://github.com/Suwayomi/Suwayomi-WebUI/pull/233) by @schroda) - (r978) increase prettier line length to 120 ([#233](https://github.com/Suwayomi/Tachidesk-WebUI/pull/233) by @schroda)
- (r979) Add chapter page dropdown ([#230](https://github.com/Suwayomi/Suwayomi-WebUI/pull/230) by @schroda) - (r979) Add chapter page dropdown ([#230](https://github.com/Suwayomi/Tachidesk-WebUI/pull/230) by @schroda)
- (r980) add chapter dropdown to reader nav bar ([#229](https://github.com/Suwayomi/Suwayomi-WebUI/pull/229) by @schroda) - (r980) add chapter dropdown to reader nav bar ([#229](https://github.com/Suwayomi/Tachidesk-WebUI/pull/229) by @schroda)
- (r981) Fix lint error ([#235](https://github.com/Suwayomi/Suwayomi-WebUI/pull/235) by @schroda) - (r981) Fix lint error ([#235](https://github.com/Suwayomi/Tachidesk-WebUI/pull/235) by @schroda)
- (r982) Fix reader nav bar scroll to page ([#236](https://github.com/Suwayomi/Suwayomi-WebUI/pull/236) by @schroda) - (r982) Fix reader nav bar scroll to page ([#236](https://github.com/Suwayomi/Tachidesk-WebUI/pull/236) by @schroda)
- (r964) Created a GridLayout enum and updated all locations to use it. ([#208](https://github.com/Suwayomi/Suwayomi-WebUI/pull/208) by @infix) - (r964) Created a GridLayout enum and updated all locations to use it. ([#208](https://github.com/Suwayomi/Tachidesk-WebUI/pull/208) by @infix)
@@ -80,71 +80,71 @@
- a lot of code cleanup - a lot of code cleanup
- some bugfixes - some bugfixes
## Suwayomi-Server Changelog ## Tachidesk-Server Changelog
- (r1114) fix broken links (by @AriaMoradi) - (r1114) fix broken links (by @AriaMoradi)
- (r1115) fix more broken stuff (by @AriaMoradi) - (r1115) fix more broken stuff (by @AriaMoradi)
- (r1116) fix more broken stuff (by @AriaMoradi) - (r1116) fix more broken stuff (by @AriaMoradi)
- (r1117) fix more broken stuff (by @AriaMoradi) - (r1117) fix more broken stuff (by @AriaMoradi)
- (r1118) Update winget.yml ([#393](https://github.com/Suwayomi/Suwayomi-Server/pull/393) by @vedantmgoyal2009) - (r1118) Update winget.yml ([#393](https://github.com/Suwayomi/Tachidesk-Server/pull/393) by @vedantmgoyal2009)
- (r1119) fix jre path([#396](https://github.com/Suwayomi/Suwayomi-Server/pull/396) by @vedantmgoyal2009) - (r1119) fix jre path([#396](https://github.com/Suwayomi/Tachidesk-Server/pull/396) by @vedantmgoyal2009)
- (r1120) Fix deb package ([#397](https://github.com/Suwayomi/Suwayomi-Server/pull/397) by @mahor1221) - (r1120) Fix deb package ([#397](https://github.com/Suwayomi/Tachidesk-Server/pull/397) by @mahor1221)
- (r1121) bump version (by @AriaMoradi) - (r1121) bump version (by @AriaMoradi)
- (r1122) Update Changelog (by @AriaMoradi) - (r1122) Update Changelog (by @AriaMoradi)
- (r1123) Add libc++-dev ([#405](https://github.com/Suwayomi/Suwayomi-Server/pull/405) by @mahor1221) - (r1123) Add libc++-dev ([#405](https://github.com/Suwayomi/Tachidesk-Server/pull/405) by @mahor1221)
- (r1124) Revert back to correct way of handling jre_dir ([#408](https://github.com/Suwayomi/Suwayomi-Server/pull/408) by @mahor1221) - (r1124) Revert back to correct way of handling jre_dir ([#408](https://github.com/Suwayomi/Tachidesk-Server/pull/408) by @mahor1221)
- (r1125) Update winget.yml ([#410](https://github.com/Suwayomi/Suwayomi-Server/pull/410) by @vedantmgoyal2009) - (r1125) Update winget.yml ([#410](https://github.com/Suwayomi/Tachidesk-Server/pull/410) by @vedantmgoyal2009)
- (r1126) Remove support for Sorayomi web interface ([#414](https://github.com/Suwayomi/Suwayomi-Server/pull/414) by @marcoebbinghaus) - (r1126) Remove support for Sorayomi web interface ([#414](https://github.com/Suwayomi/Tachidesk-Server/pull/414) by @marcoebbinghaus)
- (r1127) Fix downloader memory leak ([#418](https://github.com/Suwayomi/Suwayomi-Server/pull/418) by @Syer10) - (r1127) Fix downloader memory leak ([#418](https://github.com/Suwayomi/Tachidesk-Server/pull/418) by @Syer10)
- (r1128) Documentation cleanup ([#417](https://github.com/Suwayomi/Suwayomi-Server/pull/417) by @Syer10) - (r1128) Documentation cleanup ([#417](https://github.com/Suwayomi/Tachidesk-Server/pull/417) by @Syer10)
- (r1129) Updater cleanup and improvements ([#416](https://github.com/Suwayomi/Suwayomi-Server/pull/416) by @Syer10) - (r1129) Updater cleanup and improvements ([#416](https://github.com/Suwayomi/Tachidesk-Server/pull/416) by @Syer10)
- (r1130) replace quickjs with Mozilla Rhino ([#415](https://github.com/Suwayomi/Suwayomi-Server/pull/415) by @xhzhe) - (r1130) replace quickjs with Mozilla Rhino ([#415](https://github.com/Suwayomi/Tachidesk-Server/pull/415) by @xhzhe)
- (r1131) ktlint (by @AriaMoradi) - (r1131) ktlint (by @AriaMoradi)
- (r1132) move Tachiyomi's BuildConfig to kotlin dir (by @AriaMoradi) - (r1132) move Tachiyomi's BuildConfig to kotlin dir (by @AriaMoradi)
- (r1133) remove BuildConfig as extensions now use AppInfo (by @AriaMoradi) - (r1133) remove BuildConfig as extensions now use AppInfo (by @AriaMoradi)
- (r1134) include list of mangas missing source in restore report ([#421](https://github.com/Suwayomi/Suwayomi-Server/pull/421) by @AriaMoradi) - (r1134) include list of mangas missing source in restore report ([#421](https://github.com/Suwayomi/Tachidesk-Server/pull/421) by @AriaMoradi)
- (r1135) Update dependencies ([#422](https://github.com/Suwayomi/Suwayomi-Server/pull/422) by @Syer10) - (r1135) Update dependencies ([#422](https://github.com/Suwayomi/Tachidesk-Server/pull/422) by @Syer10)
- (r1136) Lint ([#423](https://github.com/Suwayomi/Suwayomi-Server/pull/423) by @Syer10) - (r1136) Lint ([#423](https://github.com/Suwayomi/Tachidesk-Server/pull/423) by @Syer10)
- (r1137) Fix: Error handling for popular/latest api if pageNum was supplied as zero ([#424](https://github.com/Suwayomi/Suwayomi-Server/pull/424) by @meta-boy) - (r1137) Fix: Error handling for popular/latest api if pageNum was supplied as zero ([#424](https://github.com/Suwayomi/Tachidesk-Server/pull/424) by @meta-boy)
- (r1138) Add cache control header to manga page response ([#430](https://github.com/Suwayomi/Suwayomi-Server/pull/430) by @martinek) - (r1138) Add cache control header to manga page response ([#430](https://github.com/Suwayomi/Tachidesk-Server/pull/430) by @martinek)
- (r1139) add MangaTable.lastFetchedAt and ChapterTable.chaptersLastFetchedAt ([#431](https://github.com/Suwayomi/Suwayomi-Server/pull/431) by @martinek) - (r1139) add MangaTable.lastFetchedAt and ChapterTable.chaptersLastFetchedAt ([#431](https://github.com/Suwayomi/Tachidesk-Server/pull/431) by @martinek)
- (r1140) Pre-load meta entries for all chapters for optimization ([#432](https://github.com/Suwayomi/Suwayomi-Server/pull/432) by @martinek) - (r1140) Pre-load meta entries for all chapters for optimization ([#432](https://github.com/Suwayomi/Tachidesk-Server/pull/432) by @martinek)
- (r1141) POST variant for `/{sourceId}/search` endpoint ([#434](https://github.com/Suwayomi/Suwayomi-Server/pull/434) by @martinek) - (r1141) POST variant for `/{sourceId}/search` endpoint ([#434](https://github.com/Suwayomi/Tachidesk-Server/pull/434) by @martinek)
- (r1142) Add request body to documentation ([#435](https://github.com/Suwayomi/Suwayomi-Server/pull/435) by @Syer10) - (r1142) Add request body to documentation ([#435](https://github.com/Suwayomi/Tachidesk-Server/pull/435) by @Syer10)
- (r1143) add batch download api ([#436](https://github.com/Suwayomi/Suwayomi-Server/pull/436) by @martinek) - (r1143) add batch download api ([#436](https://github.com/Suwayomi/Tachidesk-Server/pull/436) by @martinek)
- (r1144) Migrate to H2 v2 (by @AriaMoradi) - (r1144) Migrate to H2 v2 (by @AriaMoradi)
- (r1145) add category and global meta ([#438](https://github.com/Suwayomi/Suwayomi-Server/pull/438) by @AriaMoradi) - (r1145) add category and global meta ([#438](https://github.com/Suwayomi/Tachidesk-Server/pull/438) by @AriaMoradi)
- (r1146) Revert H2 database to v1 (by @AriaMoradi) - (r1146) Revert H2 database to v1 (by @AriaMoradi)
- (r1147) refactor deprecated api (by @AriaMoradi) - (r1147) refactor deprecated api (by @AriaMoradi)
- (r1148) Downloader Rewrite ([#437](https://github.com/Suwayomi/Suwayomi-Server/pull/437) by @Syer10) - (r1148) Downloader Rewrite ([#437](https://github.com/Suwayomi/Tachidesk-Server/pull/437) by @Syer10)
- (r1149) Set source preference doc fix ([#441](https://github.com/Suwayomi/Suwayomi-Server/pull/441) by @Syer10) - (r1149) Set source preference doc fix ([#441](https://github.com/Suwayomi/Tachidesk-Server/pull/441) by @Syer10)
- (r1150) Add batch chapter update endpoint ([#442](https://github.com/Suwayomi/Suwayomi-Server/pull/442) by @martinek) - (r1150) Add batch chapter update endpoint ([#442](https://github.com/Suwayomi/Tachidesk-Server/pull/442) by @martinek)
- (r1151) changes needed for tachiyomi tracker (by @AriaMoradi) - (r1151) changes needed for tachiyomi tracker (by @AriaMoradi)
- (r1152) Future proofing (by @AriaMoradi) - (r1152) Future proofing (by @AriaMoradi)
- (r1153) Fix settings/check-update endpoint ([#445](https://github.com/Suwayomi/Suwayomi-Server/pull/445) by @martinek) - (r1153) Fix settings/check-update endpoint ([#445](https://github.com/Suwayomi/Tachidesk-Server/pull/445) by @martinek)
- (r1154) Fix docs for /server/check-updates ([#447](https://github.com/Suwayomi/Suwayomi-Server/pull/447) by @martinek) - (r1154) Fix docs for /server/check-updates ([#447](https://github.com/Suwayomi/Tachidesk-Server/pull/447) by @martinek)
- (r1155) Batch editing and deleting any chapter ([#449](https://github.com/Suwayomi/Suwayomi-Server/pull/449) by @martinek) - (r1155) Batch editing and deleting any chapter ([#449](https://github.com/Suwayomi/Tachidesk-Server/pull/449) by @martinek)
- (r1156) make chapters endpoint more unifrom (by @AriaMoradi) - (r1156) make chapters endpoint more unifrom (by @AriaMoradi)
- (r1157) Add batch endpoint for removing downloads from download queue ([#452](https://github.com/Suwayomi/Suwayomi-Server/pull/452) by @martinek) - (r1157) Add batch endpoint for removing downloads from download queue ([#452](https://github.com/Suwayomi/Tachidesk-Server/pull/452) by @martinek)
- (r1158) Download queue missing update fix ([#450](https://github.com/Suwayomi/Suwayomi-Server/pull/450) by @martinek) - (r1158) Download queue missing update fix ([#450](https://github.com/Suwayomi/Tachidesk-Server/pull/450) by @martinek)
## Suwayomi-WebUI Changelog ## Tachidesk-WebUI Changelog
- (r947) Feature/swr for library screens ([#186](https://github.com/Suwayomi/Suwayomi-WebUI/pull/186) by @martinek) - (r947) Feature/swr for library screens ([#186](https://github.com/Suwayomi/Tachidesk-WebUI/pull/186) by @martinek)
- (r948) Feature/swr for simple queries ([#187](https://github.com/Suwayomi/Suwayomi-WebUI/pull/187) by @martinek) - (r948) Feature/swr for simple queries ([#187](https://github.com/Suwayomi/Tachidesk-WebUI/pull/187) by @martinek)
- (r949) Check download queue for changes and reload chapters if any chapter download changes state. ([#189](https://github.com/Suwayomi/Suwayomi-WebUI/pull/189) by @martinek) - (r949) Check download queue for changes and reload chapters if any chapter download changes state. ([#189](https://github.com/Suwayomi/Tachidesk-WebUI/pull/189) by @martinek)
- (r950) Update typescript dependency ([#190](https://github.com/Suwayomi/Suwayomi-WebUI/pull/190) by @martinek) - (r950) Update typescript dependency ([#190](https://github.com/Suwayomi/Tachidesk-WebUI/pull/190) by @martinek)
- (r951) update browserlist (by @AriaMoradi) - (r951) update browserlist (by @AriaMoradi)
- (r952) Feature/batch chapter download ([#191](https://github.com/Suwayomi/Suwayomi-WebUI/pull/191) by @martinek) - (r952) Feature/batch chapter download ([#191](https://github.com/Suwayomi/Tachidesk-WebUI/pull/191) by @martinek)
- (r953) Memoize empty view face so it does not change on rerender ([#193](https://github.com/Suwayomi/Suwayomi-WebUI/pull/193) by @martinek) - (r953) Memoize empty view face so it does not change on rerender ([#193](https://github.com/Suwayomi/Tachidesk-WebUI/pull/193) by @martinek)
- (r954) Feature/batch chapter actions ([#194](https://github.com/Suwayomi/Suwayomi-WebUI/pull/194) by @martinek) - (r954) Feature/batch chapter actions ([#194](https://github.com/Suwayomi/Tachidesk-WebUI/pull/194) by @martinek)
- (r955) Fix navbar back button behavior ([#195](https://github.com/Suwayomi/Suwayomi-WebUI/pull/195) by @martinek) - (r955) Fix navbar back button behavior ([#195](https://github.com/Suwayomi/Tachidesk-WebUI/pull/195) by @martinek)
- (r956) Options panels refactoring ([#196](https://github.com/Suwayomi/Suwayomi-WebUI/pull/196) by @martinek) - (r956) Options panels refactoring ([#196](https://github.com/Suwayomi/Tachidesk-WebUI/pull/196) by @martinek)
- (r957) Refactor and fix sorting in library ([#197](https://github.com/Suwayomi/Suwayomi-WebUI/pull/197) by @martinek) - (r957) Refactor and fix sorting in library ([#197](https://github.com/Suwayomi/Tachidesk-WebUI/pull/197) by @martinek)
- (r958) Scroll window to top when PagedPager changes page ([#198](https://github.com/Suwayomi/Suwayomi-WebUI/pull/198) by @martinek) - (r958) Scroll window to top when PagedPager changes page ([#198](https://github.com/Suwayomi/Tachidesk-WebUI/pull/198) by @martinek)
- (r959) Verticall scroll navigation and fix ([#200](https://github.com/Suwayomi/Suwayomi-WebUI/pull/200) by @martinek) - (r959) Verticall scroll navigation and fix ([#200](https://github.com/Suwayomi/Tachidesk-WebUI/pull/200) by @martinek)
- (r960) Hide overflowing text in reader title if text can't be wrapped ([#199](https://github.com/Suwayomi/Suwayomi-WebUI/pull/199) by @martinek) - (r960) Hide overflowing text in reader title if text can't be wrapped ([#199](https://github.com/Suwayomi/Tachidesk-WebUI/pull/199) by @martinek)
- (r961) Add safezone to scroll end detection to prevent edge cases when scrolling to the end would not detect end ([#201](https://github.com/Suwayomi/Suwayomi-WebUI/pull/201) by @martinek) - (r961) Add safezone to scroll end detection to prevent edge cases when scrolling to the end would not detect end ([#201](https://github.com/Suwayomi/Tachidesk-WebUI/pull/201) by @martinek)
- (r962) Refactor/download queue and cleanup visuals overall ([#202](https://github.com/Suwayomi/Suwayomi-WebUI/pull/202) by @martinek) - (r962) Refactor/download queue and cleanup visuals overall ([#202](https://github.com/Suwayomi/Tachidesk-WebUI/pull/202) by @martinek)
- (r963) Fix "back" pagination on double page layout in reader for spread pages ([#203](https://github.com/Suwayomi/Suwayomi-WebUI/pull/203) by @martinek) - (r963) Fix "back" pagination on double page layout in reader for spread pages ([#203](https://github.com/Suwayomi/Tachidesk-WebUI/pull/203) by @martinek)
@@ -152,18 +152,18 @@
## TL;DR ## TL;DR
- Fixed Windows bundler - Fixed Windows bundler
## Suwayomi-Server Changelog ## Tachidesk-Server Changelog
- (r1113) v0.6.4 (by @AriaMoradi) - (r1113) v0.6.4 (by @AriaMoradi)
- (r1114) fix broken links (by @AriaMoradi) - (r1114) fix broken links (by @AriaMoradi)
- (r1115) fix more broken stuff (by @AriaMoradi) - (r1115) fix more broken stuff (by @AriaMoradi)
- (r1116) fix more broken stuff (by @AriaMoradi) - (r1116) fix more broken stuff (by @AriaMoradi)
- (r1117) fix more broken stuff (by @AriaMoradi) - (r1117) fix more broken stuff (by @AriaMoradi)
- (r1118) Update winget.yml ([#393](https://github.com/Suwayomi/Suwayomi-Server/pull/393) by @vedantmgoyal2009) - (r1118) Update winget.yml ([#393](https://github.com/Suwayomi/Tachidesk-Server/pull/393) by @vedantmgoyal2009)
- (r1119) fix jre path([#396](https://github.com/Suwayomi/Suwayomi-Server/pull/396) by @voltrare) - (r1119) fix jre path([#396](https://github.com/Suwayomi/Tachidesk-Server/pull/396) by @voltrare)
- (r1120) Fix deb package ([#397](https://github.com/Suwayomi/Suwayomi-Server/pull/397) by @mahor1221) - (r1120) Fix deb package ([#397](https://github.com/Suwayomi/Tachidesk-Server/pull/397) by @mahor1221)
- (r1121) bump version (by @AriaMoradi) - (r1121) bump version (by @AriaMoradi)
## Suwayomi-WebUI Changelog ## Tachidesk-WebUI Changelog
- None - None
@@ -174,39 +174,39 @@
- Bug fixes and changes for packaging - Bug fixes and changes for packaging
- Documentation changes - Documentation changes
## Suwayomi-Server Changelog ## Tachidesk-Server Changelog
- (r1087) v0.6.3 (by @AriaMoradi) - (r1087) v0.6.3 (by @AriaMoradi)
- (r1088) Save categories when manga is unfavorited ([#335](https://github.com/Suwayomi/Suwayomi-Server/pull/335) by @Syer10) - (r1088) Save categories when manga is unfavorited ([#335](https://github.com/Suwayomi/Tachidesk-Server/pull/335) by @Syer10)
- (r1089) handle solid RAR archives ([#339](https://github.com/Suwayomi/Suwayomi-Server/pull/339)) cfso100@gmail.com - (r1089) handle solid RAR archives ([#339](https://github.com/Suwayomi/Tachidesk-Server/pull/339)) cfso100@gmail.com
- (r1090) add support for changing downloads dir ([#343](https://github.com/Suwayomi/Suwayomi-Server/pull/343) by @AriaMoradi) - (r1090) add support for changing downloads dir ([#343](https://github.com/Suwayomi/Tachidesk-Server/pull/343) by @AriaMoradi)
- (r1091) fix Applications dir dependency ([#344](https://github.com/Suwayomi/Suwayomi-Server/pull/344) by @AriaMoradi) - (r1091) fix Applications dir dependency ([#344](https://github.com/Suwayomi/Tachidesk-Server/pull/344) by @AriaMoradi)
- (r1092) add support for alternative web interfaces ([#342](https://github.com/Suwayomi/Suwayomi-Server/pull/342) by @AriaMoradi) - (r1092) add support for alternative web interfaces ([#342](https://github.com/Suwayomi/Tachidesk-Server/pull/342) by @AriaMoradi)
- (r1093) Add displayValues json field for select filter ([#347](https://github.com/Suwayomi/Suwayomi-Server/pull/347) by @Syer10) - (r1093) Add displayValues json field for select filter ([#347](https://github.com/Suwayomi/Tachidesk-Server/pull/347) by @Syer10)
- (r1094) document manga endpoints ([#348](https://github.com/Suwayomi/Suwayomi-Server/pull/348) by @Syer10) - (r1094) document manga endpoints ([#348](https://github.com/Suwayomi/Tachidesk-Server/pull/348) by @Syer10)
- (r1095) add ChapterCount to manga object in categoryMangas endpoint ([#349](https://github.com/Suwayomi/Suwayomi-Server/pull/349) by @abhijeetChawla) - (r1095) add ChapterCount to manga object in categoryMangas endpoint ([#349](https://github.com/Suwayomi/Tachidesk-Server/pull/349) by @abhijeetChawla)
- (r1096) document all endpoints ([#350](https://github.com/Suwayomi/Suwayomi-Server/pull/350) by @Syer10) - (r1096) document all endpoints ([#350](https://github.com/Suwayomi/Tachidesk-Server/pull/350) by @Syer10)
- (r1097) fix copymanga ([#354](https://github.com/Suwayomi/Suwayomi-Server/pull/354) by @AriaMoradi) - (r1097) fix copymanga ([#354](https://github.com/Suwayomi/Tachidesk-Server/pull/354) by @AriaMoradi)
- (r1098) fix formatting by kotlinter (by @AriaMoradi) - (r1098) fix formatting by kotlinter (by @AriaMoradi)
- (r1099) bump WebUI (by @AriaMoradi) - (r1099) bump WebUI (by @AriaMoradi)
- (r1100) fix WebUI release name (by @AriaMoradi) - (r1100) fix WebUI release name (by @AriaMoradi)
- (r1101) Fix documentation errors ([#358](https://github.com/Suwayomi/Suwayomi-Server/pull/358) by @Syer10) - (r1101) Fix documentation errors ([#358](https://github.com/Suwayomi/Tachidesk-Server/pull/358) by @Syer10)
- (r1102) Docs improvements ([#359](https://github.com/Suwayomi/Suwayomi-Server/pull/359) by @Syer10) - (r1102) Docs improvements ([#359](https://github.com/Suwayomi/Tachidesk-Server/pull/359) by @Syer10)
- (r1103) Add linux-all.tar.gz & systemd service ([#366](https://github.com/Suwayomi/Suwayomi-Server/pull/366) by @mahor1221) - (r1103) Add linux-all.tar.gz & systemd service ([#366](https://github.com/Suwayomi/Tachidesk-Server/pull/366) by @mahor1221)
- (r1104) Publish to Windows Package Managar (WinGet) ([#369](https://github.com/Suwayomi/Suwayomi-Server/pull/369) by @vedantmgoyal2009) - (r1104) Publish to Windows Package Managar (WinGet) ([#369](https://github.com/Suwayomi/Tachidesk-Server/pull/369) by @vedantmgoyal2009)
- (r1105) Refactor scripts ([#370](https://github.com/Suwayomi/Suwayomi-Server/pull/370) by @mahor1221) - (r1105) Refactor scripts ([#370](https://github.com/Suwayomi/Tachidesk-Server/pull/370) by @mahor1221)
- (r1106) Run workflow jobs toghether ([#371](https://github.com/Suwayomi/Suwayomi-Server/pull/371) by @mahor1221) - (r1106) Run workflow jobs toghether ([#371](https://github.com/Suwayomi/Tachidesk-Server/pull/371) by @mahor1221)
- (r1107) Update gradle action ([#372](https://github.com/Suwayomi/Suwayomi-Server/pull/372) by @mahor1221) - (r1107) Update gradle action ([#372](https://github.com/Suwayomi/Tachidesk-Server/pull/372) by @mahor1221)
- (r1108) Improve DocumentationDsl, bugfix default values and add queryParams ([#378](https://github.com/Suwayomi/Suwayomi-Server/pull/378) by @Syer10) - (r1108) Improve DocumentationDsl, bugfix default values and add queryParams ([#378](https://github.com/Suwayomi/Tachidesk-Server/pull/378) by @Syer10)
- (r1109) Tidy up bundler script ([#380](https://github.com/Suwayomi/Suwayomi-Server/pull/380) by @mahor1221) - (r1109) Tidy up bundler script ([#380](https://github.com/Suwayomi/Tachidesk-Server/pull/380) by @mahor1221)
- (r1110) Replace linux-all with linux-assets ([#381](https://github.com/Suwayomi/Suwayomi-Server/pull/381) by @mahor1221) - (r1110) Replace linux-all with linux-assets ([#381](https://github.com/Suwayomi/Tachidesk-Server/pull/381) by @mahor1221)
- (r1111) Rename every instance of Suwayomi jar to Suwayomi-Server.jar ([#384](https://github.com/Suwayomi/Suwayomi-Server/pull/384) by @AriaMoradi) - (r1111) Rename every instance of Tachidesk jar to Tachdidesk-Server.jar ([#384](https://github.com/Suwayomi/Tachidesk-Server/pull/384) by @AriaMoradi)
- (r1112) Fix mistakes from #384 ([#385](https://github.com/Suwayomi/Suwayomi-Server/pull/385) by @AriaMoradi) - (r1112) Fix mistakes from #384 ([#385](https://github.com/Suwayomi/Tachidesk-Server/pull/385) by @AriaMoradi)
## Suwayomi-WebUI Changelog ## Tachidesk-WebUI Changelog
- (r943) fix default width ([#171](https://github.com/Suwayomi/Suwayomi-WebUI/pull/171) by @Robonau) - (r943) fix default width ([#171](https://github.com/Suwayomi/Tachidesk-WebUI/pull/171) by @Robonau)
- (r944) added an update checker button for library ([#172](https://github.com/Suwayomi/Suwayomi-WebUI/pull/172) by @infix) - (r944) added an update checker button for library ([#172](https://github.com/Suwayomi/Tachidesk-WebUI/pull/172) by @infix)
- (r945) fix download queue delete button ([#176](https://github.com/Suwayomi/Suwayomi-WebUI/pull/176) by @Kreach37) - (r945) fix download queue delete button ([#176](https://github.com/Suwayomi/Tachidesk-WebUI/pull/176) by @Kreach37)
- (r946) fix mangadex filters ([#177](https://github.com/Suwayomi/Suwayomi-WebUI/pull/177) by @Robonau) - (r946) fix mangadex filters ([#177](https://github.com/Suwayomi/Tachidesk-WebUI/pull/177) by @Robonau)
@@ -222,35 +222,35 @@
- Sources view layouts - Sources view layouts
- Various other changes... - Various other changes...
## Suwayomi-Server Changelog ## Tachidesk-Server Changelog
- (r1074) v0.6.2 (by @AriaMoradi) - (r1074) v0.6.2 (by @AriaMoradi)
- (r1075) support array filter changes ([#304](https://github.com/Suwayomi/Suwayomi-Server/pull/304) by @AriaMoradi) - (r1075) support array filter changes ([#304](https://github.com/Suwayomi/Tachidesk-Server/pull/304) by @AriaMoradi)
- (r1076) fix filterlist bugs ([#306](https://github.com/Suwayomi/Suwayomi-Server/pull/306) by @AriaMoradi) - (r1076) fix filterlist bugs ([#306](https://github.com/Suwayomi/Tachidesk-Server/pull/306) by @AriaMoradi)
- (r1077) Update README.md ([#305](https://github.com/Suwayomi/Suwayomi-Server/pull/305) by @mahor1221) - (r1077) Update README.md ([#305](https://github.com/Suwayomi/Tachidesk-Server/pull/305) by @mahor1221)
- (r1078) fix meta update changing all keys ([#314](https://github.com/Suwayomi/Suwayomi-Server/pull/314) by @AriaMoradi) - (r1078) fix meta update changing all keys ([#314](https://github.com/Suwayomi/Tachidesk-Server/pull/314) by @AriaMoradi)
- (r1079) add support for tachiyomi extensions Lib 1.3 ([#316](https://github.com/Suwayomi/Suwayomi-Server/pull/316) by @AriaMoradi) - (r1079) add support for tachiyomi extensions Lib 1.3 ([#316](https://github.com/Suwayomi/Tachidesk-Server/pull/316) by @AriaMoradi)
- (r1080) Fix sources list of one source throws an exception ([#308](https://github.com/Suwayomi/Suwayomi-Server/pull/308) by @Syer10) - (r1080) Fix sources list of one source throws an exception ([#308](https://github.com/Suwayomi/Tachidesk-Server/pull/308) by @Syer10)
- (r1081) Improve source handling, fix errors with uninitialized mangas in broken sources ([#319](https://github.com/Suwayomi/Suwayomi-Server/pull/319) by @Syer10) - (r1081) Improve source handling, fix errors with uninitialized mangas in broken sources ([#319](https://github.com/Suwayomi/Tachidesk-Server/pull/319) by @Syer10)
- (r1082) Add thumbnail support for stub sources ([#320](https://github.com/Suwayomi/Suwayomi-Server/pull/320) by @Syer10) - (r1082) Add thumbnail support for stub sources ([#320](https://github.com/Suwayomi/Tachidesk-Server/pull/320) by @Syer10)
- (r1083) update description for Tachidesk-Sorayomi ([#326](https://github.com/Suwayomi/Suwayomi-Server/pull/326) by @DattatreyaReddy) - (r1083) update description for Tachidesk-Sorayomi ([#326](https://github.com/Suwayomi/Tachidesk-Server/pull/326) by @DattatreyaReddy)
- (r1084) Add last bit of code needed for Extensions Lib 1.3 ([#330](https://github.com/Suwayomi/Suwayomi-Server/pull/330) by @Syer10) - (r1084) Add last bit of code needed for Extensions Lib 1.3 ([#330](https://github.com/Suwayomi/Tachidesk-Server/pull/330) by @Syer10)
- (r1085) Add QuickJS, replaces Duktape for Extensions Lib 1.3 ([#331](https://github.com/Suwayomi/Suwayomi-Server/pull/331) by @Syer10) - (r1085) Add QuickJS, replaces Duktape for Extensions Lib 1.3 ([#331](https://github.com/Suwayomi/Tachidesk-Server/pull/331) by @Syer10)
- (r1086) fix auth not actually blocking requests ([#333](https://github.com/Suwayomi/Suwayomi-Server/pull/333) by @AriaMoradi) - (r1086) fix auth not actually blocking requests ([#333](https://github.com/Suwayomi/Tachidesk-Server/pull/333) by @AriaMoradi)
## Suwayomi-WebUI Changelog ## Tachidesk-WebUI Changelog
- (r930) Source filter scroll fix (array of filters on submit [#149](https://github.com/Suwayomi/Suwayomi-WebUI/pull/149) by @Robonau) - (r930) Source filter scroll fix (array of filters on submit [#149](https://github.com/Suwayomi/Tachidesk-WebUI/pull/149) by @Robonau)
- (r931) fix manga badges setting menu that turns the update/download badges on and off ([#150](https://github.com/Suwayomi/Suwayomi-WebUI/pull/150) by @Robonau) - (r931) fix manga badges setting menu that turns the update/download badges on and off ([#150](https://github.com/Suwayomi/Tachidesk-WebUI/pull/150) by @Robonau)
- (r932) move sorts to copy tachiyomi ([#151](https://github.com/Suwayomi/Suwayomi-WebUI/pull/151) by @Robonau) - (r932) move sorts to copy tachiyomi ([#151](https://github.com/Suwayomi/Tachidesk-WebUI/pull/151) by @Robonau)
- (r933) add comfortable grid option ([#152](https://github.com/Suwayomi/Suwayomi-WebUI/pull/152) by @Robonau) - (r933) add comfortable grid option ([#152](https://github.com/Suwayomi/Tachidesk-WebUI/pull/152) by @Robonau)
- (r934) source layouts ([#153](https://github.com/Suwayomi/Suwayomi-WebUI/pull/153) by @Robonau) - (r934) source layouts ([#153](https://github.com/Suwayomi/Tachidesk-WebUI/pull/153) by @Robonau)
- (r935) List layout ([#154](https://github.com/Suwayomi/Suwayomi-WebUI/pull/154) by @Robonau) - (r935) List layout ([#154](https://github.com/Suwayomi/Tachidesk-WebUI/pull/154) by @Robonau)
- (r936) in library badge to manga in sources ([#156](https://github.com/Suwayomi/Suwayomi-WebUI/pull/156) by @Robonau) - (r936) in library badge to manga in sources ([#156](https://github.com/Suwayomi/Tachidesk-WebUI/pull/156) by @Robonau)
- (r937) mass search ([#157](https://github.com/Suwayomi/Suwayomi-WebUI/pull/157) by @Robonau) - (r937) mass search ([#157](https://github.com/Suwayomi/Tachidesk-WebUI/pull/157) by @Robonau)
- (r938) 18+ tag on source/extension cards ([#160](https://github.com/Suwayomi/Suwayomi-WebUI/pull/160) by @Robonau) - (r938) 18+ tag on source/extension cards ([#160](https://github.com/Suwayomi/Tachidesk-WebUI/pull/160) by @Robonau)
- (r939) fix search source click ([#164](https://github.com/Suwayomi/Suwayomi-WebUI/pull/164) by @Robonau) - (r939) fix search source click ([#164](https://github.com/Suwayomi/Tachidesk-WebUI/pull/164) by @Robonau)
- (r940) items per row setting ([#165](https://github.com/Suwayomi/Suwayomi-WebUI/pull/165) by @Robonau) - (r940) items per row setting ([#165](https://github.com/Suwayomi/Tachidesk-WebUI/pull/165) by @Robonau)
- (r941) fix the grid width thing ([#169](https://github.com/Suwayomi/Suwayomi-WebUI/pull/169) by @Robonau) - (r941) fix the grid width thing ([#169](https://github.com/Suwayomi/Tachidesk-WebUI/pull/169) by @Robonau)
- (r942) unified library options ([#168](https://github.com/Suwayomi/Suwayomi-WebUI/pull/168) by @infix) - (r942) unified library options ([#168](https://github.com/Suwayomi/Tachidesk-WebUI/pull/168) by @infix)
# Server: v0.6.2 + WebUI: r929 # Server: v0.6.2 + WebUI: r929
## TL;DR ## TL;DR
@@ -260,28 +260,28 @@
- Better visuals for Download Queue - Better visuals for Download Queue
- A live version of WebUI is now available [at this link](https://tachidesk-webui-preview.github.io/). - A live version of WebUI is now available [at this link](https://tachidesk-webui-preview.github.io/).
## Suwayomi-Server Changelog ## Tachidesk-Server Changelog
- (r1073) Refactor debian-packager.sh, rename launcher scripts ([#303](https://github.com/Suwayomi/Suwayomi-Server/pull/303) by @mahor1221) - (r1073) Refactor debian-packager.sh, rename launcher scripts ([#303](https://github.com/Suwayomi/Tachidesk-Server/pull/303) by @mahor1221)
## Suwayomi-WebUI Changelog ## Tachidesk-WebUI Changelog
- (r912) show locale date, less confusing ([#131](https://github.com/Suwayomi/Suwayomi-WebUI/pull/131) by @AriaMoradi) - (r912) show locale date, less confusing ([#131](https://github.com/Suwayomi/Tachidesk-WebUI/pull/131) by @AriaMoradi)
- (r913) fix links to work on a bare host ([#132](https://github.com/Suwayomi/Suwayomi-WebUI/pull/132) by @AriaMoradi) - (r913) fix links to work on a bare host ([#132](https://github.com/Suwayomi/Tachidesk-WebUI/pull/132) by @AriaMoradi)
- (r914) fix direct links ([#133](https://github.com/Suwayomi/Suwayomi-WebUI/pull/133) by @AriaMoradi) - (r914) fix direct links ([#133](https://github.com/Suwayomi/Tachidesk-WebUI/pull/133) by @AriaMoradi)
- (r915) deploy to github pages (by @AriaMoradi) - (r915) deploy to github pages (by @AriaMoradi)
- (r916) fix typo (by @AriaMoradi) - (r916) fix typo (by @AriaMoradi)
- (r917) better naming (by @AriaMoradi) - (r917) better naming (by @AriaMoradi)
- (r918) update notice about github pages (by @AriaMoradi) - (r918) update notice about github pages (by @AriaMoradi)
- (r919) move text (by @AriaMoradi) - (r919) move text (by @AriaMoradi)
- (r920) make all links work by catching 404 (by @AriaMoradi) - (r920) make all links work by catching 404 (by @AriaMoradi)
- (r921) fix scrolling 8px ([#135](https://github.com/Suwayomi/Suwayomi-WebUI/pull/135) by @Robonau) - (r921) fix scrolling 8px ([#135](https://github.com/Suwayomi/Tachidesk-WebUI/pull/135) by @Robonau)
- (r922) sorting ([#136](https://github.com/Suwayomi/Suwayomi-WebUI/pull/136) by @Robonau) - (r922) sorting ([#136](https://github.com/Suwayomi/Tachidesk-WebUI/pull/136) by @Robonau)
- (r923) Close button fix ([#141](https://github.com/Suwayomi/Suwayomi-WebUI/pull/141)) z14942744@gmail.com - (r923) Close button fix ([#141](https://github.com/Suwayomi/Tachidesk-WebUI/pull/141)) z14942744@gmail.com
- (r924) add NavBarContextProvider ([#128](https://github.com/Suwayomi/Suwayomi-WebUI/pull/128) by @abhijeetChawla) - (r924) add NavBarContextProvider ([#128](https://github.com/Suwayomi/Tachidesk-WebUI/pull/128) by @abhijeetChawla)
- (r925) Resolved Merged Conflicts ([#127](https://github.com/Suwayomi/Suwayomi-WebUI/pull/127) by @abhijeetChawla) - (r925) Resolved Merged Conflicts ([#127](https://github.com/Suwayomi/Tachidesk-WebUI/pull/127) by @abhijeetChawla)
- (r926) more Download Queue info ([#138](https://github.com/Suwayomi/Suwayomi-WebUI/pull/138) by @Robonau) - (r926) more Download Queue info ([#138](https://github.com/Suwayomi/Tachidesk-WebUI/pull/138) by @Robonau)
- (r927) Source filters, move search to SourceMangas ([#142](https://github.com/Suwayomi/Suwayomi-WebUI/pull/142) by @Robonau) - (r927) Source filters, move search to SourceMangas ([#142](https://github.com/Suwayomi/Tachidesk-WebUI/pull/142) by @Robonau)
- (r928) Source genre sorts design ([#147](https://github.com/Suwayomi/Suwayomi-WebUI/pull/147) by @Robonau) - (r928) Source genre sorts design ([#147](https://github.com/Suwayomi/Tachidesk-WebUI/pull/147) by @Robonau)
- (r929) Update LibraryOptions.tsx ([#146](https://github.com/Suwayomi/Suwayomi-WebUI/pull/146) by @Robonau) - (r929) Update LibraryOptions.tsx ([#146](https://github.com/Suwayomi/Tachidesk-WebUI/pull/146) by @Robonau)
@@ -290,49 +290,49 @@
- msi and deb packages thanks to @mahor1221 - msi and deb packages thanks to @mahor1221
- [Tachidesk-Flutter](https://github.com/Suwayomi/Tachidesk-Flutter) exists now! - [Tachidesk-Flutter](https://github.com/Suwayomi/Tachidesk-Flutter) exists now!
## Suwayomi-Server Changelog ## Tachidesk-Server Changelog
- (r1047) update (by @AriaMoradi) - (r1047) update (by @AriaMoradi)
- (r1048) bump version (by @AriaMoradi) - (r1048) bump version (by @AriaMoradi)
- (r1049) Update README.md (by @AriaMoradi) - (r1049) Update README.md (by @AriaMoradi)
- (r1050) Update README.md (by @AriaMoradi) - (r1050) Update README.md (by @AriaMoradi)
- (r1051) refactor getChapter ([#268](https://github.com/Suwayomi/Suwayomi-Server/pull/268) by @AriaMoradi) - (r1051) refactor getChapter ([#268](https://github.com/Suwayomi/Tachidesk-Server/pull/268) by @AriaMoradi)
- (r1052) Improve documentation with Http codes ([#261](https://github.com/Suwayomi/Suwayomi-Server/pull/261) by @Syer10) - (r1052) Improve documentation with Http codes ([#261](https://github.com/Suwayomi/Tachidesk-Server/pull/261) by @Syer10)
- (r1053) Add Route to stop and reset the updater ([#260](https://github.com/Suwayomi/Suwayomi-Server/pull/260) by @ntbm) - (r1053) Add Route to stop and reset the updater ([#260](https://github.com/Suwayomi/Tachidesk-Server/pull/260) by @ntbm)
- (r1054) ignore non image files ([#269](https://github.com/Suwayomi/Suwayomi-Server/pull/269) by @AriaMoradi) - (r1054) ignore non image files ([#269](https://github.com/Suwayomi/Tachidesk-Server/pull/269) by @AriaMoradi)
- (r1055) fix compile erorr (by @AriaMoradi) - (r1055) fix compile erorr (by @AriaMoradi)
- (r1056) update dex2jar (by @AriaMoradi) - (r1056) update dex2jar (by @AriaMoradi)
- (r1057) Update Gradle and Dependencies ([#281](https://github.com/Suwayomi/Suwayomi-Server/pull/281) by @Syer10) - (r1057) Update Gradle and Dependencies ([#281](https://github.com/Suwayomi/Tachidesk-Server/pull/281) by @Syer10)
- (r1058) Handlers must return a result ([#282](https://github.com/Suwayomi/Suwayomi-Server/pull/282) by @Syer10) - (r1058) Handlers must return a result ([#282](https://github.com/Suwayomi/Tachidesk-Server/pull/282) by @Syer10)
- (r1059) Allow app compilation on Java 18+ ([#286](https://github.com/Suwayomi/Suwayomi-Server/pull/286) by @Syer10) - (r1059) Allow app compilation on Java 18+ ([#286](https://github.com/Suwayomi/Tachidesk-Server/pull/286) by @Syer10)
- (r1060) Automated MSI package building ([#277](https://github.com/Suwayomi/Suwayomi-Server/pull/277) by @mahor1221) - (r1060) Automated MSI package building ([#277](https://github.com/Suwayomi/Tachidesk-Server/pull/277) by @mahor1221)
- (r1061) Automated debian package building ([#287](https://github.com/Suwayomi/Suwayomi-Server/pull/287) by @mahor1221) - (r1061) Automated debian package building ([#287](https://github.com/Suwayomi/Tachidesk-Server/pull/287) by @mahor1221)
- (r1062) fix Debian package errors ([#288](https://github.com/Suwayomi/Suwayomi-Server/pull/288) by @mahor1221) - (r1062) fix Debian package errors ([#288](https://github.com/Suwayomi/Tachidesk-Server/pull/288) by @mahor1221)
- (r1063) Fix build_push.yml Hopefully ([#289](https://github.com/Suwayomi/Suwayomi-Server/pull/289) by @mahor1221) - (r1063) Fix build_push.yml Hopefully ([#289](https://github.com/Suwayomi/Tachidesk-Server/pull/289) by @mahor1221)
- (r1064) Improve windows-bundler.sh ([#290](https://github.com/Suwayomi/Suwayomi-Server/pull/290) by @mahor1221) - (r1064) Improve windows-bundler.sh ([#290](https://github.com/Suwayomi/Tachidesk-Server/pull/290) by @mahor1221)
- (r1065) add Tachidesk-Flutter to readme ([#292](https://github.com/Suwayomi/Suwayomi-Server/pull/292)) @DattatreyaReddy) - (r1065) add Tachidesk-Flutter to readme ([#292](https://github.com/Suwayomi/Tachidesk-Server/pull/292)) @DattatreyaReddy)
- (r1066) no online fetch on backup ([#293](https://github.com/Suwayomi/Suwayomi-Server/pull/293) by @AriaMoradi) - (r1066) no online fetch on backup ([#293](https://github.com/Suwayomi/Tachidesk-Server/pull/293) by @AriaMoradi)
- (r1067) auto-remove duplicate chapters ([#294](https://github.com/Suwayomi/Suwayomi-Server/pull/294) by @AriaMoradi) - (r1067) auto-remove duplicate chapters ([#294](https://github.com/Suwayomi/Tachidesk-Server/pull/294) by @AriaMoradi)
- (r1068) remove gson ([#295](https://github.com/Suwayomi/Suwayomi-Server/pull/295) by @AriaMoradi) - (r1068) remove gson ([#295](https://github.com/Suwayomi/Tachidesk-Server/pull/295) by @AriaMoradi)
## Suwayomi-WebUI Changelog ## Tachidesk-WebUI Changelog
- (r894) migrate ReaderNavbar to Mui 5 ([#84](https://github.com/Suwayomi/Suwayomi-WebUI/pull/84) by @AriaMoradi) - (r894) migrate ReaderNavbar to Mui 5 ([#84](https://github.com/Suwayomi/Tachidesk-WebUI/pull/84) by @AriaMoradi)
- (r895) migrate SpinnerImage to Mui 5 ([#97](https://github.com/Suwayomi/Suwayomi-WebUI/pull/97) by @AriaMoradi) - (r895) migrate SpinnerImage to Mui 5 ([#97](https://github.com/Suwayomi/Tachidesk-WebUI/pull/97) by @AriaMoradi)
- (r896) migrate VerticalPager to Mui 5 ([#94](https://github.com/Suwayomi/Suwayomi-WebUI/pull/94) by @AriaMoradi) - (r896) migrate VerticalPager to Mui 5 ([#94](https://github.com/Suwayomi/Tachidesk-WebUI/pull/94) by @AriaMoradi)
- (r897) migrate PagedPager to Mui 5 ([#93](https://github.com/Suwayomi/Suwayomi-WebUI/pull/93) by @AriaMoradi) - (r897) migrate PagedPager to Mui 5 ([#93](https://github.com/Suwayomi/Tachidesk-WebUI/pull/93) by @AriaMoradi)
- (r898) MangaCard imges don't stretch now ([#110](https://github.com/Suwayomi/Suwayomi-WebUI/pull/110) by @abhijeetChawla) - (r898) MangaCard imges don't stretch now ([#110](https://github.com/Suwayomi/Tachidesk-WebUI/pull/110) by @abhijeetChawla)
- (r899) show correct title ([#111](https://github.com/Suwayomi/Suwayomi-WebUI/pull/111) by @AriaMoradi) - (r899) show correct title ([#111](https://github.com/Suwayomi/Tachidesk-WebUI/pull/111) by @AriaMoradi)
- (r900) migrate DoublePage to Mui 5 ([#88](https://github.com/Suwayomi/Suwayomi-WebUI/pull/88) by @AriaMoradi) - (r900) migrate DoublePage to Mui 5 ([#88](https://github.com/Suwayomi/Tachidesk-WebUI/pull/88) by @AriaMoradi)
- (r901) migrate DoublePagedPager to Mui 5 ([#91](https://github.com/Suwayomi/Suwayomi-WebUI/pull/91) by @AriaMoradi) - (r901) migrate DoublePagedPager to Mui 5 ([#91](https://github.com/Suwayomi/Tachidesk-WebUI/pull/91) by @AriaMoradi)
- (r902) migrate Reader to Mui 5 ([#100](https://github.com/Suwayomi/Suwayomi-WebUI/pull/100) by @AriaMoradi) - (r902) migrate Reader to Mui 5 ([#100](https://github.com/Suwayomi/Tachidesk-WebUI/pull/100) by @AriaMoradi)
- (r903) migrate HorizantalPager to Mui 5 ([#92](https://github.com/Suwayomi/Suwayomi-WebUI/pull/92) by @AriaMoradi) - (r903) migrate HorizantalPager to Mui 5 ([#92](https://github.com/Suwayomi/Tachidesk-WebUI/pull/92) by @AriaMoradi)
- (r904) migrate PageNumber to Mui 5 ([#90](https://github.com/Suwayomi/Suwayomi-WebUI/pull/90) by @AriaMoradi) - (r904) migrate PageNumber to Mui 5 ([#90](https://github.com/Suwayomi/Tachidesk-WebUI/pull/90) by @AriaMoradi)
- (r905) Chapter filter is woking ([#114](https://github.com/Suwayomi/Suwayomi-WebUI/pull/114) by @abhijeetChawla) - (r905) Chapter filter is woking ([#114](https://github.com/Suwayomi/Tachidesk-WebUI/pull/114) by @abhijeetChawla)
- (r906) added extension search ([#115](https://github.com/Suwayomi/Suwayomi-WebUI/pull/115) by @abhijeetChawla) - (r906) added extension search ([#115](https://github.com/Suwayomi/Tachidesk-WebUI/pull/115) by @abhijeetChawla)
- (r907) cleanup ([#117](https://github.com/Suwayomi/Suwayomi-WebUI/pull/117) by @AriaMoradi) - (r907) cleanup ([#117](https://github.com/Suwayomi/Tachidesk-WebUI/pull/117) by @AriaMoradi)
- (r908) handle search shortcuts ([#116](https://github.com/Suwayomi/Suwayomi-WebUI/pull/116) by @AriaMoradi) - (r908) handle search shortcuts ([#116](https://github.com/Suwayomi/Tachidesk-WebUI/pull/116) by @AriaMoradi)
- (r909) Refactor for Removing unnecesary UseEffect ([#118](https://github.com/Suwayomi/Suwayomi-WebUI/pull/118) by @abhijeetChawla) - (r909) Refactor for Removing unnecesary UseEffect ([#118](https://github.com/Suwayomi/Tachidesk-WebUI/pull/118) by @abhijeetChawla)
- (r910) refactor ChapterList ([#125](https://github.com/Suwayomi/Suwayomi-WebUI/pull/125) by @abhijeetChawla) - (r910) refactor ChapterList ([#125](https://github.com/Suwayomi/Tachidesk-WebUI/pull/125) by @abhijeetChawla)
- (r911) refactor ChapterOptions ([#126](https://github.com/Suwayomi/Suwayomi-WebUI/pull/126) by @abhijeetChawla) - (r911) refactor ChapterOptions ([#126](https://github.com/Suwayomi/Tachidesk-WebUI/pull/126) by @abhijeetChawla)
@@ -349,16 +349,16 @@
- Added support for updating library(Server side only) - Added support for updating library(Server side only)
- A bunch of API breaking changes(hence why bumping to v0.6.0)! - A bunch of API breaking changes(hence why bumping to v0.6.0)!
## Suwayomi-Server Changelog ## Tachidesk-Server Changelog
- (r996) cleanup (by @AriaMoradi) - (r996) cleanup (by @AriaMoradi)
- (r999) better cleaning algorithm (by @AriaMoradi) - (r999) better cleaning algorithm (by @AriaMoradi)
- (r1007) remove anime support (by @AriaMoradi) - (r1007) remove anime support (by @AriaMoradi)
- (r1009) Fix tests ([#226](https://github.com/Suwayomi/Suwayomi-Server/pull/226) by @ntbm) - (r1009) Fix tests ([#226](https://github.com/Suwayomi/Tachidesk-Server/pull/226) by @ntbm)
- (r1010) Expose unread and download count of Manga in category api ([#227](https://github.com/Suwayomi/Suwayomi-Server/pull/227) by @ntbm) - (r1010) Expose unread and download count of Manga in category api ([#227](https://github.com/Suwayomi/Tachidesk-Server/pull/227) by @ntbm)
- (r1011) add Cache Header to Thumbnail Response for improved library performance ([#228](https://github.com/Suwayomi/Suwayomi-Server/pull/228) by @ntbm) - (r1011) add Cache Header to Thumbnail Response for improved library performance ([#228](https://github.com/Suwayomi/Tachidesk-Server/pull/228) by @ntbm)
- (r1013) Fix unread and download counts casing ([#230](https://github.com/Suwayomi/Suwayomi-Server/pull/230) by @Syer10) - (r1013) Fix unread and download counts casing ([#230](https://github.com/Suwayomi/Tachidesk-Server/pull/230) by @Syer10)
- (r1014) Fix broken test ([#231](https://github.com/Suwayomi/Suwayomi-Server/pull/231) by @ntbm) - (r1014) Fix broken test ([#231](https://github.com/Suwayomi/Tachidesk-Server/pull/231) by @ntbm)
- (r1016) Fix category reorder Endpoint. Added Test for Category Reorder ([#232](https://github.com/Suwayomi/Suwayomi-Server/pull/232) by @ntbm) - (r1016) Fix category reorder Endpoint. Added Test for Category Reorder ([#232](https://github.com/Suwayomi/Tachidesk-Server/pull/232) by @ntbm)
- (r1017) change windows bundle names (by @AriaMoradi) - (r1017) change windows bundle names (by @AriaMoradi)
- (r1018) improve tests (by @AriaMoradi) - (r1018) improve tests (by @AriaMoradi)
- (r1019) allow injecting Sources (by @AriaMoradi) - (r1019) allow injecting Sources (by @AriaMoradi)
@@ -379,33 +379,33 @@
- (r1034) Implement Update of Library/Category ([#235](https://github.com/Suwayomi/src/pull/235) by @ntbm) - (r1034) Implement Update of Library/Category ([#235](https://github.com/Suwayomi/src/pull/235) by @ntbm)
- (r1035) update (by @AriaMoradi) - (r1035) update (by @AriaMoradi)
- (r1036) Mention the existence of Mahor's Tachidesk-GTK (by @AriaMoradi) - (r1036) Mention the existence of Mahor's Tachidesk-GTK (by @AriaMoradi)
- (r1037) Add a Kotlin DSL for endpoint documentation ([#249](https://github.com/Suwayomi/Suwayomi-Server/pull/249) by @Syer10) - (r1037) Add a Kotlin DSL for endpoint documentation ([#249](https://github.com/Suwayomi/Tachidesk-Server/pull/249) by @Syer10)
- (r1038) update (by @AriaMoradi) - (r1038) update (by @AriaMoradi)
- (r1039) update (by @AriaMoradi) - (r1039) update (by @AriaMoradi)
- (r1040) cleanup directory names ([#251](https://github.com/Suwayomi/Suwayomi-Server/pull/251) by @AriaMoradi) - (r1040) cleanup directory names ([#251](https://github.com/Suwayomi/Tachidesk-Server/pull/251) by @AriaMoradi)
- (r1041) Fix first page not being detected correctly ([#253](https://github.com/Suwayomi/Suwayomi-Server/pull/253) by @AriaMoradi) - (r1041) Fix first page not being detected correctly ([#253](https://github.com/Suwayomi/Tachidesk-Server/pull/253) by @AriaMoradi)
- (r1042) Update README.md (by @AriaMoradi) - (r1042) Update README.md (by @AriaMoradi)
- (r1043) Update README.md (by @AriaMoradi) - (r1043) Update README.md (by @AriaMoradi)
- (r1044) migrate application directories ([#255](https://github.com/Suwayomi/Suwayomi-Server/pull/255) by @AriaMoradi) - (r1044) migrate application directories ([#255](https://github.com/Suwayomi/Tachidesk-Server/pull/255) by @AriaMoradi)
- (r1045) add support for MultiSelectListPreference ([#258](https://github.com/Suwayomi/Suwayomi-Server/pull/258) by @AriaMoradi) - (r1045) add support for MultiSelectListPreference ([#258](https://github.com/Suwayomi/Tachidesk-Server/pull/258) by @AriaMoradi)
- (r1046) empty searchTerm support ([#259](https://github.com/Suwayomi/Suwayomi-Server/pull/259) by @AriaMoradi) - (r1046) empty searchTerm support ([#259](https://github.com/Suwayomi/Tachidesk-Server/pull/259) by @AriaMoradi)
## Suwayomi-WebUI ## Tachidesk-WebUI
- (r821) add Permanent sidebar for desktop widths([#46](https://github.com/Suwayomi/Suwayomi-WebUI/pull/46) by @abhijeetChawla) - (r821) add Permanent sidebar for desktop widths([#46](https://github.com/Suwayomi/Tachidesk-WebUI/pull/46) by @abhijeetChawla)
- (r822) Fix Local Source being missing (by @AriaMoradi) - (r822) Fix Local Source being missing (by @AriaMoradi)
- (r823) fix the ugliness of bare messages (by @AriaMoradi) - (r823) fix the ugliness of bare messages (by @AriaMoradi)
- (r824) add pull request template (by @AriaMoradi) - (r824) add pull request template (by @AriaMoradi)
- (r825) add Unread badges ([#48](https://github.com/Suwayomi/Suwayomi-WebUI/pull/48) by @ntbm) - (r825) add Unread badges ([#48](https://github.com/Suwayomi/Tachidesk-WebUI/pull/48) by @ntbm)
- (r826) Back button implementation ([#47](https://github.com/Suwayomi/Suwayomi-WebUI/pull/47) by @abhijeetChawla) - (r826) Back button implementation ([#47](https://github.com/Suwayomi/Tachidesk-WebUI/pull/47) by @abhijeetChawla)
- (r827) remove redundant '/manga' prefix from paths (by @AriaMoradi) - (r827) remove redundant '/manga' prefix from paths (by @AriaMoradi)
- (r828) refactor (by @AriaMoradi) - (r828) refactor (by @AriaMoradi)
- (r829) put Sources and Extensions in the same screen (by @AriaMoradi) - (r829) put Sources and Extensions in the same screen (by @AriaMoradi)
- (r830) Set Fallback Image for broken Thumbnails ([#50](https://github.com/Suwayomi/Suwayomi-WebUI/pull/50) by @ntbm) - (r830) Set Fallback Image for broken Thumbnails ([#50](https://github.com/Suwayomi/Tachidesk-WebUI/pull/50) by @ntbm)
- (r833) Apply Api changes for unread badges ([#52](https://github.com/Suwayomi/Suwayomi-WebUI/pull/52) by @ntbm) - (r833) Apply Api changes for unread badges ([#52](https://github.com/Suwayomi/Tachidesk-WebUI/pull/52) by @ntbm)
- (r834) add EmptyView to DownloadQueue, refactro strings ([#53](https://github.com/Suwayomi/Suwayomi-WebUI/pull/53) by @abhijeetChawla) - (r834) add EmptyView to DownloadQueue, refactro strings ([#53](https://github.com/Suwayomi/Tachidesk-WebUI/pull/53) by @abhijeetChawla)
- (r835) Bottom navbar for mobile ([#51](https://github.com/Suwayomi/Suwayomi-WebUI/pull/51) by @abhijeetChawla) - (r835) Bottom navbar for mobile ([#51](https://github.com/Suwayomi/Tachidesk-WebUI/pull/51) by @abhijeetChawla)
- (r836) Implement Unread Filter for Library ([#54](https://github.com/Suwayomi/Suwayomi-WebUI/pull/54) by @ntbm) - (r836) Implement Unread Filter for Library ([#54](https://github.com/Suwayomi/Tachidesk-WebUI/pull/54) by @ntbm)
- (r837) fix navbar broken logic (by @AriaMoradi) - (r837) fix navbar broken logic (by @AriaMoradi)
- (r838) fix navbar (by @AriaMoradi) - (r838) fix navbar (by @AriaMoradi)
- (r839) refactor (by @AriaMoradi) - (r839) refactor (by @AriaMoradi)
@@ -417,51 +417,51 @@
- (r845) custom Extension icon, google's version is shit (by @AriaMoradi) - (r845) custom Extension icon, google's version is shit (by @AriaMoradi)
- (r846) refactor (by @AriaMoradi) - (r846) refactor (by @AriaMoradi)
- (r848) move info (by @AriaMoradi) - (r848) move info (by @AriaMoradi)
- (r849) add Search to Library ([#55](https://github.com/Suwayomi/Suwayomi-WebUI/pull/55) by @ntbm) - (r849) add Search to Library ([#55](https://github.com/Suwayomi/Tachidesk-WebUI/pull/55) by @ntbm)
- (r850) add aspect ratio to the manga card. ([#56](https://github.com/Suwayomi/Suwayomi-WebUI/pull/56) by @abhijeetChawla) - (r850) add aspect ratio to the manga card. ([#56](https://github.com/Suwayomi/Tachidesk-WebUI/pull/56) by @abhijeetChawla)
- (r851) better wording (by @AriaMoradi) - (r851) better wording (by @AriaMoradi)
- (r852) reorder nav buttons (by @AriaMoradi) - (r852) reorder nav buttons (by @AriaMoradi)
- (r853) nicer gradient (by @AriaMoradi) - (r853) nicer gradient (by @AriaMoradi)
- (r854) refactor MangaCard (by @AriaMoradi) - (r854) refactor MangaCard (by @AriaMoradi)
- (r855) closes #58 (by @AriaMoradi - (r855) closes #58 (by @AriaMoradi
- (r856) Add Resume Reading FAB Manga screen ([#59](https://github.com/Suwayomi/Suwayomi-WebUI/pull/59) by @abhijeetChawla) - (r856) Add Resume Reading FAB Manga screen ([#59](https://github.com/Suwayomi/Tachidesk-WebUI/pull/59) by @abhijeetChawla)
- (r857) add filter and badge for `downloadCount` ([#62](https://github.com/Suwayomi/Suwayomi-WebUI/pull/62) by @abhijeetChawla) - (r857) add filter and badge for `downloadCount` ([#62](https://github.com/Suwayomi/Tachidesk-WebUI/pull/62) by @abhijeetChawla)
- (r858) add issue template (by @AriaMoradi) - (r858) add issue template (by @AriaMoradi)
- (r859) Change color of navbar in light mode ([#65](https://github.com/Suwayomi/Suwayomi-WebUI/pull/65) by @abhijeetChawla) - (r859) Change color of navbar in light mode ([#65](https://github.com/Suwayomi/Tachidesk-WebUI/pull/65) by @abhijeetChawla)
- (r860) fix manga FAB margins ([#66](https://github.com/Suwayomi/Suwayomi-WebUI/pull/66) by @AriaMoradi) - (r860) fix manga FAB margins ([#66](https://github.com/Suwayomi/Tachidesk-WebUI/pull/66) by @AriaMoradi)
- (r861) remove extra scrollbar on mobile ([#67](https://github.com/Suwayomi/Suwayomi-WebUI/pull/67) by @AriaMoradi) - (r861) remove extra scrollbar on mobile ([#67](https://github.com/Suwayomi/Tachidesk-WebUI/pull/67) by @AriaMoradi)
- (r862) Fix Bad messages in Library Appbar search ([#70](https://github.com/Suwayomi/Suwayomi-WebUI/pull/70) by @ntbm) - (r862) Fix Bad messages in Library Appbar search ([#70](https://github.com/Suwayomi/Tachidesk-WebUI/pull/70) by @ntbm)
- (r863) ban the style prop (by @AriaMoradi) - (r863) ban the style prop (by @AriaMoradi)
- (r864) Updates pagination update ([#68](https://github.com/Suwayomi/Suwayomi-WebUI/pull/68) by @AriaMoradi) - (r864) Updates pagination update ([#68](https://github.com/Suwayomi/Tachidesk-WebUI/pull/68) by @AriaMoradi)
- (r865) make the whole chapter card into a button ([#73](https://github.com/Suwayomi/Suwayomi-WebUI/pull/73) by @AriaMoradi) - (r865) make the whole chapter card into a button ([#73](https://github.com/Suwayomi/Tachidesk-WebUI/pull/73) by @AriaMoradi)
- (r866) fix chapter actions not working if manga is not fetched online ([#74](https://github.com/Suwayomi/Suwayomi-WebUI/pull/74) by @AriaMoradi) - (r866) fix chapter actions not working if manga is not fetched online ([#74](https://github.com/Suwayomi/Tachidesk-WebUI/pull/74) by @AriaMoradi)
- (r867) migrate some components to Mui5 new styling system ([#72](https://github.com/Suwayomi/Suwayomi-WebUI/pull/72) by @abhijeetChawla) - (r867) migrate some components to Mui5 new styling system ([#72](https://github.com/Suwayomi/Tachidesk-WebUI/pull/72) by @abhijeetChawla)
- (r868) load first page on read manga ([#76](https://github.com/Suwayomi/Suwayomi-WebUI/pull/76) by @AriaMoradi) - (r868) load first page on read manga ([#76](https://github.com/Suwayomi/Tachidesk-WebUI/pull/76) by @AriaMoradi)
- (r869) Revert "migrate some components to Mui5 new styling system ([#72](https://github.com/Suwayomi/Suwayomi-WebUI/pull/72))" (by @AriaMoradi) - (r869) Revert "migrate some components to Mui5 new styling system ([#72](https://github.com/Suwayomi/Tachidesk-WebUI/pull/72))" (by @AriaMoradi)
- (r870) migrate Backup to Mui 5 ([#106](https://github.com/Suwayomi/Suwayomi-WebUI/pull/106) by @AriaMoradi) - (r870) migrate Backup to Mui 5 ([#106](https://github.com/Suwayomi/Tachidesk-WebUI/pull/106) by @AriaMoradi)
- (r871) migrate EmptyView to Mui 5 ([#95](https://github.com/Suwayomi/Suwayomi-WebUI/pull/95) by @AriaMoradi) - (r871) migrate EmptyView to Mui 5 ([#95](https://github.com/Suwayomi/Tachidesk-WebUI/pull/95) by @AriaMoradi)
- (r872) migrate CategorySelect to Mui 5 ([#85](https://github.com/Suwayomi/Suwayomi-WebUI/pull/85) by @AriaMoradi) - (r872) migrate CategorySelect to Mui 5 ([#85](https://github.com/Suwayomi/Tachidesk-WebUI/pull/85) by @AriaMoradi)
- (r873) migrate LibraryOptions to Mui 5 ([#83](https://github.com/Suwayomi/Suwayomi-WebUI/pull/83) by @AriaMoradi) - (r873) migrate LibraryOptions to Mui 5 ([#83](https://github.com/Suwayomi/Tachidesk-WebUI/pull/83) by @AriaMoradi)
- (r874) migrate ChapterCard.tsx to Mui 5 ([#80](https://github.com/Suwayomi/Suwayomi-WebUI/pull/80) by @AriaMoradi) - (r874) migrate ChapterCard.tsx to Mui 5 ([#80](https://github.com/Suwayomi/Tachidesk-WebUI/pull/80) by @AriaMoradi)
- (r875) migrate App.tsx to Mui 5 ([#79](https://github.com/Suwayomi/Suwayomi-WebUI/pull/79) by @AriaMoradi) - (r875) migrate App.tsx to Mui 5 ([#79](https://github.com/Suwayomi/Tachidesk-WebUI/pull/79) by @AriaMoradi)
- (r876) migrate SourceConfigure to Mui 5 ([#103](https://github.com/Suwayomi/Suwayomi-WebUI/pull/103) by @AriaMoradi) - (r876) migrate SourceConfigure to Mui 5 ([#103](https://github.com/Suwayomi/Tachidesk-WebUI/pull/103) by @AriaMoradi)
- (r877) migrate Settings to Mui 5 ([#102](https://github.com/Suwayomi/Suwayomi-WebUI/pull/102) by @AriaMoradi) - (r877) migrate Settings to Mui 5 ([#102](https://github.com/Suwayomi/Tachidesk-WebUI/pull/102) by @AriaMoradi)
- (r878) migrate Updates to Mui 5 ([#104](https://github.com/Suwayomi/Suwayomi-WebUI/pull/104) by @AriaMoradi) - (r878) migrate Updates to Mui 5 ([#104](https://github.com/Suwayomi/Tachidesk-WebUI/pull/104) by @AriaMoradi)
- (r879) Save tabs number in Url to persist tab when go to other paths ([#78](https://github.com/Suwayomi/Suwayomi-WebUI/pull/78) by @abhijeetChawla) - (r879) Save tabs number in Url to persist tab when go to other paths ([#78](https://github.com/Suwayomi/Tachidesk-WebUI/pull/78) by @abhijeetChawla)
- (r880) migrate LangSelect to Mui 5 ([#86](https://github.com/Suwayomi/Suwayomi-WebUI/pull/86) by @AriaMoradi) - (r880) migrate LangSelect to Mui 5 ([#86](https://github.com/Suwayomi/Tachidesk-WebUI/pull/86) by @AriaMoradi)
- (r881) migrate ExtensionCard.tsx to Mui 5 ([#81](https://github.com/Suwayomi/Suwayomi-WebUI/pull/81) by @AriaMoradi) - (r881) migrate ExtensionCard.tsx to Mui 5 ([#81](https://github.com/Suwayomi/Tachidesk-WebUI/pull/81) by @AriaMoradi)
- (r882) migrate SingleSearch to Mui 5 ([#101](https://github.com/Suwayomi/Suwayomi-WebUI/pull/101) by @AriaMoradi) - (r882) migrate SingleSearch to Mui 5 ([#101](https://github.com/Suwayomi/Tachidesk-WebUI/pull/101) by @AriaMoradi)
- (r883) migrate LoadingPlaceholder to Mui 5 ([#96](https://github.com/Suwayomi/Suwayomi-WebUI/pull/96) by @AriaMoradi) - (r883) migrate LoadingPlaceholder to Mui 5 ([#96](https://github.com/Suwayomi/Tachidesk-WebUI/pull/96) by @AriaMoradi)
- (r884) migrate About to Mui 5 ([#105](https://github.com/Suwayomi/Suwayomi-WebUI/pull/105) by @AriaMoradi) - (r884) migrate About to Mui 5 ([#105](https://github.com/Suwayomi/Tachidesk-WebUI/pull/105) by @AriaMoradi)
- (r885) migrate SourceCard to Mui 5 ([#82](https://github.com/Suwayomi/Suwayomi-WebUI/pull/82) by @AriaMoradi) - (r885) migrate SourceCard to Mui 5 ([#82](https://github.com/Suwayomi/Tachidesk-WebUI/pull/82) by @AriaMoradi)
- (r886) migrate Manga to Mui 5 ([#99](https://github.com/Suwayomi/Suwayomi-WebUI/pull/99) by @AriaMoradi) - (r886) migrate Manga to Mui 5 ([#99](https://github.com/Suwayomi/Tachidesk-WebUI/pull/99) by @AriaMoradi)
- (r887) migrate Browse to Mui 5 ([#98](https://github.com/Suwayomi/Suwayomi-WebUI/pull/98) by @AriaMoradi) - (r887) migrate Browse to Mui 5 ([#98](https://github.com/Suwayomi/Tachidesk-WebUI/pull/98) by @AriaMoradi)
- (r888) migrate DesktopSideBar to Mui 5 ([#87](https://github.com/Suwayomi/Suwayomi-WebUI/pull/87) by @AriaMoradi) - (r888) migrate DesktopSideBar to Mui 5 ([#87](https://github.com/Suwayomi/Tachidesk-WebUI/pull/87) by @AriaMoradi)
- (r889) cleanup library ([#107](https://github.com/Suwayomi/Suwayomi-WebUI/pull/107) by @AriaMoradi) - (r889) cleanup library ([#107](https://github.com/Suwayomi/Tachidesk-WebUI/pull/107) by @AriaMoradi)
- (r890) support for new searchTerm (by @AriaMoradi) - (r890) support for new searchTerm (by @AriaMoradi)
- (r891) Revert "support for new searchTerm" (by @AriaMoradi) - (r891) Revert "support for new searchTerm" (by @AriaMoradi)
- (r892) add support for emptySearch ([#109](https://github.com/Suwayomi/Suwayomi-WebUI/pull/109) by @AriaMoradi) - (r892) add support for emptySearch ([#109](https://github.com/Suwayomi/Tachidesk-WebUI/pull/109) by @AriaMoradi)
- (r893) add support for MultiSelectListPreference ([#108](https://github.com/Suwayomi/Suwayomi-WebUI/pull/108) by @AriaMoradi) - (r893) add support for MultiSelectListPreference ([#108](https://github.com/Suwayomi/Tachidesk-WebUI/pull/108) by @AriaMoradi)
@@ -469,24 +469,24 @@
## TL;DR ## TL;DR
- Fixed ReadComicOnline, Toonily and possibly other sources not working - Fixed ReadComicOnline, Toonily and possibly other sources not working
- Backup and Restore now includes Updates tab data - Backup and Restore now includes Updates tab data
- Removed Anime support from WebUI, Anime support will also be removed from Suwayomi-Server in a future update - Removed Anime support from WebUI, Anime support will also be removed from Tachidesk-Server in a future update
## Suwayomi-Server Changelog ## Tachidesk-Server Changelog
- (r973) convert android.jar lib to a maven repo - (r973) convert android.jar lib to a maven repo
- (r978) mimic Tachiyomi's behaviour more closely, fixes ReadComicOnline (EN) - (r978) mimic Tachiyomi's behaviour more closely, fixes ReadComicOnline (EN)
- (r980) fix export chapter ordering, include new props in backup - (r980) fix export chapter ordering, include new props in backup
- (r982) remove isNsfw annotation detection - (r982) remove isNsfw annotation detection
- (r984) use correct time conversion units when doing backups - (r984) use correct time conversion units when doing backups
- (r989) Support using a CatalogueSource instead of only HttpSources ([#219](https://github.com/Suwayomi/Suwayomi-Server/pull/219) by @Syer10) - (r989) Support using a CatalogueSource instead of only HttpSources ([#219](https://github.com/Suwayomi/Tachidesk-Server/pull/219) by @Syer10)
- (r991) Use a custom task to run electron ([#220](https://github.com/Suwayomi/Suwayomi-Server/pull/220) by @Syer10) - (r991) Use a custom task to run electron ([#220](https://github.com/Suwayomi/Tachidesk-Server/pull/220) by @Syer10)
## Suwayomi-WebUI Changelog ## Tachidesk-WebUI Changelog
- (r810) fix wrong strings in set Server Address dialog, fixes [#39](https://github.com/Suwayomi/Suwayomi-WebUI/issues/39) - (r810) fix wrong strings in set Server Address dialog, fixes [#39](https://github.com/Suwayomi/Tachidesk-WebUI/issues/39)
- (r811) fix chapterFetch loop - (r811) fix chapterFetch loop
- (r812) fix overlapping requests - (r812) fix overlapping requests
- (r813) fix typo - (r813) fix typo
- (r814) Better portrait support ([#41](https://github.com/Suwayomi/Suwayomi-WebUI/issues/41) by @minhe7735) - (r814) Better portrait support ([#41](https://github.com/Suwayomi/Tachidesk-WebUI/issues/41) by @minhe7735)
- (r815) fixes Reader navbar colors when in light mode ([#43](https://github.com/Suwayomi/Suwayomi-WebUI/issues/43) by @abhijeetChawla) - (r815) fixes Reader navbar colors when in light mode ([#43](https://github.com/Suwayomi/Tachidesk-WebUI/issues/43) by @abhijeetChawla)
- (r816) default languages cleanup, force Local source enabled - (r816) default languages cleanup, force Local source enabled
- (r817) force Local source at LangSelect - (r817) force Local source at LangSelect
- (r818) rename ExtensionLangSelect: generic name for generic use - (r818) rename ExtensionLangSelect: generic name for generic use
@@ -500,13 +500,13 @@
- added support for a equivalent page to Tachiyomi's Updates tab - added support for a equivalent page to Tachiyomi's Updates tab
- fix launchers not working on macOS M1/arm64 - fix launchers not working on macOS M1/arm64
## Suwayomi-Server Changelog ## Tachidesk-Server Changelog
- (r956) fix macOS-arm64 bundle launchers not working - (r956) fix macOS-arm64 bundle launchers not working
- (r957) Workaround StdLib issue and add KtLint to all modules ([#206](https://github.com/Suwayomi/Suwayomi-Server/pull/206) by @Syer10) - (r957) Workaround StdLib issue and add KtLint to all modules ([#206](https://github.com/Suwayomi/Tachidesk-Server/pull/206) by @Syer10)
- (r960-r963) Add recently updated chapters(Updates) endpoint - (r960-r963) Add recently updated chapters(Updates) endpoint
## Suwayomi-WebUI Changelog ## Tachidesk-WebUI Changelog
- (r808) fix chapter list not calling onlineFetch=true - (r808) fix chapter list not calling onlineFetch=true
- (r809) add support for Updates - (r809) add support for Updates
@@ -517,7 +517,7 @@
- Fixed Local source not working on Windows - Fixed Local source not working on Windows
- Fixed Chapter numbers being shown incorrectly - Fixed Chapter numbers being shown incorrectly
## Suwayomi-Server ## Tachidesk-Server
### Public API ### Public API
#### Non-breaking changes #### Non-breaking changes
- N/A - N/A
@@ -526,17 +526,17 @@
- N/A - N/A
#### Bug fixes #### Bug fixes
- (r948) Fix ManaToki (KO) and NewToki (KO) (issue [#202](https://github.com/Suwayomi/Suwayomi-Server/issue/202)) - (r948) Fix ManaToki (KO) and NewToki (KO) (issue [#202](https://github.com/Suwayomi/Tachidesk-Server/issue/202))
- (r949) Local source: fix windows paths - (r949) Local source: fix windows paths
### Private API ### Private API
- (r941) Update BytecodeEditor to use Java NIO Paths ([#200](https://github.com/Suwayomi/Suwayomi-Server/pull/200) by @Syer10) - (r941) Update BytecodeEditor to use Java NIO Paths ([#200](https://github.com/Suwayomi/Tachidesk-Server/pull/200) by @Syer10)
- (r942) Gradle Updates ([#199](https://github.com/Suwayomi/Suwayomi-Server/pull/199) by @Syer10) - (r942) Gradle Updates ([#199](https://github.com/Suwayomi/Tachidesk-Server/pull/199) by @Syer10)
## Suwayomi-WebUI ## Tachidesk-WebUI
#### Visible changes #### Visible changes
- (r804) update text positioning on Reader and Player ([#35](https://github.com/Suwayomi/Suwayomi-WebUI/pull/35) by @voltrare) - (r804) update text positioning on Reader and Player ([#35](https://github.com/Suwayomi/Tachidesk-WebUI/pull/35) by @voltrare)
- (r806) Source card for Local source is different - (r806) Source card for Local source is different
- (r807) add Local source guide - (r807) add Local source guide
@@ -552,10 +552,10 @@
## TL;DR ## TL;DR
- Loading sources' manga list is at least twice as fast - Loading sources' manga list is at least twice as fast
- Added support for Tachiyomi's Local source - Added support for Tachiyomi's Local source
- Added BasicAuth support, now you can protect your Suwayomi instance if you are running it on a public server - Added BasicAuth support, now you can protect your Tachidesk instance if you are running it on a public server
- Added ability to turn off cache for image requests - Added ability to turn off cache for image requests
## Suwayomi-Server ## Tachidesk-Server
### Public API ### Public API
#### Non-breaking changes #### Non-breaking changes
- (r915) add BasicAuth support - (r915) add BasicAuth support
@@ -577,18 +577,18 @@
## Suwayomi-WebUI ## Tachidesk-WebUI
#### Visible changes #### Visible changes
- (r790) nice looking progress percentage - (r790) nice looking progress percentage
- (r791) show a Delete button for downloaded chapters - (r791) show a Delete button for downloaded chapters
- (r792) Update hover effect using more of Material-UI color pallete ([#29](https://github.com/Suwayomi/Suwayomi-WebUI/pull/29) by @voltrare) - (r792) Update hover effect using more of Material-UI color pallete ([#29](https://github.com/Suwayomi/Tachidesk-WebUI/pull/29) by @voltrare)
- (r793) Optimize images ([#32](https://github.com/Suwayomi/Suwayomi-WebUI/pull/32) by @phanirithvij) - (r793) Optimize images ([#32](https://github.com/Suwayomi/Tachidesk-WebUI/pull/32) by @phanirithvij)
- (r794) try fix #30 ([#31](https://github.com/Suwayomi/Suwayomi-WebUI/pull/31) by @phanirithvij) - (r794) try fix #30 ([#31](https://github.com/Suwayomi/Tachidesk-WebUI/pull/31) by @phanirithvij)
- (r795) fix viewing page number when the string is long - (r795) fix viewing page number when the string is long
- (r796) show proper display name for source - (r796) show proper display name for source
- (r797) fail gracefully when a thumbnail has errors - (r797) fail gracefully when a thumbnail has errors
- (r798) fix when a source fails to load mangas - (r798) fix when a source fails to load mangas
- (r800) add Local source ([#31](https://github.com/Suwayomi/Suwayomi-WebUI/pull/31)) - (r800) add Local source ([#31](https://github.com/Suwayomi/Tachidesk-WebUI/pull/31))
- (r803) add support for useCache - (r803) add support for useCache
#### Bug fixes #### Bug fixes
@@ -607,13 +607,13 @@
- Added support for configuration of sources, this enables MangaDex, Komga, Cubari and many other sources - Added support for configuration of sources, this enables MangaDex, Komga, Cubari and many other sources
- Chapters in the Manga page and Sources in the source page now look nicer and will glow with mouse hover - Chapters in the Manga page and Sources in the source page now look nicer and will glow with mouse hover
## Suwayomi-Server ## Tachidesk-Server
### Public API ### Public API
#### Non-breaking changes #### Non-breaking changes
- (r888) add installing APK from external sources endpoint - (r888) add installing APK from external sources endpoint
#### Breaking changes #### Breaking changes
- (r877 [#188](https://github.com/Suwayomi/Suwayomi-Server/pull/188) by @Syer10) `MangaDataClass.genre` changed type to `List<String>` - (r877 [#188](https://github.com/Suwayomi/Tachidesk-Server/pull/188) by @Syer10) `MangaDataClass.genre` changed type to `List<String>`
#### Bug fixes #### Bug fixes
- (r899-r901) fix when an external apk is installed and it doesn't have the default tachiyomi-extensions name - (r899-r901) fix when an external apk is installed and it doesn't have the default tachiyomi-extensions name
@@ -624,17 +624,17 @@
- (r902) cleanup print/ln instances - (r902) cleanup print/ln instances
- (r906) better handling of uninstalling Extensions - (r906) better handling of uninstalling Extensions
## Suwayomi-WebUI ## Tachidesk-WebUI
#### Visible changes #### Visible changes
- (r770) add support for the new genre type - (r770) add support for the new genre type
- (r771) set the default value of `showNsfw` to `true` so we won't have visual artifacts with a clean install - (r771) set the default value of `showNsfw` to `true` so we won't have visual artifacts with a clean install
- (r774 [#21](https://github.com/Suwayomi/Suwayomi-WebUI/pull/21) by @voltrare) `ReaderNavbar.jsx`: Swap close and retract Navbar buttons - (r774 [#21](https://github.com/Suwayomi/Tachidesk-WebUI/pull/21) by @voltrare) `ReaderNavbar.jsx`: Swap close and retract Navbar buttons
- (r775 [#23](https://github.com/Suwayomi/Suwayomi-WebUI/pull/23) by @voltrare) `yarn.lock`: Fixes version inconsistency after commit 9b866811b - (r775 [#23](https://github.com/Suwayomi/Tachidesk-WebUI/pull/23) by @voltrare) `yarn.lock`: Fixes version inconsistency after commit 9b866811b
- (r776 [#23](https://github.com/Suwayomi/Suwayomi-WebUI/pull/23) by @voltrare) add margin between Source and Extension cards, make the Search button look nicer - (r776 [#23](https://github.com/Suwayomi/Tachidesk-WebUI/pull/23) by @voltrare) add margin between Source and Extension cards, make the Search button look nicer
- (r777) add support for installing external APK files - (r777) add support for installing external APK files
- (r778) fix the makeToaster? - (r778) fix the makeToaster?
- (r779) Action button for installing external extension - (r779) Action button for installing external extension
- (r780 Suwayomi/Suwayomi-WebUI#25) add on hover, active effect to Chapter/Episode card - (r780 Suwayomi/Tachidesk-WebUI#25) add on hover, active effect to Chapter/Episode card
- (r782-r785) updating material-ui to v5 changed the theme - (r782-r785) updating material-ui to v5 changed the theme
- (r785-r788) better `SourceCard` looks on mobile, move `SourceDataClass.isConfigurable` gear button to `SourceMangas` - (r785-r788) better `SourceCard` looks on mobile, move `SourceDataClass.isConfigurable` gear button to `SourceMangas`
- (r789) implement source configuration - (r789) implement source configuration
@@ -648,7 +648,7 @@
# Server: v0.4.9 + WebUI: r769 # Server: v0.4.9 + WebUI: r769
## Suwayomi-Server ## Tachidesk-Server
### Public API ### Public API
#### Non-breaking changes #### Non-breaking changes
- N/A - N/A
@@ -677,7 +677,7 @@
- (r873) `publish.yml` and `build_push.yml`: fix oopsies - (r873) `publish.yml` and `build_push.yml`: fix oopsies
## Suwayomi-WebUI ## Tachidesk-WebUI
#### Visible changes #### Visible changes
- (r767-r769) Support for hiding NSFW content in settings screen, extensions screen, sources screen - (r767-r769) Support for hiding NSFW content in settings screen, extensions screen, sources screen
@@ -690,14 +690,14 @@
#### Non-code changes #### Non-code changes
- (r42-r45) Change `README.md`: some links and stuff - (r42-r45) Change `README.md`: some links and stuff
- (r45-r765) Add all of the commit history from when WebUI was separated from Server, jumping from r45 to r765 (r45 is exactly the same as r765) - (r45-r765) Add all of the commit history from when WebUI was separated from Server, jumping from r45 to r765 (r45 is exactly the same as r765)
- (r766) Steal `.gitattributes` from Suwayomi-Server - (r766) Steal `.gitattributes` from Tachidesk-Server
- (r767) Dependency cleanup in `package.json` - (r767) Dependency cleanup in `package.json`
# Server: v0.4.8 + WebUI: r41 # Server: v0.4.8 + WebUI: r41
## Suwayomi-Server ## Tachidesk-Server
### Public API ### Public API
#### Non-breaking changes #### Non-breaking changes
- Added support for serializing Search Filters - Added support for serializing Search Filters
@@ -708,19 +708,19 @@
#### Bug fixes #### Bug fixes
- Fixed a bug where backup restore reversed chapter order - Fixed a bug where backup restore reversed chapter order
- Open Site feature now works properly (https://github.com/Suwayomi/Suwayomi-WebUI/issues/19) - Open Site feature now works properly (https://github.com/Suwayomi/Tachidesk-WebUI/issues/19)
### Private API ### Private API
- Added `CloudflareInterceptor` from TachiWeb-Server - Added `CloudflareInterceptor` from TachiWeb-Server
- Restoring backup for mangas in library(merging manga data) is now supported - Restoring backup for mangas in library(merging manga data) is now supported
## Suwayomi-WebUI ## Tachidesk-WebUI
#### Visible changes #### Visible changes
- Better looking manga card titles - Better looking manga card titles
- Better reader title, next, prev buttons - Better reader title, next, prev buttons
#### Bug fixes #### Bug fixes
- Open Site feature now works properly (https://github.com/Suwayomi/Suwayomi-WebUI/issues/19) - Open Site feature now works properly (https://github.com/Suwayomi/Tachidesk-WebUI/issues/19)
- Re-ordering categories now works - Re-ordering categories now works
#### Internal changes #### Internal changes

View File

@@ -1,6 +1,6 @@
# Contributing # Contributing
## Where should I start? ## Where should I start?
Checkout [This Kanban Board](https://github.com/Suwayomi/Suwayomi-Server/projects/1) to see the rough development roadmap. Checkout [This Kanban Board](https://github.com/Suwayomi/Tachidesk/projects/1) to see the rough development roadmap.
### Important notes ### Important notes
- Notify the developers on [Suwayomi discord](https://discord.gg/DDZdqZWaHA) (#tachidesk-server and #tachidesk-webui channels) or open a WIP pull request before starting if you decide to take on working on anything from/not from the roadmap in order to avoid parallel efforts on the same issue/feature. - Notify the developers on [Suwayomi discord](https://discord.gg/DDZdqZWaHA) (#tachidesk-server and #tachidesk-webui channels) or open a WIP pull request before starting if you decide to take on working on anything from/not from the roadmap in order to avoid parallel efforts on the same issue/feature.
@@ -8,56 +8,25 @@ Checkout [This Kanban Board](https://github.com/Suwayomi/Suwayomi-Server/project
- We hate big pull requests, make them as small as possible, change one meaningful thing. Spam pull requests, we don't mind. - We hate big pull requests, make them as small as possible, change one meaningful thing. Spam pull requests, we don't mind.
### Project goals and vision ### Project goals and vision
- Porting Tachiyomi and covering its features - Porting Tachiyomi and covering it's features
- Syncing with Tachiyomi, [main issue](https://github.com/Suwayomi/Suwayomi-Server/issues/159) - Syncing with Tachiyomi, [main issue](https://github.com/Suwayomi/Tachidesk-Server/issues/159)
- Generally rejecting features that Tachiyomi(main app) doesn't have, - Generally rejecting features that Tachiyomi(main app) doesn't have,
- Unless it's something that makes sense for desktop sizes or desktop form factor (keyboard + mouse) - Unless it's something that makes sense for desktop sizes or desktop form factor (keyboard + mouse)
- Additional/crazy features can go in forks and alternative clients - Additional/crazy features can go in forks and alternative clients
- [Suwayomi-WebUI](https://github.com/Suwayomi/Suwayomi-WebUI) should - [Tachidesk-WebUI](https://github.com/Suwayomi/Tachidesk-WebUI) should
- be responsive - be responsive
- support both desktop and mobile form factors well - support both desktop and mobile form factors well
## How does Suwayomi-Server work? ## How does Tachidesk-Server work?
This project has two components: This project has two components:
1. **Server:** contains the implementation of [tachiyomi's extensions library](https://github.com/tachiyomiorg/extensions-lib) and uses an Android compatibility library to run jar libraries converted from apk extensions. All this concludes to serving a GraphQL API. 1. **Server:** contains the implementation of [tachiyomi's extensions library](https://github.com/tachiyomiorg/extensions-lib) and uses an Android compatibility library to run jar libraries converted from apk extensions. All this concludes to serving a REST API.
2. **WebUI:** A React SPA(`create-react-app`) project that works with the server to do the presentation located at https://github.com/Suwayomi/Suwayomi-WebUI 2. **WebUI:** A React SPA(`create-react-app`) project that works with the server to do the presentation located at https://github.com/Suwayomi/Tachidesk-WebUI
### API
#### GraphQL
*Only available in the preview at the moment*
The GraphQL API can be queried with a POST request to `/api/graphql`. There is also the GraphiQL IDE accessible by the browser at `/api/graphql` to perform ad-hoc queries and explore the API.
#### REST
> [!WARNING]
>
> Soon to be deprecated
The REST API can be queried at `/api/v1`. An interactive Swagger API explorer is available at `/api/swagger-ui`.
### Tracker client authorization
#### OAuth
Since the url of a Suwayomi-Server is not known, it is not possible to redirect directly to the client.<br/>
Thus, to provide tracker support via oauth, the tracker clients redirect to the [suwayomi website](https://suwayomi.org/)
and there the actual redirection to the client takes place.
When implementing the login process in your client you have to make sure to follow some preconditions:
To be able to redirect to the client you have to attach a `state` object to the query of the auth url
- this `state` object has to have a `redirectUrl` which points to the client route at which you want to handle the auth result
- besides the `redirectUrl` you can pass any information you require to handle the result (e.g. the server `id` of the tracker client)
- example URL for AniList: `https://anilist.co/api/v2/oauth/authorize?client_id=ID&response_type=token&state={ redirectUrl: "http://localhost:4567/handle/oauth/result", trackerId: 1, anyOtherInfo: "your client requires" }`
Once the permission has been granted, you will get redirected to the client at the provided route (`redirectUrl`).<br/>
- Example URL (decoded) for AniList: `http://localhost:4567/handle/oauth/result?access_token=TOKEN&token_type=Bearer&expires_in=31622400&state={ redirectUrl: "http://localhost:4567/handle/oauth/result", trackerId: 1, anyOtherInfo: "your client requires" }`).<br/>
Finally, to finish the login process, you just have to pass this URL to the server as the `callbackUrl`.
## Why a web app? ## Why a web app?
This structure is chosen to This structure is chosen to
- Achieve the maximum multi-platform-ness - Achieve the maximum multi-platform-ness
- Gives the ability to access Suwayomi-Server from a remote client e.g., your phone, tablet or smart TV - Gives the ability to access Tachidesk-Server from a remote client e.g., your phone, tablet or smart TV
- Ease development of user interfaces for Suwayomi - Ease development of user interfaces for Tachidesk
## Building from source ## Building from source
### Prerequisites ### Prerequisites
@@ -65,14 +34,14 @@ You need these software packages installed in order to build the project
- Java Development Kit and Java Runtime Environment version 8 or newer(both Oracle JDK and OpenJDK works) - Java Development Kit and Java Runtime Environment version 8 or newer(both Oracle JDK and OpenJDK works)
### building the full-blown jar (Suwayomi-Server + Suwayomi-WebUI bundle) ### building the full-blown jar (Tachidesk-Server + Tachidesk-WebUI bundle)
Run `./gradlew server:downloadWebUI server:shadowJar`, the resulting built jar file will be `server/build/Suwayomi-Server-vX.Y.Z-rxxx.jar`. Run `./gradlew server:downloadWebUI server:shadowJar`, the resulting built jar file will be `server/build/Tachidesk-Server-vX.Y.Z-rxxx.jar`.
### building without `webUI` bundled (server only) ### building without `webUI` bundled (server only)
Delete `server/src/main/resources/WebUI.zip` if exists from previous runs, then run `./gradlew server:shadowJar`, the resulting built jar file will be `server/build/Suwayomi-Server-vX.Y.Z-rxxx.jar`. Delete `server/src/main/resources/WebUI.zip` if exists from previous runs, then run `./gradlew server:shadowJar`, the resulting built jar file will be `server/build/Tachidesk-Server-vX.Y.Z-rxxx.jar`.
### building the Windows package ### building the Windows package
First Build the jar, then cd into the `scripts` directory and run `./windows-bundler.sh win32` or `./windows-bundler.sh win64` depending on the target architecture, the resulting built zip package file will be `server/build/Suwayomi-Server-vX.Y.Z-rxxx-winXX.zip`. First Build the jar, then cd into the `scripts` directory and run `./windows-bundler.sh win32` or `./windows-bundler.sh win64` depending on the target architecture, the resulting built zip package file will be `server/build/Tachidesk-Server-vX.Y.Z-rxxx-winXX.zip`.
## Running in development mode ## Running in development mode
run `./gradlew :server:run --stacktrace` to run the server run `./gradlew :server:run --stacktrace` to run the server

103
README.md
View File

@@ -1,11 +1,11 @@
| Build | Stable | Preview | Support Server | | Build | Stable | Preview | Support Server |
|-----------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------| |-------|----------|---------|---------|
| ![CI](https://github.com/Suwayomi/Suwayomi-Server/actions/workflows/build_push.yml/badge.svg) | [![stable release](https://img.shields.io/github/release/Suwayomi/Suwayomi-Server.svg?maxAge=3600&label=download)](https://github.com/Suwayomi/Suwayomi-Server/releases) | [![preview](https://img.shields.io/badge/dynamic/json?url=https://github.com/Suwayomi/Suwayomi-Server-preview/raw/main/index.json&label=download&query=$.latest&color=blue)](https://github.com/Suwayomi/Suwayomi-Server-preview/releases/latest) | [![Discord](https://img.shields.io/discord/801021177333940224.svg?label=discord&labelColor=7289da&color=2c2f33&style=flat)](https://discord.gg/DDZdqZWaHA) | | ![CI](https://github.com/Suwayomi/Tachidesk/actions/workflows/build_push.yml/badge.svg) | [![stable release](https://img.shields.io/github/release/Suwayomi/Tachidesk.svg?maxAge=3600&label=download)](https://github.com/Suwayomi/Tachidesk/releases) | [![preview](https://img.shields.io/badge/dynamic/json?url=https://github.com/Suwayomi/Tachidesk-preview/raw/main/index.json&label=download&query=$.latest&color=blue)](https://github.com/Suwayomi/Tachidesk-preview/releases/latest) | [![Discord](https://img.shields.io/discord/801021177333940224.svg?label=discord&labelColor=7289da&color=2c2f33&style=flat)](https://discord.gg/DDZdqZWaHA) |
## Table of Content ## Table of Content
- [What is Suwayomi?](#what-is-suwayomi) - [What is Tachidesk?](#what-is-tachidesk)
- [Suwayomi client projects](#Suwayomi-client-projects) - [Tachidesk client projects](#tachidesk-client-projects)
* [Is this application usable? Should I test it?](#is-this-application-usable-should-i-test-it) * [Is this application usable? Should I test it?](#is-this-application-usable-should-i-test-it)
- [Downloading and Running the app](#downloading-and-running-the-app) - [Downloading and Running the app](#downloading-and-running-the-app)
* [Using Operating System Specific Bundles](#using-operating-system-specific-bundles) * [Using Operating System Specific Bundles](#using-operating-system-specific-bundles)
@@ -13,13 +13,13 @@
+ [Windows](#windows) + [Windows](#windows)
+ [macOS](#macos) + [macOS](#macos)
+ [GNU/Linux](#gnulinux) + [GNU/Linux](#gnulinux)
* [Other methods of getting Suwayomi](#other-methods-of-getting-suwayomi) * [Other methods of getting Tachidesk](#other-methods-of-getting-tachidesk)
+ [Arch Linux](#arch-linux) + [Arch Linux](#arch-linux)
+ [Ubuntu-based distributions](#ubuntu-based-distributions) + [Ubuntu-based distributions](#ubuntu-based-distributions)
+ [Docker](#docker) + [Docker](#docker)
* [Advanced Methods](#advanced-methods) * [Advanced Methods](#advanced-methods)
+ [Running the jar release directly](#running-the-jar-release-directly) + [Running the jar release directly](#running-the-jar-release-directly)
+ [Using Suwayomi Remotely](#using-suwayomi-remotely) + [Using Tachidesk Remotely](#using-tachidesk-remotely)
- [Syncing With Tachiyomi](#syncing-with-tachiyomi) - [Syncing With Tachiyomi](#syncing-with-tachiyomi)
- [Troubleshooting and Support](#troubleshooting-and-support) - [Troubleshooting and Support](#troubleshooting-and-support)
- [Contributing and Technical info](#contributing-and-technical-info) - [Contributing and Technical info](#contributing-and-technical-info)
@@ -27,29 +27,27 @@
- [License](#license) - [License](#license)
<!-- Generated with https://ecotrust-canada.github.io/markdown-toc/ --> <!-- Generated with https://ecotrust-canada.github.io/markdown-toc/ -->
# What is Suwayomi? # What is Tachidesk?
<img src="https://github.com/Suwayomi/Suwayomi-Server/raw/master/server/src/main/resources/icon/faviconlogo.png" alt="drawing" width="200"/> <img src="https://github.com/Suwayomi/Tachidesk/raw/master/server/src/main/resources/icon/faviconlogo.png" alt="drawing" width="200"/>
A free and open source manga reader server that runs extensions built for [Tachiyomi](https://tachiyomi.org/). A free and open source manga reader server that runs extensions built for [Tachiyomi](https://tachiyomi.org/).
Suwayomi is an independent Tachiyomi compatible software and is **not a Fork of** Tachiyomi. Tachidesk is an independent Tachiyomi compatible software and is **not a Fork of** Tachiyomi.
Suwayomi-Server is as multi-platform as you can get. Any platform that runs java and/or has a modern browser can run it. This includes Windows, Linux, macOS, chrome OS, etc. Follow [Downloading and Running the app](#downloading-and-running-the-app) for installation instructions. Tachidesk-Server is as multi-platform as you can get. Any platform that runs java and/or has a modern browser can run it. This includes Windows, Linux, macOS, chrome OS, etc. Follow [Downloading and Running the app](#downloading-and-running-the-app) for installation instructions.
Ability to sync with Tachiyomi is a planned feature, for more info look [here](#syncing-with-tachiyomi). Ability to sync with Tachiyomi is a planned feature, for more info look [here](#syncing-with-tachiyomi).
# Suwayomi client projects # Tachidesk client projects
**You need a client/user interface app as a front-end for Suwayomi-Server, if you [Directly Download Suwayomi-Server](https://github.com/Suwayomi/Suwayomi-Server/releases/latest) you'll get a bundled version of [Suwayomi-WebUI](https://github.com/Suwayomi/Suwayomi-WebUI) with it.** **You need a client/user interface app as a front-end for Tachidesk-Server, if you [Directly Download Tachidesk-Server](https://github.com/Suwayomi/Tachidesk-Server/releases/latest) you'll get a bundled version of [Tachidesk-WebUI](https://github.com/Suwayomi/Tachidesk-WebUI) with it.**
Here's a list of known clients/user interfaces for Suwayomi-Server: Here's a list of known clients/user interfaces for Tachidesk-Server:
##### Actively Developed Clients ##### Actively Developed Cients
- [Suwayomi-WebUI](https://github.com/Suwayomi/Suwayomi-WebUI): The web/ElectronJS front-end that Suwayomi-Server ships with by default. - [Tachidesk-WebUI](https://github.com/Suwayomi/Tachidesk-WebUI): The web/ElectronJS front-end that Tachidesk-Server ships with by default.
- [Tachidesk-JUI](https://github.com/Suwayomi/Tachidesk-JUI): The native desktop front-end for Suwayomi-Server. Currently, the most advanced. - [Tachidesk-JUI](https://github.com/Suwayomi/Tachidesk-JUI): The native desktop front-end for Tachidesk-Server. Currently the most advanced.
- [Tachidesk-qtui](https://github.com/Suwayomi/Tachidesk-qtui): A C++/Qt front-end for mobile devices(Android/linux), feature support is basic. - [Tachidesk-qtui](https://github.com/Suwayomi/Tachidesk-qtui): A C++/Qt front-end for mobile devices(Android/linux), feature support is basic.
- [Tachidesk-Sorayomi](https://github.com/Suwayomi/Tachidesk-Sorayomi): A Flutter front-end for Desktop(Linux, windows, etc.), Web and Android with a User Interface inspired by Tachiyomi. - [Tachidesk-Sorayomi](https://github.com/Suwayomi/Tachidesk-Sorayomi): A Flutter front-end for Desktop(Linux, windows, etc.), Web and Android with a User Inerface inspired by Tachiyomi.
- [Tachidesk-VaadinUI](https://github.com/Suwayomi/Tachidesk-VaadinUI): A Web front-end for Suwayomi-Server built with Vaadin. ##### Inctive/Abandoned Cients
- [Suwayomi-VUI](https://github.com/Suwayomi/Suwayomi-VUI): A preview focused web frontend built with svelte with some features the other UIs might not have (migration)
##### Inctive/Abandoned Clients
- [Equinox](https://github.com/Suwayomi/Equinox): A web user interface made with Vue.js. - [Equinox](https://github.com/Suwayomi/Equinox): A web user interface made with Vue.js.
- [Tachidesk-GTK](https://github.com/mahor1221/Tachidesk-GTK): A native Rust/GTK desktop client. - [Tachidesk-GTK](https://github.com/mahor1221/Tachidesk-GTK): A native Rust/GTK desktop client.
@@ -63,32 +61,39 @@ Here is a list of current features:
- Backup and restore support powered by Tachiyomi-compatible Backups - Backup and restore support powered by Tachiyomi-compatible Backups
- Viewing latest updated chapters. - Viewing latest updated chapters.
**Note:** These are capabilities of Suwayomi-Server, the actual working support is provided by each front-end app, checkout their respective readme for more info. **Note:** These are capabilities of Tachidesk-Server, the actual working support is provided by each front-end app, checkout their respective readme for more info.
# Downloading and Running the app # Downloading and Running the app
## Using Operating System Specific Bundles ## Using Operating System Specific Bundles
To facilitate the use of Suwayomi we provide bundle releases that include The Java Runtime Environment, ElectronJS and the Suwayomi-Launcher. To facilitate the use of Tachidesk we provide bundle releases that include The Java Runtime Environment, ElectronJS and 3 Tachidesk Launcher Scripts.
If a bundle for your operating system or cpu architecture is not provided then refer to [Advanced Methods](#advanced-methods) If a bundle for your operating system or cpu architecture is not provided then refer to [Advanced Methods](#advanced-methods)
#### Launcher Scripts
- `Tachidesk Electron Launcher`: Launches Tachidesk inside Electron as a desktop applicaton
- `Tachidesk Browser Launcher`: Launches Tachidesk in a browser window
- `Tachidesk Debug Launcher`: Launches Tachidesk with debug logs attached. If Tachidesk doesn't work for you, running this can give you insight into why.
**Node:** Linux launcher scripts are named a bit differently but work the same.
### Windows ### Windows
Download the latest `win32`(Windows 32-bit) or `win64`(Windows 64-bit) release from [the releases section](https://github.com/Suwayomi/Suwayomi-Server/releases) or a preview one from [the preview repository](https://github.com/Suwayomi/Suwayomi-Server-preview/releases). Download the latest `win32`(Windows 32-bit) or `win64`(Windows 64-bit) release from [the releases section](https://github.com/Suwayomi/Tachidesk-Server/releases) or a preview one from [the preview repository](https://github.com/Suwayomi/Tachidesk-Server-preview/releases).
Unzip the downloaded file and double-click on one of the launcher scripts. Unzip the downloaded file and double click on one of the launcher scripts.
### macOS ### macOS
Download the latest `macOS-x64`(older macOS systems) or `macOS-arm64`(Apple M1 and newer) release from [the releases section](https://github.com/Suwayomi/Suwayomi-Server/releases) or a preview one from [the preview repository](https://github.com/Suwayomi/Suwayomi-Server-preview/releases). Download the latest `macOS-x64`(older macOS systems) or `macOS-arm64`(Apple M1 and newer) release from [the releases section](https://github.com/Suwayomi/Tachidesk-Server/releases) or a preview one from [the preview repository](https://github.com/Suwayomi/Tachidesk-Server-preview/releases).
Unzip the downloaded file and double-click on one of the launcher scripts. Unzip the downloaded file and double click on one of the launcher scripts.
### GNU/Linux ### GNU/Linux
Download the latest `linux-x64`(x86_64) release from [the releases section](https://github.com/Suwayomi/Suwayomi-Server/releases) or a preview one from [the preview repository](https://github.com/Suwayomi/Suwayomi-Server-preview/releases). Download the latest `linux-x64`(x86_64) release from [the releases section](https://github.com/Suwayomi/Tachidesk-Server/releases) or a preview one from [the preview repository](https://github.com/Suwayomi/Tachidesk-Server-preview/releases).
`tar xvf` the downloaded file and double-click on one of the launcher scripts or run them using the terminal. `tar xvf` the downloaded file and double click on one of the launcher scripts or run them using the terminal.
## Other methods of getting Suwayomi ## Other methods of getting Tachidesk
### Arch Linux ### Arch Linux
You can install Suwayomi from the AUR: You can install Tachidesk from the AUR:
``` ```
yay -S tachidesk yay -S tachidesk
``` ```
@@ -96,20 +101,20 @@ yay -S tachidesk
### Debian/Ubuntu ### Debian/Ubuntu
Download the latest deb package from the release section or Install from the MPR Download the latest deb package from the release section or Install from the MPR
``` ```
git clone https://mpr.makedeb.org/suwayomi-server.git git clone https://mpr.makedeb.org/tachidesk-server.git
cd suwayomi-server cd tachidesk-server
makedeb -si makedeb -si
``` ```
### Ubuntu ### Ubuntu
``` ```
sudo add-apt-repository ppa:suwayomi/suwayomi-server sudo add-apt-repository ppa:suwayomi/tachidesk-server
sudo apt update sudo apt update
sudo apt install suwayomi-server sudo apt install tachidesk-server
``` ```
### Docker ### Docker
Check our Official Docker release [Suwayomi Container](https://github.com/orgs/Suwayomi/packages/container/package/tachidesk) for running Suwayomi Server in a docker container. Source code for our container is available at [docker-tachidesk](https://github.com/Suwayomi/docker-tachidesk). By default, the server will be running on http://localhost:4567 open this url in your browser. Check our Official Docker release [Tachidesk Container](https://github.com/orgs/Suwayomi/packages/container/package/tachidesk) for running Tachidesk Server in a docker container. Source code for our container is available at [docker-tachidesk](https://github.com/Suwayomi/docker-tachidesk). By default the server will be running on http://localhost:4567 open this url in your browser.
Install from the command line: Install from the command line:
``` ```
@@ -123,35 +128,35 @@ Run Container from the command line:
## Advanced Methods ## Advanced Methods
### Running the jar release directly ### Running the jar release directly
In order to run the app you need the following: In order to run the app you need the following:
- The jar release of Suwayomi-Server - The jar release of Tachidesk-Server
- The Java Runtime Environment(JRE) 8 or newer - The Java Runtime Environment(JRE) 8 or newer
- A Browser like Google Chrome, Firefox, Edge, etc. - A Browser like Google Chrome, Firefox, Edge, etc.
- ElectronJS (optional) - ElectronJS (optional)
Download the latest `.jar` release from [the releases section](https://github.com/Suwayomi/Suwayomi-Server/releases) or a preview jar build from [the preview repository](https://github.com/Suwayomi/Suwayomi-Server-preview/releases). Download the latest `.jar` release from [the releases section](https://github.com/Suwayomi/Tachidesk-Server/releases) or a preview jar build from [the preview repository](https://github.com/Suwayomi/Tachidesk-preview/releases).
Make sure you have The Java Runtime Environment installed on your system, Double-click on the jar file or run `java -jar Suwayomi-Server-vX.Y.Z-rxxxx.jar` from a Terminal/Command Prompt window to run the app which will open a new browser window automatically. Make sure you have The Java Runtime Environment installed on your system, Double click on the jar file or run `java -jar Tachidesk-vX.Y.Z-rxxxx.jar` from a Terminal/Command Prompt window to run the app which will open a new browser window automatically.
### Using Suwayomi Remotely ### Using Tachidesk Remotely
You can run Suwayomi on your computer or a server and connect to it remotely through one of our clients or the bundled web interface with a web browser. This method of using Suwayomi is requiring a bit of networking/firewall/port forwarding/server configuration/etc. knowledge on your side, if you can run a Minecraft server and configure it, then you are good to go. You can run Tachidesk on your computer or a server and connect to it remotely through one of our clients or the bundled web interface with a web browser. This method of using Tachidesk is requires a bit of networking/firewall/port forwarding/server configuration/etc. knowledge on your side, if you can run a Minecraft server and configure it, then you are good to go.
Check out [this wiki page](https://github.com/Suwayomi/Suwayomi-Server/wiki/Configuring-Tachidesk-Server) for a guide on configuring Suwayomi-Server. Check out [this wiki page](https://github.com/Suwayomi/Tachidesk-Server/wiki/Configuring-Tachidesk-Server) for a guide on configuring Tachidesk-Server.
If you face issues with your setup then we are happy to provide help, just join our discord server(a discord badge is on the top of the page, you are just a click-clack away!). If you face issues with your setup then we are happy to provide help, just join our discord server(a discord badge is on the top of the page, you are just a click clack away!).
## Syncing With Tachiyomi ## Syncing With Tachiyomi
### The Suwayomi extension and tracker ### The Suwayomi extension and tracker
- You can install the `Suwayomi` extension inside tachiyomi. - You can install the `Suwayomi` extension inside tachiyomi.
- The extension will load your Suwayomi library. - The extension will load your Tachidesk library.
- By manipulating extension search filters you can browse your categories. - By manipulating extension search filters you can browse your categories.
- You can enable the Suwayomi tracker to track reading progress with your Suwayomi server. - You can enable the Suwayomi tracker to track reading progress with your Tachidesk server.
- Note: Tachiyomi [only allows tracking one way](https://github.com/tachiyomiorg/tachiyomi/issues/1626), meaning that by reading chapters on other Suwayomi clients the last read chapter number will update on the tracker but tachiyomi won't automatically mark them as read for you. - Note: Tachiyomi [only allowes tracking one way](https://github.com/tachiyomiorg/tachiyomi/issues/1626), meaning that by reading chapters on other Tachidesk clients the last read chapter number will updated on the tracker but tachiyomi won't automatically mark them as read for you.
### Other methods ### Other methods
Checkout [this issue](https://github.com/Suwayomi/Suwayomi-Server/issues/159) for tracking progress. Checkout [this issue](https://github.com/Suwayomi/Tachidesk-Server/issues/159) for tracking progress.
## Troubleshooting and Support ## Troubleshooting and Support
See [this troubleshooting wiki page](https://github.com/Suwayomi/Suwayomi-Server/wiki/Troubleshooting). See [this troubleshooting wiki page](https://github.com/Suwayomi/Tachidesk/wiki/Troubleshooting).
## Contributing and Technical info ## Contributing and Technical info
See [CONTRIBUTING.md](./CONTRIBUTING.md). See [CONTRIBUTING.md](./CONTRIBUTING.md).

View File

@@ -1,11 +1,12 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile
import org.jlleitschuh.gradle.ktlint.KtlintExtension import org.jmailen.gradle.kotlinter.tasks.FormatTask
import org.jlleitschuh.gradle.ktlint.KtlintPlugin import org.jmailen.gradle.kotlinter.tasks.LintTask
@Suppress("DSL_SCOPE_VIOLATION")
plugins { plugins {
alias(libs.plugins.kotlin.jvm) alias(libs.plugins.kotlin.jvm)
alias(libs.plugins.kotlin.serialization) alias(libs.plugins.kotlin.serialization)
alias(libs.plugins.ktlint) alias(libs.plugins.kotlinter)
alias(libs.plugins.buildconfig) apply false alias(libs.plugins.buildconfig) apply false
alias(libs.plugins.download) alias(libs.plugins.download)
} }
@@ -18,7 +19,7 @@ allprojects {
repositories { repositories {
mavenCentral() mavenCentral()
google() google()
maven("https://github.com/Suwayomi/Suwayomi-Server/raw/android-jar/") maven("https://github.com/Suwayomi/Tachidesk-Server/raw/android-jar/")
maven("https://jitpack.io") maven("https://jitpack.io")
} }
} }
@@ -31,25 +32,20 @@ subprojects {
} }
} }
plugins.withType<KtlintPlugin> {
extensions.configure<KtlintExtension>("ktlint") {
version.set(libs.versions.ktlint.get())
filter {
exclude("**/generated/**")
}
}
}
tasks { tasks {
withType<KotlinJvmCompile> { withType<KotlinJvmCompile> {
dependsOn("ktlintFormat") dependsOn("formatKotlin")
kotlinOptions { kotlinOptions {
jvmTarget = JavaVersion.VERSION_1_8.toString() jvmTarget = JavaVersion.VERSION_1_8.toString()
freeCompilerArgs += listOf(
"-Xcontext-receivers",
)
} }
} }
withType<LintTask> {
source(files("src/kotlin"))
}
withType<FormatTask> {
source(files("src/kotlin"))
}
} }
} }

View File

@@ -7,5 +7,5 @@ repositories {
} }
dependencies { dependencies {
implementation(libs.zip4j) implementation("net.lingala.zip4j:zip4j:2.9.0")
} }

View File

@@ -1,9 +0,0 @@
rootProject.name = "buildSrc"
dependencyResolutionManagement {
versionCatalogs {
create("libs") {
from(files("../gradle/libs.versions.toml"))
}
}
}

View File

@@ -12,22 +12,20 @@ const val MainClass = "suwayomi.tachidesk.MainKt"
// should be bumped with each stable release // should be bumped with each stable release
val tachideskVersion = System.getenv("ProductVersion") ?: "v0.7.0" val tachideskVersion = System.getenv("ProductVersion") ?: "v0.7.0"
val webUIRevisionTag = System.getenv("WebUIRevision") ?: "r1397" val webUIRevisionTag = System.getenv("WebUIRevision") ?: "r983"
// counts commits on the current checked out branch // counts commits on the master branch
val getTachideskRevision = { val tachideskRevision = runCatching {
runCatching { System.getenv("ProductRevision") ?: ProcessBuilder()
System.getenv("ProductRevision") ?: ProcessBuilder() .command("git", "rev-list", "HEAD", "--count")
.command("git", "rev-list", "HEAD", "--count") .start()
.start() .let { process ->
.let { process -> process.waitFor()
process.waitFor() val output = process.inputStream.use {
val output = process.inputStream.use { it.bufferedReader().use(BufferedReader::readText)
it.bufferedReader().use(BufferedReader::readText)
}
process.destroy()
"r" + output.trim()
} }
}.getOrDefault("r0") process.destroy()
} "r" + output.trim()
}
}.getOrDefault("r0")

View File

@@ -1,18 +1,16 @@
[versions] [versions]
kotlin = "1.9.10" kotlin = "1.8.0"
coroutines = "1.7.3" coroutines = "1.6.4"
serialization = "1.6.0" serialization = "1.4.1"
okhttp = "5.0.0-alpha.11" # Major version is locked by Tachiyomi extensions okhttp = "5.0.0-alpha.11" # Major version is locked by Tachiyomi extensions
javalin = "4.6.8" # Javalin 5.0.0+ requires Java 11 javalin = "4.6.6" # Javalin 5.0.0+ requires Java 11
jackson = "2.13.3" # jackson version locked by javalin, ref: `io.javalin.core.util.OptionalDependency` jackson = "2.13.3" # jackson version locked by javalin, ref: `io.javalin.core.util.OptionalDependency`
exposed = "0.40.1" exposed = "0.40.1"
dex2jar = "v64" # Stuck until https://github.com/ThexXTURBOXx/dex2jar/issues/27 is fixed dex2jar = "v60"
rhino = "1.7.14" rhino = "1.7.14"
settings = "1.0.0-RC" settings = "1.0.0-RC"
twelvemonkeys = "3.9.4" twelvemonkeys = "3.9.4"
graphqlkotlin = "6.5.6" playwright = "1.28.0"
xmlserialization = "0.86.2"
ktlint = "1.0.0"
[libraries] [libraries]
# Kotlin # Kotlin
@@ -27,21 +25,17 @@ coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", ve
# Serialization # Serialization
serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "serialization" } serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "serialization" }
serialization-json-okio = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json-okio", version.ref = "serialization" }
serialization-protobuf = { module = "org.jetbrains.kotlinx:kotlinx-serialization-protobuf", version.ref = "serialization" } serialization-protobuf = { module = "org.jetbrains.kotlinx:kotlinx-serialization-protobuf", version.ref = "serialization" }
serialization-xml-core = { module = "io.github.pdvrieze.xmlutil:core-jvm", version.ref = "xmlserialization" }
serialization-xml = { module = "io.github.pdvrieze.xmlutil:serialization-jvm", version.ref = "xmlserialization" }
# Logging # Logging
slf4japi = "org.slf4j:slf4j-api:2.0.9" slf4japi = "org.slf4j:slf4j-api:2.0.6"
logback = "ch.qos.logback:logback-classic:1.3.11" logback = "ch.qos.logback:logback-classic:1.3.5"
kotlinlogging = "io.github.microutils:kotlin-logging:3.0.5" kotlinlogging = "io.github.microutils:kotlin-logging:3.0.5"
# OkHttp # OkHttp
okhttp-core = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" } okhttp-core = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" }
okhttp-logging = { module = "com.squareup.okhttp3:logging-interceptor", version.ref = "okhttp" } okhttp-logging = { module = "com.squareup.okhttp3:logging-interceptor", version.ref = "okhttp" }
okhttp-dnsoverhttps = { module = "com.squareup.okhttp3:okhttp-dnsoverhttps", version.ref = "okhttp" } okhttp-dnsoverhttps = { module = "com.squareup.okhttp3:okhttp-dnsoverhttps", version.ref = "okhttp" }
okhttp-brotli = { module = "com.squareup.okhttp3:okhttp-brotli", version.ref = "okhttp" }
okio = "com.squareup.okio:okio:3.3.0" okio = "com.squareup.okio:okio:3.3.0"
# Javalin api # Javalin api
@@ -51,11 +45,6 @@ jackson-databind = { module = "com.fasterxml.jackson.core:jackson-databind", ver
jackson-kotlin = { module = "com.fasterxml.jackson.module:jackson-module-kotlin", version.ref = "jackson" } jackson-kotlin = { module = "com.fasterxml.jackson.module:jackson-module-kotlin", version.ref = "jackson" }
jackson-annotations = { module = "com.fasterxml.jackson.core:jackson-annotations", version.ref = "jackson" } jackson-annotations = { module = "com.fasterxml.jackson.core:jackson-annotations", version.ref = "jackson" }
# GraphQL
graphql-kotlin-server = { module = "com.expediagroup:graphql-kotlin-server", version.ref = "graphqlkotlin" }
graphql-kotlin-scheme = { module = "com.expediagroup:graphql-kotlin-schema-generator", version.ref = "graphqlkotlin" }
graphql-scalars = "com.graphql-java:graphql-java-extended-scalars:20.2"
# Exposed ORM # Exposed ORM
exposed-core = { module = "org.jetbrains.exposed:exposed-core", version.ref = "exposed" } exposed-core = { module = "org.jetbrains.exposed:exposed-core", version.ref = "exposed" }
exposed-dao = { module = "org.jetbrains.exposed:exposed-dao", version.ref = "exposed" } exposed-dao = { module = "org.jetbrains.exposed:exposed-dao", version.ref = "exposed" }
@@ -67,7 +56,7 @@ h2 = "com.h2database:h2:1.4.200" # current database driver, can't update to h2 v
exposed-migrations = "com.github.Suwayomi:exposed-migrations:3.2.0" exposed-migrations = "com.github.Suwayomi:exposed-migrations:3.2.0"
# Dependency Injection # Dependency Injection
kodein = "org.kodein.di:kodein-di-conf-jvm:7.20.2" kodein = "org.kodein.di:kodein-di-conf-jvm:7.15.0"
# tray icon # tray icon
systemtray-core = "com.dorkbox:SystemTray:4.2.1" systemtray-core = "com.dorkbox:SystemTray:4.2.1"
@@ -77,7 +66,7 @@ systemtray-desktop = "com.dorkbox:Desktop:1.0"
# dependencies of Tachiyomi extensions # dependencies of Tachiyomi extensions
injekt = "com.github.inorichi.injekt:injekt-core:65b0440" injekt = "com.github.inorichi.injekt:injekt-core:65b0440"
rxjava = "io.reactivex:rxjava:1.3.8" rxjava = "io.reactivex:rxjava:1.3.8"
jsoup = "org.jsoup:jsoup:1.16.1" jsoup = "org.jsoup:jsoup:1.15.3"
# Config # Config
config = "com.typesafe:config:1.4.2" config = "com.typesafe:config:1.4.2"
@@ -90,7 +79,7 @@ sort = "com.github.gpanther:java-nat-sort:natural-comparator-1.1"
android-stubs = "com.github.Suwayomi:android-jar:1.0.0" android-stubs = "com.github.Suwayomi:android-jar:1.0.0"
# Asm modificiation # Asm modificiation
asm = "org.ow2.asm:asm:9.5" # version locked by Dex2Jar asm = "org.ow2.asm:asm:9.4" # version locked by Dex2Jar
dex2jar-translator = { module = "com.github.ThexXTURBOXx.dex2jar:dex-translator", version.ref = "dex2jar" } dex2jar-translator = { module = "com.github.ThexXTURBOXx.dex2jar:dex-translator", version.ref = "dex2jar" }
dex2jar-tools = { module = "com.github.ThexXTURBOXx.dex2jar:dex-tools", version.ref = "dex2jar" } dex2jar-tools = { module = "com.github.ThexXTURBOXx.dex2jar:dex-tools", version.ref = "dex2jar" }
@@ -103,15 +92,18 @@ xmlpull = "xmlpull:xmlpull:1.1.3.4a"
# Disk & File # Disk & File
appdirs = "net.harawata:appdirs:1.2.1" appdirs = "net.harawata:appdirs:1.2.1"
zip4j = "net.lingala.zip4j:zip4j:2.11.5" zip4j = "net.lingala.zip4j:zip4j:2.11.2"
commonscompress = "org.apache.commons:commons-compress:1.24.0" commonscompress = "org.apache.commons:commons-compress:1.23.0"
junrar = "com.github.junrar:junrar:7.5.5" junrar = "com.github.junrar:junrar:7.5.3"
# CloudflareInterceptor
playwright = { module = "com.microsoft.playwright:playwright", version.ref = "playwright" }
# AES/CBC/PKCS7Padding Cypher provider # AES/CBC/PKCS7Padding Cypher provider
bouncycastle = "org.bouncycastle:bcprov-jdk18on:1.76" bouncycastle = "org.bouncycastle:bcprov-jdk18on:1.72"
# AndroidX annotations # AndroidX annotations
android-annotations = "androidx.annotation:annotation:1.7.0" android-annotations = "androidx.annotation:annotation:1.5.0"
# Substitute for duktape-android # Substitute for duktape-android
rhino-runtime = { module = "org.mozilla:rhino-runtime", version.ref = "rhino" } # slimmer version of 'org.mozilla:rhino' rhino-runtime = { module = "org.mozilla:rhino-runtime", version.ref = "rhino" } # slimmer version of 'org.mozilla:rhino'
@@ -122,7 +114,7 @@ settings-core = { module = "com.russhwolf:multiplatform-settings-jvm", version.r
settings-serialization = { module = "com.russhwolf:multiplatform-settings-serialization-jvm", version.ref = "settings" } settings-serialization = { module = "com.russhwolf:multiplatform-settings-serialization-jvm", version.ref = "settings" }
# ICU4J # ICU4J
icu4j = "com.ibm.icu:icu4j:73.2" icu4j = "com.ibm.icu:icu4j:72.1"
# Image Decoding implementation provider # Image Decoding implementation provider
twelvemonkeys-common-lang = { module = "com.twelvemonkeys.common:common-lang", version.ref = "twelvemonkeys" } twelvemonkeys-common-lang = { module = "com.twelvemonkeys.common:common-lang", version.ref = "twelvemonkeys" }
@@ -134,13 +126,7 @@ twelvemonkeys-imageio-jpeg = { module = "com.twelvemonkeys.imageio:imageio-jpeg"
twelvemonkeys-imageio-webp = { module = "com.twelvemonkeys.imageio:imageio-webp", version.ref = "twelvemonkeys" } twelvemonkeys-imageio-webp = { module = "com.twelvemonkeys.imageio:imageio-webp", version.ref = "twelvemonkeys" }
# Testing # Testing
mockk = "io.mockk:mockk:1.13.7" mockk = "io.mockk:mockk:1.13.2"
# cron scheduler
cron4j = "it.sauronsoftware.cron4j:cron4j:2.2.5"
# cron-utils
cronUtils = "com.cronutils:cron-utils:9.2.1"
[plugins] [plugins]
# Kotlin # Kotlin
@@ -148,16 +134,16 @@ kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin"}
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin"} kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin"}
# Linter # Linter
ktlint = { id = "org.jlleitschuh.gradle.ktlint", version = "11.6.0"} kotlinter = { id = "org.jmailen.kotlinter", version = "3.12.0"}
# Build config # Build config
buildconfig = { id = "com.github.gmazzo.buildconfig", version = "3.1.0"} buildconfig = { id = "com.github.gmazzo.buildconfig", version = "3.1.0"}
# Download # Download
download = { id = "de.undercouch.download", version = "5.4.0"} download = { id = "de.undercouch.download", version = "5.3.0"}
# ShadowJar # ShadowJar
shadowjar = { id = "com.github.johnrengelman.shadow", version = "8.1.1"} shadowjar = { id = "com.github.johnrengelman.shadow", version = "7.1.2"}
[bundles] [bundles]
shared = [ shared = [
@@ -166,7 +152,6 @@ shared = [
"coroutines-core", "coroutines-core",
"coroutines-jdk8", "coroutines-jdk8",
"serialization-json", "serialization-json",
"serialization-json-okio",
"serialization-protobuf", "serialization-protobuf",
"kodein", "kodein",
"slf4japi", "slf4japi",
@@ -192,7 +177,6 @@ okhttp = [
"okhttp-core", "okhttp-core",
"okhttp-logging", "okhttp-logging",
"okhttp-dnsoverhttps", "okhttp-dnsoverhttps",
"okhttp-brotli",
] ]
javalin = [ javalin = [
"javalin-core", "javalin-core",

View File

@@ -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-8.2-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

View File

@@ -26,18 +26,18 @@ main() {
set -- "${POSITIONAL_ARGS[@]}" set -- "${POSITIONAL_ARGS[@]}"
OS="$1" OS="$1"
PLAYWRIGHT_VERSION="$(cat gradle/libs.versions.toml | grep -oP "playwright = \"\K([0-9\.]*)(?=\")")"
PLAYWRIGHT_REVISION="$(curl --silent "https://raw.githubusercontent.com/microsoft/playwright/v$PLAYWRIGHT_VERSION/packages/playwright-core/browsers.json" 2>&1 | grep -ozP "\"name\": \"chromium\",\n *\"revision\": \"\K[0-9]*")"
JAR="$(ls server/build/*.jar | tail -n1)" JAR="$(ls server/build/*.jar | tail -n1)"
RELEASE_NAME="$(echo "${JAR%.*}" | xargs basename)-$OS" RELEASE_NAME="$(echo "${JAR%.*}" | xargs basename)-$OS"
RELEASE_VERSION="$(tmp="${JAR%-*}"; echo "${tmp##*-}" | tr -d v)" RELEASE_VERSION="$(tmp="${JAR%-*}"; echo "${tmp##*-}" | tr -d v)"
#RELEASE_REVISION_NUMBER="$(tmp="${JAR%.*}" && echo "${tmp##*-}" | tr -d r)" #RELEASE_REVISION_NUMBER="$(tmp="${JAR%.*}" && echo "${tmp##*-}" | tr -d r)"
local electron_version="v28.1.3" local electron_version="v14.0.0"
# clean temporary directory on function return # clean temporary directory on function return
trap "rm -rf $RELEASE_NAME/" RETURN trap "rm -rf $RELEASE_NAME/" RETURN
mkdir "$RELEASE_NAME/" mkdir "$RELEASE_NAME/"
download_launcher
case "$OS" in case "$OS" in
debian-all) debian-all)
RELEASE="$RELEASE_NAME.deb" RELEASE="$RELEASE_NAME.deb"
@@ -51,57 +51,65 @@ main() {
move_release_to_output_dir move_release_to_output_dir
;; ;;
linux-x64) linux-x64)
# https://github.com/adoptium/temurin8-binaries/releases/ JRE="OpenJDK8U-jre_x64_linux_hotspot_8u302b08.tar.gz"
JRE_RELEASE="jdk8u392-b08" JRE_RELEASE="jdk8u302-b08"
JRE="OpenJDK8U-jre_x64_linux_hotspot_$(echo "$JRE_RELEASE" | sed 's/jdk//;s/-//g').tar.gz"
JRE_DIR="$JRE_RELEASE-jre" JRE_DIR="$JRE_RELEASE-jre"
JRE_URL="https://github.com/adoptium/temurin8-binaries/releases/download/$JRE_RELEASE/$JRE" JRE_URL="https://github.com/adoptium/temurin8-binaries/releases/download/$JRE_RELEASE/$JRE"
ELECTRON="electron-$electron_version-linux-x64.zip" ELECTRON="electron-$electron_version-linux-x64.zip"
ELECTRON_URL="https://github.com/electron/electron/releases/download/$electron_version/$ELECTRON" ELECTRON_URL="https://github.com/electron/electron/releases/download/$electron_version/$ELECTRON"
download_jre_and_electron download_jre_and_electron
PLAYWRIGHT_PLATFORM="linux"
setup_playwright
RELEASE="$RELEASE_NAME.tar.gz" RELEASE="$RELEASE_NAME.tar.gz"
make_linux_bundle make_linux_bundle
move_release_to_output_dir move_release_to_output_dir
;; ;;
macOS-x64) macOS-x64)
# https://github.com/adoptium/temurin8-binaries/releases/ JRE="OpenJDK8U-jre_x64_mac_hotspot_8u302b08.tar.gz"
JRE_RELEASE="jdk8u392-b08" JRE_RELEASE="jdk8u302-b08"
JRE="OpenJDK8U-jre_x64_mac_hotspot_$(echo "$JRE_RELEASE" | sed 's/jdk//;s/-//g').tar.gz"
JRE_DIR="$JRE_RELEASE-jre" JRE_DIR="$JRE_RELEASE-jre"
JRE_URL="https://github.com/adoptium/temurin8-binaries/releases/download/$JRE_RELEASE/$JRE" JRE_URL="https://github.com/adoptium/temurin8-binaries/releases/download/$JRE_RELEASE/$JRE"
ELECTRON="electron-$electron_version-darwin-x64.zip" ELECTRON="electron-$electron_version-darwin-x64.zip"
ELECTRON_URL="https://github.com/electron/electron/releases/download/$electron_version/$ELECTRON" ELECTRON_URL="https://github.com/electron/electron/releases/download/$electron_version/$ELECTRON"
download_jre_and_electron download_jre_and_electron
PLAYWRIGHT_PLATFORM="mac"
setup_playwright
RELEASE="$RELEASE_NAME.zip" RELEASE="$RELEASE_NAME.zip"
make_macos_bundle make_macos_bundle
move_release_to_output_dir move_release_to_output_dir
;; ;;
macOS-arm64) macOS-arm64)
# https://cdn.azul.com/zulu/bin/ JRE="zulu8.56.0.23-ca-jre8.0.302-macosx_aarch64.tar.gz"
JRE="zulu8.74.0.17-ca-jre8.0.392-macosx_aarch64.tar.gz" JRE_RELEASE="zulu8.56.0.23-ca-jre8.0.302-macosx_aarch64"
JRE_RELEASE="zulu8.74.0.17-ca-jre8.0.392-macosx_aarch64"
JRE_DIR="$JRE_RELEASE/zulu-8.jre" JRE_DIR="$JRE_RELEASE/zulu-8.jre"
JRE_URL="https://cdn.azul.com/zulu/bin/$JRE" JRE_URL="https://cdn.azul.com/zulu/bin/$JRE"
ELECTRON="electron-$electron_version-darwin-arm64.zip" ELECTRON="electron-$electron_version-darwin-arm64.zip"
ELECTRON_URL="https://github.com/electron/electron/releases/download/$electron_version/$ELECTRON" ELECTRON_URL="https://github.com/electron/electron/releases/download/$electron_version/$ELECTRON"
download_jre_and_electron download_jre_and_electron
PLAYWRIGHT_PLATFORM="mac-arm64"
setup_playwright
RELEASE="$RELEASE_NAME.zip" RELEASE="$RELEASE_NAME.zip"
make_macos_bundle make_macos_bundle
move_release_to_output_dir move_release_to_output_dir
;; ;;
windows-x86) windows-x86)
# https://github.com/adoptium/temurin8-binaries/releases/ JRE="OpenJDK8U-jre_x86-32_windows_hotspot_8u292b10.zip"
JRE_RELEASE="jdk8u392-b08" JRE_RELEASE="jdk8u292-b10"
JRE="OpenJDK8U-jre_x86-32_windows_hotspot_$(echo "$JRE_RELEASE" | sed 's/jdk//;s/-//g').zip"
JRE_DIR="$JRE_RELEASE-jre" JRE_DIR="$JRE_RELEASE-jre"
JRE_URL="https://github.com/adoptium/temurin8-binaries/releases/download/$JRE_RELEASE/$JRE" JRE_URL="https://github.com/AdoptOpenJDK/openjdk8-binaries/releases/download/$JRE_RELEASE/$JRE"
ELECTRON="electron-$electron_version-win32-ia32.zip" ELECTRON="electron-$electron_version-win32-ia32.zip"
ELECTRON_URL="https://github.com/electron/electron/releases/download/$electron_version/$ELECTRON" ELECTRON_URL="https://github.com/electron/electron/releases/download/$electron_version/$ELECTRON"
download_jre_and_electron download_jre_and_electron
PLAYWRIGHT_PLATFORM="win64"
setup_playwright
RELEASE="$RELEASE_NAME.zip" RELEASE="$RELEASE_NAME.zip"
make_windows_bundle make_windows_bundle
move_release_to_output_dir move_release_to_output_dir
@@ -111,15 +119,17 @@ main() {
move_release_to_output_dir move_release_to_output_dir
;; ;;
windows-x64) windows-x64)
# https://github.com/adoptium/temurin8-binaries/releases/ JRE="OpenJDK8U-jre_x64_windows_hotspot_8u302b08.zip"
JRE_RELEASE="jdk8u392-b08" JRE_RELEASE="jdk8u302-b08"
JRE="OpenJDK8U-jre_x64_windows_hotspot_$(echo "$JRE_RELEASE" | sed 's/jdk//;s/-//g').zip"
JRE_DIR="$JRE_RELEASE-jre" JRE_DIR="$JRE_RELEASE-jre"
JRE_URL="https://github.com/adoptium/temurin8-binaries/releases/download/$JRE_RELEASE/$JRE" JRE_URL="https://github.com/adoptium/temurin8-binaries/releases/download/$JRE_RELEASE/$JRE"
ELECTRON="electron-$electron_version-win32-x64.zip" ELECTRON="electron-$electron_version-win32-x64.zip"
ELECTRON_URL="https://github.com/electron/electron/releases/download/$electron_version/$ELECTRON" ELECTRON_URL="https://github.com/electron/electron/releases/download/$electron_version/$ELECTRON"
download_jre_and_electron download_jre_and_electron
PLAYWRIGHT_PLATFORM="win64"
setup_playwright
RELEASE="$RELEASE_NAME.zip" RELEASE="$RELEASE_NAME.zip"
make_windows_bundle make_windows_bundle
move_release_to_output_dir move_release_to_output_dir
@@ -142,12 +152,6 @@ move_release_to_output_dir() {
mv "$RELEASE" "$OUTPUT_DIR/" mv "$RELEASE" "$OUTPUT_DIR/"
} }
download_launcher() {
LAUNCHER_URL=$(curl -s "https://api.github.com/repos/Suwayomi/Suwayomi-Launcher/releases/latest" | grep "browser_download_url" | grep ".jar" | head -n 1 | cut -d '"' -f 4)
curl -L "$LAUNCHER_URL" -o "Suwayomi-Launcher.jar"
mv "Suwayomi-Launcher.jar" "$RELEASE_NAME/Suwayomi-Launcher.jar"
}
download_jre_and_electron() { download_jre_and_electron() {
if [ ! -f "$JRE" ]; then if [ ! -f "$JRE" ]; then
curl -L "$JRE_URL" -o "$JRE" curl -L "$JRE_URL" -o "$JRE"
@@ -164,9 +168,6 @@ download_jre_and_electron() {
fi fi
mv "$JRE_DIR" "$RELEASE_NAME/jre" mv "$JRE_DIR" "$RELEASE_NAME/jre"
unzip "$ELECTRON" -d "$RELEASE_NAME/electron/" unzip "$ELECTRON" -d "$RELEASE_NAME/electron/"
mkdir "$RELEASE_NAME/bin"
tree tree
} }
@@ -174,26 +175,29 @@ copy_linux_package_assets_to() {
local output_dir local output_dir
output_dir="$(readlink -e "$1" || exit 1)" output_dir="$(readlink -e "$1" || exit 1)"
cp "scripts/resources/pkg/suwayomi-server.sh" "$output_dir/" cp "scripts/resources/pkg/tachidesk-server-browser-launcher.sh" "$output_dir/"
cp "scripts/resources/pkg/suwayomi-server.desktop" "$output_dir/" cp "scripts/resources/pkg/tachidesk-server-debug-launcher.sh" "$output_dir/"
cp "scripts/resources/pkg/suwayomi-launcher.sh" "$output_dir/" cp "scripts/resources/pkg/tachidesk-server-electron-launcher.sh" "$output_dir/"
cp "scripts/resources/pkg/suwayomi-launcher.desktop" "$output_dir/" cp "scripts/resources/pkg/tachidesk-server.desktop" "$output_dir/"
cp "scripts/resources/pkg/systemd"/* "$output_dir/" cp "scripts/resources/pkg/systemd"/* "$output_dir/"
cp "server/src/main/resources/icon/faviconlogo-128.png" \ cp "server/src/main/resources/icon/faviconlogo.png" \
"$output_dir/suwayomi-server.png" "$output_dir/tachidesk-server.png"
} }
make_linux_bundle() { make_linux_bundle() {
cp "$JAR" "$RELEASE_NAME/bin/Suwayomi-Server.jar" cp "$JAR" "$RELEASE_NAME/Tachidesk-Server.jar"
cp "scripts/resources/suwayomi-launcher.sh" "$RELEASE_NAME/" cp "scripts/resources/tachidesk-server-browser-launcher.sh" "$RELEASE_NAME/"
cp "scripts/resources/suwayomi-server.sh" "$RELEASE_NAME/" cp "scripts/resources/tachidesk-server-debug-launcher.sh" "$RELEASE_NAME/"
cp "scripts/resources/tachidesk-server-electron-launcher.sh" "$RELEASE_NAME/"
tar -I "gzip -9" -cvf "$RELEASE" "$RELEASE_NAME/" tar -I "gzip -9" -cvf "$RELEASE" "$RELEASE_NAME/"
} }
make_macos_bundle() { make_macos_bundle() {
cp "$JAR" "$RELEASE_NAME/bin/Suwayomi-Server.jar" cp "$JAR" "$RELEASE_NAME/Tachidesk-Server.jar"
cp "scripts/resources/Suwayomi Launcher.command" "$RELEASE_NAME/" cp "scripts/resources/Tachidesk Browser Launcher.command" "$RELEASE_NAME/"
cp "scripts/resources/Tachidesk Debug Launcher.command" "$RELEASE_NAME/"
cp "scripts/resources/Tachidesk Electron Launcher.command" "$RELEASE_NAME/"
zip -9 -r "$RELEASE" "$RELEASE_NAME/" zip -9 -r "$RELEASE" "$RELEASE_NAME/"
} }
@@ -202,13 +206,12 @@ make_macos_bundle() {
# https://www.debian.org/doc/manuals/packaging-tutorial/packaging-tutorial.pdf # https://www.debian.org/doc/manuals/packaging-tutorial/packaging-tutorial.pdf
make_deb_package() { make_deb_package() {
#behind $RELEASE_VERSION is hyphen "-" #behind $RELEASE_VERSION is hyphen "-"
local source_dir="suwayomi-server-$RELEASE_VERSION" local source_dir="tachidesk-server-$RELEASE_VERSION"
#behind $RELEASE_VERSION is underscore "_" #behind $RELEASE_VERSION is underscore "_"
local upstream_source="suwayomi-server_$RELEASE_VERSION.orig.tar.gz" local upstream_source="tachidesk-server_$RELEASE_VERSION.orig.tar.gz"
mkdir "$RELEASE_NAME/$source_dir/" mkdir "$RELEASE_NAME/$source_dir/"
mv "$RELEASE_NAME/Suwayomi-Launcher.jar" "$RELEASE_NAME/$source_dir/Suwayomi-Launcher.jar" cp "$JAR" "$RELEASE_NAME/$source_dir/Tachidesk-Server.jar"
cp "$JAR" "$RELEASE_NAME/$source_dir/Suwayomi-Server.jar"
copy_linux_package_assets_to "$RELEASE_NAME/$source_dir/" copy_linux_package_assets_to "$RELEASE_NAME/$source_dir/"
tar -I "gzip" -C "$RELEASE_NAME/" -cvf "$upstream_source" "$source_dir" tar -I "gzip" -C "$RELEASE_NAME/" -cvf "$upstream_source" "$source_dir"
@@ -216,13 +219,12 @@ make_deb_package() {
sed -i "s/\$pkgver/$RELEASE_VERSION/" "$RELEASE_NAME/$source_dir/debian/changelog" sed -i "s/\$pkgver/$RELEASE_VERSION/" "$RELEASE_NAME/$source_dir/debian/changelog"
sed -i "s/\$pkgrel/1/" "$RELEASE_NAME/$source_dir/debian/changelog" sed -i "s/\$pkgrel/1/" "$RELEASE_NAME/$source_dir/debian/changelog"
sudo apt update
sudo apt install devscripts build-essential dh-exec sudo apt install devscripts build-essential dh-exec
cd "$RELEASE_NAME/$source_dir/" cd "$RELEASE_NAME/$source_dir/"
dpkg-buildpackage --no-sign --build=all dpkg-buildpackage --no-sign --build=all
cd - cd -
local deb="suwayomi-server_$RELEASE_VERSION-1_all.deb" local deb="tachidesk-server_$RELEASE_VERSION-1_all.deb"
mv "$RELEASE_NAME/$deb" "$RELEASE" mv "$RELEASE_NAME/$deb" "$RELEASE"
} }
@@ -255,15 +257,16 @@ make_windows_bundle() {
#WINEARCH=win32 wine "$rcedit" "$RELEASE_NAME/electron/electron.exe" \ #WINEARCH=win32 wine "$rcedit" "$RELEASE_NAME/electron/electron.exe" \
# --set-icon "$icon" # --set-icon "$icon"
cp "$JAR" "$RELEASE_NAME/bin/Suwayomi-Server.jar" cp "$JAR" "$RELEASE_NAME/Tachidesk-Server.jar"
cp "scripts/resources/Suwayomi Launcher.bat" "$RELEASE_NAME" cp "scripts/resources/Tachidesk Browser Launcher.bat" "$RELEASE_NAME"
cp "scripts/resources/Tachidesk Debug Launcher.bat" "$RELEASE_NAME"
cp "scripts/resources/Tachidesk Electron Launcher.bat" "$RELEASE_NAME"
zip -9 -r "$RELEASE" "$RELEASE_NAME" zip -9 -r "$RELEASE" "$RELEASE_NAME"
} }
make_windows_package() { make_windows_package() {
if [ "$CI" = true ]; then if [ "$CI" = true ]; then
sudo apt update
sudo apt install -y wixl sudo apt install -y wixl
fi fi
@@ -274,16 +277,17 @@ make_windows_package() {
| wixl-heat --var var.SourceDir -p "$RELEASE_NAME/" \ | wixl-heat --var var.SourceDir -p "$RELEASE_NAME/" \
--directory-ref electron --component-group electron >"$RELEASE_NAME/electron.wxs" --directory-ref electron --component-group electron >"$RELEASE_NAME/electron.wxs"
find "$RELEASE_NAME/bin" \
| wixl-heat --var var.SourceDir -p "$RELEASE_NAME/" \
--directory-ref bin --component-group bin >"$RELEASE_NAME/bin.wxs"
local icon="server/src/main/resources/icon/faviconlogo.ico" local icon="server/src/main/resources/icon/faviconlogo.ico"
local arch=${OS##*-} local arch=${OS##*-}
wixl -D ProductVersion="$RELEASE_VERSION" -D SourceDir="$RELEASE_NAME" \ wixl -D ProductVersion="$RELEASE_VERSION" -D SourceDir="$RELEASE_NAME" \
-D Icon="$icon" --arch "$arch" "scripts/resources/msi/suwayomi-server-$arch.wxs" \ -D Icon="$icon" --arch "$arch" "scripts/resources/msi/tachidesk-server-$arch.wxs" \
"$RELEASE_NAME/jre.wxs" "$RELEASE_NAME/electron.wxs" "$RELEASE_NAME/bin.wxs" -o "$RELEASE" "$RELEASE_NAME/jre.wxs" "$RELEASE_NAME/electron.wxs" -o "$RELEASE"
}
setup_playwright() {
mkdir "$RELEASE_NAME/bin"
curl -L "https://playwright.azureedge.net/builds/chromium/$PLAYWRIGHT_REVISION/chromium-$PLAYWRIGHT_PLATFORM.zip" -o "$RELEASE_NAME/bin/chromium.zip"
} }
# Error handler # Error handler

View File

@@ -1 +0,0 @@
start "" jre/bin/javaw -jar Suwayomi-Launcher.jar

View File

@@ -1,3 +0,0 @@
cd "`dirname "$0"`"
./jre/Contents/Home/bin/java -jar Suwayomi-Launcher.jar

View File

@@ -0,0 +1 @@
start "" jre/bin/javaw -jar Tachidesk-Server.jar

View File

@@ -0,0 +1,3 @@
cd "`dirname "$0"`"
./jre/Contents/Home/bin/java -jar Tachidesk-Server.jar

View File

@@ -0,0 +1,7 @@
:: cleaner output
@echo off
jre\bin\java -Dsuwayomi.tachidesk.config.server.debugLogsEnabled=true -jar Tachidesk-Server.jar
:: Prevent cmd from closing when Tachidesk crashes
pause

View File

@@ -0,0 +1,3 @@
cd "`dirname "$0"`"
./jre/Contents/Home/bin/java -Dsuwayomi.tachidesk.config.server.debugLogsEnabled=true -jar Tachidesk-Server.jar

View File

@@ -0,0 +1 @@
jre\bin\javaw "-Dsuwayomi.tachidesk.config.server.webUIInterface=electron" "-Dsuwayomi.tachidesk.config.server.electronPath=electron/electron.exe" -jar Tachidesk-Server.jar

View File

@@ -0,0 +1,3 @@
cd "`dirname "$0"`"
./jre/Contents/Home/bin/java "-Dsuwayomi.tachidesk.config.server.webUIInterface=electron" "-Dsuwayomi.tachidesk.config.server.electronPath=electron/Electron.app/Contents/MacOS/Electron" -jar Tachidesk-Server.jar

View File

@@ -1,5 +1,5 @@
suwayomi-server ($pkgver-$pkgrel) unstable; urgency=medium tachidesk-server ($pkgver-$pkgrel) unstable; urgency=medium
* See CHANGELOG.md on https://github.com/Suwayomi/Suwayomi-Server * See CHANGELOG.md on https://github.com/Suwayomi/Tachidesk-Server
-- Mahor1221 <mahor1221@pm.me> Fri, 14 Jan 2022 00:00:00 +0000 -- Mahor1221 <mahor1221@pm.me> Fri, 14 Jan 2022 00:00:00 +0000

View File

@@ -1,14 +1,14 @@
Source: suwayomi-server Source: tachidesk-server
Section: web Section: web
Priority: optional Priority: optional
Maintainer: Mahor1221 <mahor1221@pm.me> Maintainer: Mahor1221 <mahor1221@pm.me>
Build-Depends: debhelper-compat (= 13), dh-exec Build-Depends: debhelper-compat (= 13), dh-exec
Standards-Version: 4.5.1 Standards-Version: 4.5.1
Homepage: https://github.com/Suwayomi/Suwayomi-Server Homepage: https://github.com/Suwayomi/Tachidesk-Server
Package: suwayomi-server Package: tachidesk-server
Architecture: all Architecture: all
Depends: ${misc:Depends}, java8-runtime, libc++-dev Depends: ${misc:Depends}, java8-runtime-headless, libc++-dev
Description: Manga Reader Description: Manga Reader
A free and open source manga reader server that runs extensions built for Tachiyomi. A free and open source manga reader server that runs extensions built for Tachiyomi.
Suwayomi is an independent Tachiyomi compatible software and is not a Fork of Tachiyomi. Tachidesk is an independent Tachiyomi compatible software and is not a Fork of Tachiyomi.

View File

@@ -1,7 +1,7 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: suwayomi-server Upstream-Name: tachidesk-server
Upstream-Contact: https://discord.gg/DDZdqZWaHA Upstream-Contact: https://discord.gg/DDZdqZWaHA
Source: https://github.com/Suwayomi/Suwayomi-Server Source: https://github.com/Suwayomi/Tachidesk-Server
Files: * Files: *
Copyright: Contributors to the Suwayomi project Copyright: Contributors to the Suwayomi project

View File

@@ -1,13 +1,12 @@
#!/usr/bin/dh-exec #!/usr/bin/dh-exec
Suwayomi-Server.jar usr/share/java/suwayomi-server/bin/ Tachidesk-Server.jar usr/share/java/tachidesk-server/
Suwayomi-Launcher.jar usr/share/java/suwayomi-server/ tachidesk-server.png usr/share/pixmaps/
suwayomi-server.png usr/share/pixmaps/ tachidesk-server.desktop usr/share/applications/
suwayomi-server.desktop usr/share/applications/ tachidesk-server.service usr/lib/systemd/system/
suwayomi-launcher.desktop usr/share/applications/ tachidesk-server.sysusers => usr/lib/sysusers.d/tachidesk-server.conf
suwayomi-server.service usr/lib/systemd/system/ tachidesk-server.tmpfiles => usr/lib/tmpfiles.d/tachidesk-server.conf
suwayomi-server.sysusers => usr/lib/sysusers.d/suwayomi-server.conf tachidesk-server.conf => etc/tachidesk/server.conf
suwayomi-server.tmpfiles => usr/lib/tmpfiles.d/suwayomi-server.conf tachidesk-server-browser-launcher.sh => usr/bin/tachidesk-server-browser
suwayomi-server.conf => etc/suwayomi/server.conf tachidesk-server-debug-launcher.sh => usr/bin/tachidesk-server-debug
suwayomi-server.sh => usr/bin/suwayomi-server tachidesk-server-electron-launcher.sh => usr/bin/tachidesk-server-electron
suwayomi-launcher.sh => usr/bin/suwayomi-launcher

View File

@@ -1 +1 @@
suwayomi-server.png tachidesk-server.png

View File

@@ -1,64 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" UpgradeCode="*"
Version="$(var.ProductVersion)" Language="1033" Name="Suwayomi Server" Manufacturer="Suwayomi">
<Package InstallerVersion="300" Compressed="yes" />
<Media Id="1" Cabinet="Suwayomi_Server.cab" EmbedCab="yes" />
<Condition Message="This version of Windows does not support deploying 64-bit packages.">
VersionNT64
</Condition>
<!-- Directory -->
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFiles64Folder">
<Directory Id="INSTALLDIR" Name="Suwayomi-Server" >
<Directory Id="jre"/>
<Directory Id="electron"/>
<Directory Id="bin"/>
</Directory>
</Directory>
<Directory Id="ProgramMenuFolder">
<Directory Id="ProgramMenuDir" Name="Suwayomi-Server">
<Component Id="ProgramMenuDir" Guid="*">
<RemoveFolder Id="ProgramMenuDir" On="uninstall"/>
<RegistryValue Root="HKCU" Key="Software\[Manufacturer]\[ProductName]" Type="string" Value="" KeyPath="yes"/>
</Component>
</Directory>
</Directory>
<Directory Id="DesktopFolder" />
</Directory>
<!-- Component -->
<DirectoryRef Id="INSTALLDIR">
<Component Id="SuwayomiJAR" Guid="*" Win64="yes">
<File Id="Suwayomi-Launcher.jar" Source="$(var.SourceDir)/Suwayomi-Launcher.jar" KeyPath="yes" />
</Component>
<Component Id="SuwayomiLauncherBAT" Guid="*" Win64="yes">
<File Id="SuwayomiLauncher.bat" Source="$(var.SourceDir)/Suwayomi Launcher.bat" KeyPath="yes" >
<Shortcut Id="SuwayomiLauncher.lnk" Name="Suwayomi Launcher" Directory="INSTALLDIR"
WorkingDirectory="INSTALLDIR" Icon="Suwayomi.ico" IconIndex="0" Advertise="yes" />
<Shortcut Id="DesktopSuwayomiLauncher.lnk" Name="Suwayomi Launcher" Directory="DesktopFolder"
WorkingDirectory="INSTALLDIR" Icon="Suwayomi.ico" IconIndex="0" Advertise="yes" />
<Shortcut Id="ProgramMenuSuwayomiLauncher.lnk" Name="Suwayomi Launcher" Directory="ProgramMenuDir"
WorkingDirectory="INSTALLDIR" Icon="Suwayomi.ico" IconIndex="0" Advertise="yes"
Description="A free and open source manga reader that runs extensions built for Tachiyomi." />
</File>
</Component>
</DirectoryRef>
<!-- Feature -->
<Feature Id="Suwayomi_Server" Title="Suwayomi-Server" Level="1">
<ComponentGroupRef Id="jre" />
<ComponentGroupRef Id="bin" />
<ComponentRef Id="SuwayomiJAR" />
<ComponentRef Id="SuwayomiLauncherBAT" />
<ComponentRef Id="ProgramMenuDir" />
<ComponentGroupRef Id="electron" />
</Feature>
<Icon Id="Suwayomi.ico" SourceFile="$(var.Icon)" />
<Property Id="ARPPRODUCTICON" Value="Suwayomi.ico" /> <!-- Icon in Add/Remove Programs -->
</Product>
</Wix>

View File

@@ -1,60 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" UpgradeCode="*"
Version="$(var.ProductVersion)" Language="1033" Name="Suwayomi Server" Manufacturer="Suwayomi">
<Package InstallerVersion="300" Compressed="yes" />
<Media Id="1" Cabinet="Suwayomi_Server.cab" EmbedCab="yes" />
<!-- Directory -->
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLDIR" Name="Suwayomi-Server" >
<Directory Id="jre"/>
<Directory Id="electron"/>
<Directory Id="bin"/>
</Directory>
</Directory>
<Directory Id="ProgramMenuFolder">
<Directory Id="ProgramMenuDir" Name="Suwayomi-Server">
<Component Id="ProgramMenuDir" Guid="*">
<RemoveFolder Id="ProgramMenuDir" On="uninstall"/>
<RegistryValue Root="HKCU" Key="Software\[Manufacturer]\[ProductName]" Type="string" Value="" KeyPath="yes"/>
</Component>
</Directory>
</Directory>
<Directory Id="DesktopFolder" />
</Directory>
<!-- Component -->
<DirectoryRef Id="INSTALLDIR">
<Component Id="SuwayomiJAR" Guid="*">
<File Id="Suwayomi-Launcher.jar" Source="$(var.SourceDir)/Suwayomi-Launcher.jar" KeyPath="yes" />
</Component>
<Component Id="SuwayomiLauncherBAT" Guid="*" Win64="yes">
<File Id="SuwayomiLauncher.bat" Source="$(var.SourceDir)/Suwayomi Launcher.bat" KeyPath="yes" >
<Shortcut Id="SuwayomiLauncher.lnk" Name="Suwayomi Launcher" Directory="INSTALLDIR"
WorkingDirectory="INSTALLDIR" Icon="Suwayomi.ico" IconIndex="0" Advertise="yes" />
<Shortcut Id="DesktopSuwayomiLauncher.lnk" Name="Suwayomi Launcher" Directory="DesktopFolder"
WorkingDirectory="INSTALLDIR" Icon="Suwayomi.ico" IconIndex="0" Advertise="yes" />
<Shortcut Id="ProgramMenuSuwayomiLauncher.lnk" Name="Suwayomi Launcher" Directory="ProgramMenuDir"
WorkingDirectory="INSTALLDIR" Icon="Suwayomi.ico" IconIndex="0" Advertise="yes"
Description="A free and open source manga reader that runs extensions built for Tachiyomi." />
</File>
</Component>
</DirectoryRef>
<!-- Feature -->
<Feature Id="Suwayomi_Server" Title="Suwayomi-Server" Level="1">
<ComponentGroupRef Id="jre" />
<ComponentGroupRef Id="bin" />
<ComponentRef Id="SuwayomiJAR" />
<ComponentRef Id="SuwayomiLauncherBAT" />
<ComponentRef Id="ProgramMenuDir" />
<ComponentGroupRef Id="electron" />
</Feature>
<Icon Id="Suwayomi.ico" SourceFile="$(var.Icon)" />
<Property Id="ARPPRODUCTICON" Value="Suwayomi.ico" /> <!-- Icon in Add/Remove Programs -->
</Product>
</Wix>

View File

@@ -0,0 +1,86 @@
<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" UpgradeCode="*"
Version="$(var.ProductVersion)" Language="1033" Name="Tachidesk Server" Manufacturer="Suwayomi">
<Package InstallerVersion="300" Compressed="yes" />
<Media Id="1" Cabinet="Tachidesk_Server.cab" EmbedCab="yes" />
<Condition Message="This version of Windows does not support deploying 64-bit packages.">
VersionNT64
</Condition>
<!-- Directory -->
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFiles64Folder">
<Directory Id="INSTALLDIR" Name="Tachidesk-Server" >
<Directory Id="jre"/>
<Directory Id="electron"/>
</Directory>
</Directory>
<Directory Id="ProgramMenuFolder">
<Directory Id="ProgramMenuDir" Name="Tachidesk-Server">
<Component Id="ProgramMenuDir" Guid="*">
<RemoveFolder Id="ProgramMenuDir" On="uninstall"/>
<RegistryValue Root="HKCU" Key="Software\[Manufacturer]\[ProductName]" Type="string" Value="" KeyPath="yes"/>
</Component>
</Directory>
</Directory>
<Directory Id="DesktopFolder" />
</Directory>
<!-- Component -->
<DirectoryRef Id="INSTALLDIR">
<Component Id="TachideskJAR" Guid="*" Win64="yes">
<File Id="Tachidesk-Server.jar" Source="$(var.SourceDir)/Tachidesk-Server.jar" KeyPath="yes" />
</Component>
<Component Id="TachideskBrowserBAT" Guid="*" Win64="yes">
<File Id="TachideskBrowser.bat" Source="$(var.SourceDir)/Tachidesk Browser Launcher.bat" KeyPath="yes" >
<Shortcut Id="TachideskBrowser.lnk" Name="Tachidesk Browser" Directory="INSTALLDIR"
WorkingDirectory="INSTALLDIR" Icon="Tachidesk.ico" IconIndex="0" Advertise="yes" />
<Shortcut Id="DesktopTachideskBrowser.lnk" Name="Tachidesk Browser" Directory="DesktopFolder"
WorkingDirectory="INSTALLDIR" Icon="Tachidesk.ico" IconIndex="0" Advertise="yes" />
<Shortcut Id="ProgramMenuTachideskBrowser.lnk" Name="Tachidesk Browser" Directory="ProgramMenuDir"
WorkingDirectory="INSTALLDIR" Icon="Tachidesk.ico" IconIndex="0" Advertise="yes"
Description="A free and open source manga reader that runs extensions built for Tachiyomi." />
</File>
</Component>
<Component Id="TachideskDebugBAT" Guid="*" Win64="yes">
<File Id="TachideskDebug.bat" Source="$(var.SourceDir)/Tachidesk Debug Launcher.bat" KeyPath="yes">
<Shortcut Id="TachideskDebug.lnk" Name="Tachidesk Debug" Directory="INSTALLDIR"
WorkingDirectory="INSTALLDIR" Icon="Tachidesk.ico" IconIndex="0" Advertise="yes" />
<Shortcut Id="ProgramMenuTachideskDebug.lnk" Name="Tachidesk Debug" Directory="ProgramMenuDir"
WorkingDirectory="INSTALLDIR" Icon="Tachidesk.ico" IconIndex="0" Advertise="yes"
Description="Launches Tachidesk with debug logs attached. If Tachidesk doesn't work for you, running this can give you insight into why." />
</File>
</Component>
<Component Id="TachideskElectronBAT" Guid="*" Win64="yes">
<File Id="TachideskElectron.bat" Source="$(var.SourceDir)/Tachidesk Electron Launcher.bat" KeyPath="yes">
<Shortcut Id="TachideskElectron.lnk" Name="Tachidesk Electron" Directory="INSTALLDIR"
WorkingDirectory="INSTALLDIR" Icon="Tachidesk.ico" IconIndex="0" Advertise="yes" />
<Shortcut Id="DesktopTachideskElectron.lnk" Name="Tachidesk Electron" Directory="DesktopFolder"
WorkingDirectory="INSTALLDIR" Icon="Tachidesk.ico" IconIndex="0" Advertise="yes" />
<Shortcut Id="ProgramMenuTachideskElectron.lnk" Name="Tachidesk Electron" Directory="ProgramMenuDir"
WorkingDirectory="INSTALLDIR" Icon="Tachidesk.ico" IconIndex="0" Advertise="yes"
Description="Launches Tachidesk inside Electron as a desktop applicaton." />
</File>
</Component>
</DirectoryRef>
<!-- Feature -->
<Feature Id="Tachidesk_Server" Title="Tachidesk-Server" Level="1">
<ComponentGroupRef Id="jre" />
<ComponentRef Id="TachideskJAR" />
<ComponentRef Id="TachideskBrowserBAT" />
<ComponentRef Id="TachideskDebugBAT" />
<ComponentRef Id="ProgramMenuDir" />
<ComponentGroupRef Id="electron" />
<ComponentRef Id="TachideskElectronBAT" />
</Feature>
<Icon Id="Tachidesk.ico" SourceFile="$(var.Icon)" />
<Property Id="ARPPRODUCTICON" Value="Tachidesk.ico" /> <!-- Icon in Add/Remove Programs -->
</Product>
</Wix>

View File

@@ -0,0 +1,82 @@
<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" UpgradeCode="*"
Version="$(var.ProductVersion)" Language="1033" Name="Tachidesk Server" Manufacturer="Suwayomi">
<Package InstallerVersion="300" Compressed="yes" />
<Media Id="1" Cabinet="Tachidesk_Server.cab" EmbedCab="yes" />
<!-- Directory -->
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLDIR" Name="Tachidesk-Server" >
<Directory Id="jre"/>
<Directory Id="electron"/>
</Directory>
</Directory>
<Directory Id="ProgramMenuFolder">
<Directory Id="ProgramMenuDir" Name="Tachidesk-Server">
<Component Id="ProgramMenuDir" Guid="*">
<RemoveFolder Id="ProgramMenuDir" On="uninstall"/>
<RegistryValue Root="HKCU" Key="Software\[Manufacturer]\[ProductName]" Type="string" Value="" KeyPath="yes"/>
</Component>
</Directory>
</Directory>
<Directory Id="DesktopFolder" />
</Directory>
<!-- Component -->
<DirectoryRef Id="INSTALLDIR">
<Component Id="TachideskJAR" Guid="*">
<File Id="Tachidesk-Server.jar" Source="$(var.SourceDir)/Tachidesk-Server.jar" KeyPath="yes" />
</Component>
<Component Id="TachideskBrowserBAT" Guid="*">
<File Id="TachideskBrowser.bat" Source="$(var.SourceDir)/Tachidesk Browser Launcher.bat" KeyPath="yes" >
<Shortcut Id="TachideskBrowser.lnk" Name="Tachidesk Browser" Directory="INSTALLDIR"
WorkingDirectory="INSTALLDIR" Icon="Tachidesk.ico" IconIndex="0" Advertise="yes" />
<Shortcut Id="DesktopTachideskBrowser.lnk" Name="Tachidesk Browser" Directory="DesktopFolder"
WorkingDirectory="INSTALLDIR" Icon="Tachidesk.ico" IconIndex="0" Advertise="yes" />
<Shortcut Id="ProgramMenuTachideskBrowser.lnk" Name="Tachidesk Browser" Directory="ProgramMenuDir"
WorkingDirectory="INSTALLDIR" Icon="Tachidesk.ico" IconIndex="0" Advertise="yes"
Description="A free and open source manga reader that runs extensions built for Tachiyomi." />
</File>
</Component>
<Component Id="TachideskDebugBAT" Guid="*">
<File Id="TachideskDebug.bat" Source="$(var.SourceDir)/Tachidesk Debug Launcher.bat" KeyPath="yes">
<Shortcut Id="TachideskDebug.lnk" Name="Tachidesk Debug" Directory="INSTALLDIR"
WorkingDirectory="INSTALLDIR" Icon="Tachidesk.ico" IconIndex="0" Advertise="yes" />
<Shortcut Id="ProgramMenuTachideskDebug.lnk" Name="Tachidesk Debug" Directory="ProgramMenuDir"
WorkingDirectory="INSTALLDIR" Icon="Tachidesk.ico" IconIndex="0" Advertise="yes"
Description="Launches Tachidesk with debug logs attached. If Tachidesk doesn't work for you, running this can give you insight into why." />
</File>
</Component>
<Component Id="TachideskElectronBAT" Guid="*">
<File Id="TachideskElectron.bat" Source="$(var.SourceDir)/Tachidesk Electron Launcher.bat" KeyPath="yes">
<Shortcut Id="TachideskElectron.lnk" Name="Tachidesk Electron" Directory="INSTALLDIR"
WorkingDirectory="INSTALLDIR" Icon="Tachidesk.ico" IconIndex="0" Advertise="yes" />
<Shortcut Id="DesktopTachideskElectron.lnk" Name="Tachidesk Electron" Directory="DesktopFolder"
WorkingDirectory="INSTALLDIR" Icon="Tachidesk.ico" IconIndex="0" Advertise="yes" />
<Shortcut Id="ProgramMenuTachideskElectron.lnk" Name="Tachidesk Electron" Directory="ProgramMenuDir"
WorkingDirectory="INSTALLDIR" Icon="Tachidesk.ico" IconIndex="0" Advertise="yes"
Description="Launches Tachidesk inside Electron as a desktop applicaton." />
</File>
</Component>
</DirectoryRef>
<!-- Feature -->
<Feature Id="Tachidesk_Server" Title="Tachidesk-Server" Level="1">
<ComponentGroupRef Id="jre" />
<ComponentRef Id="TachideskJAR" />
<ComponentRef Id="TachideskBrowserBAT" />
<ComponentRef Id="TachideskDebugBAT" />
<ComponentRef Id="ProgramMenuDir" />
<ComponentGroupRef Id="electron" />
<ComponentRef Id="TachideskElectronBAT" />
</Feature>
<Icon Id="Tachidesk.ico" SourceFile="$(var.Icon)" />
<Property Id="ARPPRODUCTICON" Value="Tachidesk.ico" /> <!-- Icon in Add/Remove Programs -->
</Product>
</Wix>

View File

@@ -1,8 +0,0 @@
[Desktop Entry]
Type=Application
Name=Suwayomi-Launcher
Comment=Manga Reader
Exec=/usr/bin/java -jar /usr/share/java/suwayomi-server/Suwayomi-Launcher.jar "\\$@"
Icon=suwayomi-server
Terminal=false
Categories=Network;

View File

@@ -1,3 +0,0 @@
#!/bin/sh
exec /usr/bin/java -jar /usr/share/java/suwayomi-server/Suwayomi-Launcher.jar

View File

@@ -1,8 +0,0 @@
[Desktop Entry]
Type=Application
Name=Suwayomi-Server
Comment=Manga Reader
Exec=/usr/bin/java -jar /usr/share/java/suwayomi-server/bin/Suwayomi-Server.jar "\\$@"
Icon=suwayomi-server
Terminal=false
Categories=Network;

View File

@@ -1,3 +0,0 @@
#!/bin/sh
exec /usr/bin/java -jar /usr/share/java/suwayomi-server/bin/Suwayomi-Server.jar

View File

@@ -1,2 +0,0 @@
#Type Name ID GECOS Home directory Shell
u suwayomi-server - "Suwayomi Manga Server" /var/lib/suwayomi

View File

@@ -1,2 +0,0 @@
#Type Path Mode User Group Age Argument
d /var/lib/suwayomi 0755 suwayomi-server suwayomi-server

View File

@@ -1,4 +1,4 @@
TACHIDESK_ROOT_DIR="/var/lib/suwayomi" TACHIDESK_ROOT_DIR="/var/lib/tachidesk"
# Extra arguments passed to the java command # Extra arguments passed to the java command
# The default value disables the system tray icon, and launching a browser on service start. # The default value disables the system tray icon, and launching a browser on service start.

View File

@@ -5,12 +5,12 @@ After=network-online.target
[Service] [Service]
Type=simple Type=simple
User=suwayomi-server User=tachidesk
Group=suwayomi-server Group=tachidesk
SyslogIdentifier=suwayomi-server SyslogIdentifier=tachidesk
EnvironmentFile=/etc/suwayomi/server.conf EnvironmentFile=/etc/tachidesk/server.conf
ExecStart=/usr/bin/java $JAVA_ARGS -Dsuwayomi.tachidesk.config.server.rootDir="${TACHIDESK_ROOT_DIR}" -jar /usr/share/java/suwayomi-server/bin/Suwayomi-Server.jar ExecStart=/usr/bin/java $JAVA_ARGS -Dsuwayomi.tachidesk.config.server.rootDir="${TACHIDESK_ROOT_DIR}" -jar /usr/share/java/tachidesk-server/Tachidesk-Server.jar
Restart=on-failure Restart=on-failure
ProtectSystem=full ProtectSystem=full

View File

@@ -0,0 +1,2 @@
#Type Name ID GECOS Home directory Shell
u tachidesk - "Tachidesk Manga Server" /var/lib/tachidesk

View File

@@ -0,0 +1,2 @@
#Type Path Mode User Group Age Argument
d /var/lib/tachidesk 0755 tachidesk tachidesk

View File

@@ -0,0 +1,3 @@
#!/bin/sh
exec /usr/bin/java -jar /usr/share/java/tachidesk-server/Tachidesk-Server.jar

View File

@@ -0,0 +1,5 @@
#!/bin/sh
exec /usr/bin/java \
-Dsuwayomi.tachidesk.config.server.debugLogsEnabled=true \
-jar /usr/share/java/tachidesk-server/Tachidesk-Server.jar

View File

@@ -0,0 +1,12 @@
#!/bin/sh
if [ ! -f /usr/bin/electron ]; then
echo "Electron executable was not found!
In order to run this launcher, you need Electron installed."
exit 1
fi
exec /usr/bin/java \
-Dsuwayomi.tachidesk.config.server.webUIInterface=electron \
-Dsuwayomi.tachidesk.config.server.electronPath=/usr/bin/electron \
-jar /usr/share/java/tachidesk-server/Tachidesk-Server.jar

View File

@@ -0,0 +1,8 @@
[Desktop Entry]
Type=Application
Name=Tachidesk-Server
Comment=Manga Reader
Exec=/usr/bin/java -jar /usr/share/java/tachidesk-server/Tachidesk-Server.jar "\\$@"
Icon=tachidesk-server
Terminal=false
Categories=Network;

View File

@@ -1,3 +0,0 @@
#!/bin/sh
exec ./jre/bin/java -jar ./Suwayomi-Launcher.jar

View File

@@ -1,3 +0,0 @@
#!/bin/sh
exec ./jre/bin/java -jar ./bin/Suwayomi-Server.jar

View File

@@ -0,0 +1,3 @@
#!/bin/sh
exec ./jre/bin/java -jar ./Tachidesk-Server.jar

View File

@@ -0,0 +1,5 @@
#!/bin/sh
exec ./jre/bin/java \
-Dsuwayomi.tachidesk.config.server.debugLogsEnabled=true \
-jar ./Tachidesk-Server.jar

View File

@@ -0,0 +1,6 @@
#!/bin/sh
exec ./jre/bin/java \
-Dsuwayomi.tachidesk.config.server.webUIInterface=electron \
-Dsuwayomi.tachidesk.config.server.electronPath=./electron/electron \
-jar ./Tachidesk-Server.jar

View File

@@ -1,11 +1,11 @@
import de.undercouch.gradle.tasks.download.Download import de.undercouch.gradle.tasks.download.Download
import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile
import java.time.Instant import java.time.Instant
@Suppress("DSL_SCOPE_VIOLATION")
plugins { plugins {
id(libs.plugins.kotlin.jvm.get().pluginId) id(libs.plugins.kotlin.jvm.get().pluginId)
id(libs.plugins.kotlin.serialization.get().pluginId) id(libs.plugins.kotlin.serialization.get().pluginId)
id(libs.plugins.ktlint.get().pluginId) id(libs.plugins.kotlinter.get().pluginId)
application application
alias(libs.plugins.shadowjar) alias(libs.plugins.shadowjar)
id(libs.plugins.buildconfig.get().pluginId) id(libs.plugins.buildconfig.get().pluginId)
@@ -24,11 +24,6 @@ dependencies {
implementation(libs.bundles.javalin) implementation(libs.bundles.javalin)
implementation(libs.bundles.jackson) implementation(libs.bundles.jackson)
// GraphQL
implementation(libs.graphql.kotlin.server)
implementation(libs.graphql.kotlin.scheme)
implementation(libs.graphql.scalars)
// Exposed ORM // Exposed ORM
implementation(libs.bundles.exposed) implementation(libs.bundles.exposed)
implementation(libs.h2) implementation(libs.h2)
@@ -45,10 +40,6 @@ dependencies {
implementation(libs.rxjava) implementation(libs.rxjava)
implementation(libs.jsoup) implementation(libs.jsoup)
// ComicInfo
implementation(libs.serialization.xml.core)
implementation(libs.serialization.xml)
// Sort // Sort
implementation(libs.sort) implementation(libs.sort)
@@ -60,6 +51,9 @@ dependencies {
implementation(libs.commonscompress) implementation(libs.commonscompress)
implementation(libs.junrar) implementation(libs.junrar)
// CloudflareInterceptor
implementation(libs.playwright)
// AES/CBC/PKCS7Padding Cypher provider for zh.copymanga // AES/CBC/PKCS7Padding Cypher provider for zh.copymanga
implementation(libs.bouncycastle) implementation(libs.bouncycastle)
@@ -71,18 +65,17 @@ dependencies {
// implementation(fileTree("lib/")) // implementation(fileTree("lib/"))
implementation(kotlin("script-runtime")) implementation(kotlin("script-runtime"))
implementation("com.expediagroup:graphql-kotlin-server:6.4.0")
implementation("com.expediagroup:graphql-kotlin-schema-generator:6.4.0")
implementation("com.graphql-java:graphql-java-extended-scalars:20.0")
testImplementation(libs.mockk) testImplementation(libs.mockk)
implementation(libs.cron4j)
implementation(libs.cronUtils)
} }
application { application {
applicationDefaultJvmArgs = applicationDefaultJvmArgs = listOf(
listOf( "-Djunrar.extractor.thread-keep-alive-seconds=30"
"-Djunrar.extractor.thread-keep-alive-seconds=30", )
)
mainClass.set(MainClass) mainClass.set(MainClass)
} }
@@ -96,7 +89,7 @@ sourceSets {
buildConfig { buildConfig {
className("BuildConfig") className("BuildConfig")
packageName("suwayomi.tachidesk.server.generated") packageName("suwayomi.tachidesk.server")
useKotlinOutput() useKotlinOutput()
@@ -104,31 +97,33 @@ buildConfig {
buildConfigField("String", "NAME", quoteWrap(rootProject.name)) buildConfigField("String", "NAME", quoteWrap(rootProject.name))
buildConfigField("String", "VERSION", quoteWrap(tachideskVersion)) buildConfigField("String", "VERSION", quoteWrap(tachideskVersion))
buildConfigField("String", "REVISION", quoteWrap(getTachideskRevision())) buildConfigField("String", "REVISION", quoteWrap(tachideskRevision))
buildConfigField("String", "BUILD_TYPE", quoteWrap(if (System.getenv("ProductBuildType") == "Stable") "Stable" else "Preview")) 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", quoteWrap("https://github.com/Suwayomi/Tachidesk-WebUI-preview"))
buildConfigField("String", "WEBUI_TAG", quoteWrap(webUIRevisionTag)) buildConfigField("String", "WEBUI_TAG", quoteWrap(webUIRevisionTag))
buildConfigField("String", "GITHUB", quoteWrap("https://github.com/Suwayomi/Suwayomi-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"))
} }
tasks { tasks {
shadowJar { shadowJar {
isZip64 = true
manifest { manifest {
attributes( attributes(
"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 getTachideskRevision(), "Implementation-Version" to tachideskRevision
) )
} }
archiveBaseName.set(rootProject.name) archiveBaseName.set(rootProject.name)
archiveVersion.set(tachideskVersion) archiveVersion.set(tachideskVersion)
archiveClassifier.set(getTachideskRevision()) archiveClassifier.set(tachideskRevision)
destinationDirectory.set(File("$rootDir/server/build")) destinationDirectory.set(File("$rootDir/server/build"))
} }
@@ -140,34 +135,25 @@ tasks {
} }
} }
withType<KotlinJvmCompile> {
kotlinOptions {
freeCompilerArgs +=
listOf(
"-opt-in=kotlinx.serialization.ExperimentalSerializationApi",
)
}
}
named<Copy>("processResources") { named<Copy>("processResources") {
duplicatesStrategy = DuplicatesStrategy.INCLUDE duplicatesStrategy = DuplicatesStrategy.INCLUDE
mustRunAfter("downloadWebUI") mustRunAfter("downloadWebUI")
} }
register<Download>("downloadWebUI") { register<Download>("downloadWebUI") {
src("https://github.com/Suwayomi/Suwayomi-WebUI-preview/releases/download/$webUIRevisionTag/Suwayomi-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 { fun shouldOverwrite(): Boolean {
val zipPath = project.projectDir.absolutePath + "/src/main/resources/WebUI.zip" val zipPath = project.projectDir.absolutePath + "/src/main/resources/WebUI.zip"
val zipFile = net.lingala.zip4j.ZipFile(zipPath) val zipFile = net.lingala.zip4j.ZipFile(zipPath)
var shouldOverwrite = true var shouldOverwrite = true
if (zipFile.isValidZipFile) { if (zipFile.isValidZipFile) {
val zipRevision = val zipRevision = zipFile.getInputStream(zipFile.getFileHeader("revision")).bufferedReader().use {
zipFile.getInputStream(zipFile.getFileHeader("revision")).bufferedReader().use { it.readText().trim()
it.readText().trim() }
}
if (zipRevision == webUIRevisionTag) { if (zipRevision == webUIRevisionTag) {
shouldOverwrite = false shouldOverwrite = false
@@ -184,12 +170,11 @@ tasks {
group = "application" group = "application"
finalizedBy(run) finalizedBy(run)
doFirst { doFirst {
application.applicationDefaultJvmArgs = application.applicationDefaultJvmArgs = listOf(
listOf( "-Dsuwayomi.tachidesk.config.server.webUIInterface=electron",
"-Dsuwayomi.tachidesk.config.server.webUIInterface=electron", // Change this to the installed electron application
// Change this to the installed electron application "-Dsuwayomi.tachidesk.config.server.electronPath=/usr/bin/electron"
"-Dsuwayomi.tachidesk.config.server.electronPath=/usr/bin/electron", )
)
} }
} }
} }

View File

@@ -0,0 +1,212 @@
/*
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package suwayomi.tachidesk.server.util;
import com.microsoft.playwright.impl.driver.Driver;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.*;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* Copy of <a href="https://github.com/microsoft/playwright-java/blob/8c0231b0f739656e8a86bc58fca9ee778ddc571b/driver-bundle/src/main/java/com/microsoft/playwright/impl/driver/jar/DriverJar.java">DriverJar</a>
* with support for pre-installing chromium and only supports chromium playwright
*/
public class DriverJar extends Driver {
private static final String PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD = "PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD";
private static final String SELENIUM_REMOTE_URL = "SELENIUM_REMOTE_URL";
static final String PLAYWRIGHT_NODEJS_PATH = "PLAYWRIGHT_NODEJS_PATH";
private final Path driverTempDir;
private Path preinstalledNodePath;
public DriverJar() throws IOException {
// Allow specifying custom path for the driver installation
// See https://github.com/microsoft/playwright-java/issues/728
String alternativeTmpdir = System.getProperty("playwright.driver.tmpdir");
String prefix = "playwright-java-";
driverTempDir = alternativeTmpdir == null
? Files.createTempDirectory(prefix)
: Files.createTempDirectory(Paths.get(alternativeTmpdir), prefix);
driverTempDir.toFile().deleteOnExit();
String nodePath = System.getProperty("playwright.nodejs.path");
if (nodePath != null) {
preinstalledNodePath = Paths.get(nodePath);
if (!Files.exists(preinstalledNodePath)) {
throw new RuntimeException("Invalid Node.js path specified: " + nodePath);
}
}
logMessage("created DriverJar: " + driverTempDir);
}
@Override
protected void initialize(Boolean installBrowsers) throws Exception {
if (preinstalledNodePath == null && env.containsKey(PLAYWRIGHT_NODEJS_PATH)) {
preinstalledNodePath = Paths.get(env.get(PLAYWRIGHT_NODEJS_PATH));
if (!Files.exists(preinstalledNodePath)) {
throw new RuntimeException("Invalid Node.js path specified: " + preinstalledNodePath);
}
} else if (preinstalledNodePath != null) {
// Pass the env variable to the driver process.
env.put(PLAYWRIGHT_NODEJS_PATH, preinstalledNodePath.toString());
}
extractDriverToTempDir();
logMessage("extracted driver from jar to " + driverPath());
if (installBrowsers)
installBrowsers(env);
}
private void installBrowsers(Map<String, String> env) throws IOException, InterruptedException {
String skip = env.get(PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD);
if (skip == null) {
skip = System.getenv(PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD);
}
if (skip != null && !"0".equals(skip) && !"false".equals(skip)) {
System.out.println("Skipping browsers download because `PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD` env variable is set");
return;
}
if (env.get(SELENIUM_REMOTE_URL) != null || System.getenv(SELENIUM_REMOTE_URL) != null) {
logMessage("Skipping browsers download because `SELENIUM_REMOTE_URL` env variable is set");
return;
}
Chromium.preinstall(platformDir());
Path driver = driverPath();
if (!Files.exists(driver)) {
throw new RuntimeException("Failed to find driver: " + driver);
}
ProcessBuilder pb = createProcessBuilder();
pb.command().add("install");
pb.command().add("chromium");
pb.redirectError(ProcessBuilder.Redirect.INHERIT);
pb.redirectOutput(ProcessBuilder.Redirect.INHERIT);
Process p = pb.start();
boolean result = p.waitFor(10, TimeUnit.MINUTES);
if (!result) {
p.destroy();
throw new RuntimeException("Timed out waiting for browsers to install");
}
if (p.exitValue() != 0) {
throw new RuntimeException("Failed to install browsers, exit code: " + p.exitValue());
}
}
private static boolean isExecutable(Path filePath) {
String name = filePath.getFileName().toString();
return name.endsWith(".sh") || name.endsWith(".exe") || !name.contains(".");
}
private FileSystem initFileSystem(URI uri) throws IOException {
try {
return FileSystems.newFileSystem(uri, Collections.emptyMap());
} catch (FileSystemAlreadyExistsException e) {
return null;
}
}
public static URI getDriverResourceURI() throws URISyntaxException {
ClassLoader classloader = Thread.currentThread().getContextClassLoader();
return classloader.getResource("driver/" + platformDir()).toURI();
}
void extractDriverToTempDir() throws URISyntaxException, IOException {
URI originalUri = getDriverResourceURI();
URI uri = maybeExtractNestedJar(originalUri);
// Create zip filesystem if loading from jar.
try (FileSystem fileSystem = "jar".equals(uri.getScheme()) ? initFileSystem(uri) : null) {
Path srcRoot = Paths.get(uri);
// jar file system's .relativize gives wrong results when used with
// spring-boot-maven-plugin, convert to the default filesystem to
// have predictable results.
// See https://github.com/microsoft/playwright-java/issues/306
Path srcRootDefaultFs = Paths.get(srcRoot.toString());
Files.walk(srcRoot).forEach(fromPath -> {
if (preinstalledNodePath != null) {
String fileName = fromPath.getFileName().toString();
if ("node.exe".equals(fileName) || "node".equals(fileName)) {
return;
}
}
Path relative = srcRootDefaultFs.relativize(Paths.get(fromPath.toString()));
Path toPath = driverTempDir.resolve(relative.toString());
try {
if (Files.isDirectory(fromPath)) {
Files.createDirectories(toPath);
} else {
Files.copy(fromPath, toPath);
if (isExecutable(toPath)) {
toPath.toFile().setExecutable(true, true);
}
}
toPath.toFile().deleteOnExit();
} catch (IOException e) {
throw new RuntimeException("Failed to extract driver from " + uri + ", full uri: " + originalUri, e);
}
});
}
}
private URI maybeExtractNestedJar(final URI uri) throws URISyntaxException {
if (!"jar".equals(uri.getScheme())) {
return uri;
}
final String JAR_URL_SEPARATOR = "!/";
String[] parts = uri.toString().split("!/");
if (parts.length != 3) {
return uri;
}
String innerJar = String.join(JAR_URL_SEPARATOR, parts[0], parts[1]);
URI jarUri = new URI(innerJar);
try (FileSystem fs = FileSystems.newFileSystem(jarUri, Collections.emptyMap())) {
Path fromPath = Paths.get(jarUri);
Path toPath = driverTempDir.resolve(fromPath.getFileName().toString());
Files.copy(fromPath, toPath);
toPath.toFile().deleteOnExit();
return new URI("jar:" + toPath.toUri() + JAR_URL_SEPARATOR + parts[2]);
} catch (IOException e) {
throw new RuntimeException("Failed to extract driver's nested .jar from " + jarUri + "; full uri: " + uri, e);
}
}
private static String platformDir() {
String name = System.getProperty("os.name").toLowerCase();
String arch = System.getProperty("os.arch").toLowerCase();
if (name.contains("windows")) {
return "win32_x64";
}
if (name.contains("linux")) {
if (arch.equals("aarch64")) {
return "linux-arm64";
} else {
return "linux";
}
}
if (name.contains("mac os x")) {
return "mac";
}
throw new RuntimeException("Unexpected os.name value: " + name);
}
@Override
protected Path driverDir() {
return driverTempDir;
}
}

View File

@@ -0,0 +1,33 @@
package eu.kanade.domain.track.service
import eu.kanade.tachiyomi.data.track.TrackService
// import eu.kanade.tachiyomi.data.track.anilist.Anilist
import tachiyomi.core.preference.PreferenceStore
class TrackPreferences(
private val preferenceStore: PreferenceStore
) {
fun trackUsername(sync: TrackService) = preferenceStore.getString(trackUsername(sync.id), "")
fun trackPassword(sync: TrackService) = preferenceStore.getString(trackPassword(sync.id), "")
fun setTrackCredentials(sync: TrackService, username: String, password: String) {
trackUsername(sync).set(username)
trackPassword(sync).set(password)
}
fun trackToken(sync: TrackService) = preferenceStore.getString(trackToken(sync.id), "")
// fun anilistScoreType() = preferenceStore.getString("anilist_score_type", Anilist.POINT_10)
fun autoUpdateTrack() = preferenceStore.getBoolean("pref_auto_update_manga_sync_key", true)
companion object {
fun trackUsername(syncId: Long) = "pref_mangasync_username_$syncId"
private fun trackPassword(syncId: Long) = "pref_mangasync_password_$syncId"
private fun trackToken(syncId: Long) = "track_token_$syncId"
}
}

View File

@@ -9,11 +9,15 @@ package eu.kanade.tachiyomi
import android.app.Application import android.app.Application
import android.content.Context import android.content.Context
// import android.content.res.Configuration
// import android.support.multidex.MultiDex
// import timber.log.Timber
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.InjektScope import uy.kohesive.injekt.api.InjektScope
import uy.kohesive.injekt.registry.default.DefaultRegistrar import uy.kohesive.injekt.registry.default.DefaultRegistrar
open class App : Application() { open class App : Application() {
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
Injekt = InjektScope(DefaultRegistrar()) Injekt = InjektScope(DefaultRegistrar())

View File

@@ -1,34 +1,14 @@
package eu.kanade.tachiyomi package eu.kanade.tachiyomi
import suwayomi.tachidesk.manga.impl.util.storage.ImageUtil
import suwayomi.tachidesk.server.generated.BuildConfig
/** /**
* Used by extensions. * Used by extensions.
* *
* @since extension-lib 1.3 * @since extension-lib 1.3
*/ */
object AppInfo { object AppInfo {
/** /** should be something like 74 */
* fun getVersionCode() = suwayomi.tachidesk.server.BuildConfig.REVISION.substring(1).toInt()
* should be something like 74
*
* @since extension-lib 1.3
*/
fun getVersionCode() = BuildConfig.REVISION.substring(1).toInt()
/** /** should be something like "0.13.1" */
* should be something like "0.13.1" fun getVersionName() = suwayomi.tachidesk.server.BuildConfig.VERSION.substring(1)
*
* @since extension-lib 1.3
*/
fun getVersionName() = BuildConfig.VERSION.substring(1)
/**
* A list of supported image MIME types by the reader.
* e.g. ["image/jpeg", "image/png", ...]
*
* @since extension-lib 1.5
*/
fun getSupportedImageMimeTypes(): List<String> = ImageUtil.ImageType.entries.map { it.mime }
} }

View File

@@ -28,6 +28,7 @@ import uy.kohesive.injekt.api.addSingletonFactory
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
class AppModule(val app: Application) : InjektModule { class AppModule(val app: Application) : InjektModule {
override fun InjektRegistrar.registerInjectables() { override fun InjektRegistrar.registerInjectables() {
addSingleton(app) addSingleton(app)

View File

@@ -1,13 +1,12 @@
@file:Suppress("ktlint:standard:property-naming") package eu.kanade.tachiyomi.data.database.models
package suwayomi.tachidesk.manga.impl.track.tracker.model
import java.io.Serializable import java.io.Serializable
interface Track : Serializable { interface Track : Serializable {
var id: Int?
var manga_id: Int var id: Long?
var manga_id: Long
var sync_id: Int var sync_id: Int
@@ -40,9 +39,8 @@ interface Track : Serializable {
} }
companion object { companion object {
fun create(serviceId: Int): Track = fun create(serviceId: Long): Track = TrackImpl().apply {
TrackImpl().apply { sync_id = serviceId.toInt()
sync_id = serviceId }
}
} }
} }

View File

@@ -1,11 +1,10 @@
@file:Suppress("ktlint:standard:property-naming") package eu.kanade.tachiyomi.data.database.models
package suwayomi.tachidesk.manga.impl.track.tracker.model
class TrackImpl : Track { class TrackImpl : Track {
override var id: Int? = null
override var manga_id: Int = 0 override var id: Long? = null
override var manga_id: Long = 0
override var sync_id: Int = 0 override var sync_id: Int = 0

View File

@@ -0,0 +1,41 @@
package eu.kanade.tachiyomi.data.track
import eu.kanade.tachiyomi.data.track.model.TrackSearch
import eu.kanade.tachiyomi.source.Source
import tachiyomi.domain.manga.model.Manga
import tachiyomi.domain.track.model.Track
/**
* An Enhanced Track Service will never prompt the user to match a manga with the remote.
* It is expected that such Track Service can only work with specific sources and unique IDs.
*/
interface EnhancedTrackService {
/**
* This TrackService will only work with the sources that are accepted by this filter function.
*/
fun accept(source: Source): Boolean {
return source::class.qualifiedName in getAcceptedSources()
}
/**
* Fully qualified source classes that this track service is compatible with.
*/
fun getAcceptedSources(): List<String>
fun loginNoop()
/**
* match is similar to TrackService.search, but only return zero or one match.
*/
suspend fun match(manga: Manga): TrackSearch?
/**
* Checks whether the provided source/track/manga triplet is from this TrackService
*/
fun isTrackFrom(track: Track, manga: Manga, source: Source?): Boolean
/**
* Migrates the given track for the manga to the newSource, if possible
*/
fun migrateTrack(track: Track, manga: Manga, newSource: Source): Track?
}

View File

@@ -0,0 +1,43 @@
package eu.kanade.tachiyomi.data.track
// import eu.kanade.tachiyomi.data.track.anilist.Anilist
// import eu.kanade.tachiyomi.data.track.bangumi.Bangumi
// import eu.kanade.tachiyomi.data.track.kavita.Kavita
// import eu.kanade.tachiyomi.data.track.kitsu.Kitsu
// import eu.kanade.tachiyomi.data.track.komga.Komga
import eu.kanade.tachiyomi.data.track.mangaupdates.MangaUpdates
// import eu.kanade.tachiyomi.data.track.myanimelist.MyAnimeList
// import eu.kanade.tachiyomi.data.track.shikimori.Shikimori
// import eu.kanade.tachiyomi.data.track.suwayomi.Suwayomi
class TrackManager {
companion object {
const val MYANIMELIST = 1L
const val ANILIST = 2L
const val KITSU = 3L
const val SHIKIMORI = 4L
const val BANGUMI = 5L
const val KOMGA = 6L
const val MANGA_UPDATES = 7L
const val KAVITA = 8L
const val SUWAYOMI = 9L
}
// val myAnimeList = MyAnimeList(MYANIMELIST)
// val aniList = Anilist(ANILIST)
// val kitsu = Kitsu(KITSU)
// val shikimori = Shikimori(SHIKIMORI)
// val bangumi = Bangumi(BANGUMI)
// val komga = Komga(KOMGA)
val mangaUpdates = MangaUpdates(MANGA_UPDATES)
// val kavita = Kavita(KAVITA)
// val suwayomi = Suwayomi(SUWAYOMI)
// val services = listOf(myAnimeList, aniList, kitsu, shikimori, bangumi, komga, mangaUpdates, kavita, suwayomi)
val services = listOf(mangaUpdates)
fun getService(id: Long) = services.find { it.id == id }
fun hasLoggedServices() = services.any { it.isLogged }
}

View File

@@ -0,0 +1,188 @@
package eu.kanade.tachiyomi.data.track
// import androidx.annotation.CallSuper
// import androidx.annotation.ColorInt
// import androidx.annotation.DrawableRes
// import androidx.annotation.StringRes
// import eu.kanade.domain.base.BasePreferences
// import eu.kanade.domain.chapter.interactor.SyncChaptersWithTrackServiceTwoWay
// import eu.kanade.domain.track.model.toDbTrack
// import eu.kanade.domain.track.model.toDomainTrack
import eu.kanade.domain.track.service.TrackPreferences
import eu.kanade.tachiyomi.data.database.models.Track
import eu.kanade.tachiyomi.data.track.model.TrackSearch
import eu.kanade.tachiyomi.network.NetworkHelper
// import eu.kanade.tachiyomi.util.system.toast
// import logcat.LogPriority
import okhttp3.OkHttpClient
// import tachiyomi.core.util.lang.withIOContext
// import tachiyomi.core.util.lang.withUIContext
// import tachiyomi.core.util.system.logcat
// import tachiyomi.domain.chapter.interactor.GetChapterByMangaId
// import tachiyomi.domain.track.interactor.InsertTrack
import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy
import tachiyomi.domain.track.model.Track as DomainTrack
abstract class TrackService(val id: Long) {
// val preferences: BasePreferences by injectLazy()
val trackPreferences: TrackPreferences by injectLazy()
val networkService: NetworkHelper by injectLazy()
open val client: OkHttpClient
get() = networkService.client
// Name of the manga sync service to display
abstract val name: String
// Application and remote support for reading dates
open val supportsReadingDates: Boolean = false
// @DrawableRes
// abstract fun getLogo(): Int
// @ColorInt
// abstract fun getLogoColor(): Int
abstract fun getStatusList(): List<Int>
// @StringRes
abstract fun getStatus(status: Int): String?
abstract fun getReadingStatus(): Int
abstract fun getRereadingStatus(): Int
abstract fun getCompletionStatus(): Int
abstract fun getScoreList(): List<String>
// TODO: Store all scores as 10 point in the future maybe?
open fun get10PointScore(track: DomainTrack): Float {
return track.score
}
open fun indexToScore(index: Int): Float {
return index.toFloat()
}
abstract fun displayScore(track: Track): String
abstract suspend fun update(track: Track, didReadChapter: Boolean = false): Track
abstract suspend fun bind(track: Track, hasReadChapters: Boolean = false): Track
abstract suspend fun search(query: String): List<TrackSearch>
abstract suspend fun refresh(track: Track): Track
abstract suspend fun login(username: String, password: String)
// @CallSuper
open fun logout() {
trackPreferences.setTrackCredentials(this, "", "")
}
open val isLogged: Boolean
get() = getUsername().isNotEmpty() &&
getPassword().isNotEmpty()
fun getUsername() = trackPreferences.trackUsername(this).get()
fun getPassword() = trackPreferences.trackPassword(this).get()
fun saveCredentials(username: String, password: String) {
trackPreferences.setTrackCredentials(this, username, password)
}
fun withIOContext(body: () -> Unit) { body() }
fun withUIContext(body: () -> Unit) { body() }
fun registerTracking(item: Track, mangaId: Long) {
// item.manga_id = mangaId
// try {
// withIOContext {
// val allChapters = Injekt.get<GetChapterByMangaId>().await(mangaId)
// val hasReadChapters = allChapters.any { it.read }
// bind(item, hasReadChapters)
//
// val track = item.toDomainTrack(idRequired = false) ?: return@withIOContext
//
// Injekt.get<InsertTrack>().await(track)
//
// // Update chapter progress if newer chapters marked read locally
// if (hasReadChapters) {
// val latestLocalReadChapterNumber = allChapters
// .sortedBy { it.chapterNumber }
// .takeWhile { it.read }
// .lastOrNull()
// ?.chapterNumber?.toDouble() ?: -1.0
//
// if (latestLocalReadChapterNumber > track.lastChapterRead) {
// val updatedTrack = track.copy(
// lastChapterRead = latestLocalReadChapterNumber
// )
// setRemoteLastChapterRead(updatedTrack.toDbTrack(), latestLocalReadChapterNumber.toInt())
// }
// }
//
// if (this is EnhancedTrackService) {
// // Injekt.get<SyncChaptersWithTrackServiceTwoWay>().await(allChapters, track, this@TrackService)
// }
// }
// } catch (e: Throwable) {
// withUIContext {
// // Injekt.get<Application>().toast(e.message)
// }
// }
}
fun setRemoteStatus(track: Track, status: Int) {
track.status = status
if (track.status == getCompletionStatus() && track.total_chapters != 0) {
track.last_chapter_read = track.total_chapters.toFloat()
}
withIOContext { updateRemote(track) }
}
fun setRemoteLastChapterRead(track: Track, chapterNumber: Int) {
if (track.last_chapter_read == 0F && track.last_chapter_read < chapterNumber && track.status != getRereadingStatus()) {
track.status = getReadingStatus()
}
track.last_chapter_read = chapterNumber.toFloat()
if (track.total_chapters != 0 && track.last_chapter_read.toInt() == track.total_chapters) {
track.status = getCompletionStatus()
}
withIOContext { updateRemote(track) }
}
fun setRemoteScore(track: Track, scoreString: String) {
track.score = indexToScore(getScoreList().indexOf(scoreString))
withIOContext { updateRemote(track) }
}
fun setRemoteStartDate(track: Track, epochMillis: Long) {
track.started_reading_date = epochMillis
withIOContext { updateRemote(track) }
}
fun setRemoteFinishDate(track: Track, epochMillis: Long) {
track.finished_reading_date = epochMillis
withIOContext { updateRemote(track) }
}
private fun updateRemote(track: Track) {
// withIOContext {
// try {
// update(track)
// track.toDomainTrack(idRequired = false)?.let {
// Injekt.get<InsertTrack>().await(it)
// }
// } catch (e: Exception) {
// logcat(LogPriority.ERROR, e) { "Failed to update remote track data id=$id" }
// withUIContext { Injekt.get<Application>().toast(e.message) }
// }
// }
}
}

View File

@@ -0,0 +1,101 @@
package eu.kanade.tachiyomi.data.track.mangaupdates
// import android.graphics.Color
// import androidx.annotation.StringRes
// import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.models.Track
import eu.kanade.tachiyomi.data.track.TrackService
import eu.kanade.tachiyomi.data.track.mangaupdates.dto.copyTo
import eu.kanade.tachiyomi.data.track.mangaupdates.dto.toTrackSearch
import eu.kanade.tachiyomi.data.track.model.TrackSearch
class MangaUpdates(id: Long) : TrackService(id) {
companion object {
const val READING_LIST = 0
const val WISH_LIST = 1
const val COMPLETE_LIST = 2
const val UNFINISHED_LIST = 3
const val ON_HOLD_LIST = 4
}
private val interceptor by lazy { MangaUpdatesInterceptor(this) }
private val api by lazy { MangaUpdatesApi(interceptor, client) }
override val name: String = "MangaUpdates"
// override fun getLogo(): Int = R.drawable.ic_manga_updates
// override fun getLogoColor(): Int = Color.rgb(146, 160, 173)
override fun getStatusList(): List<Int> {
return listOf(READING_LIST, COMPLETE_LIST, ON_HOLD_LIST, UNFINISHED_LIST, WISH_LIST)
}
// @StringRes
override fun getStatus(status: Int): String? = when (status) {
READING_LIST -> "Reading List"
WISH_LIST -> "Wish List"
COMPLETE_LIST -> "Complete List"
ON_HOLD_LIST -> ">On Hold List"
UNFINISHED_LIST -> "Unfinished List"
else -> null
}
override fun getReadingStatus(): Int = READING_LIST
override fun getRereadingStatus(): Int = -1
override fun getCompletionStatus(): Int = COMPLETE_LIST
private val _scoreList = (0..9).flatMap { i -> (0..9).map { j -> "$i.$j" } } + listOf("10.0")
override fun getScoreList(): List<String> = _scoreList
override fun indexToScore(index: Int): Float = _scoreList[index].toFloat()
override fun displayScore(track: Track): String = track.score.toString()
override suspend fun update(track: Track, didReadChapter: Boolean): Track {
if (track.status != COMPLETE_LIST && didReadChapter) {
track.status = READING_LIST
}
api.updateSeriesListItem(track)
return track
}
override suspend fun bind(track: Track, hasReadChapters: Boolean): Track {
return try {
val (series, rating) = api.getSeriesListItem(track)
series.copyTo(track)
rating?.copyTo(track) ?: track
} catch (e: Exception) {
api.addSeriesToList(track, hasReadChapters)
track
}
}
override suspend fun search(query: String): List<TrackSearch> {
return api.search(query)
.map {
it.toTrackSearch(id)
}
}
override suspend fun refresh(track: Track): Track {
val (series, rating) = api.getSeriesListItem(track)
series.copyTo(track)
return rating?.copyTo(track) ?: track
}
override suspend fun login(username: String, password: String) {
val authenticated = api.authenticate(username, password) ?: throw Throwable("Unable to login")
saveCredentials(authenticated.uid.toString(), authenticated.sessionToken)
interceptor.newAuth(authenticated.sessionToken)
}
fun restoreSession(): String? {
return trackPreferences.trackPassword(this).get()
}
}

View File

@@ -1,5 +1,12 @@
package suwayomi.tachidesk.manga.impl.track.tracker.mangaupdates package eu.kanade.tachiyomi.data.track.mangaupdates
import eu.kanade.tachiyomi.data.database.models.Track
import eu.kanade.tachiyomi.data.track.mangaupdates.MangaUpdates.Companion.READING_LIST
import eu.kanade.tachiyomi.data.track.mangaupdates.MangaUpdates.Companion.WISH_LIST
import eu.kanade.tachiyomi.data.track.mangaupdates.dto.Context
import eu.kanade.tachiyomi.data.track.mangaupdates.dto.ListItem
import eu.kanade.tachiyomi.data.track.mangaupdates.dto.Rating
import eu.kanade.tachiyomi.data.track.mangaupdates.dto.Record
import eu.kanade.tachiyomi.network.DELETE import eu.kanade.tachiyomi.network.DELETE
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.POST import eu.kanade.tachiyomi.network.POST
@@ -17,21 +24,16 @@ import kotlinx.serialization.json.jsonArray
import kotlinx.serialization.json.jsonObject import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.put import kotlinx.serialization.json.put
import kotlinx.serialization.json.putJsonObject import kotlinx.serialization.json.putJsonObject
// import logcat.LogPriority
import okhttp3.MediaType.Companion.toMediaType import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.RequestBody.Companion.toRequestBody import okhttp3.RequestBody.Companion.toRequestBody
import suwayomi.tachidesk.manga.impl.track.tracker.mangaupdates.MangaUpdates.Companion.READING_LIST // import tachiyomi.core.util.system.logcat
import suwayomi.tachidesk.manga.impl.track.tracker.mangaupdates.MangaUpdates.Companion.WISH_LIST
import suwayomi.tachidesk.manga.impl.track.tracker.mangaupdates.dto.Context
import suwayomi.tachidesk.manga.impl.track.tracker.mangaupdates.dto.ListItem
import suwayomi.tachidesk.manga.impl.track.tracker.mangaupdates.dto.Rating
import suwayomi.tachidesk.manga.impl.track.tracker.mangaupdates.dto.Record
import suwayomi.tachidesk.manga.impl.track.tracker.model.Track
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
class MangaUpdatesApi( class MangaUpdatesApi(
interceptor: MangaUpdatesInterceptor, interceptor: MangaUpdatesInterceptor,
private val client: OkHttpClient, private val client: OkHttpClient
) { ) {
private val json: Json by injectLazy() private val json: Json by injectLazy()
@@ -45,37 +47,32 @@ class MangaUpdatesApi(
} }
suspend fun getSeriesListItem(track: Track): Pair<ListItem, Rating?> { suspend fun getSeriesListItem(track: Track): Pair<ListItem, Rating?> {
val listItem = val listItem = with(json) {
with(json) { authClient.newCall(GET("$baseUrl/v1/lists/series/${track.media_id}"))
authClient.newCall(GET("$baseUrl/v1/lists/series/${track.media_id}")) .awaitSuccess()
.awaitSuccess() .parseAs<ListItem>()
.parseAs<ListItem>() }
}
val rating = getSeriesRating(track) val rating = getSeriesRating(track)
return listItem to rating return listItem to rating
} }
suspend fun addSeriesToList( suspend fun addSeriesToList(track: Track, hasReadChapters: Boolean) {
track: Track,
hasReadChapters: Boolean,
) {
val status = if (hasReadChapters) READING_LIST else WISH_LIST val status = if (hasReadChapters) READING_LIST else WISH_LIST
val body = val body = buildJsonArray {
buildJsonArray { addJsonObject {
addJsonObject { putJsonObject("series") {
putJsonObject("series") { put("id", track.media_id)
put("id", track.media_id)
}
put("list_id", status)
} }
put("list_id", status)
} }
}
authClient.newCall( authClient.newCall(
POST( POST(
url = "$baseUrl/v1/lists/series", url = "$baseUrl/v1/lists/series",
body = body.toString().toRequestBody(contentType), body = body.toString().toRequestBody(contentType)
), )
) )
.awaitSuccess() .awaitSuccess()
.let { .let {
@@ -87,43 +84,28 @@ class MangaUpdatesApi(
} }
suspend fun updateSeriesListItem(track: Track) { suspend fun updateSeriesListItem(track: Track) {
val body = val body = buildJsonArray {
buildJsonArray { addJsonObject {
addJsonObject { putJsonObject("series") {
putJsonObject("series") { put("id", track.media_id)
put("id", track.media_id) }
} put("list_id", track.status)
put("list_id", track.status) putJsonObject("status") {
putJsonObject("status") { put("chapter", track.last_chapter_read.toInt())
put("chapter", track.last_chapter_read.toInt())
}
} }
} }
}
authClient.newCall( authClient.newCall(
POST( POST(
url = "$baseUrl/v1/lists/series/update", url = "$baseUrl/v1/lists/series/update",
body = body.toString().toRequestBody(contentType), body = body.toString().toRequestBody(contentType)
), )
) )
.awaitSuccess() .awaitSuccess()
updateSeriesRating(track) updateSeriesRating(track)
} }
suspend fun deleteSeriesFromList(track: Track) {
val body =
buildJsonArray {
add(track.media_id)
}
authClient.newCall(
POST(
url = "$baseUrl/v1/lists/series/delete",
body = body.toString().toRequestBody(contentType),
),
)
.awaitSuccess()
}
private suspend fun getSeriesRating(track: Track): Rating? { private suspend fun getSeriesRating(track: Track): Rating? {
return try { return try {
with(json) { with(json) {
@@ -138,45 +120,43 @@ class MangaUpdatesApi(
private suspend fun updateSeriesRating(track: Track) { private suspend fun updateSeriesRating(track: Track) {
if (track.score != 0f) { if (track.score != 0f) {
val body = val body = buildJsonObject {
buildJsonObject { put("rating", track.score)
put("rating", track.score) }
}
authClient.newCall( authClient.newCall(
PUT( PUT(
url = "$baseUrl/v1/series/${track.media_id}/rating", url = "$baseUrl/v1/series/${track.media_id}/rating",
body = body.toString().toRequestBody(contentType), body = body.toString().toRequestBody(contentType)
), )
) )
.awaitSuccess() .awaitSuccess()
} else { } else {
authClient.newCall( authClient.newCall(
DELETE( DELETE(
url = "$baseUrl/v1/series/${track.media_id}/rating", url = "$baseUrl/v1/series/${track.media_id}/rating"
), )
) )
.awaitSuccess() .awaitSuccess()
} }
} }
suspend fun search(query: String): List<Record> { suspend fun search(query: String): List<Record> {
val body = val body = buildJsonObject {
buildJsonObject { put("search", query)
put("search", query) put(
put( "filter_types",
"filter_types", buildJsonArray {
buildJsonArray { add("drama cd")
add("drama cd") add("novel")
add("novel") }
}, )
) }
}
return with(json) { return with(json) {
client.newCall( client.newCall(
POST( POST(
url = "$baseUrl/v1/series/search", url = "$baseUrl/v1/series/search",
body = body.toString().toRequestBody(contentType), body = body.toString().toRequestBody(contentType)
), )
) )
.awaitSuccess() .awaitSuccess()
.parseAs<JsonObject>() .parseAs<JsonObject>()
@@ -189,21 +169,17 @@ class MangaUpdatesApi(
} }
} }
suspend fun authenticate( suspend fun authenticate(username: String, password: String): Context? {
username: String, val body = buildJsonObject {
password: String, put("username", username)
): Context? { put("password", password)
val body = }
buildJsonObject {
put("username", username)
put("password", password)
}
return with(json) { return with(json) {
client.newCall( client.newCall(
PUT( PUT(
url = "$baseUrl/v1/account/login", url = "$baseUrl/v1/account/login",
body = body.toString().toRequestBody(contentType), body = body.toString().toRequestBody(contentType)
), )
) )
.awaitSuccess() .awaitSuccess()
.parseAs<JsonObject>() .parseAs<JsonObject>()
@@ -211,7 +187,7 @@ class MangaUpdatesApi(
try { try {
json.decodeFromJsonElement<Context>(obj["context"]!!) json.decodeFromJsonElement<Context>(obj["context"]!!)
} catch (e: Exception) { } catch (e: Exception) {
// logcat(LogPriority.ERROR, e) // logcat(LogPriority.ERROR, e)
null null
} }
} }

View File

@@ -1,13 +1,13 @@
package suwayomi.tachidesk.manga.impl.track.tracker.mangaupdates package eu.kanade.tachiyomi.data.track.mangaupdates
import okhttp3.Interceptor import okhttp3.Interceptor
import okhttp3.Response import okhttp3.Response
import suwayomi.tachidesk.server.generated.BuildConfig
import java.io.IOException import java.io.IOException
class MangaUpdatesInterceptor( class MangaUpdatesInterceptor(
mangaUpdates: MangaUpdates, mangaUpdates: MangaUpdates
) : Interceptor { ) : Interceptor {
private var token: String? = mangaUpdates.restoreSession() private var token: String? = mangaUpdates.restoreSession()
override fun intercept(chain: Interceptor.Chain): Response { override fun intercept(chain: Interceptor.Chain): Response {
@@ -16,11 +16,9 @@ class MangaUpdatesInterceptor(
val token = token ?: throw IOException("Not authenticated with MangaUpdates") val token = token ?: throw IOException("Not authenticated with MangaUpdates")
// Add the authorization header to the original request. // Add the authorization header to the original request.
val authRequest = val authRequest = originalRequest.newBuilder()
originalRequest.newBuilder() .addHeader("Authorization", "Bearer $token")
.addHeader("Authorization", "Bearer $token") .build()
.header("User-Agent", "Suwayomi ${BuildConfig.VERSION} (${BuildConfig.REVISION})")
.build()
return chain.proceed(authRequest) return chain.proceed(authRequest)
} }

View File

@@ -1,4 +1,4 @@
package suwayomi.tachidesk.manga.impl.track.tracker.mangaupdates.dto package eu.kanade.tachiyomi.data.track.mangaupdates.dto
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@@ -7,5 +7,5 @@ import kotlinx.serialization.Serializable
data class Context( data class Context(
@SerialName("session_token") @SerialName("session_token")
val sessionToken: String, val sessionToken: String,
val uid: Long, val uid: Long
) )

View File

@@ -1,4 +1,4 @@
package suwayomi.tachidesk.manga.impl.track.tracker.mangaupdates.dto package eu.kanade.tachiyomi.data.track.mangaupdates.dto
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@@ -6,5 +6,5 @@ import kotlinx.serialization.Serializable
data class Image( data class Image(
val url: Url? = null, val url: Url? = null,
val height: Int? = null, val height: Int? = null,
val width: Int? = null, val width: Int? = null
) )

View File

@@ -1,9 +1,9 @@
package suwayomi.tachidesk.manga.impl.track.tracker.mangaupdates.dto package eu.kanade.tachiyomi.data.track.mangaupdates.dto
import eu.kanade.tachiyomi.data.database.models.Track
import eu.kanade.tachiyomi.data.track.mangaupdates.MangaUpdates.Companion.READING_LIST
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import suwayomi.tachidesk.manga.impl.track.tracker.mangaupdates.MangaUpdates.Companion.READING_LIST
import suwayomi.tachidesk.manga.impl.track.tracker.model.Track
@Serializable @Serializable
data class ListItem( data class ListItem(
@@ -11,7 +11,7 @@ data class ListItem(
@SerialName("list_id") @SerialName("list_id")
val listId: Int? = null, val listId: Int? = null,
val status: Status? = null, val status: Status? = null,
val priority: Int? = null, val priority: Int? = null
) )
fun ListItem.copyTo(track: Track): Track { fun ListItem.copyTo(track: Track): Track {

Some files were not shown because too many files have changed in this diff Show More