beervid-app-cli 0.2.1 → 0.2.3

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 (3) hide show
  1. package/README.md +16 -5
  2. package/dist/cli.mjs +174 -250
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -2,21 +2,32 @@
2
2
 
3
3
  BEERVID 第三方应用 Open API 的 TypeScript CLI 和 Claude Code Skill,提供 TikTok 视频发布、账号授权、数据查询等完整能力。
4
4
 
5
- ## 安装
5
+ ## 安装与调用
6
6
 
7
- ### npm CLI
7
+ ### 全局安装
8
8
 
9
9
  ```bash
10
10
  npm install -g beervid-app-cli
11
11
  beervid --help
12
12
  ```
13
13
 
14
- ### Claude Code Skill
14
+ ### npx 免安装调用
15
15
 
16
- 将本仓库克隆到 Claude Code 的 skills 目录:
16
+ ```bash
17
+ npx beervid-app-cli --help
18
+ npx beervid-app-cli config --show
19
+ npx beervid-app-cli upload --file ./video.mp4
20
+ ```
21
+
22
+ ### node 直接调用
17
23
 
18
24
  ```bash
19
- git clone <repo-url> ~/.claude/skills/beervid-app-cli
25
+ # 克隆仓库后先构建
26
+ npm install && npm run build
27
+
28
+ # 通过 node 运行入口文件
29
+ node dist/cli.mjs --help
30
+ node dist/cli.mjs config --show
20
31
  ```
21
32
 
22
33
  ## 配置
