当前浏览器过旧,页面样式无法完整呈现。请使用 Chrome、Edge、Firefox 或 Safari 访问。
全部文章
一个能直接开工的 Chrome 扩展:formant

一个能直接开工的 Chrome 扩展:formant

formant 把翻译、New Tab、书签、代理、站点数据、GitHub 打包、V2EX、自动翻页、鼠标手势收进一套 Chrome MV3 扩展。后来又补了 linux.do 换皮、X 时间线翻译、Telegram 保存、freefq 导出 TXT、huavod 开控制台。设置走 option 面板,密钥放 mono,云端按 Client API Key 隔离。manifest 现在是 1.8.71。

写一个扩展功能不难。难的是把日常那一堆需求塞进一个壳子,还别互相踩。

翻译要弹窗、划词,新标签页想看天气汇率,书签得同步到自己的服务。GitHub 偶尔打包下个目录,V2EX 想自动签到,长列表懒得点下一页。代理、扩展开关、站点 Cookie 又不想再装四五套。每样单独装一个,图标能挤满工具栏,权限重复,设置散得到处都是。从零写倒也能写,就是 Service Worker 说停就停、右键菜单互相覆盖、content script 把宿主页样式搞脏,这些坑得反复踩。

formant 冲着这件事做。Chrome Manifest V3,原生 HTML / CSS / JS,后台走 Oolaf mono 的 Client API。常用能力已经串进去了,空壳演示按钮那种先别指望。

插件首页

设置用一套 option.html 挂多个面板。总开关在 #features,细节进对应锚点。工具栏图标始终打开 formant popup,不把入口让给某个子模块。后来功能加多了,popup 里也能进书签、站点数据、扩展管理;二级页顶栏统一成返回翻译加当前标题,操作放下面工具条,免得小窗口里再叠一套顶栏。

功能
翻译

密钥不进扩展仓库。本机只存 mono 地址、一把 Client API Key;GPT、百度、天气这些放 Admin 的 Formant 配置组。翻译失败链路写死了:Google 直连不行走 mono Google,再不行百度。词库打分用合并后的结果,不拿一份静态表当唯一真相。

Google 直连现在走 translate-pa.googleapis.com/v1/translate(gtx)。这条挂了,仍退回 mono Google。

划词面板、GitHub 下载进度、AutoPagerize 状态条、手势轨迹,尽量都进 Shadow DOM。页面通信走 chrome.runtime / chrome.tabs,密钥不塞进 content script。Service Worker 按随时会被杀掉来写,重要状态落 chrome.storage。

代码按模块拆:翻译、词库、New Tab、书签、GitZip、V2EX、自动翻页、代理、扩展管理、站点数据、鼠标手势,各有 bridge、option 面板。新能力往面板上挂,不为单项另开独立设置页。自有源码单文件卡在 500 行附近,background、popup 不无限胀。

翻译、词库

入口就那些:popup 输入框、划词浮标、右键「用 formant 翻译」。模式有自动 / Google / GPT / 全部。本地打分看脚本、词库、句式,简单的走 Google,绕的可以并行 GPT。原文译文都能读。默认模式、目标语言存在 chrome.storage.local,popup、划词共用。popup 打开会自动聚焦输入框。

内置俚语翻译

内置 en / zh / ja / ko / tr 俚语包,只读,能停用。自定义包在本机,JSON 导入可以新建、合并、替换。管理在 option.html#lexicon。

词库

X / Twitter 时间线另有一条翻译,默认开。匹配 x.com / pro.x.com / twitter.com,可见 tweetText 串行翻,Shadow DOM 展示。只走 translateGooglePa,不打 mono / GPT / 百度。译文颜色、字号在 option.html#x-translate,默认 #8c8c8c / 14px。

[图片占位:X 时间线译文]

New Tab

覆盖浏览器新标签页,布局能同步到 mono。第一行四张卡:天气、假期、汇率、热点英语。天气大概十分钟单独刷一次,别的卡片不动。热点英语词数可配,单词上方标美式 IPA,释义、谐音默认马赛克,点一下揭开。能单词语,也能整卡连读。已会的剔掉,会补新的上来。

