Doradx/notion2markdown-action
Doradx
Created: 2023-04-12T02:04:29Z

[Updates]

  • 2023.09.07:大版本更新,本文列出的配置参数部分已经无法生效,这里是详细参数配置
  • 2023.09.02:更新适配Notion最新图片路径;;修复图片压缩error处理。
  • 2023.06.05:添加对synced_block的支持,能够支持 Notion 中的块引用。
  • 2023.04.21:添加对audio的支持,建议使用外部 MP3 源文件。
  • 2023.04.20:添加pic_compress可选配置项,可配置为true开启图片自动压缩,默认为false
  • 2023.04.18:添加Notion一些特性支持,包括bookmarklink_previewvideopdfembed
  • 2023.04.17:添加pic_base_url可选配置项,可配置为自己图床的基础链接。图床上传过程中,如检测到此链接,将会自动查询要上传的图片是否已在图床(上传的文件名为 Notion 给图片赋予的UUID,据此检测)。此项可极大提高文章更新效率,节省宝贵的GitHub Action运行时间和CDN流量。

本项目受notion-blog-action项目启发,fork 后深度修改而得,在此感谢@Mo Huishou

概览

本方案主要是为了将 Notion 中的各种格式导出为 Markdown 格式,并在此基础上添加对 Notion 各类特性的支持,包括bookmarklink_previewvideopdfembed。符合原生 Markdown 格式的将转为纯 Markdown 语法,其它部分将转为 html 格式。渲染效果

方案主要分为三部分:

  • Notion database:创建写作, 进行稿件管理
  • notion2markdown-action:GitHub Actions 将 notion 转为 Markdown,并将图片上传图床
  • GitHub Actions: 编译部署 Hexo, 推送到 COS

实现原理

  1. 采用Notion API,从Notion中同步Dataset中的Pages,并转换为Markdown,将其中的图片上传到图床中;
  2. Hexo/Huge部署。
  3. 以上均通过Github Action实现。

食用方法

Notion 配置

  1. Untitled 复制Dataset模板
  2. 参考Notion官方教程Create an integration (notion.com),创建Notion integration
    应用,并获取**Secrets**,直达链接:My integrations | Notion Developers
  3. 将创建的Dataset数据库授权给刚创建的Integration应用,如下图:

在Notion给Integration应用授权

GitHub 配置

workflows 配置

  1. 切换到自己在 GitHub 上托管的仓库目录
  2. 添加Notion2Hexo.yml,内容如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
name: Notion2Hexo GitHub Pages

on:
workflow_dispatch:
repository_dispatch:
types:
- notion_sync

concurrency:
group: notion-sync-${{ github.ref }}

permissions:
contents: write
pages: write
id-token: write

jobs:
notionSyncTask:
name: Notion2Hexo on ${{ matrix.os }}
runs-on: ubuntu-latest
timeout-minutes: 20
strategy:
matrix:
os: [ubuntu-latest]
outputs:
HAS_CHANGES: ${{ steps.NotionSync.outputs.updated_count != '0' }}
steps:
- name: Checkout blog and theme
uses: actions/checkout@v3
with:
submodules: "recursive"
fetch-depth: 0
- name: Check the NOTION_SYNC_DATETIME
id: GetNotionSyncDatetime
run: |
echo -e "Latest commit id: $(git rev-parse HEAD)"
echo -e "Latest notion sync commit:\n$(git log -n 1 --grep="NotionSync")"
NOTION_SYNC_DATETIME=$(git log -n 1 --grep="NotionSync" --format="%aI")
echo "NOTION_SYNC_DATETIME: $NOTION_SYNC_DATETIME"
echo "NOTION_SYNC_DATETIME=$NOTION_SYNC_DATETIME" >> "$GITHUB_OUTPUT"
- name: Convert notion to markdown
id: NotionSync
uses: Doradx/notion2markdown-action@v1
with:
notion_secret: ${{ secrets.NOTION_TOKEN }}
database_id: ${{ secrets.NOTION_DATABASE_ID }}
pic_migrate: true
pic_bed_config: ${{ secrets.PICBED_CONFIG }}
pic_compress: true
output_page_dir: "source"
output_post_dir: "source/_posts/notion"
clean_unpublished_post: true
last_sync_datetime: ${{ steps.GetNotionSyncDatetime.outputs.NOTION_SYNC_DATETIME }}
timezone: "Asia/Shanghai"
- name: Sync git & build
if: steps.NotionSync.outputs.updated_count != '0'
run: |
git pull
npm install
npm run build
- name: Commit & Push
if: steps.NotionSync.outputs.updated_count != '0'
uses: stefanzweifel/git-auto-commit-action@v4
with:
file_pattern: "source/"
commit_message: Automatic NotionSync.
# 下面的操作是用于部署github pages, 各位可根据自己需要进行修改,不一定需要
- name: Setup Pages
if: steps.NotionSync.outputs.updated_count != '0'
uses: actions/configure-pages@v3
- name: Upload artifact
if: steps.NotionSync.outputs.updated_count != '0'
uses: actions/upload-pages-artifact@v2
with:
# Upload the public dir
path: "./public"
- name: Deploy to GitHub Pages
if: steps.NotionSync.outputs.updated_count != '0'
id: deployment
uses: actions/deploy-pages@v2

