Popclip Extension Development - 摘要记录 Notion Digest、Translate开发

AI 摘要: Popclip是一款Mac上的实用工具,提供了快速处理文本的方式。通过Popclip插件,用户可以在选中文本时显示自定义操作菜单,包括翻译、笔记、概念解析等功能。其中常用扩展有Bob Translate用于长文本翻译和Wikipedia查询、NotionDigest用于将选中的内容自动记录到Notion的摘要页面、中英文互译等。Popclip能够满足日常工作中的翻译、概念解析和摘要记录等需求,避免了切换App的开销,提高了效率。扩展的开发可以根据个人需求进行定制,使用Typescript和JS相关前端知识进行开发。

1. Popclip 背景诉求

在个人日常使用 Mac 浏览 Web 网站进行工作、学习过程中,经常会遇到一些需要翻译、概念解析、摘要记录的操作,通常这些操作行为会由不同的软件提供服务,比如:

  • 翻译:使用 Google 翻译、Eduic 词典(取词)、Chrome 沉浸式翻译等
  • 笔记:使用 Notion 记录一些摘要
  • 概念:通过 Wiki、Google、ChatGPT、OpenAI 等快速了解一个概念
  • 时间:通过 Alfred 脚本、Shell 命令进行时间戳\标准时间生成
  • Base64Encode\Base64Decode:通过一些 tool 工具网站编解码或者是 Shell 进行操作,类似echo amlhY2hlbm90ZQ==|base64 --decode

问题: 这些日常常规过程避免不了要在 Chrome 浏览器和第三方 App 之间(例如 Notion)来回 复制-切换-粘贴-检索Cmd+CCmd+TabCmd+V),例如你对 PopClip 不了解,你可能要复制关键词Popclip到 Google 或 Baidu 搜索栏进行信息检索-筛选,当然也可能使用 ChatGPTOpenAI+Prompt 快速获取Popclip这个组件概念,总之避免不了要使用Cmd+Tab按键在不同 App 或者 Web 到 Tab 之间进行来回切换,对希望沉浸式阅读、工作或学习还是有一定效率影响

诉求: 希望在沉浸式阅读、学习时候,不管是翻译、摘要记录等操作,尽可能少的在多 App 之间进行切换,以提升学习效率

1.1. Command-Tab Plus

为此,之前我还购买过一个在 Mac 下的Command-Tab Plus版本软件,支持通过Cmd+Tab+Number快速切换到特定的 App,虽然 Command-Tab Plus 在切指定 App 可以加速,但没有解决切换 App 带来的开销问题,而且 Command-Tab Plus 还接管了默认的 Command+Tab 操作,有时候会卡顿,同时一旦开的 Mac App 过多图标就缩小看不清了,最后放弃了该软件使用

1.2. 尝试寻求其他解决问题办法

因为日常工作会深度使用 Mac,为了在浏览 Web 网站更顺畅、无 App 切换的翻译或者 Wikipedia 某个概念,在这个背景需求驱动下,2022 年左右接触到 Popclip 这个 Mac 组件,突然发现这个就是自己一直在寻找的产品;

后续接触到 Bob Translate,以及Google 沉浸式翻译等扩展组件,加上 2023 年ChatGPT以及OpenAPI大模型的能力,基本初步解决了在阅读英文站点和 Wiki 某个概念的问题,参考之前的文章: Chatgpt Tips - ChatGPT 使用(持续更新)# OpenAI For Translation

2. Popclip 简要介绍

PopClip 是一款 Mac 上的实用工具,它为用户提供了一种快速处理文本的方式。PopClip 插件是为了增强 PopClip 功能而开发的扩展,可以在用户选中文本时显示自定义操作菜单

默认情况下,popclip 已经提供了丰富的插件,基本满足了大多数文本选择的操作,相关插件安装文档: https://pilotmoon.com/link/popclip/get-extensions

2.1. Popclip 常用扩展

Bob Translate

依赖Bob Translate 扩展,充当长文本翻译、Wikipedia,对接了 OpenAPI,官网教程: https://bobtranslate.com/guide/

NotionDigest

Notion 摘要扩展,当通过将选中内容通过摘要记录后,就会自动将内容、引入来源、记录时间按照倒排方式,结构化地记录到 Notion 的指定页面, 这也是和官方提供的 Notion 主要的一个差别,官方提供的扩展是从 Page 页的最底端追加

