脚本开发文档

发布于 5 天前  21 次阅读


Cat Browser 脚本开发文档 v2.1

目录

  1. 概述
  2. 快速开始
  3. 环境检测
  4. GM API 标准兼容
    · 4.1 存储类
    · 4.2 样式注入
    · 4.3 网络请求
    · 4.4 其他方法
  5. 特权对象:cyc_privileges
    · 5.1 UI 交互
    · 5.2 资源嗅探(阶段 B)
    · 5.3 视频悬浮窗(阶段 C)
    · 5.4 下载能力(阶段 D)
    · 5.5 网络调试(阶段 A)
    · 5.6 Aria2 下载引擎(阶段 E)
  6. 特权对象:cyc_http
  7. 特权对象:cyc_monitor
  8. 完整脚本示例
    · 8.1 嗅探视频并一键推送到 Aria2
    · 8.2 万能视频小窗播放器
    · 8.3 网络请求实时监控面板
    · 8.4 批量下载页面图片
  9. 限制与注意事项

  1. 概述

Cat Browser 为油猴脚本(UserScript)提供了一个增强的运行时环境。除了兼容标准 GM_* API 外,还额外提供三个特权对象,让脚本可以调用 App 的原生能力,实现普通浏览器做不到的功能。

三个特权对象:

对象名 用途 注入条件
cyc_privileges UI 交互、资源嗅探、视频悬浮窗、下载、Aria2 引擎、调试开关 仅 http:// / https://
cyc_http 原生跨域 HTTP 请求 仅 http:// / https://
cyc_monitor 页面网络请求监控 仅 http:// / https://

兼容性承诺: 所有特权对象在普通浏览器(Chrome + Tampermonkey 等)中均为 undefined,脚本只需做一次存在性检查即可实现降级兼容。

支持的标准: Cat Browser 兼容主流 GM_* API,无需在 @grant 中声明即可直接使用 GM_setValue、GM_xmlhttpRequest 等全部方法。


  1. 快速开始

最小可运行脚本模板// ==UserScript== // @name 我的脚本 // @namespace my-script // @version 1.0.0 // @description 脚本描述 // @author 作者名 // @match *://*/* // @grant none // ==/UserScript== (function() { 'use strict'; // 环境检测 const isCyc = typeof __cyc_privileges__ !== 'undefined'; if (isCyc) { __cyc_privileges__.toast('Cat Browser 增强环境已就绪'); } else { console.log('普通浏览器环境,部分功能不可用'); } // 你的脚本逻辑... })();

关键说明:

· @match :///* 让脚本在所有 HTTP/HTTPS 页面运行
· @grant none 表示不申请额外权限(Cat Browser 已默认开放所有 GM API)
· 所有代码包裹在 IIFE (function(){ … })() 中,避免污染全局作用域
· 'use strict' 启用严格模式,减少潜在错误


  1. 环境检测

3.1 检测是否在 Cat Browser 中运行const isCatBrowser = typeof __cyc_privileges__ !== 'undefined';

3.2 检测是否在 HTTP/HTTPS 页面

特权对象仅在 HTTP/HTTPS 页面注入,file:// 或 about:blank 不可用。const isHttpPage = window.location.protocol === 'http:' || window.location.protocol === 'https:';

3.3 完整的环境信息const env = { isCatBrowser: typeof __cyc_privileges__ !== 'undefined', isHttpPage: /^https?:/.test(window.location.href), hasPrivileges: typeof __cyc_privileges__ !== 'undefined', hasHttp: typeof __cyc_http__ !== 'undefined', hasMonitor: typeof __cyc_monitor__ !== 'undefined', hasGMApi: typeof GM_setValue === 'function', url: window.location.href, gmInfo: typeof GM_info !== 'undefined' ? GM_info : null }; console.log('环境信息:', JSON.stringify(env, null, 2));


  1. GM API 标准兼容

Cat Browser 兼容主流 GM_* API,无需在 @grant 中声明即可直接使用。

4.1 存储类

