利用 iOS 的 shortcuts 功能和 GitHub 的 rest API 我们可以轻松的从手机上直接发布博客内容到GitHub pages 上。

用 github action 自动编译博文

在 github pages 上我们需要编译好的静态网站用于发布,所以除了博客站点外,我们还需要一个存放 markdown 的源码 repo,并由 github action 来触发编译。

我选用的博客框架是基于 hugo 的,所以我可以简单的引入 action hugo-setup 来应用这个过程,具体的就是在代码目录的 .github/workflows/ 下创建 action.yml 文件,如下 (我的在 .github/workflows/deploy.yml )

name: deploy

on:
  push:
    branches:
    - master

jobs:
  deploy:
    runs-on: ubuntu-20.04
    concurrency:
      group: ${{ github.workflow }}-${{ github.ref }}
    steps:
      - uses: actions/checkout@v3
        with:
          submodules: true  # Fetch Hugo themes (true OR recursive)
          fetch-depth: 0    # Fetch all history for .GitInfo and .Lastmod

      - name: Setup Hugo
        uses: peaceiris/actions-hugo@v2
        with:
          hugo-version: '0.68.3'
          extended: true

      - name: Build
        run: hugo --minify

      - name: Deploy
        uses: peaceiris/actions-gh-pages@v3
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          publish_dir: ./public

这个 action 会在我们每次把新的 markdown 文件的修改被 commit 到 github 上时,自动激活编译,发布生成的网站到 github pages 上。

注意这里最后一个步骤 Deploy 中使用了 actions-gh-pages ,他这里默认会把编译好的站点法到 branch: gh-pages 上,如此,我们只需要把 github pages 的 repo 中设置的 branch 为 gh-pages ,并把博客站点的源码放在同 repo 的 master 分支,一举两得一个 repo 就能同时存放源码和发布站点了。

用 github api 新建文件或更新文件

首先我们需要有 GitHub personal access token,可以在 github 的 settings → Developer Settings → Personal access token 中生成。

Github rest API 中创建一个新文件的 api 是

PUT https://api.github.com/repos/:user/:repo/contents/:path-to-file
Authorization: Bearer [personal-access-token]
Accept: application/vnd.github.v3+json
Content-Type: application/json

{
    "message": "the-commit-message",
    "committer": {
        "name": "your-name",
        "email": "your-email"
    },
    "content": base64encode("your-file-content")
}

这里需要注意的是, content 所提交的内容是 md 文件的文本内容用 base64 进行 encode 后的内容。

而如果是更新已有文件,则再需要在上述参数中添加已有文件的 sha 值,获取 sha 值的方式则是使用 get 方法获取

GET https://api.github.com/repos/:user/:repo/contents/:path-to-file
Authorization: Bearer [personal-access-token]
Accept: application/vnd.github.v3+json
Content-Type: application/json

并在 PUT 请求时,加上当前文件的 sha 值

PUT https://api.github.com/repos/:user/:repo/contents/:path-to-file
Authorization: Bearer [personal-access-token]
Accept: application/vnd.github.v3+json
Content-Type: application/json

{
    "message": "the-commit-message",
    "committer": {
        "name": "your-name",
        "email": "your-email"
    },
    "content": base64encode("your-file-content"),
    "sha": "sha-value-of-current-file-from-get-api"
}

使用 ios shortcuts 提交文件到 github 上

大致的思路是,从 markdown 编辑器中,通过 share menu 分享文件,由 shortcuts 接收,执行脚本,先请求远程看是否有 sha 文件存在,如果有则更新之,否则创建一个新的文件(区别就是请求时带不带 sha )。

具体步骤如下:

  1. Receive File from Share Sheet
  2. Get text from Shortcut Input (读取文件内容)
  3. Encode Text with base64 ( 注意,这里需要选择 line breaks: none )
  4. Set varaible content to Base64 Enconded
  5. Get name of Shortcut Input (这里是重新获得文件名)
  6. Set variable fileName to Name
  7. Text https://api.github.com/repos/:user/:repo/contents/content/posts/[fileName].md (这里是组织出请求的 URL ,由于我这里使用的是 hugo 所以指定上传位置在 /content/posts/ 下)
  8. Get URLs from Text
  9. Get contents of URLs (这里是一个 Get 方法的请求,用于查看文件是否已经存在)
  10. Set varaible responseJson to Contents of URL
  11. if responseJson contains sha
  12. Get Value for sha in responseJson ( 把 sha 值取出来 )
  13. Get contents of URLs (这里请求带 sha 的 PUT 方法)
  14. Otherwise
  15. Get contents of URLs (这里请求不带 sha 的 PUT 方法)
  16. End if

这样我们就可以在任何一个 markdown 编辑器中,将我们的博客文件推送到 blog source code repo 中,并激活 github action 启动自动发布,将博文发布在 github pages 上了。

后记

这个方法可以让所有的 markdown 编辑器支持发布博客文章,但有个缺点是必须要有文件名。中文博客的一个难题是不能像英文博客一样,直接拿 title 自动生成文件名(当然也不不行,但很难看也很难管理),所以许多的只支持档案而不是文件编辑的工具就不适合这套了。

另外,现在市面上好用的 markdown 编辑器其实也没这么多,很多也不顺手。如果能直接拿苹果的 Notes.app 的 rtf 转成 markdown ,再由这个 workflow 发布成博客,那是非常有趣的。然而遗憾的是,现在 shortcuts 里自带的 rich text to markdown 的转换指令遇到中文就会乱码,无法使用。后续或许可以找个三方工具再适配一下(不知道 ios 上有没有 pandoc )