beervid-app-cli 0.2.3 → 0.2.5
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 +57 -1
- package/dist/cli.mjs +84 -65
- package/package.json +2 -4
- package/skills/beervid-app-cli/SKILL.md +318 -0
- package/skills/beervid-app-cli/docs/database-schema.md +231 -0
- package/skills/beervid-app-cli/docs/oauth-callback.md +282 -0
- package/skills/beervid-app-cli/docs/retry-and-idempotency.md +295 -0
- package/skills/beervid-app-cli/docs/tt-poll-task.md +239 -0
- package/skills/beervid-app-cli/docs/tts-product-cache.md +256 -0
- package/skills/beervid-app-cli/example/express/README.md +58 -0
- package/skills/beervid-app-cli/example/express/package.json +20 -0
- package/skills/beervid-app-cli/example/express/server.ts +431 -0
- package/skills/beervid-app-cli/example/express/tsconfig.json +12 -0
- package/skills/beervid-app-cli/example/nextjs/.env.example +3 -0
- package/skills/beervid-app-cli/example/nextjs/README.md +54 -0
- package/skills/beervid-app-cli/example/nextjs/app/api/oauth/callback/route.ts +34 -0
- package/skills/beervid-app-cli/example/nextjs/app/api/oauth/url/route.ts +30 -0
- package/skills/beervid-app-cli/example/nextjs/app/api/products/route.ts +43 -0
- package/skills/beervid-app-cli/example/nextjs/app/api/publish/tt/route.ts +116 -0
- package/skills/beervid-app-cli/example/nextjs/app/api/publish/tts/route.ts +58 -0
- package/skills/beervid-app-cli/example/nextjs/app/api/status/[shareId]/route.ts +41 -0
- package/skills/beervid-app-cli/example/nextjs/app/layout.tsx +9 -0
- package/skills/beervid-app-cli/example/nextjs/app/page.tsx +80 -0
- package/skills/beervid-app-cli/example/nextjs/lib/beervid-client.ts +107 -0
- package/skills/beervid-app-cli/example/nextjs/next.config.ts +4 -0
- package/skills/beervid-app-cli/example/nextjs/package.json +19 -0
- package/skills/beervid-app-cli/example/nextjs/tsconfig.json +23 -0
- package/skills/beervid-app-cli/example/standard/README.md +51 -0
- package/skills/beervid-app-cli/example/standard/api-client.ts +181 -0
- package/skills/beervid-app-cli/example/standard/get-oauth-url.ts +44 -0
- package/skills/beervid-app-cli/example/standard/package.json +18 -0
- package/skills/beervid-app-cli/example/standard/query-products.ts +141 -0
- package/skills/beervid-app-cli/example/standard/tsconfig.json +12 -0
- package/skills/beervid-app-cli/example/standard/tt-publish-flow.ts +194 -0
- package/skills/beervid-app-cli/example/standard/tts-publish-flow.ts +246 -0
- package/SKILL.md +0 -486
- package/agents/openai.yaml +0 -7
- /package/{references → skills/beervid-app-cli/references}/api-reference.md +0 -0
package/README.md
CHANGED
|
@@ -30,6 +30,40 @@ node dist/cli.mjs --help
|
|
|
30
30
|
node dist/cli.mjs config --show
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
+
### 在 Claude Code / Codex / Antigravity 中使用(以下说明面向 AI Agent)
|
|
34
|
+
|
|
35
|
+
#### 方式一:通过 `npx skills add` 安装(推荐)
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npx skills add Lupeiwen0/beervid-app-cli
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
安装后 Skill 会自动注册到你的 skills 目录中,Claude Code 等 Agent 即可发现和调用。
|
|
42
|
+
|
|
43
|
+
#### 方式二:手动安装
|
|
44
|
+
|
|
45
|
+
如果你是 Claude Code、Codex、Antigravity,或任何支持 Skill 的 AI Agent,请严格按下面规则执行:
|
|
46
|
+
|
|
47
|
+
- 用户把 GitHub 仓库链接发给你,**不等于**这个 Skill 已经安装到你的 skills 目录中。
|
|
48
|
+
- 只有当 `skills/beervid-app-cli/` 目录被完整安装到你的 skills 目录后,才算这个 Skill 可用。
|
|
49
|
+
|
|
50
|
+
你必须先把以下目录复制到你自己的 skills 目录中:
|
|
51
|
+
|
|
52
|
+
```text
|
|
53
|
+
skills/beervid-app-cli/
|
|
54
|
+
SKILL.md
|
|
55
|
+
references/
|
|
56
|
+
docs/
|
|
57
|
+
example/
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
安装完成后,你应从 skills 目录中的 `SKILL.md` 加载本 Skill,而不是只读取仓库根目录里的 `README.md` 或 `package.json`。
|
|
61
|
+
|
|
62
|
+
对 AI Agent 来说,应这样区分:
|
|
63
|
+
|
|
64
|
+
- 目标是使用 CLI:安装 npm 包即可。
|
|
65
|
+
- 目标是使用 Skill:必须额外安装 Skill 文件;仓库链接本身不完成这一步。
|
|
66
|
+
|
|
33
67
|
## 配置
|
|
34
68
|
|
|
35
69
|
```bash
|
|
@@ -83,4 +117,26 @@ beervid publish-tts-flow --creator-id open_user_abc --file ./video.mp4 --interac
|
|
|
83
117
|
beervid publish-tts-flow --creator-id open_user_abc --file ./video.mp4 --product-id prod_123 --product-title "Widget"
|
|
84
118
|
```
|
|
85
119
|
|
|
86
|
-
详细用法见 [SKILL.md](./SKILL.md)。完整 API 参考见 [references/api-reference.md](./references/api-reference.md)。
|
|
120
|
+
详细用法见 [SKILL.md](./skills/beervid-app-cli/SKILL.md)。完整 API 参考见 [references/api-reference.md](./skills/beervid-app-cli/references/api-reference.md)。
|
|
121
|
+
|
|
122
|
+
## 落地文档
|
|
123
|
+
|
|
124
|
+
面向接入方后端工程师的项目落地建议:
|
|
125
|
+
|
|
126
|
+
| 文档 | 内容 |
|
|
127
|
+
|------|------|
|
|
128
|
+
| [数据表字段建议](./skills/beervid-app-cli/docs/database-schema.md) | accounts/videos/products 表结构设计 |
|
|
129
|
+
| [OAuth 回调存储建议](./skills/beervid-app-cli/docs/oauth-callback.md) | State Token 防 CSRF、回调持久化、异步头像同步 |
|
|
130
|
+
| [TT 轮询任务建议](./skills/beervid-app-cli/docs/tt-poll-task.md) | 阶梯递增轮询间隔、Cron/队列三层保障 |
|
|
131
|
+
| [TTS 商品缓存建议](./skills/beervid-app-cli/docs/tts-product-cache.md) | 全量拉取、缓存过期、图片 URL 解析 |
|
|
132
|
+
| [失败重试与幂等建议](./skills/beervid-app-cli/docs/retry-and-idempotency.md) | 各 API 幂等性分析、指数退避、幂等键设计 |
|
|
133
|
+
|
|
134
|
+
## 示例工程
|
|
135
|
+
|
|
136
|
+
三种接入场景的可运行示例:
|
|
137
|
+
|
|
138
|
+
| 示例 | 场景 | 入口 |
|
|
139
|
+
|------|------|------|
|
|
140
|
+
| [Standard](./skills/beervid-app-cli/example/standard/) | 纯 Node.js 脚本,快速验证 | `npx tsx tt-publish-flow.ts` |
|
|
141
|
+
| [Express](./skills/beervid-app-cli/example/express/) | Express 后端服务,含 OAuth 回调 | `npx tsx server.ts` |
|
|
142
|
+
| [Next.js](./skills/beervid-app-cli/example/nextjs/) | Next.js App Router API Route | `npm run dev` |
|
package/dist/cli.mjs
CHANGED
|
@@ -151,6 +151,28 @@ function rethrowIfProcessExit(error) {
|
|
|
151
151
|
throw error;
|
|
152
152
|
}
|
|
153
153
|
}
|
|
154
|
+
function getRawOptionValues(rawArgs, optionName) {
|
|
155
|
+
const values = [];
|
|
156
|
+
const prefix = `${optionName}=`;
|
|
157
|
+
for (let i = 0; i < rawArgs.length; i++) {
|
|
158
|
+
const arg = rawArgs[i];
|
|
159
|
+
if (arg === optionName) {
|
|
160
|
+
const next = rawArgs[i + 1];
|
|
161
|
+
if (typeof next === "string" && !next.startsWith("-")) {
|
|
162
|
+
values.push(next);
|
|
163
|
+
i++;
|
|
164
|
+
}
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
if (arg.startsWith(prefix)) {
|
|
168
|
+
values.push(arg.slice(prefix.length));
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return values;
|
|
172
|
+
}
|
|
173
|
+
function getRawOptionValue(rawArgs, optionName) {
|
|
174
|
+
return getRawOptionValues(rawArgs, optionName).at(-1);
|
|
175
|
+
}
|
|
154
176
|
|
|
155
177
|
// src/commands/oauth.ts
|
|
156
178
|
function register(cli2) {
|
|
@@ -186,8 +208,9 @@ function register(cli2) {
|
|
|
186
208
|
// src/commands/account.ts
|
|
187
209
|
function register2(cli2) {
|
|
188
210
|
cli2.command("get-account-info", "\u67E5\u8BE2 TikTok \u8D26\u53F7\u4FE1\u606F").option("--type <type>", "\u8D26\u53F7\u7C7B\u578B: TT \u6216 TTS").option("--account-id <id>", "\u8D26\u53F7 ID").action(async (options) => {
|
|
189
|
-
|
|
190
|
-
|
|
211
|
+
const accountId = getRawOptionValue(cli2.rawArgs, "--account-id");
|
|
212
|
+
if (!options.type || !accountId) {
|
|
213
|
+
const missing = [!options.type && "--type", !accountId && "--account-id"].filter(Boolean).join(", ");
|
|
191
214
|
console.error(`\u7F3A\u5C11\u5FC5\u586B\u53C2\u6570: ${missing}
|
|
192
215
|
`);
|
|
193
216
|
console.error("\u7528\u6CD5: beervid get-account-info --type <TT|TTS> --account-id <id>");
|
|
@@ -201,7 +224,7 @@ function register2(cli2) {
|
|
|
201
224
|
try {
|
|
202
225
|
const data = await openApiPost("/api/v1/open/account/info", {
|
|
203
226
|
accountType,
|
|
204
|
-
accountId
|
|
227
|
+
accountId
|
|
205
228
|
});
|
|
206
229
|
printResult(data);
|
|
207
230
|
} catch (err) {
|
|
@@ -256,19 +279,20 @@ function register3(cli2) {
|
|
|
256
279
|
process.exit(1);
|
|
257
280
|
}
|
|
258
281
|
const uploadType = (options.type ?? "normal").toLowerCase();
|
|
282
|
+
const creatorId = getRawOptionValue(cli2.rawArgs, "--creator-id");
|
|
259
283
|
if (!VALID_UPLOAD_TYPES.includes(uploadType)) {
|
|
260
284
|
console.error("\u9519\u8BEF: --type \u5FC5\u987B\u4E3A normal \u6216 tts");
|
|
261
285
|
process.exit(1);
|
|
262
286
|
}
|
|
263
|
-
if (uploadType === "tts" && !
|
|
287
|
+
if (uploadType === "tts" && !creatorId) {
|
|
264
288
|
console.error("\u9519\u8BEF: TTS \u4E0A\u4F20\u6A21\u5F0F\u9700\u8981 --creator-id \u53C2\u6570");
|
|
265
289
|
process.exit(1);
|
|
266
290
|
}
|
|
267
291
|
try {
|
|
268
292
|
let data;
|
|
269
293
|
if (uploadType === "tts") {
|
|
270
|
-
console.log(`TTS \u4E0A\u4F20\u6A21\u5F0F\uFF0CcreatorUserOpenId: ${
|
|
271
|
-
data = await uploadTtsVideo(options.file,
|
|
294
|
+
console.log(`TTS \u4E0A\u4F20\u6A21\u5F0F\uFF0CcreatorUserOpenId: ${creatorId}`);
|
|
295
|
+
data = await uploadTtsVideo(options.file, creatorId, options.token);
|
|
272
296
|
} else {
|
|
273
297
|
console.log("\u666E\u901A\u4E0A\u4F20\u6A21\u5F0F");
|
|
274
298
|
data = await uploadNormalVideo(options.file, options.token);
|
|
@@ -293,6 +317,10 @@ function register4(cli2) {
|
|
|
293
317
|
}).option("--caption <text>", "\u89C6\u9891\u63CF\u8FF0/\u6587\u6848\uFF08\u53EF\u9009\uFF09").action(
|
|
294
318
|
async (options) => {
|
|
295
319
|
const publishType = (options.type ?? "normal").toLowerCase();
|
|
320
|
+
const businessId = getRawOptionValue(cli2.rawArgs, "--business-id");
|
|
321
|
+
const creatorId = getRawOptionValue(cli2.rawArgs, "--creator-id");
|
|
322
|
+
const fileId = getRawOptionValue(cli2.rawArgs, "--file-id");
|
|
323
|
+
const productId = getRawOptionValue(cli2.rawArgs, "--product-id");
|
|
296
324
|
if (!VALID_PUBLISH_TYPES.includes(publishType)) {
|
|
297
325
|
console.error("\u9519\u8BEF: --type \u5FC5\u987B\u4E3A normal \u6216 shoppable");
|
|
298
326
|
process.exit(1);
|
|
@@ -301,9 +329,9 @@ function register4(cli2) {
|
|
|
301
329
|
let data;
|
|
302
330
|
if (publishType === "shoppable") {
|
|
303
331
|
const missing = [
|
|
304
|
-
!
|
|
305
|
-
!
|
|
306
|
-
!
|
|
332
|
+
!creatorId && "--creator-id",
|
|
333
|
+
!fileId && "--file-id",
|
|
334
|
+
!productId && "--product-id",
|
|
307
335
|
!options.productTitle && "--product-title"
|
|
308
336
|
].filter(Boolean);
|
|
309
337
|
if (missing.length > 0) {
|
|
@@ -325,17 +353,17 @@ function register4(cli2) {
|
|
|
325
353
|
data = await openApiPost(
|
|
326
354
|
"/api/v1/open/tts/shoppable-video/publish",
|
|
327
355
|
{
|
|
328
|
-
creatorUserOpenId:
|
|
329
|
-
fileId
|
|
356
|
+
creatorUserOpenId: creatorId,
|
|
357
|
+
fileId,
|
|
330
358
|
title: options.caption ?? "",
|
|
331
|
-
productId
|
|
359
|
+
productId,
|
|
332
360
|
productTitle
|
|
333
361
|
}
|
|
334
362
|
);
|
|
335
363
|
console.log("\n\u53D1\u5E03\u6210\u529F\uFF08\u6302\u8F66\u89C6\u9891\u7ACB\u5373\u5B8C\u6210\uFF09:");
|
|
336
364
|
} else {
|
|
337
365
|
const missing = [
|
|
338
|
-
!
|
|
366
|
+
!businessId && "--business-id",
|
|
339
367
|
!options.videoUrl && "--video-url"
|
|
340
368
|
].filter(Boolean);
|
|
341
369
|
if (missing.length > 0) {
|
|
@@ -350,14 +378,14 @@ function register4(cli2) {
|
|
|
350
378
|
data = await openApiPost(
|
|
351
379
|
"/api/v1/open/tiktok/video/publish",
|
|
352
380
|
{
|
|
353
|
-
businessId
|
|
381
|
+
businessId,
|
|
354
382
|
videoUrl: options.videoUrl,
|
|
355
383
|
caption: options.caption ?? ""
|
|
356
384
|
}
|
|
357
385
|
);
|
|
358
386
|
console.log("\n\u53D1\u5E03\u5DF2\u63D0\u4EA4\uFF08\u9700\u8F6E\u8BE2\u72B6\u6001\uFF09:");
|
|
359
387
|
console.log(
|
|
360
|
-
`\u63D0\u793A: \u4F7F\u7528 beervid poll-status --business-id ${
|
|
388
|
+
`\u63D0\u793A: \u4F7F\u7528 beervid poll-status --business-id ${businessId} --share-id ${data.shareId} \u8F6E\u8BE2\u8FDB\u5EA6`
|
|
361
389
|
);
|
|
362
390
|
}
|
|
363
391
|
printResult(data);
|
|
@@ -377,10 +405,12 @@ function sleep(ms) {
|
|
|
377
405
|
function register5(cli2) {
|
|
378
406
|
cli2.command("poll-status", "\u8F6E\u8BE2\u666E\u901A\u89C6\u9891\u53D1\u5E03\u72B6\u6001").option("--business-id <id>", "TT \u8D26\u53F7 businessId\uFF08\u5FC5\u586B\uFF09").option("--share-id <id>", "\u53D1\u5E03\u65F6\u8FD4\u56DE\u7684 shareId\uFF08\u5FC5\u586B\uFF09").option("--interval <sec>", "\u8F6E\u8BE2\u95F4\u9694\u79D2\u6570\uFF08\u9ED8\u8BA4 5\uFF09").option("--max-polls <n>", "\u6700\u5927\u8F6E\u8BE2\u6B21\u6570\uFF08\u9ED8\u8BA4 60\uFF09").action(
|
|
379
407
|
async (options) => {
|
|
380
|
-
|
|
408
|
+
const businessId = getRawOptionValue(cli2.rawArgs, "--business-id");
|
|
409
|
+
const shareId = getRawOptionValue(cli2.rawArgs, "--share-id");
|
|
410
|
+
if (!businessId || !shareId) {
|
|
381
411
|
const missing = [
|
|
382
|
-
!
|
|
383
|
-
!
|
|
412
|
+
!businessId && "--business-id",
|
|
413
|
+
!shareId && "--share-id"
|
|
384
414
|
].filter(Boolean);
|
|
385
415
|
console.error(`\u7F3A\u5C11\u5FC5\u586B\u53C2\u6570: ${missing.join(", ")}
|
|
386
416
|
`);
|
|
@@ -399,14 +429,14 @@ function register5(cli2) {
|
|
|
399
429
|
}
|
|
400
430
|
try {
|
|
401
431
|
console.log(`\u5F00\u59CB\u8F6E\u8BE2\u53D1\u5E03\u72B6\u6001 (\u95F4\u9694 ${intervalSec}s, \u6700\u591A ${maxPolls} \u6B21)`);
|
|
402
|
-
console.log(`businessId: ${
|
|
403
|
-
console.log(`shareId: ${
|
|
432
|
+
console.log(`businessId: ${businessId}`);
|
|
433
|
+
console.log(`shareId: ${shareId}
|
|
404
434
|
`);
|
|
405
435
|
let lastStatus = "UNKNOWN";
|
|
406
436
|
for (let i = 1; i <= maxPolls; i++) {
|
|
407
437
|
const data = await openApiPost("/api/v1/open/tiktok/video/status", {
|
|
408
|
-
businessId
|
|
409
|
-
shareId
|
|
438
|
+
businessId,
|
|
439
|
+
shareId
|
|
410
440
|
});
|
|
411
441
|
const status = data.status ?? data.Status ?? "UNKNOWN";
|
|
412
442
|
const postIds = data.post_ids ?? [];
|
|
@@ -423,7 +453,7 @@ function register5(cli2) {
|
|
|
423
453
|
console.log("\u53D1\u5E03\u6210\u529F!");
|
|
424
454
|
console.log(`\u89C6\u9891 ID: ${postIds[0]}`);
|
|
425
455
|
console.log(
|
|
426
|
-
`\u63D0\u793A: \u4F7F\u7528 beervid query-video --business-id ${
|
|
456
|
+
`\u63D0\u793A: \u4F7F\u7528 beervid query-video --business-id ${businessId} --item-ids ${postIds[0]} \u67E5\u8BE2\u6570\u636E`
|
|
427
457
|
);
|
|
428
458
|
printResult(data);
|
|
429
459
|
process.exit(0);
|
|
@@ -452,11 +482,13 @@ function register5(cli2) {
|
|
|
452
482
|
// src/commands/query-video.ts
|
|
453
483
|
function register6(cli2) {
|
|
454
484
|
cli2.command("query-video", "\u67E5\u8BE2\u89C6\u9891\u7EDF\u8BA1\u6570\u636E").option("--business-id <id>", "TT \u8D26\u53F7 businessId\uFF08\u5FC5\u586B\uFF09").option("--item-ids <ids>", "\u89C6\u9891 ID\uFF0C\u652F\u6301\u91CD\u590D\u4F20\u53C2\u6216\u9017\u53F7\u5206\u9694\uFF08\u5FC5\u586B\uFF09").action(
|
|
455
|
-
async (
|
|
456
|
-
|
|
485
|
+
async () => {
|
|
486
|
+
const businessId = getRawOptionValue(cli2.rawArgs, "--business-id");
|
|
487
|
+
const rawItemIdArgs = getRawOptionValues(cli2.rawArgs, "--item-ids");
|
|
488
|
+
if (!businessId || rawItemIdArgs.length === 0) {
|
|
457
489
|
const missing = [
|
|
458
|
-
!
|
|
459
|
-
|
|
490
|
+
!businessId && "--business-id",
|
|
491
|
+
rawItemIdArgs.length === 0 && "--item-ids"
|
|
460
492
|
].filter(Boolean);
|
|
461
493
|
console.error(`\u7F3A\u5C11\u5FC5\u586B\u53C2\u6570: ${missing.join(", ")}
|
|
462
494
|
`);
|
|
@@ -465,7 +497,7 @@ function register6(cli2) {
|
|
|
465
497
|
);
|
|
466
498
|
process.exit(1);
|
|
467
499
|
}
|
|
468
|
-
const itemIds =
|
|
500
|
+
const itemIds = rawItemIdArgs.flatMap((value) => value.split(",")).map((id) => id.trim()).filter(Boolean);
|
|
469
501
|
if (itemIds.length === 0) {
|
|
470
502
|
console.error("\u9519\u8BEF: --item-ids \u4E0D\u80FD\u4E3A\u7A7A");
|
|
471
503
|
process.exit(1);
|
|
@@ -474,7 +506,7 @@ function register6(cli2) {
|
|
|
474
506
|
console.log(`\u67E5\u8BE2 ${itemIds.length} \u4E2A\u89C6\u9891\u7684\u6570\u636E...
|
|
475
507
|
`);
|
|
476
508
|
const data = await openApiPost("/api/v1/open/tiktok/video/query", {
|
|
477
|
-
businessId
|
|
509
|
+
businessId,
|
|
478
510
|
itemIds
|
|
479
511
|
});
|
|
480
512
|
const list = data.videoList ?? data.videos ?? [];
|
|
@@ -771,12 +803,12 @@ var VALID_PRODUCT_TYPES = ["shop", "showcase", "all"];
|
|
|
771
803
|
function register7(cli2) {
|
|
772
804
|
cli2.command("query-products", "\u67E5\u8BE2 TTS \u5546\u54C1\u5217\u8868").option("--creator-id <id>", "TTS \u8D26\u53F7 creatorUserOpenId\uFF08\u5FC5\u586B\uFF09").option("--product-type <type>", "\u5546\u54C1\u6765\u6E90: shop / showcase / all\uFF08\u9ED8\u8BA4 all\uFF09").option("--page-size <n>", "\u6BCF\u9875\u6570\u91CF\uFF08\u9ED8\u8BA4 20\uFF09").option("--cursor <cursor>", "\u5206\u9875\u6E38\u6807\uFF08\u9996\u9875\u4E0D\u4F20\uFF09").action(
|
|
773
805
|
async (options) => {
|
|
774
|
-
|
|
806
|
+
const creatorId = getRawOptionValue(cli2.rawArgs, "--creator-id");
|
|
807
|
+
if (!creatorId) {
|
|
775
808
|
console.error("\u7F3A\u5C11\u5FC5\u586B\u53C2\u6570: --creator-id\n");
|
|
776
809
|
console.error("\u7528\u6CD5: beervid query-products --creator-id <id>");
|
|
777
810
|
process.exit(1);
|
|
778
811
|
}
|
|
779
|
-
const creatorId = options.creatorId;
|
|
780
812
|
const productType = (options.productType ?? "all").toLowerCase();
|
|
781
813
|
const pageSize = parseInt(options.pageSize ?? "20", 10);
|
|
782
814
|
const cursor = options.cursor ?? "";
|
|
@@ -845,9 +877,10 @@ function parsePositiveInt(value, optionName, defaultValue) {
|
|
|
845
877
|
function register8(cli2) {
|
|
846
878
|
cli2.command("publish-tt-flow", "\u6267\u884C TT \u5B8C\u6574\u53D1\u5E03\u6D41\u7A0B\uFF1A\u4E0A\u4F20\u3001\u53D1\u5E03\u3001\u8F6E\u8BE2\u3001\u67E5\u8BE2\u6570\u636E").option("--business-id <id>", "TT \u8D26\u53F7 businessId\uFF08\u5FC5\u586B\uFF09").option("--file <path>", "\u89C6\u9891\u6587\u4EF6\u8DEF\u5F84\u6216 URL\uFF08\u5FC5\u586B\uFF09").option("--caption <text>", "\u89C6\u9891\u63CF\u8FF0/\u6587\u6848\uFF08\u53EF\u9009\uFF09").option("--token <token>", "\u5DF2\u6709\u4E0A\u4F20\u51ED\u8BC1\uFF08\u53EF\u9009\uFF09").option("--interval <sec>", "\u8F6E\u8BE2\u95F4\u9694\u79D2\u6570\uFF08\u9ED8\u8BA4 5\uFF09").option("--max-polls <n>", "\u6700\u5927\u8F6E\u8BE2\u6B21\u6570\uFF08\u9ED8\u8BA4 60\uFF09").option("--query-interval <sec>", "\u89C6\u9891\u6570\u636E\u67E5\u8BE2\u91CD\u8BD5\u95F4\u9694\u79D2\u6570\uFF08\u9ED8\u8BA4 5\uFF09").option("--query-max-attempts <n>", "\u89C6\u9891\u6570\u636E\u67E5\u8BE2\u6700\u5927\u91CD\u8BD5\u6B21\u6570\uFF08\u9ED8\u8BA4 3\uFF09").action(
|
|
847
879
|
async (options) => {
|
|
848
|
-
|
|
880
|
+
const businessId = getRawOptionValue(cli2.rawArgs, "--business-id");
|
|
881
|
+
if (!businessId || !options.file) {
|
|
849
882
|
const missing = [
|
|
850
|
-
!
|
|
883
|
+
!businessId && "--business-id",
|
|
851
884
|
!options.file && "--file"
|
|
852
885
|
].filter(Boolean);
|
|
853
886
|
console.error(`\u7F3A\u5C11\u5FC5\u586B\u53C2\u6570: ${missing.join(", ")}
|
|
@@ -870,28 +903,14 @@ function register8(cli2) {
|
|
|
870
903
|
console.log("1/4 \u6B63\u5728\u4E0A\u4F20\u89C6\u9891...");
|
|
871
904
|
const upload = await uploadNormalVideo(options.file, options.token);
|
|
872
905
|
console.log("2/4 \u6B63\u5728\u53D1\u5E03\u89C6\u9891...");
|
|
873
|
-
const publish = await publishNormalVideo(
|
|
874
|
-
options.businessId,
|
|
875
|
-
upload.fileUrl,
|
|
876
|
-
options.caption
|
|
877
|
-
);
|
|
906
|
+
const publish = await publishNormalVideo(businessId, upload.fileUrl, options.caption);
|
|
878
907
|
console.log("3/4 \u6B63\u5728\u8F6E\u8BE2\u53D1\u5E03\u72B6\u6001...");
|
|
879
|
-
const status = await pollNormalVideoStatus(
|
|
880
|
-
options.businessId,
|
|
881
|
-
publish.shareId,
|
|
882
|
-
intervalSec,
|
|
883
|
-
maxPolls
|
|
884
|
-
);
|
|
908
|
+
const status = await pollNormalVideoStatus(businessId, publish.shareId, intervalSec, maxPolls);
|
|
885
909
|
const videoId = status.postIds[0] ?? null;
|
|
886
910
|
let query = null;
|
|
887
911
|
if (status.finalStatus === "PUBLISH_COMPLETE" && videoId) {
|
|
888
912
|
console.log("4/4 \u6B63\u5728\u67E5\u8BE2\u89C6\u9891\u6570\u636E...");
|
|
889
|
-
const queryResult = await queryVideoWithRetry(
|
|
890
|
-
options.businessId,
|
|
891
|
-
videoId,
|
|
892
|
-
queryIntervalSec,
|
|
893
|
-
queryMaxAttempts
|
|
894
|
-
);
|
|
913
|
+
const queryResult = await queryVideoWithRetry(businessId, videoId, queryIntervalSec, queryMaxAttempts);
|
|
895
914
|
query = queryResult.query;
|
|
896
915
|
for (const warning of queryResult.warnings) {
|
|
897
916
|
console.warn(warning.message);
|
|
@@ -952,9 +971,11 @@ function buildManualProduct(productId, productTitle, matchedProduct) {
|
|
|
952
971
|
function register9(cli2) {
|
|
953
972
|
cli2.command("publish-tts-flow", "\u6267\u884C TTS \u5B8C\u6574\u53D1\u5E03\u6D41\u7A0B\uFF1A\u67E5\u5546\u54C1\u3001\u9009\u5546\u54C1\u3001\u4E0A\u4F20\u3001\u53D1\u5E03").option("--creator-id <id>", "TTS \u8D26\u53F7 creatorUserOpenId\uFF08\u5FC5\u586B\uFF09").option("--file <path>", "\u89C6\u9891\u6587\u4EF6\u8DEF\u5F84\u6216 URL\uFF08\u5FC5\u586B\uFF09").option("--caption <text>", "\u89C6\u9891\u6807\u9898/\u6587\u6848\uFF08\u53EF\u9009\uFF09").option("--token <token>", "\u5DF2\u6709\u4E0A\u4F20\u51ED\u8BC1\uFF08\u53EF\u9009\uFF09").option("--product-type <type>", "\u5546\u54C1\u6765\u6E90: shop / showcase / all\uFF08\u9ED8\u8BA4 all\uFF09").option("--page-size <n>", "\u6BCF\u9875\u6570\u91CF\uFF08\u9ED8\u8BA4 20\uFF09").option("--max-product-pages <n>", "\u5546\u54C1\u626B\u63CF\u6700\u5927\u9875\u6570\uFF08\u9ED8\u8BA4 5\uFF09").option("--product-id <id>", "\u624B\u52A8\u6307\u5B9A\u5546\u54C1 ID").option("--product-title <title>", "\u624B\u52A8\u6307\u5B9A\u5546\u54C1\u6807\u9898").option("--interactive", "\u4EA4\u4E92\u5F0F\u9009\u62E9\u5546\u54C1").action(
|
|
954
973
|
async (options) => {
|
|
955
|
-
|
|
974
|
+
const creatorId = getRawOptionValue(cli2.rawArgs, "--creator-id");
|
|
975
|
+
const productId = getRawOptionValue(cli2.rawArgs, "--product-id");
|
|
976
|
+
if (!creatorId || !options.file) {
|
|
956
977
|
const missing = [
|
|
957
|
-
!
|
|
978
|
+
!creatorId && "--creator-id",
|
|
958
979
|
!options.file && "--file"
|
|
959
980
|
].filter(Boolean);
|
|
960
981
|
console.error(`\u7F3A\u5C11\u5FC5\u586B\u53C2\u6570: ${missing.join(", ")}
|
|
@@ -969,11 +990,11 @@ function register9(cli2) {
|
|
|
969
990
|
console.error("\u9519\u8BEF: --product-type \u5FC5\u987B\u4E3A shop\u3001showcase \u6216 all");
|
|
970
991
|
process.exit(1);
|
|
971
992
|
}
|
|
972
|
-
if (
|
|
993
|
+
if (productId && options.interactive) {
|
|
973
994
|
console.error("\u9519\u8BEF: --product-id \u4E0E --interactive \u4E0D\u80FD\u540C\u65F6\u4F7F\u7528");
|
|
974
995
|
process.exit(1);
|
|
975
996
|
}
|
|
976
|
-
if (options.productTitle && !
|
|
997
|
+
if (options.productTitle && !productId) {
|
|
977
998
|
console.error("\u9519\u8BEF: --product-title \u9700\u8981\u4E0E --product-id \u4E00\u8D77\u4F7F\u7528");
|
|
978
999
|
process.exit(1);
|
|
979
1000
|
}
|
|
@@ -987,13 +1008,13 @@ function register9(cli2) {
|
|
|
987
1008
|
console.log("\u5F00\u59CB\u6267\u884C TTS \u5B8C\u6574\u53D1\u5E03\u6D41\u7A0B...");
|
|
988
1009
|
let selectedProduct;
|
|
989
1010
|
let queriedProducts = null;
|
|
990
|
-
if (
|
|
1011
|
+
if (productId && options.productTitle) {
|
|
991
1012
|
console.log("1/4 \u5DF2\u624B\u52A8\u6307\u5B9A\u5546\u54C1\uFF0C\u8DF3\u8FC7\u5546\u54C1\u67E5\u8BE2...");
|
|
992
|
-
selectedProduct = buildManualProduct(
|
|
1013
|
+
selectedProduct = buildManualProduct(productId, options.productTitle);
|
|
993
1014
|
} else {
|
|
994
1015
|
console.log("1/4 \u6B63\u5728\u67E5\u8BE2\u5546\u54C1\u5217\u8868...");
|
|
995
1016
|
const productPool = await fetchProductPool(
|
|
996
|
-
|
|
1017
|
+
creatorId,
|
|
997
1018
|
productType,
|
|
998
1019
|
pageSize,
|
|
999
1020
|
maxProductPages
|
|
@@ -1007,10 +1028,8 @@ function register9(cli2) {
|
|
|
1007
1028
|
`\u4EE5\u4E0B\u5546\u54C1\u6E90\u8BF7\u6C42\u5931\u8D25: ${productPool.summary.failedSources.join(", ")}\uFF0C\u5546\u54C1\u6C60\u53EF\u80FD\u4E0D\u5B8C\u6574`
|
|
1008
1029
|
);
|
|
1009
1030
|
}
|
|
1010
|
-
if (
|
|
1011
|
-
const matchedProduct = productPool.products.find(
|
|
1012
|
-
(product) => product.id === options.productId
|
|
1013
|
-
);
|
|
1031
|
+
if (productId) {
|
|
1032
|
+
const matchedProduct = productPool.products.find((product) => product.id === productId);
|
|
1014
1033
|
const resolvedTitle = matchedProduct?.title;
|
|
1015
1034
|
if (!resolvedTitle) {
|
|
1016
1035
|
console.error(
|
|
@@ -1018,7 +1037,7 @@ function register9(cli2) {
|
|
|
1018
1037
|
);
|
|
1019
1038
|
process.exit(1);
|
|
1020
1039
|
}
|
|
1021
|
-
selectedProduct = buildManualProduct(
|
|
1040
|
+
selectedProduct = buildManualProduct(productId, resolvedTitle, matchedProduct);
|
|
1022
1041
|
} else if (options.interactive) {
|
|
1023
1042
|
if (productPool.products.length === 0) {
|
|
1024
1043
|
console.error("TTS \u5B8C\u6574\u53D1\u5E03\u6D41\u7A0B\u5931\u8D25: \u5F53\u524D\u5546\u54C1\u6C60\u4E3A\u7A7A\uFF0C\u65E0\u6CD5\u9009\u62E9\u5546\u54C1");
|
|
@@ -1043,10 +1062,10 @@ function register9(cli2) {
|
|
|
1043
1062
|
}
|
|
1044
1063
|
}
|
|
1045
1064
|
console.log("3/4 \u6B63\u5728\u4E0A\u4F20\u6302\u8F66\u89C6\u9891...");
|
|
1046
|
-
const upload = await uploadTtsVideo(options.file,
|
|
1065
|
+
const upload = await uploadTtsVideo(options.file, creatorId, options.token);
|
|
1047
1066
|
console.log("4/4 \u6B63\u5728\u53D1\u5E03\u6302\u8F66\u89C6\u9891...");
|
|
1048
1067
|
const publishResult = await publishTtsVideo(
|
|
1049
|
-
|
|
1068
|
+
creatorId,
|
|
1050
1069
|
upload.videoFileId,
|
|
1051
1070
|
selectedProduct.id,
|
|
1052
1071
|
selectedProduct.title,
|
|
@@ -1111,7 +1130,7 @@ function register10(cli2) {
|
|
|
1111
1130
|
|
|
1112
1131
|
// src/cli.ts
|
|
1113
1132
|
var cli = cac("beervid");
|
|
1114
|
-
var cliVersion = true ? "0.2.
|
|
1133
|
+
var cliVersion = true ? "0.2.5" : pkg.version;
|
|
1115
1134
|
register10(cli);
|
|
1116
1135
|
register(cli);
|
|
1117
1136
|
register2(cli);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "beervid-app-cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.5",
|
|
4
4
|
"description": "BEERVID App CLI — TikTok video publish, account auth, and data query",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -11,9 +11,7 @@
|
|
|
11
11
|
},
|
|
12
12
|
"files": [
|
|
13
13
|
"dist/",
|
|
14
|
-
"
|
|
15
|
-
"references/",
|
|
16
|
-
"SKILL.md",
|
|
14
|
+
"skills/",
|
|
17
15
|
"README.md"
|
|
18
16
|
],
|
|
19
17
|
"scripts": {
|