beervid-app-cli 0.1.0
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 +67 -0
- package/SKILL.md +460 -0
- package/dist/cli.mjs +1125 -0
- package/package.json +42 -0
package/dist/cli.mjs
ADDED
|
@@ -0,0 +1,1125 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/cli.ts
|
|
4
|
+
import cac from "cac";
|
|
5
|
+
|
|
6
|
+
// src/client/index.ts
|
|
7
|
+
import { readFileSync, existsSync } from "fs";
|
|
8
|
+
import { resolve, basename } from "path";
|
|
9
|
+
function getApiKey() {
|
|
10
|
+
const key = process.env["BEERVID_APP_KEY"];
|
|
11
|
+
if (!key) {
|
|
12
|
+
console.error("\u9519\u8BEF: \u8BF7\u8BBE\u7F6E\u73AF\u5883\u53D8\u91CF BEERVID_APP_KEY");
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
return key;
|
|
16
|
+
}
|
|
17
|
+
function getBaseUrl() {
|
|
18
|
+
return process.env["BEERVID_APP_BASE_URL"] ?? "https://open.beervid.ai";
|
|
19
|
+
}
|
|
20
|
+
async function handleResponse(res, path) {
|
|
21
|
+
if (!res.ok && res.status >= 500) {
|
|
22
|
+
throw new Error(`HTTP ${res.status} \u2014 ${path}`);
|
|
23
|
+
}
|
|
24
|
+
const json = await res.json();
|
|
25
|
+
if (json.code !== 0 || !json.success) {
|
|
26
|
+
throw new Error(
|
|
27
|
+
`Open API \u9519\u8BEF [${path}]: ${json.message ?? "\u672A\u77E5\u9519\u8BEF"} (code: ${json.code})`
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
return json.data;
|
|
31
|
+
}
|
|
32
|
+
async function openApiGet(path, params) {
|
|
33
|
+
const url = new URL(path, getBaseUrl());
|
|
34
|
+
if (params) {
|
|
35
|
+
for (const [k, v] of Object.entries(params)) {
|
|
36
|
+
url.searchParams.set(k, v);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
const res = await fetch(url.toString(), {
|
|
40
|
+
method: "GET",
|
|
41
|
+
headers: {
|
|
42
|
+
"X-API-KEY": getApiKey(),
|
|
43
|
+
"Content-Type": "application/json"
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
return handleResponse(res, path);
|
|
47
|
+
}
|
|
48
|
+
async function openApiPost(path, body) {
|
|
49
|
+
const url = new URL(path, getBaseUrl());
|
|
50
|
+
const res = await fetch(url.toString(), {
|
|
51
|
+
method: "POST",
|
|
52
|
+
headers: {
|
|
53
|
+
"X-API-KEY": getApiKey(),
|
|
54
|
+
"Content-Type": "application/json"
|
|
55
|
+
},
|
|
56
|
+
body: body ? JSON.stringify(body) : void 0
|
|
57
|
+
});
|
|
58
|
+
return handleResponse(res, path);
|
|
59
|
+
}
|
|
60
|
+
async function openApiUpload(path, formData, params, auth) {
|
|
61
|
+
const url = new URL(path, getBaseUrl());
|
|
62
|
+
if (params) {
|
|
63
|
+
for (const [k, v] of Object.entries(params)) {
|
|
64
|
+
url.searchParams.set(k, v);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
const headerName = auth?.headerName ?? "X-API-KEY";
|
|
68
|
+
const headerValue = auth?.headerValue ?? getApiKey();
|
|
69
|
+
const res = await fetch(url.toString(), {
|
|
70
|
+
method: "POST",
|
|
71
|
+
headers: { [headerName]: headerValue },
|
|
72
|
+
body: formData
|
|
73
|
+
});
|
|
74
|
+
return handleResponse(res, path);
|
|
75
|
+
}
|
|
76
|
+
function detectInputType(input2) {
|
|
77
|
+
if (/^https?:\/\//i.test(input2)) return "url";
|
|
78
|
+
return "file";
|
|
79
|
+
}
|
|
80
|
+
function localFileToFile(filePath) {
|
|
81
|
+
const absPath = resolve(filePath);
|
|
82
|
+
if (!existsSync(absPath)) {
|
|
83
|
+
console.error(`\u9519\u8BEF: \u6587\u4EF6\u4E0D\u5B58\u5728 \u2014 ${absPath}`);
|
|
84
|
+
process.exit(1);
|
|
85
|
+
}
|
|
86
|
+
const buffer = readFileSync(absPath);
|
|
87
|
+
const fileName = basename(absPath);
|
|
88
|
+
const ext = fileName.split(".").pop()?.toLowerCase();
|
|
89
|
+
const mimeMap = {
|
|
90
|
+
mp4: "video/mp4",
|
|
91
|
+
mov: "video/quicktime",
|
|
92
|
+
avi: "video/x-msvideo",
|
|
93
|
+
webm: "video/webm",
|
|
94
|
+
mkv: "video/x-matroska"
|
|
95
|
+
};
|
|
96
|
+
const contentType = ext && mimeMap[ext] ? mimeMap[ext] : "application/octet-stream";
|
|
97
|
+
return new File([buffer], fileName, { type: contentType });
|
|
98
|
+
}
|
|
99
|
+
async function urlToFile(url) {
|
|
100
|
+
console.log(`\u6B63\u5728\u4E0B\u8F7D: ${url}`);
|
|
101
|
+
const res = await fetch(url);
|
|
102
|
+
if (!res.ok) {
|
|
103
|
+
throw new Error(`\u4E0B\u8F7D\u5931\u8D25: HTTP ${res.status} \u2014 ${url}`);
|
|
104
|
+
}
|
|
105
|
+
const buffer = await res.arrayBuffer();
|
|
106
|
+
const contentType = res.headers.get("content-type") ?? "video/mp4";
|
|
107
|
+
const urlPath = new URL(url).pathname;
|
|
108
|
+
const fileName = urlPath.split("/").pop() ?? "video.mp4";
|
|
109
|
+
console.log(`\u4E0B\u8F7D\u5B8C\u6210: ${fileName} (${(buffer.byteLength / 1024 / 1024).toFixed(1)} MB)`);
|
|
110
|
+
return new File([buffer], fileName, { type: contentType });
|
|
111
|
+
}
|
|
112
|
+
async function resolveFileInput(input2) {
|
|
113
|
+
if (detectInputType(input2) === "url") {
|
|
114
|
+
return urlToFile(input2);
|
|
115
|
+
}
|
|
116
|
+
return localFileToFile(input2);
|
|
117
|
+
}
|
|
118
|
+
function printResult(data) {
|
|
119
|
+
console.log(JSON.stringify(data, null, 2));
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// src/commands/utils.ts
|
|
123
|
+
function rethrowIfProcessExit(error) {
|
|
124
|
+
if (typeof error === "object" && error !== null && "name" in error && error.name === "ProcessExitError") {
|
|
125
|
+
throw error;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// src/commands/oauth.ts
|
|
130
|
+
function register(cli2) {
|
|
131
|
+
cli2.command("get-oauth-url", "\u83B7\u53D6 TikTok OAuth \u6388\u6743\u94FE\u63A5").option("--type <type>", "\u8D26\u53F7\u7C7B\u578B: tt\uFF08\u666E\u901A\u8D26\u53F7\uFF09\u6216 tts\uFF08Shop \u8D26\u53F7\uFF09").action(async (options) => {
|
|
132
|
+
if (!options.type) {
|
|
133
|
+
console.error("\u7F3A\u5C11\u5FC5\u586B\u53C2\u6570: --type\n");
|
|
134
|
+
console.error("\u7528\u6CD5: beervid get-oauth-url --type <tt|tts>");
|
|
135
|
+
process.exit(1);
|
|
136
|
+
}
|
|
137
|
+
const type = options.type.toLowerCase();
|
|
138
|
+
if (type !== "tt" && type !== "tts") {
|
|
139
|
+
console.error("\u9519\u8BEF: --type \u5FC5\u987B\u4E3A tt \u6216 tts");
|
|
140
|
+
process.exit(1);
|
|
141
|
+
}
|
|
142
|
+
try {
|
|
143
|
+
if (type === "tt") {
|
|
144
|
+
const data = await openApiGet("/api/v1/open/thirdparty-auth/tt-url");
|
|
145
|
+
console.log("TT OAuth \u6388\u6743\u94FE\u63A5:");
|
|
146
|
+
printResult({ type: "tt", url: data });
|
|
147
|
+
} else {
|
|
148
|
+
const data = await openApiGet("/api/v1/open/thirdparty-auth/tts-url");
|
|
149
|
+
console.log("TTS OAuth \u6388\u6743\u94FE\u63A5:");
|
|
150
|
+
printResult({ type: "tts", url: data.crossBorderUrl });
|
|
151
|
+
}
|
|
152
|
+
} catch (err) {
|
|
153
|
+
rethrowIfProcessExit(err);
|
|
154
|
+
console.error("\u83B7\u53D6 OAuth URL \u5931\u8D25:", err.message);
|
|
155
|
+
process.exit(1);
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// src/commands/account.ts
|
|
161
|
+
function register2(cli2) {
|
|
162
|
+
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) => {
|
|
163
|
+
if (!options.type || !options.accountId) {
|
|
164
|
+
const missing = [!options.type && "--type", !options.accountId && "--account-id"].filter(Boolean).join(", ");
|
|
165
|
+
console.error(`\u7F3A\u5C11\u5FC5\u586B\u53C2\u6570: ${missing}
|
|
166
|
+
`);
|
|
167
|
+
console.error("\u7528\u6CD5: beervid get-account-info --type <TT|TTS> --account-id <id>");
|
|
168
|
+
process.exit(1);
|
|
169
|
+
}
|
|
170
|
+
const accountType = options.type.toUpperCase();
|
|
171
|
+
if (accountType !== "TT" && accountType !== "TTS") {
|
|
172
|
+
console.error("\u9519\u8BEF: --type \u5FC5\u987B\u4E3A TT \u6216 TTS");
|
|
173
|
+
process.exit(1);
|
|
174
|
+
}
|
|
175
|
+
try {
|
|
176
|
+
const data = await openApiPost("/api/v1/open/account/info", {
|
|
177
|
+
accountType,
|
|
178
|
+
accountId: options.accountId
|
|
179
|
+
});
|
|
180
|
+
printResult(data);
|
|
181
|
+
} catch (err) {
|
|
182
|
+
rethrowIfProcessExit(err);
|
|
183
|
+
console.error("\u67E5\u8BE2\u8D26\u53F7\u4FE1\u606F\u5931\u8D25:", err.message);
|
|
184
|
+
process.exit(1);
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// src/utils/upload.ts
|
|
190
|
+
async function getUploadToken(existingToken) {
|
|
191
|
+
if (existingToken) return existingToken;
|
|
192
|
+
const tokenData = await openApiPost("/api/v1/open/upload-token/generate");
|
|
193
|
+
return tokenData.uploadToken;
|
|
194
|
+
}
|
|
195
|
+
async function uploadNormalVideo(fileInput, uploadToken) {
|
|
196
|
+
const file = await resolveFileInput(fileInput);
|
|
197
|
+
const token = await getUploadToken(uploadToken);
|
|
198
|
+
const formData = new FormData();
|
|
199
|
+
formData.append("file", file);
|
|
200
|
+
return openApiUpload(
|
|
201
|
+
"/api/v1/open/file-upload",
|
|
202
|
+
formData,
|
|
203
|
+
void 0,
|
|
204
|
+
{ headerName: "X-UPLOAD-TOKEN", headerValue: token }
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
async function uploadTtsVideo(fileInput, creatorId, uploadToken) {
|
|
208
|
+
const file = await resolveFileInput(fileInput);
|
|
209
|
+
const token = await getUploadToken(uploadToken);
|
|
210
|
+
const formData = new FormData();
|
|
211
|
+
formData.append("file", file);
|
|
212
|
+
return openApiUpload(
|
|
213
|
+
"/api/v1/open/file-upload/tts-video",
|
|
214
|
+
formData,
|
|
215
|
+
{ creatorUserOpenId: creatorId },
|
|
216
|
+
{ headerName: "X-UPLOAD-TOKEN", headerValue: token }
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// src/commands/upload.ts
|
|
221
|
+
var VALID_UPLOAD_TYPES = ["normal", "tts"];
|
|
222
|
+
function register3(cli2) {
|
|
223
|
+
cli2.command("upload", "\u4E0A\u4F20\u89C6\u9891\u6587\u4EF6\uFF08\u652F\u6301\u672C\u5730\u6587\u4EF6\u548C URL\uFF09").option("--file <path>", "\u89C6\u9891\u6587\u4EF6\u8DEF\u5F84\u6216 URL\uFF08\u5FC5\u586B\uFF09").option("--type <type>", "\u4E0A\u4F20\u7C7B\u578B: normal\uFF08\u9ED8\u8BA4\uFF09\u6216 tts").option("--creator-id <id>", "TTS \u8D26\u53F7 creatorUserOpenId\uFF08type=tts \u65F6\u5FC5\u586B\uFF09").option("--token <token>", "\u5DF2\u6709\u7684\u4E0A\u4F20\u51ED\u8BC1\uFF08\u53EF\u9009\uFF0C\u4E0D\u4F20\u5219\u81EA\u52A8\u83B7\u53D6\uFF09").action(
|
|
224
|
+
async (options) => {
|
|
225
|
+
if (!options.file) {
|
|
226
|
+
console.error("\u7F3A\u5C11\u5FC5\u586B\u53C2\u6570: --file\n");
|
|
227
|
+
console.error(
|
|
228
|
+
"\u7528\u6CD5: beervid upload --file <\u8DEF\u5F84\u6216URL> [--type tts --creator-id <id>]"
|
|
229
|
+
);
|
|
230
|
+
process.exit(1);
|
|
231
|
+
}
|
|
232
|
+
const uploadType = (options.type ?? "normal").toLowerCase();
|
|
233
|
+
if (!VALID_UPLOAD_TYPES.includes(uploadType)) {
|
|
234
|
+
console.error("\u9519\u8BEF: --type \u5FC5\u987B\u4E3A normal \u6216 tts");
|
|
235
|
+
process.exit(1);
|
|
236
|
+
}
|
|
237
|
+
if (uploadType === "tts" && !options.creatorId) {
|
|
238
|
+
console.error("\u9519\u8BEF: TTS \u4E0A\u4F20\u6A21\u5F0F\u9700\u8981 --creator-id \u53C2\u6570");
|
|
239
|
+
process.exit(1);
|
|
240
|
+
}
|
|
241
|
+
try {
|
|
242
|
+
let data;
|
|
243
|
+
if (uploadType === "tts") {
|
|
244
|
+
console.log(`TTS \u4E0A\u4F20\u6A21\u5F0F\uFF0CcreatorUserOpenId: ${options.creatorId}`);
|
|
245
|
+
data = await uploadTtsVideo(options.file, options.creatorId, options.token);
|
|
246
|
+
} else {
|
|
247
|
+
console.log("\u666E\u901A\u4E0A\u4F20\u6A21\u5F0F");
|
|
248
|
+
data = await uploadNormalVideo(options.file, options.token);
|
|
249
|
+
}
|
|
250
|
+
console.log("\n\u4E0A\u4F20\u6210\u529F:");
|
|
251
|
+
printResult(data);
|
|
252
|
+
} catch (err) {
|
|
253
|
+
rethrowIfProcessExit(err);
|
|
254
|
+
console.error("\u4E0A\u4F20\u5931\u8D25:", err.message);
|
|
255
|
+
process.exit(1);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// src/commands/publish.ts
|
|
262
|
+
var MAX_PRODUCT_TITLE_LENGTH = 29;
|
|
263
|
+
var VALID_PUBLISH_TYPES = ["normal", "shoppable"];
|
|
264
|
+
function register4(cli2) {
|
|
265
|
+
cli2.command("publish", "\u53D1\u5E03 TikTok \u89C6\u9891\uFF08\u666E\u901A/\u6302\u8F66\uFF09").option("--type <type>", "\u53D1\u5E03\u7C7B\u578B: normal\uFF08\u9ED8\u8BA4\uFF09\u6216 shoppable").option("--business-id <id>", "TT \u8D26\u53F7 businessId\uFF08\u666E\u901A\u53D1\u5E03\u5FC5\u586B\uFF09").option("--video-url <url>", "\u4E0A\u4F20\u540E\u7684\u89C6\u9891 URL\uFF08\u666E\u901A\u53D1\u5E03\u5FC5\u586B\uFF09").option("--creator-id <id>", "TTS \u8D26\u53F7 creatorUserOpenId\uFF08\u6302\u8F66\u53D1\u5E03\u5FC5\u586B\uFF09").option("--file-id <id>", "\u4E0A\u4F20\u8FD4\u56DE\u7684 videoFileId\uFF08\u6302\u8F66\u53D1\u5E03\u5FC5\u586B\uFF09").option("--product-id <id>", "\u5546\u54C1 ID\uFF08\u6302\u8F66\u53D1\u5E03\u5FC5\u586B\uFF09").option("--product-title <title>", "\u5546\u54C1\u6807\u9898\uFF0C\u6700\u591A 29 \u5B57\u7B26\uFF08\u6302\u8F66\u53D1\u5E03\u5FC5\u586B\uFF09", {
|
|
266
|
+
type: [String]
|
|
267
|
+
}).option("--caption <text>", "\u89C6\u9891\u63CF\u8FF0/\u6587\u6848\uFF08\u53EF\u9009\uFF09").action(
|
|
268
|
+
async (options) => {
|
|
269
|
+
const publishType = (options.type ?? "normal").toLowerCase();
|
|
270
|
+
if (!VALID_PUBLISH_TYPES.includes(publishType)) {
|
|
271
|
+
console.error("\u9519\u8BEF: --type \u5FC5\u987B\u4E3A normal \u6216 shoppable");
|
|
272
|
+
process.exit(1);
|
|
273
|
+
}
|
|
274
|
+
try {
|
|
275
|
+
let data;
|
|
276
|
+
if (publishType === "shoppable") {
|
|
277
|
+
const missing = [
|
|
278
|
+
!options.creatorId && "--creator-id",
|
|
279
|
+
!options.fileId && "--file-id",
|
|
280
|
+
!options.productId && "--product-id",
|
|
281
|
+
!options.productTitle && "--product-title"
|
|
282
|
+
].filter(Boolean);
|
|
283
|
+
if (missing.length > 0) {
|
|
284
|
+
console.error(`\u7F3A\u5C11\u5FC5\u586B\u53C2\u6570: ${missing.join(", ")}
|
|
285
|
+
`);
|
|
286
|
+
console.error(
|
|
287
|
+
"beervid publish --type shoppable --creator-id <id> --file-id <id> --product-id <id> --product-title <title> [--caption <text>]"
|
|
288
|
+
);
|
|
289
|
+
process.exit(1);
|
|
290
|
+
}
|
|
291
|
+
const rawProductTitle = String(options.productTitle);
|
|
292
|
+
const productTitle = rawProductTitle.slice(0, MAX_PRODUCT_TITLE_LENGTH);
|
|
293
|
+
if (rawProductTitle.length > MAX_PRODUCT_TITLE_LENGTH) {
|
|
294
|
+
console.log(
|
|
295
|
+
`\u6CE8\u610F: productTitle \u8D85\u8FC7 ${MAX_PRODUCT_TITLE_LENGTH} \u5B57\u7B26\uFF0C\u5DF2\u81EA\u52A8\u622A\u65AD\u4E3A: "${productTitle}"`
|
|
296
|
+
);
|
|
297
|
+
}
|
|
298
|
+
console.log("\u6302\u8F66\u89C6\u9891\u53D1\u5E03\u4E2D...");
|
|
299
|
+
data = await openApiPost(
|
|
300
|
+
"/api/v1/open/tts/shoppable-video/publish",
|
|
301
|
+
{
|
|
302
|
+
creatorUserOpenId: options.creatorId,
|
|
303
|
+
fileId: options.fileId,
|
|
304
|
+
title: options.caption ?? "",
|
|
305
|
+
productId: options.productId,
|
|
306
|
+
productTitle
|
|
307
|
+
}
|
|
308
|
+
);
|
|
309
|
+
console.log("\n\u53D1\u5E03\u6210\u529F\uFF08\u6302\u8F66\u89C6\u9891\u7ACB\u5373\u5B8C\u6210\uFF09:");
|
|
310
|
+
} else {
|
|
311
|
+
const missing = [
|
|
312
|
+
!options.businessId && "--business-id",
|
|
313
|
+
!options.videoUrl && "--video-url"
|
|
314
|
+
].filter(Boolean);
|
|
315
|
+
if (missing.length > 0) {
|
|
316
|
+
console.error(`\u7F3A\u5C11\u5FC5\u586B\u53C2\u6570: ${missing.join(", ")}
|
|
317
|
+
`);
|
|
318
|
+
console.error(
|
|
319
|
+
"beervid publish --type normal --business-id <id> --video-url <url> [--caption <text>]"
|
|
320
|
+
);
|
|
321
|
+
process.exit(1);
|
|
322
|
+
}
|
|
323
|
+
console.log("\u666E\u901A\u89C6\u9891\u53D1\u5E03\u4E2D...");
|
|
324
|
+
data = await openApiPost(
|
|
325
|
+
"/api/v1/open/tiktok/video/publish",
|
|
326
|
+
{
|
|
327
|
+
businessId: options.businessId,
|
|
328
|
+
videoUrl: options.videoUrl,
|
|
329
|
+
caption: options.caption ?? ""
|
|
330
|
+
}
|
|
331
|
+
);
|
|
332
|
+
console.log("\n\u53D1\u5E03\u5DF2\u63D0\u4EA4\uFF08\u9700\u8F6E\u8BE2\u72B6\u6001\uFF09:");
|
|
333
|
+
console.log(
|
|
334
|
+
`\u63D0\u793A: \u4F7F\u7528 beervid poll-status --business-id ${options.businessId} --share-id ${data.shareId} \u8F6E\u8BE2\u8FDB\u5EA6`
|
|
335
|
+
);
|
|
336
|
+
}
|
|
337
|
+
printResult(data);
|
|
338
|
+
} catch (err) {
|
|
339
|
+
rethrowIfProcessExit(err);
|
|
340
|
+
console.error("\u53D1\u5E03\u5931\u8D25:", err.message);
|
|
341
|
+
process.exit(1);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// src/commands/poll-status.ts
|
|
348
|
+
var TERMINAL_STATUSES = ["PUBLISH_COMPLETE", "FAILED"];
|
|
349
|
+
function sleep(ms) {
|
|
350
|
+
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
351
|
+
}
|
|
352
|
+
function register5(cli2) {
|
|
353
|
+
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 3\uFF09").option("--max-polls <n>", "\u6700\u5927\u8F6E\u8BE2\u6B21\u6570\uFF08\u9ED8\u8BA4 60\uFF09").action(
|
|
354
|
+
async (options) => {
|
|
355
|
+
if (!options.businessId || !options.shareId) {
|
|
356
|
+
const missing = [
|
|
357
|
+
!options.businessId && "--business-id",
|
|
358
|
+
!options.shareId && "--share-id"
|
|
359
|
+
].filter(Boolean);
|
|
360
|
+
console.error(`\u7F3A\u5C11\u5FC5\u586B\u53C2\u6570: ${missing.join(", ")}
|
|
361
|
+
`);
|
|
362
|
+
console.error("\u7528\u6CD5: beervid poll-status --business-id <id> --share-id <id>");
|
|
363
|
+
process.exit(1);
|
|
364
|
+
}
|
|
365
|
+
const intervalSec = parseInt(options.interval ?? "3", 10);
|
|
366
|
+
const maxPolls = parseInt(options.maxPolls ?? "60", 10);
|
|
367
|
+
if (Number.isNaN(intervalSec) || intervalSec <= 0) {
|
|
368
|
+
console.error("\u9519\u8BEF: --interval \u5FC5\u987B\u4E3A\u5927\u4E8E 0 \u7684\u6574\u6570");
|
|
369
|
+
process.exit(1);
|
|
370
|
+
}
|
|
371
|
+
if (Number.isNaN(maxPolls) || maxPolls <= 0) {
|
|
372
|
+
console.error("\u9519\u8BEF: --max-polls \u5FC5\u987B\u4E3A\u5927\u4E8E 0 \u7684\u6574\u6570");
|
|
373
|
+
process.exit(1);
|
|
374
|
+
}
|
|
375
|
+
try {
|
|
376
|
+
console.log(`\u5F00\u59CB\u8F6E\u8BE2\u53D1\u5E03\u72B6\u6001 (\u95F4\u9694 ${intervalSec}s, \u6700\u591A ${maxPolls} \u6B21)`);
|
|
377
|
+
console.log(`businessId: ${options.businessId}`);
|
|
378
|
+
console.log(`shareId: ${options.shareId}
|
|
379
|
+
`);
|
|
380
|
+
for (let i = 1; i <= maxPolls; i++) {
|
|
381
|
+
const data = await openApiPost("/api/v1/open/tiktok/video/status", {
|
|
382
|
+
businessId: options.businessId,
|
|
383
|
+
shareId: options.shareId
|
|
384
|
+
});
|
|
385
|
+
const status = data.status ?? data.Status ?? "UNKNOWN";
|
|
386
|
+
console.log(`[${i}/${maxPolls}] \u72B6\u6001: ${status}`);
|
|
387
|
+
if (TERMINAL_STATUSES.includes(status)) {
|
|
388
|
+
console.log("");
|
|
389
|
+
if (status === "PUBLISH_COMPLETE") {
|
|
390
|
+
console.log("\u53D1\u5E03\u6210\u529F!");
|
|
391
|
+
if (data.post_ids && data.post_ids.length > 0) {
|
|
392
|
+
console.log(`\u89C6\u9891 ID: ${data.post_ids[0]}`);
|
|
393
|
+
console.log(
|
|
394
|
+
`\u63D0\u793A: \u4F7F\u7528 beervid query-video --business-id ${options.businessId} --item-ids ${data.post_ids[0]} \u67E5\u8BE2\u6570\u636E`
|
|
395
|
+
);
|
|
396
|
+
}
|
|
397
|
+
} else {
|
|
398
|
+
console.log(`\u53D1\u5E03\u5931\u8D25: ${data.reason ?? "\u672A\u77E5\u539F\u56E0"}`);
|
|
399
|
+
}
|
|
400
|
+
printResult(data);
|
|
401
|
+
process.exit(status === "PUBLISH_COMPLETE" ? 0 : 1);
|
|
402
|
+
}
|
|
403
|
+
if (i < maxPolls) {
|
|
404
|
+
await sleep(intervalSec * 1e3);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
console.error(`
|
|
408
|
+
\u8D85\u8FC7\u6700\u5927\u8F6E\u8BE2\u6B21\u6570 (${maxPolls})\uFF0C\u72B6\u6001\u4ECD\u672A\u7EC8\u7ED3`);
|
|
409
|
+
process.exit(2);
|
|
410
|
+
} catch (err) {
|
|
411
|
+
rethrowIfProcessExit(err);
|
|
412
|
+
console.error("\u8F6E\u8BE2\u5931\u8D25:", err.message);
|
|
413
|
+
process.exit(1);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
);
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// src/commands/query-video.ts
|
|
420
|
+
function register6(cli2) {
|
|
421
|
+
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\u591A\u4E2A\u7528\u9017\u53F7\u5206\u9694\uFF08\u5FC5\u586B\uFF09").action(
|
|
422
|
+
async (options) => {
|
|
423
|
+
if (!options.businessId || !options.itemIds) {
|
|
424
|
+
const missing = [
|
|
425
|
+
!options.businessId && "--business-id",
|
|
426
|
+
!options.itemIds && "--item-ids"
|
|
427
|
+
].filter(Boolean);
|
|
428
|
+
console.error(`\u7F3A\u5C11\u5FC5\u586B\u53C2\u6570: ${missing.join(", ")}
|
|
429
|
+
`);
|
|
430
|
+
console.error(
|
|
431
|
+
"\u7528\u6CD5: beervid query-video --business-id <id> --item-ids <id1,id2,...>"
|
|
432
|
+
);
|
|
433
|
+
process.exit(1);
|
|
434
|
+
}
|
|
435
|
+
const itemIds = options.itemIds.split(",").map((id) => id.trim()).filter(Boolean);
|
|
436
|
+
if (itemIds.length === 0) {
|
|
437
|
+
console.error("\u9519\u8BEF: --item-ids \u4E0D\u80FD\u4E3A\u7A7A");
|
|
438
|
+
process.exit(1);
|
|
439
|
+
}
|
|
440
|
+
try {
|
|
441
|
+
console.log(`\u67E5\u8BE2 ${itemIds.length} \u4E2A\u89C6\u9891\u7684\u6570\u636E...
|
|
442
|
+
`);
|
|
443
|
+
const data = await openApiPost("/api/v1/open/tiktok/video/query", {
|
|
444
|
+
businessId: options.businessId,
|
|
445
|
+
itemIds
|
|
446
|
+
});
|
|
447
|
+
const list = data.videoList ?? data.videos ?? [];
|
|
448
|
+
if (list.length === 0) {
|
|
449
|
+
console.log("\u672A\u67E5\u5230\u89C6\u9891\u6570\u636E");
|
|
450
|
+
process.exit(0);
|
|
451
|
+
}
|
|
452
|
+
const normalized = list.map((v) => ({
|
|
453
|
+
itemId: v.itemId ?? v.item_id,
|
|
454
|
+
videoViews: v.videoViews ?? v.video_views ?? 0,
|
|
455
|
+
likes: v.likes ?? 0,
|
|
456
|
+
comments: v.comments ?? 0,
|
|
457
|
+
shares: v.shares ?? 0,
|
|
458
|
+
thumbnailUrl: v.thumbnailUrl ?? v.thumbnail_url ?? "",
|
|
459
|
+
shareUrl: v.shareUrl ?? v.share_url ?? ""
|
|
460
|
+
}));
|
|
461
|
+
console.log(`\u67E5\u8BE2\u5230 ${normalized.length} \u4E2A\u89C6\u9891:
|
|
462
|
+
`);
|
|
463
|
+
for (const v of normalized) {
|
|
464
|
+
console.log(` \u89C6\u9891 ${v.itemId}`);
|
|
465
|
+
console.log(
|
|
466
|
+
` \u64AD\u653E: ${v.videoViews} \u70B9\u8D5E: ${v.likes} \u8BC4\u8BBA: ${v.comments} \u5206\u4EAB: ${v.shares}`
|
|
467
|
+
);
|
|
468
|
+
if (v.shareUrl) console.log(` \u94FE\u63A5: ${v.shareUrl}`);
|
|
469
|
+
console.log("");
|
|
470
|
+
}
|
|
471
|
+
printResult({ videos: normalized, _raw: data });
|
|
472
|
+
} catch (err) {
|
|
473
|
+
rethrowIfProcessExit(err);
|
|
474
|
+
console.error("\u67E5\u8BE2\u89C6\u9891\u6570\u636E\u5931\u8D25:", err.message);
|
|
475
|
+
process.exit(1);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
);
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
// src/commands/query-products.ts
|
|
482
|
+
var VALID_PRODUCT_TYPES = ["shop", "showcase", "all"];
|
|
483
|
+
function extractImageUrl(imageStr) {
|
|
484
|
+
const match = imageStr.match(/url=([^,}]+)/);
|
|
485
|
+
return match?.[1]?.trim() ?? imageStr;
|
|
486
|
+
}
|
|
487
|
+
async function queryProducts(creatorId, type, pageSize, pageToken) {
|
|
488
|
+
return openApiPost("/api/v1/open/tts/products/query", {
|
|
489
|
+
creatorUserOpenId: creatorId,
|
|
490
|
+
productType: type,
|
|
491
|
+
pageSize,
|
|
492
|
+
pageToken
|
|
493
|
+
});
|
|
494
|
+
}
|
|
495
|
+
function register7(cli2) {
|
|
496
|
+
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(
|
|
497
|
+
async (options) => {
|
|
498
|
+
if (!options.creatorId) {
|
|
499
|
+
console.error("\u7F3A\u5C11\u5FC5\u586B\u53C2\u6570: --creator-id\n");
|
|
500
|
+
console.error("\u7528\u6CD5: beervid query-products --creator-id <id>");
|
|
501
|
+
process.exit(1);
|
|
502
|
+
}
|
|
503
|
+
const creatorId = options.creatorId;
|
|
504
|
+
const productType = (options.productType ?? "all").toLowerCase();
|
|
505
|
+
const pageSize = parseInt(options.pageSize ?? "20", 10);
|
|
506
|
+
const cursor = options.cursor ?? "";
|
|
507
|
+
if (!VALID_PRODUCT_TYPES.includes(productType)) {
|
|
508
|
+
console.error("\u9519\u8BEF: --product-type \u5FC5\u987B\u4E3A shop\u3001showcase \u6216 all");
|
|
509
|
+
process.exit(1);
|
|
510
|
+
}
|
|
511
|
+
if (Number.isNaN(pageSize) || pageSize <= 0) {
|
|
512
|
+
console.error("\u9519\u8BEF: --page-size \u5FC5\u987B\u4E3A\u5927\u4E8E 0 \u7684\u6574\u6570");
|
|
513
|
+
process.exit(1);
|
|
514
|
+
}
|
|
515
|
+
try {
|
|
516
|
+
let shopToken = "";
|
|
517
|
+
let showcaseToken = "";
|
|
518
|
+
if (cursor) {
|
|
519
|
+
try {
|
|
520
|
+
const decoded = JSON.parse(
|
|
521
|
+
Buffer.from(cursor, "base64").toString()
|
|
522
|
+
);
|
|
523
|
+
shopToken = decoded.shopToken ?? "";
|
|
524
|
+
showcaseToken = decoded.showcaseToken ?? "";
|
|
525
|
+
} catch {
|
|
526
|
+
console.error("\u9519\u8BEF: \u65E0\u6548\u7684 cursor \u683C\u5F0F");
|
|
527
|
+
process.exit(1);
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
const typesToQuery = productType === "all" ? ["shop", "showcase"] : [productType];
|
|
531
|
+
const allProducts = /* @__PURE__ */ new Map();
|
|
532
|
+
let nextShopToken = null;
|
|
533
|
+
let nextShowcaseToken = null;
|
|
534
|
+
let successCount = 0;
|
|
535
|
+
const results = await Promise.allSettled(
|
|
536
|
+
typesToQuery.map(async (type) => {
|
|
537
|
+
const token = type === "shop" ? shopToken : showcaseToken;
|
|
538
|
+
const data = await queryProducts(creatorId, type, pageSize, token);
|
|
539
|
+
return { type, data };
|
|
540
|
+
})
|
|
541
|
+
);
|
|
542
|
+
for (const result of results) {
|
|
543
|
+
if (result.status === "rejected") {
|
|
544
|
+
console.error("\u67E5\u8BE2\u5931\u8D25:", result.reason?.message);
|
|
545
|
+
continue;
|
|
546
|
+
}
|
|
547
|
+
const { type, data } = result.value;
|
|
548
|
+
successCount += 1;
|
|
549
|
+
const items = Array.isArray(data) ? data : [data];
|
|
550
|
+
for (const group of items) {
|
|
551
|
+
if (type === "shop") nextShopToken = group.nextPageToken ?? null;
|
|
552
|
+
if (type === "showcase") nextShowcaseToken = group.nextPageToken ?? null;
|
|
553
|
+
for (const product of group.products ?? []) {
|
|
554
|
+
if (!allProducts.has(product.id)) {
|
|
555
|
+
allProducts.set(product.id, {
|
|
556
|
+
id: product.id,
|
|
557
|
+
title: product.title,
|
|
558
|
+
price: product.price,
|
|
559
|
+
images: (product.images ?? []).map(extractImageUrl),
|
|
560
|
+
salesCount: product.salesCount ?? 0,
|
|
561
|
+
brandName: product.brandName ?? "",
|
|
562
|
+
shopName: product.shopName ?? "",
|
|
563
|
+
source: product.source ?? type,
|
|
564
|
+
reviewStatus: product.reviewStatus,
|
|
565
|
+
inventoryStatus: product.inventoryStatus
|
|
566
|
+
});
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
if (successCount === 0) {
|
|
572
|
+
console.error("\u67E5\u8BE2\u5546\u54C1\u5931\u8D25: \u6240\u6709\u5546\u54C1\u6E90\u90FD\u8BF7\u6C42\u5931\u8D25");
|
|
573
|
+
process.exit(1);
|
|
574
|
+
}
|
|
575
|
+
const productList = Array.from(allProducts.values());
|
|
576
|
+
let nextCursor = null;
|
|
577
|
+
if (nextShopToken || nextShowcaseToken) {
|
|
578
|
+
nextCursor = Buffer.from(
|
|
579
|
+
JSON.stringify({
|
|
580
|
+
shopToken: nextShopToken ?? "",
|
|
581
|
+
showcaseToken: nextShowcaseToken ?? ""
|
|
582
|
+
})
|
|
583
|
+
).toString("base64");
|
|
584
|
+
}
|
|
585
|
+
console.log(`\u67E5\u8BE2\u5230 ${productList.length} \u4E2A\u5546\u54C1:
|
|
586
|
+
`);
|
|
587
|
+
for (const p of productList) {
|
|
588
|
+
console.log(` [${p.source}] ${p.title}`);
|
|
589
|
+
console.log(` ID: ${p.id} \u9500\u91CF: ${p.salesCount} \u54C1\u724C: ${p.brandName}`);
|
|
590
|
+
if (p.images.length > 0) console.log(` \u56FE\u7247: ${p.images[0]}`);
|
|
591
|
+
console.log("");
|
|
592
|
+
}
|
|
593
|
+
if (nextCursor) {
|
|
594
|
+
console.log(`\u4E0B\u4E00\u9875\u6E38\u6807: ${nextCursor}`);
|
|
595
|
+
console.log(`\u4F7F\u7528: beervid query-products --creator-id ${creatorId} --cursor ${nextCursor}`);
|
|
596
|
+
} else {
|
|
597
|
+
console.log("\u5DF2\u5230\u6700\u540E\u4E00\u9875");
|
|
598
|
+
}
|
|
599
|
+
printResult({ products: productList, nextCursor });
|
|
600
|
+
} catch (err) {
|
|
601
|
+
rethrowIfProcessExit(err);
|
|
602
|
+
console.error("\u67E5\u8BE2\u5546\u54C1\u5931\u8D25:", err.message);
|
|
603
|
+
process.exit(1);
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
);
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
// src/workflows/index.ts
|
|
610
|
+
import { createInterface } from "readline/promises";
|
|
611
|
+
import { stdin as input, stdout as output } from "process";
|
|
612
|
+
var MAX_PRODUCT_TITLE_LENGTH2 = 29;
|
|
613
|
+
var TERMINAL_STATUSES2 = ["PUBLISH_COMPLETE", "FAILED"];
|
|
614
|
+
function sleep2(ms) {
|
|
615
|
+
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
616
|
+
}
|
|
617
|
+
async function publishNormalVideo(businessId, videoUrl, caption) {
|
|
618
|
+
return openApiPost("/api/v1/open/tiktok/video/publish", {
|
|
619
|
+
businessId,
|
|
620
|
+
videoUrl,
|
|
621
|
+
caption: caption ?? ""
|
|
622
|
+
});
|
|
623
|
+
}
|
|
624
|
+
async function publishTtsVideo(creatorId, fileId, productId, productTitle, caption) {
|
|
625
|
+
const normalizedTitle = productTitle.slice(0, MAX_PRODUCT_TITLE_LENGTH2);
|
|
626
|
+
const publish = await openApiPost(
|
|
627
|
+
"/api/v1/open/tts/shoppable-video/publish",
|
|
628
|
+
{
|
|
629
|
+
creatorUserOpenId: creatorId,
|
|
630
|
+
fileId,
|
|
631
|
+
title: caption ?? "",
|
|
632
|
+
productId,
|
|
633
|
+
productTitle: normalizedTitle
|
|
634
|
+
}
|
|
635
|
+
);
|
|
636
|
+
return { publish, productTitle: normalizedTitle };
|
|
637
|
+
}
|
|
638
|
+
async function pollNormalVideoStatus(businessId, shareId, intervalSec, maxPolls) {
|
|
639
|
+
for (let i = 1; i <= maxPolls; i++) {
|
|
640
|
+
const data = await openApiPost("/api/v1/open/tiktok/video/status", {
|
|
641
|
+
businessId,
|
|
642
|
+
shareId
|
|
643
|
+
});
|
|
644
|
+
const status = data.status ?? data.Status ?? "UNKNOWN";
|
|
645
|
+
if (TERMINAL_STATUSES2.includes(status)) {
|
|
646
|
+
return {
|
|
647
|
+
pollCount: i,
|
|
648
|
+
finalStatus: status,
|
|
649
|
+
reason: data.reason ?? null,
|
|
650
|
+
postIds: data.post_ids ?? [],
|
|
651
|
+
raw: data
|
|
652
|
+
};
|
|
653
|
+
}
|
|
654
|
+
if (i < maxPolls) {
|
|
655
|
+
await sleep2(intervalSec * 1e3);
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
return {
|
|
659
|
+
pollCount: maxPolls,
|
|
660
|
+
finalStatus: "TIMEOUT",
|
|
661
|
+
reason: `\u8D85\u8FC7\u6700\u5927\u8F6E\u8BE2\u6B21\u6570 (${maxPolls})\uFF0C\u72B6\u6001\u4ECD\u672A\u7EC8\u7ED3`,
|
|
662
|
+
postIds: [],
|
|
663
|
+
raw: null
|
|
664
|
+
};
|
|
665
|
+
}
|
|
666
|
+
function normalizeVideoQuery(data) {
|
|
667
|
+
const list = data.videoList ?? data.videos ?? [];
|
|
668
|
+
const videos = list.map((video) => ({
|
|
669
|
+
itemId: video.itemId ?? video.item_id,
|
|
670
|
+
videoViews: video.videoViews ?? video.video_views ?? 0,
|
|
671
|
+
likes: video.likes ?? 0,
|
|
672
|
+
comments: video.comments ?? 0,
|
|
673
|
+
shares: video.shares ?? 0,
|
|
674
|
+
thumbnailUrl: video.thumbnailUrl ?? video.thumbnail_url ?? "",
|
|
675
|
+
shareUrl: video.shareUrl ?? video.share_url ?? ""
|
|
676
|
+
}));
|
|
677
|
+
return {
|
|
678
|
+
attempts: 1,
|
|
679
|
+
videos,
|
|
680
|
+
raw: data
|
|
681
|
+
};
|
|
682
|
+
}
|
|
683
|
+
async function queryVideoWithRetry(businessId, itemId, intervalSec, maxAttempts) {
|
|
684
|
+
const warnings = [];
|
|
685
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
686
|
+
const data = await openApiPost("/api/v1/open/tiktok/video/query", {
|
|
687
|
+
businessId,
|
|
688
|
+
itemIds: [itemId]
|
|
689
|
+
});
|
|
690
|
+
const normalized = normalizeVideoQuery(data);
|
|
691
|
+
normalized.attempts = attempt;
|
|
692
|
+
if (normalized.videos.length > 0) {
|
|
693
|
+
return { query: normalized, warnings };
|
|
694
|
+
}
|
|
695
|
+
if (attempt < maxAttempts) {
|
|
696
|
+
await sleep2(intervalSec * 1e3);
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
warnings.push({
|
|
700
|
+
code: "VIDEO_QUERY_EMPTY",
|
|
701
|
+
message: `\u89C6\u9891\u6570\u636E\u67E5\u8BE2\u5728 ${maxAttempts} \u6B21\u5C1D\u8BD5\u540E\u4ECD\u4E3A\u7A7A\uFF0C\u5DF2\u8FD4\u56DE query: null`
|
|
702
|
+
});
|
|
703
|
+
return { query: null, warnings };
|
|
704
|
+
}
|
|
705
|
+
function extractImageUrl2(imageStr) {
|
|
706
|
+
const match = imageStr.match(/url=([^,}]+)/);
|
|
707
|
+
return match?.[1]?.trim() ?? imageStr;
|
|
708
|
+
}
|
|
709
|
+
function decodeCursor(cursor) {
|
|
710
|
+
const decoded = JSON.parse(Buffer.from(cursor, "base64").toString());
|
|
711
|
+
return {
|
|
712
|
+
shopToken: decoded.shopToken ?? "",
|
|
713
|
+
showcaseToken: decoded.showcaseToken ?? ""
|
|
714
|
+
};
|
|
715
|
+
}
|
|
716
|
+
function encodeCursor(cursor) {
|
|
717
|
+
return Buffer.from(JSON.stringify(cursor)).toString("base64");
|
|
718
|
+
}
|
|
719
|
+
async function queryProductsPage(creatorId, productType, pageSize, cursor) {
|
|
720
|
+
const typesToQuery = productType === "all" ? ["shop", "showcase"] : [productType];
|
|
721
|
+
const allProducts = /* @__PURE__ */ new Map();
|
|
722
|
+
let nextShopToken = "";
|
|
723
|
+
let nextShowcaseToken = "";
|
|
724
|
+
let successCount = 0;
|
|
725
|
+
const failedSources = [];
|
|
726
|
+
const results = await Promise.allSettled(
|
|
727
|
+
typesToQuery.map(async (type) => {
|
|
728
|
+
const pageToken = type === "shop" ? cursor.shopToken : cursor.showcaseToken;
|
|
729
|
+
const data = await openApiPost("/api/v1/open/tts/products/query", {
|
|
730
|
+
creatorUserOpenId: creatorId,
|
|
731
|
+
productType: type,
|
|
732
|
+
pageSize,
|
|
733
|
+
pageToken
|
|
734
|
+
});
|
|
735
|
+
return { type, data };
|
|
736
|
+
})
|
|
737
|
+
);
|
|
738
|
+
for (let i = 0; i < results.length; i++) {
|
|
739
|
+
const result = results[i];
|
|
740
|
+
const type = typesToQuery[i];
|
|
741
|
+
if (result.status === "rejected") {
|
|
742
|
+
console.warn(`Failed to query products for type "${type}":`, result.reason);
|
|
743
|
+
failedSources.push(type);
|
|
744
|
+
continue;
|
|
745
|
+
}
|
|
746
|
+
successCount += 1;
|
|
747
|
+
const { data } = result.value;
|
|
748
|
+
const groups = Array.isArray(data) ? data : [data];
|
|
749
|
+
for (const group of groups) {
|
|
750
|
+
if (type === "shop") nextShopToken = group.nextPageToken ?? "";
|
|
751
|
+
if (type === "showcase") nextShowcaseToken = group.nextPageToken ?? "";
|
|
752
|
+
for (const product of group.products ?? []) {
|
|
753
|
+
if (!allProducts.has(product.id)) {
|
|
754
|
+
allProducts.set(product.id, {
|
|
755
|
+
id: product.id,
|
|
756
|
+
title: product.title,
|
|
757
|
+
price: product.price,
|
|
758
|
+
images: (product.images ?? []).map(extractImageUrl2),
|
|
759
|
+
salesCount: product.salesCount ?? 0,
|
|
760
|
+
brandName: product.brandName ?? "",
|
|
761
|
+
shopName: product.shopName ?? "",
|
|
762
|
+
source: product.source ?? type,
|
|
763
|
+
reviewStatus: product.reviewStatus,
|
|
764
|
+
inventoryStatus: product.inventoryStatus
|
|
765
|
+
});
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
const nextCursor = nextShopToken || nextShowcaseToken ? encodeCursor({ shopToken: nextShopToken, showcaseToken: nextShowcaseToken }) : null;
|
|
771
|
+
return {
|
|
772
|
+
products: Array.from(allProducts.values()),
|
|
773
|
+
nextCursor,
|
|
774
|
+
successCount,
|
|
775
|
+
failedSources
|
|
776
|
+
};
|
|
777
|
+
}
|
|
778
|
+
async function fetchProductPool(creatorId, productType, pageSize, maxPages) {
|
|
779
|
+
const allProducts = /* @__PURE__ */ new Map();
|
|
780
|
+
let cursor = { shopToken: "", showcaseToken: "" };
|
|
781
|
+
let nextCursor = null;
|
|
782
|
+
let pagesScanned = 0;
|
|
783
|
+
const failedSourcesSet = /* @__PURE__ */ new Set();
|
|
784
|
+
for (let page = 1; page <= maxPages; page++) {
|
|
785
|
+
const pageResult = await queryProductsPage(creatorId, productType, pageSize, cursor);
|
|
786
|
+
if (pageResult.successCount === 0) {
|
|
787
|
+
throw new Error("\u6240\u6709\u5546\u54C1\u6E90\u90FD\u8BF7\u6C42\u5931\u8D25");
|
|
788
|
+
}
|
|
789
|
+
for (const src of pageResult.failedSources) {
|
|
790
|
+
failedSourcesSet.add(src);
|
|
791
|
+
}
|
|
792
|
+
pagesScanned = page;
|
|
793
|
+
for (const product of pageResult.products) {
|
|
794
|
+
if (!allProducts.has(product.id)) {
|
|
795
|
+
allProducts.set(product.id, product);
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
nextCursor = pageResult.nextCursor;
|
|
799
|
+
if (!nextCursor) {
|
|
800
|
+
break;
|
|
801
|
+
}
|
|
802
|
+
cursor = decodeCursor(nextCursor);
|
|
803
|
+
}
|
|
804
|
+
return {
|
|
805
|
+
products: Array.from(allProducts.values()),
|
|
806
|
+
summary: {
|
|
807
|
+
productType,
|
|
808
|
+
pageSize,
|
|
809
|
+
pagesScanned,
|
|
810
|
+
productCount: allProducts.size,
|
|
811
|
+
nextCursor,
|
|
812
|
+
reachedPageLimit: Boolean(nextCursor) && pagesScanned >= maxPages,
|
|
813
|
+
failedSources: Array.from(failedSourcesSet)
|
|
814
|
+
}
|
|
815
|
+
};
|
|
816
|
+
}
|
|
817
|
+
function sortProductsForSelection(products) {
|
|
818
|
+
return [...products].sort((a, b) => b.salesCount - a.salesCount);
|
|
819
|
+
}
|
|
820
|
+
function buildSelectedProductSummary(product, selectionMode) {
|
|
821
|
+
return {
|
|
822
|
+
selectionMode,
|
|
823
|
+
id: product.id,
|
|
824
|
+
title: product.title,
|
|
825
|
+
salesCount: product.salesCount,
|
|
826
|
+
source: product.source,
|
|
827
|
+
price: product.price,
|
|
828
|
+
brandName: product.brandName,
|
|
829
|
+
shopName: product.shopName
|
|
830
|
+
};
|
|
831
|
+
}
|
|
832
|
+
async function promptForProductSelection(products) {
|
|
833
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
834
|
+
throw new Error("\u4EA4\u4E92\u6A21\u5F0F\u9700\u8981\u5728 TTY \u7EC8\u7AEF\u4E2D\u8FD0\u884C");
|
|
835
|
+
}
|
|
836
|
+
const candidates = sortProductsForSelection(products).slice(0, 20);
|
|
837
|
+
console.log(`\u53EF\u9009\u5546\u54C1\uFF08\u5C55\u793A\u524D ${candidates.length} \u4E2A\uFF0C\u6309\u9500\u91CF\u964D\u5E8F\uFF09\uFF1A`);
|
|
838
|
+
for (const [index, product] of candidates.entries()) {
|
|
839
|
+
console.log(
|
|
840
|
+
`${index + 1}. [${product.source}] ${product.title} | ID: ${product.id} | \u9500\u91CF: ${product.salesCount}`
|
|
841
|
+
);
|
|
842
|
+
}
|
|
843
|
+
if (products.length > candidates.length) {
|
|
844
|
+
console.log("\u5546\u54C1\u8F83\u591A\uFF0C\u5982\u9700\u9009\u62E9\u5176\u4ED6\u5546\u54C1\uFF0C\u8BF7\u6539\u7528 --product-id/--product-title\u3002");
|
|
845
|
+
}
|
|
846
|
+
const rl = createInterface({ input, output });
|
|
847
|
+
try {
|
|
848
|
+
while (true) {
|
|
849
|
+
const answer = await rl.question(`\u8BF7\u8F93\u5165\u5546\u54C1\u5E8F\u53F7 (1-${candidates.length}): `);
|
|
850
|
+
const selectedIndex = parseInt(answer.trim(), 10);
|
|
851
|
+
if (!Number.isNaN(selectedIndex) && selectedIndex >= 1 && selectedIndex <= candidates.length) {
|
|
852
|
+
return candidates[selectedIndex - 1];
|
|
853
|
+
}
|
|
854
|
+
console.log("\u8F93\u5165\u65E0\u6548\uFF0C\u8BF7\u91CD\u65B0\u8F93\u5165\u5546\u54C1\u5E8F\u53F7\u3002");
|
|
855
|
+
}
|
|
856
|
+
} finally {
|
|
857
|
+
rl.close();
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
// src/commands/publish-tt-flow.ts
|
|
862
|
+
function parsePositiveInt(value, optionName, defaultValue) {
|
|
863
|
+
const parsed = parseInt(value ?? `${defaultValue}`, 10);
|
|
864
|
+
if (Number.isNaN(parsed) || parsed <= 0) {
|
|
865
|
+
console.error(`\u9519\u8BEF: ${optionName} \u5FC5\u987B\u4E3A\u5927\u4E8E 0 \u7684\u6574\u6570`);
|
|
866
|
+
process.exit(1);
|
|
867
|
+
}
|
|
868
|
+
return parsed;
|
|
869
|
+
}
|
|
870
|
+
function register8(cli2) {
|
|
871
|
+
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 3\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(
|
|
872
|
+
async (options) => {
|
|
873
|
+
if (!options.businessId || !options.file) {
|
|
874
|
+
const missing = [
|
|
875
|
+
!options.businessId && "--business-id",
|
|
876
|
+
!options.file && "--file"
|
|
877
|
+
].filter(Boolean);
|
|
878
|
+
console.error(`\u7F3A\u5C11\u5FC5\u586B\u53C2\u6570: ${missing.join(", ")}
|
|
879
|
+
`);
|
|
880
|
+
console.error(
|
|
881
|
+
"\u7528\u6CD5: beervid publish-tt-flow --business-id <id> --file <\u8DEF\u5F84\u6216URL> [--caption <text>]"
|
|
882
|
+
);
|
|
883
|
+
process.exit(1);
|
|
884
|
+
}
|
|
885
|
+
const intervalSec = parsePositiveInt(options.interval, "--interval", 3);
|
|
886
|
+
const maxPolls = parsePositiveInt(options.maxPolls, "--max-polls", 60);
|
|
887
|
+
const queryIntervalSec = parsePositiveInt(options.queryInterval, "--query-interval", 5);
|
|
888
|
+
const queryMaxAttempts = parsePositiveInt(
|
|
889
|
+
options.queryMaxAttempts,
|
|
890
|
+
"--query-max-attempts",
|
|
891
|
+
3
|
|
892
|
+
);
|
|
893
|
+
try {
|
|
894
|
+
console.log("\u5F00\u59CB\u6267\u884C TT \u5B8C\u6574\u53D1\u5E03\u6D41\u7A0B...");
|
|
895
|
+
console.log("1/4 \u6B63\u5728\u4E0A\u4F20\u89C6\u9891...");
|
|
896
|
+
const upload = await uploadNormalVideo(options.file, options.token);
|
|
897
|
+
console.log("2/4 \u6B63\u5728\u53D1\u5E03\u89C6\u9891...");
|
|
898
|
+
const publish = await publishNormalVideo(
|
|
899
|
+
options.businessId,
|
|
900
|
+
upload.fileUrl,
|
|
901
|
+
options.caption
|
|
902
|
+
);
|
|
903
|
+
console.log("3/4 \u6B63\u5728\u8F6E\u8BE2\u53D1\u5E03\u72B6\u6001...");
|
|
904
|
+
const status = await pollNormalVideoStatus(
|
|
905
|
+
options.businessId,
|
|
906
|
+
publish.shareId,
|
|
907
|
+
intervalSec,
|
|
908
|
+
maxPolls
|
|
909
|
+
);
|
|
910
|
+
const warnings = [];
|
|
911
|
+
const videoId = status.postIds[0] ?? null;
|
|
912
|
+
let query = null;
|
|
913
|
+
if (status.finalStatus === "PUBLISH_COMPLETE" && videoId) {
|
|
914
|
+
console.log("4/4 \u6B63\u5728\u67E5\u8BE2\u89C6\u9891\u6570\u636E...");
|
|
915
|
+
const queryResult = await queryVideoWithRetry(
|
|
916
|
+
options.businessId,
|
|
917
|
+
videoId,
|
|
918
|
+
queryIntervalSec,
|
|
919
|
+
queryMaxAttempts
|
|
920
|
+
);
|
|
921
|
+
query = queryResult.query;
|
|
922
|
+
warnings.push(...queryResult.warnings);
|
|
923
|
+
} else if (status.finalStatus === "PUBLISH_COMPLETE") {
|
|
924
|
+
warnings.push({
|
|
925
|
+
code: "VIDEO_ID_MISSING",
|
|
926
|
+
message: "\u53D1\u5E03\u6210\u529F\uFF0C\u4F46\u72B6\u6001\u7ED3\u679C\u4E2D\u672A\u8FD4\u56DE videoId\uFF0C\u5DF2\u8DF3\u8FC7\u89C6\u9891\u6570\u636E\u67E5\u8BE2"
|
|
927
|
+
});
|
|
928
|
+
}
|
|
929
|
+
const result = {
|
|
930
|
+
flowType: "tt",
|
|
931
|
+
upload,
|
|
932
|
+
publish,
|
|
933
|
+
status,
|
|
934
|
+
videoId,
|
|
935
|
+
query,
|
|
936
|
+
warnings
|
|
937
|
+
};
|
|
938
|
+
printResult(result);
|
|
939
|
+
if (status.finalStatus === "FAILED") {
|
|
940
|
+
process.exit(1);
|
|
941
|
+
}
|
|
942
|
+
if (status.finalStatus === "TIMEOUT") {
|
|
943
|
+
process.exit(2);
|
|
944
|
+
}
|
|
945
|
+
process.exit(0);
|
|
946
|
+
} catch (err) {
|
|
947
|
+
rethrowIfProcessExit(err);
|
|
948
|
+
console.error("TT \u5B8C\u6574\u53D1\u5E03\u6D41\u7A0B\u5931\u8D25:", err.message);
|
|
949
|
+
process.exit(1);
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
);
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
// src/commands/publish-tts-flow.ts
|
|
956
|
+
var VALID_PRODUCT_TYPES2 = ["shop", "showcase", "all"];
|
|
957
|
+
function parsePositiveInt2(value, optionName, defaultValue) {
|
|
958
|
+
const parsed = parseInt(value ?? `${defaultValue}`, 10);
|
|
959
|
+
if (Number.isNaN(parsed) || parsed <= 0) {
|
|
960
|
+
console.error(`\u9519\u8BEF: ${optionName} \u5FC5\u987B\u4E3A\u5927\u4E8E 0 \u7684\u6574\u6570`);
|
|
961
|
+
process.exit(1);
|
|
962
|
+
}
|
|
963
|
+
return parsed;
|
|
964
|
+
}
|
|
965
|
+
function buildManualProduct(productId, productTitle, matchedProduct) {
|
|
966
|
+
if (matchedProduct) {
|
|
967
|
+
return {
|
|
968
|
+
...matchedProduct,
|
|
969
|
+
title: productTitle
|
|
970
|
+
};
|
|
971
|
+
}
|
|
972
|
+
return {
|
|
973
|
+
id: productId,
|
|
974
|
+
title: productTitle,
|
|
975
|
+
price: null,
|
|
976
|
+
images: [],
|
|
977
|
+
salesCount: 0,
|
|
978
|
+
brandName: "",
|
|
979
|
+
shopName: "",
|
|
980
|
+
source: "manual",
|
|
981
|
+
reviewStatus: void 0,
|
|
982
|
+
inventoryStatus: void 0
|
|
983
|
+
};
|
|
984
|
+
}
|
|
985
|
+
function register9(cli2) {
|
|
986
|
+
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(
|
|
987
|
+
async (options) => {
|
|
988
|
+
if (!options.creatorId || !options.file) {
|
|
989
|
+
const missing = [
|
|
990
|
+
!options.creatorId && "--creator-id",
|
|
991
|
+
!options.file && "--file"
|
|
992
|
+
].filter(Boolean);
|
|
993
|
+
console.error(`\u7F3A\u5C11\u5FC5\u586B\u53C2\u6570: ${missing.join(", ")}
|
|
994
|
+
`);
|
|
995
|
+
console.error(
|
|
996
|
+
"\u7528\u6CD5: beervid publish-tts-flow --creator-id <id> --file <\u8DEF\u5F84\u6216URL> [--interactive]"
|
|
997
|
+
);
|
|
998
|
+
process.exit(1);
|
|
999
|
+
}
|
|
1000
|
+
const productType = (options.productType ?? "all").toLowerCase();
|
|
1001
|
+
if (!VALID_PRODUCT_TYPES2.includes(productType)) {
|
|
1002
|
+
console.error("\u9519\u8BEF: --product-type \u5FC5\u987B\u4E3A shop\u3001showcase \u6216 all");
|
|
1003
|
+
process.exit(1);
|
|
1004
|
+
}
|
|
1005
|
+
if (options.productId && options.interactive) {
|
|
1006
|
+
console.error("\u9519\u8BEF: --product-id \u4E0E --interactive \u4E0D\u80FD\u540C\u65F6\u4F7F\u7528");
|
|
1007
|
+
process.exit(1);
|
|
1008
|
+
}
|
|
1009
|
+
if (options.productTitle && !options.productId) {
|
|
1010
|
+
console.error("\u9519\u8BEF: --product-title \u9700\u8981\u4E0E --product-id \u4E00\u8D77\u4F7F\u7528");
|
|
1011
|
+
process.exit(1);
|
|
1012
|
+
}
|
|
1013
|
+
const pageSize = parsePositiveInt2(options.pageSize, "--page-size", 20);
|
|
1014
|
+
const maxProductPages = parsePositiveInt2(
|
|
1015
|
+
options.maxProductPages,
|
|
1016
|
+
"--max-product-pages",
|
|
1017
|
+
5
|
|
1018
|
+
);
|
|
1019
|
+
try {
|
|
1020
|
+
console.log("\u5F00\u59CB\u6267\u884C TTS \u5B8C\u6574\u53D1\u5E03\u6D41\u7A0B...");
|
|
1021
|
+
console.log("1/4 \u6B63\u5728\u67E5\u8BE2\u5546\u54C1\u5217\u8868...");
|
|
1022
|
+
const productPool = await fetchProductPool(
|
|
1023
|
+
options.creatorId,
|
|
1024
|
+
productType,
|
|
1025
|
+
pageSize,
|
|
1026
|
+
maxProductPages
|
|
1027
|
+
);
|
|
1028
|
+
const warnings = [];
|
|
1029
|
+
if (productPool.summary.reachedPageLimit && productPool.summary.nextCursor) {
|
|
1030
|
+
warnings.push({
|
|
1031
|
+
code: "PRODUCT_SCAN_LIMIT_REACHED",
|
|
1032
|
+
message: `\u5546\u54C1\u626B\u63CF\u5DF2\u8FBE\u5230\u9875\u6570\u4E0A\u9650 ${maxProductPages}\uFF0C\u4ECD\u5B58\u5728\u672A\u62C9\u53D6\u5206\u9875`
|
|
1033
|
+
});
|
|
1034
|
+
}
|
|
1035
|
+
if (productPool.summary.failedSources.length > 0) {
|
|
1036
|
+
warnings.push({
|
|
1037
|
+
code: "PRODUCT_SOURCE_PARTIAL_FAILURE",
|
|
1038
|
+
message: `\u4EE5\u4E0B\u5546\u54C1\u6E90\u8BF7\u6C42\u5931\u8D25: ${productPool.summary.failedSources.join(", ")}\uFF0C\u5546\u54C1\u6C60\u53EF\u80FD\u4E0D\u5B8C\u6574`
|
|
1039
|
+
});
|
|
1040
|
+
}
|
|
1041
|
+
if (productPool.products.length === 0) {
|
|
1042
|
+
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
|
+
process.exit(1);
|
|
1044
|
+
}
|
|
1045
|
+
let selectionMode = "automatic";
|
|
1046
|
+
let selectedProduct;
|
|
1047
|
+
if (options.productId) {
|
|
1048
|
+
selectionMode = "manual";
|
|
1049
|
+
const matchedProduct = productPool.products.find(
|
|
1050
|
+
(product) => product.id === options.productId
|
|
1051
|
+
);
|
|
1052
|
+
const resolvedTitle = options.productTitle ?? matchedProduct?.title;
|
|
1053
|
+
if (!resolvedTitle) {
|
|
1054
|
+
console.error(
|
|
1055
|
+
"\u9519\u8BEF: \u624B\u52A8\u6307\u5B9A --product-id \u65F6\uFF0C\u5982\u65E0\u6CD5\u4ECE\u5DF2\u626B\u63CF\u5546\u54C1\u6C60\u8865\u9F50\u6807\u9898\uFF0C\u5219\u5FC5\u987B\u663E\u5F0F\u4F20\u5165 --product-title"
|
|
1056
|
+
);
|
|
1057
|
+
process.exit(1);
|
|
1058
|
+
}
|
|
1059
|
+
selectedProduct = buildManualProduct(options.productId, resolvedTitle, matchedProduct);
|
|
1060
|
+
if (!matchedProduct) {
|
|
1061
|
+
warnings.push({
|
|
1062
|
+
code: "PRODUCT_NOT_IN_SCANNED_POOL",
|
|
1063
|
+
message: "\u624B\u52A8\u6307\u5B9A\u7684\u5546\u54C1 ID \u672A\u51FA\u73B0\u5728\u5DF2\u626B\u63CF\u5546\u54C1\u6C60\u4E2D\uFF0C\u5DF2\u4F7F\u7528\u663E\u5F0F\u53C2\u6570\u7EE7\u7EED\u53D1\u5E03"
|
|
1064
|
+
});
|
|
1065
|
+
}
|
|
1066
|
+
} else if (options.interactive) {
|
|
1067
|
+
selectionMode = "interactive";
|
|
1068
|
+
console.log("2/4 \u8BF7\u9009\u62E9\u8981\u6302\u8F66\u7684\u5546\u54C1...");
|
|
1069
|
+
selectedProduct = await promptForProductSelection(productPool.products);
|
|
1070
|
+
} else {
|
|
1071
|
+
console.log("2/4 \u6B63\u5728\u81EA\u52A8\u9009\u62E9\u5546\u54C1\uFF08\u6309\u9500\u91CF\u6700\u9AD8\u4F18\u5148\uFF09...");
|
|
1072
|
+
selectedProduct = sortProductsForSelection(productPool.products)[0];
|
|
1073
|
+
}
|
|
1074
|
+
console.log("3/4 \u6B63\u5728\u4E0A\u4F20\u6302\u8F66\u89C6\u9891...");
|
|
1075
|
+
const upload = await uploadTtsVideo(options.file, options.creatorId, options.token);
|
|
1076
|
+
console.log("4/4 \u6B63\u5728\u53D1\u5E03\u6302\u8F66\u89C6\u9891...");
|
|
1077
|
+
const publishResult = await publishTtsVideo(
|
|
1078
|
+
options.creatorId,
|
|
1079
|
+
upload.videoFileId,
|
|
1080
|
+
selectedProduct.id,
|
|
1081
|
+
selectedProduct.title,
|
|
1082
|
+
options.caption
|
|
1083
|
+
);
|
|
1084
|
+
if (publishResult.productTitle !== selectedProduct.title) {
|
|
1085
|
+
warnings.push({
|
|
1086
|
+
code: "PRODUCT_TITLE_TRUNCATED",
|
|
1087
|
+
message: "\u5546\u54C1\u6807\u9898\u8D85\u8FC7 29 \u5B57\u7B26\uFF0C\u53D1\u5E03\u65F6\u5DF2\u81EA\u52A8\u622A\u65AD"
|
|
1088
|
+
});
|
|
1089
|
+
}
|
|
1090
|
+
const result = {
|
|
1091
|
+
flowType: "tts",
|
|
1092
|
+
productQuery: productPool.summary,
|
|
1093
|
+
selectedProduct: buildSelectedProductSummary(selectedProduct, selectionMode),
|
|
1094
|
+
upload,
|
|
1095
|
+
publish: publishResult.publish,
|
|
1096
|
+
warnings
|
|
1097
|
+
};
|
|
1098
|
+
printResult(result);
|
|
1099
|
+
} catch (err) {
|
|
1100
|
+
rethrowIfProcessExit(err);
|
|
1101
|
+
console.error("TTS \u5B8C\u6574\u53D1\u5E03\u6D41\u7A0B\u5931\u8D25:", err.message);
|
|
1102
|
+
process.exit(1);
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
);
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
// src/cli.ts
|
|
1109
|
+
var cli = cac("beervid");
|
|
1110
|
+
register(cli);
|
|
1111
|
+
register2(cli);
|
|
1112
|
+
register3(cli);
|
|
1113
|
+
register4(cli);
|
|
1114
|
+
register5(cli);
|
|
1115
|
+
register6(cli);
|
|
1116
|
+
register7(cli);
|
|
1117
|
+
register8(cli);
|
|
1118
|
+
register9(cli);
|
|
1119
|
+
cli.help();
|
|
1120
|
+
cli.version("1.0.0");
|
|
1121
|
+
if (process.argv.slice(2).length === 0) {
|
|
1122
|
+
cli.outputHelp();
|
|
1123
|
+
process.exit(0);
|
|
1124
|
+
}
|
|
1125
|
+
cli.parse();
|