mirror of
https://github.com/moku-project/Moku.git
synced 2026-06-13 09:19:56 -05:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d6ea1fab67 | |||
| bf19ee02bc | |||
| 09d794da96 | |||
| baece20f46 | |||
| b170a151f0 | |||
| 6a84280db0 | |||
| be38d87bec | |||
| ab9305e6ab | |||
| ceb9ba12d7 | |||
| 2fa33bc928 |
@@ -1,11 +1,15 @@
|
|||||||
# Sourced by CI jobs that need versions from nix/versions.nix.
|
# Sourced by CI jobs that need versions from nix/versions.nix.
|
||||||
# Usage: source .github/read_versions.sh
|
# Usage: source .github/read_versions.sh
|
||||||
# Exports: MOKU_VERSION SUWA_VERSION SUWA_HASH_LINUX SUWA_HASH_MACOS_ARM64 SUWA_HASH_MACOS_X64 SUWA_HASH_WINDOWS
|
# Exports: MOKU_VERSION SUWA_VERSION SUWA_HASH_LINUX SUWA_HASH_MACOS_ARM64 SUWA_HASH_MACOS_X64 SUWA_HASH_WINDOWS
|
||||||
|
#
|
||||||
|
# Uses only POSIX -E grep (no -P) so this works on both GNU grep (Linux/Windows)
|
||||||
|
# and BSD grep (macOS), which does not support -P/PCRE.
|
||||||
|
|
||||||
_nix="$( cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd )/nix/versions.nix"
|
_nix="$( cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd )/nix/versions.nix"
|
||||||
_t=$(cat "$_nix")
|
_t=$(cat "$_nix")
|
||||||
|
|
||||||
_pick() { echo "$_t" | grep -oP "${1}\s*=\s*\"\K[^\"]+"; }
|
# Match `key = "value"` with -E, then strip the surrounding quotes.
|
||||||
|
_pick() { echo "$_t" | grep -oE "${1}"'[[:space:]]*=[[:space:]]*"[^"]+"' | grep -oE '"[^"]+"' | tr -d '"'; }
|
||||||
|
|
||||||
export MOKU_VERSION=$(_pick "moku")
|
export MOKU_VERSION=$(_pick "moku")
|
||||||
export SUWA_VERSION=$(_pick "version")
|
export SUWA_VERSION=$(_pick "version")
|
||||||
|
|||||||
@@ -22,6 +22,40 @@ jobs:
|
|||||||
sudo rm -rf /usr/local/lib/android /opt/ghc /usr/share/dotnet /opt/hostedtoolcache/CodeQL
|
sudo rm -rf /usr/local/lib/android /opt/ghc /usr/share/dotnet /opt/hostedtoolcache/CodeQL
|
||||||
sudo docker image prune -af || true
|
sudo docker image prune -af || true
|
||||||
|
|
||||||
|
- uses: pnpm/action-setup@v4
|
||||||
|
with: { version: 10 }
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 22
|
||||||
|
cache: pnpm
|
||||||
|
|
||||||
|
- name: Build frontend and pack tarball
|
||||||
|
run: |
|
||||||
|
pnpm install --frozen-lockfile
|
||||||
|
pnpm build:static
|
||||||
|
tar -czf packaging/frontend-dist.tar.gz -C dist .
|
||||||
|
|
||||||
|
- name: Compute frontend-dist sha256
|
||||||
|
run: |
|
||||||
|
SHA=$(sha256sum packaging/frontend-dist.tar.gz | awk '{print $1}')
|
||||||
|
echo "FRONTEND_SHA=$SHA" >> $GITHUB_ENV
|
||||||
|
echo "frontend-dist.tar.gz sha256: $SHA"
|
||||||
|
|
||||||
|
- name: Patch frontend-dist sha256 in flatpak manifest
|
||||||
|
run: |
|
||||||
|
python3 -c "
|
||||||
|
import re, pathlib, os
|
||||||
|
p = pathlib.Path('io.github.moku_project.Moku.yml')
|
||||||
|
content = p.read_text()
|
||||||
|
# Replace the sha256 line that follows the frontend-dist.tar.gz source entry
|
||||||
|
content = re.sub(
|
||||||
|
r'(path: packaging/frontend-dist\.tar\.gz\n\s+sha256: )[0-9a-f]{64}',
|
||||||
|
r'\g<1>' + os.environ['FRONTEND_SHA'],
|
||||||
|
content
|
||||||
|
)
|
||||||
|
p.write_text(content)
|
||||||
|
"
|
||||||
|
|
||||||
- name: Install flatpak tooling
|
- name: Install flatpak tooling
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
@@ -34,12 +68,11 @@ jobs:
|
|||||||
path: ~/.local/share/flatpak
|
path: ~/.local/share/flatpak
|
||||||
key: flatpak-runtimes-gnome48-rust-stable
|
key: flatpak-runtimes-gnome48-rust-stable
|
||||||
|
|
||||||
- name: Install runtime, SDK and rust-stable extension
|
- name: Install runtime and SDK
|
||||||
run: |
|
run: |
|
||||||
flatpak --user install -y --noninteractive flathub \
|
flatpak --user install -y --noninteractive flathub \
|
||||||
org.gnome.Platform//48 \
|
org.gnome.Platform//48 \
|
||||||
org.gnome.Sdk//48 \
|
org.gnome.Sdk//48
|
||||||
org.freedesktop.Sdk.Extension.rust-stable//48
|
|
||||||
|
|
||||||
- name: Build flatpak
|
- name: Build flatpak
|
||||||
run: |
|
run: |
|
||||||
@@ -64,14 +97,16 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
run: |
|
run: |
|
||||||
for i in $(seq 1 12); do
|
# Poll for up to 10 minutes — the release is created by the Windows workflow
|
||||||
|
# which may still be building when the flatpak bundle finishes.
|
||||||
|
for i in $(seq 1 40); do
|
||||||
RELEASE_ID=$(curl -s -H "Authorization: Bearer $GITHUB_TOKEN" \
|
RELEASE_ID=$(curl -s -H "Authorization: Bearer $GITHUB_TOKEN" \
|
||||||
"https://api.github.com/repos/moku-project/Moku/releases" \
|
"https://api.github.com/repos/moku-project/Moku/releases" \
|
||||||
| jq -r '.[] | select(.tag_name == "v${{ github.event.inputs.version }}") | .id' | head -1)
|
| jq -r '.[] | select(.tag_name == "v${{ github.event.inputs.version }}") | .id' | head -1)
|
||||||
[ -n "$RELEASE_ID" ] && break
|
[ -n "$RELEASE_ID" ] && break
|
||||||
echo "Waiting for release... attempt $i"; sleep 15
|
echo "Waiting for release... attempt $i/40"; sleep 15
|
||||||
done
|
done
|
||||||
[ -z "$RELEASE_ID" ] && { echo "ERROR: release not found"; exit 1; }
|
[ -z "$RELEASE_ID" ] && { echo "ERROR: release not found after polling"; exit 1; }
|
||||||
|
|
||||||
curl -s -X POST \
|
curl -s -X POST \
|
||||||
-H "Authorization: Bearer $GITHUB_TOKEN" \
|
-H "Authorization: Bearer $GITHUB_TOKEN" \
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: pnpm/action-setup@v4
|
- uses: pnpm/action-setup@v4
|
||||||
with: { version: latest }
|
with: { version: 10 }
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 22
|
node-version: 22
|
||||||
@@ -52,7 +52,7 @@ jobs:
|
|||||||
with: { workspaces: src-tauri }
|
with: { workspaces: src-tauri }
|
||||||
|
|
||||||
- uses: pnpm/action-setup@v4
|
- uses: pnpm/action-setup@v4
|
||||||
with: { version: latest }
|
with: { version: 10 }
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 22
|
node-version: 22
|
||||||
@@ -91,7 +91,13 @@ jobs:
|
|||||||
|
|
||||||
- name: Patch tauri.conf.json for CI
|
- name: Patch tauri.conf.json for CI
|
||||||
run: |
|
run: |
|
||||||
sed -i '' 's/"beforeBuildCommand": "pnpm build"/"beforeBuildCommand": ""/' src-tauri/tauri.conf.json
|
python3 -c "
|
||||||
|
import json, pathlib
|
||||||
|
p = pathlib.Path('src-tauri/tauri.conf.json')
|
||||||
|
c = json.loads(p.read_text())
|
||||||
|
c.setdefault('build', {})['beforeBuildCommand'] = ''
|
||||||
|
p.write_text(json.dumps(c, indent=2))
|
||||||
|
"
|
||||||
|
|
||||||
- name: Build Tauri app (aarch64)
|
- name: Build Tauri app (aarch64)
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: pnpm/action-setup@v4
|
- uses: pnpm/action-setup@v4
|
||||||
with: { version: latest }
|
with: { version: 10 }
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 22
|
node-version: 22
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: pnpm/action-setup@v4
|
- uses: pnpm/action-setup@v4
|
||||||
with: { version: latest }
|
with: { version: 10 }
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 22
|
node-version: 22
|
||||||
@@ -51,7 +51,7 @@ jobs:
|
|||||||
with: { workspaces: src-tauri }
|
with: { workspaces: src-tauri }
|
||||||
|
|
||||||
- uses: pnpm/action-setup@v4
|
- uses: pnpm/action-setup@v4
|
||||||
with: { version: latest }
|
with: { version: 10 }
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 22
|
node-version: 22
|
||||||
@@ -88,7 +88,13 @@ jobs:
|
|||||||
- name: Patch tauri.conf.json for CI
|
- name: Patch tauri.conf.json for CI
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
sed -i 's/"beforeBuildCommand": "pnpm build"/"beforeBuildCommand": ""/' src-tauri/tauri.conf.json
|
python3 -c "
|
||||||
|
import json, pathlib
|
||||||
|
p = pathlib.Path('src-tauri/tauri.conf.json')
|
||||||
|
c = json.loads(p.read_text())
|
||||||
|
c.setdefault('build', {})['beforeBuildCommand'] = ''
|
||||||
|
p.write_text(json.dumps(c, indent=2))
|
||||||
|
"
|
||||||
|
|
||||||
- name: Delete existing draft release
|
- name: Delete existing draft release
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ source=(
|
|||||||
)
|
)
|
||||||
noextract=("Suwayomi-Server-v2.1.2087.jar")
|
noextract=("Suwayomi-Server-v2.1.2087.jar")
|
||||||
sha256sums=(
|
sha256sums=(
|
||||||
'fc1c8268b812e70e56460c8930ca8ae83bcd30eea5903ddfef4e30a3a9a5c1cc'
|
'589b389b356a48d54ad4022e68eaac165a1de654d0b98edec79ebbab2c4a1275'
|
||||||
'f589a422674252394c13b289a9c8be691905bf583efb7f4d5f1501ae5e91e6b3'
|
'f589a422674252394c13b289a9c8be691905bf583efb7f4d5f1501ae5e91e6b3'
|
||||||
)
|
)
|
||||||
b2sums=(
|
b2sums=(
|
||||||
|
|||||||
@@ -80,6 +80,9 @@ modules:
|
|||||||
|
|
||||||
- name: libayatana-indicator
|
- name: libayatana-indicator
|
||||||
buildsystem: cmake-ninja
|
buildsystem: cmake-ninja
|
||||||
|
build-options:
|
||||||
|
env:
|
||||||
|
PKG_CONFIG_PATH: /app/lib/pkgconfig:/app/share/pkgconfig
|
||||||
config-opts:
|
config-opts:
|
||||||
- -DENABLE_TESTS=OFF
|
- -DENABLE_TESTS=OFF
|
||||||
- -DGSETTINGS_COMPILE=OFF
|
- -DGSETTINGS_COMPILE=OFF
|
||||||
@@ -90,6 +93,9 @@ modules:
|
|||||||
|
|
||||||
- name: libayatana-appindicator
|
- name: libayatana-appindicator
|
||||||
buildsystem: cmake-ninja
|
buildsystem: cmake-ninja
|
||||||
|
build-options:
|
||||||
|
env:
|
||||||
|
PKG_CONFIG_PATH: /app/lib/pkgconfig:/app/share/pkgconfig
|
||||||
config-opts:
|
config-opts:
|
||||||
- -DENABLE_TESTS=OFF
|
- -DENABLE_TESTS=OFF
|
||||||
- -DENABLE_BINDINGS_MONO=OFF
|
- -DENABLE_BINDINGS_MONO=OFF
|
||||||
@@ -232,6 +238,7 @@ modules:
|
|||||||
XDG_DATA_HOME: /run/build/moku/xdg-data
|
XDG_DATA_HOME: /run/build/moku/xdg-data
|
||||||
TAURI_SKIP_DEVSERVER_CHECK: 'true'
|
TAURI_SKIP_DEVSERVER_CHECK: 'true'
|
||||||
PKG_CONFIG_PATH: /usr/lib/pkgconfig:/usr/share/pkgconfig:/app/lib/pkgconfig
|
PKG_CONFIG_PATH: /usr/lib/pkgconfig:/usr/share/pkgconfig:/app/lib/pkgconfig
|
||||||
|
TAURI_CONFIG: '{"build":{"devUrl":null,"frontendDist":"../dist"},"app":{"windows":[{"devtools":false}]},"bundle":{"externalBin":[]}}'
|
||||||
build-commands:
|
build-commands:
|
||||||
- tar -xzf frontend-dist.tar.gz
|
- tar -xzf frontend-dist.tar.gz
|
||||||
- . /usr/lib/sdk/rust-stable/enable.sh && PKG_CONFIG_PATH=/usr/lib/pkgconfig:/usr/share/pkgconfig:/app/lib/pkgconfig cargo build --release --manifest-path src-tauri/Cargo.toml
|
- . /usr/lib/sdk/rust-stable/enable.sh && PKG_CONFIG_PATH=/usr/lib/pkgconfig:/usr/share/pkgconfig:/app/lib/pkgconfig cargo build --release --manifest-path src-tauri/Cargo.toml
|
||||||
@@ -244,8 +251,7 @@ modules:
|
|||||||
sources:
|
sources:
|
||||||
- type: git
|
- type: git
|
||||||
url: https://github.com/moku-project/Moku.git
|
url: https://github.com/moku-project/Moku.git
|
||||||
tag: v0.10.0
|
commit: baece20f467d2c7d4cebaa9ea8892980aa93aa10
|
||||||
commit: 239960683b6c7f1347e1798b0e179a8a46628728
|
|
||||||
- type: file
|
- type: file
|
||||||
path: packaging/frontend-dist.tar.gz
|
path: packaging/frontend-dist.tar.gz
|
||||||
sha256: 676ec2273ffd9a69248849c5d51dc4d59a5d5b68fbba7a4fe7e7b572a5f25f14
|
sha256: 676ec2273ffd9a69248849c5d51dc4d59a5d5b68fbba7a4fe7e7b572a5f25f14
|
||||||
|
|||||||
+2
-2
@@ -11,7 +11,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
frontend = {
|
frontend = {
|
||||||
pnpmHash = "sha256-18twdFhprV9v9hzvqxuVDHD6Tm4zHNDJs7s6l/7ClBo=";
|
pnpmHash = "sha256-fBkNpQXEeGZNbrpx7+0xVYYtQ6dGvpgRflCGPoxvnVY=";
|
||||||
distHash = "7db288b4b54277aa82b6ec5b21fc31a1e71f8246c50a74777500083b806c1fa5";
|
distHash = "7db288b4b54277aa82b6ec5b21fc31a1e71f8246c50a74777500083b806c1fa5";
|
||||||
distHashSri = "sha256-Z27CJz/9mmkkiEnF1R3E1ZpdW2j7unpP5+e1cqXyXxQ=";
|
distHashSri = "sha256-Z27CJz/9mmkkiEnF1R3E1ZpdW2j7unpP5+e1cqXyXxQ=";
|
||||||
};
|
};
|
||||||
@@ -21,5 +21,5 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
gitCommit = "239960683b6c7f1347e1798b0e179a8a46628728";
|
gitCommit = "239960683b6c7f1347e1798b0e179a8a46628728";
|
||||||
tarballHash = "";
|
tarballHash = "589b389b356a48d54ad4022e68eaac165a1de654d0b98edec79ebbab2c4a1275";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4992,40 +4992,40 @@
|
|||||||
{
|
{
|
||||||
"type": "archive",
|
"type": "archive",
|
||||||
"archive-type": "tar-gzip",
|
"archive-type": "tar-gzip",
|
||||||
"url": "https://static.crates.io/crates/time/time-0.3.48.crate",
|
"url": "https://static.crates.io/crates/time/time-0.3.47.crate",
|
||||||
"sha256": "fc1aa89044e7786ffb2ec017acb22cb7de5b0be46d0f21aea2b224b8561e5db2",
|
"sha256": "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c",
|
||||||
"dest": "cargo/vendor/time-0.3.48"
|
"dest": "cargo/vendor/time-0.3.47"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "inline",
|
"type": "inline",
|
||||||
"contents": "{\"package\": \"fc1aa89044e7786ffb2ec017acb22cb7de5b0be46d0f21aea2b224b8561e5db2\", \"files\": {}}",
|
"contents": "{\"package\": \"743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c\", \"files\": {}}",
|
||||||
"dest": "cargo/vendor/time-0.3.48",
|
"dest": "cargo/vendor/time-0.3.47",
|
||||||
"dest-filename": ".cargo-checksum.json"
|
"dest-filename": ".cargo-checksum.json"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "archive",
|
"type": "archive",
|
||||||
"archive-type": "tar-gzip",
|
"archive-type": "tar-gzip",
|
||||||
"url": "https://static.crates.io/crates/time-core/time-core-0.1.9.crate",
|
"url": "https://static.crates.io/crates/time-core/time-core-0.1.8.crate",
|
||||||
"sha256": "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109",
|
"sha256": "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca",
|
||||||
"dest": "cargo/vendor/time-core-0.1.9"
|
"dest": "cargo/vendor/time-core-0.1.8"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "inline",
|
"type": "inline",
|
||||||
"contents": "{\"package\": \"9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109\", \"files\": {}}",
|
"contents": "{\"package\": \"7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca\", \"files\": {}}",
|
||||||
"dest": "cargo/vendor/time-core-0.1.9",
|
"dest": "cargo/vendor/time-core-0.1.8",
|
||||||
"dest-filename": ".cargo-checksum.json"
|
"dest-filename": ".cargo-checksum.json"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "archive",
|
"type": "archive",
|
||||||
"archive-type": "tar-gzip",
|
"archive-type": "tar-gzip",
|
||||||
"url": "https://static.crates.io/crates/time-macros/time-macros-0.2.28.crate",
|
"url": "https://static.crates.io/crates/time-macros/time-macros-0.2.27.crate",
|
||||||
"sha256": "9d3bfe86347f0cc659f586f01e26303ccd32418f26f30c7b0309b3ca3a07d695",
|
"sha256": "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215",
|
||||||
"dest": "cargo/vendor/time-macros-0.2.28"
|
"dest": "cargo/vendor/time-macros-0.2.27"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "inline",
|
"type": "inline",
|
||||||
"contents": "{\"package\": \"9d3bfe86347f0cc659f586f01e26303ccd32418f26f30c7b0309b3ca3a07d695\", \"files\": {}}",
|
"contents": "{\"package\": \"2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215\", \"files\": {}}",
|
||||||
"dest": "cargo/vendor/time-macros-0.2.28",
|
"dest": "cargo/vendor/time-macros-0.2.27",
|
||||||
"dest-filename": ".cargo-checksum.json"
|
"dest-filename": ".cargo-checksum.json"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
Generated
+8
-6
@@ -574,6 +574,7 @@ version = "0.5.8"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c"
|
checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"powerfmt",
|
||||||
"serde_core",
|
"serde_core",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -4249,11 +4250,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "time"
|
name = "time"
|
||||||
version = "0.3.48"
|
version = "0.3.47"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fc1aa89044e7786ffb2ec017acb22cb7de5b0be46d0f21aea2b224b8561e5db2"
|
checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"deranged",
|
"deranged",
|
||||||
|
"itoa",
|
||||||
"num-conv",
|
"num-conv",
|
||||||
"powerfmt",
|
"powerfmt",
|
||||||
"serde_core",
|
"serde_core",
|
||||||
@@ -4263,15 +4265,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "time-core"
|
name = "time-core"
|
||||||
version = "0.1.9"
|
version = "0.1.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109"
|
checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "time-macros"
|
name = "time-macros"
|
||||||
version = "0.2.28"
|
version = "0.2.27"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9d3bfe86347f0cc659f586f01e26303ccd32418f26f30c7b0309b3ca3a07d695"
|
checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"num-conv",
|
"num-conv",
|
||||||
"time-core",
|
"time-core",
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
"version": "0.10.0",
|
"version": "0.10.0",
|
||||||
"identifier": "io.github.MokuProject.Moku",
|
"identifier": "io.github.MokuProject.Moku",
|
||||||
"build": {
|
"build": {
|
||||||
"devUrl": "http://localhost:1420",
|
|
||||||
"frontendDist": "../dist",
|
"frontendDist": "../dist",
|
||||||
"beforeBuildCommand": "pnpm build:static"
|
"beforeBuildCommand": "pnpm build:static"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"build": {
|
"build": {
|
||||||
|
"devUrl": "http://localhost:1420",
|
||||||
"beforeDevCommand": "pnpm dev"
|
"beforeDevCommand": "pnpm dev"
|
||||||
},
|
},
|
||||||
"app": {
|
"app": {
|
||||||
|
|||||||
+8
-16
@@ -9,15 +9,6 @@ import { historyState } from '$lib/state/history.svelt
|
|||||||
import { readerState } from '$lib/state/reader.svelte'
|
import { readerState } from '$lib/state/reader.svelte'
|
||||||
import { seriesState } from '$lib/state/series.svelte'
|
import { seriesState } from '$lib/state/series.svelte'
|
||||||
|
|
||||||
const KEY_URL = 'moku_server_url'
|
|
||||||
const KEY_AUTH = 'moku_auth_config'
|
|
||||||
|
|
||||||
interface SavedAuth {
|
|
||||||
mode: 'NONE' | 'BASIC_AUTH' | 'UI_LOGIN'
|
|
||||||
user?: string
|
|
||||||
pass?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
async function boot() {
|
async function boot() {
|
||||||
try {
|
try {
|
||||||
const platformAdapter = detectAdapter()
|
const platformAdapter = detectAdapter()
|
||||||
@@ -43,20 +34,21 @@ async function boot() {
|
|||||||
readerState.markers = libraryData.markers
|
readerState.markers = libraryData.markers
|
||||||
historyState.load(libraryData.sessions, libraryData.dailyReadCounts)
|
historyState.load(libraryData.sessions, libraryData.dailyReadCounts)
|
||||||
|
|
||||||
const savedUrl = (await platformAdapter.getCredential(KEY_URL)) ?? 'http://127.0.0.1:4567'
|
const savedUrl = settingsState.settings.serverUrl ?? 'http://127.0.0.1:4567'
|
||||||
const savedAuthRaw = await platformAdapter.getCredential(KEY_AUTH)
|
const authMode = settingsState.settings.serverAuthMode ?? 'NONE'
|
||||||
const savedAuth: SavedAuth = savedAuthRaw ? JSON.parse(savedAuthRaw) : { mode: 'NONE' }
|
const authUser = settingsState.settings.serverAuthUser || undefined
|
||||||
|
const authPass = settingsState.settings.serverAuthPass || undefined
|
||||||
|
|
||||||
appState.serverUrl = savedUrl
|
appState.serverUrl = savedUrl
|
||||||
appState.authMode = savedAuth.mode
|
appState.authMode = authMode === 'SIMPLE_LOGIN' ? 'UI_LOGIN' : authMode
|
||||||
|
|
||||||
configureAuth(savedUrl, savedAuth.mode, savedAuth.user, savedAuth.pass)
|
configureAuth(savedUrl, authMode, authUser, authPass)
|
||||||
|
|
||||||
await serverAdapter.connect({
|
await serverAdapter.connect({
|
||||||
baseUrl: savedUrl,
|
baseUrl: savedUrl,
|
||||||
credentials:
|
credentials:
|
||||||
savedAuth.mode === 'BASIC_AUTH' && savedAuth.user && savedAuth.pass
|
authMode === 'BASIC_AUTH' && authUser && authPass
|
||||||
? { username: savedAuth.user, password: savedAuth.pass }
|
? { username: authUser, password: authPass }
|
||||||
: undefined,
|
: undefined,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -91,10 +91,11 @@
|
|||||||
const PHASE2_MS = 10000
|
const PHASE2_MS = 10000
|
||||||
|
|
||||||
function triggerExit(cb?: () => void) {
|
function triggerExit(cb?: () => void) {
|
||||||
if (exitLock) return
|
console.log('[splash] triggerExit called — exitLock:', exitLock, 'mode:', mode, 'cb:', cb?.name ?? String(cb))
|
||||||
|
if (exitLock) { console.log('[splash] triggerExit blocked by exitLock'); return }
|
||||||
exitLock = true
|
exitLock = true
|
||||||
exiting = true
|
exiting = true
|
||||||
setTimeout(() => cb?.(), EXIT_MS)
|
setTimeout(() => { console.log('[splash] triggerExit timeout — calling cb'); cb?.() }, EXIT_MS)
|
||||||
}
|
}
|
||||||
|
|
||||||
let animFrame = 0
|
let animFrame = 0
|
||||||
@@ -125,11 +126,13 @@
|
|||||||
})
|
})
|
||||||
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
|
console.log('[splash] ringFull effect — ringFull:', ringFull, 'mode:', mode, 'exitLock:', exitLock)
|
||||||
if (!ringFull || mode === 'locked') { exitLock = false; exiting = false; return }
|
if (!ringFull || mode === 'locked') { exitLock = false; exiting = false; return }
|
||||||
cancelAnimationFrame(animFrame)
|
cancelAnimationFrame(animFrame)
|
||||||
animFrame = 0
|
animFrame = 0
|
||||||
ringProg = 1
|
ringProg = 1
|
||||||
setTimeout(() => triggerExit(onReady), 650)
|
const t = setTimeout(() => { console.log('[splash] ringFull timeout firing — calling triggerExit(onReady)'); triggerExit(onReady) }, 650)
|
||||||
|
return () => { console.log('[splash] ringFull effect cleanup — cancelling timeout'); clearTimeout(t) }
|
||||||
})
|
})
|
||||||
|
|
||||||
function submitPin() {
|
function submitPin() {
|
||||||
@@ -506,9 +509,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{:else}
|
{:else if isTauri || failed || notConfigured || ringFull}
|
||||||
<div style="position:relative;width:{ringSize}px;height:{ringSize}px;margin-bottom:20px;display:flex;align-items:center;justify-content:center">
|
<div style="position:relative;width:{ringSize}px;height:{ringSize}px;margin-bottom:20px;display:flex;align-items:center;justify-content:center">
|
||||||
{#if !failed && !notConfigured}
|
{#if !failed && !notConfigured && isTauri}
|
||||||
<svg width={ringSize} height={ringSize} class="loading-ring" style="position:absolute;top:0;left:0;pointer-events:none">
|
<svg width={ringSize} height={ringSize} class="loading-ring" style="position:absolute;top:0;left:0;pointer-events:none">
|
||||||
<circle cx={ringC} cy={ringC} r={ringR} fill="none" stroke="var(--border-base)" stroke-width="2" />
|
<circle cx={ringC} cy={ringC} r={ringR} fill="none" stroke="var(--border-base)" stroke-width="2" />
|
||||||
<circle cx={ringC} cy={ringC} r={ringR} fill="none" stroke="var(--accent)" stroke-width="2"
|
<circle cx={ringC} cy={ringC} r={ringR} fill="none" stroke="var(--accent)" stroke-width="2"
|
||||||
|
|||||||
@@ -13,9 +13,9 @@
|
|||||||
import ExtensionLibrary from "$lib/components/extensions/ExtensionLibrary.svelte";
|
import ExtensionLibrary from "$lib/components/extensions/ExtensionLibrary.svelte";
|
||||||
|
|
||||||
const anims = $derived(settingsState.settings.qolAnimations ?? true);
|
const anims = $derived(settingsState.settings.qolAnimations ?? true);
|
||||||
const cols = $derived(settingsState.settings.libraryCols ?? 5);
|
const cols = $derived(settingsState.settings.libraryPageSize ?? 5);
|
||||||
const cropCovers = $derived(settingsState.settings.cropCovers ?? true);
|
const cropCovers = $derived(settingsState.settings.libraryCropCovers ?? true);
|
||||||
const statsAlways = $derived(settingsState.settings.statsAlways ?? false);
|
const statsAlways = $derived(settingsState.settings.libraryStatsAlways ?? false);
|
||||||
|
|
||||||
let tabsEl = $state<HTMLDivElement | undefined>(undefined);
|
let tabsEl = $state<HTMLDivElement | undefined>(undefined);
|
||||||
let tabIndicator = $state({ left: 0, width: 0 });
|
let tabIndicator = $state({ left: 0, width: 0 });
|
||||||
@@ -337,14 +337,14 @@
|
|||||||
{:else}
|
{:else}
|
||||||
<div class="list">
|
<div class="list">
|
||||||
{#if showLocal}
|
{#if showLocal}
|
||||||
<div class="local-row" style="cursor:pointer" onclick={() => libraryTarget = { pkgName: '__local__', extensionName: 'Local Source', iconUrl: '' }}>
|
<button type="button" class="local-row" onclick={() => libraryTarget = { pkgName: '__local__', extensionName: 'Local Source', iconUrl: '' }}>
|
||||||
<div class="local-icon"><HardDrives size={18} weight="bold" /></div>
|
<div class="local-icon"><HardDrives size={18} weight="bold" /></div>
|
||||||
<div class="info">
|
<div class="info">
|
||||||
<span class="name">Local Source</span>
|
<span class="name">Local Source</span>
|
||||||
<span class="meta">Built-in · {localMangaCount} {localMangaCount === 1 ? "manga" : "manga"}</span>
|
<span class="meta">Built-in · {localMangaCount} {localMangaCount === "1" ? "manga" : "mangas"}</span>
|
||||||
</div>
|
</div>
|
||||||
<span class="local-badge">Built-in</span>
|
<span class="local-badge">Built-in</span>
|
||||||
</div>
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
{#each groups as { base, primary, variants }}
|
{#each groups as { base, primary, variants }}
|
||||||
<ExtensionCard
|
<ExtensionCard
|
||||||
@@ -404,8 +404,7 @@
|
|||||||
.repo-remove { display: flex; align-items: center; justify-content: center; width: 20px; height: 20px; border-radius: var(--radius-sm); color: var(--text-faint); flex-shrink: 0; transition: color var(--t-base), background var(--t-base); }
|
.repo-remove { display: flex; align-items: center; justify-content: center; width: 20px; height: 20px; border-radius: var(--radius-sm); color: var(--text-faint); flex-shrink: 0; transition: color var(--t-base), background var(--t-base); }
|
||||||
.repo-remove:hover:not(:disabled) { color: var(--color-error); background: var(--bg-overlay); }
|
.repo-remove:hover:not(:disabled) { color: var(--color-error); background: var(--bg-overlay); }
|
||||||
@keyframes panelSlide { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: translateY(0); } }
|
@keyframes panelSlide { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: translateY(0); } }
|
||||||
.local-row { display: flex; align-items: center; gap: var(--sp-3); padding: 8px var(--sp-3); border-radius: var(--radius-md); border: 1px solid transparent; transition: background var(--t-fast), border-color var(--t-fast); margin-bottom: 1px; }
|
.local-row { display: flex; align-items: center; gap: var(--sp-3); padding: 8px var(--sp-3); border-radius: var(--radius-md); border: 1px solid transparent; transition: background var(--t-fast), border-color var(--t-fast); margin-bottom: 1px; width: 100%; text-align: left; background: none; font: inherit; cursor: pointer; }
|
||||||
.local-row:hover { background: var(--bg-raised); border-color: var(--border-dim); }
|
|
||||||
.local-icon { width: 32px; height: 32px; border-radius: var(--radius-md); background: var(--accent-muted); border: 1px solid var(--accent-dim); display: flex; align-items: center; justify-content: center; color: var(--accent-fg); flex-shrink: 0; }
|
.local-icon { width: 32px; height: 32px; border-radius: var(--radius-md); background: var(--accent-muted); border: 1px solid var(--accent-dim); display: flex; align-items: center; justify-content: center; color: var(--accent-fg); flex-shrink: 0; }
|
||||||
.info { flex: 1; display: flex; flex-direction: column; gap: 2px; overflow: hidden; }
|
.info { flex: 1; display: flex; flex-direction: column; gap: 2px; overflow: hidden; }
|
||||||
.name { font-size: var(--text-base); font-weight: var(--weight-medium); color: var(--text-secondary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
.name { font-size: var(--text-base); font-weight: var(--weight-medium); color: var(--text-secondary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ export interface LibraryManga {
|
|||||||
thumbnailUrl: string;
|
thumbnailUrl: string;
|
||||||
unreadCount: number;
|
unreadCount: number;
|
||||||
downloadCount: number;
|
downloadCount: number;
|
||||||
source: { id: string; displayName: string };
|
source: { id: string; displayName: string } | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SourceLibrary {
|
export interface SourceLibrary {
|
||||||
@@ -31,7 +31,7 @@ export function libraryByExtension(
|
|||||||
const bySource = new Map<string, LibraryManga[]>();
|
const bySource = new Map<string, LibraryManga[]>();
|
||||||
for (const src of pkgSources) bySource.set(src.id, []);
|
for (const src of pkgSources) bySource.set(src.id, []);
|
||||||
for (const m of libraryManga) {
|
for (const m of libraryManga) {
|
||||||
if (sourceIds.has(m.source.id)) bySource.get(m.source.id)!.push(m);
|
if (m.source && sourceIds.has(m.source.id)) bySource.get(m.source.id)!.push(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
return pkgSources
|
return pkgSources
|
||||||
@@ -49,6 +49,7 @@ export function libraryCountByPkg(
|
|||||||
}
|
}
|
||||||
const counts: Record<string, number> = {};
|
const counts: Record<string, number> = {};
|
||||||
for (const m of libraryManga) {
|
for (const m of libraryManga) {
|
||||||
|
if (!m.source) continue;
|
||||||
const pkg = sourceIdToPkg.get(m.source.id);
|
const pkg = sourceIdToPkg.get(m.source.id);
|
||||||
if (pkg) counts[pkg] = (counts[pkg] ?? 0) + 1;
|
if (pkg) counts[pkg] = (counts[pkg] ?? 0) + 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
const entries = $derived(
|
const entries = $derived(
|
||||||
historyState.sessions
|
historyState.sessions
|
||||||
.filter((s, i, arr) => arr.findIndex(x => x.mangaId === s.mangaId) === i)
|
.filter((s, i, arr) => arr.findIndex(x => x.mangaId === s.mangaId) === i)
|
||||||
.slice(0, 10)
|
.slice(0, 6)
|
||||||
)
|
)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,8 @@ export const appState = $state({
|
|||||||
history: [] as unknown[],
|
history: [] as unknown[],
|
||||||
toasts: [] as unknown[],
|
toasts: [] as unknown[],
|
||||||
appDir: '',
|
appDir: '',
|
||||||
|
authUser: '',
|
||||||
|
authPass: '',
|
||||||
idleSplash: false,
|
idleSplash: false,
|
||||||
devSplash: false,
|
devSplash: false,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { appState } from '$lib/state/app.svelte'
|
|||||||
import { settingsState } from '$lib/state/settings.svelte'
|
import { settingsState } from '$lib/state/settings.svelte'
|
||||||
|
|
||||||
const MAX_ATTEMPTS = 40
|
const MAX_ATTEMPTS = 40
|
||||||
|
const WEB_MAX_ATTEMPTS = 1
|
||||||
const BG_MAX_ATTEMPTS = 120
|
const BG_MAX_ATTEMPTS = 120
|
||||||
|
|
||||||
export const boot = $state({
|
export const boot = $state({
|
||||||
@@ -33,11 +34,8 @@ export async function initPlatform(): Promise<void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function pinLockEnabled(): boolean {
|
function pinLockEnabled(): boolean {
|
||||||
return (
|
const pin = settingsState.settings.appLockPin
|
||||||
settingsState.settings.appLockEnabled === true &&
|
return typeof pin === 'string' && pin.length >= 4
|
||||||
typeof settingsState.settings.appLockPin === 'string' &&
|
|
||||||
settingsState.settings.appLockPin.length >= 4
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleProbeSuccess(gen: number) {
|
function handleProbeSuccess(gen: number) {
|
||||||
@@ -56,6 +54,7 @@ function handleAuthRequired(
|
|||||||
pass: string,
|
pass: string,
|
||||||
) {
|
) {
|
||||||
if (gen !== probeGeneration) return
|
if (gen !== probeGeneration) return
|
||||||
|
if (boot.skipped) return
|
||||||
boot.failed = false
|
boot.failed = false
|
||||||
appState.authMode = authMode
|
appState.authMode = authMode
|
||||||
|
|
||||||
@@ -93,13 +92,6 @@ export async function startProbe(
|
|||||||
const baseUrl = settingsState.settings.serverUrl ?? 'http://127.0.0.1:4567'
|
const baseUrl = settingsState.settings.serverUrl ?? 'http://127.0.0.1:4567'
|
||||||
configureAuth(baseUrl, authMode, user || undefined, pass || undefined)
|
configureAuth(baseUrl, authMode, user || undefined, pass || undefined)
|
||||||
|
|
||||||
if (appState.platform === 'web') {
|
|
||||||
boot.failed = true
|
|
||||||
appState.status = 'error'
|
|
||||||
startBackgroundProbe(gen, authMode, user, pass)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let tries = 0
|
let tries = 0
|
||||||
|
|
||||||
async function probe() {
|
async function probe() {
|
||||||
@@ -110,7 +102,8 @@ export async function startProbe(
|
|||||||
|
|
||||||
if (result === 'ok') { handleProbeSuccess(gen); return }
|
if (result === 'ok') { handleProbeSuccess(gen); return }
|
||||||
if (result === 'auth_required') { handleAuthRequired(gen, authMode, user, pass); return }
|
if (result === 'auth_required') { handleAuthRequired(gen, authMode, user, pass); return }
|
||||||
if (tries >= MAX_ATTEMPTS) { boot.failed = true; appState.status = 'error'; startBackgroundProbe(gen, authMode, user, pass); return }
|
const maxAttempts = appState.platform === 'tauri' ? MAX_ATTEMPTS : WEB_MAX_ATTEMPTS
|
||||||
|
if (tries >= maxAttempts) { boot.failed = true; appState.status = 'error'; startBackgroundProbe(gen, authMode, user, pass); return }
|
||||||
|
|
||||||
setTimeout(probe, Math.min(500 + tries * 200, 2000))
|
setTimeout(probe, Math.min(500 + tries * 200, 2000))
|
||||||
}
|
}
|
||||||
@@ -191,10 +184,9 @@ export function bypassBoot(
|
|||||||
user = '',
|
user = '',
|
||||||
pass = '',
|
pass = '',
|
||||||
) {
|
) {
|
||||||
const gen = probeGeneration
|
|
||||||
boot.loginRequired = false
|
boot.loginRequired = false
|
||||||
boot.sessionExpired = false
|
boot.sessionExpired = false
|
||||||
boot.skipped = true
|
boot.skipped = true
|
||||||
appState.status = 'ready'
|
appState.status = 'ready'
|
||||||
startBackgroundProbe(gen, authMode, user, pass)
|
startBackgroundProbe(probeGeneration, authMode, user, pass)
|
||||||
}
|
}
|
||||||
@@ -7,6 +7,7 @@ export interface Source {
|
|||||||
isNsfw: boolean
|
isNsfw: boolean
|
||||||
isConfigurable: boolean
|
isConfigurable: boolean
|
||||||
supportsLatest: boolean
|
supportsLatest: boolean
|
||||||
|
extension?: { pkgName: string }
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Extension {
|
export interface Extension {
|
||||||
|
|||||||
+58
-45
@@ -1,7 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { onMount } from 'svelte'
|
import { onMount } from 'svelte'
|
||||||
import { page } from '$app/stores'
|
import { page } from '$app/stores'
|
||||||
import { appState, app } from '$lib/state/app.svelte'
|
import { appState, app, type AppStatus } from '$lib/state/app.svelte'
|
||||||
import { boot } from '$lib/state/boot.svelte'
|
import { boot } from '$lib/state/boot.svelte'
|
||||||
import { notifications } from '$lib/state/notifications.svelte'
|
import { notifications } from '$lib/state/notifications.svelte'
|
||||||
import { settingsState, loadSettingsIntoState, updateSettings } from '$lib/state/settings.svelte'
|
import { settingsState, loadSettingsIntoState, updateSettings } from '$lib/state/settings.svelte'
|
||||||
@@ -34,16 +34,23 @@
|
|||||||
|
|
||||||
const isTauri = typeof window !== 'undefined' && '__TAURI_INTERNALS__' in window
|
const isTauri = typeof window !== 'undefined' && '__TAURI_INTERNALS__' in window
|
||||||
|
|
||||||
let splashDismissed = $state(false)
|
appState.status = 'booting' as AppStatus
|
||||||
let themeEditorOpen = $state(false)
|
|
||||||
let themeEditorId = $state<string | null>(null)
|
let splashDismissed = $state(false)
|
||||||
|
let settingsLoaded = $state(false)
|
||||||
|
let themeEditorOpen = $state(false)
|
||||||
|
let themeEditorId = $state<string | null>(null)
|
||||||
|
|
||||||
const splashVisible = $derived(
|
const splashVisible = $derived(
|
||||||
!splashDismissed ||
|
|
||||||
appState.status === 'booting' ||
|
appState.status === 'booting' ||
|
||||||
appState.status === 'locked' ||
|
appState.status === 'locked' ||
|
||||||
appState.status === 'error' ||
|
appState.status === 'error' ||
|
||||||
appState.status === 'auth'
|
appState.status === 'auth' ||
|
||||||
|
(appState.status === 'ready' && !splashDismissed)
|
||||||
|
)
|
||||||
|
|
||||||
|
const splashMode = $derived(
|
||||||
|
appState.status === 'locked' && settingsLoaded ? 'locked' : 'loading'
|
||||||
)
|
)
|
||||||
|
|
||||||
const ringFull = $derived(appState.status === 'ready')
|
const ringFull = $derived(appState.status === 'ready')
|
||||||
@@ -62,51 +69,57 @@
|
|||||||
const readerContainerized = $derived(settingsState.settings.readerContainerized ?? false)
|
const readerContainerized = $derived(settingsState.settings.readerContainerized ?? false)
|
||||||
const strippedLayout = $derived(isReaderRoute && !readerContainerized)
|
const strippedLayout = $derived(isReaderRoute && !readerContainerized)
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(() => {
|
||||||
const { detectAdapter } = await import('$lib/platform-adapters')
|
async function init() {
|
||||||
const { initPlatformService } = await import('$lib/platform-service')
|
const { detectAdapter } = await import('$lib/platform-adapters')
|
||||||
const { loadSettings } = await import('$lib/core/persistence/persist')
|
const { initPlatformService } = await import('$lib/platform-service')
|
||||||
const { startProbe } = await import('$lib/state/boot.svelte')
|
const { loadSettings } = await import('$lib/core/persistence/persist')
|
||||||
|
const { startProbe } = await import('$lib/state/boot.svelte')
|
||||||
|
|
||||||
const adapter = detectAdapter()
|
const adapter = detectAdapter()
|
||||||
initPlatformService(adapter)
|
initPlatformService(adapter)
|
||||||
await adapter.init()
|
await adapter.init()
|
||||||
appState.platform = adapter.platform
|
appState.platform = adapter.platform
|
||||||
appState.version = await platformService.getVersion().catch(() => '')
|
appState.version = await platformService.getVersion().catch(() => '')
|
||||||
appState.appDir = await platformService.getAppDir().catch(() => '')
|
appState.appDir = await platformService.getAppDir().catch(() => '')
|
||||||
|
|
||||||
const persisted = await loadSettings()
|
const persisted = await loadSettings()
|
||||||
const raw = persisted?.settings ?? persisted ?? null
|
const raw = persisted?.settings ?? persisted ?? null
|
||||||
await loadSettingsIntoState(raw)
|
await loadSettingsIntoState(raw)
|
||||||
|
|
||||||
const s = (raw ?? {}) as Record<string, unknown>
|
const s = (raw ?? {}) as Record<string, unknown>
|
||||||
appState.serverUrl = (s.serverUrl as string) ?? ''
|
appState.serverUrl = (s.serverUrl as string) ?? ''
|
||||||
appState.authMode = (s.serverAuthMode as 'NONE' | 'BASIC_AUTH' | 'UI_LOGIN') ?? 'NONE'
|
appState.authMode = (s.serverAuthMode as 'NONE' | 'BASIC_AUTH' | 'UI_LOGIN') ?? 'NONE'
|
||||||
appState.authUser = (s.serverAuthUser as string) ?? ''
|
appState.authUser = (s.serverAuthUser as string) ?? ''
|
||||||
appState.authPass = (s.serverAuthPass as string) ?? ''
|
appState.authPass = (s.serverAuthPass as string) ?? ''
|
||||||
|
|
||||||
applyTheme(
|
settingsLoaded = true
|
||||||
settingsState.settings.theme ?? 'dark',
|
|
||||||
settingsState.settings.customThemes ?? [],
|
|
||||||
)
|
|
||||||
|
|
||||||
if (isTauri && settingsState.settings.autoStartServer) {
|
applyTheme(
|
||||||
platformService.launchServer({
|
settingsState.settings.theme ?? 'dark',
|
||||||
binary: settingsState.settings.serverBinary,
|
settingsState.settings.customThemes ?? [],
|
||||||
binaryArgs: settingsState.settings.serverBinaryArgs,
|
)
|
||||||
webUiEnabled: settingsState.settings.suwayomiWebUI,
|
|
||||||
}).catch(() => {})
|
if (isTauri && settingsState.settings.autoStartServer) {
|
||||||
|
platformService.launchServer({
|
||||||
|
binary: settingsState.settings.serverBinary,
|
||||||
|
binaryArgs: settingsState.settings.serverBinaryArgs,
|
||||||
|
webUiEnabled: settingsState.settings.suwayomiWebUI,
|
||||||
|
}).catch(() => {})
|
||||||
|
}
|
||||||
|
|
||||||
|
startProbe(
|
||||||
|
appState.authMode ?? 'NONE',
|
||||||
|
appState.authUser ?? '',
|
||||||
|
appState.authPass ?? '',
|
||||||
|
isTauri && settingsState.settings.autoStartServer ? 2000 : 100,
|
||||||
|
)
|
||||||
|
|
||||||
|
polling = true
|
||||||
|
pollLoop()
|
||||||
}
|
}
|
||||||
|
|
||||||
startProbe(
|
init()
|
||||||
appState.authMode ?? 'NONE',
|
|
||||||
appState.authUser ?? '',
|
|
||||||
appState.authPass ?? '',
|
|
||||||
isTauri && settingsState.settings.autoStartServer ? 2000 : 100,
|
|
||||||
)
|
|
||||||
|
|
||||||
polling = true
|
|
||||||
pollLoop()
|
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
polling = false
|
polling = false
|
||||||
@@ -191,7 +204,7 @@
|
|||||||
|
|
||||||
{#if splashVisible}
|
{#if splashVisible}
|
||||||
<SplashScreen
|
<SplashScreen
|
||||||
mode={appState.status === 'locked' ? 'locked' : 'loading'}
|
mode={splashMode}
|
||||||
{ringFull}
|
{ringFull}
|
||||||
failed={appState.status === 'error'}
|
failed={appState.status === 'error'}
|
||||||
notConfigured={boot.notConfigured}
|
notConfigured={boot.notConfigured}
|
||||||
|
|||||||
Reference in New Issue
Block a user