ics_to_discourse.py 测试行为说明
我一直在对这个脚本进行一系列测试(使用和不使用 --time-only-dedupe),并认为详细记录更新/采用流程会很有用。
1. 如何确定唯一性
- 默认模式: 采用要求 开始时间 + 结束时间 + 地点 完全匹配。
- 使用
--time-only-dedupe: 采用仅要求 开始时间 + 结束时间;地点被视为“足够接近”。
如果没有现有主题符合这些规则,则会创建一个新主题。
2. UID 标记的作用
- 每个事件主题在第一篇帖子中都有一个隐藏的 HTML 标记:
<!-- ICSUID:xxxxxxxxxxxxxxxx -->
- 在后续运行中,脚本首先查找该标记。
- 如果找到,则该主题被视为 UID 匹配并直接更新,无论 DESCRIPTION 文本多么冗长或陈旧。
- 这使得 UID 成为真正的身份密钥。可见的描述字段不影响匹配。
3. UID 匹配的更新流程
- 脚本获取第一篇帖子并去除标记:
old_clean = strip_marker(old_raw)
fresh_clean = strip_marker(fresh_raw)
- 如果 old_clean == fresh_clean:不更新(避免变动)。
- 如果它们不同:检查更改是否“有意义”:
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 → 仅修订,不置顶)。
- 标签会合并(确保静态/默认标签存在,从不删除版主/手动标签)。
- 标题和类别在更新时永远不会更改。
- 无 UID 匹配的更新流程
- 脚本尝试采用:
• 构建开始/结束/地点(或仅开始/结束,使用--time-only-dedupe)的候选三元组。
• 搜索 /search.json 和 /latest.json 以查找具有匹配属性的现有事件。
• 如果找到 → 采用该主题,添加 UID 标记 + 标签(此时正文保持不变)。
• 如果未找到 → 创建一个带有标记和标签的全新主题。 - 一旦采用或创建,所有未来的同步都将直接通过 UID 解析。
- 脚本尝试采用:
⸻
- 实际后果
• 时间更改
• 默认:采用失败(时间不同)→ 创建新主题。
• 使用--time-only-dedupe:采用以同样方式失败;创建新主题。
• 地点更改
• 默认:采用失败(地点不同)→ 创建新主题。
• 使用--time-only-dedupe:采用成功(时间匹配),但地点差异被标记为“有意义”→ 更新并置顶。
• 描述更改
• 如果 DESCRIPTION 文本更改但开始/结束/地点未更改:
• 正文将安静更新(bypass_bump=True)。
• 创建主题修订,但在“最新”中不置顶。
• 如果 DESCRIPTION 未更改(或仅包含可正常化的“上次更新时间”等噪音),则根本不会进行更新。
• UID 标记
• 确保未来同步的可靠匹配。
• 意味着冗长的 DESCRIPTION 字段不会影响是否找到正确的主题。
⸻
- 为什么 DESCRIPTION 有时“保持不变”
脚本会比较整个正文(不包括 UID 标记)。
如果只有“上次更新时间”等易变行不同,但它被正常化(例如,空格、换行符、Unicode),则 old_clean 和 fresh_clean 会显示相同 → 不会进行更新。
这是故意的,以防止因 Feed 噪音而产生的变动。
⸻
总结
• 时间定义唯一性(时间更改时始终创建新主题)。
• 地点更改 → 可见置顶(以便用户注意到场地更新)。
• 描述更改 → 安静更新(修订但不置顶)。
• UID 标记 = 可靠的身份密钥,确保始终找到正确的主题,即使 DESCRIPTION 陈旧或冗长。
这取得了良好的平衡:重要更改会显示在“最新”中,不重要的变动则保持不可见。