diff --git a/AndroidCompat/Config/build.gradle.kts b/AndroidCompat/Config/build.gradle.kts index de1b5858..e69de29b 100644 --- a/AndroidCompat/Config/build.gradle.kts +++ b/AndroidCompat/Config/build.gradle.kts @@ -1,4 +0,0 @@ -dependencies { - // Config API, moved to the global build.gradle -// implementation("com.typesafe:config:1.4.0") -} \ No newline at end of file diff --git a/AndroidCompat/build.gradle.kts b/AndroidCompat/build.gradle.kts index 9ca92f9a..c7f80f17 100644 --- a/AndroidCompat/build.gradle.kts +++ b/AndroidCompat/build.gradle.kts @@ -20,16 +20,9 @@ dependencies { // Android stub library implementation(fileTree("lib/")) - - // Android JAR libs -// compileOnly( fileTree(dir: new File(rootProject.rootDir, "libs/other"), include: "*.jar") - // JSON compileOnly("com.google.code.gson:gson:2.8.6") - // Javassist - compileOnly("org.javassist:javassist:3.27.0-GA") - // XML compileOnly(group= "xmlpull", name= "xmlpull", version= "1.1.3.1") @@ -43,10 +36,8 @@ dependencies { compileOnly("androidx.annotation:annotation:1.2.0-alpha01") // substitute for duktape-android - // 'org.mozilla:rhino' includes some code that we don't need so use 'org.mozilla:rhino-runtime' instead - implementation("org.mozilla:rhino-runtime:1.7.13") - // 'org.mozilla:rhino-engine' provides the same interface as 'javax.script' a.k.a Nashorn - implementation("org.mozilla:rhino-engine:1.7.13") + implementation("org.mozilla:rhino-runtime:1.7.13") // slimmer version of 'org.mozilla:rhino' + implementation("org.mozilla:rhino-engine:1.7.13") // provides the same interface as 'javax.script' a.k.a Nashorn // Kotlin wrapper around Java Preferences, makes certain things easier val multiplatformSettingsVersion = "0.7.7" diff --git a/AndroidCompat/src/main/java/xyz/nulldev/androidcompat/AndroidCompatInitializer.kt b/AndroidCompat/src/main/java/xyz/nulldev/androidcompat/AndroidCompatInitializer.kt index f88d0a7e..5a52b1ff 100644 --- a/AndroidCompat/src/main/java/xyz/nulldev/androidcompat/AndroidCompatInitializer.kt +++ b/AndroidCompat/src/main/java/xyz/nulldev/androidcompat/AndroidCompatInitializer.kt @@ -2,7 +2,6 @@ package xyz.nulldev.androidcompat import org.kodein.di.DI import org.kodein.di.conf.global -import xyz.nulldev.androidcompat.bytecode.ModApplier import xyz.nulldev.androidcompat.config.ApplicationInfoConfigModule import xyz.nulldev.androidcompat.config.FilesConfigModule import xyz.nulldev.androidcompat.config.SystemConfigModule @@ -12,12 +11,7 @@ import xyz.nulldev.ts.config.GlobalConfigManager * Initializes the Android compatibility module */ class AndroidCompatInitializer { - - val modApplier by lazy { ModApplier() } - fun init() { - modApplier.apply() - DI.global.addImport(AndroidCompatModule().create()) //Register config modules diff --git a/AndroidCompat/src/main/java/xyz/nulldev/androidcompat/bytecode/ModApplier.kt b/AndroidCompat/src/main/java/xyz/nulldev/androidcompat/bytecode/ModApplier.kt deleted file mode 100644 index 535146cf..00000000 --- a/AndroidCompat/src/main/java/xyz/nulldev/androidcompat/bytecode/ModApplier.kt +++ /dev/null @@ -1,22 +0,0 @@ -package xyz.nulldev.androidcompat.bytecode - -import javassist.CtClass -import mu.KotlinLogging - -/** - * Applies Javassist modifications - */ - -class ModApplier { - - val logger = KotlinLogging.logger {} - - fun apply() { - logger.info { "Applying Javassist mods..." } - val modifiedClasses = mutableListOf() - - modifiedClasses.forEach { - it.toClass() - } - } -} \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2d9d3c82..7fc18b03 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,51 +2,36 @@ ## Where should I start? Checkout [This Kanban Board](https://github.com/Suwayomi/Tachidesk/projects/1) to see the rough development roadmap. -**Note to potential contributors:** Notify the developers on Suwayomi discord (#programming channel) 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. +**Note to potential contributors:** Notify the developers on [Suwayomi discord](https://discord.gg/DDZdqZWaHA) (#programming channel) 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. -## How does Tachidesk work? +## How does Tachidesk-Server work? 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 apk extensions. All this concludes to serving a REST API to `webUI`. -2. **webUI:** A react SPA(`create-react-app`) project that works with the server to do the presentation. +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/Tachidesk-WebUI -## Why a web app? +## Why a web server app? This structure is chosen to - Achieve the maximum multi-platform-ness -- Gives the ability to acces Tachidesk from a remote web browser e.g. your phone, tablet or smart TV -- Eaise development of alternative user intefaces for Tachidesk - -## User Interfaces for Tachidesk server -Currently, there are three known interfaces for Tachidesk: -1. [webUI](https://github.com/Suwayomi/Tachidesk/tree/master/webUI/react): The react SPA that Tachidesk is traditionally shipped with. -2. [TachideskJUI](https://github.com/Suwayomi/TachideskJUI): A Jetbrains Compose Native app, re-uses components made for the upcoming Tachiyomi 1.x -3. [Equinox](https://github.com/Suwayomi/Equinox): A web user interface made with Vue.js, in super early stages of development. +- Gives the ability to acces Tachidesk-Server from a remote client e.g. your phone, tablet or smart TV +- Eaise development of user intefaces for Tachidesk ## Building from source ### Prerequisites You need these software packages installed in order to build the project -### Server + - Java Development Kit and Java Runtime Environment version 8 or newer(both Oracle JDK and OpenJDK works) - Android stubs jar - - Manual download: Download [android.jar](https://raw.githubusercontent.com/Suwayomi/Tachidesk/android-jar/android.jar) and put it under `AndroidCompat/lib`. - - Automated download: Run `AndroidCompat/getAndroid.sh`(MacOS/Linux) or `AndroidCompat/getAndroid.ps1`(Windows) from project's root directory to download and rebuild the jar file from Google's repository. -### webUI -- Nodejs LTS or latest -- Yarn -- Git -### building the full-blown jar -Run `./gradlew :webUI:copyBuild server:shadowJar`, the resulting built jar file will be `server/build/Tachidesk-vX.Y.Z-rxxx.jar`. -### building without `webUI` bundled(server only) -Delete the `server/src/main/resources/react` directory if exists from previous runs, then run `./gradlew server:shadowJar`, the resulting built jar file will be `server/build/Tachidesk-vX.Y.Z-rxxx.jar`. -### building the Windows package -First Build the jar, then cd into the `scripts` directory and run `./windows-bundler.sh` (or `./windows-bundler.ps1` if you are on windows), the resulting built zip package file will be `server/build/Tachidesk-vX.Y.Z-rxxx-win64.zip`. -## Running in development mode -First satisfy [the prerequisites](#prerequisites) -### server -run `./gradlew :server:run --stacktrace` to run the server -### webUI -How to do it is described in `webUI/react/README.md` but for short, - first cd into `webUI/react` then run `yarn` to install the node modules(do this only once) - then `yarn start` to start the development server, if a new browser window doesn't get opened automatically, - then open `http://127.0.0.1:3000` in a modern browser. This is a `create-react-app` project - and supports HMR and all the other goodies you'll need. + - **Manual download:** Download [android.jar](https://raw.githubusercontent.com/Suwayomi/Tachidesk/android-jar/android.jar) and put it under `AndroidCompat/lib`. + - **Automated download:** Run `AndroidCompat/getAndroid.sh`(MacOS/Linux) or `AndroidCompat/getAndroid.ps1`(Windows) from project's root directory to download and rebuild the jar file from Google's repository. +### 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/Tachidesk-Server-vX.Y.Z-rxxx.jar`. + +### 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/Tachidesk-Server-vX.Y.Z-rxxx.jar`. + +### 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/Tachidesk-Server-vX.Y.Z-rxxx-winXX.zip`. + +## Running in development mode +run `./gradlew :server:run --stacktrace` to run the server diff --git a/README.md b/README.md index d248a128..786628fa 100644 --- a/README.md +++ b/README.md @@ -3,30 +3,43 @@ |-------|----------|---------|---------| | ![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) | -# Tachidesk +# Tachidesk-Server is a server app! You may not want to Download Tachidesk-Server directly. +Yes, you need a client/user interface app as a front-end for Tachidesk-Server, if you Directly Download Tachidesk-Server you'll get a bundled version of [Tachodesk-WebUI](https://github.com/Suwayomi/Tachidesk-WebUI) with it. + +Here's a list of known clients/user interfaces for Tachidesk-Server: +- [Tachidesk-JUI](https://github.com/Suwayomi/Tachidesk-JUI): The "official" front-end for Tachidesk-Server, A native desktop Application. +- [Tachidesk-WebUI](https://github.com/Suwayomi/Tachidesk-WebUI): The web/electrion front-end that Tachidesk is traditionally shipped with. +- [Tachidesk-qtui](https://github.com/Suwayomi/Tachidesk-qtui): A C++/Qt for Desktop and Android, in super early stage of development. +- [Equinox](https://github.com/Suwayomi/Equinox): A web user interface made with Vue.js, in super early stage of development. + +# What is Tachidesk then? drawing -A free and open source manga reader 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/). Tachidesk is an independent Tachiyomi compatible software and is **not a Fork of** Tachiyomi. -Tachidesk 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 read and write Tachiyomi compatible backups and syncing is a planned feature. -**Tachidesk needs serious front-end dev help for it's reader and other parts, if you like the app and want to see it become better please don't hesitate to contribute some code!** - ## Is this application usable? Should I test it? Here is a list of current features: -- Installing and executing Tachiyomi's Extensions, So you'll get the same sources. -- A library to save your mangas and categories to put them into. -- Searching and browsing installed sources. -- A decent chapter reader. -- Ability to download Manga for offline read -- Backup and restore support powered by Tachiyomi Legacy Backups +- From Tachiyomi + - Installing and executing Tachiyomi's Extensions, So you'll get the same sources + - A library to save your mangas and categories to put them into + - Searching and browsing installed sources + - Ability to download Manga for offline read + - Backup and restore support powered by Tachiyomi Legacy Backups +- Aniyomi + - Installing and executing Aniyomi's Extensions + - Searching and browsing installed sources. + - Viewing an anime and it's episodes -**Note:** Keep in mind that Tachidesk is alpha software and can break rarely and/or with each update. See [Troubleshooting](https://github.com/Suwayomi/Tachidesk/wiki/Troubleshooting) if it happens. +**Note:** These are capabilities of Tachidesk-Server, the actual support is provided by each fron-end app, checkout their respective readme for more info. + +**Note:** Tachidesk-Server is alpha software and can break rarely and/or with each update. See [Troubleshooting](https://github.com/Suwayomi/Tachidesk-Server/wiki/Troubleshooting) if it happens. ## Downloading and Running the app ### All Operating Systems diff --git a/build.gradle.kts b/build.gradle.kts index 28e03259..26649187 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,8 +1,6 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { - val kotlinVersion = "1.5.21" - kotlin("jvm") version kotlinVersion kotlin("plugin.serialization") version kotlinVersion } diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts new file mode 100644 index 00000000..44116137 --- /dev/null +++ b/buildSrc/build.gradle.kts @@ -0,0 +1,11 @@ +plugins { + `kotlin-dsl` +} + +repositories { + mavenCentral() +} + +dependencies { + implementation("net.lingala.zip4j:zip4j:2.9.0") +} \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/Constants.kt b/buildSrc/src/main/kotlin/Constants.kt new file mode 100644 index 00000000..d1c25d52 --- /dev/null +++ b/buildSrc/src/main/kotlin/Constants.kt @@ -0,0 +1,33 @@ +import java.io.BufferedReader + +/* + * Copyright (C) Contributors to the Suwayomi project + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +const val kotlinVersion = "1.5.21" + +const val MainClass = "suwayomi.tachidesk.MainKt" + +// should be bumped with each stable release +val tachideskVersion = System.getenv("ProductVersion") ?: "v0.4.6" + +val webUIRevisionTag = System.getenv("WebUIRevision") ?: "r24" + +// counts commit count on master +val tachideskRevision = runCatching { + System.getenv("ProductRevision") ?: Runtime + .getRuntime() + .exec("git rev-list HEAD --count") + .let { process -> + process.waitFor() + val output = process.inputStream.use { + it.bufferedReader().use(BufferedReader::readText) + } + process.destroy() + "r" + output.trim() + } +}.getOrDefault("r0") + diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 3c4101c3..af7be50b 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/server/build.gradle.kts b/server/build.gradle.kts index b5aaf467..15bad474 100644 --- a/server/build.gradle.kts +++ b/server/build.gradle.kts @@ -1,8 +1,8 @@ + import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.jmailen.gradle.kotlinter.tasks.FormatTask import org.jmailen.gradle.kotlinter.tasks.LintTask -import java.io.BufferedReader import java.time.Instant plugins { @@ -12,15 +12,6 @@ plugins { id("com.github.gmazzo.buildconfig") version "3.0.2" } -buildscript { - repositories { - mavenCentral() - } - dependencies { - classpath("net.lingala.zip4j:zip4j:2.9.0") - } -} - repositories { maven { url = uri("https://repo1.maven.org/maven2/") @@ -89,11 +80,10 @@ dependencies { // implementation(fileTree("lib/")) } -val MainClass = "suwayomi.tachidesk.MainKt" application { mainClass.set(MainClass) - // for testing electron + // uncomment for testing electron // applicationDefaultJvmArgs = listOf( // "-Dsuwayomi.tachidesk.config.server.webUIInterface=electron", // "-Dsuwayomi.tachidesk.config.server.electronPath=/usr/bin/electron" @@ -108,49 +98,27 @@ sourceSets { } } -// should be bumped with each stable release -val tachideskVersion = System.getenv("ProductVersion") ?: "v0.4.5" -val webUIRevisionTag = System.getenv("WebUIRevision") ?: "r24" - -// counts commit count on master -val tachideskRevision = runCatching { - System.getenv("ProductRevision") ?: Runtime - .getRuntime() - .exec("git rev-list HEAD --count") - .let { process -> - process.waitFor() - val output = process.inputStream.use { - it.bufferedReader().use(BufferedReader::readText) - } - process.destroy() - "r" + output.trim() - } -}.getOrDefault("r0") - buildConfig { className("BuildConfig") packageName("suwayomi.tachidesk.server") useKotlinOutput() + fun quoteWrap(obj: Any): String = """"$obj"""" - fun str(obj: Any): String { - return "\"${obj}\"" - } - - buildConfigField("String", "NAME", str(rootProject.name)) - buildConfigField("String", "VERSION", str(tachideskVersion)) - buildConfigField("String", "REVISION", str(tachideskRevision)) - buildConfigField("String", "BUILD_TYPE", str(if (System.getenv("ProductBuildType") == "Stable") "Stable" else "Preview")) + buildConfigField("String", "NAME", quoteWrap(rootProject.name)) + buildConfigField("String", "VERSION", quoteWrap(tachideskVersion)) + buildConfigField("String", "REVISION", quoteWrap(tachideskRevision)) + buildConfigField("String", "BUILD_TYPE", quoteWrap(if (System.getenv("ProductBuildType") == "Stable") "Stable" else "Preview")) buildConfigField("long", "BUILD_TIME", Instant.now().epochSecond.toString()) - buildConfigField("String", "WEBUI_REPO", str("https://github.com/Suwayomi/Tachidesk-WebUI-preview")) - buildConfigField("String", "WEBUI_TAG", str(webUIRevisionTag)) + buildConfigField("String", "WEBUI_REPO", quoteWrap("https://github.com/Suwayomi/Tachidesk-WebUI-preview")) + buildConfigField("String", "WEBUI_TAG", quoteWrap(webUIRevisionTag)) - buildConfigField("String", "GITHUB", str("https://github.com/Suwayomi/Tachidesk")) - buildConfigField("String", "DISCORD", str("https://discord.gg/DDZdqZWaHA")) + buildConfigField("String", "GITHUB", quoteWrap("https://github.com/Suwayomi/Tachidesk")) + buildConfigField("String", "DISCORD", quoteWrap("https://discord.gg/DDZdqZWaHA")) } tasks { diff --git a/server/src/main/kotlin/suwayomi/tachidesk/server/util/WebUIManager.kt b/server/src/main/kotlin/suwayomi/tachidesk/server/util/WebUIManager.kt index c9ad1821..025ac8e0 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/server/util/WebUIManager.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/server/util/WebUIManager.kt @@ -14,8 +14,9 @@ import org.kodein.di.conf.global import org.kodein.di.instance import suwayomi.tachidesk.server.ApplicationDirs import suwayomi.tachidesk.server.BuildConfig -import java.io.BufferedInputStream import java.io.File +import java.io.InputStream +import java.net.HttpURLConnection import java.net.URL import java.nio.charset.StandardCharsets import java.security.MessageDigest @@ -58,9 +59,12 @@ fun setupWebUI() { val webUIZipFile = File(webUIZipPath) // try with resources first - val resourceWebUI = try { + val resourceWebUI: InputStream? = try { BuildConfig::class.java.getResourceAsStream("/WebUI.zip") - } catch (e: NullPointerException) { null } + } catch (e: NullPointerException) { + logger.info { "No bundled WebUI.zip found!" } + null + } if (resourceWebUI == null) { // is not bundled // download webUI zip @@ -71,18 +75,25 @@ fun setupWebUI() { val data = ByteArray(1024) webUIZipFile.outputStream().use { webUIZipFileOut -> - BufferedInputStream(URL(webUIZipURL).openStream()).use { inp -> + + val connection = URL(webUIZipURL).openConnection() as HttpURLConnection + connection.connect() + val contentLength = connection.contentLength + + connection.inputStream.buffered().use { inp -> var totalCount = 0 - var tresh = 0 + + print("Download progress: % 00") while (true) { val count = inp.read(data, 0, 1024) - totalCount += count - if (totalCount > tresh + 10 * 1024) { - tresh = totalCount - print(" *") - } + if (count == -1) break + + totalCount += count + val percentage = (totalCount.toFloat() / contentLength * 100).toInt().toString().padStart(2, '0') + print("\b\b$percentage") + webUIZipFileOut.write(data, 0, count) } println()