摘要汇总后,方便自己定期的回顾和汇总相关信息,而非仅仅加入到收藏夹 ,这点和《认知觉醒》中知识内化的过程和思想是一致的

中英文互译

这个是基于 PopClip 开源的 InstantTranslate.popclipext Copy 了一份做了 Icon 和部分 Config 的修改,主要是 For 精短的文本互译

其他

  • Search:搜索相关
  • OpenLink:打开某个 URL
  • UnixTime:之前做结算相关,很多 UnixTime 时间需要转换,这个插件节省了蛮多时间

2.2. 日常需求覆盖

目前 Popclip 已经在下述场景下能够极大避免我切换 App,尤其是下述几个核心场景:

  1. 选择一段内容,通过 OpenAI 快速了解一个概念(Wiki)
  2. 选择一段内容,快速完成中英文互译
  3. 看到不错的摘要,加入到 Notion 笔记中后续总结

3. Notion Digest 扩展开发

这部分主要记录下清明几天折腾 PopClip 的过程,因为 PopClip 扩展支持和原生 App、Shell 脚本、Js 代码、Js App 交互

官网文档参考: https://www.popclip.app/dev/

3.1. PopClip 扩展开发

扩展介绍

Popclip 扩展有两类:

Snippets 代码片段(以 Yaml 或 Json 单个文件配置的,适合简单脚本),以及 Packages 包(以.popclipext结尾的文件夹称为包,适合复杂的脚本),两者差异比较: https://www.popclip.app/dev/

扩展支持多种操作类型

扩展也支持规则筛选,仅在满足特定条件下才展示 Pop 操作

扩展源码

参考: https://github.com/pilotmoon/PopClip-Extensions.git

相关 PopClip 源码位置: source位置:

NotionDigest.popclipext 包扩展

源码包: https://github.com/lupguo/PopClip-Extensions/tree/feat/notion-digest-20240408/source/NotionDigest.popclipext

  1. source 下创建 NotionDigest.popclipext 文件夹
    1. source-contrib - 用户提交和实验性扩展的文件夹
    2. source - 已发布扩展的来源(由 poplitman 维护和支持)
  2. Config.json 扩展配置文件: https://www.popclip.app/dev/config#top-level-properties
  3. Popclip Action 入口函数
  4. build.sh 构建脚本
  5. 扩展修改 - Translate

Config.json 配置

参考: https://www.popclip.app/dev/config#top-level-properties

 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
{
  "name": "Notion Digest", // 扩展名称
  "identifier": "tkstorm.popclip.extension.notion-digest", // 扩展唯一表示,开发阶段不能以com开头
  "description": "Save helpful notes to your Custom Notion Page sorted in descending order.",
  "popclip version": 3785,
  "icon": "iconify:mingcute:quill-pen-line", // 扩展icon,可以在iconify站点寻找对应的图标
  "entitlements": ["network"], // 因为使用了axios包将摘要信息发到Notion,所以扩展依赖网络能力
  "captureHtml": true,
  "module": "digest.bundle.js.lzfse", // 这里可以支持module.js,.lzfse文件是通过build.sh中压缩处理过的结果
  "options": [
    // 扩展配置选项,这里需要3项: secrets、pageId、blockId
    {
      "identifier": "secrets",
      "label": "Your Notion integrations Secrets",
      "type": "string",
      "description": "Obtain a Secrets from: https://www.notion.so/my-integrations"
    },
    {
      "identifier:": "pageId",
      "label": "Notion pageId",
      "type": "string",
      "description": "Save digest content to this page id, PopClip must have access permission to the page."
    },
    {
      "identifier:": "blockId",
      "label": "Notion first blockId",
      "type": "string",
      "description": "Save digest content after this block id: https://developers.notion.com/reference/patch-block-children"
    }
  ]
}

Options 对应配置

参考: https://www.popclip.app/dev/config#option-types

3.2. Notion Digest 工作基本流程

1
{chrome\app\...} --> [popclip] -(select text)-> [digest.js extension <markdown to notion blocks>] --> [Notion HTTP API<secret+pageId+blockID>]-> [Notion]

PopClip 扩展开发文档参考

  1. 官方文档: https://www.popclip.app/dev/#development-environment
  2. 开源仓库: https://github.com/pilotmoon/PopClip-Extensions.git

