-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* 智能防挡弹幕 * Create player.md * Update webmask.md * style: webmask.md --------- Co-authored-by: z0z0r4 <z0z0r4@outlook.com>
- Loading branch information
Showing
2 changed files
with
233 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
# 智能防挡弹幕 | ||
|
||
B 站部分视频提供“智能防挡弹幕”功能,其原理是提供了一个 webmask 二进制文件,其中保存了视频中各个位置的 svg 格式蒙版。 | ||
|
||
首先需要获取 webmask 资源的地址。 | ||
|
||
## 获取 webmask 资源地址 | ||
|
||
通过 [web 播放器资源接口](../video/player.md) 获取 webmask 二进制文件的地址。 | ||
|
||
|
||
## webmask 资源 | ||
|
||
获取的 url 没有权鉴,不需要后面的参数也可以获取。 | ||
|
||
示例: | ||
|
||
```shell | ||
curl -G https://upos-sz-staticcos-cmask.bilivideo.com/cmaskboss/825851971_30_0.webmask >> 825851971_30_0.webmask | ||
``` | ||
|
||
下载后是二进制文件。 | ||
|
||
|
||
## webmask 二进制读取 | ||
|
||
参考:[andrewvy/webmask-renderer](https://github.com/andrewvy/webmask-renderer) | ||
|
||
name | offset | length | type | desc | ||
--- | ------ | ------ | ---- | ---- | ||
mask | 0 | 4 | char | 'MASK' 文件头 | ||
version| 4 | 4 | int | 是1 | ||
vU | 8 | 4 | ? | 不知道是干什么的 | ||
Ly | 12 | 4 | int | 后续数据的段数 | ||
time_1 | 16 | 8 | long | 第一段对应视频开始时间 | ||
offset_1 | 24 | 8 | long | 第一段蒙版信息开始处对应二进制偏移 | ||
...|...|...|...|... | ||
time_{Ly} |16+(Ly-1)*16| 8 | long | 第 `Ly` 段对应视频开始时间 | ||
offset_{Ly} |24+(Ly-1)*16| 8 | long | 第 `Ly` 段蒙版信息开始处对应二进制偏移 | ||
segments_1| 由前面offset_1提供 | 由 `offset_2-offset_1` 计算得到 | binary | 蒙版信息块,使用 gzip 压缩 | ||
...|...|...|...|... | ||
|
||
|
||
蒙版信息块是经过 gzip 压缩文本得到的二进制。解压缩后得到一个字节串。 | ||
|
||
前 16 字节是两个 long,记为 `left` 和 `right`,暂时不清楚其作用。`left` 似乎和平均每张蒙版的时间有关。`right` 总是 `i*10000`,`i` 是从 0 开始数的数据段次序。 | ||
|
||
后面是各个 svg 文本直接拼起来,可以直接通过 svg 格式头 `data:image/svg+xml;base64,` 分开。 | ||
|
||
|
||
Python 示例: | ||
```python | ||
from struct import unpack | ||
import gzip | ||
|
||
f = open('你的 webmask', 'rb') | ||
buf = f.read() | ||
_Ly = buf[12:16] | ||
Ly = unpack('>i', _Ly)[0] # 大端序 int | ||
|
||
times = [] | ||
offsets = [] | ||
for idx in range(Ly): | ||
op = 16 + idx * 16 # 个人习惯,我算偏移时喜欢用 `op` 和 `ed` 作为开始和结束的名字。 | ||
time = unpack('>q', buf[op: op+8])[0] | ||
offset = unpack('>q', buf[op+8: op+16])[0] | ||
times.append(time) | ||
offsets.append(offset) | ||
|
||
frames = [] | ||
for idx in range(Ly): | ||
op = offsets[idx] | ||
if idx == Ly - 1: ed = len(buf) | ||
else: ed = offsets[idx+1] | ||
ba = buf[op: ed] | ||
bad = gzip.decompress(ba) | ||
badl = bad.split(b'data:image/svg+xml;base64,') | ||
# badl[0]是16字节,`left` 和 `right` | ||
frames.append(badl[1: ]) | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
# web 播放器信息 | ||
|
||
web 播放器的信息接口,提供正常播放需要的元数据,包括:智能防挡弹幕、字幕、章节看点等。 | ||
|
||
> https://api.bilibili.com/x/player/wbi/v2 | ||
*请求方式:GET* | ||
|
||
**url 参数:** | ||
|
||
| 参数名 | 类型 | 内容 | 必要性 | 备注 | | ||
| ------ | ---- | --------- | ----------- | ----------------- | | ||
| aid | num | 稿件 avid | 必要 (可选) | aid 与 bvid 任选 | | ||
| bvid | str | 稿件 bvid | 必要 (可选) | aid 与 bvid 任选 | | ||
| cid | num | 稿件 cid | 必要 | | | ||
| w_rid | str | 未知 | 不必要 | | | ||
| wts | num | 当前 unix 时间戳 | 不必要 | | | ||
|
||
|
||
**json 回复:** | ||
|
||
根对象: | ||
|
||
| 字段 | 类型 | 内容 | 备注 | | ||
| ------- | ---- | -------- | --------------------------- | | ||
| code | num | 返回值 | 0:成功<br />-400:请求错误 | | ||
| message | str | 错误信息 | 默认为 0 | | ||
| ttl | num | 1 | | | ||
| data | obj | 数据本体 | | | ||
|
||
`data` 对象: | ||
|
||
| 字段 | 类型 | 内容 | 备注 | | ||
| --------- | ----- | -------- | ---- | | ||
|aid | num | 视频 aid | | | ||
|bvid | str | 视频 bvid | | | ||
|cid | num | 视频 cid | | | ||
|dm_mask | obj | | webmask 信息(如果没有这一项,说明这个视频没有防挡功能) | | ||
|subtitle | obj | | 字幕信息(需要登录,不登录此项内容为 `[]` )| | ||
|view_points| array | | 章节看点信息 | | ||
| 其他 | ... | | 主要是观看记录、使用者等级权限等个人信息 | | ||
|
||
|
||
`dm_mask`对象(如果有): | ||
|
||
| 字段 | 类型 | 内容 | 备注 | | ||
| --------- | ----- | -------- | ---- | | ||
|cid | num | 视频 cid | | | ||
|plat | num | 未知 | | | ||
|fps | num | webmask 取样 fps | | | ||
|time | num | 未知 | | | ||
|mask_url | str | webmask 资源 url | | | ||
|
||
解析 webmask 请看 [智能防挡弹幕](../danmaku/webmask.md) | ||
|
||
`subtitle`对象: | ||
| 字段 | 类型 | 内容 | 备注 | | ||
| --------- | ----- | -------- | ---- | | ||
|allow_submit|bool | true | | | ||
| lan | str | "" | | | ||
|lan_doc | str | "" | | | | ||
|subtitles| array | | 不登录为 `[]` | | ||
|
||
`subtitles` 数组内的元素: | ||
|
||
| 字段 | 类型 | 内容 | 备注 | | ||
| --------- | ----- | -------- | ---- | | ||
| ai_status | num | | | | ||
| ai_type | num | | | | ||
| id | num | | | | ||
|id_str | str| | 和 id 不一样 | | ||
| is_lock | bool | | | ||
| lan | str | 语言类型英文字母缩写 || | ||
| lan_doc | str| 语言类型中文名称 | | | ||
|subtitle_url|str| 资源 url 地址 | | | ||
|type| num | 0 | | | ||
|
||
|
||
`view_point` 数组内的元素: | ||
| 字段 | 类型 | 内容 | 备注 | | ||
| --------- | ----- | -------- | ---- | | ||
| content | num | 章节名 | | | ||
| from | num | | | | ||
| to | num | | | | ||
| type | num | | | | ||
| imgUrl | str | 图片资源地址 | | | ||
| logoUrl | str | "" | | | ||
|
||
示例: | ||
|
||
```shell | ||
curl -G https://api.bilibili.com/x/player/wbi/v2?aid=515345690&cid=825851971 | ||
``` | ||
|
||
```json | ||
{ | ||
"code": 0, | ||
"message": "0", | ||
"ttl": 1, | ||
"data": { | ||
"aid": 515345690, | ||
"bvid": "BV1Fg411D7Jy", | ||
... // 省略 | ||
"dm_mask": { | ||
"cid": 825851971, | ||
"plat": 0, | ||
"fps": 30, | ||
"time": 0, | ||
"mask_url": "//upos-sz-staticcos-cmask.bilivideo.com/cmaskboss/825851971_30_0.webmask?trid=219266863a1442baa05086b4285ba923B&orderid=0,1&logo=00000000" | ||
}, | ||
"view_points": [ | ||
{ | ||
"type": 2, | ||
"from": 0, | ||
"to": 27, | ||
"content": "狗啃的", | ||
"imgUrl": "http://i0.hdslb.com/bfs/vchapter/825851971_0.jpg", | ||
"logoUrl": "" | ||
}, | ||
{ | ||
"type": 2, | ||
"from": 27, | ||
"to": 63, | ||
"content": "椒牌泡菜", | ||
"imgUrl": "http://i0.hdslb.com/bfs/vchapter/825851971_27.jpg", | ||
"logoUrl": "" | ||
}, ... // 省略 | ||
], | ||
"subtitle": { | ||
"allow_submit": true, | ||
"lan": "", | ||
"lan_doc": "", | ||
"subtitles": [], // 未登录,下面是登录的版本 | ||
"subtitles":[ | ||
{ | ||
"id": 1042985852759993300, | ||
"lan": "ai-zh", | ||
"lan_doc": "中文(自动生成)", | ||
"is_lock": false, | ||
"subtitle_url": "//aisubtitle.hdslb.com/bfs/ai_subtitle/prod/5153456908258519712094280c7c2884b77929bab82f64530f?auth_key=1714795727-a8eb254b60bc4a73bc8662da51005340-0-1c305894e48e959979b163636461fb8f", | ||
"type": 1, | ||
"id_str": "1042985852759993344", | ||
"ai_type": 0, | ||
"ai_status": 2 | ||
} | ||
] | ||
} | ||
} | ||
} | ||
``` | ||
|
||
|
||
|