mirror of
https://github.com/truewhile/MeBox.git
synced 2026-10-01 20:16:36 +08:00
feat(organize): separate source dir from destination dir (从源目录整理到目的地目录)
Previously organize only exposed a single 'target dir' that was actually the destination, conflating 源目录 (where files to organize live) with 目的地目录 (where organized files go). Add an explicit source directory: - OrganizeOptions gains SourcePath; DestPath replaces the old TargetPath (destination) for clarity. New organize.source_dir setting + source_path request override; resolveSourceRoot falls back to library path. - OrganizeLibraryWithOptions only organizes media located under the source root, so operators can point at a specific download/staging folder and organize into a distinct destination. - Handler accepts source_path/dest_path (target_path kept as a deprecated alias for the destination, backward compatible). - Settings page splits into 整理源目录(待整理) + 整理目的地目录; Tools organize panel exposes 源目录 + 目的地目录 inputs with clear copy. Defaults are unchanged (source = destination = library path) so existing setups behave identically. Adds a regression test that organize is scoped to the source directory. Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
@@ -5,8 +5,10 @@ import { api } from './client'
|
||||
// dispatching a test notification through the configured channels.
|
||||
// OrganizeOverrides are optional single-request overrides for an organize
|
||||
// action. Empty fields fall back to the system settings.
|
||||
// source_path = 源目录(待整理文件所在),dest_path = 目的地目录(整理输出到哪里)。
|
||||
export interface OrganizeOverrides {
|
||||
target_path?: string
|
||||
source_path?: string
|
||||
dest_path?: string
|
||||
transfer_mode?: string
|
||||
}
|
||||
|
||||
|
||||
@@ -152,10 +152,17 @@ const GROUPS: SettingGroup[] = [
|
||||
hint: '根据元数据(语言/国家/类型)自动分类到子目录(如:华语电影、欧美剧、日番)',
|
||||
},
|
||||
{
|
||||
key: 'organize.target_dir',
|
||||
label: '整理目标目录',
|
||||
key: 'organize.source_dir',
|
||||
label: '整理源目录(待整理)',
|
||||
type: 'text',
|
||||
hint: '留空则默认整理到各媒体库对应路径(见下方参考)',
|
||||
hint: '从该目录读取待整理文件;留空则默认整理整个媒体库(媒体库路径)。',
|
||||
placeholder: '/mnt/downloads',
|
||||
},
|
||||
{
|
||||
key: 'organize.target_dir',
|
||||
label: '整理目的地目录',
|
||||
type: 'text',
|
||||
hint: '整理后输出到该目录;留空则默认整理到各媒体库对应路径(见下方参考)。与「源目录」相互独立。',
|
||||
placeholder: '/mnt/media/organized',
|
||||
},
|
||||
{
|
||||
@@ -388,7 +395,7 @@ export function SettingsPage() {
|
||||
<div className="glass-panel">
|
||||
<div className="mb-3 flex items-center gap-2 text-sm text-ink-100">
|
||||
<FolderOpen size={16} className="text-brand-500" />
|
||||
<span>默认整理路径参考(未设目标目录时按媒体库归类)</span>
|
||||
<span>默认整理路径参考(未设目的地目录时按媒体库归类)</span>
|
||||
</div>
|
||||
<table className="w-full text-left text-sm">
|
||||
<thead className="text-xs uppercase tracking-wider text-sand-500">
|
||||
|
||||
@@ -61,13 +61,15 @@ function OrganizePanel() {
|
||||
const [smartClassify, setSmartClassify] = useState(false)
|
||||
const [loadingSettings, setLoadingSettings] = useState(true)
|
||||
|
||||
// 单次整理覆盖项:留空则沿用设置页的默认整理目录与转移方式。
|
||||
const [targetPath, setTargetPath] = useState('')
|
||||
// 单次整理覆盖项:留空则沿用设置页的默认源目录/目的地目录与转移方式。
|
||||
const [sourcePath, setSourcePath] = useState('')
|
||||
const [destPath, setDestPath] = useState('')
|
||||
const [transferMode, setTransferMode] = useState('')
|
||||
|
||||
const overrides = () => {
|
||||
const o: { target_path?: string; transfer_mode?: string } = {}
|
||||
if (targetPath.trim()) o.target_path = targetPath.trim()
|
||||
const o: { source_path?: string; dest_path?: string; transfer_mode?: string } = {}
|
||||
if (sourcePath.trim()) o.source_path = sourcePath.trim()
|
||||
if (destPath.trim()) o.dest_path = destPath.trim()
|
||||
if (transferMode) o.transfer_mode = transferMode
|
||||
return o
|
||||
}
|
||||
@@ -162,14 +164,27 @@ function OrganizePanel() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="grid gap-3 rounded-xl border border-gray-200 bg-gray-50 p-3 sm:grid-cols-2">
|
||||
<p className="text-xs text-sand-500">
|
||||
整理是「<b>从源目录整理到目的地目录</b>」:源目录是待整理文件当前所在的位置,目的地目录是整理后输出的位置。两者留空则分别沿用设置页的默认值(默认源目录 = 媒体库路径)。
|
||||
</p>
|
||||
|
||||
<div className="grid gap-3 rounded-xl border border-gray-200 bg-gray-50 p-3 sm:grid-cols-3">
|
||||
<label className="space-y-1">
|
||||
<span className="text-xs text-ink-50">整理目标目录(可选,覆盖默认设置)</span>
|
||||
<span className="text-xs text-ink-50">源目录(待整理,可选)</span>
|
||||
<input
|
||||
className="input-base w-full"
|
||||
placeholder="留空则使用「整理目标目录」设置或媒体库路径"
|
||||
value={targetPath}
|
||||
onChange={(e) => setTargetPath(e.target.value)}
|
||||
placeholder="留空则使用「整理源目录」设置或媒体库路径"
|
||||
value={sourcePath}
|
||||
onChange={(e) => setSourcePath(e.target.value)}
|
||||
/>
|
||||
</label>
|
||||
<label className="space-y-1">
|
||||
<span className="text-xs text-ink-50">目的地目录(整理输出,可选)</span>
|
||||
<input
|
||||
className="input-base w-full"
|
||||
placeholder="留空则使用「整理目的地目录」设置或媒体库路径"
|
||||
value={destPath}
|
||||
onChange={(e) => setDestPath(e.target.value)}
|
||||
/>
|
||||
</label>
|
||||
<label className="space-y-1">
|
||||
|
||||
Reference in New Issue
Block a user