ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

QOwnNotes Web Companion 浏览器扩展完全指南:网页剪藏、跨浏览器书签管理与 Homepage 搜索建议集成

QOwnNotes Web Companion 浏览器扩展完全指南:网页剪藏、跨浏览器书签管理与 Homepage 搜索建议集成
  • 桌面应用

【免费下载链接】QOwnNotes

QOwnNotes is a plain-text file notepad and todo-list manager with Markdown support and Nextcloud / ownCloud integration.

项目地址:https://gitcode.com/gh_mirrors/qo/QOwnNotes
点击查看免费下载

QOwnNotes Web Companion 是官方出品的浏览器扩展,它把浏览器与桌面笔记应用连接起来,让你能够随时将网页内容或选中文本剪藏为笔记、截取整页截图,并把书签以 Markdown 形式存放在笔记中,实现跨浏览器、跨操作系统的书签统一管理。读完本文,你将掌握扩展的安装与安全令牌配置、Web Clipper 剪藏与脚本化扩展、书签链接语法与增删改机制,以及如何通过 Homepage 建议 API 在自建导航首页中复用同一套书签数据。

本文以仓库中的 浏览器扩展官方文档 为骨架,结合 WebSocket 服务端实现 与 书签解析实体 等源码进行纵深讲解。

功能总览:剪藏与书签,一个扩展全搞定

Web Companion 扩展提供两大核心能力:

  • 网页剪藏(Web Clipper):从浏览器页面捕获内容(整页或选中文本),并可附带当前页面的截图,以新笔记的形式写入 QOwnNotes。
  • 书签管理(Bookmarks):将浏览器书签以 Markdown 链接的形式存储在 QOwnNotes 笔记中,从而在不同浏览器、不同操作系统之间共享并完全掌控你的书签。

使用前有一个关键前提:QOwnNotes 桌面应用必须处于运行状态,扩展才能与之通信。不过整个过程完全离线——扩展通过本地 WebSocket 与桌面端交互,不需要任何互联网连接。从源码看,桌面端的 WebSocketServerService 只监听QHostAddress::LocalHost(本机回环地址),默认端口为 22222(调试版为 22223),见 getDefaultPort(),这也印证了离线、本机通信的设计。

安装扩展与配置安全令牌

获取扩展

按官方文档,扩展可从以下渠道获取:

  • Chrome Web Store(扩展 ID:pkgkfnampapjbopomdpnkckbjdnpkbkp)
  • Firefox Add-ons 页面
  • Web Companion 项目的 GitHub 仓库

安全令牌:扩展与桌面端的握手凭证

扩展与 QOwnNotes 桌面端通信使用**安全令牌(Security Token)**进行认证,配置步骤如下:

  1. 安装扩展后,第一次点击浏览器工具栏中的 QOwnNotes 扩展图标,桌面端会弹出包含安全令牌的对话框,复制该令牌。
  2. 进入浏览器的扩展管理页面,打开 QOwnNotes 扩展的详情。
  3. 将令牌粘贴到扩展的 "Security Token" 字段中,完成配对。

这一机制的底层逻辑在 processMessage() 中清晰可见:桌面端收到扩展发来的每条消息都会先校验其中的token字段;若令牌为空或不匹配,服务端会返回tokenQuery类型的响应,并在桌面端弹出WebSocketTokenDialog要求用户确认令牌,之后才继续处理后续消息。令牌本身由Utils::Misc::generateRandomString(8)随机生成(8 位随机字符串),并经 CryptoService 加密后存储在设置项webSocketServerService/token中。

隐私浏览(无痕)模式

如果你需要在隐私浏览窗口中使用扩展,必须在扩展的偏好设置中允许扩展在隐私窗口中运行,否则隐私窗口中的剪藏与书签功能将不可用。

Web Clipper 网页剪藏

在网页上点击鼠标右键(或先选中一段文本再右键),即可看到 QOwnNotes 的剪藏菜单:

  • 剪藏整页内容或选中的文本,QOwnNotes 会据此创建一篇新笔记;
  • 在剪藏的同时,可以对当前网页截取整页截图,并随笔记一起保存。

从源码层面看,剪藏的完整流程是:扩展通过 WebSocket 发送newNote(或handleRawData)类型消息,携带pageUrl、contentType、headline、text等字段;服务端先调用Utils::Misc::createAbsolutePathsInHtml把 HTML 中形如/my-page.html的相对链接转换为绝对链接(基于pageUrl补全域名),然后调用mainWindow->createNewNote(...)创建新笔记;对于 HTML 内容,还会调用insertHtmlAsMarkdownIntoCurrentNote将 HTML 转换为 Markdown 写入笔记,见 processMessage() 中newNote/handleRawData分支。

