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
@@ -0,0 +1,160 @@
1
+ "use strict";
2
+ // Copied from src/download/error-handler.ts
3
+ // Original file path: src/download/error-handler.ts
4
+ /**
5
+ * 錯誤處理和重試機制
6
+ * 提供下載錯誤處理和智能重試邏輯
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.DownloadError = void 0;
10
+ exports.downloadWithRetry = downloadWithRetry;
11
+ exports.isRetryableError = isRetryableError;
12
+ exports.getDownloadErrorMessage = getDownloadErrorMessage;
13
+ const logger_1 = require("../../utils/logger"); // Updated path to shared utils logger
14
+ // No need to import withRetry here, it seems to be used elsewhere (e.g., video-downloader)
15
+ /**
16
+ * 下載錯誤類型
17
+ */
18
+ class DownloadError extends Error {
19
+ code;
20
+ retryable;
21
+ url;
22
+ constructor(message, url, code = 'DOWNLOAD_ERROR', retryable = true) {
23
+ super(message);
24
+ this.name = 'DownloadError';
25
+ this.code = code;
26
+ this.retryable = retryable;
27
+ this.url = url;
28
+ }
29
+ /**
30
+ * 判斷錯誤是否可重試
31
+ */
32
+ isRetryable() {
33
+ return this.retryable;
34
+ }
35
+ }
36
+ exports.DownloadError = DownloadError;
37
+ /**
38
+ * 計算重試延遲時間
39
+ * 使用指數退避策略
40
+ * @param attempt 當前嘗試次數(從 1 開始)
41
+ * @param options 重試選項
42
+ * @returns 延遲時間(毫秒)
43
+ */
44
+ function calculateDelay(attempt, options) {
45
+ const { minDelay = 1000, maxDelay = 30000, factor = 2 } = options;
46
+ // 指數退避: minDelay * (factor ^ (attempt - 1))
47
+ let delay = minDelay * Math.pow(factor, attempt - 1);
48
+ // 添加一些隨機性以避免 "雷暴" 效應
49
+ delay = delay * (0.8 + Math.random() * 0.4);
50
+ // 限制在最大延遲時間內
51
+ return Math.min(delay, maxDelay);
52
+ }
53
+ /**
54
+ * 帶重試機制的下載函數
55
+ * @param downloadFn 下載函數
56
+ * @param url 下載 URL
57
+ * @param options 重試選項
58
+ * @returns Promise<T> 下載結果
59
+ */
60
+ async function downloadWithRetry(downloadFn, url, options) {
61
+ const { retries, onRetry, onProgress } = options;
62
+ let attempt = 0;
63
+ let lastError;
64
+ while (attempt <= retries) {
65
+ attempt++;
66
+ try {
67
+ // 執行下載函數
68
+ return await downloadFn(onProgress);
69
+ }
70
+ catch (error) {
71
+ // 轉換為 Error 對象
72
+ lastError = error instanceof Error ? error : new Error(String(error));
73
+ // 檢查錯誤是否可重試
74
+ const isRetryable = error instanceof DownloadError
75
+ ? error.isRetryable()
76
+ : isRetryableError(lastError);
77
+ // 如果已達到最大重試次數或錯誤不可重試,拋出錯誤
78
+ if (attempt > retries || !isRetryable) {
79
+ logger_1.downloadLogger.error(`下載 ${url} 失敗,不再重試`, lastError);
80
+ throw lastError;
81
+ }
82
+ // 調用重試回調
83
+ if (onRetry) {
84
+ onRetry(lastError, attempt);
85
+ }
86
+ // 記錄日誌
87
+ logger_1.downloadLogger.warn(`下載 ${url} 失敗,準備重試 #${attempt}/${retries}:`, lastError.message);
88
+ // 計算延遲時間
89
+ const delay = calculateDelay(attempt, options);
90
+ // 等待後重試
91
+ await new Promise(resolve => setTimeout(resolve, delay));
92
+ }
93
+ }
94
+ // 理論上不應該執行到這裡
95
+ throw lastError;
96
+ }
97
+ /**
98
+ * 判斷錯誤是否可重試
99
+ * @param error 錯誤對象
100
+ * @returns 是否可重試
101
+ */
102
+ function isRetryableError(error) {
103
+ const message = error.message.toLowerCase();
104
+ const name = error.name.toLowerCase();
105
+ // 網絡錯誤通常可重試
106
+ if (name.includes('network') ||
107
+ message.includes('network') ||
108
+ message.includes('connection') ||
109
+ message.includes('timeout') ||
110
+ message.includes('timed out') ||
111
+ message.includes('429') || // Too Many Requests
112
+ message.includes('503') || // Service Unavailable
113
+ message.includes('504') // Gateway Timeout
114
+ ) {
115
+ return true;
116
+ }
117
+ // 資源錯誤通常不可重試
118
+ if (message.includes('404') || // Not Found
119
+ message.includes('403') || // Forbidden
120
+ message.includes('401') || // Unauthorized
121
+ message.includes('400') || // Bad Request
122
+ message.includes('not found') ||
123
+ message.includes('forbidden') ||
124
+ message.includes('unauthorized') ||
125
+ message.includes('bad request') ||
126
+ message.includes('permission denied')) {
127
+ return false;
128
+ }
129
+ // 默認可重試
130
+ return true;
131
+ }
132
+ /**
133
+ * 處理下載錯誤並返回友好的錯誤消息
134
+ * @param error 原始錯誤
135
+ * @param url 下載 URL
136
+ * @returns 友好的錯誤消息
137
+ */
138
+ function getDownloadErrorMessage(error, url) {
139
+ if (error instanceof DownloadError) {
140
+ return error.message;
141
+ }
142
+ const err = error instanceof Error ? error : new Error(String(error));
143
+ const message = err.message.toLowerCase();
144
+ // 常見錯誤類型的友好消息
145
+ if (message.includes('timeout') || message.includes('timed out')) {
146
+ return `下載超時,請檢查網絡連接或稍後再試`;
147
+ }
148
+ if (message.includes('404') || message.includes('not found')) {
149
+ return `影片資源不存在或已被移除`;
150
+ }
151
+ if (message.includes('403') || message.includes('forbidden')) {
152
+ return `無權訪問此影片資源,可能需要登入或權限`;
153
+ }
154
+ if (message.includes('429') || message.includes('too many requests')) {
155
+ return `下載請求過於頻繁,請稍後再試`;
156
+ }
157
+ // 其他錯誤使用原始消息
158
+ return `下載影片時發生錯誤: ${err.message}`;
159
+ }
160
+ //# sourceMappingURL=error-handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-handler.js","sourceRoot":"","sources":["../../../../src/douyin/download/error-handler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * 影片下載模組
3
+ * 提供下載抖音影片的功能
4
+ */
5
+ import { VideoInfo, DownloadOptions, DownloadResult as CommonDownloadResult } from '../../types';
6
+ import { Page } from 'puppeteer';
7
+ export * from './video-downloader';
8
+ export * from './download-manager';
9
+ export * from './path-formatter';
10
+ export * from './error-handler';
11
+ /**
12
+ * 下載多個抖音影片
13
+ * @param videoInfos 影片資訊陣列
14
+ * @param outputPath 輸出路徑
15
+ * @param options 下載選項
16
+ * @returns Promise<DownloadResult[]> 下載結果陣列
17
+ */
18
+ export declare function downloadVideos(videoInfos: VideoInfo[], // Use common VideoInfo
19
+ outputPath: string, options?: DownloadOptions): Promise<CommonDownloadResult[]>;
20
+ /**
21
+ * 從 URL 陣列下載抖音影片
22
+ * @param videoUrls 影片 URL 陣列
23
+ * @param outputPath 輸出路徑
24
+ * @param cookie 有效的抖音 Cookie
25
+ * @param options 下載選項
26
+ * @returns Promise<string[]> 下載完成的檔案路徑陣列
27
+ */
28
+ export declare function downloadVideosFromUrls(videoUrls: string[], outputPath: string, page: Page, // Changed: Accept Page object
29
+ options?: DownloadOptions): Promise<string[]>;
30
+ /**
31
+ * 從文本中解析抖音連結並下載影片
32
+ * @param text 包含抖音連結的文本
33
+ * @param outputPath 輸出路徑
34
+ * @param cookie 有效的抖音 Cookie
35
+ * @param options 下載選項
36
+ * @returns Promise<string[]> 下載完成的檔案路徑陣列
37
+ */
38
+ export declare function downloadVideosFromText(text: string, outputPath: string, page: Page, // Changed: Accept Page object
39
+ options?: DownloadOptions): Promise<string[]>;
@@ -0,0 +1,156 @@
1
+ "use strict";
2
+ // Copied from src/download/index.ts
3
+ // Original file path: src/download/index.ts
4
+ /**
5
+ * 影片下載模組
6
+ * 提供下載抖音影片的功能
7
+ */
8
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
9
+ if (k2 === undefined) k2 = k;
10
+ var desc = Object.getOwnPropertyDescriptor(m, k);
11
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
12
+ desc = { enumerable: true, get: function() { return m[k]; } };
13
+ }
14
+ Object.defineProperty(o, k2, desc);
15
+ }) : (function(o, m, k, k2) {
16
+ if (k2 === undefined) k2 = k;
17
+ o[k2] = m[k];
18
+ }));
19
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
20
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
21
+ };
22
+ Object.defineProperty(exports, "__esModule", { value: true });
23
+ exports.downloadVideos = downloadVideos;
24
+ exports.downloadVideosFromUrls = downloadVideosFromUrls;
25
+ exports.downloadVideosFromText = downloadVideosFromText;
26
+ const logger_1 = require("../../utils/logger"); // Updated path to shared utils logger
27
+ const info_1 = require("../info"); // Keep relative path within douyin
28
+ const parser_1 = require("../parser"); // Keep relative path within douyin
29
+ const download_manager_1 = require("./download-manager"); // Remove DownloadResult import
30
+ // 重新導出子模組
31
+ __exportStar(require("./video-downloader"), exports);
32
+ __exportStar(require("./download-manager"), exports);
33
+ __exportStar(require("./path-formatter"), exports);
34
+ __exportStar(require("./error-handler"), exports);
35
+ /**
36
+ * 下載多個抖音影片
37
+ * @param videoInfos 影片資訊陣列
38
+ * @param outputPath 輸出路徑
39
+ * @param options 下載選項
40
+ * @returns Promise<DownloadResult[]> 下載結果陣列
41
+ */
42
+ async function downloadVideos(videoInfos, // Use common VideoInfo
43
+ outputPath, options = {}) {
44
+ // Destructure all potential options from the input DownloadOptions
45
+ const { concurrency = 3, retries = 3, onProgress, timeout,
46
+ // headers are not part of DownloadOptions in types.ts, but are in VideoDownloadOptions
47
+ // checkExisting is not part of DownloadOptions in types.ts, but are in VideoDownloadOptions
48
+ overwrite, useSubfolders, filenameTemplate } = options;
49
+ // 目錄確保邏輯已移至 CLI 或 downloadBatch/downloadVideo
50
+ // await ensureDirectoryExists(path.isAbsolute(outputPath)
51
+ // ? outputPath
52
+ // : path.resolve(process.cwd(), outputPath));
53
+ logger_1.downloadLogger.info(`開始下載 ${videoInfos.length} 個影片`);
54
+ // 使用下載批次處理器
55
+ // Explicitly construct the options object for downloadBatch using an intersection type
56
+ const batchOptions = {
57
+ concurrency,
58
+ retries, // Pass retries (should be valid via VideoDownloadOptions)
59
+ onBatchProgress: onProgress, // Map the batch progress callback
60
+ // Pass other relevant options inherited from VideoDownloadOptions
61
+ timeout: timeout,
62
+ // headers: headers, // headers not available in input options
63
+ // checkExisting: checkExisting, // checkExisting not available in input options
64
+ overwrite: overwrite,
65
+ useSubfolders: useSubfolders,
66
+ filenameTemplate: filenameTemplate
67
+ };
68
+ const results = await (0, download_manager_1.downloadBatch)(videoInfos, outputPath, batchOptions);
69
+ // 統計結果
70
+ const successCount = results.filter(r => r.success).length;
71
+ const failCount = results.filter(r => !r.success).length;
72
+ logger_1.downloadLogger.info(`下載完成,成功: ${successCount}/${videoInfos.length},失敗: ${failCount}/${videoInfos.length}`);
73
+ return results;
74
+ }
75
+ /**
76
+ * 從 URL 陣列下載抖音影片
77
+ * @param videoUrls 影片 URL 陣列
78
+ * @param outputPath 輸出路徑
79
+ * @param cookie 有效的抖音 Cookie
80
+ * @param options 下載選項
81
+ * @returns Promise<string[]> 下載完成的檔案路徑陣列
82
+ */
83
+ async function downloadVideosFromUrls(videoUrls, outputPath, page, // Changed: Accept Page object
84
+ // cookie: string, // Removed
85
+ options = {}) {
86
+ // 獲取影片資訊
87
+ logger_1.downloadLogger.info(`[downloadVideosFromUrls] 開始獲取 ${videoUrls.length} 個影片的資訊`);
88
+ // Pass page instead of cookie
89
+ const videoInfos = await (0, info_1.fetchVideosInfoUrls)(videoUrls, page, {
90
+ concurrency: options.concurrency,
91
+ onProgress: options.onProgress
92
+ ? (current, total, overallProgress) => options.onProgress(current, total, overallProgress !== undefined ? overallProgress * 0.2 : undefined) // Adjust progress, handle undefined
93
+ : undefined
94
+ });
95
+ if (videoInfos.length === 0) {
96
+ logger_1.downloadLogger.warn('[downloadVideosFromUrls] 未找到有效的影片資訊,無法下載');
97
+ return [];
98
+ }
99
+ logger_1.downloadLogger.info(`[downloadVideosFromUrls] 成功獲取 ${videoInfos.length} 個影片的資訊,開始下載`);
100
+ // 下載影片
101
+ const results = await downloadVideos(videoInfos, outputPath, {
102
+ ...options,
103
+ onProgress: options.onProgress
104
+ ? (current, total, overallProgress) => {
105
+ // 調整進度:資訊獲取 0-20%,下載 20-100%
106
+ const adjustedProgress = overallProgress !== undefined ? 20 + (overallProgress * 0.8) : undefined; // Adjust progress, handle undefined
107
+ options.onProgress(current, total, adjustedProgress);
108
+ }
109
+ : undefined
110
+ });
111
+ // 過濾出成功的結果,返回檔案路徑
112
+ return results
113
+ .filter(result => result.success && result.filePath)
114
+ .map(result => result.filePath);
115
+ }
116
+ /**
117
+ * 從文本中解析抖音連結並下載影片
118
+ * @param text 包含抖音連結的文本
119
+ * @param outputPath 輸出路徑
120
+ * @param cookie 有效的抖音 Cookie
121
+ * @param options 下載選項
122
+ * @returns Promise<string[]> 下載完成的檔案路徑陣列
123
+ */
124
+ async function downloadVideosFromText(text, outputPath, page, // Changed: Accept Page object
125
+ // cookie: string, // Removed
126
+ options = {}) {
127
+ // 解析文本中的抖音連結
128
+ logger_1.downloadLogger.info('[downloadVideosFromText] 解析文本中的抖音連結');
129
+ const parseResults = await (0, parser_1.parseDouyinLinks)(text, {
130
+ concurrency: options.concurrency,
131
+ retries: options.retries,
132
+ onProgress: options.onProgress
133
+ ? (current, total, overallProgress) => options.onProgress(current, total, overallProgress !== undefined ? overallProgress * 0.1 : undefined) // Adjust progress, handle undefined
134
+ : undefined
135
+ });
136
+ if (parseResults.length === 0) {
137
+ logger_1.downloadLogger.warn('[downloadVideosFromText] 未找到有效的抖音影片連結');
138
+ return [];
139
+ }
140
+ // 獲取標準 URL 陣列
141
+ const videoUrls = parseResults.map((result) => result.standardUrl);
142
+ logger_1.downloadLogger.info(`[downloadVideosFromText] 找到 ${videoUrls.length} 個有效連結,開始獲取影片資訊`);
143
+ // 下載影片
144
+ // Pass page instead of cookie
145
+ return downloadVideosFromUrls(videoUrls, outputPath, page, {
146
+ ...options,
147
+ onProgress: options.onProgress
148
+ ? (current, total, overallProgress) => {
149
+ // 調整進度:解析連結 0-10%,下載 10-100%
150
+ const adjustedProgress = overallProgress !== undefined ? 10 + (overallProgress * 0.9) : undefined; // Adjust progress, handle undefined
151
+ options.onProgress(current, total, adjustedProgress);
152
+ }
153
+ : undefined
154
+ });
155
+ }
156
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/douyin/download/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * 檔名和路徑管理
3
+ * 提供格式化檔名和路徑的功能
4
+ */
5
+ import { VideoInfo } from '../../types';
6
+ /**
7
+ * 格式化輸出路徑選項
8
+ */
9
+ export interface PathFormatterOptions {
10
+ useSubfolders?: boolean;
11
+ filenameTemplate?: string;
12
+ maxFilenameLength?: number;
13
+ }
14
+ /**
15
+ * 獲取安全的檔案名(替換非法字符)
16
+ * @param filename 原始檔案名
17
+ * @param maxLength 最大長度限制
18
+ * @returns 安全的檔案名
19
+ */
20
+ /**
21
+ * 格式化日期字符串
22
+ * @param dateStr 日期字符串 (ISO 格式或 YYYY-MM-DD)
23
+ * @returns 格式化後的日期 (YYYYMMDD)
24
+ */
25
+ export declare function formatDate(dateStr: string): string;
26
+ /**
27
+ * 應用檔名模板
28
+ * @param template 模板字符串
29
+ * @param videoInfo 影片資訊
30
+ * @returns 應用模板後的字符串
31
+ */
32
+ export declare function applyFilenameTemplate(template: string, videoInfo: VideoInfo): string;
33
+ /**
34
+ * 格式化輸出路徑
35
+ * 根據影片資訊和選項,確定檔案的完整路徑
36
+ * @param videoInfo 影片資訊
37
+ * @param baseOutputPath 基本輸出路徑
38
+ * @param options 格式化選項
39
+ * @returns 格式化後的完整檔案路徑
40
+ */
41
+ export declare function formatOutputPath(videoInfo: VideoInfo, // Use common VideoInfo
42
+ baseOutputPath: string, options?: PathFormatterOptions): string;
@@ -0,0 +1,107 @@
1
+ "use strict";
2
+ // Copied from src/download/path-formatter.ts
3
+ // Original file path: src/download/path-formatter.ts
4
+ /**
5
+ * 檔名和路徑管理
6
+ * 提供格式化檔名和路徑的功能
7
+ */
8
+ var __importDefault = (this && this.__importDefault) || function (mod) {
9
+ return (mod && mod.__esModule) ? mod : { "default": mod };
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.formatDate = formatDate;
13
+ exports.applyFilenameTemplate = applyFilenameTemplate;
14
+ exports.formatOutputPath = formatOutputPath;
15
+ const fs_extra_1 = __importDefault(require("fs-extra"));
16
+ const path_1 = __importDefault(require("path"));
17
+ const file_1 = require("../../utils/file"); // Import from shared utils
18
+ /**
19
+ * 獲取安全的檔案名(替換非法字符)
20
+ * @param filename 原始檔案名
21
+ * @param maxLength 最大長度限制
22
+ * @returns 安全的檔案名
23
+ */
24
+ // Moved getSafeFilename to src/utils/file.ts
25
+ /**
26
+ * 格式化日期字符串
27
+ * @param dateStr 日期字符串 (ISO 格式或 YYYY-MM-DD)
28
+ * @returns 格式化後的日期 (YYYYMMDD)
29
+ */
30
+ function formatDate(dateStr) {
31
+ try {
32
+ const date = new Date(dateStr);
33
+ if (isNaN(date.getTime())) {
34
+ return new Date().toISOString().slice(0, 10).replace(/-/g, '');
35
+ }
36
+ return date.toISOString().slice(0, 10).replace(/-/g, '');
37
+ }
38
+ catch (error) {
39
+ // 如果解析失敗,使用當前日期
40
+ return new Date().toISOString().slice(0, 10).replace(/-/g, '');
41
+ }
42
+ }
43
+ /**
44
+ * 應用檔名模板
45
+ * @param template 模板字符串
46
+ * @param videoInfo 影片資訊
47
+ * @returns 應用模板後的字符串
48
+ */
49
+ function applyFilenameTemplate(template, videoInfo // Use common VideoInfo
50
+ ) {
51
+ // 將可用的變數替換為實際值
52
+ return template
53
+ .replace(/{id}/g, videoInfo.id || 'unknown')
54
+ .replace(/{title}/g, videoInfo.title || 'untitled')
55
+ .replace(/{date}/g, formatDate(videoInfo.releaseDate || ''))
56
+ .replace(/{user}/g, videoInfo.userName || 'unknown_user');
57
+ }
58
+ /**
59
+ * 格式化輸出路徑
60
+ * 根據影片資訊和選項,確定檔案的完整路徑
61
+ * @param videoInfo 影片資訊
62
+ * @param baseOutputPath 基本輸出路徑
63
+ * @param options 格式化選項
64
+ * @returns 格式化後的完整檔案路徑
65
+ */
66
+ function formatOutputPath(videoInfo, // Use common VideoInfo
67
+ baseOutputPath, options = {}) {
68
+ const { useSubfolders = true, filenameTemplate = "{date}-{title}", maxFilenameLength = 200 } = options;
69
+ // 檢查基本路徑是否是目錄
70
+ let isDirectory = false;
71
+ try {
72
+ isDirectory = fs_extra_1.default.statSync(baseOutputPath).isDirectory();
73
+ }
74
+ catch (error) {
75
+ // 檢查路徑是否以目錄分隔符結尾
76
+ isDirectory = baseOutputPath.endsWith(path_1.default.sep) || baseOutputPath.endsWith('/');
77
+ }
78
+ // 如果是目錄,根據選項決定使用子資料夾
79
+ if (isDirectory) {
80
+ let targetDir = baseOutputPath;
81
+ // 如果使用子資料夾,則添加使用者名稱資料夾
82
+ if (useSubfolders && videoInfo.userName) {
83
+ const userDirName = (0, file_1.getSafeFilename)(videoInfo.userName || 'unknown_user'); // Remove second argument
84
+ targetDir = path_1.default.join(baseOutputPath, userDirName);
85
+ }
86
+ // 應用檔名模板並限制長度
87
+ // Apply template first, then sanitize the result using the single-argument getSafeFilename
88
+ const templateAppliedName = applyFilenameTemplate(filenameTemplate, videoInfo);
89
+ const filename = (0, file_1.getSafeFilename)(templateAppliedName); // Remove second argument
90
+ // 確保檔名有 .mp4 擴展名
91
+ const finalName = filename.toLowerCase().endsWith('.mp4')
92
+ ? filename
93
+ : `${filename}.mp4`;
94
+ return path_1.default.join(targetDir, finalName);
95
+ }
96
+ else {
97
+ // 如果不是目錄,則直接使用指定的檔案路徑
98
+ let finalPath = baseOutputPath;
99
+ // 確保檔案擴展名為 .mp4
100
+ if (!finalPath.toLowerCase().endsWith('.mp4')) {
101
+ finalPath += '.mp4';
102
+ }
103
+ return finalPath;
104
+ }
105
+ }
106
+ // Moved ensureDirectoryExists to src/utils/file.ts
107
+ //# sourceMappingURL=path-formatter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"path-formatter.js","sourceRoot":"","sources":["../../../../src/douyin/download/path-formatter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * 影片下載核心功能
3
+ * 實現單個影片的下載邏輯
4
+ */
5
+ import { VideoInfo } from '../../types';
6
+ /**
7
+ * 下載選項
8
+ */
9
+ export interface VideoDownloadOptions {
10
+ retries?: number;
11
+ timeout?: number;
12
+ headers?: Record<string, string>;
13
+ onProgress?: (progress: number) => void;
14
+ onFileProgress?: (progress: number) => void;
15
+ checkExisting?: boolean;
16
+ overwrite?: boolean;
17
+ useSubfolders?: boolean;
18
+ filenameTemplate?: string;
19
+ }
20
+ /**
21
+ * 下載單個抖音影片
22
+ * @param videoInfo 影片資訊
23
+ * @param destPath 目標路徑(檔案或目錄)
24
+ * @param options 下載選項
25
+ * @returns Promise<string> 下載完成的檔案路徑
26
+ */
27
+ export declare function downloadVideo(videoInfo: VideoInfo, // Use common VideoInfo
28
+ destPath: string, options?: VideoDownloadOptions, downloadUrls?: string[]): Promise<string>;
29
+ /**
30
+ * 獲取影片的下載大小
31
+ * @param url 影片 URL
32
+ * @param headers 請求頭
33
+ * @returns Promise<number> 檔案大小(位元組)
34
+ */
35
+ export declare function getVideoSize(url: string, headers?: Record<string, string>): Promise<number>;