@optima-chat/browser-cli 0.10.2 → 0.12.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.
Files changed (2) hide show
  1. package/dist/index.js +56 -2
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -274,7 +274,7 @@ var BrowserAPI = class {
274
274
  async getScreenshot(sessionId) {
275
275
  return requestBinary(`/api/sessions/${sessionId}/screenshot`);
276
276
  }
277
- async runRecipeScript(name, params, pollMs = 2e3, timeoutMs = 36e4) {
277
+ async runRecipeScript(name, params, pollMs = 2e3, timeoutMs = 36e4, timeoutHint) {
278
278
  const started = await request(`/api/scripts/${name}/run`, {
279
279
  method: "POST",
280
280
  body: JSON.stringify({ params })
@@ -295,7 +295,7 @@ var BrowserAPI = class {
295
295
  }
296
296
  if (Date.now() >= deadline) {
297
297
  throw new Error(
298
- `recipe ${name} did not finish within ${Math.round(timeoutMs / 1e3)}s (task ${started.id})`
298
+ `recipe ${name} did not finish within ${Math.round(timeoutMs / 1e3)}s (task ${started.id})` + (timeoutHint ? ` \u2014\u2014 ${timeoutHint}` : "")
299
299
  );
300
300
  }
301
301
  await new Promise((r) => setTimeout(r, pollMs));
@@ -378,6 +378,9 @@ var BrowserAPI = class {
378
378
  body: JSON.stringify({ src, dest })
379
379
  });
380
380
  }
381
+ async listVideos() {
382
+ return request("/api/files/videos");
383
+ }
381
384
  };
382
385
  var api = new BrowserAPI();
383
386
 
@@ -1096,6 +1099,8 @@ function registerZiNiaoCommands(program2) {
1096
1099
  // src/commands/recipes.ts
1097
1100
  import { writeFileSync as writeFileSync4 } from "fs";
1098
1101
  import { resolve as resolve2 } from "path";
1102
+ var PUBLISH_TIMEOUT_MS = 18e5;
1103
+ var PUBLISH_TIMEOUT_HINT = "\u4EFB\u52A1\u4ECD\u5728\u540E\u7AEF\u8FD0\u884C,\u89C6\u9891\u53EF\u80FD\u5DF2\u7ECF\u53D1\u51FA\u53BB\u4E86\u3002\u53D1\u5E03\u72B6\u6001\u672A\u77E5 \u2014\u2014 \u8BF7\u5230\u5356\u5BB6\u540E\u53F0\u786E\u8BA4,\u4E0D\u8981\u91CD\u8DD1\u672C\u547D\u4EE4(\u4F1A\u53D1\u51FA\u91CD\u590D\u89C6\u9891)\u3002";
1099
1104
  async function runExport(script, params, out, timeoutMs) {
1100
1105
  const outPath = resolve2(out);
1101
1106
  const result = await api.runRecipeScript(script, { ...params, out_path: outPath }, 2e3, timeoutMs);
@@ -1131,6 +1136,33 @@ function registerRecipeCommands(program2) {
1131
1136
  process.exit(1);
1132
1137
  }
1133
1138
  });
1139
+ program2.command("publish-video").description("Publish one shoppable video to TikTok Shop").requiredOption("--ziniao-profile <id>", "ZiNiao browser profile ID").requiredOption("--video <name>", "Video file name (from list-videos)").requiredOption("--product-query <keyword>", "Product search keyword, narrow enough to hit exactly one product (ask the user)").requiredOption(
1140
+ "--product-name <text>",
1141
+ "Display name on the video: max 30 chars, letters/digits/spaces only (ask the user)"
1142
+ ).requiredOption("--caption <text>", "Video caption").option("--hashtags <text>", "Comma-separated hashtags").option("--publish-url <url>", "Video publish page URL").action(async (opts) => {
1143
+ try {
1144
+ const params = {
1145
+ ziniao_profile_id: opts.ziniaoProfile,
1146
+ video: opts.video,
1147
+ product_query: opts.productQuery,
1148
+ product_name: opts.productName,
1149
+ caption: opts.caption
1150
+ };
1151
+ if (opts.hashtags) params.hashtags = opts.hashtags;
1152
+ if (opts.publishUrl) params.publish_url = opts.publishUrl;
1153
+ const result = await api.runRecipeScript(
1154
+ "tiktok_video_publish",
1155
+ params,
1156
+ 2e3,
1157
+ PUBLISH_TIMEOUT_MS,
1158
+ PUBLISH_TIMEOUT_HINT
1159
+ );
1160
+ console.log(result.detail);
1161
+ } catch (err) {
1162
+ console.error(formatError(err));
1163
+ process.exit(1);
1164
+ }
1165
+ });
1134
1166
  }
1135
1167
 
1136
1168
  // src/commands/bitbrowser.ts
@@ -1196,6 +1228,19 @@ function registerFeikuaCommands(program2) {
1196
1228
  }
1197
1229
 
1198
1230
  // src/commands/files.ts
1231
+ function formatVideoList(videos) {
1232
+ if (videos.length === 0) {
1233
+ return `No videos found. Put your videos in:
1234
+ macOS/Linux: ~/Downloads/OptimaConnect/videos
1235
+ Windows: C:\\Users\\<\u7528\u6237\u540D>\\Downloads\\OptimaConnect\\videos
1236
+ Then try again.`;
1237
+ }
1238
+ return videos.map((v) => {
1239
+ const mb = (v.size / 1024 / 1024).toFixed(1);
1240
+ const time = v.mtime.slice(0, 19).replace("T", " ") + " UTC";
1241
+ return `${v.name} \u2014 ${mb} MB, ${time}`;
1242
+ }).join("\n");
1243
+ }
1199
1244
  function registerFileCommands(program2) {
1200
1245
  program2.command("send-file").description("Send a file from your workspace to your local download folder").requiredOption("--src <path>", "Source path in your workspace (e.g. ~/output/report.pdf)").requiredOption("--dest <path>", "Destination path relative to the download folder").action(async (opts) => {
1201
1246
  try {
@@ -1206,6 +1251,15 @@ function registerFileCommands(program2) {
1206
1251
  process.exit(1);
1207
1252
  }
1208
1253
  });
1254
+ program2.command("list-videos").description("List videos in your local video folder (requires Desktop app online)").action(async () => {
1255
+ try {
1256
+ const { videos } = await api.listVideos();
1257
+ console.log(formatVideoList(videos));
1258
+ } catch (err) {
1259
+ console.error(formatError(err));
1260
+ process.exit(1);
1261
+ }
1262
+ });
1209
1263
  }
1210
1264
 
1211
1265
  // src/index.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optima-chat/browser-cli",
3
- "version": "0.10.2",
3
+ "version": "0.12.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "bin": {