方法 参数 返回值 说明
GM_setValue(key, value) key: 字符串, value: 任意类型(自动序列化) 无 持久存储键值对
GM_getValue(key, defaultValue) key: 字符串, defaultValue: 任意类型 存储的值或默认值 读取存储的值
GM_deleteValue(key) key: 字符串 无 删除存储的键
GM_listValues() 无 字符串数组 获取所有存储的键名// 存储复杂对象 GM_setValue('myKey', { name: 'test', count: 42 }); // 读取(带默认值) const data = GM_getValue('myKey', { name: '', count: 0 }); console.log(data.name, data.count); // "test", 42 // 删除 GM_deleteValue('myKey'); // 列出所有键 const keys = GM_listValues(); console.log('已存储的键:', keys);

4.2 样式注入

方法 参数 说明
GM_addStyle(css) css: CSS 字符串 向页面注入样式GM_addStyle(` .my-highlight { background: yellow !important; border: 2px solid red; } `);

4.3 网络请求

方法 参数 说明
GM_xmlhttpRequest(details) details: 配置对象 发起跨域请求(兼容标准 GM API)

details 配置项:

属性 类型 必填 说明
url string 是 请求地址
method string 否 请求方法,默认 GET
headers object 否 请求头
data string 否 请求体
timeout number 否 超时毫秒数
onload function 否 成功回调
onerror function 否 失败回调GM_xmlhttpRequest({ url: 'https://api.example.com/data', method: 'GET', headers: { 'X-Custom': 'value' }, timeout: 10000, onload: function(response) { console.log('状态:', response.status); console.log('响应:', response.responseText); console.log('响应头:', response.responseHeaders); }, onerror: function(error) { console.error('请求失败:', error); } });

4.4 其他方法

方法 说明
GM_log(message) 输出日志到 App 控制台
GM_setClipboard(text) 复制文本到系统剪贴板
GM_openInTab(url, background) 在新标签页打开 URL(background: true 后台打开)
GM_notification(details, onclick) 显示浏览器通知
GM_info 获取脚本管理器信息对象
GM_registerMenuCommand(caption, callback) 注册菜单命令
GM_getResourceText(name) 获取 @resource 定义的文本资源内容
GM_getResourceURL(name) 获取 @resource 定义的资源 URL// 日志 GM_log('调试信息'); // 复制到剪贴板 GM_setClipboard('已复制的文本'); // 通知 GM_notification({ title: '标题', text: '内容' }); // 脚本管理器信息 console.log(GM_info.scriptHandler); // "Cat Browser" console.log(GM_info.version); // "1.0.0" // 菜单命令 GM_registerMenuCommand('我的功能', function() { alert('菜单被点击'); });


  1. 特权对象:cyc_privileges

注入条件: 仅在 http:// 和 https:// 页面可用。

5.1 UI 交互

toast(message)

· 参数: message - 字符串,要显示的文本
· 返回值: 无
· 说明: 弹出 Android 原生短 Toast(约 2 秒),线程安全

toastLong(message)

· 参数: message - 字符串,要显示的文本
· 返回值: 无
· 说明: 弹出 Android 原生长 Toast(约 3.5 秒),线程安全__cyc_privileges__.toast('操作完成'); __cyc_privileges__.toastLong('这是一条较长的提示信息');


5.2 资源嗅探(阶段 B)

getSniffedVideos()

· 参数: 无
· 返回值: JSON 字符串,解析后为数组 [{url, mimeType, size}, …]
· 说明: 获取当前页面已检测到的视频资源

getSniffedAudios()

· 参数: 无
· 返回值: JSON 字符串,解析后为数组
· 说明: 获取当前页面已检测到的音频资源

getSniffedImages()

· 参数: 无
· 返回值: JSON 字符串,解析后为数组
· 说明: 获取当前页面已检测到的图片资源

返回值对象结构:

字段 类型 说明
url string 资源 URL
mimeType string MIME 类型(如 video/mp4)
size number 文件大小(字节,-1 表示未知)const videos = JSON.parse(__cyc_privileges__.getSniffedVideos()); console.log('检测到 ' + videos.length + ' 个视频'); videos.forEach(function(v, i) { console.log('视频 ' + (i+1) + ':', v.url, v.mimeType, v.size + '字节'); });

资源更新事件:window.__cyc_on_resource_update

· 回调参数:
· type - 字符串,资源类型:"video" | "audio" | "image"
· urls - 字符串数组,新增的资源 URL
· 说明: 当页面新加载了匹配的资源时自动触发window.__cyc_on_resource_update = function(type, urls) { console.log('新发现 ' + type + ': ' + urls.length + ' 个'); if (type === 'video') { urls.forEach(function(url) { console.log(' 📹 ' + url); }); } };


