Skip to content

🔀 自定义映射 ​

当媒体库里的番剧名称和 Bangumi 上的条目对不上时(译名不同、多季合并、特摄/纪录片、续作命名特殊等),程序可能无法自动找到正确的条目。此时可以在 「映射管理」 里为「某个标题」指定对应的 Bangumi 条目 ID,同步时会优先使用这条规则。

本页是「照着做」的操作说明

本页只讲最常用的三种做法,跟着填就能用。更进阶的能力另有两页:

匹配优先级 ​

程序在自动匹配时会按以下顺序查找自定义映射(命中即停止):

  1. 集数分段映射(同一条目标题下细分了集数区间)
  2. 季度感知精确映射(指定了季度的条目)
  3. 简单精确映射(标题完全一致,所有季度共用)
  4. 正则规则(按规则列表顺序依次尝试)

这四类都属于「自定义映射」,整体优先于本地资料库(bangumi-data)、本地归档与 Bangumi 在线搜索,是最高优先级。

⚠️ 先读:映射的威力与风险 ​

自定义映射是最高优先级的规则,命中后程序会直接采用你指定的条目,不再做自动匹配。

这带来两个后果,请务必理解:

  1. 写错会「稳定地错」。程序不会再用搜索、本地归档等兜底手段去纠正它。一个配错的映射会让本来能自动匹配正确的条目变成错误,而且因为每次都很「稳定」,你很难察觉。
  2. 它会豁免屏蔽关键词。命中映射的标题即使包含你设置的屏蔽词也会照常同步。这通常是你想要的(你亲手指定了它),但要知道这个副作用。

建议的做法

  • 一次只加一条,加完观察一次同步结果,确认无误再加下一条。
  • 优先用 「候选确认」 页面一键写入(见下文),它带回填与校验,比手填 ID 不容易错。
  • 配完之后如果不确定,到 「同步记录」 详情里核对实际命中的条目。

三种常用做法 ​

1. 简单精确映射(默认) ​

  • 适用:媒体库标题固定、与 Bangumi 条目一一对应。
  • 填写:番剧名称 + Bangumi ID;季度留空。
  • 行为:只要同步请求里的标题(或原始标题)与「番剧名称」完全一致即命中,所有季度共用同一个 ID。

2. 季度感知映射 ​

  • 适用:同一标题字符串在不同季度应对应 Bangumi 上不同 subject(例如媒体库不按季拆分,但 Bangumi 分季条目)。
  • 填写:番剧名称 + Bangumi ID + 季度(正整数)。
  • 行为:仅当同步请求的 season 与填写的季度一致时才命中;留空季度则视为简单映射,所有季度共用。

例如媒体库把整部番放在「第 1 季」下、集数连续,而 Bangumi 分成两个条目:

番剧名称Bangumi ID季度
某番剧1111111
某番剧2222222

3. 正则规则 ​

  • 适用:一批标题共享命名规律(续作、系列作、带后缀的变体等),不适合逐条写精确名称。
  • 填写:添加映射时类型选 「正则规则」,填写正则表达式、Bangumi ID,以及可选的说明与限定季度。
  • 行为:对同步请求的标题与原始标题依次做匹配;第一条匹配成功的规则生效。页面底部提供 「正则匹配测试」,可先验证表达式再保存。

限定季度用于「同名番剧有多季、且各季是不同条目」的情况:填了它,规则只在指定季生效;留空则对所有季生效。

具体写法与大量示例见 正则匹配(进阶)。

季数对不上?用「集数分段」 ​

上面三种做法解决的是「标题对不上」。还有一类更麻烦的情况:两边都匹配上了,但季/集的划分不一样。

典型场景:TMDB 把一部番拆成 3 季,而 Bangumi 只分成 2 季,两边的总集数是相同的。此时无论指定哪个条目,集号都对不上。

这时候用「集数分段」:在编辑映射时打开 「集数分段」 开关,按提示三选一即可。

三种情形 ​

你的情况选哪个要填什么
这一季整个都对应另一个条目整季都对应另一个条目目标 Bangumi ID
从第 N 集开始换成另一个条目从某一集开始对应另一个条目起始集号、目标 Bangumi ID
其中某几集对应另一个条目某几集对应另一个条目起始集号、结束集号、目标 Bangumi ID

