diff --git a/changelog.md b/changelog.md index 4385a8d..3ba6b04 100644 --- a/changelog.md +++ b/changelog.md @@ -4,11 +4,8 @@ ### New Features -- 代理组图标支持SVG格式 -- 优化覆写启用逻辑 -- 覆写支持全局启用 -- 筛选过滤忽略大小写 +- 支持设置 Sub-Store 定时同步 ### Bug Fixes -- 修复 MacOS 上复制粘贴快捷键失效的问题 +- 修复全局覆写重复执行的问题 diff --git a/package.json b/package.json index 6379162..a89f9d8 100644 --- a/package.json +++ b/package.json @@ -52,6 +52,7 @@ "@types/ws": "^8.5.12", "@vitejs/plugin-react": "^4.3.1", "autoprefixer": "^10.4.20", + "cron-validator": "^1.3.1", "driver.js": "^1.3.1", "electron": "^32.0.2", "electron-builder": "^25.0.5", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b390671..b67ee45 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -93,6 +93,9 @@ importers: autoprefixer: specifier: ^10.4.20 version: 10.4.20(postcss@8.4.45) + cron-validator: + specifier: ^1.3.1 + version: 1.3.1 driver.js: specifier: ^1.3.1 version: 1.3.1 @@ -2661,6 +2664,9 @@ packages: crc@3.8.0: resolution: {integrity: sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==} + cron-validator@1.3.1: + resolution: {integrity: sha512-C1HsxuPCY/5opR55G5/WNzyEGDWFVG+6GLrA+fW/sCTcP6A6NTjUP2AK7B8n2PyFs90kDG2qzwm8LMheADku6A==} + cross-spawn@7.0.3: resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} engines: {node: '>= 8'} @@ -8717,6 +8723,8 @@ snapshots: buffer: 5.7.1 optional: true + cron-validator@1.3.1: {} + cross-spawn@7.0.3: dependencies: path-key: 3.1.1 diff --git a/src/main/resolve/server.ts b/src/main/resolve/server.ts index 5a191d1..35e69d7 100644 --- a/src/main/resolve/server.ts +++ b/src/main/resolve/server.ts @@ -57,7 +57,13 @@ export async function startPacServer(): Promise { } export async function startSubStoreServer(): Promise { - const { useSubStore = true, useCustomSubStore = false } = await getAppConfig() + const { + useSubStore = true, + useCustomSubStore = false, + subStoreBackendSyncCron = '', + subStoreBackendDownloadCron = '', + subStoreBackendUploadCron = '' + } = await getAppConfig() if (!useSubStore) return if (!subStoreFrontendPort) { subStoreFrontendPort = await findAvailablePort(4000) @@ -74,7 +80,10 @@ export async function startSubStoreServer(): Promise { SUB_STORE_BACKEND_API_PORT: subStorePort.toString(), SUB_STORE_DATA_BASE_PATH: subStoreDir(), SUB_STORE_BACKEND_CUSTOM_ICON: icon.toDataURL(), - SUB_STORE_BACKEND_CUSTOM_NAME: 'Mihomo Party' + SUB_STORE_BACKEND_CUSTOM_NAME: 'Mihomo Party', + SUB_STORE_BACKEND_SYNC_CRON: subStoreBackendSyncCron, + SUB_STORE_BACKEND_DOWNLOAD_CRON: subStoreBackendDownloadCron, + SUB_STORE_BACKEND_UPLOAD_CRON: subStoreBackendUploadCron } }) } diff --git a/src/renderer/src/components/base/base-setting-card.tsx b/src/renderer/src/components/base/base-setting-card.tsx index a108b87..61aeadb 100644 --- a/src/renderer/src/components/base/base-setting-card.tsx +++ b/src/renderer/src/components/base/base-setting-card.tsx @@ -14,7 +14,12 @@ const SettingCard: React.FC = (props) => { ) : ( - + {props.children} diff --git a/src/renderer/src/components/settings/general-config.tsx b/src/renderer/src/components/settings/general-config.tsx index 2eadec5..0e6f435 100644 --- a/src/renderer/src/components/settings/general-config.tsx +++ b/src/renderer/src/components/settings/general-config.tsx @@ -1,4 +1,4 @@ -import React, { Key, useState } from 'react' +import React, { Key } from 'react' import SettingCard from '../base/base-setting-card' import SettingItem from '../base/base-setting-item' import { Button, Input, Select, SelectItem, Switch, Tab, Tabs, Tooltip } from '@nextui-org/react' @@ -10,13 +10,11 @@ import { disableAutoRun, enableAutoRun, relaunchApp, - restartCore, - startSubStoreServer + restartCore } from '@renderer/utils/ipc' import { useAppConfig } from '@renderer/hooks/use-app-config' import { platform } from '@renderer/utils/init' import { useTheme } from 'next-themes' -import debounce from '@renderer/utils/debounce' import { IoIosHelpCircle } from 'react-icons/io' const GeneralConfig: React.FC = () => { @@ -29,20 +27,13 @@ const GeneralConfig: React.FC = () => { showTraffic = true, proxyInTray = true, useWindowFrame = false, - useSubStore = true, autoQuitWithoutCore = false, autoQuitWithoutCoreDelay = 60, - useCustomSubStore = false, - customSubStoreUrl, envType = platform === 'win32' ? 'powershell' : 'bash', autoCheckUpdate, appTheme = 'system' } = appConfig || {} - const [subStoreUrl, setSubStoreUrl] = useState(customSubStoreUrl) - const setSubStoreUrlDebounce = debounce((v: string) => { - patchAppConfig({ customSubStoreUrl: v }) - }, 500) const onThemeChange = (key: Key, type: 'theme' | 'color'): void => { const [theme, color] = appTheme.split('-') @@ -202,50 +193,7 @@ const GeneralConfig: React.FC = () => { )} - - { - try { - await patchAppConfig({ useSubStore: v }) - if (v) await startSubStoreServer() - } catch (e) { - alert(e) - } - }} - /> - - {useSubStore && ( - - { - try { - await patchAppConfig({ useCustomSubStore: v }) - if (!v) await startSubStoreServer() - } catch (e) { - alert(e) - } - }} - /> - - )} - {useCustomSubStore && ( - - { - setSubStoreUrl(v) - setSubStoreUrlDebounce(v) - }} - /> - - )} + { + const { appConfig, patchAppConfig } = useAppConfig() + const { + useSubStore = true, + useCustomSubStore = false, + customSubStoreUrl, + subStoreBackendSyncCron, + subStoreBackendDownloadCron, + subStoreBackendUploadCron + } = appConfig || {} + + const [customSubStoreUrlValue, setCustomSubStoreUrlValue] = useState(customSubStoreUrl) + const setCustomSubStoreUrl = debounce(async (v: string) => { + await patchAppConfig({ customSubStoreUrl: v }) + }, 500) + const [subStoreBackendSyncCronValue, setSubStoreBackendSyncCronValue] = + useState(subStoreBackendSyncCron) + const [subStoreBackendDownloadCronValue, setSubStoreBackendDownloadCronValue] = useState( + subStoreBackendDownloadCron + ) + const [subStoreBackendUploadCronValue, setSubStoreBackendUploadCronValue] = + useState(subStoreBackendUploadCron) + return ( + + + { + try { + await patchAppConfig({ useSubStore: v }) + if (v) await startSubStoreServer() + } catch (e) { + alert(e) + } + }} + /> + + {useSubStore && ( + + { + try { + await patchAppConfig({ useCustomSubStore: v }) + if (!v) await startSubStoreServer() + } catch (e) { + alert(e) + } + }} + /> + + )} + {useCustomSubStore ? ( + + { + setCustomSubStoreUrlValue(v) + setCustomSubStoreUrl(v) + }} + /> + + ) : ( + <> + +
+ {subStoreBackendSyncCronValue !== subStoreBackendSyncCron && ( + + )} + { + setSubStoreBackendSyncCronValue(v) + }} + /> +
+
+ +
+ {subStoreBackendDownloadCronValue !== subStoreBackendDownloadCron && ( + + )} + { + setSubStoreBackendDownloadCronValue(v) + }} + /> +
+
+ +
+ {subStoreBackendUploadCronValue !== subStoreBackendUploadCron && ( + + )} + { + setSubStoreBackendUploadCronValue(v) + }} + /> +
+
+ + )} +
+ ) +} + +export default SubStoreConfig diff --git a/src/renderer/src/pages/settings.tsx b/src/renderer/src/pages/settings.tsx index b048950..ce405e4 100644 --- a/src/renderer/src/pages/settings.tsx +++ b/src/renderer/src/pages/settings.tsx @@ -9,6 +9,7 @@ import Actions from '@renderer/components/settings/actions' import ShortcutConfig from '@renderer/components/settings/shortcut-config' import { FaTelegramPlane } from 'react-icons/fa' import SiderConfig from '@renderer/components/settings/sider-config' +import SubStoreConfig from '@renderer/components/settings/substore-config' const Settings: React.FC = () => { return ( @@ -56,6 +57,7 @@ const Settings: React.FC = () => { } > + diff --git a/src/shared/types.d.ts b/src/shared/types.d.ts index 299f337..74fe3c3 100644 --- a/src/shared/types.d.ts +++ b/src/shared/types.d.ts @@ -234,6 +234,9 @@ interface IAppConfig { sysproxyCardStatus?: CardStatus tunCardStatus?: CardStatus useSubStore: boolean + subStoreBackendSyncCron?: string + subStoreBackendDownloadCron?: string + subStoreBackendUploadCron?: string autoQuitWithoutCore?: boolean autoQuitWithoutCoreDelay?: number useCustomSubStore?: boolean