dsh-plugin-bili-timeslot 1.5.0 → 1.5.2

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 CHANGED
@@ -76,19 +76,42 @@ node scripts/mapi-timeslot.mjs clear --accounts=4620390
76
76
  node scripts/mapi-timeslot.mjs set --accounts=1234567 --name=六月 --days=1
77
77
  ```
78
78
 
79
+ ### 授权范围怎么选(关键)
80
+
81
+ | 选项 | 结果 |
82
+ |---|---|
83
+ | **代理商平台**(如「江西傲然-带货起飞 1534412」) | ✅ 账户在这里,推荐 |
84
+ | **当前用户全量账户** | ✅ 简单直接 |
85
+ | 品牌银行(客户体系) | ❌ 只能拿到客户主体,账户数为 0 |
86
+
87
+ > 实例:星河授权后覆盖「客户主体 477151 + 代理商平台 833883」= 43 个账户;
88
+ > 六月(= 江西傲然)选「代理商平台 1534412」= 259 个账户。
89
+
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
+
79
97
  要点:
80
98
  - 每个令牌**独立续期**(各自 refresh_token,互不影响)
81
99
  - 首次接触某账户会探测所有令牌(约 1 次请求),结果缓存在 `accountMap`
82
100
  - 探测不到时返回「没有令牌能访问该账户」,说明该账户未授权
83
- ### 2. 保存令牌(手动,管理员用)
101
+ ### 2. 令牌存储
84
102
 
85
- ```powershell
86
- node scripts/mapi-timeslot.mjs auth --token=access_token_xxx --refresh=refresh_token_xxx `
87
- --client-id=xxx --client-secret=xxx
88
- node scripts/mapi-timeslot.mjs status # 看状态/到期
89
103
  ```
104
+ ~/.dsh/bili-timeslot/mapi-tokens.json
105
+ {
106
+ "order": ["星河", "六月", "真龙"],
107
+ "tokens": { "星河": { access_token, refresh_token, expires_at, subjects: [...], client_id, client_secret }, ... },
108
+ "accountMap": { "4620390": "星河" } // 账户 → 令牌(探测后缓存)
109
+ }
110
+ ```
111
+
112
+ access_token 24h、refresh_token 30d;旧版单令牌文件 `mapi.json` 会自动迁移成令牌「默认」。
90
113
 
91
- 令牌存 `~/.dsh/bili-timeslot/mapi.json`:access_token 24h、refresh_token 30d。
114
+ 查看:`node scripts/mapi-timeslot.mjs status`
92
115
 
93
116
  ### 3. 自动续期(已内置)
94
117
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-plugin-bili-timeslot",
3
- "version": "1.5.0",
3
+ "version": "1.5.2",
4
4
  "description": "B站三连推广投放时段批量设置:1.0 拉空(清空时段=不投放)、2.0 拉时段(按星期/小时,SKU 驱动)。其他推广人装完即可用 /timeslot 命令。",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -27,12 +27,26 @@ const names = only ? [only] : tokenNames();
27
27
 
28
28
  async function listFor(name) {
29
29
  const map = new Map();
30
- for (let page = 1; page <= 100; page++) {
31
- const r = await api(name, `/oauth2/advertisers?page=${page}&size=100`);
32
- const recs = (r.body && r.body.data && (r.body.data.records || r.body.data.list)) || [];
33
- for (const x of recs) map.set(String(x.account_id), { id: String(x.account_id), name: x.account_name || "" });
34
- const total = (r.body && r.body.data && r.body.data.total) || 0;
35
- if (recs.length < 100 || (total && map.size >= total)) break;
30
+ const store = loadStore();
31
+ const subjects = (store.tokens[name] && store.tokens[name].subjects) || [];
32
+
33
+ // 1) 先试不带主体(部分令牌直连即可全量)
34
+ const pull = async (query) => {
35
+ for (let page = 1; page <= 50; page++) {
36
+ const r = await api(name, `/oauth2/advertisers?${query}page=${page}&size=100`);
37
+ const recs = (r.body && r.body.data && (r.body.data.records || r.body.data.list)) || [];
38
+ for (const x of recs) map.set(String(x.account_id), { id: String(x.account_id), name: x.account_name || "" });
39
+ const total = (r.body && r.body.data && r.body.data.total) || 0;
40
+ if (recs.length < 100 || (total && map.size >= total)) break;
41
+ }
42
+ };
43
+
44
+ if (subjects.length) {
45
+ for (const s of subjects) {
46
+ await pull(`subject_type=${s.type}&subject_id=${s.id}&`);
47
+ }
48
+ } else {
49
+ await pull("");
36
50
  }
37
51
  return [...map.values()];
38
52
  }