notion-caldav-sync:在Apple Calendar上显示Notion任务

Contents

虽然 Notion Calendar 和 Notion 配合更好,但实际使用中,还是更喜欢 Apple Calendar. Apple Calendar支持农历显示和法定节假日,稳定性更好,且有 iPadOS 版本。

我写了一个开源项目 notion-caldav-sync 将 Notion 所有被授权的数据库上的任务同步到 Apple Calendar 上的一个新日历 Notion.

系统结构 #

整个系统围绕“稳定性和实时性第一”的原则设计:

  1. 单向数据流:避免双向同步的复杂性和冲突(Notion → Apple Calendar)

  2. 实时响应:通过 Notion webhook 将 Notion 上的修改实时同步到 Apple Calendar

  3. 自愈机制:每30分钟执行完整校正,即使 webhook 丢失或处理失败也能恢复

  4. 轻量部署:通过Cloudflare workers + Pyodide部署

最初,我也尝试了双向同步方案,但对于 Apple Calendar 来说,双向同步容易导致数据冲突和 Notion 页面错乱。最终选择了单向同步:保持 Notion 作为唯一数据源,Apple Calendar 作为只读视图,通过点击事件链接跳转回 Notion 修改,Notion 上的变更几乎实时地通过 webhook 在 Apple Calendar 上显示。

  flowchart TD
    NotionDB[(Notion Task Databases)]
    NotionWebhook[/Notion Webhook Events/]
    Cron((Cron Full Rewrite))
    Admin[[Admin Commands]]
    Worker[Cloudflare Worker<br/>Pyodide Runtime]
    Engine[Sync Engine<br/>force Notion→CalDAV]
    KV[(Cloudflare KV STATE)]
    CalDAV[(iCloud &quot;Notion&quot; Calendar)]
    AppleCal[[Apple Calendar Views]]

    NotionWebhook -->|real-time batches| Worker
    Cron -->|self-healing interval| Worker
    Admin -->|/admin/full-sync + settings| Worker
    NotionDB -->|search/query APIs| Worker
    Worker -->|persist metadata & tokens| KV
    Worker --> Engine
    Engine -->|overwrite events| CalDAV
    Engine -->|update hashes & timestamps| KV
    CalDAV --> AppleCal

任务状态emoji #

根据Notion任务状态,我在Apple Calendar日程标题中添加了emoji,更清楚地展现。其中逾期任务⚠️是根据任务截止时间自动识别和标注的:

Notion 状态Emoji 标识含义
Not started待开始任务
In progress⚙️进行中任务
Completed已完成任务
⚠️逾期任务
Cancelled已取消任务

在 Apple Calendar 中搜索这些emoji,还可以快速找到对应状态的任务。

其他信息映射 #

Notion页面地址被写到Apple Calendar的日程URL中,点击可以直接打开Notion页面。另外,Data Source、Category和Description信息也会自动同步到日程备注中。

Cloudflare Workers + Python #

为了能够实现实时响应和定期全量同步,我使用了无服务器部署。

无服务器架构优势 #

选择 Cloudflare Workers 作为运行平台,主要考虑以下几个方面:

  1. Pyodide:Cloudflare Workers 原生支持 Python(基于 Pyodide WebAssembly 实现)

  2. Cloudflare:全球分布式部署,国内也能用

  3. 成本低:免费额度大,无需维护服务器

  4. KV 存储:原生键值存储,使用很方便

Pyodide 的技术优势 #

Pyodide 是 CPython 的 WebAssembly 移植版本:

  • 动态链接:多个 Worker 可共享 Python 运行时和包代码,大幅降低内存占用

  • JavaScript FFI:提供 Python 与 JavaScript 之间的外部函数接口,可直接调用 Web API

  • 内存快照:支持预热和快照技术,将冷启动时间降至 1 秒以下

  • Python 包支持:提供了大量 Python 标准库,并支持pywrangler打包额外的 vendor 包

pywrangler 工具链 #

pywrangler 是 Cloudflare 为 Python Workers 提供的专用 CLI 工具,封装了 wrangler 并添加了 Python 特定功能:

  • 开发服务器:pywrangler dev 本地模拟环境,支持热重载和状态持久化

  • 部署管理:pywrangler deploy 自动打包依赖并优化 WebAssembly 文件

  • 密钥管理:pywrangler secret put 安全存储敏感配置,运行时通过 env 访问

  • 日志追踪:pywrangler tail 实时查看执行日志和性能指标

  • Python 优化:自动预编译依赖、注入最小运行时、检测不兼容特性

通过 pywrangler 的封装,除了 CPU 限制和包大小限制,几乎和本地 CPython 环境一样.工具链自动处理 WebAssembly 编译、依赖管理和部署优化等复杂细节。

参考资料 #