Compare commits

...

4 Commits

Author SHA1 Message Date
Memory2314
f959801db2 Bump to 1.9.4 2026-03-29 23:41:53 +08:00
Memory2314
d2e651e79d update changelog.md 2026-03-29 23:41:53 +08:00
Memory2314
8530cdefcc pnpm update 2026-03-29 23:41:53 +08:00
StarHeart
2a4b9f4e5b
feat: support user agent config per sub (#1712)
* feat: add user agent support in profile configuration

* Introduced a new user agent field in profile settings, allowing users to specify a custom user agent.
* Updated relevant components and localization files to support the new user agent feature.
* Added a new pnpm workspace configuration for built dependencies.

* feat: enhance profile settings with user agent input and toggle functionality

* Added a user agent input field to the advanced profile settings.
* Implemented toggle icons for showing/hiding advanced settings.
* Updated layout to accommodate the new user agent input alongside the existing auth token field.

* chore: remove pnpm workspace configuration for built dependencies
2026-03-29 18:54:56 +08:00
13 changed files with 408 additions and 416 deletions

View File

@ -1,64 +1,16 @@
# 1.9.3 # 1.9.4
## 新功能 (Feat) ## 新功能 (Feat)
- 新增网络信息页卡片 - 新增每个订阅独立的 User-Agent 配置
- 更新下载新增进度显示和 SHA256 完整性校验 - 使用 mshta 在 Electron 初始化前同步检测 PowerShell 版本
## 修复 (Fix) ## 修复 (Fix)
- 修复更新软件时的超时问题 - 修复 Win7 兼容性问题
- 修复切换离开智能内核时未清理智能覆盖配置的问题 - 修复日志清理正则表达式以正确匹配带前缀的文件名
- 修复部分机场返回压缩包导致订阅导入失败的问题
- 修复悬浮窗无法关闭的问题
- 修复日志滚动延迟的问题
- 修复添加新订阅时只能重启生效的问题
- 修复进入代理列表页面时滚动位置未重置到顶部的问题
- 修复托盘流量图标闪烁问题
## 其他 (Chore) ## 其他 (Chore)
- 重构 rule-item 额外字段处理逻辑并补充类型定义
- 更新依赖 - 更新依赖
# 1.9.2
## 新功能 (Feat)
- 增加 Fish 和 Nushell 环境变量支持
- 增加规则统计和禁用开关
- 连接页面显示应用图标
- 增加订阅超时设置
- 增加 Windows 7 兼容构建支持
## 修复 (Fix)
- 修复 group.all 过滤器中代理未定义导致的错误
- 修复默认延迟测试 URL 改为 HTTPS
- 修复连接图表 z-index 和缩放问题
- 修复减少动画模式下侧边栏卡片拖拽动画异常
- 修复 IME 输入法输入时字符重复问题
- 修复配置切换失败后切换队列损坏问题
- 修复取消最大化状态未保存的问题
- 优化备份配置导入处理
- 修复禁用自动滚动时日志显示未冻结的问题
- 修复订阅页面相对时间未自动刷新的问题
- 修复连接数badge遮挡下方关闭按钮点击的问题
## 优化 (Optimize)
- 虚拟化规则编辑弹窗中的规则列表,提升渲染性能
- 优化内核启动性能
- 重构外部控制器和规则编辑器
- 优化订阅更新逻辑效率
## 其他 (Chore)
- 更新依赖
# 1.9.1
## 修复 (Fix)
- 修复 Windows 下以管理员重启开启 TUN 时因单实例锁冲突导致的闪退问题
- 修复托盘菜单开启 TUN 时管理员重启后继续执行导致的竞态问题
- 修复关键资源文件复制失败时静默跳过导致内核启动异常的问题

View File

@ -1,6 +1,6 @@
{ {
"name": "mihomo-party", "name": "mihomo-party",
"version": "1.9.3", "version": "1.9.4",
"description": "Clash Party", "description": "Clash Party",
"type": "module", "type": "module",
"main": "./out/main/index.js", "main": "./out/main/index.js",
@ -36,7 +36,7 @@
"@electron-toolkit/utils": "^4.0.0", "@electron-toolkit/utils": "^4.0.0",
"@types/plist": "^3.0.5", "@types/plist": "^3.0.5",
"adm-zip": "^0.5.16", "adm-zip": "^0.5.16",
"axios": "^1.13.6", "axios": "^1.14.0",
"chokidar": "^5.0.0", "chokidar": "^5.0.0",
"croner": "^9.1.0", "croner": "^9.1.0",
"crypto-js": "^4.2.0", "crypto-js": "^4.2.0",
@ -44,7 +44,7 @@
"file-icon": "^6.0.0", "file-icon": "^6.0.0",
"file-icon-info": "^1.1.1", "file-icon-info": "^1.1.1",
"flag-icons": "^7.5.0", "flag-icons": "^7.5.0",
"i18next": "^25.10.3", "i18next": "^25.10.10",
"iconv-lite": "^0.7.2", "iconv-lite": "^0.7.2",
"js-yaml": "^4.1.1", "js-yaml": "^4.1.1",
"plist": "^3.1.0", "plist": "^3.1.0",
@ -72,8 +72,8 @@
"@types/react-dom": "^19.2.3", "@types/react-dom": "^19.2.3",
"@types/validator": "^13.15.10", "@types/validator": "^13.15.10",
"@types/ws": "^8.18.1", "@types/ws": "^8.18.1",
"@typescript-eslint/eslint-plugin": "^8.57.1", "@typescript-eslint/eslint-plugin": "^8.57.2",
"@typescript-eslint/parser": "^8.57.1", "@typescript-eslint/parser": "^8.57.2",
"@vitejs/plugin-react": "^5.2.0", "@vitejs/plugin-react": "^5.2.0",
"chart.js": "^4.5.1", "chart.js": "^4.5.1",
"cron-validator": "^1.4.0", "cron-validator": "^1.4.0",
@ -101,20 +101,20 @@
"react-chartjs-2": "^5.3.1", "react-chartjs-2": "^5.3.1",
"react-dom": "^19.2.4", "react-dom": "^19.2.4",
"react-error-boundary": "^6.1.1", "react-error-boundary": "^6.1.1",
"react-i18next": "^16.6.0", "react-i18next": "^16.6.6",
"react-icons": "^5.6.0", "react-icons": "^5.6.0",
"react-markdown": "^10.1.0", "react-markdown": "^10.1.0",
"react-monaco-editor": "^0.59.0", "react-monaco-editor": "^0.59.0",
"react-router-dom": "^7.13.1", "react-router-dom": "^7.13.2",
"react-virtuoso": "^4.18.3", "react-virtuoso": "^4.18.3",
"swr": "^2.4.1", "swr": "^2.4.1",
"tailwindcss": "^4.2.2", "tailwindcss": "^4.2.2",
"tar": "^7.5.12", "tar": "^7.5.13",
"tsx": "^4.21.0", "tsx": "^4.21.0",
"types-pac": "^1.0.3", "types-pac": "^1.0.3",
"typescript": "^5.9.3", "typescript": "^5.9.3",
"vite": "^7.3.1", "vite": "^7.3.1",
"vite-plugin-monaco-editor": "^1.1.0" "vite-plugin-monaco-editor": "^1.1.0"
}, },
"packageManager": "pnpm@10.27.0" "packageManager": "pnpm@10.33.0"
} }

