diff --git a/.github/workflows/update-flake-lock.yml b/.github/workflows/update-flake-lock.yml index db34695..9e5ec64 100644 --- a/.github/workflows/update-flake-lock.yml +++ b/.github/workflows/update-flake-lock.yml @@ -15,6 +15,9 @@ concurrency: jobs: update: runs-on: ubuntu-24.04 + env: + CACHIX_CACHE_NAME: ${{ vars.CACHIX_CACHE_NAME }} + CACHIX_PUBLIC_KEY: ${{ vars.CACHIX_PUBLIC_KEY }} steps: - name: Check out source @@ -24,16 +27,52 @@ jobs: uses: cachix/install-nix-action@v31 with: github_access_token: ${{ github.token }} + extra_nix_config: | + extra-substituters = https://${{ vars.CACHIX_CACHE_NAME }}.cachix.org + extra-trusted-public-keys = ${{ vars.CACHIX_PUBLIC_KEY }} - name: Update lock file run: nix flake update + - name: Check for lock file changes + id: changes + run: | + if git diff --quiet -- flake.lock; then + echo "changed=false" >> "$GITHUB_OUTPUT" + else + echo "changed=true" >> "$GITHUB_OUTPUT" + fi + + - name: Validate Cachix configuration + if: steps.changes.outputs.changed == 'true' + env: + CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }} + run: | + set -euo pipefail + test -n "$CACHIX_CACHE_NAME" || { echo "CACHIX_CACHE_NAME is not configured" >&2; exit 1; } + test -n "$CACHIX_PUBLIC_KEY" || { echo "CACHIX_PUBLIC_KEY is not configured" >&2; exit 1; } + test -n "$CACHIX_AUTH_TOKEN" || { echo "CACHIX_AUTH_TOKEN is not configured" >&2; exit 1; } + + - name: Configure Cachix + if: steps.changes.outputs.changed == 'true' + uses: cachix/cachix-action@v17 + with: + name: ${{ vars.CACHIX_CACHE_NAME }} + authToken: ${{ secrets.CACHIX_AUTH_TOKEN }} + skipAddingSubstituter: true + useDaemon: true + + - name: Build and push to Cachix + if: steps.changes.outputs.changed == 'true' + run: | + set -euo pipefail + nix build .#default --no-link --print-build-logs --print-out-paths > "$RUNNER_TEMP/out-paths" + cachix push "$CACHIX_CACHE_NAME" < "$RUNNER_TEMP/out-paths" + - name: Commit and push changes + if: steps.changes.outputs.changed == 'true' run: | set -euo pipefail - if git diff --quiet -- flake.lock; then - exit 0 - fi git config user.name "github-actions[bot]" git config user.email "41898282+github-actions[bot]@users.noreply.github.com" git add flake.lock diff --git a/flake.lock b/flake.lock index a0da10c..e2d2715 100644 --- a/flake.lock +++ b/flake.lock @@ -15,16 +15,16 @@ "clash-party": { "flake": false, "locked": { - "lastModified": 1783321592, - "narHash": "sha256-ituoVv/q/aHt3KOt4fHRDGHGEwnF/nb2E73s/oYw74U=", + "lastModified": 1786451647, + "narHash": "sha256-R75fyMlfn9btbQ8yxDHM40ZP5XbS/0wFqCTgDJlWIR8=", "owner": "mihomo-party-org", "repo": "clash-party", - "rev": "1caff4cabd83d0e2768ecadf52c85c5dcc0ed9de", + "rev": "356f9817f00e8cc1a501f1c9389b3b6cf2c66105", "type": "github" }, "original": { "owner": "mihomo-party-org", - "ref": "v2.0.0", + "ref": "v2.0.1", "repo": "clash-party", "type": "github" } diff --git a/flake.nix b/flake.nix index 963fb91..07540fa 100644 --- a/flake.nix +++ b/flake.nix @@ -5,7 +5,7 @@ nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; clash-party = { - url = "github:mihomo-party-org/clash-party/v2.0.0"; + url = "github:mihomo-party-org/clash-party/v2.0.1"; flake = false; }; diff --git a/nix/package.nix b/nix/package.nix index de16c04..57683fe 100644 --- a/nix/package.nix +++ b/nix/package.nix @@ -56,7 +56,7 @@ let in stdenv.mkDerivation (finalAttrs: { pname = "clash-party"; - version = "2.0.0"; + version = "2.0.1"; dontUnpack = true; diff --git a/nix/unwrapped.nix b/nix/unwrapped.nix index 35fc227..2b1acb4 100644 --- a/nix/unwrapped.nix +++ b/nix/unwrapped.nix @@ -36,7 +36,7 @@ stdenv.mkDerivation (finalAttrs: { pname = "clash-party-unwrapped"; - version = "2.0.0"; + version = "2.0.1"; inherit src; patches = [ @@ -58,7 +58,7 @@ stdenv.mkDerivation (finalAttrs: { pnpm config set fetch-timeout 120000 pnpm config set network-concurrency 4 ''; - hash = "sha256-plsb9TjmprG5k2kYkqItEunTeyJWopRBH0SzzU/qM/8="; + hash = "sha256-g6bI798j0ld9jx9ekBcj+mSY6uWyjCWxIytxxgVcDsY="; }; nativeBuildInputs = [ diff --git a/patches/branding.patch b/patches/branding.patch index afb9f52..467d47f 100644 --- a/patches/branding.patch +++ b/patches/branding.patch @@ -1,11 +1,24 @@ diff --git a/electron-builder.yml b/electron-builder.yml +index 69a05cd..2c987b5 100644 --- a/electron-builder.yml +++ b/electron-builder.yml -@@ -59 +59 @@ +@@ -67,7 +67,7 @@ pkg: + alignment: bottomleft + file: build/background.png + linux: - executableName: mihomo-party + executableName: clash-party -@@ -68,2 +68,2 @@ + icon: build/icon.png + desktop: + entry: +@@ -76,8 +76,8 @@ linux: + Comment: A GUI client based on Mihomo + MimeType: 'x-scheme-handler/clash;x-scheme-handler/mihomo' + Keywords: proxy;clash;mihomo;vpn; - StartupWMClass: mihomo-party - Icon: mihomo-party + StartupWMClass: clash-party + Icon: clash-party + target: + - deb + - rpm diff --git a/patches/stable-core-only.patch b/patches/stable-core-only.patch index 2a12667..e94e55a 100644 --- a/patches/stable-core-only.patch +++ b/patches/stable-core-only.patch @@ -1,7 +1,10 @@ diff --git a/src/main/utils/dirs.ts b/src/main/utils/dirs.ts +index 0771ca0..4ea1cb6 100644 --- a/src/main/utils/dirs.ts +++ b/src/main/utils/dirs.ts -@@ -79,6 +79,10 @@ +@@ -86,6 +86,10 @@ export function mihomoCoreDir(): string { + } + export function mihomoCorePath(core: string): string { + if (process.platform === 'linux') { + core = 'mihomo' diff --git a/patches/system-electron-resources.patch b/patches/system-electron-resources.patch index 09879cb..0aa915c 100644 --- a/patches/system-electron-resources.patch +++ b/patches/system-electron-resources.patch @@ -1,84 +1,5 @@ -diff --git a/src/native/sysproxy/index.js b/src/native/sysproxy/index.js ---- a/src/native/sysproxy/index.js -+++ b/src/native/sysproxy/index.js -@@ -70,6 +70,12 @@ function getResourcesPath() { - try { - const { app } = require('electron') - const appPath = app.getAppPath() -+ // A shared system Electron keeps process.resourcesPath in Electron's own -+ // store path. The directory containing app.asar is the app resource path. -+ if (appPath.endsWith('.asar') && existsSync(join(dirname(appPath), 'sidecar'))) { -+ return dirname(appPath) -+ } -+ - if (existsSync(join(appPath, 'extra', 'sidecar'))) { - return appPath - } -diff --git a/src/main/utils/dirs.ts b/src/main/utils/dirs.ts ---- a/src/main/utils/dirs.ts -+++ b/src/main/utils/dirs.ts -@@ -62,13 +62,16 @@ export function workDir(): string { - } - -+export function isDevelopment(): boolean { -+ return is.dev && !app.getAppPath().endsWith('asar') -+} -+ - export function resourcesDir(): string { -- if (is.dev) { -+ const appPath = app.getAppPath() -+ if (appPath.endsWith('asar')) { -+ return path.dirname(appPath) -+ } else if (isDevelopment()) { - return path.join(__dirname, '../../extra') - } else { -- if (app.getAppPath().endsWith('asar')) { -- return process.resourcesPath -- } else { -- return path.join(app.getAppPath(), 'resources') -- } -+ return path.join(appPath, 'resources') - } - } -diff --git a/src/main/window.ts b/src/main/window.ts ---- a/src/main/window.ts -+++ b/src/main/window.ts -@@ -1,11 +1,10 @@ - import { join } from 'path' - import { readFileSync, writeFileSync } from 'fs' - import { BrowserWindow, Menu, screen, shell } from 'electron' --import { is } from '@electron-toolkit/utils' - import icon from '../../resources/icon.png?asset' - import { getAppConfig } from './config' - import { quitWithoutCore, stopCore } from './core/manager' - import { triggerSysProxy } from './sys/sysproxy' - import { hideDockIcon, showDockIcon } from './resolve/tray' --import { dataDir } from './utils/dirs' -+import { dataDir, isDevelopment } from './utils/dirs' - import { mainWindowLogger } from './utils/logger' -@@ -172,10 +171,10 @@ export async function createMainWindow(silentStart = false): Promise { - }) - -- if (is.dev) { -+ if (isDevelopment()) { - mainWindow.webContents.openDevTools() - } - -- if (is.dev && process.env['ELECTRON_RENDERER_URL']) { -+ if (isDevelopment() && process.env['ELECTRON_RENDERER_URL']) { - mainWindow.loadURL(process.env['ELECTRON_RENDERER_URL']) - } else { - mainWindow.loadFile(join(__dirname, '../renderer/index.html')) -@@ -199,7 +198,7 @@ function setupWindowEvents(window: BrowserWindow, config: WindowConfig): void { - } - - // 开发模式下始终显示窗口 -- if (!silentStart || is.dev) { -+ if (!silentStart || isDevelopment()) { - clearQuitTimeout() - window.show() - window.focusOnWebView() diff --git a/src/main/resolve/floatingWindow.ts b/src/main/resolve/floatingWindow.ts +index 49d1852..83fdb75 100644 --- a/src/main/resolve/floatingWindow.ts +++ b/src/main/resolve/floatingWindow.ts @@ -1,8 +1,8 @@ @@ -105,3 +26,91 @@ diff --git a/src/main/resolve/floatingWindow.ts b/src/main/resolve/floatingWindo } catch (error) { logError('Failed to create floating window', error) floatingWindow = null +diff --git a/src/main/utils/dirs.ts b/src/main/utils/dirs.ts +index 0771ca0..d6e2c84 100644 +--- a/src/main/utils/dirs.ts ++++ b/src/main/utils/dirs.ts +@@ -61,15 +61,18 @@ export function exePath(): string { + return app.getPath('exe') + } + ++export function isDevelopment(): boolean { ++ return is.dev && !app.getAppPath().endsWith('asar') ++} ++ + export function resourcesDir(): string { +- if (is.dev) { ++ const appPath = app.getAppPath() ++ if (appPath.endsWith('asar')) { ++ return path.dirname(appPath) ++ } else if (isDevelopment()) { + return path.join(__dirname, '../../extra') + } else { +- if (app.getAppPath().endsWith('asar')) { +- return process.resourcesPath +- } else { +- return path.join(app.getAppPath(), 'resources') +- } ++ return path.join(appPath, 'resources') + } + } + +diff --git a/src/main/window.ts b/src/main/window.ts +index d40f89c..60529a3 100644 +--- a/src/main/window.ts ++++ b/src/main/window.ts +@@ -1,12 +1,11 @@ + import { join } from 'path' + import { readFileSync } from 'fs' + import { BrowserWindow, Menu, screen, shell } from 'electron' +-import { is } from '@electron-toolkit/utils' + import icon from '../../resources/icon.png?asset' + import { getAppConfig } from './config' + import { quitWithoutCore } from './core/manager' + import { hideDockIcon, showDockIcon } from './resolve/tray' +-import { dataDir } from './utils/dirs' ++import { dataDir, isDevelopment } from './utils/dirs' + import { mainWindowLogger } from './utils/logger' + import { atomicWriteFileSync } from './utils/safeFile' + +@@ -199,12 +198,12 @@ async function createWindowInternal(): Promise { + autoQuitWithoutCoreMode + }) + +- if (is.dev) { ++ if (isDevelopment()) { + mainWindow.webContents.openDevTools() + } + + const windowToLoad = mainWindow +- if (is.dev && process.env['ELECTRON_RENDERER_URL']) { ++ if (isDevelopment() && process.env['ELECTRON_RENDERER_URL']) { + await windowToLoad.loadURL(process.env['ELECTRON_RENDERER_URL']) + } else { + await windowToLoad.loadFile(join(__dirname, '../renderer/index.html')) +@@ -228,7 +227,7 @@ function setupWindowEvents(window: BrowserWindow, config: WindowConfig): void { + } + + // 开发模式下始终显示窗口 +- if (!silentStart || is.dev) { ++ if (!silentStart || isDevelopment()) { + clearQuitTimeout() + window.show() + window.focusOnWebView() +diff --git a/src/native/sysproxy/index.js b/src/native/sysproxy/index.js +index 147988f..f1b1ff3 100644 +--- a/src/native/sysproxy/index.js ++++ b/src/native/sysproxy/index.js +@@ -71,6 +71,12 @@ function getResourcesPath() { + try { + const { app } = require('electron') + const appPath = app.getAppPath() ++ // A shared system Electron keeps process.resourcesPath in Electron's own ++ // store path. The directory containing app.asar is the app resource path. ++ if (appPath.endsWith('.asar') && existsSync(join(dirname(appPath), 'sidecar'))) { ++ return dirname(appPath) ++ } ++ + if (existsSync(join(appPath, 'extra', 'sidecar'))) { + return appPath + }