v3 to v5

47 added, 170 removed. Audit A to A.

---
name: organize-files
- version: 3
+ version: 5
description: >-
- Use this skill when the user asks the MoviePilot agent to identify and organize downloaded/local video or music files that automatic transfer cannot handle. Typical triggers include manually organizing a file or folder, a TV season pack, one music recording, or a complete album directory. If the user gives failed transfer history IDs, prefer transfer-failed-retry instead.
- allowed-tools: list_directory query_directory_settings query_download_tasks query_transfer_history delete_transfer_history recognize_media search_media query_media_detail query_library_exists transfer_file scrape_metadata ask_user_choice send_message
+ Use this skill when the user asks MoviePilot to identify and organize a local
+ or downloaded video/music file, season folder, recording, album directory, or
+ mixed folder that automatic transfer did not handle. If failed transfer
+ history IDs are supplied, use transfer-failed-retry instead.
+ allowed-tools: moviepilot_api execute_command ask_user_choice send_message
+ allowed-api-operations: storage.settings storage.list transfer.history transfer.history.delete media.recognize media.search media.detail library.exists transfer.file media.scrape
---
- # Organize Files (智能整理文件)
-
- Use this skill to help the user identify media files that MoviePilot could not organize automatically, then call the normal transfer pipeline through `transfer_file`. Do not rename, move, or copy files manually; let MoviePilot's directory, transfer mode, rename template, overwrite, scrape, and notification settings handle the actual organization.
-
- ## MoviePilot Transfer Flow
-
- MoviePilot's normal flow is:
-
- 1. `DownloadChain.download_single` adds a downloader task, records `DownloadHistory` and `DownloadFiles`, runs downloader-specific `download_added`, then sends `DownloadAdded`.
- 2. `TransferChain.process` scans completed downloader tasks in monitored download directories. If a `DownloadHistory` exists for the hash, it reuses the recorded media IDs; otherwise it falls back to path recognition.
- 3. Agent/manual organization calls `transfer_file`, which enters `TransferFileTool` -> `TransferChain.manual_transfer` -> `TransferChain.do_transfer`.
- 4. `do_transfer` recursively collects eligible video/subtitle/audio files, ignores recycle/hidden paths and configured exclude words, and reuses download history when possible. Video uses `MetaInfoPath`; music uses audio tags plus `MetaMusic`/`MusicInfo` and keeps the selected recording or album identity.
- 5. `TransferChain.__handle_transfer` chooses the target directory through `DirectoryHelper`, delegates file operations to the file manager module, and lets `TransHandler` build the final target path and name.
- 6. The callback writes `TransferHistory` success/failure records, emits transfer events, sends notifications, and may trigger `transfer-failed-retry` for failed history records.
+ # Organize Files
- Important implication: an existing `TransferHistory` for the same source path can make a later transfer skip. Delete only stale or failed history records, and only after the user has confirmed the record is safe to remove.
+ Use `moviepilot_api` for every MoviePilot business operation. Retired file,
+ recognition, transfer, and history tools are not available.
## Workflow
- ### 1. Classify The Request
-
- - If the user provides one or more failed transfer history IDs, stop and use `transfer-failed-retry`.
- - If the user provides a path, start from that path.
- - If the user describes a download task, use `query_download_tasks` to find its save path or hash, then continue with the path.
- - If the user only says "整理一下下载目录", use `query_directory_settings(directory_type="download")` first, then ask which directory or subdirectory to process if more than one candidate exists.
-
- ### 2. Inspect Candidate Files
-
- Use `list_directory` for any directory the user provides. Prefer `sort_by="time"` for "recent" or "刚下载的" requests.
-
- For directories with more than 20 items, ask the user to narrow the folder or choose the relevant child directory before running transfers. Avoid organizing a broad shared download root unless the user explicitly confirms the scope.
-
- Treat these as transfer candidates:
-
- - main media files and Blu-ray folders;
- - matching subtitle and external audio files in the same media folder;
- - episode packs where files share the same title/season pattern.
- - individual supported audio files and album folders containing multiple tracks.
-
- Skip obvious samples, trailers, screenshots, hidden folders, recycle folders, and files that are not media/subtitle/audio.
-
- ### 3. Identify The Media
-
- For the best sample file, call:
-
- ```text
- recognize_media(path="<source file path>")
- ```
-
- If recognition fails or looks wrong:
-
- 1. Extract likely title, year, media type, season/episode range, or music artist/track/album from filenames and audio tags.
- 2. For video, call `search_media(title="...", year="...", media_type="movie|tv")`. For music, call `search_media(title="<artist> - <title>", media_type="music", music_type="recording|album")`.
- 3. If several results are plausible, use `ask_user_choice` when available, or ask the user directly to choose the correct title and `media_source` + `media_id` pair.
- 4. For TV season confusion, use `query_media_detail(media_source="themoviedb", media_id="<id>", media_type="tv")` before deciding the season number. For an album, use `query_media_detail(media_type="music", music_type="album", media_source="musicbrainz", media_id="<album_id>")` and verify `total_tracks` before treating the directory as complete.
-
- Never invent an ID. Preserve the exact source-native entity returned by search: a recording is one track, an album is a multi-track collection, and an artist is browse-only and cannot be organized.
-
- ### 4. Check Existing State
-
- Before writing:
-
- - Use `query_library_exists` when a precise video or music identity is known and duplicate risk matters. For albums, an exists result is only true after complete track coverage is confirmed.
- - Use `query_transfer_history(title="<title or path keyword>", status="all")` if the file may already have a success or failure record.
- - If `transfer_file` later returns "已整理过", query transfer history, identify the matching source path, and ask before deleting the stale record.
-
- Only call `delete_transfer_history(history_id=<id>)` for the exact stale/failed record that blocks the requested source path. Do not delete unrelated successful history.
-
- ### 5. Transfer Through MoviePilot
-
- Use `transfer_file` with explicit identity whenever possible:
-
- ```text
- transfer_file(
- file_path="<source path>",
- storage="local",
- media_type="movie|tv",
- media_source="<source>",
- media_id="<native_id>",
- season=<season_number_if_tv>
- )
- ```
-
- For one recording:
-
- ```text
- transfer_file(file_path="<audio file>", media_type="music", music_type="recording", media_source="musicbrainz", media_id="<recording_id>")
- ```
-
- For a complete album, transfer the album directory once:
-
- ```text
- transfer_file(file_path="<album directory>/", media_type="music", music_type="album", media_source="musicbrainz", media_id="<album_id>")
- ```
-
- Rules:
-
- - For directories, pass a trailing slash in `file_path` so the tool treats it as a directory.
- - Prefer leaving `target_path`, `target_storage`, and `transfer_type` empty so configured directory rules apply.
- - Set `target_path` or `transfer_type` only when the user explicitly asks or the default directory configuration cannot handle the file.
- - For a single movie or a single TV season folder, transfer the folder once with the shared identity.
- - For mixed folders, split by media and transfer each file/subfolder separately.
- - For episode packs, identify the media once, then reuse the exact `media_source` + `media_id`, `media_type="tv"`, and the confirmed `season` for each item.
- - For one recording, transfer only that audio file with the recording ID.
- - For one album, verify the directory belongs to the selected album, then transfer the directory once with the album ID. Do not submit every track as an unrelated recording.
- - Never transfer an artist search result. Select a recording or album first.
- - When the user asks to refresh music tags, cover, or lyrics after transfer, call `scrape_metadata(media_type="music", ...)`; album scraping may use the album ID and reports actual lyrics counts.
-
- ### 6. Report Clearly
-
- After each transfer batch, report:
-
- - source path(s) processed;
- - recognized media title, type, `media_source` + `media_id`, season/episode range when relevant;
- - success/failure count;
- - any failed message exactly enough for the user to act, such as missing media library directory, unsupported storage, existing history, or no media recognized.
-
- If the result creates failed history records, tell the user they can retry with the history ID or let the agent continue with `transfer-failed-retry`.
-
- ## Common Cases
-
- ### User Gives A Single File
-
- 1. `recognize_media(path=...)`
- 2. If needed, `search_media(...)` and confirm the result.
- 3. `transfer_file(file_path=..., media_type=..., media_source=..., media_id=..., season=...)`
-
- ### User Gives A Season Folder
-
- 1. `list_directory(path=...)`
- 2. Pick a representative episode and run `recognize_media(path=...)`.
- 3. Confirm `media_source`, `media_id`, `media_type="tv"`, and season.
- 4. `transfer_file(file_path="<folder>/", media_type="tv", media_source="<source>", media_id="<native_id>", season=<season>)`
-
- ### User Gives One Music Track
-
- 1. `recognize_media(path=..., media_type="music")`
- 2. Confirm the artist and recording title; use `search_media(..., music_type="recording")` when ambiguous.
- 3. Check the exact recording with `query_library_exists` when duplicate risk matters.
- 4. Transfer the audio file once with the recording `media_source` + `media_id`.
-
- ### User Gives An Album Folder
-
- 1. `list_directory(path=...)` and confirm the files form one album rather than a mixed folder.
- 2. Recognize a representative track, then search/select the album entity and query album detail.
- 3. Compare the folder's supported audio-file count with album `total_tracks`; ask before proceeding when the folder appears incomplete or mixed.
- 4. Check album library existence, then transfer the directory once with `media_type="music"`, `music_type="album"`, and the album identity.
- 5. If requested, scrape the album directory for configured tags, cover, and lyrics; do not claim every lyric was found unless the tool reports it.
-
- ### User Gives A Messy Mixed Folder
-
- 1. `list_directory(path=...)`
- 2. Group candidates by likely title/year/season.
- 3. Confirm groups before writing if there is more than one media.
- 4. Transfer each group separately; do not run one directory transfer over unrelated media.
-
- ### Transfer Says The File Was Already Organized
+ 1. Establish scope. If the user provides a path, use it. If they identify a
+ downloader task, use `downloader-operation` and its fixed
+ `scripts/mp-downloader.py` helper to discover the instance and call
+ `tasks.list`. If they only name a configured root, call `storage.settings`.
+ Use `storage.list` to inspect the selected directory. Do not process a broad
+ shared root without an explicit, bounded scope.
+ 2. Classify files into movie, TV, one music recording, one complete album,
+ subtitle/sidecar, or unrelated content. Do not group unrelated media merely
+ because they share a directory.
+ 3. Call `media.recognize` with the representative title or path. If uncertain,
+ call `media.search`; if several exact candidates remain, use
+ `ask_user_choice`. Never invent or translate an ID.
+ 4. Preserve the exact `media_source` + `media_id`. For TV, verify season detail
+ with `media.detail` when numbering is ambiguous. For music, a recording is one
+ track, an album is one multi-track directory, and an artist is browse-only.
+ 5. When duplicate risk matters, call `library.exists`. If an existing transfer
+ record affects reorganization, inspect `transfer.history`.
+ 6. Before a state-changing transfer, summarize the source, target identity,
+ media type, season/music entity, storage, and mode. Continue only when the
+ user's request already authorizes that exact action or after confirmation.
+ 7. Call `transfer.file` once per verified unit. For an album, transfer the album
+ directory once only after its supported audio-file count is consistent with
+ the selected album detail.
+ 8. If requested, call `media.scrape` after a successful transfer. Report actual
+ tag, cover, and lyrics counts; never assume all lyrics were found.
- 1. `query_transfer_history(title="<title or source path keyword>", status="all")`
- 2. Find the exact record with matching `src`.
- 3. Ask the user to confirm deletion if the record is stale or failed.
- 4. `delete_transfer_history(history_id=<id>)`
- 5. Retry `transfer_file(...)`.
+ ## Structured Calls
- ## Guardrails
+ - Directory listing: `storage.list` with storage/path/paging/sort in `body`.
+ - Recognition: `media.recognize` with title/path in `query`.
+ - Search: `media.search` with title/type/source constraints in `query`.
+ - Detail: `media.detail` with `path_params.media_id` and identity/type in `query`.
+ - Library check: `library.exists` with the exact identity in `query`.
+ - Transfer: `transfer.file` with the manual-transfer request in `body`.
+ - Scrape: `media.scrape` with `path_params.storage`, file item in `body`, and
+ exact identity/type fields in `query`.
- - Do not use shell commands, raw database edits, or manual filesystem moves for organization.
- - Do not delete transfer history without an exact matching source path and user confirmation.
- - Do not use broad download roots as transfer targets unless the user explicitly confirms the scope.
- - Do not process unrelated media in one directory transfer.
- - Do not confuse a same-name recording, album, and artist; preserve `music_type` and source-native IDs.
- - Do not report a partial album as complete or present in the library.
- - Do not override target directories or transfer modes unless necessary.
- - Prefer asking one focused question over guessing media identity, season mapping, or destructive cleanup.
+ Stop and report instead of transferring when the source is missing, directory
+ configuration is absent, identity remains ambiguous, an album appears mixed or
+ incomplete, or the requested target would overwrite unrelated media.