GitHub Action 环境变量配置

前往博客仓库的settings/secrets/actions中添加环境变量,核心为NOTION_DATABASE_ID, NOTION_SECRETPICBED_CONFIG

配置完成的GITHUB ACTION环境变量

其中,

以腾讯云 COS 为例,PICBED_CONFIG的格式为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"uploader": "tcyun", // 代表当前的默认上传图床为,
"tcyun":
{
"secretId": "",
"secretKey": "",
"bucket": "", // 存储桶名,v4 和 v5 版本不一样
"appId": "",
"area": "", // 存储区域,例如 ap-beijing-1
"path": "", // 自定义存储路径,比如 img/
"customUrl": "", // 自定义域名,注意要加 http://或者 https://
"version": "v5" | "v4" // COS 版本,v4 或者 v5
}
}

如需使用不同图床,直接修改uploader字段,并配置相应的参数即可。以下提供几种常见图床的配置文件案例:

  • qiniu
1
2
3
4
5
6
7
8
9
10
11
12
13
{
"uploader": "qiniu", // 代表当前的默认上传图床为,
"qiniu":
{
"accessKey": "",
"secretKey": "",
"bucket": "", // 存储空间名
"url": "", // 自定义域名
"area": "z0" | "z1" | "z2" | "na0" | "as0", // 存储区域编号
"options": "", // 网址后缀,比如?imgslim
"path": "" // 自定义存储路径,比如 img/
}
}
  • aliyun
1
2
3
4
5
6
7
8
9
10
11
12
{
"uploader": "aliyun", // 代表当前的默认上传图床,
"aliyun": {
"accessKeyId": "",
"accessKeySecret": "",
"bucket": "", // 存储空间名
"area": "", // 存储区域代号
"path": "", // 自定义存储路径
"customUrl": "", // 自定义域名,注意要加 http://或者 https://
"options": "" // 针对图片的一些后缀处理参数 PicGo 2.2.0+ PicGo-Core 1.4.0+
}
}
  • github
1
2
3
4
5
6
7
8
9
10
{
"uploader": "github", // 代表当前的默认上传图床,
"github": {
"repo": "", // 仓库名,格式是 username/reponame
"token": "", // github token
"path": "", // 自定义存储路径,比如 img/
"customUrl": "", // 自定义域名,注意要加 http://或者 https://
"branch": "" // 分支名,默认是 main
}
}

测试效果

前往仓库的Actions页面,选择Notion2Hexo,进行测试手动部署,并查看运行情况。

手动触发,查看运行结果

搞定!尽情享受写作吧!

完整版配置文件及说明

notion2markdown提供了众多配置参数,以满足各类需求,以下为根据此 action 的配置文件,撰写的参数说明。

Action 参数说明

notion2markdown-action@v1的完整参数说明见GitHub 文档

