douyin-downloader 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.
Files changed (161) hide show
  1. package/README.md +114 -0
  2. package/dist/bin/dydl.d.ts +2 -0
  3. package/dist/bin/dydl.js +17 -0
  4. package/dist/bin/dydl.js.map +1 -0
  5. package/dist/src/cli/commands/check.d.ts +10 -0
  6. package/dist/src/cli/commands/check.js +102 -0
  7. package/dist/src/cli/commands/check.js.map +1 -0
  8. package/dist/src/cli/commands/info.d.ts +10 -0
  9. package/dist/src/cli/commands/info.js +106 -0
  10. package/dist/src/cli/commands/info.js.map +1 -0
  11. package/dist/src/cli/commands/list.d.ts +10 -0
  12. package/dist/src/cli/commands/list.js +85 -0
  13. package/dist/src/cli/commands/list.js.map +1 -0
  14. package/dist/src/cli/commands/login.d.ts +10 -0
  15. package/dist/src/cli/commands/login.js +158 -0
  16. package/dist/src/cli/commands/login.js.map +1 -0
  17. package/dist/src/cli/commands/open.d.ts +10 -0
  18. package/dist/src/cli/commands/open.js +141 -0
  19. package/dist/src/cli/commands/open.js.map +1 -0
  20. package/dist/src/cli/commands/video.d.ts +10 -0
  21. package/dist/src/cli/commands/video.js +209 -0
  22. package/dist/src/cli/commands/video.js.map +1 -0
  23. package/dist/src/cli/index.d.ts +15 -0
  24. package/dist/src/cli/index.js +134 -0
  25. package/dist/src/cli/index.js.map +1 -0
  26. package/dist/src/cli/progress-display.d.ts +80 -0
  27. package/dist/src/cli/progress-display.js +225 -0
  28. package/dist/src/cli/progress-display.js.map +1 -0
  29. package/dist/src/cli/utils.d.ts +31 -0
  30. package/dist/src/cli/utils.js +171 -0
  31. package/dist/src/cli/utils.js.map +1 -0
  32. package/dist/src/douyin/auth/cookie-path.d.ts +22 -0
  33. package/dist/src/douyin/auth/cookie-path.js +72 -0
  34. package/dist/src/douyin/auth/cookie-path.js.map +1 -0
  35. package/dist/src/douyin/auth/cookie-storage.d.ts +19 -0
  36. package/dist/src/douyin/auth/cookie-storage.js +65 -0
  37. package/dist/src/douyin/auth/cookie-storage.js.map +1 -0
  38. package/dist/src/douyin/auth/errors.d.ts +28 -0
  39. package/dist/src/douyin/auth/errors.js +49 -0
  40. package/dist/src/douyin/auth/errors.js.map +1 -0
  41. package/dist/src/douyin/auth/getDefaultCookiePath.d.ts +24 -0
  42. package/dist/src/douyin/auth/getDefaultCookiePath.js +90 -0
  43. package/dist/src/douyin/auth/getDefaultCookiePath.js.map +1 -0
  44. package/dist/src/douyin/auth/index.d.ts +16 -0
  45. package/dist/src/douyin/auth/index.js +68 -0
  46. package/dist/src/douyin/auth/index.js.map +1 -0
  47. package/dist/src/douyin/auth/isValidCookie.d.ts +18 -0
  48. package/dist/src/douyin/auth/isValidCookie.js +60 -0
  49. package/dist/src/douyin/auth/isValidCookie.js.map +1 -0
  50. package/dist/src/douyin/auth/loadAndValidateCookie.d.ts +17 -0
  51. package/dist/src/douyin/auth/loadAndValidateCookie.js +45 -0
  52. package/dist/src/douyin/auth/loadAndValidateCookie.js.map +1 -0
  53. package/dist/src/douyin/auth/loadCookie.d.ts +17 -0
  54. package/dist/src/douyin/auth/loadCookie.js +79 -0
  55. package/dist/src/douyin/auth/loadCookie.js.map +1 -0
  56. package/dist/src/douyin/auth/login.d.ts +33 -0
  57. package/dist/src/douyin/auth/login.js +157 -0
  58. package/dist/src/douyin/auth/login.js.map +1 -0
  59. package/dist/src/douyin/auth/saveCookie.d.ts +17 -0
  60. package/dist/src/douyin/auth/saveCookie.js +89 -0
  61. package/dist/src/douyin/auth/saveCookie.js.map +1 -0
  62. package/dist/src/douyin/auth/validate.d.ts +11 -0
  63. package/dist/src/douyin/auth/validate.js +104 -0
  64. package/dist/src/douyin/auth/validate.js.map +1 -0
  65. package/dist/src/douyin/browser/manager.d.ts +54 -0
  66. package/dist/src/douyin/browser/manager.js +344 -0
  67. package/dist/src/douyin/browser/manager.js.map +1 -0
  68. package/dist/src/douyin/download/download-manager.d.ts +25 -0
  69. package/dist/src/douyin/download/download-manager.js +107 -0
  70. package/dist/src/douyin/download/download-manager.js.map +1 -0
  71. package/dist/src/douyin/download/error-handler.d.ts +49 -0
  72. package/dist/src/douyin/download/error-handler.js +160 -0
  73. package/dist/src/douyin/download/error-handler.js.map +1 -0
  74. package/dist/src/douyin/download/index.d.ts +39 -0
  75. package/dist/src/douyin/download/index.js +156 -0
  76. package/dist/src/douyin/download/index.js.map +1 -0
  77. package/dist/src/douyin/download/path-formatter.d.ts +42 -0
  78. package/dist/src/douyin/download/path-formatter.js +107 -0
  79. package/dist/src/douyin/download/path-formatter.js.map +1 -0
  80. package/dist/src/douyin/download/video-downloader.d.ts +35 -0
  81. package/dist/src/douyin/download/video-downloader.js +223 -0
  82. package/dist/src/douyin/download/video-downloader.js.map +1 -0
  83. package/dist/src/douyin/index.d.ts +19 -0
  84. package/dist/src/douyin/index.js +52 -0
  85. package/dist/src/douyin/index.js.map +1 -0
  86. package/dist/src/douyin/info/batch-processor.d.ts +15 -0
  87. package/dist/src/douyin/info/batch-processor.js +65 -0
  88. package/dist/src/douyin/info/batch-processor.js.map +1 -0
  89. package/dist/src/douyin/info/browser-manager.d.ts +56 -0
  90. package/dist/src/douyin/info/browser-manager.js +225 -0
  91. package/dist/src/douyin/info/browser-manager.js.map +1 -0
  92. package/dist/src/douyin/info/error-handler.d.ts +36 -0
  93. package/dist/src/douyin/info/error-handler.js +172 -0
  94. package/dist/src/douyin/info/error-handler.js.map +1 -0
  95. package/dist/src/douyin/info/fetch-video-detail.d.ts +14 -0
  96. package/dist/src/douyin/info/fetch-video-detail.js +247 -0
  97. package/dist/src/douyin/info/fetch-video-detail.js.map +1 -0
  98. package/dist/src/douyin/info/index.d.ts +29 -0
  99. package/dist/src/douyin/info/index.js +85 -0
  100. package/dist/src/douyin/info/index.js.map +1 -0
  101. package/dist/src/douyin/info/text-processor.d.ts +15 -0
  102. package/dist/src/douyin/info/text-processor.js +47 -0
  103. package/dist/src/douyin/info/text-processor.js.map +1 -0
  104. package/dist/src/douyin/info/user.d.ts +26 -0
  105. package/dist/src/douyin/info/user.js +237 -0
  106. package/dist/src/douyin/info/user.js.map +1 -0
  107. package/dist/src/douyin/parser/containsDouyinLink.d.ts +18 -0
  108. package/dist/src/douyin/parser/containsDouyinLink.js +27 -0
  109. package/dist/src/douyin/parser/containsDouyinLink.js.map +1 -0
  110. package/dist/src/douyin/parser/extract-links.d.ts +23 -0
  111. package/dist/src/douyin/parser/extract-links.js +79 -0
  112. package/dist/src/douyin/parser/extract-links.js.map +1 -0
  113. package/dist/src/douyin/parser/extractDouyinLinks.d.ts +18 -0
  114. package/dist/src/douyin/parser/extractDouyinLinks.js +58 -0
  115. package/dist/src/douyin/parser/extractDouyinLinks.js.map +1 -0
  116. package/dist/src/douyin/parser/index.d.ts +35 -0
  117. package/dist/src/douyin/parser/index.js +70 -0
  118. package/dist/src/douyin/parser/index.js.map +1 -0
  119. package/dist/src/douyin/parser/link-patterns.d.ts +34 -0
  120. package/dist/src/douyin/parser/link-patterns.js +121 -0
  121. package/dist/src/douyin/parser/link-patterns.js.map +1 -0
  122. package/dist/src/douyin/parser/parse-batch.d.ts +26 -0
  123. package/dist/src/douyin/parser/parse-batch.js +67 -0
  124. package/dist/src/douyin/parser/parse-batch.js.map +1 -0
  125. package/dist/src/douyin/parser/parseDouyinLinks.d.ts +30 -0
  126. package/dist/src/douyin/parser/parseDouyinLinks.js +164 -0
  127. package/dist/src/douyin/parser/parseDouyinLinks.js.map +1 -0
  128. package/dist/src/douyin/parser/resolve-links.d.ts +25 -0
  129. package/dist/src/douyin/parser/resolve-links.js +131 -0
  130. package/dist/src/douyin/parser/resolve-links.js.map +1 -0
  131. package/dist/src/index.d.ts +16 -0
  132. package/dist/src/index.js +72 -0
  133. package/dist/src/index.js.map +1 -0
  134. package/dist/src/types.d.ts +217 -0
  135. package/dist/src/types.js +6 -0
  136. package/dist/src/types.js.map +1 -0
  137. package/dist/src/utils/browser.d.ts +73 -0
  138. package/dist/src/utils/browser.js +96 -0
  139. package/dist/src/utils/browser.js.map +1 -0
  140. package/dist/src/utils/error.d.ts +160 -0
  141. package/dist/src/utils/error.js +334 -0
  142. package/dist/src/utils/error.js.map +1 -0
  143. package/dist/src/utils/fetch.d.ts +41 -0
  144. package/dist/src/utils/fetch.js +155 -0
  145. package/dist/src/utils/fetch.js.map +1 -0
  146. package/dist/src/utils/file.d.ts +46 -0
  147. package/dist/src/utils/file.js +189 -0
  148. package/dist/src/utils/file.js.map +1 -0
  149. package/dist/src/utils/index.d.ts +11 -0
  150. package/dist/src/utils/index.js +29 -0
  151. package/dist/src/utils/index.js.map +1 -0
  152. package/dist/src/utils/logger.d.ts +161 -0
  153. package/dist/src/utils/logger.js +286 -0
  154. package/dist/src/utils/logger.js.map +1 -0
  155. package/dist/src/utils/performance.d.ts +98 -0
  156. package/dist/src/utils/performance.js +292 -0
  157. package/dist/src/utils/performance.js.map +1 -0
  158. package/dist/src/utils/retry.d.ts +56 -0
  159. package/dist/src/utils/retry.js +127 -0
  160. package/dist/src/utils/retry.js.map +1 -0
  161. package/package.json +61 -0