填完后页面会实时显示人话预览,例如:

媒体库 S6 E3 起 → 条目 639938(E3→该条目 E2,E4→E3,依次类推)

请务必核对这行预览再保存。

「自动推算」怎么用 ​

点 「自动推算」 按钮,程序会读取目标条目的章节列表,把「这一段第 1 集」对齐到该条目的第一集,自动填好下面的「对应该条目的第几集」。

如果推算结果和人话预览不一致,直接手动改那个数字即可。

⚠️ 集号填写须知(最容易错的地方) ​

「从第几集开始 / 到第几集结束」填的是你媒体库里的集号,也就是 Emby / Jellyfin / Plex 在该季内显示的集号(第 1 集就是 1),不是整部番连续累加的集号。

举例:媒体库第 6 季显示 E1–E12,你要让 E3 起对应另一条目,就填「从 3 开始」,而不是填 15(3 + 前面 5 季的 12 集)。

复杂度提示 ​

集数分段比前面三种做法明显更难,需要你先弄清两边各自的季/集划分。建议:

  1. 先只用一条分段,覆盖最常见的那一段;
  2. 确认同步正确后,再逐步补充分段;
  3. 遇到下面「常见场景与写法」里没覆盖的情况,再考虑手改 JSON。
手改 JSON(不推荐,供需要多条分段时使用)

弹窗界面一次只能编辑一条分段;存在多条分段时它会提示你去手改配置文件,且不会在保存时改动它们。

配置文件为程序目录下的 bangumi_mapping.json,分段写在对应标题下:

json
{
  "mappings": {
    "某番剧": {
      "subject_id": "111111",
      "segments": [
        { "season": 6, "from": 1,  "to": 12, "subject_id": "111111", "offset": 1 },
        { "season": 7, "from": 1,  "to": null, "subject_id": "222222", "offset": 1 }
      ]
    }
  }
}

字段含义:

字段含义
season该段作用于媒体库的哪一季;省略表示所有季
from / to媒体库该季内的集号区间(含两端);from 省略表示从第 1 集起,to 为 null 表示不设上界
subject_id这一段对应的 Bangumi 条目 ID
offset该段第 1 集对应的目标条目第几集(目标 = 集号 − from + offset)
episodes_of(可选)段内逐集例外,如 {"11": 5} 表示第 11 集对应目标第 5 集,优先于 offset

offset 是「第几集」,不是章节编号(sort)

offset: 1 表示「对应目标条目的第 1 集」,即使该条目在 Bangumi 上的章节编号(sort)从 13、99 或其它值开始。

程序按条目内相对集号定位(sort − 该条目首个正片 sort + 1),匹配不上才回退按 sort 直比。所以你只要填「第几集」这个人类语义即可,不用去数章节编号。

也允许填 0 或负数(媒体库集号比目标集号大时用)。但算出来的目标集号必须 ≥ 1,否则该段会被跳过并在日志里告警。

规则说明:

  • 多段重叠时取数组中靠前的一段,因此把更具体的段写在前面。
  • 集号落在所有段之外时,回退到该标题顶层的 subject_id。 :::

常见场景与写法 ​

上面三个选项覆盖不了的所有情况,都可以用「多条分段」表达。下面每个例子都标注了实测结果,可照着改。

场景 A:TMDB 拆成 3 季,Bangumi 只分 2 季 ​

两边总集数相同,前两季合并对应 Bangumi 第一个条目,第三季对应第二个条目:

json
{
  "mappings": {
    "某番剧": {
      "subject_id": "100",
      "segments": [
        { "season": 1, "from": 1, "to": 12, "subject_id": "100", "offset": 1 },
        { "season": 2, "from": 1, "to": 12, "subject_id": "100", "offset": 13 },
        { "season": 3, "from": 1, "to": 12, "subject_id": "200", "offset": 1 }
      ]
    }
  }
}

实测:S1E1→100/1、S2E1→100/13、S2E12→100/24、S3E1→200/1

关键在第二条的 offset: 13——媒体库第 2 季的第 1 集,要接在第 1 季的 12 集后面。

