diff --git a/flake.lock b/flake.lock index 09846e2..5f3edc0 100644 --- a/flake.lock +++ b/flake.lock @@ -1,20 +1,5 @@ { "nodes": { - "crane": { - "locked": { - "lastModified": 1773857772, - "narHash": "sha256-5xsK26KRHf0WytBtsBnQYC/lTWDhQuT57HJ7SzuqZcM=", - "owner": "ipetkov", - "repo": "crane", - "rev": "b556d7bbae5ff86e378451511873dfd07e4504cd", - "type": "github" - }, - "original": { - "owner": "ipetkov", - "repo": "crane", - "type": "github" - } - }, "flake-parts": { "inputs": { "nixpkgs-lib": "nixpkgs-lib" @@ -66,7 +51,6 @@ }, "root": { "inputs": { - "crane": "crane", "flake-parts": "flake-parts", "nixpkgs": "nixpkgs", "rust-overlay": "rust-overlay" diff --git a/flake.nix b/flake.nix index 657837e..ffcf714 100644 --- a/flake.nix +++ b/flake.nix @@ -4,7 +4,6 @@ inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; flake-parts.url = "github:hercules-ci/flake-parts"; - crane.url = "github:ipetkov/crane"; rust-overlay = { url = "github:oxalica/rust-overlay"; inputs.nixpkgs.follows = "nixpkgs"; @@ -12,7 +11,7 @@ }; outputs = - inputs@{ flake-parts, crane, rust-overlay, ... }: + inputs@{ flake-parts, rust-overlay, ... }: flake-parts.lib.mkFlake { inherit inputs; } { systems = [ "x86_64-linux" @@ -22,7 +21,8 @@ perSystem = { system, lib, ... }: let - version = "0.9.4"; + versions = import ./nix/versions.nix; + version = versions.moku; pkgs = import inputs.nixpkgs { inherit system; @@ -36,8 +36,6 @@ ]; }; - craneLib = (crane.mkLib pkgs).overrideToolchain rustToolchain; - runtimeLibs = with pkgs; [ webkitgtk_4_1 gtk3 @@ -53,7 +51,7 @@ gsettings-desktop-schemas ]; - frontendSrc = lib.cleanSourceWith { + src = lib.cleanSourceWith { src = ./.; filter = path: type: @@ -61,51 +59,46 @@ base = builtins.baseNameOf path; in (lib.hasInfix "/src" path) + || (lib.hasInfix "/src-tauri/src" path) + || (lib.hasInfix "/src-tauri/icons" path) + || (lib.hasInfix "/src-tauri/capabilities" path) + || (lib.hasInfix "/static" path) || base == "index.html" || base == "package.json" || base == "pnpm-lock.yaml" + || base == "pnpm-workspace.yaml" || base == "tsconfig.json" - || base == "vite.config.ts"; + || base == "vite.config.ts" + || base == "svelte.config.js" + || base == "Cargo.toml" + || base == "Cargo.lock" + || base == "build.rs" + || base == "tauri.conf.json"; }; - cargoSrc = lib.cleanSourceWith { - src = ./src-tauri; - filter = - path: type: - (craneLib.filterCargoSources path type) - || (lib.hasInfix "/icons/" path) - || (lib.hasInfix "/capabilities/" path) - || (builtins.baseNameOf path == "tauri.conf.json"); + suwayomiServer = pkgs.callPackage ./nix/server.nix { inherit versions; }; + + moku = pkgs.callPackage ./nix/moku.nix { + inherit lib pkgs rustToolchain runtimeLibs suwayomiServer version src versions; + appIcon = ./src/lib/assets/moku-icon.svg; }; - suwayomiServer = pkgs.callPackage ./nix/server.nix { }; - - frontend = pkgs.callPackage ./nix/frontend.nix { - inherit version; - src = frontendSrc; - }; - - moku = import ./nix/moku.nix { - inherit lib craneLib pkgs runtimeLibs frontend suwayomiServer version cargoSrc; - appIcon = ./src/assets/moku-icon.svg; - }; - - scripts = import ./nix/scripts.nix { inherit pkgs rustToolchain version; }; + scripts = import ./nix/scripts.nix { inherit pkgs rustToolchain version versions; }; in { packages = { - inherit moku frontend suwayomiServer; + inherit moku suwayomiServer; default = moku; }; apps = { default = { type = "app"; program = "${moku}/bin/moku"; }; - moku = { type = "app"; program = "${moku}/bin/moku"; }; - bump = { type = "app"; program = "${scripts.bump}/bin/moku-bump"; }; - post-tag-bump = { type = "app"; program = "${scripts.postTagBump}/bin/moku-post-tag-bump"; }; + moku = { type = "app"; program = "${moku}/bin/moku"; }; + bump = { type = "app"; program = "${scripts.bump}/bin/moku-bump"; }; + update = { type = "app"; program = "${scripts.update}/bin/moku-update"; }; flatpak = { type = "app"; program = "${scripts.flatpak}/bin/moku-flatpak"; }; - tunnel = { type = "app"; program = "${scripts.tunnel}/bin/moku-tunnel"; }; + tunnel = { type = "app"; program = "${scripts.tunnel}/bin/moku-tunnel"; }; }; devShells.default = pkgs.mkShell { @@ -132,11 +125,11 @@ echo "Moku dev shell — pnpm install && pnpm tauri:dev" echo "" - echo " nix run .#bump -- " + echo " nix run .#bump -- bump version + rebuild frontend" echo " git commit && git tag && git push" - echo " nix run .#post-tag-bump -- " - echo " nix run .#flatpak -- " - echo " nix run .#tunnel -- [port]" + echo " nix run .#update -- fetch hashes + patch all configs" + echo " nix run .#flatpak build flatpak bundle" + echo " nix run .#tunnel -- [port] expose local server via cloudflare" ''; }; diff --git a/nix/frontend.nix b/nix/frontend.nix index c15f4f1..821ff37 100644 --- a/nix/frontend.nix +++ b/nix/frontend.nix @@ -1,4 +1,4 @@ -{ lib, stdenv, nodejs_22, pnpm, pnpmConfigHook, fetchPnpmDeps, version, src }: +{ lib, stdenv, nodejs_22, pnpm, pnpmConfigHook, fetchPnpmDeps, version, src, versions }: stdenv.mkDerivation { pname = "moku-frontend"; @@ -10,9 +10,13 @@ stdenv.mkDerivation { pname = "moku-frontend"; inherit version src; fetcherVersion = 1; - hash = "sha256-vM//1/qe9nKDwwlmFbqvBFqF8cCjIIdNKEtktyzBFB8="; + hash = versions.frontend.pnpmHash; }; - buildPhase = "pnpm build"; + buildPhase = '' + export HOME=$(mktemp -d) + pnpm build:static + ''; + installPhase = "cp -r dist $out"; -} +} \ No newline at end of file diff --git a/nix/moku.nix b/nix/moku.nix index aae0aab..282e964 100644 --- a/nix/moku.nix +++ b/nix/moku.nix @@ -1,38 +1,61 @@ { lib, - craneLib, pkgs, + rustToolchain, runtimeLibs, - frontend, suwayomiServer, version, - cargoSrc, + versions, + src, appIcon, }: -let - commonArgs = { - src = cargoSrc; +pkgs.stdenv.mkDerivation { + pname = "moku"; + inherit version src; + + nativeBuildInputs = with pkgs; [ + rustToolchain + nodejs_22 + pnpm + pnpmConfigHook + pkg-config + wrapGAppsHook3 + rustPlatform.cargoSetupHook + ]; + + buildInputs = runtimeLibs; + + pnpmDeps = pkgs.fetchPnpmDeps { pname = "moku"; - inherit version; - strictDeps = true; - buildInputs = runtimeLibs; - nativeBuildInputs = with pkgs; [ pkg-config wrapGAppsHook3 ]; - preBuild = '' - cp -r ${frontend} ../dist - ''; + inherit version src; + fetcherVersion = 1; + hash = versions.frontend.pnpmHash; }; - cargoArtifacts = craneLib.buildDepsOnly commonArgs; -in -craneLib.buildPackage (commonArgs // { - inherit cargoArtifacts; + cargoDeps = pkgs.rustPlatform.importCargoLock { + lockFile = ../src-tauri/Cargo.lock; + outputHashes = { + "tauri-plugin-discord-rpc-0.1.0" = versions.gitDeps.tauri-plugin-discord-rpc; + }; + }; - meta.mainProgram = "moku"; + env = { + PKG_CONFIG_PATH = "${pkgs.openssl.dev}/lib/pkgconfig"; + TAURI_SKIP_DEVSERVER_CHECK = "true"; + cargoRoot = "src-tauri"; + }; + + buildPhase = '' + export HOME=$(mktemp -d) + pnpm tauri:build + ''; + + installPhase = '' + install -Dm755 src-tauri/target/release/moku $out/bin/moku - postInstall = '' mkdir -p "$out/share/applications" - cat > "$out/share/applications/moku.desktop" << EOF + cat > "$out/share/applications/moku.desktop" << EOF2 [Desktop Entry] Version=1.0 Type=Application @@ -44,17 +67,17 @@ Terminal=false Categories=Graphics;Viewer; Keywords=manga;comic;reader;suwayomi; StartupWMClass=moku -EOF +EOF2 for size in 32x32 128x128 256x256 512x512; do - src="icons/$size.png" - [ -f "$src" ] && install -Dm644 "$src" \ + f="src-tauri/icons/$size.png" + [ -f "$f" ] && install -Dm644 "$f" \ "$out/share/icons/hicolor/$size/apps/moku.png" done for size in 128x128 256x256; do - src="icons/''${size}@2x.png" - [ -f "$src" ] && install -Dm644 "$src" \ + f="src-tauri/icons/''${size}@2x.png" + [ -f "$f" ] && install -Dm644 "$f" \ "$out/share/icons/hicolor/''${size}@2/apps/moku.png" done @@ -71,4 +94,6 @@ EOF --set GDK_BACKEND wayland \ --set WEBKIT_DISABLE_SANDBOX_THIS_IS_DANGEROUS 1 ''; -}) + + meta.mainProgram = "moku"; +} diff --git a/nix/scripts.nix b/nix/scripts.nix index 8c406aa..3f366e2 100644 --- a/nix/scripts.nix +++ b/nix/scripts.nix @@ -1,4 +1,4 @@ -{ pkgs, rustToolchain, version }: +{ pkgs, rustToolchain, version, versions }: { bump = pkgs.writeShellApplication { @@ -17,87 +17,98 @@ VERSION="$1" REPO="$(git rev-parse --show-toplevel)" - echo "── Bumping version fields to $VERSION ──" - sed -i "s/\"version\": \"[^\"]*\"/\"version\": \"$VERSION\"/" \ - "$REPO/src-tauri/tauri.conf.json" - sed -i "0,/^version = \"[^\"]*\"/s//version = \"$VERSION\"/" \ - "$REPO/src-tauri/Cargo.toml" - sed -i "s/version = \"[^\"]*\";/version = \"$VERSION\";/g" \ - "$REPO/flake.nix" + sed -i "s/moku = \"[^\"]*\"/moku = \"$VERSION\"/" "$REPO/nix/versions.nix" + sed -i "s/\"version\": \"[^\"]*\"/\"version\": \"$VERSION\"/" "$REPO/src-tauri/tauri.conf.json" + sed -i "0,/^version = \"[^\"]*\"/s//version = \"$VERSION\"/" "$REPO/src-tauri/Cargo.toml" sed -i "s/^pkgver=.*/pkgver=$VERSION/" "$REPO/PKGBUILD" - sed -i "s/^pkgrel=.*/pkgrel=1/" "$REPO/PKGBUILD" - echo "Done" + sed -i "s/^pkgrel=.*/pkgrel=1/" "$REPO/PKGBUILD" - echo "── Regenerating Cargo.lock ──" (cd "$REPO/src-tauri" && cargo generate-lockfile) - echo "Done" - echo "── Building frontend ──" cd "$REPO" pnpm install --frozen-lockfile - pnpm build - echo "Done" + pnpm build:static - echo "── Repacking frontend-dist.tar.gz ──" tar -czf "$REPO/packaging/frontend-dist.tar.gz" -C "$REPO" dist - FRONTEND_SHA=$(sha256sum "$REPO/packaging/frontend-dist.tar.gz" | awk '{print $1}') - echo "sha256: $FRONTEND_SHA" + FRONTEND_SHA_HEX=$(sha256sum "$REPO/packaging/frontend-dist.tar.gz" | awk '{print $1}') + FRONTEND_SHA_SRI=$(echo "$FRONTEND_SHA_HEX" | xxd -r -p | base64 -w0 | sed 's/^/sha256-/') + + sed -i "s|distHash = \"[^\"]*\"|distHash = \"$FRONTEND_SHA_HEX\"|" "$REPO/nix/versions.nix" + sed -i "s|distHashSri = \"[^\"]*\"|distHashSri = \"$FRONTEND_SHA_SRI\"|" "$REPO/nix/versions.nix" + + MANIFEST="$REPO/io.github.moku_project.Moku.yml" + sed -i "s/tag: v[^[:space:]]*/tag: v$VERSION/" "$MANIFEST" + python3 - "$MANIFEST" "$FRONTEND_SHA_HEX" <<'PYEOF' +import re, sys +path, sha = sys.argv[1], sys.argv[2] +text = open(path).read() +updated, n = re.subn( + r'(path:\s*packaging/frontend-dist\.tar\.gz\s*\n\s*sha256:\s*)[0-9a-f]+', + r'\g<1>' + sha, text) +if n == 0: + sys.exit("ERROR: could not find frontend-dist sha256 in manifest") +open(path, 'w').write(updated) +PYEOF - echo "── Regenerating cargo-sources.json ──" python3 "$REPO/packaging/flatpak-cargo-generator.py" \ "$REPO/src-tauri/Cargo.lock" \ -o "$REPO/packaging/cargo-sources.json" - echo "Done" - echo "── Patching flatpak manifest ──" - MANIFEST="$REPO/io.github.moku_project.Moku.yml" - sed -i "s/tag: v[^[:space:]]*/tag: v$VERSION/" "$MANIFEST" - python3 - "$MANIFEST" "$FRONTEND_SHA" <<'PYEOF' - import re, sys - path, sha = sys.argv[1], sys.argv[2] - text = open(path).read() - updated, n = re.subn( - r'(path:\s*packaging/frontend-dist\.tar\.gz\s*\n\s*sha256:\s*)[0-9a-f]+', - r'\g<1>' + sha, text) - if n == 0: - sys.exit("ERROR: could not find frontend-dist sha256 in manifest") - open(path, 'w').write(updated) - PYEOF - echo "Done" - - echo "" - echo "Bumped to v$VERSION — commit, tag, push, then: nix run .#post-tag-bump -- $VERSION" + echo "Bumped to v$VERSION — commit, tag, push, then: nix run .#update -- $VERSION" ''; }; - postTagBump = pkgs.writeShellApplication { - name = "moku-post-tag-bump"; - runtimeInputs = with pkgs; [ gnused coreutils git curl ]; + update = pkgs.writeShellApplication { + name = "moku-update"; + runtimeInputs = with pkgs; [ gnused coreutils git curl nix xxd ]; text = '' - [[ $# -lt 1 ]] && { echo "Usage: nix run .#post-tag-bump -- "; exit 1; } - VERSION="$1" REPO="$(git rev-parse --show-toplevel)" + VERSIONS="$REPO/nix/versions.nix" MANIFEST="$REPO/io.github.moku_project.Moku.yml" PKGBUILD="$REPO/PKGBUILD" - echo "── Resolving commit for v$VERSION ──" - COMMIT=$(git ls-remote https://github.com/moku-project/Moku.git "refs/tags/v$VERSION" \ - | awk '{print $1}') - [[ -z "$COMMIT" ]] && { echo "ERROR: tag v$VERSION not found on remote"; exit 1; } - echo "commit: $COMMIT" - sed -i "s/commit: [0-9a-f]\{40\}/commit: $COMMIT/" "$MANIFEST" - echo "Done" + if [[ $# -ge 1 ]]; then + VERSION="$1" + else + VERSION=$(grep 'moku = "' "$VERSIONS" | head -1 | sed 's/.*"\(.*\)".*/\1/') + fi + + COMMIT=$(git ls-remote https://github.com/moku-project/Moku.git "refs/tags/v$VERSION" | awk '{print $1}') + [[ -z "$COMMIT" ]] && { echo "ERROR: tag v$VERSION not found on remote"; exit 1; } + sed -i "s/gitCommit = \"[^\"]*\"/gitCommit = \"$COMMIT\"/" "$VERSIONS" + sed -i "s/commit: [0-9a-f]\{40\}/commit: $COMMIT/" "$MANIFEST" - echo "── Fetching PKGBUILD tarball sha256 ──" TARBALL_URL="https://github.com/moku-project/Moku/archive/refs/tags/v$VERSION.tar.gz" TARBALL_SHA=$(curl -fsSL "$TARBALL_URL" | sha256sum | awk '{print $1}') + sed -i "s/tarballHash = \"[^\"]*\"/tarballHash = \"$TARBALL_SHA\"/" "$VERSIONS" sed -i "/sha256sums=/,/)/{ 0,/'/s/'[^']*'/'$TARBALL_SHA'/ }" "$PKGBUILD" - grep -q "$TARBALL_SHA" "$PKGBUILD" \ - || { echo "ERROR: PKGBUILD sha256 replacement failed"; exit 1; } - echo "Done" - echo "" - echo "post-tag-bump complete for v$VERSION" + if [[ $# -ge 2 ]]; then + SUWA_VER="$2" + JAR_URL="https://github.com/Suwayomi/Suwayomi-Server-preview/releases/download/v${SUWA_VER}/Suwayomi-Server-v${SUWA_VER}.jar" + + SUWA_SHA_HEX=$(curl -fsSL "$JAR_URL" | sha256sum | awk '{print $1}') + SUWA_SHA_SRI=$(echo "$SUWA_SHA_HEX" | xxd -r -p | base64 -w0 | sed 's/^/sha256-/') + + sed -i "s/version = \"[^\"]*\"/version = \"$SUWA_VER\"/" "$VERSIONS" + sed -i "s|hash = \"sha256-[^\"]*\"|hash = \"$SUWA_SHA_SRI\"|" "$VERSIONS" + + sed -i "s|Suwayomi-Server-preview/releases/download/v[^/]*/|Suwayomi-Server-preview/releases/download/v${SUWA_VER}/|" "$MANIFEST" + sed -i "s|Suwayomi-Server-v[0-9.]*\.jar|Suwayomi-Server-v${SUWA_VER}.jar|g" "$MANIFEST" + python3 - "$MANIFEST" "$SUWA_SHA_HEX" <<'PYEOF' +import re, sys +path, sha = sys.argv[1], sys.argv[2] +text = open(path).read() +updated, n = re.subn( + r'(dest-filename:\s*Suwayomi-Server\.jar\s*\n\s*sha256:\s*)[0-9a-f]+', + r'\g<1>' + sha, text) +if n == 0: + sys.exit("ERROR: could not find Suwayomi jar sha256 in manifest") +open(path, 'w').write(updated) +PYEOF + fi + + echo "Done — versions.nix, flatpak manifest, and PKGBUILD patched for v$VERSION" ''; }; @@ -105,19 +116,15 @@ name = "moku-flatpak"; runtimeInputs = with pkgs; [ coreutils git appstream flatpak-builder flatpak ]; text = '' - [[ $# -lt 1 ]] && { echo "Usage: nix run .#flatpak -- "; exit 1; } REPO="$(git rev-parse --show-toplevel)" - MANIFEST="$REPO/io.github.moku_project.Moku.yml" - rm -rf "$REPO/build-dir" "$REPO/repo" flatpak-builder \ --repo="$REPO/repo" \ --force-clean \ "$REPO/build-dir" \ - "$MANIFEST" + "$REPO/io.github.moku_project.Moku.yml" flatpak build-bundle "$REPO/repo" "$REPO/moku.flatpak" io.github.moku_project.Moku rm -rf "$REPO/build-dir" "$REPO/repo" - echo "moku.flatpak created" ''; }; diff --git a/nix/server.nix b/nix/server.nix index 3ed8fc2..f2fab7f 100644 --- a/nix/server.nix +++ b/nix/server.nix @@ -4,17 +4,19 @@ fetchurl, makeWrapper, jdk21_headless, + versions, }: let jdk = jdk21_headless; + ver = versions.suwayomi; in -stdenvNoCC.mkDerivation (finalAttrs: { +stdenvNoCC.mkDerivation { pname = "suwayomi-server"; - version = "2.1.2087"; + version = ver.version; src = fetchurl { - url = "https://github.com/Suwayomi/Suwayomi-Server-preview/releases/download/v${finalAttrs.version}/Suwayomi-Server-v${finalAttrs.version}.jar"; - hash = "sha256-9YmkImdCUjlME7KJqci+aRkFv1g++39NXxUBrl6R5rM="; + url = "https://github.com/Suwayomi/Suwayomi-Server-preview/releases/download/v${ver.version}/Suwayomi-Server-v${ver.version}.jar"; + hash = ver.hash; }; nativeBuildInputs = [ makeWrapper ]; @@ -37,10 +39,10 @@ stdenvNoCC.mkDerivation (finalAttrs: { description = "Free and open source manga reader server that runs extensions built for Mihon (Tachiyomi)"; homepage = "https://github.com/Suwayomi/Suwayomi-Server"; downloadPage = "https://github.com/Suwayomi/Suwayomi-Server-preview/releases"; - changelog = "https://github.com/Suwayomi/Suwayomi-Server-preview/releases/tag/v${finalAttrs.version}"; + changelog = "https://github.com/Suwayomi/Suwayomi-Server-preview/releases/tag/v${ver.version}"; license = lib.licenses.mpl20; platforms = jdk.meta.platforms; sourceProvenance = [ lib.sourceTypes.binaryBytecode ]; mainProgram = "suwayomi-server"; }; -}) +} diff --git a/nix/versions.nix b/nix/versions.nix new file mode 100644 index 0000000..e219e84 --- /dev/null +++ b/nix/versions.nix @@ -0,0 +1,21 @@ +{ + moku = "0.9.4"; + + suwayomi = { + version = "2.1.2087"; + hash = "sha256-9YmkImdCUjlME7KJqci+aRkFv1g++39NXxUBrl6R5rM="; + }; + + frontend = { + pnpmHash = "sha256-8bkwONUrr+U2OXYXvcsGytKhcImnehu+2bI/hmoFjJ4="; + distHash = "7db288b4b54277aa82b6ec5b21fc31a1e71f8246c50a74777500083b806c1fa5"; + distHashSri = "sha256-fbiiu0tCd6qCtu+SIfw+aR8Yj2bFCnR3dQAIO4BvwfM="; + }; + + gitDeps = { + tauri-plugin-discord-rpc = "sha256-xq0qyK2NrwSAFDhXo0vbvcygRD2/7uqBaLpqfpfxkrc="; + }; + + gitCommit = "239960683b6c7f1347e1798b0e179a8a46628728"; + tarballHash = ""; +} diff --git a/package.json b/package.json index 71c6eec..5b7d910 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,6 @@ "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", "build:static": "MOKU_TARGET=static vite build", "build:node": "MOKU_TARGET=node vite build", - "build:tauri": "MOKU_TARGET=static vite build", "build:android": "MOKU_TARGET=static vite build", "tauri:dev": "tauri dev --config src-tauri/tauri.dev.conf.json", "tauri:build": "tauri build" diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 5008c40..f3a5193 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -6,7 +6,7 @@ "build": { "devUrl": "http://localhost:1420", "frontendDist": "../dist", - "beforeBuildCommand": "pnpm build" + "beforeBuildCommand": "pnpm build:static" }, "app": { "windows": [ diff --git a/src/assets/moku-icon-full.svg b/src/assets/moku-icon-full.svg deleted file mode 100644 index 23b0e20..0000000 --- a/src/assets/moku-icon-full.svg +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - diff --git a/src/assets/moku-icon-splash.svg b/src/assets/moku-icon-splash.svg deleted file mode 100644 index e88a390..0000000 --- a/src/assets/moku-icon-splash.svg +++ /dev/null @@ -1,21 +0,0 @@ - - - - - diff --git a/src/assets/moku-icon-wordmark.svg b/src/assets/moku-icon-wordmark.svg deleted file mode 100644 index 74e9ef2..0000000 --- a/src/assets/moku-icon-wordmark.svg +++ /dev/null @@ -1,21 +0,0 @@ - - - - - diff --git a/src/assets/moku-icon.svg b/src/assets/moku-icon.svg deleted file mode 100644 index f522609..0000000 --- a/src/assets/moku-icon.svg +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - diff --git a/src/hooks.client.ts b/src/hooks.client.ts index 28d5358..079934c 100644 --- a/src/hooks.client.ts +++ b/src/hooks.client.ts @@ -25,11 +25,11 @@ async function resolveServerAdapter() { async function boot() { try { const platformAdapter = detectAdapter() + initPlatformService(platformAdapter) + await platformAdapter.init() const serverAdapter = await resolveServerAdapter() - - initPlatformService(platformAdapter) initRequestManager(serverAdapter) appState.platform = platformAdapter.platform @@ -53,6 +53,8 @@ async function boot() { appState.serverUrl = savedUrl appState.authMode = savedAuth.mode + appState.authUser = savedAuth.user ?? '' + appState.authPass = savedAuth.pass ?? '' configureAuth(savedUrl, savedAuth.mode, savedAuth.user, savedAuth.pass) @@ -64,6 +66,14 @@ async function boot() { : undefined, }) + const isTauri = platformAdapter.platform === 'tauri' + const autoStartServer = settingsData.settings.autoStartServer ?? false + + if (isTauri && autoStartServer) { + appState.status = 'booting' + return + } + const probe = await probeServer() if (probe === 'auth_required') { appState.status = 'auth'; return } diff --git a/src/lib/assets/favicon.svg b/src/lib/assets/favicon.svg deleted file mode 100644 index f522609..0000000 --- a/src/lib/assets/favicon.svg +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - diff --git a/src/lib/components/settings/sections/AboutSettings.svelte b/src/lib/components/settings/sections/AboutSettings.svelte index ba67e5f..3c0d301 100644 --- a/src/lib/components/settings/sections/AboutSettings.svelte +++ b/src/lib/components/settings/sections/AboutSettings.svelte @@ -155,6 +155,9 @@ {/if} +
+
Platform{platformService.platform}
+
{#if onLatestVersion}
✓ You're on the latest version. diff --git a/src/lib/request-manager/index.ts b/src/lib/request-manager/index.ts index 6a267e5..4a6f239 100644 --- a/src/lib/request-manager/index.ts +++ b/src/lib/request-manager/index.ts @@ -4,6 +4,7 @@ import * as chapters from "./chapters"; import * as downloads from "./downloads"; import * as manga from "./manga"; import * as tracking from "./tracking"; +import * as meta from "./meta"; let adapter: ServerAdapter; @@ -21,6 +22,7 @@ export function clearPageCache(chapterId?: number): void { } export const requestManager = { + meta, extensions, chapters, downloads, diff --git a/src/lib/request-manager/meta.ts b/src/lib/request-manager/meta.ts new file mode 100644 index 0000000..757775e --- /dev/null +++ b/src/lib/request-manager/meta.ts @@ -0,0 +1,9 @@ +import { getAdapter } from "$lib/request-manager"; + +export async function getAboutServer() { + return getAdapter().getAboutServer(); +} + +export async function getAboutWebUI() { + return getAdapter().getAboutWebUI(); +} \ No newline at end of file diff --git a/src/lib/server-adapters/suwayomi/index.ts b/src/lib/server-adapters/suwayomi/index.ts index 98d38c1..98b095c 100644 --- a/src/lib/server-adapters/suwayomi/index.ts +++ b/src/lib/server-adapters/suwayomi/index.ts @@ -14,6 +14,8 @@ import type { SetSocksProxyInput, SetFlareSolverrInput, TrackRecordPatch, + AboutServer, + AboutWebUI, } from '$lib/server-adapters/types' import type { DownloadStatus } from '$lib/types/api' import type { Manga, Chapter, Extension, Source, Tracker, TrackRecord, Category } from '$lib/types' @@ -84,6 +86,10 @@ import { TRACK_PROGRESS, UPDATE_TRACK, } from './tracking' +import { + GET_ABOUT_SERVER, + GET_ABOUT_WEBUI, +} from './meta' import { type GQLResponse, mapManga, @@ -205,6 +211,16 @@ export class SuwayomiAdapter implements ServerAdapter { return json.data } + async getAboutServer(): Promise { + const data = await this.gql<{ aboutServer: AboutServer }>(GET_ABOUT_SERVER) + return data.aboutServer + } + + async getAboutWebUI(): Promise { + const data = await this.gql<{ aboutWebUI: AboutWebUI }>(GET_ABOUT_WEBUI) + return data.aboutWebUI + } + async getManga(id: string): Promise { const data = await this.gql<{ manga: Record }>(GET_MANGA, { id: Number(id) }) return mapManga(data.manga) diff --git a/src/lib/server-adapters/suwayomi/meta.ts b/src/lib/server-adapters/suwayomi/meta.ts new file mode 100644 index 0000000..8718ffe --- /dev/null +++ b/src/lib/server-adapters/suwayomi/meta.ts @@ -0,0 +1,39 @@ +export const GET_ABOUT_SERVER = ` + query GetAboutServer { + aboutServer { + name version buildType buildTime github discord + } + } +` + +export const GET_ABOUT_WEBUI = ` + query GetAboutWebUI { + aboutWebUI { + channel tag updateTimestamp + } + } +` + +export const CHECK_FOR_SERVER_UPDATES = ` + query CheckForServerUpdates { + checkForServerUpdates { + channel tag url + } + } +` + +export const GET_META = ` + query GetMeta($key: String!) { + meta(key: $key) { + key value + } + } +` + +export const GET_METAS = ` + query GetMetas { + metas { + nodes { key value } + } + } +` \ No newline at end of file diff --git a/src/lib/server-adapters/types.ts b/src/lib/server-adapters/types.ts index 80baa48..a82762e 100644 --- a/src/lib/server-adapters/types.ts +++ b/src/lib/server-adapters/types.ts @@ -43,6 +43,21 @@ export interface Page { imageData?: string } +export interface AboutServer { + name: string + version: string + buildType: string + buildTime: number + github: string + discord: string +} + +export interface AboutWebUI { + channel: string + tag: string + updateTimestamp: number +} + export interface DownloadItem { chapterId: string mangaId: string @@ -140,6 +155,9 @@ export interface ServerAdapter { setChapterMeta(chapterId: string, key: string, value: string): Promise deleteChapterMeta(chapterId: string, key: string): Promise + getAboutServer(): Promise + getAboutWebUI(): Promise + getDownloads(): Promise getDownloadStatus(): Promise enqueueDownload(chapterId: string): Promise diff --git a/src/lib/state/boot.svelte.ts b/src/lib/state/boot.svelte.ts index a8c10a1..5d231e6 100644 --- a/src/lib/state/boot.svelte.ts +++ b/src/lib/state/boot.svelte.ts @@ -4,8 +4,8 @@ import { platformService } from '$lib/platform-service' import { probeServer, loginBasic, loginUI } from '$lib/core/auth' import { appState } from '$lib/state/app.svelte' -const MAX_ATTEMPTS = 15 -const BG_MAX_ATTEMPTS = 60 +const MAX_ATTEMPTS = 40 +const BG_MAX_ATTEMPTS = 120 export const boot = $state({ failed: false, @@ -70,6 +70,7 @@ export function startProbe( authMode: 'NONE' | 'BASIC_AUTH' | 'UI_LOGIN' = 'NONE', user = '', pass = '', + initialDelay = 100, ) { const gen = ++probeGeneration boot.failed = false @@ -89,10 +90,10 @@ export function startProbe( 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 } - setTimeout(probe, Math.min(300 + tries * 150, 1500)) + setTimeout(probe, Math.min(500 + tries * 200, 2000)) } - setTimeout(probe, 100) + setTimeout(probe, initialDelay) } function startBackgroundProbe( diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index a76ef7d..9959683 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -50,15 +50,21 @@ const strippedLayout = $derived(isReaderRoute && !readerContainerized) onMount(async () => { - // hooks.client.ts already ran detectAdapter(), initPlatformService(), - // loadSettingsIntoState(), and startProbe() — nothing to re-initialize here. - if (isTauri && settingsState.settings.autoStartServer) { + const { startProbe } = await import('$lib/state/boot.svelte') + platformService.launchServer({ - binary: settingsState.settings.serverBinary, - binaryArgs: settingsState.settings.serverBinaryArgs, - webUiEnabled: settingsState.settings.suwayomiWebUI, + binary: settingsState.settings.serverBinary, + binaryArgs: settingsState.settings.serverBinaryArgs, + webUiEnabled: settingsState.settings.suwayomiWebUI, }).catch(() => {}) + + startProbe( + appState.authMode ?? 'NONE', + appState.authUser ?? '', + appState.authPass ?? '', + 2000, + ) } if (settingsState.settings.discordRpc) { @@ -209,4 +215,4 @@ contain: layout style; min-width: 0; } - \ No newline at end of file +x \ No newline at end of file diff --git a/svelte.config.js b/svelte.config.js index 377bf32..f0d4651 100644 --- a/svelte.config.js +++ b/svelte.config.js @@ -5,15 +5,17 @@ const target = process.env.MOKU_TARGET ?? 'static'; const adapter = target === 'node' ? adapterNode() - : adapterStatic({ fallback: 'index.html' }); + : adapterStatic({ fallback: 'index.html', pages: 'dist', assets: 'dist' }) -/** @type {import('@sveltejs/kit').Config} */ const config = { compilerOptions: { runes: ({ filename }) => (filename.split(/[/\\]/).includes('node_modules') ? undefined : true), }, kit: { adapter, + paths: { + relative: true, + }, files: { assets: 'static', },