Skip to main content

笔记自动发布

5 min read

开始使用 note 做笔记后,大事小事都记录在笔记里,已经不怎么屁大点事都会发博客了。

痛点在于,需要手动同步文章和关联的图片到博客项目,push 到 github 后,触发自动部署更新静态页面。

想做一个类似点击公开,自动分享到博客项目的持续继承功能。

设想如下:

  • 本身 markdown 有 attribute 数据。
  • 增加 article: true 表示是需要发表到博客的项目。
  • 每次提交的时候,通过 github 提供的免费的 CI 功能 actions,扫描带有 article: true 的 markdown 文件,发送到博客项目单独分支。
  • 博客项目生成一个 pr , 方便检查文章格式等,通过人工审核后,同意合并至 master 分支,更新静态页面。

下面讲讲各个步骤细节,方便大佬们抄作业。

博客项目 同步相关

博客相关 actions 配置

  • 需要获取一个提交用的 github token , 我这里设置的名称为 blog_sync
name: sync-note
on:
push:
branches:
- develop # Change this to your default branch
paths:
- "note/docs/articles/*.md"
jobs:
make-html-send-email:
name: make-time-file
runs-on: ubuntu-latest
steps:
- name: get blog repository
uses: actions/checkout@master
- run: |
cd ..
git config --global user.email "z740713651@outlook.com"
git config --global user.name "AngusWG"
git config --global credential.helper cache
git clone https://${{secrets.blog_sync}}@github.com/AngusWG/AngusWG
cd AngusWG
git checkout dev_auto 2>/dev/null || git checkout -b dev_auto

- name: cd into note repo
run: cd ../WG & pwd

- name: install python script requirement
run: pip install .

- name: run the script sync note to blog repo
run: python wg sync_note note /home/runner/work/WG/AngusWG/docs

- name: commit note
run: |
cd /home/runner/work/WG/AngusWG
git add .
git commit -m "sync note $(date +"%Y-%m-%d %H:%M:%S")" || true
git push origin dev_auto

同步博客的 python 脚本

  • 直接用的话 需要做入参适当修改。
  • 设置 article: true 的文章会自动发表到博客。
  • 当 date 不一样时,会自动同步笔记的内容到博客。

需要笔记文件夹和博客有以下目录结构

  • sorce_note_dir: 笔记文件夹
    • articles: 可以发布的文章文件夹
      • a.md (article: true)
      • b.md (article: true)
      • c.md (article: false)
    • images: 笔记图片文件夹
      • a1.png
      • a2.png
      • c1.png
  • target_note_dir: 笔记文件夹
    • articles: 已经发布的博客文件夹
      • a.md (article: true)
      • b.md (article: true)
    • images: 博客图片文件夹
      • a1.png
      • a2.png
#!/usr/bin/env python
# encoding: utf-8
# @Time : 2022/04/18 18:22:22
# @author : zza
# @Email : z740713651@outlook.com
# @File : sync_markdown_note.py
"""同步笔记用"""

import os
import frontmatter
import re
import shutil

default_dir = "articles"
article_attribute = "article"

def _need_sync(file_path: str, output_dir: str) -> bool:
"""
判断是否要同步笔记

1 笔记里存在 属性 publish:true
2 笔记日期 > 已发布笔记日期
"""
post = frontmatter.load(file_path)
# publish
if not post.get(article_attribute):
return False
# update date
old_file = os.path.join(output_dir, default_dir, os.path.basename(file_path))
if os.path.exists(old_file):
current_date = post.get("date")
old_date = frontmatter.load(old_file).get("date")
if current_date == old_date:
return False
return True

def sync_pic(file_path: str, output_dir: str) -> None:
"""copy pic to output dir"""
# find pic in markdown file
with open(file_path, "r", encoding="utf-8") as f:
markdown_body = f.read()
pic_str_list = re.findall(r"\!\[.*\]\((.*)\)", markdown_body)
for pic_str in pic_str_list:
print(f" find pic {pic_str}")
pic_file = os.path.join(os.path.dirname(file_path), pic_str)
if not os.path.exists(pic_file):
continue
# copy pic
output_pic_file = os.path.join(output_dir, "images", os.path.basename(pic_file))
print(f" copy {os.path.abspath(pic_file)} to {output_pic_file}")
shutil.copyfile(pic_file, output_pic_file)
return

def handler_file(root: str, file: str, output_dir: str) -> None:
"""处理单个 markdown 文件"""
file_path = os.path.join(root, file)
if not _need_sync(file_path, output_dir):
return
# copy file
output_file_path = os.path.join(output_dir, default_dir, file)
print(f"copy {file_path} to {output_file_path}")
shutil.copyfile(file_path, output_file_path)
# copy pic
sync_pic(file_path, output_dir)

def main(
markdown_path: str = r"E:\PycharmProjects\WG\note",
output_dir: str = r"E:\PycharmProjects\AngusWG\docs",
) -> None:
"""
遍历 note 文件夹 articles 文件夹下所有的 md 文件

并同步到另一边文件夹下的 articles 文件夹下
- sorce_note_dir: 笔记文件夹
- articles: 可以发布的文章文件夹
- a.md (article: true)
- b.md (article: true)
- c.md (article: false)
- images: 笔记图片文件夹
- a1.png
- a2.png
- c1.png
- target_note_dir: 笔记文件夹
- articles: 已经发布的博客文件夹
- a.md (article: true)
- b.md (article: true)
- images: 博客图片文件夹
- a1.png
- a2.png
"""
# walk directory
root = os.path.join(markdown_path, default_dir)
for file in os.listdir(root):
if file.endswith(".md"):
handler_file(root, file, output_dir)

if __name__ == "__main__":
main()
# handler_file(
# r"E:\PycharmProjects\WG\note\docs\创作",
# "笔记自动发布。md",
# r"E:\PycharmProjects\AngusWG\docs",
# )

博客项目生成 pr

name: SYNC NOTE
on:
push:
branches:
- dev_auto
jobs:
SYNC_NOTE:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
ref: master
- run: ls
- name: Reset main branch
run: |
git fetch origin dev_auto:dev_auto
git reset --hard dev_auto
- name: Create Pull Request
uses: peter-evans/create-pull-request@v4
id: cpr
with:
commit-message: publish note to blog
title: sync note pull request
body: $(date +"%Y-%m-%dT%H:%M:%S%z")
branch: dev_auto
base: master

小坑:

报错 Branch 'X' no longer differs from base branch 'Y'

actions 好像将本地的分支提交一次,最开始的时候写错了, 导致反向 master 覆盖了 dev_auto 分支, 然后因为没有 git fetch ,认为无修改不生成 pr。 看 action 日志+看 issus 解决的。 action 的运行方式有点想当然了。

总结

最开始想用 tag: publish 去识别是否要发布,但是刷 attribute 的脚本不支持增加,支持覆盖, 想了想还是新弄个属性,反正人也看不到。

目前还有一个问题是,这个 action 是每次提交就会检测一遍,然后装 python 依赖的时候,其实挺慢的, 找了一下,并没有限制最小部署间隔的参数(有知道的小伙伴请告诉我)想想机器又不累,不要在乎这么多。

Loading Comments...