Repository navigation
githup v1.2.14
githup v1.2.14(翻译速度还原 · 两步验证器:手机上直接出 6 位动态码)
上一版做错了什么
v1.2.13 说「免费引擎从 2 家扩到 5 家」,把 DeepL / Google / 设备端
直接放进了协作池。实测这条路错得离谱:
手动指定「只用有道」翻同一页 —— v1.2.11 是 624ms,v1.2.13 是 9633ms,慢了 15 倍。
有道本身一点没变慢,是它的活被连不上的引擎抢走了:有道只分到 1 批,
DeepL 被派了 6 次、Google 4 次、设备端 2 次,页面在等那些根本连不上的请求。
当初设想的三重措施全没兜住:
| 措施 | 为什么没用 |
|---|---|
| 3 秒闸门 | 把单次从 8 秒砍到 3 秒,但它们被派了十几次,接力下来整页照样 9.6 秒 |
| 权重垫后 | 只相对于有道一家垫后,转轮里「所有慢引擎加起来」占了三分之二的位子 |
| 连续失败摘牌 | 要连续失败 3 次才摘,前 3 批的学费已经交完了 |
闸门治的是「单次等多久」,治不了「反复派给死引擎」。
这一版改成了什么
先验证,再准入 —— 能不能用,探一次说了算。
- 探不过 → 压根不进池。国内用户永远走有道 + MyMemory 那条快车道
- 探过了 → 才准进池。此时它是真能干活的,不是来占位置的
探测在后台跑,不占首屏时间;结果记下来,30 分钟内不再重探
(换 WiFi / 开代理 / 出国之后会自动重探一次)。
| 场景(翻同一页 120 段) | v1.2.11 | v1.2.13 | v1.2.14 |
|---|---|---|---|
| 手动指定「有道」 | 624ms | 9633ms | 624ms |
| 手动指定「MyMemory」 | 612ms | 9621ms | 614ms |
| 自动(多引擎协作) | 608ms | 9612ms | 607ms |
同一版里还有:看代码 / 改代码变成编辑器的样子(PR #12,来自 @mymine)
- 长行不用左右拖了 —— 代码默认自动折行,顶上可以切回「不换行」
- 换行时行号不错位 —— 原来行号是单独一列,代码一折行就对不上;改成按行渲染后,
行号钉在每个逻辑行的开头 - 编辑文件时也有行号和语法高亮了 —— 原来是个光秃秃的输入框
「免费引擎变多」没有落空
它变成了「能用的才算多」:海外能通的环境、或者你挂了代理,
那几家探测一过就自动加入,和 1.2.11 里的有道 / MyMemory 一样是真在干活的引擎。
而国内用户不会再为这个「多」付 15 倍的代价。
顺带一提:首屏竞速(v1.2.13 的另一项改动)经查是无辜的 ——
纯竞速版实测 624ms,和 v1.2.11 一模一样。这一版没动它。
MyMemory 配额用完之后,不再每页都白撞一次
它的免费配额是按天算的,一天之内不会自己恢复。以前撞上配额只有
「连续失败 3 次就摘牌」管着,而那本账每次换页就清零重来 ——
于是配额早就用完时,每翻一页都要先白撞 3 批(每批几十条请求)
才又一次得出「它今天不行」。看到的就是每页都莫名慢一截。
现在记一笔账:确认耗尽后 6 小时内不让它自动进池,连那 3 批学费都省了。
取 6 小时而不是一整天,是因为它的配额按 UTC 日重置 ——
半天给一次机会,跨过零点自动回来。
顺带补了一个漏:配额打满时它也可能直接回 429(而不是把警告塞进译文里),
以前只认警告那一种,429 那一路会落回「每页白撞 3 批」的老路。
手动点名要用它时不受影响 —— 你在菜单里点了它,那就得上。
同一版里还有:议题里的图片,加载得跟 README 一样快
同一个 App,README 里的图划到就出来,议题(issue / PR)里贴的截图却要等一下。
根子不在网络,在预热名单漏了它们。README 的图渲染时会被丢给原生后台下载到磁盘,
划到时是读磁盘、零网络;议题里贴的图是 GitHub 附件链接,URL 不带扩展名,
于是既被当成 <video> 渲染、也进不了只认扩展名的预热名单 —— 每次都要现拉。
现在:GitHub 附件链接也进预热名单(最多 3 个、单张超过 4MB 的不预,
免得为一张大图把后台占满);探测用的 <video> 降级成 <img> 时
直接复用已经下载好的那一份,不再重新下一遍。
一处刻意没改:拦截仍然只接管带 image/* 的请求,<video> 一律放行 ——
视频靠 Range 请求做 seek,被整包 200 接过来会把播放弄坏。
同一版里还有:议题里的图,改成按官网的答案渲染(不再靠猜)
上面那一项治的是「进不了预热名单」,这一项治的是更靠前的根子:App 得猜它是什么。
官网不用猜 —— 它的正文是服务端渲染的。你拖一个文件进议题,GitHub 上传时就记下了
它是什么,渲染正文时直接写出来:
| 你贴的 | 官网渲染出来的 |
|---|---|
| 截图 | <img width="327" height="706" src="…"> |
| 录屏 | <video src="…"> |
类型和宽高都写在 HTML 里,浏览器一点都不用猜。
我们以前拿的是 Markdown 源码自己渲染,附件在里面是
github.com/user-attachments/assets/<uuid> —— 没有扩展名,看不出是截图还是录屏。
只能乐观当 <video> 渲染、拉不动再降级成 <img>。代价是:绝大多数其实是截图的
附件都要先白跑一趟视频请求;而且拿不到宽高,图一加载完页面就跳一下。
现在正文改要官方渲染好的那份(接口带 Accept: …full+json,一份请求里 Markdown
和 HTML 都有 —— Markdown 留给「引用 / 编辑」,HTML 用来渲染)。
地址就照官网的样子用:官方正文里给的是
private-user-images.githubusercontent.com/…<uuid>.png?jwt=… —— GitHub 自己的
CDN 域名,字节直出、不用跳。官网的图快,快就快在走的是这条直路,所以这一版
把它原样留着当主路径,只把不带签名的那份(user-attachments/assets/<uuid>)
记在旁边当第二条路 —— 那份要先吃一个 302 才到 S3,多一趟往返、多一次握手。
签名 5 分钟有效带来的两个坑:渲染完立刻预热(趁签名还热),
以及缓存不再按整条 URL 记(见下一节)。
同一版里还有:预热带回来的字节,得存进同一个抽屉
上面两条官方线路是同一份字节,可缓存以前是按整条 URL 做 key 的。带签名的
地址每 5 分钟、每次请求都不一样,于是:
预热按 CDN 地址下好一份 → 加载时签名已经换了 → 缓存里没有 → 又下第二份
预热带回来的那一趟等于白做,用户滑到的每一张都还在现拉。
现在缓存 key 改成认地址里那个 uuid(asset-<uuid>):两条官方地址落到磁盘上的
同一个文件,谁先下好谁说了算,另一个直接命中。下载锁也按 uuid 走,不会一个在
下载、另一个同一时刻也在下。没有 uuid 的地址(README 的 raw / camo / 头像)原样记,
不受影响。
同一版里还有:图片不再被我们「接走」—— 接走的那条路反而更慢
从 v1.2.9 起,图片比更早的版本慢:加的东西越来越多(缓存、预热、快车道),
体感却在往回走。真因不在缓存,在**「接管」这件事本身**。
v1.2.9 之前,图一直是 WebView 自己拉的 —— Chromium 的网络栈,HTTP/2 多路复用、
TLS 会话复用、它自己的 HTTP 缓存(304)、以及边下边渲染。v1.2.9 加了 ImageProxy
之后变成「WebView 要图,我们全接过来自己下」,而一旦被接住,Chromium 就不再发它自己
那趟请求 —— 等于把快车道换成了慢车道(HTTP/1.1、只有 gzip、整包到齐才出第一帧、
还同步占住 WebView 有限的几个 IO 线程,一张慢图把后面排队的图一起拖住)。
现在改成只接得住的才接:
- 磁盘上已经有 → 接,零网络
- 磁盘上没有、匿名就能拿到 → 放手,交回 WebView 自己拉(它那套比我们快)
- 非带令牌不可的(私有仓库的图,WebView 手上没令牌)→ 才由我们来,而且是学着来的:
第一次撞 404 补令牌成功后记下这个仓库,以后首趟就带,连那趟 401 都省了
预热也学会了让路:延后 1.2 秒再动(等屏幕上的图先拉完)、从 3 条并发改成 1 条、
并且不收屏幕上的图(它们此刻正由 WebView 拉,再下一遍是同一份字节买两次单)。
同一份附件还补了「双路竞速」:主路超过 2 秒没出图就把备用路点着,谁先回来用谁 ——
不用再等主路走到超时(十几秒)才换。主路先到的话第二趟压根不发起,快图不付两份流量。
同一版里还有:点议题里的图片,看的是大图;长按,才是打开那个页面
议题里点一张截图,弹出来的不是大图,是一个顶栏写着 GitHub、下面一片白的窗口
(github.com/user-attachments/assets/…)。两个原因叠在一起:
- 官方渲染的正文把上传的截图包在
<a target="_blank">里,而 App 的外链委托挂在
document 的捕获阶段,跑在图片自己的onclick之前 —— 一点图片,先被外链
委托接走、把内嵌浏览器打开,「查看大图」永远轮不到出场; - 链接规整还把附件地址站内化成了
#/user-attachments/assets/…,可它不是站内
页面,Router 不认识,最后照样掉进那个内嵌窗口。
现在:点图片 = 查看大图;长按图片(约半秒)= 打开它指向的那个页面;
点图片边缘(链接本体)仍是打开页面 —— 行为没丢,只是不再抢「看图」的默认位。
附件地址也从站内化规则里摘了出来,它本来就该是外链。
同一版里还有:收藏夹能分类了 —— 隔层就长在收藏夹里
官方客户端的「已添加星标」里有一层「我的列表」(Lists),把 Star 过的仓库
归进不同分类。这个功能 GitHub 至今没有开放 API(REST 里翻得到 /user/starred,
翻不到任何 list 端点),所以这版照着官方的交互做成了本机功能,并且直接
长在收藏夹里,不另立入口:
- 切到「收藏夹」→ 顶部多一排横滑分类:全部收藏 / 你建的各个列表 / +新建;
点哪个看哪个,长按某个分类可以重命名、删除(删除要二次确认); - 长按仓库条目(或仓库页「更多」菜单里的「加入列表」)弹出勾选层:
勾上 = 归进这个分类,再点 = 移出,勾完弹层不关,可以连着归几个; - 归进分类的仓库自动也算收藏 —— 单击「收藏」按钮的老习惯一点没变;
从分类里移出不影响收藏,从收藏夹移出也不影响分类; - 分类里存的是仓库快照(名字 / 描述 / 星数 / 语言),点开先画快照再悄悄刷新,
断网也不会白屏。
数据保存在这台设备上(按登录账号隔离),不占 GitHub 的任何请求额度;
换设备不跟着走 —— 这是「官方没开 API」之下唯一不偷密码、不走第三方的做法。
同一版里还有:已读通知,这次是真的能删干净了
「通知 → 已读」里点删除,通知当时没了,一刷新又全部回来 ——
这个幽灵现象查到最后,根子比想象深:
删除动作其实一直是成功的(GitHub 的「标记 Done」返回 204,没毛病)。
真正的坑是 GitHub REST API 不过滤 Done 状态:标了 Done 的通知,
拉通知列表(all=true)时照样原样返回,而且返回数据里没有任何
字段能认出它已被 Done(官方最新的 API 版本也没加)。网页版收件箱
用的是带 is:done 过滤的内部接口,第三方用不了 —— 所以「已读」
列表一刷新,刚删的全回来了。
REST 层面无解,这版用本机记账补上:
- 删除成功的通知记进本机「已清除清单」(按账号隔离,最多 500 条),
渲染列表时自动挡掉 —— 删除、刷新、重启 App,都不会再回来; - Done 之后那个议题/PR 有了新动静,GitHub 会把它复活成未读送回
收件箱 —— 未读的一律放行,新消息一条不漏; - 菜单新增**「清空已读」**:一键把所有已读通知标记为 Done 并记账,
未读通知一根汗毛都不动; - 多选删除只移除真正成功的条目,真失败的留在列表里告诉你;
- 顺带治好一个哑巴病:「点开通知后还是未读」—— 单条标已读之前
用错了请求方法(PUT),改回文档的 PATCH 后真正生效。
同一版里还有:发布列表支持长按删除
仓库页「发布」标签里,以前只能新建发布,想删掉一个发错的版本、
或者给已经发出的版本补传漏掉的 APK,都得去网页版操作。现在
长按任意一条发布弹出菜单:
- 上传 APK 附件 —— 从手机里选一个文件直传到这条发布,
走和创建发布同一条原生二进制通道(单个不超过 200MB,
APK / AAB / ZIP 等任意文件都行)。如果这条发布里已有同名附件,
会先删旧的再传新的,不会出现两份同名文件;传完自动刷新列表; - 删除此发布 —— 危险确认(红色按钮、写明会连带删掉几个附件)
后调用官方接口删除;删完这条就从列表里消失,全删光自动回到空态;
git 标签会保留(GitHub 的规矩:删 Release 不删 tag); - 查看发布详情 —— 和点条目进去是同一个页面;
- 没有仓库写权限时,长按只提示「需要仓库写权限」,不出菜单 ——
看得见管不着的按钮只会招人烦。
手势和通知、收藏夹是同一套:点一下照常进详情,长按 550ms 才出菜单
(比标准 500 稍长,快滚列表不容易误弹;长按松手带出的那次误触点击
会被吞掉,不会串进详情页)。
同一版里还有:两步验证器(TOTP)—— 手机上直接出 6 位动态码
登录 GitHub、Google 这类开了两步验证的网站,除了密码还要填一个
每 30 秒变一次的 6 位动态码。以前得切到另一个验证器 App 去看,
现在 githup 自己就能算:
入口 —— 「我的 → 两步验证器」,不占底部标签页。密钥只存在你手机上,
算法也在本机跑,不联网、不需要登录 GitHub,飞机上照样出码。
添加账户的三种方式:
- 扫一扫 —— 对准网站上的二维码,自动识别、自动填入,
实时码立刻开始跳动; - 从图片识别二维码 —— 先把二维码截图存下来,再从相册选图;
- 从剪贴板粘贴 —— 网站二维码下面通常有一行「密钥」或
「手动输入」的字母数字,复制过来粘进去就行。
二维码识别是自己写的纯 JS 解码器,没有引第三方库 —— 定位图案、
透视校正、RS 纠错都是本仓代码,整包只多了几十 KB。
后台也能看 —— App 退到后台时,通知栏会自动常驻一个实时刷新的动态码,
回到 App 里自动收起;一个账户都没添加时不占通知栏。这件事不需要去设置里
开开关,本来就是跟着账户走的。
顺带修掉两个真机上才会显形的问题:
① 扫码按钮根本不显示 —— 选文件的方法挂在window.Native上,
代码里却写成window.API,于是可用性自检恒为假,按钮被直接隐藏;
② 点保存没反应 —— 保存按钮在弹层的.sheet-foot里,而绑定代码
只在.sheet-body里找它,查到null后抛异常中断,处理器从未挂上。
密钥只存在这台设备上,卸载或清除数据后就没了。重要账户建议
同时在网站保存一份恢复码,免得手机丢了进不去。
版本号只动第三位(1.2.13 → 1.2.14),按 README 的规矩属于可选更新。
请更新这一版:保持 1.2.13 的话,App 会认为你已是最新版本,
拿不到这个修复。