Files
MoviePilot/docs/mcp-api.md
jxxghp 791bcc00c0 fix(subscribe): persist cleared optional settings
Preserve explicit empty values for recognition words, keywords, paths, episode groups, downloaders, and audio thresholds. Add endpoint and persisted transaction regression coverage and document the update contract.

Refs #6894
2026-10-05 17:54:29 +08:00

97 KiB
Raw Blame History

MoviePilot MCP (Model Context Protocol) API 文档

MoviePilot 实现了标准的 Model Context Protocol (MCP),允许 AI 智能体(如 Claude, GPT 等)直接调用 MoviePilot 的功能进行媒体管理、搜索、订阅和下载。

1. 基础信息

  • 基础路径: /api/v1/mcp
  • 协议版本: 2025-11-25, 2025-06-18, 2024-11-05
  • 传输协议: HTTP (JSON-RPC 2.0)
  • 认证方式:
    • Header: X-API-KEY: <你的API_KEY>
    • Query: ?apikey=<你的API_KEY>

安全提示

MCP 使用系统配置中的 API_TOKEN 作为认证密钥,文档中的 API KEY 是请求字段名。该密钥应按管理员级 secret 保管,持有者可作为受信第三方集成调用暴露的 MoviePilot 工具。

  • 优先使用 X-API-KEY 请求头;查询参数更容易出现在代理、浏览器或客户端日志中。
  • 不要在缺少 HTTPS、访问控制和网络隔离的情况下,将 MCP、OpenAI 或 Anthropic 兼容接口直接暴露到公网。
  • MCP 隐藏工具列表只用于减少默认暴露面,不是 per-user 权限系统。

POST /api/v1/history/transfer/{history_id}/discard-corrupt 属于需要管理权限的整理恢复 REST 接口,不向 Agent gateway 暴露。成功响应的 data.history_id 为保留的整理历史 ID;任务已清理时同样返回该结构,历史不存在时返回业务失败。

图片 REST 接口 /api/v1/system/img/{proxy} 和 /api/v1/system/cache/image 自动将已配置 站点的主域名及访问地址加入图片域名白名单(含停用站点,便于展示图标),无需手动配置 SECURITY_IMAGE_DOMAINS。站点域名快照在内存中复用,同一事件循环的并发加载合并为一次查询; 站点新增、改址或删除提交后立即失效,另有 60 秒过期兜底。TMDB_IMAGE_DOMAIN、 MUSIC_COVER_PROXY、WALLPAPER_IMAGE_URL、CUSTOMIZE_WALLPAPER_API_URL 和启用时的 BANGUMI_IMAGE_DOMAIN 的 HTTP(S) 主机也自动放行,配置变更即时生效。壁纸 API 返回的其他 域名不自动扩展授权;必要时加入 SECURITY_IMAGE_DOMAINS。 域名放行后仍执行 DNS/私网校验, Fake-IP 等非公网解析地址需要通过 IMAGE_PROXY_ALLOWED_PRIVATE_RANGES 明确允许。

2. 标准 MCP 协议 (JSON-RPC 2.0)

端点

POST /api/v1/mcp

支持的方法

  • initialize: 初始化会话,协商协议版本和能力。
  • notifications/initialized: 客户端确认初始化完成。
  • tools/list: 获取可用工具列表。
  • tools/call: 调用特定工具。
  • ping: 连接存活检测。

动态插件工具

内置 Agent 的 update_plan、search_memory、session_search、memory、skills_list、skill_view、skill_manage、search_tools、read_tool_result、get_tool_execution 为会话中间件工具,不通过外部 tools/list 发布;它们维护计划、检索用户隔离的历史证据、发现工具、续读结果或查询执行回执,不能授予业务操作权限。search_memory 只保留稳定偏好和主题文件检索,旧 activity 分类已废弃。历史查询使用宿主绑定的 user_id,不接受模型指定身份。使用与恢复语义见 Agent 复杂任务执行与恢复。

tools/list 会同时返回 MoviePilot 内置工具和已启用插件通过 get_agent_tools() 声明的工具。插件启动、停止、重载或配置生效后,MCP 工具管理器会在下一次列出或调用工具时按注册表版本惰性刷新,避免继续暴露已移除的工具或遗漏新工具。

MCP 当前不会主动发送工具列表变更通知(listChanged=false)。如果客户端缓存了工具列表,插件状态变化后需要让客户端重新请求 tools/list;无法手动刷新的客户端应重新连接 MCP 服务或新建会话。

execute_code 仅在已绑定宿主会话的管理员 Agent 中提供,不发布到外部 HTTP/MCP 工具目录。内部只读 RPC 仍经过同一个 API/Skill/身份边界,默认直接执行,不要求用户逐次确认;外部客户端不能通过直接调用为自己创建 Python 会话身份。持久状态和回收语义见 Python 只读工具编排。

插件实例日志等级

plugin.loglevel.get 使用源插件 ID 查询,返回该插件全部实例(首项固定是本体自身,其后 是各个分身)的 configured_level、expires_at 与 effective_level。用某个分身自身的 实例 ID 当作 plugin_id 会被拒绝——分身的日志等级归它的源插件管。configured_level 为 null 表示没有覆盖或覆盖已过期;effective_level 才是此刻真正用于过滤的等级。

plugin.loglevel.set 与 plugin.loglevel.clear 使用该总览返回的精确 instance_id, 运行期立即生效,不必重载插件,也不改变全局日志等级。expires_at 为空表示覆盖不过期; 提交不带时区的时间会按 UTC 解读,与查询接口返回的 UTC 时刻保持一致。覆盖过期后自动回落 全局等级,不需要再调一次 clear;重复 clear 保持幂等。

覆盖只对宿主受控调用点内产生的日志生效——插件的构造与 init_plugin、事件处理器、定时 服务回调、插件自己声明的 HTTP 端点。插件自建的原生线程不继承这个绑定,其中的日志仍按 全局等级过滤,不要据此断定覆盖没有写进去。

插件实例默认调用目标

plugin.default_target.set 与 plugin.default_target.clear 使用源插件 ID 加实例 ID 指定「只给插件 ID、没给实例 ID 的调用应当落到哪个实例」。同一源插件至多一个默认调用 目标,置新会自动清掉旧的;清除只在当前置位的正是该实例时才动作,重复调用保持幂等。

一个插件有分身而未设置默认调用目标时,未指定实例的调用会直接报错,不会随机挑一个、 也不会按登记顺序取第一个:那会让同一次调用在不同时刻落到不同实例,既无法复现,也无从 知道刚才是哪个实例执行的。默认目标被停用时同样报错,不静默改走另一个正在运行的实例。 只有本体、没有任何分身的插件不受这套机制约束,不需要显式设置默认目标。

插件实例启停

plugin.instance.set_enabled 用实例 ID 启用或停用一个实例,本体与分身共用这一个入口 (实例 ID 等于插件 ID 时指的是本体自身)。

停用不是删除:业务参数与展示信息原样留在那一行等待再次启用,因而「停掉一个实例」与 「丢掉它的配置」终于是两件事——此前两者绑死,想保住配置就只能留着一个在跑的实例。 只有删掉整行才是彻底清理。停用会同时清掉该实例的默认调用目标置位与日志等级覆盖: 前者会把未指定实例的调用路由到一个不会被实例化的实例,后者本就是带失效时间的临时 调试设置。

是否启用与此刻是否在运行是两回事:前者是落盘的装载判据,后者由运行时持有、不落盘。

插件实例彻底清理

plugin.instance.purge 用实例 ID 按四项独立范围删除该实例的持久化内容:业务参数 (config)、插件数据表中的行(plugin_data)、插件自有数据库(own_database)、 插件数据目录(data_directory)。四项全部默认为假,一项都没选直接返回失败,服务端 不替调用方补默认值——清理不可逆,漏删只是少删,多删可能毁掉用户特意留下的数据。

它与停用不是一件事:停用只把启用位置假、设置原样留着随时可恢复,这里才真正删除用户 数据。响应的 purged 列出本次真正清掉的范围,目录本就不存在时不会出现在其中; instance_removed 说明实例行是否随之消失——分身会删,本体保留,本体那一行还承载着 该插件的启用状态与展示覆盖。

选了删数据目录就必然先销毁自有数据库(库文件落在该目录下),但未单独勾选 own_database 时不会把它计入 purged。实例 ID 必须是合法的插件实例 ID(字母开头、仅字母与数字): 它会被拼进插件数据目录路径,带路径分隔符或上跳的标识一律在动任何存储之前被拒绝。

插件分身的创建与恢复

plugin.clone 用源插件 ID 创建一个共享它源码的分身。suffix 可以不填:留空时由服务端 挑一个最小可用序号(本体算第 1 个实例,分身从 2 起排),因而调用方算不出分身 ID, 必须从回执的 data.instance_id 取。填了后缀则只接受 ASCII 字母与数字,且在请求解析阶段 就会被拦下——非法后缀拼出的实例 ID 用不了 Python 类名与路由段,等落库再报错意味着已经 写出一行、还要靠回滚擦掉。

占号判据不止看「此刻在不在跑」:当前已装载的类、实例表里的每一行(含已停用的分身与本体)、 安装清单,以及磁盘上留存的插件包目录,任意一项命中都算已占用。自动分配与手填后缀共用这 同一个判据,自动分配因此不会挑中一个手填时会被拒绝的 ID。

同一个后缀名下留有一个已停用的分身时,这次创建就是把那一行重新置为启用,而不是新建: 停用从不删行,业务参数一直挂在上面,恢复因而拿回的正是用户当初留下的那份配置。展示名、 描述与图标留空则沿用停用前登记的那一份,填了就按填的改。要改为「丢掉旧配置、按源插件模板 重建」,把 restore_previous 置为 false——静默丢弃用户数据不能是默认行为。恢复失败时只 把启用位退回停用,不会连同那一行与它的配置一起毁掉。

plugin.clone.restorable 用源插件 ID 列出该插件名下所有已停用、配置仍留存的分身,给出 实例 ID、相对源插件 ID 的后缀、停用前登记的展示信息,以及是否留有业务参数。启用中的分身 不在此列:它们的配置正被使用,拿来「恢复」没有意义。

被 plugin.instance.purge 彻底清理掉的分身也不在此列,而且不可恢复:清理删的是实例行 本身,恢复所依赖的那份留存配置随之消失,同后缀再建只会得到一个全新的空白分身。

3.1 结构化 Agent 工具与完整参数合同

tools/list 会为以下四个正式入口返回可直接校验的 JSON Schema。每个入口都按 operation/action 生成 oneOf 分支,分支中包含必填字段、类型、默认值、枚举、嵌套对象和互斥/至少一项等跨字段规则;外部 MCP 客户端可以在一次 tools/call 中完成参数构造,不需要猜测 URL、HTTP 方法或第三方 SDK 参数。

MCP 工具 用途 参数合同来源
moviepilot_api MoviePilot 产品业务 API:媒体、搜索、订阅、下载、整理、站点、存储、调度、工作流、插件、过滤规则和系统配置 skills/moviepilot-api/SKILL.md 及其 api/<category>.md 独立分类合同;运行时 schema 为 app/agent/policy/resources/api_mcp_schema.json
downloader_operation qBittorrent、Transmission、rTorrent 原生任务、队列、文件、限速、标签和会话操作 skills/downloader-operation/SKILL.md 与 skills/downloader-operation/scripts/mp-downloader.py 的 ACTIONS
mediaserver_operation Emby、Jellyfin、Plex、ZSpace、UGREEN、TrimeMedia、Navidrome、Vyo 原生媒体库、搜索、播放、扫描和刷新操作 skills/mediaserver-operation/SKILL.md 与 skills/mediaserver-operation/scripts/mp-mediaserver.py 的 ACTIONS
database_operation MoviePilot 配置数据库表清单、实时 schema、只读 SQL 和明确授权写入 skills/database-operation/SKILL.md 与 skills/database-operation/scripts/mp-db.py 的 ACTIONS

