dsh-shlr-bilitoolkit 0.1.22 → 0.1.24
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/README.md +1 -1
- package/dist/apis/dynamic.d.ts +2 -2
- package/dist/apis/dynamic.js +52 -26
- package/dist/endpoints.d.ts +2 -0
- package/dist/endpoints.js +2 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -121,7 +121,7 @@ dsh plugin --profile <name> add github:your-name/dsh-shlr-bilitoolkit#<ref>
|
|
|
121
121
|
## 与原 Python 版的差异 / 已知限制
|
|
122
122
|
|
|
123
123
|
- **写接口为表单编码**:原 Python 用 `requests` 的 `data=` 默认表单;本包的 `client.post` 默认把对象编码为 `application/x-www-form-urlencoded`,仅动态点赞等少数接口显式走 JSON(`jsonBody=true`)。
|
|
124
|
-
- **图文动态**:`bili_dynamic_publish` 支持「文字 +
|
|
124
|
+
- **图文动态**:`bili_dynamic_publish` 支持「文字 + 本地图片」:先上传动态图床(`x/dynamic/feed/draw/upload_bfs`,`biz=draw` + `category=daily`)拿到 `image_url` / 宽高 / `img_size`,再以新版 `x/dynamic/feed/create/dyn` 创建(JSON,外层 `dyn_req` + `content.contents` + `pics`)。已在真实账号验证通过(发布成功、详情图片可访问)。
|
|
125
125
|
- **下载 / ffmpeg**:`src/apis/download.ts` 提供 `downloadUrl` / `mergeWithFfmpeg`,为纯工具函数,未接入 dsh 工具(下载行为在 dsh 里通常不合适)。
|
|
126
126
|
|
|
127
127
|
## 风控说明
|
package/dist/apis/dynamic.d.ts
CHANGED
|
@@ -17,8 +17,8 @@ export declare class DynamicAPI {
|
|
|
17
17
|
publish(text: string, atUids?: number[], ctrl?: any[], closeComment?: boolean): Promise<string>;
|
|
18
18
|
/** 上传单张图片到 B 站动态图床,返回 pictures 需要的一段信息。 */
|
|
19
19
|
private uploadImage;
|
|
20
|
-
/** 发布图文动态(文字 +
|
|
21
|
-
publishWithImages(text: string, images: Array<string | Buffer>,
|
|
20
|
+
/** 发布图文动态(文字 + 若干张图片),走新版 JSON 创建接口。图片可传本地路径或 Buffer。 */
|
|
21
|
+
publishWithImages(text: string, images: Array<string | Buffer>, _opts?: {
|
|
22
22
|
atUids?: number[];
|
|
23
23
|
closeComment?: boolean;
|
|
24
24
|
}): Promise<string>;
|
package/dist/apis/dynamic.js
CHANGED
|
@@ -12,6 +12,16 @@ import { Dynamic } from "../models.js";
|
|
|
12
12
|
import { guessImageType } from "../util.js";
|
|
13
13
|
const FEATURES = "itemOpusStyle";
|
|
14
14
|
const REFERER = "https://t.bilibili.com/";
|
|
15
|
+
// 动态详情里的 type 是字符串枚举,删除接口要的是数字码
|
|
16
|
+
const DYN_TYPE_CODE = {
|
|
17
|
+
DYNAMIC_TYPE_NONE: 0,
|
|
18
|
+
DYNAMIC_TYPE_FORWARD: 1,
|
|
19
|
+
DYNAMIC_TYPE_DRAW: 2,
|
|
20
|
+
DYNAMIC_TYPE_WORD: 4,
|
|
21
|
+
DYNAMIC_TYPE_AV: 8,
|
|
22
|
+
DYNAMIC_TYPE_ARTICLE: 64,
|
|
23
|
+
DYNAMIC_TYPE_MUSIC: 256,
|
|
24
|
+
};
|
|
15
25
|
export class DynamicAPI {
|
|
16
26
|
client;
|
|
17
27
|
constructor(client) {
|
|
@@ -124,6 +134,7 @@ export class DynamicAPI {
|
|
|
124
134
|
// 动态图床上传是 multipart,用 form-data 包(Node 下 axios 靠它正确序列化二进制)
|
|
125
135
|
const form = new FormData();
|
|
126
136
|
form.append("biz", "draw");
|
|
137
|
+
form.append("category", "daily");
|
|
127
138
|
form.append("csrf", this.client.csrf);
|
|
128
139
|
form.append("file_up", bytes, { filename: name, contentType: guessImageType(name) });
|
|
129
140
|
const resp = await this.client.http.post(endpoints.DYNAMIC_IMAGE_UPLOAD, form, {
|
|
@@ -146,8 +157,8 @@ export class DynamicAPI {
|
|
|
146
157
|
img_size: Number(meta.img_size ?? Math.round(bytes.length / 1024)),
|
|
147
158
|
};
|
|
148
159
|
}
|
|
149
|
-
/** 发布图文动态(文字 +
|
|
150
|
-
async publishWithImages(text, images,
|
|
160
|
+
/** 发布图文动态(文字 + 若干张图片),走新版 JSON 创建接口。图片可传本地路径或 Buffer。 */
|
|
161
|
+
async publishWithImages(text, images, _opts = {}) {
|
|
151
162
|
text = (text || "").trim();
|
|
152
163
|
const pics = [];
|
|
153
164
|
for (const img of images ?? []) {
|
|
@@ -155,23 +166,18 @@ export class DynamicAPI {
|
|
|
155
166
|
}
|
|
156
167
|
if (!text && !pics.length)
|
|
157
168
|
throw new Error("动态内容不能为空");
|
|
158
|
-
|
|
159
|
-
const
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
ctrl: JSON.stringify([]),
|
|
169
|
-
csrf: this.client.csrf,
|
|
170
|
-
csrf_token: this.client.csrf,
|
|
169
|
+
// 新版创建接口(对齐网页端抓包):JSON body,外层包 dyn_req
|
|
170
|
+
const contents = text ? [{ raw_text: text, type: 1, biz_id: "" }] : [];
|
|
171
|
+
const body = {
|
|
172
|
+
dyn_req: {
|
|
173
|
+
content: { contents },
|
|
174
|
+
pics,
|
|
175
|
+
scene: 1,
|
|
176
|
+
option: {},
|
|
177
|
+
draft_id: 0,
|
|
178
|
+
},
|
|
171
179
|
};
|
|
172
|
-
|
|
173
|
-
form["pictures"] = JSON.stringify(pics);
|
|
174
|
-
const payload = await this.client.post(endpoints.DYNAMIC_CREATE, form, { Referer: REFERER });
|
|
180
|
+
const payload = await this.client.post(endpoints.DYNAMIC_CREATE_V2, body, { Referer: REFERER }, false, { csrf: this.client.csrf }, true);
|
|
175
181
|
return DynamicAPI.dynamicId(payload);
|
|
176
182
|
}
|
|
177
183
|
async repost(dynamicId, text = "") {
|
|
@@ -195,18 +201,38 @@ export class DynamicAPI {
|
|
|
195
201
|
}, false, { csrf: this.client.csrf }, true);
|
|
196
202
|
}
|
|
197
203
|
async delete(dynamicId) {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
+
// 动态 id 常超出 JS 安全整数范围(>2^53),必须全程按字符串传递,不能过 Number
|
|
205
|
+
const id = String(dynamicId);
|
|
206
|
+
// 删除接口需要 dyn_type(数字码)+ rid_str,都要先从动态详情取
|
|
207
|
+
let rawType;
|
|
208
|
+
let ridStr = "0";
|
|
209
|
+
try {
|
|
210
|
+
const resp = await this.client.http.get(`${endpoints.DYNAMIC_DETAIL}?id=${encodeURIComponent(id)}`, { headers: { Referer: REFERER } });
|
|
211
|
+
const item = resp?.data?.data?.item ?? {};
|
|
212
|
+
rawType = item?.type;
|
|
213
|
+
ridStr = String(item?.basic?.rid_str ?? item?.basic?.rid ?? "0");
|
|
214
|
+
}
|
|
215
|
+
catch {
|
|
216
|
+
// 详情取不到:rid_str 用默认值,类型仍必须能确定
|
|
217
|
+
}
|
|
218
|
+
const dynType = typeof rawType === "number" ? rawType : DYN_TYPE_CODE[String(rawType)];
|
|
219
|
+
if (dynType == null) {
|
|
220
|
+
throw new BiliApiError(`无法确定该动态的类型码(原始 type=${JSON.stringify(rawType)}),暂不支持删除`);
|
|
221
|
+
}
|
|
222
|
+
await this.client.post(endpoints.DYNAMIC_DELETE_V2, { dyn_id_str: id, dyn_type: dynType, rid_str: ridStr }, { Referer: REFERER }, false, { platform: "web", csrf: this.client.csrf }, true);
|
|
204
223
|
}
|
|
205
224
|
static dynamicId(payload) {
|
|
206
225
|
const data = payload?.data ?? {};
|
|
207
|
-
const
|
|
226
|
+
const req = data.dyn_req ?? {};
|
|
227
|
+
const value = data.dynamic_id_str ??
|
|
228
|
+
data.dynamic_id ??
|
|
229
|
+
data.dyn_id_str ??
|
|
230
|
+
data.dyn_id ??
|
|
231
|
+
req.dyn_id_str ??
|
|
232
|
+
req.dyn_id ??
|
|
233
|
+
data.id;
|
|
208
234
|
if (!value) {
|
|
209
|
-
throw new BiliApiError("动态接口未返回 dynamic_id,可能被风控拦截");
|
|
235
|
+
throw new BiliApiError("动态接口未返回 dynamic_id,可能被风控拦截", payload?.code, data);
|
|
210
236
|
}
|
|
211
237
|
return String(value);
|
|
212
238
|
}
|
package/dist/endpoints.d.ts
CHANGED
|
@@ -44,6 +44,8 @@ export declare const DYNAMIC_FEED_ALL = "https://api.bilibili.com/x/polymer/web-
|
|
|
44
44
|
export declare const DYNAMIC_FEED_SPACE = "https://api.bilibili.com/x/polymer/web-dynamic/v1/feed/space";
|
|
45
45
|
export declare const DYNAMIC_DETAIL = "https://api.bilibili.com/x/polymer/web-dynamic/v1/detail";
|
|
46
46
|
export declare const DYNAMIC_CREATE = "https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/create";
|
|
47
|
+
export declare const DYNAMIC_CREATE_V2 = "https://api.bilibili.com/x/dynamic/feed/create/dyn";
|
|
48
|
+
export declare const DYNAMIC_DELETE_V2 = "https://api.bilibili.com/x/dynamic/feed/operate/remove";
|
|
47
49
|
export declare const DYNAMIC_REPUBLISH = "https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/republish";
|
|
48
50
|
export declare const DYNAMIC_DELETE = "https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/rm_dynamic";
|
|
49
51
|
export declare const DYNAMIC_THUMB = "https://api.bilibili.com/x/dynamic/feed/dyn/thumb";
|
package/dist/endpoints.js
CHANGED
|
@@ -56,6 +56,8 @@ export const DYNAMIC_FEED_ALL = `${API_BASE}/x/polymer/web-dynamic/v1/feed/all`;
|
|
|
56
56
|
export const DYNAMIC_FEED_SPACE = `${API_BASE}/x/polymer/web-dynamic/v1/feed/space`;
|
|
57
57
|
export const DYNAMIC_DETAIL = `${API_BASE}/x/polymer/web-dynamic/v1/detail`;
|
|
58
58
|
export const DYNAMIC_CREATE = `${VC_BASE}/dynamic_svr/v1/dynamic_svr/create`;
|
|
59
|
+
export const DYNAMIC_CREATE_V2 = `${API_BASE}/x/dynamic/feed/create/dyn`;
|
|
60
|
+
export const DYNAMIC_DELETE_V2 = `${API_BASE}/x/dynamic/feed/operate/remove`;
|
|
59
61
|
export const DYNAMIC_REPUBLISH = `${VC_BASE}/dynamic_svr/v1/dynamic_svr/republish`;
|
|
60
62
|
export const DYNAMIC_DELETE = `${VC_BASE}/dynamic_svr/v1/dynamic_svr/rm_dynamic`;
|
|
61
63
|
export const DYNAMIC_THUMB = `${API_BASE}/x/dynamic/feed/dyn/thumb`;
|