Compare commits

...

33 Commits

Author SHA1 Message Date
Aria Moradi 84206a7074 bump to v0.3.7
CI Publish / Validate Gradle Wrapper (push) Successful in 13s
CI Publish / Build FatJar (push) Failing after 16s
2021-05-19 03:52:55 +04:30
Aria Moradi d1500baae1 try with access token 2021-05-19 03:21:47 +04:30
Aria Moradi 045801dd1a push to Suwayomi/Tachidesk-preview 2021-05-19 02:56:46 +04:30
Aria Moradi 14a2cbc793 [SKIP CI] fix typo 2021-05-19 02:52:28 +04:30
Aria Moradi fd385017df [SKIP CI] fix typo 2021-05-19 02:50:22 +04:30
Aria Moradi 9b05954cf2 [SKIP CI] fix typo 2021-05-19 02:49:10 +04:30
Aria Moradi 6aaf636069 [SKIP CI] update for new scripts 2021-05-19 02:47:48 +04:30
Aria Moradi d30e89e5ec update workflows to include both 32-bit and 64-bit windows bundles 2021-05-19 02:42:14 +04:30
Aria Moradi 7acc745478 Merge the two windows bundlers 2021-05-19 02:31:56 +04:30
Aria Moradi 5a9a2d816e 32-bit variant of bundler 2021-05-19 02:26:29 +04:30
Aria Moradi 105f11ed02 Merge branch 'master' of github.com:Suwayomi/Tachidesk 2021-05-19 00:28:56 +04:30
Aria Moradi 3021437a05 new preview system! 2021-05-19 00:28:14 +04:30
Aria Moradi 439602fc03 [SKIP CI] no more preview 2021-05-18 23:42:43 +04:30
Aria Moradi 34e13b9589 [SKIP CI] improve wording... 2021-05-18 23:28:59 +04:30
Aria Moradi 2aab4ae918 [SKIP CI] asking for help! 2021-05-18 23:27:14 +04:30
Aria Moradi 7ef67671a4 print tachidesk info on startup 2021-05-18 22:36:41 +04:30
Syer10 e8df84416c Smarter Chapters and cleanup (#87)
* Smarter Chapters and cleanup

* Fix check
2021-05-18 22:22:15 +04:30
Aria Moradi be930bb68b update to the new scheme 2021-05-18 22:03:18 +04:30
Aria Moradi db52948865 update windows instructions 2021-05-18 21:42:30 +04:30
Aria Moradi d2a72526f6 bump to v0.3.6
CI Publish / Validate Gradle Wrapper (push) Successful in 11s
CI Publish / Build FatJar (push) Failing after 16s
2021-05-18 21:40:42 +04:30
Aria Moradi 0a9f57b32b cleanup 2021-05-18 21:38:41 +04:30
Aria Moradi 180f210536 update windows instructions 2021-05-18 21:35:57 +04:30
Aria Moradi c1baa31eed the new and simple way of packaging windows 2021-05-18 21:31:25 +04:30
Aria Moradi cacc97cec7 bump to v0.3.5
CI Publish / Validate Gradle Wrapper (push) Successful in 11s
CI Publish / Build FatJar (push) Failing after 16s
2021-05-18 02:39:00 +04:30
Aria Moradi d5691fd81c show last read page on initial load 2021-05-18 02:26:45 +04:30
Aria Moradi 49dc9fe5f6 fix wrong chapter count, abstract next page 2021-05-18 01:10:28 +04:30
Aria Moradi c0b49c7428 Merge branch 'master' of github.com:Suwayomi/Tachidesk 2021-05-18 00:45:42 +04:30
Aria Moradi fa345af42d use Dispatchers.IO 2021-05-18 00:43:32 +04:30
Aria Moradi db3cc786a1 rename the job 2021-05-18 00:43:21 +04:30
Aria Moradi fe879ae51d [SKIP CI] update windows instructions 2021-05-18 00:01:04 +04:30
Aria Moradi 2f55460ffb unzip the jre
CI Publish / Validate Gradle Wrapper (push) Successful in 14s
CI Publish / Build FatJar (push) Failing after 17s
2021-05-17 23:33:54 +04:30
Aria Moradi fbc5bd4642 bump to v0.3.4 2021-05-17 23:29:36 +04:30
Aria Moradi 5e0c7d3c9d ditch packr because it can't load extension jars 2021-05-17 23:28:23 +04:30
40 changed files with 410 additions and 235 deletions
+2 -1
View File
@@ -24,4 +24,5 @@
*.woff binary
*.pyc binary
*.swp binary
*.pdf binary
*.pdf binary
*.exe binary
+6 -8
View File
@@ -1,18 +1,16 @@
#!/bin/bash
rm -rf preview/*.jar preview/*.zip
cp master/server/build/Tachidesk-*.jar preview
cp master/server/build/Tachidesk-*.zip preview
cd preview
new_jar_build=$(ls *.jar| tail -1)
new_jar_build=$(ls Tachidesk-*.jar)
echo "last jar build file name: $new_jar_build"
cp -f $new_jar_build Tachidesk-latest.jar
rm -rf latest_pointer/*
cp $new_jar_build latest_pointer
cp ../master/server/build/Tachidesk-*.zip latest_pointer
latest=$(ls *.jar | tail -n1 | sed -e's/Tachidesk-\|.jar//g')
latest=$(echo $new_jar_build | sed -e's/Tachidesk-\|.jar//g')
echo "{ \"latest\": \"$latest\" }" > index.json
git config --global user.email "github-actions[bot]@users.noreply.github.com"
+2 -2
View File
@@ -57,12 +57,12 @@ jobs:
**/react/node_modules
key: ${{ runner.os }}-${{ hashFiles('**/react/yarn.lock') }}
- name: Build and copy webUI, Build Jar and launch4j
- name: Build and copy webUI, Build Jar
uses: eskatos/gradle-command-action@v1
with:
build-root-directory: master
wrapper-directory: master
arguments: :webUI:copyBuild :server:windowsPackage --stacktrace
arguments: :webUI:copyBuild :server:shadowJar --stacktrace
wrapper-cache-enabled: true
dependencies-cache-enabled: true
configuration-cache-enabled: true
+7 -4
View File
@@ -18,7 +18,7 @@ jobs:
uses: gradle/wrapper-validation-action@v1
build:
name: Build FatJar
name: Build artifacts and deploy preview
needs: check_wrapper
if: "!startsWith(github.event.head_commit.message, '[SKIP CI]')"
runs-on: ubuntu-latest
@@ -69,16 +69,19 @@ jobs:
dependencies-cache-enabled: true
configuration-cache-enabled: true
- name: make windows package
- name: make windows packages
run: |
cd master/scripts
./windows-bundler.sh
./windows32-bundler.sh
./windows64-bundler.sh
- name: Checkout preview branch
uses: actions/checkout@v2
with:
ref: preview
repository: 'Suwayomi/Tachidesk-preview'
ref: main
path: preview
token: ${{ secrets.DEPLOY_PREVIEW_TOKEN }}
- name: Deploy preview
run: |
+3 -2
View File
@@ -68,10 +68,11 @@ jobs:
dependencies-cache-enabled: true
configuration-cache-enabled: true
- name: make windows package
- name: make windows packages
run: |
cd master/scripts
./windows-bundler.sh
./windows32-bundler.sh
./windows64-bundler.sh
- name: Upload Release
uses: xresloader/upload-to-github-release@master
+4 -1
View File
@@ -8,4 +8,7 @@ build
server/src/main/resources/react
server/tmp/
server/tachiserver-data/
server/tachiserver-data/
# OpenJDK downlaods
OpenJDK*
-1
View File
@@ -87,7 +87,6 @@ function Dedupe($path)
}
Dedupe "AndroidCompat/src/main/java"
Dedupe "server/src/main/java"
Dedupe "server/src/main/kotlin"
Write-Output "Copying Android.jar to library folder..."
+6 -9
View File
@@ -20,7 +20,7 @@ fi
# foolproof against running from AndroidCompat dir instead of running from project root
if [ "$(basename $(pwd))" = "AndroidCompat" ]; then
if [ "$(basename "$(pwd)")" = "AndroidCompat" ]; then
cd ..
fi
@@ -59,7 +59,7 @@ zip --delete android.jar javax/*
echo "Removing java..."
zip --delete android.jar java/*
echo "Removing overriden classes..."
echo "Removing overridden classes..."
zip --delete android.jar android/app/Application.class
zip --delete android.jar android/app/Service.class
zip --delete android.jar android/net/Uri.class
@@ -68,12 +68,12 @@ zip --delete android.jar android/os/Environment.class
zip --delete android.jar android/text/format/Formatter.class
zip --delete android.jar android/text/Html.class
# Dedup overriden Android classes
# Dedup overridden Android classes
ABS_JAR="$(realpath android.jar)"
function dedup() {
pushd "$1"
CLASSES="$(find * -type f)"
echo "$CLASSES" | while read class
CLASSES="$(find ./* -type f)"
echo "$CLASSES" | while read -r class
do
NAME="${class%.*}"
echo "Processing class: $NAME"
@@ -82,13 +82,10 @@ function dedup() {
popd
}
pushd ..
popd
dedup AndroidCompat/src/main/java
dedup server/src/main/java
dedup server/src/main/kotlin
popd
popd
echo "Copying Android.jar to library folder..."
mv tmp/android.jar AndroidCompat/lib
+5 -5
View File
@@ -16,7 +16,7 @@ This structure is chosen to
- Eaise development of alternative user intefaces for Tachidesk
## User Interfaces for Tachidesk server
Currently there are three known interfaces for Tachidesk:
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.
@@ -28,7 +28,7 @@ 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)
- 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.
- 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
@@ -38,15 +38,15 @@ Run `./gradlew :webUI:copyBuild server:shadowJar`, the resulting built jar file
### 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
Run `./gradlew :server:windowsPackage` to build a server only bundle and `./gradlew :webUI:copyBuild :server:windowsPackage` to get a full bundle , the resulting built zip package file will be `server/build/Tachidesk-vX.Y.Z-rxxx-win32.zip`.
First Build the jar, then cd into the `scripts` directory and run `./windows<bits>-bundler.sh` (or `./windows<bits>-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 satistify [the prerequisites](#prerequisites)
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 opned automatically,
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.
+5 -7
View File
@@ -1,7 +1,7 @@
| Build | Stable | Preview | Support Server |
|-------|----------|---------|---------|
| ![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/raw/preview/index.json&label=download&query=$.latest&color=blue)](https://github.com/Suwayomi/Tachidesk/tree/preview/latest_pointer) | [![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/raw/preview/index.json&label=download&query=$.latest&color=blue)](https://github.com/Suwayomi/Tachidesk/tree/preview/) | [![Discord](https://img.shields.io/discord/801021177333940224.svg?label=discord&labelColor=7289da&color=2c2f33&style=flat)](https://discord.gg/DDZdqZWaHA) |
# Tachidesk
<img src="https://github.com/Suwayomi/Tachidesk/raw/master/server/src/main/resources/icon/faviconlogo.png" alt="drawing" width="200"/>
@@ -14,6 +14,8 @@ Tachidesk is as multi-platform as you can get. Any platform that runs java and/o
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:
@@ -35,19 +37,15 @@ Download the latest "Stable" jar release from [the releases section](https://git
Double click on the jar file or run `java -jar Tachidesk-vX.Y.Z-rxxx.jar` (or `java -jar Tachidesk-latest.jar` if you have the latest preview) from a Terminal/Command Prompt window to run the app which will open a new browser window automatically. Also the System Tray Icon is your friend if you need to open the browser window again or close Tachidesk.
### Windows
Download the latest win32 release from [the releases section](https://github.com/Suwayomi/Tachidesk/releases).
Download the latest win32 or win64 (depending on your system, usually you want win64) release from [the releases section](https://github.com/Suwayomi/Tachidesk/releases).
The Windows specific build has java bundled inside, so you don't have to install java to use it. Unzip `Tachidesk-vX.Y.Z-rxxx-win32.zip` and run `server.exe`. The rest works like the previous section.
The Windows specific build has java bundled inside, so you don't have to install java to use it. Unzip `Tachidesk-vX.Y.Z-rxxx-win64.zip` and run `Tachidesk Launcher.exe` or `Tachidesk Launcher.bat`. The rest works like the previous section.
### Arch Linux
You can install Tachidesk from the AUR
```
yay -S tachidesk
```
Or the latest preview version
```
yay -S tachidesk-preview
```
### Docker
Check [arbuilder's repo](https://github.com/arbuilder/Tachidesk-docker) out for more details and the dockerfile.
Binary file not shown.
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
start "" jre/bin/javaw -jar Tachidesk.jar
+5
View File
@@ -0,0 +1,5 @@
#include <stdlib.h>
int main() {
system("start jre\\bin\\javaw -jar Tachidesk.jar");
}
+3
View File
@@ -0,0 +1,3 @@
# Building `Tachidesk Launcher.exe`
1. compile `Tachidesk Launcher.c` statically using GCC MinGW: `gcc -o "Tachidesk Launcher.exe" "Tachidesk Launcher.c"`
2. Add `server/src/main/resources/icon/faviconlogo.ico` into the exe with `rcedit` from the electron project: `rcedit "Tachidesk Launcher.exe" --set-icon faviconlogo.ico`
-41
View File
@@ -1,41 +0,0 @@
#!/bin/bash
# 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/.
echo "Downloading packr jar..."
packr="packr-all-4.0.0.jar"
curl -L "https://github.com/libgdx/packr/releases/download/4.0.0/packr-all-4.0.0.jar" -o $packr
echo "Downloading jre..."
jre="OpenJDK8U-jre_x64_windows_hotspot_8u292b10.zip"
curl -L "https://github.com/AdoptOpenJDK/openjdk8-binaries/releases/download/jdk8u292-b10/OpenJDK8U-jre_x64_windows_hotspot_8u292b10.zip" -o $jre
echo "creating windows bundle"
jar=$(ls ../server/build/Tachidesk-*.jar)
jar_name=$(echo $jar | cut -d'/' -f4)
release_name=$(echo $jar_name | cut -d'.' -f4 --complement)-win64
cp $jar "Tachidesk.jar"
java -jar $packr \
--platform windows64 \
--jdk $jre \
--executable Tachidesk \
--classpath Tachidesk.jar \
--mainclass ir.armor.tachidesk.MainKt \
--vmargs Xmx4G \
--output $release_name
cp resources/Tachidesk-debug.bat $release_name
zip_name=$release_name.zip
zip -9 -r $zip_name $release_name
cp $zip_name ../server/build/
+38
View File
@@ -0,0 +1,38 @@
# 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/.
Write-Output "Downloading jre..."
$jre="OpenJDK8U-jre_x86-32_windows_hotspot_8u292b10.zip"
if (!(Test-Path $jre)) {
Invoke-WebRequest -Uri "https://github.com/AdoptOpenJDK/openjdk8-binaries/releases/download/jdk8u292-b10/OpenJDK8U-jre_x86-32_windows_hotspot_8u292b10.zip" -OutFile $jre -UseBasicParsing
}
Write-Output "creating windows bundle"
$jar=$(Get-ChildItem ../server/build/Tachidesk-*.jar)
$release_name=$jar.BaseName + "-win32"
# make release dir
New-Item -ItemType Directory $release_name
Expand-Archive $jre -DestinationPath "./" -ErrorAction SilentlyContinue
# move jre
Move-Item "jdk8u292-b10-jre" "$release_name/jre"
Copy-Item $jar.FullName "$release_name/Tachidesk.jar"
Copy-Item "resources/Tachidesk Launcher-win32.exe" $release_name
Copy-Item "resources/Tachidesk Launcher.bat" $release_name
Copy-Item "resources/Tachidesk Debug Launcher.bat" $release_name
$zip_name="$release_name.zip"
Compress-Archive -CompressionLevel Optimal -DestinationPath $zip_name -Path $release_name -Force -ErrorAction SilentlyContinue
Remove-Item -Force -Recurse $release_name
Move-Item $zip_name "../server/build/" -ErrorAction SilentlyContinue
+41
View File
@@ -0,0 +1,41 @@
#!/bin/bash
# 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/.
echo "Downloading jre..."
jre="OpenJDK8U-jre_x86-32_windows_hotspot_8u292b10.zip"
if [ ! -f $jre ]; then
curl -L "https://github.com/AdoptOpenJDK/openjdk8-binaries/releases/download/jdk8u292-b10/OpenJDK8U-jre_x86-32_windows_hotspot_8u292b10.zip" -o $jre
fi
echo "creating windows bundle"
jar=$(ls ../server/build/Tachidesk-*.jar)
jar_name=$(echo $jar | cut -d'/' -f4)
release_name=$(echo $jar_name | cut -d'.' -f4 --complement)-win32
# make release dir
mkdir $release_name
unzip $jre
# move jre
mv jdk8u292-b10-jre $release_name/jre
cp $jar $release_name/Tachidesk.jar
cp "resources/Tachidesk Launcher-win32.exe" "$release_name/Tachidesk Launcher.exe"
cp "resources/Tachidesk Launcher.bat" $release_name
cp "resources/Tachidesk Debug Launcher.bat" $release_name
zip_name=$release_name.zip
zip -9 -r $zip_name $release_name
rm -rf $release_name
mv $zip_name ../server/build/
+38
View File
@@ -0,0 +1,38 @@
# 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/.
Write-Output "Downloading jre..."
$jre="OpenJDK8U-jre_x64_windows_hotspot_8u292b10.zip"
if (!(Test-Path $jre)) {
Invoke-WebRequest -Uri "https://github.com/AdoptOpenJDK/openjdk8-binaries/releases/download/jdk8u292-b10/OpenJDK8U-jre_x64_windows_hotspot_8u292b10.zip" -OutFile $jre -UseBasicParsing
}
Write-Output "creating windows bundle"
$jar=$(Get-ChildItem ../server/build/Tachidesk-*.jar)
$release_name=$jar.BaseName + "-win64"
# make release dir
New-Item -ItemType Directory $release_name
Expand-Archive $jre -DestinationPath "./" -ErrorAction SilentlyContinue
# move jre
Move-Item "jdk8u292-b10-jre" "$release_name/jre"
Copy-Item $jar.FullName "$release_name/Tachidesk.jar"
Copy-Item "resources/Tachidesk Launcher-win64.exe" $release_name
Copy-Item "resources/Tachidesk Launcher.bat" $release_name
Copy-Item "resources/Tachidesk Debug Launcher.bat" $release_name
$zip_name="$release_name.zip"
Compress-Archive -CompressionLevel Optimal -DestinationPath $zip_name -Path $release_name -Force -ErrorAction SilentlyContinue
Remove-Item -Force -Recurse $release_name
Move-Item $zip_name "../server/build/" -ErrorAction SilentlyContinue
+41
View File
@@ -0,0 +1,41 @@
#!/bin/bash
# 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/.
echo "Downloading jre..."
jre="OpenJDK8U-jre_x64_windows_hotspot_8u292b10.zip"
if [ ! -f $jre ]; then
curl -L "https://github.com/AdoptOpenJDK/openjdk8-binaries/releases/download/jdk8u292-b10/OpenJDK8U-jre_x64_windows_hotspot_8u292b10.zip" -o $jre
fi
echo "creating windows bundle"
jar=$(ls ../server/build/Tachidesk-*.jar)
jar_name=$(echo $jar | cut -d'/' -f4)
release_name=$(echo $jar_name | cut -d'.' -f4 --complement)-win64
# make release dir
mkdir $release_name
unzip $jre
# move jre
mv jdk8u292-b10-jre $release_name/jre
cp $jar $release_name/Tachidesk.jar
cp "resources/Tachidesk Launcher-win64.exe" "$release_name/Tachidesk Launcher.exe"
cp "resources/Tachidesk Launcher.bat" $release_name
cp "resources/Tachidesk Debug Launcher.bat" $release_name
zip_name=$release_name.zip
zip -9 -r $zip_name $release_name
rm -rf $release_name
mv $zip_name ../server/build/
+4 -19
View File
@@ -8,7 +8,6 @@ plugins {
application
id("com.github.johnrengelman.shadow") version "7.0.0"
id("org.jmailen.kotlinter") version "3.4.3"
id("edu.sc.seis.launch4j") version "2.5.0"
id("de.fuerstenau.buildconfig") version "1.1.8"
}
@@ -97,7 +96,7 @@ sourceSets {
}
// should be bumped with each stable release
val tachideskVersion = "v0.3.3"
val tachideskVersion = "v0.3.7"
// counts commit count on master
val tachideskRevision = Runtime
@@ -126,18 +125,8 @@ buildConfig {
buildConfigField("boolean", "debug", project.hasProperty("debugApp").toString())
}
launch4j { //used for windows
mainClassName = MainClass
bundledJrePath = "jre"
bundledJre64Bit = true
jreMinVersion = "8"
outputDir = "${rootProject.name}-$tachideskVersion-$tachideskRevision-win64"
icon = "${projectDir}/src/main/resources/icon/faviconlogo.ico"
jar = "${projectDir}/build/${rootProject.name}-$tachideskVersion-$tachideskRevision.jar"
}
tasks {
jar {
shadowJar {
manifest {
attributes(
mapOf(
@@ -149,9 +138,6 @@ tasks {
)
)
}
}
shadowJar {
manifest.inheritFrom(jar.get().manifest) //will make your shadowJar (produced by jar task) runnable
archiveBaseName.set(rootProject.name)
archiveVersion.set(tachideskVersion)
archiveClassifier.set(tachideskRevision)
@@ -165,11 +151,11 @@ tasks {
)
}
}
test {
useJUnit()
}
withType<ShadowJar> {
destinationDirectory.set(File("$rootDir/server/build"))
dependsOn("formatKotlin", "lintKotlin")
@@ -192,4 +178,3 @@ tasks {
source(files("src"))
}
}
@@ -22,102 +22,110 @@ import org.jetbrains.exposed.sql.and
import org.jetbrains.exposed.sql.deleteWhere
import org.jetbrains.exposed.sql.insert
import org.jetbrains.exposed.sql.select
import org.jetbrains.exposed.sql.selectAll
import org.jetbrains.exposed.sql.transactions.transaction
import org.jetbrains.exposed.sql.update
object Chapter {
/** get chapter list when showing a manga */
suspend fun getChapterList(mangaId: Int, onlineFetch: Boolean): List<ChapterDataClass> {
return if (!onlineFetch) {
suspend fun getChapterList(mangaId: Int, onlineFetch: Boolean?): List<ChapterDataClass> {
return if (onlineFetch == true) {
getSourceChapters(mangaId)
} else {
transaction {
ChapterTable.select { ChapterTable.manga eq mangaId }.orderBy(ChapterTable.chapterIndex to DESC)
.map {
ChapterTable.toDataClass(it)
}
}.ifEmpty {
// If it was explicitly set to offline dont grab chapters
if (onlineFetch == null) {
getSourceChapters(mangaId)
} else emptyList()
}
} else {
}
}
val mangaDetails = getManga(mangaId)
val source = getHttpSource(mangaDetails.sourceId.toLong())
val chapterList = source.fetchChapterList(
SManga.create().apply {
title = mangaDetails.title
url = mangaDetails.url
}
).awaitSingle()
private suspend fun getSourceChapters(mangaId: Int): List<ChapterDataClass> {
val mangaDetails = getManga(mangaId)
val source = getHttpSource(mangaDetails.sourceId.toLong())
val chapterList = source.fetchChapterList(
SManga.create().apply {
title = mangaDetails.title
url = mangaDetails.url
}
).awaitSingle()
val chapterCount = chapterList.count()
val chapterCount = chapterList.count()
transaction {
chapterList.reversed().forEachIndexed { index, fetchedChapter ->
val chapterEntry = ChapterTable.select { ChapterTable.url eq fetchedChapter.url }.firstOrNull()
if (chapterEntry == null) {
ChapterTable.insert {
it[url] = fetchedChapter.url
it[name] = fetchedChapter.name
it[date_upload] = fetchedChapter.date_upload
it[chapter_number] = fetchedChapter.chapter_number
it[scanlator] = fetchedChapter.scanlator
transaction {
chapterList.reversed().forEachIndexed { index, fetchedChapter ->
val chapterEntry = ChapterTable.select { ChapterTable.url eq fetchedChapter.url }.firstOrNull()
if (chapterEntry == null) {
ChapterTable.insert {
it[url] = fetchedChapter.url
it[name] = fetchedChapter.name
it[date_upload] = fetchedChapter.date_upload
it[chapter_number] = fetchedChapter.chapter_number
it[scanlator] = fetchedChapter.scanlator
it[chapterIndex] = index + 1
it[manga] = mangaId
}
} else {
ChapterTable.update({ ChapterTable.url eq fetchedChapter.url }) {
it[name] = fetchedChapter.name
it[date_upload] = fetchedChapter.date_upload
it[chapter_number] = fetchedChapter.chapter_number
it[scanlator] = fetchedChapter.scanlator
it[chapterIndex] = index + 1
it[manga] = mangaId
}
} else {
ChapterTable.update({ ChapterTable.url eq fetchedChapter.url }) {
it[name] = fetchedChapter.name
it[date_upload] = fetchedChapter.date_upload
it[chapter_number] = fetchedChapter.chapter_number
it[scanlator] = fetchedChapter.scanlator
it[chapterIndex] = index + 1
it[manga] = mangaId
}
it[chapterIndex] = index + 1
it[manga] = mangaId
}
}
}
}
// clear any orphaned chapters that are in the db but not in `chapterList`
val dbChapterCount = transaction { ChapterTable.select { ChapterTable.manga eq mangaId }.count() }
if (dbChapterCount > chapterCount) { // we got some clean up due
val dbChapterList = transaction { ChapterTable.select { ChapterTable.manga eq mangaId } }
// clear any orphaned chapters that are in the db but not in `chapterList`
val dbChapterCount = transaction { ChapterTable.select { ChapterTable.manga eq mangaId }.count() }
if (dbChapterCount > chapterCount) { // we got some clean up due
val dbChapterList = transaction { ChapterTable.select { ChapterTable.manga eq mangaId } }
dbChapterList.forEach {
if (it[ChapterTable.chapterIndex] >= chapterList.size ||
chapterList[it[ChapterTable.chapterIndex] - 1].url != it[ChapterTable.url]
) {
transaction {
PageTable.deleteWhere { PageTable.chapter eq it[ChapterTable.id] }
ChapterTable.deleteWhere { ChapterTable.id eq it[ChapterTable.id] }
}
dbChapterList.forEach {
if (it[ChapterTable.chapterIndex] >= chapterList.size ||
chapterList[it[ChapterTable.chapterIndex] - 1].url != it[ChapterTable.url]
) {
transaction {
PageTable.deleteWhere { PageTable.chapter eq it[ChapterTable.id] }
ChapterTable.deleteWhere { ChapterTable.id eq it[ChapterTable.id] }
}
}
}
}
val dbChapterMap = transaction {
ChapterTable.select { ChapterTable.manga eq mangaId }
.associateBy({ it[ChapterTable.url] }, { it })
}
val dbChapterMap = transaction {
ChapterTable.select { ChapterTable.manga eq mangaId }
.associateBy({ it[ChapterTable.url] }, { it })
}
return chapterList.mapIndexed { index, it ->
return chapterList.mapIndexed { index, it ->
val dbChapter = dbChapterMap.getValue(it.url)
val dbChapter = dbChapterMap.getValue(it.url)
ChapterDataClass(
it.url,
it.name,
it.date_upload,
it.chapter_number,
it.scanlator,
mangaId,
ChapterDataClass(
it.url,
it.name,
it.date_upload,
it.chapter_number,
it.scanlator,
mangaId,
dbChapter[ChapterTable.isRead],
dbChapter[ChapterTable.isBookmarked],
dbChapter[ChapterTable.lastPageRead],
dbChapter[ChapterTable.isRead],
dbChapter[ChapterTable.isBookmarked],
dbChapter[ChapterTable.lastPageRead],
chapterCount - index,
)
}
chapterCount - index,
chapterList.size
)
}
}
@@ -126,9 +134,9 @@ object Chapter {
val chapterEntry = transaction {
ChapterTable.select {
(ChapterTable.chapterIndex eq chapterIndex) and (ChapterTable.manga eq mangaId)
}.firstOrNull()!!
}.first()
}
val mangaEntry = transaction { MangaTable.select { MangaTable.id eq mangaId }.firstOrNull()!! }
val mangaEntry = transaction { MangaTable.select { MangaTable.id eq mangaId }.first() }
val source = getHttpSource(mangaEntry[MangaTable.sourceReference])
val pageList = source.fetchPageList(
@@ -139,7 +147,7 @@ object Chapter {
).awaitSingle()
val chapterId = chapterEntry[ChapterTable.id].value
val chapterCount = transaction { ChapterTable.selectAll().count() }
val chapterCount = transaction { ChapterTable.select { ChapterTable.manga eq mangaId }.count() }
// update page list for this chapter
transaction {
@@ -159,7 +159,7 @@ object Extension {
it[this.classFQName] = className
}
val extensionId = ExtensionTable.select { ExtensionTable.pkgName eq pkgName }.firstOrNull()!![ExtensionTable.id].value
val extensionId = ExtensionTable.select { ExtensionTable.pkgName eq pkgName }.first()[ExtensionTable.id].value
sources.forEach { httpSource ->
SourceTable.insert {
@@ -195,7 +195,7 @@ object Extension {
fun uninstallExtension(pkgName: String) {
logger.debug("Uninstalling $pkgName")
val extensionRecord = transaction { ExtensionTable.select { ExtensionTable.pkgName eq pkgName }.firstOrNull()!! }
val extensionRecord = transaction { ExtensionTable.select { ExtensionTable.pkgName eq pkgName }.first() }
val fileNameWithoutType = extensionRecord[ExtensionTable.apkName].substringBefore(".apk")
val jarPath = "${applicationDirs.extensionsRoot}/$fileNameWithoutType.jar"
transaction {
@@ -234,7 +234,7 @@ object Extension {
}
suspend fun getExtensionIcon(apkName: String): Pair<InputStream, String> {
val iconUrl = transaction { ExtensionTable.select { ExtensionTable.apkName eq apkName }.firstOrNull()!! }[ExtensionTable.iconUrl]
val iconUrl = transaction { ExtensionTable.select { ExtensionTable.apkName eq apkName }.first() }[ExtensionTable.iconUrl]
val saveDir = "${applicationDirs.extensionsRoot}/icon"
@@ -37,7 +37,7 @@ object Manga {
}
suspend fun getManga(mangaId: Int, onlineFetch: Boolean = false): MangaDataClass {
var mangaEntry = transaction { MangaTable.select { MangaTable.id eq mangaId }.firstOrNull()!! }
var mangaEntry = transaction { MangaTable.select { MangaTable.id eq mangaId }.first() }
return if (mangaEntry[MangaTable.initialized] && !onlineFetch) {
MangaDataClass(
@@ -78,14 +78,14 @@ object Manga {
it[MangaTable.description] = truncate(fetchedManga.description, 4096)
it[MangaTable.genre] = fetchedManga.genre
it[MangaTable.status] = fetchedManga.status
if (fetchedManga.thumbnail_url != null && fetchedManga.thumbnail_url!!.isNotEmpty())
if (fetchedManga.thumbnail_url != null && fetchedManga.thumbnail_url.orEmpty().isNotEmpty())
it[MangaTable.thumbnail_url] = fetchedManga.thumbnail_url
}
}
clearMangaThumbnail(mangaId)
mangaEntry = transaction { MangaTable.select { MangaTable.id eq mangaId }.firstOrNull()!! }
mangaEntry = transaction { MangaTable.select { MangaTable.id eq mangaId }.first() }
MangaDataClass(
mangaId,
@@ -117,7 +117,7 @@ object Manga {
return getCachedImageResponse(saveDir, fileName) {
getManga(mangaId) // make sure is initialized
val mangaEntry = transaction { MangaTable.select { MangaTable.id eq mangaId }.firstOrNull()!! }
val mangaEntry = transaction { MangaTable.select { MangaTable.id eq mangaId }.first() }
val sourceId = mangaEntry[MangaTable.sourceReference]
val source = getHttpSource(sourceId)
@@ -130,7 +130,7 @@ object Manga {
}
}
suspend fun clearMangaThumbnail(mangaId: Int) {
private fun clearMangaThumbnail(mangaId: Int) {
val saveDir = applicationDirs.thumbnailsRoot
val fileName = mangaId.toString()
@@ -40,7 +40,7 @@ object MangaList {
val mangasPage = this
val mangaList = transaction {
return@transaction mangasPage.mangas.map { manga ->
var mangaEntry = MangaTable.select { MangaTable.url eq manga.url }.firstOrNull()
val mangaEntry = MangaTable.select { MangaTable.url eq manga.url }.firstOrNull()
if (mangaEntry == null) { // create manga entry
val mangaId = MangaTable.insertAndGetId {
it[url] = manga.url
@@ -40,16 +40,16 @@ object Page {
}
suspend fun getPageImage(mangaId: Int, chapterIndex: Int, index: Int): Pair<InputStream, String> {
val mangaEntry = transaction { MangaTable.select { MangaTable.id eq mangaId }.firstOrNull()!! }
val mangaEntry = transaction { MangaTable.select { MangaTable.id eq mangaId }.first() }
val source = getHttpSource(mangaEntry[MangaTable.sourceReference])
val chapterEntry = transaction {
ChapterTable.select {
(ChapterTable.chapterIndex eq chapterIndex) and (ChapterTable.manga eq mangaId)
}.firstOrNull()!!
}.first()
}
val chapterId = chapterEntry[ChapterTable.id].value
val pageEntry = transaction { PageTable.select { (PageTable.chapter eq chapterId) and (PageTable.index eq index) }.firstOrNull()!! }
val pageEntry = transaction { PageTable.select { (PageTable.chapter eq chapterId) and (PageTable.index eq index) }.first() }
val tachiPage = Page(
pageEntry[PageTable.index],
@@ -78,11 +78,11 @@ object Page {
// TODO: rewrite this to match tachiyomi
private val applicationDirs by DI.global.instance<ApplicationDirs>()
fun getChapterDir(mangaId: Int, chapterId: Int): String {
val mangaEntry = transaction { MangaTable.select { MangaTable.id eq mangaId }.firstOrNull()!! }
val mangaEntry = transaction { MangaTable.select { MangaTable.id eq mangaId }.first() }
val sourceId = mangaEntry[MangaTable.sourceReference]
val source = getHttpSource(sourceId)
val sourceEntry = transaction { SourceTable.select { SourceTable.id eq sourceId }.firstOrNull()!! }
val chapterEntry = transaction { ChapterTable.select { ChapterTable.id eq chapterId }.firstOrNull()!! }
val sourceEntry = transaction { SourceTable.select { SourceTable.id eq sourceId }.first() }
val chapterEntry = transaction { ChapterTable.select { ChapterTable.id eq chapterId }.first() }
val chapterDir = when {
chapterEntry[ChapterTable.scanlator] != null -> "${chapterEntry[ChapterTable.scanlator]}_${chapterEntry[ChapterTable.name]}"
@@ -198,7 +198,7 @@ object LegacyBackupImport : LegacyBackupBase() {
it[description] = fetchedManga.description
it[genre] = fetchedManga.genre
it[status] = fetchedManga.status
if (fetchedManga.thumbnail_url != null && fetchedManga.thumbnail_url!!.isNotEmpty())
if (fetchedManga.thumbnail_url != null && fetchedManga.thumbnail_url.orEmpty().isNotEmpty())
it[MangaTable.thumbnail_url] = fetchedManga.thumbnail_url
}
}
@@ -10,7 +10,6 @@ package ir.armor.tachidesk.impl.util
import okhttp3.Response
import okio.buffer
import okio.sink
import java.io.BufferedInputStream
import java.io.File
import java.io.FileInputStream
import java.io.InputStream
@@ -19,12 +18,12 @@ import java.nio.file.Paths
object CachedImageResponse {
private fun pathToInputStream(path: String): InputStream {
return BufferedInputStream(FileInputStream(path))
return FileInputStream(path).buffered()
}
private fun findFileNameStartingWith(directoryPath: String, fileName: String): String? {
val target = "$fileName."
File(directoryPath).listFiles().forEach { file ->
File(directoryPath).listFiles().orEmpty().forEach { file ->
if (file.name.startsWith(target))
return "$directoryPath/${file.name}"
}
@@ -57,16 +56,13 @@ object CachedImageResponse {
}
}
}
return Pair(
pathToInputStream(fullPath),
contentType
)
return pathToInputStream(fullPath) to contentType
} else {
throw Exception("request error! ${response.code}")
}
}
suspend fun clearCachedImage(saveDir: String, fileName: String) {
fun clearCachedImage(saveDir: String, fileName: String) {
val cachedFile = findFileNameStartingWith(saveDir, fileName)
cachedFile?.also {
File(it).delete()
@@ -32,12 +32,12 @@ object GetHttpSource {
}
val sourceRecord = transaction {
SourceTable.select { SourceTable.id eq sourceId }.firstOrNull()!!
SourceTable.select { SourceTable.id eq sourceId }.first()
}
val extensionId = sourceRecord[SourceTable.extension]
val extensionRecord = transaction {
ExtensionTable.select { ExtensionTable.id eq extensionId }.firstOrNull()!!
ExtensionTable.select { ExtensionTable.id eq extensionId }.first()
}
val apkName = extensionRecord[ExtensionTable.apkName]
@@ -11,6 +11,7 @@ import kotlinx.coroutines.suspendCancellableCoroutine
import okhttp3.Call
import okhttp3.Callback
import okhttp3.Response
import okhttp3.internal.closeQuietly
import java.io.IOException
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
@@ -26,7 +27,9 @@ suspend fun Call.await(): Response {
return
}
continuation.resume(response)
continuation.resume(response) {
response.body?.closeQuietly()
}
}
override fun onFailure(call: Call, e: IOException) {
@@ -71,12 +71,14 @@ object PackageTools {
if (handler.hasException()) {
val errorFile: Path = File(applicationDirs.extensionsRoot).toPath().resolve("$fileNameWithoutType-error.txt")
logger.error(
"Detail Error Information in File $errorFile\n" +
"Please report this file to one of following link if possible (any one).\n" +
" https://sourceforge.net/p/dex2jar/tickets/\n" +
" https://bitbucket.org/pxb1988/dex2jar/issues\n" +
" https://github.com/pxb1988/dex2jar/issues\n" +
" dex2jar@googlegroups.com"
"""
Detail Error Information in File $errorFile
Please report this file to one of following link if possible (any one).
https://sourceforge.net/p/dex2jar/tickets/
https://bitbucket.org/pxb1988/dex2jar/issues
https://github.com/pxb1988/dex2jar/issues
dex2jar@googlegroups.com
""".trimIndent()
)
handler.dump(errorFile, emptyArray<String>())
}
@@ -98,18 +100,21 @@ object PackageTools {
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
)
}
appTag?.childNodes?.toList()
.orEmpty()
.asSequence()
.filter {
it.nodeType == Node.ELEMENT_NODE
}.map {
it as Element
}.filter {
it.tagName == "meta-data"
}.forEach {
putString(
it.attributes.getNamedItem("android:name").nodeValue,
it.attributes.getNamedItem("android:value").nodeValue
)
}
}
signatures = (
@@ -25,7 +25,7 @@ data class ChapterDataClass(
val lastPageRead: Int,
/** this chapter's index, starts with 1 */
val index: Int? = null,
val index: Int,
/** total chapter count, used to calculate if there's a next and prev chapter */
val chapterCount: Int? = null,
@@ -36,14 +36,14 @@ import ir.armor.tachidesk.impl.backup.legacy.LegacyBackupImport.restoreLegacyBac
import ir.armor.tachidesk.server.internal.About.getAbout
import ir.armor.tachidesk.server.util.openInBrowser
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.asCoroutineDispatcher
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.future.future
import mu.KotlinLogging
import java.io.IOException
import java.text.SimpleDateFormat
import java.util.Date
import java.util.concurrent.CompletableFuture
import java.util.concurrent.Executors
import kotlin.concurrent.thread
/*
@@ -56,7 +56,7 @@ import kotlin.concurrent.thread
object JavalinSetup {
private val logger = KotlinLogging.logger {}
private val scope = CoroutineScope(Executors.newFixedThreadPool(200).asCoroutineDispatcher())
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
private fun <T> future(block: suspend CoroutineScope.() -> T): CompletableFuture<T> {
return scope.future(block = block)
@@ -96,7 +96,10 @@ object JavalinSetup {
logger.error("NullPointerException while handling the request", e)
ctx.status(404)
}
app.exception(NoSuchElementException::class.java) { e, ctx ->
logger.error("NoSuchElementException while handling the request", e)
ctx.status(404)
}
app.exception(IOException::class.java) { e, ctx ->
logger.error("IOException while handling the request", e)
ctx.status(500)
@@ -257,7 +260,7 @@ object JavalinSetup {
app.get("/api/v1/manga/:mangaId/chapters") { ctx ->
val mangaId = ctx.pathParam("mangaId").toInt()
val onlineFetch = ctx.queryParam("onlineFetch", "false").toBoolean()
val onlineFetch = ctx.queryParam("onlineFetch")?.toBoolean()
ctx.json(future { getChapterList(mangaId, onlineFetch) })
}
@@ -41,6 +41,8 @@ val systemTray by lazy { systemTray() }
val androidCompat by lazy { AndroidCompat() }
fun applicationSetup() {
logger.info("Running Tachidesk ${BuildConfig.version} revision ${BuildConfig.revision}")
// Application dirs
val applicationDirs = ApplicationDirs()
DI.global.addImport(
+11 -7
View File
@@ -60,11 +60,13 @@ function LazyImage(props: IProps) {
};
useEffect(() => {
window.addEventListener('scroll', handleScroll);
if (settings.readerType === 'Webtoon' || settings.readerType === 'ContinuesVertical') {
window.addEventListener('scroll', handleScroll);
return () => {
window.removeEventListener('scroll', handleScroll);
};
return () => {
window.removeEventListener('scroll', handleScroll);
};
} return () => {};
}, [handleScroll]);
useEffect(() => {
@@ -92,14 +94,14 @@ function LazyImage(props: IProps) {
);
}
export default function Page(props: IProps) {
const Page = React.forwardRef((props: IProps, ref: any) => {
const {
src, index, setCurPage, settings,
} = props;
const classes = useStyles(settings)();
return (
<div style={{ margin: '0 auto' }}>
<div ref={ref} style={{ margin: '0 auto' }}>
<LazyImage
src={src}
index={index}
@@ -108,4 +110,6 @@ export default function Page(props: IProps) {
/>
</div>
);
}
});
export default Page;
@@ -24,7 +24,7 @@ const useStyles = makeStyles({
export default function PagedReader(props: IReaderProps) {
const {
pages, settings, setCurPage, curPage, manga, chapter,
pages, settings, setCurPage, curPage, manga, chapter, nextChapter,
} = props;
const classes = useStyles();
@@ -36,7 +36,7 @@ export default function PagedReader(props: IReaderProps) {
if (curPage < pages.length - 1) {
setCurPage(curPage + 1);
} else if (settings.loadNextonEnding) {
history.push(`/manga/${manga.id}/chapter/${chapter.index + 1}`);
nextChapter();
}
}
@@ -7,7 +7,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
import { makeStyles } from '@material-ui/core/styles';
import React, { useEffect } from 'react';
import React, { useEffect, useRef, useState } from 'react';
import { useHistory } from 'react-router-dom';
import Page from '../Page';
@@ -23,16 +23,18 @@ const useStyles = makeStyles({
export default function VerticalReader(props: IReaderProps) {
const {
pages, settings, setCurPage, curPage, manga, chapter,
pages, settings, setCurPage, curPage, manga, chapter, nextChapter,
} = props;
const classes = useStyles();
const history = useHistory();
const [initialScroll, setInitialScroll] = useState(-1);
const initialPageRef = useRef<HTMLDivElement>(null);
const handleLoadNextonEnding = () => {
if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight) {
setCurPage(0);
history.push(`/manga/${manga.id}/chapter/${chapter.index + 1}`);
nextChapter();
}
};
useEffect(() => {
@@ -43,6 +45,18 @@ export default function VerticalReader(props: IReaderProps) {
};
}, []);
useEffect(() => {
if ((chapter as IChapter).lastPageRead > -1) {
setInitialScroll((chapter as IChapter).lastPageRead);
}
}, []);
useEffect(() => {
if (initialScroll > -1) {
initialPageRef.current?.scrollIntoView();
}
}, [initialScroll, initialPageRef.current]);
return (
<div className={classes.reader}>
{
@@ -53,6 +67,7 @@ export default function VerticalReader(props: IReaderProps) {
src={page.src}
setCurPage={setCurPage}
settings={settings}
ref={page.index === initialScroll ? initialPageRef : null}
/>
))
}
+29 -2
View File
@@ -9,7 +9,7 @@
import CircularProgress from '@material-ui/core/CircularProgress';
import { makeStyles } from '@material-ui/core/styles';
import React, { useContext, useEffect, useState } from 'react';
import { useParams } from 'react-router-dom';
import { useHistory, useParams } from 'react-router-dom';
import HorizontalPager from '../components/reader/pager/HorizontalPager';
import Page from '../components/reader/Page';
import PageNumber from '../components/reader/PageNumber';
@@ -63,6 +63,7 @@ export default function Reader() {
const [settings, setSettings] = useLocalStorage<IReaderSettings>('readerSettings', defaultReaderSettings);
const classes = useStyles(settings)();
const history = useHistory();
const [serverAddress] = useLocalStorage<String>('serverBaseURL', '');
@@ -117,14 +118,28 @@ export default function Reader() {
useEffect(() => {
setChapter(initialChapter);
setCurPage(0);
client.get(`/api/v1/manga/${mangaId}/chapter/${chapterIndex}`)
.then((response) => response.data)
.then((data:IChapter) => {
setChapter(data);
setCurPage(data.lastPageRead);
});
}, [chapterIndex]);
useEffect(() => {
if (curPage !== -1) {
const formData = new FormData();
formData.append('lastPageRead', curPage.toString());
client.patch(`/api/v1/manga/${manga.id}/chapter/${chapter.index}`, formData);
}
if (curPage === chapter.pageCount - 1) {
const formDataRead = new FormData();
formDataRead.append('read', 'true');
client.patch(`/api/v1/manga/${manga.id}/chapter/${chapter.index}`, formDataRead);
}
}, [curPage]);
if (chapter.pageCount === -1) {
return (
<div className={classes.loading}>
@@ -133,6 +148,17 @@ export default function Reader() {
);
}
const nextChapter = () => {
if (chapter.index < chapter.chapterCount) {
const formData = new FormData();
formData.append('lastPageRead', `${chapter.pageCount - 1}`);
formData.append('read', 'true');
client.patch(`/api/v1/manga/${manga.id}/chapter/${chapter.index}`, formData);
history.push(`/manga/${manga.id}/chapter/${chapter.index + 1}`);
}
};
const pages = range(chapter.pageCount).map((index) => ({
index,
src: `${serverAddress}/api/v1/manga/${mangaId}/chapter/${chapterIndex}/page/${index}`,
@@ -155,6 +181,7 @@ export default function Reader() {
settings={settings}
manga={manga}
chapter={chapter}
nextChapter={nextChapter}
/>
</div>
);
+1
View File
@@ -116,4 +116,5 @@ interface IReaderProps {
settings: IReaderSettings
manga: IMangaCard | IManga
chapter: IChapter | IPartialChpter
nextChapter: () => void
}