5.3 视频悬浮窗(阶段 C)

getCurrentVideo()

· 参数: 无
· 返回值: 字符串,当前检测到的第一个视频 URL,无视频时返回空字符串 ""
· 说明: 获取页面上检测到的视频地址

playInFloatWindow(url)

· 参数: url - 视频 URL
· 返回值: 无
· 说明: 将指定视频在系统悬浮窗中播放(视频会以小窗口形式浮在其他 App 之上)// 检测视频并开启悬浮窗 const videoUrl = __cyc_privileges__.getCurrentVideo(); if (videoUrl) { __cyc_privileges__.playInFloatWindow(videoUrl); __cyc_privileges__.toast('已开启悬浮窗播放'); } else { __cyc_privileges__.toast('当前页面未检测到视频'); }

注意事项:

· 悬浮窗需要系统"悬浮窗权限",Cat Browser 通常会引导用户授权
· 视频格式需为系统播放器支持的格式(mp4、m3u8、ts 等)
· 如果页面有多个视频,getCurrentVideo() 返回第一个检测到的


5.4 下载能力(阶段 D)

download(url, filename)

· 参数:
· url - 下载地址
· filename - 保存的文件名
· 返回值: 无
· 说明: 触发原生下载管理器下载文件(使用系统 DownloadManager)

batchDownload(urlsJson)

· 参数: urlsJson - JSON 字符串数组,要批量下载的 URL 列表
· 返回值: 无
· 说明: 批量触发下载,会弹出确认提示// 单个下载 __cyc_privileges__.download( 'https://example.com/video.mp4', '精彩视频.mp4' ); // 批量下载 const urls = [ 'https://example.com/img1.jpg', 'https://example.com/img2.jpg', 'https://example.com/img3.jpg' ]; __cyc_privileges__.batchDownload(JSON.stringify(urls)); __cyc_privileges__.toast('开始下载 ' + urls.length + ' 个文件');


5.5 网络调试(阶段 A)

setRecordBody(enabled)

· 参数: enabled - 布尔值,是否开启响应体记录
· 返回值: 无
· 说明: 开启后,cyc_monitor 的回调中会包含 responseBody 字段// 开启响应体记录(会影响少量性能,调试完建议关闭) __cyc_privileges__.setRecordBody(true); // 关闭 __cyc_privileges__.setRecordBody(false);


5.6 Aria2 下载引擎(阶段 E)

Aria2 是 Cat Browser 内置的多线程下载引擎,支持 HTTP/BT/磁力链接,具有断点续传、后台下载能力。通过 Aria2 添加的下载任务会自动出现在 App 的下载管理界面中,进度实时更新。

方法 参数 返回值 说明
aria2AddUri(uri, dir, fileName) uri: 下载链接, dir: 保存目录, fileName: 文件名 GID 字符串(失败返回空) 添加 HTTP 下载
aria2AddTorrent(magnetOrBase64, dir) magnetOrBase64: 磁力链接或 Base64 种子, dir: 保存目录 GID 字符串 添加 BT 下载
aria2TellStatus(gid) gid: 任务 GID JSON 字符串 查询进度
aria2Pause(gid) gid: 任务 GID 无 暂停任务
aria2Unpause(gid) gid: 任务 GID 无 继续任务
aria2Remove(gid) gid: 任务 GID 无 删除任务及文件

添加 HTTP 下载const gid = __cyc_privileges__.aria2AddUri( 'https://example.com/file.mp4', '/storage/emulated/0/Download/aria2', '我的视频.mp4' ); if (gid) { __cyc_privileges__.toast('下载任务已添加'); } else { __cyc_privileges__.toast('添加失败,Aria2 可能未启动'); }

添加磁力链接const gid = __cyc_privileges__.aria2AddTorrent( 'magnet:?xt=urn:btih:abc123def456...', '/storage/emulated/0/Download/aria2' );

查询下载进度// 每 3 秒查询一次进度 const timer = setInterval(function() { const statusStr = __cyc_privileges__.aria2TellStatus(gid); if (statusStr === '{}') return; const status = JSON.parse(statusStr); console.log('状态:', status.status); console.log('已下载:', status.completedLength, '字节'); console.log('总大小:', status.totalLength, '字节'); console.log('速度:', Math.round(status.downloadSpeed / 1024), 'KB/s'); if (status.status === 'complete') { __cyc_privileges__.toast('下载完成!'); clearInterval(timer); } }, 3000);