package/dist/cli.mjs CHANGED
@@ -169,11 +169,11 @@ function register(cli2) {
169
169
  if (type === "tt") {
170
170
  const data = await openApiGet("/api/v1/open/thirdparty-auth/tt-url");
171
171
  console.log("TT OAuth \u6388\u6743\u94FE\u63A5:");
172
- printResult({ type: "tt", url: data });
172
+ printResult(data);
173
173
  } else {
174
174
  const data = await openApiGet("/api/v1/open/thirdparty-auth/tts-url");
175
175
  console.log("TTS OAuth \u6388\u6743\u94FE\u63A5:");
176
- printResult({ type: "tts", url: data.crossBorderUrl });
176
+ printResult(data);
177
177
  }
178
178
  } catch (err) {
179
179
  rethrowIfProcessExit(err);
@@ -451,7 +451,7 @@ function register5(cli2) {
451
451
 
452
452
  // src/commands/query-video.ts
453
453
  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\u591A\u4E2A\u7528\u9017\u53F7\u5206\u9694\uFF08\u5FC5\u586B\uFF09").action(
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\u652F\u6301\u91CD\u590D\u4F20\u53C2\u6216\u9017\u53F7\u5206\u9694\uFF08\u5FC5\u586B\uFF09").action(
455
455
  async (options) => {
456
456
  if (!options.businessId || !options.itemIds) {
457
457
  const missing = [
@@ -465,7 +465,7 @@ function register6(cli2) {
465
465
  );
466
466
  process.exit(1);
467
467
  }
468
- const itemIds = options.itemIds.split(",").map((id) => id.trim()).filter(Boolean);
468
+ const itemIds = (Array.isArray(options.itemIds) ? options.itemIds : [options.itemIds]).flatMap((value) => value.split(",")).map((id) => id.trim()).filter(Boolean);
469
469
  if (itemIds.length === 0) {
470
470
  console.error("\u9519\u8BEF: --item-ids \u4E0D\u80FD\u4E3A\u7A7A");
471
471
  process.exit(1);
@@ -501,7 +501,7 @@ function register6(cli2) {
501
501
  if (v.shareUrl) console.log(` \u94FE\u63A5: ${v.shareUrl}`);
502
502
  console.log("");
503
503
  }
504
- printResult({ videos: normalized, _raw: data });
504
+ printResult(data);
505
505
  } catch (err) {
506
506
  rethrowIfProcessExit(err);
507
507
  console.error("\u67E5\u8BE2\u89C6\u9891\u6570\u636E\u5931\u8D25:", err.message);
@@ -511,134 +511,6 @@ function register6(cli2) {
511
511
  );
512
512
  }
513
513
 
514
- // src/commands/query-products.ts
515
- var VALID_PRODUCT_TYPES = ["shop", "showcase", "all"];
516
- function extractImageUrl(imageStr) {
517
- const match = imageStr.match(/url=([^,}]+)/);
518
- return match?.[1]?.trim() ?? imageStr;
519
- }
520
- async function queryProducts(creatorId, type, pageSize, pageToken) {
521
- return openApiPost("/api/v1/open/tts/products/query", {
522
- creatorUserOpenId: creatorId,
523
- productType: type,
524
- pageSize,
525
- pageToken
526
- });
527
- }
528
- function register7(cli2) {
529
- 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(
530
- async (options) => {
531
- if (!options.creatorId) {
532
- console.error("\u7F3A\u5C11\u5FC5\u586B\u53C2\u6570: --creator-id\n");
533
- console.error("\u7528\u6CD5: beervid query-products --creator-id <id>");
534
- process.exit(1);
535
- }
536
- const creatorId = options.creatorId;
537
- const productType = (options.productType ?? "all").toLowerCase();
538
- const pageSize = parseInt(options.pageSize ?? "20", 10);
539
- const cursor = options.cursor ?? "";
540
- if (!VALID_PRODUCT_TYPES.includes(productType)) {
541
- console.error("\u9519\u8BEF: --product-type \u5FC5\u987B\u4E3A shop\u3001showcase \u6216 all");
542
- process.exit(1);
543
- }
544
- if (Number.isNaN(pageSize) || pageSize <= 0) {
545
- console.error("\u9519\u8BEF: --page-size \u5FC5\u987B\u4E3A\u5927\u4E8E 0 \u7684\u6574\u6570");
546
- process.exit(1);
547
- }
548
- try {
549
- let shopToken = "";
550
- let showcaseToken = "";
551
- if (cursor) {
552
- try {
553
- const decoded = JSON.parse(
554
- Buffer.from(cursor, "base64").toString()
555
- );
556
- shopToken = decoded.shopToken ?? "";
557
- showcaseToken = decoded.showcaseToken ?? "";
558
- } catch {
559
- console.error("\u9519\u8BEF: \u65E0\u6548\u7684 cursor \u683C\u5F0F");
560
- process.exit(1);
561
- }
562
- }
563
- const typesToQuery = productType === "all" ? ["shop", "showcase"] : [productType];
564
- const allProducts = /* @__PURE__ */ new Map();
565
- let nextShopToken = null;
566
- let nextShowcaseToken = null;
567
- let successCount = 0;
568
- const results = await Promise.allSettled(
569
- typesToQuery.map(async (type) => {
570
- const token = type === "shop" ? shopToken : showcaseToken;
571
- const data = await queryProducts(creatorId, type, pageSize, token);
572
- return { type, data };
573
- })
574
- );
575
- for (const result of results) {
576
- if (result.status === "rejected") {
577
- console.error("\u67E5\u8BE2\u5931\u8D25:", result.reason?.message);
578
- continue;
579
- }
580
- const { type, data } = result.value;
581
- successCount += 1;
582
- const items = Array.isArray(data) ? data : [data];
583
- for (const group of items) {
584
- if (type === "shop") nextShopToken = group.nextPageToken ?? null;
585
- if (type === "showcase") nextShowcaseToken = group.nextPageToken ?? null;
586
- for (const product of group.products ?? []) {
587
- if (!allProducts.has(product.id)) {
588
- allProducts.set(product.id, {
589
- id: product.id,
590
- title: product.title,
591
- price: product.price,
592
- images: (product.images ?? []).map(extractImageUrl),
593
- salesCount: product.salesCount ?? 0,
594
- brandName: product.brandName ?? "",
595
- shopName: product.shopName ?? "",
596
- source: product.source ?? type,
597
- reviewStatus: product.reviewStatus,
598
- inventoryStatus: product.inventoryStatus
599
- });
600
- }
601
- }
602
- }
603
- }
604
- if (successCount === 0) {
605
- console.error("\u67E5\u8BE2\u5546\u54C1\u5931\u8D25: \u6240\u6709\u5546\u54C1\u6E90\u90FD\u8BF7\u6C42\u5931\u8D25");
606
- process.exit(1);
607
- }
608
- const productList = Array.from(allProducts.values());
609
- let nextCursor = null;
610
- if (nextShopToken || nextShowcaseToken) {
611
- nextCursor = Buffer.from(
612
- JSON.stringify({
613
- shopToken: nextShopToken ?? "",
614
- showcaseToken: nextShowcaseToken ?? ""
615
- })
616
- ).toString("base64");
617
- }
618
- console.log(`\u67E5\u8BE2\u5230 ${productList.length} \u4E2A\u5546\u54C1:
619
- `);
620
- for (const p of productList) {
621
- console.log(` [${p.source}] ${p.title}`);
622
- console.log(` ID: ${p.id} \u9500\u91CF: ${p.salesCount} \u54C1\u724C: ${p.brandName}`);
623
- if (p.images.length > 0) console.log(` \u56FE\u7247: ${p.images[0]}`);
624
- console.log("");
625
- }
626
- if (nextCursor) {
627
- console.log(`\u4E0B\u4E00\u9875\u6E38\u6807: ${nextCursor}`);
628
- console.log(`\u4F7F\u7528: beervid query-products --creator-id ${creatorId} --cursor ${nextCursor}`);
629
- } else {
630
- console.log("\u5DF2\u5230\u6700\u540E\u4E00\u9875");
631
- }
632
- printResult({ products: productList, nextCursor });
633
- } catch (err) {
634
- rethrowIfProcessExit(err);
635
- console.error("\u67E5\u8BE2\u5546\u54C1\u5931\u8D25:", err.message);
636
- process.exit(1);
637
- }
638
- }
639
- );
640
- }
641
-
642
514
  // src/workflows/index.ts
643
515
  import { createInterface } from "readline/promises";
644
516
  import { stdin as input, stdout as output } from "process";
@@ -709,23 +581,6 @@ async function pollNormalVideoStatus(businessId, shareId, intervalSec, maxPolls)
709
581
  raw: lastData
710
582
  };
711
583
  }
712
- function normalizeVideoQuery(data) {
713
- const list = data.videoList ?? data.videos ?? [];
714
- const videos = list.map((video) => ({
715
- itemId: video.itemId ?? video.item_id,
716
- videoViews: video.videoViews ?? video.video_views ?? 0,
717
- likes: video.likes ?? 0,
718
- comments: video.comments ?? 0,
719
- shares: video.shares ?? 0,
720
- thumbnailUrl: video.thumbnailUrl ?? video.thumbnail_url ?? "",
721
- shareUrl: video.shareUrl ?? video.share_url ?? ""
722
- }));
723
- return {
724
- attempts: 1,
725
- videos,
726
- raw: data
727
- };
728
- }
729
584
  async function queryVideoWithRetry(businessId, itemId, intervalSec, maxAttempts) {
730
585
  const warnings = [];
731
586
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
@@ -733,10 +588,9 @@ async function queryVideoWithRetry(businessId, itemId, intervalSec, maxAttempts)
733
588
  businessId,
734
589
  itemIds: [itemId]
735
590
  });