剪藏失效的排查清单

官方文档专门给出了 Web Clipper 不工作时的排查步骤:

  1. 确认 QOwnNotes 桌面应用正在运行——这是通信的前提;
  2. 确认扩展已用安全令牌完成配置——令牌不匹配时服务端不会处理剪藏请求(对应源码中的令牌校验逻辑);
  3. 确认在首次点击扩展图标时接受了浏览器的同意(consent)对话框;
  4. Firefox 用户特别注意:需要在扩展的“权限”设置中开启可选权限Access your data for all websites(访问所有网站的数据),否则右键菜单剪藏可能报错TypeError: chrome.tabs.captureVisibleTab is not a function——这是 Firefox 对tabs.captureVisibleTabAPI 的权限限制,只有授予该可选权限后截图功能才可用。

剪藏可脚本化:websocketRawDataHook

Web Clipper 不只是“傻瓜式”剪藏,它完全可脚本化:当扩展通过浏览器右键菜单发送数据时,QOwnNotes 会调用脚本钩子websocketRawDataHook,脚本可以拦截、改写甚至完全接管剪藏内容。

钩子签名如下(见 hooks.md 文档):

/** * @param requestType 请求类型,取值 "page"(整页)或 "selection"(选中文本) * @param pageUrl 发起请求的网页 URL * @param pageTitle 发起请求的网页标题 * @param rawData 传输的原始数据,requestType 为 "page" 时是 HTML,为 "selection" 时是纯文本 * @param screenshotDataUrl 网页截图的 data URL * @return true 表示数据已被脚本处理(此时不再创建新笔记),false 表示走默认剪藏流程 */ function websocketRawDataHook(requestType, pageUrl, pageTitle, rawData, screenshotDataUrl);

对应的服务端调用链位于 callHandleWebsocketRawDataHook():当消息类型为handleRawData时,服务端解析出requestType、pageUrl、pageTitle、rawData、screenshotDataUrl五个参数并调用钩子;若钩子返回true,则跳过默认的“创建新笔记”逻辑,说明数据已被脚本自行处理(见 websocketserverservice.cpp)。

仓库自带一个可直接参考的示例脚本 websocket-raw-data-selection-in-note.qml,它只处理selection类型的请求,把网页上选中的文本直接写入当前笔记:

