技术架构深度解析:猫抓Cat-Catch如何在浏览器限制下重构媒体处理管线
2026/8/21 14:55:31 网站建设 项目流程

技术架构深度解析:猫抓Cat-Catch如何在浏览器限制下重构媒体处理管线

【免费下载链接】cat-catch猫抓 浏览器资源嗅探扩展 / cat-catch Browser Resource Sniffing Extension项目地址: https://gitcode.com/GitHub_Trending/ca/cat-catch

深夜调试一个视频站点,network 面板里几十个.ts分片不断刷新。你装上资源嗅探扩展,却发现只要切换标签页或在后台静置几分钟,下载队列就"冻结"了——Chrome 会回收扩展的 Service Worker,内存里的请求头、分片列表一并蒸发。**猫抓(cat-catch)**正是为解决这类问题而生的浏览器资源嗅探扩展,它把"嗅到资源"延伸为"完整交付":识别、过滤、解析、下载、转封装,在浏览器安全模型的重重限制下,搭起一条完整的媒体处理管线。

开场:当 Service Worker 在下载中途睡去 ⚙️

Manifest V3 把所有后台逻辑赶进了 Service Worker,而它的生命周期由浏览器裁决:空闲即回收,事件驱动唤醒。这意味着所有状态都必须可重建——猫抓的background.js第一段注释就写着"Service Worker 5 分钟后会强制终止扩展",并链接到 Chromium 的 issue 记录。

对嗅探扩展来说,这不是性能问题,而是数据完整性问题webRequest回调里捕获的请求头、正在排队的媒体列表、按 tab 划分的缓存,都是纯内存态。浏览器一回收,它们全部归零。猫抓的架构价值不在于某个炫技特性,而在于它把"随时可能被杀死"作为默认前提,设计了整套保活、落盘与重建机制——这是理解全部代码的一把钥匙。

需求的显微镜:把"能下载"拆成一张问题清单

"能下载视频"在真实场景里是一组性质完全不同的问题。猫抓的需求拆分可以画成一张清单:

需求类型判断依据
嗅到页面上的任意媒体资源刚需扩展存在的唯一理由,覆盖率决定口碑
下载时保留 referer / cookie / token刚需大量站点鉴权后才返回媒体,裸 URL 下载必 403
动态加载、加密的 m3u8 流痛点页面脚本运行时才发起请求,且分片常带 AES-128 加密
大文件不占满内存痛点长视频分片总量大,内存态缓存必然爆掉
做成完整视频管理库伪需求浏览器扩展的内存与生命周期撑不起,属于越界

猫抓的选择是"识别优先、交付可控":嗅探端做高覆盖,交付端把复杂留给自己。于是出现了onSendHeadersonResponseStarted双阶段监听——前者截获请求头(含鉴权信息),后者拿到响应头(content-typecontent-lengthcontent-disposition)判断"这是不是媒体",两阶段合并,才得到一个可以完整复现下载的请求快照。这张快照,就是后续一切功能的数据底座。

图:扩展弹出界面把"捕获→预览→下载"收进一个面板,嗅探只是第一步,交付才是终点

方案的角力场:存储、保活与嗅探的三场权衡 ⚖️

存储策略:session 优先、local 兜底,而不是二选一

代码里反复出现一行降级链:chrome.storage.session ?? chrome.storage.local。这不是偷懒,而是一场精确的权衡:

方案优势代价结论
storage.local持久、跨会话高频写入有 IO 错误风险,无内存态快放弃
storage.session内存级速度,无 IO 压力Firefox 与低版本 Chromium 不支持;扩展重载即丢放弃
session 优先 + local 兜底快的地方快,稳的地方稳需要"重建"逻辑采用

关键洞察是:session 丢数据不可怕,可怕的是丢得不明不白。猫抓配合防抖批量写——单 tab 积压 100 条或距上次写入超 500ms 时,延后 2 秒或 5 秒才落盘一次;单 tab 数据超过 99 条干脆不再写 storage,只在内存中维护。存储在这里被降级为"可丢失的镜像",真正的数据活在 Service Worker 内存里。

保活机制:三路冗余,对抗生命周期裁决

MV3 禁止持久后台页后,猫抓选择了三种策略叠加:

策略原理局限
webNavigation空监听每次导航重置 Service Worker 空闲时钟只对导航事件生效
onConnect心跳 Portcontent script 建立命名端口,后台 250 秒后主动断开,反复拉长生命周期需要页面侧配合,是业界知名 hack
setInterval(getPlatformInfo, 25s)周期性 API 调用维持活跃依赖实现细节,未来可能失效

这套"保活组合拳"的哲学是:不赌单一机制。每个方案都可能被浏览器更新击穿,但三条路同时失效的概率极低。这也解释了为什么background.js顶部同时挂着空监听、Port 心跳和定时器——它们是同一需求的三份保险。

嗅探策略:webRequest 为主,declarativeNetRequest 为辅

为什么不全面转向 Manifest V3 力推的declarativeNetRequest(dNR)?因为它只能改请求、读不到响应头、也拿不到请求体——而猫抓判断资源靠的恰恰是响应头。dNR 的用武之地在另一处:模拟手机 UA。updateSessionRules按 tab 动态注入modifyHeaders规则,把一个标签页的 UA 全局替换为移动端,这是 dNR 的舒适区。嗅探用 webRequest 拿数据,篡改用 dNR 免权限,各取所长。

实现的解剖室:从请求头到下载器的四段流水线 🔧