场景 B:同一季内,第 13 集起换成另一个条目 ​

json
{
  "mappings": {
    "某番剧": {
      "subject_id": "100",
      "segments": [
        { "season": 1, "from": 1,  "to": 12,   "subject_id": "100", "offset": 1 },
        { "season": 1, "from": 13, "to": null, "subject_id": "200", "offset": 1 }
      ]
    }
  }
}

实测:S1E12→100/12、S1E13→200/1

to: null 表示「从这里一直到最后」,不用管这一季到底有多少集。

先确认是否需要手写:当 bangumi-data 已为该条目标注 TMDB 集边界 (形如 tv/278043/season/1/episode/13 的来源,表示该条目从合并季第 13 集起), 程序会自动完成同样的换算,无需再配 segments。只有库中未标注边界时, 才需要按本场景手写。二者可共存:映射仍然优先,自动换算只在没有映射命中时生效。

场景 C:整季对应另一个条目(不用写集号) ​

json
{
  "mappings": {
    "某番剧": {
      "subject_id": "100",
      "segments": [
        { "season": 2, "to": null, "subject_id": "300", "offset": 1 }
      ]
    }
  }
}

实测:S2E1→300/1、S2E5→300/5;而 S1E1 不在任何段内,回退到顶层 subject_id。

from 省略即从第 1 集开始。

场景 D:多集并一集(媒体库集数比 Bangumi 少) ​

例如媒体库把两集并成了一集,媒体库 E5、E6 实际都对应 Bangumi 第 5 集:

json
{
  "mappings": {
    "某番剧": {
      "subject_id": "100",
      "segments": [
        { "season": 1, "from": 5, "to": 5, "subject_id": "100", "offset": 5 },
        { "season": 1, "from": 6, "to": 6, "subject_id": "100", "offset": 5 }
      ]
    }
  }
}

实测:S1E5→100/5、S1E6→100/5

写法要点:把范围拆成多段,每段都指向同一个目标集号。因为 offset 是「该段第 1 集对应的目标集号」,所以每段写 offset: 5 就都落到第 5 集。

重复同步不会有副作用

E5、E6 都指向 Bangumi 第 5 集时,无论先看完哪一集,另一集再上报都会发现第 5 集已经是看过状态,程序会跳过写入(不报错、不重复计数)。所以这类配置是安全的。

区间较长时,逐段写会很啰嗦,可以改用下面的 episodes_of 一次钉死。

场景 E:一集拆多集(媒体库集数比 Bangumi 多) ​

方向和场景 D 相反:Bangumi 的一集,在媒体库/媒体库里被拆成了两集。典型是总集篇——Bangumi 上第 3 集是 recap,媒体库里却是 E3 和 E4 两个文件。

这时媒体库 E3、E4 都应对应 Bangumi 第 3 集,而后面的集号要整体顺延:

json
{
  "mappings": {
    "某番剧": {
      "subject_id": "100",
      "segments": [
        { "season": 1, "from": 1, "to": 2, "subject_id": "100", "offset": 1 },
        { "season": 1, "from": 3, "to": 4, "subject_id": "100", "offset": 3,
          "episodes_of": { "3": 3, "4": 3 } },
        { "season": 1, "from": 5, "to": null, "subject_id": "100", "offset": 4 }
      ]
    }
  }
}

实测:E1→1、E2→2、E3→3、E4→3、E5→4、E6→5、E7→6

写法要点:拆集的处理分三步——拆开的那几集用 episodes_of 钉到同一目标集,下一段的 offset 要相应加 1(上例第三段 offset: 4,因为 E5 应接在目标第 4 集)。若不调整后面的 offset,从 E5 起会整体错位一集。

判断用 D 还是 E

两者在配置上都是「多个媒体库集指向同一个 Bangumi 集」,区别只在业务语义:

  • D(并集):媒体库少了几集 → 是媒体库把两集并成了一集。
  • E(拆集):媒体库多了几集 → 是媒体库把一集拆成了两集。

写法上的实际差别:D 每段各自独立、互不影响;E 需要在拆集点之后调整后续段的 offset,否则会错位。

场景 F:整部均匀拆集(用 episodes_of 批量生成) ​

