Remove obsolete file manager organize options (#12)

Remove UI options for features that no longer exist:
- qB download auto-organize
- downloader smart classification
- seeding (keep seeding)

Also remove related warning banners and simplify move transfer labels.

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: truewhile <truewhile@users.noreply.github.com>
This commit is contained in:
truewhile
2026-09-02 11:43:39 +08:00
committed by GitHub
parent f1b7d99a33
commit 73dc37fef8
7 changed files with 3 additions and 53 deletions
@@ -18,7 +18,6 @@ type AutoOrganizeSettingsPanelProps = {
loading: boolean loading: boolean
saving: boolean saving: boolean
running: boolean running: boolean
moveKeepsSeeding: boolean
onRefresh: () => void onRefresh: () => void
onSave: () => void onSave: () => void
onRunNow: () => void onRunNow: () => void
@@ -40,7 +39,6 @@ export function AutoOrganizeSettingsPanel({
loading, loading,
saving, saving,
running, running,
moveKeepsSeeding,
onRefresh, onRefresh,
onSave, onSave,
onRunNow, onRunNow,
@@ -108,7 +106,6 @@ export function AutoOrganizeSettingsPanel({
<AutoOrganizeBasicTab <AutoOrganizeBasicTab
config={config} config={config}
currentDir={currentDir} currentDir={currentDir}
moveKeepsSeeding={moveKeepsSeeding}
onConfigChange={onConfigChange} onConfigChange={onConfigChange}
/> />
)} )}
+1 -13
View File
@@ -13,11 +13,9 @@ type AutoOrganizeTabProps = {
export function AutoOrganizeBasicTab({ export function AutoOrganizeBasicTab({
config, config,
currentDir, currentDir,
moveKeepsSeeding,
onConfigChange, onConfigChange,
}: AutoOrganizeTabProps & { }: AutoOrganizeTabProps & {
currentDir: string currentDir: string
moveKeepsSeeding: boolean
}) { }) {
return ( return (
<> <>
@@ -68,7 +66,7 @@ export function AutoOrganizeBasicTab({
onChange={(event) => onConfigChange('transferMode', event.target.value)} onChange={(event) => onConfigChange('transferMode', event.target.value)}
> >
<option value="hardlink">硬链接</option> <option value="hardlink">硬链接</option>
<option value="move">移动(关闭保种才会移动)</option> <option value="move">移动</option>
<option value="copy">复制</option> <option value="copy">复制</option>
<option value="symlink">软链接</option> <option value="symlink">软链接</option>
</select> </select>
@@ -85,20 +83,10 @@ export function AutoOrganizeBasicTab({
</label> </label>
</div> </div>
{moveKeepsSeeding && (
<div className="rounded-xl border border-orange-300 bg-orange-50 px-3 py-2 text-xs text-orange-700">
当前同时选择了“移动”和“保种”。为避免 qB 做种源文件被删除,后端会实际使用硬链接;Docker / NAS
多挂载或不同子卷下可能报 invalid cross-device link。需要真正移动时请关闭“保种”,需要保种但硬链接失败时请选择“复制”。
</div>
)}
<div className="flex flex-wrap items-center gap-3"> <div className="flex flex-wrap items-center gap-3">
<BooleanSetting config={config} settingKey="enabled" label="整理源目录定时自动整理" onConfigChange={onConfigChange} /> <BooleanSetting config={config} settingKey="enabled" label="整理源目录定时自动整理" onConfigChange={onConfigChange} />
<BooleanSetting config={config} settingKey="afterDownload" label="qB 下载完成后自动整理" onConfigChange={onConfigChange} />
<BooleanSetting config={config} settingKey="downloadSmartClassify" label="下载器智能分类" onConfigChange={onConfigChange} />
<BooleanSetting config={config} settingKey="smartClassify" label="智能分类到子库" onConfigChange={onConfigChange} /> <BooleanSetting config={config} settingKey="smartClassify" label="智能分类到子库" onConfigChange={onConfigChange} />
<BooleanSetting config={config} settingKey="autoAddLibrary" label="自动注册目的地媒体库" onConfigChange={onConfigChange} /> <BooleanSetting config={config} settingKey="autoAddLibrary" label="自动注册目的地媒体库" onConfigChange={onConfigChange} />
<BooleanSetting config={config} settingKey="keepSeeding" label="保种" onConfigChange={onConfigChange} />
</div> </div>
</> </>
) )
-5
View File
@@ -4,7 +4,6 @@ import { ChevronUp, Home } from 'lucide-react'
import { filesAPI, type FileEntry, type FileListing } from '../api/files' import { filesAPI, type FileEntry, type FileListing } from '../api/files'
import { libraryAPI } from '../api/library' import { libraryAPI } from '../api/library'
import type { Library } from '../types' import type { Library } from '../types'
import { settingOn } from './autoOrganizeModel'
import { AutoOrganizeSettingsPanel } from './AutoOrganizeSettingsPanel' import { AutoOrganizeSettingsPanel } from './AutoOrganizeSettingsPanel'
import { FileBrowserRoots } from './FileBrowserRoots' import { FileBrowserRoots } from './FileBrowserRoots'
import { FileEntriesTable } from './FileEntriesTable' import { FileEntriesTable } from './FileEntriesTable'
@@ -36,7 +35,6 @@ export function FileManagerPage() {
() => libraries.filter((library) => !isCloudLibraryPath(library.path)), () => libraries.filter((library) => !isCloudLibraryPath(library.path)),
[libraries], [libraries],
) )
const autoMoveKeepsSeeding = autoOrganize.moveKeepsSeeding
const refresh = useCallback(() => { const refresh = useCallback(() => {
setLoading(true) setLoading(true)
@@ -68,7 +66,6 @@ export function FileManagerPage() {
selectedPath: fileOperations.selected?.path, selectedPath: fileOperations.selected?.path,
selectedPaths: fileOperations.selectedPaths, selectedPaths: fileOperations.selectedPaths,
scrapeAfter, scrapeAfter,
keepSeeding: settingOn(autoOrganize.config.keepSeeding),
onScrapeAfterChange: setScrapeAfter, onScrapeAfterChange: setScrapeAfter,
onClearSelected: () => fileOperations.setSelectedPaths([]), onClearSelected: () => fileOperations.setSelectedPaths([]),
refresh, refresh,
@@ -102,7 +99,6 @@ export function FileManagerPage() {
loading={autoOrganize.loading} loading={autoOrganize.loading}
saving={autoOrganize.saving} saving={autoOrganize.saving}
running={autoOrganize.running} running={autoOrganize.running}
moveKeepsSeeding={autoMoveKeepsSeeding}
onRefresh={autoOrganize.refresh} onRefresh={autoOrganize.refresh}
onSave={() => void autoOrganize.save()} onSave={() => void autoOrganize.save()}
onRunNow={autoOrganize.runNow} onRunNow={autoOrganize.runNow}
@@ -119,7 +115,6 @@ export function FileManagerPage() {
organizeDestPath={manualOrganize.organizeDestPath} organizeDestPath={manualOrganize.organizeDestPath}
organizeMediaType={manualOrganize.organizeMediaType} organizeMediaType={manualOrganize.organizeMediaType}
organizeTransferMode={manualOrganize.organizeTransferMode} organizeTransferMode={manualOrganize.organizeTransferMode}
manualMoveKeepsSeeding={manualOrganize.manualMoveKeepsSeeding}
scanAfter={manualOrganize.scanAfter} scanAfter={manualOrganize.scanAfter}
scrapeAfter={scrapeAfter} scrapeAfter={scrapeAfter}
organizeReady={manualOrganize.organizeReady} organizeReady={manualOrganize.organizeReady}
+1 -9
View File
@@ -15,7 +15,6 @@ type ManualOrganizePanelProps = {
organizeDestPath: string organizeDestPath: string
organizeMediaType: string organizeMediaType: string
organizeTransferMode: string organizeTransferMode: string
manualMoveKeepsSeeding: boolean
scanAfter: boolean scanAfter: boolean
scrapeAfter: boolean scrapeAfter: boolean
organizeReady: boolean organizeReady: boolean
@@ -40,7 +39,6 @@ export function ManualOrganizePanel({
organizeDestPath, organizeDestPath,
organizeMediaType, organizeMediaType,
organizeTransferMode, organizeTransferMode,
manualMoveKeepsSeeding,
scanAfter, scanAfter,
scrapeAfter, scrapeAfter,
organizeReady, organizeReady,
@@ -119,19 +117,13 @@ export function ManualOrganizePanel({
<span className="text-xs text-ink-50">整理方式</span> <span className="text-xs text-ink-50">整理方式</span>
<select className="input-base w-full" value={organizeTransferMode} onChange={(event) => onTransferModeChange(event.target.value)}> <select className="input-base w-full" value={organizeTransferMode} onChange={(event) => onTransferModeChange(event.target.value)}>
<option value="hardlink">硬链接</option> <option value="hardlink">硬链接</option>
<option value="move">移动(关闭保种才会移动)</option> <option value="move">移动</option>
<option value="copy">复制</option> <option value="copy">复制</option>
<option value="symlink">软链接</option> <option value="symlink">软链接</option>
</select> </select>
</label> </label>
</div> </div>
{manualMoveKeepsSeeding && (
<div className="rounded-xl border border-orange-300 bg-orange-50 px-3 py-2 text-xs text-orange-700">
“保种”已开启,选择“移动”时后端会改用硬链接以保留下载源。要执行真正移动,请先在上方自动整理设置里关闭“保种”并保存。
</div>
)}
<div className="flex flex-wrap items-center gap-2"> <div className="flex flex-wrap items-center gap-2">
<label className="flex items-center gap-2 rounded-lg border border-gray-200 bg-gray-50 px-2 py-1 text-xs text-ink-100"> <label className="flex items-center gap-2 rounded-lg border border-gray-200 bg-gray-50 px-2 py-1 text-xs text-ink-100">
<input type="checkbox" checked={scanAfter} onChange={(event) => onScanAfterChange(event.target.checked)} /> <input type="checkbox" checked={scanAfter} onChange={(event) => onScanAfterChange(event.target.checked)} />
-12
View File
@@ -2,16 +2,13 @@ import type { Setting } from '../types'
export type AutoOrganizeConfig = { export type AutoOrganizeConfig = {
enabled: string enabled: string
afterDownload: string
scrapeAfter: string scrapeAfter: string
downloadSmartClassify: string
smartClassify: string smartClassify: string
autoAddLibrary: string autoAddLibrary: string
sourceDir: string sourceDir: string
targetDir: string targetDir: string
transferMode: string transferMode: string
intervalSeconds: string intervalSeconds: string
keepSeeding: string
movieFormat: string movieFormat: string
tvFormat: string tvFormat: string
animeFormat: string animeFormat: string
@@ -24,16 +21,13 @@ export type AutoOrganizeConfig = {
export const AUTO_ORGANIZE_DEFAULTS: AutoOrganizeConfig = { export const AUTO_ORGANIZE_DEFAULTS: AutoOrganizeConfig = {
enabled: 'false', enabled: 'false',
afterDownload: 'false',
scrapeAfter: 'true', scrapeAfter: 'true',
downloadSmartClassify: 'true',
smartClassify: 'true', smartClassify: 'true',
autoAddLibrary: 'true', autoAddLibrary: 'true',
sourceDir: '', sourceDir: '',
targetDir: '', targetDir: '',
transferMode: 'hardlink', transferMode: 'hardlink',
intervalSeconds: '300', intervalSeconds: '300',
keepSeeding: 'true',
movieFormat: '{title} ({year})/{title} ({year})', movieFormat: '{title} ({year})/{title} ({year})',
tvFormat: '{title} ({year})/Season {season:02}/{title} S{season:02}E{episode:02}', tvFormat: '{title} ({year})/Season {season:02}/{title} S{season:02}E{episode:02}',
animeFormat: '{title}/Season {season:02}/{title} S{season:02}E{episode:02}', animeFormat: '{title}/Season {season:02}/{title} S{season:02}E{episode:02}',
@@ -46,16 +40,13 @@ export const AUTO_ORGANIZE_DEFAULTS: AutoOrganizeConfig = {
export const AUTO_ORGANIZE_KEYS: Record<keyof AutoOrganizeConfig, string> = { export const AUTO_ORGANIZE_KEYS: Record<keyof AutoOrganizeConfig, string> = {
enabled: 'organize.auto', enabled: 'organize.auto',
afterDownload: 'organizer.auto_after_download',
scrapeAfter: 'organize.scrape_after', scrapeAfter: 'organize.scrape_after',
downloadSmartClassify: 'downloads.smart_classify',
smartClassify: 'organizer.smart_classify', smartClassify: 'organizer.smart_classify',
autoAddLibrary: 'organize.auto_add_library', autoAddLibrary: 'organize.auto_add_library',
sourceDir: 'organize.source_dir', sourceDir: 'organize.source_dir',
targetDir: 'organize.target_dir', targetDir: 'organize.target_dir',
transferMode: 'organize.transfer_mode', transferMode: 'organize.transfer_mode',
intervalSeconds: 'organize.interval_seconds', intervalSeconds: 'organize.interval_seconds',
keepSeeding: 'organize.keep_seeding',
movieFormat: 'organize.movie_format', movieFormat: 'organize.movie_format',
tvFormat: 'organize.tv_format', tvFormat: 'organize.tv_format',
animeFormat: 'organize.anime_format', animeFormat: 'organize.anime_format',
@@ -72,16 +63,13 @@ export function mergeAutoOrganizeSettings(rows: Setting[]): AutoOrganizeConfig {
const idx = settingIndex(rows) const idx = settingIndex(rows)
return { return {
enabled: idx[AUTO_ORGANIZE_KEYS.enabled] ?? AUTO_ORGANIZE_DEFAULTS.enabled, enabled: idx[AUTO_ORGANIZE_KEYS.enabled] ?? AUTO_ORGANIZE_DEFAULTS.enabled,
afterDownload: idx[AUTO_ORGANIZE_KEYS.afterDownload] ?? AUTO_ORGANIZE_DEFAULTS.afterDownload,
scrapeAfter: idx[AUTO_ORGANIZE_KEYS.scrapeAfter] ?? AUTO_ORGANIZE_DEFAULTS.scrapeAfter, scrapeAfter: idx[AUTO_ORGANIZE_KEYS.scrapeAfter] ?? AUTO_ORGANIZE_DEFAULTS.scrapeAfter,
downloadSmartClassify: idx[AUTO_ORGANIZE_KEYS.downloadSmartClassify] ?? AUTO_ORGANIZE_DEFAULTS.downloadSmartClassify,
smartClassify: idx[AUTO_ORGANIZE_KEYS.smartClassify] ?? AUTO_ORGANIZE_DEFAULTS.smartClassify, smartClassify: idx[AUTO_ORGANIZE_KEYS.smartClassify] ?? AUTO_ORGANIZE_DEFAULTS.smartClassify,
autoAddLibrary: idx[AUTO_ORGANIZE_KEYS.autoAddLibrary] ?? AUTO_ORGANIZE_DEFAULTS.autoAddLibrary, autoAddLibrary: idx[AUTO_ORGANIZE_KEYS.autoAddLibrary] ?? AUTO_ORGANIZE_DEFAULTS.autoAddLibrary,
sourceDir: idx[AUTO_ORGANIZE_KEYS.sourceDir] ?? AUTO_ORGANIZE_DEFAULTS.sourceDir, sourceDir: idx[AUTO_ORGANIZE_KEYS.sourceDir] ?? AUTO_ORGANIZE_DEFAULTS.sourceDir,
targetDir: idx[AUTO_ORGANIZE_KEYS.targetDir] ?? AUTO_ORGANIZE_DEFAULTS.targetDir, targetDir: idx[AUTO_ORGANIZE_KEYS.targetDir] ?? AUTO_ORGANIZE_DEFAULTS.targetDir,
transferMode: idx[AUTO_ORGANIZE_KEYS.transferMode] ?? AUTO_ORGANIZE_DEFAULTS.transferMode, transferMode: idx[AUTO_ORGANIZE_KEYS.transferMode] ?? AUTO_ORGANIZE_DEFAULTS.transferMode,
intervalSeconds: idx[AUTO_ORGANIZE_KEYS.intervalSeconds] ?? AUTO_ORGANIZE_DEFAULTS.intervalSeconds, intervalSeconds: idx[AUTO_ORGANIZE_KEYS.intervalSeconds] ?? AUTO_ORGANIZE_DEFAULTS.intervalSeconds,
keepSeeding: idx[AUTO_ORGANIZE_KEYS.keepSeeding] ?? AUTO_ORGANIZE_DEFAULTS.keepSeeding,
movieFormat: idx[AUTO_ORGANIZE_KEYS.movieFormat] ?? AUTO_ORGANIZE_DEFAULTS.movieFormat, movieFormat: idx[AUTO_ORGANIZE_KEYS.movieFormat] ?? AUTO_ORGANIZE_DEFAULTS.movieFormat,
tvFormat: idx[AUTO_ORGANIZE_KEYS.tvFormat] ?? AUTO_ORGANIZE_DEFAULTS.tvFormat, tvFormat: idx[AUTO_ORGANIZE_KEYS.tvFormat] ?? AUTO_ORGANIZE_DEFAULTS.tvFormat,
animeFormat: idx[AUTO_ORGANIZE_KEYS.animeFormat] ?? AUTO_ORGANIZE_DEFAULTS.animeFormat, animeFormat: idx[AUTO_ORGANIZE_KEYS.animeFormat] ?? AUTO_ORGANIZE_DEFAULTS.animeFormat,
+1 -7
View File
@@ -1,4 +1,4 @@
import { useCallback, useEffect, useMemo, useState } from 'react' import { useCallback, useEffect, useState } from 'react'
import toast from 'react-hot-toast' import toast from 'react-hot-toast'
import { adminAPI } from '../api/admin' import { adminAPI } from '../api/admin'
@@ -79,11 +79,6 @@ export function useAutoOrganizeSettings({ onScrapeAfterChange }: UseAutoOrganize
} }
}, [dirty, save]) }, [dirty, save])
const moveKeepsSeeding = useMemo(
() => config.transferMode === 'move' && settingOn(config.keepSeeding),
[config.keepSeeding, config.transferMode],
)
return { return {
config, config,
dirty, dirty,
@@ -91,7 +86,6 @@ export function useAutoOrganizeSettings({ onScrapeAfterChange }: UseAutoOrganize
running, running,
loading, loading,
activeTab, activeTab,
moveKeepsSeeding,
refresh, refresh,
save, save,
runNow, runNow,
-4
View File
@@ -17,7 +17,6 @@ type UseManualOrganizeOptions = {
selectedPath?: string selectedPath?: string
selectedPaths: string[] selectedPaths: string[]
scrapeAfter: boolean scrapeAfter: boolean
keepSeeding: boolean
onScrapeAfterChange: (value: boolean) => void onScrapeAfterChange: (value: boolean) => void
onClearSelected: () => void onClearSelected: () => void
refresh: () => void refresh: () => void
@@ -29,7 +28,6 @@ export function useManualOrganize({
selectedPath, selectedPath,
selectedPaths, selectedPaths,
scrapeAfter, scrapeAfter,
keepSeeding,
onScrapeAfterChange, onScrapeAfterChange,
onClearSelected, onClearSelected,
refresh, refresh,
@@ -59,7 +57,6 @@ export function useManualOrganize({
) )
const organizeSource = organizeSources.length === 1 ? organizeSources[0] : `${organizeSources.length} 个已选项目` const organizeSource = organizeSources.length === 1 ? organizeSources[0] : `${organizeSources.length} 个已选项目`
const organizeReady = organizeSources.length > 0 && Boolean(organizeDestPath.trim()) const organizeReady = organizeSources.length > 0 && Boolean(organizeDestPath.trim())
const manualMoveKeepsSeeding = organizeTransferMode === 'move' && keepSeeding
const runManualOrganize = async (dryRun: boolean) => { const runManualOrganize = async (dryRun: boolean) => {
if (!organizeReady) { if (!organizeReady) {
@@ -124,7 +121,6 @@ export function useManualOrganize({
previewItems, previewItems,
organizeSource, organizeSource,
organizeReady, organizeReady,
manualMoveKeepsSeeding,
setOrganizeLibraryID, setOrganizeLibraryID,
setOrganizeDestPath, setOrganizeDestPath,
setOrganizeTransferMode, setOrganizeTransferMode,