679
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -248,6 +248,7 @@ export async function createProfile(item: Partial<IProfileItem>): Promise<IProfi
allowFixedInterval: item.allowFixedInterval || false, allowFixedInterval: item.allowFixedInterval || false,
autoUpdate: item.autoUpdate ?? false, autoUpdate: item.autoUpdate ?? false,
authToken: item.authToken, authToken: item.authToken,
userAgent: item.userAgent,
updated: new Date().getTime(), updated: new Date().getTime(),
updateTimeout: item.updateTimeout || 5 updateTimeout: item.updateTimeout || 5
} }
@ -268,7 +269,7 @@ export async function createProfile(item: Partial<IProfileItem>): Promise<IProfi
const baseOptions: Omit<FetchOptions, 'useProxy' | 'timeout'> = { const baseOptions: Omit<FetchOptions, 'useProxy' | 'timeout'> = {
url: item.url, url: item.url,
mixedPort, mixedPort,
userAgent: userAgent || `mihomo.party/v${app.getVersion()} (clash.meta)`, userAgent: item.userAgent || userAgent || `mihomo.party/v${app.getVersion()} (clash.meta)`,
authToken: item.authToken, authToken: item.authToken,
substore: newItem.substore || false substore: newItem.substore || false
} }

View File

@ -108,6 +108,17 @@ const EditInfoModal: React.FC<Props> = (props) => {
placeholder={t('profiles.editInfo.authTokenPlaceholder')} placeholder={t('profiles.editInfo.authTokenPlaceholder')}
/> />
</SettingItem> </SettingItem>
<SettingItem title={t('profiles.editInfo.userAgent')}>
<Input
size="sm"
className={cn(inputWidth)}
value={values.userAgent || ''}
onValueChange={(v) => {
setValues({ ...values, userAgent: v || undefined })
}}
placeholder={t('profiles.editInfo.userAgentPlaceholder')}
/>
</SettingItem>
<SettingItem title={t('profiles.editInfo.useProxy')}> <SettingItem title={t('profiles.editInfo.useProxy')}>
<Switch <Switch
size="sm" size="sm"

View File

@ -496,6 +496,8 @@
"profiles.editInfo.url": "Subscription URL", "profiles.editInfo.url": "Subscription URL",
"profiles.editInfo.authToken": "Authorization Token", "profiles.editInfo.authToken": "Authorization Token",
"profiles.editInfo.authTokenPlaceholder": "Bearer token or other auth header value", "profiles.editInfo.authTokenPlaceholder": "Bearer token or other auth header value",
"profiles.editInfo.userAgent": "User Agent",
"profiles.editInfo.userAgentPlaceholder": "Leave empty to use global User Agent",
"profiles.editInfo.useProxy": "Use Proxy to Update", "profiles.editInfo.useProxy": "Use Proxy to Update",
"profiles.editInfo.interval": "Upd. Interval", "profiles.editInfo.interval": "Upd. Interval",
"profiles.editInfo.intervalPlaceholder": "e.g.: 30 or '0 * * * *'", "profiles.editInfo.intervalPlaceholder": "e.g.: 30 or '0 * * * *'",

View File

@ -471,6 +471,8 @@
"profiles.editInfo.title": "ویرایش اطلاعات", "profiles.editInfo.title": "ویرایش اطلاعات",
"profiles.editInfo.name": "نام", "profiles.editInfo.name": "نام",
"profiles.editInfo.url": "آدرس اشتراک", "profiles.editInfo.url": "آدرس اشتراک",
"profiles.editInfo.userAgent": "User Agent",
"profiles.editInfo.userAgentPlaceholder": "برای استفاده از User Agent جهانی خالی بگذارید",
"profiles.editInfo.useProxy": "استفاده از پراکسی برای به‌روزرسانی", "profiles.editInfo.useProxy": "استفاده از پراکسی برای به‌روزرسانی",
"profiles.editInfo.interval": "فاصله به‌روزرسانی", "profiles.editInfo.interval": "فاصله به‌روزرسانی",
"profiles.editInfo.fixedInterval": "فاصله به‌روزرسانی ثابت", "profiles.editInfo.fixedInterval": "فاصله به‌روزرسانی ثابت",

View File

@ -473,6 +473,8 @@
"profiles.editInfo.title": "Редактировать информацию", "profiles.editInfo.title": "Редактировать информацию",
"profiles.editInfo.name": "Имя", "profiles.editInfo.name": "Имя",
"profiles.editInfo.url": "URL подписки", "profiles.editInfo.url": "URL подписки",
"profiles.editInfo.userAgent": "User Agent",
"profiles.editInfo.userAgentPlaceholder": "Оставьте пустым для глобального User Agent",
"profiles.editInfo.useProxy": "Использовать прокси для обновления", "profiles.editInfo.useProxy": "Использовать прокси для обновления",
"profiles.editInfo.interval": "Интервал обн.", "profiles.editInfo.interval": "Интервал обн.",
"profiles.editInfo.fixedInterval": "Фиксированный интервал обновления", "profiles.editInfo.fixedInterval": "Фиксированный интервал обновления",

View File

@ -501,6 +501,8 @@
"profiles.editInfo.url": "订阅地址", "profiles.editInfo.url": "订阅地址",
"profiles.editInfo.authToken": "授权令牌", "profiles.editInfo.authToken": "授权令牌",
"profiles.editInfo.authTokenPlaceholder": "Bearer token 或其他认证头值", "profiles.editInfo.authTokenPlaceholder": "Bearer token 或其他认证头值",
"profiles.editInfo.userAgent": "User Agent",
"profiles.editInfo.userAgentPlaceholder": "留空则使用全局 User Agent",
"profiles.editInfo.useProxy": "使用代理更新", "profiles.editInfo.useProxy": "使用代理更新",
"profiles.editInfo.interval": "更新间隔", "profiles.editInfo.interval": "更新间隔",
"profiles.editInfo.intervalPlaceholder": "例如30 或 '0 * * * *'", "profiles.editInfo.intervalPlaceholder": "例如30 或 '0 * * * *'",

View File

@ -501,6 +501,8 @@
"profiles.editInfo.url": "訂閱地址", "profiles.editInfo.url": "訂閱地址",
"profiles.editInfo.authToken": "授權令牌", "profiles.editInfo.authToken": "授權令牌",
"profiles.editInfo.authTokenPlaceholder": "Bearer token 或其他認證頭值", "profiles.editInfo.authTokenPlaceholder": "Bearer token 或其他認證頭值",
"profiles.editInfo.userAgent": "User Agent",
"profiles.editInfo.userAgentPlaceholder": "留空則使用全局 User Agent",
"profiles.editInfo.useProxy": "使用代理更新", "profiles.editInfo.useProxy": "使用代理更新",
"profiles.editInfo.interval": "更新間隔", "profiles.editInfo.interval": "更新間隔",
"profiles.editInfo.intervalPlaceholder": "例如30 或 '0 * * * *'", "profiles.editInfo.intervalPlaceholder": "例如30 或 '0 * * * *'",

View File

@ -18,7 +18,7 @@ import { useAppConfig } from '@renderer/hooks/use-app-config'
import { getFilePath, readTextFile, subStoreCollections, subStoreSubs } from '@renderer/utils/ipc' import { getFilePath, readTextFile, subStoreCollections, subStoreSubs } from '@renderer/utils/ipc'
import type { KeyboardEvent } from 'react' import type { KeyboardEvent } from 'react'
import { ReactNode, useCallback, useEffect, useMemo, useRef, useState } from 'react' import { ReactNode, useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { MdContentPaste } from 'react-icons/md' import { MdContentPaste, MdUnfoldMore, MdUnfoldLess } from 'react-icons/md'
import { import {
DndContext, DndContext,
closestCenter, closestCenter,
@ -53,6 +53,7 @@ const Profiles: React.FC = () => {
const [sortedItems, setSortedItems] = useState(items) const [sortedItems, setSortedItems] = useState(items)
const [useProxy, setUseProxy] = useState(false) const [useProxy, setUseProxy] = useState(false)
const [authToken, setAuthToken] = useState('') const [authToken, setAuthToken] = useState('')
const [userAgent, setUserAgent] = useState('')
const [showAdvanced, setShowAdvanced] = useState(false) const [showAdvanced, setShowAdvanced] = useState(false)
const [subStoreImporting, setSubStoreImporting] = useState(false) const [subStoreImporting, setSubStoreImporting] = useState(false)
const [importing, setImporting] = useState(false) const [importing, setImporting] = useState(false)
@ -135,10 +136,12 @@ const Profiles: React.FC = () => {
type: 'remote', type: 'remote',
url, url,
useProxy, useProxy,
authToken: authToken || undefined authToken: authToken || undefined,
userAgent: userAgent || undefined
}) })
setUrl('') setUrl('')
setAuthToken('') setAuthToken('')
setUserAgent('')
setImporting(false) setImporting(false)
} }
const pageRef = useRef<HTMLDivElement>(null) const pageRef = useRef<HTMLDivElement>(null)
@ -300,7 +303,11 @@ const Profiles: React.FC = () => {
isIconOnly isIconOnly
onPress={() => setShowAdvanced(!showAdvanced)} onPress={() => setShowAdvanced(!showAdvanced)}
> >
🔑 {showAdvanced ? (
<MdUnfoldLess className="text-lg" />
) : (
<MdUnfoldMore className="text-lg" />
)}
</Button> </Button>
</Tooltip> </Tooltip>
<Button <Button
@ -426,6 +433,7 @@ const Profiles: React.FC = () => {
</Dropdown> </Dropdown>
</div> </div>
{showAdvanced && ( {showAdvanced && (
<div className="flex gap-2">
<Input <Input
size="sm" size="sm"
type="password" type="password"
@ -433,9 +441,17 @@ const Profiles: React.FC = () => {
value={authToken} value={authToken}
onValueChange={setAuthToken} onValueChange={setAuthToken}
onKeyUp={handleInputKeyUp} onKeyUp={handleInputKeyUp}
className="w-full" className="flex-1"
startContent={<span className="text-default-400 text-sm">🔑</span>}
/> />
<Input
size="sm"
placeholder={t('profiles.editInfo.userAgentPlaceholder')}
value={userAgent}
onValueChange={setUserAgent}
onKeyUp={handleInputKeyUp}
className="flex-1"
/>
</div>
)} )}
</div> </div>
<Divider /> <Divider />

View File

@ -519,6 +519,7 @@ interface IProfileItem {
allowFixedInterval?: boolean allowFixedInterval?: boolean
autoUpdate?: boolean autoUpdate?: boolean
authToken?: string authToken?: string
userAgent?: string
updateTimeout?: number updateTimeout?: number
} }