Compare commits

..

1300 Commits
main ... v1.5.7

Author SHA1 Message Date
MystiPanda
50ade92238 Release 1.5.7 2024-03-11 17:09:01 +08:00
MystiPanda
b598d00aef fix: display error 2024-03-11 16:18:39 +08:00
MystiPanda
97bee17e4e chore: Change IP 2024-03-11 16:05:09 +08:00
MystiPanda
6aa5c79332 fix: a little 2024-03-11 15:02:41 +08:00
MystiPanda
7c5ce756f9 fix: Change DNS for MacOS Tun Mode
#568
2024-03-11 14:55:00 +08:00
MystiPanda
43d53a9ffa fix: default value 2024-03-11 13:17:45 +08:00
MystiPanda
e6589bee5b fix: Try to fix touch drag
#456
2024-03-11 12:36:20 +08:00
MystiPanda
9f94cad615 feat: Allow to control whether auto check update 2024-03-11 12:17:46 +08:00
MystiPanda
7778d9f773 style: fix a little 2024-03-10 23:56:04 +08:00
MystiPanda
564bd55147 style: fix styles 2024-03-10 23:47:12 +08:00
MystiPanda
a7ff806522 fix styles 2024-03-10 22:13:25 +08:00
MystiPanda
ac3b074d66 chore: proxy group header height 2024-03-10 21:56:49 +08:00
MystiPanda
da949c2604 chore: adjust proxy group font style 2024-03-10 21:52:40 +08:00
MystiPanda
20a9775dc6 chore: Adjust Profile Style 2024-03-10 21:37:52 +08:00
MystiPanda
8ec19e058f chore: Add Default value 2024-03-10 21:15:22 +08:00
MystiPanda
a5c4549722 style: Adjust icon color 2024-03-10 20:48:13 +08:00
Amnesiash
c7d302aa16
style: Adjust colorful icon (#558)
Co-authored-by: MystiPanda <mystipanda@proton.me>
2024-03-10 20:37:00 +08:00
MystiPanda
77ac565ff3 chore: i18n 2024-03-10 20:33:27 +08:00
MystiPanda
2e6f834a50 chore: Update Icon 2024-03-10 20:14:51 +08:00
MystiPanda
5b044cca9e feat: Add option to control menu icon 2024-03-10 19:54:47 +08:00
MystiPanda
2ab5623809 chore: Adjust styles 2024-03-10 13:24:38 +08:00
MystiPanda
2d07f0d77c Revert "chore: Adjust secondary text style (#545)"
This reverts commit 8ba7f9f70216ac3ae5ff2ac859ec2170737d0cd1.
2024-03-10 13:08:09 +08:00
Amnesiash
8ba7f9f702
chore: Adjust secondary text style (#545) 2024-03-10 12:54:34 +08:00
MystiPanda
460ac7a86b style: Adjust delay fontSize
#544
2024-03-10 12:51:53 +08:00
MystiPanda
f93a1ab3eb docs: update preview 2024-03-10 12:32:08 +08:00
MystiPanda
6b02696aa8 chore: Change Default Font 2024-03-10 12:23:11 +08:00
MystiPanda
25f20d6a85 chore: delete debug output 2024-03-10 11:47:55 +08:00
MystiPanda
8387964bae Release 1.5.6 2024-03-10 11:43:37 +08:00
MystiPanda
926278617f feat: Add default webui
#530
2024-03-10 11:41:22 +08:00
MystiPanda
1933737a0c Adjust styles 2024-03-10 11:21:17 +08:00
MystiPanda
b3e5288bde Adjust styles 2024-03-10 11:12:54 +08:00
wonfen
ed6e966b2f Sytle: UI improvement & Update Readme 2024-03-10 07:00:24 +08:00
MystiPanda
9315fe36b6 fix: fix a little 2024-03-10 00:41:18 +08:00
black23eep
41fbf5ba36
Update layout-traffic.tsx (#528) 2024-03-10 00:35:26 +08:00
MystiPanda
40db481453 chore: update 2024-03-10 00:34:22 +08:00
MystiPanda
1b5e295744 fix: fontSize and some styles 2024-03-10 00:22:22 +08:00
Amnesiash
b42a52f7f6
fix settings.svg (#526) 2024-03-10 00:04:06 +08:00
MystiPanda
8268df84d0 chore: center 2024-03-09 23:38:03 +08:00
Charles
eb6fa5f1f1
tweak(ui): menu icon use svg component (#524) 2024-03-09 23:13:08 +08:00
MystiPanda
025c8856ed fix: img path error 2024-03-09 22:43:53 +08:00
MystiPanda
ed421445e9 Release 1.5.5 2024-03-09 22:02:36 +08:00
Amnesiash
0cda07106b
refactor: Upgrade to the new UI (#521)
Co-authored-by: MystiPanda <mystipanda@proton.me>
2024-03-09 21:37:21 +08:00
wonfen
f335941b62 UI: change paste icon, delete default profile name 2024-03-09 02:34:33 +08:00
Pylogmon
f0719f8bde
feat: Merge Providers (#508) 2024-03-08 11:37:52 +08:00
MystiPanda
27fe28661c
feat: Add animation for provider update 2024-03-02 13:52:48 +08:00
MystiPanda
bb13b12de6
chore: fix style 2024-02-28 18:25:50 +08:00
MystiPanda
1117e28b2e
feat: Try to support touch drag 2024-02-27 23:41:52 +08:00
MystiPanda
0f48873c25
chore: Remove unnecessary hotkey 2024-02-27 11:18:52 +08:00
MystiPanda
faf61b4af3
fix: Image display failed on Linux 2024-02-26 13:31:51 +08:00
Cyenoch
e29ce93d32
Feat: Provide a switch for allowing invalid certificates (#450) 2024-02-25 16:07:06 +08:00
MystiPanda
38ab68492e
chore: change style 2024-02-24 15:39:29 +08:00
MystiPanda
53b1576e5f
Release 1.5.4 2024-02-24 14:00:01 +08:00
MystiPanda
2835e79973
feat: Support Open/Close Dashboard Hotkey
#439
2024-02-24 13:39:30 +08:00
MystiPanda
8e4d7e989b
feat: Show current proxy for group node
#444
2024-02-24 13:09:53 +08:00
MystiPanda
603c6b826c
feat: allow disable group icon 2024-02-24 12:38:17 +08:00
MystiPanda
51bcc77cb3
refactor: Optimize implementation of Custom tray icon 2024-02-24 11:25:22 +08:00
MystiPanda
a30d07b924
feat: Support Custom Tray Icon 2024-02-24 00:52:21 +08:00
MystiPanda
11faa5fe39
Release 1.5.3 2024-02-22 00:23:56 +08:00
MystiPanda
ce8383b26f
feat: add reset button 2024-02-22 00:19:45 +08:00
MystiPanda
bd8f07c90a
fix: Do not set autolaunch at init
#423 #424
2024-02-21 23:50:50 +08:00
MystiPanda
fee077bebd
chore: rm -m arg 2024-02-21 23:38:01 +08:00
MystiPanda
558f4d93ba
chore: change default value of dns hijack 2024-02-21 16:40:47 +08:00
MystiPanda
e77d126349
chore: change default value of strict route 2024-02-21 11:32:51 +08:00
MystiPanda
cd8667d6de
chore: fix placeholder 2024-02-21 11:13:28 +08:00
MystiPanda
8a2d06d010
chore: Add Translation 2024-02-21 11:06:32 +08:00
MystiPanda
92741fc733
feat: Disable system stack when service mode is turned off 2024-02-21 10:52:03 +08:00
MystiPanda
1cff162649
fix: Config data display error
#417
2024-02-21 10:02:28 +08:00
MystiPanda
f59be465ea
Release 1.5.2 2024-02-21 00:04:11 +08:00
MystiPanda
27305317ce
chore: Auto Update config.yml 2024-02-20 23:54:02 +08:00
MystiPanda
8378320e50
feat: Support Tun Config (#416) 2024-02-20 23:27:03 +08:00
MystiPanda
86a69952db
chore: Update patch file 2024-02-20 18:39:36 +08:00
MystiPanda
e212ebfdb9
fix: Allow program run with administrator to start at startup 2024-02-20 18:35:39 +08:00
MystiPanda
f235125d48
chore: add tooltip for tun mode 2024-02-19 18:10:10 +08:00
MystiPanda
8efa815eb9
feat: Support custom delay timeout (#397) 2024-02-18 11:11:22 +08:00
MystiPanda
e54d42576b
build: Try restart windows service after install (#395) 2024-02-18 10:19:54 +08:00
MystiPanda
1e18539862 fix: Merge profile unexpect behavior 2024-02-17 15:58:52 +08:00
MystiPanda
673fdf4721 ci: Update Release Note 2024-02-15 20:05:00 +08:00
MystiPanda
57d6bfba51 ci: change tag 2024-02-15 19:45:37 +08:00
MystiPanda
8fa23aecda chore: update ci script 2024-02-15 19:14:35 +08:00
MystiPanda
f9c10533e8 chore: Change CI Name 2024-02-15 18:45:13 +08:00
MystiPanda
c891c3723e ci: Support alpha package 2024-02-15 18:43:20 +08:00
MystiPanda
a0625ef2e7 chore: remove 32bit package 2024-02-15 18:22:15 +08:00
MystiPanda
b2774abb54 chore: default show proxy detials 2024-02-15 18:17:21 +08:00
wonfen
fa089bbc40 doc: remove 32bit package 2024-02-12 02:25:18 +08:00
MystiPanda
8437d1763f fix: build error 2024-02-11 20:51:00 +08:00
MystiPanda
0532b0f9df Release v1.5.1 2024-02-11 20:32:25 +08:00
MystiPanda
5f8eb853f0 style: clear script 2024-02-11 20:03:14 +08:00
MystiPanda
9125a85382 fix: Custom GLOBAL group display error 2024-02-11 18:27:27 +08:00
MystiPanda
5b3dc44c72 feat: Show proxies count for provider 2024-02-10 13:13:27 +08:00
MystiPanda
ee5147f111 feat: Save window maximize state 2024-02-10 12:51:30 +08:00
MystiPanda
f67137fd5e style: change config name
#350
2024-02-08 10:23:54 +08:00
MystiPanda
b67db4a896 fix: Script profile invalid
#347
2024-02-06 08:55:44 +08:00
MystiPanda
067018828c Release 1.5.0 2024-02-06 00:41:12 +08:00
MystiPanda
e990530ada refactor: Remove clash field filter 2024-02-05 17:28:36 +08:00
wonfen
45f863a72a chore: enable clash field TLS fingerprint 2024-02-04 13:07:25 +08:00
MystiPanda
519febbeb2 fix: Try to fix traffic parse error
#337
2024-02-04 10:24:37 +08:00
wonfen
854b1a4caf chore: update changelog 2024-02-03 16:14:26 +08:00
MystiPanda
08eb95e73a fix: Copy Env Type Select Error 2024-02-02 17:57:56 +08:00
MystiPanda
66f8fbf08c chore: typo 2024-02-02 17:47:28 +08:00
MystiPanda
86a30bbb29 chore: Update Changelog 2024-02-02 17:34:15 +08:00
MystiPanda
966c453c27 fix: prevent_exit 2024-02-02 17:26:31 +08:00
MystiPanda
c7bcaf0193 Release 1.4.11 2024-02-02 16:56:39 +08:00
MystiPanda
0ac91e36a0 fix: exit_app event 2024-02-02 16:32:19 +08:00
MystiPanda
6f1299ce9e chore: fix styles 2024-02-02 16:15:23 +08:00
MystiPanda
83ca29d649 chore: Remove prevent_close 2024-02-02 15:57:03 +08:00
MystiPanda
d0206044dc fix: Fix Nisi Error 2024-02-02 15:53:28 +08:00
ycjcl868
d4623e4175
chore: unused clash core (#284) 2024-01-23 11:22:15 +08:00
MystiPanda
68ef03377d chore: fix style 2024-01-21 13:49:07 +08:00
MystiPanda
d3f9d3d033 revert: some style 2024-01-21 13:49:07 +08:00
wonfen
a6ccd04471 Sytle: UI improvement 2024-01-20 16:05:01 +08:00
Lai Zn
0fd8174e77
fix: Solve the confliction issues on auto updater failure (#273) 2024-01-20 13:03:48 +08:00
MystiPanda
ebc63f479a revert: Support both registry and api for windows sysproxy 2024-01-20 12:16:46 +08:00
MystiPanda
570c39c20a build: Update lock file 2024-01-18 22:34:14 +08:00
MystiPanda
1d57257cf5 Release v1.4.10 2024-01-18 22:26:23 +08:00
MystiPanda
82d7baee0b feat: Add exit button on setting page 2024-01-18 22:19:14 +08:00
MystiPanda
1d91e1f1f7 build: Update Depends 2024-01-18 16:26:38 +08:00
MystiPanda
15e8894614 feat: Support Custom Start Page 2024-01-18 15:37:02 +08:00
Lai Zn
0ae96918e9
feat: Use url path name as fallback subscription name (#255) 2024-01-18 14:36:37 +08:00
MystiPanda
e970880059 feat: Show SubInfo for Proxy Provider
#211
2024-01-18 14:26:57 +08:00
Lai Zn
69ae86aba8
fix: make port change set to system proxy immediately (#256) 2024-01-18 09:37:46 +08:00
MystiPanda
8142e1be49 fix: use nanoid to compatible with old devices 2024-01-18 01:16:39 +08:00
MystiPanda
cbc7612451 feat: Optimizing Provider Support 2024-01-18 01:02:30 +08:00
Kiri
09e6a7b7cc
feat: Add support for loong64 (#246) 2024-01-17 22:30:51 +08:00
Lai Zn
082e35668a
docs: Add guidelines for windows development (#250) 2024-01-17 19:02:39 +08:00
MystiPanda
c9e78c837b fix: Do not use proxy when test on tun mode 2024-01-17 18:08:09 +08:00
MystiPanda
2d171db672 Release v1.4.9 2024-01-17 15:43:15 +08:00
MystiPanda
a8b11abec8 feat: Support Startup Script 2024-01-17 15:06:16 +08:00
MystiPanda
b08333dccd feat: Support proxy group icon 2024-01-17 13:32:56 +08:00
MystiPanda
98bad48971 fix: Fix connection table sort error
#108
2024-01-17 12:54:54 +08:00
MystiPanda
53375bb536 chore: Update I18n 2024-01-17 11:30:19 +08:00
MystiPanda
88798093e1 fix: csp error 2024-01-17 11:08:14 +08:00
MystiPanda
45a28751af feat: Add Test Page 2024-01-17 11:02:17 +08:00
MystiPanda
1670c44464 fix: fix column width 2024-01-16 19:02:38 +08:00
MystiPanda
a286ac85dc Release v1.4.8 2024-01-16 15:36:04 +08:00
MystiPanda
1606adc0ab feat: Support both registry and api for windows sysproxy 2024-01-16 15:11:53 +08:00
MystiPanda
b4ce557d92 fix: Can not use specify update time when create profile 2024-01-16 10:29:04 +08:00
MystiPanda
2ba7fff8d4 refactor: rm theme blur 2024-01-15 17:13:55 +08:00
MystiPanda
98efc93610 Revert Use Tauri Http Api 2024-01-15 10:18:04 +08:00
MystiPanda
2680507eae Revert Use Tauri Websocket 2024-01-15 10:17:00 +08:00
MystiPanda
df72392ad2 fix: Fix connections sort issue and add total traffic info 2024-01-15 00:46:19 +08:00
MystiPanda
a6acb15a00 refactor: Use Tauri Http API 2024-01-14 19:35:03 +08:00
MystiPanda
ba7242a815 refactor: Use Tauri WebSocket 2024-01-14 17:30:18 +08:00
MystiPanda
99740c1324 fix patch error 2024-01-11 14:47:25 +08:00
MystiPanda
c04b20d1fa Release v1.4.7 2024-01-11 13:19:05 +08:00
MystiPanda
e127067878 feat: Disable updater for portable 2024-01-11 12:44:30 +08:00
MystiPanda
6f03b72368 feat: Support hide group
#214
2024-01-11 12:34:05 +08:00
Morris Li
7bd3ee9340
Fix expired Tauri domain (#222) 2024-01-11 10:17:56 +08:00
MystiPanda
c94db606e5 build: Use old sysproxy 2024-01-10 19:24:14 +08:00
MystiPanda
4d2474226b refactor: cargo clippy 2024-01-10 17:36:35 +08:00
MystiPanda
1ffc4f538b refactor: Optimizing the implementation of Linux URL Scheme registration 2024-01-10 16:34:35 +08:00
MystiPanda
6702ac957b fix: resolve scheme error 2024-01-10 15:37:40 +08:00
MystiPanda
ba42b2e77d fix: linux build error 2024-01-10 15:22:08 +08:00
MystiPanda
fba18ca40a feat: Support URL Scheme for MacOS 2024-01-10 14:04:06 +08:00
MystiPanda
3a2a7a1476 feat: Support URL Scheme for Linux 2024-01-10 13:03:34 +08:00
MystiPanda
3c6d6b90bc build: fix macos build script 2024-01-09 22:49:11 +08:00
MystiPanda
47dc9ee304 fix patch error 2024-01-09 22:25:25 +08:00
MystiPanda
0045bf206c Release v1.4.6 2024-01-09 22:17:29 +08:00
MystiPanda
669a1a6953 feat: Support URL Scheme for Windows
#165
2024-01-09 21:57:06 +08:00
MystiPanda
e28452cc7b feat: Optimize control button style 2024-01-09 16:04:56 +08:00
MystiPanda
5ceac03db1 feat: Add pin button 2024-01-09 15:13:59 +08:00
MystiPanda
96215e5950 fix: Fix some compile error 2024-01-09 14:52:43 +08:00
wonfen
7a030b9224 Style: UI improvement & 1.4.6 ready 2024-01-09 13:57:53 +08:00
wonfen
e743478a4d chore: UI adjustment 2024-01-08 19:32:21 +08:00
MystiPanda
bc29c80d44 chore: Use Latest and compatible core 2023-12-23 12:09:19 +08:00
MystiPanda
82b8a474d7 fix: Cargo clippy 2023-12-21 16:49:21 +08:00
MystiPanda
99851b297d fix: Get filename error
#165
2023-12-19 19:52:13 +08:00
MystiPanda
e3a500e12c fix: portable flag 2023-12-15 21:39:34 +08:00
MystiPanda
378666e3cc chore: update service url 2023-12-15 20:38:17 +08:00
MystiPanda
b65ad1ebd7 fix: user-agent version error 2023-12-15 15:18:01 +08:00
MystiPanda
933a821b5f fix: Subinfo parse error 2023-12-15 11:35:10 +08:00
MystiPanda
159337ddbd Release 1.4.5 2023-12-14 17:40:48 +08:00
MystiPanda
2e25a4333a fix: Window control button icon issue
#136
2023-12-14 14:59:55 +08:00
MystiPanda
64fafb0795 chore: Remove unsafe function 2023-12-14 13:56:51 +08:00
MystiPanda
5927e0bb3b fix: icon size 2023-12-14 13:20:01 +08:00
MystiPanda
e21596db83 feat: Update MacOS tray icon 2023-12-14 13:11:46 +08:00
MystiPanda
8a608c3c3e chore: Optimize service path 2023-12-14 13:03:52 +08:00
MystiPanda
76f9db8516 chore: Optimize upgrade process 2023-12-14 11:24:26 +08:00
MystiPanda
90f4809b7c chore: default enable clash field filter 2023-12-14 10:49:58 +08:00
MystiPanda
3ff1af9fd6 chore: Delete unnecessary drag area 2023-12-13 11:09:19 +08:00
MystiPanda
711dd520f7 chore: Change service path 2023-12-13 10:59:07 +08:00
MystiPanda
99503c836a fix: Save wrong window size 2023-12-12 16:42:19 +08:00
MystiPanda
2c8bc51862 Revert "fix: Change PID file path"
This reverts commit d64bdf02de5bb0c34c2165e3dddcb239e6c26034.
2023-12-12 15:59:00 +08:00
MystiPanda
5e7aa15232 fix: Can't switch env type 2023-12-11 10:51:59 +08:00
MystiPanda
d0761869b6 build: fix update issue 2023-12-10 22:24:46 +08:00
MystiPanda
bb99b89228 build: fix patch 2023-12-10 21:40:57 +08:00
MystiPanda
7b88beb0b5 v1.4.4 2023-12-10 21:36:22 +08:00
MystiPanda
82c630bd0e
feat: Support windows aarch64 (#112) 2023-12-10 20:45:27 +08:00
MystiPanda
bb4f11e1b8 feat: Patch for windows aarch64 2023-12-10 19:50:01 +08:00
MystiPanda
3182d20b7c build: Update Depends 2023-12-10 17:14:48 +08:00
MystiPanda
a6f15e2474 chore: Hide script mode for alpha core 2023-12-10 16:31:55 +08:00
MystiPanda
0c3f03680c Support upgrade alpha core 2023-12-10 15:57:10 +08:00
MystiPanda
a66e8dfc9f feat: Support update geodata
#37
2023-12-10 15:22:04 +08:00
zclkkk
556232aac4
chore: Allow user to choose where to install (#110) 2023-12-10 09:50:43 +08:00
MystiPanda
7fcfaadd91 chore: Remove script mode 2023-12-09 17:04:03 +08:00
MystiPanda
18d388e1e2 docs: Update ISSUE_TEMPLATE 2023-12-09 12:00:01 +08:00
MystiPanda
7de6622d74 feat: Support different tray icon for macos 2023-12-09 11:22:02 +08:00
MystiPanda
9af1f90990 feat: Support different tray icon for linux 2023-12-09 11:03:19 +08:00
Pylogmon
15ab43963d
feat: Optimize copy environment variable logic (#106) 2023-12-08 22:16:42 +08:00
MystiPanda
6b7465a4b0 perf: Improves window creation speed 2023-12-08 13:10:35 +08:00
MystiPanda
d64bdf02de fix: Change PID file path
#99
2023-12-08 11:59:40 +08:00
MystiPanda
4a2c94993a docs: Update README 2023-12-07 16:49:59 +08:00
MystiPanda
86c318d86b feat: Add AppImage for x86 linux 2023-12-07 16:38:39 +08:00
MystiPanda
bffc1ad41d ci: fix build script 2023-12-07 16:17:34 +08:00
MystiPanda
2a685c116f chore: Fix build error 2023-12-07 16:02:29 +08:00
MystiPanda
0e271d2924 ci: Fix Linux CI Script 2023-12-07 15:57:53 +08:00
MystiPanda
7127c4d590 ci: Fix Linux Build Script 2023-12-07 15:34:49 +08:00
MystiPanda
a82929996b chore: change default port to 7897 2023-12-07 14:52:14 +08:00
MystiPanda
3f01f52c7b refactor: fix depends 2023-12-07 14:44:44 +08:00
MystiPanda
9c94494622 refactor: Remove unnecessary changes 2023-12-07 13:43:53 +08:00
MystiPanda
c8a508f35c Revert "chore: change default port to 7897"
This reverts commit 4ec73ef1c3e546d36706a034f65781cf0694deed.
2023-12-07 13:32:49 +08:00
wonfen
4ec73ef1c3 chore: change default port to 7897 2023-12-06 03:37:16 +08:00
MystiPanda
3465b79e5b docs: Update README 2023-12-05 17:02:54 +08:00
MystiPanda
726a0a33ae docs: UPDATELOG 2023-12-05 16:47:42 +08:00
MystiPanda
ba05810d80 Release 1.4.3 2023-12-05 16:28:50 +08:00
MystiPanda
10bb53e7de chore: fix appid 2023-12-05 15:41:13 +08:00
MystiPanda
dd8a083546 refactor: Change app_home to standard locations of app_data 2023-12-05 15:39:44 +08:00
MystiPanda
84131a71c9 fix: Stop core before install update 2023-12-05 15:01:15 +08:00
MystiPanda
4909a11896 docs: Update README 2023-12-05 13:33:23 +08:00
MystiPanda
4069357b81 refactor: Remove page animation 2023-12-05 13:30:55 +08:00
MystiPanda
e6e87bcc40 refactor: Change Tun Icon Color 2023-12-05 13:23:54 +08:00
MystiPanda
7ba22045e8 build: Dependency downgrade 2023-12-05 12:55:20 +08:00
Pylogmon
d4040b61c4
refactor: Change Portable Config Path (#66) 2023-12-05 12:52:26 +08:00
Pylogmon
7534f8fc37
refactor: Hide Clash Field Option when Disable Filter (#63) 2023-12-05 08:34:57 +08:00
MystiPanda
7ced009e92
Update README.md 2023-12-04 14:51:46 +08:00
MystiPanda
cc13c71e40 ci: fix updater 2023-12-04 13:51:46 +08:00
MystiPanda
d2f09209a7 chore: Use Nsis 2023-12-04 13:45:28 +08:00
Pylogmon
a241b04d99
fix: Open File (#56) 2023-12-04 12:15:12 +08:00
Pylogmon
4f35d907cb
fix: Get Profile Filename (#54) 2023-12-04 12:15:01 +08:00
MystiPanda
9e50d144a3
chore: change linux meta core to compatible 2023-12-04 11:38:54 +08:00
wonfen
8514bb48c4 chore: change windows meta core to compatible 2023-12-04 06:00:31 +08:00
WhizPanda
3ae633a2a1 fix: alpha core can't display memory 2023-12-03 18:55:38 +08:00
WhizPanda
2799cb9118 style: fix icon size 2023-12-03 18:28:41 +08:00
WhizPanda
d20346b6ac docs: Update README.md 2023-12-03 16:42:49 +08:00
Pylogmon
2f00666a68
style: improve drag icon style (#51) 2023-12-03 16:27:13 +08:00
WhizPanda
80f4570093 ci: Fix Portable Script 2023-12-03 15:36:39 +08:00
wonfen
3f0a2ba48f docs: update readme 2023-12-03 15:25:33 +08:00
WhizPanda
fc90094e8a
feat: Support Both Stable and Alpha Version (#47) 2023-12-03 14:26:03 +08:00
wonfen
20d580ade8 release: 1.4.2, tweak UI, fix emoji on mac 2023-12-03 14:01:53 +08:00
WhizPanda
290a024a9e chore: Adjust style 2023-12-02 23:20:04 +08:00
WhizPanda
64a283c3a6 chore: Replace Repo Name 2023-12-02 23:04:04 +08:00
WhizPanda
3e93f0ecbc build: Update Depends 2023-12-02 22:36:04 +08:00
WhizPanda
b12bcc1c49 style: Improve Style 2023-12-02 16:23:53 +08:00
WhizPanda
05d7313dcc feat: Support New Clash Field
#46
2023-12-02 15:18:54 +08:00
WhizPanda
c0b6e549f0 build: Update Cargo Depends 2023-12-01 15:52:49 +08:00
WhizPanda
31f9bf219e build: Update Depends 2023-12-01 14:49:32 +08:00
WhizPanda
4906ca7059 feat: support random mixed port 2023-12-01 12:56:18 +08:00
WhizPanda
b963a7a0e5
fix: Fix Updater Script 2023-12-01 11:19:49 +08:00
WhizPanda
5d6dadda76
Remove unnecessary conditions 2023-12-01 11:11:20 +08:00
Pylogmon
77f69fd223
feat: Add Windows x86 and Linux armv7 Support (#44)
* feat: Add Windows x86 and Linux armv7 Support

* ci: Remove Linux armv7 Support
2023-12-01 11:03:18 +08:00
Pylogmon
7f5052bc87
feat: Use Latest Meta Core mihomo (#41) 2023-12-01 02:44:18 +08:00
Pylogmon
3009c1f4f6
feat: Support cross-compiling to aarch64 (#40)
#19
2023-11-30 22:46:09 +08:00
Pylogmon
5425872bba
feat: Support Disable Tray Click Event (#38)
#21
2023-11-30 22:45:02 +08:00
Pylogmon
0759e17295
feat: Set different tray icon on tun mode (#33)
好看!
2023-11-30 01:29:11 +08:00
Pylogmon
56a59d25df
feat: Add Download Progress for Updater (#34) 2023-11-30 01:28:46 +08:00
Pylogmon
887f92babe
feat: Support Drag to Reorder the Profile (#29)
* feat: Support Drag to Reorder the Profile

* style: Remove unnecessary styles
2023-11-29 08:54:02 +08:00
wonfen
197f942b3f
Merge pull request #27 from Pylogmon/emoji-font
feat: Embed Emoji fonts
2023-11-28 10:41:35 +08:00
Pylogmon
a5be7a35e9 feat: Embed Emoji fonts 2023-11-28 10:36:32 +08:00
wonfen
e347675265 fix: Adjust font order 2023-11-28 10:03:01 +08:00
wonfen
02a084d571 chore: update preview gif 2023-11-28 08:49:22 +08:00
wonfen
7fbcc23d94 Merge branch 'main' of github.com:wonfen/clash-verge-rev 2023-11-28 07:53:11 +08:00
wonfen
bda87167a3 update clashmeta core, Imporve UI, merge PR, reset icons, fix CI 2023-11-28 07:49:44 +08:00
wonfen
34f53c287e
Merge pull request #24 from Pylogmon/tray
fix: Tray Icon Tooltip is Empty
2023-11-28 01:46:41 +08:00
wonfen
9ab07f37d7
Merge pull request #21 from Pylogmon/tray-event
feat: Config Tray Click Event
2023-11-28 01:46:16 +08:00
Pylogmon
36399b39fb chore: fix style 2023-11-27 20:10:31 +08:00
Pylogmon
1e015287a1 chore: Add Translation 2023-11-27 20:04:47 +08:00
Pylogmon
a590aa8485 fix: Tray Icon Tooltip is Empty 2023-11-27 19:55:42 +08:00
Pylogmon
c0582fde66 chore: Remove Debug Info 2023-11-26 18:49:48 +08:00
Pylogmon
d8d75b4afa feat: Config Tray Click Event 2023-11-26 18:35:21 +08:00
wonfen
9d4942723c fix: portable CI again 2023-11-23 15:01:30 +08:00
wonfen
e5b1ece5c0 chore: change preview gif and fix portable CI 2023-11-23 14:34:11 +08:00
wonfen
1b25bfbf5a fix: CI portable 2023-11-23 13:42:16 +08:00
wonfen
7c64d9f42a
Merge pull request #3 from Kuingsmile/main
fix: Downgrade runas to fix service install bug
2023-11-23 11:11:06 +08:00
wonfen
61f9f4ef58 chore: update clash.meta core to 2023.11.23, change win icons. 2023-11-23 11:10:32 +08:00
Kuingsmile
b8eac56213 fix: Downgrade runas to fix service install bug 2023-11-22 17:17:12 -08:00
wonfen
ab5fb5749b
Merge pull request #2 from Kuingsmile/main
feat: Update DialogContent width in EditorViewer
2023-11-23 07:46:12 +08:00
Kuingsmile
e0fb9a1b25 feat: Update DialogContent width in EditorViewer
component
2023-11-22 06:49:47 -08:00
wonfen
97e717f646
Merge pull request #1 from Kuingsmile/main
feat: add UWP loopback tools
2023-11-22 16:23:38 +08:00
Kuingsmile
caa82ad1e6 feat: add UWP loopback tools 2023-11-22 00:15:41 -08:00
wonfen
7ec251ea6d chore: UI adjustment, add translation, fix CI 2023-11-22 14:52:14 +08:00
wonfen
675b0c3cca chore: update readme & fix updater issue 2023-11-22 07:31:38 +08:00
wonfen
05e54d4b7f chore: remove old updater CI 2023-11-22 07:06:08 +08:00
wonfen
b4527c90e5 Merge remote-tracking branch 'nyanpasu/main' 2023-11-22 06:48:30 +08:00
wonfen
dbc626734d chore: delete clash core, update CI, change profile name, change URL test link 2023-11-22 02:56:47 +08:00
keiko233
3f2ce3cb80 chore: fix typos 2023-11-16 11:31:06 +08:00
keiko233
0820d6d6fb chore: add updater workflow 2023-11-16 10:59:27 +08:00
keiko233
a8c74e39c2 chore: remove un supported platform
* I don't have the relevant equipment to test with
* May support in future
2023-11-16 10:56:03 +08:00
keiko233
d58c29907d chore: no need for second build 2023-11-16 10:41:28 +08:00
keiko233
2322733427 chore: fix missing assets type 2023-11-16 10:37:26 +08:00
keiko233
d76e8fe85a chore: remove un supported platform 2023-11-16 10:30:25 +08:00
keiko233
0c2e4fe34a chore: fix typos 2023-11-16 10:30:01 +08:00
keiko233
30b6c87a49 docs: add preview gif 2023-11-15 15:17:51 +08:00
keiko233
540221467a chore: clean up workflows 2023-11-15 14:37:10 +08:00
keiko233
d44d331a78 Bump Version 1.4.0 2023-11-15 14:06:29 +08:00
keiko233
595554f18a chore: add release build 2023-11-15 13:52:56 +08:00
keiko233
84d3c3f7eb fix: rust lint 2023-11-15 13:49:06 +08:00
keiko233
890f55c9dc chore: test: use pnpm 2023-11-13 14:49:28 +08:00
keiko233
575a14e1f3 feat: minor tweaks 2023-11-12 00:10:23 +08:00
keiko233
91074bebd6 feat: Nyanpasu Misc 2023-11-12 00:09:32 +08:00
keiko233
3459a16b48 chore: switch updater endpoints 2023-11-12 00:08:23 +08:00
keiko233
88c9b6849f fix: valid with unified-delay & tcp-concurrent 2023-11-11 22:34:30 +08:00
keiko233
d87bb25baf chore: delete current release assets 2023-11-11 22:27:28 +08:00
keiko233
34cb796505 feat: add baseContentIn animation 2023-11-11 19:34:03 +08:00
keiko233
1eb34e0662 feat: add route transition 2023-11-11 18:32:11 +08:00
keiko233
01d631033f feat: Material You! 2023-11-11 17:12:57 +08:00
keiko233
84b2c07340 fix: touchpad scrolling causes blank area to appear 2023-11-11 15:03:41 +08:00
keiko233
a86eeb636d chore: drop upload-artifact & use prerelease 2023-11-11 15:00:54 +08:00
keiko233
417a5a8214 chore: fix: typos
* ↑ baka
2023-11-10 11:50:01 +08:00
keiko233
bcf40dde8c fix: typos 2023-11-10 11:35:38 +08:00
keiko233
cad87484c7 fix: download clash core from backup repo 2023-11-10 11:26:05 +08:00
keiko233
b8ad641ed6 chore: add dev workflow 2023-11-10 10:38:41 +08:00
keiko233
ae8197be8b feat: default disable ipv6 2023-11-10 09:10:15 +08:00
keiko233
eafb0274a7 feat: default enable unified-delay & tcp-concurrent with use meta core 2023-11-10 09:08:17 +08:00
keiko233
71a23a4e02 refactor: copy_clash_env 2023-11-09 10:52:52 +08:00
keiko233
26fd90dfa3 feat: support copy CMD & PowerShell proxy env 2023-11-09 09:58:17 +08:00
keiko233
e393ebede2 fix: use meta Country.mmdb 2023-11-09 09:35:41 +08:00
keiko233
2981bb3f19 feat: default use meta core
* :)
2023-11-09 09:34:03 +08:00
keiko233
6e9f05abb1 feat: update Clash Default bypass addrs
*Enabling TUN will cause the local address to go through the proxy
2023-11-09 09:33:38 +08:00
GyDi
9df1115380 chore: fix check 2023-11-03 16:00:34 +08:00
GyDi
f22e360cbb chore: fix check script 2023-11-03 15:52:36 +08:00
MZhao
67769af6f4
feat: new windows tray icons (#899) 2023-11-03 15:01:46 +08:00
Aromia
b1a9a1d6d9
chore: update download links in README.md (#896) 2023-11-03 11:21:20 +08:00
Goooler
cf0606ecb7
chore: bump github actions (#868)
https://github.com/actions/checkout/releases/tag/v4.0.0
https://github.com/actions/setup-node/releases/tag/v4.0.0
2023-11-02 20:14:05 +08:00
neovali
7287edcd6f
chore: add fedora linux install description (#874) 2023-11-02 20:13:24 +08:00
GyDi
e0d26203dd feat: support auto clean log files 2023-11-02 20:12:46 +08:00
GyDi
7e3a85e9da
fix: latency url empty 2023-11-01 23:22:30 +08:00
GyDi
5a0fed9c93 feat: increase the concurrency of latency test 2023-11-01 20:52:38 +08:00
GyDi
1f1e743912
fix: change default port 2023-10-31 14:56:19 +08:00
GyDi
b4301ed0d5
fix: csp 2023-10-31 12:00:57 +08:00
GyDi
b5391560fc
v1.3.8 2023-10-31 01:29:20 +08:00
GyDi
718989cbcf
chore: update log 2023-10-31 01:28:57 +08:00
GyDi
d0aee76962
fix: add default valid key 2023-10-30 17:10:51 +08:00
GyDi
fb08af96bd
fix: page null exception, close #821 2023-10-30 00:53:24 +08:00
GyDi
510a0c5e70
feat: adjust the delay display interval and color, close #836 2023-10-29 23:01:05 +08:00
keiko233
89bdc8ec75 chore: update dependencies 2023-10-22 00:44:01 +08:00
keiko233
ae25ade318 chore: tsconfig: skip Lib Check 2023-10-21 23:53:57 +08:00
keiko233
dd5e46a8a7 feat: theme: change color 2023-10-21 17:30:50 +08:00
keiko233
f7218aaa9e chore: update README.md 2023-10-21 17:02:13 +08:00
keiko233
ee79bcfc44 feat: profiles: import btn with loading state 2023-10-21 16:50:46 +08:00
keiko233
2c2c174874 feat: profile-viewer: handleOk with loading state 2023-10-21 16:47:39 +08:00
keiko233
f57c49ce3a feat: base-dialog: okBtn use LoadingButton 2023-10-21 16:47:10 +08:00
keiko233
06121acfac chore: import MUI Lab 2023-10-21 16:43:30 +08:00
keiko233
2078ce7446 chore: Update dependencies 2023-10-21 16:43:16 +08:00
keiko233
49f41abfdb feat: Nyanpasu Misc 2023-10-20 11:52:40 +08:00
keiko233
70fcfe6d6c feat: Theme support modify --background-color 2023-10-20 11:12:49 +08:00
keiko233
b060b4b9bf feat: settings use Grid layout 2023-10-20 10:05:03 +08:00
keiko233
ee2135bfb3 chore: Use your own update endpoints and public keys 2023-10-19 09:37:31 +08:00
keiko233
7daa322441 chore: readme remove ad 2023-10-18 13:38:58 +08:00
GyDi
74252cb66b chore: fix rust lint 2023-10-18 13:38:03 +08:00
GyDi
5fe2be031f
chore: fix rust lint 2023-10-11 14:55:20 +08:00
GyDi
2ba3aaba47
chore: fix alpha ci 2023-10-11 14:31:44 +08:00
GyDi
ad8903991c
fix: try fix csp 2023-10-11 14:21:56 +08:00
GyDi
3e5624c570
chore: update readme 2023-10-11 00:04:56 +08:00
keiko233
88d3bba300 feat: add Connections Info to ConnectionsPage
*Add Upload Traffic, Download Traffic and Active Connections to ConnectionsPage.
*IConnections uploadTotal and downloadTotal data missing not displayed, add it to ConnectionsPage interface here.
2023-10-10 17:05:31 +08:00
Majokeiko
f5ee6f3537
feat: ClashFieldViewer BaseDialog maxHeight usage percentage (#813)
*The overall interface will be more intuitive when the content is longer.
2023-10-10 14:29:27 +08:00
GyDi
afc77e7adc
chore: update readme 2023-10-10 10:25:57 +08:00
GyDi
024f42fce6
chore: update readme 2023-10-10 10:25:01 +08:00
GyDi
8a5f12b97c
chore: update clash meta 2023-10-08 21:45:12 +08:00
GyDi
954b21cf39
chore: update readme 2023-09-11 10:24:44 +08:00
GyDi
74d095774d
chore: fix updater 2023-09-11 10:16:54 +08:00
GyDi
17a2722e6d
chore: fix updater 2023-09-11 10:12:40 +08:00
GyDi
c843bddbfe
chore: fix clash map, close #736 2023-09-10 19:06:02 +08:00
GyDi
3f22a49755
v1.3.7 2023-09-10 19:02:10 +08:00
GyDi
7af2ffcebf
chore: update log 2023-09-10 19:01:59 +08:00
GyDi
de90c959e0
chore: update auto launch 2023-09-10 18:45:17 +08:00
GyDi
9987dc1eb4
fix: i18n 2023-09-10 15:03:29 +08:00
GyDi
3efd575dd2
feat: add Open Dashboard to the hotkey, close #723 2023-09-10 14:46:03 +08:00
GyDi
f4c7b17a87
feat: add check for updates button, close #766 2023-09-10 14:30:31 +08:00
GyDi
16d80718cb
fix: fix page undefined exception, close #770 2023-09-10 13:45:18 +08:00
GyDi
ad228d53b7
feat: add paste and clear icon 2023-09-09 16:52:00 +08:00
Majokeiko
15ee1e531b
feat: Subscription URL TextField use multiline (#761)
*Subscription link that are too long can make reading difficult, so use multiline TextField.
2023-09-07 16:14:42 +08:00
GyDi
1c8fb3392a
chore: update mmdb 2023-08-28 15:06:13 +08:00
GyDi
8647866a32
fix: set min window size, close #734 2023-08-28 15:00:27 +08:00
GyDi
23351c4f1c
chore: change ubuntu ci version 2023-08-28 14:44:09 +08:00
GyDi
1367c304cf
chore: update clash 2023-08-28 14:22:50 +08:00
GyDi
26d6bcb074
chore: update release link 2023-08-14 11:11:15 +08:00
GyDi
b0d651ece1
chore: update clash meta 2023-08-14 11:09:19 +08:00
GyDi
b6d50ba6a4
fix: rm debug code 2023-08-12 19:16:20 +08:00
GyDi
b3ab6a9166
v1.3.6 2023-08-12 16:12:03 +08:00
GyDi
f39a5ac9c2
chore: update log 2023-08-12 16:11:50 +08:00
GyDi
38a9a9240d
fix: use sudo when pkexec not found 2023-08-12 15:58:37 +08:00
GyDi
241b22a465
chore: update ci 2023-08-12 15:41:26 +08:00
GyDi
741abc0366
feat: show loading when change profile 2023-08-05 22:07:30 +08:00
GyDi
7854775de5
fix: remove div 2023-08-05 21:43:58 +08:00
GyDi
e62eaa6b4b
fix: list key 2023-08-05 21:43:05 +08:00
GyDi
b4cce23ef4
feat: support proxy provider update 2023-08-05 21:38:44 +08:00
GyDi
2bcaf90fc8
feat: add repo link 2023-08-05 19:54:59 +08:00
GyDi
96ffbe2f84
feat: support clash meta memory usage display 2023-08-05 19:40:23 +08:00
GyDi
6f5acee1c3
fix: websocket disconnect when window focus 2023-08-05 17:21:15 +08:00
GyDi
54e491d8bf
feat: supports show connection detail 2023-08-05 16:52:14 +08:00
GyDi
ab6374e278
chore: update geo data to meta, close #707 2023-08-05 13:42:37 +08:00
GyDi
2fda4c9f67
chore: fix faq 2023-08-05 13:41:30 +08:00
GyDi
5138a45b0f
chore: add faq and download link 2023-08-05 13:38:19 +08:00
GyDi
b224d4fa8a
chore: add promotion 2023-08-05 12:57:48 +08:00
whitemirror33
a552e44483
feat: update connection table with wider process column and click to show full detail (#696) 2023-08-04 14:36:28 +08:00
GyDi
0cf3bba118
feat: more trace logs 2023-08-04 14:15:15 +08:00
Andrei Shevchuk
2c48ea3508
feat: Add Russian Language (#697)
* Add Russian Language

* Add Russian support

* Minor update

* Update Russian translation
2023-08-03 11:07:58 +08:00
GyDi
b9b6212b75
fix: try fix undefined error 2023-07-28 09:26:06 +08:00
GyDi
b978aaec21
chore: alpha ci 2023-07-26 17:07:20 +08:00
GyDi
af704681d9
feat: center window when out of monitor 2023-07-24 20:55:26 +08:00
GyDi
1443ddfe6c
chore: fix test ci 2023-07-24 09:59:13 +08:00
GyDi
54457a3e1b
chore: fix test ci 2023-07-24 09:47:05 +08:00
GyDi
bf180e6a2c
chore: test ci 2023-07-24 09:28:54 +08:00
GyDi
864a5820c9
chore: test ci 2023-07-24 09:13:19 +08:00
GyDi
4d3ca49c3f
v1.3.5 2023-07-23 13:31:51 +08:00
GyDi
c49c3cf7f0
chore: update log 2023-07-23 13:31:34 +08:00
GyDi
5d5ab57469
fix: blurry tray icon in Windows 2023-07-23 13:25:54 +08:00
GyDi
31978d8de0
chore: update clash core 2023-07-23 13:11:35 +08:00
GyDi
e8eb68bf24
chore: fix check script 2023-07-23 13:11:17 +08:00
GyDi
9ea08f4fed
chore: update issue templates 2023-07-22 23:04:13 +08:00
GyDi
fe078a5c5b
v1.3.4 2023-07-22 20:38:08 +08:00
GyDi
61933954f3
chore: update log 2023-07-22 20:37:22 +08:00
GyDi
4c243638cb
fix: enable context menu in editable element 2023-07-22 17:21:04 +08:00
GyDi
02ba04b5d8
feat: support copy environment variable 2023-07-22 15:35:32 +08:00
GyDi
4f158a4829
fix: save window size and pos in Windows 2023-07-22 13:13:16 +08:00
GyDi
177a22df59
feat: save window size and position 2023-07-22 10:58:16 +08:00
GyDi
6b0ca2966e
feat: app log level add silent 2023-07-22 09:25:54 +08:00
GyDi
aadfaf7150
feat: overwrite resource file according to file modified 2023-07-22 09:18:54 +08:00
GyDi
b307b9a66b
feat: support app log level settings 2023-07-22 08:53:37 +08:00
Kimiblock Moe
6c1ab6002d
feat: Use polkit to elevate permission instaed of sudo (#678) 2023-07-21 23:05:33 +08:00
GyDi
9638eefc91
chore: update check script 2023-07-11 13:25:55 +08:00
GyDi
9e9c4ad587
fix: optimize traffic graph high CPU usage when hidden 2023-07-10 23:44:09 +08:00
GyDi
ce231431b9
fix: remove fallback group select status, close #659 2023-07-10 23:16:19 +08:00
GyDi
06e1e14e02
chore: update clash 2023-07-10 13:36:17 +08:00
GyDi
416e7884f5
feat: add unified-delay field 2023-06-30 13:58:51 +08:00
GyDi
d579222007
v1.3.3 2023-06-30 09:38:33 +08:00
GyDi
30243c84cd
chore: update log 2023-06-30 09:35:49 +08:00
GyDi
3557a77645
fix: error boundary with key 2023-06-30 09:17:59 +08:00
GyDi
97be28638b
chore: update clash meta 2023-06-30 09:02:26 +08:00
GyDi
aba0826c38
fix: connections is null 2023-06-30 09:02:17 +08:00
GyDi
f032228d0e
fix: font family not works in some interfaces, close #639 2023-06-29 14:21:14 +08:00
GyDi
6cf174c5ed
fix: encodeURIComponent secret 2023-06-29 14:15:57 +08:00
GyDi
c2109d245f
chore: update clash & clash meta 2023-06-08 13:52:40 +08:00
GyDi
6a9745171e
feat: add error boundary to the app root 2023-06-08 13:50:45 +08:00
GyDi
f9a68e8b23
fix: encode controller secret, close #601 2023-06-08 13:48:58 +08:00
GyDi
6e391df5ee
fix: linux not change icon 2023-05-28 18:14:11 +08:00
GyDi
f5edca94d3
fix: try fix blank error 2023-05-28 17:35:00 +08:00
GyDi
60046abec3
fix: close all connections when change mode 2023-05-28 17:07:39 +08:00
GyDi
cafc2060b8 fix: macos not change icon 2023-05-28 16:46:17 +08:00
GyDi
b1f45752cf chore: update deps 2023-05-28 16:45:43 +08:00
GyDi
ed17551170 chore: update clash 2023-05-28 16:44:07 +08:00
w568w
ef5adab638
feat: show tray icon variants in different status (#537) 2023-05-28 10:55:39 +08:00
GyDi
fb653ff99d
fix: error message null 2023-05-19 10:53:11 +08:00
GyDi
78fc47a9c4
chore: update gh proxy 2023-05-19 09:44:31 +08:00
GyDi
2a124cea61
v1.3.2 2023-05-19 00:57:22 +08:00
GyDi
4c7cc563dc
chore: update log 2023-05-19 00:57:10 +08:00
GyDi
6114af4f93
fix: profile data undefined error, close #566 2023-05-18 20:02:46 +08:00
GyDi
8c31629655
chore: update clash core 2023-05-05 20:45:52 +08:00
GyDi
03c8a8edb2
chore: update deps 2023-05-05 20:27:46 +08:00
yettera765
3eeaee154f
fix: import url error (#543)
use rustls instead of depending user's system tls
2023-05-05 12:08:08 +08:00
GyDi
8cf8fa7c80
v1.3.1 2023-04-11 10:04:55 +08:00
GyDi
6b4f6fc71e
chore: update log 2023-04-11 10:04:28 +08:00
Tatius Titus
30c2680b6f
chore: Upgrade to React 18 (#495)
* chore: Upgrade to React 18

* runfix: Add children type to FC components

* chore: Remove @types/react
2023-04-07 12:59:44 +08:00
Mr-Spade
fb7b1800cc
fix: linux DEFAULT_BYPASS (#503) 2023-04-07 12:47:13 +08:00
GyDi
ff573bf377
chore: update deps 2023-04-02 11:20:18 +08:00
GyDi
0a33bb861e
fix: open file with vscode 2023-04-02 11:19:48 +08:00
GyDi
728756289b
chore: update deps 2023-04-02 10:09:14 +08:00
GyDi
56ccd3a0ac
chore: update clash meta 2023-04-02 09:43:32 +08:00
Tatius Titus
66f3f0ba07
fix: Do not render div as a descendant of p (#494) 2023-04-02 09:37:09 +08:00
Srinivas Gowda
af5e0d589e
chore: update clash core version (#476) 2023-03-27 10:59:27 +08:00
GyDi
533dc99e7d
fix: use replace instead 2023-03-17 08:37:45 +08:00
GyDi
fc5ca965ba
fix: escape path space 2023-03-17 08:36:19 +08:00
John Smith
9c4a46bcdb
fix: escape the space in path (#451) 2023-03-17 08:20:35 +08:00
GyDi
52658886e7
fix: add target os linux 2023-03-16 23:57:34 +08:00
GyDi
8174ab7616
chore: fix ci 2023-03-16 23:54:14 +08:00
GyDi
2b6acedae1
fix: appimage path unwrap panic 2023-03-16 23:45:48 +08:00
GyDi
d00fe9c5f4
v1.3.0 2023-03-16 21:33:51 +08:00
GyDi
88aa270728
chore: update log 2023-03-16 21:33:14 +08:00
GyDi
4ae409c7f4
feat: auto restart core after grand permission 2023-03-16 21:32:39 +08:00
GyDi
9a29c9abdd
feat: add restart core button 2023-03-16 20:56:37 +08:00
GyDi
66d93ea037
fix: remove esc key listener in macOS 2023-03-16 20:42:45 +08:00
GyDi
6c0066dbfb
feat: support update all profiles 2023-03-16 20:32:41 +08:00
GyDi
4fde644733
chore: rm file 2023-03-16 20:31:48 +08:00
GyDi
e7841c60df
fix: adjust style 2023-03-16 19:32:59 +08:00
hybo
94f647b24a
chore: evaluate error context lazily (#447) 2023-03-16 17:06:52 +08:00
GyDi
630249d22a
fix: adjust swr option 2023-03-16 17:03:12 +08:00
GyDi
db99b4cb54
fix: infinite retry when websocket error 2023-03-16 17:03:00 +08:00
GyDi
c77db23586
fix: type error 2023-03-16 13:51:46 +08:00
GyDi
daf66bcec4
chore: update deps 2023-03-16 13:42:27 +08:00
GyDi
8caf36349f
chore: fix ci 2023-03-16 13:18:05 +08:00
GyDi
6934de58e5
chore: fix ci 2023-03-16 13:16:30 +08:00
GyDi
54a5007c01
feat: support to grant permission to clash core 2023-03-16 11:16:54 +08:00
GyDi
e25a455698
fix: do not parse log except the clash core 2023-03-16 10:34:28 +08:00
GyDi
ab429dfeb6
feat: support clash fields filter in ui 2023-03-15 08:43:24 +08:00
GyDi
c5289dc0e8
fix: field sort for filter 2023-03-15 08:43:03 +08:00
boatrainlsz
d191877002
chore: update README (#435) 2023-03-07 22:55:38 +08:00
GyDi
4d979160c2
chore: update deps 2023-03-07 00:10:49 +08:00
GyDi
d00e8f6e19
chore: update clash 2023-03-06 23:35:30 +08:00
GyDi
91b77e5237
fix: add meta fields 2023-02-18 00:46:03 +08:00
GyDi
5b8c246d53
chore: update clash 2023-02-18 00:09:40 +08:00
GyDi
b374b9b91c
feat: open dir on the tray 2023-02-17 00:15:21 +08:00
GyDi
403717117e
fix: runtime config user select 2023-02-17 00:00:23 +08:00
GyDi
027295d995
feat: support to disable clash fields filter 2023-02-16 23:52:55 +08:00
GyDi
c9b7eccbc1
fix: app_handle as_ref 2023-02-15 17:25:35 +08:00
GyDi
2b6d9348cd
fix: use crate 2023-02-11 23:31:55 +08:00
GyDi
692f8c8454
fix: appimage auto launch, close #403 2023-02-11 23:19:08 +08:00
inRm3D
6783355c4d
chore: add openssl depend (#395) 2023-02-02 10:54:15 +08:00
GyDi
fb9cca1e99
v1.2.3 2023-02-01 22:11:34 +08:00
GyDi
eb770ede1a
chore: update log 2023-02-01 22:11:06 +08:00
GyDi
2643e853af
chore: aarch script 2023-02-01 21:41:15 +08:00
GyDi
b79456e91b
chore: update clash 2023-01-30 20:50:08 +08:00
GyDi
ac66c086f8
chore: meta ci 2023-01-30 20:40:57 +08:00
GyDi
ebccf401dd
chore: fix ci 2023-01-22 13:31:34 +08:00
GyDi
66494845b7
chore: fix ci 2023-01-19 18:02:08 +08:00
GyDi
e6c36ad602
chore: alpha ci 2023-01-18 23:39:27 +08:00
inRm3D
26379182db
chore: try fix missing libssl3 (#378)
* Update ci.yml

* use package from source
2023-01-18 23:36:18 +08:00
GyDi
bba03d14d4
fix: compatible with UTF8 BOM, close #283 2023-01-17 19:51:02 +08:00
GyDi
23b728a762
feat: adjust macOS window style 2023-01-16 22:57:53 +08:00
GyDi
819c5207d2
fix: use selected proxy after profile changed 2023-01-15 21:33:03 +08:00
GyDi
311358544e
fix: error log 2023-01-15 19:11:51 +08:00
GyDi
4480ecc96d
chore: ci 2023-01-14 22:22:18 +08:00
GyDi
6c5f70a205
v1.2.2 2023-01-14 22:01:28 +08:00
GyDi
99adfb4a9e
chore: update log 2023-01-14 21:56:27 +08:00
GyDi
7909cf4067
fix: adjust fields order 2023-01-14 14:57:55 +08:00
GyDi
780ab20aeb
fix: add meta fields 2023-01-14 14:51:29 +08:00
GyDi
73119bb7c5
chore: ci 2023-01-14 12:20:17 +08:00
GyDi
f20f0f064e
chore: update clash meta 2023-01-14 12:16:09 +08:00
GyDi
1b44ae098c
fix: add os platform value 2023-01-14 12:07:31 +08:00
GyDi
453c230716
feat: recover core after panic, close #353 2023-01-14 11:45:47 +08:00
GyDi
439d885ee1
chore: allow unused 2023-01-13 23:11:48 +08:00
GyDi
43dee3ef76
fix: reconnect traffic websocket 2023-01-13 23:02:45 +08:00
GyDi
c71ba6ff8d
chore: update deps 2023-01-13 21:29:21 +08:00
GyDi
fb7a36eb73
feat: use decorations in Linux, close #354 2023-01-12 00:42:33 +08:00
GyDi
e7f294a065
fix: parse bytes precision, close #334 2023-01-11 14:05:49 +08:00
GyDi
d5037f180e
fix: trigger new profile dialog, close #356 2023-01-11 13:45:16 +08:00
GyDi
e90158809a
fix: parse log cause panic 2023-01-11 13:30:14 +08:00
GyDi
0cb802ed9a
chore: update clash meta 2023-01-09 21:55:03 +08:00
GyDi
d0b47204f4
v1.2.1 2022-12-23 22:44:27 +08:00
GyDi
351cb391e5
chore: update log 2022-12-23 22:44:00 +08:00
GyDi
051be927cd
fix: avoid setting login item repeatedly, close #326 2022-12-23 22:39:27 +08:00
GyDi
8bad2c2113
fix: adjust code 2022-12-15 21:54:48 +08:00
GyDi
2bcf6fb3eb
fix: adjust delay check concurrency 2022-12-15 12:23:57 +08:00
GyDi
d1ba0ed2b2
chore: adjust code 2022-12-15 12:22:20 +08:00
GyDi
6e421e60c5
fix: change default column to auto 2022-12-14 16:56:33 +08:00
GyDi
8385050804
fix: change default app version 2022-12-14 16:15:53 +08:00
GyDi
bfe4f08232
fix: adjust rule ui 2022-12-14 15:59:41 +08:00
GyDi
132f914b0d
fix: adjust log ui 2022-12-14 15:49:05 +08:00
GyDi
97d82b03ab
fix: keep delay data 2022-12-14 15:29:02 +08:00
GyDi
f06fa3f9b7
fix: use list item button 2022-12-14 15:16:49 +08:00
GyDi
6337788a22
fix: proxy item style 2022-12-14 15:15:44 +08:00
GyDi
024db4358b
feat: auto proxy layout column 2022-12-14 15:07:51 +08:00
GyDi
173f35487e
chore: fix ci 2022-12-13 18:13:28 +08:00
GyDi
74cbe82dd1
chore: fix ci 2022-12-13 18:11:43 +08:00
GyDi
a8c30d30a9
chore: fix ci 2022-12-13 18:02:23 +08:00
GyDi
1b7a52d5af
chore: alpha ci 2022-12-13 17:44:46 +08:00
GyDi
e5109789bf
chore: alpha ci 2022-12-13 17:41:53 +08:00
GyDi
4d2b35e09d
feat: support to change proxy layout column 2022-12-13 17:34:39 +08:00
GyDi
5c5177ec57
feat: support to open core dir 2022-12-13 00:44:24 +08:00
GyDi
d93b00cd15
chore: update deps 2022-12-12 00:00:45 +08:00
MoeShin
39ade59174
fix: Virtuoso no work in legacy browsers (#318) 2022-12-08 10:47:42 +08:00
GyDi
0309c815b9
chore: update deps 2022-12-04 20:54:43 +08:00
GyDi
ce613098db
fix: adjust ui 2022-12-04 00:45:39 +08:00
GyDi
ab34044196
feat: profile page ui 2022-11-28 22:29:58 +08:00
GyDi
17f724748f
chore: deps 2022-11-28 22:27:23 +08:00
GyDi
f3a917b5e7
chore: update clash version 2022-11-26 13:25:52 +08:00
GyDi
376011ea08
fix: refresh websocket 2022-11-25 22:22:57 +08:00
GyDi
2ce7624c14
fix: adjust ui 2022-11-24 18:24:34 +08:00
GyDi
c62dddd5b9
feat: save some fields in the runtime config, close #292 2022-11-24 17:52:25 +08:00
GyDi
490ba9f140
chore: alpha ci 2022-11-24 11:14:03 +08:00
GyDi
f76890cc56
fix: parse bytes base 1024 2022-11-24 11:11:31 +08:00
GyDi
e1c8f1fed9
fix: add clash fields 2022-11-24 10:46:21 +08:00
GyDi
6e19a4ab8b
chore: ci 2022-11-24 10:41:03 +08:00
GyDi
b156523a7f
chore: ci 2022-11-24 10:35:22 +08:00
GyDi
d20b745ae5
fix: direct mode hide proxies 2022-11-24 10:35:09 +08:00
GyDi
c51e9e6b2c
feat: add meta feature 2022-11-24 10:26:41 +08:00
GyDi
1a31fa9067
fix: profile can not edit 2022-11-24 10:26:25 +08:00
GyDi
558b8499af
chore: ci 2022-11-23 23:46:32 +08:00
GyDi
986c162988
v1.2.0 2022-11-23 23:15:39 +08:00
GyDi
770d5cd11c
chore: ci 2022-11-23 23:15:20 +08:00
GyDi
446d2ab3af
chore: update log 2022-11-23 23:13:44 +08:00
GyDi
2f9bf7f063
feat: display proxy group type 2022-11-23 18:27:57 +08:00
GyDi
72ff9c0964
chore: rm dead code 2022-11-23 17:45:49 +08:00
GyDi
33b1a11d85
fix: parse logger time 2022-11-23 17:45:43 +08:00
GyDi
06dabf1e4e
fix: adjust service mode ui 2022-11-23 17:45:22 +08:00
GyDi
28d3691e0b
feat: add use clash hook 2022-11-23 17:44:40 +08:00
GyDi
ffa21fbfd2
fix: adjust style 2022-11-23 17:42:01 +08:00
GyDi
db028665fd
fix: check hotkey and optimize hotkey input, close #287 2022-11-23 17:30:19 +08:00
GyDi
6bc83d9f27
fix: mutex dead lock 2022-11-23 16:04:25 +08:00
GyDi
790d832155
fix: adjust item ui 2022-11-23 15:29:42 +08:00
GyDi
f477cecdeb
fix: regenerate config before change core 2022-11-23 09:57:21 +08:00
GyDi
e031389021
fix: close connections when profile change 2022-11-23 00:20:57 +08:00
GyDi
e00f826eb8
fix: lint 2022-11-22 23:02:18 +08:00
GyDi
24f4e8ab99
chore: fix check script 2022-11-22 23:01:04 +08:00
GyDi
1550d528bd
fix: windows service mode 2022-11-22 22:01:34 +08:00
GyDi
40c041031e
fix: init config file 2022-11-22 22:01:19 +08:00
GyDi
3e555ec9f1
chore: fix mmdb url 2022-11-22 21:15:45 +08:00
GyDi
5098f14aab
fix: service mode error and fallback to sidecar 2022-11-22 20:47:21 +08:00
GyDi
a355a9c85e
fix: service mode viewer ui 2022-11-22 20:45:17 +08:00
GyDi
e7db2a8573
chore: update check script 2022-11-22 20:44:44 +08:00
GyDi
9b18bd0b48
fix: create theme error, close #294 2022-11-22 16:01:33 +08:00
GyDi
f95ddd594e
feat: guard the mixed-port and external-controller 2022-11-22 15:45:17 +08:00
GyDi
fe8168784f
feat: adjust builtin script and support meta guard script 2022-11-22 12:00:48 +08:00
MoeShin
4046f143f6
fix: matchMedia().addEventListener #258 (#296) 2022-11-22 09:25:39 +08:00
GyDi
e4e16999c8
chore: alpha release add portable 2022-11-22 00:16:30 +08:00
GyDi
10f3ba4ff4
chore: alpha ci 2022-11-21 23:19:25 +08:00
GyDi
3cd2be5081
fix: check config 2022-11-21 23:11:56 +08:00
GyDi
c9359978f9
fix: show global when no rule groups 2022-11-21 23:06:32 +08:00
GyDi
781c67b31a
fix: service viewer ref 2022-11-21 23:02:48 +08:00
GyDi
020bd129fb
fix: service ref error 2022-11-21 22:33:06 +08:00
GyDi
8086b6d78c
feat: disable script mode when use clash meta 2022-11-21 22:28:57 +08:00
GyDi
48e14b36b8
feat: check config when change core 2022-11-21 22:27:55 +08:00
GyDi
b3c1c56579
fix: group proxies render list is null 2022-11-21 22:10:24 +08:00
GyDi
bd0e932910
feat: support builtin script for enhanced mode 2022-11-21 21:05:00 +08:00
GyDi
525e5f88ae
chore: update ci 2022-11-20 23:17:05 +08:00
GyDi
005eeb0e0b
chore: update ci node version 2022-11-20 23:14:43 +08:00
GyDi
d21bb015e8
fix: pretty bytes 2022-11-20 23:08:30 +08:00
GyDi
7338838b0e
feat: adjust profiles page ui 2022-11-20 22:37:34 +08:00
GyDi
8bb4803ff9
refactor: adjust base components export 2022-11-20 22:03:55 +08:00
GyDi
892b919cf3
refactor: adjust setting dialog component 2022-11-20 21:48:39 +08:00
GyDi
572d81ecef
fix: use verge hook 2022-11-20 20:12:58 +08:00
GyDi
a4ce7a4037
feat: optimize proxy page ui 2022-11-20 19:46:16 +08:00
GyDi
6eafb15cf9
chore: adjust type 2022-11-19 17:22:29 +08:00
GyDi
e19fe5ce1c
fix: adjust notice 2022-11-19 01:24:07 +08:00
GyDi
9d2017e598
feat: add error boundary 2022-11-19 01:22:19 +08:00
GyDi
f33c419ed9
chore: rm polyfill 2022-11-19 01:22:00 +08:00
GyDi
f425fbaf9d
feat: adjust clash log 2022-11-18 22:08:06 +08:00
GyDi
bcc5ec897a
fix: windows issue 2022-11-18 20:15:34 +08:00
GyDi
f5f2fe3472
fix: change dev log level 2022-11-18 18:37:29 +08:00
GyDi
b7c3863882
fix: patch clash config 2022-11-18 18:37:17 +08:00
GyDi
d759f48ee8
fix: cmds params 2022-11-18 18:26:55 +08:00
GyDi
3a37075e71
Merge branch 'refactor' 2022-11-18 18:21:49 +08:00
GyDi
58366c0b87
chore: rm code 2022-11-18 18:19:26 +08:00
GyDi
2667ed13f1
refactor: done 2022-11-18 18:18:41 +08:00
GyDi
34daffbc96
refactor: adjust all path methods and reduce unwrap 2022-11-18 10:26:39 +08:00
GyDi
be81cd72af
fix: adjust singleton detect 2022-11-18 08:24:27 +08:00
GyDi
4ae00714d2
fix: change template 2022-11-18 08:04:26 +08:00
GyDi
f24cbb6692
refactor: rm code 2022-11-17 23:21:13 +08:00
GyDi
5a35c5b928
refactor: fix 2022-11-17 22:53:41 +08:00
GyDi
1880da6351
refactor: rm dead code 2022-11-17 22:52:22 +08:00
GyDi
df93cb103c
refactor: for windows 2022-11-17 20:19:40 +08:00
GyDi
63b474a32c
refactor: wip 2022-11-17 17:07:13 +08:00
GyDi
abdbf158d1
refactor: wip 2022-11-16 01:26:41 +08:00
GyDi
ee68d80d0a
refactor: wip 2022-11-15 01:33:50 +08:00
GyDi
c8e6f3a627
refactor: rm update item block_on 2022-11-14 23:07:51 +08:00
GyDi
dc941575fe
refactor: fix 2022-11-14 22:50:47 +08:00
GyDi
e64103e5f2
fix: copy resource file 2022-11-14 21:11:42 +08:00
GyDi
f0ab03a9fb
chore: tmpl add clash core 2022-11-14 21:10:29 +08:00
GyDi
09965f1cc6
feat: add draft 2022-11-14 19:31:22 +08:00
GyDi
d2852bb34a
refactor: fix 2022-11-14 01:45:58 +08:00
GyDi
b03c52a501
refactor: wip 2022-11-14 01:26:33 +08:00
GyDi
fd6633f536
fix: MediaQueryList addEventListener polyfill 2022-11-13 10:27:26 +08:00
GyDi
320ac81f48
chore: fix ci 2022-11-12 17:07:47 +08:00
GyDi
70bcd2428f
chore: alpha ci 2022-11-12 17:06:26 +08:00
GyDi
71f5ada0a3
chore: lock version 2022-11-12 17:06:18 +08:00
GyDi
aab5141404
chore: fix ci 2022-11-12 16:54:57 +08:00
GyDi
ff6b119f27
chore: alpha ci 2022-11-12 16:47:27 +08:00
GyDi
7ef4b7eeb8
fix: change default tun dns-hijack 2022-11-12 11:48:02 +08:00
GyDi
4668be6e24
chore: format rust code 2022-11-12 11:37:23 +08:00
GyDi
a211fc7c97
fix: something 2022-11-11 22:45:32 +08:00
GyDi
54af0b675d
chore: update deps 2022-11-11 21:28:34 +08:00
GyDi
8c8171e774
feat: change default latency test url 2022-11-11 01:24:18 +08:00
GyDi
0bb1790206
fix: provider proxy sort by delay 2022-11-11 01:21:23 +08:00
GyDi
45fc84d8be
chore: rm dead code 2022-11-10 22:58:46 +08:00
GyDi
f7500f4cad
chore: clash meta compatible and geosite.dat 2022-11-10 22:58:34 +08:00
GyDi
0cfd718d8a
feat: auto close connection when proxy changed 2022-11-10 01:27:05 +08:00
GyDi
5f486d0f51
fix: profile item menu ui dense 2022-11-09 15:53:42 +08:00
GyDi
6e5a2f85a1
fix: disable auto scroll to proxy 2022-11-09 11:44:09 +08:00
GyDi
e66a89208d
feat: support to change external controller 2022-11-06 23:23:26 +08:00
GyDi
7f65c501c6
feat: add sub-rules 2022-11-05 15:50:06 +08:00
GyDi
22c2382765
feat(macOS): support cmd+w and cmd+q 2022-11-04 00:51:46 +08:00
GyDi
38e1a4febf
chore: update clash meta 2022-11-04 00:36:32 +08:00
GyDi
8db554b377
chore: fix ci 2022-11-03 01:34:23 +08:00
GyDi
5f5cc55331
chore: compatible ci 2022-11-03 01:32:16 +08:00
GyDi
2f8b39186f
chore: update ci 2022-11-03 01:15:50 +08:00
GyDi
a3a724e2e6
chore: test ci 2022-11-03 00:51:49 +08:00
GyDi
73235c8699
chore: test ci 2022-11-03 00:48:27 +08:00
GyDi
7e5999e862
chore: add x 2022-11-02 00:57:27 +08:00
GyDi
afa244dcb0
v1.1.2 2022-11-02 00:54:51 +08:00
GyDi
4ea5bb2390
fix: check remote profile 2022-11-02 00:51:25 +08:00
GyDi
e545d552f6
chore: update log 2022-11-02 00:44:45 +08:00
GyDi
56fe7b3596
feat: add version on tray 2022-11-01 23:29:59 +08:00
GyDi
eb28ec866a
feat: add animation 2022-10-29 23:36:10 +08:00
GyDi
4649454282
fix: remove smoother 2022-10-29 20:05:55 +08:00
angrylid
a45dc6efda
feat: add animation to ProfileNew component (#252)
* chore: add .vscode to .gitignore

* feat: add animation to ProfileNew component
2022-10-29 20:02:51 +08:00
GyDi
9e56b9fbb5
fix: icon button color 2022-10-29 19:22:15 +08:00
GyDi
5504994cb9
feat: check remote profile field 2022-10-28 13:00:52 +08:00
GyDi
acff6d0432
fix: init system proxy correctly 2022-10-28 01:33:21 +08:00
GyDi
eea9cb7c5b
fix: open file 2022-10-28 01:26:45 +08:00
GyDi
c0ddddfb1f
fix: reset proxy 2022-10-28 01:06:54 +08:00
GyDi
f7dab3ca56
fix: init config error 2022-10-28 01:02:47 +08:00
GyDi
e11b4038a3
feat: system tray support zh language 2022-10-28 00:40:29 +08:00
GyDi
b635e64803
fix: adjust reset proxy 2022-10-27 21:14:14 +08:00
GyDi
20a194b49a
fix: adjust code 2022-10-27 21:13:27 +08:00
GyDi
33a5fb8837
fix: add https proxy 2022-10-26 17:11:54 +08:00
GyDi
59dae640db
fix: auto scroll into view when sorted proxies changed 2022-10-26 01:24:06 +08:00
GyDi
a6ac75e97b
feat: display delay check result timely 2022-10-26 01:11:02 +08:00
GyDi
cc5b33a8ec
fix: refresh proxies interval, close #235 2022-10-26 01:08:34 +08:00
GyDi
6e1a627b84
fix: style 2022-10-25 23:54:21 +08:00
GyDi
62d4c65e1c
chore: update deps 2022-10-25 23:54:10 +08:00
GyDi
600134a3ac
fix: fetch profile with system proxy, close #249 2022-10-25 23:45:24 +08:00
LooSheng
df14af7337
fix: The profile is replaced when the request fails. (#246) 2022-10-23 17:22:26 +08:00
GyDi
2f740b570d
fix: default dns config 2022-10-22 22:26:40 +08:00
GyDi
294d980b52
fix: kill clash when exit in service mode, close #241 2022-10-22 13:55:06 +08:00
GyDi
c9d9909d74
chore: update mmdb 2022-10-22 13:30:08 +08:00
GyDi
90eeabae7b
feat: update profile with system proxy/clash proxy 2022-10-18 23:19:21 +08:00
GyDi
a32c77c5f1
chore: adjust code 2022-10-17 23:26:25 +08:00
GyDi
910846f2ce
fix: icon button color inherit 2022-10-16 14:40:45 +08:00
GyDi
35d0438261
fix: app version to string 2022-10-16 14:38:57 +08:00
GyDi
515af472ce
fix: break loop when core terminated 2022-10-14 14:46:15 +08:00
GyDi
f062f7f9fe
feat: change global mode ui, close #226 2022-10-13 11:54:52 +08:00
GyDi
f68378041f
feat: default user agent same with app version 2022-10-12 11:28:47 +08:00
GyDi
30ef3057ac
v1.1.1 2022-10-11 23:03:12 +08:00
GyDi
48f3a934c9
chore: update log 2022-10-11 23:02:49 +08:00
GyDi
38d1fde84f
fix: api error handle 2022-10-11 22:51:18 +08:00
GyDi
dd78670a4b
fix: clash meta not load geoip, close #212 2022-10-11 22:24:54 +08:00
GyDi
b8a8190a43
fix: sort proxy during loading, close #221 2022-10-11 22:06:55 +08:00
GyDi
2d0989342f
fix: not create windows when enable slient start 2022-10-11 21:50:00 +08:00
GyDi
15ff9b06a1
fix: root background color 2022-10-11 20:49:03 +08:00
GyDi
41b19f69de
fix: create window correctly 2022-10-11 00:57:34 +08:00
GyDi
f2bd6f1fce
fix: set_activation_policy 2022-10-10 22:15:21 +08:00
GyDi
ec94218a4b
chore: rm aarch64 ci 2022-09-28 18:50:33 +08:00
GyDi
c2e5c7cf38
chore: test ci 2022-09-28 17:26:32 +08:00
GyDi
bac5734527
chore: test ci 2022-09-28 17:12:27 +08:00
GyDi
bef4033d94
chore: fix ci 2022-09-28 16:04:05 +08:00
GyDi
64216cba67
chore: fix test ci 2022-09-28 15:19:50 +08:00
Particle_G
a9d6167a9f
chore: add support for windows arm64, close #216 (#209) 2022-09-28 15:13:24 +08:00
GyDi
6c6b40548f
fix: disable spell check 2022-09-28 14:15:22 +08:00
苏业钦
a916d88e85
chore: add support linux arm64 (#215) 2022-09-28 10:40:41 +08:00
GyDi
ab2f0548a3
chore: clash meta linux use compatible version 2022-09-27 00:16:22 +08:00
GyDi
e30ba07285
feat: optimize config feedback 2022-09-26 20:46:29 +08:00
GyDi
1b336d973d
fix: adjust init launch on dev 2022-09-26 01:35:19 +08:00
GyDi
7b1866737f
v1.1.0 2022-09-26 01:27:56 +08:00
GyDi
eedc4ab648
chore: update log 2022-09-26 01:27:32 +08:00
GyDi
5e429c7a94
fix: ignore disable auto launch error 2022-09-26 01:09:05 +08:00
GyDi
57d23eb043
fix(macos): set auto launch path to application 2022-09-25 23:36:55 +08:00
GyDi
5ebd9be89a
fix: i18n 2022-09-25 01:41:46 +08:00
GyDi
5a743779e2
feat: show connections with table layout 2022-09-25 01:35:21 +08:00
GyDi
0495062110
fix: style 2022-09-24 20:55:40 +08:00
GyDi
d522191f69
fix: save enable log on localstorage 2022-09-24 19:03:14 +08:00
Priestch
bbbdc8b7a6
fix: typo in api.ts (#207) 2022-09-24 18:48:11 +08:00
GyDi
c00ed8aa5a
chore: use ubuntu latest 2022-09-24 16:08:39 +08:00
GyDi
0beaa94068
feat: show loading on proxy group delay check 2022-09-24 15:31:09 +08:00
GyDi
96e76665d6
fix: refresh clash ui await patch 2022-09-24 14:01:28 +08:00
Shun Li
6423a29600
feat: add chains[0] and process to connections display (#205)
* add chains[0] display

* add metadata.process to connections
2022-09-24 13:06:32 +08:00
GyDi
8bddf30dcf
refactor(hotkey): use tauri global shortcut 2022-09-23 15:31:01 +08:00
GyDi
a6b2db182d
feat: adjust connection page ui 2022-09-23 00:08:52 +08:00
GyDi
b9f3f9d859
Merge pull request #197 from FoundTheWOUT/main
Support ordering connection
2022-09-22 22:55:46 +08:00
GyDi
6331447dcd
feat: yaml merge key 2022-09-21 22:15:24 +08:00
GyDi
4213ee660f
feat: toggle log ws 2022-09-20 22:15:28 +08:00
GyDi
3bd9287c5d
chore: update deps 2022-09-20 21:26:38 +08:00
GyDi
b23d3f7c8b
feat: add rule page 2022-09-18 23:19:02 +08:00
GyDi
f8d9e5e027
feat: hotkey viewer 2022-09-18 15:52:53 +08:00
GyDi
8fa7fb3b1f
feat: refresh ui when hotkey clicked 2022-09-18 15:50:03 +08:00
FoundTheWOUT
63d92a0872 Support ordering connection 2022-09-15 15:52:12 +08:00
GyDi
509d83365e
feat: support hotkey (wip) 2022-09-14 01:19:02 +08:00
GyDi
d6ab73c905
fix: remove dead code 2022-09-12 13:42:21 +08:00
GyDi
5a93ba05d5
fix: style 2022-09-12 13:42:13 +08:00
GyDi
2d2fdf0b1e
fix: handle is none 2022-09-12 00:45:19 +08:00
GyDi
cf96622261
fix: unused 2022-09-12 00:02:25 +08:00
GyDi
47c8ccb0e5
refactor: optimize 2022-09-11 20:58:55 +08:00
GyDi
02fdb8778b
fix: style 2022-09-11 18:38:51 +08:00
GyDi
6bed7f0e66
fix: windows logo size 2022-09-11 17:50:58 +08:00
GyDi
7597d335b9
feat: hide window on macos 2022-09-09 16:42:35 +08:00
GyDi
f32c5ba244
fix: do not kill sidecar during updating 2022-09-09 16:33:04 +08:00
GyDi
ab53ab21e2
fix: delay update config 2022-09-09 16:30:27 +08:00
GyDi
acfe5dbb49
fix: reduce logo size 2022-09-09 16:19:13 +08:00
GyDi
f9b91fa189
feat: system proxy setting 2022-09-07 01:51:43 +08:00
GyDi
2462e68ba1
fix: window center 2022-09-06 22:18:06 +08:00
GyDi
019b2a1681
chore: update resource 2022-09-06 15:32:22 +08:00
GyDi
e94a07b677
fix: log level warn value 2022-09-06 14:42:58 +08:00
GyDi
c058c29755
feat: change default singleton port and support to change the port 2022-09-06 00:45:01 +08:00
GyDi
9e7c7ac163
feat: log info 2022-09-05 20:30:39 +08:00
GyDi
fcee41f00d
feat: kill clash by pid 2022-09-05 16:30:29 +08:00
GyDi
ff2c1bf8ed
feat: change clash port in dialog 2022-09-05 02:12:25 +08:00
GyDi
a2cf26e7ed
feat: add proxy item check loading 2022-09-04 23:53:48 +08:00
GyDi
71e6900375
feat: compatible with proxy providers health check 2022-09-04 22:55:54 +08:00
GyDi
3bdc98bd12 v1.0.6 2022-09-03 00:40:50 +08:00
GyDi
68d2a6e951
chore: update log 2022-09-03 00:39:39 +08:00
GyDi
acf47ac947
chore: update deps 2022-09-02 23:06:00 +08:00
GyDi
fda24e5f5a
chore: update deps 2022-09-02 01:35:06 +08:00
GyDi
05eca8e4d8
chore: use ubuntu 18.04 2022-09-02 01:27:06 +08:00
GyDi
b915f3b1a9
feat: add empty ui 2022-09-02 01:09:38 +08:00
GyDi
ab58968f4d
feat: complete i18n 2022-09-02 01:05:45 +08:00
GyDi
820d1e7570
fix: increase delay checker concurrency 2022-09-02 00:41:43 +08:00
GyDi
a120c8cf98
fix: external controller allow lan 2022-09-02 00:24:19 +08:00
GyDi
5a35ea116f
chore: update clash meta version 2022-09-02 00:11:52 +08:00
GyDi
e72ad1f030
fix: remove useless optimizations 2022-08-31 21:44:23 +08:00
GyDi
a17362437a
chore: test ci 2022-08-29 17:26:09 +08:00
GyDi
8643dc43b1
chore: update clash 2022-08-29 11:11:55 +08:00
GyDi
e1c869a358
chore: add test ci os version 2022-08-29 11:02:14 +08:00
GyDi
2f5b8d9abe Merge branch 'main' of github.com:zzzgydi/clash-verge 2022-08-24 22:41:36 +08:00
GyDi
db324f54eb
chore: update auto launch 2022-08-24 22:41:12 +08:00
GyDi
3242efb1a2
fix: reduce unsafe unwrap 2022-08-23 15:19:04 +08:00
FoundTheWOUT
30f9f1a021 fix: timer restore at app launch 2022-08-23 10:35:36 +08:00
GyDi
3f58d05aa7
fix: adjust log text 2022-08-19 17:11:59 +08:00
GyDi
c611a51575
fix: only script profile can display console 2022-08-17 01:45:37 +08:00
GyDi
73458dcd28 v1.0.5 2022-08-16 23:56:29 +08:00
GyDi
23ebeb1cc0
chore: update log 2022-08-16 23:56:04 +08:00
GyDi
a7ba9f1886
fix: fill button title attr 2022-08-16 23:46:33 +08:00
GyDi
d5192e2244
feat: windows portable version do not check update 2022-08-16 01:53:40 +08:00
GyDi
7eb595170f
fix: do not reset system proxy when consistent 2022-08-16 01:27:32 +08:00
GyDi
bd576ca808
fix: adjust web ui item style 2022-08-16 01:08:54 +08:00
GyDi
2f8146b11f
fix: clash field state error 2022-08-16 00:48:06 +08:00
GyDi
7f321c89cb
feat: adjust clash info parsing logs 2022-08-15 20:21:43 +08:00
GyDi
fa65f606b8
fix: badge color error 2022-08-15 20:15:44 +08:00
GyDi
7a3285adaf
fix: web ui port value error 2022-08-15 20:14:33 +08:00
GyDi
8bf78fef10
fix: delay show window 2022-08-15 01:37:26 +08:00
GyDi
78f97ce4df
feat: adjust runtime config 2022-08-15 01:30:37 +08:00
GyDi
66ccbf70f8
feat: support restart app on tray 2022-08-15 01:22:39 +08:00
GyDi
cb48600b40
fix: adjust dialog action button variant 2022-08-15 00:55:35 +08:00
GyDi
33ce235713
feat: optimize profile page 2022-08-14 23:10:19 +08:00
GyDi
f1a68ece01
fix: script code error 2022-08-12 23:41:25 +08:00
GyDi
dd563360af
fix: script exception handle 2022-08-12 11:14:34 +08:00
GyDi
7f6dac4271
feat: refactor 2022-08-12 03:20:55 +08:00
GyDi
178fd8e828
feat: adjust tun mode config 2022-08-11 03:26:08 +08:00
GyDi
1641e02a7d
feat: reimplement enhanced mode 2022-08-11 02:55:10 +08:00
GyDi
cfd04e9bb4
feat: use rquickjs crate 2022-08-10 13:05:48 +08:00
GyDi
38effaf740
feat: reimplement enhanced mode 2022-08-09 21:15:55 +08:00
GyDi
a68eb4a73e
chore: format 2022-08-09 14:33:47 +08:00
GyDi
c02990ef98
fix: change fields 2022-08-09 14:31:59 +08:00
FoundTheWOUT
5aa7d5ffe9
fix: silent start (#150) 2022-08-09 14:14:06 +08:00
GyDi
4942b0fca5
fix: save profile when update 2022-08-08 23:17:22 +08:00
GyDi
aed1bdff5a
fix: list compare wrong 2022-08-08 23:16:28 +08:00
GyDi
929c840006
fix: button color 2022-08-08 23:15:05 +08:00
GyDi
57aef1d3c2
chore: rm code 2022-08-08 22:30:13 +08:00
GyDi
c1734a094c
fix: limit theme mode value 2022-08-08 22:28:44 +08:00
GyDi
99c46685ac
feat: finish clash field control 2022-08-08 22:14:03 +08:00
GyDi
066b08040a
feat: clash field viewer wip 2022-08-08 01:51:30 +08:00
GyDi
35de2334fb fix: add valid clash field 2022-08-07 20:52:50 +08:00
GyDi
5564c966a5
feat: support web ui 2022-08-06 21:56:54 +08:00
GyDi
0891b5e7b7
feat: adjust setting page style 2022-08-06 03:48:03 +08:00
GyDi
f3341f201f
refactor: ts path alias 2022-08-06 02:35:11 +08:00
GyDi
bf0dafabe2
fix: icon style 2022-08-06 01:44:33 +08:00
GyDi
60f6587169
fix: reduce unwrap 2022-07-30 23:32:52 +08:00
GyDi
a9bf32919e
feat: runtime config viewer 2022-07-25 01:20:13 +08:00
GyDi
7633f9f88b
chore: fix updater script 2022-07-18 12:55:59 +08:00
GyDi
9b56233938
v1.0.4 2022-07-17 17:56:07 +08:00
GyDi
65074264b8
chore: update log 2022-07-17 17:52:41 +08:00
GyDi
4f6fceb87f
feat: improve log rule 2022-07-17 17:39:44 +08:00
GyDi
659fdd1d37
fix: import mod 2022-07-17 16:51:54 +08:00
GyDi
8bce2ce040
feat: theme mode support follows system 2022-07-17 16:02:17 +08:00
GyDi
55cc83a5d4
chore: update deps 2022-07-17 14:54:09 +08:00
GyDi
6a51e93ded
refactor: mode manage on tray 2022-07-13 02:26:54 +08:00
GyDi
fcf570e96e
chore: rm code 2022-07-13 01:07:29 +08:00
GyDi
cbc184e953
fix: add tray separator 2022-07-13 01:05:53 +08:00
GyDi
98f9063352
Merge pull request #128 from Limsanity/main
feat: support switch proxy mode
2022-07-13 01:02:14 +08:00
limsanity
c278f1af00 style: resolve formatting problem 2022-07-13 00:54:47 +08:00
limsanity
fbb17a0ba5 feat(system tray): support switch rule/global/direct/script mode in system tray 2022-07-13 00:43:27 +08:00
GyDi
8637a9823e
chore: update deps 2022-07-11 00:41:21 +08:00
GyDi
d717fe7e8c
chore: update clash version 2022-07-08 01:42:14 +08:00
GyDi
5e8dfe7267
chore: update aarch rule 2022-07-07 02:54:20 +08:00
GyDi
aaa4fbcdbd
chore: aarch upload script 2022-07-07 02:53:53 +08:00
GyDi
150f0cf486
fix: instantiate core after init app, close #122 2022-07-06 15:14:33 +08:00
GyDi
711b220a05
chore: update clash version 2022-07-06 00:54:01 +08:00
GyDi
b615c485f7
chore: update deps 2022-07-06 00:49:09 +08:00
GyDi
2f3b6b29ae
fix: rm macOS transition props 2022-07-05 01:24:23 +08:00
GyDi
7aecd83c4a
chore: update deps 2022-07-05 00:52:22 +08:00
GyDi
3b460ab91f
chore: change tray icon 2022-06-22 01:26:25 +08:00
GyDi
661c0eb970 v1.0.3 2022-06-20 02:09:12 +08:00
GyDi
f4a1f1fdc8
chore: update log 2022-06-20 02:06:46 +08:00
GyDi
b5432c3728
chore: update clash version 2022-06-20 01:47:15 +08:00
GyDi
6d0625c409
fix: improve external-controller parse and log 2022-06-20 01:36:56 +08:00
GyDi
2f1ea08b8a
chore: update macos icon 2022-06-18 18:41:53 +08:00
GyDi
a092da1943
fix: show windows on click 2022-06-18 17:28:37 +08:00
GyDi
43ef3cc562
chore: new logo for mac 2022-06-18 17:28:05 +08:00
GyDi
047774475c
chore: update alpha ci 2022-06-17 01:18:19 +08:00
GyDi
91b8504df5
chore: update tauri 2022-06-17 01:16:46 +08:00
GyDi
a4fb2dfcf8
fix: adjust update profile notice error 2022-06-15 02:42:04 +08:00
GyDi
ba16ec02e5
fix: style issue on mac 2022-06-15 02:41:37 +08:00
GyDi
55b7af2623
chore: update version 2022-06-15 01:15:05 +08:00
GyDi
b428eff10e
feat: improve yaml file error log 2022-06-14 01:40:02 +08:00
GyDi
35aee15b6d
chore: update deps 2022-06-14 01:23:58 +08:00
GyDi
6f53c1bfde
Merge pull request #104 from FoundTheWOUT/main
fix: check script run on all OS
2022-06-12 22:25:05 +08:00
FoundTheWOUT
db0230ed75 fix: check script run on all OS 2022-06-05 23:55:41 +08:00
GyDi
7fa3c1e12a
feat: save proxy page state 2022-06-04 18:55:39 +08:00
GyDi
3b5993652f
chore: portable script 2022-06-02 00:56:05 +08:00
GyDi
be4ad8947f
chore: updater script 2022-06-01 10:06:08 +08:00
GyDi
2ead15e78e v1.0.2 2022-06-01 01:26:05 +08:00
GyDi
aa0740ff94
chore: update log 2022-06-01 01:25:39 +08:00
GyDi
6d3f837820
fix: macOS disable transparent 2022-06-01 01:04:46 +08:00
GyDi
359b82c29c
chore: rm some files 2022-06-01 00:49:52 +08:00
GyDi
b54171bc2c
chore: rust cache 2022-06-01 00:47:04 +08:00
GyDi
936b2131e0
chore: adjust ci and script 2022-06-01 00:43:57 +08:00
GyDi
aaef6a9e9c chore: enable meta by default 2022-06-01 00:31:12 +08:00
GyDi
9327006e61
chore: rm file 2022-05-30 00:58:48 +08:00
GyDi
5225c841ae
chore: adjust code 2022-05-30 00:57:31 +08:00
GyDi
8464e319fd
chore: update deps 2022-05-29 23:35:22 +08:00
GyDi
98b8bd90ea
fix: window transparent and can not get hwnd 2022-05-25 19:06:06 +08:00
GyDi
ae94993b09
fix: create main window 2022-05-25 16:45:18 +08:00
GyDi
72f10aaed1
chore: update deps 2022-05-25 16:12:48 +08:00
GyDi
4a74bae8c7
chore: update clash core 2022-05-25 16:08:58 +08:00
ctaoist
5164aec37b
feat: light mode wip (#96)
* 关闭窗口释放UI资源

* windows 还有左键点击事件

* 兼容enhance profile

* bug 修复
2022-05-25 16:06:39 +08:00
GyDi
1581e9b1cd
chore: update clash version 2022-05-18 14:14:37 +08:00
GyDi
536e3ffb11
chore: alpha ci 2022-05-18 14:07:41 +08:00
GyDi
d6103191ba
chore: error text 2022-05-18 09:58:20 +08:00
GyDi
49e37a19a5
chore: ci 2022-05-17 12:35:42 +08:00
GyDi
d02431e260
chore: fix alpha ci 2022-05-17 12:34:30 +08:00
GyDi
f24f6ead92
chore: alpha ci 2022-05-17 11:41:45 +08:00
GyDi
b7bdb7ae50
chore: meta 2022-05-17 02:46:15 +08:00
GyDi
2dcf8ac96f
chore: fix ci 2022-05-17 02:21:58 +08:00
GyDi
5421c94853
chore: test ci 2022-05-17 02:17:02 +08:00
GyDi
10f6bc092a
chore: alpha 2022-05-17 02:11:29 +08:00
GyDi
be9ea4ea8e
feat: clash meta core supports 2022-05-17 01:59:49 +08:00
GyDi
f5c6fa842a
fix: adjust notice 2022-05-17 00:51:37 +08:00
GyDi
e0943ce905
fix: label text 2022-05-16 20:26:13 +08:00
GyDi
61e7df77a7
feat: script mode 2022-05-16 20:18:56 +08:00
GyDi
a5434360bc
chore: test ci 2022-05-16 17:55:14 +08:00
GyDi
ba29c66e3b
chore: update deps 2022-05-16 17:54:21 +08:00
GyDi
b3a72d55ae
feat: clash meta core support (wip) 2022-05-16 01:52:50 +08:00
GyDi
c382ad1cc8
fix: icon path 2022-05-13 12:28:36 +08:00
GyDi
363e28f323
fix: icon issue 2022-05-13 02:46:06 +08:00
GyDi
d695656b8c
fix: notice ui blocking 2022-05-13 02:29:43 +08:00
GyDi
31c6cbc0a2
fix: service mode error 2022-05-13 02:11:03 +08:00
GyDi
b93284bc2f
chore: fix linux build ci 2022-05-11 12:39:41 +08:00
GyDi
99c855b01b
chore: test ci 2022-05-11 12:20:20 +08:00
GyDi
c2eaedc959
chore: test ci 2022-05-11 12:12:55 +08:00
GyDi
a631cd67ec
chore: test ci fix deps 2022-05-11 11:30:19 +08:00
GyDi
66fccd3c68
chore: test ci 2022-05-11 11:22:09 +08:00
GyDi
9a4ebf4daa
chore: test ci 2022-05-11 10:51:28 +08:00
GyDi
91c14211c6
chore: continue on error 2022-05-11 01:26:11 +08:00
GyDi
1ea07c458b
chore: test linux 2022-05-11 00:52:20 +08:00
GyDi
591add6e0c
chore: test ci 2022-05-11 00:31:19 +08:00
GyDi
b99fff66df v1.0.1 2022-05-10 21:40:33 +08:00
GyDi
f54ba05b00
chore: update log 2022-05-10 21:40:07 +08:00
GyDi
6596fb00c7
fix: win11 drag lag 2022-05-09 14:41:26 +08:00
GyDi
df0b5a80dc
chore: change default height 2022-05-09 14:01:46 +08:00
GyDi
8cdbb31dbe
fix: rm unwrap 2022-05-09 14:01:14 +08:00
GyDi
0be4b1222d
feat: reduce gpu usage when hidden 2022-05-07 14:43:52 +08:00
GyDi
18a6bfd73a
feat: interval update from now field 2022-05-07 14:43:08 +08:00
GyDi
5e2271b237
feat: adjust theme 2022-05-06 14:04:39 +08:00
GyDi
798999d490
fix: edit profile info 2022-05-06 12:46:27 +08:00
GyDi
0e68c5e8bc
feat: supports more remote headers close #81 2022-05-06 10:52:59 +08:00
GyDi
9694af82f4
feat: check the remote profile 2022-05-06 01:26:24 +08:00
GyDi
28a4386975
fix: change window default size 2022-05-06 01:15:15 +08:00
GyDi
a238f7beba
chore: update deps 2022-05-06 01:14:13 +08:00
GyDi
75ba16281b
chore: change default user agent 2022-05-06 00:42:20 +08:00
GyDi
ad65a278d4
chore: merge
feat: remove outdated config
2022-04-28 16:28:18 +08:00
tianyoulan
a2320b3f8d feat: fix typo 2022-04-28 15:35:17 +08:00
tianyoulan
ae12853ad0 feat: remove trailing comma 2022-04-28 15:05:10 +08:00
tianyoulan
68adf6dc2f feat: remove outdated config 2022-04-28 15:02:37 +08:00
GyDi
f88989bd4b
fix: change service installer and uninstaller 2022-04-27 15:46:44 +08:00
GyDi
77ef3847ce v1.0.0 2022-04-26 00:50:48 +08:00
GyDi
b8291837fc
chore: update log 2022-04-26 00:49:07 +08:00
GyDi
423a7f951a
fix: adjust connection scroll 2022-04-26 00:37:28 +08:00
GyDi
557f5fe364
fix: adjust something 2022-04-25 20:00:11 +08:00
GyDi
5308970ad8
fix: adjust debounce wait time 2022-04-25 19:39:21 +08:00
GyDi
6b368953f4
feat: windows service mode ui 2022-04-25 16:12:04 +08:00
GyDi
2d0b63c29d
feat: add some commands 2022-04-24 21:03:47 +08:00
GyDi
34e941c8cb
feat: windows service mode 2022-04-24 21:00:17 +08:00
GyDi
76cf007fff
chore: update check script 2022-04-24 15:35:30 +08:00
GyDi
321963be83
wip: windows service mode 2022-04-23 17:26:32 +08:00
GyDi
c733bda6c3
test: windows service 2022-04-21 21:28:44 +08:00
GyDi
e67b50b976
chore: adjust guard log 2022-04-21 19:51:20 +08:00
GyDi
9e3c080909
fix: adjust dns config 2022-04-21 19:50:22 +08:00
GyDi
cb661aaebd
feat: add update interval 2022-04-21 14:26:41 +08:00
GyDi
573571978c
chore: adjust 2022-04-21 14:24:35 +08:00
GyDi
dc492a2a0a
chore: update clash version 2022-04-20 21:02:41 +08:00
GyDi
e47747dd0e
feat: refactor and supports cron tasks 2022-04-20 20:39:27 +08:00
GyDi
4de944b41e
feat: supports cron update profiles 2022-04-20 20:37:16 +08:00
GyDi
5f7a1fa5cd
refactor: verge 2022-04-20 11:17:54 +08:00
GyDi
b8ad328cde
refactor: wip 2022-04-20 01:44:47 +08:00
GyDi
3076fd19c1
refactor: mutex 2022-04-19 14:38:59 +08:00
GyDi
fac437b8c1
fix: traffic graph adapt to different fps 2022-04-19 13:55:26 +08:00
GyDi
697c25015e
refactor: wip 2022-04-19 01:41:20 +08:00
GyDi
d83b404fc3
chore: check script proxy agent supports 2022-04-17 00:37:21 +08:00
GyDi
ab7313cbc4
feat: optimize traffic graph quadratic curve 2022-04-16 22:32:44 +08:00
GyDi
1b8d70322b
feat: optimize the animation of the traffic graph 2022-04-16 17:28:30 +08:00
GyDi
844ffab4ed
fix: optimize clash launch 2022-04-15 01:29:25 +08:00
GyDi
f5d0513d1f
fix: reset after exit 2022-04-14 01:29:33 +08:00
GyDi
557abd4285
fix: adjust code 2022-04-14 01:29:02 +08:00
GyDi
f4f1a0fbc6 v0.0.29 2022-04-13 01:30:08 +08:00
GyDi
74e10dc012
chore: update log 2022-04-13 01:29:48 +08:00
GyDi
359812b7ed
chore: update dep 2022-04-13 01:21:49 +08:00
GyDi
c2449e53c4
chore: rename green to portable 2022-04-13 01:17:40 +08:00
GyDi
1a91249da2
feat: system tray add tun mode 2022-04-13 01:09:51 +08:00
GyDi
b9162f9576
fix: adjust log 2022-04-13 00:49:30 +08:00
GyDi
f726e8a7b3
feat: supports change config dir 2022-04-12 23:09:32 +08:00
GyDi
2f284cfdc9
chore: update clash version 2022-04-12 23:04:19 +08:00
GyDi
b74696adba
feat: add default user agent 2022-04-12 01:05:51 +08:00
GyDi
c8ccba0192
chore: rm console 2022-04-11 02:26:09 +08:00
GyDi
41b0e05f62
feat: connections page supports filter 2022-04-11 02:25:34 +08:00
GyDi
847d5f1b3b
feat: log page supports filter 2022-04-11 01:46:33 +08:00
GyDi
0445f9dfc2
fix: check button hover style 2022-04-10 03:33:17 +08:00
GyDi
3001c780bd
feat: optimize delay checker concurrency strategy 2022-04-10 02:58:48 +08:00
GyDi
68ad5e2320
feat: support sort proxy node and custom test url 2022-04-10 02:09:36 +08:00
GyDi
b5e229b19c
chore: update deps 2022-04-10 01:31:05 +08:00
GyDi
453d798fcf
refactor: proxy head 2022-04-08 01:35:18 +08:00
GyDi
451afdb660 v0.0.28 2022-04-07 01:28:30 +08:00
GyDi
d298bda92c
chore: update log 2022-04-07 01:27:48 +08:00
GyDi
fd99ba6255
feat: handle remote clash config fields 2022-04-07 01:20:44 +08:00
GyDi
6ade0b2b1a
fix: icon button color inherit 2022-04-06 22:52:00 +08:00
GyDi
9902003da9
fix: remove the lonely zero 2022-04-06 22:48:10 +08:00
GyDi
0ff2fcac11
chore: readme 2022-04-06 01:52:20 +08:00
GyDi
e80be8e7b6 v0.0.27 2022-04-06 01:21:33 +08:00
GyDi
fe0ad0f5cb
chore: update log 2022-04-06 01:19:13 +08:00
GyDi
cb8e162f4e
refactor: update profile menu 2022-04-06 01:13:06 +08:00
GyDi
ae8c30fe57
chore: add updater script 2022-04-05 23:24:52 +08:00
GyDi
ab82db9e22
chore: updater json supports arch field 2022-04-05 23:19:54 +08:00
GyDi
cb9d3098de
chore: add ci 2022-04-05 20:21:53 +08:00
GyDi
c927419c99
refactor: enhanced mode ui component 2022-04-03 01:41:48 +08:00
GyDi
c009026961
feat: add text color 2022-04-02 17:18:38 +08:00
GyDi
51cf442fa5
fix: i18n add value 2022-04-02 13:49:48 +08:00
GyDi
954e3553ee
fix: proxy page first render 2022-04-02 01:23:31 +08:00
GyDi
cde17385b4
feat: control final tun config 2022-04-01 23:55:44 +08:00
GyDi
5b9e078061
chore: add debug feature 2022-04-01 23:43:35 +08:00
GyDi
0290d9ddfc
feat: support css injection 2022-04-01 02:08:42 +08:00
GyDi
eab671d102
fix: console warning 2022-04-01 01:16:23 +08:00
GyDi
f9a96ff914
feat: support theme setting 2022-03-31 23:38:00 +08:00
GyDi
3ec2b46d28
feat: add text color 2022-03-31 23:34:36 +08:00
GyDi
aec30b89e0
feat: add theme setting 2022-03-31 23:11:50 +08:00
GyDi
309c33e190
refactor: ui theme 2022-03-30 12:36:39 +08:00
GyDi
9c0276f97b
chore: add api 2022-03-30 01:30:22 +08:00
GyDi
0a3402ff43
fix: icon button title 2022-03-30 01:29:25 +08:00
GyDi
bd82308024
chore: update tauri 2022-03-29 23:05:32 +08:00
GyDi
db3b634e62
fix: macOS transition flickers close #47 2022-03-29 01:39:54 +08:00
GyDi
40bcb22977
chore: update deps 2022-03-29 01:33:14 +08:00
GyDi
4bd94092f1
fix: csp image data 2022-03-28 23:17:11 +08:00
GyDi
cac1ce6895
chore: readme 2022-03-28 01:33:58 +08:00
GyDi
5c3696123a v0.0.26 2022-03-28 01:30:54 +08:00
GyDi
4140fc86ee
chore: update log 2022-03-28 01:18:18 +08:00
GyDi
2ad771e7fd
fix: close dialog after save 2022-03-28 01:09:34 +08:00
GyDi
5a38468144
refactor: optimize enhance mode strategy 2022-03-28 01:07:14 +08:00
GyDi
0a9c81772f
fix: change to deep copy 2022-03-28 00:56:48 +08:00
GyDi
c9649ac501
feat: enhanced mode supports more fields 2022-03-27 20:36:13 +08:00
GyDi
6ea567742b
chore: profile release 2022-03-27 01:38:40 +08:00
GyDi
f31349eaa0
feat: supports edit profile file 2022-03-27 00:58:17 +08:00
GyDi
9d44668d5f
feat: supports silent start 2022-03-26 18:56:16 +08:00
GyDi
a12f58c1c7
feat: use crate open 2022-03-23 23:00:14 +08:00
GyDi
b5283eaaed
fix: window style close #45 2022-03-23 21:43:13 +08:00
GyDi
4b6189af5f
feat: enhance connections display order 2022-03-23 14:02:08 +08:00
GyDi
5d0ffbe453
chore: adjust style 2022-03-23 13:58:57 +08:00
GyDi
502706931e
fix: manage global proxy correctly 2022-03-23 12:49:34 +08:00
GyDi
57c411288f
fix: tauri csp 2022-03-23 01:47:35 +08:00
GyDi
b09b7b11a1
feat: save global selected 2022-03-22 12:38:59 +08:00
GyDi
1a7b3c7294 v0.0.25 2022-03-22 01:51:06 +08:00
GyDi
4678fc7dde
chore: update log 2022-03-22 01:50:24 +08:00
GyDi
9f492fad49
chore: update clash core 2022-03-22 01:50:15 +08:00
GyDi
bd0a959e18
fix: windows style 2022-03-22 01:36:06 +08:00
GyDi
dd605e2610
fix: update state 2022-03-22 01:27:22 +08:00
inRm3D
9910f6b817
chore: readme (#43) 2022-03-21 21:55:45 +08:00
GyDi
991897aff4
chore: tauri feature 2022-03-21 11:40:52 +08:00
GyDi
3cde019208
fix: profile item loading state 2022-03-21 11:40:27 +08:00
GyDi
2f6efbed63
chore: tauri allowList 2022-03-20 13:16:50 +08:00
GyDi
5cff4e299b
chore: update clash version 2022-03-20 12:37:55 +08:00
GyDi
bce33639da v0.0.24 2022-03-20 01:50:39 +08:00
GyDi
366c465cad
chore: update log 2022-03-20 01:50:15 +08:00
GyDi
acc6e05bdc
feat: system tray supports system proxy setting 2022-03-20 01:36:43 +08:00
GyDi
4ce15577cd
feat: prevent context menu on Windows close #22 2022-03-19 19:28:53 +08:00
GyDi
98fa4d5e65
feat: create local profile with selected file 2022-03-19 19:21:55 +08:00
GyDi
7fe94076c7
feat: reduce the impact of the enhanced mode 2022-03-19 16:02:47 +08:00
GyDi
b8b0c8fa63
fix: adjust windows style 2022-03-19 15:35:59 +08:00
GyDi
e585e87bec
feat: parse update log 2022-03-19 15:31:58 +08:00
GyDi
6a4924bb16
chore: update log supports 2022-03-19 14:04:58 +08:00
GyDi
ab0d516d91
chore: updater proxy 2022-03-19 11:14:12 +08:00
GyDi
b756ae39d0
chore: ci support linux 2022-03-19 10:50:44 +08:00
GyDi
c15c38ea8f
chore: readme 2022-03-18 19:02:53 +08:00
GyDi
743963318f
feat: fill i18n 2022-03-18 14:59:23 +08:00
GyDi
ed3fc50858
feat: dayjs i18n 2022-03-18 14:45:24 +08:00
GyDi
5b886fe6be
feat: connections page simply support 2022-03-18 14:43:22 +08:00
GyDi
7074bbc405
feat: add wintun.dll by default 2022-03-18 11:49:00 +08:00
GyDi
ef314c1707
fix: change mixed port error 2022-03-18 11:39:02 +08:00
GyDi
a3e7626dd9
chore: add dev feature 2022-03-18 10:59:35 +08:00
GyDi
5cb5d74eed
chore: rename temp dir 2022-03-18 10:20:24 +08:00
GyDi
6eee10d46d
chore: resolve wintun.dll 2022-03-17 19:29:30 +08:00
GyDi
2d95f2b0d6
fix: auto launch path 2022-03-16 18:44:25 +08:00
GyDi
ec41bb9c70
fix: tun mode config 2022-03-15 14:23:57 +08:00
GyDi
2d1780b1cf
fix: adjsut open cmd error 2022-03-15 12:51:39 +08:00
GyDi
d9ce99887c
chore: fix ci env 2022-03-15 00:00:20 +08:00
GyDi
9b9cc90414 v0.0.23 2022-03-14 01:34:26 +08:00
GyDi
c1eb539a5c
feat: event emit when clash config update 2022-03-13 01:37:41 +08:00
GyDi
e1793f57ef
chore: fix ci 2022-03-13 00:59:42 +08:00
GyDi
dbd09a8743
chore: update tauri action 2022-03-13 00:58:49 +08:00
GyDi
0d189ca617
chore: green version bundle 2022-03-13 00:52:31 +08:00
GyDi
dc9bcc40ee
chore: rm then 2022-03-12 23:58:20 +08:00
GyDi
4991f7ff39
feat: i18n supports 2022-03-12 23:07:45 +08:00
GyDi
a393b8b122
fix: parse external-controller 2022-03-12 21:35:20 +08:00
GyDi
c73b354386
fix: config file case close #18 2022-03-12 21:03:17 +08:00
GyDi
392ecee3ff
chore: merge 2022-03-12 18:45:07 +08:00
ttyS3
bae721c49e
chore: show open app and log dir failed message 2022-03-12 18:04:56 +08:00
GyDi
4e806e21a6
chore: adjust error log 2022-03-12 15:57:16 +08:00
GyDi
ec0fdf83b2
feat: change open command on linux
refactor(logging): refine open dir failed log message, add Linux support
2022-03-12 15:40:23 +08:00
ttyS3
cb94d8414f
feat: add Linux open dir support
refactor(logging): refine open dir failed log message
2022-03-12 03:18:25 +08:00
GyDi
8890051c17
fix: patch item option 2022-03-11 19:56:56 +08:00
GyDi
cf00c9476f
fix: user agent not works 2022-03-11 19:50:51 +08:00
GyDi
b2a24c7abd v0.0.22 2022-03-10 02:27:00 +08:00
GyDi
732a1f4694
chore: rm dead code 2022-03-10 02:25:35 +08:00
GyDi
4c5aa7084e
fix: external-controller 2022-03-10 02:19:06 +08:00
GyDi
fe1fea671c
feat: support more options for remote profile 2022-03-10 02:03:55 +08:00
GyDi
04c754c0ac
chore: reduce icon size on macOS 2022-03-10 01:04:53 +08:00
GyDi
754c22c84e
chore: adjust icon 2022-03-10 00:04:59 +08:00
GyDi
629331870b
chore: add linux link 2022-03-09 20:14:15 +08:00
GyDi
78774315cb
feat: linux system proxy 2022-03-09 19:48:32 +08:00
GyDi
36b9c07928
chore: update deps 2022-03-09 02:36:40 +08:00
GyDi
40a818630d
fix: change proxy bypass on mac 2022-03-09 02:36:03 +08:00
GyDi
568511a4cf
fix: kill sidecars after install still in test 2022-03-09 02:09:51 +08:00
GyDi
109fb39e09
fix: log some error 2022-03-09 02:00:56 +08:00
GyDi
68450d2042
chore: rename productName 2022-03-09 01:53:34 +08:00
GyDi
8a052bbed6
chore: update tauri version 2022-03-09 01:50:37 +08:00
GyDi
3afbb56640
fix: apply_blur parameter 2022-03-08 10:44:41 +08:00
GyDi
c0ad84a491
fix: limit enhanced profile range 2022-03-08 01:45:46 +08:00
GyDi
c72f17605c
chore: update deps 2022-03-08 01:18:20 +08:00
GyDi
42fbee0cdb
chore: add default bypass 2022-03-08 00:39:09 +08:00
GyDi
e9b7ec735f
fix: profile updated field 2022-03-07 01:41:42 +08:00
GyDi
743788135f
fix: profile field check 2022-03-07 01:30:32 +08:00
GyDi
8ea3e6fa26
fix: create dir panic 2022-03-07 01:06:21 +08:00
GyDi
f23c83e681 v0.0.21 2022-03-06 18:36:02 +08:00
GyDi
b615bda17e
chore: default release body 2022-03-06 18:34:38 +08:00
GyDi
f7c7cd1d3c chore: update deps 2022-03-06 18:04:44 +08:00
GyDi
c7e7be4379
fix: only error when selected 2022-03-06 17:06:45 +08:00
GyDi
d63d49f246
feat: enhance profile status 2022-03-06 17:02:29 +08:00
GyDi
dad94edb20
feat: menu item refresh enhanced mode 2022-03-06 15:46:16 +08:00
GyDi
7108d5f3ab
fix: enhanced profile consistency 2022-03-06 15:40:16 +08:00
GyDi
ef47a74920
feat: profile enhanced mode 2022-03-06 14:59:25 +08:00
GyDi
a43dab8057
feat: profile enhanced ui 2022-03-05 22:54:39 +08:00
GyDi
f44039b628
feat: profile item adjust 2022-03-05 19:04:20 +08:00
GyDi
08fa5205b0
fix: simply compatible with proxy providers 2022-03-05 16:18:44 +08:00
GyDi
b91daebd92
fix: component warning 2022-03-05 15:48:39 +08:00
GyDi
9cd6c5c624
chore: update copyright 2022-03-05 01:51:29 +08:00
GyDi
650e017b72
fix: when updater failed 2022-03-04 02:10:27 +08:00
GyDi
18f9d6dec5 fix: log file 2022-03-04 02:08:26 +08:00
GyDi
4df6571ad9
chore: update deps 2022-03-03 20:37:06 +08:00
GyDi
0f5923a10a
chore: enhance wip 2022-03-03 01:58:05 +08:00
GyDi
bcdae1169e
fix: result 2022-03-03 01:56:47 +08:00
GyDi
f260d5df49
feat: enhanced profile (wip) 2022-03-03 01:52:02 +08:00
GyDi
808b861dd1 v0.0.20 2022-03-02 01:59:53 +08:00
GyDi
17f1c487a8
feat: edit profile item 2022-03-02 01:58:16 +08:00
GyDi
8dc2c1a38f
fix: cover profile extra 2022-03-02 01:45:00 +08:00
GyDi
220a494692
chore: adjust log field 2022-03-02 01:13:31 +08:00
GyDi
db6bc10196
chore: rm file 2022-03-02 00:58:07 +08:00
GyDi
1880363aeb
feat: use nanoid 2022-03-02 00:56:05 +08:00
GyDi
19c7b59883
feat: compatible profile config 2022-03-01 11:05:33 +08:00
GyDi
749df89229
refactor: profile config 2022-03-01 08:58:47 +08:00
GyDi
444f2172fa v0.0.19 2022-02-28 01:59:53 +08:00
GyDi
77a77c0ea7
wip: refactor profile 2022-02-28 01:59:13 +08:00
GyDi
dbf380a0d1
refactor: use anyhow to handle error 2022-02-28 01:34:25 +08:00
GyDi
ade34f5217
fix: display menu only on macos 2022-02-27 01:47:56 +08:00
GyDi
e89607799a
fix: proxy global showType 2022-02-27 01:33:22 +08:00
GyDi
d05d8d6a9e
feat: native menu supports 2022-02-27 01:29:57 +08:00
GyDi
b6aa50d3dc
chore: update deps 2022-02-27 01:16:43 +08:00
GyDi
9df361935f
feat: filter proxy and display type 2022-02-27 00:58:14 +08:00
GyDi
98b8a122b6
feat: use lock fn 2022-02-26 17:39:36 +08:00
GyDi
c7232522ee
feat: refactor proxy page 2022-02-26 17:39:08 +08:00
GyDi
5280f1d745
feat: proxy group auto scroll to current 2022-02-26 01:21:39 +08:00
GyDi
b52a081e7b v0.0.18 2022-02-25 02:13:41 +08:00
GyDi
f981a44861
chore: ci 2022-02-25 02:12:55 +08:00
GyDi
d7c5ce0750
feat: clash tun mode supports 2022-02-25 02:09:39 +08:00
GyDi
9ccc66ca1e
feat: use enhanced guard-state 2022-02-25 01:22:33 +08:00
GyDi
8606af3616
feat: guard state supports debounce guard 2022-02-25 01:21:13 +08:00
GyDi
f6e821ba6b
feat: adjust clash version display 2022-02-24 23:04:18 +08:00
GyDi
e8dbcf819b
feat: hide command window 2022-02-24 22:46:12 +08:00
GyDi
bbe2ef4e8e
fix: use full clash config 2022-02-23 23:23:07 +08:00
GyDi
dd15455031
feat: enhance log data 2022-02-23 02:00:45 +08:00
GyDi
12ac7bb338
chore: update readme 2022-02-22 21:54:33 +08:00
GyDi
46ef348f0d v0.0.17 2022-02-22 02:08:31 +08:00
GyDi
1a55cca8af
fix: reconnect websocket when restart clash 2022-02-22 02:05:22 +08:00
GyDi
81ee989f1f
chore: enhance publish ci 2022-02-22 01:56:06 +08:00
GyDi
c9c06f8a3d
fix: wrong exe path 2022-02-21 22:33:37 +08:00
GyDi
72127979c3
chore: use tauri cli 2022-02-21 22:31:00 +08:00
GyDi
1ad3ddef94 v0.0.16 2022-02-21 01:33:11 +08:00
GyDi
97ec5eabf7
feat: change window style 2022-02-20 23:46:13 +08:00
GyDi
e12e3a3f2d
feat: fill verge template 2022-02-20 20:12:55 +08:00
GyDi
4ff625f23b
feat: enable customize guard duration 2022-02-20 20:11:39 +08:00
GyDi
e38dcd85ac
feat: system proxy guard 2022-02-20 18:53:21 +08:00
GyDi
0245baf1b6
feat: enable show or hide traffic graph 2022-02-19 18:14:40 +08:00
GyDi
10b55c043c
fix: patch verge config 2022-02-19 17:32:23 +08:00
GyDi
457655b416
feat: traffic line graph 2022-02-19 17:02:24 +08:00
GyDi
7e4506c860
chore: update deps 2022-02-19 00:34:09 +08:00
GyDi
794d376348
feat: adjust profile item ui 2022-02-19 00:23:47 +08:00
GyDi
c60578f5b5
feat: adjust fetch profile url 2022-02-19 00:09:36 +08:00
GyDi
3a9a392a77
feat: inline config file template 2022-02-18 23:57:13 +08:00
GyDi
a13d4698be
chore: update check script 2022-02-18 23:49:39 +08:00
GyDi
c046a1993e
fix: fetch profile panic 2022-02-17 13:44:26 +08:00
GyDi
f709117cc4
feat: kill sidecars when update app 2022-02-17 02:10:25 +08:00
GyDi
30dd298fca
feat: delete file 2022-02-17 01:58:12 +08:00
GyDi
0ff8bb8090
feat: lock some async functions 2022-02-17 01:42:25 +08:00
GyDi
74bbd3c3a2
chore: tauri updater env 2022-02-16 11:02:00 +08:00
GyDi
2e82eaf59a
chore: add pubkey 2022-02-16 10:59:31 +08:00
GyDi
7f1df1f1bd v0.0.15 2022-02-16 03:22:25 +08:00
GyDi
3c79238a44
feat: support open dir 2022-02-16 03:21:34 +08:00
GyDi
0aa2565df3
fix: spawn command 2022-02-16 02:43:52 +08:00
GyDi
22b11db16e
feat: change allow list 2022-02-16 02:42:56 +08:00
GyDi
d0e678b5e9
feat: support check delay 2022-02-16 02:22:01 +08:00
GyDi
e7bba968b3 fix: import error 2022-02-15 01:36:19 +08:00
GyDi
4934a24293
feat: scroll to proxy item 2022-02-15 01:34:10 +08:00
GyDi
ccb68bcda9
chore: update deps 2022-02-15 00:33:58 +08:00
GyDi
66bf4ba3ad
fix: not open file when new profile 2022-02-15 00:21:34 +08:00
GyDi
78a0cfd052
feat: edit system proxy bypass 2022-02-14 01:26:24 +08:00
GyDi
8548373742
feat: disable user select 2022-02-13 19:52:35 +08:00
GyDi
2dfd725ee0
fix: reset value correctly 2022-02-13 19:40:31 +08:00
GyDi
5b779b4f14
feat: new profile able to edit name and desc 2022-02-13 19:33:24 +08:00
GyDi
fc48aa7155 chore: adjust files 2022-02-13 19:27:24 +08:00
GyDi
6193a842f4
feat: update tauri version 2022-02-13 18:45:03 +08:00
GyDi
eb86b471fe
fix: something 2022-02-12 21:12:39 +08:00
GyDi
2b52584547
fix: menu without fragment 2022-02-10 01:42:52 +08:00
GyDi
6e3cc57f48
feat: display clash core version 2022-02-10 01:35:55 +08:00
GyDi
f2c04621a5
feat: adjust profile item menu 2022-02-10 01:14:57 +08:00
GyDi
3ed6938d4a v0.0.14 2022-02-09 02:11:01 +08:00
GyDi
99fec25ed5
feat: profile item ui 2022-02-09 02:08:27 +08:00
GyDi
73758ad1fd
fix: proxy list error 2022-02-09 02:02:29 +08:00
GyDi
c53fe0ed1f
feat: support new profile 2022-02-07 17:26:05 +08:00
GyDi
6082c2bcac
feat: support open command for viewing 2022-02-07 16:45:20 +08:00
GyDi
069abed784
chore: add item template yaml 2022-02-02 20:56:06 +08:00
GyDi
7d8fa4d78a
fix: something 2022-01-31 23:34:58 +08:00
GyDi
76081f8d89
fix: macos auto launch fail 2022-01-31 23:32:41 +08:00
GyDi
5ef4285558
chore: update deps and app name 2022-01-31 23:27:11 +08:00
GyDi
aa7df4282e
chore: cargo update 2022-01-28 22:02:17 +08:00
GyDi
0ef1d5d0de
chore: update clash version 2022-01-28 22:00:15 +08:00
GyDi
cceb4bb81f v0.0.13 2022-01-25 02:11:00 +08:00
GyDi
f0f45e007d
feat: global proxies use virtual list 2022-01-25 02:08:10 +08:00
GyDi
6a8ffe1642
feat: enable change proxy mode 2022-01-25 01:51:44 +08:00
GyDi
3a73868c10
feat: update styles 2022-01-25 01:48:26 +08:00
GyDi
ab1b5897a6
feat: manage clash mode 2022-01-24 23:13:13 +08:00
GyDi
f94734a5c8 chore: update readme 2022-01-22 23:57:39 +08:00
GyDi
61b86c9584 v0.0.12 2022-01-21 03:09:21 +08:00
GyDi
1ac1d6e903
chore: update ci 2022-01-21 03:08:40 +08:00
GyDi
b6c58f74c0
fix: type error 2022-01-21 03:08:20 +08:00
GyDi
c88e99d87c v0.0.12 2022-01-21 02:59:33 +08:00
GyDi
8d7ab9d05e
refactor: rename profiles & command state 2022-01-21 02:57:15 +08:00
GyDi
47155a4a29
feat: change system porxy when changed port 2022-01-21 02:50:13 +08:00
GyDi
d0b87fd7c3
feat: enable change mixed port 2022-01-21 02:32:23 +08:00
GyDi
d49fd37656
feat: manage clash config 2022-01-21 02:31:44 +08:00
GyDi
0bd29d71be
chore: add ahooks 2022-01-21 02:29:45 +08:00
GyDi
4b5b62c8ae
fix: restart clash should update something 2022-01-21 00:29:33 +08:00
GyDi
65fb2ca2d5
feat: enable update clash info 2022-01-20 23:41:08 +08:00
GyDi
0d5bfc0997
feat: rename edit as view 2022-01-19 23:58:34 +08:00
GyDi
4f02c373c2
chore: adjust ci 2022-01-19 23:55:05 +08:00
GyDi
209a5b1207
fix: script error... 2022-01-19 00:49:23 +08:00
GyDi
95349eacab
fix: tag error 2022-01-19 00:46:43 +08:00
GyDi
82ba604b99
fix: script error 2022-01-19 00:42:37 +08:00
GyDi
46a8dec655
feat: test auto gen update.json ci 2022-01-19 00:37:59 +08:00
GyDi
b5af234524 v0.0.11 2022-01-17 02:53:07 +08:00
GyDi
b5c41750f7
fix: remove cargo test 2022-01-17 02:50:19 +08:00
GyDi
6083824eec v0.0.11 2022-01-17 02:44:08 +08:00
GyDi
40977785c3
feat: adjust setting typography 2022-01-17 02:42:52 +08:00
GyDi
5eddf4f1aa
feat: enable force select profile 2022-01-17 02:28:23 +08:00
GyDi
99a8e25411
feat: support edit profile item 2022-01-17 02:16:17 +08:00
GyDi
08587d8f2f
fix: reduce proxy item height 2022-01-17 02:15:54 +08:00
GyDi
3480d50f61
feat: adjust control ui 2022-01-17 02:15:06 +08:00
GyDi
43af55252d
feat: update profile supports noproxy 2022-01-16 22:57:42 +08:00
GyDi
9c43b31fc0
refactor: something 2022-01-16 18:30:25 +08:00
GyDi
9ec7184aa1
fix: put profile request with no proxy 2022-01-16 18:20:01 +08:00
GyDi
4e2cb30db7
refactor: notice caller 2022-01-16 17:56:43 +08:00
GyDi
9ca83d3291
chore: change ci 2022-01-16 16:03:53 +08:00
GyDi
6b2172d873
fix: ci strategy 2022-01-16 14:30:49 +08:00
GyDi
1a5d9f7dad
chore: enhance ci 2022-01-16 14:27:41 +08:00
GyDi
a8425862f0
feat: rename page 2022-01-16 03:25:50 +08:00
GyDi
a3a3db6abb
refactor: setting page 2022-01-16 03:22:37 +08:00
GyDi
d6c3bc57c0
feat: refactor and adjust ui 2022-01-16 03:11:07 +08:00
GyDi
59c09f90f9
feat: rm some commands 2022-01-16 03:09:36 +08:00
GyDi
d982b83e14
feat: change type 2022-01-15 21:58:13 +08:00
GyDi
cc0e930d34
feat: supports auto launch on macos and windows 2022-01-15 21:55:05 +08:00
GyDi
3c3d77fbea
chore: add auto-launch 2022-01-15 21:00:19 +08:00
GyDi
da7453fdbf v0.0.10 2022-01-13 02:53:29 +08:00
GyDi
5fcd25506e feat: adjust proxy page 2022-01-13 02:51:30 +08:00
GyDi
4979a472de feat: press esc hide the window 2022-01-13 02:11:50 +08:00
GyDi
4e8d4f4591 fix: version update error 2022-01-12 22:19:44 +08:00
GyDi
0f5d2b15e0 v0.0.9 2022-01-12 02:55:07 +08:00
GyDi
7fc9631434 feat: show system proxy info 2022-01-12 02:54:50 +08:00
GyDi
df5953dd7b feat: support blur window 2022-01-12 02:27:29 +08:00
GyDi
8f5b2b4a0e chore: add macos startup todo 2022-01-11 23:14:43 +08:00
GyDi
43c63ffa70 chore: cargo update 2022-01-11 23:13:02 +08:00
GyDi
6779bc7459 v0.0.8 2022-01-11 02:27:04 +08:00
GyDi
664be2d0ba chore: update ci 2022-01-11 02:26:50 +08:00
GyDi
6113898b69 feat: windows support startup 2022-01-11 02:24:43 +08:00
GyDi
79aad6b5c2 feat: window self startup 2022-01-11 02:21:51 +08:00
GyDi
6da7757d36 fix: text 2022-01-10 22:57:21 +08:00
GyDi
dbb3cb8cc8 chore: ignore update json 2022-01-10 22:08:57 +08:00
GyDi
579f36a1dd fix: update profile after restart clash 2022-01-10 22:08:18 +08:00
GyDi
72c2b306cf fix: get proxies multiple times 2022-01-10 21:25:41 +08:00
GyDi
c2673cd396 docs: fix img width 2022-01-10 02:52:12 +08:00
GyDi
8eb152816a docs: update 2022-01-10 02:49:42 +08:00
GyDi
a0bc8a21a5 v0.0.7 2022-01-10 02:17:35 +08:00
GyDi
08e4d72758 feat: use tauri updater 2022-01-10 02:15:38 +08:00
GyDi
66340a27fa feat: support update checker 2022-01-10 02:05:35 +08:00
GyDi
83fe9835b6 v0.0.6 2022-01-09 21:36:43 +08:00
GyDi
4c1a50a3ca chore: ci add macos 2022-01-09 21:34:14 +08:00
GyDi
fe44a7b3bc feat: support macos proxy config 2022-01-09 21:19:35 +08:00
GyDi
e86d192db7 feat: custom window decorations 2022-01-08 22:23:48 +08:00
GyDi
ea8f1c52f9 feat: profiles add menu and delete button 2022-01-08 16:52:18 +08:00
GyDi
a4c1573c45 fix: delete profile item command 2022-01-08 14:21:12 +08:00
GyDi
182bf49ad0 chore: temp 2022-01-08 02:54:37 +08:00
GyDi
13e1ddbccd v0.0.5 2022-01-08 02:12:56 +08:00
GyDi
327b9a1757 chore: enhance ci 2022-01-08 02:12:12 +08:00
GyDi
18c48db7f7 chore: rename script 2022-01-08 01:56:28 +08:00
GyDi
b6543bd87f chore: update publish script 2022-01-08 01:51:24 +08:00
GyDi
9ad8f71d7c refactor: rename 2022-01-08 01:27:25 +08:00
GyDi
e369311fc2 refactor: impl structs methods 2022-01-07 23:29:20 +08:00
GyDi
72ff261fe3 chore: update clash version 2022-01-06 23:40:57 +08:00
GyDi
774c6f7e05 fix: initialize profiles state 2022-01-05 23:30:18 +08:00
GyDi
771af6ae08 chore: fixed tauri rev 2022-01-05 23:27:26 +08:00
GyDi
b3cd207444 feat: delay put profiles and retry 2022-01-05 02:01:32 +08:00
GyDi
03f9fa4bc2 refactor: impl as struct methods 2022-01-05 02:00:59 +08:00
GyDi
e32bfd9aab feat: Window Send and Sync 2022-01-04 21:29:04 +08:00
GyDi
7e47f8f893 chore: update tauri 2022-01-04 21:25:00 +08:00
GyDi
cb816e9653 feat: support restart sidecar tray event 2021-12-31 18:24:50 +08:00
GyDi
6b3e7cbc08 feat: prevent click same 2021-12-31 18:21:35 +08:00
GyDi
db4993ae9b fix: item header bgcolor 2021-12-31 18:19:53 +08:00
GyDi
4dc3cf6c6b feat: scroller stable 2021-12-31 18:19:17 +08:00
GyDi
2b84bbf3a8 feat: compatible with macos(wip) 2021-12-29 18:49:38 +08:00
GyDi
26ef4c9961 chore: change tauri to git repo 2021-12-29 18:47:29 +08:00
GyDi
4f56c38599 fix: null type error 2021-12-29 01:01:22 +08:00
GyDi
240f4dcfb1 chore: dev support macos 2021-12-29 01:01:09 +08:00
GyDi
ac6abd81c9 v0.0.4 2021-12-28 01:48:25 +08:00
GyDi
14bda4f3a5 feat: record selected proxy 2021-12-28 01:47:43 +08:00
GyDi
61b9670b45 feat: display version 2021-12-28 01:35:58 +08:00
GyDi
01e8db317e chore: save lock file 2021-12-28 00:14:15 +08:00
GyDi
92fc09493e chore: post version script 2021-12-27 23:07:56 +08:00
GyDi
d927209db7 v0.0.3 2021-12-27 23:06:46 +08:00
GyDi
e94007b21f v0.0.3 2021-12-27 23:06:45 +08:00
GyDi
18750f275a
chore: update version 2021-12-27 10:21:49 +08:00
GyDi
d686a853f4
chore: update version 2021-12-27 10:21:10 +08:00
325 changed files with 12703 additions and 46267 deletions

View File

@ -1,5 +0,0 @@
[target.aarch64-unknown-linux-gnu]
linker = "aarch64-linux-gnu-gcc"
[target.armv7-unknown-linux-gnueabihf]
linker = "arm-linux-gnueabihf-gcc"

View File

@ -1,50 +1,23 @@
name: 问题反馈 / Bug report name: Bug report
title: "[BUG] " description: Create a report to help us improve
description: 反馈你遇到的问题 / Report the issue you are experiencing title: "[BUG]"
labels: ["bug"] labels: ["bug"]
type: "Bug"
body: body:
- type: markdown
attributes:
value: |
## 在提交问题之前,请确认以下事项:
1. 请 **确保** 您已经查阅了 [Clash Verge Rev 官方文档](https://clash-verge-rev.github.io/guide/term.html) 以及 [常见问题](https://clash-verge-rev.github.io/faq/windows.html)
2. 请 **确保** [已有的问题](https://github.com/clash-verge-rev/clash-verge-rev/issues?q=is%3Aissue) 中没有人提交过相似issue否则请在已有的issue下进行讨论
3. 请 **务必** 给issue填写一个简洁明了的标题以便他人快速检索
4. 请 **务必** 查看 [Alpha](https://github.com/clash-verge-rev/clash-verge-rev/releases/tag/alpha) 版本更新日志
5. 请 **务必** 尝试 [Alpha](https://github.com/clash-verge-rev/clash-verge-rev/releases/tag/alpha) 版本,确定问题是否仍然存在
6. 请 **务必** 按照模板规范详细描述问题以及尝试更新 Alpha 版本否则issue将会被直接关闭
## Before submitting the issue, please make sure of the following checklist:
1. Please make sure you have read the [Clash Verge Rev official documentation](https://clash-verge-rev.github.io/guide/term.html) and [FAQ](https://clash-verge-rev.github.io/faq/windows.html)
2. Please make sure there is no similar issue in the [existing issues](https://github.com/clash-verge-rev/clash-verge-rev/issues?q=is%3Aissue), otherwise please discuss under the existing issue
3. Please be sure to fill in a concise and clear title for the issue so that others can quickly search
4. Please be sure to check out [Alpha](https://github.com/clash-verge-rev/clash-verge-rev/releases/tag/alpha) version update log
5. Please be sure to try the [Alpha](https://github.com/clash-verge-rev/clash-verge-rev/releases/tag/alpha) version to ensure that the problem still exists
6. Please describe the problem in detail according to the template specification and try to update the Alpha version, otherwise the issue will be closed
- type: textarea - type: textarea
id: description
attributes: attributes:
label: 问题描述 / Describe the bug label: Describe the bug
description: 详细清晰地描述你遇到的问题,并配合截图 / Describe the problem you encountered in detail and clearly, and provide screenshots description: A clear and concise description of what the bug is.
validations: validations:
required: true required: true
- type: textarea - type: textarea
attributes: attributes:
label: 软件版本 / Verge Version label: To Reproduce
description: 请提供Verge的具体版本如果是alpha版本请注明下载时间(精确到小时分钟) / Please provide the specific version of Verge. If it is an alpha version, please indicate the download time (accurate to hours and minutes) description: Steps to reproduce the behavior.
validations:
required: true
- type: textarea
attributes:
label: 复现步骤 / To Reproduce
description: 请提供复现问题的步骤 / Steps to reproduce the behavior
validations: validations:
required: true required: true
- type: dropdown - type: dropdown
attributes: attributes:
label: 操作系统 / OS label: Platform
options: options:
- Windows - Windows
- Linux - Linux
@ -53,13 +26,20 @@ body:
required: true required: true
- type: input - type: input
attributes: attributes:
label: 操作系统版本 / OS Version label: System Version
description: 请提供你的操作系统版本Linux请额外提供桌面环境及窗口系统 / Please provide your OS version, for Linux, please also provide the desktop environment and window system placeholder: "e.g. macOS 10.15.7"
validations:
required: true
- type: input
attributes:
label: Software Version
placeholder: "e.g. 1.4.3"
validations: validations:
required: true required: true
- type: textarea - type: textarea
attributes: attributes:
label: 日志(勿上传日志文件,请粘贴日志内容) / Log (Do not upload the log file, paste the log content directly) label: Log
description: 请提供完整或相关部分的Debug日志请在“软件左侧菜单”->“设置”->“日志等级”调整到debugVerge错误请把“杂项设置”->“app日志等级”调整到debug并重启Verge生效。日志文件在“软件左侧菜单”->“设置”->“日志目录”下) / Please provide a complete or relevant part of the Debug log (please adjust the "Log level" to debug in "Software left menu" -> "Settings" -> "Log level". If there is a Verge error, please adjust "Miscellaneous settings" -> "app log level" to debug, and restart Verge to take effect. The log file is under "Software left menu" -> "Settings" -> "Log directory") description: "Log file content or screenshot"
validations: - type: textarea
required: true attributes:
label: Additional Information

View File

@ -1,4 +0,0 @@
contact_links:
- name: 讨论交流 / Communication
url: https://t.me/clash_verge_rev
about: 在 Telegram 群组中与其他用户讨论交流 / Communicate with other users in the Telegram group

View File

@ -1,47 +1,27 @@
name: 功能请求 / Feature request name: Feature request
title: "[Feature] " description: Suggest an idea for this project
description: 提出你的功能请求 / Propose your feature request title: "[Feature]"
labels: ["enhancement"] labels: ["enhancement"]
type: "Feature"
body: body:
- type: markdown
attributes:
value: |
## 在提交问题之前,请确认以下事项:
1. 请 **确保** 您已经查阅了 [Clash Verge Rev 官方文档](https://clash-verge-rev.github.io/guide/term.html) 确认软件不存在类似的功能
2. 请 **确保** [已有的问题](https://github.com/clash-verge-rev/clash-verge-rev/issues?q=is%3Aissue) 中没有人提交过相似issue否则请在已有的issue下进行讨论
3. 请 **务必** 给issue填写一个简洁明了的标题以便他人快速检索
4. 请 **务必** 先下载 [Alpha](https://github.com/clash-verge-rev/clash-verge-rev/releases/tag/alpha) 版本测试,确保该功能还未实现
5. 请 **务必** 按照模板规范详细描述问题否则issue将会被关闭
## Before submitting the issue, please make sure of the following checklist:
1. Please make sure you have read the [Clash Verge Rev official documentation](https://clash-verge-rev.github.io/guide/term.html) to confirm that the software does not have similar functions
2. Please make sure there is no similar issue in the [existing issues](https://github.com/clash-verge-rev/clash-verge-rev/issues?q=is%3Aissue), otherwise please discuss under the existing issue
3. Please be sure to fill in a concise and clear title for the issue so that others can quickly search
4. Please be sure to download the [Alpha](https://github.com/clash-verge-rev/clash-verge-rev/releases/tag/alpha) version for testing to ensure that the function has not been implemented
5. Please describe the problem in detail according to the template specification, otherwise the issue will be closed
- type: textarea - type: textarea
id: description
attributes: attributes:
label: 功能描述 / Feature description label: Is your feature request related to a problem? Please describe.
description: 详细清晰地描述你的功能请求 / A clear and concise description of what the feature is description: A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
validations: validations:
required: true required: true
- type: textarea - type: textarea
attributes: attributes:
label: 使用场景 / Use case label: Describe the solution you'd like
description: 请描述你的功能请求的使用场景 / Please describe the use case of your feature request description: A clear and concise description of what you want to happen.
validations: validations:
required: true required: true
- type: checkboxes - type: textarea
id: os-labels
attributes: attributes:
label: 适用系统 / Target OS label: Describe alternatives you've considered
description: 请选择该功能适用的操作系统(至少选择一个) / Please select the operating system(s) for this feature request (select at least one) description: A clear and concise description of any alternative solutions or features you've considered.
options:
- label: windows
- label: macos
- label: linux
validations: validations:
required: true required: true
- type: textarea
attributes:
label: Additional context
description: Add any other context or screenshots about the feature request here.

4
.github/build-for-linux/Dockerfile vendored Normal file
View File

@ -0,0 +1,4 @@
FROM rust:buster
COPY entrypoint.sh /entrypoint.sh
RUN chmod a+x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]

14
.github/build-for-linux/action.yml vendored Normal file
View File

@ -0,0 +1,14 @@
name: "Build for Linux"
branding:
icon: user-check
color: gray-dark
inputs:
target:
required: true
description: "Rust Target"
runs:
using: "docker"
image: "Dockerfile"
args:
- ${{ inputs.target }}

8
.github/build-for-linux/build.sh vendored Normal file
View File

@ -0,0 +1,8 @@
pnpm install
pnpm check $INPUT_TARGET
sed -i "s/#openssl/openssl={version=\"0.10\",features=[\"vendored\"]}/g" src-tauri/Cargo.toml
if [ "$INPUT_TARGET" = "x86_64-unknown-linux-gnu" ]; then
pnpm build --target $INPUT_TARGET
else
pnpm build --target $INPUT_TARGET -b deb
fi

37
.github/build-for-linux/entrypoint.sh vendored Normal file
View File

@ -0,0 +1,37 @@
#!/bin/bash
wget https://nodejs.org/dist/v20.10.0/node-v20.10.0-linux-x64.tar.xz
tar -Jxvf ./node-v20.10.0-linux-x64.tar.xz
export PATH=$(pwd)/node-v20.10.0-linux-x64/bin:$PATH
npm install pnpm -g
rustup target add "$INPUT_TARGET"
if [ "$INPUT_TARGET" = "x86_64-unknown-linux-gnu" ]; then
apt-get update
apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev libayatana-appindicator3-dev librsvg2-dev patchelf
elif [ "$INPUT_TARGET" = "aarch64-unknown-linux-gnu" ]; then
dpkg --add-architecture arm64
apt-get update
apt-get install -y libncurses6:arm64 libtinfo6:arm64 linux-libc-dev:arm64 libncursesw6:arm64 libssl3:arm64 libcups2:arm64
apt-get install -y --no-install-recommends g++-aarch64-linux-gnu libc6-dev-arm64-cross libssl-dev:arm64 libwebkit2gtk-4.0-dev:arm64 libgtk-3-dev:arm64 patchelf:arm64 librsvg2-dev:arm64 libayatana-appindicator3-dev:arm64
export CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc
export CC_aarch64_unknown_linux_gnu=aarch64-linux-gnu-gcc
export CXX_aarch64_unknown_linux_gnu=aarch64-linux-gnu-g++
export PKG_CONFIG_PATH=/usr/lib/aarch64-linux-gnu/pkgconfig
export PKG_CONFIG_ALLOW_CROSS=1
elif [ "$INPUT_TARGET" = "armv7-unknown-linux-gnueabihf" ]; then
dpkg --add-architecture armhf
apt-get update
apt-get install -y libncurses6:armhf libtinfo6:armhf linux-libc-dev:armhf libncursesw6:armhf libssl3:armhf libcups2:armhf
apt-get install -y --no-install-recommends g++-arm-linux-gnueabihf libc6-dev-armhf-cross libssl-dev:armhf libwebkit2gtk-4.0-dev:armhf libgtk-3-dev:armhf patchelf:armhf librsvg2-dev:armhf libayatana-appindicator3-dev:armhf
export CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc
export CC_armv7_unknown_linux_gnueabihf=arm-linux-gnueabihf-gcc
export CXX_armv7_unknown_linux_gnueabihf=arm-linux-gnueabihf-g++
export PKG_CONFIG_PATH=/usr/lib/arm-linux-gnueabihf/pkgconfig
export PKG_CONFIG_ALLOW_CROSS=1
else
echo "Unknown target: $INPUT_TARGET" && exit 1
fi
bash .github/build-for-linux/build.sh

View File

@ -2,214 +2,16 @@ name: Alpha Build
on: on:
workflow_dispatch: workflow_dispatch:
schedule: push:
# UTC+8 0,6,12,18 branches: [main]
- cron: "0 16,22,4,10 * * *" tags-ignore: [updater, alpha]
permissions: write-all permissions: write-all
env: env:
CARGO_INCREMENTAL: 0 CARGO_INCREMENTAL: 0
RUST_BACKTRACE: short RUST_BACKTRACE: short
concurrency:
# only allow per workflow per commit (and not pr) to run at a time
group: "${{ github.workflow }} - ${{ github.head_ref || github.ref }}"
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
jobs: jobs:
check_commit:
runs-on: ubuntu-latest
outputs:
should_run: ${{ steps.check.outputs.should_run }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 2
- name: Check if version changed or src changed
id: check
run: |
# For manual workflow_dispatch, always run
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
echo "should_run=true" >> $GITHUB_OUTPUT
exit 0
fi
# Store current version from package.json
CURRENT_VERSION=$(cat package.json | jq -r '.version')
echo "Current version: $CURRENT_VERSION"
# Get the previous commit's package.json version
git checkout HEAD~1 package.json
PREVIOUS_VERSION=$(cat package.json | jq -r '.version')
echo "Previous version: $PREVIOUS_VERSION"
# Reset back to current commit
git checkout HEAD package.json
# Check if version changed
if [ "$CURRENT_VERSION" != "$PREVIOUS_VERSION" ]; then
echo "Version changed from $PREVIOUS_VERSION to $CURRENT_VERSION"
echo "should_run=true" >> $GITHUB_OUTPUT
exit 0
fi
# Check if src or src-tauri directories changed
CURRENT_SRC_HASH=$(git rev-parse HEAD:src)
PREVIOUS_SRC_HASH=$(git rev-parse HEAD~1:src 2>/dev/null || echo "")
CURRENT_TAURI_HASH=$(git rev-parse HEAD:src-tauri 2>/dev/null || echo "")
PREVIOUS_TAURI_HASH=$(git rev-parse HEAD~1:src-tauri 2>/dev/null || echo "")
echo "Current src hash: $CURRENT_SRC_HASH"
echo "Previous src hash: $PREVIOUS_SRC_HASH"
echo "Current tauri hash: $CURRENT_TAURI_HASH"
echo "Previous tauri hash: $PREVIOUS_TAURI_HASH"
if [ "$CURRENT_SRC_HASH" != "$PREVIOUS_SRC_HASH" ] || [ "$CURRENT_TAURI_HASH" != "$PREVIOUS_TAURI_HASH" ]; then
echo "Source directories changed"
echo "should_run=true" >> $GITHUB_OUTPUT
else
echo "Version and source directories unchanged"
echo "should_run=false" >> $GITHUB_OUTPUT
fi
delete_old_assets:
needs: check_commit
if: ${{ needs.check_commit.outputs.should_run == 'true' }}
runs-on: ubuntu-latest
steps:
- name: Delete Old Alpha Release Assets
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const releaseTag = 'alpha';
try {
// Get the release by tag name
const { data: release } = await github.rest.repos.getReleaseByTag({
owner: context.repo.owner,
repo: context.repo.repo,
tag: releaseTag
});
console.log(`Found release with ID: ${release.id}`);
// Delete each asset
if (release.assets && release.assets.length > 0) {
console.log(`Deleting ${release.assets.length} assets`);
for (const asset of release.assets) {
console.log(`Deleting asset: ${asset.name} (${asset.id})`);
await github.rest.repos.deleteReleaseAsset({
owner: context.repo.owner,
repo: context.repo.repo,
asset_id: asset.id
});
}
console.log('All assets deleted successfully');
} else {
console.log('No assets found to delete');
}
} catch (error) {
if (error.status === 404) {
console.log('Release not found, nothing to delete');
} else {
console.error('Error:', error);
throw error;
}
}
update_tag:
name: Update tag
runs-on: ubuntu-latest
needs: delete_old_assets
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Fetch Alpha update logs
id: fetch_alpha_logs
run: |
# Check if UPDATELOG.md exists
if [ -f "UPDATELOG.md" ]; then
# Extract the section starting with ## and containing -alpha until the next ## or end of file
# ALPHA_LOGS=$(awk '/^## .*-alpha/{flag=1; print; next} /^## /{flag=0} flag' UPDATELOG.md)
ALPHA_LOGS=$(awk '/^## v/{if(flag) exit; flag=1} flag' UPDATELOG.md)
if [ -n "$ALPHA_LOGS" ]; then
echo "Found alpha update logs"
echo "ALPHA_LOGS<<EOF" >> $GITHUB_ENV
echo "$ALPHA_LOGS" >> $GITHUB_ENV
echo "EOF" >> $GITHUB_ENV
else
echo "No alpha sections found in UPDATELOG.md"
fi
else
echo "UPDATELOG.md file not found"
fi
shell: bash
- name: Set Env
run: |
echo "BUILDTIME=$(TZ=Asia/Shanghai date)" >> $GITHUB_ENV
shell: bash
- run: |
# 检查 ALPHA_LOGS 是否存在,如果不存在则使用默认消息
if [ -z "$ALPHA_LOGS" ]; then
echo "No alpha logs found, using default message"
ALPHA_LOGS="More new features are now supported. Check for detailed changelog soon."
else
echo "Using found alpha logs"
fi
# 生成 release.txt 文件
cat > release.txt << EOF
$ALPHA_LOGS
## 我应该下载哪个版本?
### MacOS
- MacOS intel芯片: x64.dmg
- MacOS apple M芯片: aarch64.dmg
### Linux
- Linux 64位: amd64.deb/amd64.rpm
- Linux arm64 architecture: arm64.deb/aarch64.rpm
- Linux armv7架构: armhf.deb/armhfp.rpm
### Windows (不再支持Win7)
#### 正常版本(推荐)
- 64位: x64-setup.exe
- arm64架构: arm64-setup.exe
#### 便携版问题很多不再提供
#### 内置Webview2版(体积较大仅在企业版系统或无法安装webview2时使用)
- 64位: x64_fixed_webview2-setup.exe
- arm64架构: arm64_fixed_webview2-setup.exe
### FAQ
- [常见问题](https://clash-verge-rev.github.io/faq/windows.html)
### 稳定机场VPN推荐
- [狗狗加速](https://verge.dginv.click/#/register?code=oaxsAGo6)
Created at ${{ env.BUILDTIME }}.
EOF
- name: Upload Release
uses: softprops/action-gh-release@v2
with:
tag_name: alpha
name: "Clash Verge Rev Alpha"
body_path: release.txt
prerelease: true
token: ${{ secrets.GITHUB_TOKEN }}
generate_release_notes: true
alpha: alpha:
needs: update_tag
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@ -222,14 +24,23 @@ jobs:
target: aarch64-apple-darwin target: aarch64-apple-darwin
- os: macos-latest - os: macos-latest
target: x86_64-apple-darwin target: x86_64-apple-darwin
- os: ubuntu-22.04
target: x86_64-unknown-linux-gnu
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout Repository - name: Checkout Repository
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Apply Patch
if: matrix.target == 'aarch64-pc-windows-msvc'
run: |
git config --global user.email "clash-verge-rev@github.io"
git config --global user.name "clash-verge-rev"
git am patches/support-windows-aarch64.patch
- name: Init Submodule
if: matrix.target == 'aarch64-pc-windows-msvc'
run: git submodule update --init --recursive
- name: Install Rust Stable - name: Install Rust Stable
uses: dtolnay/rust-toolchain@stable uses: dtolnay/rust-toolchain@stable
@ -240,23 +51,16 @@ jobs:
uses: Swatinem/rust-cache@v2 uses: Swatinem/rust-cache@v2
with: with:
workspaces: src-tauri workspaces: src-tauri
cache-all-crates: true
cache-on-failure: true
- name: Install dependencies (ubuntu only)
if: matrix.os == 'ubuntu-22.04'
run: |
sudo apt-get update
sudo apt-get install -y libxslt1.1 libwebkit2gtk-4.1-dev libayatana-appindicator3-dev librsvg2-dev patchelf
- name: Install Node - name: Install Node
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
node-version: "22" node-version: "20"
- uses: pnpm/action-setup@v4 - uses: pnpm/action-setup@v2
name: Install pnpm name: Install pnpm
with: with:
version: 8
run_install: false run_install: false
- name: Pnpm install and check - name: Pnpm install and check
@ -264,22 +68,12 @@ jobs:
pnpm i pnpm i
pnpm check ${{ matrix.target }} pnpm check ${{ matrix.target }}
- name: Release Alpha Version
run: pnpm release-alpha-version
- name: Tauri build - name: Tauri build
uses: tauri-apps/tauri-action@v0 uses: tauri-apps/tauri-action@v0
env: env:
NODE_OPTIONS: "--max_old_space_size=4096"
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }} TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }} TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
with: with:
tagName: alpha tagName: alpha
releaseName: "Clash Verge Rev Alpha" releaseName: "Clash Verge Rev Alpha"
@ -289,225 +83,87 @@ jobs:
tauriScript: pnpm tauriScript: pnpm
args: --target ${{ matrix.target }} args: --target ${{ matrix.target }}
alpha-for-linux-arm: - name: Portable Bundle
needs: update_tag if: matrix.os == 'windows-latest'
run: pnpm portable ${{ matrix.target }} --alpha
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
alpha-for-linux:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
include: include:
- os: ubuntu-22.04 - os: ubuntu-latest
target: x86_64-unknown-linux-gnu
- os: ubuntu-latest
target: aarch64-unknown-linux-gnu target: aarch64-unknown-linux-gnu
arch: arm64
- os: ubuntu-22.04
target: armv7-unknown-linux-gnueabihf
arch: armhf
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout Repository - name: Checkout Repository
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Install Rust Stable
uses: dtolnay/rust-toolchain@stable
- name: Add Rust Target
run: rustup target add ${{ matrix.target }}
- name: Rust Cache
uses: Swatinem/rust-cache@v2
with:
workspaces: src-tauri
cache-all-crates: true
- name: Install Node
uses: actions/setup-node@v4
with:
node-version: "22"
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
run_install: false
- name: Pnpm install and check
run: |
pnpm i
pnpm check ${{ matrix.target }}
- name: Release Alpha Version
run: pnpm release-alpha-version
- name: "Setup for linux"
run: |-
sudo ls -lR /etc/apt/
cat > /tmp/sources.list << EOF
deb [arch=amd64,i386] http://archive.ubuntu.com/ubuntu jammy main multiverse universe restricted
deb [arch=amd64,i386] http://archive.ubuntu.com/ubuntu jammy-security main multiverse universe restricted
deb [arch=amd64,i386] http://archive.ubuntu.com/ubuntu jammy-updates main multiverse universe restricted
deb [arch=amd64,i386] http://archive.ubuntu.com/ubuntu jammy-backports main multiverse universe restricted
deb [arch=armhf,arm64] http://ports.ubuntu.com/ubuntu-ports jammy main multiverse universe restricted
deb [arch=armhf,arm64] http://ports.ubuntu.com/ubuntu-ports jammy-security main multiverse universe restricted
deb [arch=armhf,arm64] http://ports.ubuntu.com/ubuntu-ports jammy-updates main multiverse universe restricted
deb [arch=armhf,arm64] http://ports.ubuntu.com/ubuntu-ports jammy-backports main multiverse universe restricted
EOF
sudo mv /etc/apt/sources.list /etc/apt/sources.list.default
sudo mv /tmp/sources.list /etc/apt/sources.list
sudo dpkg --add-architecture ${{ matrix.arch }}
sudo apt update
sudo apt install -y \
libxslt1.1:${{ matrix.arch }} \
libwebkit2gtk-4.1-dev:${{ matrix.arch }} \
libayatana-appindicator3-dev:${{ matrix.arch }} \
libssl-dev:${{ matrix.arch }} \
patchelf:${{ matrix.arch }} \
librsvg2-dev:${{ matrix.arch }}
- name: "Install aarch64 tools"
if: matrix.target == 'aarch64-unknown-linux-gnu'
run: |
sudo apt install -y \
gcc-aarch64-linux-gnu \
g++-aarch64-linux-gnu
- name: "Install armv7 tools"
if: matrix.target == 'armv7-unknown-linux-gnueabihf'
run: |
sudo apt install -y \
gcc-arm-linux-gnueabihf \
g++-arm-linux-gnueabihf
- name: Build for Linux - name: Build for Linux
run: | uses: ./.github/build-for-linux
export PKG_CONFIG_ALLOW_CROSS=1
if [ "${{ matrix.target }}" == "aarch64-unknown-linux-gnu" ]; then
export PKG_CONFIG_PATH=/usr/lib/aarch64-linux-gnu/pkgconfig/:$PKG_CONFIG_PATH
export PKG_CONFIG_SYSROOT_DIR=/usr/aarch64-linux-gnu/
elif [ "${{ matrix.target }}" == "armv7-unknown-linux-gnueabihf" ]; then
export PKG_CONFIG_PATH=/usr/lib/arm-linux-gnueabihf/pkgconfig/:$PKG_CONFIG_PATH
export PKG_CONFIG_SYSROOT_DIR=/usr/arm-linux-gnueabihf/
fi
pnpm build --target ${{ matrix.target }}
env: env:
NODE_OPTIONS: "--max_old_space_size=4096" TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }} TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }} with:
target: ${{ matrix.target }}
- name: Get Version - name: Get Version
run: | run: |
sudo apt-get update sudo apt-get update
sudo apt-get install jq sudo apt-get install jq
echo "VERSION=$(cat package.json | jq '.version' | tr -d '"')" >> $GITHUB_ENV echo "VERSION=$(cat package.json | jq '.version' | tr -d '"')" >> $GITHUB_ENV
echo "BUILDTIME=$(TZ=Asia/Shanghai date)" >> $GITHUB_ENV
- name: Upload Release - name: Upload Release
uses: softprops/action-gh-release@v2 if: startsWith(matrix.target, 'x86_64')
uses: softprops/action-gh-release@v1
with: with:
tag_name: alpha tag_name: alpha
name: "Clash Verge Rev Alpha" name: "Clash Verge Rev Alpha"
body: "More new features are now supported."
prerelease: true prerelease: true
token: ${{ secrets.GITHUB_TOKEN }} token: ${{ secrets.GITHUB_TOKEN }}
files: | files: src-tauri/target/${{ matrix.target }}/release/bundle/appimage/*.AppImage*
src-tauri/target/${{ matrix.target }}/release/bundle/deb/*.deb - name: Upload Release
src-tauri/target/${{ matrix.target }}/release/bundle/rpm/*.rpm uses: softprops/action-gh-release@v1
with:
alpha-for-fixed-webview2: tag_name: alpha
needs: update_tag name: "Clash Verge Rev Alpha"
strategy: body: "More new features are now supported."
fail-fast: false prerelease: true
matrix: token: ${{ secrets.GITHUB_TOKEN }}
include: files: src-tauri/target/${{ matrix.target }}/release/bundle/deb/*.deb
- os: windows-latest update_tag:
target: x86_64-pc-windows-msvc name: Update tag
arch: x64 runs-on: ubuntu-latest
- os: windows-latest needs: [alpha, alpha-for-linux]
target: aarch64-pc-windows-msvc
arch: arm64
runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout Repository - name: Checkout repository
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Set Env
- name: Add Rust Target
run: rustup target add ${{ matrix.target }}
- name: Rust Cache
uses: Swatinem/rust-cache@v2
with:
workspaces: src-tauri
cache-all-crates: true
cache-on-failure: true
- name: Install Node
uses: actions/setup-node@v4
with:
node-version: "22"
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
run_install: false
- name: Pnpm install and check
run: | run: |
pnpm i echo "BUILDTIME=$(TZ=Asia/Shanghai date)" >> $GITHUB_ENV
pnpm check ${{ matrix.target }} shell: bash
- name: Update Tag
- name: Release Alpha Version uses: richardsimko/update-tag@v1
run: pnpm release-alpha-version with:
tag_name: alpha
- name: Download WebView2 Runtime
run: |
invoke-webrequest -uri https://github.com/westinyang/WebView2RuntimeArchive/releases/download/109.0.1518.78/Microsoft.WebView2.FixedVersionRuntime.109.0.1518.78.${{ matrix.arch }}.cab -outfile Microsoft.WebView2.FixedVersionRuntime.109.0.1518.78.${{ matrix.arch }}.cab
Expand .\Microsoft.WebView2.FixedVersionRuntime.109.0.1518.78.${{ matrix.arch }}.cab -F:* ./src-tauri
Remove-Item .\src-tauri\tauri.windows.conf.json
Rename-Item .\src-tauri\webview2.${{ matrix.arch }}.json tauri.windows.conf.json
- name: Tauri build
id: build
uses: tauri-apps/tauri-action@v0
env: env:
NODE_OPTIONS: "--max_old_space_size=4096"
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }} - run: |
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }} cat > release.txt << 'EOF'
with: ## Clash Verge Rev Alpha
tauriScript: pnpm Created at ${{ env.BUILDTIME }}.
args: --target ${{ matrix.target }} EOF
- name: Rename
run: |
$files = Get-ChildItem ".\src-tauri\target\${{ matrix.target }}\release\bundle\nsis\*-setup.exe"
foreach ($file in $files) {
$newName = $file.Name -replace "-setup\.exe$", "_fixed_webview2-setup.exe"
Rename-Item $file.FullName $newName
}
$files = Get-ChildItem ".\src-tauri\target\${{ matrix.target }}\release\bundle\nsis\*.nsis.zip"
foreach ($file in $files) {
$newName = $file.Name -replace "-setup\.nsis\.zip$", "_fixed_webview2-setup.nsis.zip"
Rename-Item $file.FullName $newName
}
$files = Get-ChildItem ".\src-tauri\target\${{ matrix.target }}\release\bundle\nsis\*-setup.exe.sig"
foreach ($file in $files) {
$newName = $file.Name -replace "-setup\.exe\.sig$", "_fixed_webview2-setup.exe.sig"
Rename-Item $file.FullName $newName
}
- name: Upload Release - name: Upload Release
uses: softprops/action-gh-release@v2 uses: softprops/action-gh-release@v1
with: with:
tag_name: alpha tag_name: alpha
name: "Clash Verge Rev Alpha" name: "Clash Verge Rev Alpha"
body_path: release.txt
prerelease: true prerelease: true
token: ${{ secrets.GITHUB_TOKEN }} token: ${{ secrets.GITHUB_TOKEN }}
files: src-tauri/target/${{ matrix.target }}/release/bundle/nsis/*setup* generate_release_notes: true
- name: Portable Bundle
run: pnpm portable-fixed-webview2 ${{ matrix.target }} --alpha
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@ -1,94 +0,0 @@
name: Development Test
on:
workflow_dispatch:
permissions: write-all
env:
CARGO_INCREMENTAL: 0
RUST_BACKTRACE: short
concurrency:
# only allow per workflow per commit (and not pr) to run at a time
group: "${{ github.workflow }} - ${{ github.head_ref || github.ref }}"
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
jobs:
dev:
strategy:
fail-fast: false
matrix:
include:
- os: windows-latest
target: x86_64-pc-windows-msvc
bundle: nsis
- os: macos-latest
target: aarch64-apple-darwin
bundle: dmg
- os: macos-latest
target: x86_64-apple-darwin
bundle: dmg
runs-on: ${{ matrix.os }}
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Install Rust Stable
uses: dtolnay/rust-toolchain@stable
- name: Add Rust Target
run: rustup target add ${{ matrix.target }}
- name: Rust Cache
uses: Swatinem/rust-cache@v2
with:
workspaces: src-tauri
cache-all-crates: true
cache-on-failure: true
- name: Install Node
uses: actions/setup-node@v4
with:
node-version: "20"
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
run_install: false
- name: Pnpm install and check
run: |
pnpm i
pnpm check ${{ matrix.target }}
- name: Tauri build
uses: tauri-apps/tauri-action@v0
env:
NODE_OPTIONS: "--max_old_space_size=4096"
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
with:
tauriScript: pnpm
args: --target ${{ matrix.target }} -b ${{ matrix.bundle }}
- name: Upload Artifacts
if: matrix.os == 'macos-latest'
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.target }}
path: src-tauri/target/${{ matrix.target }}/release/bundle/dmg/*.dmg
if-no-files-found: error
- name: Upload Artifacts
if: matrix.os == 'windows-latest'
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.target }}
path: src-tauri/target/${{ matrix.target }}/release/bundle/nsis/*.exe
if-no-files-found: error

View File

@ -6,10 +6,6 @@ permissions: write-all
env: env:
CARGO_INCREMENTAL: 0 CARGO_INCREMENTAL: 0
RUST_BACKTRACE: short RUST_BACKTRACE: short
concurrency:
# only allow per workflow per commit (and not pr) to run at a time
group: "${{ github.workflow }} - ${{ github.head_ref || github.ref }}"
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
jobs: jobs:
release: release:
@ -25,14 +21,23 @@ jobs:
target: aarch64-apple-darwin target: aarch64-apple-darwin
- os: macos-latest - os: macos-latest
target: x86_64-apple-darwin target: x86_64-apple-darwin
- os: ubuntu-22.04
target: x86_64-unknown-linux-gnu
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout Repository - name: Checkout Repository
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Apply Patch
if: matrix.target == 'aarch64-pc-windows-msvc'
run: |
git config --global user.email "clash-verge-rev@github.io"
git config --global user.name "clash-verge-rev"
git am patches/support-windows-aarch64.patch
- name: Init Submodule
if: matrix.target == 'aarch64-pc-windows-msvc'
run: git submodule update --init --recursive
- name: Install Rust Stable - name: Install Rust Stable
uses: dtolnay/rust-toolchain@stable uses: dtolnay/rust-toolchain@stable
@ -43,23 +48,16 @@ jobs:
uses: Swatinem/rust-cache@v2 uses: Swatinem/rust-cache@v2
with: with:
workspaces: src-tauri workspaces: src-tauri
cache-all-crates: true
cache-on-failure: true
- name: Install dependencies (ubuntu only)
if: matrix.os == 'ubuntu-22.04'
run: |
sudo apt-get update
sudo apt-get install -y libxslt1.1 libwebkit2gtk-4.1-dev libayatana-appindicator3-dev librsvg2-dev patchelf
- name: Install Node - name: Install Node
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
node-version: "22" node-version: "20"
- uses: pnpm/action-setup@v4 - uses: pnpm/action-setup@v2
name: Install pnpm name: Install pnpm
with: with:
version: 8
run_install: false run_install: false
- name: Pnpm install and check - name: Pnpm install and check
@ -70,253 +68,86 @@ jobs:
- name: Tauri build - name: Tauri build
uses: tauri-apps/tauri-action@v0 uses: tauri-apps/tauri-action@v0
env: env:
NODE_OPTIONS: "--max_old_space_size=4096"
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }} TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }} TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
with: with:
tagName: v__VERSION__ tagName: v__VERSION__
releaseName: "Clash Verge Rev v__VERSION__" releaseName: "Clash Verge Rev v__VERSION__"
releaseBody: "More new features are now supported." releaseBody: "More new features are now supported."
releaseDraft: false
prerelease: false
tauriScript: pnpm tauriScript: pnpm
args: --target ${{ matrix.target }} args: --target ${{ matrix.target }}
release-for-linux-arm: - name: Portable Bundle
if: matrix.os == 'windows-latest'
run: pnpm portable ${{ matrix.target }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
release-for-linux:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
include: include:
- os: ubuntu-22.04 - os: ubuntu-latest
target: x86_64-unknown-linux-gnu
- os: ubuntu-latest
target: aarch64-unknown-linux-gnu target: aarch64-unknown-linux-gnu
arch: arm64
- os: ubuntu-22.04
target: armv7-unknown-linux-gnueabihf
arch: armhf
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout Repository - name: Checkout Repository
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Install Rust Stable
uses: dtolnay/rust-toolchain@stable
- name: Add Rust Target
run: rustup target add ${{ matrix.target }}
- name: Rust Cache
uses: Swatinem/rust-cache@v2
with:
workspaces: src-tauri
cache-all-crates: true
- name: Install Node
uses: actions/setup-node@v4
with:
node-version: "22"
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
run_install: false
- name: Pnpm install and check
run: |
pnpm i
pnpm check ${{ matrix.target }}
- name: "Setup for linux"
run: |-
sudo ls -lR /etc/apt/
cat > /tmp/sources.list << EOF
deb [arch=amd64,i386] http://archive.ubuntu.com/ubuntu jammy main multiverse universe restricted
deb [arch=amd64,i386] http://archive.ubuntu.com/ubuntu jammy-security main multiverse universe restricted
deb [arch=amd64,i386] http://archive.ubuntu.com/ubuntu jammy-updates main multiverse universe restricted
deb [arch=amd64,i386] http://archive.ubuntu.com/ubuntu jammy-backports main multiverse universe restricted
deb [arch=armhf,arm64] http://ports.ubuntu.com/ubuntu-ports jammy main multiverse universe restricted
deb [arch=armhf,arm64] http://ports.ubuntu.com/ubuntu-ports jammy-security main multiverse universe restricted
deb [arch=armhf,arm64] http://ports.ubuntu.com/ubuntu-ports jammy-updates main multiverse universe restricted
deb [arch=armhf,arm64] http://ports.ubuntu.com/ubuntu-ports jammy-backports main multiverse universe restricted
EOF
sudo mv /etc/apt/sources.list /etc/apt/sources.list.default
sudo mv /tmp/sources.list /etc/apt/sources.list
sudo dpkg --add-architecture ${{ matrix.arch }}
sudo apt update
sudo apt install -y \
libxslt1.1:${{ matrix.arch }} \
libwebkit2gtk-4.1-dev:${{ matrix.arch }} \
libayatana-appindicator3-dev:${{ matrix.arch }} \
libssl-dev:${{ matrix.arch }} \
patchelf:${{ matrix.arch }} \
librsvg2-dev:${{ matrix.arch }}
- name: "Install aarch64 tools"
if: matrix.target == 'aarch64-unknown-linux-gnu'
run: |
sudo apt install -y \
gcc-aarch64-linux-gnu \
g++-aarch64-linux-gnu
- name: "Install armv7 tools"
if: matrix.target == 'armv7-unknown-linux-gnueabihf'
run: |
sudo apt install -y \
gcc-arm-linux-gnueabihf \
g++-arm-linux-gnueabihf
- name: Build for Linux - name: Build for Linux
run: | uses: ./.github/build-for-linux
export PKG_CONFIG_ALLOW_CROSS=1
if [ "${{ matrix.target }}" == "aarch64-unknown-linux-gnu" ]; then
export PKG_CONFIG_PATH=/usr/lib/aarch64-linux-gnu/pkgconfig/:$PKG_CONFIG_PATH
export PKG_CONFIG_SYSROOT_DIR=/usr/aarch64-linux-gnu/
elif [ "${{ matrix.target }}" == "armv7-unknown-linux-gnueabihf" ]; then
export PKG_CONFIG_PATH=/usr/lib/arm-linux-gnueabihf/pkgconfig/:$PKG_CONFIG_PATH
export PKG_CONFIG_SYSROOT_DIR=/usr/arm-linux-gnueabihf/
fi
pnpm build --target ${{ matrix.target }}
env: env:
NODE_OPTIONS: "--max_old_space_size=4096" TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }} TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }} with:
target: ${{ matrix.target }}
- name: Get Version - name: Get Version
run: | run: |
sudo apt-get update sudo apt-get update
sudo apt-get install jq sudo apt-get install jq
echo "VERSION=$(cat package.json | jq '.version' | tr -d '"')" >> $GITHUB_ENV echo "VERSION=$(cat package.json | jq '.version' | tr -d '"')" >> $GITHUB_ENV
echo "BUILDTIME=$(TZ=Asia/Shanghai date)" >> $GITHUB_ENV
- name: Upload Release - name: Upload Release
uses: softprops/action-gh-release@v2 if: startsWith(matrix.target, 'x86_64')
uses: softprops/action-gh-release@v1
with: with:
tag_name: v${{env.VERSION}} tag_name: v${{env.VERSION}}
name: "Clash Verge Rev v${{env.VERSION}}" name: "Clash Verge Rev v${{env.VERSION}}"
body: "More new features are now supported." body: "More new features are now supported."
token: ${{ secrets.GITHUB_TOKEN }} token: ${{ secrets.GITHUB_TOKEN }}
files: | files: src-tauri/target/${{ matrix.target }}/release/bundle/appimage/*.AppImage*
src-tauri/target/${{ matrix.target }}/release/bundle/deb/*.deb
src-tauri/target/${{ matrix.target }}/release/bundle/rpm/*.rpm
release-for-fixed-webview2:
strategy:
fail-fast: false
matrix:
include:
- os: windows-latest
target: x86_64-pc-windows-msvc
arch: x64
- os: windows-latest
target: aarch64-pc-windows-msvc
arch: arm64
runs-on: ${{ matrix.os }}
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Add Rust Target
run: rustup target add ${{ matrix.target }}
- name: Rust Cache
uses: Swatinem/rust-cache@v2
with:
workspaces: src-tauri
cache-all-crates: true
cache-on-failure: true
- name: Install Node
uses: actions/setup-node@v4
with:
node-version: "22"
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
run_install: false
- name: Pnpm install and check
run: |
pnpm i
pnpm check ${{ matrix.target }}
- name: Download WebView2 Runtime
run: |
invoke-webrequest -uri https://github.com/westinyang/WebView2RuntimeArchive/releases/download/109.0.1518.78/Microsoft.WebView2.FixedVersionRuntime.109.0.1518.78.${{ matrix.arch }}.cab -outfile Microsoft.WebView2.FixedVersionRuntime.109.0.1518.78.${{ matrix.arch }}.cab
Expand .\Microsoft.WebView2.FixedVersionRuntime.109.0.1518.78.${{ matrix.arch }}.cab -F:* ./src-tauri
Remove-Item .\src-tauri\tauri.windows.conf.json
Rename-Item .\src-tauri\webview2.${{ matrix.arch }}.json tauri.windows.conf.json
- name: Tauri build
id: build
uses: tauri-apps/tauri-action@v0
env:
NODE_OPTIONS: "--max_old_space_size=4096"
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
with:
tauriScript: pnpm
args: --target ${{ matrix.target }}
- name: Rename
run: |
$files = Get-ChildItem ".\src-tauri\target\${{ matrix.target }}\release\bundle\nsis\*-setup.exe"
foreach ($file in $files) {
$newName = $file.Name -replace "-setup\.exe$", "_fixed_webview2-setup.exe"
Rename-Item $file.FullName $newName
}
$files = Get-ChildItem ".\src-tauri\target\${{ matrix.target }}\release\bundle\nsis\*.nsis.zip"
foreach ($file in $files) {
$newName = $file.Name -replace "-setup\.nsis\.zip$", "_fixed_webview2-setup.nsis.zip"
Rename-Item $file.FullName $newName
}
$files = Get-ChildItem ".\src-tauri\target\${{ matrix.target }}\release\bundle\nsis\*-setup.exe.sig"
foreach ($file in $files) {
$newName = $file.Name -replace "-setup\.exe\.sig$", "_fixed_webview2-setup.exe.sig"
Rename-Item $file.FullName $newName
}
- name: Upload Release - name: Upload Release
uses: softprops/action-gh-release@v2 uses: softprops/action-gh-release@v1
with: with:
tag_name: v${{steps.build.outputs.appVersion}} tag_name: v${{env.VERSION}}
name: "Clash Verge Rev v${{steps.build.outputs.appVersion}}" name: "Clash Verge Rev v${{env.VERSION}}"
body: "More new features are now supported." body: "More new features are now supported."
token: ${{ secrets.GITHUB_TOKEN }} token: ${{ secrets.GITHUB_TOKEN }}
files: src-tauri/target/${{ matrix.target }}/release/bundle/nsis/*setup* files: src-tauri/target/${{ matrix.target }}/release/bundle/deb/*.deb
- name: Portable Bundle
run: pnpm portable-fixed-webview2 ${{ matrix.target }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
release-update: release-update:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: [release, release-for-linux-arm] needs: [release, release-for-linux]
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v4 uses: actions/checkout@v3
- name: Install Node - name: Install Node
uses: actions/setup-node@v4 uses: actions/setup-node@v3
with: with:
node-version: "22" node-version: "20"
- uses: pnpm/action-setup@v4 - uses: pnpm/action-setup@v2
name: Install pnpm name: Install pnpm
with: with:
version: 8
run_install: false run_install: false
- name: Pnpm install - name: Pnpm install
@ -326,50 +157,3 @@ jobs:
run: pnpm updater run: pnpm updater
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
release-update-for-fixed-webview2:
runs-on: ubuntu-latest
needs: [release-for-fixed-webview2]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install Node
uses: actions/setup-node@v4
with:
node-version: "22"
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
run_install: false
- name: Pnpm install
run: pnpm i
- name: Release updater file
run: pnpm updater-fixed-webview2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
submit-to-winget:
runs-on: ubuntu-latest
needs: [release-update]
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Get Version
run: |
sudo apt-get update
sudo apt-get install jq
echo "VERSION=$(cat package.json | jq '.version' | tr -d '"')" >> $GITHUB_ENV
- name: Submit to Winget
uses: vedantmgoyal9/winget-releaser@main
with:
identifier: ClashVergeRev.ClashVergeRev
version: ${{env.VERSION}}
release-tag: v${{env.VERSION}}
installers-regex: '_(arm64|x64|x86)-setup\.exe$'
token: ${{ secrets.WINGET_TOKEN }}

View File

@ -7,16 +7,17 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v4 uses: actions/checkout@v3
- name: Install Node - name: Install Node
uses: actions/setup-node@v4 uses: actions/setup-node@v3
with: with:
node-version: "22" node-version: "20"
- uses: pnpm/action-setup@v4 - uses: pnpm/action-setup@v2
name: Install pnpm name: Install pnpm
with: with:
version: 8
run_install: false run_install: false
- name: Pnpm install - name: Pnpm install
@ -26,27 +27,3 @@ jobs:
run: pnpm updater run: pnpm updater
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
release-update-for-fixed-webview2:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install Node
uses: actions/setup-node@v4
with:
node-version: "22"
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
run_install: false
- name: Pnpm install
run: pnpm i
- name: Release updater file
run: pnpm updater-fixed-webview2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

3
.gitignore vendored
View File

@ -1,5 +1,4 @@
node_modules node_modules
.pnpm-store
.DS_Store .DS_Store
dist dist
dist-ssr dist-ssr
@ -7,5 +6,3 @@ dist-ssr
update.json update.json
scripts/_env.sh scripts/_env.sh
.vscode .vscode
.tool-versions
.idea

View File

@ -1,16 +1,4 @@
#!/bin/bash #!/bin/sh
. "$(dirname "$0")/_/husky.sh"
#pnpm pretty-quick --staged pnpm pretty-quick --staged
# 运行 clippy fmt
cargo fmt --manifest-path ./src-tauri/Cargo.toml
if [ $? -ne 0 ]; then
echo "rustfmt failed to format the code. Please fix the issues and try again."
exit 1
fi
#git add .
# 允许提交
exit 0

View File

@ -1,13 +0,0 @@
#!/bin/bash
# 运行 clippy
# cargo clippy --manifest-path ./src-tauri/Cargo.toml --fix
# 如果 clippy 失败,阻止 push
# if [ $? -ne 0 ]; then
# echo "Clippy found issues in sub_crate. Please fix them before pushing."
# exit 1
# fi
# 允许 push
exit 0

View File

@ -1 +0,0 @@
nodejs 21.7.1

View File

@ -17,28 +17,15 @@ If you're a Windows user, you may need to perform some additional steps:
- Make sure to add Rust and Node.js to your system's PATH. This is usually done during the installation process, but you can verify and manually add them if necessary. - Make sure to add Rust and Node.js to your system's PATH. This is usually done during the installation process, but you can verify and manually add them if necessary.
- The gnu `patch` tool should be installed - The gnu `patch` tool should be installed
When you setup `Rust` environment, Only use toolchain with `Windows MSVC` , to change settings follow command: ### Install Node.js Packages
After installing Rust and Node.js, install the necessary Node.js packages:
```shell ```shell
rustup target add x86_64-pc-windows-msvc pnpm i
rustup set default-host x86_64-pc-windows-msvc
``` ```
### Install Node.js Package ### Download the Clash Binary
After installing Rust and Node.js, install the necessary Node.js and Node Package Manager:
```shell
npm install pnpm -g
```
### Install Dependencies
```shell
pnpm install
```
### Download the Mihomo Core Binary
You have two options for downloading the clash binary: You have two options for downloading the clash binary:
@ -48,7 +35,7 @@ You have two options for downloading the clash binary:
# Use '--force' to force update to the latest version # Use '--force' to force update to the latest version
# pnpm run check --force # pnpm run check --force
``` ```
- Manually download it from the [Mihomo release](https://github.com/MetaCubeX/mihomo/releases). After downloading, rename the binary according to the [Tauri configuration](https://tauri.app/v1/api/config#bundleconfig.externalbin). - Manually download it from the [Clash Meta release](https://github.com/MetaCubeX/Clash.Meta/releases). After downloading, rename the binary according to the [Tauri configuration](https://tauri.app/v1/api/config#bundleconfig.externalbin).
### Run the Development Server ### Run the Development Server
@ -62,38 +49,12 @@ pnpm dev:diff
### Build the Project ### Build the Project
To build this project: If you want to build the project, use:
```shell ```shell
pnpm build pnpm build
``` ```
For a faster build, use the following command
```shell
pnpm build:fast
```
This uses Rust's fast-release profile which significantly reduces compilation time by disabling optimization and LTO. The resulting binary will be larger and less performant than the standard build, but it's useful for testing changes quickly.
The `Artifacts` will display in the `log` in the Terminal.
### Build clean
To clean rust build:
```shell
pnpm clean
```
### Portable Version (Windows Only)
To package portable version after the build:
```shell
pnpm portable
```
## Contributing Your Changes ## Contributing Your Changes
Once you have made your changes: Once you have made your changes:

View File

@ -1,5 +1,5 @@
<h1 align="center"> <h1 align="center">
<img src="./src-tauri/icons/icon.png" alt="Clash" width="128" /> <img src="./src/assets/image/logo.png" alt="Clash" width="128" />
<br> <br>
Continuation of <a href="https://github.com/zzzgydi/clash-verge">Clash Verge</a> Continuation of <a href="https://github.com/zzzgydi/clash-verge">Clash Verge</a>
<br> <br>
@ -9,12 +9,6 @@
A Clash Meta GUI based on <a href="https://github.com/tauri-apps/tauri">Tauri</a>. A Clash Meta GUI based on <a href="https://github.com/tauri-apps/tauri">Tauri</a>.
</h3> </h3>
## Preview
| Dark | Light |
| -------------------------------- | --------------------------------- |
| ![预览](./docs/preview_dark.png) | ![预览](./docs/preview_light.png) |
## Install ## Install
请到发布页面下载对应的安装包:[Release page](https://github.com/clash-verge-rev/clash-verge-rev/releases)<br> 请到发布页面下载对应的安装包:[Release page](https://github.com/clash-verge-rev/clash-verge-rev/releases)<br>
@ -25,39 +19,37 @@ Supports Windows (x64/x86), Linux (x64/arm64) and macOS 10.15+ (intel/apple).
--- ---
### TG 频道: [@clash_verge_rev](https://t.me/clash_verge_re) ### TG Group: [@clash_verge_rev](https://t.me/clash_verge_rev)
## Promotion ## Promotion
[狗狗加速 —— 技术流机场 Doggygo VPN](https://verge.dginv.click/#/register?code=oaxsAGo6) [狗狗加速 —— 技术流机场 Doggygo VPN](https://狗狗加速.com)
- 高性能海外机场,免费试用,优惠套餐,解锁流媒体,全球首家支持 Hysteria 协议。 - 高性能海外机场,免费试用,优惠套餐,解锁流媒体,全球首家支持 Hysteria 协议。
- 使用 Clash Verge 专属邀请链接注册送 3 天,每天 1G 流量免费试用:[点此注册](https://verge.dginv.click/#/register?code=oaxsAGo6) - 使用 Clash Verge 专属邀请链接注册送 3 天,每天 1G 流量免费试用:https://verge.狗狗加速.com/#/register?code=oaxsAGo6
- Clash Verge 专属 8 折优惠码: verge20 (仅有 500 份) - Clash Verge 专属 8 折优惠码: verge20 (仅有 500 份)
- 优惠套餐每月仅需 15.8 元160G 流量,年付 8 折 - 优惠套餐每月仅需 15.8 元160G 流量,年付 8 折
- 海外团队,无跑路风险,高达 50% 返佣 - 海外团队,无跑路风险,高达 50% 返佣
- 集群负载均衡设计,高速专线(兼容老客户端)极低延迟无视晚高峰4K 秒开 - 集群负载均衡设计,高速专线(兼容老客户端)极低延迟无视晚高峰4K 秒开
- 全球首家 Hysteria 协议机场,现已上线更快的 `Hysteria2` 协议(Clash Verge 客户端最佳搭配) - 全球首家 Hysteria 协议机场,现已上线更快的 `Hysteria2` 协议(Clash Verge 客户端最佳搭配)
- 解锁流媒体及 ChatGPT - 解锁流媒体及 ChatGPT
- 官网:[https://狗狗加速.com](https://verge.dginv.click/#/register?code=oaxsAGo6) - 官网https://狗狗加速.com
## Features ## Features
- 基于性能强劲的 Rust 和 Tauri 2 框架 - Since the clash core has been removed. The project no longer maintains the clash core, but only the Clash Meta core.
- 内置[Clash.Meta(mihomo)](https://github.com/MetaCubeX/mihomo)内核,并支持切换 `Alpha` 版本内核。 - Profiles management and enhancement (by yaml and Javascript). [Doc](https://clash-verge-rev.github.io)
- 简洁美观的用户界面,支持自定义主题颜色、代理组/托盘图标以及 `CSS Injection` - Improved UI and supports custom theme color.
- 配置文件管理和增强Merge 和 Script配置文件语法提示。 - Built-in support [Clash.Meta(mihomo)](https://github.com/MetaCubeX/mihomo) core.
- 系统代理和守卫、`TUN(虚拟网卡)` 模式。 - System proxy setting and guard.
- 可视化节点和规则编辑
- WebDav 配置备份和同步 ## Preview
![preview](./docs/preview.gif)
### FAQ ### FAQ
Refer to [Doc FAQ Page](https://clash-verge-rev.github.io/faq/windows.html) Refer to [Doc FAQ Page](https://clash-verge-rev.github.io/faq.html)
### Donation
[捐助Clash Verge Rev的开发](https://github.com/sponsors/clash-verge-rev)
## Development ## Development

View File

@ -1,804 +1,3 @@
## v2.2.3
#### 已知问题
- 仅在Ubuntu 22.04/24.04Fedora 41 **Gnome桌面环境** 做过简单测试不保证其他其他Linux发行版可用将在未来做进一步适配和调优
- MacOS 自定义图标与速率显示推荐图标尺寸为 256x256。其他尺寸可能会导致不正常图标和速率间隙
- MacOS 下 墙贴主要为浅色Tray 图标深色时图标闪烁;彩色 Tray 速率颜色淡
- Linux 下 Clash Verge Rev 内存占用显著高于 Windows / MacOS
### 2.2.3 相对于 2.2.2
#### 修复了:
- 首页“当前代理”因为重复刷新导致的CPU占用过高的问题
- “开机自启”和“DNS覆写”开关跳动问题
- 自定义托盘图标未能应用更改
- MacOS 自定义托盘图标显示速率时图标和文本间隙过大
- MacOS 托盘速率显示不全
- Linux 在系统服务模式下无法拉起 Mihomo 内核
- 使用异步操作,避免获取系统信息和切换代理模式可能带来的崩溃
- 相同节点名称可能导致的页面渲染出错
- URL Schemes被截断的问题
- 首页流量统计卡更好的时间戳范围
- 静默启动无法触发自动轻量化计时器
#### 新增了:
- Mihomo(Meta)内核升级至 1.19.4
- Clash Verge Rev 从现在开始不再强依赖系统服务和管理权限
- 支持根据用户偏好选择Sidecar(用户空间)模式或安装服务
- 增加载入初始配置文件的错误提示,防止切换到错误的订阅配置
- 检测是否以管理员模式运行软件,如果是提示无法使用开机自启
- 代理组显示节点数量
- 统一运行模式检测支持管理员模式下开启TUN模式
- 托盘切换代理模式会根据设置自动断开之前连接
- 如订阅获取失败回退使用Clash内核代理再次尝试
#### 移除了:
- 实时保存窗口位置和大小。这个功能可能会导致窗口异常大小和位置,还需观察。
#### 优化了:
- 重构了后端内核管理逻辑,更轻量化和有效的管理内核,提高了性能和稳定性
- 前端统一刷新应用数据,优化数据获取和刷新逻辑
- 优化首页流量图表代码,调整图表文字边距
- MacOS 托盘速率更好的显示样式和更新逻辑
- 首页仅在有流量图表时显示流量图表区域
- 更新DNS默认覆写配置
- 移除测试目录,简化资源初始化逻辑
## v2.2.2
**发行代号:拓**
感谢 Tunglies 对 Verge 后端重构,性能优化做出的重大贡献!
代号释义: 本次发布在功能上的大幅扩展。新首页设计为用户带来全新交互体验DNS 覆写功能增强网络控制能力解锁测试页面助力内容访问自由度提升轻量模式提供灵活使用选择。此外macOS 应用菜单集成、sidecar 模式、诊断信息导出等新特性进一步丰富了软件的适用场景。这些新增功能显著拓宽了 Clash Verge 的功能边界,为用户提供了更强大的工具和可能性。
#### 已知问题
- 仅在Ubuntu 22.04/24.04Fedora 41 **Gnome桌面环境** 做过简单测试不保证其他其他Linux发行版可用将在未来做进一步适配和调优
### 2.2.2 相对于 2.2.1(已下架不再提供)
#### 修复了:
- 弹黑框的问题(原因是服务崩溃触发重装机制)
- MacOS进入轻量模式以后隐藏Dock图标
- 增加轻量模式缺失的tray翻译
- Linux下的窗口边框被削掉的问题
#### 新增了:
- 加强服务检测和重装逻辑
- 增强内核与服务保活机制
- 增加服务模式下的僵尸进程清理机制
- 新增当服务模式多次尝试失败后自动回退至用户空间模式
### 2.2.1 相对于 2.2.0(已下架不再提供)
#### 修复了:
1. **首页**
- 修复 Direct 模式首页无法渲染
- 修复 首页启用轻量模式导致 ClashVergeRev 从托盘退出
- 修复 系统代理标识判断不准的问题
- 修复 系统代理地址错误的问题
- 代理模式“多余的切换动画”
2. **系统**
- 修复 MacOS 无法使用快捷键粘贴/选择/复制订阅地址。
- 修复 代理端口设置同步问题。
- 修复 Linux 无法与 Mihomo 核心 和 ClashVergeRev 服务通信
3. **界面**
- 修复 连接详情卡没有跟随主题色
4. **轻量模式**
- 修复 MacOS 轻量模式下 Dock 栏图标无法隐藏。
#### 新增了:
1. **首页**
- 首页文本过长自动截断
2. **轻量模式**
- 新增托盘进入轻量模式支持
- 新增进入轻量模式快捷键支持
3. **系统**
- 在 ClashVergeRev 对 Mihomo 进行操作时,总是尝试确保两者运行
- 服务器模式下启动mihomo内核的时候查找并停止其他已经存在的内核进程防止内核假死等问题带来的通信失败
4. **托盘**
- 新增 MacOS 启用托盘速率显示时,可选隐藏托盘图标显示
---
## 2.2.0(已下架不再提供)
#### 新增功能
1. **首页**
- 新增首页功能,默认启动页面改为首页。
- 首页流量图卡片显示上传/下载名称。
- 首页支持轻量模式切换。
- 流量统计数据持久保存。
- 限制首页配置文件卡片URL长度。
2. **DNS 设置与覆写**
- 新增 DNS 覆写功能。
- 默认启用 DNS 覆写。
3. **解锁测试**
- 新增解锁测试页面。
4. **轻量模式**
- 新增轻量模式及设置。
- 添加自动轻量模式定时器。
5. **系统支持**
- Mihomo(meta)内核升级 1.19.3
- macOS 支持 CMD+W 关闭窗口。
- 新增 macOS 应用菜单。
- 添加 macOS 安装服务时候的管理员权限提示。
- 新增 sidecar(用户空间启动内核) 模式。
6. **其他**
- 增强延迟测试日志和错误处理。
- 添加诊断信息导出。
- 新增代理命令。
#### 修复
1. **系统**
- 修复 Windows 热键崩溃。
- 修复 macOS 无框标题。
- 修复 macOS 静默启动崩溃。
- 修复 macOS tray图标错位到左上角的问题。
- 修复 Windows/Linux 运行时崩溃。
- 修复 Win10 阴影和边框问题。
- 修复 升级或重装后开机自启状态检测和同步问题。
2. **构建**
- 修复构建失败问题。
#### 优化
1. **性能**
- 重构后端,巨幅性能优化。
- 优化首页组件性能。
- 优化流量图表资源使用。
- 提升代理组列表滚动性能。
- 加快应用退出速度。
- 加快进入轻量模式速度。
- 优化小数值速度更新。
- 增加请求超时至 60 秒。
- 修复代理节点选择同步。
- 优化修改verge配置性能。
2. **重构**
- 重构后端,巨幅性能优化。
- 优化定时器管理。
- 重构 MihomoManager 处理流量。
- 优化 WebSocket 连接。
3. **其他**
- 更新依赖。
- 默认 TUN 堆栈改为 gvisor。
---
## v2.1.2
**发行代号:臻**
代号释义: 千锤百炼臻至善,集性能跃升、功能拓展、交互焕新于一体,彰显持续打磨、全方位优化的迭代精神。
感谢 Tychristine 对社区群组管理做出的重大贡献!
##### 2.1.2相对2.1.1(已下架不再提供)更新了:
- 无法更新和签名验证失败的问题(该死的CDN缓存)
- 设置菜单区分Verge基本设置和高级设置
- 增加v2 Updater的更多功能和权限
- 退出Verge后Tun代理状态仍保留的问题
##### 2.1.1相对2.1.0(已下架不再提供)更新了:
- 检测所需的Clash Verge Service版本杀毒软件误报可能与此有关因为检测和安装新版本Service需管理员权限
- MacOS下支持彩色托盘图标和更好速率显示感谢Tunglies
- 文件类型判断不准导致脚本检测报错的问题
- 打开Win下的阴影(Win10因底层兼容性问题可能圆角和边框显示不太完美)
- 边框去白边
- 修复Linux下编译问题
- 修复热键无法关闭面板的问题
##### 2.1.0 - 发行代号:臻
### 功能新增
- 新增窗口状态实时监控与自动保存功能
- 增强核心配置变更时的验证与错误处理机制
- 支持通过环境变量`CLASH_VERGE_REV_IP`自定义复制IP地址
- 添加连接表列宽持久化设置与进程过滤功能
- 新增代理组首字母导航与动态滚动定位功能
- 实现连接追踪暂停/恢复功能
- 支持从托盘菜单快速切换代理配置
- 添加轻量级模式开关选项
- 允许用户自定义TUN模式增强类型和FakeIP范围
- 新增系统代理状态指示器
- 增加Alpha版本自动重命名逻辑
- 优化字母导航工具提示与防抖交互机制
### 性能优化
- 重构代理列表渲染逻辑,提升布局计算效率
- 优化代理数据更新机制采用乐观UI策略
- 改进虚拟列表渲染性能Virtuoso
- 提升主窗口Clash模式切换速度感谢Tunglies
- 加速内核关闭流程并优化管理逻辑
- 优化节点延迟刷新速率
- 改进托盘网速显示更新逻辑
- 提升配置验证错误信息的可读性
- 重构服务架构优化代码组织结构感谢Tunglies
- 优化内核启动时的配置验证流程
### 问题修复
- 修复删除节点时关联组信息残留问题
- 解决菜单切换异常与重复勾选问题
- 修正连接页流量计算错误
- 修复Windows圆角显示异常问题
- 解决控制台废弃API警告
- 修复全局热键空值导致的崩溃
- 修复Alpha版本Windows打包重命名问题
- 修复MacOS端口切换崩溃问题
- 解决Linux持续集成更新器问题
- 修复静默启动后热键失效问题
- 修正TypeScript代理组类型定义
- 修复Windows托盘图标空白问题
- 优化远程目标地址显示替换旧版IP展示
### 交互体验
- 统一多平台托盘图标点击行为
- 优化代理列表滚动流畅度
- 改进日志搜索功能与数据管理
- 重构热键管理逻辑,修复托盘冻结问题
- 优化托盘网速显示样式
- 增强字母导航工具提示的动态响应
### 国际化
- 新增配置检查多语言支持
- 添加轻量级模式多语言文本
- 完善多语言翻译内容
### 维护更新
- 将默认TUN协议栈改为gVisor
- 更新Node.js运行版本
- 移除自动生成更新器文件
- 清理废弃代码与未使用组件
- 禁用工作流自动Alpha标签更新
- 更新依赖库版本
- 添加MacOS格式转换函数专项测试
- 优化开发模式日志输出
### 安全增强
- 强化应用启动时的配置验证机制
- 改进脚本验证与异常处理流程
- 修复编译警告(移除无用导入)
---
## v2.0.3
### Notice
- !!使用出现异常的,打开设置-->配置目录 备份 后 删除所有文件 尝试是否正常!
- 历时3个月的紧密开发与严格测试稳定版2.0.0终于发布了巨量改进与性能、稳定性提升目前Clash Verge Rev已经有了比肩cfw的健壮性而且更强大易用
- 由于更改了服务安装逻辑每次更新安装需要输入系统密码卸载老版本服务和安装新版本服务以后可以丝滑使用tun(虚拟网卡)模式
### 2.0.3相对于2.0.2改进修复了:
1. 修复VLess-URL识别网络类型错误 f400f90 #2126
2. 新增系统代理绕过文本校验 c71e18e
3. 修复脚本编辑器UI显示不正确 6197249 #2267
4. 修复Shift热键无效 589324b #2278
5. 新增nushell环境变量复制 d233a84
6. 修复全局扩展脚本无法覆写DNS d22b37c #2235
7. 切换到系统代理相对于稳定的版本 38745d4
8. 修改fake-ip-range网段 0e3b631
9. 修复窗口隐藏后WebSocket未断开连接减小内存风险 b42d13f
10. 改进系统代理绕过设置 c5c840d
11. 修复i18n翻译文本缺失 b149084
12. 修复双击托盘图标打开面板 f839d3b #2346
13. 修复Windows10窗口白色边框 4f6ca40 #2425
14. 修复Windows窗口状态恢复 4f6ca40
15. 改进保存配置文件自动重启Mihomo内核 0669f7a
16. 改进更新托盘图标性能 d9291d4
17. 修复保存配置后代理列表未更新 542baf9 #2460
18. 新增MacOS托盘显示实时速率可在"界面设置"中关闭 1b2f1b6
19. 新增托盘菜单显示已设置的快捷键 eeff4d4
20. 新增重载配置文件错误响应"400"时显示更多错误信息 c5989d2 #2492
21. 修复GUI代理状态与菜单显示不一致 13b63b5 #2502
22. 新增默认语言跟随系统语言(无语言支持即为英语),添加了阿拉伯语、印尼语、鞑靼语支持 9655f77 #2940
### Features
- Meta(mihomo)内核升级 1.19.1
- 增加更多语言和托盘语言跟随
- MacOS增加状态栏速率显示
- 托盘显示快捷键
- 重载配置文件错误响应"400"时显示更多错误信息
- 改进保存配置文件自动重启Mihomo内核
### Performance
- 改进更新托盘图标性能
- 窗口隐藏后WebSocket断开连接
---
## v2.0.2
### Notice
- !!使用出现异常的,打开设置-->配置目录 备份 后 删除所有文件 尝试是否正常!
- 历时3个月的紧密开发与严格测试稳定版2.0.0终于发布了巨量改进与性能、稳定性提升目前Clash Verge Rev已经有了比肩cfw的健壮性而且更强大易用
- 由于更改了服务安装逻辑Mac/Linux 首次安装需要输入系统密码卸载和安装服务,以后可以丝滑使用 tun(虚拟网卡)模式
- 因 Tauri 2.0 底层 bug关闭窗口后保留webview进程优点是再次打开面板更快缺点是内存使用略有增加
### 2.0.2相对于2.0.1改进了:
- MacOS 下自定义图标可以支持彩色、单色切换
- 修正了 Linux 下多个内核僵尸进程的问题
- 修正了 DNS ipv6 强制覆盖的逻辑
- 修改了 MacOS tun 模式下覆盖设置 dns 字段的问题
- 修正了 MacOS tray 图标不会随代理模式更改的问题
- 静默启动下重复运行会出现多个实例的bug
- 安装的时候自动删除历史残留启动项
- Tun模式默认是还用内核推荐的 mixed 堆栈
- 改进了默认窗口大小(启动软件窗口不会那么小了)
- 改进了 WebDAV 备份超时时间机制
- 测试菜单添加滚动条
- 改进和修正了 Tun 模式下对设置的覆盖逻辑
- 修复了打开配置出错的问题
- 修复了配置文件无法拖拽添加的问题
- 改善了浅色模式的对比度
### 2.0.1相对于2.0.0改进了:
- 无法从 2.0rc和2.0.0 升级的问题已经安装了2.0版本的需手动下载安装)
- MacOS 系统下少有的无法安装服务,无法启动的问题,目前更健壮了
- 当系统中没有 yaml 编辑器的情况下,打开文件程序崩溃的问题
- Windows 应用内升级和覆盖安装不会删除老执行文件的问题
- 修改优化了 mac 下 fakeip 段和 dns
- 测试菜单 svg 图标格式检查
- 应用内升级重复安装 vs runtime 的问题
- 修复外部控制下密码有特殊字符认证出错的问题
- 修复恢复 Webdav 备份设置后, Webdav 设置丢失的问题
- 代理页面增加快速回到顶部的按钮
### Breaking changes
- 重大框架升级:使用 Tauri 2.0(巨量改进与性能提升)
- 出现 bug 到 issues 中提出以后不再接受1.x版本的bug反馈。
- 强烈建议完全删除 1.x 老版本再安装此版本 !!使用出现异常的,打开设置-->配置目录 备份 后 删除所有文件 尝试是否正常!
### Features
- Meta(mihomo)内核升级 1.18.10
- Win 下的系统代理替换为 Shadowsocks/CFW/v2rayN 等成熟的 sysproxy.exe 方案,解决拨号/VPN 环境下无法设置系统代理的问题
- 服务模式改进为启动软件时自动安装TUN 模式可自由开启不再限制于服务模式
- Mac 下可用 URL Scheme 导入订阅
- 可使用 Ctrl(cmd)+Q 快捷键退出程序
- 成功导入订阅的提示消息
- 能自动选中新导入的订阅
- 日志加入颜色区分
- 改进多处文本表述
- 加入图标 svg 格式检测
- 增加更多 app 调试日志
- 添加 MacOS 下白色桌面的 tray 黑色配色但会代理系统代理、tun 模式图标失效的问题)
- 增加 Webdav 备份功能
- 添加统一延迟的设置开关
- 添加 Windows 下自动检测并下载 vc runtime 的功能
- 支持显示 mux 和 mptcp 的节点标识
- 延迟测试连接更换 http 的 cp.cloudflare.com/generate_204 (关闭统一延迟的情况下延迟测试结果会有所增加)
- 重构日志记录逻辑可以收集和筛选所有日志类型了之前无法记录debug的日志类型
### Performance
- 优化及重构内核启动管理逻辑
- 优化 TUN 启动逻辑
- 重构和优化 app_handle
- 重构系统代理绕过逻辑
- 移除无用的 PID 创建逻辑
- 优化系统 DNS 设置逻辑
- 后端实现窗口控制
- 重构 MacOS 下的 DNS 设置逻辑
### Bugs Fixes
- 修复已有多个订阅导入新订阅会跳选订阅的问题
- 修复多个 Linux 下的 bug, Tun 模式在 Linux 下目前工作正常
- 修复 Linux wayland 下任务栏图标缺失的问题
- 修复 Linux KDE 桌面环境无法启动的问题
- 移除多余退出变量和钩子
- 修复 MacOS 下 tray 菜单重启 app 失效的问题
- 修复某些特定配置文件载入失败的问题
- 修复 MacOS 下 tun 模式 fakeip 不生效的问题
- 修复 Linux 下 关闭 tun 模式文件报错的问题
- 修复快捷键设置的相关 bug
- 修复 Win 下点左键菜单闪现的问题Mac 下的操作逻辑相反,默认情况下不管点左/右键均会打开菜单,闪现不属于 bug
### Known issues
- Windows 下窗口大小无法记忆(等待上游修复)
- Webdav 备份因为安全性和兼容性问题,暂不支持跨平台配置同步
---
## v1.7.7
### Bugs Fixes
- 修复导入订阅没有自动重载(不显示节点)的问题
- 英语状态下修复 Windows 工具栏提示文本超过限制的问题
---
## v1.7.6
### Notice
- Clash Verge Rev 目前已进入稳定周期,日后更新将着重于 bug 修复与内核常规升级
### Features
- Meta(mihomo)内核升级 1.18.7
- 界面细节调整
- 优化服务模式安装逻辑
- 移除无用的 console log
- 能自动选择第一个订阅
### Bugs Fixes
- 修复服务模式安装问题
- 修复 Mac 下的代理绕过 CIDR 写法过滤
- 修复 32 位升级 URL
- 修复不同分组 URL 测试地址配置无效的问题
- 修复 Web UI 下的一处 hostname 参数
---
## v1.7.5
### Features
- 展示局域网 IP 地址信息
- 在设置页面直接复制环境变量
- 优化服务模式安装逻辑
### Performance
- 优化切换订阅速度
- 优化更改端口速度
### Bugs Fixes
- 调整 MacOS 托盘图标大小
- Trojan URI 解析错误
- 卡片拖动显示层级错误
- 代理绕过格式检查错误
- MacOS 下编辑器最大化失败
- MacOS 服务安装失败
- 更改窗口大小导致闪退的问题
---
## v1.7.3
### Features
- 支持可视化编辑订阅代理组
- 支持可视化编辑订阅节点
- 支持可视化编辑订阅规则
- 扩展脚本支持订阅名称参数 `function main(config, profileName)`
### Bugs Fixes
- 代理绕过格式检查错误
---
## v1.7.2
### Break Changes
- 更新后请务必重新导入所有订阅,包括 Remote 和 Local
- 此版本重构了 Merge/Script更新前请先备份好自定义 Merge 和 Script更新并不会删除配置文件但是旧版 Merge 和 Script 在更新后无法从前端访问,备份以防万一)
- Merge 改名为 `扩展配置`,分为 `全局扩展配置``订阅扩展配置`,全局扩展配置对所有订阅生效,订阅扩展配置只对关联的订阅生效
- Script 改名为 `扩展脚本`,同样分为 `全局扩展脚本``订阅扩展脚本`
- 订阅扩展配置在订阅右键菜单里进入
- 执行优先级为: 全局扩展配置 -> 全局扩展脚本 -> 订阅扩展配置 ->订阅扩展脚本
- 扩展配置删除了 `prepend/append` 能力,请使用 右键订阅 -> `编辑规则`/`编辑节点`/`编辑代理组` 来代替
- MacOS 用户更新后请重新安装服务模式
### Features
- 升级内核到 1.18.6
- 移除内核授权,改为服务模式实现
- 自动填充本地订阅名称
- 添加重大更新处理逻辑
- 订阅单独指定扩展配置/脚本(需要重新导入订阅)
- 添加可视化规则编辑器(需要重新导入订阅)
- 编辑器新增工具栏按钮(格式化、最大化/最小化)
- WEBUI 使用最新版 metacubex并解决无法自动登陆问问题
- 禁用部分 Webview2 快捷键
- 热键配置新增连接符 + 号
- 新增部分悬浮提示按钮,用于解释说明
- 当日志等级为`Debug`时(更改需重启软件生效),支持点击内存主动内存回收(绿色文字)
- 设置页面右上角新增 TG 频道链接
- 各种细节优化和界面性能优化
### Bugs Fixes
- 修复代理绕过格式检查
- 通过进程名称关闭进程
- 退出软件时恢复 DNS 设置
- 修复创建本地订阅时更新间隔无法保存
- 连接页面列宽无法调整
---
## v1.7.1
### Break Changes
- 更新后请务必重新导入所有订阅,包括 Remote 和 Local
- 此版本重构了 Merge/Script更新前请先备份好自定义 Merge 和 Script更新并不会删除配置文件但是旧版 Merge 和 Script 在更新后无法从前端访问,备份以防万一)
- Merge 改名为 `扩展配置`,分为 `全局扩展配置``订阅扩展配置`,全局扩展配置对所有订阅生效,订阅扩展配置只对关联的订阅生效
- Script 改名为 `扩展脚本`,同样分为 `全局扩展脚本``订阅扩展脚本`
- 订阅扩展配置在订阅右键菜单里进入
- 执行优先级为: 全局扩展配置 -> 全局扩展脚本 -> 订阅扩展配置 ->订阅扩展脚本
- 扩展配置删除了 `prepend/append` 能力,请使用 右键订阅 -> `编辑规则`/`编辑节点`/`编辑代理组` 来代替
- MacOS 用户更新后请重新安装服务模式
### Features
- 升级内核到 1.18.6
- 移除内核授权,改为服务模式实现
- 自动填充本地订阅名称
- 添加重大更新处理逻辑
- 订阅单独指定扩展配置/脚本(需要重新导入订阅)
- 添加可视化规则编辑器(需要重新导入订阅)
- 编辑器新增工具栏按钮(格式化、最大化/最小化)
- WEBUI 使用最新版 metacubex并解决无法自动登陆问问题
- 禁用部分 Webview2 快捷键
- 热键配置新增连接符 + 号
- 新增部分悬浮提示按钮,用于解释说明
- 当日志等级为`Debug`时(更改需重启软件生效),支持点击内存主动内存回收(绿色文字)
- 设置页面右上角新增 TG 频道链接
- 各种细节优化和界面性能优化
### Bugs Fixes
- 修复代理绕过格式检查
- 通过进程名称关闭进程
- 退出软件时恢复 DNS 设置
- 修复创建本地订阅时更新间隔无法保存
- 连接页面列宽无法调整
---
## v1.7.0
### Break Changes
- 此版本重构了 Merge/Script更新前请先备份好自定义 Merge 和 Script更新并不会删除配置文件但是旧版 Merge 和 Script 在更新后无法从前端访问,备份以防万一)
- Merge 改名为 `扩展配置`,分为 `全局扩展配置``订阅扩展配置`,全局扩展配置对所有订阅生效,订阅扩展配置只对关联的订阅生效
- Script 改名为 `扩展脚本`,同样分为 `全局扩展脚本``订阅扩展脚本`
- 执行优先级为: 全局扩展配置 -> 全局扩展脚本 -> 订阅扩展配置 ->订阅扩展脚本
- MacOS 用户更新后请重新安装服务模式
### Features
- 移除内核授权,改为服务模式实现
- 自动填充本地订阅名称
- 添加重大更新处理逻辑
- 订阅单独指定扩展配置/脚本(需要重新导入订阅)
- 添加可视化规则编辑器(需要重新导入订阅)
- 编辑器新增工具栏按钮(格式化、最大化/最小化)
- WEBUI 使用最新版 metacubex并解决无法自动登陆问问题
- 禁用部分 Webview2 快捷键
- 热键配置新增连接符 + 号
- 新增部分悬浮提示按钮,用于解释说明
- 当日志等级为`Debug`时(更改需重启软件生效),支持点击内存主动内存回收(绿色文字)
- 设置页面右上角新增 TG 频道链接
### Bugs Fixes
- 修复代理绕过格式检查
- 通过进程名称关闭进程
- 退出软件时恢复 DNS 设置
- 修复创建本地订阅时更新间隔无法保存
- 连接页面列宽无法调整
---
## v1.6.6
### Features
- MacOS 应用签名
- 删除 AppImage
- 应用更新对话框添加下载按钮
- 设置系统代理绕过时保留默认值
- 系统代理绕过设置输入格式检查
### Bugs Fixes
- MacOS 代理组图标无法显示
- RPM 包依赖缺失
---
## v1.6.5
### Features
- 添加 RPM 包支持
- 优化细节
### Bugs Fixes
- MacOS 10.15 编辑器空白的问题
- MacOS 低版本启动白屏的问题
---
## v1.6.4
### Features
- 系统代理支持 PAC 模式
- 允许关闭不使用的端口
- 使用新的应用图标
- MacOS 支持切换托盘图标单色/彩色模式
- CSS 注入支持通过编辑器编辑
- 优化代理组列表性能
- 优化流量图显性能
- 支持波斯语
### Bugs Fixes
- Kill 内核后 Tun 开启缓慢的问题
- 代理绕过为空时使用默认值
- 无法读取剪切板内容
- Windows 下覆盖安装无法内核占用问题
---
## v1.6.2
### Features
- 支持本地文件拖拽导入
- 重新支持 32 位 CPU
- 新增内置 Webview2 版本
- 优化 Merge 逻辑,支持深度合并
- 删除 Merge 配置中的 append/prepend-provider 字段
- 支持更新稳定版内核
### Bugs Fixes
- MacOS DNS 还原失败
- CMD 环境变量格式错误
- Linux 下与 N 卡的兼容性问题
- 修改 Tun 设置不立即生效
---
## v1.6.1
### Features
- 鼠标悬浮显示当前订阅的名称 [#938](https://github.com/clash-verge-rev/clash-verge-rev/pull/938)
- 日志过滤支持正则表达式 [#959](https://github.com/clash-verge-rev/clash-verge-rev/pull/959)
- 更新 Clash 内核到 1.18.4
### Bugs Fixes
- 修复 Linux KDE 环境下系统代理无法开启的问题
- 窗口最大化图标调整 [#924](https://github.com/clash-verge-rev/clash-verge-rev/pull/924)
- 修改 MacOS 托盘点击行为(左键菜单,右键点击事件)
- 修复 MacOS 服务模式安装失败的问题
---
## v1.6.0
### Features
- Meta(mihomo)内核回退 1.18.1(当前新版内核 hy2 协议有 bug等修复后更新
- 多处界面细节调整 [#724](https://github.com/clash-verge-rev/clash-verge-rev/pull/724) [#799](https://github.com/clash-verge-rev/clash-verge-rev/pull/799) [#900](https://github.com/clash-verge-rev/clash-verge-rev/pull/900) [#901](https://github.com/clash-verge-rev/clash-verge-rev/pull/901)
- Linux 下新增服务模式
- 新增订阅卡片右键可以打开机场首页
- url-test 支持手动选择、节点组 fixed 节点使用角标展示 [#840](https://github.com/clash-verge-rev/clash-verge-rev/pull/840)
- Clash 配置、Merge 配置提供 JSON Schema 语法支持、连接界面调整 [#887](https://github.com/clash-verge-rev/clash-verge-rev/pull/887)
- 修改 Merge 配置文件默认内容 [#889](https://github.com/clash-verge-rev/clash-verge-rev/pull/889)
- 修改 tun 模式默认 mtu 为 1500老版本升级需在 tun 模式设置下“重置为默认值”。
- 使用 npm 安装 meta-json-schema [#895](https://github.com/clash-verge-rev/clash-verge-rev/pull/895)
- 更新部分翻译 [#904](https://github.com/clash-verge-rev/clash-verge-rev/pull/904)
- 支持 ico 格式的任务栏图标
### Bugs Fixes
- 修复 Linux KDE 环境下系统代理无法开启的问题
- 修复延迟检测动画问题
- 窗口最大化图标调整 [#816](https://github.com/clash-verge-rev/clash-verge-rev/pull/816)
- 修复 Windows 某些情况下无法安装服务模式 [#822](https://github.com/clash-verge-rev/clash-verge-rev/pull/822)
- UI 细节修复 [#821](https://github.com/clash-verge-rev/clash-verge-rev/pull/821)
- 修复使用默认编辑器打开配置文件
- 修复内核文件在特定目录也可以更新的问题 [#857](https://github.com/clash-verge-rev/clash-verge-rev/pull/857)
- 修复服务模式的安装目录问题
- 修复删除配置文件的“更新间隔”出现的问题 [#907](https://github.com/clash-verge-rev/clash-verge-rev/issues/907)
### 已知问题(历史遗留问题,暂未找到有效解决方案)
- MacOS M 芯片下服务模式无法安装;临时解决方案:在内核 ⚙️ 下,手动授权,再打开 tun 模式。
- MacOS 下如果删除过网络配置,会导致无法正常打开系统代理;临时解决方案:使用浏览器代理插件或手动配置系统代理。
- Window 拨号连接下无法正确识别并打开系统代理;临时解决方案:使用浏览器代理插件或使用 tun 模式。
---
## v1.5.11
### Features
- Meta(mihomo)内核更新 1.18.2
### Bugs Fixes
- 升级图标无法点击的问题
- 卸载时检查安装目录是否为空
- 代理界面图标重合的问题
---
## v1.5.10
### Features
- 优化 Linux 托盘菜单显示
- 添加透明代理端口设置
- 删除订阅前确认
### Bugs Fixes
- 删除 MacOS 程序坞图标
- Windows 下 service 日志没有清理
- MacOS 无法开启系统代理
---
## v1.5.9
### Features
- 缓存代理组图标
- 使用`boa_engine` 代替 `rquickjs`
- 支持 Linux armv7
### Bugs Fixes
- Windows 首次安装无法点击
- Windows 触摸屏无法拖动
- 规则列表 `REJECT-DROP` 颜色
- MacOS Dock 栏不显示图标
- MacOS 自定义字体无效
- 避免使用空 UA 拉取订阅
---
## v1.5.8
### Features
- 优化 UI 细节
- Linux 绘制窗口圆角
- 开放 DevTools
### Bugs Fixes
- 修复 MacOS 下开启 Tun 内核崩溃的问题
---
## v1.5.7 ## v1.5.7
### Features ### Features

BIN
docs/preview.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 314 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 274 KiB

View File

@ -1,113 +1,80 @@
{ {
"name": "clash-verge", "name": "clash-verge",
"version": "2.2.3", "version": "1.5.7",
"license": "GPL-3.0-only", "license": "GPL-3.0-only",
"scripts": { "scripts": {
"dev": "cross-env RUST_BACKTRACE=1 tauri dev -f verge-dev -- --profile fast-dev", "dev": "tauri dev",
"dev:diff": "cross-env RUST_BACKTRACE=1 tauri dev -f verge-dev -- --profile fast-dev", "dev:diff": "tauri dev -f verge-dev",
"build": "cross-env NODE_OPTIONS='--max-old-space-size=4096' tauri build", "build": "tauri build",
"build:fast": "cross-env NODE_OPTIONS='--max-old-space-size=4096' tauri build -- --profile fast-release",
"tauri": "tauri", "tauri": "tauri",
"web:dev": "vite", "web:dev": "vite",
"web:build": "tsc --noEmit && vite build", "web:build": "tsc && vite build",
"web:serve": "vite preview", "web:serve": "vite preview",
"check": "node scripts/check.mjs", "check": "node scripts/check.mjs",
"updater": "node scripts/updater.mjs", "updater": "node scripts/updater.mjs",
"updater-fixed-webview2": "node scripts/updater-fixed-webview2.mjs",
"portable": "node scripts/portable.mjs", "portable": "node scripts/portable.mjs",
"portable-fixed-webview2": "node scripts/portable-fixed-webview2.mjs", "prepare": "husky install"
"fix-alpha-version": "node scripts/fix-alpha_version.mjs",
"release-version": "node scripts/release_version.mjs",
"release-alpha-version": "node scripts/release-alpha_version.mjs",
"prepare": "husky",
"clippy": "cargo clippy --manifest-path ./src-tauri/Cargo.toml"
}, },
"dependencies": { "dependencies": {
"@dnd-kit/core": "^6.3.1", "@dnd-kit/core": "^6.1.0",
"@dnd-kit/sortable": "^10.0.0", "@dnd-kit/sortable": "^8.0.0",
"@dnd-kit/utilities": "^3.2.2", "@dnd-kit/utilities": "^3.2.2",
"@emotion/react": "^11.14.0", "@emotion/react": "^11.11.3",
"@emotion/styled": "^11.14.0", "@emotion/styled": "^11.11.0",
"@juggle/resize-observer": "^3.4.0", "@juggle/resize-observer": "^3.4.0",
"@mui/icons-material": "^6.4.8", "@mui/icons-material": "^5.15.5",
"@mui/lab": "6.0.0-beta.25", "@mui/lab": "5.0.0-alpha.149",
"@mui/material": "^6.4.8", "@mui/material": "^5.15.5",
"@mui/x-data-grid": "^7.28.0", "@mui/x-data-grid": "^6.18.7",
"@tauri-apps/api": "2.2.0", "@tauri-apps/api": "^1.5.3",
"@tauri-apps/plugin-clipboard-manager": "^2.2.2", "ahooks": "^3.7.8",
"@tauri-apps/plugin-dialog": "^2.2.0", "axios": "^1.6.5",
"@tauri-apps/plugin-fs": "^2.2.0", "dayjs": "1.11.5",
"@tauri-apps/plugin-global-shortcut": "^2.2.0", "i18next": "^23.7.16",
"@tauri-apps/plugin-notification": "^2.2.2",
"@tauri-apps/plugin-process": "^2.2.0",
"@tauri-apps/plugin-shell": "2.2.0",
"@tauri-apps/plugin-updater": "2.3.0",
"@types/d3-shape": "^3.1.7",
"@types/json-schema": "^7.0.15",
"ahooks": "^3.8.4",
"axios": "^1.8.3",
"cli-color": "^2.0.4",
"d3-shape": "^3.2.0",
"dayjs": "1.11.13",
"foxact": "^0.2.44",
"glob": "^11.0.1",
"i18next": "^24.2.3",
"js-base64": "^3.7.7",
"js-yaml": "^4.1.0",
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
"monaco-editor": "^0.52.2", "monaco-editor": "^0.34.1",
"monaco-yaml": "^5.3.1", "nanoid": "^5.0.4",
"nanoid": "^5.1.5", "react": "^18.2.0",
"peggy": "^4.2.0", "react-dom": "^18.2.0",
"react": "^18.3.1", "react-error-boundary": "^3.1.4",
"react-dom": "^18.3.1", "react-hook-form": "^7.49.3",
"react-error-boundary": "^4.1.2",
"react-hook-form": "^7.54.2",
"react-i18next": "^13.5.0", "react-i18next": "^13.5.0",
"react-markdown": "^9.1.0", "react-router-dom": "^6.21.2",
"react-monaco-editor": "^0.56.2",
"react-router-dom": "^6.30.0",
"react-transition-group": "^4.4.5", "react-transition-group": "^4.4.5",
"react-virtuoso": "^4.12.5", "react-virtuoso": "^4.6.2",
"recharts": "^2.15.1", "recoil": "^0.7.7",
"sockette": "^2.0.6", "snarkdown": "^2.0.0",
"swr": "^2.3.3", "swr": "^1.3.0",
"tar": "^7.4.3", "tar": "^6.2.0"
"types-pac": "^1.0.3",
"zustand": "^5.0.3"
}, },
"devDependencies": { "devDependencies": {
"@actions/github": "^6.0.0", "@actions/github": "^5.1.1",
"@tauri-apps/cli": "2.2.7", "@tauri-apps/cli": "^1.5.9",
"@types/fs-extra": "^9.0.13",
"@types/js-cookie": "^3.0.6", "@types/js-cookie": "^3.0.6",
"@types/js-yaml": "^4.0.9",
"@types/lodash-es": "^4.17.12", "@types/lodash-es": "^4.17.12",
"@types/react": "^18.3.18", "@types/react": "^18.2.48",
"@types/react-dom": "^18.3.5", "@types/react-dom": "^18.2.18",
"@types/react-transition-group": "^4.4.12", "@types/react-transition-group": "^4.4.10",
"@vitejs/plugin-legacy": "^6.0.2", "@vitejs/plugin-react": "^4.2.1",
"@vitejs/plugin-react": "^4.3.4", "adm-zip": "^0.5.10",
"adm-zip": "^0.5.16",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"https-proxy-agent": "^7.0.6", "fs-extra": "^11.2.0",
"husky": "^9.1.7", "https-proxy-agent": "^5.0.1",
"meta-json-schema": "^1.19.3", "husky": "^7.0.4",
"node-fetch": "^3.3.2", "node-fetch": "^3.3.2",
"prettier": "^3.5.3", "prettier": "^2.8.8",
"pretty-quick": "^4.1.1", "pretty-quick": "^3.3.1",
"sass": "^1.86.0", "sass": "^1.70.0",
"terser": "^5.39.0", "typescript": "^5.3.3",
"typescript": "^5.8.2", "vite": "^5.0.11",
"vite": "^6.2.2",
"vite-plugin-monaco-editor": "^1.1.0", "vite-plugin-monaco-editor": "^1.1.0",
"vite-plugin-svgr": "^4.3.0" "vite-plugin-svgr": "^4.2.0"
}, },
"prettier": { "prettier": {
"tabWidth": 2, "tabWidth": 2,
"semi": true, "semi": true,
"singleQuote": false, "singleQuote": false,
"endOfLine": "lf" "endOfLine": "lf"
}, }
"type": "module",
"packageManager": "pnpm@9.13.2"
} }

View File

@ -0,0 +1,195 @@
From 871c9a6d1ed014c93da2436a437df03734e9f76c Mon Sep 17 00:00:00 2001
From: MystiPanda <mystipanda@proton.me>
Date: Sun, 10 Dec 2023 19:47:45 +0800
Subject: [PATCH] feat: Support windows aarch64
---
.gitmodules | 3 +
src-tauri/Cargo.toml | 2 +-
src-tauri/quick-rs | 1 +
src-tauri/src/enhance/script.rs | 130 +++++++++++++++++++-------------
4 files changed, 81 insertions(+), 55 deletions(-)
create mode 100644 .gitmodules
create mode 160000 src-tauri/quick-rs
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..2eda7e4
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "src-tauri/quick-rs"]
+ path = src-tauri/quick-rs
+ url = https://github.com/clash-verge-rev/quick-rs.git
diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml
index 2f1a3be..d67f6ed 100644
--- a/src-tauri/Cargo.toml
+++ b/src-tauri/Cargo.toml
@@ -25,7 +25,6 @@ log4rs = "1"
nanoid = "0.4"
chrono = "0.4"
sysinfo = "0.30"
-rquickjs = "0.3" # 高版本不支持 Linux aarch64
serde_json = "1.0"
serde_yaml = "0.9"
once_cell = "1.18"
@@ -33,6 +32,7 @@ port_scanner = "0.1.5"
delay_timer = "0.11.5"
parking_lot = "0.12"
percent-encoding = "2.3.1"
+quick-rs = { path = "quick-rs" }
window-shadows = { version = "0.2" }
tokio = { version = "1", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }
diff --git a/src-tauri/quick-rs b/src-tauri/quick-rs
new file mode 160000
index 0000000..78277c4
--- /dev/null
+++ b/src-tauri/quick-rs
@@ -0,0 +1 @@
+Subproject commit 78277c4509c64f18c0fc5c9f2b84671de7c83343
diff --git a/src-tauri/src/enhance/script.rs b/src-tauri/src/enhance/script.rs
index 30a922f..d47dc33 100644
--- a/src-tauri/src/enhance/script.rs
+++ b/src-tauri/src/enhance/script.rs
@@ -3,61 +3,83 @@ use anyhow::Result;
use serde_yaml::Mapping;
pub fn use_script(script: String, config: Mapping) -> Result<(Mapping, Vec<(String, String)>)> {
- use rquickjs::{function::Func, Context, Runtime};
- use std::sync::{Arc, Mutex};
-
- let runtime = Runtime::new().unwrap();
- let context = Context::full(&runtime).unwrap();
- let outputs = Arc::new(Mutex::new(vec![]));
-
- let copy_outputs = outputs.clone();
- let result = context.with(|ctx| -> Result<Mapping> {
- ctx.globals().set(
- "__verge_log__",
- Func::from(move |level: String, data: String| {
- let mut out = copy_outputs.lock().unwrap();
- out.push((level, data));
- }),
- )?;
-
- ctx.eval(
- r#"var console = Object.freeze({
- log(data){__verge_log__("log",JSON.stringify(data))},
- info(data){__verge_log__("info",JSON.stringify(data))},
- error(data){__verge_log__("error",JSON.stringify(data))},
- debug(data){__verge_log__("debug",JSON.stringify(data))},
- });"#,
- )?;
-
- let config = use_lowercase(config.clone());
- let config_str = serde_json::to_string(&config)?;
-
- let code = format!(
- r#"try{{
+ use quick_rs::{context::Context, function::Function, module::Module, runtime::Runtime};
+
+ let config = use_lowercase(config.clone());
+ let config_str = serde_json::to_string(&config)?;
+
+ let runtime = Runtime::new();
+ let context = Context::from(&runtime);
+
+ let code = format!(
+ r#"
+ let output = [];
+
+ function __verge_log__(type, data) {{
+ output.push([type, data]);
+ }}
+
+ var console = Object.freeze({{
+ log(data) {{ __verge_log__("log", JSON.stringify(data)) }},
+ info(data) {{ __verge_log__("info", JSON.stringify(data)) }},
+ error(data) {{ __verge_log__("error", JSON.stringify(data)) }},
+ debug(data) {{ __verge_log__("debug", JSON.stringify(data)) }},
+ }});
+
{script};
- JSON.stringify(main({config_str})||'')
- }} catch(err) {{
- `__error_flag__ ${{err.toString()}}`
- }}"#
- );
- let result: String = ctx.eval(code.as_str())?;
- if result.starts_with("__error_flag__") {
- anyhow::bail!(result[15..].to_owned());
- }
- if result == "\"\"" {
- anyhow::bail!("main function should return object");
- }
- Ok(serde_json::from_str::<Mapping>(result.as_str())?)
- });
-
- let mut out = outputs.lock().unwrap();
- match result {
- Ok(config) => Ok((use_lowercase(config), out.to_vec())),
- Err(err) => {
- out.push(("exception".into(), err.to_string()));
- Ok((config, out.to_vec()))
- }
- }
+
+ export function _main(){{
+ try{{
+ let result = JSON.stringify(main({config_str})||"");
+ return JSON.stringify({{result, output}});
+ }} catch(err) {{
+ output.push(["exception", err.toString()]);
+ return JSON.stringify({{result: "__error__", output}});
+ }}
+ }}
+ "#
+ );
+ let value = context.eval_module(&code, "_main")?;
+ let module = Module::new(value)?;
+ let value = module.get("_main")?;
+ let function = Function::new(value)?;
+ let value = function.call(vec![])?;
+ let result = serde_json::from_str::<serde_json::Value>(&value.to_string()?)?;
+ result
+ .as_object()
+ .map(|obj| {
+ let result = obj.get("result").unwrap().as_str().unwrap();
+ let output = obj.get("output").unwrap();
+
+ let mut out = output
+ .as_array()
+ .unwrap()
+ .iter()
+ .map(|item| {
+ let item = item.as_array().unwrap();
+ (
+ item[0].as_str().unwrap().into(),
+ item[1].as_str().unwrap().into(),
+ )
+ })
+ .collect::<Vec<_>>();
+ if result.is_empty() {
+ anyhow::bail!("main function should return object");
+ }
+ if result == "__error__" {
+ return Ok((config, out.to_vec()));
+ }
+ let result = serde_json::from_str::<Mapping>(result);
+
+ match result {
+ Ok(config) => Ok((use_lowercase(config), out.to_vec())),
+ Err(err) => {
+ out.push(("exception".into(), err.to_string()));
+ Ok((config, out.to_vec()))
+ }
+ }
+ })
+ .unwrap_or_else(|| anyhow::bail!("Unknown result"))
}
#[test]
--
2.43.0.windows.1

9542
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -1,14 +1,11 @@
import fs from "fs"; import fs from "fs-extra";
import fsp from "fs/promises";
import zlib from "zlib"; import zlib from "zlib";
import { extract } from "tar"; import tar from "tar";
import path from "path"; import path from "path";
import AdmZip from "adm-zip"; import AdmZip from "adm-zip";
import fetch from "node-fetch"; import fetch from "node-fetch";
import { HttpsProxyAgent } from "https-proxy-agent"; import proxyAgent from "https-proxy-agent";
import { execSync } from "child_process"; import { execSync } from "child_process";
import { log_info, log_debug, log_error, log_success } from "./utils.mjs";
import { glob } from "glob";
const cwd = process.cwd(); const cwd = process.cwd();
const TEMP_DIR = path.join(cwd, "node_modules/.verge"); const TEMP_DIR = path.join(cwd, "node_modules/.verge");
@ -24,7 +21,6 @@ const PLATFORM_MAP = {
"i686-unknown-linux-gnu": "linux", "i686-unknown-linux-gnu": "linux",
"aarch64-unknown-linux-gnu": "linux", "aarch64-unknown-linux-gnu": "linux",
"armv7-unknown-linux-gnueabihf": "linux", "armv7-unknown-linux-gnueabihf": "linux",
"riscv64gc-unknown-linux-gnu": "linux",
"loongarch64-unknown-linux-gnu": "linux", "loongarch64-unknown-linux-gnu": "linux",
}; };
const ARCH_MAP = { const ARCH_MAP = {
@ -37,7 +33,6 @@ const ARCH_MAP = {
"i686-unknown-linux-gnu": "ia32", "i686-unknown-linux-gnu": "ia32",
"aarch64-unknown-linux-gnu": "arm64", "aarch64-unknown-linux-gnu": "arm64",
"armv7-unknown-linux-gnueabihf": "arm", "armv7-unknown-linux-gnueabihf": "arm",
"riscv64gc-unknown-linux-gnu": "riscv64",
"loongarch64-unknown-linux-gnu": "loong64", "loongarch64-unknown-linux-gnu": "loong64",
}; };
@ -64,13 +59,12 @@ const META_ALPHA_MAP = {
"win32-x64": "mihomo-windows-amd64-compatible", "win32-x64": "mihomo-windows-amd64-compatible",
"win32-ia32": "mihomo-windows-386", "win32-ia32": "mihomo-windows-386",
"win32-arm64": "mihomo-windows-arm64", "win32-arm64": "mihomo-windows-arm64",
"darwin-x64": "mihomo-darwin-amd64-compatible", "darwin-x64": "mihomo-darwin-amd64",
"darwin-arm64": "mihomo-darwin-arm64", "darwin-arm64": "mihomo-darwin-arm64",
"linux-x64": "mihomo-linux-amd64-compatible", "linux-x64": "mihomo-linux-amd64-compatible",
"linux-ia32": "mihomo-linux-386", "linux-ia32": "mihomo-linux-386",
"linux-arm64": "mihomo-linux-arm64", "linux-arm64": "mihomo-linux-arm64",
"linux-arm": "mihomo-linux-armv7", "linux-arm": "mihomo-linux-armv7",
"linux-riscv64": "mihomo-linux-riscv64",
"linux-loong64": "mihomo-linux-loong64", "linux-loong64": "mihomo-linux-loong64",
}; };
@ -85,7 +79,7 @@ async function getLatestAlphaVersion() {
process.env.https_proxy; process.env.https_proxy;
if (httpProxy) { if (httpProxy) {
options.agent = new HttpsProxyAgent(httpProxy); options.agent = proxyAgent(httpProxy);
} }
try { try {
const response = await fetch(META_ALPHA_VERSION_URL, { const response = await fetch(META_ALPHA_VERSION_URL, {
@ -94,9 +88,9 @@ async function getLatestAlphaVersion() {
}); });
let v = await response.text(); let v = await response.text();
META_ALPHA_VERSION = v.trim(); // Trim to remove extra whitespaces META_ALPHA_VERSION = v.trim(); // Trim to remove extra whitespaces
log_info(`Latest alpha version: ${META_ALPHA_VERSION}`); console.log(`Latest alpha version: ${META_ALPHA_VERSION}`);
} catch (error) { } catch (error) {
log_error("Error fetching latest alpha version:", error.message); console.error("Error fetching latest alpha version:", error.message);
process.exit(1); process.exit(1);
} }
} }
@ -111,13 +105,12 @@ const META_MAP = {
"win32-x64": "mihomo-windows-amd64-compatible", "win32-x64": "mihomo-windows-amd64-compatible",
"win32-ia32": "mihomo-windows-386", "win32-ia32": "mihomo-windows-386",
"win32-arm64": "mihomo-windows-arm64", "win32-arm64": "mihomo-windows-arm64",
"darwin-x64": "mihomo-darwin-amd64-compatible", "darwin-x64": "mihomo-darwin-amd64",
"darwin-arm64": "mihomo-darwin-arm64", "darwin-arm64": "mihomo-darwin-arm64",
"linux-x64": "mihomo-linux-amd64-compatible", "linux-x64": "mihomo-linux-amd64-compatible",
"linux-ia32": "mihomo-linux-386", "linux-ia32": "mihomo-linux-386",
"linux-arm64": "mihomo-linux-arm64", "linux-arm64": "mihomo-linux-arm64",
"linux-arm": "mihomo-linux-armv7", "linux-arm": "mihomo-linux-armv7",
"linux-riscv64": "mihomo-linux-riscv64",
"linux-loong64": "mihomo-linux-loong64", "linux-loong64": "mihomo-linux-loong64",
}; };
@ -132,7 +125,7 @@ async function getLatestReleaseVersion() {
process.env.https_proxy; process.env.https_proxy;
if (httpProxy) { if (httpProxy) {
options.agent = new HttpsProxyAgent(httpProxy); options.agent = proxyAgent(httpProxy);
} }
try { try {
const response = await fetch(META_VERSION_URL, { const response = await fetch(META_VERSION_URL, {
@ -141,9 +134,9 @@ async function getLatestReleaseVersion() {
}); });
let v = await response.text(); let v = await response.text();
META_VERSION = v.trim(); // Trim to remove extra whitespaces META_VERSION = v.trim(); // Trim to remove extra whitespaces
log_info(`Latest release version: ${META_VERSION}`); console.log(`Latest release version: ${META_VERSION}`);
} catch (error) { } catch (error) {
log_error("Error fetching latest release version:", error.message); console.error("Error fetching latest release version:", error.message);
process.exit(1); process.exit(1);
} }
} }
@ -153,13 +146,13 @@ async function getLatestReleaseVersion() {
*/ */
if (!META_MAP[`${platform}-${arch}`]) { if (!META_MAP[`${platform}-${arch}`]) {
throw new Error( throw new Error(
`clash meta alpha unsupported platform "${platform}-${arch}"`, `clash meta alpha unsupported platform "${platform}-${arch}"`
); );
} }
if (!META_ALPHA_MAP[`${platform}-${arch}`]) { if (!META_ALPHA_MAP[`${platform}-${arch}`]) {
throw new Error( throw new Error(
`clash meta alpha unsupported platform "${platform}-${arch}"`, `clash meta alpha unsupported platform "${platform}-${arch}"`
); );
} }
@ -175,8 +168,8 @@ function clashMetaAlpha() {
const zipFile = `${name}-${META_ALPHA_VERSION}.${urlExt}`; const zipFile = `${name}-${META_ALPHA_VERSION}.${urlExt}`;
return { return {
name: "verge-mihomo-alpha", name: "clash-meta-alpha",
targetFile: `verge-mihomo-alpha-${SIDECAR_HOST}${isWin ? ".exe" : ""}`, targetFile: `clash-meta-alpha-${SIDECAR_HOST}${isWin ? ".exe" : ""}`,
exeFile, exeFile,
zipFile, zipFile,
downloadURL, downloadURL,
@ -192,8 +185,8 @@ function clashMeta() {
const zipFile = `${name}-${META_VERSION}.${urlExt}`; const zipFile = `${name}-${META_VERSION}.${urlExt}`;
return { return {
name: "verge-mihomo", name: "clash-meta",
targetFile: `verge-mihomo-${SIDECAR_HOST}${isWin ? ".exe" : ""}`, targetFile: `clash-meta-${SIDECAR_HOST}${isWin ? ".exe" : ""}`,
exeFile, exeFile,
zipFile, zipFile,
downloadURL, downloadURL,
@ -208,44 +201,44 @@ async function resolveSidecar(binInfo) {
const sidecarDir = path.join(cwd, "src-tauri", "sidecar"); const sidecarDir = path.join(cwd, "src-tauri", "sidecar");
const sidecarPath = path.join(sidecarDir, targetFile); const sidecarPath = path.join(sidecarDir, targetFile);
await fsp.mkdir(sidecarDir, { recursive: true }); await fs.mkdirp(sidecarDir);
if (!FORCE && fs.existsSync(sidecarPath)) return; if (!FORCE && (await fs.pathExists(sidecarPath))) return;
const tempDir = path.join(TEMP_DIR, name); const tempDir = path.join(TEMP_DIR, name);
const tempZip = path.join(tempDir, zipFile); const tempZip = path.join(tempDir, zipFile);
const tempExe = path.join(tempDir, exeFile); const tempExe = path.join(tempDir, exeFile);
await fsp.mkdir(tempDir, { recursive: true }); await fs.mkdirp(tempDir);
try { try {
if (!fs.existsSync(tempZip)) { if (!(await fs.pathExists(tempZip))) {
await downloadFile(downloadURL, tempZip); await downloadFile(downloadURL, tempZip);
} }
if (zipFile.endsWith(".zip")) { if (zipFile.endsWith(".zip")) {
const zip = new AdmZip(tempZip); const zip = new AdmZip(tempZip);
zip.getEntries().forEach((entry) => { zip.getEntries().forEach((entry) => {
log_debug(`"${name}" entry name`, entry.entryName); console.log(`[DEBUG]: "${name}" entry name`, entry.entryName);
}); });
zip.extractAllTo(tempDir, true); zip.extractAllTo(tempDir, true);
await fsp.rename(tempExe, sidecarPath); await fs.rename(tempExe, sidecarPath);
log_success(`unzip finished: "${name}"`); console.log(`[INFO]: "${name}" unzip finished`);
} else if (zipFile.endsWith(".tgz")) { } else if (zipFile.endsWith(".tgz")) {
// tgz // tgz
await fsp.mkdir(tempDir, { recursive: true }); await fs.mkdirp(tempDir);
await extract({ await tar.extract({
cwd: tempDir, cwd: tempDir,
file: tempZip, file: tempZip,
//strip: 1, // 可能需要根据实际的 .tgz 文件结构调整 //strip: 1, // 可能需要根据实际的 .tgz 文件结构调整
}); });
const files = await fsp.readdir(tempDir); const files = await fs.readdir(tempDir);
log_debug(`"${name}" files in tempDir:`, files); console.log(`[DEBUG]: "${name}" files in tempDir:`, files);
const extractedFile = files.find((file) => file.startsWith("虚空终端-")); const extractedFile = files.find((file) => file.startsWith("虚空终端-"));
if (extractedFile) { if (extractedFile) {
const extractedFilePath = path.join(tempDir, extractedFile); const extractedFilePath = path.join(tempDir, extractedFile);
await fsp.rename(extractedFilePath, sidecarPath); await fs.rename(extractedFilePath, sidecarPath);
log_success(`"${name}" file renamed to "${sidecarPath}"`); console.log(`[INFO]: "${name}" file renamed to "${sidecarPath}"`);
execSync(`chmod 755 ${sidecarPath}`); execSync(`chmod 755 ${sidecarPath}`);
log_success(`chmod binary finished: "${name}"`); console.log(`[INFO]: "${name}" chmod binary finished`);
} else { } else {
throw new Error(`Expected file not found in ${tempDir}`); throw new Error(`Expected file not found in ${tempDir}`);
} }
@ -255,15 +248,16 @@ async function resolveSidecar(binInfo) {
const writeStream = fs.createWriteStream(sidecarPath); const writeStream = fs.createWriteStream(sidecarPath);
await new Promise((resolve, reject) => { await new Promise((resolve, reject) => {
const onError = (error) => { const onError = (error) => {
log_error(`"${name}" gz failed:`, error.message); console.error(`[ERROR]: "${name}" gz failed:`, error.message);
reject(error); reject(error);
}; };
readStream readStream
.pipe(zlib.createGunzip().on("error", onError)) .pipe(zlib.createGunzip().on("error", onError))
.pipe(writeStream) .pipe(writeStream)
.on("finish", () => { .on("finish", () => {
console.log(`[INFO]: "${name}" gunzip finished`);
execSync(`chmod 755 ${sidecarPath}`); execSync(`chmod 755 ${sidecarPath}`);
log_success(`chmod binary finished: "${name}"`); console.log(`[INFO]: "${name}" chmod binary finished`);
resolve(); resolve();
}) })
.on("error", onError); .on("error", onError);
@ -271,58 +265,35 @@ async function resolveSidecar(binInfo) {
} }
} catch (err) { } catch (err) {
// 需要删除文件 // 需要删除文件
await fsp.rm(sidecarPath, { recursive: true, force: true }); await fs.remove(sidecarPath);
throw err; throw err;
} finally { } finally {
// delete temp dir // delete temp dir
await fsp.rm(tempDir, { recursive: true, force: true }); await fs.remove(tempDir);
} }
} }
const resolveSetDnsScript = () =>
resolveResource({
file: "set_dns.sh",
localPath: path.join(cwd, "scripts/set_dns.sh"),
});
const resolveUnSetDnsScript = () =>
resolveResource({
file: "unset_dns.sh",
localPath: path.join(cwd, "scripts/unset_dns.sh"),
});
/** /**
* download the file to the resources dir * download the file to the resources dir
*/ */
async function resolveResource(binInfo) { async function resolveResource(binInfo) {
const { file, downloadURL, localPath } = binInfo; const { file, downloadURL } = binInfo;
const resDir = path.join(cwd, "src-tauri/resources"); const resDir = path.join(cwd, "src-tauri/resources");
const targetPath = path.join(resDir, file); const targetPath = path.join(resDir, file);
if (!FORCE && fs.existsSync(targetPath)) return; if (!FORCE && (await fs.pathExists(targetPath))) return;
if (downloadURL) { await fs.mkdirp(resDir);
await fsp.mkdir(resDir, { recursive: true }); await downloadFile(downloadURL, targetPath);
await downloadFile(downloadURL, targetPath);
}
if (localPath) { console.log(`[INFO]: ${file} finished`);
await fs.copyFile(localPath, targetPath, (err) => {
if (err) {
console.error("Error copying file:", err);
} else {
console.log("File was copied successfully");
}
});
log_debug(`copy file finished: "${localPath}"`);
}
log_success(`${file} finished`);
} }
/** /**
* download file and save to `path` * download file and save to `path`
*/ async function downloadFile(url, path) { */
async function downloadFile(url, path) {
const options = {}; const options = {};
const httpProxy = const httpProxy =
@ -332,7 +303,7 @@ async function resolveResource(binInfo) {
process.env.https_proxy; process.env.https_proxy;
if (httpProxy) { if (httpProxy) {
options.agent = new HttpsProxyAgent(httpProxy); options.agent = proxyAgent(httpProxy);
} }
const response = await fetch(url, { const response = await fetch(url, {
@ -341,9 +312,9 @@ async function resolveResource(binInfo) {
headers: { "Content-Type": "application/octet-stream" }, headers: { "Content-Type": "application/octet-stream" },
}); });
const buffer = await response.arrayBuffer(); const buffer = await response.arrayBuffer();
await fsp.writeFile(path, new Uint8Array(buffer)); await fs.writeFile(path, new Uint8Array(buffer));
log_success(`download finished: ${url}`); console.log(`[INFO]: download finished "${url}"`);
} }
// SimpleSC.dll // SimpleSC.dll
@ -354,111 +325,51 @@ const resolvePlugin = async () => {
const tempDir = path.join(TEMP_DIR, "SimpleSC"); const tempDir = path.join(TEMP_DIR, "SimpleSC");
const tempZip = path.join( const tempZip = path.join(
tempDir, tempDir,
"NSIS_Simple_Service_Plugin_Unicode_1.30.zip", "NSIS_Simple_Service_Plugin_Unicode_1.30.zip"
); );
const tempDll = path.join(tempDir, "SimpleSC.dll"); const tempDll = path.join(tempDir, "SimpleSC.dll");
const pluginDir = path.join(process.env.APPDATA, "Local/NSIS"); const pluginDir = path.join(process.env.APPDATA, "Local/NSIS");
const pluginPath = path.join(pluginDir, "SimpleSC.dll"); const pluginPath = path.join(pluginDir, "SimpleSC.dll");
await fsp.mkdir(pluginDir, { recursive: true }); await fs.mkdirp(pluginDir);
await fsp.mkdir(tempDir, { recursive: true }); await fs.mkdirp(tempDir);
if (!FORCE && fs.existsSync(pluginPath)) return; if (!FORCE && (await fs.pathExists(pluginPath))) return;
try { try {
if (!fs.existsSync(tempZip)) { if (!(await fs.pathExists(tempZip))) {
await downloadFile(url, tempZip); await downloadFile(url, tempZip);
} }
const zip = new AdmZip(tempZip); const zip = new AdmZip(tempZip);
zip.getEntries().forEach((entry) => { zip.getEntries().forEach((entry) => {
log_debug(`"SimpleSC" entry name`, entry.entryName); console.log(`[DEBUG]: "SimpleSC" entry name`, entry.entryName);
}); });
zip.extractAllTo(tempDir, true); zip.extractAllTo(tempDir, true);
await fsp.cp(tempDll, pluginPath, { recursive: true, force: true }); await fs.copyFile(tempDll, pluginPath);
log_success(`unzip finished: "SimpleSC"`); console.log(`[INFO]: "SimpleSC" unzip finished`);
} finally { } finally {
await fsp.rm(tempDir, { recursive: true, force: true }); await fs.remove(tempDir);
} }
}; };
// service chmod
const resolveServicePermission = async () => {
const serviceExecutables = [
"clash-verge-service*",
"install-service*",
"uninstall-service*",
];
const resDir = path.join(cwd, "src-tauri/resources");
for (let f of serviceExecutables) {
// 使用glob模块来处理通配符
const files = glob.sync(path.join(resDir, f));
for (let filePath of files) {
if (fs.existsSync(filePath)) {
execSync(`chmod 755 ${filePath}`);
log_success(`chmod finished: "${filePath}"`);
}
}
}
};
// 在 resolveResource 函数后添加新函数
async function resolveLocales() {
const srcLocalesDir = path.join(cwd, "src/locales");
const targetLocalesDir = path.join(cwd, "src-tauri/resources/locales");
try {
// 确保目标目录存在
await fsp.mkdir(targetLocalesDir, { recursive: true });
// 读取所有语言文件
const files = await fsp.readdir(srcLocalesDir);
// 复制每个文件
for (const file of files) {
const srcPath = path.join(srcLocalesDir, file);
const targetPath = path.join(targetLocalesDir, file);
await fsp.copyFile(srcPath, targetPath);
log_success(`Copied locale file: ${file}`);
}
log_success("All locale files copied successfully");
} catch (err) {
log_error("Error copying locale files:", err.message);
throw err;
}
}
/** /**
* main * main
*/ */
const SERVICE_URL = `https://github.com/clash-verge-rev/clash-verge-service/releases/download/${SIDECAR_HOST}`; const SERVICE_URL = `https://github.com/clash-verge-rev/clash-verge-service/releases/download/${SIDECAR_HOST}`;
const resolveService = () => { const resolveService = () =>
let ext = platform === "win32" ? ".exe" : "";
let suffix = platform === "linux" ? "-" + SIDECAR_HOST : "";
resolveResource({ resolveResource({
file: "clash-verge-service" + suffix + ext, file: "clash-verge-service.exe",
downloadURL: `${SERVICE_URL}/clash-verge-service${ext}`, downloadURL: `${SERVICE_URL}/clash-verge-service.exe`,
}); });
}; const resolveInstall = () =>
const resolveInstall = () => {
let ext = platform === "win32" ? ".exe" : "";
let suffix = platform === "linux" ? "-" + SIDECAR_HOST : "";
resolveResource({ resolveResource({
file: "install-service" + suffix + ext, file: "install-service.exe",
downloadURL: `${SERVICE_URL}/install-service${ext}`, downloadURL: `${SERVICE_URL}/install-service.exe`,
}); });
}; const resolveUninstall = () =>
const resolveUninstall = () => {
let ext = platform === "win32" ? ".exe" : "";
let suffix = platform === "linux" ? "-" + SIDECAR_HOST : "";
resolveResource({ resolveResource({
file: "uninstall-service" + suffix + ext, file: "uninstall-service.exe",
downloadURL: `${SERVICE_URL}/uninstall-service${ext}`, downloadURL: `${SERVICE_URL}/uninstall-service.exe`,
}); });
};
const resolveMmdb = () => const resolveMmdb = () =>
resolveResource({ resolveResource({
file: "Country.mmdb", file: "Country.mmdb",
@ -480,30 +391,24 @@ const resolveEnableLoopback = () =>
downloadURL: `https://github.com/Kuingsmile/uwp-tool/releases/download/latest/enableLoopback.exe`, downloadURL: `https://github.com/Kuingsmile/uwp-tool/releases/download/latest/enableLoopback.exe`,
}); });
const resolveWinSysproxy = () =>
resolveResource({
file: "sysproxy.exe",
downloadURL: `https://github.com/clash-verge-rev/sysproxy/releases/download/${arch}/sysproxy.exe`,
});
const tasks = [ const tasks = [
// { name: "clash", func: resolveClash, retry: 5 }, // { name: "clash", func: resolveClash, retry: 5 },
{ {
name: "verge-mihomo-alpha", name: "clash-meta-alpha",
func: () => func: () =>
getLatestAlphaVersion().then(() => resolveSidecar(clashMetaAlpha())), getLatestAlphaVersion().then(() => resolveSidecar(clashMetaAlpha())),
retry: 5, retry: 5,
}, },
{ {
name: "verge-mihomo", name: "clash-meta",
func: () => func: () =>
getLatestReleaseVersion().then(() => resolveSidecar(clashMeta())), getLatestReleaseVersion().then(() => resolveSidecar(clashMeta())),
retry: 5, retry: 5,
}, },
{ name: "plugin", func: resolvePlugin, retry: 5, winOnly: true }, { name: "plugin", func: resolvePlugin, retry: 5, winOnly: true },
{ name: "service", func: resolveService, retry: 5 }, { name: "service", func: resolveService, retry: 5, winOnly: true },
{ name: "install", func: resolveInstall, retry: 5 }, { name: "install", func: resolveInstall, retry: 5, winOnly: true },
{ name: "uninstall", func: resolveUninstall, retry: 5 }, { name: "uninstall", func: resolveUninstall, retry: 5, winOnly: true },
{ name: "mmdb", func: resolveMmdb, retry: 5 }, { name: "mmdb", func: resolveMmdb, retry: 5 },
{ name: "geosite", func: resolveGeosite, retry: 5 }, { name: "geosite", func: resolveGeosite, retry: 5 },
{ name: "geoip", func: resolveGeoIP, retry: 5 }, { name: "geoip", func: resolveGeoIP, retry: 5 },
@ -513,51 +418,19 @@ const tasks = [
retry: 5, retry: 5,
winOnly: true, winOnly: true,
}, },
{
name: "service_chmod",
func: resolveServicePermission,
retry: 5,
unixOnly: platform === "linux" || platform === "darwin",
},
{
name: "windows-sysproxy",
func: resolveWinSysproxy,
retry: 5,
winOnly: true,
},
{
name: "set_dns_script",
func: resolveSetDnsScript,
retry: 5,
macosOnly: true,
},
{
name: "unset_dns_script",
func: resolveUnSetDnsScript,
retry: 5,
macosOnly: true,
},
{
name: "locales",
func: resolveLocales,
retry: 2,
},
]; ];
async function runTask() { async function runTask() {
const task = tasks.shift(); const task = tasks.shift();
if (!task) return; if (!task) return;
if (task.unixOnly && platform === "win32") return runTask(); if (task.winOnly && process.platform !== "win32") return runTask();
if (task.winOnly && platform !== "win32") return runTask();
if (task.macosOnly && platform !== "darwin") return runTask();
if (task.linuxOnly && platform !== "linux") return runTask();
for (let i = 0; i < task.retry; i++) { for (let i = 0; i < task.retry; i++) {
try { try {
await task.func(); await task.func();
break; break;
} catch (err) { } catch (err) {
log_error(`task::${task.name} try ${i} ==`, err.message); console.error(`[ERROR]: task::${task.name} try ${i} ==`, err.message);
if (i === task.retry - 1) throw err; if (i === task.retry - 1) throw err;
} }
} }
@ -565,3 +438,4 @@ async function runTask() {
} }
runTask(); runTask();
runTask();

View File

@ -1,56 +0,0 @@
import { exec } from "child_process";
import { promisify } from "util";
import fs from "fs/promises";
import path from "path";
/**
* 为Alpha版本重命名版本号
*/
const execPromise = promisify(exec);
/**
* 标准输出HEAD hash
*/
async function getLatestCommitHash() {
try {
const { stdout } = await execPromise("git rev-parse HEAD");
const commitHash = stdout.trim();
// 格式化只截取前7位字符
const formathash = commitHash.substring(0, 7);
console.log(`Found the latest commit hash code: ${commitHash}`);
return formathash;
} catch (error) {
console.error("pnpm run fix-alpha-version ERROR", error);
}
}
/**
* @param string 传入格式化后的hash
* 将新的版本号写入文件 package.json
*/
async function updatePackageVersion(newVersion) {
// 获取内容根目录
const _dirname = process.cwd();
const packageJsonPath = path.join(_dirname, "package.json");
try {
// 读取文件
const data = await fs.readFile(packageJsonPath, "utf8");
const packageJson = JSON.parse(data);
// 获取键值替换
let result = packageJson.version.replace("alpha", newVersion);
console.log("[INFO]: Current version is: ", result);
packageJson.version = result;
// 写入版本号
await fs.writeFile(
packageJsonPath,
JSON.stringify(packageJson, null, 2),
"utf8",
);
console.log(`[INFO]: Alpha version update to: ${newVersion}`);
} catch (error) {
console.error("pnpm run fix-alpha-version ERROR", error);
}
}
const newVersion = await getLatestCommitHash();
updatePackageVersion(newVersion).catch(console.error);

View File

@ -1,103 +0,0 @@
import fs from "fs";
import fsp from "fs/promises";
import path from "path";
import AdmZip from "adm-zip";
import { createRequire } from "module";
import { getOctokit, context } from "@actions/github";
const target = process.argv.slice(2)[0];
const alpha = process.argv.slice(2)[1];
const ARCH_MAP = {
"x86_64-pc-windows-msvc": "x64",
"i686-pc-windows-msvc": "x86",
"aarch64-pc-windows-msvc": "arm64",
};
const PROCESS_MAP = {
x64: "x64",
ia32: "x86",
arm64: "arm64",
};
const arch = target ? ARCH_MAP[target] : PROCESS_MAP[process.arch];
/// Script for ci
/// 打包绿色版/便携版 (only Windows)
async function resolvePortable() {
if (process.platform !== "win32") return;
const releaseDir = target
? `./src-tauri/target/${target}/release`
: `./src-tauri/target/release`;
const configDir = path.join(releaseDir, ".config");
if (!fs.existsSync(releaseDir)) {
throw new Error("could not found the release dir");
}
await fsp.mkdir(configDir, { recursive: true });
if (!fs.existsSync(path.join(configDir, "PORTABLE"))) {
await fsp.writeFile(path.join(configDir, "PORTABLE"), "");
}
const zip = new AdmZip();
zip.addLocalFile(path.join(releaseDir, "Clash Verge.exe"));
zip.addLocalFile(path.join(releaseDir, "verge-mihomo.exe"));
zip.addLocalFile(path.join(releaseDir, "verge-mihomo-alpha.exe"));
zip.addLocalFolder(path.join(releaseDir, "resources"), "resources");
zip.addLocalFolder(
path.join(
releaseDir,
`Microsoft.WebView2.FixedVersionRuntime.109.0.1518.78.${arch}`,
),
`Microsoft.WebView2.FixedVersionRuntime.109.0.1518.78.${arch}`,
);
zip.addLocalFolder(configDir, ".config");
const require = createRequire(import.meta.url);
const packageJson = require("../package.json");
const { version } = packageJson;
const zipFile = `Clash.Verge_${version}_${arch}_fixed_webview2_portable.zip`;
zip.writeZip(zipFile);
console.log("[INFO]: create portable zip successfully");
// push release assets
if (process.env.GITHUB_TOKEN === undefined) {
throw new Error("GITHUB_TOKEN is required");
}
const options = { owner: context.repo.owner, repo: context.repo.repo };
const github = getOctokit(process.env.GITHUB_TOKEN);
const tag = alpha ? "alpha" : process.env.TAG_NAME || `v${version}`;
console.log("[INFO]: upload to ", tag);
const { data: release } = await github.rest.repos.getReleaseByTag({
...options,
tag,
});
let assets = release.assets.filter((x) => {
return x.name === zipFile;
});
if (assets.length > 0) {
let id = assets[0].id;
await github.rest.repos.deleteReleaseAsset({
...options,
asset_id: id,
});
}
console.log(release.name);
await github.rest.repos.uploadReleaseAsset({
...options,
release_id: release.id,
name: zipFile,
data: zip.toBuffer(),
});
}
resolvePortable().catch(console.error);

View File

@ -1,20 +1,17 @@
import fs from "fs"; import fs from "fs-extra";
import path from "path"; import path from "path";
import AdmZip from "adm-zip"; import AdmZip from "adm-zip";
import { createRequire } from "module"; import { createRequire } from "module";
import fsp from "fs/promises"; import { getOctokit, context } from "@actions/github";
const target = process.argv.slice(2)[0]; const target = process.argv.slice(2)[0];
const alpha = process.argv.slice(2)[1];
const ARCH_MAP = { const ARCH_MAP = {
"x86_64-pc-windows-msvc": "x64", "x86_64-pc-windows-msvc": "x64",
"aarch64-pc-windows-msvc": "arm64", "aarch64-pc-windows-msvc": "arm64",
}; };
const PROCESS_MAP = {
x64: "x64",
arm64: "arm64",
};
const arch = target ? ARCH_MAP[target] : PROCESS_MAP[process.arch];
/// Script for ci /// Script for ci
/// 打包绿色版/便携版 (only Windows) /// 打包绿色版/便携版 (only Windows)
async function resolvePortable() { async function resolvePortable() {
@ -25,28 +22,64 @@ async function resolvePortable() {
: `./src-tauri/target/release`; : `./src-tauri/target/release`;
const configDir = path.join(releaseDir, ".config"); const configDir = path.join(releaseDir, ".config");
if (!fs.existsSync(releaseDir)) { if (!(await fs.pathExists(releaseDir))) {
throw new Error("could not found the release dir"); throw new Error("could not found the release dir");
} }
await fsp.mkdir(configDir, { recursive: true }); await fs.mkdir(configDir);
if (!fs.existsSync(path.join(configDir, "PORTABLE"))) { await fs.createFile(path.join(configDir, "PORTABLE"));
await fsp.writeFile(path.join(configDir, "PORTABLE"), "");
}
const zip = new AdmZip(); const zip = new AdmZip();
zip.addLocalFile(path.join(releaseDir, "clash-verge.exe")); zip.addLocalFile(path.join(releaseDir, "Clash Verge.exe"));
zip.addLocalFile(path.join(releaseDir, "verge-mihomo.exe")); zip.addLocalFile(path.join(releaseDir, "clash-meta.exe"));
zip.addLocalFile(path.join(releaseDir, "verge-mihomo-alpha.exe")); zip.addLocalFile(path.join(releaseDir, "clash-meta-alpha.exe"));
zip.addLocalFolder(path.join(releaseDir, "resources"), "resources"); zip.addLocalFolder(path.join(releaseDir, "resources"), "resources");
zip.addLocalFolder(configDir, ".config"); zip.addLocalFolder(configDir, ".config");
const require = createRequire(import.meta.url); const require = createRequire(import.meta.url);
const packageJson = require("../package.json"); const packageJson = require("../package.json");
const { version } = packageJson; const { version } = packageJson;
const zipFile = `Clash.Verge_${version}_${arch}_portable.zip`;
const zipFile = `Clash.Verge_${version}_${ARCH_MAP[target]}_portable.zip`;
zip.writeZip(zipFile); zip.writeZip(zipFile);
console.log("[INFO]: create portable zip successfully"); console.log("[INFO]: create portable zip successfully");
// push release assets
if (process.env.GITHUB_TOKEN === undefined) {
throw new Error("GITHUB_TOKEN is required");
}
const options = { owner: context.repo.owner, repo: context.repo.repo };
const github = getOctokit(process.env.GITHUB_TOKEN);
const tag = alpha ? "alpha" : process.env.TAG_NAME || `v${version}`;
console.log("[INFO]: upload to ", tag);
const { data: release } = await github.rest.repos.getReleaseByTag({
...options,
tag,
});
let assets = release.assets.filter((x) => {
return x.name === zipFile;
});
if (assets.length > 0) {
let id = assets[0].id;
await github.rest.repos.deleteReleaseAsset({
...options,
asset_id: id,
});
}
console.log(release.name);
await github.rest.repos.uploadReleaseAsset({
...options,
release_id: release.id,
name: zipFile,
data: zip.toBuffer(),
});
} }
resolvePortable().catch(console.error); resolvePortable().catch(console.error);

View File

@ -1,96 +0,0 @@
import fs from "fs/promises";
import path from "path";
/**
* 更新 package.json 文件中的版本号
*/
async function updatePackageVersion() {
const _dirname = process.cwd();
const packageJsonPath = path.join(_dirname, "package.json");
try {
const data = await fs.readFile(packageJsonPath, "utf8");
const packageJson = JSON.parse(data);
let result = packageJson.version;
if (!result.includes("alpha")) {
result = `${result}-alpha`;
}
console.log("[INFO]: Current package.json version is: ", result);
packageJson.version = result;
await fs.writeFile(
packageJsonPath,
JSON.stringify(packageJson, null, 2),
"utf8",
);
console.log(`[INFO]: package.json version updated to: ${result}`);
} catch (error) {
console.error("Error updating package.json version:", error);
}
}
/**
* 更新 Cargo.toml 文件中的版本号
*/
async function updateCargoVersion() {
const _dirname = process.cwd();
const cargoTomlPath = path.join(_dirname, "src-tauri", "Cargo.toml");
try {
const data = await fs.readFile(cargoTomlPath, "utf8");
const lines = data.split("\n");
const updatedLines = lines.map((line) => {
if (line.startsWith("version =")) {
const versionMatch = line.match(/version\s*=\s*"([^"]+)"/);
if (versionMatch && !versionMatch[1].includes("alpha")) {
const newVersion = `${versionMatch[1]}-alpha`;
return line.replace(versionMatch[1], newVersion);
}
}
return line;
});
await fs.writeFile(cargoTomlPath, updatedLines.join("\n"), "utf8");
} catch (error) {
console.error("Error updating Cargo.toml version:", error);
}
}
/**
* 更新 tauri.conf.json 文件中的版本号
*/
async function updateTauriConfigVersion() {
const _dirname = process.cwd();
const tauriConfigPath = path.join(_dirname, "src-tauri", "tauri.conf.json");
try {
const data = await fs.readFile(tauriConfigPath, "utf8");
const tauriConfig = JSON.parse(data);
let version = tauriConfig.version;
if (!version.includes("alpha")) {
version = `${version}-alpha`;
}
console.log("[INFO]: Current tauri.conf.json version is: ", version);
tauriConfig.version = version;
await fs.writeFile(
tauriConfigPath,
JSON.stringify(tauriConfig, null, 2),
"utf8",
);
console.log(`[INFO]: tauri.conf.json version updated to: ${version}`);
} catch (error) {
console.error("Error updating tauri.conf.json version:", error);
}
}
/**
* 主函数依次更新所有文件的版本号
*/
async function main() {
await updatePackageVersion();
await updateCargoVersion();
await updateTauriConfigVersion();
}
main().catch(console.error);

View File

@ -1,197 +0,0 @@
import fs from "fs/promises";
import path from "path";
import { program } from "commander";
/**
* 验证版本号格式
* @param {string} version
* @returns {boolean}
*/
function isValidVersion(version) {
return /^v?\d+\.\d+\.\d+(-(alpha|beta|rc)(\.\d+)?)?$/i.test(version);
}
/**
* 标准化版本号确保v前缀可选
* @param {string} version
* @returns {string}
*/
function normalizeVersion(version) {
return version.startsWith("v") ? version : `v${version}`;
}
/**
* 更新 package.json 文件中的版本号
* @param {string} newVersion 新版本号
*/
async function updatePackageVersion(newVersion) {
const _dirname = process.cwd();
const packageJsonPath = path.join(_dirname, "package.json");
try {
const data = await fs.readFile(packageJsonPath, "utf8");
const packageJson = JSON.parse(data);
console.log(
"[INFO]: Current package.json version is: ",
packageJson.version,
);
packageJson.version = newVersion.startsWith("v")
? newVersion.slice(1)
: newVersion;
await fs.writeFile(
packageJsonPath,
JSON.stringify(packageJson, null, 2),
"utf8",
);
console.log(
`[INFO]: package.json version updated to: ${packageJson.version}`,
);
return packageJson.version;
} catch (error) {
console.error("Error updating package.json version:", error);
throw error;
}
}
/**
* 更新 Cargo.toml 文件中的版本号
* @param {string} newVersion 新版本号
*/
async function updateCargoVersion(newVersion) {
const _dirname = process.cwd();
const cargoTomlPath = path.join(_dirname, "src-tauri", "Cargo.toml");
try {
const data = await fs.readFile(cargoTomlPath, "utf8");
const lines = data.split("\n");
const versionWithoutV = newVersion.startsWith("v")
? newVersion.slice(1)
: newVersion;
const updatedLines = lines.map((line) => {
if (line.trim().startsWith("version =")) {
return line.replace(
/version\s*=\s*"[^"]+"/,
`version = "${versionWithoutV}"`,
);
}
return line;
});
await fs.writeFile(cargoTomlPath, updatedLines.join("\n"), "utf8");
console.log(`[INFO]: Cargo.toml version updated to: ${versionWithoutV}`);
} catch (error) {
console.error("Error updating Cargo.toml version:", error);
throw error;
}
}
/**
* 更新 tauri.conf.json 文件中的版本号
* @param {string} newVersion 新版本号
*/
async function updateTauriConfigVersion(newVersion) {
const _dirname = process.cwd();
const tauriConfigPath = path.join(_dirname, "src-tauri", "tauri.conf.json");
try {
const data = await fs.readFile(tauriConfigPath, "utf8");
const tauriConfig = JSON.parse(data);
const versionWithoutV = newVersion.startsWith("v")
? newVersion.slice(1)
: newVersion;
console.log(
"[INFO]: Current tauri.conf.json version is: ",
tauriConfig.version,
);
tauriConfig.version = versionWithoutV;
await fs.writeFile(
tauriConfigPath,
JSON.stringify(tauriConfig, null, 2),
"utf8",
);
console.log(
`[INFO]: tauri.conf.json version updated to: ${versionWithoutV}`,
);
} catch (error) {
console.error("Error updating tauri.conf.json version:", error);
throw error;
}
}
/**
* 获取当前版本号从package.json
*/
async function getCurrentVersion() {
const _dirname = process.cwd();
const packageJsonPath = path.join(_dirname, "package.json");
try {
const data = await fs.readFile(packageJsonPath, "utf8");
const packageJson = JSON.parse(data);
return packageJson.version;
} catch (error) {
console.error("Error getting current version:", error);
throw error;
}
}
/**
* 主函数更新所有文件的版本号
* @param {string} versionArg 版本参数可以是标签或完整版本号
*/
async function main(versionArg) {
if (!versionArg) {
console.error("Error: Version argument is required");
process.exit(1);
}
try {
let newVersion;
const validTags = ["alpha", "beta", "rc"];
// 判断参数是标签还是完整版本号
if (validTags.includes(versionArg.toLowerCase())) {
// 标签模式:在当前版本基础上添加标签
const currentVersion = await getCurrentVersion();
const baseVersion = currentVersion.replace(
/-(alpha|beta|rc)(\.\d+)?$/i,
"",
);
newVersion = `${baseVersion}-${versionArg.toLowerCase()}`;
} else {
// 完整版本号模式
if (!isValidVersion(versionArg)) {
console.error(
"Error: Invalid version format. Expected format: vX.X.X or vX.X.X-tag (e.g. v2.2.3 or v2.2.3-alpha)",
);
process.exit(1);
}
newVersion = normalizeVersion(versionArg);
}
console.log(`[INFO]: Updating versions to: ${newVersion}`);
await updatePackageVersion(newVersion);
await updateCargoVersion(newVersion);
await updateTauriConfigVersion(newVersion);
console.log("[SUCCESS]: All version updates completed successfully!");
} catch (error) {
console.error("[ERROR]: Failed to update versions:", error);
process.exit(1);
}
}
// Example:
// pnpm release-version 2.2.3-alpha
// 设置命令行界面
program
.name("pnpm release-version")
.description(
"Update project version numbers. Can add tag (alpha/beta/rc) or set full version (e.g. v2.2.3 or v2.2.3-alpha)",
)
.argument(
"<version>",
"version tag (alpha/beta/rc) or full version (e.g. v2.2.3 or v2.2.3-alpha)",
)
.action(main)
.parse(process.argv);

View File

@ -1,66 +0,0 @@
#!/bin/bash
# 验证IPv4地址格式
function is_valid_ipv4() {
local ip=$1
local IFS='.'
local -a octets
[[ ! $ip =~ ^([0-9]+\.){3}[0-9]+$ ]] && return 1
read -r -a octets <<<"$ip"
[ "${#octets[@]}" -ne 4 ] && return 1
for octet in "${octets[@]}"; do
if ! [[ "$octet" =~ ^[0-9]+$ ]] || ((octet < 0 || octet > 255)); then
return 1
fi
done
return 0
}
# 验证IPv6地址格式
function is_valid_ipv6() {
local ip=$1
if [[ ! $ip =~ ^([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}$ ]] &&
[[ ! $ip =~ ^(([0-9a-fA-F]{0,4}:){0,7}:|(:[0-9a-fA-F]{0,4}:){0,6}:[0-9a-fA-F]{0,4})$ ]]; then
return 1
fi
return 0
}
# 验证IP地址是否为有效的IPv4或IPv6
function is_valid_ip() {
is_valid_ipv4 "$1" || is_valid_ipv6 "$1"
}
# 检查参数
[ $# -lt 1 ] && echo "Usage: $0 <IP address>" && exit 1
! is_valid_ip "$1" && echo "$1 is not a valid IP address." && exit 1
# 获取网络接口和硬件端口
nic=$(route -n get default | grep "interface" | awk '{print $2}')
hardware_port=$(networksetup -listallhardwareports | awk -v dev="$nic" '
/Hardware Port:/{port=$0; gsub("Hardware Port: ", "", port)}
/Device: /{if ($2 == dev) {print port; exit}}
')
# 获取当前DNS设置
original_dns=$(networksetup -getdnsservers "$hardware_port")
# 检查当前DNS设置是否有效
is_valid_dns=false
for ip in $original_dns; do
ip=$(echo "$ip" | tr -d '[:space:]')
if [ -n "$ip" ] && (is_valid_ipv4 "$ip" || is_valid_ipv6 "$ip"); then
is_valid_dns=true
break
fi
done
# 更新DNS设置
if [ "$is_valid_dns" = false ]; then
echo "empty" >.original_dns.txt
else
echo "$original_dns" >.original_dns.txt
fi
networksetup -setdnsservers "$hardware_port" "$1"

View File

@ -1,20 +0,0 @@
#!/bin/bash
nic=$(route -n get default | grep "interface" | awk '{print $2}')
hardware_port=$(networksetup -listallhardwareports | awk -v dev="$nic" '
/Hardware Port:/{
port=$0; gsub("Hardware Port: ", "", port)
}
/Device: /{
if ($2 == dev) {
print port;
exit
}
}
')
if [ -f .original_dns.txt ]; then
original_dns=$(cat .original_dns.txt)
networksetup -setdnsservers "$hardware_port" $original_dns
rm -rf .original_dns.txt
fi

View File

@ -1,5 +1,4 @@
import fs from "fs"; import fs from "fs-extra";
import fsp from "fs/promises";
import path from "path"; import path from "path";
const UPDATE_LOG = "UPDATELOG.md"; const UPDATE_LOG = "UPDATELOG.md";
@ -13,11 +12,11 @@ export async function resolveUpdateLog(tag) {
const file = path.join(cwd, UPDATE_LOG); const file = path.join(cwd, UPDATE_LOG);
if (!fs.existsSync(file)) { if (!(await fs.pathExists(file))) {
throw new Error("could not found UPDATELOG.md"); throw new Error("could not found UPDATELOG.md");
} }
const data = await fsp.readFile(file, "utf-8"); const data = await fs.readFile(file).then((d) => d.toString("utf8"));
const map = {}; const map = {};
let p = ""; let p = "";
@ -43,42 +42,3 @@ export async function resolveUpdateLog(tag) {
return map[tag].join("\n").trim(); return map[tag].join("\n").trim();
} }
export async function resolveUpdateLogDefault() {
const cwd = process.cwd();
const file = path.join(cwd, UPDATE_LOG);
if (!fs.existsSync(file)) {
throw new Error("could not found UPDATELOG.md");
}
const data = await fsp.readFile(file, "utf-8");
const reTitle = /^## v[\d\.]+/;
const reEnd = /^---/;
let isCapturing = false;
let content = [];
let firstTag = "";
for (const line of data.split("\n")) {
if (reTitle.test(line) && !isCapturing) {
isCapturing = true;
firstTag = line.slice(3).trim();
continue;
}
if (isCapturing) {
if (reEnd.test(line)) {
break;
}
content.push(line);
}
}
if (!firstTag) {
throw new Error("could not found any version tag in UPDATELOG.md");
}
return content.join("\n").trim();
}

View File

@ -1,157 +0,0 @@
import fetch from "node-fetch";
import { getOctokit, context } from "@actions/github";
import { resolveUpdateLog } from "./updatelog.mjs";
const UPDATE_TAG_NAME = "updater";
const UPDATE_JSON_FILE = "update-fixed-webview2.json";
const UPDATE_JSON_PROXY = "update-fixed-webview2-proxy.json";
/// generate update.json
/// upload to update tag's release asset
async function resolveUpdater() {
if (process.env.GITHUB_TOKEN === undefined) {
throw new Error("GITHUB_TOKEN is required");
}
const options = { owner: context.repo.owner, repo: context.repo.repo };
const github = getOctokit(process.env.GITHUB_TOKEN);
const { data: tags } = await github.rest.repos.listTags({
...options,
per_page: 10,
page: 1,
});
// get the latest publish tag
const tag = tags.find((t) => t.name.startsWith("v"));
console.log(tag);
console.log();
const { data: latestRelease } = await github.rest.repos.getReleaseByTag({
...options,
tag: tag.name,
});
const updateData = {
name: tag.name,
notes: await resolveUpdateLog(tag.name), // use updatelog.md
pub_date: new Date().toISOString(),
platforms: {
"windows-x86_64": { signature: "", url: "" },
"windows-aarch64": { signature: "", url: "" },
"windows-x86": { signature: "", url: "" },
"windows-i686": { signature: "", url: "" },
},
};
const promises = latestRelease.assets.map(async (asset) => {
const { name, browser_download_url } = asset;
// win64 url
if (name.endsWith("x64_fixed_webview2-setup.nsis.zip")) {
updateData.platforms["windows-x86_64"].url = browser_download_url;
}
// win64 signature
if (name.endsWith("x64_fixed_webview2-setup.nsis.zip.sig")) {
const sig = await getSignature(browser_download_url);
updateData.platforms["windows-x86_64"].signature = sig;
}
// win32 url
if (name.endsWith("x86_fixed_webview2-setup.nsis.zip")) {
updateData.platforms["windows-x86"].url = browser_download_url;
updateData.platforms["windows-i686"].url = browser_download_url;
}
// win32 signature
if (name.endsWith("x86_fixed_webview2-setup.nsis.zip.sig")) {
const sig = await getSignature(browser_download_url);
updateData.platforms["windows-x86"].signature = sig;
updateData.platforms["windows-i686"].signature = sig;
}
// win arm url
if (name.endsWith("arm64_fixed_webview2-setup.nsis.zip")) {
updateData.platforms["windows-aarch64"].url = browser_download_url;
}
// win arm signature
if (name.endsWith("arm64_fixed_webview2-setup.nsis.zip.sig")) {
const sig = await getSignature(browser_download_url);
updateData.platforms["windows-aarch64"].signature = sig;
}
});
await Promise.allSettled(promises);
console.log(updateData);
// maybe should test the signature as well
// delete the null field
Object.entries(updateData.platforms).forEach(([key, value]) => {
if (!value.url) {
console.log(`[Error]: failed to parse release for "${key}"`);
delete updateData.platforms[key];
}
});
// 生成一个代理github的更新文件
// 使用 https://hub.fastgit.xyz/ 做github资源的加速
const updateDataNew = JSON.parse(JSON.stringify(updateData));
Object.entries(updateDataNew.platforms).forEach(([key, value]) => {
if (value.url) {
updateDataNew.platforms[key].url =
"https://download.clashverge.dev/" + value.url;
} else {
console.log(`[Error]: updateDataNew.platforms.${key} is null`);
}
});
// update the update.json
const { data: updateRelease } = await github.rest.repos.getReleaseByTag({
...options,
tag: UPDATE_TAG_NAME,
});
// delete the old assets
for (let asset of updateRelease.assets) {
if (asset.name === UPDATE_JSON_FILE) {
await github.rest.repos.deleteReleaseAsset({
...options,
asset_id: asset.id,
});
}
if (asset.name === UPDATE_JSON_PROXY) {
await github.rest.repos
.deleteReleaseAsset({ ...options, asset_id: asset.id })
.catch(console.error); // do not break the pipeline
}
}
// upload new assets
await github.rest.repos.uploadReleaseAsset({
...options,
release_id: updateRelease.id,
name: UPDATE_JSON_FILE,
data: JSON.stringify(updateData, null, 2),
});
await github.rest.repos.uploadReleaseAsset({
...options,
release_id: updateRelease.id,
name: UPDATE_JSON_PROXY,
data: JSON.stringify(updateDataNew, null, 2),
});
}
// get the signature file content
async function getSignature(url) {
const response = await fetch(url, {
method: "GET",
headers: { "Content-Type": "application/octet-stream" },
});
return response.text();
}
resolveUpdater().catch(console.error);

View File

@ -1,15 +1,10 @@
import fetch from "node-fetch"; import fetch from "node-fetch";
import { getOctokit, context } from "@actions/github"; import { getOctokit, context } from "@actions/github";
import { resolveUpdateLog, resolveUpdateLogDefault } from "./updatelog.mjs"; import { resolveUpdateLog } from "./updatelog.mjs";
// Add stable update JSON filenames
const UPDATE_TAG_NAME = "updater"; const UPDATE_TAG_NAME = "updater";
const UPDATE_JSON_FILE = "update.json"; const UPDATE_JSON_FILE = "update.json";
const UPDATE_JSON_PROXY = "update-proxy.json"; const UPDATE_JSON_PROXY = "update-proxy.json";
// Add alpha update JSON filenames
const ALPHA_TAG_NAME = "updater-alpha";
const ALPHA_UPDATE_JSON_FILE = "update.json";
const ALPHA_UPDATE_JSON_PROXY = "update-proxy.json";
/// generate update.json /// generate update.json
/// upload to update tag's release asset /// upload to update tag's release asset
@ -21,293 +16,171 @@ async function resolveUpdater() {
const options = { owner: context.repo.owner, repo: context.repo.repo }; const options = { owner: context.repo.owner, repo: context.repo.repo };
const github = getOctokit(process.env.GITHUB_TOKEN); const github = getOctokit(process.env.GITHUB_TOKEN);
// Fetch all tags using pagination const { data: tags } = await github.rest.repos.listTags({
let allTags = []; ...options,
let page = 1; per_page: 10,
const perPage = 100; page: 1,
});
while (true) { // get the latest publish tag
const { data: pageTags } = await github.rest.repos.listTags({ const tag = tags.find((t) => t.name.startsWith("v"));
...options,
per_page: perPage,
page: page,
});
allTags = allTags.concat(pageTags); console.log(tag);
// Break if we received fewer tags than requested (last page)
if (pageTags.length < perPage) {
break;
}
page++;
}
const tags = allTags;
console.log(`Retrieved ${tags.length} tags in total`);
// More flexible tag detection with regex patterns
const stableTagRegex = /^v\d+\.\d+\.\d+$/; // Matches vX.Y.Z format
// const preReleaseRegex = /^v\d+\.\d+\.\d+-(alpha|beta|rc|pre)/i; // Matches vX.Y.Z-alpha/beta/rc format
const preReleaseRegex = /^(alpha|beta|rc|pre)$/i; // Matches exact alpha/beta/rc/pre tags
// Get the latest stable tag and pre-release tag
const stableTag = tags.find((t) => stableTagRegex.test(t.name));
const preReleaseTag = tags.find((t) => preReleaseRegex.test(t.name));
console.log("All tags:", tags.map((t) => t.name).join(", "));
console.log("Stable tag:", stableTag ? stableTag.name : "None found");
console.log(
"Pre-release tag:",
preReleaseTag ? preReleaseTag.name : "None found",
);
console.log(); console.log();
// Process stable release const { data: latestRelease } = await github.rest.repos.getReleaseByTag({
if (stableTag) { ...options,
await processRelease(github, options, stableTag, false); tag: tag.name,
} });
// Process pre-release if found const updateData = {
if (preReleaseTag) { name: tag.name,
await processRelease(github, options, preReleaseTag, true); notes: await resolveUpdateLog(tag.name), // use updatelog.md
} pub_date: new Date().toISOString(),
} platforms: {
win64: { signature: "", url: "" }, // compatible with older formats
linux: { signature: "", url: "" }, // compatible with older formats
darwin: { signature: "", url: "" }, // compatible with older formats
"darwin-aarch64": { signature: "", url: "" },
"darwin-intel": { signature: "", url: "" },
"darwin-x86_64": { signature: "", url: "" },
"linux-x86_64": { signature: "", url: "" },
"linux-aarch64": { signature: "", url: "" },
"linux-armv7": { signature: "", url: "" },
"windows-x86_64": { signature: "", url: "" },
"windows-aarch64": { signature: "", url: "" },
},
};
// Process a release (stable or alpha) and generate update files const promises = latestRelease.assets.map(async (asset) => {
async function processRelease(github, options, tag, isAlpha) { const { name, browser_download_url } = asset;
if (!tag) return;
try { // win64 url
const { data: release } = await github.rest.repos.getReleaseByTag({ if (name.endsWith("x64-setup.nsis.zip")) {
...options, updateData.platforms.win64.url = browser_download_url;
tag: tag.name, updateData.platforms["windows-x86_64"].url = browser_download_url;
});
const updateData = {
name: tag.name,
notes: await resolveUpdateLog(tag.name).catch(() =>
resolveUpdateLogDefault().catch(() => "No changelog available"),
),
pub_date: new Date().toISOString(),
platforms: {
win64: { signature: "", url: "" }, // compatible with older formats
linux: { signature: "", url: "" }, // compatible with older formats
darwin: { signature: "", url: "" }, // compatible with older formats
"darwin-aarch64": { signature: "", url: "" },
"darwin-intel": { signature: "", url: "" },
"darwin-x86_64": { signature: "", url: "" },
"linux-x86_64": { signature: "", url: "" },
"linux-x86": { signature: "", url: "" },
"linux-i686": { signature: "", url: "" },
"linux-aarch64": { signature: "", url: "" },
"linux-armv7": { signature: "", url: "" },
"windows-x86_64": { signature: "", url: "" },
"windows-aarch64": { signature: "", url: "" },
"windows-x86": { signature: "", url: "" },
"windows-i686": { signature: "", url: "" },
},
};
const promises = release.assets.map(async (asset) => {
const { name, browser_download_url } = asset;
// Process all the platform URL and signature data
// win64 url
if (name.endsWith("x64-setup.exe")) {
updateData.platforms.win64.url = browser_download_url;
updateData.platforms["windows-x86_64"].url = browser_download_url;
}
// win64 signature
if (name.endsWith("x64-setup.exe.sig")) {
const sig = await getSignature(browser_download_url);
updateData.platforms.win64.signature = sig;
updateData.platforms["windows-x86_64"].signature = sig;
}
// win32 url
if (name.endsWith("x86-setup.exe")) {
updateData.platforms["windows-x86"].url = browser_download_url;
updateData.platforms["windows-i686"].url = browser_download_url;
}
// win32 signature
if (name.endsWith("x86-setup.exe.sig")) {
const sig = await getSignature(browser_download_url);
updateData.platforms["windows-x86"].signature = sig;
updateData.platforms["windows-i686"].signature = sig;
}
// win arm url
if (name.endsWith("arm64-setup.exe")) {
updateData.platforms["windows-aarch64"].url = browser_download_url;
}
// win arm signature
if (name.endsWith("arm64-setup.exe.sig")) {
const sig = await getSignature(browser_download_url);
updateData.platforms["windows-aarch64"].signature = sig;
}
// darwin url (intel)
if (name.endsWith(".app.tar.gz") && !name.includes("aarch")) {
updateData.platforms.darwin.url = browser_download_url;
updateData.platforms["darwin-intel"].url = browser_download_url;
updateData.platforms["darwin-x86_64"].url = browser_download_url;
}
// darwin signature (intel)
if (name.endsWith(".app.tar.gz.sig") && !name.includes("aarch")) {
const sig = await getSignature(browser_download_url);
updateData.platforms.darwin.signature = sig;
updateData.platforms["darwin-intel"].signature = sig;
updateData.platforms["darwin-x86_64"].signature = sig;
}
// darwin url (aarch)
if (name.endsWith("aarch64.app.tar.gz")) {
updateData.platforms["darwin-aarch64"].url = browser_download_url;
// 使linux可以检查更新
updateData.platforms.linux.url = browser_download_url;
updateData.platforms["linux-x86_64"].url = browser_download_url;
updateData.platforms["linux-x86"].url = browser_download_url;
updateData.platforms["linux-i686"].url = browser_download_url;
updateData.platforms["linux-aarch64"].url = browser_download_url;
updateData.platforms["linux-armv7"].url = browser_download_url;
}
// darwin signature (aarch)
if (name.endsWith("aarch64.app.tar.gz.sig")) {
const sig = await getSignature(browser_download_url);
updateData.platforms["darwin-aarch64"].signature = sig;
updateData.platforms.linux.signature = sig;
updateData.platforms["linux-x86_64"].signature = sig;
updateData.platforms["linux-x86"].url = browser_download_url;
updateData.platforms["linux-i686"].url = browser_download_url;
updateData.platforms["linux-aarch64"].signature = sig;
updateData.platforms["linux-armv7"].signature = sig;
}
});
await Promise.allSettled(promises);
console.log(updateData);
// maybe should test the signature as well
// delete the null field
Object.entries(updateData.platforms).forEach(([key, value]) => {
if (!value.url) {
console.log(`[Error]: failed to parse release for "${key}"`);
delete updateData.platforms[key];
}
});
// Generate a proxy update file for accelerated GitHub resources
const updateDataNew = JSON.parse(JSON.stringify(updateData));
Object.entries(updateDataNew.platforms).forEach(([key, value]) => {
if (value.url) {
updateDataNew.platforms[key].url =
"https://download.clashverge.dev/" + value.url;
} else {
console.log(`[Error]: updateDataNew.platforms.${key} is null`);
}
});
// Get the appropriate updater release based on isAlpha flag
const releaseTag = isAlpha ? ALPHA_TAG_NAME : UPDATE_TAG_NAME;
console.log(
`Processing ${isAlpha ? "alpha" : "stable"} release:`,
releaseTag,
);
try {
let updateRelease;
try {
// Try to get the existing release
const response = await github.rest.repos.getReleaseByTag({
...options,
tag: releaseTag,
});
updateRelease = response.data;
console.log(
`Found existing ${releaseTag} release with ID: ${updateRelease.id}`,
);
} catch (error) {
// If release doesn't exist, create it
if (error.status === 404) {
console.log(
`Release with tag ${releaseTag} not found, creating new release...`,
);
const createResponse = await github.rest.repos.createRelease({
...options,
tag_name: releaseTag,
name: isAlpha
? "Auto-update Alpha Channel"
: "Auto-update Stable Channel",
body: `This release contains the update information for ${isAlpha ? "alpha" : "stable"} channel.`,
prerelease: isAlpha,
});
updateRelease = createResponse.data;
console.log(
`Created new ${releaseTag} release with ID: ${updateRelease.id}`,
);
} else {
// If it's another error, throw it
throw error;
}
}
// File names based on release type
const jsonFile = isAlpha ? ALPHA_UPDATE_JSON_FILE : UPDATE_JSON_FILE;
const proxyFile = isAlpha ? ALPHA_UPDATE_JSON_PROXY : UPDATE_JSON_PROXY;
// Delete existing assets with these names
for (let asset of updateRelease.assets) {
if (asset.name === jsonFile) {
await github.rest.repos.deleteReleaseAsset({
...options,
asset_id: asset.id,
});
}
if (asset.name === proxyFile) {
await github.rest.repos
.deleteReleaseAsset({ ...options, asset_id: asset.id })
.catch(console.error); // do not break the pipeline
}
}
// Upload new assets
await github.rest.repos.uploadReleaseAsset({
...options,
release_id: updateRelease.id,
name: jsonFile,
data: JSON.stringify(updateData, null, 2),
});
await github.rest.repos.uploadReleaseAsset({
...options,
release_id: updateRelease.id,
name: proxyFile,
data: JSON.stringify(updateDataNew, null, 2),
});
console.log(
`Successfully uploaded ${isAlpha ? "alpha" : "stable"} update files to ${releaseTag}`,
);
} catch (error) {
console.error(
`Failed to process ${isAlpha ? "alpha" : "stable"} release:`,
error.message,
);
} }
} catch (error) { // win64 signature
if (error.status === 404) { if (name.endsWith("x64-setup.nsis.zip.sig")) {
console.log(`Release not found for tag: ${tag.name}, skipping...`); const sig = await getSignature(browser_download_url);
updateData.platforms.win64.signature = sig;
updateData.platforms["windows-x86_64"].signature = sig;
}
// win arm url
if (name.endsWith("arm64-setup.nsis.zip")) {
updateData.platforms["windows-aarch64"].url = browser_download_url;
}
// win arm signature
if (name.endsWith("arm64-setup.nsis.zip.sig")) {
const sig = await getSignature(browser_download_url);
updateData.platforms["windows-aarch64"].signature = sig;
}
// darwin url (intel)
if (name.endsWith(".app.tar.gz") && !name.includes("aarch")) {
updateData.platforms.darwin.url = browser_download_url;
updateData.platforms["darwin-intel"].url = browser_download_url;
updateData.platforms["darwin-x86_64"].url = browser_download_url;
}
// darwin signature (intel)
if (name.endsWith(".app.tar.gz.sig") && !name.includes("aarch")) {
const sig = await getSignature(browser_download_url);
updateData.platforms.darwin.signature = sig;
updateData.platforms["darwin-intel"].signature = sig;
updateData.platforms["darwin-x86_64"].signature = sig;
}
// darwin url (aarch)
if (name.endsWith("aarch64.app.tar.gz")) {
updateData.platforms["darwin-aarch64"].url = browser_download_url;
}
// darwin signature (aarch)
if (name.endsWith("aarch64.app.tar.gz.sig")) {
const sig = await getSignature(browser_download_url);
updateData.platforms["darwin-aarch64"].signature = sig;
}
// linux x64 url
if (name.endsWith("amd64.AppImage.tar.gz")) {
updateData.platforms.linux.url = browser_download_url;
updateData.platforms["linux-x86_64"].url = browser_download_url;
// 暂时使用x64版本的url和sig使得可以检查更新但aarch64版本还不支持构建appimage
updateData.platforms["linux-aarch64"].url = browser_download_url;
updateData.platforms["linux-armv7"].url = browser_download_url;
}
// linux x64 signature
if (name.endsWith("amd64.AppImage.tar.gz.sig")) {
const sig = await getSignature(browser_download_url);
updateData.platforms.linux.signature = sig;
updateData.platforms["linux-x86_64"].signature = sig;
// 暂时使用x64版本的url和sig使得可以检查更新但aarch64版本还不支持构建appimage
updateData.platforms["linux-aarch64"].signature = sig;
updateData.platforms["linux-armv7"].signature = sig;
}
});
await Promise.allSettled(promises);
console.log(updateData);
// maybe should test the signature as well
// delete the null field
Object.entries(updateData.platforms).forEach(([key, value]) => {
if (!value.url) {
console.log(`[Error]: failed to parse release for "${key}"`);
delete updateData.platforms[key];
}
});
// 生成一个代理github的更新文件
// 使用 https://hub.fastgit.xyz/ 做github资源的加速
const updateDataNew = JSON.parse(JSON.stringify(updateData));
Object.entries(updateDataNew.platforms).forEach(([key, value]) => {
if (value.url) {
updateDataNew.platforms[key].url =
"https://mirror.ghproxy.com/" + value.url;
} else { } else {
console.error( console.log(`[Error]: updateDataNew.platforms.${key} is null`);
`Failed to get release for tag: ${tag.name}`, }
error.message, });
);
// update the update.json
const { data: updateRelease } = await github.rest.repos.getReleaseByTag({
...options,
tag: UPDATE_TAG_NAME,
});
// delete the old assets
for (let asset of updateRelease.assets) {
if (asset.name === UPDATE_JSON_FILE) {
await github.rest.repos.deleteReleaseAsset({
...options,
asset_id: asset.id,
});
}
if (asset.name === UPDATE_JSON_PROXY) {
await github.rest.repos
.deleteReleaseAsset({ ...options, asset_id: asset.id })
.catch(console.error); // do not break the pipeline
} }
} }
// upload new assets
await github.rest.repos.uploadReleaseAsset({
...options,
release_id: updateRelease.id,
name: UPDATE_JSON_FILE,
data: JSON.stringify(updateData, null, 2),
});
await github.rest.repos.uploadReleaseAsset({
...options,
release_id: updateRelease.id,
name: UPDATE_JSON_PROXY,
data: JSON.stringify(updateDataNew, null, 2),
});
} }
// get the signature file content // get the signature file content

View File

@ -1,11 +0,0 @@
import clc from "cli-color";
export const log_success = (msg, ...optionalParams) =>
console.log(clc.green(msg), ...optionalParams);
export const log_error = (msg, ...optionalParams) =>
console.log(clc.red(msg), ...optionalParams);
export const log_info = (msg, ...optionalParams) =>
console.log(clc.bgBlue(msg), ...optionalParams);
var debugMsg = clc.xterm(245);
export const log_debug = (msg, ...optionalParams) =>
console.log(debugMsg(msg), ...optionalParams);

View File

@ -1 +0,0 @@
avoid-breaking-exported-api = true

View File

@ -1,8 +1,6 @@
# Generated by Cargo # Generated by Cargo
# will have compiled files and executables # will have compiled files and executables
/target/ /target/
gen/
WixTools WixTools
resources resources
sidecar sidecar

6671
src-tauri/Cargo.lock generated

File diff suppressed because it is too large Load Diff

118
src-tauri/Cargo.toml Executable file → Normal file
View File

@ -1,6 +1,6 @@
[package] [package]
name = "clash-verge" name = "clash-verge"
version = "2.2.3" version = "1.5.7"
description = "clash verge" description = "clash verge"
authors = ["zzzgydi", "wonfen", "MystiPanda"] authors = ["zzzgydi", "wonfen", "MystiPanda"]
license = "GPL-3.0-only" license = "GPL-3.0-only"
@ -9,85 +9,45 @@ default-run = "clash-verge"
edition = "2021" edition = "2021"
build = "build.rs" build = "build.rs"
[package.metadata.bundle]
identifier = "io.github.clash-verge-rev.clash-verge-rev"
[build-dependencies] [build-dependencies]
tauri-build = { version = "2.1.0", features = [] } tauri-build = { version = "1", features = [] }
[dependencies] [dependencies]
warp = "0.3" warp = "0.3"
anyhow = "1.0.97" which = "6.0.0"
dirs = "6.0" anyhow = "1.0"
open = "5.3" dirs = "5.0"
open = "5.0"
log = "0.4" log = "0.4"
ctrlc = "3.4"
dunce = "1.0" dunce = "1.0"
log4rs = "1" log4rs = "1"
nanoid = "0.4" nanoid = "0.4"
chrono = "0.4.40" chrono = "0.4"
sysinfo = "0.34" sysinfo = "0.30"
boa_engine = "0.20.0" rquickjs = "0.3" # 高版本不支持 Linux aarch64
serde_json = "1.0" serde_json = "1.0"
serde_yaml = "0.9" serde_yaml = "0.9"
once_cell = "1.21.3" once_cell = "1.18"
port_scanner = "0.1.5" port_scanner = "0.1.5"
delay_timer = "0.11.6" delay_timer = "0.11.5"
parking_lot = "0.12" parking_lot = "0.12"
percent-encoding = "2.3.1" percent-encoding = "2.3.1"
tokio = { version = "1.44", features = [ window-shadows = { version = "0.2" }
"rt-multi-thread", tokio = { version = "1", features = ["full"] }
"macros",
"time",
"sync",
] }
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
reqwest = { version = "0.12", features = ["json", "rustls-tls", "cookies"] } reqwest = { version = "0.11", features = ["json", "rustls-tls"] }
regex = "1.11.1" sysproxy = { git="https://github.com/zzzgydi/sysproxy-rs", branch = "main" }
sysproxy = { git = "https://github.com/clash-verge-rev/sysproxy-rs", rev = "3d748b5" } auto-launch = { git="https://github.com/zzzgydi/auto-launch", branch = "main" }
image = "0.25.6" tauri = { version = "1.5", features = [ "path-all", "protocol-asset", "dialog-open", "notification-all", "icon-png", "clipboard-all", "global-shortcut-all", "process-all", "shell-all", "system-tray", "updater", "window-all"] }
imageproc = "0.25.0"
tauri = { version = "2.4.0", features = [
"protocol-asset",
"devtools",
"tray-icon",
"image-ico",
"image-png",
] }
network-interface = { version = "2.0.1", features = ["serde"] }
tauri-plugin-shell = "2.2.0"
tauri-plugin-dialog = "2.2.0"
tauri-plugin-fs = "2.2.0"
tauri-plugin-process = "2.2.0"
tauri-plugin-clipboard-manager = "2.2.2"
tauri-plugin-deep-link = "2.2.0"
tauri-plugin-devtools = "2.0.0"
zip = "2.5.0"
reqwest_dav = "0.1.15"
aes-gcm = { version = "0.10.3", features = ["std"] }
base64 = "0.22.1"
getrandom = "0.3.2"
tokio-tungstenite = "0.26.2"
futures = "0.3"
sys-locale = "0.3.2"
async-trait = "0.1.88"
mihomo_api = { path = "src_crates/crate_mihomo_api" }
ab_glyph = "0.2.29"
tungstenite = "0.26.2"
libc = "0.2"
[target.'cfg(windows)'.dependencies] [target.'cfg(windows)'.dependencies]
runas = "=1.2.0" runas = "=1.0.0" # 高版本会返回错误 Status
deelevate = "0.2.0" deelevate = "0.2.0"
winreg = "0.55.0" winreg = "0.52.0"
[target.'cfg(target_os = "linux")'.dependencies] [target.'cfg(target_os = "linux")'.dependencies]
users = "0.11.0" #openssl
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies]
tauri-plugin-autostart = "2.2.0"
tauri-plugin-global-shortcut = "2.2.0"
tauri-plugin-updater = "2.6.1"
tauri-plugin-window-state = "2.2.1"
[features] [features]
default = ["custom-protocol"] default = ["custom-protocol"]
@ -99,39 +59,3 @@ panic = "abort"
codegen-units = 1 codegen-units = 1
lto = true lto = true
opt-level = "s" opt-level = "s"
strip = true
[profile.dev]
incremental = true
[profile.fast-release]
inherits = "release" # 继承 release 的配置
panic = "abort" # 与 release 相同
codegen-units = 256 # 增加编译单元,提升编译速度
lto = false # 禁用 LTO提升编译速度
opt-level = 0 # 禁用优化,大幅提升编译速度
debug = true # 保留调试信息
strip = false # 不剥离符号,保留调试信息
[profile.fast-dev]
inherits = "dev" # 继承 dev 的配置
codegen-units = 256 # 增加编译单元,提升编译速度
opt-level = 0 # 禁用优化,进一步提升编译速度
incremental = true # 启用增量编译
debug = true # 保留调试信息
strip = false # 不剥离符号,保留调试信息
[lib]
name = "app_lib"
crate-type = ["staticlib", "cdylib", "rlib"]
[dev-dependencies]
tempfile = "3.19.1"
[workspace]
members = ["src_crates/crate_mihomo_api"]
# [patch.crates-io]
# bitflags = { git = "https://github.com/bitflags/bitflags", rev = "2.9.0" }
# zerocopy = { git = "https://github.com/google/zerocopy", rev = "v0.8.24" }
# tungstenite = { git = "https://github.com/snapview/tungstenite-rs", rev = "v0.26.2" }

17
src-tauri/Info.plist Normal file
View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>Clash Verge</string>
<key>CFBundleURLSchemes</key>
<array>
<string>clash</string>
</array>
</dict>
</array>
</dict>
</plist>

Binary file not shown.

View File

@ -1,21 +0,0 @@
{
"identifier": "desktop-capability",
"platforms": ["macOS", "windows", "linux"],
"webviews": ["main"],
"windows": ["main"],
"permissions": [
"global-shortcut:default",
"updater:default",
"dialog:default",
"dialog:allow-ask",
"dialog:allow-message",
"updater:default",
"updater:allow-check",
"updater:allow-download-and-install",
"process:allow-restart",
"deep-link:default",
"window-state:default",
"window-state:default",
"autostart:default"
]
}

View File

@ -1,83 +0,0 @@
{
"identifier": "migrated",
"description": "permissions that were migrated from v1",
"local": true,
"windows": ["main"],
"permissions": [
"core:default",
"fs:allow-read-file",
"fs:allow-exists",
{
"identifier": "fs:scope",
"allow": ["$APPDATA/**", "$RESOURCE/../**", "**"]
},
"fs:allow-write-file",
{
"identifier": "fs:scope",
"allow": ["$APPDATA/**", "$RESOURCE/../**", "**"]
},
"fs:allow-app-read",
"fs:allow-app-read-recursive",
"fs:allow-appcache-read",
"fs:allow-appcache-read-recursive",
"fs:allow-appconfig-read",
"fs:allow-appconfig-read-recursive",
"core:window:allow-create",
"core:window:allow-center",
"core:window:allow-request-user-attention",
"core:window:allow-set-resizable",
"core:window:allow-set-maximizable",
"core:window:allow-set-minimizable",
"core:window:allow-set-closable",
"core:window:allow-set-title",
"core:window:allow-maximize",
"core:window:allow-unmaximize",
"core:window:allow-minimize",
"core:window:allow-unminimize",
"core:window:allow-show",
"core:window:allow-hide",
"core:window:allow-close",
"core:window:allow-set-decorations",
"core:window:allow-set-always-on-top",
"core:window:allow-set-content-protected",
"core:window:allow-set-size",
"core:window:allow-set-min-size",
"core:window:allow-set-max-size",
"core:window:allow-set-position",
"core:window:allow-set-fullscreen",
"core:window:allow-set-focus",
"core:window:allow-set-icon",
"core:window:allow-set-skip-taskbar",
"core:window:allow-set-cursor-grab",
"core:window:allow-set-cursor-visible",
"core:window:allow-set-cursor-icon",
"core:window:allow-set-cursor-position",
"core:window:allow-set-ignore-cursor-events",
"core:window:allow-start-dragging",
"core:window:allow-maximize",
"core:window:allow-toggle-maximize",
"core:window:allow-unmaximize",
"core:window:allow-minimize",
"core:window:allow-unminimize",
"core:window:allow-set-maximizable",
"core:window:allow-set-minimizable",
"core:webview:allow-print",
"shell:allow-execute",
"shell:allow-open",
"shell:allow-kill",
"shell:allow-spawn",
"shell:allow-stdin-write",
"dialog:allow-open",
"global-shortcut:allow-is-registered",
"global-shortcut:allow-register",
"global-shortcut:allow-register-all",
"global-shortcut:allow-unregister",
"global-shortcut:allow-unregister-all",
"process:allow-restart",
"process:allow-exit",
"clipboard-manager:allow-read-text",
"clipboard-manager:allow-write-text",
"shell:default",
"dialog:default"
]
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.6 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

View File

@ -1,4 +0,0 @@
#!/bin/bash
chmod +x /usr/bin/install-service
chmod +x /usr/bin/uninstall-service
chmod +x /usr/bin/clash-verge-service

View File

@ -1,2 +0,0 @@
#!/bin/bash
/usr/bin/uninstall-service

View File

@ -1,14 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<false/>
<key>com.apple.security.application-groups</key>
<array>
<string>io.github.clash-verge-rev.clash-verge-rev</string>
</array>
<key>com.apple.security.inherit</key>
<true/>
</dict>
</plist>

View File

@ -1,216 +0,0 @@
use super::CmdResult;
use crate::{
feat, logging,
utils::{dirs, logging::Type},
wrap_err,
};
use tauri::Manager;
/// 打开应用程序所在目录
#[tauri::command]
pub fn open_app_dir() -> CmdResult<()> {
let app_dir = wrap_err!(dirs::app_home_dir())?;
wrap_err!(open::that(app_dir))
}
/// 打开核心所在目录
#[tauri::command]
pub fn open_core_dir() -> CmdResult<()> {
let core_dir = wrap_err!(tauri::utils::platform::current_exe())?;
let core_dir = core_dir.parent().ok_or("failed to get core dir")?;
wrap_err!(open::that(core_dir))
}
/// 打开日志目录
#[tauri::command]
pub fn open_logs_dir() -> CmdResult<()> {
let log_dir = wrap_err!(dirs::app_logs_dir())?;
wrap_err!(open::that(log_dir))
}
/// 打开网页链接
#[tauri::command]
pub fn open_web_url(url: String) -> CmdResult<()> {
wrap_err!(open::that(url))
}
/// 打开/关闭开发者工具
#[tauri::command]
pub fn open_devtools(app_handle: tauri::AppHandle) {
if let Some(window) = app_handle.get_webview_window("main") {
if !window.is_devtools_open() {
window.open_devtools();
} else {
window.close_devtools();
}
}
}
/// 退出应用
#[tauri::command]
pub fn exit_app() {
feat::quit(Some(0));
}
/// 重启应用
#[tauri::command]
pub async fn restart_app() -> CmdResult<()> {
feat::restart_app();
Ok(())
}
/// 获取便携版标识
#[tauri::command]
pub fn get_portable_flag() -> CmdResult<bool> {
Ok(*dirs::PORTABLE_FLAG.get().unwrap_or(&false))
}
/// 获取应用目录
#[tauri::command]
pub fn get_app_dir() -> CmdResult<String> {
let app_home_dir = wrap_err!(dirs::app_home_dir())?
.to_string_lossy()
.to_string();
Ok(app_home_dir)
}
/// 获取当前自启动状态
#[tauri::command]
pub fn get_auto_launch_status() -> CmdResult<bool> {
use crate::core::sysopt::Sysopt;
wrap_err!(Sysopt::global().get_launch_status())
}
/// 下载图标缓存
#[tauri::command]
pub async fn download_icon_cache(url: String, name: String) -> CmdResult<String> {
let icon_cache_dir = wrap_err!(dirs::app_home_dir())?.join("icons").join("cache");
let icon_path = icon_cache_dir.join(&name);
// 如果文件已存在,直接返回路径
if icon_path.exists() {
return Ok(icon_path.to_string_lossy().to_string());
}
// 确保缓存目录存在
if !icon_cache_dir.exists() {
let _ = std::fs::create_dir_all(&icon_cache_dir);
}
// 使用临时文件名来下载
let temp_path = icon_cache_dir.join(format!("{}.downloading", &name));
// 下载文件到临时位置
let response = wrap_err!(reqwest::get(&url).await)?;
// 检查内容类型是否为图片
let content_type = response
.headers()
.get(reqwest::header::CONTENT_TYPE)
.and_then(|v| v.to_str().ok())
.unwrap_or("");
let is_image = content_type.starts_with("image/");
// 获取响应内容
let content = wrap_err!(response.bytes().await)?;
// 检查内容是否为HTML (针对CDN错误页面)
let is_html = content.len() > 15
&& (content.starts_with(b"<!DOCTYPE html")
|| content.starts_with(b"<html")
|| content.starts_with(b"<?xml"));
// 只有当内容确实是图片时才保存
if is_image && !is_html {
{
let mut file = match std::fs::File::create(&temp_path) {
Ok(file) => file,
Err(_) => {
if icon_path.exists() {
return Ok(icon_path.to_string_lossy().to_string());
} else {
return Err("Failed to create temporary file".into());
}
}
};
wrap_err!(std::io::copy(&mut content.as_ref(), &mut file))?;
}
// 再次检查目标文件是否已存在,避免重命名覆盖其他线程已完成的文件
if !icon_path.exists() {
match std::fs::rename(&temp_path, &icon_path) {
Ok(_) => {}
Err(_) => {
let _ = std::fs::remove_file(&temp_path);
if icon_path.exists() {
return Ok(icon_path.to_string_lossy().to_string());
}
}
}
} else {
let _ = std::fs::remove_file(&temp_path);
}
Ok(icon_path.to_string_lossy().to_string())
} else {
let _ = std::fs::remove_file(&temp_path);
Err(format!("下载的内容不是有效图片: {}", url))
}
}
#[derive(Debug, serde::Serialize, serde::Deserialize)]
pub struct IconInfo {
name: String,
previous_t: String,
current_t: String,
}
/// 复制图标文件
#[tauri::command]
pub fn copy_icon_file(path: String, icon_info: IconInfo) -> CmdResult<String> {
use std::{fs, path::Path};
let file_path = Path::new(&path);
let icon_dir = wrap_err!(dirs::app_home_dir())?.join("icons");
if !icon_dir.exists() {
let _ = fs::create_dir_all(&icon_dir);
}
let ext = match file_path.extension() {
Some(e) => e.to_string_lossy().to_string(),
None => "ico".to_string(),
};
let dest_path = icon_dir.join(format!(
"{0}-{1}.{ext}",
icon_info.name, icon_info.current_t
));
if file_path.exists() {
if icon_info.previous_t.trim() != "" {
fs::remove_file(
icon_dir.join(format!("{0}-{1}.png", icon_info.name, icon_info.previous_t)),
)
.unwrap_or_default();
fs::remove_file(
icon_dir.join(format!("{0}-{1}.ico", icon_info.name, icon_info.previous_t)),
)
.unwrap_or_default();
}
logging!(
info,
Type::Cmd,
true,
"Copying icon file path: {:?} -> file dist: {:?}",
path,
dest_path
);
match fs::copy(file_path, &dest_path) {
Ok(_) => Ok(dest_path.to_string_lossy().to_string()),
Err(err) => Err(err.to_string()),
}
} else {
Err("file not found".to_string())
}
}

View File

@ -1,223 +0,0 @@
use super::CmdResult;
use crate::{config::*, core::*, feat, module::mihomo::MihomoManager, wrap_err};
use serde_yaml::Mapping;
/// 复制Clash环境变量
#[tauri::command]
pub fn copy_clash_env() -> CmdResult {
feat::copy_clash_env();
Ok(())
}
/// 获取Clash信息
#[tauri::command]
pub fn get_clash_info() -> CmdResult<ClashInfo> {
Ok(Config::clash().latest().get_client_info())
}
/// 修改Clash配置
#[tauri::command]
pub async fn patch_clash_config(payload: Mapping) -> CmdResult {
wrap_err!(feat::patch_clash(payload).await)
}
/// 修改Clash模式
#[tauri::command]
pub async fn patch_clash_mode(payload: String) -> CmdResult {
feat::change_clash_mode(payload);
Ok(())
}
/// 切换Clash核心
#[tauri::command]
pub async fn change_clash_core(clash_core: String) -> CmdResult<Option<String>> {
log::info!(target: "app", "changing core to {clash_core}");
match CoreManager::global()
.change_core(Some(clash_core.clone()))
.await
{
Ok(_) => {
log::info!(target: "app", "core changed to {clash_core}");
handle::Handle::notice_message("config_core::change_success", &clash_core);
handle::Handle::refresh_clash();
Ok(None)
}
Err(err) => {
let error_msg = err.to_string();
log::error!(target: "app", "failed to change core: {error_msg}");
handle::Handle::notice_message("config_core::change_error", &error_msg);
Ok(Some(error_msg))
}
}
}
/// 重启核心
#[tauri::command]
pub async fn restart_core() -> CmdResult {
wrap_err!(CoreManager::global().restart_core().await)
}
/// 获取代理延迟
#[tauri::command]
pub async fn clash_api_get_proxy_delay(
name: String,
url: Option<String>,
timeout: i32,
) -> CmdResult<serde_json::Value> {
MihomoManager::global()
.test_proxy_delay(&name, url, timeout)
.await
}
/// 测试URL延迟
#[tauri::command]
pub async fn test_delay(url: String) -> CmdResult<u32> {
Ok(feat::test_delay(url).await.unwrap_or(10000u32))
}
/// 保存DNS配置到单独文件
#[tauri::command]
pub async fn save_dns_config(dns_config: Mapping) -> CmdResult {
use crate::utils::dirs;
use serde_yaml;
use std::fs;
// 获取DNS配置文件路径
let dns_path = dirs::app_home_dir()
.map_err(|e| e.to_string())?
.join("dns_config.yaml");
// 保存DNS配置到文件
let yaml_str = serde_yaml::to_string(&dns_config).map_err(|e| e.to_string())?;
fs::write(&dns_path, yaml_str).map_err(|e| e.to_string())?;
log::info!(target: "app", "DNS config saved to {:?}", dns_path);
Ok(())
}
/// 应用或撤销DNS配置
#[tauri::command]
pub fn apply_dns_config(apply: bool) -> CmdResult {
use crate::{
config::Config,
core::{handle, CoreManager},
utils::dirs,
};
use tauri::async_runtime;
// 使用spawn来处理异步操作
async_runtime::spawn(async move {
if apply {
// 读取DNS配置文件
let dns_path = match dirs::app_home_dir() {
Ok(path) => path.join("dns_config.yaml"),
Err(e) => {
log::error!(target: "app", "Failed to get home dir: {}", e);
return;
}
};
if !dns_path.exists() {
log::warn!(target: "app", "DNS config file not found");
return;
}
let dns_yaml = match std::fs::read_to_string(&dns_path) {
Ok(content) => content,
Err(e) => {
log::error!(target: "app", "Failed to read DNS config: {}", e);
return;
}
};
// 解析DNS配置并创建patch
let patch_config = match serde_yaml::from_str::<serde_yaml::Mapping>(&dns_yaml) {
Ok(config) => {
let mut patch = serde_yaml::Mapping::new();
patch.insert("dns".into(), config.into());
patch
}
Err(e) => {
log::error!(target: "app", "Failed to parse DNS config: {}", e);
return;
}
};
log::info!(target: "app", "Applying DNS config from file");
// 重新生成配置确保DNS配置被正确应用
// 这里不调用patch_clash以避免将DNS配置写入config.yaml
Config::runtime()
.latest()
.patch_config(patch_config.clone());
// 首先重新生成配置
if let Err(err) = Config::generate().await {
log::error!(target: "app", "Failed to regenerate config with DNS: {}", err);
return;
}
// 然后应用新配置
if let Err(err) = CoreManager::global().update_config().await {
log::error!(target: "app", "Failed to apply config with DNS: {}", err);
} else {
log::info!(target: "app", "DNS config successfully applied");
handle::Handle::refresh_clash();
}
} else {
// 当关闭DNS设置时不需要对配置进行任何修改
// 直接重新生成配置让enhance函数自动跳过DNS配置的加载
log::info!(target: "app", "DNS settings disabled, regenerating config");
// 重新生成配置
if let Err(err) = Config::generate().await {
log::error!(target: "app", "Failed to regenerate config: {}", err);
return;
}
// 应用新配置
match CoreManager::global().update_config().await {
Ok(_) => {
log::info!(target: "app", "Config regenerated successfully");
handle::Handle::refresh_clash();
}
Err(err) => {
log::error!(target: "app", "Failed to apply regenerated config: {}", err);
}
}
}
});
Ok(())
}
/// 检查DNS配置文件是否存在
#[tauri::command]
pub fn check_dns_config_exists() -> CmdResult<bool> {
use crate::utils::dirs;
let dns_path = dirs::app_home_dir()
.map_err(|e| e.to_string())?
.join("dns_config.yaml");
Ok(dns_path.exists())
}
/// 获取DNS配置文件内容
#[tauri::command]
pub async fn get_dns_config_content() -> CmdResult<String> {
use crate::utils::dirs;
use std::fs;
let dns_path = dirs::app_home_dir()
.map_err(|e| e.to_string())?
.join("dns_config.yaml");
if !dns_path.exists() {
return Err("DNS config file not found".into());
}
let content = fs::read_to_string(&dns_path).map_err(|e| e.to_string())?;
Ok(content)
}

View File

@ -1,9 +0,0 @@
use crate::module::lightweight;
use super::CmdResult;
#[tauri::command]
pub async fn entry_lightweight_mode() -> CmdResult {
lightweight::entry_lightweight_mode();
Ok(())
}

File diff suppressed because it is too large Load Diff

View File

@ -1,38 +0,0 @@
use anyhow::Result;
// Common result type used by command functions
pub type CmdResult<T = ()> = Result<T, String>;
// Command modules
pub mod app;
pub mod clash;
pub mod lightweight;
pub mod media_unlock_checker;
pub mod network;
pub mod profile;
pub mod proxy;
pub mod runtime;
pub mod save_profile;
pub mod service;
pub mod system;
pub mod uwp;
pub mod validate;
pub mod verge;
pub mod webdav;
// Re-export all command functions for backwards compatibility
pub use app::*;
pub use clash::*;
pub use lightweight::*;
pub use media_unlock_checker::*;
pub use network::*;
pub use profile::*;
pub use proxy::*;
pub use runtime::*;
pub use save_profile::*;
pub use service::*;
pub use system::*;
pub use uwp::*;
pub use validate::*;
pub use verge::*;
pub use webdav::*;

View File

@ -1,63 +0,0 @@
use super::CmdResult;
use crate::wrap_err;
use network_interface::NetworkInterface;
use serde_yaml::Mapping;
use sysproxy::{Autoproxy, Sysproxy};
/// get the system proxy
#[tauri::command]
pub fn get_sys_proxy() -> CmdResult<Mapping> {
let current = wrap_err!(Sysproxy::get_system_proxy())?;
let mut map = Mapping::new();
map.insert("enable".into(), current.enable.into());
map.insert(
"server".into(),
format!("{}:{}", current.host, current.port).into(),
);
map.insert("bypass".into(), current.bypass.into());
Ok(map)
}
/// get the system proxy
#[tauri::command]
pub fn get_auto_proxy() -> CmdResult<Mapping> {
let current = wrap_err!(Autoproxy::get_auto_proxy())?;
let mut map = Mapping::new();
map.insert("enable".into(), current.enable.into());
map.insert("url".into(), current.url.into());
Ok(map)
}
/// 获取网络接口列表
#[tauri::command]
pub fn get_network_interfaces() -> Vec<String> {
use sysinfo::Networks;
let mut result = Vec::new();
let networks = Networks::new_with_refreshed_list();
for (interface_name, _) in &networks {
result.push(interface_name.clone());
}
result
}
/// 获取网络接口详细信息
#[tauri::command]
pub fn get_network_interfaces_info() -> CmdResult<Vec<NetworkInterface>> {
use network_interface::{NetworkInterface, NetworkInterfaceConfig};
let names = get_network_interfaces();
let interfaces = wrap_err!(NetworkInterface::show())?;
let mut result = Vec::new();
for interface in interfaces {
if names.contains(&interface.name) {
result.push(interface);
}
}
Ok(result)
}

View File

@ -1,244 +0,0 @@
use super::CmdResult;
use crate::{
config::{Config, IProfiles, PrfItem, PrfOption},
core::{handle, tray::Tray, CoreManager},
feat, logging, ret_err,
utils::{dirs, help, logging::Type},
wrap_err,
};
/// 获取配置文件列表
#[tauri::command]
pub fn get_profiles() -> CmdResult<IProfiles> {
let _ = Tray::global().update_menu();
Ok(Config::profiles().data().clone())
}
/// 增强配置文件
#[tauri::command]
pub async fn enhance_profiles() -> CmdResult {
wrap_err!(feat::enhance_profiles().await)?;
handle::Handle::refresh_clash();
Ok(())
}
/// 导入配置文件
#[tauri::command]
pub async fn import_profile(url: String, option: Option<PrfOption>) -> CmdResult {
let item = wrap_err!(PrfItem::from_url(&url, None, None, option).await)?;
wrap_err!(Config::profiles().data().append_item(item))
}
/// 重新排序配置文件
#[tauri::command]
pub async fn reorder_profile(active_id: String, over_id: String) -> CmdResult {
wrap_err!(Config::profiles().data().reorder(active_id, over_id))
}
/// 创建配置文件
#[tauri::command]
pub async fn create_profile(item: PrfItem, file_data: Option<String>) -> CmdResult {
let item = wrap_err!(PrfItem::from(item, file_data).await)?;
wrap_err!(Config::profiles().data().append_item(item))
}
/// 更新配置文件
#[tauri::command]
pub async fn update_profile(index: String, option: Option<PrfOption>) -> CmdResult {
wrap_err!(feat::update_profile(index, option).await)
}
/// 删除配置文件
#[tauri::command]
pub async fn delete_profile(index: String) -> CmdResult {
let should_update = wrap_err!({ Config::profiles().data().delete_item(index) })?;
if should_update {
wrap_err!(CoreManager::global().update_config().await)?;
handle::Handle::refresh_clash();
}
Ok(())
}
/// 修改profiles的配置
#[tauri::command]
pub async fn patch_profiles_config(profiles: IProfiles) -> CmdResult<bool> {
logging!(info, Type::Cmd, true, "开始修改配置文件");
// 保存当前配置,以便在验证失败时恢复
let current_profile = Config::profiles().latest().current.clone();
logging!(info, Type::Cmd, true, "当前配置: {:?}", current_profile);
// 如果要切换配置,先检查目标配置文件是否有语法错误
if let Some(new_profile) = profiles.current.as_ref() {
if current_profile.as_ref() != Some(new_profile) {
logging!(info, Type::Cmd, true, "正在切换到新配置: {}", new_profile);
// 获取目标配置文件路径
let profiles_config = Config::profiles();
let profiles_data = profiles_config.latest();
let config_file_result = match profiles_data.get_item(new_profile) {
Ok(item) => {
if let Some(file) = &item.file {
let path = dirs::app_profiles_dir().map(|dir| dir.join(file));
path.ok()
} else {
None
}
}
Err(e) => {
logging!(error, Type::Cmd, true, "获取目标配置信息失败: {}", e);
None
}
};
// 如果获取到文件路径检查YAML语法
if let Some(file_path) = config_file_result {
if !file_path.exists() {
logging!(
error,
Type::Cmd,
true,
"目标配置文件不存在: {}",
file_path.display()
);
handle::Handle::notice_message(
"config_validate::file_not_found",
format!("{}", file_path.display()),
);
return Ok(false);
}
match std::fs::read_to_string(&file_path) {
Ok(content) => match serde_yaml::from_str::<serde_yaml::Value>(&content) {
Ok(_) => {
logging!(info, Type::Cmd, true, "目标配置文件语法正确");
}
Err(err) => {
let error_msg = format!(" {}", err);
logging!(
error,
Type::Cmd,
true,
"目标配置文件存在YAML语法错误:{}",
error_msg
);
handle::Handle::notice_message(
"config_validate::yaml_syntax_error",
&error_msg,
);
return Ok(false);
}
},
Err(err) => {
let error_msg = format!("无法读取目标配置文件: {}", err);
logging!(error, Type::Cmd, true, "{}", error_msg);
handle::Handle::notice_message(
"config_validate::file_read_error",
&error_msg,
);
return Ok(false);
}
}
}
}
}
// 更新profiles配置
logging!(info, Type::Cmd, true, "正在更新配置草稿");
let _ = Config::profiles().draft().patch_config(profiles);
// 更新配置并进行验证
match CoreManager::global().update_config().await {
Ok((true, _)) => {
logging!(info, Type::Cmd, true, "配置更新成功");
handle::Handle::refresh_clash();
let _ = Tray::global().update_tooltip();
Config::profiles().apply();
wrap_err!(Config::profiles().data().save_file())?;
Ok(true)
}
Ok((false, error_msg)) => {
logging!(warn, Type::Cmd, true, "配置验证失败: {}", error_msg);
Config::profiles().discard();
// 如果验证失败,恢复到之前的配置
if let Some(prev_profile) = current_profile {
logging!(
info,
Type::Cmd,
true,
"尝试恢复到之前的配置: {}",
prev_profile
);
let restore_profiles = IProfiles {
current: Some(prev_profile),
items: None,
};
// 静默恢复,不触发验证
wrap_err!({ Config::profiles().draft().patch_config(restore_profiles) })?;
Config::profiles().apply();
wrap_err!(Config::profiles().data().save_file())?;
logging!(info, Type::Cmd, true, "成功恢复到之前的配置");
}
// 发送验证错误通知
handle::Handle::notice_message("config_validate::error", &error_msg);
Ok(false)
}
Err(e) => {
logging!(warn, Type::Cmd, true, "更新过程发生错误: {}", e);
Config::profiles().discard();
handle::Handle::notice_message("config_validate::boot_error", e.to_string());
Ok(false)
}
}
}
/// 根据profile name修改profiles
#[tauri::command]
pub async fn patch_profiles_config_by_profile_index(
_app_handle: tauri::AppHandle,
profile_index: String,
) -> CmdResult<bool> {
logging!(info, Type::Cmd, true, "切换配置到: {}", profile_index);
let profiles = IProfiles {
current: Some(profile_index),
items: None,
};
patch_profiles_config(profiles).await
}
/// 修改某个profile item的
#[tauri::command]
pub fn patch_profile(index: String, profile: PrfItem) -> CmdResult {
wrap_err!(Config::profiles().data().patch_item(index, profile))?;
Ok(())
}
/// 查看配置文件
#[tauri::command]
pub fn view_profile(app_handle: tauri::AppHandle, index: String) -> CmdResult {
let file = {
wrap_err!(Config::profiles().latest().get_item(&index))?
.file
.clone()
.ok_or("the file field is null")
}?;
let path = wrap_err!(dirs::app_profiles_dir())?.join(file);
if !path.exists() {
ret_err!("the file not found");
}
wrap_err!(help::open_file(app_handle, path))
}
/// 读取配置文件内容
#[tauri::command]
pub fn read_profile_file(index: String) -> CmdResult<String> {
let profiles = Config::profiles();
let profiles = profiles.latest();
let item = wrap_err!(profiles.get_item(&index))?;
let data = wrap_err!(item.read_file())?;
Ok(data)
}

View File

@ -1,24 +0,0 @@
use super::CmdResult;
use crate::module::mihomo::MihomoManager;
#[tauri::command]
pub async fn get_proxies() -> CmdResult<serde_json::Value> {
let mannager = MihomoManager::global();
mannager
.refresh_proxies()
.await
.map(|_| mannager.get_proxies())
.or_else(|_| Ok(mannager.get_proxies()))
}
#[tauri::command]
pub async fn get_providers_proxies() -> CmdResult<serde_json::Value> {
let mannager = MihomoManager::global();
mannager
.refresh_providers_proxies()
.await
.map(|_| mannager.get_providers_proxies())
.or_else(|_| Ok(mannager.get_providers_proxies()))
}

View File

@ -1,36 +0,0 @@
use super::CmdResult;
use crate::{config::*, wrap_err};
use anyhow::Context;
use serde_yaml::Mapping;
use std::collections::HashMap;
/// 获取运行时配置
#[tauri::command]
pub fn get_runtime_config() -> CmdResult<Option<Mapping>> {
Ok(Config::runtime().latest().config.clone())
}
/// 获取运行时YAML配置
#[tauri::command]
pub fn get_runtime_yaml() -> CmdResult<String> {
let runtime = Config::runtime();
let runtime = runtime.latest();
let config = runtime.config.as_ref();
wrap_err!(config
.ok_or(anyhow::anyhow!("failed to parse config to yaml file"))
.and_then(
|config| serde_yaml::to_string(config).context("failed to convert config to yaml")
))
}
/// 获取运行时存在的键
#[tauri::command]
pub fn get_runtime_exists() -> CmdResult<Vec<String>> {
Ok(Config::runtime().latest().exists_keys.clone())
}
/// 获取运行时日志
#[tauri::command]
pub fn get_runtime_logs() -> CmdResult<HashMap<String, Vec<(String, String)>>> {
Ok(Config::runtime().latest().chain_logs.clone())
}

View File

@ -1,116 +0,0 @@
use super::CmdResult;
use crate::{config::*, core::*, utils::dirs, wrap_err};
use std::fs;
/// 保存profiles的配置
#[tauri::command]
pub async fn save_profile_file(index: String, file_data: Option<String>) -> CmdResult {
if file_data.is_none() {
return Ok(());
}
// 在异步操作前完成所有文件操作
let (file_path, original_content, is_merge_file) = {
let profiles = Config::profiles();
let profiles_guard = profiles.latest();
let item = wrap_err!(profiles_guard.get_item(&index))?;
// 确定是否为merge类型文件
let is_merge = item.itype.as_ref().is_some_and(|t| t == "merge");
let content = wrap_err!(item.read_file())?;
let path = item.file.clone().ok_or("file field is null")?;
let profiles_dir = wrap_err!(dirs::app_profiles_dir())?;
(profiles_dir.join(path), content, is_merge)
};
// 保存新的配置文件
wrap_err!(fs::write(&file_path, file_data.clone().unwrap()))?;
let file_path_str = file_path.to_string_lossy().to_string();
println!(
"[cmd配置save] 开始验证配置文件: {}, 是否为merge文件: {}",
file_path_str, is_merge_file
);
// 对于 merge 文件,只进行语法验证,不进行后续内核验证
if is_merge_file {
println!("[cmd配置save] 检测到merge文件只进行语法验证");
match CoreManager::global()
.validate_config_file(&file_path_str, Some(true))
.await
{
Ok((true, _)) => {
println!("[cmd配置save] merge文件语法验证通过");
// 成功后尝试更新整体配置
if let Err(e) = CoreManager::global().update_config().await {
println!("[cmd配置save] 更新整体配置时发生错误: {}", e);
log::warn!(target: "app", "更新整体配置时发生错误: {}", e);
}
return Ok(());
}
Ok((false, error_msg)) => {
println!("[cmd配置save] merge文件语法验证失败: {}", error_msg);
// 恢复原始配置文件
wrap_err!(fs::write(&file_path, original_content))?;
// 发送合并文件专用错误通知
let result = (false, error_msg.clone());
crate::cmd::validate::handle_yaml_validation_notice(&result, "合并配置文件");
return Ok(());
}
Err(e) => {
println!("[cmd配置save] 验证过程发生错误: {}", e);
// 恢复原始配置文件
wrap_err!(fs::write(&file_path, original_content))?;
return Err(e.to_string());
}
}
}
// 非merge文件使用完整验证流程
match CoreManager::global()
.validate_config_file(&file_path_str, None)
.await
{
Ok((true, _)) => {
println!("[cmd配置save] 验证成功");
Ok(())
}
Ok((false, error_msg)) => {
println!("[cmd配置save] 验证失败: {}", error_msg);
// 恢复原始配置文件
wrap_err!(fs::write(&file_path, original_content))?;
// 智能判断错误类型
let is_script_error = file_path_str.ends_with(".js")
|| error_msg.contains("Script syntax error")
|| error_msg.contains("Script must contain a main function")
|| error_msg.contains("Failed to read script file");
if error_msg.contains("YAML syntax error")
|| error_msg.contains("Failed to read file:")
|| (!file_path_str.ends_with(".js") && !is_script_error)
{
// 普通YAML错误使用YAML通知处理
println!("[cmd配置save] YAML配置文件验证失败发送通知");
let result = (false, error_msg.clone());
crate::cmd::validate::handle_yaml_validation_notice(&result, "YAML配置文件");
} else if is_script_error {
// 脚本错误使用专门的通知处理
println!("[cmd配置save] 脚本文件验证失败,发送通知");
let result = (false, error_msg.clone());
crate::cmd::validate::handle_script_validation_notice(&result, "脚本文件");
} else {
// 普通配置错误使用一般通知
println!("[cmd配置save] 其他类型验证失败,发送一般通知");
handle::Handle::notice_message("config_validate::error", &error_msg);
}
Ok(())
}
Err(e) => {
println!("[cmd配置save] 验证过程发生错误: {}", e);
// 恢复原始配置文件
wrap_err!(fs::write(&file_path, original_content))?;
Err(e.to_string())
}
}
}

View File

@ -1,40 +0,0 @@
use super::CmdResult;
use crate::{
core::{service, CoreManager},
utils::i18n::t,
};
async fn execute_service_operation(
service_op: impl std::future::Future<Output = Result<(), impl ToString + std::fmt::Debug>>,
op_type: &str,
) -> CmdResult {
if service_op.await.is_err() {
let emsg = format!("{} {} failed", op_type, "Service");
return Err(t(emsg.as_str()));
}
if CoreManager::global().restart_core().await.is_err() {
let emsg = format!("{} {} failed", "Restart", "Core");
return Err(t(emsg.as_str()));
}
Ok(())
}
#[tauri::command]
pub async fn install_service() -> CmdResult {
execute_service_operation(service::install_service(), "Install").await
}
#[tauri::command]
pub async fn uninstall_service() -> CmdResult {
execute_service_operation(service::uninstall_service(), "Uninstall").await
}
#[tauri::command]
pub async fn reinstall_service() -> CmdResult {
execute_service_operation(service::reinstall_service(), "Reinstall").await
}
#[tauri::command]
pub async fn repair_service() -> CmdResult {
execute_service_operation(service::force_reinstall_service(), "Repair").await
}

View File

@ -1,94 +0,0 @@
use super::CmdResult;
use crate::{
core::{handle, CoreManager},
module::sysinfo::PlatformSpecification,
};
use once_cell::sync::Lazy;
use std::{
sync::atomic::{AtomicI64, Ordering},
time::{SystemTime, UNIX_EPOCH},
};
use tauri_plugin_clipboard_manager::ClipboardExt;
// 存储应用启动时间的全局变量
static APP_START_TIME: Lazy<AtomicI64> = Lazy::new(|| {
// 获取当前系统时间,转换为毫秒级时间戳
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_millis() as i64;
AtomicI64::new(now)
});
#[tauri::command]
pub async fn export_diagnostic_info() -> CmdResult<()> {
let sysinfo = PlatformSpecification::new_async().await;
let info = format!("{:?}", sysinfo);
let app_handle = handle::Handle::global().app_handle().unwrap();
let cliboard = app_handle.clipboard();
if cliboard.write_text(info).is_err() {
log::error!(target: "app", "Failed to write to clipboard");
}
Ok(())
}
#[tauri::command]
pub async fn get_system_info() -> CmdResult<String> {
let sysinfo = PlatformSpecification::new_async().await;
let info = format!("{:?}", sysinfo);
Ok(info)
}
/// 获取当前内核运行模式
#[tauri::command]
pub async fn get_running_mode() -> Result<String, String> {
Ok(CoreManager::global().get_running_mode().await.to_string())
}
/// 获取应用的运行时间(毫秒)
#[tauri::command]
pub fn get_app_uptime() -> CmdResult<i64> {
let start_time = APP_START_TIME.load(Ordering::Relaxed);
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_millis() as i64;
Ok(now - start_time)
}
/// 检查应用是否以管理员身份运行
#[tauri::command]
#[cfg(target_os = "windows")]
pub fn is_admin() -> CmdResult<bool> {
use deelevate::{PrivilegeLevel, Token};
let result = Token::with_current_process()
.and_then(|token| token.privilege_level())
.map(|level| level != PrivilegeLevel::NotPrivileged)
.unwrap_or(false);
Ok(result)
}
/// 非Windows平台检测是否以管理员身份运行
#[tauri::command]
#[cfg(not(target_os = "windows"))]
pub fn is_admin() -> CmdResult<bool> {
#[cfg(target_os = "macos")]
{
Ok(unsafe { libc::geteuid() } == 0)
}
#[cfg(target_os = "linux")]
{
Ok(unsafe { libc::geteuid() } == 0)
}
#[cfg(not(any(target_os = "macos", target_os = "linux")))]
{
Ok(false)
}
}

View File

@ -1,28 +0,0 @@
use super::CmdResult;
/// Platform-specific implementation for UWP functionality
#[cfg(windows)]
mod platform {
use super::CmdResult;
use crate::{core::win_uwp, wrap_err};
pub async fn invoke_uwp_tool() -> CmdResult {
wrap_err!(win_uwp::invoke_uwptools().await)
}
}
/// Stub implementation for non-Windows platforms
#[cfg(not(windows))]
mod platform {
use super::CmdResult;
pub async fn invoke_uwp_tool() -> CmdResult {
Ok(())
}
}
/// Command exposed to Tauri
#[tauri::command]
pub async fn invoke_uwp_tool() -> CmdResult {
platform::invoke_uwp_tool().await
}

View File

@ -1,104 +0,0 @@
use super::CmdResult;
use crate::core::*;
/// 发送脚本验证通知消息
#[tauri::command]
pub async fn script_validate_notice(status: String, msg: String) -> CmdResult {
handle::Handle::notice_message(&status, &msg);
Ok(())
}
/// 处理脚本验证相关的所有消息通知
/// 统一通知接口,保持消息类型一致性
pub fn handle_script_validation_notice(result: &(bool, String), file_type: &str) {
if !result.0 {
let error_msg = &result.1;
// 根据错误消息内容判断错误类型
let status = if error_msg.starts_with("File not found:") {
"config_validate::file_not_found"
} else if error_msg.starts_with("Failed to read script file:") {
"config_validate::script_error"
} else if error_msg.starts_with("Script syntax error:") {
"config_validate::script_syntax_error"
} else if error_msg == "Script must contain a main function" {
"config_validate::script_missing_main"
} else {
// 如果是其他类型错误,作为一般脚本错误处理
"config_validate::script_error"
};
log::warn!(target: "app", "{} 验证失败: {}", file_type, error_msg);
handle::Handle::notice_message(status, error_msg);
}
}
/// 验证指定脚本文件
#[tauri::command]
pub async fn validate_script_file(file_path: String) -> CmdResult<bool> {
log::info!(target: "app", "验证脚本文件: {}", file_path);
match CoreManager::global()
.validate_config_file(&file_path, None)
.await
{
Ok(result) => {
handle_script_validation_notice(&result, "脚本文件");
Ok(result.0) // 返回验证结果布尔值
}
Err(e) => {
let error_msg = e.to_string();
log::error!(target: "app", "验证脚本文件过程发生错误: {}", error_msg);
handle::Handle::notice_message("config_validate::process_terminated", &error_msg);
Ok(false)
}
}
}
/// 处理YAML验证相关的所有消息通知
/// 统一通知接口,保持消息类型一致性
pub fn handle_yaml_validation_notice(result: &(bool, String), file_type: &str) {
if !result.0 {
let error_msg = &result.1;
println!("[通知] 处理{}验证错误: {}", file_type, error_msg);
// 检查是否为merge文件
let is_merge_file = file_type.contains("合并");
// 根据错误消息内容判断错误类型
let status = if error_msg.starts_with("File not found:") {
"config_validate::file_not_found"
} else if error_msg.starts_with("Failed to read file:") {
"config_validate::yaml_read_error"
} else if error_msg.starts_with("YAML syntax error:") {
if is_merge_file {
"config_validate::merge_syntax_error"
} else {
"config_validate::yaml_syntax_error"
}
} else if error_msg.contains("mapping values are not allowed") {
if is_merge_file {
"config_validate::merge_mapping_error"
} else {
"config_validate::yaml_mapping_error"
}
} else if error_msg.contains("did not find expected key") {
if is_merge_file {
"config_validate::merge_key_error"
} else {
"config_validate::yaml_key_error"
}
} else {
// 如果是其他类型错误,根据文件类型作为一般错误处理
if is_merge_file {
"config_validate::merge_error"
} else {
"config_validate::yaml_error"
}
};
log::warn!(target: "app", "{} 验证失败: {}", file_type, error_msg);
println!("[通知] 发送通知: status={}, msg={}", status, error_msg);
handle::Handle::notice_message(status, error_msg);
}
}

View File

@ -1,16 +0,0 @@
use super::CmdResult;
use crate::{config::*, feat, wrap_err};
/// 获取Verge配置
#[tauri::command]
pub fn get_verge_config() -> CmdResult<IVergeResponse> {
let verge = Config::verge();
let verge_data = verge.data().clone();
Ok(IVergeResponse::from(verge_data))
}
/// 修改Verge配置
#[tauri::command]
pub async fn patch_verge_config(payload: IVerge) -> CmdResult {
wrap_err!(feat::patch_verge(payload, false).await)
}

View File

@ -1,46 +0,0 @@
use super::CmdResult;
use crate::{config::*, core, feat, wrap_err};
use reqwest_dav::list_cmd::ListFile;
/// 保存 WebDAV 配置
#[tauri::command]
pub async fn save_webdav_config(url: String, username: String, password: String) -> CmdResult<()> {
let patch = IVerge {
webdav_url: Some(url),
webdav_username: Some(username),
webdav_password: Some(password),
..IVerge::default()
};
Config::verge().draft().patch_config(patch.clone());
Config::verge().apply();
Config::verge()
.data()
.save_file()
.map_err(|err| err.to_string())?;
core::backup::WebDavClient::global().reset();
Ok(())
}
/// 创建 WebDAV 备份并上传
#[tauri::command]
pub async fn create_webdav_backup() -> CmdResult<()> {
wrap_err!(feat::create_backup_and_upload_webdav().await)
}
/// 列出 WebDAV 上的备份文件
#[tauri::command]
pub async fn list_webdav_backup() -> CmdResult<Vec<ListFile>> {
wrap_err!(feat::list_wevdav_backup().await)
}
/// 删除 WebDAV 上的备份文件
#[tauri::command]
pub async fn delete_webdav_backup(filename: String) -> CmdResult<()> {
wrap_err!(feat::delete_webdav_backup(filename).await)
}
/// 从 WebDAV 恢复备份文件
#[tauri::command]
pub async fn restore_webdav_backup(filename: String) -> CmdResult<()> {
wrap_err!(feat::restore_webdav_backup(filename).await)
}

353
src-tauri/src/cmds.rs Normal file
View File

@ -0,0 +1,353 @@
use crate::{
config::*,
core::*,
feat,
utils::{dirs, help, resolve},
};
use crate::{ret_err, wrap_err};
use anyhow::{Context, Result};
use serde_yaml::Mapping;
use std::collections::{HashMap, VecDeque};
use sysproxy::Sysproxy;
use tauri::api;
type CmdResult<T = ()> = Result<T, String>;
#[tauri::command]
pub fn get_profiles() -> CmdResult<IProfiles> {
Ok(Config::profiles().data().clone())
}
#[tauri::command]
pub async fn enhance_profiles() -> CmdResult {
wrap_err!(CoreManager::global().update_config().await)?;
handle::Handle::refresh_clash();
Ok(())
}
#[tauri::command]
pub async fn import_profile(url: String, option: Option<PrfOption>) -> CmdResult {
let item = wrap_err!(PrfItem::from_url(&url, None, None, option).await)?;
wrap_err!(Config::profiles().data().append_item(item))
}
#[tauri::command]
pub async fn reorder_profile(active_id: String, over_id: String) -> CmdResult {
wrap_err!(Config::profiles().data().reorder(active_id, over_id))
}
#[tauri::command]
pub async fn create_profile(item: PrfItem, file_data: Option<String>) -> CmdResult {
let item = wrap_err!(PrfItem::from(item, file_data).await)?;
wrap_err!(Config::profiles().data().append_item(item))
}
#[tauri::command]
pub async fn update_profile(index: String, option: Option<PrfOption>) -> CmdResult {
wrap_err!(feat::update_profile(index, option).await)
}
#[tauri::command]
pub async fn delete_profile(index: String) -> CmdResult {
let should_update = wrap_err!({ Config::profiles().data().delete_item(index) })?;
if should_update {
wrap_err!(CoreManager::global().update_config().await)?;
handle::Handle::refresh_clash();
}
Ok(())
}
/// 修改profiles的
#[tauri::command]
pub async fn patch_profiles_config(profiles: IProfiles) -> CmdResult {
wrap_err!({ Config::profiles().draft().patch_config(profiles) })?;
match CoreManager::global().update_config().await {
Ok(_) => {
handle::Handle::refresh_clash();
Config::profiles().apply();
wrap_err!(Config::profiles().data().save_file())?;
Ok(())
}
Err(err) => {
Config::profiles().discard();
log::error!(target: "app", "{err}");
Err(format!("{err}"))
}
}
}
/// 修改某个profile item的
#[tauri::command]
pub fn patch_profile(index: String, profile: PrfItem) -> CmdResult {
wrap_err!(Config::profiles().data().patch_item(index, profile))?;
wrap_err!(timer::Timer::global().refresh())
}
#[tauri::command]
pub fn view_profile(app_handle: tauri::AppHandle, index: String) -> CmdResult {
let file = {
wrap_err!(Config::profiles().latest().get_item(&index))?
.file
.clone()
.ok_or("the file field is null")
}?;
let path = wrap_err!(dirs::app_profiles_dir())?.join(file);
if !path.exists() {
ret_err!("the file not found");
}
wrap_err!(help::open_file(app_handle, path))
}
#[tauri::command]
pub fn read_profile_file(index: String) -> CmdResult<String> {
let profiles = Config::profiles();
let profiles = profiles.latest();
let item = wrap_err!(profiles.get_item(&index))?;
let data = wrap_err!(item.read_file())?;
Ok(data)
}
#[tauri::command]
pub fn save_profile_file(index: String, file_data: Option<String>) -> CmdResult {
if file_data.is_none() {
return Ok(());
}
let profiles = Config::profiles();
let profiles = profiles.latest();
let item = wrap_err!(profiles.get_item(&index))?;
wrap_err!(item.save_file(file_data.unwrap()))
}
#[tauri::command]
pub fn get_clash_info() -> CmdResult<ClashInfo> {
Ok(Config::clash().latest().get_client_info())
}
#[tauri::command]
pub fn get_runtime_config() -> CmdResult<Option<Mapping>> {
Ok(Config::runtime().latest().config.clone())
}
#[tauri::command]
pub fn get_runtime_yaml() -> CmdResult<String> {
let runtime = Config::runtime();
let runtime = runtime.latest();
let config = runtime.config.as_ref();
wrap_err!(config
.ok_or(anyhow::anyhow!("failed to parse config to yaml file"))
.and_then(
|config| serde_yaml::to_string(config).context("failed to convert config to yaml")
))
}
#[tauri::command]
pub fn get_runtime_exists() -> CmdResult<Vec<String>> {
Ok(Config::runtime().latest().exists_keys.clone())
}
#[tauri::command]
pub fn get_runtime_logs() -> CmdResult<HashMap<String, Vec<(String, String)>>> {
Ok(Config::runtime().latest().chain_logs.clone())
}
#[tauri::command]
pub async fn patch_clash_config(payload: Mapping) -> CmdResult {
wrap_err!(feat::patch_clash(payload).await)
}
#[tauri::command]
pub fn get_verge_config() -> CmdResult<IVerge> {
Ok(Config::verge().data().clone())
}
#[tauri::command]
pub async fn patch_verge_config(payload: IVerge) -> CmdResult {
wrap_err!(feat::patch_verge(payload).await)
}
#[tauri::command]
pub async fn change_clash_core(clash_core: Option<String>) -> CmdResult {
wrap_err!(CoreManager::global().change_core(clash_core).await)
}
/// restart the sidecar
#[tauri::command]
pub async fn restart_sidecar() -> CmdResult {
wrap_err!(CoreManager::global().run_core().await)
}
#[tauri::command]
pub fn grant_permission(_core: String) -> CmdResult {
#[cfg(any(target_os = "macos", target_os = "linux"))]
return wrap_err!(manager::grant_permission(_core));
#[cfg(not(any(target_os = "macos", target_os = "linux")))]
return Err("Unsupported target".into());
}
/// get the system proxy
#[tauri::command]
pub fn get_sys_proxy() -> CmdResult<Mapping> {
let current = wrap_err!(Sysproxy::get_system_proxy())?;
let mut map = Mapping::new();
map.insert("enable".into(), current.enable.into());
map.insert(
"server".into(),
format!("{}:{}", current.host, current.port).into(),
);
map.insert("bypass".into(), current.bypass.into());
Ok(map)
}
#[tauri::command]
pub fn get_clash_logs() -> CmdResult<VecDeque<String>> {
Ok(logger::Logger::global().get_log())
}
#[tauri::command]
pub fn open_app_dir() -> CmdResult<()> {
let app_dir = wrap_err!(dirs::app_home_dir())?;
wrap_err!(open::that(app_dir))
}
#[tauri::command]
pub fn open_core_dir() -> CmdResult<()> {
let core_dir = wrap_err!(tauri::utils::platform::current_exe())?;
let core_dir = core_dir.parent().ok_or("failed to get core dir")?;
wrap_err!(open::that(core_dir))
}
#[tauri::command]
pub fn open_logs_dir() -> CmdResult<()> {
let log_dir = wrap_err!(dirs::app_logs_dir())?;
wrap_err!(open::that(log_dir))
}
#[tauri::command]
pub fn open_web_url(url: String) -> CmdResult<()> {
wrap_err!(open::that(url))
}
#[cfg(windows)]
pub mod uwp {
use super::*;
use crate::core::win_uwp;
#[tauri::command]
pub async fn invoke_uwp_tool() -> CmdResult {
wrap_err!(win_uwp::invoke_uwptools().await)
}
}
#[tauri::command]
pub async fn clash_api_get_proxy_delay(
name: String,
url: Option<String>,
timeout: i32,
) -> CmdResult<clash_api::DelayRes> {
match clash_api::get_proxy_delay(name, url, timeout).await {
Ok(res) => Ok(res),
Err(err) => Err(err.to_string()),
}
}
#[tauri::command]
pub fn get_portable_flag() -> CmdResult<bool> {
Ok(*dirs::PORTABLE_FLAG.get().unwrap_or(&false))
}
#[tauri::command]
pub async fn test_delay(url: String) -> CmdResult<u32> {
Ok(feat::test_delay(url).await.unwrap_or(10000u32))
}
#[tauri::command]
pub fn get_app_dir() -> CmdResult<String> {
let app_home_dir = wrap_err!(dirs::app_home_dir())?
.to_string_lossy()
.to_string();
Ok(app_home_dir)
}
#[tauri::command]
pub fn copy_icon_file(path: String, name: String) -> CmdResult<String> {
let file_path = std::path::Path::new(&path);
let icon_dir = wrap_err!(dirs::app_home_dir())?.join("icons");
if !icon_dir.exists() {
let _ = std::fs::create_dir_all(&icon_dir);
}
let dest_path = icon_dir.join(name);
if file_path.exists() {
match std::fs::copy(file_path, &dest_path) {
Ok(_) => Ok(dest_path.to_string_lossy().to_string()),
Err(err) => Err(err.to_string()),
}
} else {
return Err("file not found".to_string());
}
}
#[tauri::command]
pub fn exit_app(app_handle: tauri::AppHandle) {
let _ = resolve::save_window_size_position(&app_handle, true);
resolve::resolve_reset();
api::process::kill_children();
app_handle.exit(0);
std::process::exit(0);
}
#[cfg(windows)]
pub mod service {
use super::*;
use crate::core::win_service;
#[tauri::command]
pub async fn check_service() -> CmdResult<win_service::JsonResponse> {
wrap_err!(win_service::check_service().await)
}
#[tauri::command]
pub async fn install_service() -> CmdResult {
wrap_err!(win_service::install_service().await)
}
#[tauri::command]
pub async fn uninstall_service() -> CmdResult {
wrap_err!(win_service::uninstall_service().await)
}
}
#[cfg(not(windows))]
pub mod service {
use super::*;
#[tauri::command]
pub async fn check_service() -> CmdResult {
Ok(())
}
#[tauri::command]
pub async fn install_service() -> CmdResult {
Ok(())
}
#[tauri::command]
pub async fn uninstall_service() -> CmdResult {
Ok(())
}
}
#[cfg(not(windows))]
pub mod uwp {
use super::*;
#[tauri::command]
pub async fn invoke_uwp_tool() -> CmdResult {
Ok(())
}
}

View File

@ -13,7 +13,7 @@ pub struct IClashTemp(pub Mapping);
impl IClashTemp { impl IClashTemp {
pub fn new() -> Self { pub fn new() -> Self {
let template = Self::template(); let template = Self::template();
match dirs::clash_path().and_then(|path| help::read_mapping(&path)) { match dirs::clash_path().and_then(|path| help::read_merge_mapping(&path)) {
Ok(mut map) => { Ok(mut map) => {
template.0.keys().for_each(|key| { template.0.keys().for_each(|key| {
if !map.contains_key(key) { if !map.contains_key(key) {
@ -32,17 +32,14 @@ impl IClashTemp {
pub fn template() -> Self { pub fn template() -> Self {
let mut map = Mapping::new(); let mut map = Mapping::new();
let mut tun = Mapping::new(); let mut tun = Mapping::new();
tun.insert("enable".into(), false.into());
tun.insert("stack".into(), "gvisor".into()); tun.insert("stack".into(), "gvisor".into());
tun.insert("device".into(), "Meta".into());
tun.insert("auto-route".into(), true.into()); tun.insert("auto-route".into(), true.into());
tun.insert("strict-route".into(), false.into()); tun.insert("strict-route".into(), false.into());
tun.insert("auto-detect-interface".into(), true.into()); tun.insert("auto-detect-interface".into(), true.into());
tun.insert("dns-hijack".into(), vec!["any:53"].into()); tun.insert("dns-hijack".into(), vec!["any:53"].into());
tun.insert("mtu".into(), 9000.into());
#[cfg(not(target_os = "windows"))]
map.insert("redir-port".into(), 7895.into());
#[cfg(target_os = "linux")]
map.insert("tproxy-port".into(), 7896.into());
map.insert("mixed-port".into(), 7897.into()); map.insert("mixed-port".into(), 7897.into());
map.insert("socks-port".into(), 7898.into()); map.insert("socks-port".into(), 7898.into());
map.insert("port".into(), 7899.into()); map.insert("port".into(), 7899.into());
@ -50,29 +47,18 @@ impl IClashTemp {
map.insert("allow-lan".into(), false.into()); map.insert("allow-lan".into(), false.into());
map.insert("mode".into(), "rule".into()); map.insert("mode".into(), "rule".into());
map.insert("external-controller".into(), "127.0.0.1:9097".into()); map.insert("external-controller".into(), "127.0.0.1:9097".into());
let mut cors_map = Mapping::new();
cors_map.insert("allow-private-network".into(), true.into());
cors_map.insert("allow-origins".into(), vec!["*"].into());
map.insert("secret".into(), "".into()); map.insert("secret".into(), "".into());
map.insert("tun".into(), tun.into()); map.insert("tun".into(), tun.into());
map.insert("external-controller-cors".into(), cors_map.into());
map.insert("unified-delay".into(), true.into());
Self(map) Self(map)
} }
fn guard(mut config: Mapping) -> Mapping { fn guard(mut config: Mapping) -> Mapping {
#[cfg(not(target_os = "windows"))]
let redir_port = Self::guard_redir_port(&config);
#[cfg(target_os = "linux")]
let tproxy_port = Self::guard_tproxy_port(&config);
let mixed_port = Self::guard_mixed_port(&config); let mixed_port = Self::guard_mixed_port(&config);
let socks_port = Self::guard_socks_port(&config); let socks_port = Self::guard_socks_port(&config);
let port = Self::guard_port(&config); let port = Self::guard_port(&config);
let ctrl = Self::guard_server_ctrl(&config); let ctrl = Self::guard_server_ctrl(&config);
#[cfg(not(target_os = "windows"))]
config.insert("redir-port".into(), redir_port.into());
#[cfg(target_os = "linux")]
config.insert("tproxy-port".into(), tproxy_port.into());
config.insert("mixed-port".into(), mixed_port.into()); config.insert("mixed-port".into(), mixed_port.into());
config.insert("socks-port".into(), socks_port.into()); config.insert("socks-port".into(), socks_port.into());
config.insert("port".into(), port.into()); config.insert("port".into(), port.into());
@ -124,53 +110,19 @@ impl IClashTemp {
}), }),
} }
} }
#[cfg(not(target_os = "windows"))]
pub fn guard_redir_port(config: &Mapping) -> u16 {
let mut port = config
.get("redir-port")
.and_then(|value| match value {
Value::String(val_str) => val_str.parse().ok(),
Value::Number(val_num) => val_num.as_u64().map(|u| u as u16),
_ => None,
})
.unwrap_or(7895);
if port == 0 {
port = 7895;
}
port
}
#[cfg(target_os = "linux")]
pub fn guard_tproxy_port(config: &Mapping) -> u16 {
let mut port = config
.get("tproxy-port")
.and_then(|value| match value {
Value::String(val_str) => val_str.parse().ok(),
Value::Number(val_num) => val_num.as_u64().map(|u| u as u16),
_ => None,
})
.unwrap_or(7896);
if port == 0 {
port = 7896;
}
port
}
pub fn guard_mixed_port(config: &Mapping) -> u16 { pub fn guard_mixed_port(config: &Mapping) -> u16 {
let raw_value = config.get("mixed-port"); let mut port = config
.get("mixed-port")
let mut port = raw_value
.and_then(|value| match value { .and_then(|value| match value {
Value::String(val_str) => val_str.parse().ok(), Value::String(val_str) => val_str.parse().ok(),
Value::Number(val_num) => val_num.as_u64().map(|u| u as u16), Value::Number(val_num) => val_num.as_u64().map(|u| u as u16),
_ => None, _ => None,
}) })
.unwrap_or(7897); .unwrap_or(7897);
if port == 0 { if port == 0 {
port = 7897; port = 7897;
} }
port port
} }

View File

@ -1,14 +1,11 @@
use super::{Draft, IClashTemp, IProfiles, IRuntime, IVerge}; use super::{Draft, IClashTemp, IProfiles, IRuntime, IVerge};
use crate::{ use crate::{
config::PrfItem, enhance,
core::{handle, CoreManager}, utils::{dirs, help},
enhance, logging,
utils::{dirs, help, logging::Type},
}; };
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
use std::path::PathBuf; use std::{env::temp_dir, path::PathBuf};
use tokio::time::{sleep, Duration};
pub const RUNTIME_CONFIG: &str = "clash-verge.yaml"; pub const RUNTIME_CONFIG: &str = "clash-verge.yaml";
pub const CHECK_CONFIG: &str = "clash-verge-check.yaml"; pub const CHECK_CONFIG: &str = "clash-verge-check.yaml";
@ -49,80 +46,21 @@ impl Config {
} }
/// 初始化订阅 /// 初始化订阅
pub async fn init_config() -> Result<()> { pub fn init_config() -> Result<()> {
if Self::profiles() crate::log_err!(Self::generate());
.data() if let Err(err) = Self::generate_file(ConfigType::Run) {
.get_item(&"Merge".to_string()) log::error!(target: "app", "{err}");
.is_err()
{
let merge_item = PrfItem::from_merge(Some("Merge".to_string()))?;
Self::profiles().data().append_item(merge_item.clone())?;
}
if Self::profiles()
.data()
.get_item(&"Script".to_string())
.is_err()
{
let script_item = PrfItem::from_script(Some("Script".to_string()))?;
Self::profiles().data().append_item(script_item.clone())?;
}
// 生成运行时配置
if let Err(err) = Self::generate().await {
logging!(error, Type::Config, true, "生成运行时配置失败: {}", err);
} else {
logging!(info, Type::Config, true, "生成运行时配置成功");
}
// 生成运行时配置文件并验证 let runtime_path = dirs::app_home_dir()?.join(RUNTIME_CONFIG);
let config_result = Self::generate_file(ConfigType::Run); // 如果不存在就将默认的clash文件拿过来
if !runtime_path.exists() {
let validation_result = if config_result.is_ok() { help::save_yaml(
// 验证配置文件 &runtime_path,
logging!(info, Type::Config, true, "开始验证配置"); &Config::clash().latest().0,
Some("# Clash Verge Runtime"),
match CoreManager::global().validate_config().await { )?;
Ok((is_valid, error_msg)) => {
if !is_valid {
logging!(
warn,
Type::Config,
true,
"[首次启动] 配置验证失败,使用默认最小配置启动: {}",
error_msg
);
CoreManager::global()
.use_default_config("config_validate::boot_error", &error_msg)
.await?;
Some(("config_validate::boot_error", error_msg))
} else {
logging!(info, Type::Config, true, "配置验证成功");
Some(("config_validate::success", String::new()))
}
}
Err(err) => {
logging!(warn, Type::Config, true, "验证进程执行失败: {}", err);
CoreManager::global()
.use_default_config("config_validate::process_terminated", "")
.await?;
Some(("config_validate::process_terminated", String::new()))
}
} }
} else {
logging!(warn, Type::Config, true, "生成配置文件失败,使用默认配置");
CoreManager::global()
.use_default_config("config_validate::error", "")
.await?;
Some(("config_validate::error", String::new()))
};
// 在单独的任务中发送通知
if let Some((msg_type, msg_content)) = validation_result {
tauri::async_runtime::spawn(async move {
sleep(Duration::from_secs(2)).await;
handle::Handle::notice_message(msg_type, &msg_content);
});
} }
Ok(()) Ok(())
} }
@ -130,7 +68,7 @@ impl Config {
pub fn generate_file(typ: ConfigType) -> Result<PathBuf> { pub fn generate_file(typ: ConfigType) -> Result<PathBuf> {
let path = match typ { let path = match typ {
ConfigType::Run => dirs::app_home_dir()?.join(RUNTIME_CONFIG), ConfigType::Run => dirs::app_home_dir()?.join(RUNTIME_CONFIG),
ConfigType::Check => dirs::app_home_dir()?.join(CHECK_CONFIG), ConfigType::Check => temp_dir().join(CHECK_CONFIG),
}; };
let runtime = Config::runtime(); let runtime = Config::runtime();
@ -145,8 +83,8 @@ impl Config {
} }
/// 生成订阅存好 /// 生成订阅存好
pub async fn generate() -> Result<()> { pub fn generate() -> Result<()> {
let (config, exists_keys, logs) = enhance::enhance().await; let (config, exists_keys, logs) = enhance::enhance();
*Config::runtime().draft() = IRuntime { *Config::runtime().draft() = IRuntime {
config: Some(config), config: Some(config),

View File

@ -1,95 +0,0 @@
use crate::utils::dirs::get_encryption_key;
use aes_gcm::{
aead::{Aead, KeyInit},
Aes256Gcm, Key,
};
use base64::{engine::general_purpose::STANDARD, Engine};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
const NONCE_LENGTH: usize = 12;
/// Encrypt data
pub fn encrypt_data(data: &str) -> Result<String, Box<dyn std::error::Error>> {
let encryption_key = get_encryption_key()?;
let key = Key::<Aes256Gcm>::from_slice(&encryption_key);
let cipher = Aes256Gcm::new(key);
// Generate random nonce
let mut nonce = vec![0u8; NONCE_LENGTH];
getrandom::fill(&mut nonce)?;
// Encrypt data
let ciphertext = cipher
.encrypt(nonce.as_slice().into(), data.as_bytes())
.map_err(|e| format!("Encryption failed: {}", e))?;
// Concatenate nonce and ciphertext and encode them in base64
let mut combined = nonce;
combined.extend(ciphertext);
Ok(STANDARD.encode(combined))
}
/// Decrypt data
pub fn decrypt_data(encrypted: &str) -> Result<String, Box<dyn std::error::Error>> {
let encryption_key = get_encryption_key()?;
let key = Key::<Aes256Gcm>::from_slice(&encryption_key);
let cipher = Aes256Gcm::new(key);
// Decode from base64
let data = STANDARD.decode(encrypted)?;
if data.len() < NONCE_LENGTH {
return Err("Invalid encrypted data".into());
}
// Separate nonce and ciphertext
let (nonce, ciphertext) = data.split_at(NONCE_LENGTH);
// Decrypt data
let plaintext = cipher
.decrypt(nonce.into(), ciphertext)
.map_err(|e| format!("Decryption failed: {}", e))?;
String::from_utf8(plaintext).map_err(|e| e.into())
}
/// Serialize encrypted function
pub fn serialize_encrypted<T, S>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
where
T: Serialize,
S: Serializer,
{
// 如果序列化失败,返回 None
let json = match serde_json::to_string(value) {
Ok(j) => j,
Err(_) => return serializer.serialize_none(),
};
// 如果加密失败,返回 None
match encrypt_data(&json) {
Ok(encrypted) => serializer.serialize_str(&encrypted),
Err(_) => serializer.serialize_none(),
}
}
/// Deserialize decrypted function
pub fn deserialize_encrypted<'a, T, D>(deserializer: D) -> Result<T, D::Error>
where
T: for<'de> Deserialize<'de> + Default,
D: Deserializer<'a>,
{
// 如果反序列化字符串失败,返回默认值
let encrypted = match String::deserialize(deserializer) {
Ok(s) => s,
Err(_) => return Ok(T::default()),
};
// 如果解密失败,返回默认值
let decrypted_string = match decrypt_data(&encrypted) {
Ok(data) => data,
Err(_) => return Ok(T::default()),
};
// 如果 JSON 解析失败,返回默认值
match serde_json::from_str(&decrypted_string) {
Ok(value) => Ok(value),
Err(_) => Ok(T::default()),
}
}

View File

@ -1,18 +1,15 @@
mod clash; mod clash;
#[allow(clippy::module_inception)]
mod config; mod config;
mod draft; mod draft;
mod encrypt;
mod prfitem; mod prfitem;
mod profiles; mod profiles;
mod runtime; mod runtime;
mod verge; mod verge;
pub use self::{ pub use self::clash::*;
clash::*, config::*, draft::*, encrypt::*, prfitem::*, profiles::*, runtime::*, verge::*, pub use self::config::*;
}; pub use self::draft::*;
pub use self::prfitem::*;
pub const DEFAULT_PAC: &str = r#"function FindProxyForURL(url, host) { pub use self::profiles::*;
return "PROXY 127.0.0.1:%mixed-port%; SOCKS5 127.0.0.1:%mixed-port%; DIRECT;"; pub use self::runtime::*;
} pub use self::verge::*;
"#;

Some files were not shown because too many files have changed in this diff Show More