background.jsfindMedia展开,是一条边界清晰的处理流水线:

捕获 → 过滤 → 入缓存 → 交付 │ │ │ │ │ │ │ └── downloader.html / m3u8.html(StreamSaver / 在线ffmpeg) │ │ └── 查重 + 防抖落盘 + 角标数字 │ └── CheckExtension / CheckType / 正则黑名单 └── onSendHeaders(请求头)+ onResponseStarted(响应头)

过滤阶段最能体现"约束前置"的设计。CheckExtensionCheckType都接受"操作符 + 数值"的大小条件(如>100 KB500-1000 MB),把用户的过滤意图编译成一次判定:

// 根据响应头 content-type 匹配类型表,支持通配 audio/* 与大小表达式 function CheckType(dataType, dataSize) { const typeInfo = G.Type.get(dataType.split("/")[0] + "/*") || G.Type.get(dataType); if (!typeInfo) return false; // 未配置的类型直接放行 if (!typeInfo.state) return "break"; // 用户关闭的类型提前中断 if (typeInfo.size != 0 && dataSize != undefined && !operatorCheck(dataSize, typeInfo)) return "break"; return true; }

模块之间的协作关系值得注意:background.js只做编排,不碰页面 DOM;页面内的捕获交给catch-script/catch.jsCatCatcher类,它注入 MAIN world,代理MediaSource方法、用 MutationObserver 监听动态插入的 iframe,甚至为了兼容会克隆 iframe 并移除sandbox属性(对应 issue #576)——嗅探端与交付端通过runtime.sendMessageaddMedia消息对接,background.js只认 URL 与请求头,不关心是谁发现的。

M3U8 解析器是交付端的集大成者:用 hls.js 解析清单,用从 hls.js 中分离出的AESDecryptor解密分片,用 StreamSaver 边下边存,可选的在线 ffmpeg 以嵌套 iframe 方式完成转封装。默认下载线程数为 6G.M3u8Thread: 6),这个数字是分片数量、磁盘 IO、目标站点负载之间的经验平衡点——线程太少喂不饱带宽,太多则大概率被站点风控,6 是猫抓长期验证后的取值。

图:M3U8 解析器界面暴露了完整的技术面——分片列表、密钥/IV、线程数与下载范围,全部可调

国际化:用工具链锁住社区协作

_locales/下已有 10 种语言,贡献者来自 changelog 各处署名。真正的工程智慧在tools/sync-locales.js:以英文为基准,为缺失 key 的语言文件自动填充英文占位,保证任何语言在任何版本都不缺 key。翻译者无需理解架构,维护者不必手动同步,这降低了开源协作的隐性门槛。

踩坑实录:以版本号为刻度的一路修复

把 changelog 当技术日志读,能看到真实的失败与纠正:

  • iframe 沙箱吞掉捕获sandbox属性隔离了脚本,MediaSource 代理失效,最终用克隆节点移除属性的方式绕过(issue #576);
  • "一次性 URL"难题:部分站点生成的 m3u8 地址仅对单次请求有效,2.7.0 改为从扩展缓存中直接读取 m3u8 内容再解析,绕开地址时效;
  • BYTERANGE 分片:2.6.8 支持EXT-X-BYTERANGE标签合并下载,补齐了非标准切片的覆盖;
  • 下载失败率高:2.7.1 引入自动重试,用成功率换取用户耐心;
  • 在线 ffmpeg 文件丢失:从"新开标签"改为"嵌套 iframe"模式(2.6.8),解决跨标签通信的偶发失败;
  • Firefox 的差异化storage.session缺失、blob URL 下载、录制脚本兼容,都需要分支处理——跨浏览器从来不是口号,而是一行行G.isFirefox

这些修复的共同特征是都在模块内部完成:改catch.js不动background.js,改 m3u8 解析器不影响嗅探引擎。渐进式演进在这里不是理念,而是模块边界带来的自然结果。

启发的搬运工:三条可迁移原则与理性展望 💡

原则一:把平台的限制当成接口,而不是边界。存储降级链、三路保活、双阶段嗅探,都是在"限制不可绕过"的前提下设计出的方案。任何扩展项目都该先问:我的 Service Worker 被杀死后,用户会失去什么?

原则二:用"内存为主、落盘为镜"的缓存模型应对配额与性能。高频数据留在内存,storage 只做低频镜像,配合防抖与阈值(99 条内写盘、超过 9999 条清空)控制写入成本。浏览器扩展的内存策略,本质是"可重建状态"的设计。

原则三:用注入式脚本换取功能的热插拔。catch.jssearch.js按需注入、随时移除、独立 i18n,让深度搜索这类高风险脚本可以在出问题时单独回滚。松散耦合换来的是可运维性。

理性的展望同样重要:猫抓在浏览器内已经触到能力上限——MV3 下 dNR 对 webRequest 的逐步收紧、大文件受限于downloadsAPI 与内存模型、跨浏览器行为差异永远存在。它的下一步如果走向 AI 辅助识别或云端协同,必须先回答"Service Worker 生命周期"这个老问题在新场景下的新版本。但正因如此,这套围绕限制建立的架构才值得反复研读:它证明了真正可用的技术方案,从来不是对限制的规避,而是与限制的共处。

【免费下载链接】cat-catch猫抓 浏览器资源嗅探扩展 / cat-catch Browser Resource Sniffing Extension项目地址: https://gitcode.com/GitHub_Trending/ca/cat-catch

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询