Files
MoonTVPlus/SOURCE_SCRIPT.md

204 lines
3.5 KiB
Markdown
Raw Permalink Normal View History

2026-03-21 14:44:53 +08:00
# 视频源脚本编写教程
## 最小模板
```js
return {
meta: {
name: '示例脚本',
author: 'admin'
},
async getSources(ctx) {
return [{ id: 'default', name: '默认源' }];
},
async search(ctx, { keyword, page, sourceId }) {
return {
list: [],
page,
pageCount: 1,
total: 0
};
},
async recommend(ctx, { page }) {
return {
list: [],
page: page || 1,
pageCount: 1,
total: 0
};
},
async detail(ctx, { id, sourceId }) {
return {
id,
title: '',
poster: '',
year: '',
desc: '',
playbacks: [
{
sourceId,
sourceName: '默认源',
episodes: [],
episodes_titles: []
}
]
};
},
2026-03-22 16:31:47 +08:00
async resolvePlayUrl(ctx, { playUrl, sourceId, episodeIndex }) {
2026-03-21 14:44:53 +08:00
return {
url: playUrl,
type: 'auto',
headers: {}
};
}
};
```
## 支持的 hook
1. `getSources()`
返回脚本管理的子源列表
2. `search({ keyword, page, sourceId })`
搜索
3. `recommend({ page })`
推荐
4. `detail({ id, sourceId })`
详情
2026-03-22 16:31:47 +08:00
5. `resolvePlayUrl({ playUrl, sourceId, episodeIndex })`
2026-03-21 14:44:53 +08:00
播放前解析最终地址
## `ctx` 里能用什么
1. `ctx.fetch(...)`
发请求
2. `ctx.request.get/getJson/getHtml/post`
快捷请求
3. `ctx.html.load(html)`
`cheerio` 风格解析
4. `ctx.cache.get/set/del`
脚本缓存
5. `ctx.log.info/warn/error`
输出测试日志
6. `ctx.utils.buildUrl/joinUrl/randomUA/sleep/base64Encode/base64Decode/now`
常用工具
7. `ctx.config.get/require/all`
读脚本配置
8. `ctx.runtime`
当前脚本信息
## `search` 返回格式
```js
{
list: [
{
id: '123',
title: '凡人修仙传',
poster: 'https://...',
year: '2025',
desc: '简介',
type_name: '动漫',
douban_id: 0,
vod_remarks: '更新至10集'
}
],
page: 1,
pageCount: 1,
total: 1
}
```
## `detail` 返回格式
```js
{
id: '123',
title: '凡人修仙传',
poster: 'https://...',
year: '2025',
desc: '简介',
playbacks: [
{
sourceId: 'default',
sourceName: '默认源',
episodes: [
'https://example.com/play/1',
2026-03-22 16:31:47 +08:00
{
playUrl: 'https://example.com/play/2',
needResolve: false
}
2026-03-21 14:44:53 +08:00
],
episodes_titles: ['第1集', '第2集']
}
]
}
```
2026-03-22 16:31:47 +08:00
说明:
- `episodes` 可以是字符串,默认等价于 `{ playUrl: '...', needResolve: true }`
- `needResolve` 默认为 `true`
- 显式写 `needResolve: false` 时,播放页会直接使用该地址,不再调用 `resolvePlayUrl`
2026-03-21 14:44:53 +08:00
## `resolvePlayUrl` 返回格式
```js
{
url: 'https://real-url.m3u8',
type: 'auto',
headers: {}
}
```
## 最简单的搜索例子
```js
async search(ctx, { keyword, page, sourceId }) {
const data = await ctx.request.getJson('https://example.com/api/search', {
query: { wd: keyword, pg: page }
});
return {
list: (data.list || []).map((item) => ({
id: String(item.id),
title: item.title,
poster: item.pic || '',
year: item.year || '',
desc: item.desc || ''
})),
page,
pageCount: data.pagecount || 1,
total: data.total || 0
};
}
```
## 最简单的播放解析例子
```js
async resolvePlayUrl(ctx, { playUrl }) {
return {
url: playUrl,
type: 'auto',
headers: {}
};
}
```
## 导入格式
```json
{
"key": "demo",
"name": "演示脚本",
"description": "test",
"enabled": true,
"code": "return { ... }"
}
```