From d3b24e2692a0c5772dca483087005c5aa6582742 Mon Sep 17 00:00:00 2001 From: VirtualHotBar <96966978+VirtualHotBar@users.noreply.github.com> Date: Wed, 4 Mar 2026 23:24:50 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E9=AB=98=E7=BA=A7?= =?UTF-8?q?=E8=AE=BE=E7=BD=AE=E5=92=8C=E9=A2=9D=E5=A4=96=E5=90=AF=E5=8A=A8?= =?UTF-8?q?=E5=8F=82=E6=95=B0=E5=8A=9F=E8=83=BD=EF=BC=8C=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src-tauri/locales/en.json | 5 +++ src-tauri/locales/zh-cn.json | 5 +++ src-tauri/locales/zh-hant.json | 5 +++ src/page/setting/setting.tsx | 41 +++++++++++++++++++- src/services/config.ts | 2 + src/type/config.d.ts | 2 + src/utils/cliArgs.ts | 69 ++++++++++++++++++++++++++++++++++ src/utils/openlist/process.ts | 4 +- src/utils/rclone/process.ts | 2 + src/utils/schemas.ts | 3 ++ 10 files changed, 136 insertions(+), 2 deletions(-) create mode 100644 src/utils/cliArgs.ts diff --git a/src-tauri/locales/en.json b/src-tauri/locales/en.json index 3107531..ebb4224 100644 --- a/src-tauri/locales/en.json +++ b/src-tauri/locales/en.json @@ -199,6 +199,10 @@ "log": "Log", "start_hide": "Hide Window on Startup", "auto_recover_components": "Auto-recover Components", + "advanced_settings": "Advanced Settings", + "extra_startup_args": "Extra Startup Args", + "rclone_extra_args": "Rclone Extra Startup Args", + "openlist_extra_args": "OpenList Extra Startup Args", "quit": "Quit", "tray_show": "Show Main Window", "open_log_dir": "Open Log Folder", @@ -704,3 +708,4 @@ "export_import_config_description": "Export current configuration or restore configuration from file", "confirm_import_description": "Importing configuration will overwrite all current settings and automatically restart the software. Continue?" } + diff --git a/src-tauri/locales/zh-cn.json b/src-tauri/locales/zh-cn.json index 740c687..7b3765b 100644 --- a/src-tauri/locales/zh-cn.json +++ b/src-tauri/locales/zh-cn.json @@ -199,6 +199,10 @@ "log": "日志", "start_hide": "启动时隐藏窗口", "auto_recover_components": "组件自愈", + "advanced_settings": "高级设置", + "extra_startup_args": "额外启动参数", + "rclone_extra_args": "Rclone 启动参数", + "openlist_extra_args": "OpenList 启动参数", "quit": "退出", "tray_show": "显示主窗口", "open_log_dir": "打开日志目录", @@ -704,3 +708,4 @@ "export_import_config_description": "导出当前配置或者从文件恢复配置", "confirm_import_description": "导入配置将覆盖当前所有配置并自动重启软件,是否继续?" } + diff --git a/src-tauri/locales/zh-hant.json b/src-tauri/locales/zh-hant.json index 7f119bc..2b5f234 100644 --- a/src-tauri/locales/zh-hant.json +++ b/src-tauri/locales/zh-hant.json @@ -199,6 +199,10 @@ "log": "日誌", "start_hide": "啟動時隱藏視窗", "auto_recover_components": "元件異常自動修復", + "advanced_settings": "高級設置", + "extra_startup_args": "額外啟動參數", + "rclone_extra_args": "Rclone 額外啟動參數", + "openlist_extra_args": "OpenList 額外啟動參數", "quit": "退出", "tray_show": "顯示主視窗", "open_log_dir": "打開日誌目錄", @@ -704,3 +708,4 @@ "export_import_config_description": "導出當前配置或者從文件恢復配置", "confirm_import_description": "導入配置將覆蓋當前所有配置並自動重啓軟件,是否繼續?" } + diff --git a/src/page/setting/setting.tsx b/src/page/setting/setting.tsx index 8cc0227..870a62f 100644 --- a/src/page/setting/setting.tsx +++ b/src/page/setting/setting.tsx @@ -1,5 +1,5 @@ import { useEffect, useReducer, useState } from 'react' -import { Button, Card, Form, Grid, Input, Link, Message, Modal, Select, Space, Switch, Tooltip } from '@arco-design/web-react' +import { Button, Card, Collapse, Form, Grid, Input, Link, Message, Modal, Select, Space, Switch, Tooltip } from '@arco-design/web-react' import { nmConfig, osInfo, roConfig, saveNmConfig } from '../../services/config'; import { getAutostartState, setAutostartState, setThemeMode } from '../../controller/setting/setting'; import { useTranslation } from 'react-i18next'; @@ -249,6 +249,45 @@ export default function Setting_page() { + +
+ + + + { + nmConfig.framework.rclone.extraArgs = value + forceUpdate() + }} + /> + + + { + nmConfig.framework.openlist.extraArgs = value + forceUpdate() + }} + /> + + + +
+ +
+
+
{ shell.open(roConfig.url.rclone) }}>Rclone( { if ((rcloneInfo.process.log || '').trim()) { diff --git a/src/services/config.ts b/src/services/config.ts index da96a75..6dfc48d 100644 --- a/src/services/config.ts +++ b/src/services/config.ts @@ -75,10 +75,12 @@ let nmConfig: NMConfig = { rclone: { user: randomString(32), password: randomString(128), + extraArgs: '', }, openlist: { user: 'admin', password: randomString(16),//process.env.NODE_ENV === 'development' ? 'admin' : randomString(32),!!!!!密码长度为32时rclone会报错 + extraArgs: '', } } } diff --git a/src/type/config.d.ts b/src/type/config.d.ts index a062561..c3e6179 100644 --- a/src/type/config.d.ts +++ b/src/type/config.d.ts @@ -24,10 +24,12 @@ interface NMConfig { rclone: { user: string, password: string, + extraArgs?: string, }, openlist: { user: string, password: string, + extraArgs?: string, } } } diff --git a/src/utils/cliArgs.ts b/src/utils/cliArgs.ts new file mode 100644 index 0000000..fcb48ea --- /dev/null +++ b/src/utils/cliArgs.ts @@ -0,0 +1,69 @@ +function parseExtraCliArgs(input?: string): string[] { + if (!input || !input.trim()) return [] + + const args: string[] = [] + let current = '' + let quote: '"' | "'" | null = null + + for (let i = 0; i < input.length; i++) { + const ch = input[i]! + const next = input[i + 1] + + if (ch === '\\') { + if (quote === '"') { + // In double quotes, allow escaping quote/backslash. + if (next === '"' || next === '\\') { + current += next + i++ + continue + } + current += ch + continue + } + + if (!quote) { + // Outside quotes, only treat as escape for whitespace/quote/backslash. + if (next && (/\s/.test(next) || next === '"' || next === "'" || next === '\\')) { + current += next + i++ + continue + } + // Keep normal Windows paths like C:\temp\logs literally. + current += ch + continue + } + } + + if (quote) { + if (ch === quote) { + quote = null + } else { + current += ch + } + continue + } + + if (ch === '"' || ch === "'") { + quote = ch + continue + } + + if (/\s/.test(ch)) { + if (current) { + args.push(current) + current = '' + } + continue + } + + current += ch + } + + if (current) { + args.push(current) + } + + return args +} + +export { parseExtraCliArgs } diff --git a/src/utils/openlist/process.ts b/src/utils/openlist/process.ts index 12162fc..7dce15a 100644 --- a/src/utils/openlist/process.ts +++ b/src/utils/openlist/process.ts @@ -7,6 +7,7 @@ import { openlist_api_ping } from "./request"; import { addParams, openlistDataDir } from "./paths"; import { openlistLogFile } from "../netmountPaths"; import { restartSidecar, startSidecarAndWait, stopSidecarGracefully } from "../sidecarService"; +import { parseExtraCliArgs } from "../cliArgs"; async function startOpenlist() { //设置默认临时(缓存)目录 @@ -32,7 +33,8 @@ async function startOpenlist() { const args: string[] = [ 'server', - ...addParams() + ...addParams(), + ...parseExtraCliArgs(nmConfig.framework.openlist.extraArgs) ]; console.log('OpenList start args:', args) diff --git a/src/utils/rclone/process.ts b/src/utils/rclone/process.ts index eb09348..338adff 100644 --- a/src/utils/rclone/process.ts +++ b/src/utils/rclone/process.ts @@ -8,6 +8,7 @@ import { delStorage } from "../../controller/storage/storage"; import { nmConfig, osInfo } from "../../services/config"; import { netmountLogDir, rcloneConfigFile, rcloneLogFile } from "../netmountPaths"; import { restartSidecar, startSidecarAndWait, stopSidecarGracefully } from "../sidecarService"; +import { parseExtraCliArgs } from "../cliArgs"; async function startRclone() { if (rcloneInfo.process.child) { @@ -47,6 +48,7 @@ async function startRclone() { if (nmConfig.framework.rclone.user === '') { args.push('--rc-no-auth') } + args.push(...parseExtraCliArgs(nmConfig.framework.rclone.extraArgs)) // 使用 Rust 端启动 sidecar,确保由主进程创建 const pid = await startSidecarAndWait({ diff --git a/src/utils/schemas.ts b/src/utils/schemas.ts index 5764089..bab2cb0 100644 --- a/src/utils/schemas.ts +++ b/src/utils/schemas.ts @@ -274,6 +274,7 @@ export const NMConfigSchema = z.object({ settings: z.object({ themeMode: z.enum(['dark', 'light', 'auto']).or(z.string()), startHide: z.boolean(), + autoRecoverComponents: z.boolean(), language: z.string().optional(), path: z.object({ cacheDir: z.string().optional(), @@ -283,10 +284,12 @@ export const NMConfigSchema = z.object({ rclone: z.object({ user: z.string(), password: z.string(), + extraArgs: z.string().optional(), }), openlist: z.object({ user: z.string(), password: z.string(), + extraArgs: z.string().optional(), }), }), });