3.3. Notion 应用创建以及 RESTAPI 调试

  1. 申请应用,开发相关授权(获取页面信息、获取用户信息), 参考: https://developers.notion.com/reference/capabilities
  2. 提取&保存密钥,用于 RapidAPI\Postman 调试
  3. 使用 RapidAPI 进行测试(获取用户接口,确保 RestAPI 请求正常)
  4. 打开 Notion,对摘要页面进行扩展集成连接(Connetion)
  5. RapidAPI 模拟搜索请求(查询接口信息)
  6. 将保存消息摘要的 Notion Page 授权 Notion-Digest 应用

Notion 应用 API 文档参考

3.4. Notion Digest 扩展配置

Notion Digest 包含参数:

Notion’s Secret

Obtain a Secrets from: https://www.notion.so/my-integrations

Digest’s PageID

首先要获取一个页面 ID,再通过 copy link → 转 uuid 得到页面的 ID,提取页面 pageId 信息 fac77968cbd4410ea2204aafc7063807

获取到 Link: https://www.notion.so/hold7habits/Message-Digest-fac77968cbd4410ea2204aafc7063807?pvs=4

Page First BlockID

1
2
3
curl "https://api.notion.com/v1/blocks/{pageId}/children?page_size=1" \
-H 'Authorization: Bearer {Your_Notion_Secret}' \
-H 'Notion-Version: 2022-06-28'

Response : get first blockId 8fefee27-d477-44b1-aeea-f9cd5a5814c2

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
{
  "object": "list",
  "results": [
    {
      "object": "block",
      "id": "8fefee27-d477-44b1-aeea-f9cd5a5814c2",
      "parent": {
        "type": "page_id",
        "page_id": "fac77968-cbd4-410e-a220-4aafc7063807"
      }
      ...
    }
  ],
  "request_id": "58ee3246-84c5-432b-a018-3834dc3c5de2"
}

3.5. Typescript、JS 相关前端知识学习

这部分内容基本都是基于 ChatGPT 协作下完成的,具体代码开发环节 Google 很少,例如 tsc、onwatch、相关工具和 js 包使用等(npm、async、await、promise、axios 包使用)

  • npm 和 npx 区别: 一个是包安装,一个是执行临时工具或命令
  • browserify: 用于在浏览器端使用类似于 Node.js 的模块化开发方式,核心功能 CommonJs 模块化规范支持、依赖解析、压缩分割代码等插件系统
  • promise - JavaScript 中用于处理异步操作的对象,它代表一个异步操作的最终完成或失败,并返回结果值,避免了回调地狱(callback hell)的问题
    • 状态:Promise 对象有三种状态:pending(进行中)、fulfilled(已成功)和 rejected(已失败)。状态一旦改变就不会再变。
    • 回调:Promise 可以注册两种回调函数:成功时的回调(then  方法)和失败时的回调(catch  方法)。
    • 链式调用:Promise 可以通过链式调用的方式处理多个异步操作,每个  then  方法返回一个新的 Promise。
  • async、await - 使用  async  和  await  可以让异步代码看起来更像同步代码
    • asyncasync  关键字用于定义一个函数是异步的。当函数被调用时,它会返回一个 Promise 对象,无论函数内部是否显式地返回 Promise。
    • awaitawait  关键字只能在  async  函数内部使用,它用于等待一个 Promise 对象的解决。当遇到  await  关键字时,代码执行会暂停,直到 Promise 对象解决后才会继续执行后续代码
  • 日期转换: 获取当前日期字符串格式
  • 文件监听: 监听文件文件变更使用 onchange,监听 node.js 应用程序文件变更使用 nodemon
  • typescript: tsc 编译工具、typescript 初始化(tsconfig.json)
  • JSON 对象和字符串转换: JSON.stringify - 将 js 对象转成 json 字符串、JSON.parse - JSON 字符串转换为对应的 JavaScript 对象

4. 总结

  1. 好的软件是容易扩展和生态丰富的,Respect - Popclip
  2. 想到什么积极去做就好,花了 3 天时间完成 Notion Digest开发 - Popclip 扩展开发
  3. 带着问题去学习和实践,效率会更高效,遇到问题解决问题 - 拥抱 OpenAI
  4. 先完成再完美,不要想着一步登天 - 《如何成为不完美主义者》、《微习惯》