mirror of
https://github.com/Suwayomi/Suwayomi-Server.git
synced 2026-07-03 10:54:38 -05:00
Compare commits
42 Commits
renovate/g
...
e4440ad502
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e4440ad502 | ||
|
|
e71c94547d | ||
|
|
84a1789850 | ||
|
|
70a027f6f0 | ||
|
|
650c075723 | ||
|
|
a69e29d1a5 | ||
|
|
eec0951a75 | ||
|
|
4ace76f508 | ||
|
|
cd91b6e6ef | ||
|
|
f748bc7f6d | ||
|
|
11ff4bb280 | ||
|
|
388586f23b | ||
|
|
b8ffbebc76 | ||
|
|
3048df307d | ||
|
|
3b3770cb3d | ||
|
|
9667aeba18 | ||
|
|
6c8a024b0f | ||
|
|
5b2613dad3 | ||
|
|
396cfa734a | ||
|
|
a1fdf6d77a | ||
|
|
07ae17105b | ||
|
|
b8772f60bf | ||
|
|
733b9c9919 | ||
|
|
0b0c056bcb | ||
|
|
aff95bfc37 | ||
|
|
00bc3e39b6 | ||
|
|
e9c2cc49a6 | ||
|
|
ea310ba54b | ||
|
|
72347f45cc | ||
|
|
1e73e526c6 | ||
|
|
8fd0fdba08 | ||
|
|
4b61d375ed | ||
|
|
3cf4cf6cf8 | ||
|
|
74ade8a3a3 | ||
|
|
3bb2e4329e | ||
|
|
33ec15c136 | ||
|
|
3a78453a02 | ||
|
|
b7c259a4cb | ||
|
|
41ef220a0b | ||
|
|
85fe9802e2 | ||
|
|
676aed14c0 | ||
|
|
ceac5f74c4 |
6
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
6
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -42,7 +42,7 @@ body:
|
||||
label: Suwayomi-Server version
|
||||
description: You can find your Suwayomi-Server version in **More → About**.
|
||||
placeholder: |
|
||||
Example: "v2.3.2226"
|
||||
Example: "v2.2.2100"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
@@ -143,13 +143,11 @@ body:
|
||||
options:
|
||||
- label: I have searched the existing issues and this is a new ticket, **NOT** a duplicate or related to another open or closed issue.
|
||||
required: true
|
||||
- label: I have checked the ongoing preview changelog of **[Suwayomi-WebUI](https://github.com/Suwayomi/Suwayomi-WebUI/blob/master/CHANGELOG.md)** and **[Suwayomi-Server](https://github.com/Suwayomi/Suwayomi-Server/blob/master/CHANGELOG.md)** and this bug has **NOT** been listed as fixed
|
||||
required: true
|
||||
- label: I have written a short but informative title (ideally less than ~100 characters).
|
||||
required: true
|
||||
- label: I have tried the troubleshooting guide described in [README.md](https://github.com/Suwayomi/Suwayomi-Server?tab=readme-ov-file#troubleshooting-and-support)
|
||||
required: true
|
||||
- label: I have updated the (**[Suwayomi-WebUI](https://github.com/suwayomi/suwayomi-webui/releases/latest)** and **[Suwayomi-Server](https://github.com/suwayomi/suwayomi-server/releases/latest)**) to the latest versions
|
||||
- label: I have updated to the **[latest version](https://github.com/suwayomi/suwayomi-server/releases/latest)**.
|
||||
required: true
|
||||
- label: I have filled out all of the requested information in this form, including specific version numbers.
|
||||
required: true
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
2
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
@@ -31,7 +31,7 @@ body:
|
||||
required: true
|
||||
- label: I have written a short but informative title (ideally less than ~100 characters).
|
||||
required: true
|
||||
- label: I have updated the (**[Suwayomi-WebUI](https://github.com/suwayomi/suwayomi-webui/releases/latest)** and **[Suwayomi-Server](https://github.com/suwayomi/suwayomi-server/releases/latest)**) to the latest versions
|
||||
- label: I have updated to the **[latest version](https://github.com/suwayomi/suwayomi-server/releases/latest)**.
|
||||
required: true
|
||||
- label: I have filled out all of the requested information in this form, including specific version numbers.
|
||||
required: true
|
||||
36
CHANGELOG.md
36
CHANGELOG.md
@@ -6,41 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
||||
|
||||
## [Unreleased] (Preview)
|
||||
|
||||
### Added
|
||||
- .
|
||||
|
||||
### Changed
|
||||
- .
|
||||
|
||||
### Fixed
|
||||
- .
|
||||
|
||||
## [v2.3.2226] - 2026-07-01
|
||||
|
||||
### Fixed
|
||||
- (**Extension/API**) Fix GQL handling of extensions without an extension store
|
||||
- (**Build/Bundler**) Fix build continuing if errors happen
|
||||
|
||||
## [v2.3.2223] + [WebUI: v20260509.01] - 2026-06-30
|
||||
|
||||
### Major Changes
|
||||
|
||||
#### Added [SyncYomi](https://github.com/syncyomi/syncyomi) support
|
||||
This allows you to sync your server manga with other Mihon-based forks! As long as the fork supports SyncYomi it can be sync with!
|
||||
|
||||
#### Support Extension API v1.6
|
||||
This update allows Suwayomi to load and use v1.6 extensions, it is a minor improvement over the existing 1.4 extension API that cleans up much of what we had! It is the basis of future extension APIs that will allow for further development.
|
||||
|
||||
This also allows us to move to Mihon's Extension Store system and replace our Extension Repo system. Old Extension Repos are still compatible and will be automatically migrated if they move to the Extension Store system.
|
||||
|
||||
> [!WARNING]
|
||||
> Please back up your Extension Repos, because of the new Extension Stores system you may lose them in the update process and may need to re-add them.
|
||||
|
||||
### Added
|
||||
- (**Sync**) Added [SyncYomi](https://github.com/syncyomi/syncyomi) support
|
||||
- (**OPDS**) Add option to skip chapter metadata feed providing direct stream/download links
|
||||
- (**Extension/API**) Support Extensions API v1.6
|
||||
- (**Tracker/API**) Add mutation to bind existing track record
|
||||
|
||||
### Changed
|
||||
- (**Database/H2**) Use the latest H2 database engine
|
||||
@@ -457,7 +426,6 @@ Huge thanks to @martinek who pulled the most of the weight this release!
|
||||
|
||||
<!-- WEBUI LINKS -->
|
||||
|
||||
[WebUI: v20260509.01]: https://github.com/Suwayomi/Suwayomi-WebUI/blob/master/CHANGELOG.md#2026050901-r3147---2026-05-09
|
||||
[WebUI: v20260508.01]: https://github.com/Suwayomi/Suwayomi-WebUI/blob/master/CHANGELOG.md#2026050801-r3136---2026-05-08
|
||||
[WebUI: v20251230.01]: https://github.com/Suwayomi/Suwayomi-WebUI/blob/master/CHANGELOG.md#2025123001-r2937---2025-12-30
|
||||
[WebUI: v20250801.01]: https://github.com/Suwayomi/Suwayomi-WebUI/blob/master/CHANGELOG.md#2025080101-r2717---2025-08-01
|
||||
@@ -484,9 +452,7 @@ Huge thanks to @martinek who pulled the most of the weight this release!
|
||||
|
||||
<!-- SERVER LINKS -->
|
||||
|
||||
[unreleased]: https://github.com/suwayomi/suwayomi-server/compare/v2.3.2226...HEAD
|
||||
[v2.3.2226]: https://github.com/suwayomi/suwayomi-server/compare/v2.3.2223...v2.3.2226
|
||||
[v2.3.2223]: https://github.com/suwayomi/suwayomi-server/compare/v2.2.2100...v2.3.2223
|
||||
[unreleased]: https://github.com/suwayomi/suwayomi-server/compare/v2.2.2100...HEAD
|
||||
[v2.2.2100]: https://github.com/suwayomi/suwayomi-server/compare/v2.1.1867...v2.2.2100
|
||||
[v2.1.1867]: https://github.com/suwayomi/suwayomi-server/compare/v2.0.1727...v2.1.1867
|
||||
[v2.0.1727]: https://github.com/suwayomi/suwayomi-server/compare/v1.1.1...v2.0.1727
|
||||
|
||||
@@ -10,9 +10,9 @@ import java.io.BufferedReader
|
||||
const val MainClass = "suwayomi.tachidesk.MainKt"
|
||||
|
||||
// should be bumped with each stable release
|
||||
val getTachideskVersion = { "v2.3.${getCommitCount()}" }
|
||||
val getTachideskVersion = { "v2.2.${getCommitCount()}" }
|
||||
|
||||
val webUIRevisionTag = "r3147"
|
||||
val webUIRevisionTag = "r3136"
|
||||
|
||||
val webviewJbrRelease = "jbr-release-25.0.3b508.4"
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ dex2jar = "2.4.37"
|
||||
polyglot = "25.0.3"
|
||||
settings = "1.3.0"
|
||||
twelvemonkeys = "3.13.1"
|
||||
graphqlkotlin = "10.1.2"
|
||||
graphqlkotlin = "10.0.0"
|
||||
xmlserialization = "0.91.3"
|
||||
ktlint = "1.8.0"
|
||||
koin = "4.2.2"
|
||||
|
||||
@@ -26,7 +26,7 @@ main() {
|
||||
set -- "${POSITIONAL_ARGS[@]}"
|
||||
|
||||
OS="$1"
|
||||
JAR="$(ls server/build/*.jar | tail -n1)" || error $LINENO "No JAR found in server/build/" 1
|
||||
JAR="$(ls server/build/*.jar | tail -n1)"
|
||||
RELEASE_NAME="$(echo "${JAR%.*}" | xargs basename)-$OS"
|
||||
RELEASE_VERSION=$(echo "$JAR" | grep -oP "v\K[0-9]+\.[0-9]+\.[0-9]+")
|
||||
#RELEASE_REVISION_NUMBER="$(tmp="${JAR%.*}" && echo "${tmp##*-}" | tr -d r)"
|
||||
@@ -34,12 +34,12 @@ main() {
|
||||
|
||||
# clean temporary directory on function return
|
||||
trap "rm -rf $RELEASE_NAME/" RETURN
|
||||
mkdir "$RELEASE_NAME/" || error $LINENO "Failed to create release directory" 1
|
||||
mkdir "$RELEASE_NAME/"
|
||||
|
||||
download_launcher
|
||||
|
||||
if [ ! -f scripts/resources/catch_abort.so ]; then
|
||||
gcc -fPIC -shared scripts/resources/catch_abort.c -lpthread -o scripts/resources/catch_abort.so || error $LINENO "Failed to compile catch_abort" 1
|
||||
gcc -fPIC -shared scripts/resources/catch_abort.c -lpthread -o scripts/resources/catch_abort.so
|
||||
fi
|
||||
|
||||
JRE_ZULU="25.34.17_25.0.3"
|
||||
@@ -67,7 +67,7 @@ main() {
|
||||
linux-assets)
|
||||
RELEASE="$RELEASE_NAME.tar.gz"
|
||||
copy_linux_package_assets_to "$RELEASE_NAME/"
|
||||
tar -I "gzip -9" -cvf "$RELEASE" "$RELEASE_NAME/" || error $LINENO "Failed to create tar.gz" 1
|
||||
tar -I "gzip -9" -cvf "$RELEASE" "$RELEASE_NAME/"
|
||||
move_release_to_output_dir
|
||||
;;
|
||||
linux-x64)
|
||||
@@ -145,55 +145,52 @@ move_release_to_output_dir() {
|
||||
if [ -f "$OUTPUT_DIR/$RELEASE" ]; then
|
||||
rm "$OUTPUT_DIR/$RELEASE"
|
||||
fi
|
||||
mv "$RELEASE" "$OUTPUT_DIR/" || error $LINENO "Failed to move release to output dir" 1
|
||||
mv "$RELEASE" "$OUTPUT_DIR/"
|
||||
}
|
||||
|
||||
download_launcher() {
|
||||
LAUNCHER_URL=$(curl -sf "https://api.github.com/repos/Suwayomi/Suwayomi-Launcher/releases/latest" | grep "browser_download_url" | grep ".jar" | head -n 1 | cut -d '"' -f 4)
|
||||
if [ -z "$LAUNCHER_URL" ]; then
|
||||
error $LINENO "Failed to determine launcher URL from GitHub API" 1
|
||||
fi
|
||||
curl -fL "$LAUNCHER_URL" -o "Suwayomi-Launcher.jar" || error $LINENO "Failed to download launcher JAR" 1
|
||||
mv "Suwayomi-Launcher.jar" "$RELEASE_NAME/Suwayomi-Launcher.jar" || error $LINENO "Failed to move launcher JAR" 1
|
||||
curl -fL "$LAUNCHER_URL" -o "Suwayomi-Launcher.jar"
|
||||
mv "Suwayomi-Launcher.jar" "$RELEASE_NAME/Suwayomi-Launcher.jar"
|
||||
}
|
||||
|
||||
download_jogamp() {
|
||||
local platform="$1"
|
||||
if [ ! -f jogamp-all-platforms.7z ]; then
|
||||
curl -f "https://jogamp.org/deployment/jogamp-current/archive/jogamp-all-platforms.7z" -o jogamp-all-platforms.7z || error $LINENO "Failed to download jogamp archive" 1
|
||||
curl -f "https://jogamp.org/deployment/jogamp-current/archive/jogamp-all-platforms.7z" -o jogamp-all-platforms.7z
|
||||
fi
|
||||
|
||||
7z x jogamp-all-platforms.7z "jogamp-all-platforms/lib/$platform/" || error $LINENO "Failed to extract jogamp archive" 1
|
||||
7z x jogamp-all-platforms.7z "jogamp-all-platforms/lib/$platform/"
|
||||
mkdir -p "$RELEASE_NAME/natives/"
|
||||
mv jogamp-all-platforms/lib/* "$RELEASE_NAME/natives/" || error $LINENO "Failed to move natives" 1
|
||||
mv jogamp-all-platforms/lib/* "$RELEASE_NAME/natives/"
|
||||
rm -rf jogamp-all-platforms
|
||||
}
|
||||
|
||||
download_electron() {
|
||||
if [ ! -f "$ELECTRON" ]; then
|
||||
curl -fL "$ELECTRON_URL" -o "$ELECTRON" || error $LINENO "Failed to download electron" 1
|
||||
curl -fL "$ELECTRON_URL" -o "$ELECTRON"
|
||||
fi
|
||||
|
||||
unzip "$ELECTRON" -d "$RELEASE_NAME/electron/" || error $LINENO "Failed to extract electron" 1
|
||||
unzip "$ELECTRON" -d "$RELEASE_NAME/electron/"
|
||||
}
|
||||
|
||||
setup_jre() {
|
||||
if [ -d "jre" ]; then
|
||||
chmod +x ./jre/bin/java || error $LINENO "Failed to set java executable permission" 1
|
||||
chmod +x ./jre/lib/jspawnhelper || error $LINENO "Failed to set jspawnhelper executable permission" 1
|
||||
mv "jre" "$RELEASE_NAME/jre" || error $LINENO "Failed to move jre" 1
|
||||
chmod +x ./jre/bin/java
|
||||
chmod +x ./jre/lib/jspawnhelper
|
||||
mv "jre" "$RELEASE_NAME/jre"
|
||||
else
|
||||
if [ ! -f "$JRE" ]; then
|
||||
curl -fL "$JRE_URL" -o "$JRE" || error $LINENO "Failed to download JRE" 1
|
||||
curl -fL "$JRE_URL" -o "$JRE"
|
||||
fi
|
||||
|
||||
local ext="${JRE##*.}"
|
||||
if [ "$ext" = "zip" ]; then
|
||||
unzip "$JRE" || error $LINENO "Failed to extract JRE zip" 1
|
||||
unzip "$JRE"
|
||||
else
|
||||
tar xvf "$JRE" || error $LINENO "Failed to extract JRE tar" 1
|
||||
tar xvf "$JRE"
|
||||
fi
|
||||
mv "$JRE_DIR" "$RELEASE_NAME/jre" || error $LINENO "Failed to move extracted JRE" 1
|
||||
mv "$JRE_DIR" "$RELEASE_NAME/jre"
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -201,31 +198,31 @@ copy_linux_package_assets_to() {
|
||||
local output_dir
|
||||
output_dir="$(readlink -e "$1" || exit 1)"
|
||||
|
||||
cp "scripts/resources/pkg/suwayomi-server.sh" "$output_dir/" || error $LINENO "Failed to copy server script" 1
|
||||
cp "scripts/resources/pkg/suwayomi-server.desktop" "$output_dir/" || error $LINENO "Failed to copy server desktop file" 1
|
||||
cp "scripts/resources/pkg/suwayomi-launcher.sh" "$output_dir/" || error $LINENO "Failed to copy launcher script" 1
|
||||
cp "scripts/resources/pkg/suwayomi-launcher.desktop" "$output_dir/" || error $LINENO "Failed to copy launcher desktop file" 1
|
||||
cp "scripts/resources/pkg/systemd"/* "$output_dir/" || error $LINENO "Failed to copy systemd files" 1
|
||||
cp "scripts/resources/pkg/suwayomi-server.sh" "$output_dir/"
|
||||
cp "scripts/resources/pkg/suwayomi-server.desktop" "$output_dir/"
|
||||
cp "scripts/resources/pkg/suwayomi-launcher.sh" "$output_dir/"
|
||||
cp "scripts/resources/pkg/suwayomi-launcher.desktop" "$output_dir/"
|
||||
cp "scripts/resources/pkg/systemd"/* "$output_dir/"
|
||||
cp "server/src/main/resources/icon/faviconlogo-128.png" \
|
||||
"$output_dir/suwayomi-server.png" || error $LINENO "Failed to copy icon" 1
|
||||
"$output_dir/suwayomi-server.png"
|
||||
}
|
||||
|
||||
make_linux_bundle() {
|
||||
mkdir "$RELEASE_NAME/bin"
|
||||
cp "$JAR" "$RELEASE_NAME/bin/Suwayomi-Server.jar" || error $LINENO "Failed to copy server jar" 1
|
||||
cp "scripts/resources/suwayomi-launcher.sh" "$RELEASE_NAME/" || error $LINENO "Failed to copy launcher script" 1
|
||||
cp "scripts/resources/suwayomi-server.sh" "$RELEASE_NAME/" || error $LINENO "Failed to copy server script" 1
|
||||
cp "scripts/resources/catch_abort.so" "$RELEASE_NAME/bin/" || error $LINENO "Failed to copy catch_abort" 1
|
||||
cp "$JAR" "$RELEASE_NAME/bin/Suwayomi-Server.jar"
|
||||
cp "scripts/resources/suwayomi-launcher.sh" "$RELEASE_NAME/"
|
||||
cp "scripts/resources/suwayomi-server.sh" "$RELEASE_NAME/"
|
||||
cp "scripts/resources/catch_abort.so" "$RELEASE_NAME/bin/"
|
||||
|
||||
tar -I "gzip -9" -cvf "$RELEASE" "$RELEASE_NAME/" || error $LINENO "Failed to create tar.gz" 1
|
||||
tar -I "gzip -9" -cvf "$RELEASE" "$RELEASE_NAME/"
|
||||
}
|
||||
|
||||
make_macos_bundle() {
|
||||
mkdir "$RELEASE_NAME/bin"
|
||||
cp "$JAR" "$RELEASE_NAME/bin/Suwayomi-Server.jar" || error $LINENO "Failed to copy server jar" 1
|
||||
cp "scripts/resources/Suwayomi Launcher.command" "$RELEASE_NAME/" || error $LINENO "Failed to copy launcher command" 1
|
||||
cp "$JAR" "$RELEASE_NAME/bin/Suwayomi-Server.jar"
|
||||
cp "scripts/resources/Suwayomi Launcher.command" "$RELEASE_NAME/"
|
||||
|
||||
tar -I "gzip -9" -cvf "$RELEASE" "$RELEASE_NAME/" || error $LINENO "Failed to create tar.gz" 1
|
||||
tar -I "gzip -9" -cvf "$RELEASE" "$RELEASE_NAME/"
|
||||
}
|
||||
|
||||
# https://wiki.debian.org/SimplePackagingTutorial
|
||||
@@ -236,28 +233,28 @@ make_deb_package() {
|
||||
#behind $RELEASE_VERSION is underscore "_"
|
||||
local upstream_source="suwayomi-server_$RELEASE_VERSION.orig.tar.gz"
|
||||
|
||||
mkdir "$RELEASE_NAME/$source_dir/" || error $LINENO "Failed to create source directory" 1
|
||||
mv "$RELEASE_NAME/natives" "$RELEASE_NAME/$source_dir/natives" || error $LINENO "Failed to move natives" 1
|
||||
mv "$RELEASE_NAME/Suwayomi-Launcher.jar" "$RELEASE_NAME/$source_dir/Suwayomi-Launcher.jar" || error $LINENO "Failed to move launcher jar" 1
|
||||
cp "$JAR" "$RELEASE_NAME/$source_dir/Suwayomi-Server.jar" || error $LINENO "Failed to copy server jar" 1
|
||||
mkdir "$RELEASE_NAME/$source_dir/"
|
||||
mv "$RELEASE_NAME/natives" "$RELEASE_NAME/$source_dir/natives"
|
||||
mv "$RELEASE_NAME/Suwayomi-Launcher.jar" "$RELEASE_NAME/$source_dir/Suwayomi-Launcher.jar"
|
||||
cp "$JAR" "$RELEASE_NAME/$source_dir/Suwayomi-Server.jar"
|
||||
copy_linux_package_assets_to "$RELEASE_NAME/$source_dir/"
|
||||
cp "scripts/resources/catch_abort.so" "$RELEASE_NAME/$source_dir/" || error $LINENO "Failed to copy catch_abort" 1
|
||||
tar -I "gzip" -C "$RELEASE_NAME/" -cvf "$upstream_source" "$source_dir" || error $LINENO "Failed to create source tar.gz" 1
|
||||
cp "scripts/resources/catch_abort.so" "$RELEASE_NAME/$source_dir/"
|
||||
tar -I "gzip" -C "$RELEASE_NAME/" -cvf "$upstream_source" "$source_dir"
|
||||
|
||||
cp -r "scripts/resources/deb/" "$RELEASE_NAME/$source_dir/debian/" || error $LINENO "Failed to copy debian resources" 1
|
||||
sed -i "s/\$pkgver/$RELEASE_VERSION/" "$RELEASE_NAME/$source_dir/debian/changelog" || error $LINENO "Failed to update changelog" 1
|
||||
sed -i "s/\$pkgrel/1/" "$RELEASE_NAME/$source_dir/debian/changelog" || error $LINENO "Failed to update changelog" 1
|
||||
cp -r "scripts/resources/deb/" "$RELEASE_NAME/$source_dir/debian/"
|
||||
sed -i "s/\$pkgver/$RELEASE_VERSION/" "$RELEASE_NAME/$source_dir/debian/changelog"
|
||||
sed -i "s/\$pkgrel/1/" "$RELEASE_NAME/$source_dir/debian/changelog"
|
||||
|
||||
if [ "${CI:-}" = true ]; then
|
||||
sudo apt update || error $LINENO "Failed to update apt" 1
|
||||
sudo apt install devscripts build-essential dh-exec || error $LINENO "Failed to install build deps" 1
|
||||
sudo apt update
|
||||
sudo apt install devscripts build-essential dh-exec
|
||||
fi
|
||||
cd "$RELEASE_NAME/$source_dir/" || error $LINENO "Failed to change directory" 1
|
||||
dpkg-buildpackage --no-sign --build=all || error $LINENO "Debian package build failed" 1
|
||||
cd - || error $LINENO "Failed to return to previous directory" 1
|
||||
cd "$RELEASE_NAME/$source_dir/"
|
||||
dpkg-buildpackage --no-sign --build=all
|
||||
cd -
|
||||
|
||||
local deb="suwayomi-server_$RELEASE_VERSION-1_all.deb"
|
||||
mv "$RELEASE_NAME/$deb" "$RELEASE" || error $LINENO "Failed to move resulting .deb" 1
|
||||
mv "$RELEASE_NAME/$deb" "$RELEASE"
|
||||
}
|
||||
|
||||
# https://linuxconfig.org/building-a-hello-world-appimage-on-linux
|
||||
@@ -265,20 +262,20 @@ make_appimage() {
|
||||
local APPIMAGE_URL="https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage"
|
||||
local APPIMAGE_TOOLNAME="appimagetool-x86_64.AppImage"
|
||||
mkdir "$RELEASE_NAME/bin/"
|
||||
cp "$JAR" "$RELEASE_NAME/bin/Suwayomi-Server.jar" || error $LINENO "Failed to copy server jar" 1
|
||||
cp "$JAR" "$RELEASE_NAME/bin/Suwayomi-Server.jar"
|
||||
|
||||
cp "scripts/resources/pkg/suwayomi-server.desktop" "$RELEASE_NAME/suwayomi-server.desktop" || error $LINENO "Failed to copy desktop file" 1
|
||||
cp "server/src/main/resources/icon/faviconlogo.png" "$RELEASE_NAME/suwayomi-server.png" || error $LINENO "Failed to copy icon" 1
|
||||
cp "scripts/resources/appimage/AppRun" "$RELEASE_NAME/AppRun" || error $LINENO "Failed to copy AppRun" 1
|
||||
chmod +x "$RELEASE_NAME/AppRun" || error $LINENO "Failed to make AppRun executable" 1
|
||||
cp "scripts/resources/pkg/suwayomi-server.desktop" "$RELEASE_NAME/suwayomi-server.desktop"
|
||||
cp "server/src/main/resources/icon/faviconlogo.png" "$RELEASE_NAME/suwayomi-server.png"
|
||||
cp "scripts/resources/appimage/AppRun" "$RELEASE_NAME/AppRun"
|
||||
chmod +x "$RELEASE_NAME/AppRun"
|
||||
|
||||
if [ "${CI:-}" = true ]; then
|
||||
sudo apt update || error $LINENO "Failed to update apt" 1
|
||||
sudo apt install libfuse2 || error $LINENO "Failed to install libfuse2" 1
|
||||
sudo apt update
|
||||
sudo apt install libfuse2
|
||||
fi
|
||||
curl -fL $APPIMAGE_URL -o $APPIMAGE_TOOLNAME || error $LINENO "Failed to download appimagetool" 1
|
||||
chmod +x $APPIMAGE_TOOLNAME || error $LINENO "Failed to make appimagetool executable" 1
|
||||
ARCH=x86_64 ./$APPIMAGE_TOOLNAME "$RELEASE_NAME" "$RELEASE" || error $LINENO "AppImage creation failed" 1
|
||||
curl -fL $APPIMAGE_URL -o $APPIMAGE_TOOLNAME
|
||||
chmod +x $APPIMAGE_TOOLNAME
|
||||
ARCH=x86_64 ./$APPIMAGE_TOOLNAME "$RELEASE_NAME" "$RELEASE"
|
||||
}
|
||||
|
||||
make_windows_bundle() {
|
||||
@@ -303,7 +300,7 @@ make_windows_bundle() {
|
||||
#local rcedit_url="https://github.com/electron/rcedit/releases/download/v0.1.1/$rcedit"
|
||||
## change electron's icon
|
||||
#if [ ! -f "$rcedit" ]; then
|
||||
#curl -fL "$rcedit_url" -o "$rcedit" || error $LINENO "Failed to download rcedit" 1
|
||||
#curl -fL "$rcedit_url" -o "$rcedit"
|
||||
#fi
|
||||
|
||||
#local icon="server/src/main/resources/icon/faviconlogo.ico"
|
||||
@@ -311,38 +308,38 @@ make_windows_bundle() {
|
||||
# --set-icon "$icon"
|
||||
|
||||
mkdir "$RELEASE_NAME/bin"
|
||||
cp "$JAR" "$RELEASE_NAME/bin/Suwayomi-Server.jar" || error $LINENO "Failed to copy server jar" 1
|
||||
cp "scripts/resources/Suwayomi Launcher.bat" "$RELEASE_NAME" || error $LINENO "Failed to copy launcher bat" 1
|
||||
cp "$JAR" "$RELEASE_NAME/bin/Suwayomi-Server.jar"
|
||||
cp "scripts/resources/Suwayomi Launcher.bat" "$RELEASE_NAME"
|
||||
|
||||
zip -9 -r "$RELEASE" "$RELEASE_NAME" || error $LINENO "Failed to create windows bundle zip" 1
|
||||
zip -9 -r "$RELEASE" "$RELEASE_NAME"
|
||||
}
|
||||
|
||||
make_windows_package() {
|
||||
if [ "${CI:-}" = true ]; then
|
||||
sudo apt update || error $LINENO "Failed to update apt" 1
|
||||
sudo apt install -y wixl || error $LINENO "Failed to install wixl" 1
|
||||
sudo apt update
|
||||
sudo apt install -y wixl
|
||||
fi
|
||||
|
||||
find "$RELEASE_NAME/jre" \
|
||||
| wixl-heat --var var.SourceDir -p "$RELEASE_NAME/" \
|
||||
--directory-ref jre --component-group jre >"$RELEASE_NAME/jre.wxs" || error $LINENO "Failed to heat jre" 1
|
||||
--directory-ref jre --component-group jre >"$RELEASE_NAME/jre.wxs"
|
||||
find "$RELEASE_NAME/electron" \
|
||||
| wixl-heat --var var.SourceDir -p "$RELEASE_NAME/" \
|
||||
--directory-ref electron --component-group electron >"$RELEASE_NAME/electron.wxs" || error $LINENO "Failed to heat electron" 1
|
||||
--directory-ref electron --component-group electron >"$RELEASE_NAME/electron.wxs"
|
||||
find "$RELEASE_NAME/natives" \
|
||||
| wixl-heat --var var.SourceDir -p "$RELEASE_NAME/" \
|
||||
--directory-ref natives --component-group natives >"$RELEASE_NAME/natives.wxs" || error $LINENO "Failed to heat natives" 1
|
||||
--directory-ref natives --component-group natives >"$RELEASE_NAME/natives.wxs"
|
||||
|
||||
find "$RELEASE_NAME/bin" \
|
||||
| wixl-heat --var var.SourceDir -p "$RELEASE_NAME/" \
|
||||
--directory-ref bin --component-group bin >"$RELEASE_NAME/bin.wxs" || error $LINENO "Failed to heat bin" 1
|
||||
--directory-ref bin --component-group bin >"$RELEASE_NAME/bin.wxs"
|
||||
|
||||
local icon="server/src/main/resources/icon/faviconlogo.ico"
|
||||
local arch=${OS##*-}
|
||||
|
||||
wixl -D ProductVersion="$RELEASE_VERSION" -D SourceDir="$RELEASE_NAME" \
|
||||
-D Icon="$icon" --arch "$arch" "scripts/resources/msi/suwayomi-server-$arch.wxs" \
|
||||
"$RELEASE_NAME/jre.wxs" "$RELEASE_NAME/electron.wxs" "$RELEASE_NAME/natives.wxs" "$RELEASE_NAME/bin.wxs" -o "$RELEASE" || error $LINENO "Windows package build failed" 1
|
||||
"$RELEASE_NAME/jre.wxs" "$RELEASE_NAME/electron.wxs" "$RELEASE_NAME/natives.wxs" "$RELEASE_NAME/bin.wxs" -o "$RELEASE"
|
||||
}
|
||||
|
||||
# Error handler
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<string name="opds_feeds_root">Suwayomi OPDS Katalog</string>
|
||||
<string name="opds_feeds_chapter_details">%1$s | %2$s | Details</string>
|
||||
<string name="opds_feeds_sources_title">Alle Quellen</string>
|
||||
<string name="opds_feeds_genres_title">Genren</string>
|
||||
<string name="opds_feeds_genres_title">Genres</string>
|
||||
<string name="opds_feeds_genres_entry_content">Durchsuche Serien nach Genre</string>
|
||||
<string name="opds_feeds_status_entry_content">Durchsuche Serien nach Publikationsstatus</string>
|
||||
<string name="opds_feeds_languages_title">Sprachen</string>
|
||||
@@ -122,7 +122,4 @@
|
||||
<string name="webview_label_login_required">Deine Konfiguration erfordert die Anmeldung. Bitte gib Benutzername und Passwort ein.</string>
|
||||
<string name="opds_linktitle_first_page">Erste Seite</string>
|
||||
<string name="opds_linktitle_last_page">Letzte Seite</string>
|
||||
<string name="opds_error_chapters_not_found">Keine Kapitel gefunden oder die Quelle ist nicht erreichbar auf Seite %1$d.</string>
|
||||
<string name="opds_chapter_title_fallback">Kapitel %1$s</string>
|
||||
<string name="opds_chapter_title_oneshot">Oneshot</string>
|
||||
</resources>
|
||||
|
||||
@@ -122,6 +122,4 @@
|
||||
<string name="login_label_login">Σύνδεση</string>
|
||||
<string name="login_placeholder_username">Πληκτρολόγησε όνομα χρήστη...</string>
|
||||
<string name="login_placeholder_password">Μυστικό...</string>
|
||||
<string name="opds_error_chapters_not_found">Δεν βρέθηκαν κεφάλαια ή η πηγή είναι μη διαθέσιμη στη σελίδα %1$d.</string>
|
||||
<string name="opds_chapter_title_fallback">Κεφάλαιο %1$s</string>
|
||||
</resources>
|
||||
|
||||
@@ -122,6 +122,4 @@
|
||||
<string name="webview_label_login_required">Su configuración requiere que inicie sesión. Introduzca su nombre de usuario y contraseña.</string>
|
||||
<string name="opds_linktitle_first_page">Primera página</string>
|
||||
<string name="opds_linktitle_last_page">Última página</string>
|
||||
<string name="opds_error_chapters_not_found">No se encontraron capítulos o la fuente no está disponible en la página %1$d.</string>
|
||||
<string name="opds_chapter_title_fallback">Capítulo %1$s</string>
|
||||
</resources>
|
||||
|
||||
@@ -122,7 +122,4 @@
|
||||
<string name="login_label_login">Se connecter</string>
|
||||
<string name="login_placeholder_username">Tapez le nom d\'utilisateur…</string>
|
||||
<string name="login_placeholder_password">Secret…</string>
|
||||
<string name="opds_error_chapters_not_found">Aucun chapitre trouvé ou la source est inaccessible à la page %1$d.</string>
|
||||
<string name="opds_chapter_title_fallback">Chapitre %1$s</string>
|
||||
<string name="opds_chapter_title_oneshot">One shot</string>
|
||||
</resources>
|
||||
|
||||
@@ -122,6 +122,4 @@
|
||||
<string name="login_label_login">Accedi</string>
|
||||
<string name="login_placeholder_username">Digita il nome utente...</string>
|
||||
<string name="login_placeholder_password">Segreto...</string>
|
||||
<string name="opds_error_chapters_not_found">Nessun capitolo trovato o la fonte non è raggiungibile alla pagina %1$d.</string>
|
||||
<string name="opds_chapter_title_fallback">Capitolo %1$s</string>
|
||||
</resources>
|
||||
|
||||
@@ -60,7 +60,4 @@
|
||||
<string name="opds_feeds_library_sources_title">ソース</string>
|
||||
<string name="opds_feeds_library_sources_entry_content">ソース別にライブラリ内のマンガを閲覧</string>
|
||||
<string name="opds_feeds_search_results_title">検索結果</string>
|
||||
<string name="opds_error_chapters_not_found">ページ %1$d で章が見つからないか、ソースに接続できません。</string>
|
||||
<string name="opds_chapter_title_oneshot">読み切り</string>
|
||||
<string name="opds_chapter_title_fallback">第 %1$s 話</string>
|
||||
</resources>
|
||||
|
||||
@@ -76,6 +76,4 @@
|
||||
<string name="opds_facet_filter_all">Wszystkie</string>
|
||||
<string name="opds_facet_filter_downloaded">Pobrane</string>
|
||||
<string name="opds_facet_filter_ongoing">Trwające</string>
|
||||
<string name="opds_error_chapters_not_found">Nie znaleziono rozdziałów lub źródło jest nieosiągalne na stronie %1$d.</string>
|
||||
<string name="opds_chapter_title_fallback">Rozdział %1$s</string>
|
||||
</resources>
|
||||
|
||||
@@ -122,6 +122,4 @@
|
||||
<string name="login_label_login">Entrar</string>
|
||||
<string name="login_placeholder_username">Digite o nome de usuário...</string>
|
||||
<string name="login_placeholder_password">Segredo...</string>
|
||||
<string name="opds_error_chapters_not_found">Nenhum capítulo encontrado ou a fonte está inacessível na página %1$d.</string>
|
||||
<string name="opds_chapter_title_fallback">Capítulo %1$s</string>
|
||||
</resources>
|
||||
|
||||
@@ -122,7 +122,4 @@
|
||||
<string name="opds_search_description">Ищите тайтлы в каталоге.</string>
|
||||
<string name="opds_error_manga_not_found">Тайтл с ID %1$d не найден.</string>
|
||||
<string name="opds_chapter_details_base">Тайтл: %1$s | %2$s</string>
|
||||
<string name="opds_error_chapters_not_found">Главы не найдены или источник недоступен на странице %1$d.</string>
|
||||
<string name="opds_chapter_title_fallback">Глава %1$s</string>
|
||||
<string name="opds_chapter_title_oneshot">Ваншот</string>
|
||||
</resources>
|
||||
|
||||
@@ -53,7 +53,4 @@
|
||||
<string name="opds_chapter_status_unread">⭕</string>
|
||||
<string name="opds_chapter_details_base">%1$s | %2$s</string>
|
||||
<string name="opds_feeds_genre_specific_title">இசைவகை: %1$s</string>
|
||||
<string name="opds_error_chapters_not_found">பக்கம் %1$d இல் அத்தியாயங்கள் எதுவும் காணப்படவில்லை அல்லது மூலத்தை அணுக முடியவில்லை.</string>
|
||||
<string name="opds_chapter_title_oneshot">ஒன்-ஷாட்</string>
|
||||
<string name="opds_chapter_title_fallback">அத்தியாயம் %1$s</string>
|
||||
</resources>
|
||||
|
||||
@@ -122,6 +122,4 @@
|
||||
<string name="webview_label_login_required">Cấu hình của bạn yêu cầu bạn phải đăng nhập. Vui lòng nhập tên người dùng và mật khẩu.</string>
|
||||
<string name="opds_linktitle_first_page">Trang đầu</string>
|
||||
<string name="opds_linktitle_last_page">Trang cuối</string>
|
||||
<string name="opds_error_chapters_not_found">Không tìm thấy chương nào hoặc nguồn không thể truy cập tại trang %1$d.</string>
|
||||
<string name="opds_chapter_title_fallback">Chương %1$s</string>
|
||||
</resources>
|
||||
|
||||
@@ -122,7 +122,4 @@
|
||||
<string name="login_placeholder_username">输入用户名…</string>
|
||||
<string name="login_placeholder_password">密匙…</string>
|
||||
<string name="label_error">错误</string>
|
||||
<string name="opds_error_chapters_not_found">第 %1$d 页未找到任何章节,或图源无法访问。</string>
|
||||
<string name="opds_chapter_title_fallback">第 %1$s 章</string>
|
||||
<string name="opds_chapter_title_oneshot">单篇</string>
|
||||
</resources>
|
||||
|
||||
@@ -22,7 +22,7 @@ import kotlinx.coroutines.flow.onEach
|
||||
import okhttp3.Cache
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.logging.HttpLoggingInterceptor
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetSource
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetCatalogueSource
|
||||
import java.net.CookieHandler
|
||||
import java.net.CookieManager
|
||||
import java.net.CookiePolicy
|
||||
@@ -62,7 +62,7 @@ class NetworkHelper(
|
||||
userAgent
|
||||
.drop(1)
|
||||
.onEach {
|
||||
GetSource.unregisterAllSources() // need to reset the headers
|
||||
GetCatalogueSource.unregisterAllCatalogueSources() // need to reset the headers
|
||||
}.launchIn(GlobalScope)
|
||||
}
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ import org.jetbrains.exposed.v1.jdbc.insert
|
||||
import org.jetbrains.exposed.v1.jdbc.insertAndGetId
|
||||
import org.jetbrains.exposed.v1.jdbc.selectAll
|
||||
import org.jetbrains.exposed.v1.jdbc.transactions.transaction
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetSource.registerSource
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetCatalogueSource.registerCatalogueSource
|
||||
import suwayomi.tachidesk.manga.impl.util.storage.ImageUtil
|
||||
import suwayomi.tachidesk.manga.model.table.ExtensionTable
|
||||
import suwayomi.tachidesk.manga.model.table.SourceTable
|
||||
@@ -497,7 +497,7 @@ class LocalSource(
|
||||
}
|
||||
|
||||
val fs = LocalSourceFileSystem(applicationDirs)
|
||||
registerSource(ID to LocalSource(fs, LocalCoverManager(fs)))
|
||||
registerCatalogueSource(ID to LocalSource(fs, LocalCoverManager(fs)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -305,7 +305,8 @@ object SyncYomiSyncService {
|
||||
|
||||
logger.debug { "Starting merge. Local list size: ${localMangaListSafe.size}, Remote list size: ${remoteMangaListSafe.size}" }
|
||||
|
||||
fun mangaCompositeKey(manga: BackupManga): String = "${manga.source}|${manga.url}"
|
||||
fun mangaCompositeKey(manga: BackupManga): String =
|
||||
"${manga.source}|${manga.url}|${manga.title.lowercase().trim()}|${manga.author?.lowercase()?.trim()}"
|
||||
|
||||
// Create maps using composite keys
|
||||
val localMangaMap = localMangaListSafe.associateBy { mangaCompositeKey(it) }
|
||||
@@ -414,7 +415,7 @@ object SyncYomiSyncService {
|
||||
return remoteChapters // If not syncing chapters, keep remote untouched
|
||||
}
|
||||
|
||||
fun chapterCompositeKey(chapter: BackupChapter): String = chapter.url
|
||||
fun chapterCompositeKey(chapter: BackupChapter): String = "${chapter.url}|${chapter.name}|${chapter.chapterNumber}"
|
||||
|
||||
val localChapterMap = localChapters.associateBy { chapterCompositeKey(it) }
|
||||
val remoteChapterMap = remoteChapters.associateBy { chapterCompositeKey(it) }
|
||||
|
||||
@@ -28,7 +28,7 @@ import suwayomi.tachidesk.graphql.types.preferenceOf
|
||||
import suwayomi.tachidesk.graphql.types.updateFilterList
|
||||
import suwayomi.tachidesk.manga.impl.MangaList.insertOrUpdate
|
||||
import suwayomi.tachidesk.manga.impl.Source
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetSource
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetCatalogueSource
|
||||
import suwayomi.tachidesk.manga.model.table.MangaTable
|
||||
import suwayomi.tachidesk.manga.model.table.SourceMetaTable
|
||||
import suwayomi.tachidesk.manga.model.table.SourceTable
|
||||
@@ -256,7 +256,7 @@ class SourceMutation {
|
||||
val (clientMutationId, sourceId, type, page, query, filters) = input
|
||||
|
||||
return future {
|
||||
val source = GetSource.getSourceOrNull(sourceId)!!
|
||||
val source = GetCatalogueSource.getCatalogueSourceOrNull(sourceId)!!
|
||||
val mangasPage =
|
||||
when (type) {
|
||||
FetchSourceMangaType.SEARCH -> {
|
||||
|
||||
@@ -148,36 +148,6 @@ class TrackMutation {
|
||||
}
|
||||
}
|
||||
|
||||
data class BindTrackRecordInput(
|
||||
val clientMutationId: String? = null,
|
||||
val mangaId: Int,
|
||||
val trackRecordId: Int,
|
||||
)
|
||||
|
||||
data class BindTrackRecordPayload(
|
||||
val clientMutationId: String?,
|
||||
val trackRecord: TrackRecordType,
|
||||
)
|
||||
|
||||
@RequireAuth
|
||||
fun bindTrackRecord(input: BindTrackRecordInput): CompletableFuture<BindTrackRecordPayload?> {
|
||||
val (clientMutationId, mangaId, trackRecordId) = input
|
||||
|
||||
return future {
|
||||
val boundTrackRecordId = Track.bindTrackRecord(mangaId, trackRecordId)
|
||||
|
||||
val trackRecord =
|
||||
transaction {
|
||||
TrackRecordTable.selectAll().where { TrackRecordTable.id eq boundTrackRecordId }.first()
|
||||
}
|
||||
|
||||
BindTrackRecordPayload(
|
||||
clientMutationId,
|
||||
TrackRecordType(trackRecord),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
data class FetchTrackInput(
|
||||
val clientMutationId: String? = null,
|
||||
val recordId: Int,
|
||||
|
||||
@@ -71,8 +71,8 @@ class ExtensionType(
|
||||
fun source(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<SourceNodeList> =
|
||||
dataFetchingEnvironment.getValueFromDataLoader<String, SourceNodeList>("SourcesForExtensionDataLoader", pkgName)
|
||||
|
||||
fun extensionStore(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<ExtensionStoreType?> =
|
||||
dataFetchingEnvironment.getValueFromDataLoader<String, ExtensionStoreType?>("ExtensionStoreDataLoader", storeIndexUrl.orEmpty())
|
||||
fun extensionStore(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<ExtensionStoreType> =
|
||||
dataFetchingEnvironment.getValueFromDataLoader<String, ExtensionStoreType>("ExtensionStoreDataLoader", storeIndexUrl.orEmpty())
|
||||
}
|
||||
|
||||
data class ExtensionNodeList(
|
||||
|
||||
@@ -9,8 +9,8 @@ package suwayomi.tachidesk.graphql.types
|
||||
|
||||
import com.expediagroup.graphql.generator.annotations.GraphQLDeprecated
|
||||
import com.expediagroup.graphql.server.extensions.getValueFromDataLoader
|
||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||
import eu.kanade.tachiyomi.source.ConfigurableSource
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
import graphql.schema.DataFetchingEnvironment
|
||||
@@ -24,8 +24,8 @@ import suwayomi.tachidesk.graphql.server.primitives.NodeList
|
||||
import suwayomi.tachidesk.graphql.server.primitives.PageInfo
|
||||
import suwayomi.tachidesk.manga.impl.Source.getSourcePreferencesRaw
|
||||
import suwayomi.tachidesk.manga.impl.extension.Extension
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetSource
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetSource.getSourceOrStub
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetCatalogueSource
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetCatalogueSource.getCatalogueSourceOrStub
|
||||
import suwayomi.tachidesk.manga.model.dataclass.ContentWarning
|
||||
import suwayomi.tachidesk.manga.model.table.ExtensionTable
|
||||
import suwayomi.tachidesk.manga.model.table.SourceTable
|
||||
@@ -53,18 +53,18 @@ class SourceType(
|
||||
@GraphQLDeprecated("", ReplaceWith("homeUrl"))
|
||||
val baseUrl: String?,
|
||||
) : Node {
|
||||
constructor(row: ResultRow, sourceExtension: ResultRow, source: Source) : this(
|
||||
constructor(row: ResultRow, sourceExtension: ResultRow, catalogueSource: CatalogueSource) : this(
|
||||
id = row[SourceTable.id].value,
|
||||
name = row[SourceTable.name],
|
||||
lang = row[SourceTable.lang],
|
||||
contentWarning = ContentWarning.valueOf(row[SourceTable.contentWarning]),
|
||||
iconUrl = Extension.proxyExtensionIconUrl(sourceExtension[ExtensionTable.pkgName]),
|
||||
supportsLatest = source.supportsLatest,
|
||||
isConfigurable = source is ConfigurableSource,
|
||||
supportsLatest = catalogueSource.supportsLatest,
|
||||
isConfigurable = catalogueSource is ConfigurableSource,
|
||||
isNsfw = row[SourceTable.contentWarning] >= ContentWarning.MIXED.ordinal,
|
||||
displayName = source.toString(),
|
||||
homeUrl = runCatching { (source as? HttpSource)?.getHomeUrl() }.getOrNull(),
|
||||
baseUrl = runCatching { (source as? HttpSource)?.baseUrl }.getOrNull(),
|
||||
displayName = catalogueSource.toString(),
|
||||
homeUrl = runCatching { (catalogueSource as? HttpSource)?.getHomeUrl() }.getOrNull(),
|
||||
baseUrl = runCatching { (catalogueSource as? HttpSource)?.baseUrl }.getOrNull(),
|
||||
)
|
||||
|
||||
fun manga(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<MangaNodeList> =
|
||||
@@ -75,7 +75,7 @@ class SourceType(
|
||||
|
||||
fun preferences(): List<Preference> = getSourcePreferencesRaw(id).map { preferenceOf(it) }
|
||||
|
||||
fun filters(): List<Filter> = getSourceOrStub(id).getFilterList().map { filterOf(it) }
|
||||
fun filters(): List<Filter> = getCatalogueSourceOrStub(id).getFilterList().map { filterOf(it) }
|
||||
|
||||
fun meta(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<List<SourceMetaType>> =
|
||||
dataFetchingEnvironment.getValueFromDataLoader<Long, List<SourceMetaType>>("SourceMetaDataLoader", id)
|
||||
@@ -84,8 +84,8 @@ class SourceType(
|
||||
@Suppress("ktlint:standard:function-naming")
|
||||
fun SourceType(row: ResultRow): SourceType? {
|
||||
val catalogueSource =
|
||||
GetSource
|
||||
.getSourceOrNull(row[SourceTable.id].value)
|
||||
GetCatalogueSource
|
||||
.getCatalogueSourceOrNull(row[SourceTable.id].value)
|
||||
?: return null
|
||||
val sourceExtension =
|
||||
if (row.hasValue(ExtensionTable.id)) {
|
||||
@@ -296,7 +296,7 @@ data class FilterChange(
|
||||
)
|
||||
|
||||
fun updateFilterList(
|
||||
source: Source,
|
||||
source: CatalogueSource,
|
||||
changes: List<FilterChange>?,
|
||||
): FilterList {
|
||||
val filterList = source.getFilterList()
|
||||
|
||||
@@ -7,7 +7,7 @@ package suwayomi.tachidesk.manga.impl
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||
import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.source.model.UpdateStrategy
|
||||
@@ -38,7 +38,7 @@ import org.jetbrains.exposed.v1.jdbc.update
|
||||
import suwayomi.tachidesk.manga.impl.download.DownloadManager
|
||||
import suwayomi.tachidesk.manga.impl.download.DownloadManager.EnqueueInput
|
||||
import suwayomi.tachidesk.manga.impl.track.Track
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetSource.getSourceOrStub
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetCatalogueSource.getCatalogueSourceOrStub
|
||||
import suwayomi.tachidesk.manga.model.dataclass.ChapterDataClass
|
||||
import suwayomi.tachidesk.manga.model.dataclass.MangaChapterDataClass
|
||||
import suwayomi.tachidesk.manga.model.dataclass.PaginatedList
|
||||
@@ -119,7 +119,7 @@ object Chapter {
|
||||
transaction {
|
||||
MangaTable.selectAll().where { MangaTable.id eq mangaId }.first()
|
||||
}
|
||||
val source = getSourceOrStub(mangaEntry[MangaTable.sourceReference])
|
||||
val source = getCatalogueSourceOrStub(mangaEntry[MangaTable.sourceReference])
|
||||
|
||||
val chapters =
|
||||
Manga
|
||||
@@ -139,7 +139,7 @@ object Chapter {
|
||||
fun updateChapterListDatabase(
|
||||
mangaEntry: ResultRow,
|
||||
chapters: List<SChapter>,
|
||||
source: Source,
|
||||
source: CatalogueSource,
|
||||
): List<SChapter> {
|
||||
val currentLatestChapterNumber = Manga.getLatestChapter(mangaEntry[MangaTable.id].value)?.chapterNumber ?: 0f
|
||||
val numberOfCurrentChapters = getCountOfMangaChapters(mangaEntry[MangaTable.id].value)
|
||||
|
||||
@@ -11,7 +11,7 @@ import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.HttpException
|
||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||
import eu.kanade.tachiyomi.network.awaitSuccess
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||
import eu.kanade.tachiyomi.source.local.LocalSource
|
||||
import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
@@ -41,8 +41,8 @@ import org.jetbrains.exposed.v1.jdbc.transactions.transaction
|
||||
import org.jetbrains.exposed.v1.jdbc.update
|
||||
import suwayomi.tachidesk.manga.impl.download.fileProvider.impl.MissingThumbnailException
|
||||
import suwayomi.tachidesk.manga.impl.util.network.await
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetSource.getSourceOrNull
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetSource.getSourceOrStub
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetCatalogueSource.getCatalogueSourceOrNull
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetCatalogueSource.getCatalogueSourceOrStub
|
||||
import suwayomi.tachidesk.manga.impl.util.source.StubSource
|
||||
import suwayomi.tachidesk.manga.impl.util.storage.ImageResponse.clearCachedImage
|
||||
import suwayomi.tachidesk.manga.impl.util.storage.ImageResponse.getImageResponse
|
||||
@@ -91,7 +91,7 @@ object Manga {
|
||||
|
||||
suspend fun fetchMangaAndChapters(
|
||||
mangaEntry: ResultRow,
|
||||
source: Source,
|
||||
source: CatalogueSource,
|
||||
fetchDetails: Boolean,
|
||||
fetchChapters: Boolean,
|
||||
): SMangaUpdate {
|
||||
@@ -139,7 +139,7 @@ object Manga {
|
||||
return mangaInfoMutex.get(mangaId) { Mutex() }.withLock {
|
||||
val mangaEntry =
|
||||
transaction { MangaTable.selectAll().where { MangaTable.id eq mangaId }.first() }
|
||||
val source = getSourceOrNull(mangaEntry[MangaTable.sourceReference]) ?: return null
|
||||
val source = getCatalogueSourceOrNull(mangaEntry[MangaTable.sourceReference]) ?: return null
|
||||
val sManga =
|
||||
fetchMangaAndChapters(
|
||||
mangaEntry,
|
||||
@@ -161,7 +161,7 @@ object Manga {
|
||||
var mangaEntry =
|
||||
transaction { MangaTable.selectAll().where { MangaTable.id eq mangaId }.first() }
|
||||
val source =
|
||||
getSourceOrNull(mangaEntry[MangaTable.sourceReference])
|
||||
getCatalogueSourceOrNull(mangaEntry[MangaTable.sourceReference])
|
||||
?: throw NullPointerException("Missing source ${mangaEntry[MangaTable.sourceReference]}")
|
||||
val mangaUpdate =
|
||||
fetchMangaAndChapters(
|
||||
@@ -186,7 +186,7 @@ object Manga {
|
||||
|
||||
fun updateMangaDatabase(
|
||||
mangaEntry: ResultRow,
|
||||
source: Source,
|
||||
source: CatalogueSource,
|
||||
sManga: SManga,
|
||||
): SManga {
|
||||
transaction {
|
||||
@@ -238,7 +238,6 @@ object Manga {
|
||||
it[MangaTable.lastFetchedAt] = Instant.now().epochSecond
|
||||
|
||||
it[MangaTable.updateStrategy] = sManga.update_strategy.name
|
||||
it[MangaTable.memo] = Json.encodeToString(sManga.memo)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -413,7 +412,7 @@ object Manga {
|
||||
val mangaEntry = transaction { MangaTable.selectAll().where { MangaTable.id eq mangaId }.first() }
|
||||
val sourceId = mangaEntry[MangaTable.sourceReference]
|
||||
|
||||
return when (val source = getSourceOrStub(sourceId)) {
|
||||
return when (val source = getCatalogueSourceOrStub(sourceId)) {
|
||||
is HttpSource -> {
|
||||
getImageResponse(cacheSaveDir, fileName) {
|
||||
fetchHttpSourceMangaThumbnail(source, mangaEntry)
|
||||
|
||||
@@ -19,7 +19,7 @@ import org.jetbrains.exposed.v1.jdbc.batchInsert
|
||||
import org.jetbrains.exposed.v1.jdbc.selectAll
|
||||
import org.jetbrains.exposed.v1.jdbc.statements.toExecutable
|
||||
import org.jetbrains.exposed.v1.jdbc.transactions.transaction
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetSource.getSourceOrStub
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetCatalogueSource.getCatalogueSourceOrStub
|
||||
import suwayomi.tachidesk.manga.model.dataclass.PagedMangaListDataClass
|
||||
import suwayomi.tachidesk.manga.model.table.MangaTable
|
||||
import suwayomi.tachidesk.manga.model.table.toDataClass
|
||||
@@ -36,7 +36,7 @@ object MangaList {
|
||||
require(pageNum > 0) {
|
||||
"pageNum = $pageNum is not in valid range"
|
||||
}
|
||||
val source = getSourceOrStub(sourceId)
|
||||
val source = getCatalogueSourceOrStub(sourceId)
|
||||
val mangasPage =
|
||||
if (popular) {
|
||||
source.getPopularManga(pageNum)
|
||||
|
||||
@@ -21,7 +21,7 @@ import org.jetbrains.exposed.v1.jdbc.transactions.transaction
|
||||
import org.jetbrains.exposed.v1.jdbc.update
|
||||
import suwayomi.tachidesk.graphql.types.DownloadConversion
|
||||
import suwayomi.tachidesk.manga.impl.util.getChapterCachePath
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetSource.getSourceOrStub
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetCatalogueSource.getCatalogueSourceOrStub
|
||||
import suwayomi.tachidesk.manga.impl.util.storage.ImageResponse.getImageResponse
|
||||
import suwayomi.tachidesk.manga.impl.util.storage.ImageUtil
|
||||
import suwayomi.tachidesk.manga.model.table.ChapterTable
|
||||
@@ -118,7 +118,7 @@ object Page {
|
||||
return imageFile.inputStream() to (ImageUtil.findImageType { imageFile.inputStream() }?.mime ?: "image/jpeg")
|
||||
}
|
||||
|
||||
val source = getSourceOrStub(mangaEntry[MangaTable.sourceReference])
|
||||
val source = getCatalogueSourceOrStub(mangaEntry[MangaTable.sourceReference])
|
||||
source as HttpSource
|
||||
|
||||
if (pageEntry[PageTable.imageUrl] == null) {
|
||||
|
||||
@@ -7,14 +7,14 @@ package suwayomi.tachidesk.manga.impl
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||
import eu.kanade.tachiyomi.source.model.Filter
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
import io.javalin.json.JsonMapper
|
||||
import io.javalin.json.fromJsonString
|
||||
import kotlinx.serialization.Serializable
|
||||
import suwayomi.tachidesk.manga.impl.MangaList.processEntries
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetSource.getSourceOrStub
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetCatalogueSource.getCatalogueSourceOrStub
|
||||
import suwayomi.tachidesk.manga.model.dataclass.PagedMangaListDataClass
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
@@ -24,7 +24,7 @@ object Search {
|
||||
searchTerm: String,
|
||||
pageNum: Int,
|
||||
): PagedMangaListDataClass {
|
||||
val source = getSourceOrStub(sourceId)
|
||||
val source = getCatalogueSourceOrStub(sourceId)
|
||||
val searchManga = source.getSearchManga(pageNum, searchTerm, getFilterListOf(source))
|
||||
return searchManga.processEntries(sourceId)
|
||||
}
|
||||
@@ -34,7 +34,7 @@ object Search {
|
||||
pageNum: Int,
|
||||
filter: FilterData,
|
||||
): PagedMangaListDataClass {
|
||||
val source = getSourceOrStub(sourceId)
|
||||
val source = getCatalogueSourceOrStub(sourceId)
|
||||
val filterList = if (filter.filter != null) buildFilterList(sourceId, filter.filter) else source.getFilterList()
|
||||
val searchManga = source.getSearchManga(pageNum, filter.searchTerm ?: "", filterList)
|
||||
return searchManga.processEntries(sourceId)
|
||||
@@ -43,7 +43,7 @@ object Search {
|
||||
private val filterListCache = mutableMapOf<Long, FilterList>()
|
||||
|
||||
private fun getFilterListOf(
|
||||
source: Source,
|
||||
source: CatalogueSource,
|
||||
reset: Boolean = false,
|
||||
): FilterList {
|
||||
if (reset || !filterListCache.containsKey(source.id)) {
|
||||
@@ -56,7 +56,7 @@ object Search {
|
||||
sourceId: Long,
|
||||
reset: Boolean,
|
||||
): List<FilterObject> {
|
||||
val source = getSourceOrStub(sourceId)
|
||||
val source = getCatalogueSourceOrStub(sourceId)
|
||||
|
||||
return getFilterListOf(source, reset).list.map {
|
||||
FilterObject(
|
||||
@@ -111,7 +111,7 @@ object Search {
|
||||
sourceId: Long,
|
||||
changes: List<FilterChange>,
|
||||
) {
|
||||
val source = getSourceOrStub(sourceId)
|
||||
val source = getCatalogueSourceOrStub(sourceId)
|
||||
val filterList = getFilterListOf(source, false)
|
||||
updateFilterList(filterList, changes)
|
||||
}
|
||||
@@ -169,7 +169,7 @@ object Search {
|
||||
sourceId: Long,
|
||||
changes: List<FilterChange>,
|
||||
): FilterList {
|
||||
val source = getSourceOrStub(sourceId)
|
||||
val source = getCatalogueSourceOrStub(sourceId)
|
||||
val filterList = source.getFilterList()
|
||||
return updateFilterList(filterList, changes)
|
||||
}
|
||||
|
||||
@@ -26,9 +26,9 @@ import org.jetbrains.exposed.v1.jdbc.statements.toExecutable
|
||||
import org.jetbrains.exposed.v1.jdbc.transactions.transaction
|
||||
import suwayomi.tachidesk.manga.impl.Source.preferenceScreenMap
|
||||
import suwayomi.tachidesk.manga.impl.extension.Extension.proxyExtensionIconUrl
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetSource.getSourceOrNull
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetSource.getSourceOrStub
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetSource.unregisterSource
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetCatalogueSource.getCatalogueSourceOrNull
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetCatalogueSource.getCatalogueSourceOrStub
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetCatalogueSource.unregisterCatalogueSource
|
||||
import suwayomi.tachidesk.manga.model.dataclass.ContentWarning
|
||||
import suwayomi.tachidesk.manga.model.dataclass.SourceDataClass
|
||||
import suwayomi.tachidesk.manga.model.table.ExtensionTable
|
||||
@@ -43,7 +43,7 @@ object Source {
|
||||
fun getSourceList(): List<SourceDataClass> {
|
||||
return transaction {
|
||||
SourceTable.selectAll().mapNotNull {
|
||||
val catalogueSource = getSourceOrNull(it[SourceTable.id].value) ?: return@mapNotNull null
|
||||
val catalogueSource = getCatalogueSourceOrNull(it[SourceTable.id].value) ?: return@mapNotNull null
|
||||
val sourceExtension = ExtensionTable.selectAll().where { ExtensionTable.id eq it[SourceTable.extension] }.first()
|
||||
|
||||
SourceDataClass(
|
||||
@@ -64,7 +64,7 @@ object Source {
|
||||
fun getSource(sourceId: Long): SourceDataClass? { // all the data extracted fresh form the source instance
|
||||
return transaction {
|
||||
val source = SourceTable.selectAll().where { SourceTable.id eq sourceId }.firstOrNull() ?: return@transaction null
|
||||
val catalogueSource = getSourceOrNull(sourceId) ?: return@transaction null
|
||||
val catalogueSource = getCatalogueSourceOrNull(sourceId) ?: return@transaction null
|
||||
val extension = ExtensionTable.selectAll().where { ExtensionTable.id eq source[SourceTable.extension] }.first()
|
||||
|
||||
SourceDataClass(
|
||||
@@ -107,7 +107,7 @@ object Source {
|
||||
}
|
||||
|
||||
fun getSourcePreferencesRaw(sourceId: Long): List<Preference> {
|
||||
val source = getSourceOrStub(sourceId)
|
||||
val source = getCatalogueSourceOrStub(sourceId)
|
||||
|
||||
if (source is ConfigurableSource) {
|
||||
val sourceShardPreferences = source.sourcePreferences()
|
||||
@@ -157,7 +157,7 @@ object Source {
|
||||
pref.callChangeListener(newValue)
|
||||
|
||||
// must reload the source because a preference was changed
|
||||
unregisterSource(sourceId)
|
||||
unregisterCatalogueSource(sourceId)
|
||||
}
|
||||
|
||||
fun getSourcesMetaMaps(ids: List<Long>): Map<Long, Map<String, String>> =
|
||||
|
||||
@@ -8,6 +8,7 @@ package suwayomi.tachidesk.manga.impl.backup.proto.handlers
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import eu.kanade.tachiyomi.source.model.UpdateStrategy
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.jetbrains.exposed.v1.core.ResultRow
|
||||
import org.jetbrains.exposed.v1.core.SortOrder
|
||||
import org.jetbrains.exposed.v1.core.and
|
||||
@@ -77,7 +78,7 @@ object BackupMangaHandler {
|
||||
lastModifiedAt = mangaRow[MangaTable.lastModifiedAt],
|
||||
version = mangaRow[MangaTable.version],
|
||||
initialized = mangaRow[MangaTable.initialized],
|
||||
memo = mangaRow[MangaTable.memo].encodeToByteArray(),
|
||||
memo = Json.encodeToString(mangaRow[MangaTable.memo]).encodeToByteArray(),
|
||||
)
|
||||
|
||||
val mangaId = mangaRow[MangaTable.id].value
|
||||
@@ -115,7 +116,6 @@ object BackupMangaHandler {
|
||||
sourceOrder = chapters.size - it[ChapterTable.sourceOrder],
|
||||
lastModifiedAt = it[ChapterTable.lastModifiedAt],
|
||||
version = it[ChapterTable.version],
|
||||
memo = it[ChapterTable.memo].encodeToByteArray(),
|
||||
).apply {
|
||||
if (flags.includeClientData) {
|
||||
this.meta = chapterToMeta[it[ChapterTable.id].value] ?: emptyMap()
|
||||
|
||||
@@ -39,7 +39,7 @@ data class BackupManga(
|
||||
@ProtoNumber(106) var lastModifiedAt: Long = 0,
|
||||
@ProtoNumber(109) var version: Long = 0,
|
||||
@ProtoNumber(111) var initialized: Boolean = false,
|
||||
@ProtoNumber(112) var memo: ByteArray = JsonObjectEmptyBytes,
|
||||
@ProtoNumber(13) var memo: ByteArray = JsonObjectEmptyBytes,
|
||||
// suwayomi
|
||||
@ProtoNumber(9000) var meta: Map<String, String> = emptyMap(),
|
||||
)
|
||||
|
||||
@@ -23,7 +23,7 @@ import org.jetbrains.exposed.v1.jdbc.selectAll
|
||||
import org.jetbrains.exposed.v1.jdbc.transactions.transaction
|
||||
import org.jetbrains.exposed.v1.jdbc.update
|
||||
import suwayomi.tachidesk.manga.impl.ChapterDownloadHelper
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetSource.getSourceOrStub
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetCatalogueSource.getCatalogueSourceOrStub
|
||||
import suwayomi.tachidesk.manga.model.dataclass.ChapterDataClass
|
||||
import suwayomi.tachidesk.manga.model.table.ChapterTable
|
||||
import suwayomi.tachidesk.manga.model.table.MangaTable
|
||||
@@ -77,7 +77,7 @@ suspend fun refreshChapterPageList(
|
||||
return mutex.withLock {
|
||||
val chapterEntry = existingChapterEntry ?: transaction { ChapterTable.selectAll().where { ChapterTable.id eq chapterId }.first() }
|
||||
val mangaEntry = transaction { MangaTable.selectAll().where { MangaTable.id eq mangaId }.first() }
|
||||
val source = getSourceOrStub(mangaEntry[MangaTable.sourceReference])
|
||||
val source = getCatalogueSourceOrStub(mangaEntry[MangaTable.sourceReference])
|
||||
|
||||
val pageList =
|
||||
source
|
||||
|
||||
@@ -10,6 +10,7 @@ package suwayomi.tachidesk.manga.impl.extension
|
||||
import android.net.Uri
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.source.SourceFactory
|
||||
import eu.kanade.tachiyomi.source.local.LocalSource
|
||||
@@ -40,7 +41,7 @@ import suwayomi.tachidesk.manga.impl.util.PackageTools.dex2jar
|
||||
import suwayomi.tachidesk.manga.impl.util.PackageTools.getPackageInfo
|
||||
import suwayomi.tachidesk.manga.impl.util.PackageTools.loadExtensionSources
|
||||
import suwayomi.tachidesk.manga.impl.util.network.await
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetSource
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetCatalogueSource
|
||||
import suwayomi.tachidesk.manga.impl.util.storage.ImageResponse.clearCachedImage
|
||||
import suwayomi.tachidesk.manga.impl.util.storage.ImageResponse.getImageResponse
|
||||
import suwayomi.tachidesk.manga.impl.util.storage.ImageResponse.saveImage
|
||||
@@ -154,16 +155,7 @@ object Extension {
|
||||
|
||||
var contentWarning = packageInfo.applicationInfo.metaData.getInt(METADATA_CONTENT_WARNING)
|
||||
if (contentWarning == 0) {
|
||||
contentWarning = packageInfo.applicationInfo.metaData
|
||||
.getString(METADATA_CONTENT_WARNING)
|
||||
?.toIntOrNull()
|
||||
?: 0
|
||||
if (contentWarning == 0) {
|
||||
contentWarning = packageInfo.applicationInfo.metaData
|
||||
.getString(METADATA_NSFW)
|
||||
?.toIntOrNull()
|
||||
?: 0
|
||||
}
|
||||
contentWarning = packageInfo.applicationInfo.metaData.getInt(METADATA_NSFW)
|
||||
}
|
||||
|
||||
val className =
|
||||
@@ -173,7 +165,7 @@ object Extension {
|
||||
|
||||
dex2jar(apkFilePath, jarFilePath, fileNameWithoutType)
|
||||
extractAssetsFromApk(apkFilePath, jarFilePath)
|
||||
extractAndCacheApkIcon(apkFilePath, packageInfo.packageName)
|
||||
extractAndCacheApkIcon(apkFilePath, apkName)
|
||||
|
||||
// clean up
|
||||
File(apkFilePath).delete()
|
||||
@@ -181,12 +173,12 @@ object Extension {
|
||||
try {
|
||||
// collect sources from the extension
|
||||
val extensionMainClassInstance = loadExtensionSources(jarFilePath, className)
|
||||
val sources: List<Source> =
|
||||
val sources: List<CatalogueSource> =
|
||||
when (extensionMainClassInstance) {
|
||||
is Source -> listOf(extensionMainClassInstance)
|
||||
is SourceFactory -> extensionMainClassInstance.createSources()
|
||||
else -> throw RuntimeException("Unknown source class type! ${extensionMainClassInstance.javaClass}")
|
||||
}
|
||||
}.map { it as CatalogueSource }
|
||||
|
||||
val langs = sources.map { it.lang }.toSet()
|
||||
val extensionLang =
|
||||
@@ -265,7 +257,7 @@ object Extension {
|
||||
|
||||
private fun extractAndCacheApkIcon(
|
||||
apkFilePath: String,
|
||||
pkgName: String,
|
||||
apkName: String,
|
||||
) {
|
||||
val iconCacheDir = "${applicationDirs.extensionsRoot}/icon"
|
||||
try {
|
||||
@@ -278,15 +270,15 @@ object Extension {
|
||||
?.first
|
||||
}
|
||||
if (iconData == null) {
|
||||
logger.warn { "No icon found in APK $pkgName" }
|
||||
logger.warn { "No icon found in APK $apkName" }
|
||||
return
|
||||
}
|
||||
|
||||
File(iconCacheDir).mkdirs()
|
||||
clearCachedImage(iconCacheDir, pkgName)
|
||||
saveImage("$iconCacheDir/$pkgName", iconData.inputStream(), null)
|
||||
clearCachedImage(iconCacheDir, apkName)
|
||||
saveImage("$iconCacheDir/$apkName", iconData.inputStream(), null)
|
||||
} catch (e: Exception) {
|
||||
logger.warn(e) { "Failed to extract icon from APK $pkgName" }
|
||||
logger.warn(e) { "Failed to extract icon from APK $apkName" }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -379,7 +371,7 @@ object Extension {
|
||||
|
||||
SourceTable.deleteWhere { SourceTable.extension eq extensionId }
|
||||
|
||||
if (extensionRecord[ExtensionTable.isObsolete] || extensionRecord[ExtensionTable.apkUrl] == null) {
|
||||
if (extensionRecord[ExtensionTable.isObsolete]) {
|
||||
ExtensionTable.deleteWhere { ExtensionTable.pkgName eq pkgName }
|
||||
} else {
|
||||
ExtensionTable.update({ ExtensionTable.pkgName eq pkgName }) {
|
||||
@@ -397,7 +389,7 @@ object Extension {
|
||||
PackageTools.jarLoaderMap.remove(jarPath)?.close()
|
||||
|
||||
// clear all loaded sources
|
||||
sources.forEach { GetSource.unregisterSource(it) }
|
||||
sources.forEach { GetCatalogueSource.unregisterCatalogueSource(it) }
|
||||
|
||||
File(jarPath).delete()
|
||||
}
|
||||
|
||||
@@ -222,48 +222,6 @@ object Track {
|
||||
}
|
||||
}
|
||||
|
||||
fun bindTrackRecord(
|
||||
mangaId: Int,
|
||||
trackRecordId: Int,
|
||||
): Int {
|
||||
val (trackRecord, existingTrackRecord) =
|
||||
transaction {
|
||||
val trackRecord =
|
||||
TrackRecordTable
|
||||
.selectAll()
|
||||
.where {
|
||||
(TrackRecordTable.id eq trackRecordId)
|
||||
}.first()
|
||||
.toTrackRecordDataClass()
|
||||
|
||||
val existingTrackRecord =
|
||||
TrackRecordTable
|
||||
.selectAll()
|
||||
.where {
|
||||
(TrackRecordTable.mangaId eq mangaId) and (TrackRecordTable.trackerId eq trackRecord.trackerId)
|
||||
}.firstOrNull()
|
||||
?.toTrackRecordDataClass()
|
||||
|
||||
trackRecord to existingTrackRecord
|
||||
}
|
||||
|
||||
val isAlreadyBoundToManga = trackRecord.mangaId == mangaId
|
||||
if (isAlreadyBoundToManga) {
|
||||
return trackRecordId
|
||||
}
|
||||
|
||||
val hasRecordForTracker = existingTrackRecord != null
|
||||
if (hasRecordForTracker) {
|
||||
val updatedTrack = trackRecord.copy(id = existingTrackRecord.id, mangaId = mangaId).toTrack()
|
||||
|
||||
return updateTrackRecord(updatedTrack)
|
||||
}
|
||||
|
||||
val newTrack = trackRecord.copy(mangaId = mangaId).toTrack()
|
||||
|
||||
return insertTrackRecord(newTrack)
|
||||
}
|
||||
|
||||
suspend fun refresh(recordId: Int) {
|
||||
val recordDb =
|
||||
transaction {
|
||||
@@ -465,9 +423,9 @@ object Track {
|
||||
}
|
||||
}
|
||||
|
||||
fun updateTrackRecord(track: Track): Int = updateTrackRecords(listOf(track)).first()
|
||||
fun updateTrackRecord(track: Track) = updateTrackRecords(listOf(track))
|
||||
|
||||
fun updateTrackRecords(tracks: List<Track>): List<Int> =
|
||||
fun updateTrackRecords(tracks: List<Track>) =
|
||||
transaction {
|
||||
if (tracks.isNotEmpty()) {
|
||||
BatchUpdateStatement(TrackRecordTable)
|
||||
@@ -489,8 +447,6 @@ object Track {
|
||||
}.toExecutable()
|
||||
.execute(this@transaction)
|
||||
}
|
||||
|
||||
tracks.map { it.id!! }
|
||||
}
|
||||
|
||||
fun insertTrackRecord(track: Track): Int = insertTrackRecords(listOf(track)).first()
|
||||
|
||||
@@ -11,7 +11,7 @@ import io.github.oshai.kotlinlogging.KotlinLogging
|
||||
import org.jetbrains.exposed.v1.core.eq
|
||||
import org.jetbrains.exposed.v1.jdbc.selectAll
|
||||
import org.jetbrains.exposed.v1.jdbc.transactions.transaction
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetSource
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetCatalogueSource
|
||||
import suwayomi.tachidesk.manga.model.table.ChapterTable
|
||||
import suwayomi.tachidesk.manga.model.table.MangaTable
|
||||
import suwayomi.tachidesk.server.ApplicationDirs
|
||||
@@ -37,7 +37,7 @@ private fun getMangaDir(
|
||||
private fun getMangaDir(mangaId: Int): String =
|
||||
transaction {
|
||||
val mangaEntry = MangaTable.selectAll().where { MangaTable.id eq mangaId }.first()
|
||||
val source = GetSource.getSourceOrStub(mangaEntry[MangaTable.sourceReference])
|
||||
val source = GetCatalogueSource.getCatalogueSourceOrStub(mangaEntry[MangaTable.sourceReference])
|
||||
|
||||
getMangaDir(mangaEntry[MangaTable.title], source.toString())
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ package suwayomi.tachidesk.manga.impl.util.source
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.source.SourceFactory
|
||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
@@ -21,14 +22,14 @@ import suwayomi.tachidesk.server.ApplicationDirs
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
object GetSource {
|
||||
object GetCatalogueSource {
|
||||
private val logger = KotlinLogging.logger { }
|
||||
|
||||
private val sourceCache = ConcurrentHashMap<Long, Source>()
|
||||
private val sourceCache = ConcurrentHashMap<Long, CatalogueSource>()
|
||||
private val applicationDirs: ApplicationDirs by injectLazy()
|
||||
|
||||
private fun getSource(sourceId: Long): Source? {
|
||||
val cachedResult: Source? = sourceCache[sourceId]
|
||||
private fun getCatalogueSource(sourceId: Long): CatalogueSource? {
|
||||
val cachedResult: CatalogueSource? = sourceCache[sourceId]
|
||||
if (cachedResult != null) {
|
||||
return cachedResult
|
||||
}
|
||||
@@ -61,25 +62,25 @@ object GetSource {
|
||||
return sourceCache[sourceId]!!
|
||||
}
|
||||
|
||||
fun getSourceOrNull(sourceId: Long): Source? =
|
||||
fun getCatalogueSourceOrNull(sourceId: Long): CatalogueSource? =
|
||||
try {
|
||||
getSource(sourceId)
|
||||
getCatalogueSource(sourceId)
|
||||
} catch (e: Exception) {
|
||||
logger.warn(e) { "getCatalogueSource($sourceId) failed" }
|
||||
null
|
||||
}
|
||||
|
||||
fun getSourceOrStub(sourceId: Long): Source = getSourceOrNull(sourceId) ?: StubSource(sourceId)
|
||||
fun getCatalogueSourceOrStub(sourceId: Long): CatalogueSource = getCatalogueSourceOrNull(sourceId) ?: StubSource(sourceId)
|
||||
|
||||
fun registerSource(sourcePair: Pair<Long, Source>) {
|
||||
fun registerCatalogueSource(sourcePair: Pair<Long, CatalogueSource>) {
|
||||
sourceCache += sourcePair
|
||||
}
|
||||
|
||||
fun unregisterSource(sourceId: Long) {
|
||||
fun unregisterCatalogueSource(sourceId: Long) {
|
||||
sourceCache.remove(sourceId)
|
||||
}
|
||||
|
||||
fun unregisterAllSources() {
|
||||
fun unregisterAllCatalogueSources() {
|
||||
(sourceCache - 0L).forEach { (id, _) ->
|
||||
sourceCache.remove(id)
|
||||
}
|
||||
@@ -23,7 +23,7 @@ object ExtensionTable : IntIdTable() {
|
||||
|
||||
val name = varchar("name", 128)
|
||||
val pkgName = varchar("pkg_name", 128)
|
||||
val apkUrl = varchar("apk_url", 2048).nullable()
|
||||
val apkUrl = varchar("apk_url", 2048)
|
||||
val extensionLib = varchar("extension_lib", 16).nullable()
|
||||
val versionName = varchar("version_name", 16)
|
||||
val versionCode = long("version_code")
|
||||
|
||||
@@ -22,7 +22,7 @@ import org.jetbrains.exposed.v1.jdbc.andWhere
|
||||
import org.jetbrains.exposed.v1.jdbc.select
|
||||
import org.jetbrains.exposed.v1.jdbc.transactions.transaction
|
||||
import suwayomi.tachidesk.manga.impl.MangaList.insertOrUpdate
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetSource
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetCatalogueSource
|
||||
import suwayomi.tachidesk.manga.model.dataclass.toGenreList
|
||||
import suwayomi.tachidesk.manga.model.table.CategoryMangaTable
|
||||
import suwayomi.tachidesk.manga.model.table.CategoryTable
|
||||
@@ -231,7 +231,7 @@ object MangaRepository {
|
||||
pageNum: Int,
|
||||
sort: String,
|
||||
): Pair<List<OpdsMangaAcqEntry>, Boolean> {
|
||||
val source = GetSource.getSourceOrStub(sourceId)
|
||||
val source = GetCatalogueSource.getCatalogueSourceOrStub(sourceId)
|
||||
val mangasPage: MangasPage =
|
||||
if (sort == "latest" && source.supportsLatest) {
|
||||
source.getLatestUpdates(pageNum)
|
||||
|
||||
@@ -14,7 +14,7 @@ import org.koin.core.context.stopKoin
|
||||
import suwayomi.tachidesk.manga.impl.Source
|
||||
import suwayomi.tachidesk.manga.impl.extension.Extension
|
||||
import suwayomi.tachidesk.manga.impl.extension.ExtensionsList
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetSource
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetCatalogueSource
|
||||
import suwayomi.tachidesk.server.applicationSetup
|
||||
import suwayomi.tachidesk.server.settings.SettingsRegistry
|
||||
import suwayomi.tachidesk.test.BASE_PATH
|
||||
@@ -51,7 +51,7 @@ class CloudFlareTest {
|
||||
Source
|
||||
.getSourceList()
|
||||
.firstNotNullOf { it.id.toLong().takeIf { it == 3122156392225024195L } }
|
||||
.let(GetSource::getSourceOrNull) as HttpSource
|
||||
.let(GetCatalogueSource::getCatalogueSourceOrNull) as HttpSource
|
||||
}
|
||||
setLoggingEnabled(true)
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ import suwayomi.tachidesk.manga.impl.extension.Extension.installExtension
|
||||
import suwayomi.tachidesk.manga.impl.extension.Extension.uninstallExtension
|
||||
import suwayomi.tachidesk.manga.impl.extension.Extension.updateExtension
|
||||
import suwayomi.tachidesk.manga.impl.extension.ExtensionsList.getExtensionList
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetSource.getSourceOrNull
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetCatalogueSource.getCatalogueSourceOrNull
|
||||
import suwayomi.tachidesk.manga.model.dataclass.ExtensionDataClass
|
||||
import suwayomi.tachidesk.server.applicationSetup
|
||||
import suwayomi.tachidesk.server.settings.SettingsRegistry
|
||||
@@ -82,7 +82,7 @@ class TestExtensionCompatibility {
|
||||
.filter {
|
||||
// filter local source
|
||||
it.id.toLong() != 0L
|
||||
}.map { getSourceOrNull(it.id.toLong())!! as HttpSource }
|
||||
}.map { getCatalogueSourceOrNull(it.id.toLong())!! as HttpSource }
|
||||
}
|
||||
setLoggingEnabled(true)
|
||||
File("$BASE_PATH/sources.txt").writeText(sources.joinToString("\n") { "${it.name} - ${it.lang.uppercase()} - ${it.id}" })
|
||||
|
||||
@@ -24,8 +24,8 @@ import suwayomi.tachidesk.manga.impl.Search.SerializableGroup
|
||||
import suwayomi.tachidesk.manga.impl.Search.getFilterList
|
||||
import suwayomi.tachidesk.manga.impl.Search.setFilter
|
||||
import suwayomi.tachidesk.manga.impl.Search.sourceSearch
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetSource.registerSource
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetSource.unregisterSource
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetCatalogueSource.registerCatalogueSource
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetCatalogueSource.unregisterCatalogueSource
|
||||
import suwayomi.tachidesk.manga.impl.util.source.StubSource
|
||||
import suwayomi.tachidesk.test.ApplicationTest
|
||||
import suwayomi.tachidesk.test.createSMangas
|
||||
@@ -53,7 +53,7 @@ class SearchTest : ApplicationTest() {
|
||||
|
||||
@BeforeAll
|
||||
fun setup() {
|
||||
registerSource(sourceId to source)
|
||||
registerCatalogueSource(sourceId to source)
|
||||
|
||||
this.source.mangas = createSMangas(mangasCount)
|
||||
}
|
||||
@@ -70,7 +70,7 @@ class SearchTest : ApplicationTest() {
|
||||
|
||||
@AfterAll
|
||||
fun teardown() {
|
||||
unregisterSource(this.sourceId)
|
||||
unregisterCatalogueSource(this.sourceId)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -347,7 +347,7 @@ class FilterListTest : ApplicationTest() {
|
||||
private fun registerSource(sourceClass: KClass<*>): EmptyFilterListSource =
|
||||
synchronized(sourceClass) {
|
||||
val source = sourceClass.primaryConstructor!!.call(sourceCount) as EmptyFilterListSource
|
||||
registerSource(sourceCount to source)
|
||||
registerCatalogueSource(sourceCount to source)
|
||||
sourceCount++
|
||||
source
|
||||
}
|
||||
@@ -355,7 +355,7 @@ class FilterListTest : ApplicationTest() {
|
||||
@AfterAll
|
||||
@JvmStatic
|
||||
fun teardown() {
|
||||
(0 until sourceCount).forEach { unregisterSource(it) }
|
||||
(0 until sourceCount).forEach { unregisterCatalogueSource(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user