Tips

  • 只有状态为已发布的文章才会被Github Action转为Markdown
  • Notion上设置的文章封面会被用作文章的cover字段,并上传图床
  • Notion中每个页面会有一个独一无二的 UID, 为方便管理,此 ID 会被同步到*.md文件的id属性
  • Notion中每个页面会有created_timelast_edited_time, 会被分别同步到*.md文件的createdupdated属性
  • Notion Dataset中,使用status进行阶段管理,其中只有处于已发布状态的文章会被自动处理。所以,只需要保证已发布状态存在即可,其它几个状态可以根据喜好修改或删除;
  • Notion Dataset中,每篇文章都设置了众多属性,其均会写入到最终Markdown文件头部的 YAML 配置中,可根据自身需要添加属性,但注意字段名最好不要有特殊字符,否则可能出错;
  • 使用hexo的童鞋,如部署过慢,建议升级hexo版本,并清理项目依赖(在package.json中),可极大提升部署效率。博主升级后时间缩短了一半,目前约90s内能完成部署。

Actions 耗时分析

notion_sync.yml

对于此任务,最耗时的部分在于图床上传,具体耗时与图片数量和~~~~`GitHub Actions`~~~~的具体执行机器有关(每次机器都不一样)。

由于是每小时轮询,当查到 Notion 无需要发布的文献时候

本文处理耗时约~~~~`17s`~~~~,各任务为并行,取决于执行机器网速和图片数量。此步骤主要瓶颈在于 GitHub 上传图床速度,可优化面较小。。。或许用 GitHub 做图床会非常快?利好图床采用外网平台的童鞋。

deploy.yml

此任务最大耗时在依赖安装(~~~~`Install dependencies~~~~)和部署(~~~~Deploy`~~~~):

  • 升级~~~~`Hexo~~~~到最新版~~~~v6.3.0~~~~,并清理~~~~package.json~~~~中无用的包后,依赖安装约耗时~~~~20s`
  • 部署部分主要还是网络问题,速度取决于你的部署类型,博主使用腾讯云 COS,单次部署上传约~~~~`30s`

单次部署的典型耗时约~~~~`1min`

经过多轮优化后,notion2markdown-action@v1的执行速度已经大幅提升。

单次执行轮询约20~30秒,Notion 页面转 Markdown 的速度瓶颈在图床的上传速度。

此外,另一瓶颈在于Hexo的部署速度,与部署方式密切相关。

据测试,单次部署到腾讯云约 2 分钟,部署到 GitHub Pages 约 20 秒。

渲染效果展示

Notion 页面:

博客渲染页面:

Q&A

  • 如何更新已发布的文章?

撰写修改后,将文章状态修改为~~~~`待发布`~~~~即可,会自动更新。

直接修改即可,插件会自动更新对应 Markdown 文件。

  • 如何删除已发布的文章?

直接将文章状态从已发布改为任何其它状态即可。

注意:需要Notion2Hexo.yml中配置clean_unpublished_post: true

  • 更新已发布的文章,如何保证文章链接不变?

方案 1(手动):给Notion的文章手动设置abbrlink,会同步到Markdown文件中

方案 2(自动):采用rozbo/hexo-abbrlink插件的童鞋,Notion文章的 abbrlink 留空即可,会自动处理;当然如果想自定义abbrlink,直接填写即可

rozbo/hexo-abbrlink会在Deploy阶段自动给文章生成abbrlink,当将已发布文章修改后重新发布时,会读取原 Markfown 文件中的abbrlink并同步到 Notion 文章。

  • 如何修改同步频次?

notion_sync.yml配置中修改 schedule配置即可,格式为 cron,可利用Crontab.guru进行可视化调整。

注意:不要改那么高频!GitHub 对于私有仓库,调用 GitHub Actions 的时间是有限的,Pro 用户每个月 3000 分钟。小心 GitHub 找你收钱。根据推算,建议触发间隔不小于 10 分钟!

  • 如何嵌入 HTML 等代码?

Notion中直接粘贴即可,需要确保在粘贴过程中 Notion 没有给你的 URL 链接自动加上超链接,否则可能渲染出错,例如:

1
2
3
4
5
6
7
8
9
<iframe
width="560"
height="315"
src="https://www.youtube.com/embed/r7iLI8vW4bE"
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
allowfullscreen
></iframe>

复制后直接粘贴到 Notion 的文章,它会自动给 URL 加上超链接:

1
2
3
4
5
6
7
8
9
10
<iframe
width="560"
height="315"
src="[https://www.youtube.com/embed/r7iLI8vW4bE](https://www.youtube.com/embed/r7iLI8vW4bE)
"
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
allowfullscreen
></iframe>