如果每一集都被均匀拆成了 2 集(Bangumi 12 集 ↔ 媒体库 24 集),逐条手写 episodes_of 不现实,可按规律生成:

json
{
  "mappings": {
    "某番剧": {
      "subject_id": "100",
      "segments": [
        { "season": 1, "from": 1, "to": 24, "subject_id": "100", "offset": 1,
          "episodes_of": {
            "1": 1, "2": 1, "3": 2, "4": 2, "5": 3, "6": 3,
            "7": 4, "8": 4, "9": 5, "10": 5, "11": 6, "12": 6,
            "13": 7, "14": 7, "15": 8, "16": 8, "17": 9, "18": 9,
            "19": 10, "20": 10, "21": 11, "22": 11, "23": 12, "24": 12
          } }
      ]
    }
  }
}

规律是:媒体库第 n 集 → 目标第 ⌈n / 2⌉ 集(向上取整)。实测该配置下 E1–E24 全部映射正确。

episodes_of 必须覆盖到段末

episodes_of 只写一部分(比如只写到第 12 集)而段里 to 是 24 时,没覆盖到的集不会按前面的规律延续,而是直接回退到 offset 的线性推算。

实测:只写前 12 个键时,E13 得到的是 13(而不是期望的 7),E14→14、E24→24——和拆集语义完全不符,且不会报错。

所以要用 episodes_of,就得把它写满整个段;否则请改用「多段拼接」(见场景 E)。

只写 offset 是不够的

单靠 offset 是线性的,无法表达「两集对一集」。实测 offset: 1 只给出 E1→1, E2→2, E3→3…,与拆集语义不符。遇到拆集必须用 episodes_of(或拆成多段)。

场景 G:用 episodes_of 一次钉死多个例外 ​

episodes_of 是「段内逐集例外」,比 offset 优先。同一段里可以让多集指向同一目标:

json
{
  "mappings": {
    "某番剧": {
      "subject_id": "100",
      "segments": [
        { "season": 1, "from": 4, "to": 8, "subject_id": "100", "offset": 1,
          "episodes_of": { "5": 5, "6": 5, "7": 6 } }
      ]
    }
  }
}

上例中第 4、8 集按 offset 推(分别对应目标第 1、5 集),第 5、6 集都对应目标第 5 集,第 7 集对应目标第 6 集。

它也能用来处理小数集号或跳号:"episodes_of": { "3": 4 } 会让第 3 集指向目标第 4 集,其余仍按 offset 推。

场景 H:只有某几集属于另一个条目(特别篇、总集篇) ​

想把第 7 集单独指到另一个条目,顺序很关键:

json
{
  "mappings": {
    "某番剧": {
      "subject_id": "100",
      "segments": [
        { "season": 1, "from": 7, "to": 7,    "subject_id": "999", "offset": 1 },
        { "season": 1, "from": 1, "to": null, "subject_id": "100", "offset": 1 }
      ]
    }
  }
}

实测:S1E6→100/6、S1E7→999/1、S1E8→100/8

最常见的配置错误

如果把宽段(from: 1, to: null)写在前面,它会先命中,特例段永远不会生效,而且不会报错:

jsonc
// ❌ 错误:第 7 集的段被前面的宽段吞掉了
"segments": [
  { "season": 1, "from": 1, "to": null, "subject_id": "100", "offset": 1 },
  { "season": 1, "from": 7, "to": 7,    "subject_id": "999", "offset": 1 }
]

实测结果:S1E7→100/7(特例没有生效)

规则:to 为 null(或很大的数)的段会一直吃到这一季末尾,必须放在最后。把特例、例外写在前面,兜底的宽段写在最后。

场景 I:不写 season,对所有季生效 ​

省略 season 时该段对所有季都生效,适合「媒体库每季都是同一个编号规律」的情况:

json
{
  "mappings": {
    "某番剧": {
      "subject_id": "100",
      "segments": [
        { "from": 1, "to": 12, "subject_id": "200", "offset": 1 }
      ]
    }
  }
}

实测:S1E1→200/1、S3E1→200/1

场景 J:offset 为负或很小时 ​

offset 允许负数,当媒体库集号比目标集号大时使用。但要注意算出来的目标集号必须 ≥ 1,否则该段会被跳过并记录告警:

