B 站体验增强核心,一装到位:CDN 优选(救海外卡顿)· 免登录看评论/动态/1080p · 主题跟随系统深浅 · 评论显 IP 属地 · 播放不息屏——统一设置面板集中开关。Safari 友好、无需扩展、零外部依赖。
These are versions of this script where the code was updated. Show all versions.
perf(feed): 封面 AVIF/WEBP 协商(同步懒加载/卸载)+ decoding=async + hover 预览并发数硬上限;Feed 0.3.8→0.3.9
参考 BewlyCat 思路但重新校验实现:其 URL 拼法(直接加 .avif 后缀)实测对真实 CDN 404, 改用验证生效的 @{w}w_{h}h_1c.{format} 缩放+格式参数(640x360 JPEG 比原图省 81%,AVIF 再省 45%)
fix(core): 抽屉 iframe 销毁顺序补 contentWindow.close()(参考 BewlyCat 踩坑记录: 先移出 DOM 会导致 contentWindow 提前变 null、close() 从未真正生效);Core 0.5.20→0.5.21
Co-Authored-By: Claude Sonnet 5 [email protected]
feat(feed): 卡片新增「稍后再看」「我不想看」(反馈到 B 站推荐接口 + 本地模糊撤销浮层);Feed 0.3.4→0.3.8
fix(core): 去掉抽屉「用力甩偶发露白」的历史补丁——多轮排查确认为 iOS/macOS Safari 对 iframe 原生文档滚动的平台级限制,标准 CSS 手法均无效(详见 issue #4),保留死代码不如不留; site-drawer 放行卡片操作控件(.bk-feed-noopen),不再被误判成「点视频」接管;Core 0.5.19→0.5.20
style(core): 抽屉顶部按钮改「跟随主题+反相阴影」凸显——浅色黑投影/深色白辉光,去白玻璃;Core 0.5.18→0.5.19
Co-Authored-By: Claude Opus 4.8 [email protected]
style(core): 抽屉顶部控制按钮固定浅色玻璃,深色下不再糊进暗遮罩;Core 0.5.17→0.5.18
新标签/关闭两颗按钮此前用 background:var(--bg1) 跟随页面主题,但它们浮在顶部暗遮罩 (dmask rgba(0,0,0,.5)) 上——遮罩深浅色下都是暗的,深色模式下暗按钮压暗遮罩、糊成一团看不清。 改为不跟主题、固定浅色(白底 + 轻模糊 + 更深阴影),两种模式都是「暗底上的白按钮」,清晰有分离感; 浅色模式观感基本不变。
fix(core): 评论属地——SPA 换视频时断开旧评论树观察器,堵内存泄漏(#3);Core 0.5.16→0.5.17
内存泄漏审计发现:comment-location 给评论树各层 shadowRoot 挂的 MutationObserver 从不断开。 SPA 换视频时评论组件重建,walk() 给新树挂新观察器,但旧树的观察器仍在——其回调引用模块闭包、 一直可达,反手把已脱离 DOM 的整棵旧评论树吊住不放,每看一个带评论的视频积一棵。
修:记住所有评论树观察器,bind 新评论组件(换视频)时先全部 disconnect 再重挂。observed WeakSet 无需重置(旧 root 已脱离可 GC、新 root 天然不在集合里)。
审计同时确认干净的部分(记录备查):Feed 窗口化卡片有 unobserve+teardown、MSE 预览经 bkTeardown→mseCleanup 完整拆除并 revoke blob URL;所有 setInterval 有界;缓存均 LRU。 低优先固有增长(非本次处理):feed items[]/seen(无限流数据、刷新重置)、way-back titleById(每视频一小字符串)。
fix(core): 抽屉内存回收——去死代码 about:blank、iframe 内清理补 unload+srcObject(#3);Core 0.5.15→0.5.16
复核网络证据后修正了 0.5.15 的注释与两处实现:此前引的「WebKit 天生无解」来源均站不住 (#11683 2007 年即判定「不是泄漏」;#229606 是 WebGL、已 resolved;blob-url 帖是 iOS15 特例、非 MSE)。反例 amazon-chime-sdk#771 的结论恰是「应用层没做清理、补上即好」。更可能 的真因是旧代码那个 iframe 从没被真正销毁过(一直复用、只导 about:blank)。0.5.15 改成销毁重造 方向对,但仍有两个洞,本次补齐:
frame.src='about:blank'
是否根治仍须真机内存实测确认(Web Inspector Memory 时间线:反复开关抽屉看内存能否回落到基线)。
fix(core): 抽屉关闭改「销毁+重造 iframe」而非长驻复用,缓解视频内存不回收(#3);Core 0.5.14→0.5.15
调研结论:关抽屉内存不清是真实存在的 WebKit 已知缺陷类别(video/MSE 解码内存在「同一 iframe 反复换 src」的用法下回收不可靠——WebKit bug 11683 等、以及社区对视频元素反复换源 内存增长的报告),但不是「Safari 的锅、我们什么都做不了」:我们此前只做了一半缓解 (导去 about:blank),却把同一个 元素长驻复用一整个页面会话,从未真正销毁过。</p> <p>两处补齐已知缓解手法(缓解、非根治,仍可能有引擎侧残留):</p> <ul> <li>core/drawer.ts:closeDrawer 里导去 about:blank 后,把 <iframe> 元素整个移出 DOM 并置 null; openDrawer 若发现 iframe 已被销毁则新造一个挂回面板。iframe 创建逻辑抽成 createFrame(), 初建/重建共用。快速重开(closeTimer 未到期)不受影响,iframe 不会被销毁、原地揭幕。</li> <li>entry-core.ts:iframe 内监听 pagehide(父页导 about:blank 时触发),抢在文档被拆之前主动 暂停视频、清空 src、调用 load()——同类问题其它项目的处理方式,能降低但不保证消除增长。</li> </ul> <p>Co-Authored-By: Claude Sonnet 5 <a href="mailto:[email protected]" rel="nofollow">[email protected]</a></p>
fix(core): 抽屉打开即把焦点落到播放器,空格等快捷键立即可用(#3 评论);Core 0.5.13→0.5.14
根因:抽屉由父页点击打开,焦点留在父页,keydown 到不了 iframe → B 站播放器快捷键收不到; 即便手点进 iframe,焦点落在 上,空格滚动视频页而非暂停。整条链路此前无任何 focus 调用。
两段式修:
perf(core): 主题同步的全文档观察器收窄到 #commentapp(#3 第二轮);Core 0.5.12→0.5.13
theme-sync 有个 MutationObserver 监听 document.documentElement 的 subtree——目的极单一: 在评论组件 bili-comments 懒加载/SPA 重建时给它补设 .theme 属性(syncComponentTheme 只碰 bili-comments)。但为抓一个标签出现而观察整个文档树,在播放页会被弹幕/播放器的高频 DOM churn 以 ~60 次/秒触发,是 profile 里的第二功耗热点。
改为只观察评论容器 #commentapp 子树(只在评论加载/翻页时变动,频率低得多);#commentapp 未挂载时短轮询等它出现,找到即观察、即停,~20s 兜底放弃。功能不变(评论主题照常跟随)。
perf(core): 回程功耗优化——去掉每帧布局动画与全 head 观察器(#3);Core 0.5.11→0.5.12
Timeline profile 定位(三个 1080p 配置干净对照):关掉回程主线程 JS 直接砍半(104→54ms/s)、 microtask 少 ~62/秒、event 少 ~17/秒、CPU −7 点——回程是发热主因(用户直觉正确)。逐项修:
fix(core): 抽屉 iframe 深色下向上回弹露白——html/body 跟随 --bg1;Core 0.5.10→0.5.11
抽屉里向上橡皮筋回弹(overscroll)会露出根元素背景,而 B 站深色只给部分容器上色、 html/body 根仍是白 → 露白(theme-sync 那句垫底只作用于 html,且用户可能用 B 站原生深色、 没开 theme-sync)。在抽屉 iframe 无条件注入的样式里,让 html/body 背景跟随 B 站自己的 主题 token var(--bg1)(深即深、浅即浅),不依赖 theme-sync 开关;未定义时声明失效不强上色。
ci: 加 ESLint + tsc 类型检查 + GitHub Actions CI(typecheck/lint/test/build/dist 同步校验)
补上「集成靠审查、纯逻辑靠单测」之外的机械关卡:
tsc --noEmit
| void
| undefined
无行为改动,不升版本(类型修正 / 死代码 / 形参重命名)。
test: 引入 Vitest 测纯逻辑层,并把硬逻辑从 init() 闭包抽成纯函数;Core 0.5.9→0.5.10
针对「脚本变大如何保正确性」:给纯逻辑层补单测(32 例)。这类逻辑是最易犯错、也最该测的 (历史那个 click/web/h5 前缀误杀、回程切片、wbi 签名都属此类);集成/环境正确性仍靠审查 + 真机。
抽取(行为保持,原调用点不变,靠 build 编译验证):
工具链:Vitest(devDep),npm run test;co-located src/*/.test.ts,node 环境不碰 DOM。 .npmrc 关 verify-deps-before-run(pnpm 11 因 esbuild 构建脚本被忽略会在 run 前中断)。
npm run test
feat: 「关于」页显示 Feed 版本;Feed 版本同样单一源并上报(Core 0.5.8→0.5.9 / Feed 0.3.2→0.3.3)
feat(core): 设置面板加「关于」页(版本号 + GitHub / 反馈 / GreasyFork 链接);Core 0.5.7→0.5.8
feat(core): 设置齿轮并入 Feed 右下按钮组、去掉左下吸边;README 加开发期说明并去过时(#2 追加);Core 0.5.6→0.5.7
1) 打开设置的入口统一到右下:
2) README:
feat(core): 打开方式接管收窄到浏览页——播放页内点视频走原生 SPA、喂给回程;Core 0.5.5→0.5.6
全站抽屉/打开方式此前在「所有页」接管视频点击,含播放页本身,导致:① 新标签模式下 播放页点相关视频也新开标签、永不 SPA → 回程恒 0 层;② 抽屉模式在播放页叠抽屉。
改为把接管收窄到「浏览/列表」语境(首页/搜索/空间/收藏/历史/动态…), 视频播放页内一律放行走原生 SPA:既喂给回程建来时路,又不叠抽屉。三种模式各自自洽 (抽屉/新标签模式下每个播放页/标签都是独立的一份来时路)。
refactor(core): 移除「埋点拦截」模块——误伤面大、非核心,得不偿失(#2 追加);Core 0.5.3→0.5.5
埋点拦截要靠猜 B 站的私有埋点路径做前缀匹配,天然最易误伤相邻接口: 先有「免登录 + 埋点拦截」同开反复重刷(收窄过一次),又有前缀 click-interface/click 连坐 click/web/h5 播放上报、真登录下所有视频不进观看历史。而它只是省流/降开销的边角功能 (头牌是 CDN 优选 / 免登录 / 主题跟随),换来的持续误伤风险不划算,整模块移除。
本提交替换上一条「摘 click-interface」的修法(79a0f4c,已撤回):模块既除,历史自然恢复。
fix(core): 埋点拦截误杀播放上报致观看历史全丢——从黑名单摘掉 click-interface(#2 追加);Core 0.5.3→0.5.4
真登录账号下所有视频都不进观看历史(不分打开方式,原生直开也不记)。根因:埋点拦截 黑名单里的 'api.bilibili.com/x/click-interface/click' 用前缀命中把 click/web/h5 一起拦了, 而 click/web/h5 是每次播放一次的「播放上报」,B 站据它写入观看历史——被拦=历史不写入。 实测关掉埋点拦截历史即恢复,确证。
修:从 TELEMETRY 摘掉 click-interface 整条。该接口低频(每播一次),非省流大头 (大头是 data.bilibili.com/log 与 sendBeacon),放行零感知代价,换回观看历史。
fix(core): 免登录修 iPad/移动 Safari 只能 480p(掰回桌面 DASH 路径)(#2 追加);Core 0.5.2→0.5.3
iPad/移动 Safari 触发 B 站触屏判定 → 播放器发 platform=html5(MP4),服务端对 html5 的免登录 try_look 只给 480p,qn=80 也被打回,手动切也被服务端拉回——桌面无此问题, beefreely 同病(两者都只改 qn/try_look、不碰 platform)。非 Safari 编解码限制。
修:playurl 重签时强改 platform=pc + fnval=4048(全 DASH) + fourk=1,掰回桌面策略 放行 1080p 试看。桌面本就这套零风险,iPad 靠 MSE 放 DASH。实机 iPad 验证 1080p 通。
fix(core): 免登录修 UP 空间页死循环 + 对照 beefreely 全面补洞(#2 追加);Core 0.5.1→0.5.2
对照 references/beefreely 全源码逐端点审计,修 5 处:
审计结论存档:wbi 签名我们比 beefreely 更对(其 sub key 误读 img url);个人页排除 更安全非 gap;双方均无 -352/w_webid 风控处理;假历史/直播 WS/下载器接口有意不做。
feat(core): 回程胶囊迁入 Core(顶层+抽屉内)+ 齿轮仅首页吸边;Core 0.5.0→0.5.1
feat(core): 全站抽屉——「打开方式」移入 Core、全站视频点击生效;Core 0.4.7→0.5.0 / Feed 0.3.1→0.3.2
「打开方式」从 Feed 解耦、上移到 Core:全站(首页 / 搜索 / 收藏 / 历史 / 别人空间…)点视频 都按它在 底部抽屉 / 网页全屏抽屉 / 新标签 / 当前页 打开,不跳走、不丢当前列表。
fix(core): 免登录去掉打开视频时闪现的「账号未登录」红色 toast(回应 #2);Core 0.4.6→0.4.7
免登录伪造登录后,个别带假 cookie 的请求被服务端判 -101,页面会在打开视频瞬间闪一个红色 「账号未登录」toast(Vant 的 .van-message-error,一闪即逝)——这是 B 站原生提示、非本套件 所加。免登录开启时注入 CSS 藏掉它;不影响真登录 / 未启用免登录用户的正常错误提示。
fix(core): 免登录在个人页不伪造登录,修收藏/历史反复重刷(#2 追加);Core 0.4.5→0.4.6
收藏/历史/稍后看/清单/消息/账号等「需真登录」的个人数据页:免登录伪造登录会让页面拿假身份 取不到数据、前后端状态打架 → 反复重刷。现这些页免登录一律不碰,并清掉之前在视频/首页种下的 假 DedeUserID cookie,让它们按未登录干净处理(跳登录 / 空列表),不再重刷。视频/首页/搜索/ 他人空间等公开页照常生效。
fix(core): 跨子域设置共享 + 埋点拦截收窄,修免登录多页问题(#2 追加);Core 0.4.4→0.4.5
feat(core): 免登录看评论/动态/1080p 模块(回应 #2);Core 0.4.3→0.4.4
Issue #2:装 beefreely 等免登录脚本会与 BiliKit 抢改 fetch/XHR,时好时坏。 本次 BiliKit 自带「免登录」模块,装它即可卸载 beefreely,从根上消掉竞态。
三 agent 并行审查后硬化:responseText 补 responseType 守卫、rewriteRequest 只签 一次、wbi key 按天失效、Request 请求用克隆保 headers/signal、installNetHook 幂等。 设计与逆向记录见 docs/RESEARCH-no-login.md。
feat(feed): 抽屉「网页全屏」打开方式 + 首帧揭幕(回应 #2)
Issue #2 提到「抽屉能否默认网页全屏、更沉浸」,本次实现:
Feed 0.3.0→0.3.1 / Core 0.4.2→0.4.3
feat: 封面「真视频」秒开预览 (MSE);Feed 0.2.2→0.3.0 / Core 0.4.1→0.4.2
hover 封面用 MSE 只取 init + 头几秒 dash 分段边播边补,起播接近手机 App 原生, 热门冷门都覆盖。关键:分段字节走浏览器 fetch(原生同法,bilivideo 对本源放行 CORS、冷门也回 206),绕开 CDN 对 GM 请求的反爬 403;GM 仅作兜底。
Feed(0.3.0):
Core(0.4.2):
探针实测原生 hover(diag/home-hover-probe)→ 调研文档 docs/RESEARCH-mse-preview.md。
fix(core): 埋点面板开关+小字排版不再挤成一排;build:core 不清空 dist
feat(core): 新增「埋点拦截」模块,Core 0.3.1→0.4.0
页面世界 hook fetch/XHR/sendBeacon,拦掉行为遥测(data.bilibili.com/log/web 等)与广告投放(cm.bilibili.com),命中即短路不发起。首页性能探针实测: 空闲 72s 内约 65% 请求为埋点/广告(data.bilibili.com 一家占 62%、~4.7 次/s), 拦掉零功能损失、页面无感。