mirror of
https://gh.catmak.name/https://github.com/mihomo-party-org/mihomo-party
synced 2025-12-27 05:00:30 +08:00
Improve substore integration
This commit is contained in:
parent
1cbae3a510
commit
1773be543f
14
src/main/core/subStoreApi.ts
Normal file
14
src/main/core/subStoreApi.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import axios from 'axios'
|
||||
import { subStorePort } from '../resolve/server'
|
||||
|
||||
export async function subStoreSubs(): Promise<ISubStoreSub[]> {
|
||||
const res = await axios.get(`http://127.0.0.1:${subStorePort}/api/subs`)
|
||||
|
||||
return res.data.data as ISubStoreSub[]
|
||||
}
|
||||
|
||||
export async function subStoreCollections(): Promise<ISubStoreSub[]> {
|
||||
const res = await axios.get(`http://127.0.0.1:${subStorePort}/api/collections`)
|
||||
|
||||
return res.data.data as ISubStoreSub[]
|
||||
}
|
||||
@ -60,6 +60,7 @@ import { getInterfaces } from '../sys/interface'
|
||||
import { copyEnv } from '../resolve/tray'
|
||||
import { registerShortcut } from '../resolve/shortcut'
|
||||
import { mainWindow } from '..'
|
||||
import { subStoreCollections, subStoreSubs } from '../core/subStoreApi'
|
||||
|
||||
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
|
||||
@ -168,6 +169,8 @@ export function registerIpcMainHandlers(): void {
|
||||
)
|
||||
ipcMain.handle('startSubStoreServer', () => ipcErrorWrapper(startSubStoreServer)())
|
||||
ipcMain.handle('subStorePort', () => subStorePort)
|
||||
ipcMain.handle('subStoreSubs', () => ipcErrorWrapper(subStoreSubs)())
|
||||
ipcMain.handle('subStoreCollections', () => ipcErrorWrapper(subStoreCollections)())
|
||||
ipcMain.handle('setNativeTheme', (_e, theme) => {
|
||||
setNativeTheme(theme)
|
||||
})
|
||||
|
||||
@ -12,8 +12,14 @@ import BasePage from '@renderer/components/base/base-page'
|
||||
import ProfileItem from '@renderer/components/profiles/profile-item'
|
||||
import { useProfileConfig } from '@renderer/hooks/use-profile-config'
|
||||
import { useAppConfig } from '@renderer/hooks/use-app-config'
|
||||
import { getFilePath, readTextFile, subStorePort } from '@renderer/utils/ipc'
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import {
|
||||
getFilePath,
|
||||
readTextFile,
|
||||
subStoreCollections,
|
||||
subStorePort,
|
||||
subStoreSubs
|
||||
} from '@renderer/utils/ipc'
|
||||
import { ReactNode, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { MdContentPaste } from 'react-icons/md'
|
||||
import {
|
||||
DndContext,
|
||||
@ -27,6 +33,7 @@ import { SortableContext } from '@dnd-kit/sortable'
|
||||
import { FaPlus } from 'react-icons/fa6'
|
||||
import { IoMdRefresh } from 'react-icons/io'
|
||||
import SubStoreIcon from '@renderer/components/base/substore-icon'
|
||||
import useSWR from 'swr'
|
||||
|
||||
const Profiles: React.FC = () => {
|
||||
const {
|
||||
@ -43,11 +50,51 @@ const Profiles: React.FC = () => {
|
||||
const { current, items = [] } = profileConfig || {}
|
||||
const [sortedItems, setSortedItems] = useState(items)
|
||||
const [useProxy, setUseProxy] = useState(false)
|
||||
const [subStoreImporting, setSubStoreImporting] = useState(false)
|
||||
const [importing, setImporting] = useState(false)
|
||||
const [updating, setUpdating] = useState(false)
|
||||
const [fileOver, setFileOver] = useState(false)
|
||||
const [url, setUrl] = useState('')
|
||||
const sensors = useSensors(useSensor(PointerSensor))
|
||||
const { data: subs = [], mutate: mutateSubs } = useSWR(
|
||||
useSubStore ? 'subStoreSubs' : undefined,
|
||||
useSubStore ? subStoreSubs : (): undefined => {}
|
||||
)
|
||||
const { data: collections = [], mutate: mutateCollections } = useSWR(
|
||||
useSubStore ? 'subStoreCollections' : undefined,
|
||||
useSubStore ? subStoreCollections : (): undefined => {}
|
||||
)
|
||||
const subStoreMenuItems = useMemo(() => {
|
||||
const items: { icon?: ReactNode; key: string; name: string; divider: boolean }[] = [
|
||||
{
|
||||
key: 'open-substore',
|
||||
name: '访问 SubStore',
|
||||
icon: <SubStoreIcon />,
|
||||
divider: Boolean(subs) || Boolean(collections)
|
||||
}
|
||||
]
|
||||
if (subs) {
|
||||
subs.forEach((sub, index) => {
|
||||
items.push({
|
||||
key: `sub-${sub.name}`,
|
||||
name: sub.displayName,
|
||||
icon: sub.icon ? <img src={sub.icon} className="h-[18px] w-[18px]" /> : null,
|
||||
divider: index === subs.length - 1 && Boolean(collections)
|
||||
})
|
||||
})
|
||||
}
|
||||
if (collections) {
|
||||
collections.forEach((sub) => {
|
||||
items.push({
|
||||
key: `collection-${sub.name}`,
|
||||
name: sub.displayName,
|
||||
icon: sub.icon ? <img src={sub.icon} className="h-[18px] w-[18px]" /> : null,
|
||||
divider: false
|
||||
})
|
||||
})
|
||||
}
|
||||
return items
|
||||
}, [subs, collections])
|
||||
const handleImport = async (): Promise<void> => {
|
||||
setImporting(true)
|
||||
await addProfileItem({ name: '', type: 'remote', url, useProxy })
|
||||
@ -194,12 +241,16 @@ const Profiles: React.FC = () => {
|
||||
导入
|
||||
</Button>
|
||||
{useSubStore && (
|
||||
<Button
|
||||
title="SubStore"
|
||||
onPress={async () => {
|
||||
const port = await subStorePort()
|
||||
open(`https://sub-store.vercel.app/subs?api=http://127.0.0.1:${port}`)
|
||||
<Dropdown
|
||||
onOpenChange={() => {
|
||||
mutateSubs()
|
||||
mutateCollections()
|
||||
}}
|
||||
>
|
||||
<DropdownTrigger>
|
||||
<Button
|
||||
isLoading={subStoreImporting}
|
||||
title="SubStore"
|
||||
className="ml-2"
|
||||
size="sm"
|
||||
isIconOnly
|
||||
@ -207,6 +258,58 @@ const Profiles: React.FC = () => {
|
||||
>
|
||||
<SubStoreIcon />
|
||||
</Button>
|
||||
</DropdownTrigger>
|
||||
<DropdownMenu
|
||||
onAction={async (key) => {
|
||||
if (key === 'open-substore') {
|
||||
const port = await subStorePort()
|
||||
open(`https://sub-store.vercel.app/subs?api=http://127.0.0.1:${port}`)
|
||||
} else if (key.toString().startsWith('sub-')) {
|
||||
setSubStoreImporting(true)
|
||||
try {
|
||||
const port = await subStorePort()
|
||||
const sub = subs.find(
|
||||
(sub) => sub.name === key.toString().replace('sub-', '')
|
||||
)
|
||||
await addProfileItem({
|
||||
name: sub?.displayName ?? '',
|
||||
type: 'remote',
|
||||
url: `http://127.0.0.1:${port}/download/${key.toString().replace('sub-', '')}?target=ClashMeta`,
|
||||
useProxy
|
||||
})
|
||||
} catch (e) {
|
||||
alert(e)
|
||||
} finally {
|
||||
setSubStoreImporting(false)
|
||||
}
|
||||
} else if (key.toString().startsWith('collection-')) {
|
||||
setSubStoreImporting(true)
|
||||
try {
|
||||
const port = await subStorePort()
|
||||
const sub = collections.find(
|
||||
(sub) => sub.name === key.toString().replace('sub-', '')
|
||||
)
|
||||
await addProfileItem({
|
||||
name: sub?.displayName ?? '',
|
||||
type: 'remote',
|
||||
url: `http://127.0.0.1:${port}/download/collection/${key.toString().replace('collection-', '')}?target=ClashMeta`,
|
||||
useProxy
|
||||
})
|
||||
} catch (e) {
|
||||
alert(e)
|
||||
} finally {
|
||||
setSubStoreImporting(false)
|
||||
}
|
||||
}
|
||||
}}
|
||||
>
|
||||
{subStoreMenuItems.map((item) => (
|
||||
<DropdownItem startContent={item?.icon} key={item.key} showDivider={item.divider}>
|
||||
{item.name}
|
||||
</DropdownItem>
|
||||
))}
|
||||
</DropdownMenu>
|
||||
</Dropdown>
|
||||
)}
|
||||
<Dropdown>
|
||||
<DropdownTrigger>
|
||||
|
||||
@ -299,6 +299,14 @@ export async function subStorePort(): Promise<number> {
|
||||
return ipcErrorWrapper(await window.electron.ipcRenderer.invoke('subStorePort'))
|
||||
}
|
||||
|
||||
export async function subStoreSubs(): Promise<ISubStoreSub[]> {
|
||||
return ipcErrorWrapper(await window.electron.ipcRenderer.invoke('subStoreSubs'))
|
||||
}
|
||||
|
||||
export async function subStoreCollections(): Promise<ISubStoreSub[]> {
|
||||
return ipcErrorWrapper(await window.electron.ipcRenderer.invoke('subStoreCollections'))
|
||||
}
|
||||
|
||||
export async function openFile(
|
||||
type: 'profile' | 'override',
|
||||
id: string,
|
||||
|
||||
7
src/shared/types.d.ts
vendored
7
src/shared/types.d.ts
vendored
@ -399,3 +399,10 @@ interface IProfileItem {
|
||||
useProxy?: boolean
|
||||
extra?: ISubscriptionUserInfo
|
||||
}
|
||||
|
||||
interface ISubStoreSub {
|
||||
name: string
|
||||
displayName: sstring
|
||||
icon?: string
|
||||
tag?: string[]
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user