ICS → Discourse 导入器(通过 REST API)

ics_to_discourse.py 测试行为说明

我一直在对这个脚本进行一系列测试(使用和不使用 --time-only-dedupe),并认为详细记录更新/采用流程会很有用。


1. 如何确定唯一性

  • 默认模式: 采用要求 开始时间 + 结束时间 + 地点 完全匹配。
  • 使用 --time-only-dedupe 采用仅要求 开始时间 + 结束时间;地点被视为“足够接近”。

如果没有现有主题符合这些规则,则会创建一个新主题。


2. UID 标记的作用

  • 每个事件主题在第一篇帖子中都有一个隐藏的 HTML 标记:
  <!-- ICSUID:xxxxxxxxxxxxxxxx -->
  • 在后续运行中,脚本首先查找该标记。
  • 如果找到,则该主题被视为 UID 匹配并直接更新,无论 DESCRIPTION 文本多么冗长或陈旧。
  • 这使得 UID 成为真正的身份密钥。可见的描述字段不影响匹配。

3. UID 匹配的更新流程

  1. 脚本获取第一篇帖子并去除标记:
 old_clean = strip_marker(old_raw)
 fresh_clean = strip_marker(fresh_raw)
  1. 如果 old_clean == fresh_clean:不更新(避免变动)。
  2. 如果它们不同:检查更改是否“有意义”:
meaningful = (
    _norm_time(old_attrs.get("start")) != _norm_time(new_attrs.get("start"))
    or _norm_time(old_attrs.get("end")) != _norm_time(new_attrs.get("end"))
    or _norm_loc(old_attrs.get("location")) != _norm_loc(new_attrs.get("location"))
)
  • 如果 meaningful = True → 更新并置顶(主题在“最新”中显示)。

  • 如果 meaningful = False → 安静更新(bypass_bump=True → 仅修订,不置顶)。

    1. 标签会合并(确保静态/默认标签存在,从不删除版主/手动标签)。
    2. 标题和类别在更新时永远不会更改。

  1. 无 UID 匹配的更新流程
    1. 脚本尝试采用:
      • 构建开始/结束/地点(或仅开始/结束,使用 --time-only-dedupe)的候选三元组。
      • 搜索 /search.json 和 /latest.json 以查找具有匹配属性的现有事件。
      • 如果找到 → 采用该主题,添加 UID 标记 + 标签(此时正文保持不变)。
      • 如果未找到 → 创建一个带有标记和标签的全新主题。
    2. 一旦采用或创建,所有未来的同步都将直接通过 UID 解析。

  1. 实际后果
    • 时间更改
    • 默认:采用失败(时间不同)→ 创建新主题。
    • 使用 --time-only-dedupe:采用以同样方式失败;创建新主题。
    • 地点更改
    • 默认:采用失败(地点不同)→ 创建新主题。
    • 使用 --time-only-dedupe:采用成功(时间匹配),但地点差异被标记为“有意义”→ 更新并置顶。
    • 描述更改
    • 如果 DESCRIPTION 文本更改但开始/结束/地点未更改:
    • 正文将安静更新(bypass_bump=True)。
    • 创建主题修订,但在“最新”中不置顶。
    • 如果 DESCRIPTION 未更改(或仅包含可正常化的“上次更新时间”等噪音),则根本不会进行更新。
    • UID 标记
    • 确保未来同步的可靠匹配。
    • 意味着冗长的 DESCRIPTION 字段不会影响是否找到正确的主题。

  1. 为什么 DESCRIPTION 有时“保持不变”
    脚本会比较整个正文(不包括 UID 标记)。
    如果只有“上次更新时间”等易变行不同,但它被正常化(例如,空格、换行符、Unicode),则 old_clean 和 fresh_clean 会显示相同 → 不会进行更新。
    这是故意的,以防止因 Feed 噪音而产生的变动。

总结
• 时间定义唯一性(时间更改时始终创建新主题)。
• 地点更改 → 可见置顶(以便用户注意到场地更新)。
• 描述更改 → 安静更新(修订但不置顶)。
• UID 标记 = 可靠的身份密钥,确保始终找到正确的主题,即使 DESCRIPTION 陈旧或冗长。

这取得了良好的平衡:重要更改会显示在“最新”中,不重要的变动则保持不可见。