这四个工具都要求管理员级 MCP 集成身份;tools/list 的可见性不等于绕过业务权限或写操作确认。下载器和媒体服务器工具会在一次调用内自动选择默认/唯一实例;实例不明确时,错误结果会列出可复用的精确实例名。数据库工具不接受任意连接串或凭据,脚本从 MoviePilot 运行时配置读取数据库连接。

app/agent/policy/resources/api_mcp_schema.json 是 moviepilot_api 的生成制品,不是设置项或 API 参数的手工事实源。scripts/generate_agent_api_mcp_schema.py 从当前 FastAPI OpenAPI、固定 operation 路由和 Agent 专用英文参数说明生成该文件;运行时直接读取它响应外部 MCP tools/list,测试会校验生成结果没有漂移。修改 API、请求模型或 operation 后应重新生成并提交该文件,不应直接编辑 JSON。

当前完整 FastAPI OpenAPI 包含 421 个 HTTP 操作,其中 231 个稳定业务操作进入 moviepilot_api,使用 229 个固定路由模板:228 条 OpenAPI 路由直接匹配,另有 1 条只允许 tmdb、douban、bangumi、anilist 四个来源的受限人物作品动态路由。每个 operation 均同时具备固定 method/path、角色权限、副作用等级、确认与恢复策略、结果敏感性、英文用途说明, 以及可直接提交的 path/query/body JSON Schema;Skill front matter、正文 operation 章节、运行时 注册表和 MCP tools/list 的 231 个 oneOf 分支必须完全一致。

数量不相等是明确的安全与语义边界,而不是漏生成。当前 410 条路由均被审计并锁定为以下一种 归属,审计生成器不再提供“未归类”兜底:

归属 数量 Agent 使用方式
gateway 228 通过 moviepilot_api 的稳定 operation 和精确参数合同调用
consolidated 71 通过同领域聚合 operation 调用,不复制数据源或前端专用路由
provider-skill 12 通过下载器或媒体服务器 Skill 调用第三方 provider API
alternate-auth-duplicate 11 使用对应 bearer-authenticated gateway operation,不暴露 API_TOKEN 兼容副本
transport_or_identity 76 由登录、令牌、MCP、会话、回调、健康检查等宿主传输/身份边界拥有
stream_or_binary 10 由直接客户端处理流式日志、消息、文件、图片等非结构化响应
ui_presentation 13 由前端或插件渲染面拥有,不作为业务 Agent operation

逐路由归属见 docs/refactor/agent-api-surface-audit.md,并由 tests/test_agent_api_surface_audit.py 对当前 OpenAPI、固定注册表、MCP schema、英文 Skill 合同及全部非网关归属做漂移检查。任何新增端点必须先明确归属;对 Agent 开放时还必须补齐 operation ID、权限、副作用、确认、恢复、结果敏感性及精确参数说明。

moviepilot_api 调用形状

{
  "name": "moviepilot_api",
  "arguments": {
    "operation_id": "subscription.list",
    "path_params": {},
    "query": {"page": 1, "count": 20},
    "body": {}
  }
}

只允许传 tools/list 对应 operation 分支中声明的 path_params、query 和 body 字段。不得传 URL、认证头、API Token 或任意 HTTP 方法。

内置 Agent 工具同样禁止额外顶层字段。业务参数不能平铺在 operation_id 旁边: 例如 media.detail 的 media_id 属于 path_params,media_source 与 type_name 属于 query; subscription.execution.list 使用 query.limit,不能套用其它列表的 page / count; site.rss 支持 query.page / query.count,不接受 site_id 筛选。 工具说明内联了这三个接口的完整 JSON 示例,示例 ID 必须替换为前序查询返回的真实 ID。 参数错误在请求发出前返回纠错回执和该 operation 的 input_contract(网关错误码为 invalid_input), 并指出具体缺失或错误字段(如 query.media_source)、未声明字段或顶层参数的正确位置, 不回显参数值。模型应根据该合同修正参数后重试;写入参数错误不会创建执行认领。

body 使用原生 JSON 值。对象和数组直接传入;仅在选定的 operation 允许时传 null。当前唯一的字符串请求体为 system.upgrade.dev 的固定值 "dev"。网关会按选定的 operation 合同校验请求体类型和字段。

search.torrents 可能按媒体标题与别名分轮搜索站点:MoviePilot 内层请求最多等待 290 秒,Agent 工具总等待上限为 300 秒,预留 10 秒处理超时与返回结果;V3 MCP 包装层继续使用原有 mcp_proxy_timeout 配置(默认 600 秒)。其它 operation 沿用原有超时配置。page / count 只分页已完成的搜索结果,不会缩短站点搜索过程。

查询结果的兼容分页合同如下:

  • 原先返回完整列表、没有分页参数的接口会在端点签名、OpenAPI、Skill 和 MCP oneOf 中显式声明可选 page / count;page 必须不小于 1,count 范围为 1 到 200。两者都省略时仍返回原来的完整列表,不启用分页;显式传入任一参数时才分页,缺失的 page 按 1、缺失的 count 按 50 处理。FastAPI 的 response 注入对象不是业务输入,不会出现在 REST、Skill 或 MCP 参数中。
  • 数据库列表在查询层先应用授权范围和业务筛选,再执行稳定排序、LIMIT/OFFSET 和同条件精确 COUNT;不得先全表加载、响应后切片。纯内存、配置、缓存、文件系统或运行时列表可以在序列化边界切片。已有 max_results 等原生限量参数的接口继续支持显式限量;原生限量参数默认值为 None 时,省略所有分页和限量参数仍返回完整列表,显式 page/count 的优先级由端点合同说明。
  • REST 响应的 data 保持原列表结构,不改成 {items,total}。X-Result-Count 报告本次实际返回数量;仅当 MoviePilot 已经取得完整筛选结果时,才增加精确的 X-Total-Count。原有结构化分页接口继续在既有 data.total 与 data.items / data.list 中返回总数。
  • moviepilot_api 把这些响应头投影为响应中的附加 collection 对象:result_count 为本次返回数量,total_count 仅在精确可知时出现,page / count 在可用时出现。collection 是附加元数据,不替换或改写 data。
  • Agent 仅查询数量或摘要时,应对支持精确总数的列表发送最小窗口;兼容分页接口使用 page=1,count=1,然后直接读取 collection.total_count。即使列表内容触发 64KB 工具预览截断,网关也会把 collection 放在 data 前面,确保总数仍可见;不得因为条目被截断就回退到数据库统计。
  • 已经由第三方接口原生分页或限量、但上游没有返回总数的查询不会伪造 total_count;Agent 应以 result_count 判断当前页是否为空,并按原接口的分页参数继续读取。

downloader_operation / mediaserver_operation 调用形状

{
  "name": "downloader_operation",
  "arguments": {
    "client": "main-qb",
    "action": "tasks.list",
    "arguments": {
      "status": "downloading",
      "offset": 0,
      "limit": 20
    }
  }
}

媒体服务器将顶层实例字段改为 server,其余结构相同。client/server 可省略;具体 action 的 arguments 必须严格匹配对应 oneOf 分支。

database_operation 调用形状

{
  "name": "database_operation",
  "arguments": {
    "action": "query",
    "arguments": {
      "sql": "SELECT title, year FROM downloadhistory ORDER BY id DESC",
      "limit": 20,
      "write": false
    }
  }
}

数据库 action 参数为:

  • tables:无参数,列出当前数据库实际表。
  • schema:必填 table_name,必须使用 tables 返回的精确名称。
  • query:sql 与 file 二选一;可选 limit(默认 100)和 write(默认 false)。默认只允许 SELECT、WITH、EXPLAIN。
  • write:sql 与 file 二选一,只允许单条写入或结构变更语句;必须已有明确授权。

数据库 ORM 当前维护的完整表清单与字段基线见 skills/database-operation/SKILL.md 的 Core Tables;运行时仍应先调用 schema,因为实际部署可能存在迁移差异或插件表。

系统设置、配置变量与数据库配置

系统设置统一使用 moviepilot_api,不需要恢复旧的 query_system_settings / update_system_settings 工具:

  • config.system.list 只返回分页的轻量合同索引,不读取当前值;支持 group、keyword、source、offset 和 limit。
  • config.system.describe 读取一个精确设置的完整 JSON Schema、默认值/单位/示例、依赖与冲突、写入边界、当前值和稳定 revision;敏感值默认脱敏。
  • config.system.get 同时查询 Settings 运行配置变量和 SystemConfigKey 数据库配置。可用 setting_key 精确读取,或用 group + keyword 发现键;单项默认返回完整值,多项默认只返回摘要。
  • 每个发现结果都返回动态 definition:声明类型、当前值形状、是否可空/敏感、允许的更新操作、列表默认匹配字段和持久化位置。Agent 应先发现定义,再按返回的精确键和形状调用更新。
  • config.system.update 支持 replace、merge_dict、upsert_list_item、remove_list_item。Settings 字段会执行类型转换并持久化到 app.env;SystemConfigKey 会经配置服务写入数据库并发布配置变更事件。
  • 新客户端应将 describe 返回的 revision 作为 expected_revision 回传;省略该字段仍保留旧客户端的非条件更新兼容行为。generic_write_allowed=false 的复杂或内部配置必须改用返回的专用 operation,过期 revision 返回冲突而不覆盖其他写入。
  • 敏感值默认脱敏;只有管理员明确要求时才传 query.show_secrets=true,并继续受宿主确认和保护输出策略约束。
  • database_operation 直接修改 systemconfig 只用于受控数据修复。普通配置修改不得绕过键注册、类型转换、插件 mutation 门禁和事件通知。

skills/moviepilot-api/SKILL.md 只维护稳定的发现与更新流程,不复制当前版本全部 Settings / SystemConfigKey 清单。真实键、类型和值形状由 config.system.list / config.system.describe 运行时发现;MCP tools/list 的 config.system.list/describe/get/update 分支负责说明发现参数和更新请求结构。


4. 客户端配置示例

Claude Desktop (Anthropic)

在Claude Desktop的配置文件中添加MoviePilot的MCP服务器配置:

macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
Windows: %APPDATA%\Claude\claude_desktop_config.json

使用请求头方式:

{
  "mcpServers": {
    "moviepilot": {
      "url": "http://localhost:3001/api/v1/mcp",
      "headers": {
        "X-API-KEY": "your_api_key_here"
      }
    }
  }
}

或使用查询参数方式:

{
  "mcpServers": {
    "moviepilot": {
      "url": "http://localhost:3001/api/v1/mcp?apikey=your_api_key_here"
    }
  }
}

4.1 Agent 外部 MCP Client 配置

MoviePilot 的内置 Agent 也可以作为 MCP Client 连接外部 MCP 服务器,将外部工具注入到智能助手工具列表中。当前支持:

  • stdio:按配置的命令和参数启动本地 MCP 进程,通过标准输入输出交换 JSON-RPC 消息。
  • sse:连接旧版 HTTP+SSE MCP 服务,先读取 endpoint 事件,再向返回的 endpoint POST JSON-RPC 消息。
  • http / streamable_http:连接 Streamable HTTP MCP 服务,直接向配置 URL POST JSON-RPC 消息。

这些配置是管理员级 Agent 运行时配置,保存在 SystemConfigKey.AIAgentMcpServers 中。外部 MCP 工具默认要求管理员上下文调用,避免普通用户触发高权限外部工具。

