Merge remote-tracking branch 'upstream/master'

This commit is contained in:
wuziqian211 2024-08-07 04:20:09 +08:00
commit 7437b5399b
25 changed files with 5048 additions and 249 deletions

View File

@ -67,11 +67,13 @@ B站 API 采用 C/S 结构,大多数接口为 REST API 和 gRPC少部分接
- [x] [APP API 签名](docs/misc/sign/APP.md)`appkey`与`sign`
- [x] [已知的 APPKey](docs/misc/sign/APPKey.md)
- [x] [Wbi 签名](docs/misc/sign/wbi.md)`wts`与`w_rid`
- [ ] [bili_ticket](docs/misc/sign/bili_ticket.md)
- [x] [公共错误码](docs/misc/errcode.md)
- [x] [图片格式化](docs/misc/picture.md)
- [x] [bvid 说明](docs/misc/bvid_desc.md)
- [ ] [设备唯一标识BUVID](docs/misc/device_identity.md)
- [ ] [获取 buvid3 / buvid4 / b_nut](docs/misc/buvid3_4.md)
- [ ] [gRPC API 接口定义](grpc_api)
- [ ] [登录](docs/login)
- [x] [登录操作 (人机认证)](docs/login/login_action)
@ -207,6 +209,7 @@ B站 API 采用 C/S 结构,大多数接口为 REST API 和 gRPC少部分接
- [ ] 动态列表
- [x] [特定话题动态列表](docs/dynamic/tag_dynamics.md)
- [ ] [动态内容](docs/dynamic/get_dynamic_detail.md)
- [ ] [导航栏动态](docs/dynamic/nav.md)
- [ ] [相簿](docs/album)
- [x] [基本信息](docs/album/info.md)
- [x] [相簿列表](docs/album/list.md)
@ -357,6 +360,7 @@ OR Aifadian[https://afdian.net/@ShakaiAneE](https://afdian.net/@ShakaiAneE)
- [SocialSisterYi/bcut-asr](https://github.com/SocialSisterYi/bcut-asr): 使用必剪API的语音字幕识别
- [CzJam/Bili_Realtime_Data](https://github.com/CzJam/Bili_Realtime_Data): Bilibili粉丝与视频实时数据统计
- [kingwingfly/fav](https://github.com/kingwingfly/fav): 自动同步bili收藏夹、合集视频到本地的CLI工具Rust实现并提供一个文档测试完善的Rust风格的用于构建有状态爬虫的核心库
- [linyuye/Bilibili_crawler](https://github.com/linyuye/Bilibili_crawler): 基于bilibili懒加载api爬取b站动态视频等评论区
### 其他

View File

@ -16,6 +16,7 @@ B站的番剧视频为http流媒体需要对应的api以视频id获取取流u
| 64 | 720P 高清 | web端默认值<br />B站前端需要登录才能选择但是直接发送请求可以不登录就拿到720P的取流地址<br />**无720P时则为720P60** |
| 74 | 720P60 高帧率 | 需要认证登录账号 |
| 80 | 1080P 高清 | TV端与APP端默认值<br />需要认证登录账号 |
| 100 | 智能修复 | 仅支持dash方式<br />需要`fnval&12240=12240`<br />需要认证登录账号 |
| 112 | 1080P+ 高码率 | 大多情况需求认证大会员账号 |
| 116 | 1080P60 高帧率 | 大多情况需求认证大会员账号 |
| 120 | 4K 超清 | 需要`fnval&128=128`且`fourk=1`<br />大多情况需求认证大会员账号 |
@ -44,6 +45,7 @@ B站的番剧视频为http流媒体需要对应的api以视频id获取取流u
| 512 | 是否需求杜比视界 | 必须为dash格式<br />大多情况需求认证大会员账号 |
| 1024 | 是否需求 8K 分辨率 | 必须为dash格式<br />需要`qn=127`<br />大多情况需求认证大会员账号 |
| 2048 | 是否需求 av1 编码 | 必须为dash格式 |
| 12240 | 是否需求智能修复 | 必须为dash格式<br />需要认证大会员账号 |
例如请求dash格式且需要HDR的视频流则`fnval=16|64=80`

View File

@ -1,6 +1,6 @@
# 通过ip确定地理位置
## 通过ip确定位置
## 根据请求IP确定属地
> https://api.bilibili.com/x/web-interface/zone
@ -60,3 +60,94 @@ curl 'https://api.bilibili.com/x/web-interface/zone'
```
</details>
## 查询任意 IP 地址的归属地
> https://api.live.bilibili.com/ip_service/v1/ip_service/get_ip_addr
> https://api.live.bilibili.com/client/v1/Ip/getInfoNew
注: 两接口等效
*请求方式GET*
**URL参数:**
| 参数名 | 类型 | 内容 | 必要性 | 备注 |
| ------ | ---- | -------- | ------ | ---- |
| ip | str | IP地址 | 不必要 | IPv4或IPv6地址不限, 留空与[根据请求IP确定地理位置](#根据请求ip确定地理位置)基本相同 |
**JSON回复:**
根对象:
| 字段 | 类型 | 内容 | 备注 |
| ------- | ---- | -------- | ------- |
| code | num | 返回值 | 0: 成功 |
| message | str | 错误信息 | 默认为空 |
| msg | str | 错误信息 | 同message |
| data | obj | 信息本体 | 出错时为空数组 |
`data`对象:
与[根据请求IP确定地理位置](#根据请求ip确定地理位置)回复的`data`对象基本相同, 但无 `country_code` 字段
**示例:**
查询请求IP地址的归属地:
```shell
curl -G 'https://api.live.bilibili.com/client/v1/Ip/getInfoNew'
```
<details>
<summary>查看响应示例:</summary>
```json
{
"code": 0,
"msg": "",
"message": "",
"data": {
"addr": "104.28.156.113",
"country": "新加坡",
"province": "新加坡",
"city": "",
"isp": "cloudflare.com",
"latitude": "1.352083",
"longitude": "103.819836"
}
}
```
</details>
查询IP地址`8.8.8.8`的归属地:
```shell
curl -G 'https://api.live.bilibili.com/ip_service/v1/ip_service/get_ip_addr' \
--data-urlencode 'ip=8.8.8.8'
```
<details>
<summary>查看响应示例:</summary>
```json
{
"code": 0,
"msg": "",
"message": "",
"data": {
"addr": "8.8.8.8",
"country": "GOOGLE.COM",
"province": "GOOGLE.COM",
"city": "",
"isp": "level3.com",
"latitude": "",
"longitude": ""
}
}
```
</details>

1167
docs/dynamic/nav.md Normal file

File diff suppressed because it is too large Load Diff

View File

@ -22,7 +22,7 @@
| 字段 | 类型 | 内容 | 备注 |
| ------- | ----------------------------- | -------- | --------------------------------------------------- |
| code | num | 返回值 | 0成功<br />-400请求错误<br />-403访问权限不足 |
| code | num | 返回值 | 0成功<br />-400请求错误<br />-403访问权限不足<br />11010: 内容不存在 |
| message | str | 错误信息 | 默认为0 |
| data | 有效时obj<br />无效或null | 信息本体 | |

View File

@ -2,7 +2,7 @@
## 用户关注的所有UP的直播情况
> https://api.bilibili.com/x/space/wbi/acc/info
> https://api.live.bilibili.com/xlive/web-ucenter/user/following
*请求方式GET*

View File

@ -1,5 +1,83 @@
# 直播间管理
## 开通直播间
> https://api.live.bilibili.com/xlive/app-blink/v1/preLive/CreateRoom
*请求方式POST*
认证方式CookieSESSDATA
鉴权方式Cookie中`bili_jct`的值正确并与`csrf`相同
**正文参数( application/x-www-form-urlencoded **
| 参数名 | 类型 | 内容 | 必要性 | 备注 |
| ------- | ---- | ------------------------ | ------ | -------------------- |
| platform | str | 客户端? | 必要 | 默认值web |
| visit_id | str | 未知 | | 默认空 |
| csrf | str | CSRF Token位于cookie | 必要 | |
| csrf_token | str | CSRF Token位于 cookie | | |
**json回复**
根对象:
| 字段 | 类型 | 内容 | 备注 |
| ------- | ------ | -------- | ------------------------------------------------------ |
| code | num | 返回值 | 0成功<br />1531193016已经创建直播间~<br />-400请求错误 |
| ttl | str | 错误信息 | 默认为1 |
| message | str | 错误信息 | 默认为0 |
| data | array | 信息本体 | |
`data`对象:
| 字段 | 类型 | 内容 | 备注 |
| --------- | ----- | ---------------- | ---------------------- |
| roomID | str | 直播间房间号 | 创建成功返回直播间号 |
**示例:**
开通直播间
```shell
curl 'https://api.live.bilibili.com/xlive/app-blink/v1/preLive/CreateRoom' \
--data-urlencode 'platform=web' \
--data-urlencode 'visit_id=' \
--data-urlencode 'csrf=xxx' \
--data-urlencode 'csrf_token=xxx' \
-b 'SESSDATA=xxx;bili_jct=xx'
```
<details>
<summary>查看响应示例:</summary>
```json
{
"code": 0,
"message": "0",
"ttl": 1,
"data": {
"roomID": "1234"
}
}
```
```json
{
"code": 1531193016,
"message": "已经创建直播间~",
"ttl": 1,
"data": {
"roomID": ""
}
}
```
</details>
## 更新直播间标题
> https://api.live.bilibili.com/room/v1/Room/update
@ -83,7 +161,7 @@ curl 'https://api.live.bilibili.com/room/v1/Room/update' \
| 字段 | 类型 | 内容 | 备注 |
| ------- | ---- | -------- | ------------------------------------------------------------ |
| code | num | 返回值 | 0成功<br />65530token错误登录错误<br />1错误<br />60009分区不存在<br />60013非常抱歉您所在的地区受实名认证限制无法开播<br />**(其他错误码有待补充)** |
| code | num | 返回值 | 0成功<br />65530token错误登录错误<br />1错误<br />60009分区不存在<br />60024: 目标分区需要人脸认证<br />60013非常抱歉您所在的地区受实名认证限制无法开播<br />**(其他错误码有待补充)** |
| msg | str | 错误信息 | 默认为空 |
| message | str | 错误信息 | 默认为空 |
| data | obj | 信息本体 | |

View File

@ -3,11 +3,19 @@
## 未读消息数
> https://api.bilibili.com/x/msgfeed/unread
> https://api.vc.bilibili.com/x/im/web/msgfeed/unread (新接口)
*请求方式GET*
认证方式CookieSESSDATA
**URL参数:**
| 参数名 | 类型 | 内容 | 必要性 | 备注 |
| -------- | ---- | ---- | ------ | -------------------------- |
| build | num | 0 | 不必要 | 从新接口发现, 作用尚不明确 |
| mobi_app | str | web | 不必要 | 从新接口发现, 作用尚不明确 |
**json回复**
根对象:
@ -19,23 +27,29 @@
| ttl | num | 1 | |
| data | obj | 信息本体 | |
data 对象:
`data` 对象:
| 字段 | 类型 | 内容 | 备注 |
| ------- | ---- | -------------- | ------------ |
| at | num | 未读at数 | |
| chat | num | 0 | 作用尚不明确 |
| like | num | 未读点赞数 | |
| reply | num | 未读回复数 | |
| sys_msg | num | 未读系统通知数 | |
| up | num | UP主助手信息数 | |
| 字段 | 类型 | 内容 | 备注 |
| ------------- | ---- | -------------- | ---------------------- |
| at | num | 未读at数 | |
| chat | num | 0 | 作用尚不明确 |
| coin | num | 未读投币数 | |
| danmu | num | 未读弹幕数 | |
| favorite | num | 未读收藏数? | |
| like | num | 未读点赞数 | |
| recv_like | num | 未读点赞数 | |
| recv_reply | num | 未读回复数 | |
| reply | num | 未读回复数 | |
| sys_msg | num | 未读系统通知数 | |
| sys_msg_style | num | 1 | 仅新接口, 作用尚不明确 |
| up | num | UP主助手信息数 | |
**示例:**
以下信息代表了未读点赞数为10未读回复数为4未读at消息数为3未读系统通知数为2UP主助手信息数为1
```shell
curl 'https://api.bilibili.com/x/msgfeed/unread' \
curl 'https://api.vc.bilibili.com/x/im/web/msgfeed/unread' \
-b 'SESSDATA=xxx'
```
@ -50,9 +64,15 @@ curl 'https://api.bilibili.com/x/msgfeed/unread' \
"data": {
"at": 3,
"chat": 0,
"coin": 0,
"danmu": 0,
"favorite": 0,
"like": 10,
"recv_like": 10,
"recv_reply": 4,
"reply": 4,
"sys_msg": 2,
"sys_msg_style": 1,
"up": 1
}
}

View File

@ -8,24 +8,37 @@
认证方式CookieSESSDATA
**URL参数:**
| 参数名 | 类型 | 内容 | 必要性 | 备注 |
| ----------- | ---- | ---- | ------ | ---- |
| build | num | 0 | 不必要 | ? |
| mobi_app | str | web | 不必要 | ? |
| unread_type | num | 0 | 不必要 | ? |
**json回复**
根对象:
| 字段 | 类型 | 内容 | 备注 |
| ------- | ---- | -------- | --------------------------- |
| code | num | 返回值 | 0成功<br />-6账号未登录 |
| code | num | 返回值 | 0成功<br />-101:账号未登录 |
| message | str | 错误信息 | 默认为ok |
| ttl | num | 1 | |
| data | obj | 信息本体 | |
`data` 对象:
| 字段 | 类型 | 内容 | 备注 |
| --------------- | ---- | -------------------- | ---- |
| unfollow_unread | num | 未关注用户未读私信数 | |
| follow_unread | num | 已关注用户未读私信数 | |
| _gt_ | num | 0 | |
| 字段 | 类型 | 内容 | 备注 |
| ----------------------- | ---- | ----------------------- | ---- |
| unfollow_unread | num | 未关注用户未读私信数 | |
| follow_unread | num | 已关注用户未读私信数 | |
| unfollow_push_msg | num | 未关注用户推送消息数? | |
| dustbin_push_msg | num | 已拦截的推送消息数? | |
| dustbin_unread | num | 已拦截的未读消息数? | |
| biz_msg_unfollow_unread | num | 未订阅的未读系统通知数? | |
| biz_msg_follow_unread | num | 已订阅的未读系统通知数? | |
| custom_unread | num | 自定义未读消息数? | |
**示例:**
@ -41,14 +54,19 @@ curl 'https://api.vc.bilibili.com/session_svr/v1/session_svr/single_unread' \
```json
{
"code": 0,
"msg": "ok",
"message": "ok",
"data": {
"unfollow_unread": 1,
"follow_unread": 6,
"_gt_": 0
}
"code": 0,
"msg": "ok",
"message": "ok",
"data": {
"unfollow_unread": 1,
"follow_unread": 6,
"unfollow_push_msg": 0,
"dustbin_push_msg": 0,
"dustbin_unread": 0,
"biz_msg_unfollow_unread": 0,
"biz_msg_follow_unread": 1,
"custom_unread": 0
}
}
```

85
docs/misc/buvid3_4.md Normal file
View File

@ -0,0 +1,85 @@
# 获取 buvid3 / buvid4 / b_nut
## 游客获取 buvid3 / buvid4
> https://api.bilibili.com/x/frontend/finger/spi
*请求方式: GET*
**JSON回复:**
根对象:
| 字段 | 类型 | 内容 | 备注 |
| ------- | ---- | -------- | -------- |
| code | num | 返回值 | 0成功 |
| message | str | 信息 | ok: 成功 |
| data | obj | 数据本体 | |
`data`对象:
| 字段 | 类型 | 内容 | 备注 |
| ---- | ---- | ------ | ---- |
| b_3 | str | buvid3 | 需手动存放至 cookie 中 |
| b_4 | str | buvid4 | 同上 |
**示例:**
注: 建议自行生成, 不要复制本处示例的 buvid3 / buvid4.
```shell
curl -G 'https://api.bilibili.com/x/frontend/finger/spi'
```
<details>
<summary>查看响应示例:</summary>
```json
{
"code": 0,
"data": {
"b_3": "D9656DA8-9BEF-F464-5B72-C4849AFD336379044infoc",
"b_4": "F6E0FD4B-520C-1902-4F7B-E461D8D1F5AB79044-024072309-666onEZSnlHVPjoRp4kDYg=="
},
"message": "ok"
}
```
</details>
## 从响应头获取 buvid3 / b_nut
使用 `GET``HEAD` 方法请求 `https://www.bilibili.com/`, 且请求头中 `User-Agent` 字段不包含 `curl` `python` `awa` 等敏感子字符串, 且相同 `User-Agent` 字段不得短时多次请求. 在响应头中的 `Set-Cookie` 字段中, 即可找到 `buvid3``b_nut`.
若不带任何 Cookie 请求, 则 `b_nut` 为响应生成时刻的 UNIX 秒级时间戳.
若请求 Cookie 仅带有 `buvid3`, 则 `b_nut``100`.
若请求 Cookie 仅带有 `b_nut`, 则与不带任何 Cookie 的响应相同.
若请求 Cookie 仅带有 `buvid3``b_nut`, 则响应无 `Set-Cookie` 字段.
若请求 Cookie 带有其他字段, 无影响.
**示例:**
```shell
curl -I "https://www.bilibili.com/" -A "awa"
```
<details>
<summary>查看响应示例:</summary>
```http
HTTP/2 200
date: Fri, 26 Jul 2024 06:38:43 GMT
content-type: text/html; charset=utf-8
support: nantianmen
set-cookie: buvid3=805E4894-96A2-0684-6F00-C6EA1FFB911023315infoc; path=/; expires=Sat, 26 Jul 2025 06:38:43 GMT; domain=.bilibili.com
set-cookie: b_nut=1721975923; path=/; expires=Sat, 26 Jul 2025 06:38:43 GMT; domain=.bilibili.com
vary: Origin,Accept-Encoding
idc: shjd
expires: Fri, 26 Jul 2024 06:38:42 GMT
cache-control: no-cache
x-cache-webcdn: MISS from blzone01
x-cache-time: 0
x-save-date: Fri, 26 Jul 2024 06:38:43 GMT
```
</details>

View File

@ -248,10 +248,9 @@ print(av2bv(avid: 111298867365120))
print(bv2av(bvid: "BV1L9Uoa9EUx"))
```
### Java
```
```java
import java.math.BigInteger;
/**
@ -266,8 +265,7 @@ public class AVBVConverter {
private static final String DATA = "FcwAPNKTMug3GV5Lj7EJnHpWsx4tb8haYeviqBz6rkCy12mUSDQX9RdoZf";
public static String av2bv(int aidParam) {
public static String av2bv(long aidParam) {
BigInteger aid = BigInteger.valueOf(aidParam);
char[] bytes = {'B', 'V', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0'};
int bvIndex = bytes.length - 1;
@ -275,18 +273,14 @@ public class AVBVConverter {
while (tmp.compareTo(BigInteger.ZERO) > 0) {
bytes[bvIndex] = DATA.charAt(tmp.mod(BigInteger.valueOf(BASE)).intValue());
tmp = tmp.divide(BigInteger.valueOf(BASE));
bvIndex -= 1;
bvIndex--;
}
swap(bytes, 3, 9);
swap(bytes, 4, 7);
StringBuilder sb = new StringBuilder(bytes.length);
for (Character ch : bytes) {
sb.append(ch);
}
return sb.toString();
return new String(bytes);
}
public static int bv2av(String bvid) {
public static long bv2av(String bvid) {
char[] bvidArr = bvid.toCharArray();
swap(bvidArr, 3, 9);
swap(bvidArr, 4, 7);
@ -296,7 +290,7 @@ public class AVBVConverter {
tmp = tmp.multiply(BigInteger.valueOf(BASE)).add(BigInteger.valueOf(DATA.indexOf(c)));
}
BigInteger xor = tmp.and(MASK_CODE).xor(XOR_CODE);
return xor.intValue();
return xor.longValue();
}
@ -314,21 +308,17 @@ public class AVBVConverter {
final int aid2 = 305988942;
final String bv2 = "BV1aP411K7it";
//av ==> bv
assert av2bv(aid1).equals(bv1);
assert av2bv(aid2).equals(bv2);
//bv ==>av
assert bv2av(bv1) == aid1;
assert bv2av(bv2) == aid2;
}
}
```
### Golang
```go

View File

@ -2,7 +2,7 @@
## 设备唯一标识 BUVID
注意区分于 Web 端的 buvid3, buvid4.
注意区分于 Web 端的 [buvid3, buvid4](buvid3_4.md).
BUVID 在 APP 首次安装于某设备, 且首次启动时生成.

View File

@ -1,18 +1,33 @@
# 图片格式化
对于\*.hdslb.com/bfs下的图片文件都可以使用以下格式化参数
对于 `*.hdslb.com/bfs` 下的图片文件都可以使用以下可选格式化参数.
> \*.hdslb.com/bfs/\*/\*.\[jpg/png/gif\]@{width}w\_{high}h\_{quality}q.{format}
使用 `@` 开始参数 (无论格式如何, 无论是否有参数, 通过计算 HASH 发现, 使用 `@` 均会导致返回图片不同), 多个参数以 `_` 分隔, 图片格式无需分隔且必须放在最后
| 可选参数 | 含义 | 备注 |
| -------- | ---------------- | ---------------- |
| width | 图片最大限制宽度 | |
| high | 图片最大限制高度 | |
| quality | 图片质量百分比 | 仅限webp |
| format | 图片格式 | 仅限png/jpg/webp/[avg_color](#avg_color格式说明) |
参见: [#191](https://github.com/SocialSisterYi/bilibili-API-collect/issues/191)
注: jpg 即 jpeg, 二者等效. 网页端常用 AVIF, WebP.
| 参数 | 格式 | 含义 | 备注 |
| ---- | ------- | ---------------- | ---------------- |
| w | ${int}w | 图片最大限制宽度 | 范围 [1, 9223372036854775807] |
| h | ${int}h | 图片最大限制高度 | 范围 [1, 9223372036854775807] |
| s | ${int}s | 作用尚不明确 | 不影响输出结果, 范围 [1, 9223372036854775807] |
| e | ${int}e | 改变大小 | 0: 保留比例取其小, 1: 保留比例取其大, 2: 不保留原比例 |
| p | ${int}p | 缩放倍数 | 默认100, 范围 [1, 1000] |
| o | ${int}o | 作用尚不明确 | 不影响输出结果 范围 [0, 1] |
| q | ${int}q | 图片质量百分比 | 仅限webp/jpeg/avif |
| c | ${int}c | 裁切图片(如果宽高允许) | 0: 不裁切但会修改图片, 1: 上传时的预设规则(若无则右下), 2: 左上, 3: 右上 |
| f | ${int}f | 作用尚不明确 | [0, 1]: 不改变图片, 2: 会改变图片 |
| progressive | progressive | 图片编码方式 | 仅限 jpeg(无: baseline, 有: progressive)/png(无:non-interlaced, 有: interlaced) |
| ! | !${str} | 加载来源 | web-home-carousel-cover, header, web-dynamic, web-avatar-space-header, ... |
| . | .${str} | 图片格式 | 仅限 png/jpeg/webp/avif/[avg_color](#avg_color格式说明) |
**示例:**
<details>
<summary>查看示例:</summary>
原始图片
https://i1.hdslb.com/bfs/archive/e5fff1472bad1c0c6bcb3004205f9be23b58ffc0.jpg
@ -43,6 +58,7 @@ https://i1.hdslb.com/bfs/archive/e5fff1472bad1c0c6bcb3004205f9be23b58ffc0.jpg@1q
![](https://i1.hdslb.com/bfs/archive/e5fff1472bad1c0c6bcb3004205f9be23b58ffc0.jpg@1q.webp)
</details>
## avg_color格式说明

View File

@ -1,8 +1,11 @@
`bili_ticket` 目前没发现多少风控价值,但是暂且在这里提供一份示例。
# BiliTicket
## 简述
`bili_ticket` 位于请求头 Cookie 中, 非必需, 但存在可降低风控概率
由 [@aynuarance](https://github.com/aynuarance) 于 [#903](https://github.com/SocialSisterYi/bilibili-API-collect/issues/903) 提供的思路,根据时间戳使用 `hmac_sha256` 算法计算 `hexsign`
是 [JWT 令牌](https://jwt.io/),有效时长为 259260 秒,即 3 天。
例如 `eyJhbGciOiJIUzI1NiIsImtpZCI6InMwMyIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MDI3NDI3NDYsImlhdCI6MTcwMjQ4MzQ4NiwicGx0IjotMX0.xQgtTAc41NA1gzvd9yKUPgucUy_DKcQj6OG1vj8V7ZA`
@ -14,7 +17,18 @@
}
```
# Python 示例
## 算法
1. 获取 UNIX 秒级时间戳存入变量如 `timestamp`
2. 计算变量 `hexsign` 值,使用 `hmac_sha256` 算法,密钥为 `XgwSnGZ1p`,消息为字符串 `"ts"` 与变量 `timestamp` 值拼接
3. 构造请求参数,`key_id` 为 `ec02``hexsign` 为变量 `hexsign` 值,`context[ts]` 为变量 `timestamp` 值,`csrf` 为 cookie 中的 `bili_jct` 值也可为空
4. 发送 `POST` 请求,获取 `data` 字段中的 `ticket` 字段的值即为所求
## Demo
### Python
需要 `requests` 依赖
```python
import hmac
@ -59,4 +73,106 @@ if __name__ == '__main__':
'user-agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0"
}
resp = requests.post(url, params=params,headers=headers).json()
```
print(resp)
```
### Java
无需第三方依赖
```java
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
public class BiliTicketDemo {
/**
* Convert a byte array to a hex string.
*
* @param bytes The byte array to convert.
* @return The hex string representation of the given byte array.
*/
public static String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
String hex = Integer.toHexString(0xff & b);
if (hex.length() == 1) {
sb.append('0');
}
sb.append(hex);
}
return sb.toString();
}
/**
* Generate a HMAC-SHA256 hash of the given message string using the given key
* string.
*
* @param key The key string to use for the HMAC-SHA256 hash.
* @param message The message string to hash.
* @throws Exception If an error occurs during the HMAC-SHA256 hash generation.
* @return The HMAC-SHA256 hash of the given message string using the given key
* string.
*/
public static String hmacSha256(String key, String message) throws Exception {
Mac mac = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
mac.init(secretKeySpec);
byte[] hash = mac.doFinal(message.getBytes(StandardCharsets.UTF_8));
return bytesToHex(hash);
}
/**
* Get a Bilibili web ticket for the given CSRF token.
*
* @param csrf The CSRF token to use for the web ticket, can be {@code null} or
* empty.
* @return The Bilibili web ticket raw response for the given CSRF token.
* @throws Exception If an error occurs during the web ticket generation.
* @see https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/misc/sign/bili_ticket.md
*/
public static String getBiliTicket(String csrf) throws Exception {
// params
long ts = System.currentTimeMillis() / 1000;
String hexSign = hmacSha256("XgwSnGZ1p", "ts" + ts);
StringBuilder url = new StringBuilder(
"https://api.bilibili.com/bapis/bilibili.api.ticket.v1.Ticket/GenWebTicket");
url.append('?');
url.append("key_id=ec02").append('&');
url.append("hexsign=").append(hexSign).append('&');
url.append("context[ts]=").append(ts).append('&');
url.append("csrf=").append(csrf == null ? "" : csrf);
// request
HttpURLConnection conn = (HttpURLConnection) new URI(url.toString()).toURL().openConnection();
conn.setRequestMethod("POST");
conn.addRequestProperty("User-Agent", "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0");
InputStream in = conn.getInputStream();
ByteArrayOutputStream out = new ByteArrayOutputStream();
int b;
while ((b = in.read()) != -1) {
out.write(b);
}
return new String(out.toByteArray(), StandardCharsets.UTF_8);
}
/**
* Main method to test the BiliTicketDemo class.
*
* @param args The command line arguments (not used).
*/
public static void main(String[] args) {
try {
System.out.println(getBiliTicket("")); // use empty CSRF here
} catch (Exception e) {
e.printStackTrace();
}
}
}
```

View File

@ -120,7 +120,7 @@
## Demo
含 [Python](#Python)、[JavaScript](#JavaScript)、[Golang](#Golang)、[C#](#CSharp)、[Java](#Java)、[Swift](#Swift)、[C++](#CPlusPlus) 语言编写的 Demo 。
含 [Python](#Python)、[JavaScript](#JavaScript)、[Golang](#Golang)、[C#](#CSharp)、[Java](#Java)、[Kotlin](#Kotlin)、[Swift](#Swift)、[C++](#CPlusPlus)、[Rust](#Rust) 语言编写的 Demo 。
### Python
@ -658,14 +658,13 @@ bar=514&baz=1919810&foo=114&wts=1687541921&w_rid=26e82b1b9b3a11dbb1807a9228a40d3
### Java
需要 `hutool` 依赖
```java
package com.example.demo;
import cn.hutool.crypto.SecureUtil;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.stream.Collectors;
public class WbiTest {
private static final int[] mixinKeyEncTab = new int[]{
@ -675,44 +674,126 @@ public class WbiTest {
36, 20, 34, 44, 52
};
private static final char[] hexDigits = "0123456789abcdef".toCharArray();
public static String md5(String input) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] messageDigest = md.digest(input.getBytes(StandardCharsets.UTF_8));
char[] result = new char[messageDigest.length * 2];
for (int i = 0; i < messageDigest.length; i++) {
result[i * 2] = hexDigits[(messageDigest[i] >> 4) & 0xF];
result[i * 2 + 1] = hexDigits[messageDigest[i] & 0xF];
}
return new String(result);
} catch (NoSuchAlgorithmException e) {
return null;
}
}
public static String getMixinKey(String imgKey, String subKey) {
String s = imgKey + subKey;
StringBuilder key = new StringBuilder();
for (int i = 0; i < 32; i++) {
for (int i = 0; i < 32; i++)
key.append(s.charAt(mixinKeyEncTab[i]));
}
return key.toString();
}
public static void main(String[] args) {
String imgKey = "653657f524a547ac981ded72ea172057";
String subKey = "6e4909c702f846728e64f6007736a338";
String mixinKey = getMixinKey(imgKey, subKey);
System.out.println(mixinKey);
//72136226c6a73669787ee4fd02a74c27
//{
// foo: 'one one four',
// bar: '五一四',
// baz: 1919810
//}
LinkedHashMap<String, Object> map = new LinkedHashMap<>();
map.put("foo", "one one four");
map.put("bar", "五一四");
map.put("baz", 1919810);
map.put("wts", System.currentTimeMillis() / 1000);
map.put("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36");
map.put("Referer", "https://www.bilibili.com/");
StringJoiner param = new StringJoiner("&");
//排序 + 拼接字符串
map.entrySet().stream()
.sorted(Map.Entry.comparingByKey())
.forEach(entry -> param.add(entry.getKey() + "=" + URLUtil.encode(entry.getValue().toString())));
String s = param + mixinKey;
String wbiSign = SecureUtil.md5(s);
System.out.println(wbiSign);
String finalParam = param + "&w_rid=" + wbiSign;
System.out.println(finalParam);
}
public static String encodeURIComponent(Object o) {
return URLEncoder.encode(o.toString(), StandardCharsets.UTF_8).replace("+", "%20");
}
public static void main(String[] args) {
String imgKey = "653657f524a547ac981ded72ea172057";
String subKey = "6e4909c702f846728e64f6007736a338";
String mixinKey = getMixinKey(imgKey, subKey);
System.out.println(mixinKey); // 72136226c6a73669787ee4fd02a74c27
// 用TreeMap自动排序
TreeMap<String, Object> map = new TreeMap<>();
map.put("foo", "one one four");
map.put("bar", "五一四");
map.put("baz", 1919810);
map.put("wts", System.currentTimeMillis() / 1000);
String param = map.entrySet().stream()
.map(it -> String.format("%s=%s", it.getKey(), encodeURIComponent(it.getValue())))
.collect(Collectors.joining("&"));
String s = param + mixinKey;
String wbiSign = md5(s);
System.out.println(wbiSign);
String finalParam = param + "&w_rid=" + wbiSign;
System.out.println(finalParam);
}
}
```
### Kotlin
```kotlin
import java.net.URLEncoder
import java.nio.charset.StandardCharsets
import java.security.MessageDigest
private val hexDigits = "0123456789abcdef".toCharArray()
fun ByteArray.toHexString() = buildString(this.size shl 1) {
this@toHexString.forEach { byte ->
append(hexDigits[byte.toInt() ushr 4 and 15])
append(hexDigits[byte.toInt() and 15])
}
}
fun String.toMD5(): String {
val md = MessageDigest.getInstance("MD5")
val digest = md.digest(this.toByteArray())
return digest.toHexString()
}
private val mixinKeyEncTab = intArrayOf(
46, 47, 18, 2, 53, 8, 23, 32, 15, 50, 10, 31, 58, 3, 45, 35, 27, 43, 5, 49,
33, 9, 42, 19, 29, 28, 14, 39, 12, 38, 41, 13, 37, 48, 7, 16, 24, 55, 40,
61, 26, 17, 0, 1, 60, 51, 30, 4, 22, 25, 54, 21, 56, 59, 6, 63, 57, 62, 11,
36, 20, 34, 44, 52
)
fun getMixinKey(imgKey: String, subKey: String): String {
val s = imgKey + subKey
return buildString {
repeat(32) {
append(s[mixinKeyEncTab[it]])
}
}
}
fun Any.encodeURIComponent() =
URLEncoder.encode(this.toString(), StandardCharsets.UTF_8).replace("+", "%20")
fun encWbi(params: Map<String, Any>, imgKey: String, subKey: String): String {
val mixinKey = getMixinKey(imgKey, subKey)
val s = params.toSortedMap().let {
it["wts"] to System.currentTimeMillis() / 1000
it.entries.joinToString("&") { (k, v) ->
"${k.encodeURIComponent()}=${v.encodeURIComponent()}"
}
}
return "$s&w_rid=${(s + mixinKey).toMD5()}"
}
fun main() {
val imgKey = "653657f524a547ac981ded72ea172057"
val subKey = "6e4909c702f846728e64f6007736a338"
val mixinKey = getMixinKey(imgKey, subKey)
println(mixinKey) // 72136226c6a73669787ee4fd02a74c27
// 需要加签的参数
val param = mapOf(
"foo" to "one+one four",
"bar" to "五一四",
"baz" to 1919810,
)
println(encWbi(param, imgKey, subKey))
}
```
@ -867,6 +948,7 @@ struct ResWbi {
fn get_mixin_key(orig: &[u8]) -> String {
MIXIN_KEY_ENC_TAB
.iter()
.take(32)
.map(|&i| orig[i] as char)
.collect::<String>()
}
@ -891,23 +973,34 @@ fn get_url_encoded(s: &str) -> String {
}
// 为请求参数进行 wbi 签名
fn encode_wbi(params: &mut Vec<(&str, String)>, (img_key, sub_key): (String, String)) -> String {
let mixin_key = get_mixin_key((img_key + &sub_key).as_bytes());
fn encode_wbi(params: Vec<(&str, String)>, (img_key, sub_key): (String, String)) -> String {
let cur_time = match SystemTime::now().duration_since(UNIX_EPOCH) {
Ok(t) => t.as_secs(),
Err(_) => panic!("SystemTime before UNIX EPOCH!"),
};
_encode_wbi(params, (img_key, sub_key), cur_time)
}
fn _encode_wbi(
mut params: Vec<(&str, String)>,
(img_key, sub_key): (String, String),
timestamp: u64,
) -> String {
let mixin_key = get_mixin_key((img_key + &sub_key).as_bytes());
// 添加当前时间戳
params.push(("wts", cur_time.to_string()));
params.push(("wts", timestamp.to_string()));
// 重新排序
params.sort_by(|a, b| a.0.cmp(b.0));
let query = params.iter().fold(String::from(""), |acc, (k, v)| {
acc + format!("{}={}&", get_url_encoded(k), get_url_encoded(v)).as_str()
});
// 拼接参数
let query = params
.iter()
.map(|(k, v)| format!("{}={}", get_url_encoded(k), get_url_encoded(v)))
.collect::<Vec<_>>()
.join("&");
// 计算签名
let web_sign = format!("{:?}", md5::compute(query.clone() + &mixin_key));
query + &format!("w_rid={}", web_sign)
// 返回最终的 query
query + &format!("&w_rid={}", web_sign)
}
async fn get_wbi_keys() -> Result<(String, String), reqwest::Error> {
@ -922,23 +1015,76 @@ async fn get_wbi_keys() -> Result<(String, String), reqwest::Error> {
.await?
.json::<ResWbi>()
.await?;
Ok((
take_filename(wbi_img.img_url).unwrap(),
take_filename(wbi_img.sub_url).unwrap(),
))
}
Ok((wbi_img.img_url, wbi_img.sub_url))
fn take_filename(url: String) -> Option<String> {
url.rsplit_once('/')
.and_then(|(_, s)| s.rsplit_once('.'))
.map(|(s, _)| s.to_string())
}
#[tokio::main]
async fn main() {
let urls = get_wbi_keys().await.unwrap();
let mut params = vec![
let keys = get_wbi_keys().await.unwrap();
let params = vec![
("foo", String::from("114")),
("bar", String::from("514")),
("baz", String::from("1919810")),
];
let query = encode_wbi(&mut params, urls);
let query = encode_wbi(params, keys);
println!("{}", query);
}
// 取自文档描述的测试用例
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_get_filename() {
assert_eq!(
take_filename(
"https://i0.hdslb.com/bfs/wbi/7cd084941338484aae1ad9425b84077c.png".to_string()
),
Some("7cd084941338484aae1ad9425b84077c".to_string())
);
}
#[test]
fn test_get_mixin_key() {
let concat_key =
"7cd084941338484aae1ad9425b84077c".to_string() + "4932caff0ff746eab6f01bf08b70ac45";
assert_eq!(
get_mixin_key(concat_key.as_bytes()),
"ea1db124af3c7062474693fa704f4ff8"
);
}
#[test]
fn test_encode_wbi() {
let params = vec![
("foo", String::from("114")),
("bar", String::from("514")),
("zab", String::from("1919810")),
];
assert_eq!(
_encode_wbi(
params,
(
"7cd084941338484aae1ad9425b84077c".to_string(),
"4932caff0ff746eab6f01bf08b70ac45".to_string()
),
1702204169
),
"bar=514&foo=114&wts=1702204169&zab=1919810&w_rid=8f6f2b5b3d485fe1886cec6a0be8c5d4"
.to_string()
)
}
}
```
### Swift
@ -1151,4 +1297,4 @@ int main() {
```text
avid=1755630705&cid=1574294582&fnval=4048&fnver=0&fourk=1&qn=32&wts=1717922933&w_rid=43571b838a1611fa121189083cfc1784
```
```

View File

@ -2,7 +2,8 @@
## 获取当前时间戳
> https://api.bilibili.com/x/report/click/now
> https://api.bilibili.com/x/report/click/now
> https://api.bilibili.com/x/click-interface/click/now
*请求方式GET*

View File

@ -250,7 +250,7 @@
| title | str | 直播间标题 | |
| cover | str | 直播间封面 url | |
| watched_show | obj | | |
| roomid | num | 直播间 id(短号) | |
| roomid | num | 直播间 id | |
| roundStatus | num | 轮播状态 | 0未轮播<br />1轮播 |
| broadcast_type | num | 0 | |

View File

@ -1008,6 +1008,325 @@ curl -G 'http://space.bilibili.com/ajax/settings/getSettings' \
</details>
#### 查询可用头图列表 (Web端)
> https://space.bilibili.com/ajax/topphoto/getlist
*请求方式: GET*
注: 带有转义
**URL参数:**
| 参数名 | 类型 | 内容 | 必要性 | 备注 |
| ------ | ---- | ----------- | ------ | -------------------------- |
| mid | num | 目标用户mid | 必要 | 非负数, 即使该用户并不存在 |
**JSON回复:**
根对象:
| 字段 | 类型 | 内容 | 备注 |
| ------ | ------------------------- | -------------------------------------- | ---- |
| status | bool | 成功: true<br />失败: false | |
| data | 成功: array<br/>失败: str | 成功: 信息本体<br />失败: "用户id错误" | |
`data`数组中的对象:
| 字段 | 类型 | 内容 | 备注 |
| ------------- | ---- | ----------- | ------------------------------------ |
| id | num | 空间头图 ID | |
| product_name | str | 显示名称 | |
| price | num | 价格 | |
| coin_type | num | 支付类型? | |
| vip_free | num | 大会员免费 | |
| s_img | str | 小图 URI | 需要自行与 `i0.hdslb.com` 拼接成 URL |
| l_img | str | 大图 URI | 同 s_img |
| thumbnail_img | str | 空 | 并不存在的缩略图? |
| sort_num | num | 排序编号 | |
| is_disable | num | 已禁用 | 0: 未禁用 |
| expire | num | 过期时间? | UNIX 时间戳, 或 0 为永不过期 |
| had | num | 是否拥有? | 当 expire 不为 0 时 为 1, 否则为 0 |
**示例:**
查询`mid=1145141919810000000`的可用空间头图
```shell
curl -G "https://space.bilibili.com/ajax/topphoto/getlist" \
--data-urlencode "mid=1145141919810000000"
```
<details>
<summary>查看响应示例:</summary>
```json
{
"status": true,
"data": [
{
"id": 1,
"product_name": "bilibili春",
"price": 0,
"coin_type": 0,
"vip_free": 0,
"s_img": "bfs/space/768cc4fd97618cf589d23c2711a1d1a729f42235.png",
"l_img": "bfs/space/cb1c3ef50e22b6096fde67febe863494caefebad.png",
"thumbnail_img": "",
"sort_num": 19,
"is_disable": 0,
"expire": 0,
"had": 0
},
{
"id": 2,
"product_name": "两人单车",
"price": 0,
"coin_type": 0,
"vip_free": 0,
"s_img": "bfs/space/d60a4be11f1bca6168a60a53c64bca18eddd6443.jpg",
"l_img": "bfs/space/44873d3568bdcb3d850d234e02a19602972450f1.png",
"thumbnail_img": "",
"sort_num": 16,
"is_disable": 0,
"expire": 0,
"had": 0
},
{
"id": 5,
"product_name": "成为偶像",
"price": 0,
"coin_type": 0,
"vip_free": 0,
"s_img": "bfs/space/5fe2632486a5a91a234f0e7cb368ab6397477da4.jpg",
"l_img": "bfs/space/87277d30cd19edcec9db466a9a3e556aeb0bc0ed.png",
"thumbnail_img": "",
"sort_num": 15,
"is_disable": 0,
"expire": 0,
"had": 0
},
{
"id": 11,
"product_name": "星际勘探",
"price": 0,
"coin_type": 0,
"vip_free": 0,
"s_img": "bfs/space/6849abc6e67000ad807b35a970aba31dd1e400dd.jpg",
"l_img": "bfs/space/c919a9818172a8297f8b0597722f96504a1e1d88.png",
"thumbnail_img": "",
"sort_num": 14,
"is_disable": 0,
"expire": 0,
"had": 0
},
{
"id": 10,
"product_name": "星O大战",
"price": 0,
"coin_type": 0,
"vip_free": 0,
"s_img": "bfs/space/ff3b0882e55c1099738e59616e5956ad357d9948.jpg",
"l_img": "bfs/space/e22f5b8e06ea3ee4de9e4da702ce8ef9a2958f5a.png",
"thumbnail_img": "",
"sort_num": 13,
"is_disable": 0,
"expire": 0,
"had": 0
},
{
"id": 12,
"product_name": "王牌特工",
"price": 0,
"coin_type": 0,
"vip_free": 0,
"s_img": "bfs/space/f5d38e2af44fd12fa65423aff55933fcf9071419.jpg",
"l_img": "bfs/space/8cd85a382756ab938df23a856017abccd187188e.png",
"thumbnail_img": "",
"sort_num": 12,
"is_disable": 0,
"expire": 0,
"had": 0
},
{
"id": 3,
"product_name": "仰望星空",
"price": 0,
"coin_type": 0,
"vip_free": 0,
"s_img": "bfs/space/c9dae917e24b4fc17c4d544caf6b6c0b17f8692b.jpg",
"l_img": "bfs/space/9ccc0447aebf0656809b339b41aa5b3705f27c47.png",
"thumbnail_img": "",
"sort_num": 11,
"is_disable": 0,
"expire": 0,
"had": 0
},
{
"id": 14,
"product_name": "雨过天晴",
"price": 0,
"coin_type": 0,
"vip_free": 0,
"s_img": "bfs/space/1115b2fdabd128337f892feada4ce32e51f3a5ad.jpg",
"l_img": "bfs/space/6a1198e25f8764bd30d53411dac9fdf840bc3265.png",
"thumbnail_img": "",
"sort_num": 10,
"is_disable": 0,
"expire": 0,
"had": 0
},
{
"id": 6,
"product_name": "绿荫秘境",
"price": 0,
"coin_type": 0,
"vip_free": 0,
"s_img": "bfs/space/dc02d22a718c1c436f1a355b3cd726b04098ef7d.jpg",
"l_img": "bfs/space/265ecddc52d74e624dc38cf0cff13317085aedf7.png",
"thumbnail_img": "",
"sort_num": 9,
"is_disable": 0,
"expire": 0,
"had": 0
},
{
"id": 13,
"product_name": "漫游仙境",
"price": 0,
"coin_type": 0,
"vip_free": 0,
"s_img": "bfs/space/184abe52a5ea9390b506c064cfba4f8f20ae9cca.jpg",
"l_img": "bfs/space/24d0815514951bb108fbb360b04a969441079315.png",
"thumbnail_img": "",
"sort_num": 7,
"is_disable": 0,
"expire": 0,
"had": 0
},
{
"id": 15,
"product_name": "放课后time",
"price": 0,
"coin_type": 0,
"vip_free": 0,
"s_img": "bfs/space/aea2dd7b8894ce31d578d4fad6a7188c7b49cb2f.jpg",
"l_img": "bfs/space/6e799ff2de2de55d27796707a283068d66cdf3f4.png",
"thumbnail_img": "",
"sort_num": 6,
"is_disable": 0,
"expire": 0,
"had": 0
},
{
"id": 4,
"product_name": "昴宿星团",
"price": 0,
"coin_type": 0,
"vip_free": 0,
"s_img": "bfs/space/1f4eaf70d1bb981f6057b3e440249d7a1f65774f.jpg",
"l_img": "bfs/space/3ab888c1d149e864ab44802dea8c1443e940fa0d.png",
"thumbnail_img": "",
"sort_num": 5,
"is_disable": 0,
"expire": 0,
"had": 0
},
{
"id": 7,
"product_name": "蔷薇洛丽塔",
"price": 0,
"coin_type": 0,
"vip_free": 0,
"s_img": "bfs/space/718eac8c71e29b8a80431c46110805c3a40e30a6.jpg",
"l_img": "bfs/space/70ce28bcbcb4b7d0b4f644b6f082d63a702653c1.png",
"thumbnail_img": "",
"sort_num": 4,
"is_disable": 0,
"expire": 0,
"had": 0
},
{
"id": 9,
"product_name": "黑暗之门",
"price": 0,
"coin_type": 0,
"vip_free": 0,
"s_img": "bfs/space/ef1b08e62fdc35b06e39795bc6de8e510935bf97.jpg",
"l_img": "bfs/space/cd52d4ac1d336c940cc4958120170f7928d9e606.png",
"thumbnail_img": "",
"sort_num": 3,
"is_disable": 0,
"expire": 0,
"had": 0
},
{
"id": 19,
"product_name": "你的名字",
"price": 0,
"coin_type": 0,
"vip_free": 0,
"s_img": "bfs/space/373e127e8784d3e4c1b5e6db0c27702ba077643f.jpg",
"l_img": "bfs/space/f49642b3683a08e3190f29d5a095386451f8952c.jpg",
"thumbnail_img": "",
"sort_num": 2,
"is_disable": 0,
"expire": 0,
"had": 0
}
]
}
```
</details>
### 设置空间头图 (Web端)
> https://space.bilibili.com/ajax/settings/setToutu
*请求方式: POST*
认证方式: Cookie (SESSDATA)
鉴权方式: referer为 `.bilibili.com` 域名下
**正文参数(application/x-www-form-urlencoded):**
| 参数名 | 类型 | 内容 | 必要性 | 备注 |
| ------ | ---- | ---------------------------------- | ------ | ---- |
| id | num | 头图 ID | 必要 | |
| csrf | str | CSRF Token (即 Cookie bili_jct 值) | 不必要 | |
**JSON回复:**
| 字段 | 类型 | 内容 | 备注 |
| ------ | ---- | -------- | --------------------------- |
| status | bool | 状态 | true: 成功<br />false: 失败 |
| data | str | 错误信息 | 正确时无此项 (带有转义) |
**示例:**
设置空间头图为为`王牌特工(id=12)`
```shell
curl -X POST "https://space.bilibili.com/ajax/settings/setToutu" \
--referer "https://space.bilibili.com/" \
--data-urlencode "id=12" \
--data-urlencode "csrf=xxx" \
-b "SESSDATA=xxx; bili_jct=xxx"
```
<details>
<summary>查看响应示例:</summary>
```json
{
"status": true
}
```
</details>
#### 调整空间板块布局
> http://space.bilibili.com/ajax/settings/setIndexOrder
@ -1034,7 +1353,7 @@ curl -G 'http://space.bilibili.com/ajax/settings/getSettings' \
| 3 | (左侧)订阅番剧 |
| 4 | (左侧)订阅标签 |
| 5 | (左侧)最近投币的视频 |
| 6 | (左侧)我的圈子**(此板块被隐藏)** |
| 6 | (左侧)我的圈子 **(此板块被隐藏)** |
| 7 | (左侧)我的频道 |
| 8 | (左侧)我的专栏 |
| 9 | (左侧)我的相簿 |
@ -1050,24 +1369,26 @@ curl -G 'http://space.bilibili.com/ajax/settings/getSettings' \
| 字段 | 类型 | 内容 | 备注 |
| ------ | ---- | -------- | ----------------------------------- |
| ststus | bool | 操作结果 | true操作成功<br />false操作失败 |
| status | bool | 操作结果 | true操作成功<br />false操作失败 |
| data | str | 错误信息 | 正确时无此项 |
**示例:**
调整空间布局为:
>我的稿件 直播间
>我的专栏 个人资料
>订阅番剧 公告
>我的收藏夹 官方活动
>我的相簿 最近玩的游戏
>最近投币的视频
>订阅标签
>我的频道
```text
我的稿件 直播间
我的专栏 个人资料
订阅番剧 公告
我的收藏夹 官方活动
我的相簿 最近玩的游戏
最近投币的视频
订阅标签
我的频道
```
```shell
curl 'http://space.bilibili.com/ajax/settings/setIndexOrder' \
curl 'https://space.bilibili.com/ajax/settings/setIndexOrder' \
--data-urlencode 'index_order=1,8,3,2,9,5,4,7,22,23,21,24,25,6' \
--data-urlencode 'csrf=xxx' \
-b 'SESSDATA=xxx;DedeUserID=1;DedeUserID__ckMd5=1;' \
@ -1113,7 +1434,7 @@ curl 'http://space.bilibili.com/ajax/settings/setIndexOrder' \
| 字段 | 类型 | 内容 | 备注 |
| ------ | ---- | -------- | ----------------------------------- |
| ststus | bool | 操作结果 | true操作成功<br />false操作失败 |
| status | bool | 操作结果 | true操作成功<br />false操作失败 |
| data | str | 错误信息 | 正确时无此项 |
**示例:**
@ -1121,7 +1442,7 @@ curl 'http://space.bilibili.com/ajax/settings/setIndexOrder' \
设置`关注的TAG`为隐藏
```shell
curl 'http://space.bilibili.com/ajax/settings/setPrivacy' \
curl 'https://space.bilibili.com/ajax/settings/setPrivacy' \
--data-urlencode 'tags=0' \
--data-urlencode 'csrf=xxx' \
-b 'SESSDATA=xxx;DedeUserID=1;DedeUserID__ckMd5=1;' \
@ -4298,7 +4619,7 @@ curl -G 'https://api.bilibili.com/x/space/bangumi/follow/list' \
| 字段 | 类型 | 内容 | 备注 |
| ------ | ---------------------------- | -------------------------------------- | --------------------------- |
| ststus | bool | 返回值 | false错误<br />true正确 |
| status | bool | 返回值 | false错误<br />true正确 |
| data | 错误时str<br />正确时obj | 错误时:错误信息<br />正确时:数据本体 | 正确时不返回错误信息 |
`data`对象:

View File

@ -130,7 +130,7 @@ curl 'https://app.bilibili.com/x/v2/view/like' \
</details>
### 判断视频是否被点赞(双端)
### 判断视频近期是否被点赞(双端)
> https://api.bilibili.com/x/web-interface/archive/has/like
@ -138,6 +138,9 @@ curl 'https://app.bilibili.com/x/v2/view/like' \
认证方式APP或CookieSESSDATA
注: 这一 API 实际上只能判断出视频**在近期内**是否被点赞, 并不能判断出视频是否被点赞.
「近期」的定义不明, 但至少半年前点赞过的视频, 用这一接口获取到的结果就已经是 `0` 了. 参见 [#380](https://github.com/SocialSisterYi/bilibili-API-collect/issues/380).
**url参数**
| 参数名 | 类型 | 内容 | 必要性 | 备注 |
@ -459,8 +462,6 @@ curl -G 'https://api.bilibili.com/x/web-interface/archive/coins' \
### 收藏视频(双端)
> https://api.bilibili.com/medialist/gateway/coll/resource/deal
>
> https://api.bilibili.com/x/v3/fav/resource/deal
*请求方式POST*
@ -475,8 +476,8 @@ curl -G 'https://api.bilibili.com/x/web-interface/archive/coins' \
| access_key | str | APP 登录 Token | APP 方式必要 | |
| rid | num | 稿件 avid | 必要 | |
| type | num | 必须为2 | 必要 | |
| add_media_ids | nums | 需要加入的收藏夹 mlid | 非必要 | 同时添加多个,用`,`%2C分隔 |
| del_media_ids | nums | 需要取消的收藏夹 mlid | 非必要 | 同时取消多个,用`,`%2C分隔 |
| add_media_ids | nums | 需要加入的收藏夹 mlid | 非必要(可选) | 同时添加多个,用`,`%2C分隔 |
| del_media_ids | nums | 需要取消的收藏夹 mlid | 非必要(可选) | 同时取消多个,用`,`%2C分隔 |
| csrf | str | CSRF Token位于 Cookie | Cookie 方式必要 | |
**json回复**
@ -485,7 +486,7 @@ curl -G 'https://api.bilibili.com/x/web-interface/archive/coins' \
| 字段 | 类型 | 内容 | 备注 |
| ------- | ---- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| code | num | 返回值 | 0成功<br />-101账号未登录<br />-111csrf校验失败<br />-400请求错误<br />-403访问权限不足<br />10003不存在该稿件<br />11201已经收藏过了<br />11202已经取消收藏了<br />11203达到收藏上限<br />72010017参数错误 |
| code | num | 返回值 | 0成功<br />-101账号未登录<br />-111csrf校验失败<br />-400请求错误<br />-403访问权限不足<br />10003不存在该稿件<br />11010: 您访问的内容不存在<br />11201已经收藏过了<br />11202已经取消收藏了<br />11203达到收藏上限<br />72010017参数错误 |
| message | str | 错误信息 | 正确为success |
| data | obj | 信息本体 | |
@ -538,6 +539,81 @@ curl 'https://api.bilibili.com/medialist/gateway/coll/resource/deal' \
</details>
### 收藏视频Web端
> https://api.bilibili.com/x/v3/fav/resource/deal
*请求方式: POST*
认证方式: CookieSESSDATA
**正文参数(application/x-www-form-urlencoded):**
| 参数名 | 类型 | 内容 | 必要性 | 备注 |
| ------------- | ---- | ---------------------------------- | ------------ | ------------------------------ |
| rid | num | 稿件 avid | 必要 | |
| type | num | 必须为2 | 必要 | |
| add_media_ids | nums | 需要加入的收藏夹 mlid | 非必要(可选) | 同时添加多个,用`,`%2C分隔 |
| del_media_ids | nums | 需要取消的收藏夹 mlid | 非必要(可选) | 同时取消多个,用`,`%2C分隔 |
| csrf | str | CSRF Token (即 Cookie 中 bili_jct) | 必要 | |
| platform | str | 平台标识? | 非必要 | web端: web |
| eab_x | num | 1 | 非必要 | 作用尚不明确 |
| ramval | num | 正整数 | 非必要 | 可能与在该页面的停留时间相关? |
| ga | num | 1 | 非必要 | 作用尚不明确 |
| gaia_source | str | ??? | 非必要 | web端: web_normal |
**JSON回复:**
根对象:
| 字段 | 类型 | 内容 | 备注 |
| ------- | ---- | -------- | ------- |
| code | num | 返回值 | 0: 成功<br />-101: 账号未登录<br />-111: csrf 校验失败<br />2001000: 参数错误 |
| message | str | 错误信息 | 默认为0 |
| ttl | num | 1 | |
| data | obj | 信息本体 | 错误时为 null 或不存在 |
`data`对象:
| 字段 | 类型 | 内容 | 备注 |
| ----------- | ---- | --------------------- | ----------------------- |
| prompt | bool | 是否为未关注用户收藏? | false<br />true是 |
| ga_data | null | | 作用尚不明确 |
| toast_msg | str | 空 | 作用尚不明确 |
| success_num | num | 0 | 作用尚不明确 |
**示例:**
将视频 `av1906473802` 添加到收藏夹 `1164192068`
```shell
curl -sX POST "https://api.bilibili.com/x/v3/fav/resource/deal" \
--data-urlencode "rid=1906473802" \
--data-urlencode "type=2" \
--data-urlencode "csrf=xxx" \
--data-urlencode "add_media_ids=1164192068" \
-b "SESSDATA=xxx; bili_jct=xxx"
```
<details>
<summary>查看响应示例:</summary>
```json
{
"code": 0,
"message": "0",
"ttl": 1,
"data": {
"prompt": false,
"ga_data": null,
"toast_msg": "",
"success_num": 0
}
}
```
</details>
### 判断视频是否被收藏(双端)
> https://api.bilibili.com/x/v2/fav/video/favoured

File diff suppressed because it is too large Load Diff

View File

@ -4,6 +4,7 @@
## 获取视频详细信息(web端)
> https://api.bilibili.com/x/web-interface/wbi/view
> https://api.bilibili.com/x/web-interface/view
*请求方式GET*

View File

@ -13,7 +13,7 @@ web 播放器的信息接口,提供正常播放需要的元数据,包括:
| aid | num | 稿件 avid | 必要 (可选) | aid 与 bvid 任选 |
| bvid | str | 稿件 bvid | 必要 (可选) | aid 与 bvid 任选 |
| cid | num | 稿件 cid | 必要 | |
| w_rid | str | 未知 | 不必要 | |
| w_rid | str | WBI 签名 | 不必要 | |
| wts | num | 当前 unix 时间戳 | 不必要 | |

View File

@ -1,10 +1,5 @@
# 视频推荐
- [获取单视频推荐列表web端](#获取单视频推荐列表web端)
- [获取首页视频推荐列表web端](#获取首页视频推荐列表web端)
- [获取短视频模式视频列表](#获取短视频模式视频列表)
---
## 获取单视频推荐列表web端
> https://api.bilibili.com/x/web-interface/archive/related
@ -297,67 +292,116 @@ curl -G 'https://api.bilibili.com/x/web-interface/archive/related' \
## 获取首页视频推荐列表web端
> https://api.bilibili.com/x/web-interface/index/top/rcmd
> https://api.bilibili.com/x/web-interface/wbi/index/top/feed/rcmd
*请求方式GET*
认证方式CookieSESSDATA
最多获取14条推荐视频
最多获取30条推荐视频,直播及推荐边栏
**url参数**
| 参数名 | 类型 | 内容 | 必要性 | 备注 |
|--------------|-----|---------------------------|-----|------------------------------|
| fresh_type | num | 相关性 | 非必要 | 默认为3 <br /> 值越大推荐内容越相关 |
| version | num | web端新旧版本:0为旧版本1为新版本 | 非必要 | 默认为0 <br /> 1,0分别为新旧web端 |
| ps | num | pagesize 单页返回的记录条数默认为10或8 | 非必要 | 默认为10 <br /> 当version为1时默认为8 |
| fresh_idx | num | 翻页相关 | 非必要 | 默认为1 <br /> 与翻页相关 |
| fresh_idx_1h | num | 翻页相关 | 非必要 | 默认为1 <br /> 与翻页相关 |
| 参数名 | 类型 | 内容 | 必要性 | 备注 |
|---------------|------|------------------------|--------|-------------------------------------------------------|
| fresh_type | num | 相关性 | 非必要 | 默认为 4 <br /> 值越大推荐内容越相关 |
| ps | num | 单页返回的记录条数 | 非必要 | 默认为 12, 留空即最大值为 30 |
| fresh_idx | num | 当前翻页号 | 非必要 | 以 1 开始 |
| fresh_idx_1h | num | 当前翻页号(一小时前?) | 非必要 | 以 1 开始, 默认与 fresh_idx 内容相同 |
| brush | num | 刷子? | 非必要 | 以 1 开始, 默认与 fresh_idx 内容相同 |
| fetch_row | num | 本次抓取的最后一行行号 | 非必要 | 1 递归加上本次抓取总行数 |
| web_location | num | 网页位置 | 非必要 | 主页为 1430650 |
| y_num | num | 普通列数 | 非必要 | 一行中视频,直播及广告数 |
| last_y_num | num | 总列数 | 非必要 | 普通列数 + 边栏列数 |
| feed_version | str | V8 | 非必要 | 作用尚不明确 |
| homepage_ver | num | 1 | 非必要 | 首页版本 |
| screen | str | 浏览器视口大小 | 非必要 | 水平在前垂直在后以减号分割 |
| seo_info | str | 空 | 非必要 | 作用尚不明确 |
| last_showlist | str | 上次抓取的视频av号列表 | 非必要 | av与数字间用下划线分隔, 若视频UP主已关注则中间再插入n |
| uniq_id | str | ??? | 非必要 | 作用尚不明确 |
| w_rid | str | WBI 签名 | 非必要 | 见[WBI 签名](../misc/sign/wbi.md) |
| wts | num | UNIX 时间戳 | 非必要 | 见[WBI 签名](../misc/sign/wbi.md) |
**json回复**
根对象:
| 字段 | 类型 | 内容 | 备注 |
|-------------|-------|------|----------------------|
| code | num | 返回值 | 0成功 <br />-400请求错误 |
| message | str | 错误信息 | 默认为0 |
| ttl | num | 1 | |
| data | array | 推荐列表 | |
| userfeature | str | 用户功能 | |
| abtest | obj | 用户分组 | |
| 字段 | 类型 | 内容 | 备注 |
|-------------|------|----------|------------------------------|
| code | num | 返回值 | 0成功 <br />-400请求错误 |
| message | str | 错误信息 | 默认为0 |
| ttl | num | 1 | |
| data | obj | | |
`data`数组
`data`对象:
| 项 | 类型 | 内容 | 备注 |
|-----| ---- |-----------| ---- |
| 0 | obj | 推荐视频1 | |
| n | obj | 推荐视频(n+1) | |
| …… | obj | …… | …… |
| 13 | obj | 推荐视频13 | |
| 字段 | 类型 | 内容 | 备注 |
|--------------------------|-------|-----------|--------------------------------|
| business_card | null | | |
| floor_info | null | | |
| item | array | 推荐列表 | |
| mid | num | 用户mid | 未登录为0 |
| preload_expose_pct | num | 0.5 | 用于预加载? |
| preload_floor_expose_pct | num | 0.5 | 用于预加载? |
| side_bar_column | array | 边栏列表? | 可参考字段 item 及对应功能文档 |
| user_feature | null | | |
`data`数组中的对象:
`data`对象中`item`数组中的对象:
基本同「[获取视频详细信息web端](info.md#获取视频详细信息web端)」中的data对象
| 字段 | 类型 | 内容 | 备注 |
|--------------------------|------|--------------------|-------------------------------------------|
| av_feature | null | | |
| business_info | obj | 商业推广信息 | 无为null, 此处无参考意义 |
| bvid | str | 视频bvid | |
| cid | num | 稿件cid | |
| dislike_switch | num | 1 | 显示不感兴趣开关? |
| dislike_switch_pc | num | 0 | 显示不感兴趣开关(PC)? |
| duraion | num | 视频时长 | |
| enable_vt | num | 0 | 作用尚不明确 |
| goto | num | 目标类型 | av: 视频<br />ogv: 边栏<br />live: 直播 |
| duraion | num | 视频时长 | |
| id | num | 视频aid / 直播间id | |
| is_followed | num | 已关注 | 0: 未关注<br />1: 已关注 |
| is_stock | num | 0 | 作用尚不明确 |
| ogv_info | null | | |
| owner | obj | UP主 | |
| pic | str | 封面 | |
| pic_4_3 | str | 封面(4:3) | |
| pos | num | 0 | 位置? |
| pubdate | num | 发布时间 | |
| rcmd_reason | obj | 推荐理由 | 直播等为null |
| room_info | obj | 直播间信息 | 普通视频等为null, 参见[直播](../live) |
| show_info | num | 展示信息 | 1: 普通视频<br />0: 直播 |
| stat | obj | 视频状态信息 | 直播等为null, 参见[视频基本信息](info.md) |
| title | str | 标题 | |
| track_id | str | 跟踪标识? | |
| uri | str | 目标页 URI | |
| vt_display | str | 空 | 作用尚不明确 |
`abtest`对象:
`item`数组中的对象中的`owner`对象:
| 字段 | 类型 | 内容 | 备注 |
|-------|-----|------|-----|
| group | str | 用户分组 | |
| 字段 | 类型 | 内容 | 备注 |
| face | str | 头像URL | |
| mid | num | UP主mid | |
| name | str | UP昵称 | |
`item`数组中的对象中的`rcmd_reason`对象:
| 字段 | 类型 | 内容 | 备注 |
| reason_type | num | 原因类型 | 0: 无<br />1: 已关注<br />3: 高点赞量 |
| content | str | 原因描述 | 当 reason_type 为 3 时存在 |
**示例:**
获取新版web端首页推荐视频列表
```shell
curl -G 'https://api.bilibili.com/x/web-interface/index/top/rcmd' \
--data-urlencode 'fresh_type=3' \
--data-urlencode 'version=1' \
--data-urlencode 'ps=10' \
--data-urlencode 'fresh_idx=1' \
--data-urlencode 'fresh_idx_1h=1'
curl -G 'https://api.bilibili.com/x/web-interface/wbi/index/top/feed/rcmd' \
--data-urlencode 'fresh_type=4' \
--data-urlencode 'ps=12' \
--data-urlencode 'fresh_idx=5' \
--data-urlencode 'fresh_idx_1h=5' \
--data-urlencode 'fetch_row=16'
```
<details>
@ -365,47 +409,733 @@ curl -G 'https://api.bilibili.com/x/web-interface/index/top/rcmd' \
```json
{
"code": 0,
"message": "0",
"ttl": 1,
"data": {
"item": [
{
"id": 511495739,
"bvid": "BV1Cu411z7mG",
"cid": 717978243,
"goto": "av",
"uri": "http://www.bilibili.com/video/BV1Cu411z7mG",
"pic": "http://i2.hdslb.com/bfs/archive/e05f487bc9f26baa568f10fe69a0e1ea5e0fbc23.jpg",
"title": "请大家助力我的梦想为凑够10万赞在街头唱《Be Crazy For Me》",
"duration": 199,
"pubdate": 1652605500,
"owner": {
"mid": 1723817,
"name": "樱萍Apple",
"face": "http://i2.hdslb.com/bfs/face/6e0fa1bdbbf7e0dd929d968df3b57ca99d187e25.jpg"
},
"stat": {
"view": 263169,
"like": 39871,
"danmaku": 543
},
"avfeature": "{\"ctr\":0.192554,\"wdur\":2.323159,\"duration\":213.318313,\"wdlks\":0.685926,\"multi_score_0\":0.452564,\"multi_score_1\":0.112414,\"multi_score_2\":0.03976,\"rankscore\":13.906487,\"av_play\":258890,\"av_like\":39224,\"av_coin\":7165,\"reason_type\":3,\"av_feature\":\"|real_matchtype -1 |s_e online_av2av_v2 |source_len 1 |m_k_w 0 \"}",
"isfollowed": 0,
"rcmdreason": {
"content": "3万点赞",
"reasontype": 3
},
"showinfo": 1,
"trackid": "web_pegasus_0.shylf-ai-recsys-1355.165525355529.398"
}
......
],
"userfeature": "{\"enter_rank\":1500,\"is_fallback\":0,\"s_fresh_idx\":41,\"s_fresh_idx_session\":31,\"s_session_idx\":1,\"fresh_idx\":1,\"fresh_idx_1h\":1}",
"abtest": {
"group": "b"
"code": 0,
"message": "0",
"ttl": 1,
"data": {
"item": [
{
"id": 1354614895,
"bvid": "BV1Dz42117GZ",
"cid": 1548835687,
"goto": "av",
"uri": "https://www.bilibili.com/video/BV1Dz42117GZ",
"pic": "http://i1.hdslb.com/bfs/archive/b47154987b4c0f40a39779c09a9d485176d1238f.jpg",
"pic_4_3": "http://i0.hdslb.com/bfs/archive/b47154987b4c0f40a39779c09a9d485176d1238f.jpg",
"title": "做数学题总是抄错 | 看错 | 算错 怎么破?决定高考分数的这个非智力因素不容忽视",
"duration": 882,
"pubdate": 1715946937,
"owner": {
"mid": 374484802,
"name": "数学阮禾老师",
"face": "https://i1.hdslb.com/bfs/face/4df57e4b48b04206bce7572831688741580ca0e1.jpg"
},
"stat": {
"view": 48250,
"like": 2959,
"danmaku": 433,
"vt": 0
},
"av_feature": null,
"is_followed": 0,
"rcmd_reason": {
"reason_type": 0
},
"show_info": 1,
"track_id": "web_pegasus_4.router-web-pegasus-1554782-5c89895477-smhn8.1721098961744.133",
"pos": 0,
"room_info": null,
"ogv_info": null,
"business_info": null,
"is_stock": 0,
"enable_vt": 0,
"vt_display": "",
"dislike_switch": 1,
"dislike_switch_pc": 0
},
{
"id": 1255924089,
"bvid": "BV1DJ4m1u7Mp",
"cid": 1600833978,
"goto": "av",
"uri": "https://www.bilibili.com/video/BV1DJ4m1u7Mp",
"pic": "http://i0.hdslb.com/bfs/archive/5068d860e8bbc37679ece933aa8e6d8428cfb5c1.jpg",
"pic_4_3": "http://i0.hdslb.com/bfs/aistory/2024-07-01-1145021255924089_1612_gener.jpg",
"title": "人类这种生物,看到按钮就会按下去。",
"duration": 326,
"pubdate": 1719805500,
"owner": {
"mid": 5616993,
"name": "马夫鱼33",
"face": "https://i0.hdslb.com/bfs/face/4c2af23046147e91ce5a4af3375464fdcf1956e6.jpg"
},
"stat": {
"view": 667067,
"like": 28529,
"danmaku": 483,
"vt": 0
},
"av_feature": null,
"is_followed": 0,
"rcmd_reason": {
"content": "2万点赞",
"reason_type": 3
},
"show_info": 1,
"track_id": "web_pegasus_4.router-web-pegasus-1554782-5c89895477-smhn8.1721098961744.133",
"pos": 0,
"room_info": null,
"ogv_info": null,
"business_info": null,
"is_stock": 0,
"enable_vt": 0,
"vt_display": "",
"dislike_switch": 1,
"dislike_switch_pc": 0
},
{
"id": 1306020278,
"bvid": "BV1rM4m117Ry",
"cid": 1608959606,
"goto": "av",
"uri": "https://www.bilibili.com/video/BV1rM4m117Ry",
"pic": "http://i0.hdslb.com/bfs/archive/49f62c70f17d0afe00e5e620dd366c68149c780e.jpg",
"pic_4_3": "http://i0.hdslb.com/bfs/archive/49f62c70f17d0afe00e5e620dd366c68149c780e.jpg",
"title": "Axios 前后端对接教程HTTP",
"duration": 352,
"pubdate": 1720440325,
"owner": {
"mid": 260736087,
"name": "三分钟实验室",
"face": "https://i0.hdslb.com/bfs/face/6172aa089ed0b26ffffb72018422eb4280d4da41.jpg"
},
"stat": {
"view": 7527,
"like": 365,
"danmaku": 1,
"vt": 0
},
"av_feature": null,
"is_followed": 0,
"rcmd_reason": {
"reason_type": 0
},
"show_info": 1,
"track_id": "web_pegasus_4.router-web-pegasus-1554782-5c89895477-smhn8.1721098961744.133",
"pos": 0,
"room_info": null,
"ogv_info": null,
"business_info": null,
"is_stock": 0,
"enable_vt": 0,
"vt_display": "",
"dislike_switch": 1,
"dislike_switch_pc": 0
},
{
"id": 1755972439,
"bvid": "BV1g4421D7qn",
"cid": 1597039275,
"goto": "av",
"uri": "https://www.bilibili.com/video/BV1g4421D7qn",
"pic": "http://i2.hdslb.com/bfs/archive/35ee2ffaab4206d17893a3f48cdf512b4f028fdc.jpg",
"pic_4_3": "http://i0.hdslb.com/bfs/aistory/2024-06-26-21354756381755972439_16_12_5326_crop.jpg",
"title": "《我爱发明》里那些抽象发明 歹徒兴奋床!",
"duration": 659,
"pubdate": 1719408945,
"owner": {
"mid": 348989367,
"name": "沫子瞪片",
"face": "https://i0.hdslb.com/bfs/face/a2131d38a2ea73f16ff25e61dbeb40377233f552.jpg"
},
"stat": {
"view": 1540767,
"like": 65409,
"danmaku": 5383,
"vt": 0
},
"av_feature": null,
"is_followed": 0,
"rcmd_reason": {
"reason_type": 0
},
"show_info": 1,
"track_id": "web_pegasus_4.router-web-pegasus-1554782-5c89895477-smhn8.1721098961744.133",
"pos": 0,
"room_info": null,
"ogv_info": null,
"business_info": null,
"is_stock": 0,
"enable_vt": 0,
"vt_display": "",
"dislike_switch": 1,
"dislike_switch_pc": 0
},
{
"id": 1055953358,
"bvid": "BV1jH4y1w7A6",
"cid": 1598484848,
"goto": "av",
"uri": "https://www.bilibili.com/video/BV1jH4y1w7A6",
"pic": "http://i1.hdslb.com/bfs/archive/accdb655b4f2bef665e6fdedb4de28de2feda078.jpg",
"pic_4_3": "http://i0.hdslb.com/bfs/aistory/2024-06-28-12560692491055953358_16_12_2438_crop.jpg",
"title": "为什么一个数的5次方个位数是自己",
"duration": 327,
"pubdate": 1719550565,
"owner": {
"mid": 483522694,
"name": "火星课堂",
"face": "https://i1.hdslb.com/bfs/face/fe751f0d7062c8e8adcef501390d48330fac0514.jpg"
},
"stat": {
"view": 244673,
"like": 5406,
"danmaku": 210,
"vt": 0
},
"av_feature": null,
"is_followed": 0,
"rcmd_reason": {
"reason_type": 0
},
"show_info": 1,
"track_id": "web_pegasus_4.router-web-pegasus-1554782-5c89895477-smhn8.1721098961744.133",
"pos": 0,
"room_info": null,
"ogv_info": null,
"business_info": {
"id": 0,
"contract_id": "",
"res_id": 1055953358,
"asg_id": 0,
"pos_num": 0,
"name": "",
"pic": "",
"litpic": "",
"url": "",
"style": 0,
"agency": "",
"label": "",
"intro": "",
"creative_type": 0,
"request_id": "1721098961752q172a25a216a162q1363",
"src_id": 5637,
"area": 0,
"is_ad_loc": true,
"ad_cb": "",
"title": "",
"server_type": 0,
"cm_mark": 0,
"stime": 0,
"mid": "",
"activity_type": 0,
"epid": 0,
"sub_title": "",
"ad_desc": "",
"adver_name": "",
"null_frame": false,
"pic_main_color": "",
"card_type": 0,
"business_mark": null,
"inline": {
"inline_use_same": 0,
"inline_type": 0,
"inline_url": "",
"inline_barrage_switch": 0
},
"operater": "",
"jump_target": 0,
"show_urls": null,
"click_urls": null
},
"is_stock": 1,
"enable_vt": 0,
"vt_display": "",
"dislike_switch": 1,
"dislike_switch_pc": 0
},
{
"id": 1763571437,
"bvid": "",
"cid": 0,
"goto": "live",
"uri": "https://live.bilibili.com/1763571437",
"pic": "http://i0.hdslb.com/bfs/live/new_room_cover/f1787ef2ce4a2a031fb4a6a63b62d15493268d71.jpg",
"pic_4_3": "",
"title": "【新V】今天不要再把自己笨哭了",
"duration": 0,
"pubdate": 0,
"owner": {
"mid": 3546712666802274,
"name": "伊柒璇儿_鹤熙冠",
"face": "https://i0.hdslb.com/bfs/face/3e0ff3d7d53b9ac1a2d90ea563e22d3f70ad28cc.jpg"
},
"stat": null,
"av_feature": null,
"is_followed": 0,
"rcmd_reason": null,
"show_info": 0,
"track_id": "web_pegasus_4.router-web-pegasus-1554782-5c89895477-smhn8.1721098961744.133",
"pos": 0,
"room_info": {
"room_id": 1763571437,
"uid": 3546712666802274,
"live_status": 1,
"show": {
"short_id": 0,
"title": "【新V】今天不要再把自己笨哭了",
"cover": "http://i0.hdslb.com/bfs/live/new_room_cover/f1787ef2ce4a2a031fb4a6a63b62d15493268d71.jpg",
"keyframe": "http://i0.hdslb.com/bfs/live-key-frame/keyframe07161101001763571437k9l40v.jpg",
"popularity_count": 8539,
"tag_list": null,
"live_start_time": 0,
"live_id": 0,
"hidden_online": false
},
"area": {
"area_id": 0,
"area_name": "虚拟日常",
"parent_area_id": 9,
"parent_area_name": "虚拟主播",
"old_area_id": 0,
"old_area_name": "",
"old_area_tag": "",
"area_pk_status": 0,
"is_video_room": false
},
"watched_show": {
"switch": true,
"num": 168,
"text_small": "168",
"text_large": "168人看过",
"icon": "https://i0.hdslb.com/bfs/live/a725a9e61242ef44d764ac911691a7ce07f36c1d.png",
"icon_location": "",
"icon_web": "https://i0.hdslb.com/bfs/live/8d9d0f33ef8bf6f308742752d13dd0df731df19c.png"
}
},
"ogv_info": null,
"business_info": null,
"is_stock": 0,
"enable_vt": 0,
"vt_display": "",
"dislike_switch": 1,
"dislike_switch_pc": 0
},
{
"id": 1855792572,
"bvid": "BV16s421T7CU",
"cid": 1587596195,
"goto": "av",
"uri": "https://www.bilibili.com/video/BV16s421T7CU",
"pic": "http://i2.hdslb.com/bfs/archive/1b9d9799260a075b094212bf79e3d7ccb9e04087.jpg",
"pic_4_3": "http://i0.hdslb.com/bfs/aistory/2024-06-19-14044883851855792572_16_12_7260_crop.jpg",
"title": "压缩蚊件.zip",
"duration": 66,
"pubdate": 1718777086,
"owner": {
"mid": 173947574,
"name": "好奇五先生",
"face": "https://i2.hdslb.com/bfs/face/1c69fff12a2d0d50e71931cef0486ab919a818a2.jpg"
},
"stat": {
"view": 951633,
"like": 22930,
"danmaku": 932,
"vt": 0
},
"av_feature": null,
"is_followed": 0,
"rcmd_reason": {
"reason_type": 0
},
"show_info": 1,
"track_id": "web_pegasus_4.router-web-pegasus-1554782-5c89895477-smhn8.1721098961744.133",
"pos": 0,
"room_info": null,
"ogv_info": null,
"business_info": null,
"is_stock": 0,
"enable_vt": 0,
"vt_display": "",
"dislike_switch": 1,
"dislike_switch_pc": 0
},
{
"id": 1405866842,
"bvid": "BV11r421F7E8",
"cid": 1589772517,
"goto": "av",
"uri": "https://www.bilibili.com/video/BV11r421F7E8",
"pic": "http://i2.hdslb.com/bfs/archive/50b1bb8d227d17a3b6195e80128ab295d152d3be.jpg",
"pic_4_3": "http://i0.hdslb.com/bfs/aistory/2024-06-20-2148551405866842_1612_gener.jpg",
"title": "【音游推荐】暑期音游推荐,不同基础都可入坑",
"duration": 311,
"pubdate": 1718891332,
"owner": {
"mid": 592146708,
"name": "Qc天水",
"face": "https://i0.hdslb.com/bfs/face/2998a9e762aa07559b2acf54234f07979c959ffe.jpg"
},
"stat": {
"view": 278997,
"like": 6698,
"danmaku": 303,
"vt": 0
},
"av_feature": null,
"is_followed": 0,
"rcmd_reason": {
"reason_type": 0
},
"show_info": 1,
"track_id": "web_pegasus_4.router-web-pegasus-1554782-5c89895477-smhn8.1721098961744.133",
"pos": 0,
"room_info": null,
"ogv_info": null,
"business_info": null,
"is_stock": 0,
"enable_vt": 0,
"vt_display": "",
"dislike_switch": 1,
"dislike_switch_pc": 0
},
{
"id": 1055540151,
"bvid": "BV1in4y197U4",
"cid": 1582190043,
"goto": "av",
"uri": "https://www.bilibili.com/video/BV1in4y197U4",
"pic": "http://i2.hdslb.com/bfs/archive/9a366971fadd6e4dfd1813c42b180c8779038627.jpg",
"pic_4_3": "http://i0.hdslb.com/bfs/aistory/2024-06-15-18004087071055540151_16_12_7856_crop.jpg",
"title": "我把裁判罚下场了",
"duration": 217,
"pubdate": 1718445600,
"owner": {
"mid": 475304452,
"name": "生姜蛋包饭",
"face": "https://i1.hdslb.com/bfs/face/40feee36c71f7f53931854fc54c88d530360b1a7.jpg"
},
"stat": {
"view": 678085,
"like": 62171,
"danmaku": 832,
"vt": 0
},
"av_feature": null,
"is_followed": 0,
"rcmd_reason": {
"content": "6万点赞",
"reason_type": 3
},
"show_info": 1,
"track_id": "web_pegasus_4.router-web-pegasus-1554782-5c89895477-smhn8.1721098961744.133",
"pos": 0,
"room_info": null,
"ogv_info": null,
"business_info": null,
"is_stock": 0,
"enable_vt": 0,
"vt_display": "",
"dislike_switch": 1,
"dislike_switch_pc": 0
},
{
"id": 1505823466,
"bvid": "BV1vS421d7No",
"cid": 1596567774,
"goto": "av",
"uri": "https://www.bilibili.com/video/BV1vS421d7No",
"pic": "http://i2.hdslb.com/bfs/archive/b2b19b067cdbf7dd93be5fc01009e72c20572184.jpg",
"pic_4_3": "http://i0.hdslb.com/bfs/aistory/2024-06-26-1241021505823466_1612_gener.jpg",
"title": "AI 视频:两小儿辩日",
"duration": 138,
"pubdate": 1719376858,
"owner": {
"mid": 589397373,
"name": "宝玉xp",
"face": "https://i0.hdslb.com/bfs/face/c2c29f6e1bb9b0860241f0df4d2cdea8242ab5d2.jpg"
},
"stat": {
"view": 1216188,
"like": 54839,
"danmaku": 194,
"vt": 0
},
"av_feature": null,
"is_followed": 0,
"rcmd_reason": {
"reason_type": 0
},
"show_info": 1,
"track_id": "web_pegasus_4.router-web-pegasus-1554782-5c89895477-smhn8.1721098961744.133",
"pos": 0,
"room_info": null,
"ogv_info": null,
"business_info": null,
"is_stock": 0,
"enable_vt": 0,
"vt_display": "",
"dislike_switch": 1,
"dislike_switch_pc": 0
},
{
"id": 1055744039,
"bvid": "BV1Zn4y1Q7zj",
"cid": 1575814128,
"goto": "av",
"uri": "https://www.bilibili.com/video/BV1Zn4y1Q7zj",
"pic": "http://i0.hdslb.com/bfs/archive/5288cf0830e49de414084c4168b11033b08f8507.jpg",
"pic_4_3": "http://i0.hdslb.com/bfs/aistory/2024-06-09-17404720501055744039_16_12_294_crop.jpg",
"title": "【诺子】重新“看见”世界是一种什么样的感觉?",
"duration": 579,
"pubdate": 1717926045,
"owner": {
"mid": 10276136,
"name": "诺子喵呜",
"face": "https://i2.hdslb.com/bfs/face/7e6846ed5619b945c888b8f8db5000469f6353ff.jpg"
},
"stat": {
"view": 1016467,
"like": 97886,
"danmaku": 979,
"vt": 0
},
"av_feature": null,
"is_followed": 0,
"rcmd_reason": {
"reason_type": 0
},
"show_info": 1,
"track_id": "web_pegasus_4.router-web-pegasus-1554782-5c89895477-smhn8.1721098961744.133",
"pos": 0,
"room_info": null,
"ogv_info": null,
"business_info": null,
"is_stock": 0,
"enable_vt": 0,
"vt_display": "",
"dislike_switch": 1,
"dislike_switch_pc": 0
},
{
"id": 1706215690,
"bvid": "BV1tT421k7By",
"cid": 1611364587,
"goto": "av",
"uri": "https://www.bilibili.com/video/BV1tT421k7By",
"pic": "http://i1.hdslb.com/bfs/archive/cd3308109e8726fe4147dd25ed7ca0dbeeda1dc1.jpg",
"pic_4_3": "http://i0.hdslb.com/bfs/aistory/2024-07-11-00194836761706215690_16_12_3934_crop.jpg",
"title": "谷歌翻译20遍《河中石兽》泌尿系统",
"duration": 145,
"pubdate": 1720628387,
"owner": {
"mid": 1030835113,
"name": "象哥嘎",
"face": "https://i1.hdslb.com/bfs/face/aa0ae89fa72dab7b8bc082433769b1768f51c3dc.jpg"
},
"stat": {
"view": 78600,
"like": 3437,
"danmaku": 328,
"vt": 0
},
"av_feature": null,
"is_followed": 0,
"rcmd_reason": {
"reason_type": 0
},
"show_info": 1,
"track_id": "web_pegasus_4.router-web-pegasus-1554782-5c89895477-smhn8.1721098961744.133",
"pos": 0,
"room_info": null,
"ogv_info": null,
"business_info": null,
"is_stock": 0,
"enable_vt": 0,
"vt_display": "",
"dislike_switch": 1,
"dislike_switch_pc": 0
}
],
"side_bar_column": [
{
"id": 25502,
"goto": "comic",
"track_id": "",
"pos": 1,
"card_type": "漫画",
"card_type_en": "comic",
"cover": "http://i0.hdslb.com/bfs/manga-static/5e410bf6f73ff87f87b543e4b918de5f024652e8.jpg",
"url": "https://manga.bilibili.com/detail/mc25502",
"title": "头文字D",
"sub_title": "",
"duration": 0,
"stats": null,
"room_info": null,
"styles": [
"游戏竞技"
],
"comic": {
"comic_id": 25502,
"title": "头文字D",
"horizontal_cover": "http://i0.hdslb.com/bfs/manga-static/5e410bf6f73ff87f87b543e4b918de5f024652e8.jpg",
"square_cover": "http://i0.hdslb.com/bfs/manga-static/da660f6274730af82d557f21a6247d4f6b1e300b.jpg",
"vertical_cover": "http://i0.hdslb.com/bfs/manga-static/64df8b860d2bf6bf2edd0426b4aefbff25b51386.jpg",
"is_finish": 1,
"status": 0,
"last_ord": 724,
"total": 724,
"release_time": "",
"last_short_title": "番外05",
"discount_type": 0,
"recommendation": "秋名山下坡最快的AE86神话",
"last_read_ep_id": 0,
"latest_ep_short_title": "",
"style": [
"游戏竞技"
],
"author_name": [
"重野秀一 ",
"讲谈社"
],
"allow_wait_free": false,
"type": 0,
"rank": null,
"operate_cover": "",
"rookie_type": 0
},
"producer": null,
"source": "",
"av_feature": null,
"is_rec": 0,
"is_finish": 0,
"is_started": 0,
"is_play": 0,
"enable_vt": 0,
"vt_display": ""
},
{
"id": 47800,
"goto": "ogv",
"track_id": "",
"pos": 2,
"card_type": "番剧",
"card_type_en": "bangumi",
"cover": "https://i0.hdslb.com/bfs/bangumi/image/1c61f75b571fffb8c5a2bd0396b49ce3529776f4.png",
"url": "https://www.bilibili.com/bangumi/play/ss47800",
"title": "铁甲小宝 重制版 中文配音",
"sub_title": "童年经典回归!",
"duration": 1382000,
"stats": {
"follow": 116644,
"view": 10864687,
"danmaku": 42428,
"reply": 11448,
"coin": 18904,
"series_follow": 209046,
"series_view": 17474247,
"likes": 61376,
"favorite": 116644
},
"room_info": null,
"new_ep": {
"id": 824212,
"index_show": "更新至第30话",
"cover": "http://i0.hdslb.com/bfs/archive/e185c054588945a1de6648ff7fb5001852df39f4.png",
"title": "30",
"long_title": "巨大机器来袭!!",
"pub_time": "2024-07-15 18:00:01",
"duration": 1382000,
"day_of_week": 1
},
"styles": [
"日常",
"热血",
"搞笑",
"原创",
"特摄"
],
"comic": null,
"producer": [
{
"mid": 928123,
"name": "哔哩哔哩番剧",
"type": 3,
"is_contribute": 1
}
],
"source": "",
"av_feature": null,
"is_rec": 0,
"is_finish": 0,
"is_started": 1,
"is_play": 1,
"horizontal_cover_16_9": "https://i0.hdslb.com/bfs/bangumi/image/ec5065dc0e88417abd4792d5caa96dacc99d1d51.png",
"horizontal_cover_16_10": "https://i0.hdslb.com/bfs/bangumi/image/5cc132e336cc72e6521bba928d8a0e50bd5a6d34.png",
"enable_vt": 0,
"vt_display": ""
},
{
"id": 48020,
"goto": "ogv",
"track_id": "",
"pos": 3,
"card_type": "国创",
"card_type_en": "guochuang",
"cover": "https://i0.hdslb.com/bfs/bangumi/image/fcb176fcbf5a66fd122fa99f9fdf2cabf22468bb.png",
"url": "https://www.bilibili.com/bangumi/play/ss48020",
"title": "不白吃古诗词漫游记 第二季",
"sub_title": "古诗词这动人的浪漫",
"duration": 179000,
"stats": {
"follow": 2173495,
"view": 325366,
"danmaku": 110,
"reply": 208,
"coin": 443,
"series_follow": 2208624,
"series_view": 3322752487,
"likes": 8794,
"favorite": 2173495
},
"room_info": null,
"new_ep": {
"id": 830238,
"index_show": "更新至第7话",
"cover": "http://i0.hdslb.com/bfs/archive/6db74bc8ab2670181562314a24abe525cebb7c76.jpg",
"title": "7",
"long_title": "王维当个官怎么还郁闷了?",
"pub_time": "2024-07-15 19:00:00",
"duration": 179000,
"day_of_week": 1
},
"styles": [
"少儿",
"历史",
"原创",
"古风"
],
"comic": null,
"producer": [],
"source": "",
"av_feature": null,
"is_rec": 0,
"is_finish": 0,
"is_started": 1,
"is_play": 1,
"horizontal_cover_16_9": "https://i0.hdslb.com/bfs/bangumi/image/f19013ddd7f87b0e03df10feccc4a61a3a43774a.png",
"horizontal_cover_16_10": "https://i0.hdslb.com/bfs/bangumi/image/966553b199829aae7e47882edbe053463ee85276.png",
"enable_vt": 0,
"vt_display": ""
}
],
"business_card": null,
"floor_info": null,
"user_feature": null,
"preload_expose_pct": 0.5,
"preload_floor_expose_pct": 0.5,
"mid": 645769214
}
}
}
```

View File

@ -78,28 +78,58 @@ curl 'https://api.bilibili.com/x/v2/history/report' \
认证方式仅可CookieSESSDATA
默认间隔15秒一次
默认间隔15秒一次, 亦可记录播放历史
亦可记录播放历史
尽管以下除正文 `aid` 以外的参数均为非必要, 但缺少可能会导致播放不被记录, 同一 IP/登陆用户 每五分钟最多记录一次播放
该接口较为复杂, 且参数计算方法均为推测, 实际过程不明, 可能含有错误, 若要正式使用可以把已播放的持续时间全都设为相同值
**URL参数:**
| 参数名 | 类型 | 内容 | 必要性 | 备注 |
| ------------------------- | ---- | ------------------------------ | ------ | ------- |
| w_start_ts | num | 参见请求正文同名无`w_`前缀参数 | 非必要 | UNIX 秒级时间戳 |
| w_mid | num | 参见请求正文同名无`w_`前缀参数 | 非必要 | |
| w_aid | num | 参见请求正文同名无`w_`前缀参数 | 非必要 | |
| w_dt | num | 2 | 非必要 | |
| w_realtime | num | 参见请求正文同名无`w_`前缀参数 | 非必要 | 单位 秒 |
| w_playedtime | num | 参见请求正文同名无`w_`前缀参数 | 非必要 | 单位 秒 |
| w_real_played_time | num | 参见请求正文同名无`w_`前缀参数 | 非必要 | 单位 秒 |
| w_video_duration | num | 参见请求正文同名无`w_`前缀参数 | 非必要 | 单位 秒 |
| w_last_play_progress_time | num | 参见请求正文同名无`w_`前缀参数 | 非必要 | 单位 秒 |
| web_location | num | 网页位置 | 非必要 | 视频详情页播放器: 1315873 |
| w_rid | num | WBI 签名 | 非必要 | 参见[WBI 签名](docs/misc/sign/wbi.md) |
| wts | num | UNIX 秒级时间戳 | 非必要 | 参见[WBI 签名](docs/misc/sign/wbi.md) |
**正文参数( application/x-www-form-urlencoded **
| 参数名 | 类型 | 内容 | 必要性 | 备注 |
| ----------- | ---- | ------------------------ | ------------ | ------------------------------------------------------------ |
| aid | num | 稿件avid | 必要(可选) | avid与bvid任选一个 |
| bvid | str | 稿件bvid | 必要(可选) | avid与bvid任选一个 |
| cid | num | 视频cid | 非必要 | 用于识别分P |
| epid | num | 番剧epid | 非必要 | |
| sid | num | 番剧ssid | 非必要 | |
| mid | num | 当前用户mid | 非必要 | |
| played_time | num | 视频播放进度 | 非必要 | 单位为秒<br />默认为0 |
| realtime | num | 总计播放时间 | 非必要 | 单位为秒 |
| start_ts | num | 开始播放时刻 | 非必要 | 时间戳 |
| type | num | 视频类型 | 非必要 | 3投稿视频<br />4剧集<br />10课程 |
| sub_type | num | 剧集副类型 | 非必要 | 当`type=4`时本参数有效<br />1番剧<br />2电影<br />3纪录片<br />4国创<br />5电视剧<br />7综艺 |
| dt | num | 2 | 非必要 | |
| play_type | num | 播放动作 | 非必要 | 0播放中<br />1开始播放<br />2暂停<br />3继续播放 |
| csrf | str | CSRF Token位于cookie | 非必要 | |
| 参数名 | 类型 | 内容 | 必要性 | 备注 |
| ----------------------- | ---- | ---------------------------------- | ------------ | ----------------------------------------------------------- |
| aid | num | 稿件avid | 必要(可选) | avid与bvid任选一个(网页端请求默认仅使用aid) |
| bvid | str | 稿件bvid | 必要(可选) | avid与bvid任选一个 |
| cid | num | 视频cid | 非必要 | 用于识别分P |
| epid | num | 番剧epid | 非必要 | |
| sid | num | 番剧ssid | 非必要 | |
| mid | num | 当前用户mid | 非必要 | |
| played_time | num | 视频播放进度 | 非必要 | 单位 秒<br />播放完成为 -1 |
| realtime | num | 本轮页面会话真实播放时间 | 非必要 | 单位 秒 |
| real_played_time | num | 本轮页面会话真实视频播放持续时间 | 非必要 | 单位 秒 |
| refer_url | str | 与请求头 Referer 字段相同 | 非必要 | |
| quality | num | 视频清晰度 | 非必要 | 参见[qn视频清晰度标识](videostream_url.md#qn视频清晰度标识) |
| video_duration | num | 视频时长 | 非必要 | 单位 秒 |
| last_play_progress_time | num | play_time 与 本轮页面会话开始时 played_time 之和 | 非必要 | 单位 秒 |
| max_play_progress_time | num | 本轮页面会话所有最大 last_play_progress_time 与 本轮页面会话开始时 played_time 之和 | 非必要 | 单位 秒 |
| start_ts | num | 开始播放时刻 | 非必要 | 时间戳 |
| type | num | 视频类型 | 非必要 | 3投稿视频<br />4剧集<br />10课程 |
| sub_type | num | 剧集副类型 | 非必要 | 0: 普通投稿视频<br />1番剧<br />2电影<br />3纪录片<br />4国创<br />5电视剧<br />7综艺 |
| dt | num | 2 | 非必要 | |
| outer | num | 0 | 非必要 | |
| spmid | str | 333.788.0.0 | 非必要 | 作用尚不明确 |
| from_spmid | str | 播放来源? | 非必要 | 也可为空, 如: 444.41.list.card_archive.click |
| session | str | 会话信息? | 非必要 | 每次刷新均不同, 生成原理尚不明确 |
| extra | obj | 额外信息, 如播放器版本 | 非必要 | 如: `{"player_version":"4.8.36"}` |
| play_type | num | 播放动作 | 非必要 | 0播放中<br />1开始播放<br />2暂停<br />3继续播放<br />4: 结束播放 |
| csrf | str | CSRF Token即 Cookie 中 bili_jct) | 非必要 | |
**json回复**

View File

@ -1,9 +1,5 @@
# 分区最新视频
- [获取分区最新视频列表](#获取分区最新视频列表)
---
## 获取分区最新视频列表
> https://api.bilibili.com/x/web-interface/dynamic/region
@ -15,7 +11,7 @@
| 参数名 | 类型 | 内容 | 必要性 | 备注 |
| ------ | ---- | ----------- | ------ | ------- |
| pn | num | 页码 | 非必要 | 默认为1 |
| ps | num | 每页项数 | 非必要 | 默认为5 |
| ps | num | 每页项数 | 非必要 | 默认为14, 留空为5 |
| rid | num | 目标分区tid | 必要 | |
**json回复**
@ -197,3 +193,445 @@ curl -G 'https://api.bilibili.com/x/web-interface/dynamic/region' \
```
</details>
### 获取分区标签近期互动列表
> https://api.bilibili.com/x/web-interface/dynamic/tag
*请求方式: GET*
**url参数**
| 参数名 | 类型 | 内容 | 必要性 | 备注 |
| ------ | ---- | ---------- | ------ | ----------------- |
| ps | num | 视频数 | 非必要 | 默认为14, 留空为5 |
| pn | num | 列数 | 非必要 | 留空为1 |
| rid | num | 目标分区id | 必要 | 参见[视频分区一览](../video/video_zone.md) |
| tag_id | num | 目标标签id | 必要 | |
**json回复:**
与[获取分区最新视频列表](#获取分区最新视频列表)相同, 略
**示例:**
获取`tid=136(游戏->音游)`分区中`tag_id=10026108(Phigros)`标签近期互动列表的2条视频信息
```shell
curl -G 'https://api.bilibili.com/x/web-interface/dynamic/tag' \
--data-urlencode 'rid=136' \
--data-urlencode 'tag_id=10026108' \
--data-urlencode 'ps=2' \
--data-urlencode 'pn=1'
```
<details>
<summary>查看响应示例:</summary>
```json
{
"code": 0,
"message": "0",
"ttl": 1,
"data": {
"page": {
"num": 1,
"size": 2,
"count": 152
},
"archives": [
{
"aid": 1452657587,
"videos": 1,
"tid": 136,
"tname": "音游",
"copyright": 1,
"pic": "http://i1.hdslb.com/bfs/archive/4cb13f97e0d4b43645728432468e44b40ad343de.jpg",
"title": "【MuseDash x Phigros/逆天愚人节谱面】Retribution ~Cycle of Redemption~ Lv.? AP",
"pubdate": 1712310000,
"ctime": 1712302810,
"desc": "谱师Mayflycmd@命令提示符 ",
"state": 0,
"duration": 189,
"rights": {
"bp": 0,
"elec": 0,
"download": 0,
"movie": 0,
"pay": 0,
"hd5": 0,
"no_reprint": 1,
"autoplay": 1,
"ugc_pay": 0,
"is_cooperation": 0,
"ugc_pay_preview": 0,
"no_background": 0,
"arc_pay": 0,
"pay_free_watch": 0
},
"owner": {
"mid": 3493136175204754,
"name": "TempoTiger",
"face": "https://i1.hdslb.com/bfs/face/0cf2722f9aaa0db94f9166a8084e347bca3580f4.jpg"
},
"stat": {
"aid": 1452657587,
"view": 27021,
"danmaku": 141,
"reply": 113,
"favorite": 306,
"coin": 144,
"share": 95,
"now_rank": 0,
"his_rank": 0,
"like": 1050,
"dislike": 0,
"vt": 0,
"vv": 27021
},
"dynamic": "",
"cid": 1494650111,
"dimension": {
"width": 1920,
"height": 1080,
"rotate": 0
},
"short_link_v2": "https://b23.tv/BV1Eq421w7T4",
"first_frame": "http://i0.hdslb.com/bfs/storyff/n240405sa2zsrp9x2i3erx1ln8icirs6_firsti.jpg",
"pub_location": "广东",
"cover43": "",
"bvid": "BV1Eq421w7T4",
"season_type": 0,
"is_ogv": false,
"ogv_info": null,
"rcmd_reason": "",
"enable_vt": 0,
"ai_rcmd": null
},
{
"aid": 1155789590,
"videos": 1,
"tid": 136,
"tname": "音游",
"copyright": 1,
"pic": "http://i1.hdslb.com/bfs/archive/c75674c8d104421d1794e69926d42ffa90e7d73d.jpg",
"title": "[Phigros 自制谱] 把一切都倾注进去吧!/ 雑踏、僕らの街 - TOGENASHI TOGEARI",
"pubdate": 1719687153,
"ctime": 1719687153,
"desc": "不是,你们怎么忍住把这键盘歌写这么简单的?\n不是你们怎么忍住把这键盘歌写这么简单的\n不是你们怎么忍住把这键盘歌写这么简单的\n\n应该是 Phigros 第一个写满三分钟的,虽然后面抄了很多重复配置,但无伤大雅(\n个人定数 16.6,其实就两段 5k 键盘难,看时间长多给了 0.1\n所以啊\n\n愤怒也好喜悦也好悲伤也好把一切都倾注进去\n怒りも喜びも哀しさも、全部ぶちこめ。\n\n-- 6.30 更新,修了一个特效的问题,改了一个很蹭的配置和一个很丑的排键",
"state": 0,
"duration": 201,
"mission_id": 1726375,
"rights": {
"bp": 0,
"elec": 0,
"download": 0,
"movie": 0,
"pay": 0,
"hd5": 0,
"no_reprint": 1,
"autoplay": 1,
"ugc_pay": 0,
"is_cooperation": 0,
"ugc_pay_preview": 0,
"no_background": 0,
"arc_pay": 0,
"pay_free_watch": 0
},
"owner": {
"mid": 341532844,
"name": "西宮缄",
"face": "https://i1.hdslb.com/bfs/face/1387108d9337c04c27ce2d8d75679e40540d4c14.jpg"
},
"stat": {
"aid": 1155789590,
"view": 39479,
"danmaku": 303,
"reply": 169,
"favorite": 1650,
"coin": 473,
"share": 653,
"now_rank": 0,
"his_rank": 0,
"like": 5843,
"dislike": 0,
"vt": 0,
"vv": 39479
},
"dynamic": "打这个比溜冰还爽",
"cid": 1600971084,
"dimension": {
"width": 2000,
"height": 1500,
"rotate": 0
},
"season_id": 3395535,
"short_link_v2": "https://b23.tv/BV1iZ421g7E8",
"first_frame": "http://i1.hdslb.com/bfs/storyff/n240630sa3chl8idnpz8d31t6yaczagn_firsti.jpg",
"pub_location": "天津",
"cover43": "",
"bvid": "BV1iZ421g7E8",
"season_type": 0,
"is_ogv": false,
"ogv_info": null,
"rcmd_reason": "",
"enable_vt": 0,
"ai_rcmd": null
}
]
}
}
```
</details>
### 获取分区近期投稿列表
> https://api.bilibili.com/x/web-interface/newlist
*请求方式: GET*
注: 该接口在 Web 端实际情况中被请求, 但似乎未在页面中显示, 作用尚不清楚
**URL参数:**
| 参数名 | 类型 | 内容 | 必要性 | 备注 |
| ------ | ---- | ---------- | ------ | ----------------- |
| ps | num | 视频数 | 非必要 | 默认为14, 留空为5 |
| pn | num | 页码 | 非必要 | 默认为1 |
| rid | num | 目标分区id | 非必要 | 参见[视频分区一览](../video/video_zone.md) |
| type | num | 类型? | 非必要 | 默认为0 |
**JSON回复:**
与[获取分区最新视频列表](#获取分区最新视频列表)相同, 略
**示例:**
与[获取分区最新视频列表](#获取分区最新视频列表)相似, 略
### 获取分区近期投稿列表 (带排序)
> https://api.bilibili.com/x/web-interface/newlist_rank
*请求方式: GET*
**URL参数:**
| 参数名 | 类型 | 内容 | 必要性 | 备注 |
| ----------- | ---- | --------- | ------ | ------- |
| main_ver | str | 主页版本 | 非必要 | 默认为 `v3` |
| search_type | str | 搜索类型 | 必要 | 默认为 `video` |
| view_type | str | 查看类型? | 必要 | 默认为 `hot_rank` |
| copy_right | num | 版权? | 非必要 | 默认为 `-1` |
| new_web_tag | num | 标签? | 非必要 | 默认为 `1` |
| order | str | 排序方式 | 非必要 | click: 按播放排序(默认)<br />scores: 按评论数排序<br />stow: 按收藏排序<br />coin: 按硬币数排序<br />dm: 按弹幕数排序|
| cate_id | num | 分区id | 必要 | 留空会导致响应中`data`中`result`为`null`, 参见[视频分区一览](../video/video_zone.md) |
| page | num | 页码 | 非必要 | 默认以 `1` 开始 |
| pagesize | num | 视频数 | 必要 | 默认为 `30`, 留空会导致 -500 |
| time_from | num | 起始时间 | 必要 | yyyyMMdd, 默认为 `time_to` - 7 |
| time_to | num | 结束时间 | 必要 | yyyyMMdd, 默认为当前时间(大于起始时间) |
**JSON回复:**
根对象:
| 字段 | 类型 | 内容 | 备注 |
| ------- | ---- | -------- | ----- |
| code | num | 返回值 | 0成功<br />-500: 未传pagesize<br />-10: 未传其余必要参数 |
| message | str | 错误信息 | 无为0 |
| ttl | num | 1 | |
| data | obj | 信息本体 | 错误为null |
`data`对象:
| 字段 | 类型 | 内容 | 备注 |
| ---------------- | ----- | ------------------ | ----- |
| exp_list | null | | 作用尚不明确 |
| show_module_list | array | 显示模块列表? | |
| result | array | 结果本体 | 失败时为null |
| show_column | num | 0 | 作用尚不明确 |
| rqt_type | str | search | 作用尚不明确 |
| numPages | num | 页码 | 失败时为0 |
| numResults | num | 视频数 | 失败时为0 |
| crr_query | str | 空 | 作用尚不明确 |
| pagesize | num | 视频数 | |
| suggest_keyword | num | 空 | 作用尚不明确 |
| egg_info | null | | 作用尚不明确 |
| cache | num | 0 | 作用尚不明确 |
| exp_bits | num | 1 | 作用尚不明确 |
| exp_str | str | 空 | 作用尚不明确 |
| seid | str | 一串字符串中的数字 | 作用尚不明确 |
| msg | str | 结果信息 | 成功时为`success`, 反之为`as error.` |
| egg_hit | num | 0 | 作用尚不明确 |
| page | num | 页码 | |
`data`中的`show_module_list`数组:
| 项 | 类型 | 内容 | 备注 |
| ---- | ---- | ------------- | ---- |
| 0 | str | tips | |
| 1 | str | brand_ad | |
| 2 | str | esports | |
| 3 | str | activity | |
| 4 | str | web_game | |
| 5 | str | card | |
| 6 | str | media_bangumi | |
| 7 | str | media_ft | |
| 8 | str | bili_user | |
| 9 | str | user | |
| 10 | str | star | |
| 11 | str | video | |
`data`中的`result`数组中的对象:
| 字段 | 类型 | 内容 | 备注 |
| -------------- | ---- | -------------- | ----- |
| pubdate | str | 发布时间 | 格式为 `yyyy-MM-dd HH:mm:ss` |
| pic | str | 封面图 | |
| tag | str | 标签 | 用 `,` 分隔 |
| duration | num | 时长 | 单位为秒 |
| id | num | aid | |
| rank_score | num | 排序分数? | |
| badgepay | bool | 是否有角标? | |
| senddate | num | 发送时间? | UNIX 秒级时间戳 |
| author | str | UP主名 | |
| review | num | 评论数 | |
| mid | num | UP主mid | |
| is_union_video | num | 是否为联合投稿 | |
| rank_index | num | 排序索引号 | |
| type | str | 类型 | video: 视频 |
| arcrank | str | 0 | 作用尚不明确 |
| play | str | 播放数 | |
| rank_offset | num | 排序偏移? | 与 `rank_index` 相同 |
| description | str | 简介 | |
| video_review | num | 弹幕数? | |
| is_pay | num | 是否付费? | 0: 免费<br />1: 付费 |
| favorites | num | 收藏数 | |
| arcurl | str | 视频播放页URL | |
| bvid | str | bvid | |
| title | str | 标题 | |
| vt | num | 0 | 作用尚不明确 |
| enable_vt | num | 0 | 作用尚不明确 |
| vt_display | str | 空 | 作用尚不明确 |
**示例:**
获取`tid=231(科技->计算机技术)`分区近期投稿列表, 按播放数排序, 页码为1, 视频数为2, 时间一周
```shell
curl -G 'https://api.bilibili.com/x/web-interface/newlist_rank' \
--data-urlencode 'search_type=video' \
--data-urlencode 'view_type=hot_rank' \
--data-urlencode 'order=click' \
--data-urlencode 'cate_id=231' \
--data-urlencode 'page=1' \
--data-urlencode 'pagesize=2' \
--data-urlencode 'time_from=20240716' \
--data-urlencode 'time_to=20240723'
```
<details>
<summary>查看响应示例:</summary>
```json
{
"code": 0,
"message": "0",
"ttl": 1,
"data": {
"exp_list": null,
"show_module_list": [
"tips",
"brand_ad",
"esports",
"activity",
"web_game",
"card",
"media_bangumi",
"media_ft",
"bili_user",
"user",
"star",
"video"
],
"result": [
{
"pubdate": "2024-07-19 15:27:23",
"pic": "//i0.hdslb.com/bfs/archive/a6c2a8669e623333eee4bd8316b4e7b01716b7f2.jpg",
"tag": "微软,Microsoft",
"duration": 14,
"id": 1406270001,
"rank_score": 237205,
"badgepay": false,
"senddate": 1721410429,
"author": "柚子木字幕组",
"review": 928,
"mid": 221648,
"is_union_video": 0,
"rank_index": 1,
"type": "video",
"arcrank": "0",
"play": "237205",
"rank_offset": 1,
"description": "X",
"video_review": 42,
"is_pay": 0,
"favorites": 618,
"arcurl": "http://www.bilibili.com/video/av1406270001",
"bvid": "BV1gr421M7rE",
"title": "突发:微软服务中断正在影响全球用户",
"vt": 0,
"enable_vt": 0,
"vt_display": ""
},
{
"pubdate": "2024-07-17 22:12:47",
"pic": "//i0.hdslb.com/bfs/archive/1b02bc3806369f8c051a84e1ffef11b22695e659.jpg",
"tag": "演讲,大学,编程,英伟达,人工智能,TED,AI,黄仁勋",
"duration": 1908,
"id": 1556206286,
"rank_score": 52653,
"badgepay": false,
"senddate": 1721225567,
"author": "YouTube精选字幕组",
"review": 147,
"mid": 487511093,
"is_union_video": 0,
"rank_index": 2,
"type": "video",
"arcrank": "0",
"play": "52648",
"rank_offset": 2,
"description": "New SciTech\n上月加州理工学院毕业典礼上刚刚带领英伟达达成世界第一市值的CEO黄仁勋到场分享对当下AI革命趋势的见解、带领英伟达转型成AI公司的历程、以及自己在职场这么多年的人生感悟。\n\n全程没有上位者那种空洞无意义的说教都是真实的发展故事和对未来世界的看法。如果你的工作生活中有涉及到AI技术的可能那么这期演讲将会非常有意义。",
"video_review": 16,
"is_pay": 0,
"favorites": 2152,
"arcurl": "http://www.bilibili.com/video/av1556206286",
"bvid": "BV1C1421b7dD",
"title": "“这个时代要跑,不要走”黄仁勋加州理工毕业演讲完整版",
"vt": 0,
"enable_vt": 0,
"vt_display": ""
}
],
"show_column": 0,
"rqt_type": "search",
"numPages": 404,
"numResults": 808,
"crr_query": "",
"pagesize": 2,
"suggest_keyword": "",
"egg_info": null,
"cache": 0,
"exp_bits": 1,
"exp_str": "",
"seid": "6717218533109517809",
"msg": "success",
"egg_hit": 0,
"page": 1
}
}
```
</details>