Skip to main content
Glama

tmdb-media

TypeScript/Node implementation of the TMDB local media metadata tool described in docs/spec-tmdb-media.md.

Current status: iteration 1 (read-only pipeline) in progress, building on the parser benchmark spike. It does not write media metadata, rename files, move files, delete files, or touch a media library.

The iteration provides these read-only commands:

  • scan — discover media files under a configured library root.

  • search — query TMDB for candidate matches.

  • match — score and rank candidates against a parsed file.

  • details — fetch canonical metadata for a chosen candidate.

  • scrape --dry-run — run the full pipeline and report what would be written, without writing anything to the media library.

Run

corepack pnpm install
corepack pnpm benchmark:parser
corepack pnpm test
corepack pnpm typecheck

Parse one filename or path:

corepack pnpm exec tsx src/cli.ts parse "/Volumes/Media/TV/庆余年/Season 1/第01集.mkv" --json

Related MCP server: Mediabox MCP

Parser Spike Result

The fixture at tests/fixtures/parser-samples.json currently shows:

  • PTT + normalization baseline: 9/14 required cases.

  • Enhanced parser: 14/14 required cases.

The enhanced parser layers Chinese season/episode handling and parent-directory title inference on top of parse-torrent-title. Known-hard cases are also tracked in the fixture but do not gate the command.

如何使用 (Usage)

本项目有两种用法:CLI(你在终端手动跑)和 MCP(AI 客户端如 Claude Code / Codex 通过对话调用)。两者底层是同一套管线。

刮削分两种模式,区别在「动不动真实视频文件」:

模式

做什么

动视频吗

CLI

MCP 工具

① 轻量 sidecar

在视频旁边写 metadata.json / metadata.md

不动,只新增旁车文件

scrape

plan_scrape → write_artifacts

② 完整 organize

tinyMediaManager / Jellyfin 式整理:重命名文件夹、把分集移进 Season N/、写 tvshow.nfo + 分集 NFO、下载 poster/fanart/剧照

会重命名/移动真实视频

organize(+ undo)

plan_organize → apply_organize(+ undo_organize)

两种模式都很保守:默认 dry-run、默认不覆盖、执行前需二次确认;organize 还可整次回滚。

CLI 用法

CLI 既能用源码跑(corepack pnpm exec tsx src/cli.ts <cmd>),也能 build 后用 node dist/cli.js <cmd>。下面用配置示例里的库名 movies / tv 举例。

# 列出某库(或子目录)的视频文件(只读)
node dist/cli.js scan -l tv -s "庆余年"

# 搜 TMDB 候选
node dist/cli.js search "庆余年" -t tv
node dist/cli.js search "盗梦空间" -t movie -y 2010

# 取某 TMDB id 的规范元数据
node dist/cli.js details tv 272432
node dist/cli.js details movie 27205 --language zh-CN

# 发现/挑片(只读):趋势、推荐、相似
node dist/cli.js trending movie                       # 本周热门电影(默认 week)
node dist/cli.js trending tv -w day                   # 当日热门剧集
node dist/cli.js recommend movie 27205                # 与某电影相关的推荐
node dist/cli.js similar tv 272432 --language zh-CN   # 与某剧集相似的作品

# 扫描 + 解析 + 匹配,看会命中什么(只读,不写)
node dist/cli.js match -l tv -s "庆余年"
node dist/cli.js match -l tv -s "某改名文件夹" --tmdb-id tv:272432   # 强制锁定作品

# 模式①:sidecar 刮削。默认 DRY-RUN,加 --yes 才真正写
node dist/cli.js scrape -l tv -s "庆余年"                 # dry-run,看会写什么
node dist/cli.js scrape -l tv -s "庆余年" --yes           # 真正写出 metadata.json/.md
node dist/cli.js scrape -l tv -s "某文件夹" --tmdb-id tv:272432 --yes   # 强制作品后写
node dist/cli.js scrape -l tv -s "庆余年" --yes --overwrite             # 覆盖已有 sidecar(先备份 .bak.<ts>)