Agent MCP 配置接口

这些接口使用登录态鉴权,并要求当前用户为超级管理员。

方法 路径 说明
GET /api/v1/message/agent/mcp/servers 查询已配置的外部 MCP 服务器列表
POST /api/v1/message/agent/mcp/servers 保存外部 MCP 服务器列表
POST /api/v1/message/agent/mcp/servers/test 测试单个外部 MCP 服务器,返回发现的工具列表

5. 错误码说明

错误码 消息 说明
-32700 Parse error JSON 格式错误
-32600 Invalid Request 无效的 JSON-RPC 请求
-32601 Method not found 方法不存在
-32602 Invalid params 参数验证失败
-32002 Session not found 会话不存在或已过期
-32003 Not initialized 会话未完成初始化流程
-32603 Internal error 服务器内部错误

6. RESTful API

HTTP 工具管理端点统一位于 /api/v1/mcp,并与标准 MCP JSON-RPC 端点共享同一最终工具目录。

相关 REST 端点

MoviePilot 也提供普通 REST API 给前端和自动化客户端使用。所有接口同样需要 API KEY 认证,在请求头中添加 X-API-KEY: <api_key> 或在查询参数中添加 apikey=<api_key>。

REST API 版本

  • 普通 JSON REST 接口统一使用 /api/v1,不再提供 /api/v2 套壳版本。
  • 成功和失败响应都只包含 success、message、data 三个顶层字段;各接口只有 data 的模型可以变化。
  • 成功响应为 {"success": true, "message": "", "data": <接口数据>}。HTTP 错误保留原状态码,返回 {"success": false, "message": <错误原因>, "data": null};请求参数校验错误会在 data 中附带结构化错误列表。
  • 查询接口未命中但请求已正常完成时仍返回 success=true,存在性等业务状态通过 data 表达。例如 /mediaserver/exists 未命中时返回空的 data.item。
  • 每个普通 JSON 端点都会在 OpenAPI 中声明具体的 Response[DataModel],开放 API 文档后,调用方可从 /docs 或 /api/v1/openapi.json 查询数据结构。
  • SSE、文件、图片、HTML、空响应,以及 OAuth2 登录、OpenAI、Anthropic、MCP JSON-RPC 等标准协议端点保持协议原生响应体;它们会在 OpenAPI 中显式声明对应的流、文件或协议模型。
  • 插件通过 get_api() 动态注册的 /api/v1/plugin/... 端点不属于主程序统一响应信封范围。插件自行声明响应模型、状态码和返回体,宿主只补充路径与鉴权依赖。

GitHub Token 授权

GitHub Token 是可选的管理员配置,可在设置页或首次初始化页通过 GitHub Device Flow 授权, 也可以直接保存已有的 PAT。Device Flow 请求 read:user、repo、workflow:用于读取授权 用户身份、读写公开和私有仓库,以及推送 GitHub Actions 工作流文件。旧 OAuth Token 缺少这些 范围时,状态接口会提示重新授权。授权接口只返回脱敏状态,不会把访问 Token 或刷新 Token 放进响应。

反馈问题和创建 PR 两个 Agent Skill 共用服务端 Token。它们先读取目标仓库的 REPO_GITHUB_TOKEN,再回退到 GITHUB_TOKEN;两种设置页入口(Device Flow 和手动 PAT) 都保存到 GITHUB_TOKEN,因此授权一次后无需在对话中重复提供凭据。OAuth 授权包含仓库读写 权限,GitHub 会在确认页展示;手动 PAT 也必须具备目标仓库对应的 Issue、Fork、Contents、PR 和必要时的 workflow 权限。

已完成初始化的实例使用登录态超级管理员接口:

方法 路径 说明
GET /api/v1/github/auth/status 查询 Token 是否已配置、是否有效、来源和脱敏摘要
POST /api/v1/github/auth/start 申请设备码;响应包含 session_id、verification_uri 和 user_code
POST /api/v1/github/auth/poll 请求体 {"session_id":"..."},轮询授权状态
POST /api/v1/github/auth/manual 请求体 {"token":"..."},保存手动 PAT
DELETE /api/v1/github/auth/token 清除 Token 和 OAuth 刷新元数据

首次初始化窗口使用同样的操作,但路径前缀为 /api/v1/login/github-auth,例如 /api/v1/login/github-auth/start;这些接口只在系统尚未创建用户时开放,初始化完成后返回 409,不应作为已初始化实例的未认证管理入口。

GITHUB_TOKEN 属于敏感运行时设置,通用环境设置接口只返回脱敏值。Agent Skill 只读取服务端 配置,不会要求用户在聊天中发送 Token 或密码。OAuth 与 PAT 实际能访问的仓库仍受 GitHub 账号和仓库策略限制。

客户端可发送 X-MoviePilot-Locale: zh-CN|zh-TW|en-US 或 Accept-Language。后端会按当前请求语言直接翻译顶层 message;未提供语言头时使用简体中文,翻译缺失时回退原文本。SSE 和业务数据中原有的 text_i18n、error_i18n 等展示字段继续保留。

GET /api/v1/login/wallpaper 会将壁纸 URL 放在 data 字段中。POST /api/v1/user/avatar/{user_id} 会以 data.filename 返回原始文件名。上述接口的 message 均不承载业务数据。

FastAPI 的 HTTP 异常和参数校验异常统一使用 message,不再返回顶层 detail / detail_i18n。

交互式接口文档 /docs(Swagger UI)和 /redoc 读取 /api/v1/openapi.json,页面版本号直接使用 version.py 中的后端 APP_VERSION。这三个地址默认关闭,返回 404;在系统设置「高级设置 → 实验室」中打开「开放 API 文档」(API_DOCS_ENABLE)后立即可用,无需重启。文档在首次访问时生成,之后会常驻约 20–30MB 内存;关闭开关后,下一次文档请求会释放缓存的文档,其余内部缓存在重启后释放。镜像内置的 nginx 只转发 /api 路径,/docs 和 /redoc 需要直接访问后端端口。

系统更新

系统 Release 更新采用“检查、后台下载、确认安装”三阶段流程,以下接口均要求超级管理员登录态。后台每 6 小时按独立开关检查更新:MOVIEPILOT_AUTO_UPDATE=true 检查稳定版 v3 GitHub Release,AUTO_UPDATE_RESOURCE=true 检查站点资源包,并分别提示升级。任一开关开启即启用定时服务;两者均关闭时移除定时服务并隐藏版本提醒。手动检查、下载和安装仍可用。独立布尔配置 MOVIEPILOT_UPDATE_DEV 控制启动时跟踪 Dev 分支;升级类型只有 application(主程序,前端版本由后端 Release 中的 version.py 决定)与 resources(认证资源和索引资源)。下载完成前不重启服务,安装接口只消费已下载并校验的完整制品,启动器会先应用主程序包,再应用资源包,之后才启动进程;启动后的初始化不会再次下载或触发资源重启。原 Dev 更新入口继续保留,但 /system/upgrade 只接受请求体 "dev",不再处理 Release 更新。

方法 路径 说明
GET /api/v1/system/update/status 查询聚合状态、实时提醒开关 auto_update / auto_update_resource 及 updates 中两类升级明细的 idle、available、downloading、ready、installing 或 failed 状态,以及版本、字节数和进度
POST /api/v1/system/update/check 立即检查最新稳定版 v3 Release 和当前平台站点资源包
POST /api/v1/system/update/download 请求体可传 {"target":"application"} 或 {"target":"resources"};后台下载并校验对应制品
POST /api/v1/system/update/install 请求体可传 {"target":"application"} 或 {"target":"resources"};再次校验对应制品,写入安装意图并重启
POST /api/v1/system/upgrade 保留 Dev 更新并重启,请求体只能为 "dev"

媒体识别 / 整理

媒体识别、搜索和手动整理统一使用 media_source + media_id 表示媒体主身份。内置来源通过 MediaSource 提供 themoviedb、douban、bangumi、anilist、imdb、tvdb、musicbrainz、theaudiodb、doubanmusic 九个具有宿主模块实现的常量;该列表不是插件来源白名单,插件可以注册符合 OpenAPI 格式约束的稳定扩展标识。media_id 是该来源的原生 ID,不添加 tmdb: 等前缀。需要精确身份时两个字段必须同时提供,不能只传其中一个。

媒体来源列表 /api/v1/media/source 仅预置上述九个来源,其余来源由启用插件注册后提供。哔哩哔哩、芒果 TV、咪咕视频、腾讯视频、爱奇艺不再占用内置来源标识,宿主也不再转换这些插件来源的旧别名;调用方应使用插件声明的准确来源 ID。

影视自动识别在未指定来源时只使用 TMDB,未命中时不会继续查询其它影视源。音乐路径识别严格按 AcoustID 音频指纹、文件标签、文件名三级依次执行;指纹或标签直接提供 MusicBrainz Recording ID 时,会直接查询 MusicBrainz 详情,未绑定身份的音乐标题及目录识别按 SEARCH_SOURCE 中内置音乐来源的配置顺序回退(MusicBrainz、TheAudioDB、豆瓣音乐),未选择音乐来源时兼容默认 MusicBrainz。显式 media_source / 主身份或 MusicBrainz 发行标签固定所属来源;来源之间不转换或拼接 ID。MediaInfo 响应仍可能包含 tmdb_id、douban_id、bangumi_id、anilist_id 等跨源映射辅助字段,但这些字段不是通用请求入口。明确归属 /tmdb、/douban、/bangumi、/anilist 的接口,以及固定使用 TMDB 的剧集组和排期接口,仍可按其单数据源契约接收原生 ID。