假期卡常驻「今天 M月D日 周X」。假期、汇率各自有缓存时间戳。数据超过 24 小时,卡底会出琥珀色「N 天前更新」。打开新标签页时,天气超过 30 分钟、假期跨天、汇率超 24 小时才补拉。后台 10 分钟 alarm 仍只刷天气,假期只在跨天时顺带查。

换电脑打开空主页会自动拉云端。现在也不只看「空」:本机 revision 落后云端,打开 New Tab 就会对账拉取。点「同步」时,本机落后改用云端布局,不再按图标数量误判,旧电脑也盖不掉云端。空布局点同步,仍不会把云端已有的盖掉。壁纸、遮罩、城市在 #newtab,连 mono 仍在 #sync。

快捷图标先请求各站 {origin}/favicon.ico。裂了再回退 Google s2/favicons,Google 地址不写回保存字段。成功拉到的图标以 data URL 缓存在 newtabCacheFavicons,按 origin / 自定义 src;未命中先文字占位再换图。14 天 stale-while-revalidate。换一把 Client API Key 会清掉这坨缓存。编辑图标链接后,默认 favicon 不再写入 src,避免保存完变成文字占位。

添加、编辑链接 dialog 请求 mono 时会出半透明 loading,期间锁表单、按钮,Esc、点遮罩也关不掉,免得连点。

每日单词,可听读

书签、图片

书签变更会防抖上传,也能手动同步。按 Client API Key 隔离,全站一个池那种没有。空文件夹列表不会覆盖云端。换一把 Key,本机 New Tab、词卡、手势缓存会清掉,免得串数据。

书签

图片右键可以另存 PNG / JPG,转码在扩展里做,要 downloads 权限。

图片另存为

Telegram Web(web.telegram.org / webk / webz)上,已能看见的图片、视频会补 Shadow DOM 保存按钮,默认开。视频在页面里分片拉,用 <a download> 落盘,整段文件不塞进 Service Worker。没嵌 TG Downloader,也不接它的云端站。

[图片占位:Telegram 保存按钮]

GitZip、V2EX、自动翻页

GitHub 公开仓库、目录、文件页可以勾选打包。单文件、目录 ZIP、多选、整仓都行。只走公开 API,不存 GitHub PAT,不接 OAuth。匿名接口有速率上限,大目录、狂点可能被限,面板会提示。选择方式、主题在 #gitzip。关掉总开关,页面注入、菜单一起停,popup 还在。

github 下载

V2EX Plus 是上游 GPLv3 模块改过来的:自动签到、未读角标、楼中楼、用户卡、sov2ex。设置字段还用 chrome.storage.sync.options,对上游兼容。关掉就停 alarm、badge、DNR、页面增强,工具栏点击行为不动。带这个模块一起分发,整体按 GPLv3 处理。

主题帖默认先拉齐评论分页再组楼中楼:最多 100 页、4 路并发 fetch,解析后只导入回复单元格,按楼层一次性插入。楼主回复背景默认关(opReplyBg)。

v2ex

AutoPagerize 滚到底会接下页。内置一大坨站点 XPath,Google / Bing 有优先覆盖,也能配排除列表。本域带 cookie 拉,跨域才走 background。HTML 解析后先去掉脚本再插入,避免宿主页跑远端代码。linux.do 已硬排除,翻页不进这个站。

自动翻页

linux.do、freefq、huavod

linux.do 有一套列表换皮,默认开。只动 https://linux.do/ 非帖子页的 .topic-list:formant token,行高大约 48px,欢迎横幅藏掉,分类 Tab 收紧。手法参考 linuxdo-lark-ui(MIT),没整份拷油猴,品牌、侧栏、详情结构不改。列表未读、新帖左侧有 accent 竖条,标题加粗;底栏分类常显,tag 悬停再出。

列表页点帖子 /t/ 链接改 window.open 新标签,拦截 capture,避免 Discourse SPA 在当前页跳。Ctrl / Cmd / Shift / Alt 仍交浏览器。顶栏搜索、全页 /search 里的帖子链一样处理。关总开关后恢复原行为。

详情页按阅读向收了一圈控件:topic-map、楼层轴、楼主徽章、分享书签举报那排、相关话题、标语条。点赞、回复常显。

