VOD 主配置顶层结构
点播(VOD)功能通过主配置 JSON 文件驱动,每个站点对应 sites[] 中的一个元素。配置文件可以同时包含直播 lives[] 和点播 sites[] 。
{
// ── 全局 Spider 包(所有站点默认使用,站点可覆盖)
"spider": "https://example.com/spider.jar",
// ── 点播站点列表(详见本页第 02 节)
"sites": [
{
"key": "cctv",
"name": "央视影音",
"type": 3,
"api": "csp_CCTV",
"jar": "https://example.com/spider.jar"
}
],
// ── 直播源列表(详见直播配置页)
"lives": [],
// ── 解析器列表(详见本页第 08 节)
"parses": [
{ "name": "在线解析1", "type": 1, "url": "https://jx.example.com/?url=" }
],
// ── 播放标记(哪些来源需要走解析器)
"flags": ["youku", "iqiyi", "bilibili"],
// ── 广告 URL 过滤关键词(匹配到则拦截)
"ads": ["ad.example.com", "tracking.example.com"],
// ── URL 重写规则
"rules": [
{ "regex": "http://old\\.cdn\\.com", "replace": "https://new.cdn.com" }
],
// ── 自定义 DNS 映射
"hosts": ["192.168.1.1 internal.example.com"],
// ── DNS over HTTPS
"doh": [
{ "name": "阿里 DoH", "url": "https://dns.alidns.com/dns-query" }
],
// ── 全局响应头注入(OkHttp 响应拦截器)
"headers": [
{ "name": "Access-Control-Allow-Origin", "value": "*" }
],
// ── HTTP 代理
"proxy": [
{ "host": "proxy.example.com", "port": 8080,
"username": "user", "password": "pass" }
],
// ── 壁纸 URL
"wallpaper": "https://example.com/wallpaper.jpg",
// ── 配置公告(App 启动时展示)
"notice": "更新日期:2026-01-01"
}
"urls"
数组,每个元素是一个子配置的 URL(Depot 模式)。App
会自动加载第一个子配置,同时合并多个配置源。这是「聚合壳」的常用写法。
Depot 聚合壳写法
{
"urls": [
{
"name": "主配置",
"url": "https://example.com/main_config.json",
"desc": "包含直播 + 点播"
},
{
"name": "备用配置",
"url": "https://example2.com/config.json"
}
]
}
sites[] 站点字段详解
每个点播站点是 sites 数组中的一个对象,对应一个数据源(如某影视网站爬虫)。
| 字段 | 类型 | 必填 | 说明 | 示例值 |
|---|---|---|---|---|
| key | string | 必填 | 全局唯一标识符(数据库主键),用于持久化用户的搜索可用/切换状态 | "cctv" |
| name | string | 必填 | 在 App 中的显示名称 | "央视影音" |
| type | number | 可选 |
Spider 类型,决定如何加载
api
:
0
=内置(XML/JSON API),
1
=JS(QuickJS),
2
=Python(Chaquopy),
3
=JAR(Java/Kotlin DEX)。默认
0
|
3 |
| api | string | 必填 |
内置时为接口 URL;JS/Python/JAR 时为 Spider 类名(通常以
csp_
为前缀)
|
"csp_MySpider"
/
"https://api.example.com/"
|
| jar | string | 可选 |
Spider 文件 URL(type=1 时为 .js,type=2 时为 .py,type=3 时为
.jar/.dex)。未设置则继承顶层
spider
字段
|
"https://example.com/spider.jar" |
| ext | string / object | 可选 |
传给
Spider.init(ctx, extend)
的扩展参数。可以是远程 URL(自动 fetch)或 JSON 字符串或对象
|
"https://example.com/ext.json" |
| playUrl | string | 可选 | 全局解析前缀 URL,点播解析失败时自动拼接视频地址尝试解析 | "https://jx.example.com/?url=" |
| click | string | 可选 | 点击播放时先经此 URL 跳转解析 | "https://jx.example.com/?url=" |
| timeout | number | 可选 | 请求超时秒数(最小 1 秒,内部转换为毫秒)。若未设置则使用全局播放超时 | 15 |
| searchable | number | 可选 |
搜索状态:
0
=禁止,
1
=允许(默认),
2
=已被用户禁用。注意:
0
表示强制禁用,用户无法开启;
1
/
2
用户可切换
|
1 |
| changeable | number | 可选 |
用户是否可切换来源:
0
=强制禁止,
1
=允许(默认),
2
=用户已禁用
|
1 |
| quickSearch | number | 可选 |
是否参与快速搜索(搜索时直接返回结果不分页):
0
=不参与,
1
=参与(默认)
|
1 |
| indexs | number | 可选 |
是否加入全局搜索索引:
0
=不加(默认),
1
=加入
|
1 |
| hide | number | 可选 |
隐藏该站点:
0
=显示(默认),
1
=隐藏(不在站点列表里出现但仍可通过 key 引用)
|
0 |
| categories | array | 可选 |
白名单分类列表。设置后
homeContent
返回的 class 会过滤,只保留列表中的分类名。未设置则显示全部
|
["电影","电视剧","综艺"] |
| header | object | 可选 | 附加到该站点所有请求的 HTTP 请求头 | {"Cookie":"sess=abc","X-Token":"xyz"} |
| style | object | 可选 | 封面展示样式,格式见第 04 节 style 字段说明 | {"type":"rect"} |
{
"spider": "https://example.com/spider.jar",
"sites": [
{
"key": "site_a",
"name": "Site A",
"type": 3,
"api": "csp_SiteA",
// jar 未设置 → 继承顶层 spider
"ext": "https://example.com/ext_a.json",
"searchable": 1,
"changeable": 1,
"categories": ["电影", "电视剧"]
},
{
"key": "site_b_js",
"name": "Site B (JS)",
"type": 1,
"api": "csp_SiteB",
"jar": "https://example.com/siteb.js",
"ext": "https://example.com/ext_b.json",
"searchable": 1,
"timeout": 20
},
{
"key": "site_c_xml",
"name": "Site C (内置 XML API)",
"type": 0,
"api": "https://api.sitec.com/",
"searchable": 0
}
]
}
type 类型与 Spider 加载机制
type 字段决定如何加载和运行 api 字段指定的爬虫:
| type 值 | 类型名 | 加载引擎 | jar 格式 | api 格式 | 适用场景 |
|---|---|---|---|---|---|
| 0 | 内置 | App 内置解析器 | 无需指定 | HTTP(S) API URL 或内置规则名 | 遵循标准 CMS API(苹果 XML/JSON API 格式)的站点 |
| 1 | JS | QuickJS(嵌入式 JS 引擎) |
远程
.js
文件 URL
|
JS 文件中导出的爬虫类名 | 需要 JavaScript 自定义解析逻辑的站点 |
| 2 | Python | Chaquopy(Android Python 3) |
远程
.py
文件 URL
|
Python 文件中的爬虫类名 | 需要 Python 库(requests / BeautifulSoup 等)的站点 |
| 3 | JAR | Android DexClassLoader |
远程
.jar
文件(包含 classes.dex)
|
爬虫类的完整类名或
csp_
简写
|
需要 Android SDK / Java 库的高性能场景 |
jar 字段继承规则
当站点 jar 为空时,自动继承顶层 spider 字段的值。通常一个配置文件只需要一个 spider.jar,各站点只写 api (类名)即可:
{
"spider": "https://example.com/spider.jar",
"sites": [
{ "key": "s1", "name": "站点1", "type": 3, "api": "csp_Site1" },
{ "key": "s2", "name": "站点2", "type": 3, "api": "csp_Site2" },
// 覆盖:站点3 使用不同的 jar
{ "key": "s3", "name": "站点3", "type": 1, "api": "csp_Site3",
"jar": "https://other.example.com/site3.js" }
]
}
<rss>
/
<class>
/
<list>
/
<video>
(XML) 或
class[]
/
list[]
(JSON)。
api
字段填接口根 URL 即可(无需 Spider 代码)。
Vod 视频对象字段
Spider 各方法返回的 list[] 数组中,每个元素是一个 Vod 对象,字段名使用下划线命名法,兼容苹果 CMS XML API 格式。
| JSON 字段 | 类型 | 说明 | 示例值 |
|---|---|---|---|
| vod_id | string |
视频唯一 ID,传入
detailContent()
和
playerContent()
|
"movie_123" |
| vod_name | string | 视频标题 | "流浪地球2" |
| vod_pic | string | 封面图 URL | "https://img.example.com/cover.jpg" |
| vod_remarks | string | 备注标签(如 "HD"、"完结"、更新集数) |
"HD"
/
"更新至第12集"
|
| type_name | string | 分类名称(用于列表展示) | "电影" |
| vod_year | string | 年份 | "2023" |
| vod_area | string | 地区 | "中国大陆" |
| vod_director | string | 导演(可多人,逗号分隔) | "郭帆" |
| vod_actor | string | 主演(可多人,逗号分隔) | "吴京,李雪健,沙溢" |
| vod_content | string | 剧情简介 | "2058年,地球发动机建设进程启动..." |
| vod_play_from | string |
播放来源名称(线路名),多来源用
$$$
分隔
|
"线路1$$$线路2$$$线路3" |
| vod_play_url | string |
剧集 URL 列表,集与集之间用
#
,按集名
$
URL 格式。多来源与 vod_play_from 对应,用
$$$
分隔
|
"第1集$url1#第2集$url2$$$线路2第1集$url3#线路2第2集$url4" |
| vod_tag | string |
特殊标签:
"folder"
表示此条目是一个目录(点进去载入子列表)
|
"folder" |
| style | object | 封面样式覆盖(详见下方 style 说明) | {"type":"rect"} |
| land | number |
封面比例快捷字段:
1
=横屏(16:9),
0
=竖屏
|
1 |
| circle | number |
圆形显示:
1
=圆形封面,
0
=矩形
|
0 |
| ratio | number |
封面宽高比(浮点数),如
1.778
= 16:9
|
0.75 |
style 对象说明
| style.type 值 | 显示效果 |
|---|---|
| "rect" | 标准矩形封面(默认,竖版海报) |
| "square" | 正方形封面(适合专辑/歌手头像) |
| "thumb" | 横版缩略图(适合综艺/新闻) |
| "oval" | 椭圆形封面 |
播放信息格式(vod_play_from / vod_play_url)
vod_play_from 和 vod_play_url 是点播最关键的字段,用于构建剧集列表和播放选项。
单来源(单线路)
{
"vod_id": "drama_456",
"vod_name": "某电视剧",
"vod_play_from": "线路1",
// 格式:集名$URL#集名$URL#...
"vod_play_url": "第1集$https://v.ex.com/ep1.m3u8#第2集$https://v.ex.com/ep2.m3u8#第3集$https://v.ex.com/ep3.m3u8"
}
多来源(多线路)
{
"vod_id": "drama_456",
"vod_name": "某电视剧",
// $$$ 分隔多个来源
"vod_play_from": "线路1$$$线路2$$$线路3",
// 与 vod_play_from 按顺序对应,同样用 $$$ 分隔
"vod_play_url": "第1集$url1a#第2集$url2a$$$第1集$url1b#第2集$url2b$$$第1集$url1c"
}
电影(单集)
{
"vod_id": "movie_789",
"vod_name": "流浪地球2",
"vod_play_from": "高清播放",
// 集名为空字符串或影片名均可,App 只会显示一集
"vod_play_url": "$https://v.example.com/wandering_earth_2.mp4"
}
playerContent()
返回的
url
字段才是最终发送给播放器的真实流地址(m3u8/mp4 等)。
vod_play_url
里的地址是 Spider 的内部 ID 或直链,具体格式由你的 Spider 决定。
Result 返回结构
Spider 所有方法都通过 JSON 字符串返回一个 Result 对象(序列化后的 JSON),以下是各字段说明:
| 字段 | 类型 | 主要用途 | 说明 |
|---|---|---|---|
| class | array | homeContent() |
分类列表(Class 对象数组),用于首页分类导航 |
| list | array | 所有方法 | 视频对象列表(Vod 对象数组) |
| filters | object | homeContent() |
筛选器字典,key 为 type_id,value 为 Filter 对象数组。详见第 07 节 |
| pagecount | number | categoryContent() |
总页数(用于分页导航) |
| url | string/object | playerContent() |
最终播放 URL,或包含多个备用地址的对象 |
| header | object | playerContent() |
播放请求附带的 HTTP 请求头 |
| parse | number | playerContent() |
0
=直接播放(默认),
1
=交给解析器(parses[])再解析
|
| jx | number | playerContent() |
1
=使用解析器(parse=1 的别名)
|
| format | string | playerContent() |
强制 MIME 类型:
"hls"
/
"mpd"
等
|
| click | string | playerContent() |
二次解析跳转 URL |
| key | string | playerContent() |
DRM ClearKey 密钥(kid:key 或 JSON 字符串) |
| drm | object | playerContent() |
DRM 配置对象(同直播 drm 字段格式) |
| subs | array |
playerContent()
/
detailContent()
|
字幕列表(Sub 对象数组,含 url/name/lang/format 字段) |
| danmaku | array / string |
playerContent()
/
detailContent()
|
弹幕数据 URL 或 XML 内容 |
| desc | string | playerContent() |
辅助描述信息(如集标题) |
| flag | string | playerContent() |
指定使用的解析器名称(对应 parses[].name) |
| msg | string | 所有方法 | 错误或提示信息,非空时 App 会弹出提示 |
| code | number | 所有方法 |
状态码,非 0 时
msg
才会显示
|
各方法返回示例
{
"class": [
{ "type_id": "1", "type_name": "电影", "type_flag": "0" },
{ "type_id": "2", "type_name": "电视剧", "type_flag": "0" },
{ "type_id": "3", "type_name": "综艺", "type_flag": "0" }
],
"filters": {
"1": [
{
"key": "area",
"name": "地区",
"value": [
{ "n": "全部", "v": "" },
{ "n": "中国大陆", "v": "1" },
{ "n": "香港", "v": "2" }
]
},
{
"key": "year",
"name": "年份",
"init": "2024",
"value": [
{ "n": "全部", "v": "" },
{ "n": "2025", "v": "2025" },
{ "n": "2024", "v": "2024" }
]
}
]
}
}
{
"parse": 0,
"url": "https://v.example.com/stream.m3u8",
"header": { "Referer": "https://example.com/" },
"format": "hls"
}
{
"parse": 1,
"url": "https://v.youku.com/v_show/id_xxx.html",
"flag": "youku"
}
Class(分类)与 Filter(筛选)
Class 对象字段
| 字段 | 类型 | 说明 | 示例值 |
|---|---|---|---|
| type_id | string |
分类 ID,传入
categoryContent(tid, ...)
的第一个参数
|
"1" |
| type_name | string | 分类显示名 | "电影" |
| type_flag | string |
是否有筛选器:
"0"
=无,
"1"
=有。设为 "1" 则 App 在该分类显示筛选按钮
|
"1" |
| type_extend | string |
额外参数,随 tid 一起传给
categoryContent()
(较少用)
|
"" |
Filter 对象字段
| 字段 | 类型 | 说明 | 示例值 |
|---|---|---|---|
| key | string |
筛选条件键名,传入
categoryContent()
的
extend
HashMap 中
|
"area" |
| name | string | 筛选条件显示名 | "地区" |
| init | string | 默认选中项的值(对应 Value.v),不设则默认选第一项 |
""
/
"2024"
|
| value | array | 下拉选项列表(Value 对象数组) | [{"n":"全部","v":""},{"n":"大陆","v":"1"}] |
Value 对象字段
| 字段 | 类型 | 说明 | 示例值 |
|---|---|---|---|
| n | string | 显示名称(display name) | "中国大陆" |
| v | string | 实际传参值(value),传入 extend HashMap | "1" |
筛选器工作流程
-
1homeContent(true) 返回 filters{}
filters是一个 Map,key=type_id,value=Filter 数组。当 filter=true 时 App 需要展示筛选选项。 -
2用户选择筛选条件App 把用户选择汇聚成 HashMap<String,String>,key=Filter.key,value=选中的 Value.v。
-
3categoryContent(tid, pg, filter=true, extend) 被调用extend 参数包含所有选中的筛选条件,Spider 根据这些参数修改请求 URL。
@Override
public String categoryContent(String tid, String pg, boolean filter,
HashMap<String, String> extend) throws Exception {
String area = extend.getOrDefault("area", "");
String year = extend.getOrDefault("year", "");
String url = "https://api.example.com/vod?type=" + tid
+ "&pg=" + pg
+ "&area=" + area
+ "&year=" + year;
// fetch & build result...
}
parses[] 解析器配置
解析器(parses)负责把 VIP 视频平台的播放页面 URL 解析成直链。Spider 在
playerContent()
中返回
parse=1
时,App 会根据视频 URL 匹配对应解析器。
| 字段 | 类型 | 必填 | 说明 | 示例值 |
|---|---|---|---|---|
| name | string | 必填 | 解析器名称(显示名 + Spider 返回的 flag 字段与此匹配) | "在线解析1" |
| type | number | 可选 |
解析器类型:
0
=WebView 内嵌解析,
1
=JSON 接口解析,
2
=嗅探,
3
=JS 脚本,
4
=神嗅(自动选择最佳解析器)
|
1 |
| url | string | 必填 | 解析服务 URL,type=1 时视频 URL 直接拼接到此 URL 末尾发起请求;type=0/2 时为 WebView 加载的基地址 | "https://jx.example.com/?url=" |
| ext | object | 可选 |
扩展配置对象,包含
flag
和
header
子字段
|
{"flag":["youku","iqiyi"]} |
| ext.flag | array | 可选 |
此解析器负责的来源标记列表(与全局
flags[]
及 Spider 返回的
flag
字段匹配)
|
["youku","iqiyi","bilibili"] |
| ext.header | object | 可选 | 调用解析接口时附加的请求头(如 Cookie、Authorization) | {"Cookie":"token=abc123"} |
parse type 详解
| type 值 | 名称 | 工作方式 | 适用场景 |
|---|---|---|---|
| 0 | WebView | 在 WebView 中加载页面,嗅探视频流 URL | 有反爬的大平台(爱奇艺、优酷等) |
| 1 | JSON 接口 | 直接 HTTP 请求解析接口,接口返回 JSON 含播放 URL | 公开解析接口(免费 jx 服务) |
| 2 | 嗅探 | 加载请求链,从 HTTP 流量中嗅探视频文件请求 | 隐藏在页面 js 中的播放地址 |
| 3 | JS 脚本 | 执行自定义 QuickJS 脚本完成解析逻辑 | 有特殊解密逻辑的平台 |
| 4 | 神(God) | App 自动尝试所有可用解析器 | 不确定需要哪个解析器时的兜底 |
{
"parses": [
{
"name": "免费解析1",
"type": 1,
"url": "https://jx.example.com/api/?url="
// ext 未设则接受所有 flag
},
{
"name": "youku专用解析",
"type": 3,
"url": "https://jx2.example.com/youku.js",
"ext": {
"flag": ["youku"],
"header": { "Cookie": "yk_token=abc" }
}
},
{
"name": "WebView嗅探",
"type": 0,
"url": "https://jx3.example.com/",
"ext": { "flag": ["iqiyi", "bilibili"] }
}
],
// 全局 flag:URL 中含有这些关键词才走解析
"flags": ["youku.com", "iqiyi.com", "bilibili.com", "v.qq.com"]
}
全局网络控制字段
以下顶层字段作用于整个 App 的网络层,与直播/点播均相关。
| 字段 | 类型 | 说明 | 示例值 |
|---|---|---|---|
| headers | array | OkHttp 响应拦截器注入头,对所有出站请求的响应生效(常用于解决跨域) | [{"name":"Access-Control-Allow-Origin","value":"*"}] |
| proxy | array | HTTP 代理配置列表,字段:host, port, username, password, regex(可选:仅匹配正则的请求走代理) | [{"host":"127.0.0.1","port":7890}] |
| rules | array |
URL 正则替换规则,每个对象含
regex
(匹配模式)和
replace
(替换值)
|
[{"regex":"http://","replace":"https://"}] |
| hosts | array |
自定义 DNS 映射,格式
"IP 域名"
(类似 hosts 文件)
|
["1.2.3.4 api.example.com"] |
| doh | array | DNS over HTTPS 配置,字段:name, url(DoH 服务地址) | [{"name":"阿里","url":"https://dns.alidns.com/dns-query"}] |
| ads | array | 广告 URL 关键词黑名单,URL 中包含任一关键词则拦截该请求 | ["ad.douyin.com","tracking.qq.com"] |
| flags | array | 触发解析器的来源标识(URL 关键词),URL 中含有这些词时交给 parses[] 处理 | ["youku.com","iqiyi.com","bilibili.com"] |
| wallpaper | string | App 壁纸图片 URL | "https://example.com/bg.jpg" |
| logo | string | 全局台标前缀(直播用) | "https://img.example.com/logos/" |
| epg | string | 全局 EPG 订阅地址(直播用) | "https://epg.example.com/e.xml" |
| notice | string | 配置更新公告,App 启动时展示 | "2026-01-01 更新内容..." |
完整配置示例
{
"spider": "https://cdn.example.com/spider.jar",
"sites": [
{
"key": "site_a",
"name": "站点 A",
"type": 3,
"api": "csp_SiteA",
"ext": "https://cdn.example.com/ext_a.json",
"searchable": 1,
"changeable": 1,
"categories": ["电影", "电视剧"]
},
{
"key": "site_b_js",
"name": "站点 B(JS)",
"type": 1,
"api": "csp_SiteB",
"jar": "https://cdn.example.com/siteb.js",
"searchable": 1,
"timeout": 20
}
],
"lives": [
{
"name": "直播订阅",
"url": "https://cdn.example.com/live.m3u",
"epg": "https://epg.example.com/e.xml"
}
],
"parses": [
{
"name": "通用解析",
"type": 1,
"url": "https://jx.example.com/?url="
}
],
"flags": ["youku.com", "iqiyi.com", "bilibili.com", "v.qq.com"],
"ads": ["ads.example.com", "tracker.example.com"],
"rules": [
{ "regex": "\\bhttp://", "replace": "https://" }
],
"doh": [
{ "name": "Cloudflare", "url": "https://1.1.1.1/dns-query" }
],
"epg": "https://epg.example.com/all.xml",
"notice": "配置更新于 2026-01-01",
"wallpaper": "https://cdn.example.com/bg.jpg"
}