方法 路径 说明
GET /api/v1/media/search 按标题搜索媒体、合集、影视人物或音乐;人物结果可同时包含 MusicBrainz 艺术家,参数:title、type、page、count,可重复传入可选 media_source;未指定 music_type 时音乐搜索只返回单曲和专辑,显式 music_type 仍可用于专用实体选择;内置模块只处理自身支持的来源,插件模块可以处理其注册的扩展来源,旧客户端的逗号格式仅在输入边界兼容
GET /api/v1/media/recognize 识别标题,参数:title、subtitle、custom_words,可选 media_source;当 title 为含目录的媒体文件路径时,会合并父目录中的名称、年份等信息
GET /api/v1/media/recognize_file 识别文件路径,参数:path,可选 media_source
GET /api/v1/media/{media_id} 按原生 ID 查询影视或音乐详情;必填参数:media_source、type_name,其中 media_source 与路径中的 media_id 组成统一媒体身份,type_name 支持电影、电视剧和音乐
POST /api/v1/media/scrape/{storage} 刮削媒体元数据;请求体为 FileItem,可选查询参数 media_source、media_id、type_name(电影/电视剧/音乐)和 TMDB episode_group。剧集组用于指定电视剧的季集顺序;音乐会按策略处理音频标签、封面和歌词。会覆盖目标位置已有的图片、NFO 和音频标签,与文件管理、手动整理一样需要管理权限
POST /api/v1/transfer/manual/target-path 按源文件与目录配置匹配手动整理目标路径;请求体为 ManualTransferItem,该接口不执行媒体识别
POST /api/v1/transfer/manual/history 查询文件、批量文件或目录命中的成功整理历史摘要,用于进入手动整理界面时显示重新整理状态
POST /api/v1/transfer/manual 手动整理;请求体可用 media_source + media_id 指定本次识别与刮削数据源;logids 会先还原为同一个显式文件批次,多首音乐因而共享专辑识别上下文;音乐请求未传 music_type 时,目录按 album、文件按 recording 解释;使用 music_type=album 和 MusicBrainz 发行组 media_id 时,可另传 musicbrainz_release_id(Release UUID)明确选定发行版;后端核验该版属于该发行组,失败不改用默认版;GET /api/v1/music/album/{album_id} 接受同名可选查询参数用于预先核对该版曲目;预览与执行须保持相同 ID 和文件范围;可用最多三项的 music_release_regions(ISO 3166-1)和 music_release_scripts(ISO 15924)仅覆盖本次 MusicBrainz 发行版本排序,省略时继承系统设置;命中持久失败历史,且未指定媒体身份、未开启 reorganize 时,由调度器重试原计划(包括 logid 历史入口);显式重整先校验并放弃确定失败任务,再清理旧目标和记录;旧版失败历史仍清理后重试;reorganize=true 时清理命中的成功历史和非移动模式旧目标后重新整理
GET /api/v1/transfer/tasks/manual-reviews 管理员分页查询 durable 人工复核任务;state 仅允许 manual_review(默认)或已经人工判定、等待调度恢复的 retry_wait,支持 page 与 page_size。响应只公开任务、源文件、状态、步骤意图/证据/错误和复核修订号,不返回 lease 或 attempt 身份
GET /api/v1/transfer/tasks/{task_id}/manual-review 管理员查询单个 durable 人工复核任务详情;仅可读取 manual_review 或已经人工判定的 retry_wait 任务,其余状态按不存在处理
POST /api/v1/transfer/tasks/{task_id}/manual-review 管理员判定处于 manual_review 的 durable 整理步骤;请求包含 operation_id、`decision=not_applied

SMB 下载器监控与服务端整理

下载器原生保存路径与 MoviePilot 的存储访问路径是两个地址空间。下载器配置的 path_mapping 每项按 [存储路径, 下载器路径] 保存,例如 ["smb:/incoming", "/downloads"]:任务下发使用 /downloads,任务返回的 path、save_path、content_path 保留映射后的 smb: 前缀。本地路径仍不带前缀。 调用方不能把远程 URI 直接交给本地 Path.exists/stat。

例如下载器在 10.10.10.11,MoviePilot 在 10.10.10.10:配置 SMB 主机 10.10.10.11、共享 data;目录配置选择资源存储 smb、资源目录 /incoming、 监控方式 downloader、媒体库存储 smb、媒体库目录 /media;再配置上述下载器映射。 /incoming 和 /media 均相对于共享根目录,不是 MoviePilot 本地目录。 自动整理按存储和完整目录段匹配源文件,通过实际存储查询文件和目录;查询失败 与确认不存在分别记录,未入队任务保留给下一次监控重试。

SMB 配置支持两种明确的路径模式:旧字段 share: "data" 保持共享内路径; 新字段 shares: ["video", "downloads"] 使用虚拟根目录,路径首段为共享名称。 即使多共享模式只剩一项,也不会自动退回旧路径语义。所有共享使用同一主机、 账号和 SMB 服务;浏览 / 返回 /video/、/downloads/,只允许访问已配置的共享。 虚拟根和共享根不可删除、重命名;虚拟根不能作为媒体库目录,共享根(例如 /video)可以。 存储卡片和仪表板显示配置中首个共享报告的卷容量及当前账号可用空间,不累加其他共享。 多个共享可能共用存储池,SMB 卷序列号也不一定代表独立磁盘;若共享属于不同卷, 显示的是首项所在卷的容量,并非整台服务器的总容量。

对 10.10.10.11 的 downloads 和 video 共享,可选择源存储 smb、 源目录 /downloads,目标存储 smb、目标目录 /video/电影;下载器映射使用 ["smb:/downloads", "/downloads"]。切换新旧模式后须更新目录设置、下载器映射及 其他已保存路径;应先处理完旧路径的在途整理任务,不会自动重写历史任务。 若开启按媒体类型、类别自动建目录,媒体库根目录可设为 /video,由整理规则追加子目录。 同路径的远程监控目录收到缺少存储前缀的下载器路径时,日志会提示检查路径映射。

同一 SMB 服务内,copy 对共享内和跨共享文件都使用服务端 CopyChunk; move 在同一共享内使用重命名,跨共享使用服务端复制成功后删除源文件。 跨共享移动不是原子操作:复制失败不删源;删除失败时保留两份并报错;目标已存在 或查询状态不明时不启动复制,冲突由上层覆盖策略处理。中断后的不确定结果仍由 持久整理步骤核验,不能仅凭目标存在就认定复制成功。

link 仅支持同一共享内、同一文件系统且服务端支持硬链接的情况。SMB 标准接口 不支持跨共享硬链接;即使 video 与 downloads 位于同一磁盘,也不能绕过此限制。 需要硬链接时,可在服务端提供包含这两个目录的共同共享。 服务器不支持 CopyChunk 或权限不足时明确失败,所有上述操作都不回退本地下载再上传。 此保证不涉及显式下载或音乐内嵌标签写入等内容处理流程。

媒体自动分类

媒体预览应先通过媒体详情接口取得完整信息,避免将搜索摘要中缺失的字段误判为不匹配。媒体输入会按所选策略异步补充缺失信息;显式标准化事实按原值计算。近期历史影响分析只读取一次媒体详情,再分别按活动策略与候选策略补充信息和比较,无法读取详情的记录不视为未变化。

媒体自动分类使用完整、可版本化的策略作为唯一写入合同。先读取当前策略的 revision,再用字段目录中的稳定字段 ID 和操作符构造规则;发布和回滚均使用 expected_revision 做并发校验,成功后产生新的 revision。旧 /media/category 与 /media/category/config 只读投影仅为兼容客户端保留,不属于 Agent 的 operation。

方法 路径 说明
GET /api/v1/media/classification/fields 登录用户读取标准字段、操作符、通用选项、来源候选与策略限制
GET /api/v1/media/classification/policy 登录用户读取当前活动策略和 revision
POST /api/v1/media/classification/validate 超级管理员校验完整草稿,不保存
POST /api/v1/media/classification/preview 登录用户对完整媒体详情或标准化事实执行单次只读预览,可选草稿策略
POST /api/v1/media/classification/impact 超级管理员比较活动策略与草稿对近期历史或显式样本的有界影响
GET /api/v1/media/classification/history 超级管理员读取可回滚的有限历史版本
PUT /api/v1/media/classification/policy 超级管理员在 expected_revision 匹配时校验并发布完整策略,需要写操作确认
POST /api/v1/media/classification/rollback/{revision} 超级管理员将指定历史策略作为新版本发布,需要当前 expected_revision 和写操作确认

transfer/manual 在 preview=true 时保留预览的 summary/items/message,不返回执行状态。 预览项新增可选 source_storage/source_item/music。source_item 保留本次源文件的存储标识, 不包含下载 URL、缩略图和递归子节点;纠正时可复用实际选中文件,不能根据目录名扩大范围。 音乐 music.status 区分 local_tags(可信标签)、local_cue(本地 CUE)、 matched(在线已确认)、manual(本次或已记录的人工选择)、metadata(已有信息但没有在线核验证据)、 not_found、ambiguous、conflict、service_error、budget_exhausted、unsupported。 它与预览项 success 独立:已确认身份仍可能因目标目录或分类失败;仅标签含 MBID 不算在线确认。 online_confirmed 仅在 matched 时为真。field_sources 表明曲名、专辑、艺人、曲序等字段的实际来源, candidates 最多五条,只保留身份及展示摘要,不把评分显示为置信概率。 read_status 区分 tags/stream_only/unreadable/name_only/companion/unknown: 无标签、读取失败及仅有远端名称证据不是同一种状态。 group_id/group_directory/group_size 由本次实际发行分组生成(数量为音频成员数), CUE 和歌词通过 file_role=companion 与音频共享组;同目录不同发行以及不同存储不混组。 该分组只供当前已预览文件聚合,不是访问凭证、数据库身份或展开目录的授权; 按组纠正必须只提交该组已预览的 source_item,并重新预览,不能把选定专辑应用到整包其它发行。 尚未解包或提取的音乐包返回逐文件 unsupported,计入失败统计,不再仅在批次总提示中出现。 请求可传入 skip_success=true,在预览与执行中跳过同存储、同源路径已成功整理的文件, 也识别成功移动后的目标现址。该选项优先于 reorganize 和历史入口的强制整理, 不清理被跳过文件的历史和旧目标;失败记录及未处理文件继续原有流程,默认 false 保持现有行为。 被跳过文件不进入预览列表;全部跳过时返回空列表、零计数和跳过数量提示。 实际提交返回独立的 data.items 回执,即使批次 success=false 也保留其他文件的结果。 每项包含 source/target/target_dir/success/message/failure_stage/recovery_action/overwrite_skipped/state; state=accepted 仅表示已接收,retry_wait 表示原计划已交给后台恢复,均不代表入库。 仅 completed 表示执行和终态原子结算已确认;failed 表示本次失败,skipped 表示历史、模板或覆盖策略跳过。 manual_review 表示等待人工复核,应先在整理队列中确认执行结果,不能自动重提。 success 表示本次操作被接收或完成,不能代替 state 判断入库;客户端不得在部分接收后原样重提整个批次。

站点

方法 路径 说明
GET /api/v1/site/media/{media_type} 按媒体类型查询已配置且启用的可搜索站点;media_type 支持 movie、tv、music 或对应中文类型,音乐仅返回明确声明音乐能力的站点,影视不返回纯音乐站点

搜索 / 种子 / 字幕

方法 路径 说明
GET /api/v1/search/media/{media_id} 按统一媒体身份搜索站点种子资源;必填参数:media_source,其它参数:mtype、area、season、sites、music_type、include_candidates
GET /api/v1/search/media/{media_id}/stream 按统一媒体身份渐进式搜索站点种子资源,返回 SSE,参数同上
GET /api/v1/search/title 按关键字模糊搜索站点种子资源,参数:keyword、page、sites,可选 mtype=音乐 仅搜索音乐分类
GET /api/v1/search/title/stream 按关键字渐进式搜索站点种子资源,返回 SSE,参数:keyword、page、sites,可选 mtype=音乐
GET /api/v1/search/subtitle/title 按关键字搜索站点字幕资源,参数:keyword、page、sites
GET /api/v1/search/subtitle/title/stream 按关键字渐进式搜索站点字幕资源,返回 SSE,参数:keyword、page、sites
GET /api/v1/search/subtitle/media/{media_id} 按统一媒体身份精确搜索站点字幕资源;必填参数:media_source,其它参数:mtype、season、episode、sites
GET /api/v1/search/subtitle/media/{media_id}/stream 按统一媒体身份渐进式精确搜索站点字幕资源,返回 SSE,参数同上
GET /api/v1/search/last 获取上一次种子搜索结果
GET /api/v1/search/last/context 获取上一次搜索结果及可复用搜索参数,params.result_type 为 torrent 或 subtitle
POST /api/v1/search/recommend 获取 AI 推荐资源,请求体:filtered_indices、check_only、force

渐进式搜索在无业务事件时每 15 秒发送 {"type":"heartbeat"},客户端应将其仅用于连接保活。超过 48 条的最终 replace 会分批发送:首批 type=replace,后续批次 type=append,所有批次均带 replace_batch=true、从 0 开始的 batch_index、batch_count 和最终 total_items;客户端必须按顺序收齐后再原子替换结果。最终 done 在已发送 replace 后不重复携带 items。

AniList 榜单 / 探索

AniList 榜单、探索、详情、人物和推荐接口优先通过 anilist-chinese 代理查询。代理不可用时自动回退 AniList 官方 GraphQL,并合并 anilist-chinese 每日数据集;媒体标题优先使用项目提供的中文标题,未提供中文标题时回退 AniList 原语言标题。

方法 路径 说明
GET /api/v1/anilist/trending 查询 TRENDING NOW 榜单,参数:page、count
GET /api/v1/anilist/popular-this-season 查询 POPULAR THIS SEASON 榜单,参数:page、count
GET /api/v1/anilist/discover 组合探索动画,参数:search、genre、format、season、season_year、status、country、sort、page、count
GET /api/v1/anilist/{anilist_id} 查询动画详情
GET /api/v1/anilist/credits/{anilist_id} 查询日语配音演员,参数:page、count
GET /api/v1/anilist/recommend/{anilist_id} 查询相关推荐,参数:page、count
GET /api/v1/anilist/person/{person_id} 查询人物详情
GET /api/v1/anilist/person/credits/{person_id} 查询人物参与的动画作品,参数:page、count

音乐元数据 / 推荐 / 探索

音乐元数据使用 MusicMeta / MusicInfo 独立模型。music_type=recording 表示单曲,album 表示包含多首曲目的完整专辑,artist 仅用于浏览;稳定身份分别使用对应的 musicbrainz:<mbid>。单曲和专辑可进入搜索、订阅、下载、整理、刮削和已配置音乐媒体服务器的入库检查,艺术家不能作为订阅或下载目标。

音乐与影视共用媒体搜索、资源查询、过滤、匹配和订阅搜索编排。资源 meta_info 来自 标题、副标题的实际解析,不用目标媒体回填证据;title_aliases、album_aliases、 artist_aliases 分别保留同一实体的可信别名及展示转简体前的原文。

MUSIC_METADATA_TO_SIMPLIFIED 同样适用于同步/异步专辑详情及其逐曲文本, 也适用于音乐整理最终命名:完整本地标签、手选专辑发行版和手选录音均按开关转换。 转换不改写原始音频标签、来源缓存、歌词或媒体身份;关闭开关保留原文。 录音身份不等同于专辑发行身份,单曲仍保留已有的本地专辑字段优先级; 多艺人署名完整保留,不自动截取第一位艺人。

音乐元数据、单曲和专辑模型还分别保留 composers、conductors、orchestras 人名列表, 以及 performers 乐器/声部到人名列表的映射(未指定乐器使用 performer 键)。 这些字段不会混入主艺人或艺人别名;空字段在简化卡片中省略,完整模型与旧缓存兼容。 明确的 PT 副标题角色和原生标签可提供本地证据,完整标签仍可直接整理。 MusicBrainz 从实际 Recording/Work 关系补充角色,不凭作品名推断演奏者; 角色摘要不足时每批最多补查三个录音详情,沿用已有 HTTP 预算和缓存。 自动识别拒绝已知阵容冲突,仅有作曲家相同不足以确认录音;明确录音/发行 ID 可补足缺失关系, 但不能覆盖已知冲突。整专可用实际逐曲关系核验阵容,不把专辑或某一曲的角色广播到其他曲目。

角色标签使用 ID3 的 TCOM/TPE3/TMCL(兼容 v2.3 IPLS)、Vorbis/APEv2 文本字段, 以及 MP4 的 ©wrt 和 CONDUCTOR freeform。独立 ORCHESTRA 和 MP4 PERFORMER 为兼容自定义字段, 并非所有播放器都支持;制作人不会被当作演奏者。映射参照 Picard 标签对照。 音乐资源解析同样应用全局或订阅自定义识别词,MusicMeta.apply_words 返回实际应用记录, 旧结果缺少该字段时按空列表处理。副标题的明确录音版本参与匹配;单曲所属专辑字段 不能证明资源覆盖整张专辑,无曲序的单曲也会标记为 partial_album 待确认项。 这些名称、艺名和版本规则也适用于显式选择的 TheAudioDB 与豆瓣音乐;查询专辑或确认 单曲所属专辑时优先使用专辑艺人,不能覆盖单曲的表演者。版本字段中双方明确且唯一的 年份、录制日期冲突会使资源进入 version_mismatch 待确认项,缺少日期不单独造成淘汰。

音乐资源搜索及对应 SSE 接口默认只返回精确匹配。手动调用可传 include_candidates=true, 额外返回待确认资源及关联专辑:match_status=candidate、match_reason 描述原因, 且 media_info 为空、不绑定目标 ID;精确结果为 match_status=exact。自动订阅和批量下载 不采用待确认项。单曲的关联专辑不代表已经确认包含该单曲;专辑资源可以先下载,订阅会累计其中可识别的独立曲目并在全部曲目收齐后完成。 SSE 的 candidate_items 是站点原始返回数量,match_counts 记录身份、分类及规则淘汰原因。 只有完整过滤后还有精确结果时才会按多名称设置提前停止;音乐元数据多来源结果先各自去重再公平合并。

音乐识别结果同时提供 audio_format、audio_lossless、audio_quality、bit_depth、sample_rate、bitrate、audio_specs 和 audio_quality_score。本地文件识别读取实际音频流参数,并使用 Chromaprint 的 fpcalc 在本地生成指纹后查询 AcoustID;音频文件本身不会上传。站点资源识别从标题和描述提取声明参数;码率、采样率的存储单位分别为 bps 和 Hz。

原生 AcoustID 识别会核验最多五个 Recording 候选,以实际时长、有效曲名、艺人和版本排除冲突。 唯一高分且时长吻合的指纹可补齐无标签或纯编号文件;Unknown Artist 等占位不是艺人冲突。 真实数字歌曲标签仍可整理,01、Track 01 等抓轨占位不会仅凭完整字段认定为可信歌曲。 近分歧义或候选被截断时保留 raw_data.recognition.status=ambiguous,不能由返回顺序自动选中。 原生指纹命中的诊断含 method=fingerprint、identity_type=recording、release_verified=false; 指纹不证明实际发行,补充发行 ID 只保留实际标签提供的值,album_id 只沿用标签发行组 ID。 旧插件的单 ID 接口保持兼容,不人为添加 AcoustID 分数或降低其文本核验要求。 指纹生成和候选详情共用最多 90 秒、16 次 HTTP 尝试的预算;嵌套调用服从已有更早的预算。 指纹缓存保留全部候选,成功、无匹配、临时故障分别在 3600、300、15 秒后过期。

MusicMeta.music_type 保留已绑定主身份的实体类型;仅从名称推测时可为空。 MusicMeta.album_type 和 secondary_types 保留标签声明的发行主副类型,例如 EP、Single、Compilation; 它们与 recording/album/artist 实体类型不同,不能根据曲目数量覆盖明确的标签类型。 media_source、media_id 与 music_type 必须一起解释,不能把专辑 ID 当作 Recording ID。 补充字段 musicbrainz_release_id、musicbrainz_release_group_id、musicbrainz_release_track_id 分别表示具体发行、发行组和发行中的曲目,不能替代主身份。original_year 与 release_year 分别保留原始发行年份和当前发行年份,year 继续用于兼容展示;发行组尚未选定具体 Release 时 不能凭首发年份填充 release_year。total_discs 保留真实碟数。 field_sources 按字段记录 tag、album_tags、stream、filename、directory、torrent、 remote 或 manual 等来源,缺失表示来源未记录;该说明不等于远端身份已验证,也不用于绕过整理准入。

MUSIC_CUE_ENABLE 默认开启,可在“设置 → 系统 → 高级设置 → 媒体 → 音乐 CUE 识别”关闭。 已分轨专辑附带错误 CUE 时,关闭后重新预览或重新提交整理,系统只按音频标签和文件名识别, 不读取、校验或自动归档 CUE。此全局开关同时适用于自动整理、手动预览和实际整理, 切换后不会复用另一种模式的专辑识别缓存;已经生成的整理计划不会自动改写。整轨专辑应保持开启。

开启时,有效 CUE 可补充专辑和逐轨信息,相关字段来源为 cue。music_layout=image_cue 表示 一个音频文件包含多个逻辑音轨,music_type=album,不使用开头的 Recording 指纹替代整张专辑。 整轨归档会保留音频及 cue_filename 的原名,只规范专辑目录,避免破坏 FILE 引用;不自动切轨。 cue_tracks 保留逻辑曲目及每秒 75 帧的索引。tracks_cue 的分轨索引仅辅助元数据, 原 CUE 不随改名自动复制。绝对/跨目录引用、冲突索引、超出音频时长等问题通过 organization_error 返回,并在实际文件操作前阻止整理;原始文件内容不被修改。

音乐刮削补写标签或内嵌封面时,如果本地目标是硬链接或软链接,会先写入独立副本, 全部成功后原子替换目标;源文件字节与权限保持不变。实际发生写入后,目标成为普通文件, 会独立占用磁盘空间。未发生标签变化且没有其它写入时保留原链接;跳过标签及封面可保持链接整理。 写入失败或目标在处理期间改变时,丢弃临时副本,不覆盖原目标。LRC 与 Lyricsfile 旁挂也按目录项原子替换。 WAV、DSF、AIFF、DSDIFF 和 MP3 使用原生 ID3 帧,MP4/M4A 使用标准 atom 及文本 freeform;无标签音频可直接补写, 错误扩展名按实际容器处理。Recording、Release、Release Group、Release Track ID 分别写入专用标签; 仅有首发年份时只写原始年份标签,不能据此生成当前发行日期;已有同年的完整日期不因模型只携带年份而截断。 APEv2 按标准标签映射 使用下划线形式的 MusicBrainz 字段和 Originalyear,不套用 ID3 的带空格描述;读取仍兼容旧字段别名。 WMA/ASF 使用 Title、Author、WM/AlbumTitle、WM/PartOfSet、MusicBrainz/* 等原生属性, 兼容旧版小写字段;标准 WM/TrackNumber 从 1 开始,旧 WM/Track 从 0 开始。 WM/Lyrics 可读取纯文本歌词,WM/Picture 可补写封面,沿用相同的链接隔离与覆盖策略。 WMA Lossless 只由实际 Codec List 类型确认,不从高码率或扩展名猜测,未提供的位深保持未知。 独立乐团/演奏者字段 WM/Orchestra、WM/Performer 为自定义兼容属性。 等价的组合/独立曲数标签不会触发音频复制;曲数、碟数和更精确的原有日期保持有效。

音乐整理按每个文件的 storage 决定证据来源:远端仅使用名称、目录和原始种子线索, 不读取本机同路径的标签、时长或 CUE。仅有 .m4a 扩展名时不声明 AAC/ALAC 或有损/无损。 明确按音乐整理的镜像(如 ISO)及压缩包会返回先提取/解压的失败提示,不执行自动转换。 明确按影视整理的附加音轨不继承旧音乐历史身份。

专辑曲目按身份、曲名、碟号/曲序与时长的唯一证据对位,不按文件排序补齐未匹配曲目。 编号文件名可由位置或唯一时长补全,真实标签中的数字曲名仍作为名称证据。 重复版本、同分候选和明显时长冲突保留未匹配;手选发行允许按唯一位置纠正旧曲名, 但不绕过时长冲突。手选批次不能完整对位时会在文件操作前返回核对提示。

目录匹配优先直查明确的 musicbrainz_release_id,musicbrainz_release_group_id 只约束发行搜索。 普通 Music/inbox 等目录名不作为专辑名;真实标签或种子明确给出的同名作品仍可搜索。 曲名反查使用 MusicBrainz 的 Recording 搜索及其关联发行;Release 搜索不支持 recording 字段。 同等搜索相关度优先检查被多首录音共同命中的发行,避免单曲的多个版本占满候选预算。 候选必须覆盖全部本地逻辑曲目;部分下载不要求覆盖远端专辑的全部歌曲。 身份、当前发行年和明确艺人冲突不能靠其它分数抵消;原始年份只辅助排名。 不同录音序列的近分候选不自动采用,同发行组且录音序列相同的地区/文字版本沿用用户偏好。 匹配成功时 raw_data.match_score 是 0–100 的排序分数,不是概率;match_coverage=1 仅表示当前输入文件全覆盖。 整轨 CUE 以逻辑歌曲数和相邻索引时长参与匹配,返回仍为物理文件的专辑身份;修改 CUE 会使目录缓存失效。

每个来源最多 8 次 HTTP 尝试、45 秒,最多回退三个内置来源(总上限 24 次、135 秒);已有更小的外层预算继续生效,切换来源不能恢复额度。HTTP 缓存命中不消耗请求额度。来源故障允许尝试下一来源,歧义或证据冲突立即停止。 TheAudioDB 和豆瓣音乐的正常无匹配 HTTP 响应缓存五分钟,网络故障、非法响应和预算耗尽不缓存为空。 MusicBrainz 和 TheAudioDB 对标题、版本及年份仍合理但艺人名称不一致的候选,按来源返回的真实 Artist ID 补充别名;每批最多查询三个去重身份,沿用当前请求预算和缓存。带声调、空格的拼音可通过来源别名确认,不从拼音猜测艺人身份。别名只追加到 artist_aliases,不修改 artists、artist_ids 或主身份;整专详情只继承同来源、同 Artist ID 的已核实别名,合辑中其他艺人不会继承专辑署名。不同实体同分或共享同一 ISRC 仍保留歧义。 次级来源整专识别必须取得完整曲目表并唯一对位当前全部文件;普通专辑目录不证明具体发行,返回 identity_type=album、release_verified=false,保留本地碟号、曲序、总数、当前发行年和首发年。配置来源顺序也参与目录缓存键。 无匹配与服务故障分开处理:目录成功结果缓存一小时,无匹配缓存五分钟,服务故障仅冷却十五秒; 无身份的 MusicBrainz 元数据负缓存最多五分钟,连接失败或预算耗尽不写成这种负缓存。 MusicInfo.raw_data.recognition 可携带 status、message、requests、candidates 诊断;多来源回退还包含 sources 数组,各项含 source 及该来源自己的诊断和请求数。 ambiguous、conflict、service_error、budget_exhausted 均不能冒充远端匹配成功;整理规划遇到这些状态时停止文件操作, 歧义不再回退为逐曲猜测。目录结果在 Python 调用方中保持字典兼容,并额外保留 recognition 属性。 音乐缓存删除/清空同时清理来源响应及目录状态;刷新前进行中的目录查询不能回填刷新后的缓存。 同一整理批次复用有界只读音频/CUE快照;文件指纹变化、批次退出都会失效,不缓存可写音频对象。

尚未生成文件计划的 service_error / budget_exhausted 会保留持久准入,30秒后重新识别, 重试上限沿用整理失败重试策略。恢复读取最初选中的发行范围和发行偏好,不能直接复用旧失败媒体信息。 预算耗尽后正常记录失败;手动重试已结算的零文件操作音乐拒绝,可在事务中创建新的识别任务, 原失败历史及结算回执保留。任何带文件操作、兼容 provider 操作或不确定证据的计划继续原有执行重放,不能自动重规划目标。 这个等待状态表示任务仍在处理中,不能作为文件整理完成的证据。

方法 路径 说明
GET /api/v1/media/search 当 type=music 或指定音乐 media_source 时按歌曲或专辑关键词搜索音乐元数据;艺术家统一由 type=person 搜索,支持 TMDB 与 MusicBrainz 来源。参数:title、type、count、可重复的 media_source 枚举,以及可选的 music_type 实体过滤
POST /api/v1/music/recognize 按 media_source + media_id 识别音乐详情,请求体:MusicRecognizeRequest
GET /api/v1/music/explore 按来源浏览音乐;media_source=musicbrainz 支持 `mode=chart
POST /api/v1/music/library/status 按 MusicBrainz、TheAudioDB 或豆瓣音乐的稳定专辑 ID 批量查询媒体库是否已存在;请求体为 items 专辑列表,返回对应的 exists 状态,供艺人作品资源矩阵默认排除已入库项目
GET /api/v1/music/album/{album_id} 按来源专辑 ID 查询专辑详情、完整曲目和发行版本,参数:media_source
GET /api/v1/music/album/{album_id}/related 按来源查询关联专辑,参数:media_source、count
GET /api/v1/music/artist/{artist_id} 查询艺术家详情;艺术家为只读浏览实体,参数:media_source
GET /api/v1/music/artist/{artist_id}/albums 分页查询艺术家的专辑、EP 和单曲,参数:media_source、page、count、album_type
GET /api/v1/music/artist/{artist_id}/related 查询关联艺术家,参数:media_source、count
GET /api/v1/recommend/music_weekly 浏览本周热门音乐,参数:page、count
GET /api/v1/recommend/music_douban 浏览豆瓣音乐新碟榜,参数:page、count

