利用Notion API+Github Actions回顾阅读的文章


前言

每天看着不断推送的手机消息,明知道其中有价值的并不多,但是又怕错过有价值的信息,这种心态在当今是一种很普遍的心态。因此,面对这种局面,如何摆脱海量信息的冲击和无价值信息的禁锢,是面对的一个艰巨的挑战。之前看到一篇文章——优化自己的信息源,建议主动获取信息。回想我的信息管理方法,差不多也是按照这个思路来的,一般是:

  • 收集:初步加上标签和分类;
  • 预处理:检视阅读,找出其中要点;
  • 深度阅读:阅读,加上摘要和思考内容;

最后这些标注和内容都汇总到我的notion数据库中,但是逐渐发现缺乏回顾的环节,手动去获取这些积累的信息,也存在实际操作性不强的问题,我是如何艰难地克服「效率成瘾」的?建议我们要自动化一些操作来提升效率。

因此,我希望通过自动化的方法来回顾我看过和思考的内容。

方案

整体设计

  1. Notion API自动化获取信息;
  2. Github Actions提供workflow;
  3. 微信接收——Notion打开;

说明

  1. 信息存储在Notion中,因此使用其提供的API实现自动化的获取;
  2. 具体的回顾方式:每天定时发送,因此需要事件触发机制——定时周期发送,这种实现方法有很多,本文采用Github Actions,因为免费且可用性很强;
  3. 接收方式:微信接收最方面,但是其SDK存在一些麻烦,因此一种间接的方式是通过发邮件到QQ邮箱,然后在微信中接收,然后利用默认浏览器打开Notion的链接;

具体过程

Notion API

本文不会介绍Notion。

这里使用Notion API来查询数据库。其中注意使用的是filter和sort。其中需要考虑的问题是:

  • 查询API endpoints的方法;
  • API响应结果的解析
    • 这个需要进行测试,我感觉Notion给出的API文档说的不够清楚,需要自己去试,可能会出现很多问题;
    • 这里我使用postman进行接口的测试;
    • 还有一个要吐槽的是:Notion API中好像没有获取整篇文档的接口和选择,只能获取page的url;

Github Actions

1. 触发事件

  1. 手动出发:便于调试;
  2. 定时触发:schedule 其中需要crontab表达式,不太了解的可以参考这里

2. 设计actions

本文设计了两个workflow,其实也不一定这样设计,主要我是为了多了解一下Github Actions的使用,如果你觉得麻烦可以放到一个workflow里,说到这里,想起之前看到的一篇文章——新技术学习不完全指北:以 Rust 为例。其中有一个观点,超纲训练是巩固知识的可靠方式,我这里也算超纲训练一下。

第一个workflow用来获取Notion中的信息,使用Notion提供的JavaScript SDK实现,具体包括:

  • 查询Notion database,并根据属性过滤和排序文章列表,以实现随机获取文章;
  • 生成文章摘要模板,用于后续的邮件发送;

第二个workflow主要是利用上一个workflow生成的信息并发送邮件,其中需要实现:

技术细节

重用workflow

由于本文设计了两个workflows,从程序设计的角度看,其实是为了解耦以实现重用已有的workflow。类似于函数的设计,需要遵从一定的规范,比如:为了安全性,有些函数通过加限定符规定只能被同一个模块下的函数调用。Github Actions中也有类似的规定,与其说这些workflow像函数,不如说它们更像RPC。每个workflow都可以包含一个或者多个jobs,也就可以视为一个或者多个进程。

为了重用可共享的workflow,要求:

  • 需要复用的workflow支持 workflow_call 出发事件;
    name: notion-article-query
    
    # Controls when the workflow will run
    on:
      workflow_call:
    

这样,此workflow才能在别的workflow中使用,该workflow只能在别的workflow的jobs中使用,而不是steps。并且需要满足一定的条件,即如下其一:

  • 两个workflows需要在同一个目录下;
  • 被重用的workflow需要存储在共有仓库并且组织允许你使用这些公有仓库;
name: notion-article-review

on:
  schedule:
    - cron: '0 4 * * *'
  workflow_dispatch:
jobs:
  article-query:
    uses: ./.github/workflows/notion-article-query.yml
    secrets: inherit
  article-review:
        runs-on: ubuntu-latest