# 模式②:organize(Jellyfin 式整理,会重命名/移动真实视频)。默认 DRY-RUN
# 同时支持电影和剧集:--tmdb-id 接受 movie:603 / tv:272432 / 裸 id(默认 tv)
node dist/cli.js organize -l tv -s "低智商犯罪" --tmdb-id 272432         # 剧集 dry-run:打印改名 + 每集移动
node dist/cli.js organize -l tv -s "低智商犯罪" --tmdb-id 272432 --yes   # 剧集真正执行,打印 run-id
node dist/cli.js organize -l tv -s "低智商犯罪" --tmdb-id 272432 --yes --no-images   # 不下图片
node dist/cli.js organize -l tv -s "低智商犯罪" --tmdb-id 272432 --yes --overwrite   # 覆盖已有 NFO/图片
node dist/cli.js organize -l movies -s "某电影文件夹" --tmdb-id movie:603         # 电影 dry-run
node dist/cli.js organize -l movies -s "某电影文件夹" --tmdb-id movie:603 --yes   # 电影真正执行

# 回滚一次 organize(用 organize --yes 打印的 run-id)
node dist/cli.js undo <run-id>

关键点:

  • scrape / organize 默认都是 dry-run,必须显式 --yes 才动磁盘。

  • organize 同时支持电影和剧集;--tmdb-id 必填,接受 movie:603 / tv:272432 / 裸 272432(裸 id 默认按 tv 处理)。

    • 剧集布局:文件夹改名为 片名 (年份),每集移进 Season N/片名 - SxxExx - 标题,写 tvshow.nfo + 分集 NFO,下 poster/fanart/剧照。

    • 电影布局:把文件夹与主视频都重命名为 片名 (年份)(如 片名 (年份).mkv),写 movie.nfo,下 poster/fanart——没有 Season 文件夹、没有分集。

  • 每次 organize --yes 都会落一个 run-id,可用 undo <run-id> 整次回滚(移回视频、删除新建的 Season 目录与 NFO/图片、把文件夹名改回去)。

  • 任何命令都不传绝对路径,只用 -l/--library 库名 + -s/--subpath 相对子路径。

MCP 用法

MCP server 跑的是编译后的 dist/cli.js mcp,共暴露 12 个工具:

工具

作用

破坏性

get_capabilities

列出库、默认/回退语言、支持格式、minConfidence、视频扩展名、TMDB 署名

否(只读)

scan_media_files

分页列出某库的视频文件(含 existingArtifacts)

否(只读)

search_tmdb

按标题(可带年份)搜 TMDB 候选

否(只读)

get_tmdb_metadata

取某 TMDB id 的规范元数据

否(只读)

get_trending

取趋势:{ type, window?(day/week,默认 week), language? },挑片/发现用

否(只读)

get_recommendations

取某 TMDB id 的推荐:{ type, tmdb_id, language? }

否(只读)

get_similar

取某 TMDB id 的相似作品:{ type, tmdb_id, language? }

否(只读)

plan_scrape

模式① 规划 sidecar 写入(不写),返回 plan_id + expected_plan_hash

否(只读)

write_artifacts

模式① 按计划写出 sidecar,需 plan_id + expected_plan_hash

是(destructive)

plan_organize

模式② 规划 Jellyfin 式整理(电影 / 剧集均可,tmdb_id 接受 movie:603 / tv:272432 / 裸 id),不动文件,返回 plan_id + expected_plan_hash

否(只读)

apply_organize

模式② 执行整理:重命名/移动视频 + 写 NFO + 下图片,需 plan_id + expected_plan_hash,落 run_id

是(destructive,动真实视频!)

undo_organize

按 run_id 整次回滚一次 apply_organize

是(destructive)

工作流 A:sidecar 刮削(模式①,不动视频)

  1. plan — plan_scrape({ library, subpath?, tmdb_id?, ... }) 规划,返回 plan_id、expected_plan_hash 和 targets(将写哪些文件、命中哪部作品、置信度)。不写任何文件。

  2. 确认 — 把 targets 念给用户看,等用户核对。

  3. write — 用户确认后 write_artifacts({ plan_id, expected_plan_hash }) 原子写出(hash 不符会报 PLAN_STALE,重新 plan 即可)。

