mirror of
https://gh.catmak.name/https://github.com/mihomo-party-org/mihomo-party
synced 2026-02-10 11:40:28 +08:00
Compare commits
3 Commits
56e328191f
...
197c9d3af8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
197c9d3af8 | ||
|
|
388581d75e | ||
|
|
3c148f2c01 |
4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
@ -205,6 +205,8 @@ jobs:
|
||||
GITHUB_EVENT_NAME: workflow_dispatch
|
||||
run: node scripts/update-version.mjs
|
||||
- name: Prepare
|
||||
env:
|
||||
LEGACY_BUILD: 'true'
|
||||
run: pnpm prepare --${{ matrix.arch }}
|
||||
- name: Build
|
||||
env:
|
||||
@ -263,7 +265,7 @@ jobs:
|
||||
arch:
|
||||
- x64
|
||||
- arm64
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
@ -332,11 +332,13 @@ function getSysproxyNodeName() {
|
||||
}
|
||||
})()
|
||||
|
||||
const isWin7Build = process.env.LEGACY_BUILD === 'true'
|
||||
|
||||
switch (platform) {
|
||||
case 'win32':
|
||||
if (arch === 'x64') return 'sysproxy.win32-x64-msvc.node'
|
||||
if (arch === 'x64') return isWin7Build ? 'sysproxy.win32-x64-msvc-win7.node' : 'sysproxy.win32-x64-msvc.node'
|
||||
if (arch === 'arm64') return 'sysproxy.win32-arm64-msvc.node'
|
||||
if (arch === 'ia32') return 'sysproxy.win32-ia32-msvc.node'
|
||||
if (arch === 'ia32') return isWin7Build ? 'sysproxy.win32-ia32-msvc-win7.node' : 'sysproxy.win32-ia32-msvc.node'
|
||||
break
|
||||
case 'darwin':
|
||||
if (arch === 'x64') return 'sysproxy.darwin-x64.node'
|
||||
|
||||
@ -65,26 +65,33 @@ export async function getProfileItem(id: string | undefined): Promise<IProfileIt
|
||||
|
||||
export async function changeCurrentProfile(id: string): Promise<void> {
|
||||
// 使用队列确保 profile 切换串行执行,避免竞态条件
|
||||
changeProfileQueue = changeProfileQueue.then(async () => {
|
||||
const { current } = await getProfileConfig()
|
||||
if (current === id) return
|
||||
let taskError: unknown = null
|
||||
changeProfileQueue = changeProfileQueue
|
||||
.catch(() => {
|
||||
})
|
||||
.then(async () => {
|
||||
const { current } = await getProfileConfig()
|
||||
if (current === id) return
|
||||
|
||||
try {
|
||||
await updateProfileConfig((config) => {
|
||||
config.current = id
|
||||
return config
|
||||
})
|
||||
await restartCore()
|
||||
} catch (e) {
|
||||
// 回滚配置
|
||||
await updateProfileConfig((config) => {
|
||||
config.current = current
|
||||
return config
|
||||
})
|
||||
throw e
|
||||
}
|
||||
})
|
||||
try {
|
||||
await updateProfileConfig((config) => {
|
||||
config.current = id
|
||||
return config
|
||||
})
|
||||
await restartCore()
|
||||
} catch (e) {
|
||||
// 回滚配置
|
||||
await updateProfileConfig((config) => {
|
||||
config.current = current
|
||||
return config
|
||||
})
|
||||
taskError = e
|
||||
}
|
||||
})
|
||||
await changeProfileQueue
|
||||
if (taskError) {
|
||||
throw taskError
|
||||
}
|
||||
}
|
||||
|
||||
export async function updateProfileItem(item: IProfileItem): Promise<void> {
|
||||
@ -249,6 +256,14 @@ export async function createProfile(item: Partial<IProfileItem>): Promise<IProfi
|
||||
useProxy: true,
|
||||
timeout: subscriptionTimeout
|
||||
})
|
||||
} else if (newItem.substore) {
|
||||
// SubStore requests (especially collections) need more time as they fetch and merge multiple subscriptions
|
||||
// Use the full subscriptionTimeout since SubStore is a local server and doesn't need smart fallback
|
||||
result = await fetchAndValidateSubscription({
|
||||
...baseOptions,
|
||||
useProxy: false,
|
||||
timeout: subscriptionTimeout
|
||||
})
|
||||
} else {
|
||||
const smartTimeout = 5000
|
||||
try {
|
||||
|
||||
@ -1,11 +1,19 @@
|
||||
const { existsSync } = require('fs')
|
||||
const { join, dirname } = require('path')
|
||||
const os = require('os')
|
||||
|
||||
const { platform, arch } = process
|
||||
|
||||
let nativeBinding = null
|
||||
let loadError = null
|
||||
|
||||
function isWindows7() {
|
||||
if (platform !== 'win32') return false
|
||||
const release = os.release()
|
||||
// Windows 7 is NT 6.1
|
||||
return release.startsWith('6.1')
|
||||
}
|
||||
|
||||
function isMusl() {
|
||||
// 优先使用 process.report(Node.js 12+,最可靠)
|
||||
if (process.report && typeof process.report.getReport === 'function') {
|
||||
@ -23,10 +31,11 @@ function isMusl() {
|
||||
}
|
||||
|
||||
function getBindingName() {
|
||||
const win7 = isWindows7()
|
||||
switch (platform) {
|
||||
case 'win32':
|
||||
if (arch === 'x64') return 'sysproxy.win32-x64-msvc.node'
|
||||
if (arch === 'ia32') return 'sysproxy.win32-ia32-msvc.node'
|
||||
if (arch === 'x64') return win7 ? 'sysproxy.win32-x64-msvc-win7.node' : 'sysproxy.win32-x64-msvc.node'
|
||||
if (arch === 'ia32') return win7 ? 'sysproxy.win32-ia32-msvc-win7.node' : 'sysproxy.win32-ia32-msvc.node'
|
||||
if (arch === 'arm64') return 'sysproxy.win32-arm64-msvc.node'
|
||||
break
|
||||
case 'darwin':
|
||||
|
||||
@ -1,20 +1,60 @@
|
||||
import React, { useRef } from 'react'
|
||||
import React, { useRef, useState, useCallback } from 'react'
|
||||
import { Input, InputProps } from '@heroui/react'
|
||||
import { FaSearch } from 'react-icons/fa'
|
||||
|
||||
interface CollapseInputProps extends InputProps {
|
||||
interface CollapseInputProps extends Omit<InputProps, 'onValueChange'> {
|
||||
title: string
|
||||
onValueChange?: (value: string) => void
|
||||
}
|
||||
|
||||
const CollapseInput: React.FC<CollapseInputProps> = (props) => {
|
||||
const { title, ...inputProps } = props
|
||||
const { title, value, onValueChange, ...inputProps } = props
|
||||
const inputRef = useRef<HTMLInputElement>(null)
|
||||
const isComposingRef = useRef(false)
|
||||
const [localValue, setLocalValue] = useState(value || '')
|
||||
|
||||
// 同步外部 value 变化
|
||||
React.useEffect(() => {
|
||||
if (!isComposingRef.current) {
|
||||
setLocalValue(value || '')
|
||||
}
|
||||
}, [value])
|
||||
|
||||
const handleChange = useCallback(
|
||||
(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const newValue = e.target.value
|
||||
setLocalValue(newValue)
|
||||
// 只在非组合输入时触发外部更新
|
||||
if (!isComposingRef.current) {
|
||||
onValueChange?.(newValue)
|
||||
}
|
||||
},
|
||||
[onValueChange]
|
||||
)
|
||||
|
||||
const handleCompositionStart = useCallback(() => {
|
||||
isComposingRef.current = true
|
||||
}, [])
|
||||
|
||||
const handleCompositionEnd = useCallback(
|
||||
(e: React.CompositionEvent<HTMLInputElement>) => {
|
||||
isComposingRef.current = false
|
||||
// 组合输入结束后,触发一次更新
|
||||
onValueChange?.(e.currentTarget.value)
|
||||
},
|
||||
[onValueChange]
|
||||
)
|
||||
|
||||
return (
|
||||
<div className="flex">
|
||||
<Input
|
||||
size="sm"
|
||||
ref={inputRef}
|
||||
{...inputProps}
|
||||
value={localValue as string}
|
||||
onChange={handleChange}
|
||||
onCompositionStart={handleCompositionStart}
|
||||
onCompositionEnd={handleCompositionEnd}
|
||||
style={{ paddingInlineEnd: 0 }}
|
||||
classNames={{
|
||||
inputWrapper: 'cursor-pointer bg-transparent p-0 data-[hover=true]:bg-content2',
|
||||
|
||||
@ -303,7 +303,7 @@ const drawSvg = async (
|
||||
if (upload === currentUploadRef.current && download === currentDownloadRef.current) return
|
||||
currentUploadRef.current = upload
|
||||
currentDownloadRef.current = download
|
||||
const svg = `data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 140 36"><image height="36" width="36" href="${trayIconBase64}"/><text x="140" y="15" font-size="18" font-family="PingFang SC" font-weight="bold" text-anchor="end">${calcTraffic(upload)}/s</text><text x="140" y="34" font-size="18" font-family="PingFang SC" font-weight="bold" text-anchor="end">${calcTraffic(download)}/s</text></svg>`
|
||||
const svg = `data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 156 36"><image height="36" width="36" href="${trayIconBase64}"/><text x="156" y="15" font-size="18" font-family="PingFang SC" font-weight="bold" text-anchor="end" fill="black">${calcTraffic(upload)}/s</text><text x="156" y="34" font-size="18" font-family="PingFang SC" font-weight="bold" text-anchor="end" fill="black">${calcTraffic(download)}/s</text></svg>`
|
||||
const image = await loadImage(svg)
|
||||
window.electron.ipcRenderer.send('trayIconUpdate', image, true)
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user