专辑下载与订阅按“累计曲目”处理:下载层读取种子文件清单并记录可识别的独立音轨,允许不完整资源先进入下载;活动订阅跨轮次合并去重,API 返回 completed_tracks,达到 total_tracks 后才完成订阅。媒体库完整性检查仍要求本地专辑具备完整曲目。音乐整理会迁移与音轨同目录、同主干名的 .lrc、.txt 和 .lyricsfile.yaml 旁挂歌词。音乐刮削默认使用“质量升级”策略:先读取已有旁挂和 MP3/FLAC/Ogg/MP4 内嵌歌词,再聚合插件、LRCLIB、AMLL TTML 和 TheAudioDB 纯文本候选;逐字 Lyricsfile、逐行同步 LRC、纯文本依次降级,任何覆盖入口都不会用低质量结果替换高质量歌词。Lyricsfile 会保留为 .lyricsfile.yaml,同时生成播放器兼容的 .lrc。

AMLL 使用无需鉴权的原生搜索与获取接口,先尝试 ISRC,再核对完整曲名、艺术家和已有专辑;搜索最多读取 20 项并下载 3 个匹配候选。TTML 只转换主唱内容,排除翻译、音译和背景人声;可靠的逐词或逐行时轴会保留,缺乏完整行时轴时降为纯文本。AMLL_BASE_URL 可配置兼容实例地址,网络超时为 10 秒,限流时进入最多 300 秒的有界冷却。动态搜索和 ISRC 查询缓存 1 小时,固定 ID 歌词缓存 7 天,未命中缓存 5 分钟。接口与格式依据见 AMLL HTTP API。