[图片占位:linux.do 列表换皮]

freefq.com / www.freefq.com(含 /m/)默认开导出。解除禁复制,挂 Shadow DOM「导出 TXT」。PC 取 td#text,移动端取 div.wz,UTF-8(BOM)经 chrome.downloads 落盘。不走 mono,不新要权限。页尾脚本爱绑 onmousedown / onselectstart / oncontextmenu,扩展会清掉,短时轮询防再绑。

[图片占位:freefq 导出 TXT]

huavod.com 控制台解锁默认开。动态 DNR 拦页面拉的 disable-devtool 脚本。MAIN world 在 document_start 挂起 DisableDevtool.isSuspend;没有用户手势时吞掉 history.back、history.go(-n),开 F12 不至于被踢回上一页。

[图片占位:huavod 控制台]

这两项开关在 #features,概览文案也写了。

鼠标手势

后来加的,默认关着。本机要是还开着 smartUp,两边会抢右键,只开一个就行。开了之后,普通网页按住右键划,路径收成 L / R / U / D。默认左退右进,上下刷新,右下关当前标签,上到顶,下到底。

设置页点某个动作的「绘制」,画板里按住左键划一下松手就绑上。网页上仍是右键。位移太小放行系统菜单,输入框、可编辑区域不触发。轨迹 Shadow DOM。一条路径不能绑两个动作。

映射能同步到 mono,按 Client API Key 隔离,规则按 New Tab 那套来。「刷新」是拉,「同步」是推。空映射不会覆盖云端已有的。总开关只存在本机,不同步。chrome://、商店页、PDF 注入不进去。

代理、扩展、站点数据

代理走 chrome.proxy.settings:直连、系统代理、PAC(URL / 本地脚本)、最多五条固定服务器。默认偏系统代理,固定代理端口默认 7890。细配在 #proxy,popup 顶上能快捷切。不做账号密码认证,也没整包塞第三方代理扩展。

代理

扩展管理用 chrome.management 列出本机扩展,能搜、能开关,formant 自己不出现。完整面板在 #extensions,popup 顶栏也有二级入口。不做分组、锁定、别名那一套。

扩展管理

站点数据在 popup 里读当前 http / https 页的 Cookie、localStorage、sessionStorage。进去、切 Tab 会自动拉。能复制、单条删、整页清,都要确认。Cookie 经 background 转发。不搞跨站批量写。

storage数据

JSON Prettify 是 DevTools 面板加内容脚本查看器。后来整页查看器、DevTools 面板也补了 JS / CSS 美化:打开 .js / .css 纯文本页(min.js 那种)自动缩进,JSON 仍走树视图。高亮自研,没嵌 prettier。面板名是 formant,JSON / JS / CSS 响应一块收。

json美化

各模块有总开关。关了停运行时,配置尽量留着。权限按能力要:alarms、bookmarks、contextMenus、cookies、downloads、management、proxy、scripting、storage 这些;GitHub、V2EX、Imgur 的 host 按需列。右键菜单按自己的 ID 增删,不 removeAll() 把别人的菜单清掉。

开关

接到 mono

扩展侧就两样:环境(dev 连本地,prod 连 www.oolaf.top)、一把 Client API Key。设置页顶栏会显示 Key 指纹,不展示全文。New Tab 布局、热点英语、书签、手势映射都按这把 Key 隔离。

服务端大概是这些:formant.translate.* 翻译通道,formant.weather.* / formant.exchange.* 天气汇率,formant.vocab.model_key / card_size 热点英语,formant.newtab.default_home 默认主页。密钥只放 Admin,不进扩展仓库。

本地加载

  1. Chrome 打开 chrome://extensions,打开开发者模式

  2. 「加载已解压的扩展程序」,选中仓库里的 formant/ 目录

  3. 打开 option.html#sync,填环境、Client API Key

  4. 到 #features 打开要用的模块,再到对应面板细调

版本号看 formant/manifest.json 的 version。要改某一块,从对应 bridge / option 面板顺着读就行。

下载

评论

在这里阅读读者对这篇文章的讨论。

暂无评论