更多复杂的功能可以参考Github Actions的文档

jobs之间共享数据

首先从直觉上来看,不同的jobs可能在不同的虚拟机上,因此通过文件等方式是无法完成数据是共享的,这与RPC也是类似的。照着这个思路来想:

  • 引入第三方 两者的区别主要是:

    Caching is used to re-use data/files between jobs or workflows while Artifacts are used to save files after workflow ended.

    可以参考这里
  • workflow执行返回
    • 使用命令行:定义jobs的输出可以使用命令行的方式,官方直接给出例子,其中的命令是Github Actions专有的命令,可以参考文档 Workflow commands for GitHub Actions,告诉你怎么完成output的设置;
      echo "::workflow-command parameter1={data},parameter2={data}::{command value}"
      
      这一点本文没有使用。
    • 使用JavaScript:这种适合复杂逻辑的场景,本文使用这种方式,通过引入@actions/core 完成输入和输出的设置,本文利用这个实现文章摘要的传递。
      const core = require("@actions/core")
      let context = `
        <html>
         <head>
          <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
         </head>
          <body>
            <p>题目:${title}</p>
            <p>标签:${tags}</p>
            <p>总结:${summary}</p>
            <p>链接:<a href="${url}">文章内容</a></p>
          </body>
        </html>
      `;
      core.setOutput('article-item', context)
      
      注意,这是一个step中实现的输出,为了在重用的workflow中输出数据,需要将steps中的输出映射到jobs中,如下:
      on:
        workflow_call:
          outputs:
            article-item:
              description: "article items"
              value: ${{ jobs.query-article.outputs.output1 }}
      jobs:
        query-article:
          outputs:
            output1: ${{ steps.query-step.outputs.article-item }}
          steps:
            - name: Query Notion Articles
              id: query-step
                      # 对应上述index.js的执行和输出
              run: npm install && npm run server
      
      在其他的workflow中使用时,如下:
      jobs:
        article-query:
          uses: ./.github/workflows/notion-article-query.yml
          secrets: inherit
        article-review:
          needs: article-query
          steps:
            - name: send mail
              uses: dawidd6/action-send-mail@master
              with:
                html_body: ${{ needs.article-query.outputs.article-item }}
      
      其中needs 是用于编排不同的jobs的,后续会说明,直接引用这里使用的workflow并获取对应的输出的参数即可。

编排jobs

如果没有加限制,不同的jobs之间是独立的,例如上述的两个workflow作为两个jobs使用时,如果不加限制,article-review可能无法获取article-query的article-item结果,因为它可能先执行结束,因此需要 needs 来保证不同的jobs的执行顺序,从而构建一个dependency graph,使得不同的jobs之间可以串行、并行等。

本文需要保证 article-review 在article-query之后执行,因此需要needs来维护依赖关系。

注意secrets

存储secrets

敏感的信息保证不存在在代码中,Github提供一种不公开的方式,同时还定义了不同的粒度,可以参考具体文档

Untitled

使用secrets

这些secrets可以作为环境变量在workflow中使用,这里需要使用Github Actions提供的 secrets context实现,具体参考文档,代码如下:

name: Query Notion Articles
    id: query-step
    run: npm install && npm run server
    env: 
      # Required mail server address:
      NOTION_API_KEY: ${{ secrets.NOTION_API_KEY }}
      # Required mail server port:
      DATABASE_ID: ${{ secrets.ARTICLE_DATABASE_ID }}

不同workflow之间传递secrets

这个问题可能很少有人提到,我在构建的时候遇到这个问题,在重用已有的workflow时,如果也存在secrets需要保密,需要在调用workflow中声明引用的workflow将集成本workflow下的所有secrets,操作如下:

jobs:
  article-query:
    uses: ./.github/workflows/notion-article-query.yml
    secrets: inherit
 
  article-review:
        runs-on: ubuntu-latest

具体细节可以参考文档

邮件模板

本文只是设计了一个简单文章摘要,包括:

  • 题目
  • 标签
  • 总结
  • 文章内容的url;

一种锦上添花的操作是使用HTML Email,阮一峰专门针对这个写了一篇文章,可以参考。

总结

整个项目的代码在仓库,最终的结果如下:

Untitled

总的来看,这个过程:


文章作者: alex Li
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 alex Li !
  目录