mirror of
https://github.com/pompurin404/mihomo-party.git
synced 2024-11-15 19:22:31 +08:00
support webdav backup
This commit is contained in:
parent
dbb50421a9
commit
9266d6b76e
|
@ -22,7 +22,9 @@
|
|||
"@electron-toolkit/preload": "^3.0.1",
|
||||
"@electron-toolkit/utils": "^3.0.0",
|
||||
"@mihomo-party/sysproxy": "^2.0.0",
|
||||
"adm-zip": "^0.5.15",
|
||||
"axios": "^1.7.3",
|
||||
"webdav": "^5.7.1",
|
||||
"ws": "^8.18.0",
|
||||
"yaml": "^2.5.0"
|
||||
},
|
||||
|
@ -40,7 +42,6 @@
|
|||
"@types/react-dom": "^18.3.0",
|
||||
"@types/ws": "^8.5.12",
|
||||
"@vitejs/plugin-react": "^4.3.1",
|
||||
"adm-zip": "^0.5.15",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"dayjs": "^1.11.12",
|
||||
"electron": "^31.3.1",
|
||||
|
|
179
pnpm-lock.yaml
179
pnpm-lock.yaml
|
@ -17,9 +17,15 @@ importers:
|
|||
'@mihomo-party/sysproxy':
|
||||
specifier: ^2.0.0
|
||||
version: 2.0.0
|
||||
adm-zip:
|
||||
specifier: ^0.5.15
|
||||
version: 0.5.15
|
||||
axios:
|
||||
specifier: ^1.7.3
|
||||
version: 1.7.3
|
||||
webdav:
|
||||
specifier: ^5.7.1
|
||||
version: 5.7.1
|
||||
ws:
|
||||
specifier: ^8.18.0
|
||||
version: 8.18.0
|
||||
|
@ -66,9 +72,6 @@ importers:
|
|||
'@vitejs/plugin-react':
|
||||
specifier: ^4.3.1
|
||||
version: 4.3.1(vite@5.3.5(@types/node@22.1.0))
|
||||
adm-zip:
|
||||
specifier: ^0.5.15
|
||||
version: 0.5.15
|
||||
autoprefixer:
|
||||
specifier: ^10.4.20
|
||||
version: 10.4.20(postcss@8.4.41)
|
||||
|
@ -273,6 +276,9 @@ packages:
|
|||
resolution: {integrity: sha512-YTnYtra7W9e6/oAZEHj0bJehPRUlLH9/fbpT5LfB0NhQXyALCRkRs3zH9v07IYhkgpqX6Z78FnuccZr/l4Fs4Q==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@buttercup/fetch@0.2.1':
|
||||
resolution: {integrity: sha512-sCgECOx8wiqY8NN1xN22BqqKzXYIG2AicNLlakOAI4f0WgyLVUbAigMf8CZhBtJxdudTcB1gD5lciqi44jwJvg==}
|
||||
|
||||
'@develar/schema-utils@2.6.5':
|
||||
resolution: {integrity: sha512-0cp4PsWQ/9avqTVMCtZ+GirikIA36ikvjtHweU4/j8yLtgObI0+JUPhYFScgwlteveGB1rt3Cm8UhN04XayDig==}
|
||||
engines: {node: '>= 8.9.0'}
|
||||
|
@ -2126,6 +2132,9 @@ packages:
|
|||
balanced-match@1.0.2:
|
||||
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
|
||||
|
||||
base-64@1.0.0:
|
||||
resolution: {integrity: sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==}
|
||||
|
||||
base64-js@1.5.1:
|
||||
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
|
||||
|
||||
|
@ -2179,6 +2188,9 @@ packages:
|
|||
builder-util@25.0.3:
|
||||
resolution: {integrity: sha512-eH5c1ukdY2xjtFQWQ6jlzEuXuqcuAVc3UQ6V6fdYu9Kg3CkDbCR82Mox42uaJDmee9WXSbP/88cOworFdOHPhw==}
|
||||
|
||||
byte-length@1.0.2:
|
||||
resolution: {integrity: sha512-ovBpjmsgd/teRmgcPh23d4gJvxDoXtAzEL9xTfMU8Yc2kqCDb7L9jAG0XHl1nzuGl+h3ebCIF1i62UFyA9V/2Q==}
|
||||
|
||||
cac@6.7.14:
|
||||
resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
|
||||
engines: {node: '>=8'}
|
||||
|
@ -2218,6 +2230,9 @@ packages:
|
|||
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
charenc@0.0.2:
|
||||
resolution: {integrity: sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==}
|
||||
|
||||
chokidar@3.6.0:
|
||||
resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
|
||||
engines: {node: '>= 8.10.0'}
|
||||
|
@ -2359,6 +2374,9 @@ packages:
|
|||
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
|
||||
engines: {node: '>= 8'}
|
||||
|
||||
crypt@0.0.2:
|
||||
resolution: {integrity: sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==}
|
||||
|
||||
cssesc@3.0.0:
|
||||
resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
|
||||
engines: {node: '>=4'}
|
||||
|
@ -2367,6 +2385,10 @@ packages:
|
|||
csstype@3.1.3:
|
||||
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
|
||||
|
||||
data-uri-to-buffer@4.0.1:
|
||||
resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==}
|
||||
engines: {node: '>= 12'}
|
||||
|
||||
data-view-buffer@1.0.1:
|
||||
resolution: {integrity: sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
@ -2529,6 +2551,10 @@ packages:
|
|||
end-of-stream@1.4.4:
|
||||
resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==}
|
||||
|
||||
entities@5.0.0:
|
||||
resolution: {integrity: sha512-BeJFvFRJddxobhvEdm5GqHzRV/X+ACeuw0/BuuxsCh1EUZcAIz8+kYmBp/LrQuloy6K1f3a0M7+IhmZ7QnkISA==}
|
||||
engines: {node: '>=0.12'}
|
||||
|
||||
env-paths@2.2.1:
|
||||
resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==}
|
||||
engines: {node: '>=6'}
|
||||
|
@ -2674,12 +2700,20 @@ packages:
|
|||
fast-levenshtein@2.0.6:
|
||||
resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
|
||||
|
||||
fast-xml-parser@4.4.1:
|
||||
resolution: {integrity: sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw==}
|
||||
hasBin: true
|
||||
|
||||
fastq@1.17.1:
|
||||
resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==}
|
||||
|
||||
fd-slicer@1.1.0:
|
||||
resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==}
|
||||
|
||||
fetch-blob@3.2.0:
|
||||
resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==}
|
||||
engines: {node: ^12.20 || >= 14.13}
|
||||
|
||||
file-entry-cache@6.0.1:
|
||||
resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==}
|
||||
engines: {node: ^10.12.0 || >=12.0.0}
|
||||
|
@ -2726,6 +2760,10 @@ packages:
|
|||
resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==}
|
||||
engines: {node: '>= 6'}
|
||||
|
||||
formdata-polyfill@4.0.10:
|
||||
resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==}
|
||||
engines: {node: '>=12.20.0'}
|
||||
|
||||
fraction.js@4.3.7:
|
||||
resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==}
|
||||
|
||||
|
@ -2907,6 +2945,9 @@ packages:
|
|||
resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
hot-patcher@2.0.1:
|
||||
resolution: {integrity: sha512-ECg1JFG0YzehicQaogenlcs2qg6WsXQsxtnbr1i696u5tLUjtJdQAh0u2g0Q5YV45f263Ta1GnUJsc8WIfJf4Q==}
|
||||
|
||||
http-cache-semantics@4.1.1:
|
||||
resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==}
|
||||
|
||||
|
@ -2999,6 +3040,9 @@ packages:
|
|||
resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
is-buffer@1.1.6:
|
||||
resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==}
|
||||
|
||||
is-callable@1.2.7:
|
||||
resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
@ -3184,6 +3228,9 @@ packages:
|
|||
keyv@4.5.4:
|
||||
resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
|
||||
|
||||
layerr@3.0.0:
|
||||
resolution: {integrity: sha512-tv754Ki2dXpPVApOrjTyRo4/QegVb9eVFq4mjqp4+NM5NaX7syQvN5BBNfV/ZpAHCEHV24XdUVrBAoka4jt3pA==}
|
||||
|
||||
lazy-val@1.0.5:
|
||||
resolution: {integrity: sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q==}
|
||||
|
||||
|
@ -3286,6 +3333,9 @@ packages:
|
|||
resolution: {integrity: sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
md5@2.3.0:
|
||||
resolution: {integrity: sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==}
|
||||
|
||||
merge2@1.4.1:
|
||||
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
|
||||
engines: {node: '>= 8'}
|
||||
|
@ -3442,6 +3492,9 @@ packages:
|
|||
resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==}
|
||||
engines: {node: '>= 0.6'}
|
||||
|
||||
nested-property@4.0.0:
|
||||
resolution: {integrity: sha512-yFehXNWRs4cM0+dz7QxCd06hTbWbSkV0ISsqBfkntU6TOY4Qm3Q88fRRLOddkGh2Qq6dZvnKVAahfhjcUvLnyA==}
|
||||
|
||||
next-themes@0.3.0:
|
||||
resolution: {integrity: sha512-/QHIrsYpd6Kfk7xakK4svpDI5mmXP0gfvCoJdGpZQ2TOrQZmsW0QxjaiLn8wbIKjtm4BTSqLoix4lxYYOnLJ/w==}
|
||||
peerDependencies:
|
||||
|
@ -3458,6 +3511,14 @@ packages:
|
|||
node-api-version@0.2.0:
|
||||
resolution: {integrity: sha512-fthTTsi8CxaBXMaBAD7ST2uylwvsnYxh2PfaScwpMhos6KlSFajXQPcM4ogNE1q2s3Lbz9GCGqeIHC+C6OZnKg==}
|
||||
|
||||
node-domexception@1.0.0:
|
||||
resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==}
|
||||
engines: {node: '>=10.5.0'}
|
||||
|
||||
node-fetch@3.3.2:
|
||||
resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==}
|
||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||
|
||||
node-gyp@9.4.1:
|
||||
resolution: {integrity: sha512-OQkWKbjQKbGkMf/xqI1jjy3oCTgMKJac58G2+bjZb3fza6gW2YrCSdMQYaoTb70crvE//Gngr4f0AgVHmqHvBQ==}
|
||||
engines: {node: ^12.13 || ^14.13 || >=16}
|
||||
|
@ -3576,6 +3637,9 @@ packages:
|
|||
path-parse@1.0.7:
|
||||
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
|
||||
|
||||
path-posix@1.0.0:
|
||||
resolution: {integrity: sha512-1gJ0WpNIiYcQydgg3Ed8KzvIqTsDpNwq+cjBCssvBtuTWjEqY1AW+i+OepiEMqDCzyro9B2sLAe4RBPajMYFiA==}
|
||||
|
||||
path-scurry@1.11.1:
|
||||
resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==}
|
||||
engines: {node: '>=16 || 14 >=14.18'}
|
||||
|
@ -3708,6 +3772,9 @@ packages:
|
|||
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
querystringify@2.2.0:
|
||||
resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==}
|
||||
|
||||
queue-microtask@1.2.3:
|
||||
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
|
||||
|
||||
|
@ -3844,6 +3911,9 @@ packages:
|
|||
resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
requires-port@1.0.0:
|
||||
resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==}
|
||||
|
||||
resedit@1.7.0:
|
||||
resolution: {integrity: sha512-dbsZ0gk5opWPFlKMqvxCrLCuMZUVmsW3yTPT0tT4mYwo5fjQM8c4HMN9ZJt6dRDqDV/78m9SU4rv24PN4NiYaA==}
|
||||
engines: {node: '>=12', npm: '>=6'}
|
||||
|
@ -4070,6 +4140,9 @@ packages:
|
|||
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
strnum@1.0.5:
|
||||
resolution: {integrity: sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==}
|
||||
|
||||
sucrase@3.35.0:
|
||||
resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==}
|
||||
engines: {node: '>=16 || 14 >=14.17'}
|
||||
|
@ -4244,6 +4317,13 @@ packages:
|
|||
uri-js@4.4.1:
|
||||
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
|
||||
|
||||
url-join@5.0.0:
|
||||
resolution: {integrity: sha512-n2huDr9h9yzd6exQVnH/jU5mr+Pfx08LRXXZhkLLetAMESRj+anQsTAh940iMrIetKAmry9coFuZQ2jY8/p3WA==}
|
||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||
|
||||
url-parse@1.5.10:
|
||||
resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==}
|
||||
|
||||
use-callback-ref@1.3.2:
|
||||
resolution: {integrity: sha512-elOQwe6Q8gqZgDA8mrh44qRTQqpIHDcZ3hXTLjBe1i4ph8XpNJnO+aQf3NaG+lriLopI4HMx9VjQLfPQ6vhnoA==}
|
||||
engines: {node: '>=10'}
|
||||
|
@ -4354,6 +4434,14 @@ packages:
|
|||
wcwidth@1.0.1:
|
||||
resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==}
|
||||
|
||||
web-streams-polyfill@3.3.3:
|
||||
resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==}
|
||||
engines: {node: '>= 8'}
|
||||
|
||||
webdav@5.7.1:
|
||||
resolution: {integrity: sha512-JVPn3nLxXJfHSRvennHsOrDYjFLkilZ1Qlw8Ff6hpqp6AvkgF7a//aOh5wA4rMp+sLZ1Km0V+iv0LyO1FIwtXg==}
|
||||
engines: {node: '>=16'}
|
||||
|
||||
which-boxed-primitive@1.0.2:
|
||||
resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==}
|
||||
|
||||
|
@ -4590,6 +4678,10 @@ snapshots:
|
|||
'@babel/helper-validator-identifier': 7.24.7
|
||||
to-fast-properties: 2.0.0
|
||||
|
||||
'@buttercup/fetch@0.2.1':
|
||||
optionalDependencies:
|
||||
node-fetch: 3.3.2
|
||||
|
||||
'@develar/schema-utils@2.6.5':
|
||||
dependencies:
|
||||
ajv: 6.12.6
|
||||
|
@ -7415,6 +7507,8 @@ snapshots:
|
|||
|
||||
balanced-match@1.0.2: {}
|
||||
|
||||
base-64@1.0.0: {}
|
||||
|
||||
base64-js@1.5.1: {}
|
||||
|
||||
binary-extensions@2.3.0: {}
|
||||
|
@ -7512,6 +7606,8 @@ snapshots:
|
|||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
byte-length@1.0.2: {}
|
||||
|
||||
cac@6.7.14: {}
|
||||
|
||||
cacache@16.1.3:
|
||||
|
@ -7574,6 +7670,8 @@ snapshots:
|
|||
ansi-styles: 4.3.0
|
||||
supports-color: 7.2.0
|
||||
|
||||
charenc@0.0.2: {}
|
||||
|
||||
chokidar@3.6.0:
|
||||
dependencies:
|
||||
anymatch: 3.1.3
|
||||
|
@ -7705,10 +7803,14 @@ snapshots:
|
|||
shebang-command: 2.0.0
|
||||
which: 2.0.2
|
||||
|
||||
crypt@0.0.2: {}
|
||||
|
||||
cssesc@3.0.0: {}
|
||||
|
||||
csstype@3.1.3: {}
|
||||
|
||||
data-uri-to-buffer@4.0.1: {}
|
||||
|
||||
data-view-buffer@1.0.1:
|
||||
dependencies:
|
||||
call-bind: 1.0.7
|
||||
|
@ -7923,6 +8025,8 @@ snapshots:
|
|||
dependencies:
|
||||
once: 1.4.0
|
||||
|
||||
entities@5.0.0: {}
|
||||
|
||||
env-paths@2.2.1: {}
|
||||
|
||||
err-code@2.0.3: {}
|
||||
|
@ -8188,6 +8292,10 @@ snapshots:
|
|||
|
||||
fast-levenshtein@2.0.6: {}
|
||||
|
||||
fast-xml-parser@4.4.1:
|
||||
dependencies:
|
||||
strnum: 1.0.5
|
||||
|
||||
fastq@1.17.1:
|
||||
dependencies:
|
||||
reusify: 1.0.4
|
||||
|
@ -8196,6 +8304,11 @@ snapshots:
|
|||
dependencies:
|
||||
pend: 1.2.0
|
||||
|
||||
fetch-blob@3.2.0:
|
||||
dependencies:
|
||||
node-domexception: 1.0.0
|
||||
web-streams-polyfill: 3.3.3
|
||||
|
||||
file-entry-cache@6.0.1:
|
||||
dependencies:
|
||||
flat-cache: 3.2.0
|
||||
|
@ -8240,6 +8353,10 @@ snapshots:
|
|||
combined-stream: 1.0.8
|
||||
mime-types: 2.1.35
|
||||
|
||||
formdata-polyfill@4.0.10:
|
||||
dependencies:
|
||||
fetch-blob: 3.2.0
|
||||
|
||||
fraction.js@4.3.7: {}
|
||||
|
||||
framer-motion@11.3.21(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
|
||||
|
@ -8449,6 +8566,8 @@ snapshots:
|
|||
dependencies:
|
||||
lru-cache: 6.0.0
|
||||
|
||||
hot-patcher@2.0.1: {}
|
||||
|
||||
http-cache-semantics@4.1.1: {}
|
||||
|
||||
http-proxy-agent@5.0.0:
|
||||
|
@ -8553,6 +8672,8 @@ snapshots:
|
|||
call-bind: 1.0.7
|
||||
has-tostringtag: 1.0.2
|
||||
|
||||
is-buffer@1.1.6: {}
|
||||
|
||||
is-callable@1.2.7: {}
|
||||
|
||||
is-ci@3.0.1:
|
||||
|
@ -8716,6 +8837,8 @@ snapshots:
|
|||
dependencies:
|
||||
json-buffer: 3.0.1
|
||||
|
||||
layerr@3.0.0: {}
|
||||
|
||||
lazy-val@1.0.5: {}
|
||||
|
||||
lazystream@1.0.1:
|
||||
|
@ -8817,6 +8940,12 @@ snapshots:
|
|||
escape-string-regexp: 4.0.0
|
||||
optional: true
|
||||
|
||||
md5@2.3.0:
|
||||
dependencies:
|
||||
charenc: 0.0.2
|
||||
crypt: 0.0.2
|
||||
is-buffer: 1.1.6
|
||||
|
||||
merge2@1.4.1: {}
|
||||
|
||||
meta-json-schema@1.18.6: {}
|
||||
|
@ -8959,6 +9088,8 @@ snapshots:
|
|||
|
||||
negotiator@0.6.3: {}
|
||||
|
||||
nested-property@4.0.0: {}
|
||||
|
||||
next-themes@0.3.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
|
||||
dependencies:
|
||||
react: 18.3.1
|
||||
|
@ -8975,6 +9106,14 @@ snapshots:
|
|||
dependencies:
|
||||
semver: 7.6.3
|
||||
|
||||
node-domexception@1.0.0: {}
|
||||
|
||||
node-fetch@3.3.2:
|
||||
dependencies:
|
||||
data-uri-to-buffer: 4.0.1
|
||||
fetch-blob: 3.2.0
|
||||
formdata-polyfill: 4.0.10
|
||||
|
||||
node-gyp@9.4.1:
|
||||
dependencies:
|
||||
env-paths: 2.2.1
|
||||
|
@ -9104,6 +9243,8 @@ snapshots:
|
|||
|
||||
path-parse@1.0.7: {}
|
||||
|
||||
path-posix@1.0.0: {}
|
||||
|
||||
path-scurry@1.11.1:
|
||||
dependencies:
|
||||
lru-cache: 10.4.3
|
||||
|
@ -9206,6 +9347,8 @@ snapshots:
|
|||
|
||||
punycode@2.3.1: {}
|
||||
|
||||
querystringify@2.2.0: {}
|
||||
|
||||
queue-microtask@1.2.3: {}
|
||||
|
||||
quick-lru@5.1.1: {}
|
||||
|
@ -9358,6 +9501,8 @@ snapshots:
|
|||
|
||||
require-directory@2.1.1: {}
|
||||
|
||||
requires-port@1.0.0: {}
|
||||
|
||||
resedit@1.7.0:
|
||||
dependencies:
|
||||
pe-library: 0.4.0
|
||||
|
@ -9635,6 +9780,8 @@ snapshots:
|
|||
|
||||
strip-json-comments@3.1.1: {}
|
||||
|
||||
strnum@1.0.5: {}
|
||||
|
||||
sucrase@3.35.0:
|
||||
dependencies:
|
||||
'@jridgewell/gen-mapping': 0.3.5
|
||||
|
@ -9856,6 +10003,13 @@ snapshots:
|
|||
dependencies:
|
||||
punycode: 2.3.1
|
||||
|
||||
url-join@5.0.0: {}
|
||||
|
||||
url-parse@1.5.10:
|
||||
dependencies:
|
||||
querystringify: 2.2.0
|
||||
requires-port: 1.0.0
|
||||
|
||||
use-callback-ref@1.3.2(@types/react@18.3.3)(react@18.3.1):
|
||||
dependencies:
|
||||
react: 18.3.1
|
||||
|
@ -9933,6 +10087,25 @@ snapshots:
|
|||
dependencies:
|
||||
defaults: 1.0.4
|
||||
|
||||
web-streams-polyfill@3.3.3: {}
|
||||
|
||||
webdav@5.7.1:
|
||||
dependencies:
|
||||
'@buttercup/fetch': 0.2.1
|
||||
base-64: 1.0.0
|
||||
byte-length: 1.0.2
|
||||
entities: 5.0.0
|
||||
fast-xml-parser: 4.4.1
|
||||
hot-patcher: 2.0.1
|
||||
layerr: 3.0.0
|
||||
md5: 2.3.0
|
||||
minimatch: 9.0.5
|
||||
nested-property: 4.0.0
|
||||
node-fetch: 3.3.2
|
||||
path-posix: 1.0.0
|
||||
url-join: 5.0.0
|
||||
url-parse: 1.5.10
|
||||
|
||||
which-boxed-primitive@1.0.2:
|
||||
dependencies:
|
||||
is-bigint: 1.0.4
|
||||
|
|
72
src/main/resolve/backup.ts
Normal file
72
src/main/resolve/backup.ts
Normal file
|
@ -0,0 +1,72 @@
|
|||
import { getAppConfig } from '../config'
|
||||
import AdmZip from 'adm-zip'
|
||||
import {
|
||||
appConfigPath,
|
||||
controledMihomoConfigPath,
|
||||
dataDir,
|
||||
overrideConfigPath,
|
||||
overrideDir,
|
||||
profileConfigPath,
|
||||
profilesDir
|
||||
} from '../utils/dirs'
|
||||
import { app } from 'electron'
|
||||
|
||||
export async function webdavBackup(): Promise<boolean> {
|
||||
const webdav = await import('webdav')
|
||||
const createClient = webdav.createClient
|
||||
const { webdavUrl = '', webdavUsername = '', webdavPassword = '' } = await getAppConfig()
|
||||
const zip = new AdmZip()
|
||||
|
||||
zip.addLocalFile(appConfigPath())
|
||||
zip.addLocalFile(controledMihomoConfigPath())
|
||||
zip.addLocalFile(profileConfigPath())
|
||||
zip.addLocalFile(overrideConfigPath())
|
||||
zip.addLocalFolder(profilesDir(), 'profiles')
|
||||
zip.addLocalFolder(overrideDir(), 'override')
|
||||
const zipFileName = `backup-${new Date().toISOString().replace(/:/g, '-')}.zip`
|
||||
|
||||
const client = createClient(webdavUrl, {
|
||||
username: webdavUsername,
|
||||
password: webdavPassword
|
||||
})
|
||||
try {
|
||||
await client.createDirectory('mihomo-party')
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
|
||||
return await client.putFileContents(`mihomo-party/${zipFileName}`, zip.toBuffer())
|
||||
}
|
||||
|
||||
export async function webdavRestore(filename: string): Promise<void> {
|
||||
const webdav = await import('webdav')
|
||||
const createClient = webdav.createClient
|
||||
const { webdavUrl = '', webdavUsername = '', webdavPassword = '' } = await getAppConfig()
|
||||
|
||||
const client = createClient(webdavUrl, {
|
||||
username: webdavUsername,
|
||||
password: webdavPassword
|
||||
})
|
||||
const zipData = await client.getFileContents(`/mihomo-party/${filename}`)
|
||||
const zip = new AdmZip(zipData)
|
||||
zip.extractAllTo(dataDir(), true)
|
||||
app.relaunch()
|
||||
app.quit()
|
||||
}
|
||||
|
||||
export async function listWebdavBackups(): Promise<string[]> {
|
||||
const webdav = await import('webdav')
|
||||
const createClient = webdav.createClient
|
||||
const { webdavUrl = '', webdavUsername = '', webdavPassword = '' } = await getAppConfig()
|
||||
|
||||
const client = createClient(webdavUrl, {
|
||||
username: webdavUsername,
|
||||
password: webdavPassword
|
||||
})
|
||||
const files = await client.getDirectoryContents('mihomo-party', { glob: '*.zip' })
|
||||
if (Array.isArray(files)) {
|
||||
return files.map((file) => file.basename)
|
||||
} else {
|
||||
return files.data.map((file) => file.basename)
|
||||
}
|
||||
}
|
|
@ -50,6 +50,7 @@ import { checkUpdate } from '../resolve/autoUpdater'
|
|||
import { getFilePath, openUWPTool, readTextFile, setupFirewall } from '../sys/misc'
|
||||
import { getRuntimeConfig, getRuntimeConfigStr } from '../core/factory'
|
||||
import { isPortable, setPortable } from './dirs'
|
||||
import { listWebdavBackups, webdavBackup, webdavRestore } from '../resolve/backup'
|
||||
|
||||
function ipcErrorWrapper<T>( // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
fn: (...args: any[]) => Promise<T> // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
|
@ -137,5 +138,8 @@ export function registerIpcMainHandlers(): void {
|
|||
ipcMain.handle('setupFirewall', ipcErrorWrapper(setupFirewall))
|
||||
ipcMain.handle('setPortable', (_e, portable) => ipcErrorWrapper(setPortable)(portable))
|
||||
ipcMain.handle('isPortable', isPortable)
|
||||
ipcMain.handle('webdavBackup', ipcErrorWrapper(webdavBackup))
|
||||
ipcMain.handle('webdavRestore', (_e, filename) => ipcErrorWrapper(webdavRestore)(filename))
|
||||
ipcMain.handle('listWebdavBackups', ipcErrorWrapper(listWebdavBackups))
|
||||
ipcMain.handle('quitApp', () => app.quit())
|
||||
}
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
import { Modal, ModalContent, ModalHeader, ModalBody, ModalFooter, Button } from '@nextui-org/react'
|
||||
import { webdavRestore } from '@renderer/utils/ipc'
|
||||
import React, { useState } from 'react'
|
||||
interface Props {
|
||||
filenames: string[]
|
||||
onClose: () => void
|
||||
}
|
||||
const WebdavRestoreModal: React.FC<Props> = (props) => {
|
||||
const { filenames, onClose } = props
|
||||
const [restoring, setRestoring] = useState(false)
|
||||
|
||||
return (
|
||||
<Modal
|
||||
backdrop="blur"
|
||||
hideCloseButton
|
||||
isOpen={true}
|
||||
onOpenChange={onClose}
|
||||
scrollBehavior="inside"
|
||||
>
|
||||
<ModalContent>
|
||||
<ModalHeader className="flex">恢复备份</ModalHeader>
|
||||
<ModalBody>
|
||||
{filenames.length === 0 ? (
|
||||
<div className="flex justify-center">还没有备份</div>
|
||||
) : (
|
||||
filenames.map((filename) => (
|
||||
<Button
|
||||
size="sm"
|
||||
fullWidth
|
||||
key={filename}
|
||||
isLoading={restoring}
|
||||
variant="flat"
|
||||
onPress={async () => {
|
||||
setRestoring(true)
|
||||
try {
|
||||
await webdavRestore(filename)
|
||||
} catch (e) {
|
||||
alert(`恢复失败: ${e}`)
|
||||
} finally {
|
||||
setRestoring(false)
|
||||
}
|
||||
}}
|
||||
>
|
||||
{filename}
|
||||
</Button>
|
||||
))
|
||||
)}
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button variant="light" onPress={onClose}>
|
||||
关闭
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
export default WebdavRestoreModal
|
|
@ -12,7 +12,9 @@ import {
|
|||
patchControledMihomoConfig,
|
||||
isPortable,
|
||||
setPortable,
|
||||
restartCore
|
||||
restartCore,
|
||||
webdavBackup,
|
||||
listWebdavBackups
|
||||
} from '@renderer/utils/ipc'
|
||||
import { IoLogoGithub } from 'react-icons/io5'
|
||||
import { platform, version } from '@renderer/utils/init'
|
||||
|
@ -20,6 +22,7 @@ import useSWR from 'swr'
|
|||
import { Key, useState } from 'react'
|
||||
import debounce from '@renderer/utils/debounce'
|
||||
import { useTheme } from 'next-themes'
|
||||
import WebdavRestoreModal from '@renderer/components/settings/webdav-restore-modal'
|
||||
|
||||
const Settings: React.FC = () => {
|
||||
const { setTheme } = useTheme()
|
||||
|
@ -37,8 +40,15 @@ const Settings: React.FC = () => {
|
|||
autoCheckUpdate,
|
||||
userAgent,
|
||||
autoCloseConnection = true,
|
||||
appTheme = 'system'
|
||||
appTheme = 'system',
|
||||
webdavUrl,
|
||||
webdavUsername,
|
||||
webdavPassword
|
||||
} = appConfig || {}
|
||||
const [backuping, setBackuping] = useState(false)
|
||||
const [restoring, setRestoring] = useState(false)
|
||||
const [filenames, setFilenames] = useState<string[]>([])
|
||||
const [restoreOpen, setRestoreOpen] = useState(false)
|
||||
const [url, setUrl] = useState(delayTestUrl)
|
||||
const setUrlDebounce = debounce((v: string) => {
|
||||
patchAppConfig({ delayTestUrl: v })
|
||||
|
@ -47,7 +57,10 @@ const Settings: React.FC = () => {
|
|||
const setUaDebounce = debounce((v: string) => {
|
||||
patchAppConfig({ userAgent: v })
|
||||
}, 500)
|
||||
|
||||
const [webdav, setWebdav] = useState({ webdavUrl, webdavUsername, webdavPassword })
|
||||
const setWebdavDebounce = debounce(({ webdavUrl, webdavUsername, webdavPassword }) => {
|
||||
patchAppConfig({ webdavUrl, webdavUsername, webdavPassword })
|
||||
}, 500)
|
||||
const onThemeChange = (key: Key, type: 'theme' | 'color'): void => {
|
||||
const [theme, color] = appTheme.split('-')
|
||||
|
||||
|
@ -72,238 +85,323 @@ const Settings: React.FC = () => {
|
|||
}
|
||||
}
|
||||
|
||||
const handleBackup = async (): Promise<void> => {
|
||||
setBackuping(true)
|
||||
try {
|
||||
await webdavBackup()
|
||||
new window.Notification('备份成功', { body: '备份文件已上传至WebDav' })
|
||||
} catch (e) {
|
||||
alert(e)
|
||||
} finally {
|
||||
setBackuping(false)
|
||||
}
|
||||
}
|
||||
|
||||
const handleRestore = async (): Promise<void> => {
|
||||
try {
|
||||
setRestoring(true)
|
||||
const filenames = await listWebdavBackups()
|
||||
setRestoring(false)
|
||||
setFilenames(filenames)
|
||||
setRestoreOpen(true)
|
||||
} catch (e) {
|
||||
alert(`获取备份列表失败: ${e}`)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<BasePage
|
||||
title="应用设置"
|
||||
header={
|
||||
<Button
|
||||
isIconOnly
|
||||
size="sm"
|
||||
onPress={() => {
|
||||
window.open('https://github.com/pompurin404/mihomo-party')
|
||||
}}
|
||||
>
|
||||
<IoLogoGithub className="text-lg" />
|
||||
</Button>
|
||||
}
|
||||
>
|
||||
<SettingCard>
|
||||
<SettingItem title="开机自启" divider>
|
||||
<Switch
|
||||
<>
|
||||
{restoreOpen && (
|
||||
<WebdavRestoreModal filenames={filenames} onClose={() => setRestoreOpen(false)} />
|
||||
)}
|
||||
|
||||
<BasePage
|
||||
title="应用设置"
|
||||
header={
|
||||
<Button
|
||||
isIconOnly
|
||||
size="sm"
|
||||
isSelected={enable}
|
||||
onValueChange={async (v) => {
|
||||
try {
|
||||
if (v) {
|
||||
await enableAutoRun()
|
||||
} else {
|
||||
await disableAutoRun()
|
||||
}
|
||||
} catch (e) {
|
||||
alert(e)
|
||||
} finally {
|
||||
mutateEnable()
|
||||
}
|
||||
onPress={() => {
|
||||
window.open('https://github.com/pompurin404/mihomo-party')
|
||||
}}
|
||||
/>
|
||||
</SettingItem>
|
||||
<SettingItem title="自动检查更新" divider>
|
||||
<Switch
|
||||
size="sm"
|
||||
isSelected={autoCheckUpdate}
|
||||
onValueChange={(v) => {
|
||||
patchAppConfig({ autoCheckUpdate: v })
|
||||
}}
|
||||
/>
|
||||
</SettingItem>
|
||||
<SettingItem title="静默启动" divider>
|
||||
<Switch
|
||||
size="sm"
|
||||
isSelected={silentStart}
|
||||
onValueChange={(v) => {
|
||||
patchAppConfig({ silentStart: v })
|
||||
}}
|
||||
/>
|
||||
</SettingItem>
|
||||
{platform === 'darwin' && (
|
||||
<>
|
||||
<SettingItem title="显示Dock图标" divider>
|
||||
<Switch
|
||||
size="sm"
|
||||
isSelected={useDockIcon}
|
||||
onValueChange={async (v) => {
|
||||
await patchAppConfig({ useDockIcon: v })
|
||||
}}
|
||||
/>
|
||||
</SettingItem>
|
||||
<SettingItem title="显示网速信息" divider>
|
||||
<Switch
|
||||
size="sm"
|
||||
isSelected={showTraffic}
|
||||
onValueChange={async (v) => {
|
||||
await patchAppConfig({ showTraffic: v })
|
||||
await restartCore()
|
||||
}}
|
||||
/>
|
||||
</SettingItem>
|
||||
</>
|
||||
)}
|
||||
{platform === 'win32' && (
|
||||
<SettingItem title="数据存储路径" divider>
|
||||
<Select
|
||||
className="w-[150px]"
|
||||
>
|
||||
<IoLogoGithub className="text-lg" />
|
||||
</Button>
|
||||
}
|
||||
>
|
||||
<SettingCard>
|
||||
<SettingItem title="开机自启" divider>
|
||||
<Switch
|
||||
size="sm"
|
||||
selectedKeys={new Set([portable ? 'portable' : 'data'])}
|
||||
onSelectionChange={async (v) => {
|
||||
isSelected={enable}
|
||||
onValueChange={async (v) => {
|
||||
try {
|
||||
await setPortable(v.currentKey === 'portable')
|
||||
if (v) {
|
||||
await enableAutoRun()
|
||||
} else {
|
||||
await disableAutoRun()
|
||||
}
|
||||
} catch (e) {
|
||||
alert(e)
|
||||
} finally {
|
||||
mutatePortable()
|
||||
mutateEnable()
|
||||
}
|
||||
}}
|
||||
>
|
||||
<SelectItem key="data">AppData</SelectItem>
|
||||
<SelectItem key="portable">安装目录</SelectItem>
|
||||
</Select>
|
||||
/>
|
||||
</SettingItem>
|
||||
)}
|
||||
|
||||
<SettingItem title="背景色" divider={appTheme !== 'system'}>
|
||||
<Tabs
|
||||
size="sm"
|
||||
color="primary"
|
||||
selectedKey={appTheme.split('-')[0]}
|
||||
onSelectionChange={(key) => {
|
||||
onThemeChange(key, 'theme')
|
||||
}}
|
||||
>
|
||||
<Tab key="system" title="自动" />
|
||||
<Tab key="dark" title="深色" />
|
||||
<Tab key="gray" title="灰色" />
|
||||
<Tab key="light" title="浅色" />
|
||||
</Tabs>
|
||||
</SettingItem>
|
||||
{appTheme !== 'system' && (
|
||||
<SettingItem title="主题色">
|
||||
<SettingItem title="自动检查更新" divider>
|
||||
<Switch
|
||||
size="sm"
|
||||
isSelected={autoCheckUpdate}
|
||||
onValueChange={(v) => {
|
||||
patchAppConfig({ autoCheckUpdate: v })
|
||||
}}
|
||||
/>
|
||||
</SettingItem>
|
||||
<SettingItem title="静默启动" divider>
|
||||
<Switch
|
||||
size="sm"
|
||||
isSelected={silentStart}
|
||||
onValueChange={(v) => {
|
||||
patchAppConfig({ silentStart: v })
|
||||
}}
|
||||
/>
|
||||
</SettingItem>
|
||||
{platform === 'darwin' && (
|
||||
<>
|
||||
<SettingItem title="显示Dock图标" divider>
|
||||
<Switch
|
||||
size="sm"
|
||||
isSelected={useDockIcon}
|
||||
onValueChange={async (v) => {
|
||||
await patchAppConfig({ useDockIcon: v })
|
||||
}}
|
||||
/>
|
||||
</SettingItem>
|
||||
<SettingItem title="显示网速信息" divider>
|
||||
<Switch
|
||||
size="sm"
|
||||
isSelected={showTraffic}
|
||||
onValueChange={async (v) => {
|
||||
await patchAppConfig({ showTraffic: v })
|
||||
await restartCore()
|
||||
}}
|
||||
/>
|
||||
</SettingItem>
|
||||
</>
|
||||
)}
|
||||
{platform === 'win32' && (
|
||||
<SettingItem title="数据存储路径" divider>
|
||||
<Select
|
||||
className="w-[150px]"
|
||||
size="sm"
|
||||
selectedKeys={new Set([portable ? 'portable' : 'data'])}
|
||||
onSelectionChange={async (v) => {
|
||||
try {
|
||||
await setPortable(v.currentKey === 'portable')
|
||||
} catch (e) {
|
||||
alert(e)
|
||||
} finally {
|
||||
mutatePortable()
|
||||
}
|
||||
}}
|
||||
>
|
||||
<SelectItem key="data">AppData</SelectItem>
|
||||
<SelectItem key="portable">安装目录</SelectItem>
|
||||
</Select>
|
||||
</SettingItem>
|
||||
)}
|
||||
<SettingItem title="背景色" divider={appTheme !== 'system'}>
|
||||
<Tabs
|
||||
size="sm"
|
||||
color="primary"
|
||||
selectedKey={appTheme.split('-')[1] || 'blue'}
|
||||
selectedKey={appTheme.split('-')[0]}
|
||||
onSelectionChange={(key) => {
|
||||
onThemeChange(key, 'color')
|
||||
onThemeChange(key, 'theme')
|
||||
}}
|
||||
>
|
||||
<Tab key="blue" title="蓝色" />
|
||||
<Tab key="pink" title="粉色" />
|
||||
<Tab key="green" title="绿色" />
|
||||
<Tab key="system" title="自动" />
|
||||
<Tab key="dark" title="深色" />
|
||||
<Tab key="gray" title="灰色" />
|
||||
<Tab key="light" title="浅色" />
|
||||
</Tabs>
|
||||
</SettingItem>
|
||||
)}
|
||||
</SettingCard>
|
||||
<SettingCard>
|
||||
<SettingItem title="订阅拉取 UA" divider>
|
||||
<Input
|
||||
size="sm"
|
||||
className="w-[60%]"
|
||||
value={ua}
|
||||
placeholder="默认 clash-meta"
|
||||
onValueChange={(v) => {
|
||||
setUa(v)
|
||||
setUaDebounce(v)
|
||||
}}
|
||||
></Input>
|
||||
</SettingItem>
|
||||
<SettingItem title="延迟测试地址" divider>
|
||||
<Input
|
||||
size="sm"
|
||||
className="w-[60%]"
|
||||
value={url}
|
||||
placeholder="默认https://www.gstatic.com/generate_204"
|
||||
onValueChange={(v) => {
|
||||
setUrl(v)
|
||||
setUrlDebounce(v)
|
||||
}}
|
||||
></Input>
|
||||
</SettingItem>
|
||||
<SettingItem title="延迟测试超时时间" divider>
|
||||
<Input
|
||||
type="number"
|
||||
size="sm"
|
||||
className="w-[60%]"
|
||||
value={delayTestTimeout?.toString()}
|
||||
placeholder="默认5000"
|
||||
onValueChange={(v) => {
|
||||
patchAppConfig({ delayTestTimeout: parseInt(v) })
|
||||
}}
|
||||
/>
|
||||
</SettingItem>
|
||||
<SettingItem title="接管DNS设置" divider>
|
||||
<Switch
|
||||
size="sm"
|
||||
isSelected={controlDns}
|
||||
onValueChange={async (v) => {
|
||||
await patchAppConfig({ controlDns: v })
|
||||
await patchControledMihomoConfig({})
|
||||
}}
|
||||
/>
|
||||
</SettingItem>
|
||||
<SettingItem title="接管域名嗅探设置" divider>
|
||||
<Switch
|
||||
size="sm"
|
||||
isSelected={controlSniff}
|
||||
onValueChange={async (v) => {
|
||||
await patchAppConfig({ controlSniff: v })
|
||||
await patchControledMihomoConfig({})
|
||||
}}
|
||||
/>
|
||||
</SettingItem>
|
||||
<SettingItem title="自动断开连接">
|
||||
<Switch
|
||||
size="sm"
|
||||
isSelected={autoCloseConnection}
|
||||
onValueChange={(v) => {
|
||||
patchAppConfig({ autoCloseConnection: v })
|
||||
}}
|
||||
/>
|
||||
</SettingItem>
|
||||
</SettingCard>
|
||||
<SettingCard>
|
||||
<SettingItem title="检查更新" divider>
|
||||
<Button
|
||||
size="sm"
|
||||
onPress={async () => {
|
||||
try {
|
||||
const version = await checkUpdate()
|
||||
{appTheme !== 'system' && (
|
||||
<SettingItem title="主题色">
|
||||
<Tabs
|
||||
size="sm"
|
||||
color="primary"
|
||||
selectedKey={appTheme.split('-')[1] || 'blue'}
|
||||
onSelectionChange={(key) => {
|
||||
onThemeChange(key, 'color')
|
||||
}}
|
||||
>
|
||||
<Tab key="blue" title="蓝色" />
|
||||
<Tab key="pink" title="粉色" />
|
||||
<Tab key="green" title="绿色" />
|
||||
</Tabs>
|
||||
</SettingItem>
|
||||
)}
|
||||
</SettingCard>
|
||||
<SettingCard>
|
||||
<SettingItem title="WebDav地址" divider>
|
||||
<Input
|
||||
size="sm"
|
||||
className="w-[60%]"
|
||||
value={webdav.webdavUrl}
|
||||
onValueChange={(v) => {
|
||||
setWebdav({ ...webdav, webdavUrl: v })
|
||||
setWebdavDebounce({ ...webdav, webdavUrl: v })
|
||||
}}
|
||||
/>
|
||||
</SettingItem>
|
||||
<SettingItem title="WebDav用户名" divider>
|
||||
<Input
|
||||
size="sm"
|
||||
className="w-[60%]"
|
||||
value={webdav.webdavUsername}
|
||||
onValueChange={(v) => {
|
||||
setWebdav({ ...webdav, webdavUsername: v })
|
||||
setWebdavDebounce({ ...webdav, webdavUsername: v })
|
||||
}}
|
||||
/>
|
||||
</SettingItem>
|
||||
<SettingItem title="WebDav密码" divider>
|
||||
<Input
|
||||
size="sm"
|
||||
className="w-[60%]"
|
||||
type="password"
|
||||
value={webdav.webdavPassword}
|
||||
onValueChange={(v) => {
|
||||
setWebdav({ ...webdav, webdavPassword: v })
|
||||
setWebdavDebounce({ ...webdav, webdavPassword: v })
|
||||
}}
|
||||
/>
|
||||
</SettingItem>
|
||||
<div className="flex justify0between">
|
||||
<Button
|
||||
isLoading={backuping}
|
||||
fullWidth
|
||||
size="sm"
|
||||
className="mr-1"
|
||||
onPress={handleBackup}
|
||||
>
|
||||
备份
|
||||
</Button>
|
||||
<Button
|
||||
isLoading={restoring}
|
||||
fullWidth
|
||||
size="sm"
|
||||
className="ml-1"
|
||||
onPress={handleRestore}
|
||||
>
|
||||
恢复
|
||||
</Button>
|
||||
</div>
|
||||
</SettingCard>
|
||||
<SettingCard>
|
||||
<SettingItem title="订阅拉取 UA" divider>
|
||||
<Input
|
||||
size="sm"
|
||||
className="w-[60%]"
|
||||
value={ua}
|
||||
placeholder="默认 clash-meta"
|
||||
onValueChange={(v) => {
|
||||
setUa(v)
|
||||
setUaDebounce(v)
|
||||
}}
|
||||
></Input>
|
||||
</SettingItem>
|
||||
<SettingItem title="延迟测试地址" divider>
|
||||
<Input
|
||||
size="sm"
|
||||
className="w-[60%]"
|
||||
value={url}
|
||||
placeholder="默认https://www.gstatic.com/generate_204"
|
||||
onValueChange={(v) => {
|
||||
setUrl(v)
|
||||
setUrlDebounce(v)
|
||||
}}
|
||||
></Input>
|
||||
</SettingItem>
|
||||
<SettingItem title="延迟测试超时时间" divider>
|
||||
<Input
|
||||
type="number"
|
||||
size="sm"
|
||||
className="w-[60%]"
|
||||
value={delayTestTimeout?.toString()}
|
||||
placeholder="默认5000"
|
||||
onValueChange={(v) => {
|
||||
patchAppConfig({ delayTestTimeout: parseInt(v) })
|
||||
}}
|
||||
/>
|
||||
</SettingItem>
|
||||
<SettingItem title="接管DNS设置" divider>
|
||||
<Switch
|
||||
size="sm"
|
||||
isSelected={controlDns}
|
||||
onValueChange={async (v) => {
|
||||
await patchAppConfig({ controlDns: v })
|
||||
await patchControledMihomoConfig({})
|
||||
}}
|
||||
/>
|
||||
</SettingItem>
|
||||
<SettingItem title="接管域名嗅探设置" divider>
|
||||
<Switch
|
||||
size="sm"
|
||||
isSelected={controlSniff}
|
||||
onValueChange={async (v) => {
|
||||
await patchAppConfig({ controlSniff: v })
|
||||
await patchControledMihomoConfig({})
|
||||
}}
|
||||
/>
|
||||
</SettingItem>
|
||||
<SettingItem title="自动断开连接">
|
||||
<Switch
|
||||
size="sm"
|
||||
isSelected={autoCloseConnection}
|
||||
onValueChange={(v) => {
|
||||
patchAppConfig({ autoCloseConnection: v })
|
||||
}}
|
||||
/>
|
||||
</SettingItem>
|
||||
</SettingCard>
|
||||
<SettingCard>
|
||||
<SettingItem title="检查更新" divider>
|
||||
<Button
|
||||
size="sm"
|
||||
onPress={async () => {
|
||||
try {
|
||||
const version = await checkUpdate()
|
||||
|
||||
if (version) {
|
||||
new window.Notification(`v${version}版本已发布`, {
|
||||
body: '点击前往下载'
|
||||
}).onclick = (): void => {
|
||||
open(`https://github.com/pompurin404/mihomo-party/releases/tag/v${version}`)
|
||||
if (version) {
|
||||
new window.Notification(`v${version}版本已发布`, {
|
||||
body: '点击前往下载'
|
||||
}).onclick = (): void => {
|
||||
open(`https://github.com/pompurin404/mihomo-party/releases/tag/v${version}`)
|
||||
}
|
||||
} else {
|
||||
new window.Notification('当前已是最新版本', { body: '无需更新' })
|
||||
}
|
||||
} else {
|
||||
new window.Notification('当前已是最新版本', { body: '无需更新' })
|
||||
} catch (e) {
|
||||
alert(e)
|
||||
}
|
||||
} catch (e) {
|
||||
alert(e)
|
||||
}
|
||||
}}
|
||||
>
|
||||
检查更新
|
||||
</Button>
|
||||
</SettingItem>
|
||||
<SettingItem title="退出应用" divider>
|
||||
<Button size="sm" onPress={quitApp}>
|
||||
退出应用
|
||||
</Button>
|
||||
</SettingItem>
|
||||
<SettingItem title="应用版本">
|
||||
<div>v{version}</div>
|
||||
</SettingItem>
|
||||
</SettingCard>
|
||||
</BasePage>
|
||||
}}
|
||||
>
|
||||
检查更新
|
||||
</Button>
|
||||
</SettingItem>
|
||||
<SettingItem title="退出应用" divider>
|
||||
<Button size="sm" onPress={quitApp}>
|
||||
退出应用
|
||||
</Button>
|
||||
</SettingItem>
|
||||
<SettingItem title="应用版本">
|
||||
<div>v{version}</div>
|
||||
</SettingItem>
|
||||
</SettingCard>
|
||||
</BasePage>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -253,6 +253,18 @@ export async function isPortable(): Promise<boolean> {
|
|||
return ipcErrorWrapper(await window.electron.ipcRenderer.invoke('isPortable'))
|
||||
}
|
||||
|
||||
export async function webdavBackup(): Promise<boolean> {
|
||||
return ipcErrorWrapper(await window.electron.ipcRenderer.invoke('webdavBackup'))
|
||||
}
|
||||
|
||||
export async function webdavRestore(filename: string): Promise<void> {
|
||||
return ipcErrorWrapper(await window.electron.ipcRenderer.invoke('webdavRestore', filename))
|
||||
}
|
||||
|
||||
export async function listWebdavBackups(): Promise<string[]> {
|
||||
return ipcErrorWrapper(await window.electron.ipcRenderer.invoke('listWebdavBackups'))
|
||||
}
|
||||
|
||||
export async function quitApp(): Promise<void> {
|
||||
return ipcErrorWrapper(await window.electron.ipcRenderer.invoke('quitApp'))
|
||||
}
|
||||
|
|
3
src/shared/types.d.ts
vendored
3
src/shared/types.d.ts
vendored
|
@ -218,6 +218,9 @@ interface IAppConfig {
|
|||
controlSniff?: boolean
|
||||
useDockIcon?: boolean
|
||||
showTraffic?: boolean
|
||||
webdavUrl?: string
|
||||
webdavUsername?: string
|
||||
webdavPassword?: string
|
||||
useNameserverPolicy: boolean
|
||||
nameserverPolicy: { [key: string]: string | string[] }
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user