package/README.md ADDED
@@ -0,0 +1,114 @@
1
+ # 抖音影片解析與下載工具 (douyin-downloader)
2
+
3
+ [![NPM version](https://img.shields.io/npm/v/douyin-downloader.svg?style=flat)](https://www.npmjs.com/package/douyin-downloader)
4
+ [![License](https://img.shields.io/npm/l/douyin-downloader.svg?style=flat)](https://github.com/gkctou/douyin-downloader/blob/main/LICENSE)
5
+
6
+ 一個基於 Node.js 和 Puppeteer 的命令列工具,用於解析和下載抖音 (Douyin) 影片,並獲取影片及用戶資訊。
7
+
8
+ ## ✨ 功能特性
9
+
10
+ * **影片下載**: 下載指定的單一抖音影片。
11
+ * **影片資訊**: 獲取影片的詳細資訊 (作者、標題、發布時間等)。
12
+ * **用戶影片列表**: 獲取指定用戶發布的所有影片連結列表。
13
+ * **登入與驗證**: 支援透過掃描 QR Code 登入抖音帳號,並驗證登入狀態。
14
+ * **自訂輸出**: 可指定下載目錄和檔案名稱,或將資訊輸出至檔案。
15
+ * **瀏覽器操作**: 可開啟已載入 Cookie 的瀏覽器實例。
16
+ * **詳細日誌**: 提供詳細模式 (`--verbose`) 以方便調試。
17
+
18
+ ## 🚀 安裝
19
+
20
+ 確保您的系統已安裝 Node.js (建議版本 >= 20.0.0) 和 npm。
21
+
22
+ ```bash
23
+ npm install -g douyin-downloader
24
+ ```
25
+
26
+ 或者,如果您不想全域安裝,可以使用 `npx`:
27
+
28
+ ```bash
29
+ npx dy-dl <命令> [選項]
30
+ ```
31
+
32
+ ## 🛠️ 使用說明
33
+
34
+ `douyin-downloader` 提供了一個名為 `dy-dl` 的命令列介面。
35
+
36
+ ### 基本命令格式
37
+
38
+ ```bash
39
+ dy-dl <命令> [選項] [參數]
40
+ ```
41
+
42
+ ### 可用命令
43
+
44
+ * **`login`**: 登入抖音帳號並儲存 Cookie。
45
+ ```bash
46
+ dy-dl login
47
+ ```
48
+ 執行後會開啟瀏覽器顯示 QR Code,請使用抖音 App 掃描登入。Cookie 將儲存於預設路徑。
49
+
50
+ * **`check`**: 檢查已儲存的 Cookie 是否有效。
51
+ ```bash
52
+ dy-dl check
53
+ ```
54
+
55
+ * **`open`**: 開啟一個已載入 Cookie 的瀏覽器實例。
56
+ ```bash
57
+ dy-dl open
58
+ ```
59
+
60
+ * **`video <影片連結>`**: 下載單個影片。
61
+ ```bash
62
+ # 下載影片到目前目錄
63
+ dy-dl video https://v.douyin.com/xxxxxxx/
64
+
65
+ # 指定下載目錄
66
+ dy-dl video -d ./downloads https://v.douyin.com/xxxxxxx/
67
+
68
+ # 指定下載目錄和檔案名稱 (注意: -f 僅適用於單個影片下載)
69
+ dy-dl video -d ./downloads -f my_video.mp4 https://v.douyin.com/xxxxxxx/
70
+ ```
71
+
72
+ * **`info <影片連結>`**: 獲取影片資訊。
73
+ ```bash
74
+ # 輸出資訊到控制台
75
+ dy-dl info https://v.douyin.com/xxxxxxx/
76
+
77
+ # 輸出資訊到 JSON 檔案
78
+ dy-dl info -f video_info.json https://v.douyin.com/xxxxxxx/
79
+ ```
80
+
81
+ * **`list <用戶主頁連結>`**: 獲取用戶影片列表。
82
+ ```bash
83
+ # 獲取用戶所有影片列表並輸出到控制台
84
+ dy-dl list https://www.douyin.com/user/MS4wLjABAAAAxxxxxxxxxxxxxxxx
85
+
86
+ # 獲取用戶最新的 10 個影片列表
87
+ dy-dl list -n 10 https://www.douyin.com/user/MS4wLjABAAAAxxxxxxxxxxxxxxxx
88
+
89
+ # 獲取用戶影片列表並輸出到 JSON 檔案
90
+ dy-dl list -f user_videos.json https://www.douyin.com/user/MS4wLjABAAAAxxxxxxxxxxxxxxxx
91
+ ```
92
+
93
+ ### 全局選項
94
+
95
+ * **`-v, --verbose`**: 顯示詳細日誌輸出。
96
+ * **`-h, --help`**: 顯示幫助訊息。
97
+
98
+ ## 🔑 身份驗證 (Cookie)
99
+
100
+ 部分功能 (如下載某些受限影片或獲取完整的用戶列表) 可能需要登入狀態。使用 `dy-dl login` 命令登入後,Cookie 會被儲存。工具在執行需要驗證的操作時會自動載入儲存的 Cookie。您可以使用 `dy-dl check` 來確認 Cookie 的有效性。
101
+
102
+ Cookie 預設儲存路徑會根據您的作業系統而有所不同 (通常在用戶設定或應用程式資料目錄下)。
103
+
104
+ ## 📄 授權條款
105
+
106
+ 本專案採用 [MIT](LICENSE) 授權條款。
107
+
108
+ ## 🤝 貢獻
109
+
110
+ 歡迎提交 Issue 或 Pull Request。
111
+
112
+ ---
113
+
114
+ **免責聲明**: 本工具僅供學習和技術研究使用,請勿用於非法用途或侵犯版權。下載的內容版權歸原作者所有。
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const cli_1 = require("../src/cli");
5
+ // Logger level setting is now handled inside the Logger constructor
6
+ // 運行 CLI 程序
7
+ (async () => {
8
+ try {
9
+ await (0, cli_1.runCli)();
10
+ }
11
+ catch (error) {
12
+ console.error('CLI 執行錯誤:', error); // Keep error logging
13
+ process.exit(1);
14
+ }
15
+ // No finally block needed as logger level doesn't need explicit restoration for process exit
16
+ })();
17
+ //# sourceMappingURL=dydl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dydl.js","sourceRoot":"","sources":["../../bin/dydl.ts"],"names":[],"mappings":";;;AAEA,oCAAoC;AACpC,oEAAoE;AAEpE,YAAY;AACZ,CAAC,KAAK,IAAI,EAAE;IACV,IAAI,CAAC;QACH,MAAM,IAAA,YAAM,GAAE,CAAC;IACjB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,CAAC,qBAAqB;QACxD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,6FAA6F;AAC/F,CAAC,CAAC,EAAE,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * 檢查命令
3
+ * 提供 'dydl check' 命令的實現
4
+ */
5
+ import { Command } from 'commander';
6
+ /**
7
+ * 註冊檢查命令
8
+ * @param program Commander 實例
9
+ */
10
+ export declare function registerCheckCommand(program: Command): void;
@@ -0,0 +1,102 @@
1
+ "use strict";
2
+ /**
3
+ * 檢查命令
4
+ * 提供 'dydl check' 命令的實現
5
+ */
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
18
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
19
+ }) : function(o, v) {
20
+ o["default"] = v;
21
+ });
22
+ var __importStar = (this && this.__importStar) || (function () {
23
+ var ownKeys = function(o) {
24
+ ownKeys = Object.getOwnPropertyNames || function (o) {
25
+ var ar = [];
26
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
27
+ return ar;
28
+ };
29
+ return ownKeys(o);
30
+ };
31
+ return function (mod) {
32
+ if (mod && mod.__esModule) return mod;
33
+ var result = {};
34
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
35
+ __setModuleDefault(result, mod);
36
+ return result;
37
+ };
38
+ })();
39
+ var __importDefault = (this && this.__importDefault) || function (mod) {
40
+ return (mod && mod.__esModule) ? mod : { "default": mod };
41
+ };
42
+ Object.defineProperty(exports, "__esModule", { value: true });
43
+ exports.registerCheckCommand = registerCheckCommand;
44
+ // 使用 dynamic import 代替直接導入 ESM 模塊
45
+ // import ora from 'ora';
46
+ // import chalk from 'chalk';
47
+ const fs_1 = __importDefault(require("fs"));
48
+ const auth_1 = require("../../douyin/auth"); // Corrected path
49
+ const logger_1 = require("../../utils/logger"); // Updated path to shared utils logger
50
+ // import { cleanupBrowser } from '../../utils/browser'; // Removed old cleanup
51
+ /**
52
+ * 註冊檢查命令
53
+ * @param program Commander 實例
54
+ */
55
+ function registerCheckCommand(program) {
56
+ program
57
+ .command('check')
58
+ .description('檢查儲存的 Cookie 是否有效')
59
+ .argument('[cookie-path]', '要檢查的 cookie 檔案路徑', (0, auth_1.getDefaultCookiePath)())
60
+ .action(async (cookiePath) => {
61
+ logger_1.cliLogger.debug(`檢查命令執行,Cookie 路徑: ${cookiePath}`);
62
+ // 動態導入 ESM 模塊
63
+ const [{ default: ora }, { default: chalk }] = await Promise.all([
64
+ Promise.resolve().then(() => __importStar(require('ora'))),
65
+ Promise.resolve().then(() => __importStar(require('chalk')))
66
+ ]);
67
+ const spinner = ora('檢查 Cookie...').start();
68
+ try {
69
+ // 檢查檔案是否存在
70
+ if (!fs_1.default.existsSync(cookiePath)) {
71
+ spinner.fail(`Cookie 檔案不存在: ${cookiePath}`);
72
+ console.log(chalk.yellow(`請執行 ${chalk.cyan('dydl login')} 先登入抖音`));
73
+ return;
74
+ }
75
+ // 加載 Cookie
76
+ const cookie = await (0, auth_1.loadCookie)(cookiePath);
77
+ if (!cookie) {
78
+ spinner.fail(`Cookie 檔案為空: ${cookiePath}`);
79
+ return;
80
+ }
81
+ // 驗證 Cookie
82
+ spinner.text = '正在驗證 Cookie 有效性...';
83
+ const isValid = await (0, auth_1.isValidCookie)(cookie);
84
+ if (isValid) {
85
+ spinner.succeed(`Cookie 有效 (${cookiePath})`);
86
+ }
87
+ else {
88
+ spinner.fail(`Cookie 已過期或無效`);
89
+ console.log(chalk.yellow(`請執行 ${chalk.cyan('dydl login')} 重新登入抖音`));
90
+ }
91
+ }
92
+ catch (error) {
93
+ spinner.fail(`檢查 Cookie 時發生錯誤`);
94
+ const err = error instanceof Error ? error : new Error(String(error));
95
+ logger_1.cliLogger.error('檢查命令執行失敗:', err);
96
+ console.error(chalk.red(err.message));
97
+ process.exitCode = 1;
98
+ }
99
+ // Removed finally block with cleanupBrowser
100
+ });
101
+ }
102
+ //# sourceMappingURL=check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check.js","sourceRoot":"","sources":["../../../../src/cli/commands/check.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAeH,oDAkDC;AA9DD,kCAAkC;AAClC,yBAAyB;AACzB,6BAA6B;AAC7B,4CAAoB;AACpB,4CAAoF,CAAC,iBAAiB;AACtG,+CAAyD,CAAC,sCAAsC;AAChG,+EAA+E;AAE/E;;;GAGG;AACH,SAAgB,oBAAoB,CAAC,OAAgB;IACnD,OAAO;SACJ,OAAO,CAAC,OAAO,CAAC;SAChB,WAAW,CAAC,mBAAmB,CAAC;SAChC,QAAQ,CAAC,eAAe,EAAE,kBAAkB,EAAE,IAAA,2BAAoB,GAAE,CAAC;SACrE,MAAM,CAAC,KAAK,EAAE,UAAU,EAAE,EAAE;QAC3B,kBAAM,CAAC,KAAK,CAAC,qBAAqB,UAAU,EAAE,CAAC,CAAC;QAEhD,cAAc;QACd,MAAM,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;8DACxD,KAAK;8DACL,OAAO;SACf,CAAC,CAAC;QAEH,MAAM,OAAO,GAAG,GAAG,CAAC,cAAc,CAAC,CAAC,KAAK,EAAE,CAAC;QAE5C,IAAI,CAAC;YACH,WAAW;YACX,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;gBAC/B,OAAO,CAAC,IAAI,CAAC,iBAAiB,UAAU,EAAE,CAAC,CAAC;gBAC5C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC;gBACnE,OAAO;YACT,CAAC;YAED,YAAY;YACZ,MAAM,MAAM,GAAG,MAAM,IAAA,iBAAU,EAAC,UAAU,CAAC,CAAC;YAC5C,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,OAAO,CAAC,IAAI,CAAC,gBAAgB,UAAU,EAAE,CAAC,CAAC;gBAC3C,OAAO;YACT,CAAC;YAED,YAAY;YACZ,OAAO,CAAC,IAAI,GAAG,oBAAoB,CAAC;YACpC,MAAM,OAAO,GAAG,MAAM,IAAA,oBAAa,EAAC,MAAM,CAAC,CAAC;YAE5C,IAAI,OAAO,EAAE,CAAC;gBACZ,OAAO,CAAC,OAAO,CAAC,cAAc,UAAU,GAAG,CAAC,CAAC;YAC/C,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;gBAC9B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC,CAAC;YACtE,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;YAChC,MAAM,GAAG,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;YACtE,kBAAM,CAAC,KAAK,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;YAC/B,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;YACtC,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACvB,CAAC;QACD,4CAA4C;IAC9C,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * 資訊命令
3
+ * 提供 'dydl info' 命令的實現
4
+ */
5
+ import { Command } from 'commander';
6
+ /**
7
+ * 註冊資訊命令
8
+ * @param program Commander 實例
9
+ */
10
+ export declare function registerInfoCommand(program: Command): void;
@@ -0,0 +1,106 @@
1
+ "use strict";
2
+ /**
3
+ * 資訊命令
4
+ * 提供 'dydl info' 命令的實現
5
+ */
6
+ var __importDefault = (this && this.__importDefault) || function (mod) {
7
+ return (mod && mod.__esModule) ? mod : { "default": mod };
8
+ };
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.registerInfoCommand = registerInfoCommand;
11
+ const fs_extra_1 = __importDefault(require("fs-extra"));
12
+ const path_1 = __importDefault(require("path"));
13
+ const utils_1 = require("../utils");
14
+ const manager_1 = require("../../douyin/browser/manager");
15
+ const parser_1 = require("../../douyin/parser");
16
+ const info_1 = require("../../douyin/info");
17
+ /**
18
+ * 註冊資訊命令
19
+ * @param program Commander 實例
20
+ */
21
+ function registerInfoCommand(program) {
22
+ program
23
+ .command('info')
24
+ .description('獲取抖音影片的詳細資訊')
25
+ .argument('<sources...>', '影片連結或包含連結的文本')
26
+ .option('-c, --cookie <path>', '指定包含有效 Cookie 的檔案路徑')
27
+ .option('--user-data-dir <path>', '指定 Puppeteer 使用者資料目錄')
28
+ .option('-f, --file <path>', '將結果輸出為 JSON 檔案的路徑')
29
+ .action(async (sources, options) => {
30
+ const outputFile = options.file;
31
+ const cookiePath = options.cookie;
32
+ const userDataDir = options.userDataDir;
33
+ // --- 輸出控制 ---
34
+ const isSilent = !outputFile; // Determine if silent mode is needed
35
+ // Silent logic for logger is now handled in logger constructor
36
+ let browser = null;
37
+ try {
38
+ // 1. 檢查 Cookie
39
+ // checkAndGetCookie will respect silent mode if console is overridden at entry point
40
+ const cookie = await (0, utils_1.checkAndGetCookie)(cookiePath, isSilent); // Pass isSilent
41
+ if (!cookie) {
42
+ // Error message is handled inside checkAndGetCookie (if not silent)
43
+ // or just exits silently if silent. We still need to set exit code.
44
+ // Use console.error directly as it's not overridden
45
+ console.error('錯誤:缺少有效的 Cookie,無法獲取資訊。');
46
+ console.error(`請執行 'dydl login' 登入抖音並取得 Cookie`);
47
+ process.exitCode = 1;
48
+ return;
49
+ }
50
+ // 2. 啟動瀏覽器
51
+ browser = await (0, manager_1.launchBrowser)({ headless: 'new', userDataDir });
52
+ const page = await (0, manager_1.newPage)(browser);
53
+ await (0, manager_1.setCookiesOnPage)(page, cookie, '.douyin.com');
54
+ // 3. 解析連結
55
+ const combinedText = sources.join(' ');
56
+ const parseResults = await (0, parser_1.parseDouyinLinks)(combinedText, { concurrency: 3 }); // Use default concurrency for now
57
+ if (parseResults.length === 0) {
58
+ console.error('錯誤:未在輸入中找到有效的抖音影片連結。');
59
+ process.exitCode = 1;
60
+ return; // Exit early
61
+ }
62
+ const videoUrls = parseResults.map(r => r.standardUrl);
63
+ // 4. 獲取影片資訊
64
+ const videoInfos = await (0, info_1.fetchVideosInfoUrls)(videoUrls, page, { concurrency: 3 }); // Use default concurrency
65
+ if (videoInfos.length === 0) {
66
+ console.error('錯誤:無法獲取任何影片的詳細資訊。');
67
+ process.exitCode = 1;
68
+ return;
69
+ }
70
+ // 5. 準備結果 (單個物件或陣列)
71
+ const result = videoInfos.length === 1 ? videoInfos[0] : videoInfos;
72
+ // 6. 輸出結果
73
+ if (outputFile) {
74
+ // 輸出到檔案
75
+ try {
76
+ const outputDir = path_1.default.dirname(outputFile);
77
+ await fs_extra_1.default.ensureDir(outputDir);
78
+ await fs_extra_1.default.writeJson(outputFile, result, { spaces: 2 });
79
+ // No console output if writing to file successfully
80
+ }
81
+ catch (error) {
82
+ // Always output critical errors to stderr
83
+ console.error(`錯誤:無法寫入 JSON 檔案 ${outputFile}:`, error);
84
+ process.exitCode = 1;
85
+ }
86
+ }
87
+ else {
88
+ // 輸出到控制台
89
+ // Ensure only this JSON is printed
90
+ process.stdout.write(JSON.stringify(result, null, 2) + '\n');
91
+ }
92
+ }
93
+ catch (error) {
94
+ // Always output critical errors to stderr
95
+ console.error('獲取影片資訊過程中發生錯誤:', error);
96
+ process.exitCode = 1;
97
+ }
98
+ finally {
99
+ if (browser) {
100
+ await (0, manager_1.closeBrowser)(browser);
101
+ }
102
+ // Console restore logic moved to bin/dydl.ts
103
+ }
104
+ });
105
+ }
106
+ //# sourceMappingURL=info.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"info.js","sourceRoot":"","sources":["../../../../src/cli/commands/info.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * 列表命令
3
+ * 提供 'dydl list' 命令的實現,用於獲取用戶影片列表
4
+ */
5
+ import { Command } from 'commander';
6
+ /**
7
+ * 註冊列表命令
8
+ * @param program Commander 實例
9
+ */
10
+ export declare function registerListCommand(program: Command): void;
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ /**
3
+ * 列表命令
4
+ * 提供 'dydl list' 命令的實現,用於獲取用戶影片列表
5
+ */
6
+ var __importDefault = (this && this.__importDefault) || function (mod) {
7
+ return (mod && mod.__esModule) ? mod : { "default": mod };
8
+ };
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.registerListCommand = registerListCommand;
11
+ const fs_extra_1 = __importDefault(require("fs-extra"));
12
+ const path_1 = __importDefault(require("path"));
13
+ const utils_1 = require("../utils");
14
+ const user_1 = require("../../douyin/info/user"); // Correct path
15
+ /**
16
+ * 註冊列表命令
17
+ * @param program Commander 實例
18
+ */
19
+ function registerListCommand(program) {
20
+ program
21
+ .command('list')
22
+ .description('獲取指定抖音使用者發布的影片列表')
23
+ .argument('<user_profile_url>', '使用者的個人頁面連結 (僅支援單個)')
24
+ .option('-c, --cookie <path>', '指定包含有效 Cookie 的檔案路徑')
25
+ .option('--user-data-dir <path>', '指定 Puppeteer 使用者資料目錄 (主要用於 Cookie 相關操作)')
26
+ .option('-f, --file <path>', '將結果輸出為 JSON 檔案的路徑')
27
+ .option('-n, --count <number>', '指定獲取影片的數量 (預設獲取全部)', '0') // Default to '0' for all
28
+ .action(async (userProfileUrl, options) => {
29
+ // --- 輸入驗證 ---
30
+ // Commander's .argument('<arg>') handles the presence of the argument.
31
+ // We need to ensure only one URL is conceptually passed, although commander collects extras in program.args
32
+ // A simple check on the input argument itself is sufficient here as we define only one.
33
+ // If multiple URLs were intended, we'd use '<urls...>' and check options.args length.
34
+ const outputFile = options.file;
35
+ const cookiePath = options.cookie;
36
+ const userDataDir = options.userDataDir; // Keep for consistency, might be used by cookie logic
37
+ const count = parseInt(options.count, 10);
38
+ if (isNaN(count) || count < 0) {
39
+ console.error('錯誤:--count 參數必須是一個非負整數。');
40
+ process.exitCode = 1;
41
+ return;
42
+ }
43
+ // --- 輸出控制 ---
44
+ const isSilent = !outputFile; // Determine if silent mode is needed
45
+ // Silent logic for logger is now handled in logger constructor
46
+ try {
47
+ // 1. 檢查 Cookie, pass silent flag
48
+ const cookie = await (0, utils_1.checkAndGetCookie)(cookiePath, isSilent); // Pass isSilent // userDataDir might be implicitly used here if cookiePath is null
49
+ if (!cookie) {
50
+ // Error message is handled inside checkAndGetCookie (if not silent)
51
+ // or just exits silently if silent. We still need to set exit code.
52
+ process.exitCode = 1; // Ensure exit code is set even if silent
53
+ return;
54
+ }
55
+ // 2. 獲取用戶影片列表
56
+ // Pass an empty options object to fetchUserVideos to avoid triggering onProgress
57
+ const userVideos = await (0, user_1.fetchUserVideos)(userProfileUrl, cookie, count, {});
58
+ // 3. 輸出結果
59
+ if (outputFile) {
60
+ // 輸出到檔案
61
+ try {
62
+ const outputDir = path_1.default.dirname(outputFile);
63
+ await fs_extra_1.default.ensureDir(outputDir);
64
+ await fs_extra_1.default.writeJson(outputFile, userVideos, { spaces: 2 });
65
+ // No console output on success
66
+ }
67
+ catch (error) {
68
+ console.error(`錯誤:無法寫入 JSON 檔案 ${outputFile}:`, error);
69
+ process.exitCode = 1;
70
+ }
71
+ }
72
+ else {
73
+ // 輸出到控制台
74
+ process.stdout.write(JSON.stringify(userVideos, null, 2) + '\n');
75
+ }
76
+ }
77
+ catch (error) {
78
+ // Handle errors from checkAndGetCookie or fetchUserVideos
79
+ console.error('獲取用戶影片列表過程中發生錯誤:', error);
80
+ process.exitCode = 1;
81
+ }
82
+ // Console restore logic moved to bin/dydl.ts
83
+ });
84
+ }
85
+ //# sourceMappingURL=list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.js","sourceRoot":"","sources":["../../../../src/cli/commands/list.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * 登入命令
3
+ * 提供 'dydl login' 命令的實現
4
+ */
5
+ import { Command } from 'commander';
6
+ /**
7
+ * 註冊登入命令
8
+ * @param program Commander 實例
9
+ */
10
+ export declare function registerLoginCommand(program: Command): void;
@@ -0,0 +1,158 @@
1
+ "use strict";
2
+ /**
3
+ * 登入命令
4
+ * 提供 'dydl login' 命令的實現
5
+ */
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
18
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
19
+ }) : function(o, v) {
20
+ o["default"] = v;
21
+ });
22
+ var __importStar = (this && this.__importStar) || (function () {
23
+ var ownKeys = function(o) {
24
+ ownKeys = Object.getOwnPropertyNames || function (o) {
25
+ var ar = [];
26
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
27
+ return ar;
28
+ };
29
+ return ownKeys(o);
30
+ };
31
+ return function (mod) {
32
+ if (mod && mod.__esModule) return mod;
33
+ var result = {};
34
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
35
+ __setModuleDefault(result, mod);
36
+ return result;
37
+ };
38
+ })();
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ exports.registerLoginCommand = registerLoginCommand;
41
+ // 使用 dynamic import 代替直接導入 ESM 模塊
42
+ // import ora from 'ora';
43
+ // import chalk from 'chalk';
44
+ const auth_1 = require("../../douyin/auth"); // Corrected path, import LoginOptions
45
+ const auth_2 = require("../../douyin/auth"); // Corrected path (getDefaultCookiePath is in auth)
46
+ const logger_1 = require("../../utils/logger"); // Updated path to shared utils logger
47
+ const browser_1 = require("../../utils/browser"); // Updated path to shared utils
48
+ const fs = __importStar(require("fs")); // 引入 fs 模組用於讀取檔案
49
+ /**
50
+ * 註冊登入命令
51
+ * @param program Commander 實例
52
+ */
53
+ function registerLoginCommand(program) {
54
+ program
55
+ .command('login')
56
+ .description('登入抖音並儲存 Cookie')
57
+ .argument('[cookie-path]', '儲存 cookie 的檔案路徑', (0, auth_2.getDefaultCookiePath)())
58
+ .option('-l, --load-cookie <cookie>', '載入初始 Cookie (可以是字串或檔案路徑)')
59
+ .action(async (cookiePath, options) => {
60
+ logger_1.cliLogger.debug(`登入命令執行,Cookie 儲存路徑: ${cookiePath}`);
61
+ logger_1.cliLogger.debug(`CLI 選項: ${JSON.stringify(options)}`);
62
+ // 動態導入 ESM 模塊 (移到最前面)
63
+ const [{ default: ora }, { default: chalk }] = await Promise.all([
64
+ Promise.resolve().then(() => __importStar(require('ora'))),
65
+ Promise.resolve().then(() => __importStar(require('chalk')))
66
+ ]);
67
+ let initialCookieString = undefined;
68
+ // --- 處理 --load-cookie 選項 ---
69
+ if (options.loadCookie) {
70
+ const loadCookieValue = options.loadCookie;
71
+ try {
72
+ // 嘗試判斷是否為檔案路徑
73
+ if (fs.existsSync(loadCookieValue) && fs.statSync(loadCookieValue).isFile()) {
74
+ logger_1.cliLogger.info(`偵測到 --load-cookie 為檔案路徑,正在讀取: ${loadCookieValue}`);
75
+ initialCookieString = fs.readFileSync(loadCookieValue, 'utf-8').trim();
76
+ if (initialCookieString) { // 檢查是否已定義
77
+ logger_1.cliLogger.debug(`從檔案讀取的 Cookie: ${initialCookieString.substring(0, 50)}...`); // 只記錄部分 Cookie
78
+ }
79
+ }
80
+ else {
81
+ logger_1.cliLogger.info(`將 --load-cookie 視為 Cookie 字串`);
82
+ initialCookieString = loadCookieValue.trim();
83
+ }
84
+ }
85
+ catch (err) {
86
+ const readErr = err instanceof Error ? err : new Error(String(err));
87
+ logger_1.cliLogger.error(`處理 --load-cookie (${loadCookieValue}) 時發生錯誤: ${readErr.message}`);
88
+ // 在這裡使用 chalk 前確保它已被載入
89
+ console.error(chalk.red(`錯誤:無法讀取或處理 --load-cookie 指定的值: ${loadCookieValue}`));
90
+ process.exit(1);
91
+ }
92
+ }
93
+ // --- 結束處理 --load-cookie 選項 ---
94
+ // --- 自動載入 cookiePath (如果存在且未通過 --load-cookie 指定) ---
95
+ if (initialCookieString === undefined) {
96
+ try {
97
+ if (fs.existsSync(cookiePath) && fs.statSync(cookiePath).isFile()) {
98
+ logger_1.cliLogger.info(`未指定 --load-cookie,但找到現有 Cookie 檔案,正在載入: ${cookiePath}`);
99
+ initialCookieString = fs.readFileSync(cookiePath, 'utf-8').trim();
100
+ if (initialCookieString) {
101
+ logger_1.cliLogger.debug(`從檔案 ${cookiePath} 讀取的 Cookie: ${initialCookieString.substring(0, 50)}...`);
102
+ }
103
+ else {
104
+ logger_1.cliLogger.warn(`現有 Cookie 檔案 ${cookiePath} 為空`);
105
+ }
106
+ }
107
+ }
108
+ catch (err) {
109
+ const readErr = err instanceof Error ? err : new Error(String(err));
110
+ logger_1.cliLogger.warn(`嘗試自動載入現有 Cookie 檔案 ${cookiePath} 時發生錯誤: ${readErr.message}`);
111
+ // 不終止程序,允許繼續無初始 Cookie 的登入
112
+ }
113
+ }
114
+ // --- 結束自動載入 cookiePath ---
115
+ const spinner = ora('準備登入抖音...').start();
116
+ try {
117
+ spinner.info(`即將開啟瀏覽器,請在瀏覽器中完成登入`);
118
+ spinner.text = '等待登入中,請在瀏覽器中完成登入...';
119
+ spinner.start();
120
+ // 準備登入選項
121
+ const loginOpts = {
122
+ initialCookie: initialCookieString,
123
+ // 可以根據需要從 CLI 選項傳遞其他參數,例如 headless
124
+ // headless: options.headless // 假設有 --headless 選項
125
+ };
126
+ // 執行登入,傳遞儲存路徑和選項
127
+ const cookie = await (0, auth_1.login)(cookiePath, loginOpts);
128
+ // login 函數現在可能返回 string 或 LoginResult,但在此 CLI 情境下,autoCleanup 預設為 true,應只返回 string
129
+ if (typeof cookie === 'string' && cookie) {
130
+ spinner.succeed(`登入成功!Cookie 已儲存至 ${cookiePath}`);
131
+ console.log(chalk.green('✔') + ' 現在可以使用其他命令下載影片');
132
+ }
133
+ else {
134
+ spinner.fail('登入失敗,未能獲取有效的 Cookie');
135
+ }
136
+ }
137
+ catch (error) {
138
+ spinner.fail('登入過程中發生錯誤');
139
+ const err = error instanceof Error ? error : new Error(String(error));
140
+ logger_1.cliLogger.error('登入命令執行失敗:', err);
141
+ // 在這裡使用 chalk 前確保它已被載入
142
+ console.error(chalk.red(err.message));
143
+ process.exitCode = 1;
144
+ }
145
+ finally {
146
+ // 確保在登入完成後清理瀏覽器資源,讓程序可以正常退出
147
+ try {
148
+ await (0, browser_1.cleanupBrowser)();
149
+ logger_1.cliLogger.debug('已清理瀏覽器資源');
150
+ }
151
+ catch (cleanupError) {
152
+ const err = cleanupError instanceof Error ? cleanupError : new Error(String(cleanupError));
153
+ logger_1.cliLogger.error('清理瀏覽器資源失敗:', err);
154
+ }
155
+ }
156
+ });
157
+ }
158
+ //# sourceMappingURL=login.js.map