工作流 B:organize 整理(模式②,会动真实视频)

  1. plan — plan_organize({ library, subpath, tmdb_id, images?, overwrite? }) 规划,返回 plan_id、expected_plan_hash、show_folder_rename(文件夹改名)、seasons、moves(每集要移到哪)、NFO/图片数量、unmatched。不动任何文件。tmdb_id 同时支持电影和剧集,接受 movie:603 / tv:272432 / 裸 272432(裸 id 默认 tv);电影布局只把文件夹+主视频重命名为「片名 (年份)」并写 movie.nfo + poster/fanart(无 Season 文件夹、无分集)。

  2. 确认(重点) — organize 会重命名文件夹、移动真实视频,所以必须把文件夹改名和每集移动一条条念给用户,明确告知这会改动真实文件,等用户确认。

  3. apply — 用户确认后 apply_organize({ plan_id, expected_plan_hash }) 执行,返回一个 run_id。

  4. undo(必要时) — 出问题或用户反悔,用 undo_organize({ run_id }) 整次回滚。

安全红线:root 由配置固定,只传 library + subpath,绝不传绝对路径;organize 因为动真实文件,必须 plan → 给用户看 → 确认 → apply,必要时 undo;纯数字集号 / 被改名的文件夹用 tmdb_id(如 "tv:272432")强制锁定作品。

如何集成 (Integration)

前置准备

# 1. 安装依赖并构建(MCP / dist 用法都需要先 build)
corepack pnpm install
corepack pnpm build

# 2. 配置 config.toml(参考 config.example.toml,填好每个库的 root 与 type)
cp config.example.toml config.toml

# 3. 设置 TMDB 凭据(环境变量,不要写进配置文件)
export TMDB_ACCESS_TOKEN="<your-tmdb-v4-read-access-token>"

库根目录在配置里固定,AI / MCP 调用方只传库名 + 相对子路径,绝不传绝对路径。

在 Claude Code 注册

方式 A:项目级 .mcp.json(已提供示例,把占位 token 换成你自己的):

{
  "mcpServers": {
    "tmdb-media": {
      "command": "node",
      "args": ["dist/cli.js", "mcp"],
      "env": {
        "TMDB_ACCESS_TOKEN": "<your-tmdb-v4-read-access-token>",
        "TMDB_MEDIA_CONFIG": "config.toml"
      }
    }
  }
}

方式 B:命令行一键添加:

claude mcp add tmdb-media -- node dist/cli.js mcp

随仓库还附带一个 Claude Code skill .claude/skills/tmdb-scrape/SKILL.md, 覆盖 sidecar 刮削和 organize 整理两套安全工作流,用户提到「刮削 / scrape / organize / Jellyfin / 重命名 / TMDB 元数据 / 识别媒体文件夹」等时会自动触发。

在 Codex 注册

在 ~/.codex/config.toml 加:

[mcp_servers.tmdb-media]
command = "node"
args = ["dist/cli.js", "mcp"]

[mcp_servers.tmdb-media.env]
TMDB_ACCESS_TOKEN = "<your-tmdb-v4-read-access-token>"
TMDB_MEDIA_CONFIG = "config.toml"

环境变量说明

  • TMDB_ACCESS_TOKEN — TMDB v4 read access token(Bearer,优先)。

  • TMDB_API_KEY — TMDB v3 api key(TMDB_ACCESS_TOKEN 缺失时的回退)。

  • TMDB_MEDIA_CONFIG —(可选)config.toml 路径;不设则用 $XDG_CONFIG_HOME/tmdb-media/config.toml。

  • TMDB_MEDIA_LOG_LEVEL —(可选)日志级别,默认 info。

鉴权只走以上环境变量,不要写进配置文件,也不要在对话里打印 / 回显。

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      A
      quality
      C
      maintenance
      Giving AI assistants the ability to search movies and TV shows, find torrents with magnet links, check streaming availability, and explore cast/crew metadata.
      66
      10
      95 npm
      17
      MIT
    • A
      license
      Not graded
      quality
      B
      maintenance
      Enables natural-language discovery and resolution of movies and TV shows into verified canonical media, then requesting them through an existing Seerr/Radarr/Sonarr stack. Exposes these capabilities via MCP tools and a REST API for AI agents.
      MIT