会导致最终的Markdown渲染出错,出现以下情况:

  • 什么图片会被上传到图床?

为节省空间,本插件只将 Notion 存储的图片转到图床中,外链图片和原本就属于自己图床的图片链接不会被上传。

注意:插入外链图片时请检查是否允许跨域,否则可能图片不显示。

  • 想要更多关于notion2markdown-action的参数介绍?

总结

优势

  • 功能完备,虽然有一些小坑,但NotionMarkdown功能完备
  • 自动化部署,只需要在Notion编辑即可,且方便管理,剩余流程全自动
  • 利用Notion可在多端同步编辑,图床自动上传,无需关心其它问题,转注写作即可
  • 理论上支持各类静态博客,因为原理就是Notion to Markdown,通用型极高
  • 可设置指定的目录存储 Notion 导出的 post, 例如: source/_posts/notion,不影响原先使用其它编辑器撰写的文章
  • 多处备份,Notion+GitHub,暂不用担心数据丢失

不足

  • Notion的有些特性,Markdown可能不支持,所以写作时的结果和发表后的结果可能有差异。

例如如何嵌入HTML代码…添加Bilibili/YouTube/163等视频或音乐iframe媒体文件,Markdown导入Notion时,Notion给转成了embed类型,再导出Markdown的时候就全成链接了!!!麻了。。。解决方案也很简单,将iframe代码直接复制粘贴到Notion中粘贴为纯文本即可,记得检查Notion是否把链接给转成了引用。

Note: The scheduleevent can be delayed during periods of high loads of GitHub Actions workflow runs. High load times include the start of every hour. If the load is sufficiently high enough, some queued jobs may be dropped. To decrease the chance of delay, schedule your workflow to run at a different time of the hour.

  • 后期可考虑换为Webhook(更及时、节省资源) - 已支持,详情见:
Doradx/notion2markdown-vercel
Doradx
Created: 2023-04-18T02:53:33Z

特别鸣谢@王云子同学协助debug并完善此项目。

部署案例

后记

为了折腾自动化部署,fork 了notion-blog-action后,捣鼓了半天,重写 debug…已麻…近期肯定是不想再折腾了 😂

notion2markdown-vercel

由于前面配置的GitHub Actions通过crontab控制部署间隔,或手动调用。

当我想要提高部署的实时性时,面临以下几个问题:

  • 将定时任务间隔缩小:会大量消耗 GitHub Actions 的时间(每个月每个账号 3000 分钟)
  • 打开GitHub手动触发GitHub Actions:既繁琐又慢,我可不想在每次写完文章又打开 GitHub 一通乱点。

要么实时性较差,要么操作复杂。故为了方便博客同步,我采用Webhook触发GitHub Actions, 触发Notion同步Hexo部署

方案概览

部署后的工作流为:

  • 人工同步(实时性强,我最常用):每次写完 or 更新文章,点击 Notion 上的超链接,部署博客,等待约2分钟即可;

  • 自动同步(懒惰版):在树莓派部署了cron任务,每两分钟检查是否有文章需要同步,若有,直接触发 GitHub Action,发布约需5分钟

总的来说,部署不算快捷,但省事,手机端&电脑端都可以写作,写完将博文调为[待发布]状态即可。

快速部署

点击这里快速部署 Vercel!部署过程中需要填写以下环境变量:

环境变量列表

  • GITHUB_REPO: 你的博客代码仓库
  • GITHUB_USERNAME: GGitHub 用户名
  • GITHUB_TOKEN:GitHub 的 Token,很多人的博客是私有仓库
  • NOTION_DATABASE_ID:前面已经使用过的 Notion 数据库 ID
  • NOTION_TOKEN:前面已经使用过的 Notion 认证 Token

配置完成后,访问主页即可看到两个同步超链接,如:notion2markdown-vercel.vercel.app

实例页面,Actions即为目前支持的动作

将其链接复制后,配置到 Notion 主页面的描述栏,即可实现博主的效果。

博客更大的意义在于记录,而不是折腾各种工具。

目前对于这套流程较为满意,希望能加油产出内容!

主要参考