mirror of
https://gh.catmak.name/https://github.com/mihomo-party-org/mihomo-party
synced 2025-12-27 05:00:30 +08:00
support substore cron
This commit is contained in:
parent
9f5a39f652
commit
3eabb15efb
@ -4,11 +4,8 @@
|
|||||||
|
|
||||||
### New Features
|
### New Features
|
||||||
|
|
||||||
- 代理组图标支持SVG格式
|
- 支持设置 Sub-Store 定时同步
|
||||||
- 优化覆写启用逻辑
|
|
||||||
- 覆写支持全局启用
|
|
||||||
- 筛选过滤忽略大小写
|
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|
||||||
- 修复 MacOS 上复制粘贴快捷键失效的问题
|
- 修复全局覆写重复执行的问题
|
||||||
|
|||||||
@ -52,6 +52,7 @@
|
|||||||
"@types/ws": "^8.5.12",
|
"@types/ws": "^8.5.12",
|
||||||
"@vitejs/plugin-react": "^4.3.1",
|
"@vitejs/plugin-react": "^4.3.1",
|
||||||
"autoprefixer": "^10.4.20",
|
"autoprefixer": "^10.4.20",
|
||||||
|
"cron-validator": "^1.3.1",
|
||||||
"driver.js": "^1.3.1",
|
"driver.js": "^1.3.1",
|
||||||
"electron": "^32.0.2",
|
"electron": "^32.0.2",
|
||||||
"electron-builder": "^25.0.5",
|
"electron-builder": "^25.0.5",
|
||||||
|
|||||||
8
pnpm-lock.yaml
generated
8
pnpm-lock.yaml
generated
@ -93,6 +93,9 @@ importers:
|
|||||||
autoprefixer:
|
autoprefixer:
|
||||||
specifier: ^10.4.20
|
specifier: ^10.4.20
|
||||||
version: 10.4.20(postcss@8.4.45)
|
version: 10.4.20(postcss@8.4.45)
|
||||||
|
cron-validator:
|
||||||
|
specifier: ^1.3.1
|
||||||
|
version: 1.3.1
|
||||||
driver.js:
|
driver.js:
|
||||||
specifier: ^1.3.1
|
specifier: ^1.3.1
|
||||||
version: 1.3.1
|
version: 1.3.1
|
||||||
@ -2661,6 +2664,9 @@ packages:
|
|||||||
crc@3.8.0:
|
crc@3.8.0:
|
||||||
resolution: {integrity: sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==}
|
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:
|
cross-spawn@7.0.3:
|
||||||
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
|
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
|
||||||
engines: {node: '>= 8'}
|
engines: {node: '>= 8'}
|
||||||
@ -8717,6 +8723,8 @@ snapshots:
|
|||||||
buffer: 5.7.1
|
buffer: 5.7.1
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
cron-validator@1.3.1: {}
|
||||||
|
|
||||||
cross-spawn@7.0.3:
|
cross-spawn@7.0.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
path-key: 3.1.1
|
path-key: 3.1.1
|
||||||
|
|||||||
@ -57,7 +57,13 @@ export async function startPacServer(): Promise<void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function startSubStoreServer(): 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 (!useSubStore) return
|
||||||
if (!subStoreFrontendPort) {
|
if (!subStoreFrontendPort) {
|
||||||
subStoreFrontendPort = await findAvailablePort(4000)
|
subStoreFrontendPort = await findAvailablePort(4000)
|
||||||
@ -74,7 +80,10 @@ export async function startSubStoreServer(): Promise<void> {
|
|||||||
SUB_STORE_BACKEND_API_PORT: subStorePort.toString(),
|
SUB_STORE_BACKEND_API_PORT: subStorePort.toString(),
|
||||||
SUB_STORE_DATA_BASE_PATH: subStoreDir(),
|
SUB_STORE_DATA_BASE_PATH: subStoreDir(),
|
||||||
SUB_STORE_BACKEND_CUSTOM_ICON: icon.toDataURL(),
|
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
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,7 +14,12 @@ const SettingCard: React.FC<Props> = (props) => {
|
|||||||
</Card>
|
</Card>
|
||||||
) : (
|
) : (
|
||||||
<Accordion isCompact className={`${props.className} my-2`} variant="splitted" {...props}>
|
<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}
|
{props.children}
|
||||||
</AccordionItem>
|
</AccordionItem>
|
||||||
</Accordion>
|
</Accordion>
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import React, { Key, useState } from 'react'
|
import React, { Key } from 'react'
|
||||||
import SettingCard from '../base/base-setting-card'
|
import SettingCard from '../base/base-setting-card'
|
||||||
import SettingItem from '../base/base-setting-item'
|
import SettingItem from '../base/base-setting-item'
|
||||||
import { Button, Input, Select, SelectItem, Switch, Tab, Tabs, Tooltip } from '@nextui-org/react'
|
import { Button, Input, Select, SelectItem, Switch, Tab, Tabs, Tooltip } from '@nextui-org/react'
|
||||||
@ -10,13 +10,11 @@ import {
|
|||||||
disableAutoRun,
|
disableAutoRun,
|
||||||
enableAutoRun,
|
enableAutoRun,
|
||||||
relaunchApp,
|
relaunchApp,
|
||||||
restartCore,
|
restartCore
|
||||||
startSubStoreServer
|
|
||||||
} from '@renderer/utils/ipc'
|
} from '@renderer/utils/ipc'
|
||||||
import { useAppConfig } from '@renderer/hooks/use-app-config'
|
import { useAppConfig } from '@renderer/hooks/use-app-config'
|
||||||
import { platform } from '@renderer/utils/init'
|
import { platform } from '@renderer/utils/init'
|
||||||
import { useTheme } from 'next-themes'
|
import { useTheme } from 'next-themes'
|
||||||
import debounce from '@renderer/utils/debounce'
|
|
||||||
import { IoIosHelpCircle } from 'react-icons/io'
|
import { IoIosHelpCircle } from 'react-icons/io'
|
||||||
|
|
||||||
const GeneralConfig: React.FC = () => {
|
const GeneralConfig: React.FC = () => {
|
||||||
@ -29,20 +27,13 @@ const GeneralConfig: React.FC = () => {
|
|||||||
showTraffic = true,
|
showTraffic = true,
|
||||||
proxyInTray = true,
|
proxyInTray = true,
|
||||||
useWindowFrame = false,
|
useWindowFrame = false,
|
||||||
useSubStore = true,
|
|
||||||
autoQuitWithoutCore = false,
|
autoQuitWithoutCore = false,
|
||||||
autoQuitWithoutCoreDelay = 60,
|
autoQuitWithoutCoreDelay = 60,
|
||||||
useCustomSubStore = false,
|
|
||||||
customSubStoreUrl,
|
|
||||||
envType = platform === 'win32' ? 'powershell' : 'bash',
|
envType = platform === 'win32' ? 'powershell' : 'bash',
|
||||||
autoCheckUpdate,
|
autoCheckUpdate,
|
||||||
appTheme = 'system'
|
appTheme = 'system'
|
||||||
} = appConfig || {}
|
} = appConfig || {}
|
||||||
|
|
||||||
const [subStoreUrl, setSubStoreUrl] = useState(customSubStoreUrl)
|
|
||||||
const setSubStoreUrlDebounce = debounce((v: string) => {
|
|
||||||
patchAppConfig({ customSubStoreUrl: v })
|
|
||||||
}, 500)
|
|
||||||
const onThemeChange = (key: Key, type: 'theme' | 'color'): void => {
|
const onThemeChange = (key: Key, type: 'theme' | 'color'): void => {
|
||||||
const [theme, color] = appTheme.split('-')
|
const [theme, color] = appTheme.split('-')
|
||||||
|
|
||||||
@ -202,50 +193,7 @@ const GeneralConfig: React.FC = () => {
|
|||||||
</SettingItem>
|
</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>
|
<SettingItem title="使用系统标题栏" divider>
|
||||||
<Switch
|
<Switch
|
||||||
size="sm"
|
size="sm"
|
||||||
|
|||||||
187
src/renderer/src/components/settings/substore-config.tsx
Normal file
187
src/renderer/src/components/settings/substore-config.tsx
Normal 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
|
||||||
@ -9,6 +9,7 @@ import Actions from '@renderer/components/settings/actions'
|
|||||||
import ShortcutConfig from '@renderer/components/settings/shortcut-config'
|
import ShortcutConfig from '@renderer/components/settings/shortcut-config'
|
||||||
import { FaTelegramPlane } from 'react-icons/fa'
|
import { FaTelegramPlane } from 'react-icons/fa'
|
||||||
import SiderConfig from '@renderer/components/settings/sider-config'
|
import SiderConfig from '@renderer/components/settings/sider-config'
|
||||||
|
import SubStoreConfig from '@renderer/components/settings/substore-config'
|
||||||
|
|
||||||
const Settings: React.FC = () => {
|
const Settings: React.FC = () => {
|
||||||
return (
|
return (
|
||||||
@ -56,6 +57,7 @@ const Settings: React.FC = () => {
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<GeneralConfig />
|
<GeneralConfig />
|
||||||
|
<SubStoreConfig />
|
||||||
<SiderConfig />
|
<SiderConfig />
|
||||||
<WebdavConfig />
|
<WebdavConfig />
|
||||||
<MihomoConfig />
|
<MihomoConfig />
|
||||||
|
|||||||
3
src/shared/types.d.ts
vendored
3
src/shared/types.d.ts
vendored
@ -234,6 +234,9 @@ interface IAppConfig {
|
|||||||
sysproxyCardStatus?: CardStatus
|
sysproxyCardStatus?: CardStatus
|
||||||
tunCardStatus?: CardStatus
|
tunCardStatus?: CardStatus
|
||||||
useSubStore: boolean
|
useSubStore: boolean
|
||||||
|
subStoreBackendSyncCron?: string
|
||||||
|
subStoreBackendDownloadCron?: string
|
||||||
|
subStoreBackendUploadCron?: string
|
||||||
autoQuitWithoutCore?: boolean
|
autoQuitWithoutCore?: boolean
|
||||||
autoQuitWithoutCoreDelay?: number
|
autoQuitWithoutCoreDelay?: number
|
||||||
useCustomSubStore?: boolean
|
useCustomSubStore?: boolean
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user