tellStatus 返回字段说明

字段 类型 说明
status string active / paused / complete / error / removed
completedLength string 已下载字节数
totalLength string 总字节数
downloadSpeed string 下载速度(B/s)
uploadSpeed string 上传速度(B/s)

暂停 / 继续 / 删除__cyc_privileges__.aria2Pause(gid); // 暂停 __cyc_privileges__.aria2Unpause(gid); // 继续 __cyc_privileges__.aria2Remove(gid); // 删除

注意事项:

· 保存目录需使用绝对路径,推荐 /storage/emulated/0/Download/aria2
· 添加任务前 Aria2 服务需已运行(App 通常开机自启)
· 任务添加后会自动出现在 App 的"下载管理"界面中
· aria2Remove 会删除已下载的文件,谨慎调用
· aria2AddUri 返回空字符串表示添加失败(通常因为 Aria2 服务未启动)


  1. 特权对象:cyc_http

注入条件: 仅在 http:// 和 https:// 页面可用。

发起完全不受浏览器同源策略、CORS 限制、SameSite Cookie 策略限制的 HTTP 请求。使用 OkHttp 原生引擎,性能优于 GM_xmlhttpRequest。

request(requestId, optionsJson)

· 参数:
· requestId - 整数,自定义请求 ID(用于在回调中区分不同请求)
· optionsJson - JSON 字符串,包含:
· url - 必填,请求地址
· method - 可选,GET/POST/PUT/DELETE 等,默认 "GET"
· headers - 可选,请求头对象,默认 {}
· body - 可选,请求体字符串(POST 时使用)
· timeout - 可选,超时毫秒数,默认 10000
· 返回值: 无(异步,通过回调获取结果)
· 回调: 需全局定义 window.__cyc_http_callback = function(requestId, success, resultJson)

回调参数说明:

参数 类型 说明
requestId number 请求 ID,对应 request() 调用时的 ID
success boolean 请求是否成功(网络层无异常)
resultJson string JSON 字符串,解析后包含 status、responseText 等

resultJson 解析后的字段:

字段 类型 说明
status number HTTP 状态码(0 表示网络错误)
statusText string 状态文本或错误信息
responseText string 响应体文本
responseHeaders object 响应头键值对// 1. 定义全局回调 window.__cyc_http_callback = function(requestId, success, resultJson) { const result = JSON.parse(resultJson); if (requestId === 1) { if (success && result.status === 200) { const data = JSON.parse(result.responseText); console.log('请求成功:', data); console.log('响应头:', result.responseHeaders); } else { console.error('请求失败:', result.status, result.statusText); } } }; // 2. 发起 GET 请求 __cyc_http__.request(1, JSON.stringify({ url: 'https://jsonplaceholder.typicode.com/posts/1', method: 'GET', headers: { 'X-Custom-Header': 'my-value' }, timeout: 10000 })); // 3. POST 请求示例 __cyc_http__.request(2, JSON.stringify({ url: 'https://api.example.com/submit', method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: 'test', value: 123 }), timeout: 15000 }));

与 GM_xmlhttpRequest 的区别:

特性 cyc_http.request() GM_xmlhttpRequest()
引擎 OkHttp(原生层) WebView 内部
CORS 完全不受限制 受浏览器策略限制
Cookie 不受 SameSite 限制 受 Cookie 策略限制
回调方式 全局单回调函数 每个请求独立回调


  1. 特权对象:cyc_monitor

注入条件: 仅在 http:// 和 https:// 页面可用。

实时监控页面发出的所有网络请求,采用"订阅制"模式,脚本需先注册关心的 URL 模式。

7.1 订阅管理方法

subscribe(scriptId, subscriptionId, pattern)

· 参数:
· scriptId - 脚本 ID(整数,用于区分不同脚本,可自定义)
· subscriptionId - 订阅 ID(字符串,用于后续取消订阅)
· pattern - URL 匹配模式(字符串,忽略大小写,包含即匹配)
· 返回值: 无
· 限制: 每个脚本最多 10 个订阅,全局最多 100 个

unsubscribe(scriptId, subscriptionId)

· 参数: 与 subscribe 一致
· 返回值: 无