function websocketRawDataHook(requestType, pageUrl, pageTitle, rawData, screenshotDataUrl) { // 只处理选中文本,整页请求忽略 if (requestType != "selection") { return false; } // 将页面选中的文本写入当前笔记 script.noteTextEditWrite(rawData); return true; }

书签管理:把书签装进笔记

如果你希望对浏览器书签拥有完全控制权,并在不同浏览器与操作系统间共用,QOwnNotes 扩展正是为此设计的。它的核心思想是:书签就是笔记里的 Markdown 链接,书签数据随笔记走,天然跨平台。

默认行为:当前笔记的链接

默认情况下,点击浏览器工具栏的 QOwnNotes 图标,扩展弹窗会展示当前笔记中的所有链接,这些链接会被自动打上current标签。这一行为对应源码中Bookmark::parseBookmarks(text, withBasicUrls)的“基本链接解析”分支(bookmark.cpp):形如[名称](http://...)的命名链接和形如<http://...>的裸链接都会被解析出来并标记为current,从而在扩展弹窗中呈现。

用笔记管理书签:bookmarks 标签与 Bookmarks 笔记

除了当前笔记,你还可以用专门的笔记管理持久书签:

  • 带有笔记标签bookmarks的笔记(标签名可在设置中修改)会被视为书签库,其中的链接会显示在扩展弹窗中,且可以附加标签(tags)和描述(description);
  • 新书签默认写入一篇名为Bookmarks的笔记(笔记名同样可在设置中修改)。

这两项设置的默认值在源码中一目了然:getBookmarksTag()读取设置项webSocketServerService/bookmarksTag,默认"bookmarks";getBookmarksNoteName()读取设置项webSocketServerService/bookmarksNoteName,默认"Bookmarks"(见 websocketserverservice.cpp)。新增书签时,服务端的createBookmarks()会向Bookmarks笔记追加- 名称 描述形式的 Markdown 行;如果该笔记尚不存在,会自动创建并打上bookmarks标签(见 createBookmarks())。此外,扩展还支持一键导入浏览器现有书签到 QOwnNotes。

书签链接语法

在bookmarks标签的笔记中,书签遵循以下 Markdown 语法,可以组合使用标签与描述:

- [页面名称](https://www.example.com) - [页面名称](https://www.example.com) #tag1 #tag2 - [页面名称](https://www.example.com) 仅一段描述 - [页面名称](https://www.example.com) #tag1 #tag2 描述与标签并存 * [页面名称](https://www.example.com) 列表符号 `*` 同样有效

底层解析逻辑见 Bookmark::parseBookmarks():正则([-*]\s+\[([^\[\]]+?)\]\(([\w-]+://.+?)\)(.*)$)匹配-/*开头的列表项,捕获链接名称、URL 与剩余文本;剩余文本中形如#xxx的片段被提取为标签,其余部分作为描述。也就是说,标签以#前缀、空格分隔,描述放在标签之后。

你还可以在扩展弹窗中按名称、URL、标签或描述进行搜索。至于当前笔记中正文里的其他链接,同样会被解析显示,但不带标签和描述(对应源码中withBasicUrls参数控制的两类解析路径)。

书签的增删改在底层如何完成

书签数据并非“只读快照”,在扩展里编辑或删除书签会真实回写笔记文件:

  • 新增:newBookmarks消息 → createBookmarks() 追加 Markdown 行并落盘;
  • 删除:deleteBookmark消息 → deleteBookmark() 在所有带bookmarks标签的笔记(以及Bookmarks命名笔记、当前笔记)中按 Markdown 文本精确匹配并移除对应行;
  • 编辑:editBookmark消息 → editBookmark() 在所有相关笔记中替换匹配的 Markdown 行。

删除与编辑完成后,服务端还会通知主窗口重载当前笔记,保证界面与磁盘内容一致。这也解释了为什么书签能“跨浏览器、跨系统”:书签本质是你笔记文件夹中的 Markdown 文本,只要同步笔记文件夹,书签就跟着走了。

进阶:用 Homepage 建议 API 把书签接入导航首页

扩展文档还提到一项衍生能力——Homepage 建议 API:QOwnNotes 可以暴露一个本地 HTTP 端点,供 Homepage。

在 QOwnNotes 中启用

  1. 打开设置 -> 浏览器扩展 / 命令片段(对应设置界面源码 webcompanionsettingswidget.cpp);
  2. 开启Enable socket server(启用 Socket 服务器,这是 WebSocket 通信的总开关,对应设置项enableSocketServer,默认开启,见 misc.cpp);
  3. 在Bookmark suggestion API分组中,勾选Enable Homepage-compatible bookmark suggestions API并设置端口。

服务只绑定到127.0.0.1(本机回环),不会暴露到局域网。端口默认值为22224(调试版为 22225),设置项为webSocketServerService/bookmarkSuggestionApiPort;勾选启用后,服务端会在该端口启动一个仅接受 GET 请求的最小 HTTP 服务(见 startSuggestionHttpServer() 与 processHttpRequest())。

端点与参数

  • 端点:GET /suggest?q=查询词
  • 可选参数:limit(返回条数,默认10,上限50,超出会被钳制,见 processHttpRequest())
  • 可选参数:token(若你在 QOwnNotes 中配置了安全令牌,则必须携带;令牌缺失或不匹配会返回401 Unauthorized,见 websocketserverservice.cpp)

注意,这里的“建议 API 令牌”与扩展通信令牌是两套独立令牌:建议 API 令牌存储在webSocketServerService/bookmarkSuggestionApiToken设置项中,为空时自动生成 32 位随机串并加密保存(见 getOrGenerateBookmarkSuggestionApiToken())。如果你使用了docs/homepage下的custom.js,需要把QON_TOKEN设为与 QOwnNotes 中配置的同一个安全令牌,脚本会在请求建议时自动附加&token=...。

响应是一个 JSON 数组,格式为[查询词, [建议1, 建议2, ...]]:

["home", ["Homepage", "https://example.com/home", "Some Home Link"]]

其中每一条建议可以是书签名称,也可以是书签 URL(匹配时按“前缀匹配优先、子串匹配兜底”的顺序返回,结果会去重并受limit约束,相关逻辑见 Bookmark::suggestionStrings())。为了减少开销,书签数据带有约 2.5 秒的缓存,建议响应也有最多 200 条的结果缓存(见 getBookmarksForSuggestions())。

Homepage 配置示例

在 Homepage 的配置中,将search块的suggestionUrl指向本地端点即可:

search: provider: custom url: https://example.com/search?q= suggestionUrl: http://127.0.0.1:22224/suggest?q= showSearchSuggestions: true

在标准 Homepage 安装中,把上述search配置块加入以下任一文件:

  • settings.yaml(Homepage 全局设置)
  • settings.yml(同上,视你的部署而定)
  • 挂载到容器内/app/config/settings.yaml的配置文件

如果你的 Homepage 部署把配置拆成了多个文件,请编辑已经包含searchprovider 设置的那个文件。

定制前端资产:custom.js 与 custom.css

仓库的 docs/homepage 目录提供了一套开箱即用的 Homepage 定制资产:

  • custom.js:拦截 Homepage 的搜索建议接口响应,从http://127.0.0.1:22224/suggest?q=<query>&limit=<QON_LIMIT>拉取 QOwnNotes 建议并合并展示;还会把“名称 + URL”成对出现的书签建议映射到实际 URL,点击时直接打开书签地址而不是把文本当搜索词提交,并防止 Homepage 客户端把合并结果硬性截断到 4 条。
  • custom.css:为 QOwnNotes 来源的建议行(CSS 类qon-suggestion)添加左边框与绿色文字,便于视觉区分。

custom.js顶部提供了几个可调参数:

参数默认值作用
QON_URLhttp://127.0.0.1:22224/suggest?q=QOwnNotes 本地建议 API 地址
QON_TOKEN空与 QOwnNotes 中配置的安全令牌一致(用于鉴权)
QON_LIMIT20每次请求获取的 QOwnNotes 建议数量
QON_LABEL[QON]建议文本前缀,用于在 UI 中标识来源
DEBUGfalse设为true时输出调试日志

使用要求:

  • 当你的 Homepage 部署支持加载custom.js/custom.css时,将这两个文件放到对应位置(例如 Homepage 实例的自定义资产目录),修改后建议强制刷新页面以加载新版本;
  • 如果 Homepage 运行在与 QOwnNotes 不同的机器/容器上,需要把这两个文件放到托管 Homepage 的那台实例上,它才能查询本机 QOwnNotes 的建议 API 并合并展示;
  • 启用安全令牌时,务必在custom.js中把QON_TOKEN设为与 QOwnNotes 相同的令牌,并保持suggestionUrl不变(脚本会自动附加令牌参数)。

安全提示

由于书签数据中可能包含敏感的 URL,若你需要让端点可被 localhost 之外访问,必须在端点前放置反向代理并加以访问限制(例如防火墙规则或白名单),不要把建议 API 裸暴露到公网。

相关文件导航

以下文件可以帮助你继续深入本文涉及的每个环节:

  • 官方英文版扩展文档:webpage/src/getting-started/browser-extension.md
  • Homepage 建议 API 文档:webpage/src/getting-started/homepage-suggestion-api.md
  • 剪藏钩子完整说明(含其他脚本钩子):webpage/src/scripting/hooks.md
  • 剪藏脚本示例:docs/scripting/examples/websocket-raw-data-selection-in-note.qml
  • WebSocket 服务与建议 API 服务端实现:src/services/websocketserverservice.cpp
  • 书签解析与建议匹配核心逻辑:src/entities/bookmark.cpp
  • “浏览器扩展 / 命令片段”设置界面:src/widgets/settings/webcompanionsettingswidget.cpp
  • Homepage 定制资产说明与示例:docs/homepage/README.md、docs/homepage/custom.js、docs/homepage/custom.css

掌握以上内容后,你就可以在 QOwnNotes 中搭建一套“浏览器剪藏 + 笔记书签库 + 导航首页搜索建议”的完整工作流:日常浏览时随手剪藏与截屏,书签统一沉淀在 Markdown 笔记里跨设备同步,回到 Homepage 导航页时又能直接搜索并打开这些书签,全程离线、数据完全归你所有。

  • 桌面应用

【免费下载链接】QOwnNotes

QOwnNotes is a plain-text file notepad and todo-list manager with Markdown support and Nextcloud / ownCloud integration.

项目地址:https://gitcode.com/gh_mirrors/qo/QOwnNotes
点击查看免费下载

相关推荐

上一篇:OpenPanel高级查询技巧:利用Clickhouse实现复杂数据分析
下一篇:MozStumbler 新手指南:地图界面、扫描指示与 10+ 设置项逐项详解

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进