beervid-app-cli 0.2.2 → 0.2.4
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 +45 -0
- package/SKILL.md +204 -376
- package/dist/cli.mjs +117 -151
- package/docs/database-schema.md +231 -0
- package/docs/oauth-callback.md +282 -0
- package/docs/retry-and-idempotency.md +295 -0
- package/docs/tt-poll-task.md +239 -0
- package/docs/tts-product-cache.md +256 -0
- package/example/express/README.md +58 -0
- package/example/express/package.json +20 -0
- package/example/express/server.ts +431 -0
- package/example/express/tsconfig.json +12 -0
- package/example/nextjs/.env.example +3 -0
- package/example/nextjs/README.md +54 -0
- package/example/nextjs/app/api/oauth/callback/route.ts +34 -0
- package/example/nextjs/app/api/oauth/url/route.ts +30 -0
- package/example/nextjs/app/api/products/route.ts +43 -0
- package/example/nextjs/app/api/publish/tt/route.ts +116 -0
- package/example/nextjs/app/api/publish/tts/route.ts +58 -0
- package/example/nextjs/app/api/status/[shareId]/route.ts +41 -0
- package/example/nextjs/app/layout.tsx +9 -0
- package/example/nextjs/app/page.tsx +80 -0
- package/example/nextjs/lib/beervid-client.ts +107 -0
- package/example/nextjs/next.config.ts +4 -0
- package/example/nextjs/package.json +19 -0
- package/example/nextjs/tsconfig.json +23 -0
- package/example/standard/README.md +51 -0
- package/example/standard/api-client.ts +181 -0
- package/example/standard/get-oauth-url.ts +44 -0
- package/example/standard/package.json +18 -0
- package/example/standard/query-products.ts +141 -0
- package/example/standard/tsconfig.json +12 -0
- package/example/standard/tt-publish-flow.ts +194 -0
- package/example/standard/tts-publish-flow.ts +246 -0
- package/package.json +3 -1
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) {
|
|
@@ -169,11 +191,11 @@ function register(cli2) {
|
|
|
169
191
|
if (type === "tt") {
|
|
170
192
|
const data = await openApiGet("/api/v1/open/thirdparty-auth/tt-url");
|
|
171
193
|
console.log("TT OAuth \u6388\u6743\u94FE\u63A5:");
|
|
172
|
-
printResult(
|
|
194
|
+
printResult(data);
|
|
173
195
|
} else {
|
|
174
196
|
const data = await openApiGet("/api/v1/open/thirdparty-auth/tts-url");
|
|
175
197
|
console.log("TTS OAuth \u6388\u6743\u94FE\u63A5:");
|
|
176
|
-
printResult(
|
|
198
|
+
printResult(data);
|
|
177
199
|
}
|
|
178
200
|
} catch (err) {
|
|
179
201
|
rethrowIfProcessExit(err);
|
|
@@ -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);
|
|
@@ -451,12 +481,14 @@ function register5(cli2) {
|
|
|
451
481
|
|
|
452
482
|
// src/commands/query-video.ts
|
|
453
483
|
function register6(cli2) {
|
|
454
|
-
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\
|
|
455
|
-
async (
|
|
456
|
-
|
|
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(
|
|
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 ?? [];
|
|
@@ -501,7 +533,7 @@ function register6(cli2) {
|
|
|
501
533
|
if (v.shareUrl) console.log(` \u94FE\u63A5: ${v.shareUrl}`);
|
|
502
534
|
console.log("");
|
|
503
535
|
}
|
|
504
|
-
printResult(
|
|
536
|
+
printResult(data);
|
|
505
537
|
} catch (err) {
|
|
506
538
|
rethrowIfProcessExit(err);
|
|
507
539
|
console.error("\u67E5\u8BE2\u89C6\u9891\u6570\u636E\u5931\u8D25:", err.message);
|
|
@@ -581,23 +613,6 @@ async function pollNormalVideoStatus(businessId, shareId, intervalSec, maxPolls)
|
|
|
581
613
|
raw: lastData
|
|
582
614
|
};
|
|
583
615
|
}
|
|
584
|
-
function normalizeVideoQuery(data) {
|
|
585
|
-
const list = data.videoList ?? data.videos ?? [];
|
|
586
|
-
const videos = list.map((video) => ({
|
|
587
|
-
itemId: video.itemId ?? video.item_id,
|
|
588
|
-
videoViews: video.videoViews ?? video.video_views ?? 0,
|
|
589
|
-
likes: video.likes ?? 0,
|
|
590
|
-
comments: video.comments ?? 0,
|
|
591
|
-
shares: video.shares ?? 0,
|
|
592
|
-
thumbnailUrl: video.thumbnailUrl ?? video.thumbnail_url ?? "",
|
|
593
|
-
shareUrl: video.shareUrl ?? video.share_url ?? ""
|
|
594
|
-
}));
|
|
595
|
-
return {
|
|
596
|
-
attempts: 1,
|
|
597
|
-
videos,
|
|
598
|
-
raw: data
|
|
599
|
-
};
|
|
600
|
-
}
|
|
601
616
|
async function queryVideoWithRetry(businessId, itemId, intervalSec, maxAttempts) {
|
|
602
617
|
const warnings = [];
|
|
603
618
|
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
@@ -605,10 +620,9 @@ async function queryVideoWithRetry(businessId, itemId, intervalSec, maxAttempts)
|
|
|
605
620
|
businessId,
|
|
606
621
|
itemIds: [itemId]
|
|
607
622
|
});
|
|
608
|
-
const
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
return { query: normalized, warnings };
|
|
623
|
+
const list = data.videoList ?? data.videos ?? [];
|
|
624
|
+
if (list.length > 0) {
|
|
625
|
+
return { query: data, warnings };
|
|
612
626
|
}
|
|
613
627
|
if (attempt < maxAttempts) {
|
|
614
628
|
await sleep2(intervalSec * 1e3);
|
|
@@ -642,6 +656,7 @@ async function queryProductsPage(creatorId, productType, pageSize, cursor) {
|
|
|
642
656
|
return token !== null;
|
|
643
657
|
});
|
|
644
658
|
const allProducts = /* @__PURE__ */ new Map();
|
|
659
|
+
const rawGroups = [];
|
|
645
660
|
let nextShopToken = cursor.shopToken;
|
|
646
661
|
let nextShowcaseToken = cursor.showcaseToken;
|
|
647
662
|
let successCount = 0;
|
|
@@ -669,6 +684,7 @@ async function queryProductsPage(creatorId, productType, pageSize, cursor) {
|
|
|
669
684
|
successCount += 1;
|
|
670
685
|
const { data } = result.value;
|
|
671
686
|
const groups = Array.isArray(data) ? data : [data];
|
|
687
|
+
rawGroups.push(...groups);
|
|
672
688
|
for (const group of groups) {
|
|
673
689
|
const token = group.nextPageToken === void 0 ? null : group.nextPageToken;
|
|
674
690
|
if (type === "shop") nextShopToken = token;
|
|
@@ -694,6 +710,7 @@ async function queryProductsPage(creatorId, productType, pageSize, cursor) {
|
|
|
694
710
|
const nextCursor = encodeCursor({ shopToken: nextShopToken, showcaseToken: nextShowcaseToken });
|
|
695
711
|
return {
|
|
696
712
|
products: Array.from(allProducts.values()),
|
|
713
|
+
rawGroups,
|
|
697
714
|
nextCursor,
|
|
698
715
|
successCount,
|
|
699
716
|
failedSources
|
|
@@ -701,6 +718,7 @@ async function queryProductsPage(creatorId, productType, pageSize, cursor) {
|
|
|
701
718
|
}
|
|
702
719
|
async function fetchProductPool(creatorId, productType, pageSize, maxPages) {
|
|
703
720
|
const allProducts = /* @__PURE__ */ new Map();
|
|
721
|
+
const rawGroups = [];
|
|
704
722
|
let cursor = { shopToken: "", showcaseToken: "" };
|
|
705
723
|
let nextCursor = null;
|
|
706
724
|
let pagesScanned = 0;
|
|
@@ -714,6 +732,7 @@ async function fetchProductPool(creatorId, productType, pageSize, maxPages) {
|
|
|
714
732
|
failedSourcesSet.add(src);
|
|
715
733
|
}
|
|
716
734
|
pagesScanned = page;
|
|
735
|
+
rawGroups.push(...pageResult.rawGroups);
|
|
717
736
|
for (const product of pageResult.products) {
|
|
718
737
|
if (!allProducts.has(product.id)) {
|
|
719
738
|
allProducts.set(product.id, product);
|
|
@@ -727,6 +746,7 @@ async function fetchProductPool(creatorId, productType, pageSize, maxPages) {
|
|
|
727
746
|
}
|
|
728
747
|
return {
|
|
729
748
|
products: Array.from(allProducts.values()),
|
|
749
|
+
rawGroups,
|
|
730
750
|
summary: {
|
|
731
751
|
productType,
|
|
732
752
|
pageSize,
|
|
@@ -738,17 +758,6 @@ async function fetchProductPool(creatorId, productType, pageSize, maxPages) {
|
|
|
738
758
|
}
|
|
739
759
|
};
|
|
740
760
|
}
|
|
741
|
-
function buildSkippedProductQuerySummary(productType, pageSize) {
|
|
742
|
-
return {
|
|
743
|
-
productType,
|
|
744
|
-
pageSize,
|
|
745
|
-
pagesScanned: 0,
|
|
746
|
-
productCount: 0,
|
|
747
|
-
nextCursor: null,
|
|
748
|
-
reachedPageLimit: false,
|
|
749
|
-
failedSources: []
|
|
750
|
-
};
|
|
751
|
-
}
|
|
752
761
|
function isProductPublishable(product) {
|
|
753
762
|
if (product.reviewStatus && product.reviewStatus.toUpperCase() !== "APPROVED") return false;
|
|
754
763
|
if (product.inventoryStatus && product.inventoryStatus.toUpperCase() !== "IN_STOCK") return false;
|
|
@@ -757,18 +766,6 @@ function isProductPublishable(product) {
|
|
|
757
766
|
function sortProductsForSelection(products) {
|
|
758
767
|
return products.filter(isProductPublishable).sort((a, b) => b.salesCount - a.salesCount);
|
|
759
768
|
}
|
|
760
|
-
function buildSelectedProductSummary(product, selectionMode) {
|
|
761
|
-
return {
|
|
762
|
-
selectionMode,
|
|
763
|
-
id: product.id,
|
|
764
|
-
title: product.title,
|
|
765
|
-
salesCount: product.salesCount,
|
|
766
|
-
source: product.source,
|
|
767
|
-
price: product.price,
|
|
768
|
-
brandName: product.brandName,
|
|
769
|
-
shopName: product.shopName
|
|
770
|
-
};
|
|
771
|
-
}
|
|
772
769
|
async function promptForProductSelection(products) {
|
|
773
770
|
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
774
771
|
throw new Error("\u4EA4\u4E92\u6A21\u5F0F\u9700\u8981\u5728 TTY \u7EC8\u7AEF\u4E2D\u8FD0\u884C");
|
|
@@ -806,12 +803,12 @@ var VALID_PRODUCT_TYPES = ["shop", "showcase", "all"];
|
|
|
806
803
|
function register7(cli2) {
|
|
807
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(
|
|
808
805
|
async (options) => {
|
|
809
|
-
|
|
806
|
+
const creatorId = getRawOptionValue(cli2.rawArgs, "--creator-id");
|
|
807
|
+
if (!creatorId) {
|
|
810
808
|
console.error("\u7F3A\u5C11\u5FC5\u586B\u53C2\u6570: --creator-id\n");
|
|
811
809
|
console.error("\u7528\u6CD5: beervid query-products --creator-id <id>");
|
|
812
810
|
process.exit(1);
|
|
813
811
|
}
|
|
814
|
-
const creatorId = options.creatorId;
|
|
815
812
|
const productType = (options.productType ?? "all").toLowerCase();
|
|
816
813
|
const pageSize = parseInt(options.pageSize ?? "20", 10);
|
|
817
814
|
const cursor = options.cursor ?? "";
|
|
@@ -858,7 +855,7 @@ function register7(cli2) {
|
|
|
858
855
|
} else {
|
|
859
856
|
console.log("\u5DF2\u5230\u6700\u540E\u4E00\u9875");
|
|
860
857
|
}
|
|
861
|
-
printResult(
|
|
858
|
+
printResult(pageResult.rawGroups);
|
|
862
859
|
} catch (err) {
|
|
863
860
|
rethrowIfProcessExit(err);
|
|
864
861
|
console.error("\u67E5\u8BE2\u5546\u54C1\u5931\u8D25:", err.message);
|
|
@@ -880,9 +877,10 @@ function parsePositiveInt(value, optionName, defaultValue) {
|
|
|
880
877
|
function register8(cli2) {
|
|
881
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(
|
|
882
879
|
async (options) => {
|
|
883
|
-
|
|
880
|
+
const businessId = getRawOptionValue(cli2.rawArgs, "--business-id");
|
|
881
|
+
if (!businessId || !options.file) {
|
|
884
882
|
const missing = [
|
|
885
|
-
!
|
|
883
|
+
!businessId && "--business-id",
|
|
886
884
|
!options.file && "--file"
|
|
887
885
|
].filter(Boolean);
|
|
888
886
|
console.error(`\u7F3A\u5C11\u5FC5\u586B\u53C2\u6570: ${missing.join(", ")}
|
|
@@ -905,42 +903,25 @@ function register8(cli2) {
|
|
|
905
903
|
console.log("1/4 \u6B63\u5728\u4E0A\u4F20\u89C6\u9891...");
|
|
906
904
|
const upload = await uploadNormalVideo(options.file, options.token);
|
|
907
905
|
console.log("2/4 \u6B63\u5728\u53D1\u5E03\u89C6\u9891...");
|
|
908
|
-
const publish = await publishNormalVideo(
|
|
909
|
-
options.businessId,
|
|
910
|
-
upload.fileUrl,
|
|
911
|
-
options.caption
|
|
912
|
-
);
|
|
906
|
+
const publish = await publishNormalVideo(businessId, upload.fileUrl, options.caption);
|
|
913
907
|
console.log("3/4 \u6B63\u5728\u8F6E\u8BE2\u53D1\u5E03\u72B6\u6001...");
|
|
914
|
-
const status = await pollNormalVideoStatus(
|
|
915
|
-
options.businessId,
|
|
916
|
-
publish.shareId,
|
|
917
|
-
intervalSec,
|
|
918
|
-
maxPolls
|
|
919
|
-
);
|
|
920
|
-
const warnings = [];
|
|
908
|
+
const status = await pollNormalVideoStatus(businessId, publish.shareId, intervalSec, maxPolls);
|
|
921
909
|
const videoId = status.postIds[0] ?? null;
|
|
922
910
|
let query = null;
|
|
923
911
|
if (status.finalStatus === "PUBLISH_COMPLETE" && videoId) {
|
|
924
912
|
console.log("4/4 \u6B63\u5728\u67E5\u8BE2\u89C6\u9891\u6570\u636E...");
|
|
925
|
-
const queryResult = await queryVideoWithRetry(
|
|
926
|
-
options.businessId,
|
|
927
|
-
videoId,
|
|
928
|
-
queryIntervalSec,
|
|
929
|
-
queryMaxAttempts
|
|
930
|
-
);
|
|
913
|
+
const queryResult = await queryVideoWithRetry(businessId, videoId, queryIntervalSec, queryMaxAttempts);
|
|
931
914
|
query = queryResult.query;
|
|
932
|
-
|
|
915
|
+
for (const warning of queryResult.warnings) {
|
|
916
|
+
console.warn(warning.message);
|
|
917
|
+
}
|
|
933
918
|
}
|
|
934
|
-
|
|
935
|
-
flowType: "tt",
|
|
919
|
+
printResult({
|
|
936
920
|
upload,
|
|
937
921
|
publish,
|
|
938
|
-
status,
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
warnings
|
|
942
|
-
};
|
|
943
|
-
printResult(result);
|
|
922
|
+
status: status.raw,
|
|
923
|
+
query
|
|
924
|
+
});
|
|
944
925
|
if (status.finalStatus === "FAILED") {
|
|
945
926
|
process.exit(1);
|
|
946
927
|
}
|
|
@@ -990,9 +971,11 @@ function buildManualProduct(productId, productTitle, matchedProduct) {
|
|
|
990
971
|
function register9(cli2) {
|
|
991
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(
|
|
992
973
|
async (options) => {
|
|
993
|
-
|
|
974
|
+
const creatorId = getRawOptionValue(cli2.rawArgs, "--creator-id");
|
|
975
|
+
const productId = getRawOptionValue(cli2.rawArgs, "--product-id");
|
|
976
|
+
if (!creatorId || !options.file) {
|
|
994
977
|
const missing = [
|
|
995
|
-
!
|
|
978
|
+
!creatorId && "--creator-id",
|
|
996
979
|
!options.file && "--file"
|
|
997
980
|
].filter(Boolean);
|
|
998
981
|
console.error(`\u7F3A\u5C11\u5FC5\u586B\u53C2\u6570: ${missing.join(", ")}
|
|
@@ -1007,11 +990,11 @@ function register9(cli2) {
|
|
|
1007
990
|
console.error("\u9519\u8BEF: --product-type \u5FC5\u987B\u4E3A shop\u3001showcase \u6216 all");
|
|
1008
991
|
process.exit(1);
|
|
1009
992
|
}
|
|
1010
|
-
if (
|
|
993
|
+
if (productId && options.interactive) {
|
|
1011
994
|
console.error("\u9519\u8BEF: --product-id \u4E0E --interactive \u4E0D\u80FD\u540C\u65F6\u4F7F\u7528");
|
|
1012
995
|
process.exit(1);
|
|
1013
996
|
}
|
|
1014
|
-
if (options.productTitle && !
|
|
997
|
+
if (options.productTitle && !productId) {
|
|
1015
998
|
console.error("\u9519\u8BEF: --product-title \u9700\u8981\u4E0E --product-id \u4E00\u8D77\u4F7F\u7528");
|
|
1016
999
|
process.exit(1);
|
|
1017
1000
|
}
|
|
@@ -1023,40 +1006,30 @@ function register9(cli2) {
|
|
|
1023
1006
|
);
|
|
1024
1007
|
try {
|
|
1025
1008
|
console.log("\u5F00\u59CB\u6267\u884C TTS \u5B8C\u6574\u53D1\u5E03\u6D41\u7A0B...");
|
|
1026
|
-
const warnings = [];
|
|
1027
|
-
let selectionMode = "automatic";
|
|
1028
1009
|
let selectedProduct;
|
|
1029
|
-
let
|
|
1030
|
-
if (
|
|
1031
|
-
selectionMode = "manual";
|
|
1010
|
+
let queriedProducts = null;
|
|
1011
|
+
if (productId && options.productTitle) {
|
|
1032
1012
|
console.log("1/4 \u5DF2\u624B\u52A8\u6307\u5B9A\u5546\u54C1\uFF0C\u8DF3\u8FC7\u5546\u54C1\u67E5\u8BE2...");
|
|
1033
|
-
selectedProduct = buildManualProduct(
|
|
1013
|
+
selectedProduct = buildManualProduct(productId, options.productTitle);
|
|
1034
1014
|
} else {
|
|
1035
1015
|
console.log("1/4 \u6B63\u5728\u67E5\u8BE2\u5546\u54C1\u5217\u8868...");
|
|
1036
1016
|
const productPool = await fetchProductPool(
|
|
1037
|
-
|
|
1017
|
+
creatorId,
|
|
1038
1018
|
productType,
|
|
1039
1019
|
pageSize,
|
|
1040
1020
|
maxProductPages
|
|
1041
1021
|
);
|
|
1042
|
-
|
|
1022
|
+
queriedProducts = productPool.rawGroups;
|
|
1043
1023
|
if (productPool.summary.reachedPageLimit && productPool.summary.nextCursor) {
|
|
1044
|
-
|
|
1045
|
-
code: "PRODUCT_SCAN_LIMIT_REACHED",
|
|
1046
|
-
message: `\u5546\u54C1\u626B\u63CF\u5DF2\u8FBE\u5230\u9875\u6570\u4E0A\u9650 ${maxProductPages}\uFF0C\u4ECD\u5B58\u5728\u672A\u62C9\u53D6\u5206\u9875`
|
|
1047
|
-
});
|
|
1024
|
+
console.warn(`\u5546\u54C1\u626B\u63CF\u5DF2\u8FBE\u5230\u9875\u6570\u4E0A\u9650 ${maxProductPages}\uFF0C\u4ECD\u5B58\u5728\u672A\u62C9\u53D6\u5206\u9875`);
|
|
1048
1025
|
}
|
|
1049
1026
|
if (productPool.summary.failedSources.length > 0) {
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
message: `\u4EE5\u4E0B\u5546\u54C1\u6E90\u8BF7\u6C42\u5931\u8D25: ${productPool.summary.failedSources.join(", ")}\uFF0C\u5546\u54C1\u6C60\u53EF\u80FD\u4E0D\u5B8C\u6574`
|
|
1053
|
-
});
|
|
1054
|
-
}
|
|
1055
|
-
if (options.productId) {
|
|
1056
|
-
selectionMode = "manual";
|
|
1057
|
-
const matchedProduct = productPool.products.find(
|
|
1058
|
-
(product) => product.id === options.productId
|
|
1027
|
+
console.warn(
|
|
1028
|
+
`\u4EE5\u4E0B\u5546\u54C1\u6E90\u8BF7\u6C42\u5931\u8D25: ${productPool.summary.failedSources.join(", ")}\uFF0C\u5546\u54C1\u6C60\u53EF\u80FD\u4E0D\u5B8C\u6574`
|
|
1059
1029
|
);
|
|
1030
|
+
}
|
|
1031
|
+
if (productId) {
|
|
1032
|
+
const matchedProduct = productPool.products.find((product) => product.id === productId);
|
|
1060
1033
|
const resolvedTitle = matchedProduct?.title;
|
|
1061
1034
|
if (!resolvedTitle) {
|
|
1062
1035
|
console.error(
|
|
@@ -1064,13 +1037,12 @@ function register9(cli2) {
|
|
|
1064
1037
|
);
|
|
1065
1038
|
process.exit(1);
|
|
1066
1039
|
}
|
|
1067
|
-
selectedProduct = buildManualProduct(
|
|
1040
|
+
selectedProduct = buildManualProduct(productId, resolvedTitle, matchedProduct);
|
|
1068
1041
|
} else if (options.interactive) {
|
|
1069
1042
|
if (productPool.products.length === 0) {
|
|
1070
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");
|
|
1071
1044
|
process.exit(1);
|
|
1072
1045
|
}
|
|
1073
|
-
selectionMode = "interactive";
|
|
1074
1046
|
console.log("2/4 \u8BF7\u9009\u62E9\u8981\u6302\u8F66\u7684\u5546\u54C1...");
|
|
1075
1047
|
selectedProduct = await promptForProductSelection(productPool.products);
|
|
1076
1048
|
} else {
|
|
@@ -1090,30 +1062,24 @@ function register9(cli2) {
|
|
|
1090
1062
|
}
|
|
1091
1063
|
}
|
|
1092
1064
|
console.log("3/4 \u6B63\u5728\u4E0A\u4F20\u6302\u8F66\u89C6\u9891...");
|
|
1093
|
-
const upload = await uploadTtsVideo(options.file,
|
|
1065
|
+
const upload = await uploadTtsVideo(options.file, creatorId, options.token);
|
|
1094
1066
|
console.log("4/4 \u6B63\u5728\u53D1\u5E03\u6302\u8F66\u89C6\u9891...");
|
|
1095
1067
|
const publishResult = await publishTtsVideo(
|
|
1096
|
-
|
|
1068
|
+
creatorId,
|
|
1097
1069
|
upload.videoFileId,
|
|
1098
1070
|
selectedProduct.id,
|
|
1099
1071
|
selectedProduct.title,
|
|
1100
1072
|
options.caption
|
|
1101
1073
|
);
|
|
1102
1074
|
if (publishResult.productTitle !== selectedProduct.title) {
|
|
1103
|
-
|
|
1104
|
-
code: "PRODUCT_TITLE_TRUNCATED",
|
|
1105
|
-
message: "\u5546\u54C1\u6807\u9898\u8D85\u8FC7 29 \u5B57\u7B26\uFF0C\u53D1\u5E03\u65F6\u5DF2\u81EA\u52A8\u622A\u65AD"
|
|
1106
|
-
});
|
|
1075
|
+
console.warn("\u5546\u54C1\u6807\u9898\u8D85\u8FC7 29 \u5B57\u7B26\uFF0C\u53D1\u5E03\u65F6\u5DF2\u81EA\u52A8\u622A\u65AD");
|
|
1107
1076
|
}
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
selectedProduct: buildSelectedProductSummary(selectedProduct, selectionMode),
|
|
1077
|
+
printResult({
|
|
1078
|
+
products: queriedProducts,
|
|
1079
|
+
selectedProduct,
|
|
1112
1080
|
upload,
|
|
1113
|
-
publish: publishResult.publish
|
|
1114
|
-
|
|
1115
|
-
};
|
|
1116
|
-
printResult(result);
|
|
1081
|
+
publish: publishResult.publish
|
|
1082
|
+
});
|
|
1117
1083
|
} catch (err) {
|
|
1118
1084
|
rethrowIfProcessExit(err);
|
|
1119
1085
|
console.error("TTS \u5B8C\u6574\u53D1\u5E03\u6D41\u7A0B\u5931\u8D25:", err.message);
|
|
@@ -1164,7 +1130,7 @@ function register10(cli2) {
|
|
|
1164
1130
|
|
|
1165
1131
|
// src/cli.ts
|
|
1166
1132
|
var cli = cac("beervid");
|
|
1167
|
-
var cliVersion = true ? "0.2.
|
|
1133
|
+
var cliVersion = true ? "0.2.4" : pkg.version;
|
|
1168
1134
|
register10(cli);
|
|
1169
1135
|
register(cli);
|
|
1170
1136
|
register2(cli);
|