json
{
  "mappings": {
    "某番剧": {
      "subject_id": "100",
      "segments": [
        { "season": 1, "from": 1, "to": null, "subject_id": "100", "offset": -1 }
      ]
    }
  }
}

实测:S1E1 算出 1−1+(−1) = −1,非法 → 跳过该段并告警;S1E5→100/3 正常。

若要整段向左平移,请改用「把该段起点写在第一个有效集号上」,而不是用负偏移硬怼。

排错清单 ​

分段配置写完不生效时,按这个顺序自查:

现象多半是
某一集仍匹配到别的条目前面有 to: null 的宽段把它吞了 → 把宽段挪到最后
整条配置完全没生效season 写错了(注意这里填的是媒体库的季号)
集号对不上,差了固定的几集offset 算错 → 记住它是「该段第 1 集对应的目标第几集」(不是章节编号 sort)
某几集之后目标集号变成和媒体库集号一样episodes_of 没写满整个段 → 补全,或改用多段拼接
拆集场景里后续集号整体错位一集拆集点之后那一段的 offset 忘了 +1
段内个别集对不上用 episodes_of 单独钉死那几集
集号填成了累计值「从/到」填的是该季内的集号,不是整部番累加的集号

配置改动后,程序会在下次同步时自动重新加载。想立刻验证,可在 「调试工具」 里发起一次测试匹配,或在 「同步记录」 详情里核对实际命中的条目与集号。

映射里要填什么 ​

每条映射至少需要:

  • 番剧名称 / 正则表达式:精确映射需与同步请求里的标题字符串尽量一致(包括标点、空格、季名等)。不确定时,可到 「同步记录」 查看失败条目实际带入的标题,按日志里的写法填写。
  • Bangumi ID:该番在 Bangumi 上的 subject 编号(纯数字)。打开对应条目页面,地址一般为 https://bgm.tv/subject/数字,其中的数字即为 ID。

对于简单精确映射,程序会按「第一季 / 主条目」逻辑使用你填的 ID:一般填系列第一季或主条目的 ID,后续季数由程序根据续集链等逻辑处理,无需为每一季各写一条。若某季在 Bangumi 上是独立 subject 且简单映射对不上,请改用 季度感知映射 分别指定。

写入时会校验 ID

添加或编辑映射时,程序会校验你填的 Bangumi ID:必须是纯数字,且对应条目必须是动画或三次元。填了书籍 / 音乐 / 游戏的 ID 会被直接拒绝并说明原因。

如果当时没有可用的 Bangumi 账号或网络不通,校验会放行(不阻塞你编辑),无效 ID 会在真正同步时才暴露。

映射是全局配置 ​

映射只按标题保存,不分用户、也不分媒体源。也就是说:只要标题匹配,所有媒体服务器用户、所有 Bangumi 账号、所有媒体源都会使用同一条映射。

这是有意设计的。之所以不需要按用户区分:能走到匹配这一步的请求,其用户已经通过了账号权限校验,同一账号体系内不会出现「同一个标题需要映射到不同条目」的正当场景。

批量导入与导出 ​

  • 批量导入:粘贴 JSON 或上传 .json 文件。可勾选「与现有映射合并」;不勾选则覆盖全部现有映射与规则。
  • 导出映射:下载当前映射的完整 JSON,便于备份或迁移。
  • 清空所有:删除全部映射与规则(不可撤销,操作前建议先导出备份)。

导入支持两种 JSON 形态:顶层 {"番剧名": "id"} 的简单对象,或带 mappings / rules 字段的完整结构。

与候选确认的关系 ​

自动匹配失败但存在相近搜索结果时,程序会将候选沉淀到 「候选确认」 页面。确认某条候选后,可一键写入自定义映射,无需手填 Bangumi ID。

候选列表按相似度 score 降序展示,最相近的候选排在最前;若候选项均不符合,可点击「手动指定 Bangumi ID」直接输入条目 ID(方案 A),系统会校验 ID 有效性后再写入映射。

确认即补发

确认候选或手动指定 ID 后,若原同步记录状态为 error / queued,会自动触发一次补发同步,无需手动重试。

接下来 ​