mirror of
https://github.com/truewhile/MeBox.git
synced 2026-09-29 03:26:37 +08:00
d03f84e78d
- Add OrganizeDirectory service: walk an arbitrary source directory (download dir / NAS direct-read path) and organize video files into the destination, without requiring the source to be a registered library. - Dedup: skip media already present in the destination (matched by scanned DB identity title+year[/season+episode], robust to dir case/layout, plus a filesystem folder fallback). - 洗版 (resolution replacement): when the source resolution is higher than the existing version, replace the lower-res file (+NFO sidecar +DB row). Prefers scanned dimensions, then ffprobe, then filename token; never replaces on unknown resolution. - New endpoints: GET /admin/organize/sources (download/media dir candidates) and POST /admin/organize/source. - UI: ToolsPage adds a '整理来源目录(去重+洗版)' form so operators can pick the download dir as the organize source. Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
59 lines
2.0 KiB
TypeScript
59 lines
2.0 KiB
TypeScript
import { api } from './client'
|
|
|
|
// toolsAPI groups admin-only endpoints that don't fit the other domain
|
|
// modules: organizing media files into the canonical naming layout, and
|
|
// 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 {
|
|
source_path?: string
|
|
dest_path?: string
|
|
transfer_mode?: string
|
|
}
|
|
|
|
// OrganizeSource is a selectable organize source directory (e.g. the download
|
|
// directory) surfaced so operators can organize an arbitrary directory and not
|
|
// only registered libraries.
|
|
export interface OrganizeSource {
|
|
label: string
|
|
path: string
|
|
kind: string
|
|
}
|
|
|
|
export const toolsAPI = {
|
|
organizeMedia: (mediaID: string, opts?: OrganizeOverrides) =>
|
|
api
|
|
.post<{ path: string }>(`/admin/media/${mediaID}/organize`, opts ?? {})
|
|
.then((r) => r.data),
|
|
|
|
organizeLibrary: (libraryID: string, opts?: OrganizeOverrides) =>
|
|
api
|
|
.post<Record<string, unknown>>(
|
|
`/admin/libraries/${libraryID}/organize`,
|
|
opts ?? {},
|
|
)
|
|
.then((r) => r.data),
|
|
|
|
// organizeSources lists selectable source directories (download/media dir).
|
|
organizeSources: () =>
|
|
api
|
|
.get<{ sources: OrganizeSource[] }>('/admin/organize/sources')
|
|
.then((r) => r.data.sources ?? []),
|
|
|
|
// organizeDirectory organizes an arbitrary source directory (e.g. downloads)
|
|
// into the destination with dedup + 洗版 (resolution replacement).
|
|
organizeDirectory: (opts: OrganizeOverrides) =>
|
|
api
|
|
.post<{ organized: number; skipped: number; replaced?: number; errors?: string[] }>(
|
|
'/admin/organize/source',
|
|
opts,
|
|
)
|
|
.then((r) => r.data),
|
|
|
|
notifyTest: (title: string, body: string) =>
|
|
api
|
|
.post<{ message: string }>('/admin/notify/test', { title, body })
|
|
.then((r) => r.data),
|
|
}
|