JS 解析规则 · 开发文档
需超级直播海外版 3.2.0 及以上。在频道地址里用 js:// 调用本机或 HTTP(S) 上的 JavaScript 脚本,把网页/接口解析成可播放地址。运行时为内置 QuickJS;脚本里可用 ms、ku9(与 cjs 同一对象)。
js:// 解析规则自超级直播海外版 3.2.0(versionCode 360)起支持;更早版本不可用。请先到 下载页 安装最新 APK。
com.hd.zhibo)需开启「扩展支持库 / JS」能力后,才可跑用户脚本。支持本机文件(外部存储 cjzb/js/,路径由系统现取,勿写死 /storage/emulated/0),以及远程 js://http(s)://…/xxx.js?id=;也可简写为 js_http://… / js_https://…(等价)。
1. 脚本怎么跑
| 频道地址写法 | 入口 |
|---|---|
js:///绝对路径.js或 js://http(s)://某脚本.js?id=或简写 js_http:// / js_https://某脚本.js?id= |
全局 main(item)。远程简写会归一成 js://http(s)://…;远程时 item.url 为真实 http(s)://…(含查询) |
局域网 http://盒子IP:9188/ms/js/文件名.js?id= |
同一份 main(item)(手机助手可访问盒子上的脚本) |
/sdcard/cjzb/http.js |
http_dispatch(method, path, query, body),仅当内置 Lua 没有这条路由时 |
item 常用字段:
item.url:整段频道地址(含js://…与查询)item.pageUrl:查询参数page=的值(若有)item.name:频道 id / 名称侧传入的标识
推荐返回对象(也可用字符串直接返回可播 URL):
function main(item) {
// …
return {
url: "https://cdn.example/live.m3u8",
referer: "https://www.example.com/",
userAgent: "Mozilla/5.0"
};
}
url 必填。也可用 playUrl / playurl,或 { urls: [{ url: "…" }] }。referer、userAgent(或 ua)以及 headers 对象会写入播放请求头。
2. 运行限制
- 脚本最长约 1MB;运行内存上限约 16MB;单次执行超过约 20 秒会被打断。
- 脚本里发起的 HTTP 只允许
http:///https://,单次回包上限约 2MB。 - 最终播放地址协议须为:
http(s)/rtmp/rtsp/udp/rtp/file。 - 调试:脚本里
ku9.log(...)或ms.log("i", "…"),logcat 标签多为Qjs。
返回的播放地址前面可加解码前缀(可选)。宿主在真正起播前会剥掉前缀,再把剩下的 URL 交给对应解码路径;脚本里读到的 item.url 一般已是剥过的干净地址,不要自己再解析或叠两层(如 sys:sys:…)。规范写法是单冒号;写成 sys:// / soft:// / soft_hw:// 也等价(宿主会连同紧随的 // 一并去掉)。
| 前缀 | 含义 | 例子 |
|---|---|---|
sys: |
强制走系统播放器(Android MediaPlayer / 厂商播放器),不走 App 内置解码。 | sys:http://cdn.example/live.m3u8 |
soft: |
强制走 App 内置软解(软件解码路径)。 | soft:http://cdn.example/live.ts |
soft_hw: |
强制走 App 内置硬解(MediaCodec 等硬件解码,仍由内置播放器接管,不是系统播放器)。 | soft_hw:udp://239.1.1.1:1234 |
未加前缀时,按用户在菜单里选的解码方式起播。脚本返回址若带了前缀,优先于频道下发地址上的前缀。
3. 函数返回值约定
- string:文本(hex、Base64、JSON 文本等)。
- 字节:原始字节。若内容是合法 UTF-8,宿主常做成 string;否则为
ArrayBuffer。失败时加密类函数多返回null。 - 每个函数通常有蛇形与驼峰两个名字,例如
xxtea_decrypt与xxteaDecrypt。下表只写一个。
4. ku9 网络(仅 JS)
ku9 与 cjs 是同一对象。ku9.get / post / request 不带 App 登录 Bearer;需要鉴权时请自己在 headers 里加。
| 函数 | 参数 | 返回 |
|---|---|---|
get(url, headers) | headers 可省,对象或 "Name: value\r\n" | 字节(响应正文)。失败多为 "" |
post(url, body, headers) | 同上 | |
request(url, method, headers, body, followRedirects) | followRedirects === false 时不跟随跳转 | 对象:code 数字,body 字节,url/error 字符串,headers 值为字符串 |
request(url, opts) | opts.method / headers / body|data / followRedirects | 同上 |
getQuery(url, key) | string;没有则 "" | |
getCache(key) / setCache(key, value, ttlMs) | ttlMs 可省(毫秒);过期后取不到 | get 为字节;set 无返回 |
log(...) | 若干参数拼成一行 | 无 |
var r = ku9.request("https://example/api", "POST", {
"Content-Type": "application/json",
"Referer": "https://example/"
}, JSON.stringify({ a: 1 }));
if (!r || r.code !== 200) throw new Error("http " + (r && r.code));
var data = JSON.parse(r.body);
5. 加密与摘要
ms 与 ku9 上都有。字符串参数按 UTF-8 字节参与运算。
| 函数 | 说明 |
|---|---|
md5 / sha1 / sha256 | 返回小写 hex string |
sha512 | 返回 64 字节原文,不是 hex 文本 |
hash(algo, data, raw) / hash_hmac(algo, data, key, raw) | algo 如 "md5"、"sha384";raw 为真返回字节 |
crc32(data) | 数字 |
xxtea_decrypt / xxtea_encrypt | 与常见 PHP XXTEA(末尾长度字)一致;失败 null |
aes_cbc_decrypt/encrypt、aes_ecb_decrypt、sm4_ecb_decrypt | PKCS7;失败 null |
cipher(name, mode, data, key, iv, opts) | 如 "aes-128-ctr";mode 以 e 开头为加密 |
rsa_public_encrypt / rsa_sign / rsa_verify | PEM 或裸 base64;失败见上表约定 |
gzip / gunzip | 字节;失败 null |
hex_encode/decode、b64_encode/decode、urlencode/urldecode | 编解码工具;失败多为 null |
random_bytes(n) | 最多 1MB;返回字节;失败 null |
若接口给的是 Base64 密文,可先 b64_decode(或 atob)再 xxtea_decrypt。
6. 设备与时间
| 函数 | 返回 |
|---|---|
mac() / mac_address(iface) | 网卡 MAC string;没有则 "" |
uuid() / device_id() | 设备码 string |
time() / current_time_sec() | 秒(数字) |
current_time_millis() / now_ms() | 毫秒(数字) |
microtime(asFloat) | 不传:string,形如 "0.微秒 秒";asFloat 为真:数字(秒的小数) |
uniqid(prefix, moreEntropy) | string;moreEntropy 为真时末尾再加随机 hex |
播放器还会在最终地址上替换 [mac]、[uuid]、[port]、[httpport]。脚本里也可用 ms.proxy_port() 自行拼端口。
7. 只在 ms 上
下列能力挂在 ms;其中 HTTP 变体可能自动带上 App 侧鉴权头(与 ku9.* 不同)。
| 函数 | 返回 |
|---|---|
http_get(url) / download(url) | 字节(GET 正文)。HTTP 4xx/5xx 或失败为 null |
http_request(method, url, headers, body) | 成功:字节。失败 null |
http_ex(method, url, headers, body, opts) | 对象:status 数字,body 字节,headers 值为 string。opts.redirect === false 时不跟随跳转 |
http_status(url) | 数字(状态码)。失败 -1 |
ws_text(url, headers, body, opts) | 字节。opts.binary 为真时按二进制帧收取 |
download_to_file(url, path, md5) | 布尔。md5 可省,有则按文件内容核对 |
read_file(path) | 字节。打不开为 null |
write_file(path, data) | 布尔。父目录不存在则失败(不会自动建目录) |
isfile(path) | 数字:普通文件为 1,否则 0 |
isdir(path) | 数字:目录为 1,否则 0 |
mkdir(path) | 数字:建好或本来就是目录为 0,失败为 1(中间缺的目录会一并建出) |
md5_file(path) | string,32 位小写 hex。打不开为 "" |
appname() | string,应用显示名;没有则 "" |
vername() | string,versionName,如 3.2.0 |
appver() | string,versionCode 的十进制数字 |
pkname() | string,包名(超级直播 com.hd.zhibo) |
abi() | 数字 |
api_base() / auth_token() | string |
proxy_port() | 数字,本机代理端口;没有则 null |
json_decode(text) | 对象或数组;失败 null |
json_encode(value) | string;失败 null |
log(level, msg) | 无。level 以 w / e 开头分别为警告和错误 |
stop_play() | 无 |
set_dns_rules(text) / set_engine_params(text) | 无。参数为 string |
crypto_selftest() | 数字。0 为通过 |
常量:ms.ACTION_LIVE = 0,ACTION_CATCHUP = 1,ACTION_VOD = 2,ACTION_TIMESHIFT = 3。
8. 全局函数
atob(s):Base64 → 0–255 字符 string(可用charCodeAt取字节)btoa(s):接受上述 string 或Uint8Array/ArrayBuffer,返回 Base64 string
9. 本机 http_dispatch
文件:/sdcard/cjzb/http.js(须返回 string):
function http_dispatch(method, path, query, body) {
// method、path、query 均为 string;query 是 JSON 文本
// body:合法 UTF-8 为 string;否则可能是 Uint8Array
return "{\"code\":0}";
}
10. 最小可用示例
把下面保存为外部存储 cjzb/js/demo.js,频道地址写成:
js:///sdcard/cjzb/js/demo.js?page=https://example.com/live
function main(item) {
ku9.log("page=", item.pageUrl || "");
var page = item.pageUrl || ku9.getQuery(item.url, "page");
if (!page) throw new Error("missing page");
var html = ku9.get(page, {
"User-Agent": "Mozilla/5.0",
"Referer": "https://example.com/"
});
if (!html) throw new Error("empty body");
// 按站点自己改:这里只是示意
var m = String(html).match(/https?:\/\/[^"'\s]+\.m3u8[^"'\s]*/i);
if (!m) throw new Error("m3u8 not found");
return {
url: m[0],
referer: "https://example.com/",
userAgent: "Mozilla/5.0"
};
}