插件可通过 get_module() 注册 music_lyrics_candidates(music),负责匹配并下载歌词内容,返回 list[MusicLyrics] 参与宿主择优;MetaMusic、MusicInfo 和 MusicLyrics 均可从 app.sdk.media 导入。该接口不需要注册 HTTP 路由,歌词文件仍由刮削链统一写入。完整契约和示例见歌词插件开发说明。

音乐订阅可使用 audio_quality=hires|lossless|lossy(支持正则组合)、audio_format、min_bitrate、min_bit_depth、min_sample_rate 过滤资源。best_version=1 开启音质洗版,系统按格式、无损属性、位深、采样率和码率换算 0-100 优先级,只下载高于 current_priority 的候选;DSD 或 24-bit/192 kHz 无损资源达到终态 100。内置规则 HIRES、LOSSLESS、FLAC、ALAC、APE、WAV、DSD、MP3、AAC、OPUS、BITRATE320、BITRATE256、BITRATE192 可用于自定义过滤规则组。

下载

方法 路径 说明
GET /api/v1/download/ 查询正在下载的任务,参数:name;关联下载历史时返回媒体类型、来源站点 site_name,以及 media.poster 海报和 media.backdrop 背景图;兼容字段 media.image 与 media.poster 相同
POST /api/v1/download/ 添加含媒体信息的下载任务,请求体包含媒体信息和种子信息
POST /api/v1/download/add 添加不含媒体信息的下载任务,请求体包含 torrent_in,可选且必须成对提供 media_source + media_id,并支持 music_type、downloader、save_path;影视或音乐识别失败时统一响应 data.requires_confirmation=true,用户确认后可用 allow_unrecognized=true 重试本次下载
POST /api/v1/download/subtitle 下载字幕到识别出的媒体下载目录,请求体包含 subtitle_in,并必须提供 media_source + media_id;可选 save_path
GET /api/v1/download/start/{hashString} 恢复下载任务,参数:name
GET /api/v1/download/stop/{hashString} 暂停下载任务,参数:name
PATCH /api/v1/download/{hashString} 高级更新下载任务,可修改限速、标签、Tracker、保存目录和下载器分类
POST /api/v1/download/{hashString}/classify-source recognize 模式重新识别媒体并按当前生效分类计算保存位置,manual 模式使用明确目标目录;execute=false 只预览,execute=true 由下载器移动任务数据;可传当前策略中已启用的 media_category 路径覆盖自动分类
GET /api/v1/download/clients 查询可用下载器
GET /api/v1/download/paths 查询可用于下载接口 save_path 参数的下载路径
DELETE /api/v1/download/{hashString} 删除下载任务,参数:name

资源目录重新分类只接受仍存在于下载器且具有可恢复媒体类型的下载历史任务;识别模式可复用历史中的媒体来源和同来源媒体 ID,也可在请求中指定来源、媒体 ID 或当前策略中已启用且媒体类型匹配的 media_category。 目标路径必须落在已配置的资源根目录内,并且目录需开启“资源目录按类别分类”或绑定固定分类。 识别模式会优先使用媒体识别链产生的当前生效分类路径;例如 MusicBrainz 返回 Album 主类型和 Compilation 副类型并命中默认精选集规则时,目标分类为 Album/Compilation。识别结果尚无可用分类路径时,音乐兼容退回主类型目录。 执行时 MoviePilot 调用下载器的位置更新能力,不直接移动或改写 PT 数据文件。

历史

方法 路径 说明
GET /api/v1/history/download 按下载时间倒序查询下载历史,参数:page、count;poster 为海报,兼容字段 image 为背景图
DELETE /api/v1/history/download 删除下载历史,请求体为下载历史记录

系统

方法 路径 说明
GET /api/v1/system/ping 登录用户服务存活检测,用于前端重启后轮询恢复状态
GET /api/v1/dashboard/system 查询仪表板系统摘要,包括主机名称、操作系统、MoviePilot 运行时间和后端版本
GET /api/v1/dashboard/schedule 查询所有后台定时服务,包含当前完成百分比、进度文本和执行状态
GET /api/v1/dashboard/schedule/{job_id}/progress 查询指定后台定时服务的实时进度详情
GET /api/v1/dashboard/schedule2/{job_id}/progress 使用 API_TOKEN 查询指定后台定时服务的实时进度详情
GET /api/v1/system/setting/public/{key} 登录用户读取白名单内非敏感系统设置,仅支持目录、存储、站点范围、默认订阅规则、Follow 订阅者和插件市场地址等前端必需配置;存储只返回 name 和 type,与 /api/v1/storage/options 一致,不含连接配置
POST /api/v1/system/setting/PLUGIN_MARKET/sync-wiki 管理员从 MoviePilot Wiki 的插件文档同步公开插件仓库清单,和本地 PLUGIN_MARKET 合并去重后写入配置
GET /api/v1/system/module-catalog 查询宿主模块及其服务类型目录,供前端选择器构造选项
GET /api/v1/system/modulelist 查询已启用模块,保留 name 原始中文字段,并提供 name_i18n 和 name_key 给多语言前端展示
GET /api/v1/system/module-settings 管理员查询没有其它激活配置、可由用户统一开关的内置模块
GET /api/v1/system/moduletest/{moduleid} 测试指定模块可用性,标准响应的 message 会按请求语言直接返回翻译文本
GET /api/v1/message/agent/mcp/servers 管理员查询 Agent 外部 MCP 服务器配置
POST /api/v1/message/agent/mcp/servers 管理员保存 Agent 外部 MCP 服务器配置
POST /api/v1/message/agent/mcp/servers/test 管理员测试单个 Agent 外部 MCP 服务器并读取工具列表

