mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-09-05 15:38:19 +08:00
feat(agent): complete music workflow support
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: moviepilot-api
|
||||
version: 10
|
||||
version: 11
|
||||
description: >-
|
||||
Use this skill when you need to call MoviePilot REST API endpoints directly
|
||||
with the bundled Python client. Covers MoviePilot HTTP endpoints across media
|
||||
@@ -175,18 +175,31 @@ AniList endpoints prefer the `anilist-chinese` proxy and fall back to official A
|
||||
| GET | `/api/v1/anilist/person/{person_id}` | Staff detail |
|
||||
| GET | `/api/v1/anilist/person/credits/{person_id}` | Staff anime credits. Params: `page`, `count` |
|
||||
|
||||
### Music (3 endpoints)
|
||||
### Music (6 entity endpoints plus unified search)
|
||||
|
||||
Music uses the independent `MusicMeta` / `MusicInfo` contract and a
|
||||
`musicbrainz:<recording_mbid>` identity. MoviePilot searches, recognizes,
|
||||
subscribes to, downloads, and organizes music; it does not manage a music
|
||||
library, playlists, or an artist library.
|
||||
source-native MusicBrainz identity. `music_type=recording` is one track,
|
||||
`album` is a multi-track collection, and `artist` is browse-only. MoviePilot
|
||||
searches, recognizes, subscribes to, downloads, organizes, scrapes, and checks
|
||||
music on configured music-capable media servers; it does not manage playlists.
|
||||
|
||||
| Method | Path | Description |
|
||||
|--------|------|-------------|
|
||||
| GET | `/api/v1/music/search` | Search tracks, albums, or artists. Params: `query`, `count` |
|
||||
| GET | `/api/v1/media/search` | Search tracks, albums, or artists with `type=music` or `source=musicbrainz`. Params: `title`, `type`, `count` |
|
||||
| POST | `/api/v1/music/recognize` | Resolve music metadata. Body: `source`, `media_id` |
|
||||
| GET | `/api/v1/music/explore` | Explore the monthly site-wide music chart. Params: `page`, `count` |
|
||||
| GET | `/api/v1/music/explore` | Explore ListenBrainz charts or fresh albums. Params: `mode`, `entity`, `range_name`, `sort_by`, `sort`, `days`, `past`, `future`, `min_listen_count`, `with_cover`, `page`, `count` |
|
||||
| GET | `/api/v1/music/album/{album_id}` | Album detail with tracks and releases. Params: `source` |
|
||||
| GET | `/api/v1/music/artist/{artist_id}` | Browse artist detail. Params: `source` |
|
||||
| GET | `/api/v1/music/artist/{artist_id}/albums` | Browse artist albums/EPs/singles. Params: `source`, `page`, `count`, `album_type` |
|
||||
| GET | `/api/v1/music/artist/{artist_id}/related` | Browse related artists. Params: `source`, `count` |
|
||||
|
||||
Music acquisition rules:
|
||||
|
||||
- Reuse `source`, `media_id`, and `music_type` from search/detail results. Never substitute a same-name entity.
|
||||
- Subscribe/download one recording as one track. Subscribe/download one album as a complete multi-track pack.
|
||||
- Album torrent validation compares supported audio files with `total_tracks`; incomplete resources do not complete the subscription.
|
||||
- Artist IDs are never subscription, torrent, download, transfer, or library-existence targets.
|
||||
- `/api/v1/media/scrape/{storage}` writes configured music tags/covers and can fetch LRCLIB lyrics as `.lrc`/`.txt` sidecars. External metadata, cover, exploration, statistics, and lyrics requests use bounded TTL/LRU caches in their owning modules/helpers.
|
||||
|
||||
### Search / Torrents / Subtitles (11 endpoints)
|
||||
|
||||
@@ -224,7 +237,7 @@ Streaming search sends `{"type":"heartbeat"}` every 15 seconds without business
|
||||
| Method | Path | Description |
|
||||
|--------|------|-------------|
|
||||
| GET | `/api/v1/subscribe/` | List all subscriptions |
|
||||
| POST | `/api/v1/subscribe/` | Add subscription. Body accepts `media_source` + `media_id` and compatible `tmdbid`, `doubanid`, `bangumiid`, `anilistid` fields |
|
||||
| POST | `/api/v1/subscribe/` | Add subscription. Music requires `type=music`, `music_type=recording|album`, and exact `media_source` + `media_id`; video also accepts compatible dedicated IDs |
|
||||
| PUT | `/api/v1/subscribe/` | Update subscription. Body: Subscribe JSON |
|
||||
| GET | `/api/v1/subscribe/list` | List subscriptions (API_TOKEN auth, use `--token-param`) |
|
||||
| GET | `/api/v1/subscribe/{subscribe_id}` | Subscription detail |
|
||||
@@ -615,6 +628,26 @@ python scripts/mp-api.py GET /api/v1/search/last
|
||||
python scripts/mp-api.py POST /api/v1/download/add --json '{"torrent_url":"<url_from_search>"}'
|
||||
```
|
||||
|
||||
### Search and subscribe to one recording or complete album
|
||||
|
||||
```bash
|
||||
# 1. Search MusicBrainz entities through the unified media search
|
||||
python scripts/mp-api.py GET /api/v1/media/search title="Artist - Title" type="music" count=20
|
||||
|
||||
# 2a. For an album, inspect its complete track list before subscribing
|
||||
python scripts/mp-api.py GET /api/v1/music/album/<album_mbid> source="musicbrainz"
|
||||
|
||||
# 2b. Check the exact entity subscription separately; music_type prevents recording/album ambiguity
|
||||
python scripts/mp-api.py GET /api/v1/subscribe/media/musicbrainz:<mbid> music_type="album"
|
||||
|
||||
# 3. Add one exact album subscription. REST enum values use the localized MediaType value.
|
||||
python scripts/mp-api.py POST /api/v1/subscribe/ --json '{"name":"Album Title","type":"音乐","music_type":"album","media_source":"musicbrainz","media_id":"<album_mbid>"}'
|
||||
|
||||
# For one track, use that track's recording MBID and music_type=recording instead.
|
||||
```
|
||||
|
||||
Do not create an artist subscription. Select a recording or album from the artist catalog first. For an album manual download, use one matched album resource; the download layer rejects resources whose audio-file list does not cover `total_tracks`.
|
||||
|
||||
### Search and download subtitles
|
||||
|
||||
```bash
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
---
|
||||
name: organize-files
|
||||
version: 1
|
||||
version: 2
|
||||
description: >-
|
||||
Use this skill when the user asks the MoviePilot agent to identify and organize downloaded/local media files that automatic transfer cannot handle. Typical triggers include: manually organize a file or folder, organize unrecognized downloads, fix files stuck in a download directory, identify a messy episode pack, move/copy/link files into the library, or organize files by explicit TMDB/Douban ID. 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 ask_user_choice send_message
|
||||
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
|
||||
---
|
||||
|
||||
# Organize Files (智能整理文件)
|
||||
@@ -17,7 +17,7 @@ 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 media/subtitle/audio files, ignores recycle/hidden paths and configured exclude words, resolves download history when possible, builds `MetaInfoPath`, then either uses explicit media info or calls `MediaChain.recognize_by_meta`.
|
||||
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.
|
||||
|
||||
@@ -43,6 +43,7 @@ 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.
|
||||
|
||||
@@ -56,18 +57,18 @@ recognize_media(path="<source file path>")
|
||||
|
||||
If recognition fails or looks wrong:
|
||||
|
||||
1. Extract likely title, year, media type, season, and episode range from filenames.
|
||||
2. Call `search_media(title="...", year="...", media_type="movie|tv")`.
|
||||
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/TMDB ID.
|
||||
4. For TV season confusion, use `query_media_detail(tmdb_id=<id>, media_type="tv")` before deciding the season number.
|
||||
4. For TV season confusion, use `query_media_detail(tmdb_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 a TMDB/Douban ID. When unsure, ask for confirmation.
|
||||
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 `tmdb_id` and `media_type` are known and duplicate risk matters.
|
||||
- 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.
|
||||
|
||||
@@ -87,6 +88,18 @@ transfer_file(
|
||||
)
|
||||
```
|
||||
|
||||
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.
|
||||
@@ -95,6 +108,10 @@ Rules:
|
||||
- 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 `tmdbid`, `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
|
||||
|
||||
@@ -122,6 +139,21 @@ If the result creates failed history records, tell the user they can retry with
|
||||
3. Confirm `tmdbid`, `media_type="tv"`, and season.
|
||||
4. `transfer_file(file_path="<folder>/", media_type="tv", tmdbid=<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=...)`
|
||||
@@ -143,5 +175,7 @@ If the result creates failed history records, tell the user they can retry with
|
||||
- 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.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
name: transfer-failed-retry
|
||||
version: 2
|
||||
description: Use this skill when you need to retry failed file transfers/organizations. Given one or more failed transfer history record IDs, this skill guides you through querying the failure details, deleting the old records, and re-identifying and re-organizing the files. Supports batch processing of multiple files from the same media (e.g., multiple episodes of a TV show). This skill is automatically triggered when the system detects transfer failures and the AI agent retry feature is enabled.
|
||||
version: 3
|
||||
description: Use this skill when you need to retry failed video or music transfers/organizations. Given failed transfer history IDs, query the exact records, group by trustworthy movie/series/recording/album identity, delete only the old records being retried, then re-identify and re-organize through MoviePilot. This skill is automatically triggered when transfer failures occur and AI retry is enabled.
|
||||
allowed-tools: query_transfer_history delete_transfer_history recognize_media transfer_file search_media
|
||||
---
|
||||
|
||||
@@ -16,7 +16,7 @@ You need the following tools:
|
||||
- `delete_transfer_history` - Delete a transfer history record
|
||||
- `recognize_media` - Recognize media info from file path or title
|
||||
- `transfer_file` - Transfer/organize files to the media library
|
||||
- `search_media` - Search TMDB for media information
|
||||
- `search_media` - Search video metadata or MusicBrainz recording/album/artist candidates
|
||||
|
||||
## Workflow
|
||||
|
||||
@@ -35,11 +35,12 @@ From each record, extract the following key information:
|
||||
- **src**: Source file path
|
||||
- **title**: The recognized title (may be incorrect)
|
||||
- **errmsg**: The error message explaining why the transfer failed
|
||||
- **type**: Media type (movie/tv)
|
||||
- **type**: Media type (movie/tv/music)
|
||||
- **tmdbid**: TMDB ID (if available)
|
||||
- **seasons/episodes**: Season/episode info (if TV show)
|
||||
- **downloader**: Which downloader was used
|
||||
- **download_hash**: The torrent hash
|
||||
- **media_source/media_id**: Exact source-native identity; required to preserve selected music entities
|
||||
|
||||
### Step 2: Analyze the Failure Reason
|
||||
|
||||
@@ -47,7 +48,7 @@ Common failure reasons and how to handle them:
|
||||
|
||||
| Error Message | Cause | Solution |
|
||||
|---------------|-------|----------|
|
||||
| 未识别到媒体信息 | File name couldn't be matched to any media | Use `search_media` to find the correct TMDB ID, then use `transfer_file` with explicit `tmdbid` |
|
||||
| 未识别到媒体信息 | File name or audio tags could not be matched | Use `search_media` to find the exact video ID or music recording/album identity, then transfer with explicit IDs |
|
||||
| 源目录不存在 | Source file was moved or deleted | Cannot retry - skip this record |
|
||||
| 目标路径不存在 | Target directory issue | Retry transfer - the directory config may have been fixed |
|
||||
| 文件已存在 | Target file already exists | May need to use `force` mode or skip |
|
||||
@@ -73,14 +74,18 @@ Based on the failure analysis in Step 2:
|
||||
recognize_media(path="<source_file_path>")
|
||||
```
|
||||
|
||||
2. If recognition fails, try searching TMDB with keywords extracted from the filename:
|
||||
2. If recognition fails, search the appropriate metadata source with keywords extracted from the filename or audio tags:
|
||||
```
|
||||
search_media(title="<extracted_title>", media_type="movie" or "tv")
|
||||
# or for music
|
||||
search_media(title="<artist> - <track_or_album>", media_type="music", music_type="recording" or "album")
|
||||
```
|
||||
|
||||
3. Once you have the correct TMDB ID, re-transfer with explicit identification:
|
||||
3. Once you have the exact identity, re-transfer with explicit identification:
|
||||
```
|
||||
transfer_file(file_path="<source_path>", tmdbid=<tmdb_id>, media_type="movie" or "tv")
|
||||
# or for music
|
||||
transfer_file(file_path="<source_path>", media_type="music", music_type="recording" or "album", media_source="musicbrainz", media_id="<recording_or_album_id>")
|
||||
```
|
||||
|
||||
#### Case B: Transfer Error (file operation failed)
|
||||
@@ -99,6 +104,13 @@ For TV shows where episode info couldn't be determined:
|
||||
transfer_file(file_path="<source_path>", tmdbid=<tmdb_id>, media_type="tv", season=<season_number>)
|
||||
```
|
||||
|
||||
#### Case D: Music Recording Or Album
|
||||
|
||||
1. A recording is one track. Retry the individual audio file with its recording ID.
|
||||
2. An album is a collection like a TV season pack. If several failed tracks share one album directory and album ID, verify the group and retry the directory once with the album ID.
|
||||
3. Never use an artist ID as a transfer target. Search/select a recording or album instead.
|
||||
4. Do not infer that a directory is complete merely because it has multiple files. Preserve the album identity and let the transfer/download pipeline enforce expected-track semantics where available.
|
||||
|
||||
### Step 5: Report Result
|
||||
|
||||
After the retry attempt, report the result:
|
||||
@@ -108,13 +120,13 @@ After the retry attempt, report the result:
|
||||
|
||||
## Batch Processing (批量处理)
|
||||
|
||||
When multiple files from the same source fail simultaneously (e.g., 10 episodes of the same TV show all fail with the same error), the system groups them and triggers a single batch retry.
|
||||
When multiple files fail simultaneously (for example, TV episodes or tracks from one album), the system may trigger one batch retry. Treat the batch as candidates for grouping, not proof that every record has the same identity.
|
||||
|
||||
### Key Optimization Rules for Batch Processing:
|
||||
|
||||
1. **Identify media ONCE, apply to ALL files**: Since batch files typically belong to the same media, perform media recognition (`recognize_media`) or search (`search_media`) only ONCE using the first file, then reuse the result (tmdbid, media_type) for all subsequent files.
|
||||
1. **Group first, identify once per verified group**: Group by source directory and exact media identity. Reuse video IDs within one movie/series group and reuse an album ID for tracks from one album. Do not apply one recording ID to multiple different tracks.
|
||||
|
||||
2. **Process each file individually for delete + transfer**: Even though the media identity is shared, you must still:
|
||||
2. **Choose the correct retry unit**: For movies, recordings, and TV episode files, delete and retry each exact failed record/file as needed. For a verified album directory, delete the selected failed records and submit the album directory once rather than repeatedly transferring every track.
|
||||
- Delete each failed history record individually
|
||||
- Transfer each file individually (they have different source paths)
|
||||
|
||||
@@ -158,7 +170,8 @@ transfer_file(file_path="/downloads/Show.Name.S01E04.1080p.mkv", tmdbid=789, med
|
||||
- **Do not retry** if the error is about missing directory configuration - this requires user intervention.
|
||||
- **For unrecognized media**, always try `recognize_media` with the file path first before falling back to `search_media`.
|
||||
- **Be cautious with TV shows** - ensure the correct season and episode information is used.
|
||||
- **For batch processing**, always reuse media identification results across all files to save time and resources.
|
||||
- **For batch processing**, reuse media identification only inside a verified group. Same source location alone does not prove shared identity.
|
||||
- **For music**, keep recording, album, and artist semantics distinct. Artists are browse-only; albums are multi-track retry units.
|
||||
- When this skill is triggered automatically by the system, it provides the `history_id`(s) directly. Start from Step 1 with those specific IDs.
|
||||
|
||||
## Example: Single File Retry Flow
|
||||
|
||||
Reference in New Issue
Block a user