unsubscribeAll(scriptId)

· 参数: scriptId - 脚本 ID
· 返回值: 无
· 说明: 取消该脚本的所有订阅

7.2 回调:window.__cyc_on_request

· 回调参数: info 对象,包含以下字段:

字段 类型 说明
scriptId number 脚本 ID
subscriptionId string 匹配的订阅 ID
url string 请求 URL(敏感参数已擦除)
method string 请求方法(GET/POST 等)
status number 响应状态码(-1 表示仅请求阶段)
duration number 请求耗时(毫秒)
requestHeaders object 请求头键值对
responseHeaders object 响应头键值对
responseBody string 响应体文本(需开启 setRecordBody(true),仅文本类型,最大 50KB)// 1. 定义回调 window.__cyc_on_request = function(info) { console.log('══════════════════════════════'); console.log('请求方法:', info.method); console.log('请求 URL:', info.url); console.log('状态码:', info.status); console.log('耗时:', info.duration + 'ms'); console.log('请求头:', JSON.stringify(info.requestHeaders)); console.log('响应头:', JSON.stringify(info.responseHeaders)); if (info.responseBody) { console.log('响应体 (前100字符):', info.responseBody.substring(0, 100)); } }; // 2. 开启响应体记录(阶段 A) __cyc_privileges__.setRecordBody(true); // 3. 订阅特定 API 接口 __cyc_monitor__.subscribe(1, 'api-monitor', '/api/'); // 4. 订阅所有请求(调试用,注意性能) __cyc_monitor__.subscribe(1, 'all-requests', ''); // 5. 取消单个订阅 __cyc_monitor__.unsubscribe(1, 'api-monitor'); // 6. 取消全部订阅 __cyc_monitor__.unsubscribeAll(1);

敏感参数保护: 以下参数名会自动替换为 ***:
token, access_token, refresh_token, key, api_key, secret, password, auth, sign, signature 等 20+ 个常见敏感参数名。


  1. 完整脚本示例

8.1 嗅探视频并一键推送到 Aria2// ==UserScript== // @name 视频一键下载(Aria2) // @match *://*/* // @grant none // ==/UserScript== (function() { 'use strict'; if (typeof __cyc_privileges__ === 'undefined') return; const DIR = '/storage/emulated/0/Download/aria2'; // 创建浮动按钮 const btn = document.createElement('div'); btn.textContent = '📥 下载全部视频'; btn.style.cssText = 'position:fixed;bottom:20px;right:20px;z-index:99999;background:#ff6600;color:#fff;padding:12px 18px;border-radius:25px;cursor:pointer;font-size:15px;font-family:sans-serif;box-shadow:0 4px 15px rgba(0,0,0,0.3);'; btn.onclick = function() { const videos = JSON.parse(__cyc_privileges__.getSniffedVideos()); if (videos.length === 0) { __cyc_privileges__.toast('未检测到视频'); return; } videos.forEach(function(v, i) { const ext = v.url.split('.').pop().split('?')[0] || 'mp4'; const gid = __cyc_privileges__.aria2AddUri(v.url, DIR, 'video_' + (i+1) + '.' + ext); console.log('添加任务:', gid); }); __cyc_privileges__.toast('已添加 ' + videos.length + ' 个下载任务到 Aria2'); }; document.body.appendChild(btn); })();

8.2 万能视频小窗播放器// ==UserScript== // @name 万能视频小窗播放器 // @match *://*/* // @grant none // ==/UserScript== (function() { 'use strict'; if (typeof __cyc_privileges__ === 'undefined') return; // 监听资源更新 window.__cyc_on_resource_update = function(type, urls) { if (type !== 'video' || urls.length === 0) return; showFloatButton(urls[0]); }; // 页面加载后检查已有视频 setTimeout(function() { const videoUrl = __cyc_privileges__.getCurrentVideo(); if (videoUrl) showFloatButton(videoUrl); }, 2000); function showFloatButton(videoUrl) { if (document.getElementById('cyc-float-btn')) return; const btn = document.createElement('div'); btn.id = 'cyc-float-btn'; btn.textContent = '▶️ 小窗播放'; btn.style.cssText = 'position:fixed;bottom:20px;right:20px;z-index:99999;background:#ff6600;color:#fff;padding:12px 18px;border-radius:25px;cursor:pointer;font-size:15px;font-family:sans-serif;box-shadow:0 4px 15px rgba(0,0,0,0.3);'; btn.onclick = function() { __cyc_privileges__.playInFloatWindow(videoUrl); __cyc_privileges__.toast('已开启悬浮窗播放'); }; document.body.appendChild(btn); } })();