736
- const normalized = normalizeVideoQuery(data);
737
- normalized.attempts = attempt;
738
- if (normalized.videos.length > 0) {
739
- return { query: normalized, warnings };
591
+ const list = data.videoList ?? data.videos ?? [];
592
+ if (list.length > 0) {
593
+ return { query: data, warnings };
740
594
  }
741
595
  if (attempt < maxAttempts) {
742
596
  await sleep2(intervalSec * 1e3);
@@ -748,25 +602,31 @@ async function queryVideoWithRetry(businessId, itemId, intervalSec, maxAttempts)
748
602
  });
749
603
  return { query: null, warnings };
750
604
  }
751
- function extractImageUrl2(imageStr) {
605
+ function extractImageUrl(imageStr) {
752
606
  const match = imageStr.match(/url=([^,}]+)/);
753
607
  return match?.[1]?.trim() ?? imageStr;
754
608
  }
755
609
  function decodeCursor(cursor) {
756
610
  const decoded = JSON.parse(Buffer.from(cursor, "base64").toString());
757
611
  return {
758
- shopToken: decoded.shopToken ?? "",
759
- showcaseToken: decoded.showcaseToken ?? ""
612
+ shopToken: decoded.shopToken === void 0 ? "" : decoded.shopToken,
613
+ showcaseToken: decoded.showcaseToken === void 0 ? "" : decoded.showcaseToken
760
614
  };
761
615
  }
762
616
  function encodeCursor(cursor) {
617
+ if (cursor.shopToken === null && cursor.showcaseToken === null) return null;
763
618
  return Buffer.from(JSON.stringify(cursor)).toString("base64");
764
619
  }