缓存管理

以下接口使用登录态鉴权,并要求当前用户为超级管理员。

方法 路径 说明
GET /api/v1/tmdb/cache media.cache.get:查询 TheMovieDb 识别缓存统计、共享识别累计成功命中次数及开关状态
DELETE /api/v1/tmdb/cache/{cache_key} media.cache.delete:按缓存键删除单条 TheMovieDb 识别缓存,缓存键需要进行 URL 编码
DELETE /api/v1/tmdb/cache media.cache.clear:清空全部 TheMovieDb 识别缓存
GET /api/v1/music/cache music.cache.get:查询 MusicBrainz 音乐识别缓存统计及条目列表
DELETE /api/v1/music/cache/{cache_key} music.cache.delete:按缓存键删除单条音乐识别缓存,缓存键需要进行 URL 编码
DELETE /api/v1/music/cache music.cache.clear:清空全部音乐识别缓存

TMDB 缓存查询响应的 data 包含 count、recognized、unrecognized、data,以及共享识别统计字段 shared_recognized 和开关字段 shared_recognize_enabled。共享命中次数仅在共享结果驱动的二次媒体识别成功后累计。

音乐识别缓存查询响应的 data 包含 count、recognized、unrecognized 和 data;条目字段包括缓存键、media_id、title、artists、album、year、music_type 和 cover_url。未携带远端身份的兜底负缓存仅保留在内存,不参与持久化。 缓存键为不透明值,管理调用必须使用查询返回的原始键,不自行拼接。识别缓存按请求的 单曲、专辑或未限定实体范围隔离,版本及 ISRC 不同的文本识别请求也不会共用结果; 旧版未包含这些证据的派生缓存在升级后重新建立,不影响下载历史或订阅数据。 名称确认规则更新时同样重建旧派生缓存,避免艺术家前后缀误截断的旧结果继续命中。

订阅搜索执行批次

订阅搜索会持久化为可恢复的执行批次,Agent 可以使用以下 moviepilot_api operation 查询或停止当前用户可见的批次:

Operation 方法 路径 说明
subscription.execution.list GET /api/v1/subscribe/execution/batches 查询最近的订阅搜索批次,limit 默认 10
subscription.execution.get GET /api/v1/subscribe/execution/batches/{batch_id} 查询一个批次的状态、进度、恢复信息和最终结果
subscription.execution.cancel PUT /api/v1/subscribe/execution/batches/{batch_id}/cancel 在下载副作用边界前请求取消一个批次

取消是幂等的状态请求,不会撤销已经提交到下载器的任务;批次详情中的状态和任务结果才是最终事实。

跨来源订阅回显

GET /api/v1/subscribe/media/{media_id} 先按 media_source、media_id 和可选季号查询当前用户可访问的订阅。 影视身份未命中且提供 mtype、title 时,会按类型、规范标题和可选季号跨来源查找; 有年份时优先精确年份,其次匹配订阅年份为空的未定档媒体;没有年份时只匹配年份也为空的订阅。 音乐订阅始终只按媒体身份查询。

订阅可选设置清空

PUT /api/v1/subscribe/(subscription.update)只更新显式提交的字段,省略字段保留原值。 custom_words、keyword、save_path、episode_group、downloader、 min_bitrate、min_bit_depth、min_sample_rate 与筛选字段 filter、include、exclude、quality、resolution、effect、audio_quality、audio_format 均可通过 null 清空,也兼容表单提交的空字符串 "";清空会实际覆盖数据库旧值。 非空字符串不自动裁剪,数值 0 保留。此规则不扩展到名称、类型、季号、总集数等字段, 媒体身份仍要求 media_source 与 media_id 成对提交。

单条订阅搜索周期

POST /api/v1/subscribe/ 和 PUT /api/v1/subscribe/ 支持 search_interval: 取值为 1–8760 的整数小时数,null 表示跟随系统的 SUBSCRIBE_SEARCH_INTERVAL。 更新时省略该字段保留原值,显式传入 null 恢复系统周期。默认订阅规则同样可保存此字段。

仅在启用 SUBSCRIBE_SEARCH 时执行定时搜索,每五分钟检查到期订阅,再通过原有搜索队列和站点限流执行; 实际开始时间可能因站点忙而延后。last_search 为系统维护的 UTC 搜索尝试开始时间,重启后仍有效,公共写接口忽略它。 旧订阅尚无搜索时间时,以添加时间计算到期。新订阅首次搜索、手动搜索和 RSS 刷新不受周期过滤影响; 手动主动搜索会更新最近搜索时间。电影、电视剧和音乐均支持独立周期。

自动批次只在启动时随机错峰 0–60 秒,不再按订阅数量累加分钟级等待;同站点访问间隔、唯一在途租约和错误冷却继续生效。 站点暂不可用时,任务保存未完成站点并按 next_run_at 恢复,不重复查询已完成站点或插件源;队列和站点游标可跨重启恢复。 waiting_site_budget 表示可恢复等待,error 中的“等待站点”或“站点冷却中”是原因提示,不表示搜索失败;重新执行时清除旧提示。 卡片应按 state / phase 展示简短标签,原因放入详情提示。恢复调度每 10 秒检查空闲消费者,长搜索由调度器持续托管。 实际吞吐仍受站点访问限制和网络响应时间影响,配置周期不是全部站点必须完成的截止时间。

插件补充接口

GET /api/v1/plugin/history/{plugin_id}

按需读取指定已安装插件的最新远端更新说明。该接口用于前端在用户点击“查看更新说明”时再实时访问插件仓库,避免加载已安装插件列表时批量请求网络。

GET /api/v1/plugin/rating?plugin_ids={plugin_id,...}

批量查询插件平均分、评分人数和当前安装实例评分。plugin_ids 省略时查询中心端已有的全部插件评分。

GET /api/v1/plugin/rating/{plugin_id}

查询单个插件平均分、评分人数和当前安装实例评分。中心端暂不可用时返回该插件的零评分结果。

POST /api/v1/plugin/rating/{plugin_id}

为已安装插件提交当前安装实例评分,请求体为 {"rating": 4.5}。评分范围为 0.1 至 5.0,精确到 0.1;同一安装实例再次提交会更新原评分。

1. 列出所有工具

GET /api/v1/mcp/tools

获取所有可用的MCP工具列表。

MCP、HTTP 工具管理接口、本地 CLI 和内置 Agent 都从同一严格目录生成工具列表。 旧业务工具名不再注册,也没有 MCP 别名或兼容目录;例如 search_media、add_subscribe、query_download_tasks、query_schedulers 会直接返回工具不存在。插件工具仍由插件的 get_agent_tools() 动态声明,重名会让目录 构造失败,不采用 first-wins 覆盖。

固定目录按职责收敛为:

工具 说明
moviepilot_api 通过固定 operation_id 调用受控 MoviePilot 业务 API;不接受 URL、HTTP method、认证头或 Token
agent_task 通过 `action=create
persona 通过 `action=list
send_message、send_local_file 当前目录中可用的消息和文件发送能力;实际渠道能力仍由运行时校验
browse_webpage、recognize_captcha 浏览和验证码等非 MoviePilot 业务 API 能力
query_doctor_report 只读系统诊断

read_skill、read_file、write_file、edit_file、apply_patch、execute_command、 search_web 和 view_image 不通过 MCP 暴露。隐藏列表只负责收敛接口暴露面,不替代各工具自身的 权限、路径和网络边界。

browse_webpage(action="screenshot") 的外部直调仍返回 JSON 字符串,保留 url/title/screenshot_base64/format/note 并用 success/execution_outcome 明确状态。 内置 Agent 在专用格式化路径把成功截图转换为图像输入,外部 HTTP/MCP 客户端仍按 原 JSON 合同消费;本次不宣称外部 MCP 已提供原生 image content block。 screenshot 可选传入 selector,在原浏览器会话中截取唯一匹配的可见元素;省略时仍截取 当前视口。两种截图遵守相同的格式、字节和像素上限,元素不存在或匹配多个时返回失败。 recognize_captcha 的成功字段保持不变;OCR 无结果或服务异常时仍返回 success=false、 空 captcha_text,并增加 recovery,提示内置 Agent 先截取当前验证码供多模态识别。 URL 安全校验拒绝不提供绕过式恢复指引,截图或 OCR 成功也不代表网站已接受验证码。

view_image 只供内置 Agent 使用:它会在 Agent 专用格式化路径把 URL、本地图片或图片内容转换为 原生图像输入,HTTP/MCP 直调不提供该工具,避免把只能由视觉中间件消费的图像块误当作普通 JSON。

内置命令工具 execute_command(action="run") 的返回值为 JSON 字符串,包含 success、execution_outcome、status、exit_code、timed_out、timeout、 output_truncated、output_file、output 和 message。正常退出码 0 才是成功, 非零退出及已停止的超时执行为失败,无法确认进程结束时为 unknown。输出预览与状态分开, 不再通过中文完成提示判断成功。后台 start/read/wait/write/interrupt/kill 保持会话状态与游标协议; env 同时适用于 start 和 run,此工具仍不通过 MCP 暴露。

run、pipe 和 PTY 共享 cwd/shell/login:默认及相对 cwd 使用 MoviePilot 根目录, POSIX 默认非登录;Windows 未指定时保留已有解释器/UTF-8 策略。回包包含实际 shell/login。 项目安装目录存在 venv,或 Docker 的 VENV_PATH 环境存在时,三种模式都会把该环境的 bin(Windows 为 Scripts)放在子进程 PATH 最前、设置 VIRTUAL_ENV,并让裸 python/python3 使用项目专用入口 moviepilot-python;入口不存在时回退到环境中的标准 Python。执行 Python 应直接使用 python -m ...,尤其是下载器、SMB、媒体服务器等需要系统 权限的操作。安装依赖优先使用项目 uv pip ... 或绑定环境中的 python -m pip ...,不要改用 系统解释器或 sudo pip。 write(close_stdin=true) 仅在 pipe 模式支持末段输入后 EOF,回包包含 stdin_closed;输出可继续读取。 PTY 会在写入之前拒绝 half-close,空 write 不代表 EOF,控制字节在 pipe 中也不等于信号。 新增 interrupt 只发送一次平台支持的中断并返回 signal/signal_sent,不会升级强杀; kill 保留终止语义但提前拒绝无效信号。上述能力仍为内置管理员 Agent 工具,不扩大外部 MCP 目录。

后台句柄按宿主用户和真实任务作用域隔离;相同对话的不同定时 run_id 也不会共享终端。 正常对话可跨轮继续,清空/更换用户或定时运行收尾只回收自身进程。子任务仅在父任务明确提供 terminal_sessions 时获得指定 read/wait 授权,不能凭句柄或任务文字访问其他终端。 缺失、封闭或无权限均返回 terminal_access_denied,不会回显其他任务状态;宿主重启不恢复旧句柄。