8.3 网络请求实时监控面板// ==UserScript== // @name 网络请求实时监控 // @match *://*/* // @grant none // ==/UserScript== (function() { 'use strict'; if (typeof __cyc_monitor__ === 'undefined') return; // 开启响应体记录 if (typeof __cyc_privileges__ !== 'undefined') { __cyc_privileges__.setRecordBody(true); } const panel = document.createElement('div'); panel.style.cssText = 'position:fixed;bottom:10px;right:10px;z-index:99999;background:rgba(0,0,0,0.9);color:#0f0;font-size:11px;font-family:monospace;padding:10px;border-radius:6px;max-width:400px;max-height:40vh;overflow-y:auto;min-width:250px;'; panel.innerHTML = '<b>🌐 网络监控</b><br>'; document.body.appendChild(panel); const maxLines = 20; const lines = []; window.__cyc_on_request = function(info) { const color = info.status >= 400 ? '#f44' : info.status >= 200 ? '#4f4' : '#ff4'; const text = info.method.toUpperCase() + ' ' + info.status + ' ' + info.url.substring(0, 60) + ' ' + info.duration + 'ms'; lines.push('<span style="color:' + color + '">' + text + '</span>'); if (lines.length > maxLines) lines.shift(); panel.innerHTML = '<b>🌐 网络监控</b><br>' + lines.join('<br>'); }; // 订阅所有请求 __cyc_monitor__.subscribe(999, 'ui-monitor', ''); })();

8.4 批量下载页面图片// ==UserScript== // @name 批量下载页面图片 // @match *://*/* // @grant none // ==/UserScript== (function() { 'use strict'; if (typeof __cyc_privileges__ === 'undefined') { alert('请使用 Cat Browser 运行此脚本'); return; } const images = JSON.parse(__cyc_privileges__.getSniffedImages()); if (images.length === 0) { __cyc_privileges__.toast('未检测到图片'); return; } const urls = images.map(function(img) { return img.url; }); __cyc_privileges__.batchDownload(JSON.stringify(urls)); __cyc_privileges__.toast('开始下载 ' + urls.length + ' 张图片'); })();


  1. 限制与注意事项

9.1 注入限制

限制项 说明
协议限制 仅在 http:// 和 https:// 页面可用,file:// 或 about:blank 不可用
注入时机 特权对象在页面开始加载后注入
每页一次 每个页面只注入一次,刷新页面后重新注入

9.2 监控限制

限制项 说明
单脚本订阅数 最多 10 个 URL 模式
全局订阅数 总计最多 100 个
响应体大小 最大 50KB,超过部分截断
响应体类型 仅文本类型(HTML/JSON/XML/JS 等),二进制类型不包含
敏感参数保护 URL 中的 token、key、password 等自动擦除为 ***

9.3 Aria2 限制

限制项 说明
引擎状态 Aria2 服务需正常运行
保存目录 需使用绝对路径,推荐 /storage/emulated/0/Download/aria2
任务可见性 通过脚本添加的任务会出现在 App 下载管理界面
删除行为 aria2Remove 会同时删除已下载的文件

9.4 最佳实践

实践 说明
环境检测 始终用 typeof cyc_privileges !== 'undefined' 检测
降级处理 在普通浏览器中提供替代方案或提示用户使用 Cat Browser
@grant none Cat Browser 已默认开放所有 GM API,不需要额外声明
资源释放 脚本禁用/卸载时建议调用 unsubscribeAll() 清理订阅
性能考虑 不要在页面高频事件(如 scroll、mousemove)中频繁调用特权方法
Aria2 检测 调用 aria2AddUri 前可检查返回值是否为空,判断 Aria2 是否可用
响应体调试 调试完成后记得 setRecordBody(false) 关闭响应体记录
作用域隔离 始终将脚本代码包裹在 (function(){ 'use strict'; … })() 中


此文档涵盖 Cat Browser 全部脚本开发能力,脚本作者可直接复制示例代码,替换 URL 和参数即可开发出可用的脚本。