support substore cron

This commit is contained in:
pompurin404 2024-09-13 15:04:23 +08:00
parent 9f5a39f652
commit 3eabb15efb
No known key found for this signature in database
9 changed files with 223 additions and 63 deletions

View File

@ -4,11 +4,8 @@
### New Features
- 代理组图标支持SVG格式
- 优化覆写启用逻辑
- 覆写支持全局启用
- 筛选过滤忽略大小写
- 支持设置 Sub-Store 定时同步
### Bug Fixes
- 修复 MacOS 上复制粘贴快捷键失效的问题
- 修复全局覆写重复执行的问题

View File

@ -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",

View File

@ -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

View File

@ -57,7 +57,13 @@ export async function startPacServer(): Promise<void> {
}
export async function startSubStoreServer(): Promise<void> {
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<void> {
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
}
})
}

View File

@ -14,7 +14,12 @@ const SettingCard: React.FC<Props> = (props) => {
</Card>
) : (
<Accordion isCompact className={`${props.className} my-2`} variant="splitted" {...props}>
<AccordionItem hideIndicator keepContentMounted title={props.title}>
<AccordionItem
className="data-[open=true]:pb-2"
hideIndicator
keepContentMounted
title={props.title}
>
{props.children}
</AccordionItem>
</Accordion>

View File

@ -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 = () => {
</SettingItem>
</>
)}
<SettingItem title="启用 Sub-Store" divider>
<Switch
size="sm"
isSelected={useSubStore}
onValueChange={async (v) => {
try {
await patchAppConfig({ useSubStore: v })
if (v) await startSubStoreServer()
} catch (e) {
alert(e)
}
}}
/>
</SettingItem>
{useSubStore && (
<SettingItem title="使用自建 Sub-Store 后端" divider>
<Switch
size="sm"
isSelected={useCustomSubStore}
onValueChange={async (v) => {
try {
await patchAppConfig({ useCustomSubStore: v })
if (!v) await startSubStoreServer()
} catch (e) {
alert(e)
}
}}
/>
</SettingItem>
)}
{useCustomSubStore && (
<SettingItem title="自建 Sub-Store 后端地址" divider>
<Input
size="sm"
className="w-[60%]"
value={subStoreUrl}
placeholder="必须包含协议头"
onValueChange={(v: string) => {
setSubStoreUrl(v)
setSubStoreUrlDebounce(v)
}}
/>
</SettingItem>
)}
<SettingItem title="使用系统标题栏" divider>
<Switch
size="sm"

View File

@ -0,0 +1,187 @@
import React, { useState } from 'react'
import SettingCard from '@renderer/components/base/base-setting-card'
import SettingItem from '@renderer/components/base/base-setting-item'
import { Button, Input, Switch } from '@nextui-org/react'
import { startSubStoreServer } from '@renderer/utils/ipc'
import { useAppConfig } from '@renderer/hooks/use-app-config'
import debounce from '@renderer/utils/debounce'
import { isValidCron } from 'cron-validator'
const SubStoreConfig: React.FC = () => {
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 (
<SettingCard title="Sub-Store 设置">
<SettingItem title="启用 Sub-Store" divider>
<Switch
size="sm"
isSelected={useSubStore}
onValueChange={async (v) => {
try {
await patchAppConfig({ useSubStore: v })
if (v) await startSubStoreServer()
} catch (e) {
alert(e)
}
}}
/>
</SettingItem>
{useSubStore && (
<SettingItem title="使用自建 Sub-Store 后端" divider>
<Switch
size="sm"
isSelected={useCustomSubStore}
onValueChange={async (v) => {
try {
await patchAppConfig({ useCustomSubStore: v })
if (!v) await startSubStoreServer()
} catch (e) {
alert(e)
}
}}
/>
</SettingItem>
)}
{useCustomSubStore ? (
<SettingItem title="自建 Sub-Store 后端地址">
<Input
size="sm"
className="w-[60%]"
value={customSubStoreUrlValue}
placeholder="必须包含协议头"
onValueChange={(v: string) => {
setCustomSubStoreUrlValue(v)
setCustomSubStoreUrl(v)
}}
/>
</SettingItem>
) : (
<>
<SettingItem title="定时同步订阅/文件" divider>
<div className="flex w-[60%] gap-2">
{subStoreBackendSyncCronValue !== subStoreBackendSyncCron && (
<Button
size="sm"
color="primary"
onPress={async () => {
if (
!subStoreBackendSyncCronValue ||
isValidCron(subStoreBackendSyncCronValue)
) {
await patchAppConfig({
subStoreBackendSyncCron: subStoreBackendSyncCronValue
})
new Notification('重启应用生效')
} else {
alert('Cron 表达式无效')
}
}}
>
</Button>
)}
<Input
size="sm"
className="flex-grown"
value={subStoreBackendSyncCronValue}
placeholder="Cron 表达式"
onValueChange={(v: string) => {
setSubStoreBackendSyncCronValue(v)
}}
/>
</div>
</SettingItem>
<SettingItem title="定时恢复配置" divider>
<div className="flex w-[60%] gap-2">
{subStoreBackendDownloadCronValue !== subStoreBackendDownloadCron && (
<Button
size="sm"
color="primary"
onPress={async () => {
if (
!subStoreBackendDownloadCronValue ||
isValidCron(subStoreBackendDownloadCronValue)
) {
await patchAppConfig({
subStoreBackendDownloadCron: subStoreBackendDownloadCronValue
})
new Notification('重启应用生效')
} else {
alert('Cron 表达式无效')
}
}}
>
</Button>
)}
<Input
size="sm"
className="flex-grown"
value={subStoreBackendDownloadCronValue}
placeholder="Cron 表达式"
onValueChange={(v: string) => {
setSubStoreBackendDownloadCronValue(v)
}}
/>
</div>
</SettingItem>
<SettingItem title="定时备份配置">
<div className="flex w-[60%] gap-2">
{subStoreBackendUploadCronValue !== subStoreBackendUploadCron && (
<Button
size="sm"
color="primary"
onPress={async () => {
if (
!subStoreBackendUploadCronValue ||
isValidCron(subStoreBackendUploadCronValue)
) {
await patchAppConfig({
subStoreBackendUploadCron: subStoreBackendUploadCronValue
})
new Notification('重启应用生效')
} else {
alert('Cron 表达式无效')
}
}}
>
</Button>
)}
<Input
size="sm"
className="flex-grown"
value={subStoreBackendUploadCronValue}
placeholder="Cron 表达式"
onValueChange={(v: string) => {
setSubStoreBackendUploadCronValue(v)
}}
/>
</div>
</SettingItem>
</>
)}
</SettingCard>
)
}
export default SubStoreConfig

View File

@ -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 = () => {
}
>
<GeneralConfig />
<SubStoreConfig />
<SiderConfig />
<WebdavConfig />
<MihomoConfig />

View File

@ -234,6 +234,9 @@ interface IAppConfig {
sysproxyCardStatus?: CardStatus
tunCardStatus?: CardStatus
useSubStore: boolean
subStoreBackendSyncCron?: string
subStoreBackendDownloadCron?: string
subStoreBackendUploadCron?: string
autoQuitWithoutCore?: boolean
autoQuitWithoutCoreDelay?: number
useCustomSubStore?: boolean