mirror of
https://gh.catmak.name/https://github.com/mihomo-party-org/mihomo-party
synced 2025-12-27 05:00:30 +08:00
support custom substore backend
This commit is contained in:
parent
1773be543f
commit
a1d3558581
@ -1,14 +1,17 @@
|
|||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import { subStorePort } from '../resolve/server'
|
import { subStorePort } from '../resolve/server'
|
||||||
|
import { getAppConfig } from '../config'
|
||||||
|
|
||||||
export async function subStoreSubs(): Promise<ISubStoreSub[]> {
|
export async function subStoreSubs(): Promise<ISubStoreSub[]> {
|
||||||
const res = await axios.get(`http://127.0.0.1:${subStorePort}/api/subs`)
|
const { useCustomSubStore = false, customSubStoreUrl = '' } = await getAppConfig()
|
||||||
|
const baseUrl = useCustomSubStore ? customSubStoreUrl : `http://127.0.0.1:${subStorePort}`
|
||||||
|
const res = await axios.get(`${baseUrl}/api/subs`)
|
||||||
return res.data.data as ISubStoreSub[]
|
return res.data.data as ISubStoreSub[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function subStoreCollections(): Promise<ISubStoreSub[]> {
|
export async function subStoreCollections(): Promise<ISubStoreSub[]> {
|
||||||
const res = await axios.get(`http://127.0.0.1:${subStorePort}/api/collections`)
|
const { useCustomSubStore = false, customSubStoreUrl = '' } = await getAppConfig()
|
||||||
|
const baseUrl = useCustomSubStore ? customSubStoreUrl : `http://127.0.0.1:${subStorePort}`
|
||||||
|
const res = await axios.get(`${baseUrl}/api/collections`)
|
||||||
return res.data.data as ISubStoreSub[]
|
return res.data.data as ISubStoreSub[]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -53,8 +53,8 @@ export async function startPacServer(): Promise<void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function startSubStoreServer(): Promise<void> {
|
export async function startSubStoreServer(): Promise<void> {
|
||||||
const { useSubStore = true } = await getAppConfig()
|
const { useSubStore = true, useCustomSubStore = false } = await getAppConfig()
|
||||||
if (!useSubStore) return
|
if (!useSubStore || useCustomSubStore) return
|
||||||
if (subStorePort) return
|
if (subStorePort) return
|
||||||
subStorePort = await findAvailablePort(3000)
|
subStorePort = await findAvailablePort(3000)
|
||||||
new Worker(path.join(resourcesFilesDir(), 'sub-store.bundle.js'), {
|
new Worker(path.join(resourcesFilesDir(), 'sub-store.bundle.js'), {
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import React, { Key } from 'react'
|
import React, { Key, useState } 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, Select, SelectItem, Switch, Tab, Tabs } from '@nextui-org/react'
|
import { Button, Input, Select, SelectItem, Switch, Tab, Tabs } from '@nextui-org/react'
|
||||||
import { BiCopy } from 'react-icons/bi'
|
import { BiCopy } from 'react-icons/bi'
|
||||||
import useSWR from 'swr'
|
import useSWR from 'swr'
|
||||||
import {
|
import {
|
||||||
@ -16,6 +16,7 @@ import {
|
|||||||
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'
|
||||||
|
|
||||||
const GeneralConfig: React.FC = () => {
|
const GeneralConfig: React.FC = () => {
|
||||||
const { data: enable, mutate: mutateEnable } = useSWR('checkAutoRun', checkAutoRun)
|
const { data: enable, mutate: mutateEnable } = useSWR('checkAutoRun', checkAutoRun)
|
||||||
@ -28,11 +29,17 @@ const GeneralConfig: React.FC = () => {
|
|||||||
proxyInTray = true,
|
proxyInTray = true,
|
||||||
useWindowFrame = false,
|
useWindowFrame = false,
|
||||||
useSubStore = true,
|
useSubStore = true,
|
||||||
|
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('-')
|
||||||
|
|
||||||
@ -170,6 +177,36 @@ const GeneralConfig: React.FC = () => {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</SettingItem>
|
</SettingItem>
|
||||||
|
{useSubStore && (
|
||||||
|
<SettingItem title="使用自建Substore后端" 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="自建SubStore后端地址" 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"
|
||||||
|
|||||||
@ -46,7 +46,7 @@ const Profiles: React.FC = () => {
|
|||||||
mutateProfileConfig
|
mutateProfileConfig
|
||||||
} = useProfileConfig()
|
} = useProfileConfig()
|
||||||
const { appConfig } = useAppConfig()
|
const { appConfig } = useAppConfig()
|
||||||
const { useSubStore = true } = appConfig || {}
|
const { useSubStore = true, useCustomSubStore = false, customSubStoreUrl = '' } = appConfig || {}
|
||||||
const { current, items = [] } = profileConfig || {}
|
const { current, items = [] } = profileConfig || {}
|
||||||
const [sortedItems, setSortedItems] = useState(items)
|
const [sortedItems, setSortedItems] = useState(items)
|
||||||
const [useProxy, setUseProxy] = useState(false)
|
const [useProxy, setUseProxy] = useState(false)
|
||||||
@ -65,12 +65,14 @@ const Profiles: React.FC = () => {
|
|||||||
useSubStore ? subStoreCollections : (): undefined => {}
|
useSubStore ? subStoreCollections : (): undefined => {}
|
||||||
)
|
)
|
||||||
const subStoreMenuItems = useMemo(() => {
|
const subStoreMenuItems = useMemo(() => {
|
||||||
|
console.log(subs, collections)
|
||||||
const items: { icon?: ReactNode; key: string; name: string; divider: boolean }[] = [
|
const items: { icon?: ReactNode; key: string; name: string; divider: boolean }[] = [
|
||||||
{
|
{
|
||||||
key: 'open-substore',
|
key: 'open-substore',
|
||||||
name: '访问 SubStore',
|
name: '访问 SubStore',
|
||||||
icon: <SubStoreIcon />,
|
icon: <SubStoreIcon />,
|
||||||
divider: Boolean(subs) || Boolean(collections)
|
divider:
|
||||||
|
(Boolean(subs) && subs.length > 0) || (Boolean(collections) && collections.length > 0)
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
if (subs) {
|
if (subs) {
|
||||||
@ -79,7 +81,7 @@ const Profiles: React.FC = () => {
|
|||||||
key: `sub-${sub.name}`,
|
key: `sub-${sub.name}`,
|
||||||
name: sub.displayName,
|
name: sub.displayName,
|
||||||
icon: sub.icon ? <img src={sub.icon} className="h-[18px] w-[18px]" /> : null,
|
icon: sub.icon ? <img src={sub.icon} className="h-[18px] w-[18px]" /> : null,
|
||||||
divider: index === subs.length - 1 && Boolean(collections)
|
divider: index === subs.length - 1 && Boolean(collections) && collections.length > 0
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -263,7 +265,11 @@ const Profiles: React.FC = () => {
|
|||||||
onAction={async (key) => {
|
onAction={async (key) => {
|
||||||
if (key === 'open-substore') {
|
if (key === 'open-substore') {
|
||||||
const port = await subStorePort()
|
const port = await subStorePort()
|
||||||
|
if (useCustomSubStore) {
|
||||||
|
open(`https://sub-store.vercel.app/subs?api=${customSubStoreUrl}`)
|
||||||
|
} else {
|
||||||
open(`https://sub-store.vercel.app/subs?api=http://127.0.0.1:${port}`)
|
open(`https://sub-store.vercel.app/subs?api=http://127.0.0.1:${port}`)
|
||||||
|
}
|
||||||
} else if (key.toString().startsWith('sub-')) {
|
} else if (key.toString().startsWith('sub-')) {
|
||||||
setSubStoreImporting(true)
|
setSubStoreImporting(true)
|
||||||
try {
|
try {
|
||||||
@ -274,7 +280,9 @@ const Profiles: React.FC = () => {
|
|||||||
await addProfileItem({
|
await addProfileItem({
|
||||||
name: sub?.displayName ?? '',
|
name: sub?.displayName ?? '',
|
||||||
type: 'remote',
|
type: 'remote',
|
||||||
url: `http://127.0.0.1:${port}/download/${key.toString().replace('sub-', '')}?target=ClashMeta`,
|
url: useCustomSubStore
|
||||||
|
? `${customSubStoreUrl}/download/${key.toString().replace('sub-', '')}?target=ClashMeta`
|
||||||
|
: `http://127.0.0.1:${port}/download/${key.toString().replace('sub-', '')}?target=ClashMeta`,
|
||||||
useProxy
|
useProxy
|
||||||
})
|
})
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -286,13 +294,16 @@ const Profiles: React.FC = () => {
|
|||||||
setSubStoreImporting(true)
|
setSubStoreImporting(true)
|
||||||
try {
|
try {
|
||||||
const port = await subStorePort()
|
const port = await subStorePort()
|
||||||
const sub = collections.find(
|
const collection = collections.find(
|
||||||
(sub) => sub.name === key.toString().replace('sub-', '')
|
(collection) =>
|
||||||
|
collection.name === key.toString().replace('collection-', '')
|
||||||
)
|
)
|
||||||
await addProfileItem({
|
await addProfileItem({
|
||||||
name: sub?.displayName ?? '',
|
name: collection?.displayName ?? '',
|
||||||
type: 'remote',
|
type: 'remote',
|
||||||
url: `http://127.0.0.1:${port}/download/collection/${key.toString().replace('collection-', '')}?target=ClashMeta`,
|
url: useCustomSubStore
|
||||||
|
? `${customSubStoreUrl}/download/collection/${key.toString().replace('collection-', '')}?target=ClashMeta`
|
||||||
|
: `http://127.0.0.1:${port}/download/collection/${key.toString().replace('collection-', '')}?target=ClashMeta`,
|
||||||
useProxy
|
useProxy
|
||||||
})
|
})
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
2
src/shared/types.d.ts
vendored
2
src/shared/types.d.ts
vendored
@ -220,6 +220,8 @@ interface IAppConfig {
|
|||||||
connectionDirection: 'asc' | 'desc'
|
connectionDirection: 'asc' | 'desc'
|
||||||
connectionOrderBy: 'time' | 'upload' | 'download' | 'uploadSpeed' | 'downloadSpeed'
|
connectionOrderBy: 'time' | 'upload' | 'download' | 'uploadSpeed' | 'downloadSpeed'
|
||||||
useSubStore: boolean
|
useSubStore: boolean
|
||||||
|
useCustomSubStore?: boolean
|
||||||
|
customSubStoreUrl?: string
|
||||||
autoSetDNS?: boolean
|
autoSetDNS?: boolean
|
||||||
originDNS?: string
|
originDNS?: string
|
||||||
useWindowFrame: boolean
|
useWindowFrame: boolean
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user