mirror of
https://gh.catmak.name/https://github.com/mihomo-party-org/mihomo-party
synced 2025-12-28 05:30:29 +08:00
Compare commits
12 Commits
f7b9eb2113
...
0a969e9e38
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0a969e9e38 | ||
|
|
f62b8cff67 | ||
|
|
1b7c2ee01e | ||
|
|
866cdb4661 | ||
|
|
2e4090460d | ||
|
|
f2ed0caced | ||
|
|
6993015ce1 | ||
|
|
e3e373d579 | ||
|
|
be7f8677b0 | ||
|
|
dab2ead5fd | ||
|
|
1260b8fb4e | ||
|
|
46aa654ee3 |
@ -8,5 +8,7 @@
|
||||
<true/>
|
||||
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.disable-library-validation</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
37
changelog.md
37
changelog.md
@ -1,28 +1,21 @@
|
||||
## 1.8.1
|
||||
|
||||
### 新功能 (Feat)
|
||||
- 重构 DNS 控制模块,改为“覆写”逻辑,当开关打开后,使用DNS 设置中的配置覆盖订阅原始配置,关闭开关恢复订阅原始配置
|
||||
|
||||
### 性能提升(Perf)
|
||||
- 更新依赖,提升页面响应性
|
||||
- 优化订阅切换逻辑,大幅提升切换速度和稳定性
|
||||
|
||||
### 修复 (Fix)
|
||||
- “使用自动 Smart 规则覆写”没有覆盖兜底的 MATCH 规则
|
||||
- 移除默认的 Smart "policy-priority" 规则
|
||||
-
|
||||
|
||||
## 1.8.0
|
||||
|
||||
### 新功能 (Feat)
|
||||
**重大更新:本次更新增加了 Smart Core,可以根据用户使用习惯和节点质量自动选择符合您的最优节点。并内置了“一键开启”,适合不想折腾自定义规则的用户
|
||||
“一键开启”内置 Smart规则的功能在“内核设置”下的“使用自动 Smart 规则覆写”,原理:当开关开启后,自动载入覆写脚本,新增 Smart Group,并替换当前配置文件下的默认出站规则为"Smart Group",您的所有代理流量都将从此分组下的节点流出。如果使用“全局模式”请选择名称为"Smart Group"的节点,以使用该功能。**
|
||||
|
||||
注意:本功能还在测试中,如遇到问题请发 issue 反馈
|
||||
|
||||
## 1.7.7
|
||||
|
||||
### 新功能 (Feat)
|
||||
- Mihomo 内核升级 v1.19.12
|
||||
- 新增 Webdav 最大备数设置和清理逻辑
|
||||
|
||||
### 修复 (Fix)
|
||||
- 修复 MacOS 下无法启动的问题(重置工作目录权限)
|
||||
- 尝试修复不同版本 MacOS 下安装软件时候的报错(Input/output error)
|
||||
- 部分遗漏的多国语言翻译
|
||||
|
||||
## 1.7.6
|
||||
|
||||
**此版本修复了 1.7.5 中的几个严重 bug,推荐所有人更新**
|
||||
|
||||
### 修复 (Fix)
|
||||
- 修复了内核1.19.8更新后gist同步失效的问题(#780)
|
||||
- 部分遗漏的多国语言翻译
|
||||
- MacOS 下启动Error: EACCES: permission denied
|
||||
- MacOS 系统代理 bypass 不生效
|
||||
- MacOS 系统代理开启时 500 报错
|
||||
@ -39,12 +39,14 @@ mac:
|
||||
target:
|
||||
- pkg
|
||||
entitlementsInherit: build/entitlements.mac.plist
|
||||
hardenedRuntime: true
|
||||
gatekeeperAssess: false
|
||||
extendInfo:
|
||||
- NSCameraUsageDescription: Application requests access to the device's camera.
|
||||
- NSMicrophoneUsageDescription: Application requests access to the device's microphone.
|
||||
- NSDocumentsFolderUsageDescription: Application requests access to the user's Documents folder.
|
||||
- NSDownloadsFolderUsageDescription: Application requests access to the user's Downloads folder.
|
||||
notarize: true
|
||||
notarize: false
|
||||
artifactName: ${name}-macos-${version}-${arch}.${ext}
|
||||
pkg:
|
||||
allowAnywhere: false
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mihomo-party",
|
||||
"version": "1.8.0",
|
||||
"version": "1.8.1",
|
||||
"description": "Mihomo Party",
|
||||
"main": "./out/main/index.js",
|
||||
"author": "mihomo-party-org",
|
||||
|
||||
@ -4,12 +4,11 @@ import { addOverrideItem, removeOverrideItem, getOverrideItem } from './override
|
||||
const SMART_OVERRIDE_ID = 'smart-core-override'
|
||||
|
||||
/**
|
||||
* 生成 Smart 内核的覆写配置模板
|
||||
* Smart 内核的覆写配置模板
|
||||
*/
|
||||
function generateSmartOverrideTemplate(useLightGBM: boolean, collectData: boolean, strategy: string): string {
|
||||
return `
|
||||
// Smart 内核覆写配置
|
||||
// 此配置会在启用 Smart 内核时自动应用
|
||||
// 配置会在启用 Smart 内核时自动应用
|
||||
|
||||
function main(config) {
|
||||
try {
|
||||
@ -30,7 +29,7 @@ function main(config) {
|
||||
config['proxy-groups'] = []
|
||||
}
|
||||
|
||||
// 查找现有的 Smart 代理组并更新配置
|
||||
// 查找现有的 Smart 代理组并更新
|
||||
let smartGroupExists = false
|
||||
for (let i = 0; i < config['proxy-groups'].length; i++) {
|
||||
const group = config['proxy-groups'][i]
|
||||
@ -38,11 +37,9 @@ function main(config) {
|
||||
smartGroupExists = true
|
||||
console.log('[Smart Override] Found existing smart group:', group.name)
|
||||
|
||||
// 确保 Smart 组有正确的配置
|
||||
if (!group['policy-priority']) {
|
||||
group['policy-priority'] = '' // policy-priority: <1 means lower priority, >1 means higher priority, the default is 1, pattern support regex and string
|
||||
}
|
||||
// 始终使用用户配置的值
|
||||
group.uselightgbm = ${useLightGBM}
|
||||
group.collectdata = ${collectData}
|
||||
group.strategy = '${strategy}'
|
||||
@ -50,11 +47,11 @@ function main(config) {
|
||||
}
|
||||
}
|
||||
|
||||
// 如果没有 Smart 组且有可用代理,创建一个示例组
|
||||
// 如果没有 Smart 组且有可用代理,创建示例组
|
||||
if (!smartGroupExists && config.proxies && Array.isArray(config.proxies) && config.proxies.length > 0) {
|
||||
console.log('[Smart Override] Creating new smart group with', config.proxies.length, 'proxies')
|
||||
|
||||
// 获取所有代理的名称,确保代理对象有name属性
|
||||
// 获取所有代理的名称
|
||||
const proxyNames = config.proxies
|
||||
.filter(proxy => proxy && typeof proxy === 'object' && proxy.name)
|
||||
.map(proxy => proxy.name)
|
||||
@ -69,7 +66,6 @@ function main(config) {
|
||||
strategy: '${strategy}',
|
||||
proxies: proxyNames
|
||||
}
|
||||
// 将 Smart 分组插入到第一个位置
|
||||
config['proxy-groups'].unshift(smartGroup)
|
||||
console.log('[Smart Override] Created smart group at first position with proxies:', proxyNames)
|
||||
} else {
|
||||
@ -79,11 +75,11 @@ function main(config) {
|
||||
console.log('[Smart Override] No proxies available, skipping smart group creation')
|
||||
}
|
||||
|
||||
// 处理规则替换:将非 DIRECT 规则替换为 Smart Group
|
||||
// 处理规则替换
|
||||
if (config.rules && Array.isArray(config.rules)) {
|
||||
console.log('[Smart Override] Processing rules, original count:', config.rules.length)
|
||||
|
||||
// 收集所有代理组名称,用于智能识别
|
||||
// 收集所有代理组名称
|
||||
const proxyGroupNames = new Set()
|
||||
if (config['proxy-groups'] && Array.isArray(config['proxy-groups'])) {
|
||||
config['proxy-groups'].forEach(group => {
|
||||
@ -102,7 +98,7 @@ function main(config) {
|
||||
'COMPATIBLE'
|
||||
])
|
||||
|
||||
// 添加常见的规则参数,这些不应该被替换
|
||||
// 添加常见的规则参数,不应该替换
|
||||
const ruleParams = new Set(['no-resolve', 'force-remote-dns', 'prefer-ipv6'])
|
||||
|
||||
console.log('[Smart Override] Found', proxyGroupNames.size, 'proxy groups:', Array.from(proxyGroupNames))
|
||||
@ -123,12 +119,12 @@ function main(config) {
|
||||
let targetIndex = -1
|
||||
let targetValue = ''
|
||||
|
||||
// 对于 MATCH 规则,目标在第2个位置(索引1)
|
||||
// 处理 MATCH 规则
|
||||
if (parts[0] === 'MATCH' && parts.length === 2) {
|
||||
targetIndex = 1
|
||||
targetValue = parts[1]
|
||||
} else if (parts.length >= 3) {
|
||||
// 对于其他规则,从第3个参数开始查找(索引2),找到第一个不是规则参数的值
|
||||
// 处理其他规则
|
||||
for (let i = 2; i < parts.length; i++) {
|
||||
const part = parts[i]
|
||||
if (!ruleParams.has(part)) {
|
||||
@ -140,7 +136,7 @@ function main(config) {
|
||||
}
|
||||
|
||||
if (targetIndex !== -1 && targetValue) {
|
||||
// 检查是否应该替换这个目标
|
||||
// 检查是否应该替换
|
||||
const shouldReplace = !builtinTargets.has(targetValue) &&
|
||||
(proxyGroupNames.has(targetValue) ||
|
||||
!ruleParams.has(targetValue))
|
||||
@ -154,7 +150,7 @@ function main(config) {
|
||||
}
|
||||
}
|
||||
} else if (typeof rule === 'object' && rule !== null) {
|
||||
// 处理对象格式的规则
|
||||
// 处理对象格式
|
||||
let targetField = ''
|
||||
let targetValue = ''
|
||||
|
||||
@ -268,10 +264,8 @@ export async function manageSmartOverride(): Promise<void> {
|
||||
const { enableSmartCore = true, enableSmartOverride = true, core } = await getAppConfig()
|
||||
|
||||
if (enableSmartCore && enableSmartOverride && core === 'mihomo-smart') {
|
||||
// 启用 Smart 内核且启用覆写时创建或更新覆写配置
|
||||
await createSmartOverride()
|
||||
} else {
|
||||
// 其他情况删除覆写配置
|
||||
await removeSmartOverride()
|
||||
}
|
||||
}
|
||||
|
||||
@ -266,7 +266,6 @@ async function checkProfile(): Promise<void> {
|
||||
console.log('Profile check stdout:', stdout)
|
||||
console.log('Profile check stderr:', stderr)
|
||||
|
||||
// 提取错误信息
|
||||
const errorLines = stdout
|
||||
.split('\n')
|
||||
.filter((line) => line.includes('level=error') || line.includes('error'))
|
||||
@ -278,7 +277,6 @@ async function checkProfile(): Promise<void> {
|
||||
})
|
||||
.filter(line => line.length > 0)
|
||||
|
||||
// 如果没有找到错误行,显示完整输出
|
||||
if (errorLines.length === 0) {
|
||||
const allLines = stdout.split('\n').filter(line => line.trim().length > 0)
|
||||
throw new Error(`${i18next.t('mihomo.error.profileCheckFailed')}:\n${allLines.join('\n')}`)
|
||||
|
||||
@ -168,7 +168,7 @@ export const mihomoUpgrade = async (): Promise<void> => {
|
||||
return await instance.post('/upgrade')
|
||||
}
|
||||
|
||||
// Smart 内核特有的 API
|
||||
// Smart 内核 API
|
||||
export const mihomoSmartGroupWeights = async (groupName: string): Promise<Record<string, number>> => {
|
||||
const instance = await getAxios()
|
||||
return await instance.get(`/group/${encodeURIComponent(groupName)}/weights`)
|
||||
|
||||
@ -69,7 +69,7 @@ export function mihomoCoreDir(): string {
|
||||
|
||||
export function mihomoCorePath(core: string): string {
|
||||
const isWin = process.platform === 'win32'
|
||||
// 处理 Smart 内核的特殊情况
|
||||
// 处理 Smart 内核
|
||||
if (core === 'mihomo-smart') {
|
||||
return path.join(mihomoCoreDir(), `mihomo-smart${isWin ? '.exe' : ''}`)
|
||||
}
|
||||
|
||||
@ -143,7 +143,7 @@ export function registerIpcMainHandlers(): void {
|
||||
ipcErrorWrapper(mihomoGroupDelay)(group, url)
|
||||
)
|
||||
ipcMain.handle('patchMihomoConfig', (_e, patch) => ipcErrorWrapper(patchMihomoConfig)(patch))
|
||||
// Smart 内核特有的 API
|
||||
// Smart 内核 API
|
||||
ipcMain.handle('mihomoSmartGroupWeights', (_e, groupName) =>
|
||||
ipcErrorWrapper(mihomoSmartGroupWeights)(groupName)
|
||||
)
|
||||
|
||||
@ -39,7 +39,7 @@ const ConnectionItem: React.FC<Props> = (props) => {
|
||||
<Chip
|
||||
color={`${info.isActive ? 'primary' : 'danger'}`}
|
||||
size="sm"
|
||||
radius="xs"
|
||||
radius="sm"
|
||||
variant="dot"
|
||||
>
|
||||
{info.metadata.type}({info.metadata.network.toUpperCase()})
|
||||
@ -65,16 +65,16 @@ const ConnectionItem: React.FC<Props> = (props) => {
|
||||
<Chip
|
||||
className="flag-emoji text-ellipsis whitespace-nowrap overflow-hidden"
|
||||
size="sm"
|
||||
radius="xs"
|
||||
radius="sm"
|
||||
variant="bordered"
|
||||
>
|
||||
{info.chains[0]}
|
||||
</Chip>
|
||||
<Chip size="sm" radius="xs" variant="bordered">
|
||||
<Chip size="sm" radius="sm" variant="bordered">
|
||||
↑ {calcTraffic(info.upload)} ↓ {calcTraffic(info.download)}
|
||||
</Chip>
|
||||
{info.uploadSpeed !== 0 || info.downloadSpeed !== 0 ? (
|
||||
<Chip color="primary" size="sm" radius="xs" variant="bordered">
|
||||
<Chip color="primary" size="sm" radius="sm" variant="bordered">
|
||||
↑ {calcTraffic(info.uploadSpeed || 0)}/s ↓ {calcTraffic(info.downloadSpeed || 0)}
|
||||
/s
|
||||
</Chip>
|
||||
|
||||
@ -68,7 +68,7 @@ const ProxyItem: React.FC<Props> = (props) => {
|
||||
? 'bg-primary/30 border-r-2 border-r-primary border-l-2 border-l-primary'
|
||||
: 'bg-content2'
|
||||
}`}
|
||||
radius="xs"
|
||||
radius="sm"
|
||||
>
|
||||
<CardBody className="p-1">
|
||||
{proxyDisplayMode === 'full' ? (
|
||||
|
||||
@ -89,11 +89,9 @@ const Mihomo: React.FC = () => {
|
||||
await patchAppConfig({ [key]: value })
|
||||
await restartCore()
|
||||
} catch (e) {
|
||||
// 显示详细的错误信息
|
||||
const errorMessage = e instanceof Error ? e.message : String(e)
|
||||
console.error('Core restart failed:', errorMessage)
|
||||
|
||||
// 如果是配置检查失败,显示详细错误
|
||||
if (errorMessage.includes('配置检查失败') || errorMessage.includes('Profile Check Failed')) {
|
||||
await showDetailedError(t('mihomo.error.profileCheckFailed'), errorMessage)
|
||||
} else {
|
||||
@ -108,7 +106,7 @@ const Mihomo: React.FC = () => {
|
||||
<>
|
||||
{lanOpen && <InterfaceModal onClose={() => setLanOpen(false)} />}
|
||||
<BasePage title={t('mihomo.title')}>
|
||||
{/* Smart 内核专用设置区域 */}
|
||||
{/* Smart 内核设置 */}
|
||||
<SettingCard>
|
||||
<div className={`rounded-md border p-2 transition-all duration-200 ${
|
||||
enableSmartCore
|
||||
@ -126,17 +124,15 @@ const Mihomo: React.FC = () => {
|
||||
onValueChange={async (v) => {
|
||||
await patchAppConfig({ enableSmartCore: v })
|
||||
if (v && core !== 'mihomo-smart') {
|
||||
// 启用 Smart 内核时,自动切换到 Smart 内核
|
||||
await handleConfigChangeWithRestart('core', 'mihomo-smart')
|
||||
} else if (!v && core === 'mihomo-smart') {
|
||||
// 禁用 Smart 内核时,切换回普通内核
|
||||
await handleConfigChangeWithRestart('core', 'mihomo')
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</SettingItem>
|
||||
|
||||
{/* Smart 覆写开关 - 只在启用 Smart 内核时显示 */}
|
||||
{/* Smart 覆写开关 */}
|
||||
{enableSmartCore && (
|
||||
<SettingItem
|
||||
title={
|
||||
@ -159,7 +155,6 @@ const Mihomo: React.FC = () => {
|
||||
color="primary"
|
||||
onValueChange={async (v) => {
|
||||
await patchAppConfig({ enableSmartOverride: v })
|
||||
// 重新生成覆写配置
|
||||
await restartCore()
|
||||
}}
|
||||
/>
|
||||
@ -219,10 +214,8 @@ const Mihomo: React.FC = () => {
|
||||
}}
|
||||
>
|
||||
{enableSmartCore ? (
|
||||
// 启用 Smart 内核时,只显示 Smart 版本
|
||||
<SelectItem key="mihomo-smart">{t(CoreMap['mihomo-smart'])}</SelectItem>
|
||||
) : (
|
||||
// 未启用 Smart 内核时,显示普通版本
|
||||
<>
|
||||
<SelectItem key="mihomo">{t(CoreMap['mihomo'])}</SelectItem>
|
||||
<SelectItem key="mihomo-alpha">{t(CoreMap['mihomo-alpha'])}</SelectItem>
|
||||
@ -231,7 +224,7 @@ const Mihomo: React.FC = () => {
|
||||
</Select>
|
||||
</SettingItem>
|
||||
|
||||
{/* Smart 内核专用配置选项 */}
|
||||
{/* Smart 内核配置项 */}
|
||||
{enableSmartCore && core === 'mihomo-smart' && (
|
||||
<>
|
||||
<SettingItem
|
||||
@ -244,7 +237,6 @@ const Mihomo: React.FC = () => {
|
||||
isSelected={smartCoreUseLightGBM}
|
||||
onValueChange={async (v) => {
|
||||
await patchAppConfig({ smartCoreUseLightGBM: v })
|
||||
// 重新生成覆写配置
|
||||
await restartCore()
|
||||
}}
|
||||
/>
|
||||
@ -260,7 +252,6 @@ const Mihomo: React.FC = () => {
|
||||
isSelected={smartCoreCollectData}
|
||||
onValueChange={async (v) => {
|
||||
await patchAppConfig({ smartCoreCollectData: v })
|
||||
// 重新生成覆写配置
|
||||
await restartCore()
|
||||
}}
|
||||
/>
|
||||
@ -279,7 +270,6 @@ const Mihomo: React.FC = () => {
|
||||
onSelectionChange={async (v) => {
|
||||
const strategy = v.currentKey as 'sticky-sessions' | 'round-robin'
|
||||
await patchAppConfig({ smartCoreStrategy: strategy })
|
||||
// 重新生成覆写配置
|
||||
await restartCore()
|
||||
}}
|
||||
>
|
||||
|
||||
@ -85,7 +85,7 @@ const Profiles: React.FC = () => {
|
||||
<div>
|
||||
{sub.tag?.map((tag) => {
|
||||
return (
|
||||
<Chip key={tag} size="sm" className="ml-1" radius="xs">
|
||||
<Chip key={tag} size="sm" className="ml-1" radius="sm">
|
||||
{tag}
|
||||
</Chip>
|
||||
)
|
||||
@ -108,7 +108,7 @@ const Profiles: React.FC = () => {
|
||||
<div>
|
||||
{sub.tag?.map((tag) => {
|
||||
return (
|
||||
<Chip key={tag} size="sm" className="ml-1" radius="xs">
|
||||
<Chip key={tag} size="sm" className="ml-1" radius="sm">
|
||||
{tag}
|
||||
</Chip>
|
||||
)
|
||||
|
||||
@ -324,7 +324,7 @@ const Proxies: React.FC = () => {
|
||||
<Avatar
|
||||
className="bg-transparent mr-2"
|
||||
size="sm"
|
||||
radius="xs"
|
||||
radius="sm"
|
||||
src={
|
||||
groups[index].icon.startsWith('<svg')
|
||||
? `data:image/svg+xml;utf8,${groups[index].icon}`
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user