dsh-plugin-bili-timeslot 1.5.2 → 1.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/SKILL.md +85 -102
- package/package.json +1 -1
package/SKILL.md
CHANGED
|
@@ -1,141 +1,106 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: bili-timeslot
|
|
3
|
-
description: B站三连推广「投放时段」批量设置:走官方 MAPI 开放接口(1.0 单元批量操作 + 2.0
|
|
3
|
+
description: B站三连推广「投放时段」批量设置:走官方 MAPI 开放接口(1.0 单元批量操作 + 2.0 项目保存),无需浏览器;支持多代理商多令牌、SKU 检索账户、1.0 拉空、2.0 设时段,全部带回读校验。
|
|
4
4
|
whenToUse: 当用户说「拉空时段 / 拉时段 / 清空投放时段 / 把账户时段拉空 / 1.0 拉空 / 2.0 拉时段 / 批量设置投放时段」时使用。
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# B站三连推广 · 投放时段(MAPI 版)
|
|
8
8
|
|
|
9
|
-
>
|
|
10
|
-
> 速度:88 个单元 2 秒级(旧网页版逐单元要 105 秒)。
|
|
9
|
+
> 只用官方 MAPI 接口,不需要开浏览器。88 个单元约 2 秒(旧网页版逐单元要 105 秒)。
|
|
11
10
|
|
|
12
11
|
## 一、概念
|
|
13
12
|
|
|
14
13
|
| 版本 | 接口 | 能不能拉空 |
|
|
15
14
|
|---|---|---|
|
|
16
|
-
| **1.0 单元** | `
|
|
17
|
-
| **2.0 项目** | `promotion/
|
|
15
|
+
| **1.0 单元** | `cpc/v3/unit/list_units` + `cpc/v3/batch/update_unit` | ✅ 能(`launch_time` = 7 个空数组) |
|
|
16
|
+
| **2.0 项目** | `cpc/v4/promotion/list` + `get` + `save` | ❌ 不能(平台要求至少选一天) |
|
|
18
17
|
|
|
19
|
-
- `launch_time` 固定 7 个数组,顺序 =
|
|
18
|
+
- `launch_time` 固定 7 个数组,顺序 = 周一…周日,元素是小时字符串 `"0"`~`"23"`
|
|
20
19
|
- 拉空 = `[[],[],[],[],[],[],[]]`
|
|
21
20
|
- 周一全天 = `[["0"..."23"], [], [], [], [], [], []]`
|
|
22
21
|
|
|
23
|
-
##
|
|
22
|
+
## 二、令牌与授权
|
|
24
23
|
|
|
25
|
-
### 1.
|
|
24
|
+
### 1. 应用与 OAuth
|
|
26
25
|
|
|
27
26
|
```
|
|
28
27
|
授权链接:https://ad.bilibili.com/developer/developer-authorization?client_id={APP_ID}
|
|
29
28
|
换取令牌:POST https://cm.bilibili.com/takumi/api/open_api/oauth2/token
|
|
30
29
|
```
|
|
31
30
|
|
|
32
|
-
-
|
|
33
|
-
-
|
|
34
|
-
-
|
|
31
|
+
- 授权后浏览器跳 `redirect_uri?code=xxx`;code 10 分钟有效、只能用一次
|
|
32
|
+
- 换 token 时 `redirect_uri` 必须与授权时**逐字符一致**(差个斜杠报 227014)
|
|
33
|
+
- 应用凭据在 `scripts/mapi-app.json`(client_id / client_secret / redirect_uri)
|
|
35
34
|
|
|
36
|
-
###
|
|
37
|
-
|
|
38
|
-
推广人只需两步:
|
|
39
|
-
|
|
40
|
-
```
|
|
41
|
-
1. 打开授权链接(用他自己的广告后台账号):
|
|
42
|
-
https://ad.bilibili.com/developer/developer-authorization?client_id={APP_ID}
|
|
43
|
-
选「品牌银行(组织体系)」→ 点「授权」
|
|
44
|
-
|
|
45
|
-
2. 浏览器跳到 https://example.com/bilibili-callback?code=code_xxxx
|
|
46
|
-
复制整条地址,粘进插件:
|
|
47
|
-
/timeslot https://example.com/bilibili-callback?code=code_xxxx
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
插件会自动:抓 code → 从回调地址推导 `redirect_uri`(避免 227014)→ 用 `scripts/mapi-app.json` 里的 client_id/secret 换 token → 存本机 `~/.dsh/bili-timeslot/mapi.json`。
|
|
51
|
-
|
|
52
|
-
也可以只贴 `code_xxxx`。授权码 10 分钟内有效、只能用一次;失败会给明确原因(227014 回调不匹配 / 227016 过期)。
|
|
53
|
-
### 5. 多代理商(多令牌)
|
|
54
|
-
|
|
55
|
-
不同代理商是**独立登录账号**(如 星河 / 六月 / 真龙),各自授权一次,令牌库会保存多份,
|
|
56
|
-
执行时**按账户自动路由**到能访问它的令牌。
|
|
57
|
-
|
|
58
|
-
```
|
|
59
|
-
存储:~/.dsh/bili-timeslot/mapi-tokens.json
|
|
60
|
-
{ order:[...], tokens:{ 星河:{access_token,refresh_token,expires_at,subjects:[],...}, 六月:{...} },
|
|
61
|
-
accountMap:{ "4620390":"星河" } } // 账户→令牌 的探测缓存
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
```powershell
|
|
65
|
-
# 各代理商分别授权一次(回调地址各自粘)
|
|
66
|
-
node scripts/mapi-auth.mjs --url="<星河回调地址>" --name=星河
|
|
67
|
-
node scripts/mapi-auth.mjs --url="<六月回调地址>" --name=六月
|
|
68
|
-
node scripts/mapi-auth.mjs --url="<真龙回调地址>" --name=真龙
|
|
69
|
-
|
|
70
|
-
# 看所有令牌与覆盖主体
|
|
71
|
-
node scripts/mapi-timeslot.mjs status
|
|
72
|
-
node scripts/mapi-accounts.mjs # 汇总所有令牌的账户
|
|
73
|
-
|
|
74
|
-
# 执行时自动选令牌;也可 --name= 强制
|
|
75
|
-
node scripts/mapi-timeslot.mjs clear --accounts=4620390
|
|
76
|
-
node scripts/mapi-timeslot.mjs set --accounts=1234567 --name=六月 --days=1
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
### 授权范围怎么选(关键)
|
|
35
|
+
### 2. 授权范围怎么选(关键)
|
|
80
36
|
|
|
81
37
|
| 选项 | 结果 |
|
|
82
38
|
|---|---|
|
|
83
|
-
|
|
|
39
|
+
| **代理商平台** | ✅ 账户在代理商主体下(如「江西傲然-带货起飞 1534412」= 259 个账户) |
|
|
84
40
|
| **当前用户全量账户** | ✅ 简单直接 |
|
|
85
|
-
| 品牌银行(客户体系) |
|
|
41
|
+
| 品牌银行(客户体系) | ⚠️ 只能拿到客户主体,账户数可能为 0 |
|
|
86
42
|
|
|
87
|
-
>
|
|
43
|
+
> 实例:星河覆盖「客户主体 477151 + 代理商平台 833883」= 43 个账户;
|
|
88
44
|
> 六月(= 江西傲然)选「代理商平台 1534412」= 259 个账户。
|
|
89
45
|
|
|
90
|
-
###
|
|
91
|
-
|
|
92
|
-
1. **一个登录账号 = 一个令牌**。切代理商必须先到 `https://e.bilibili.com/site/account/select` 退出再登,否则授权出来的还是上一个主体。
|
|
93
|
-
2. 授权页顶部会显示「当前登录账号 / BID」,授权前先核对。
|
|
94
|
-
3. 拿到令牌后立刻用 `mapi-accounts.mjs --name=xxx` 验账户数,为 0 就是范围选错了。
|
|
95
|
-
4. 账户数 >100 的令牌**必须按主体分页**拉(`subject_type & subject_id`),否则只能拿到 100 个。
|
|
96
|
-
|
|
97
|
-
要点:
|
|
98
|
-
- 每个令牌**独立续期**(各自 refresh_token,互不影响)
|
|
99
|
-
- 首次接触某账户会探测所有令牌(约 1 次请求),结果缓存在 `accountMap`
|
|
100
|
-
- 探测不到时返回「没有令牌能访问该账户」,说明该账户未授权
|
|
101
|
-
### 2. 令牌存储
|
|
46
|
+
### 3. 令牌库(多代理商)
|
|
102
47
|
|
|
103
48
|
```
|
|
104
49
|
~/.dsh/bili-timeslot/mapi-tokens.json
|
|
105
50
|
{
|
|
106
|
-
"order": ["
|
|
107
|
-
"tokens": { "星河": { access_token, refresh_token, expires_at, subjects: [...], client_id, client_secret }
|
|
108
|
-
"accountMap": { "4620390": "
|
|
51
|
+
"order": ["默认", "六月", "真龙"],
|
|
52
|
+
"tokens": { "星河": { access_token, refresh_token, expires_at, subjects: [...], client_id, client_secret } },
|
|
53
|
+
"accountMap": { "4620390": "默认" } // 账户 → 令牌(探测后缓存)
|
|
109
54
|
}
|
|
110
55
|
```
|
|
111
56
|
|
|
112
|
-
access_token 24h、refresh_token 30d
|
|
57
|
+
- access_token 24h、refresh_token 30d
|
|
58
|
+
- 旧版单文件 `mapi.json` 会自动迁移成令牌「默认」
|
|
59
|
+
- 一个令牌只覆盖**授权时那个账号有权限的账户**,不同代理商互不可见
|
|
60
|
+
|
|
61
|
+
### 4. 一键授权(推广人用,30 秒)
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
1. 用自己的广告后台账号打开:
|
|
65
|
+
https://ad.bilibili.com/developer/developer-authorization?client_id={APP_ID}
|
|
66
|
+
选「代理商平台」或「当前用户全量账户」→ 点「授权」
|
|
67
|
+
|
|
68
|
+
2. 浏览器跳到 https://example.com/bilibili-callback?code=code_xxxx
|
|
69
|
+
复制整条地址,粘进插件(--name 区分代理商):
|
|
70
|
+
node scripts/mapi-auth.mjs --url="<回调地址>" --name=六月
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
向导会自动:抓 code → 从回调地址推导 `redirect_uri`(避免 227014)→ 换 token → 写入令牌库 → 拉取覆盖主体。
|
|
113
74
|
|
|
114
|
-
|
|
75
|
+
### 5. 授权时的坑
|
|
115
76
|
|
|
116
|
-
|
|
77
|
+
1. **一个登录账号 = 一个令牌**。切代理商先到 `https://e.bilibili.com/site/account/select` 退出再登,否则授权出来还是上一个主体。
|
|
78
|
+
2. 授权页顶部显示「当前登录账号 / BID」,授权前先核对。
|
|
79
|
+
3. 授权完立刻验账户数:`node scripts/mapi-accounts.mjs --name=xxx`,为 0 就是范围选错。
|
|
80
|
+
4. 账户数 >100 的令牌**必须按主体分页**拉(`subject_type & subject_id`),否则只拿到 100 个。
|
|
81
|
+
|
|
82
|
+
### 6. 自动续期
|
|
117
83
|
|
|
118
84
|
- 距到期 **10 分钟内**自动用 refresh_token 换新并写回
|
|
119
85
|
- 接口返回 401 时强制刷新后重试一次
|
|
120
|
-
- 每次续期把 refresh_token 的 30
|
|
86
|
+
- 每次续期把 refresh_token 的 30 天重置 → 每月用一次就不会过期
|
|
121
87
|
|
|
122
88
|
## 三、接口清单
|
|
123
89
|
|
|
124
90
|
```
|
|
125
|
-
#
|
|
126
|
-
GET /open_api/oauth2/
|
|
127
|
-
|
|
91
|
+
# 授权主体 / 账户
|
|
92
|
+
GET /open_api/oauth2/subjects → 主体列表
|
|
93
|
+
GET /open_api/oauth2/advertisers?subject_type=&subject_id=&page=&size=100
|
|
94
|
+
→ data.records[]:account_id / account_name(>100 需按主体分页)
|
|
128
95
|
|
|
129
|
-
# 1.0
|
|
96
|
+
# 1.0 单元
|
|
130
97
|
GET /open_api/cpc/v3/unit/list_units?account_id=&page=&size=100
|
|
131
98
|
→ result.data[]:unit_id / unit_name / unit_status / launch_time
|
|
132
|
-
|
|
133
|
-
# 1.0 批量改时段(≤100 个/次,异步)
|
|
134
99
|
POST /open_api/cpc/v3/batch/update_unit
|
|
135
100
|
{ account_id, operation_type: 8,
|
|
136
|
-
operations: [{ unit_ids: [
|
|
101
|
+
operations: [{ unit_ids: [...≤100], launch_time: [[小时]×7] }] }
|
|
137
102
|
|
|
138
|
-
# 2.0
|
|
103
|
+
# 2.0 项目
|
|
139
104
|
GET /open_api/cpc/v4/promotion/list?account_id=&promotion_status=1,2&page=&size=100
|
|
140
105
|
GET /open_api/cpc/v4/promotion/get?account_id=&promotion_id=
|
|
141
106
|
POST /open_api/cpc/v4/promotion/save (全量回写!必须先 get 再改)
|
|
@@ -146,7 +111,13 @@ POST /open_api/cpc/v4/promotion/save (全量回写!必须先 get 再改
|
|
|
146
111
|
## 四、用法
|
|
147
112
|
|
|
148
113
|
```powershell
|
|
149
|
-
#
|
|
114
|
+
# 令牌
|
|
115
|
+
node scripts/mapi-timeslot.mjs status
|
|
116
|
+
node scripts/mapi-auth.mjs --url="<回调地址>" --name=六月
|
|
117
|
+
node scripts/mapi-accounts.mjs # 汇总所有令牌的账户
|
|
118
|
+
node scripts/mapi-accounts.mjs --sku=AI绘画 # 按 SKU 关键词
|
|
119
|
+
|
|
120
|
+
# 1.0 单元
|
|
150
121
|
node scripts/mapi-timeslot.mjs list --accounts=4564097
|
|
151
122
|
node scripts/mapi-timeslot.mjs clear --accounts=4564097,4620390
|
|
152
123
|
node scripts/mapi-timeslot.mjs set --accounts=4564097 --days=1,2,3,4,5 --hours=6-18
|
|
@@ -156,10 +127,8 @@ node scripts/mapi-timeslot.mjs set --accounts=4564097 --days=1,2,3,4,5,6,7 --h
|
|
|
156
127
|
node scripts/mapi-project.mjs list --accounts=4564097
|
|
157
128
|
node scripts/mapi-project.mjs set --accounts=4564097 --days=1 --hours=0-24
|
|
158
129
|
|
|
159
|
-
#
|
|
160
|
-
node scripts/mapi-
|
|
161
|
-
node scripts/mapi-accounts.mjs --sku=AI绘画 # 关键词命中(读 ../sku-accounts.json)
|
|
162
|
-
node scripts/mapi-accounts.mjs --sku=原画 --json # 只输出 id 数组
|
|
130
|
+
# 强制指定令牌
|
|
131
|
+
node scripts/mapi-timeslot.mjs set --accounts=1234567 --name=六月 --days=1
|
|
163
132
|
```
|
|
164
133
|
|
|
165
134
|
**默认行为**:没明确说版本 → 1.0 和 2.0 都处理;说了版本只做那个(`--version=1.0|2.0`)。
|
|
@@ -167,22 +136,21 @@ node scripts/mapi-accounts.mjs --sku=原画 --json # 只输出 id 数组
|
|
|
167
136
|
## 五、执行流程(SOP)
|
|
168
137
|
|
|
169
138
|
```
|
|
170
|
-
1. 解析账户:用户给账户ID优先;给 SKU 就用 mapi-accounts.mjs
|
|
139
|
+
1. 解析账户:用户给账户ID优先;给 SKU 就用 mapi-accounts.mjs 检索;再按账户路由令牌
|
|
171
140
|
2. 预演(--dry):确认账户数、单元数、目标时段
|
|
172
|
-
3. 执行:1.0
|
|
141
|
+
3. 执行:1.0 batch/update_unit;2.0 promotion/save(先 get 再 save)
|
|
173
142
|
4. 回读校验:重新 list/get,比对 launch_time
|
|
174
143
|
5. 报告:改了几个 / 未生效几个 / 耗时
|
|
175
144
|
```
|
|
176
145
|
|
|
177
146
|
## 六、已知坑
|
|
178
147
|
|
|
179
|
-
1. **单元列表会返回已删除单元**(unit_status=4,仍带旧 launch_time
|
|
180
|
-
只处理 `1有效/2暂停/5未开始/6预算超限/7不在时段`,排除 `3已结束/4已删除`,否则数量虚高。
|
|
148
|
+
1. **单元列表会返回已删除单元**(unit_status=4,仍带旧 launch_time)。只处理 `1有效/2暂停/5未开始/6预算超限/7不在时段`,排除 `3已结束/4已删除`,否则数量虚高。
|
|
181
149
|
2. **批量操作是异步的**:提交成功 ≠ 生效,必须隔 1~2 秒重新 list_units 回读校验。
|
|
182
150
|
3. **2.0 项目保存是全量覆盖**:不先 `get` 就 `save`,未传字段会被清空/恢复默认。
|
|
183
|
-
4. **MAPI 只返回新三连单元**(`adp_version=6
|
|
151
|
+
4. **MAPI 只返回新三连单元**(`adp_version=6`);老三连账户查不到,只能去网页后台处理。
|
|
184
152
|
5. **授权范围 = 可操作账户范围**:报 `227021 主体无权访问该账户` 就是该账户不在令牌授权内。
|
|
185
|
-
6.
|
|
153
|
+
6. 单账户禁止并发提交批量任务(分布式锁),并发会报「禁止同时生成多个批量任务」。
|
|
186
154
|
7. `redirect_uri` 必须与授权时逐字符一致,否则换 token 报 227014。
|
|
187
155
|
|
|
188
156
|
## 七、速度对比
|
|
@@ -190,7 +158,7 @@ node scripts/mapi-accounts.mjs --sku=原画 --json # 只输出 id 数组
|
|
|
190
158
|
| 方案 | 88 个单元 | 请求数 |
|
|
191
159
|
|---|---|---|
|
|
192
160
|
| 网页接口逐单元(旧) | ≈105s | 245 |
|
|
193
|
-
| 网页接口并发(旧) | ≈85s
|
|
161
|
+
| 网页接口并发(旧) | ≈85s(会限流假成功) | 245 |
|
|
194
162
|
| **MAPI 批量(本版)** | **2.1s** | **4** |
|
|
195
163
|
| MAPI 2.0 项目(7 个) | 3.5s | 21 |
|
|
196
164
|
|
|
@@ -198,16 +166,19 @@ node scripts/mapi-accounts.mjs --sku=原画 --json # 只输出 id 数组
|
|
|
198
166
|
|
|
199
167
|
| 文件 | 作用 |
|
|
200
168
|
|---|---|
|
|
201
|
-
| `scripts/mapi-
|
|
169
|
+
| `scripts/mapi-store.mjs` | 多令牌库:加载/保存/续期/按账户路由 |
|
|
170
|
+
| `scripts/mapi-auth.mjs` | 一键授权向导(贴回调地址 → 换 token → 存库) |
|
|
171
|
+
| `scripts/mapi-timeslot.mjs` | 1.0 单元:列表 / 拉空 / 设时段 |
|
|
202
172
|
| `scripts/mapi-project.mjs` | 2.0 项目:列表 / 设时段 |
|
|
203
|
-
| `scripts/mapi-accounts.mjs` |
|
|
173
|
+
| `scripts/mapi-accounts.mjs` | 授权账户汇总 + SKU 检索 |
|
|
174
|
+
| `scripts/mapi-app.json` | 应用凭据(仅 zip 分发版包含,npm 包排除) |
|
|
204
175
|
| `sku-accounts.json` | SKU → 账户关键词 → 客户 映射 |
|
|
205
176
|
|
|
206
177
|
### 历史(已弃用)
|
|
207
178
|
|
|
208
|
-
早期版本走网页接口(CDP
|
|
209
|
-
|
|
210
|
-
|
|
179
|
+
早期版本走网页接口(CDP 驱动浏览器,`report/list/unit` + `save_unit` 逐单元写)。
|
|
180
|
+
保留仅供排障:慢 40 倍,且并发会触发限流「接口返回成功但不生效」。
|
|
181
|
+
脚本:`bili-cdp.mjs`、`lib-cdp.mjs`、`bulk-timeslot.mjs`、`clear-slot-1.0-fast.mjs`、`set-timeslot-*.mjs`。
|
|
211
182
|
|
|
212
183
|
## 九、SKU → 客户 映射
|
|
213
184
|
|
|
@@ -222,3 +193,15 @@ node scripts/mapi-accounts.mjs --sku=原画 --json # 只输出 id 数组
|
|
|
222
193
|
> 「原画」只用「原画」匹配,不要用「绘画」,否则会误命中「AI绘画」账户。
|
|
223
194
|
|
|
224
195
|
账户来源优先级:① 用户给的账户ID > ② SKU 关键词检索 > ③ 查不到就问用户。
|
|
196
|
+
|
|
197
|
+
## 十、权限边界(多人协作)
|
|
198
|
+
|
|
199
|
+
| 对象 | 归属 | 别人能否看到 |
|
|
200
|
+
|---|---|---|
|
|
201
|
+
| 令牌库 `mapi-tokens.json` | 各自机器的用户目录 | ❌ 不能 |
|
|
202
|
+
| 许可证 `license.json` | 按机器指纹绑定 | ❌ 不能 |
|
|
203
|
+
| 签名私钥 `owner-private.pem` | 仅管理员机器 | ❌ 绝不分发 |
|
|
204
|
+
| `client_id/secret`(应用身份) | 随包分发 | ⚠️ 可见,但只能授权他们自己有权限的账户 |
|
|
205
|
+
|
|
206
|
+
- 每人授权拿到的是**自己的令牌**,只覆盖自己账号有权限的账户
|
|
207
|
+
- 别人拿你的包也无法操作你的账户(API 返回 `227021`)
|