后台命令的 start 新增 yield_time_ms(默认 250、上限 10000,0 不等待)。 read/wait/write/interrupt/kill 接受 since_seq 和 since_offset:一起传回上次响应的 output_until_seq/output_until_offset,后者表示下一分片内的 UTF-8 字节位置; 首次显式传 offset=0 开启部分分片读取。不传 offset 的旧调用只返回完整分片, 页预算过小时返回 read_limit_too_small 和 minimum_read_bytes。 所有后台动作都返回实际交付的输出游标,last_seq 不代表已读位置。 wait 可由新增输出提前唤醒,0ms 表示非阻塞读取;output_complete 表示读取器已收尾, output_lost 表示输出存在不可恢复缺口。动作已执行后的分页错误放在 output_error 中, 保留会话 ID,调用方应仅重试读取;纯读错误返回 execution_outcome=failed。

下载器和媒体服务器的第三方原生高级能力不注册成永久 MCP 工具。内置 Agent 按需 加载 downloader-operation 或 mediaserver-operation Skill,通过固定脚本读取本机 配置、发现 provider 能力并调用受控 action;脚本不接受任意 URL、认证信息或任意 SDK method。普通 MCP 客户端如需这些 provider 原生能力,应使用对应第三方服务的 正式 API,而不是依赖已删除的 MoviePilot 旧工具名。

send_message 新增可选的 rich_message 字符串参数,用于传入一份完整的 GitHub 风格 Markdown 正文。Telegram 渠道会把它转换为 Bot API Rich Message,支持标题、列表、表格、引用、代码块和链接,并按 Rich Message 限制自动分段;没有使用该参数时继续走原有普通消息链路。广播到其它通知渠道时,同一正文会作为普通 text 回退。rich_message 是完整正文,不应再同时传 message、title 或 image_url 表达同一份内容。内置 Agent 在 Telegram 会话中的普通回复、流式首发和后续流式编辑都会优先使用该富文本链路。

moviepilot_api 的模型可见输入固定为:

{
  "operation_id": "media.search",
  "path_params": {},
  "query": {"title": "流浪地球", "type": "media"},
  "body": {}
}

宿主按 operation_id 决定固定 method 与 path,使用真实持久化管理员身份为 API KEY 集成签发短期本机令牌,并按 operation 执行权限、确认、结果脱敏和恢复策略。 调用方不能注入 host、URL、认证头或 API Token。 网关按后端监听配置 HOST / PORT 通过 HTTP 直连本机 API,并绕过环境代理。 0.0.0.0 / :: 通配监听分别使用 127.0.0.1 / ::1 回环地址,显式 IPv6 地址按 URL 规范加方括号。 APP_DOMAIN 用于 Passkey 等对外地址,不作为网关基址;反代域名在容器内不可达时无需清空该配置。 通知渠道的 subscription.add、subscription.update、subscription.delete 使用渠道账号绑定的 有效 MoviePilot 用户身份,渠道管理员也不会借用超级管理员身份。创建时订阅归属绑定用户, 普通用户只能修改或删除自己的订阅;未绑定或绑定用户已停用时拒绝执行。三项操作仍保留确认机制。 Web Agent 直接调用 moviepilot_api 时,宿主会自动加载 moviepilot-api Skill 的 operation 白名单后再执行;这只是授权兜底,不会放宽固定 operation、身份、权限 或确认策略。

当前业务 operation 分组如下;主流程与分类索引见 skills/moviepilot-api/SKILL.md, 完整参数合同见其 skills/moviepilot-api/api/*.md 分类文档和各 REST 请求模型:

领域 Operation ID
媒体/搜索 media.search、media.person.search、media.person.credits、media.recognize、media.scrape、media.episode_schedule、media.detail、search.torrents、search.results、recommendation.list
媒体自动分类 media.classification.fields、media.classification.policy.get、media.classification.policy.validate、media.classification.policy.preview、media.classification.policy.impact、media.classification.policy.history、media.classification.policy.update、media.classification.policy.rollback
订阅 subscription.add、subscription.update、subscription.search、subscription.list、subscription.shares、subscription.popular、subscription.history、subscription.delete、subscription.execution.list、subscription.execution.get、subscription.execution.cancel
下载/历史 download.add、download.artist_collection、download.history.delete、transfer.history.delete
媒体缓存 media.cache.get、media.cache.delete、media.cache.clear、music.cache.get、music.cache.delete、music.cache.clear
媒体库/存储/转移 library.exists、storage.settings、storage.list、transfer.history、transfer.file
站点 site.list、site.update、site.userdata、site.test、site.cookie.update
调度/工作流 scheduler.list、scheduler.run、workflow.list、workflow.run
插件 plugin.installed、plugin.market、plugin.capabilities、plugin.config.get、plugin.config.update、plugin.reload、plugin.install、plugin.uninstall、plugin.data
规则/配置/命令 filter.builtin、filter.custom、filter.groups、filter.custom.add、filter.custom.update、filter.custom.delete、filter.group.add、filter.group.update、filter.group.delete、config.identifiers.get、config.identifiers.update、config.system.get、config.system.update、slash.list、slash.run

download.list、download.update、download.delete、downloaders.list 和 library.latest 已从 Agent operation 目录删除,避免与 provider Skill 重复。供前端和 其它宿主使用的普通 REST 端点仍然保留。

Agent 自主定时任务与人格

agent_task 是唯一的自主任务工具,要求管理员权限:

Action 说明
create 创建单次或周期任务,并保存任务内容及当前用户、会话上下文
list 查询任务配置、启用状态、下次执行时间及最近执行结果
update 修改任务内容或触发器,也可通过 enabled 暂停、恢复任务
run 使用整数 task_id 将当前用户已启用的任务提交为立即执行
delete 永久删除任务并立即移除运行时调度

trigger_type=date 表示单次执行:“30 分钟后检查”这类相对时间传 delay_minutes=30,由后端计算精确时间;固定时间则传 ISO 8601 trigger,支持精确到秒。trigger_type=cron 使用标准五段 cron(分、时、日、月、周),适合周期检查。未显式携带时区的时间按 MoviePilot 的 TZ 配置解释。任务由内存调度器精确触发,配置持久化到数据库,服务重启后会自动恢复;触发后 Agent 在原会话中执行 content,执行过程及最终结果均不绑定创建任务时的消息渠道,而是通过 MoviePilot 已配置的通知渠道广播。如果 Agent 在执行过程中已通过消息工具发送完整结果,任务结束时不会再次发送相同的最终回复。

服务重启时仍处于运行中的任务会显示为 interrupted,表示上次结果未知且可能已有部分操作。中断的一次任务不会自动补跑,暂停后恢复也仍保留中断状态;需要先核对实际结果,再用 agent_task(action="run") 明确立即重跑,或通过 agent_task(action="update") 提供新的 trigger_type 与未来触发时间重新安排。

Agent 自主任务使用数据库中的整数 task_id。scheduler.list 与 scheduler.run operation 仅面向系统、插件和工作流注册的运行时定时服务,使用字符串 job_id,不会返回或执行 agent-task-*。两类 ID 不可混用;需要立即执行自主任务时,应先通过 agent_task(action="list") 确认归属和状态,再调用 agent_task(action="run")。立即执行只提交任务,不在当前工具调用内等待结果,从而避免同一 Agent 会话互相等待;执行结果仍按上述通知规则广播。

上述过滤只约束 Agent 工具,避免模型混用两类任务。前端系统设置和仪表盘使用的 /api/v1/dashboard/schedule 仍返回完整运行时列表,其中包含 provider=[Agent] 的自主任务;前端通过 /api/v1/system/runscheduler 立即执行这类列表项的行为也保持不变。

创建单次任务的参数示例:

{
  "tool_name": "agent_task",
  "arguments": {
    "action": "create",
    "name": "检查电影资源",
    "content": "搜索电影《示例电影》是否已有可下载资源,并报告站点、版本和大小;不要自动下载。",
    "trigger_type": "date",
    "delay_minutes": 30
  }
}

创建每天 20:30 执行的周期任务时,使用 trigger_type=cron 和 trigger="30 20 * * *"。

persona 使用 action=list|switch|update。list 可按 query 过滤; switch 和 update 必须提供 persona_id,且只有系统管理员可用。update 支持替换 label、 description、aliases、instructions,或通过 append_instructions 追加规则。旧的 query_personas、switch_persona 和 update_persona_definition 不再注册。

认证: 需要API KEY,在请求头中添加 X-API-KEY: <api_key> 或在查询参数中添加 apikey=<api_key>

响应示例:

{
  "success": true,
  "message": "",
  "data": [
    {
      "name": "moviepilot_api",
      "description": "调用经过白名单审核的 MoviePilot 业务 API...",
      "inputSchema": {
        "type": "object",
        "properties": {
          "operation_id": {
            "type": "string",
            "description": "稳定的 MoviePilot API operation ID"
          }
        },
        "required": ["operation_id"]
      }
    }
  ]
}

系统诊断工具

query_doctor_report 以只读方式返回 MoviePilot Doctor 诊断报告,可通过 deep 启用深度检查,并通过 include_details 控制是否返回完整详情。每条诊断项的 affects_report_status 表示其是否参与整体状态聚合;插件日志异常会保留为 warn/degraded 线索,但该字段为 false,不会单独把系统整体状态降为 degraded。

2. 调用工具

POST /api/v1/mcp/tools/call

调用指定的MCP工具。

认证: 需要API KEY,在请求头中添加 X-API-KEY: <api_key> 或在查询参数中添加 apikey=<api_key>

请求体:

{
  "tool_name": "moviepilot_api",
  "arguments": {
    "operation_id": "media.search",
    "query": {
      "title": "流浪地球",
      "type": "media"
    }
  }
}

响应示例:

{
  "success": true,
  "message": "",
  "data": {
    "result": "{\"success\":true,\"message\":\"\",\"data\":[...]}"
  }
}

错误响应示例:

{
  "success": false,
  "message": "调用工具失败: 参数验证失败",
  "data": null
}

3. 获取工具详情

GET /api/v1/mcp/tools/{tool_name}

获取指定工具的详细信息。

认证: 需要API KEY,在请求头中添加 X-API-KEY: <api_key> 或在查询参数中添加 apikey=<api_key>

路径参数:

  • tool_name: 工具名称

响应示例:

{
  "success": true,
  "message": "",
  "data": {
    "name": "moviepilot_api",
    "description": "调用经过白名单审核的 MoviePilot 业务 API...",
    "inputSchema": {
      "type": "object",
      "properties": {
        "operation_id": {
          "type": "string",
          "description": "稳定的 MoviePilot API operation ID"
        }
      },
      "required": ["operation_id"]
    }
  }
}

4. 获取工具参数Schema

GET /api/v1/mcp/tools/{tool_name}/schema

获取指定工具的参数Schema(JSON Schema格式)。

认证: 需要API KEY,在请求头中添加 X-API-KEY: <api_key> 或在查询参数中添加 apikey=<api_key>

路径参数:

  • tool_name: 工具名称

响应示例:

{
  "success": true,
  "message": "",
  "data": {
    "type": "object",
    "properties": {
      "operation_id": {
        "type": "string",
        "description": "稳定的 MoviePilot API operation ID"
      },
      "query": {
        "type": "object",
        "description": "固定 operation 的查询参数"
      }
    },
    "required": ["operation_id"]
  }
}

分类条件字段字典

GET /api/v1/media/classification/fields 的 fields 与 retired_fields 使用同一字段目录 schema: options 提供来源无关的 {value, label},source_options 按数据源 ID 提供开放候选。国家与语言显示中文名称,规则保存标准代码;风格保存与分类事实归一化共用的稳定键。来源风格和音乐枚举保留原始大小写。

客户端合并通用选项和所选来源的候选;未限制来源时展示全部候选并标注来源。allow_custom_values 为真时允许输入其他值,切换来源不得清空已有条件。source_options 缺失等价于空目录;候选是录入辅助,不改变来源支持等级或规则校验范围。公司、平台和用户标签等开放字段应使用媒体预览中的原值。