765
620
  async function queryProductsPage(creatorId, productType, pageSize, cursor) {
766
- const typesToQuery = productType === "all" ? ["shop", "showcase"] : [productType];
621
+ const allTypesToQuery = productType === "all" ? ["shop", "showcase"] : [productType];
622
+ const typesToQuery = allTypesToQuery.filter((type) => {
623
+ const token = type === "shop" ? cursor.shopToken : cursor.showcaseToken;
624
+ return token !== null;
625
+ });
767
626
  const allProducts = /* @__PURE__ */ new Map();
768
- let nextShopToken = "";
769
- let nextShowcaseToken = "";
627
+ const rawGroups = [];
628
+ let nextShopToken = cursor.shopToken;
629
+ let nextShowcaseToken = cursor.showcaseToken;
770
630
  let successCount = 0;
771
631
  const failedSources = [];
772
632
  const results = await Promise.allSettled(
@@ -776,7 +636,7 @@ async function queryProductsPage(creatorId, productType, pageSize, cursor) {
776
636
  creatorUserOpenId: creatorId,
777
637
  productType: type,
778
638
  pageSize,
779
- pageToken
639
+ pageToken: pageToken ?? ""
780
640
  });
781
641
  return { type, data };
782
642
  })
@@ -792,16 +652,18 @@ async function queryProductsPage(creatorId, productType, pageSize, cursor) {
792
652
  successCount += 1;
793
653
  const { data } = result.value;
794
654
  const groups = Array.isArray(data) ? data : [data];
655
+ rawGroups.push(...groups);
795
656
  for (const group of groups) {
796
- if (type === "shop") nextShopToken = group.nextPageToken ?? "";
797
- if (type === "showcase") nextShowcaseToken = group.nextPageToken ?? "";
657
+ const token = group.nextPageToken === void 0 ? null : group.nextPageToken;
658
+ if (type === "shop") nextShopToken = token;
659
+ if (type === "showcase") nextShowcaseToken = token;
798
660
  for (const product of group.products ?? []) {
799
661
  if (!allProducts.has(product.id)) {
800
662
  allProducts.set(product.id, {
801
663
  id: product.id,
802
664
  title: product.title,
803
665
  price: product.price,
804
- images: (product.images ?? []).map(extractImageUrl2),
666
+ images: (product.images ?? []).map(extractImageUrl),
805
667
  salesCount: product.salesCount ?? 0,
806
668
  brandName: product.brandName ?? "",
807
669
  shopName: product.shopName ?? "",
@@ -813,9 +675,10 @@ async function queryProductsPage(creatorId, productType, pageSize, cursor) {
813
675
  }
814
676
  }
815
677
  }
816
- const nextCursor = nextShopToken || nextShowcaseToken ? encodeCursor({ shopToken: nextShopToken, showcaseToken: nextShowcaseToken }) : null;
678
+ const nextCursor = encodeCursor({ shopToken: nextShopToken, showcaseToken: nextShowcaseToken });
817
679
  return {
818
680
  products: Array.from(allProducts.values()),
681
+ rawGroups,
819
682
  nextCursor,
820
683
  successCount,
821
684
  failedSources
@@ -823,6 +686,7 @@ async function queryProductsPage(creatorId, productType, pageSize, cursor) {
823
686
  }
824
687
  async function fetchProductPool(creatorId, productType, pageSize, maxPages) {
825
688
  const allProducts = /* @__PURE__ */ new Map();
689
+ const rawGroups = [];
826
690
  let cursor = { shopToken: "", showcaseToken: "" };
827
691
  let nextCursor = null;
828
692
  let pagesScanned = 0;
@@ -836,6 +700,7 @@ async function fetchProductPool(creatorId, productType, pageSize, maxPages) {
836
700
  failedSourcesSet.add(src);
837
701
  }
838
702
  pagesScanned = page;
703
+ rawGroups.push(...pageResult.rawGroups);
839
704
  for (const product of pageResult.products) {
840
705
  if (!allProducts.has(product.id)) {
841
706
  allProducts.set(product.id, product);
@@ -849,6 +714,7 @@ async function fetchProductPool(creatorId, productType, pageSize, maxPages) {
849
714
  }
850
715
  return {
851
716
  products: Array.from(allProducts.values()),
717
+ rawGroups,
852
718
  summary: {
853
719
  productType,
854
720
  pageSize,
@@ -860,27 +726,23 @@ async function fetchProductPool(creatorId, productType, pageSize, maxPages) {
860
726
  }
861
727
  };
862
728
  }
863
- function sortProductsForSelection(products) {
864
- return [...products].sort((a, b) => b.salesCount - a.salesCount);
729
+ function isProductPublishable(product) {
730
+ if (product.reviewStatus && product.reviewStatus.toUpperCase() !== "APPROVED") return false;
731
+ if (product.inventoryStatus && product.inventoryStatus.toUpperCase() !== "IN_STOCK") return false;
732
+ return true;
865
733
  }
866
- function buildSelectedProductSummary(product, selectionMode) {
867
- return {
868
- selectionMode,
869
- id: product.id,
870
- title: product.title,
871
- salesCount: product.salesCount,
872
- source: product.source,
873
- price: product.price,
874
- brandName: product.brandName,
875
- shopName: product.shopName
876
- };
734
+ function sortProductsForSelection(products) {
735
+ return products.filter(isProductPublishable).sort((a, b) => b.salesCount - a.salesCount);
877
736
  }
878
737
  async function promptForProductSelection(products) {
879
738
  if (!process.stdin.isTTY || !process.stdout.isTTY) {
880
739
  throw new Error("\u4EA4\u4E92\u6A21\u5F0F\u9700\u8981\u5728 TTY \u7EC8\u7AEF\u4E2D\u8FD0\u884C");
881
740
  }
882
- const candidates = sortProductsForSelection(products).slice(0, 20);
883
- console.log(`\u53EF\u9009\u5546\u54C1\uFF08\u5C55\u793A\u524D ${candidates.length} \u4E2A\uFF0C\u6309\u9500\u91CF\u964D\u5E8F\uFF09\uFF1A`);
741
+ const candidates = products.filter(isProductPublishable).sort((a, b) => b.salesCount - a.salesCount).slice(0, 20);
742
+ if (candidates.length === 0) {
743
+ throw new Error("\u5F53\u524D\u5546\u54C1\u6C60\u4E2D\u6CA1\u6709\u53EF\u53D1\u5E03\u5546\u54C1\uFF08\u5BA1\u6838\u672A\u901A\u8FC7\u6216\u65E0\u5E93\u5B58\uFF09\uFF0C\u5982\u9700\u5F3A\u5236\u6307\u5B9A\u8BF7\u4F7F\u7528 --product-id/--product-title");
744
+ }
745
+ console.log(`\u53EF\u9009\u5546\u54C1\uFF08\u5C55\u793A\u524D ${candidates.length} \u4E2A\uFF0C\u6309\u9500\u91CF\u964D\u5E8F\uFF0C\u5DF2\u8FC7\u6EE4\u4E0D\u53EF\u53D1\u5E03\u5546\u54C1\uFF09\uFF1A`);
884
746
  for (const [index, product] of candidates.entries()) {
885
747
  console.log(
886
748
  `${index + 1}. [${product.source}] ${product.title} | ID: ${product.id} | \u9500\u91CF: ${product.salesCount}`
@@ -904,6 +766,73 @@ async function promptForProductSelection(products) {
904
766
  }
905
767
  }
906
768
 
769
+ // src/commands/query-products.ts
770
+ var VALID_PRODUCT_TYPES = ["shop", "showcase", "all"];
771
+ function register7(cli2) {
772
+ cli2.command("query-products", "\u67E5\u8BE2 TTS \u5546\u54C1\u5217\u8868").option("--creator-id <id>", "TTS \u8D26\u53F7 creatorUserOpenId\uFF08\u5FC5\u586B\uFF09").option("--product-type <type>", "\u5546\u54C1\u6765\u6E90: shop / showcase / all\uFF08\u9ED8\u8BA4 all\uFF09").option("--page-size <n>", "\u6BCF\u9875\u6570\u91CF\uFF08\u9ED8\u8BA4 20\uFF09").option("--cursor <cursor>", "\u5206\u9875\u6E38\u6807\uFF08\u9996\u9875\u4E0D\u4F20\uFF09").action(
773
+ async (options) => {
774
+ if (!options.creatorId) {
775
+ console.error("\u7F3A\u5C11\u5FC5\u586B\u53C2\u6570: --creator-id\n");
776
+ console.error("\u7528\u6CD5: beervid query-products --creator-id <id>");
777
+ process.exit(1);
778
+ }
779
+ const creatorId = options.creatorId;
780
+ const productType = (options.productType ?? "all").toLowerCase();
781
+ const pageSize = parseInt(options.pageSize ?? "20", 10);
782
+ const cursor = options.cursor ?? "";
783
+ if (!VALID_PRODUCT_TYPES.includes(productType)) {
784
+ console.error("\u9519\u8BEF: --product-type \u5FC5\u987B\u4E3A shop\u3001showcase \u6216 all");
785
+ process.exit(1);
786
+ }
787
+ if (Number.isNaN(pageSize) || pageSize <= 0) {
788
+ console.error("\u9519\u8BEF: --page-size \u5FC5\u987B\u4E3A\u5927\u4E8E 0 \u7684\u6574\u6570");
789
+ process.exit(1);
790
+ }
791
+ try {
792
+ let inputCursor = { shopToken: "", showcaseToken: "" };
793
+ if (cursor) {
794
+ try {
795
+ inputCursor = decodeCursor(cursor);
796
+ } catch {
797
+ console.error("\u9519\u8BEF: \u65E0\u6548\u7684 cursor \u683C\u5F0F");
798
+ process.exit(1);
799
+ }
800
+ }
801
+ const pageResult = await queryProductsPage(
802
+ creatorId,
803
+ productType,
804
+ pageSize,
805
+ inputCursor
806
+ );
807
+ if (pageResult.successCount === 0 && pageResult.failedSources.length > 0) {
808
+ console.error("\u67E5\u8BE2\u5546\u54C1\u5931\u8D25: \u6240\u6709\u5546\u54C1\u6E90\u90FD\u8BF7\u6C42\u5931\u8D25");
809
+ process.exit(1);
810
+ }
811
+ const productList = pageResult.products;
812
+ console.log(`\u67E5\u8BE2\u5230 ${productList.length} \u4E2A\u5546\u54C1:
813
+ `);
814
+ for (const p of productList) {
815
+ console.log(` [${p.source}] ${p.title}`);
816
+ console.log(` ID: ${p.id} \u9500\u91CF: ${p.salesCount} \u54C1\u724C: ${p.brandName}`);
817
+ if (p.images.length > 0) console.log(` \u56FE\u7247: ${p.images[0]}`);
818
+ console.log("");
819
+ }
820
+ if (pageResult.nextCursor) {
821
+ console.log(`\u4E0B\u4E00\u9875\u6E38\u6807: ${pageResult.nextCursor}`);
822
+ console.log(`\u4F7F\u7528: beervid query-products --creator-id ${creatorId} --cursor ${pageResult.nextCursor}`);
823
+ } else {
824
+ console.log("\u5DF2\u5230\u6700\u540E\u4E00\u9875");
825
+ }
826
+ printResult(pageResult.rawGroups);
827
+ } catch (err) {
828
+ rethrowIfProcessExit(err);
829
+ console.error("\u67E5\u8BE2\u5546\u54C1\u5931\u8D25:", err.message);
830
+ process.exit(1);
831
+ }
832
+ }
833
+ );
834
+ }
835
+
907
836
  // src/commands/publish-tt-flow.ts
908
837
  function parsePositiveInt(value, optionName, defaultValue) {
909
838
  const parsed = parseInt(value ?? `${defaultValue}`, 10);
@@ -953,7 +882,6 @@ function register8(cli2) {
953
882
  intervalSec,
954
883
  maxPolls
955
884
  );
956
- const warnings = [];
957
885
  const videoId = status.postIds[0] ?? null;
958
886
  let query = null;
959
887
  if (status.finalStatus === "PUBLISH_COMPLETE" && videoId) {
@@ -965,18 +893,16 @@ function register8(cli2) {
965
893
  queryMaxAttempts
966
894
  );
967
895
  query = queryResult.query;
968
- warnings.push(...queryResult.warnings);
896
+ for (const warning of queryResult.warnings) {
897
+ console.warn(warning.message);
898
+ }
969
899
  }
970
- const result = {
971
- flowType: "tt",
900
+ printResult({
972
901
  upload,
973
902
  publish,
974
- status,
975
- videoId,
976
- query,
977
- warnings
978
- };
979
- printResult(result);
903
+ status: status.raw,
904
+ query
905
+ });
980
906
  if (status.finalStatus === "FAILED") {
981
907
  process.exit(1);
982
908
  }
@@ -1059,58 +985,62 @@ function register9(cli2) {
1059
985
  );
1060
986
  try {
1061
987
  console.log("\u5F00\u59CB\u6267\u884C TTS \u5B8C\u6574\u53D1\u5E03\u6D41\u7A0B...");
1062
- console.log("1/4 \u6B63\u5728\u67E5\u8BE2\u5546\u54C1\u5217\u8868...");
1063
- const productPool = await fetchProductPool(
1064
- options.creatorId,
1065
- productType,
1066
- pageSize,
1067
- maxProductPages
1068
- );
1069
- const warnings = [];
1070
- if (productPool.summary.reachedPageLimit && productPool.summary.nextCursor) {
1071
- warnings.push({
1072
- code: "PRODUCT_SCAN_LIMIT_REACHED",
1073
- message: `\u5546\u54C1\u626B\u63CF\u5DF2\u8FBE\u5230\u9875\u6570\u4E0A\u9650 ${maxProductPages}\uFF0C\u4ECD\u5B58\u5728\u672A\u62C9\u53D6\u5206\u9875`
1074
- });
1075
- }
1076
- if (productPool.summary.failedSources.length > 0) {
1077
- warnings.push({
1078
- code: "PRODUCT_SOURCE_PARTIAL_FAILURE",
1079
- message: `\u4EE5\u4E0B\u5546\u54C1\u6E90\u8BF7\u6C42\u5931\u8D25: ${productPool.summary.failedSources.join(", ")}\uFF0C\u5546\u54C1\u6C60\u53EF\u80FD\u4E0D\u5B8C\u6574`
1080
- });
1081
- }
1082
- if (productPool.products.length === 0) {
1083
- 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");
1084
- process.exit(1);
1085
- }
1086
- let selectionMode = "automatic";
1087
988
  let selectedProduct;
1088
- if (options.productId) {
1089
- selectionMode = "manual";
1090
- const matchedProduct = productPool.products.find(
1091
- (product) => product.id === options.productId
989
+ let queriedProducts = null;
990
+ if (options.productId && options.productTitle) {
991
+ console.log("1/4 \u5DF2\u624B\u52A8\u6307\u5B9A\u5546\u54C1\uFF0C\u8DF3\u8FC7\u5546\u54C1\u67E5\u8BE2...");
992
+ selectedProduct = buildManualProduct(options.productId, options.productTitle);
993
+ } else {
994
+ console.log("1/4 \u6B63\u5728\u67E5\u8BE2\u5546\u54C1\u5217\u8868...");
995
+ const productPool = await fetchProductPool(
996
+ options.creatorId,
997
+ productType,
998
+ pageSize,
999
+ maxProductPages
1092
1000
  );
1093
- const resolvedTitle = options.productTitle ?? matchedProduct?.title;
1094
- if (!resolvedTitle) {
1095
- console.error(
1096
- "\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"
1001
+ queriedProducts = productPool.rawGroups;
1002
+ if (productPool.summary.reachedPageLimit && productPool.summary.nextCursor) {
1003
+ console.warn(`\u5546\u54C1\u626B\u63CF\u5DF2\u8FBE\u5230\u9875\u6570\u4E0A\u9650 ${maxProductPages}\uFF0C\u4ECD\u5B58\u5728\u672A\u62C9\u53D6\u5206\u9875`);
1004
+ }
1005
+ if (productPool.summary.failedSources.length > 0) {
1006
+ console.warn(
1007
+ `\u4EE5\u4E0B\u5546\u54C1\u6E90\u8BF7\u6C42\u5931\u8D25: ${productPool.summary.failedSources.join(", ")}\uFF0C\u5546\u54C1\u6C60\u53EF\u80FD\u4E0D\u5B8C\u6574`
1097
1008
  );
1098
- process.exit(1);
1099
1009
  }
1100
- selectedProduct = buildManualProduct(options.productId, resolvedTitle, matchedProduct);
1101
- if (!matchedProduct) {
1102
- warnings.push({
1103
- code: "PRODUCT_NOT_IN_SCANNED_POOL",
1104
- 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"
1105
- });
1010
+ if (options.productId) {
1011
+ const matchedProduct = productPool.products.find(
1012
+ (product) => product.id === options.productId
1013
+ );
1014
+ const resolvedTitle = matchedProduct?.title;
1015
+ if (!resolvedTitle) {
1016
+ console.error(
1017
+ "\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"
1018
+ );
1019
+ process.exit(1);
1020
+ }
1021
+ selectedProduct = buildManualProduct(options.productId, resolvedTitle, matchedProduct);
1022
+ } else if (options.interactive) {
1023
+ if (productPool.products.length === 0) {
1024
+ 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");
1025
+ process.exit(1);
1026
+ }
1027
+ console.log("2/4 \u8BF7\u9009\u62E9\u8981\u6302\u8F66\u7684\u5546\u54C1...");
1028
+ selectedProduct = await promptForProductSelection(productPool.products);
1029
+ } else {
1030
+ if (productPool.products.length === 0) {
1031
+ 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");
1032
+ process.exit(1);
1033
+ }
1034
+ console.log("2/4 \u6B63\u5728\u81EA\u52A8\u9009\u62E9\u5546\u54C1\uFF08\u6309\u9500\u91CF\u6700\u9AD8\u4F18\u5148\uFF09...");
1035
+ const publishable = sortProductsForSelection(productPool.products);
1036
+ if (publishable.length === 0) {
1037
+ console.error(
1038
+ "TTS \u5B8C\u6574\u53D1\u5E03\u6D41\u7A0B\u5931\u8D25: \u5546\u54C1\u6C60\u4E2D\u6CA1\u6709\u53EF\u53D1\u5E03\u5546\u54C1\uFF08\u5BA1\u6838\u672A\u901A\u8FC7\u6216\u65E0\u5E93\u5B58\uFF09\uFF0C\u5982\u9700\u5F3A\u5236\u6307\u5B9A\u8BF7\u4F7F\u7528 --product-id/--product-title"
1039
+ );
1040
+ process.exit(1);
1041
+ }
1042
+ selectedProduct = publishable[0];
1106
1043
  }
1107
- } else if (options.interactive) {
1108
- selectionMode = "interactive";
1109
- console.log("2/4 \u8BF7\u9009\u62E9\u8981\u6302\u8F66\u7684\u5546\u54C1...");
1110
- selectedProduct = await promptForProductSelection(productPool.products);
1111
- } else {
1112
- console.log("2/4 \u6B63\u5728\u81EA\u52A8\u9009\u62E9\u5546\u54C1\uFF08\u6309\u9500\u91CF\u6700\u9AD8\u4F18\u5148\uFF09...");
1113
- selectedProduct = sortProductsForSelection(productPool.products)[0];
1114
1044
  }
1115
1045
  console.log("3/4 \u6B63\u5728\u4E0A\u4F20\u6302\u8F66\u89C6\u9891...");
1116
1046
  const upload = await uploadTtsVideo(options.file, options.creatorId, options.token);
@@ -1123,20 +1053,14 @@ function register9(cli2) {
1123
1053
  options.caption
1124
1054
  );
1125
1055
  if (publishResult.productTitle !== selectedProduct.title) {
1126
- warnings.push({
1127
- code: "PRODUCT_TITLE_TRUNCATED",
1128
- message: "\u5546\u54C1\u6807\u9898\u8D85\u8FC7 29 \u5B57\u7B26\uFF0C\u53D1\u5E03\u65F6\u5DF2\u81EA\u52A8\u622A\u65AD"
1129
- });
1056
+ console.warn("\u5546\u54C1\u6807\u9898\u8D85\u8FC7 29 \u5B57\u7B26\uFF0C\u53D1\u5E03\u65F6\u5DF2\u81EA\u52A8\u622A\u65AD");
1130
1057
  }
1131
- const result = {
1132
- flowType: "tts",
1133
- productQuery: productPool.summary,
1134
- selectedProduct: buildSelectedProductSummary(selectedProduct, selectionMode),
1058
+ printResult({
1059
+ products: queriedProducts,
1060
+ selectedProduct,
1135
1061
  upload,
1136
- publish: publishResult.publish,
1137
- warnings
1138
- };
1139
- printResult(result);
1062
+ publish: publishResult.publish
1063
+ });
1140
1064
  } catch (err) {
1141
1065
  rethrowIfProcessExit(err);
1142
1066
  console.error("TTS \u5B8C\u6574\u53D1\u5E03\u6D41\u7A0B\u5931\u8D25:", err.message);
@@ -1187,7 +1111,7 @@ function register10(cli2) {
1187
1111
 
1188
1112
  // src/cli.ts
1189
1113
  var cli = cac("beervid");
1190
- var cliVersion = true ? "0.2.1" : pkg.version;
1114
+ var cliVersion = true ? "0.2.3" : pkg.version;
1191
1115
  register10(cli);
1192
1116
  register(cli);
1193
1117
  register2(cli);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "beervid-app-cli",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "BEERVID App CLI — TikTok video publish, account auth, and data query",
5
5
  "type": "module",
6
6
  "engines": {