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,344 @@
1
+ "use strict";
2
+ // src/douyin/browser/manager.ts
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.launchBrowser = launchBrowser;
8
+ exports.newPage = newPage;
9
+ exports.setCookiesOnPage = setCookiesOnPage;
10
+ exports.closeBrowser = closeBrowser;
11
+ exports.launchLoginBrowser = launchLoginBrowser;
12
+ const puppeteer_extra_1 = __importDefault(require("puppeteer-extra"));
13
+ const puppeteer_extra_plugin_stealth_1 = __importDefault(require("puppeteer-extra-plugin-stealth"));
14
+ const logger_1 = require("../../utils/logger"); // 確保路徑正確
15
+ const env_paths_1 = __importDefault(require("env-paths")); // 匯入 env-paths
16
+ const path_1 = __importDefault(require("path")); // 匯入 path 模組
17
+ const fs_1 = __importDefault(require("fs")); // 匯入 fs 模組
18
+ // 應用 stealth plugin (理想情況下應在應用程式入口點執行一次)
19
+ // 暫時放在這裡以保持模組封裝性
20
+ // 使用 !puppeteer.plugins.some(...) 檢查確保只應用一次
21
+ if (!puppeteer_extra_1.default.plugins.find((p) => p.name === 'stealth')) {
22
+ puppeteer_extra_1.default.use((0, puppeteer_extra_plugin_stealth_1.default)());
23
+ logger_1.utilsLogger.debug('Stealth plugin applied to puppeteer-extra in browser manager.');
24
+ }
25
+ // --- 預設 User Data Directory ---
26
+ // 定義應用程式名稱
27
+ const APP_NAME = 'douyin-downloader';
28
+ // 獲取標準路徑
29
+ const paths = (0, env_paths_1.default)(APP_NAME, { suffix: '' }); // suffix: '' 避免額外的 'nodejs' 路徑
30
+ // 建立 Puppeteer 專用的資料目錄路徑
31
+ const puppeteerUserDataPath = path_1.default.join(paths.data, 'puppeteer');
32
+ // 確保目錄存在
33
+ try {
34
+ fs_1.default.mkdirSync(puppeteerUserDataPath, { recursive: true });
35
+ logger_1.utilsLogger.debug(`預設 Puppeteer User Data Directory 設定為: ${puppeteerUserDataPath}`);
36
+ }
37
+ catch (error) {
38
+ logger_1.utilsLogger.error(`無法創建預設 Puppeteer User Data Directory (${puppeteerUserDataPath}):`, error);
39
+ // 如果無法創建,則不設定預設值,讓 Puppeteer 使用其內部預設
40
+ }
41
+ /**
42
+ * 啟動一個新的 Puppeteer 瀏覽器實例。
43
+ * @param options 啟動選項
44
+ * @returns Promise<Browser>
45
+ */
46
+ async function launchBrowser(options = {}) {
47
+ logger_1.utilsLogger.debug('啟動新的 Puppeteer 瀏覽器實例...', options);
48
+ let headlessOption;
49
+ if (options.headless === 'shell') {
50
+ headlessOption = 'shell';
51
+ }
52
+ else if (options.headless === false) {
53
+ headlessOption = false;
54
+ }
55
+ else {
56
+ // 預設為新版無頭模式 (如果未定義或為 true)
57
+ // 注意: @types/puppeteer 可能不直接支援 'new' 字面值,使用 true 作為替代
58
+ // 預設為新版無頭模式 (如果未定義或為 true)
59
+ // 注意: @types/puppeteer 可能不直接支援 'new' 字面值,使用 true 作為替代
60
+ // headlessOption = true; // Keep previous logic for reference
61
+ // Match reference/DouyinParser.ts: force non-headless for login, allow override?
62
+ // For launchBrowser (general purpose), let's keep the flexible option
63
+ // For launchLoginBrowser, it forces headless: false
64
+ // Map 'new' to true, otherwise use the provided value or default undefined to true.
65
+ if (options.headless === 'new') {
66
+ headlessOption = true; // Map 'new' to classic headless (true)
67
+ logger_1.utilsLogger.debug("Mapping headless: 'new' to headless: true");
68
+ }
69
+ else {
70
+ // Assign 'shell', false, true directly. Default undefined to true.
71
+ headlessOption = options.headless === undefined ? true : options.headless;
72
+ }
73
+ }
74
+ // Revert to more comprehensive args, keeping lang setting
75
+ const defaultArgs = [
76
+ '--no-sandbox',
77
+ '--disable-setuid-sandbox',
78
+ '--disable-dev-shm-usage', // Crucial for Docker/CI environments
79
+ // '--disable-accelerated-2d-canvas',
80
+ '--no-first-run',
81
+ '--no-zygote',
82
+ // '--disable-gpu', // Often needed in headless environments
83
+ // '--disable-extensions',
84
+ '--disable-background-networking',
85
+ '--disable-background-timer-throttling',
86
+ // '--disable-popup-blocking',
87
+ '--disable-hang-monitor',
88
+ '--disable-ipc-flooding-protection',
89
+ '--disable-renderer-backgrounding',
90
+ '--enable-automation',
91
+ '--disable-infobars', // Hide "Chrome is controlled by automated test software"
92
+ '--disable-blink-features=AutomationControlled', // Further hide automation flags
93
+ '--window-size=1920,1080', // Set window size via args
94
+ '--lang=zh-CN' // Keep language setting
95
+ ];
96
+ if (!options.userDataDir)
97
+ logger_1.utilsLogger.debug('未提供 userDataDir,將使用預設路徑:', puppeteerUserDataPath);
98
+ const launchOptions = {
99
+ headless: headlessOption,
100
+ executablePath: options.executablePath,
101
+ // 優先使用選項中提供的 userDataDir,否則使用 env-paths 計算出的預設路徑 (如果成功創建)
102
+ userDataDir: options.userDataDir ?? (fs_1.default.existsSync(puppeteerUserDataPath) ? puppeteerUserDataPath : undefined),
103
+ args: [...defaultArgs, ...(options.args || [])], // Combine default and custom args
104
+ defaultViewport: { width: 1920, height: 1080 }, // Keep null when using window-size arg
105
+ timeout: options.timeout || 60000,
106
+ env: {
107
+ ...process.env, // Inherit existing env vars
108
+ LANG: 'zh_CN.UTF-8'
109
+ }
110
+ };
111
+ try {
112
+ const browser = await puppeteer_extra_1.default.launch(launchOptions);
113
+ const pid = browser.process()?.pid;
114
+ logger_1.utilsLogger.debug(`Puppeteer 瀏覽器已成功啟動 (PID: ${pid})`);
115
+ // 監聽斷開連接事件
116
+ browser.on('disconnected', () => {
117
+ logger_1.utilsLogger.warn(`Puppeteer 瀏覽器 (PID: ${pid}) 已斷開連接。`);
118
+ });
119
+ // 將啟動選項附加到瀏覽器實例上,供 newPage 使用
120
+ browser.__launchOptions = options;
121
+ return browser;
122
+ }
123
+ catch (error) {
124
+ const err = error instanceof Error ? error : new Error(String(error));
125
+ logger_1.utilsLogger.error('啟動 Puppeteer 瀏覽器失敗:', err);
126
+ // 考慮拋出更具體的錯誤類型
127
+ throw new Error(`無法啟動瀏覽器: ${err.message}`);
128
+ }
129
+ }
130
+ /**
131
+ * 在指定的瀏覽器實例中創建一個新頁面。
132
+ * 應用通用設定,如 User-Agent 和資源攔截。
133
+ * @param browser 瀏覽器實例
134
+ * @param options 創建頁面的選項 (可覆蓋瀏覽器啟動時的選項)
135
+ * @returns Promise<Page>
136
+ */
137
+ async function newPage(browser, options = {}) {
138
+ // 從瀏覽器實例獲取啟動選項作為預設值
139
+ const browserLaunchOptions = browser.__launchOptions || {};
140
+ // 合併選項,優先使用 newPage 傳入的選項
141
+ const pageOptions = {
142
+ // Update default User-Agent to match reference/DouyinParser.ts
143
+ userAgent: options.userAgent ?? browserLaunchOptions.userAgent ?? 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
144
+ blockResources: options.blockResources ?? browserLaunchOptions.blockResources ?? false, // 預設阻擋資源
145
+ timeout: options.timeout ?? browserLaunchOptions.timeout ?? 60000, // 使用瀏覽器或預設超時
146
+ };
147
+ logger_1.utilsLogger.debug(`準備獲取或創建新頁面,選項:`, pageOptions);
148
+ let page;
149
+ const pages = await browser.pages();
150
+ // 檢查是否存在一個 'about:blank' 頁面可供重複使用
151
+ if (pages.length === 1 && pages[0].url() === 'about:blank') {
152
+ logger_1.utilsLogger.debug('發現一個現有的 about:blank 頁面,將重複使用它。');
153
+ page = pages[0];
154
+ }
155
+ else {
156
+ logger_1.utilsLogger.debug('未找到可重複使用的 about:blank 頁面,創建新頁面。');
157
+ page = await browser.newPage();
158
+ }
159
+ try {
160
+ // 設定 User-Agent
161
+ await page.setUserAgent(pageOptions.userAgent);
162
+ // 設定 Accept-Language HTTP 標頭
163
+ await page.setExtraHTTPHeaders({
164
+ 'Accept-Language': 'zh-CN,zh;q=0.9' // Prefer Simplified Chinese
165
+ });
166
+ logger_1.utilsLogger.debug('Accept-Language header set to zh-CN');
167
+ // 設定請求攔截 (資源阻擋)
168
+ if (pageOptions.blockResources) {
169
+ await page.setRequestInterception(true);
170
+ page.on('request', (request) => {
171
+ const resourceType = request.resourceType();
172
+ // 阻擋圖片、樣式表、字體、媒體資源
173
+ if (['image', 'stylesheet', 'font', 'media'].includes(resourceType)) { //
174
+ request.abort().catch(e => logger_1.utilsLogger.debug(`無法中止請求 ${request.url()}: ${e.message}`)); // 改用 debug 級別
175
+ }
176
+ else {
177
+ request.continue().catch(e => logger_1.utilsLogger.debug(`無法繼續請求 ${request.url()}: ${e.message}`)); // 改用 debug 級別
178
+ }
179
+ });
180
+ }
181
+ // 設定預設超時
182
+ page.setDefaultNavigationTimeout(pageOptions.timeout * 2); // 導航超時設為兩倍
183
+ page.setDefaultTimeout(pageOptions.timeout);
184
+ logger_1.utilsLogger.debug(`頁面創建成功。`);
185
+ return page;
186
+ }
187
+ catch (error) {
188
+ logger_1.utilsLogger.error('配置新頁面失敗:', error);
189
+ // 如果頁面已創建但配置失敗,嘗試關閉它
190
+ if (!page.isClosed()) {
191
+ await page.close().catch(e => logger_1.utilsLogger.error('配置錯誤後關閉頁面失敗:', e));
192
+ }
193
+ throw error; // 重新拋出錯誤
194
+ }
195
+ }
196
+ /**
197
+ * 在指定的頁面上設置 Cookie。
198
+ * @param page Puppeteer 頁面實例
199
+ * @param cookieString Cookie 字串 (例如來自 document.cookie)
200
+ * @param domain 可選: Cookie 的域。如果未提供,則嘗試從頁面 URL 推斷。
201
+ */
202
+ async function setCookiesOnPage(page, cookieString, domain = '.douyin.com') {
203
+ if (!cookieString) {
204
+ logger_1.utilsLogger.debug('未提供 cookie 字串,跳過 setCookiesOnPage。');
205
+ return;
206
+ }
207
+ let targetDomain = domain;
208
+ const pageUrl = page.url();
209
+ // 如果未提供 domain,嘗試從 page URL 推斷
210
+ if (!targetDomain && pageUrl && pageUrl !== 'about:blank') {
211
+ try {
212
+ targetDomain = new URL(pageUrl).hostname;
213
+ }
214
+ catch (e) {
215
+ logger_1.utilsLogger.warn(`無法從 URL 解析 domain: ${pageUrl}`, e);
216
+ }
217
+ }
218
+ if (!targetDomain) {
219
+ logger_1.utilsLogger.warn(`無法確定 Cookie 的域 (URL: ${pageUrl})。跳過設置 Cookie。`);
220
+ return;
221
+ }
222
+ try {
223
+ // Match reference/DouyinParser.ts: Use hardcoded domain
224
+ const cookieDomain = '.douyin.com';
225
+ logger_1.utilsLogger.debug(`解析 Cookie,將使用固定 domain: ${cookieDomain} 進行設置`);
226
+ // 解析 Cookie 字串 (Simplified like reference)
227
+ const cookiesToSet = cookieString.split(';')
228
+ .map(pair => {
229
+ const parts = pair.trim().split('=');
230
+ if (parts.length >= 2) {
231
+ const name = parts[0].trim();
232
+ const value = parts.slice(1).join('=').trim(); // Keep original value, don't decode like current code
233
+ if (!name || value === undefined)
234
+ return null;
235
+ // Set name, value, domain, and a far-future expires date for persistence
236
+ const farFuture = new Date();
237
+ farFuture.setFullYear(farFuture.getFullYear() + 1); // Expire in 1 year
238
+ return {
239
+ name,
240
+ value,
241
+ domain: cookieDomain,
242
+ expires: farFuture.getTime() / 1000, // Puppeteer expects Unix timestamp in seconds
243
+ path: '/' // Add common path
244
+ };
245
+ }
246
+ return null;
247
+ })
248
+ .filter(cookie => cookie !== null); // Simple filter
249
+ if (cookiesToSet.length > 0) {
250
+ // Use 'as any[]' like reference, although CookieParam[] should work if types match
251
+ await page.setCookie(...cookiesToSet);
252
+ logger_1.utilsLogger.debug(`為域 ${cookieDomain} 設置了 ${cookiesToSet.length} 個 Cookie`);
253
+ }
254
+ else {
255
+ logger_1.utilsLogger.warn(`從字串解析後沒有有效的 Cookie 可設置: "${cookieString}"`);
256
+ }
257
+ }
258
+ catch (error) {
259
+ const err = error instanceof Error ? error : new Error(String(error));
260
+ logger_1.utilsLogger.error(`設置 Cookie 失敗 (Domain: ${domain}, URL: ${pageUrl}):`, err);
261
+ // 可選擇重新拋出錯誤或進行其他處理
262
+ }
263
+ }
264
+ /**
265
+ * 安全地關閉瀏覽器實例。
266
+ * @param browser 要關閉的瀏覽器實例
267
+ */
268
+ async function closeBrowser(browser) {
269
+ if (browser && browser.isConnected()) {
270
+ const pid = browser.process()?.pid;
271
+ logger_1.utilsLogger.debug(`正在關閉瀏覽器實例 (PID: ${pid})...`);
272
+ try {
273
+ await browser.close();
274
+ logger_1.utilsLogger.debug(`瀏覽器實例 (PID: ${pid}) 已成功關閉。`);
275
+ }
276
+ catch (error) {
277
+ const err = error instanceof Error ? error : new Error(String(error));
278
+ logger_1.utilsLogger.error(`關閉瀏覽器實例 (PID: ${pid}) 失敗:`, err);
279
+ // 根據需要決定是否重新拋出錯誤
280
+ }
281
+ }
282
+ else {
283
+ logger_1.utilsLogger.debug('瀏覽器實例已關閉或為 null。');
284
+ }
285
+ }
286
+ /**
287
+ * 創建一個專用於登入的瀏覽器實例 (非無頭模式)。
288
+ * 返回瀏覽器、頁面和一個清理函數。
289
+ * @param options 登入瀏覽器的特定啟動選項
290
+ * @returns Promise<{ browser: Browser; page: Page; cleanup: () => Promise<void> }>
291
+ */
292
+ async function launchLoginBrowser(options = {}) {
293
+ logger_1.utilsLogger.info('啟動專用登入瀏覽器 (非無頭模式)...');
294
+ // 強制非無頭模式,並可能使用不同的用戶數據目錄
295
+ const loginOptions = {
296
+ ...options,
297
+ headless: false, // 確保非無頭
298
+ blockResources: options.blockResources ?? false, // 登入時通常需要看到所有內容
299
+ timeout: options.timeout || 120000, // 為手動登入設置更長的超時
300
+ };
301
+ let browser = null;
302
+ let page = null;
303
+ try {
304
+ // 使用通用的 launchBrowser 啟動瀏覽器
305
+ browser = await launchBrowser(loginOptions);
306
+ // 使用通用的 newPage 創建頁面,繼承部分選項
307
+ page = await newPage(browser, {
308
+ blockResources: loginOptions.blockResources,
309
+ timeout: loginOptions.timeout,
310
+ userAgent: loginOptions.userAgent, // 傳遞指定的 User Agent
311
+ });
312
+ // 特別為登入互動增加超時時間
313
+ page.setDefaultNavigationTimeout(loginOptions.timeout * 2); // 使用 ! 斷言 timeout 已有預設值
314
+ page.setDefaultTimeout(loginOptions.timeout);
315
+ // 創建清理函數
316
+ const cleanup = async () => {
317
+ logger_1.utilsLogger.debug('開始清理登入瀏覽器資源...');
318
+ // 先關閉頁面,再關閉瀏覽器
319
+ if (page && !page.isClosed()) {
320
+ try {
321
+ await page.close();
322
+ logger_1.utilsLogger.debug('登入頁面已關閉。');
323
+ }
324
+ catch (e) {
325
+ logger_1.utilsLogger.error('關閉登入頁面時出錯:', e);
326
+ }
327
+ }
328
+ // 使用通用的 closeBrowser 函數
329
+ await closeBrowser(browser);
330
+ logger_1.utilsLogger.debug('登入瀏覽器清理完成。');
331
+ };
332
+ return { browser, page, cleanup };
333
+ }
334
+ catch (error) {
335
+ logger_1.utilsLogger.error('啟動或配置登入瀏覽器失敗:', error);
336
+ // 如果部分組件已創建,嘗試清理
337
+ if (page && !page.isClosed())
338
+ await page.close().catch(e => logger_1.utilsLogger.error('登入瀏覽器清理過程中關閉頁面出錯:', e));
339
+ if (browser)
340
+ await closeBrowser(browser); // 嘗試關閉瀏覽器
341
+ throw error; // 重新拋出原始錯誤
342
+ }
343
+ }
344
+ //# sourceMappingURL=manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manager.js","sourceRoot":"","sources":["../../../../src/douyin/browser/manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * 並行下載管理器
3
+ * 實現多個影片的並行下載和進度追蹤
4
+ */
5
+ import { VideoInfo, DownloadResult as CommonDownloadResult } from '../../types';
6
+ import { VideoDownloadOptions } from './video-downloader';
7
+ /**
8
+ * 下載結果
9
+ */
10
+ /**
11
+ * 批量下載選項
12
+ */
13
+ export interface BatchDownloadOptions extends VideoDownloadOptions {
14
+ concurrency?: number;
15
+ onBatchProgress?: (current: number, total: number, overallProgress: number) => void;
16
+ }
17
+ /**
18
+ * 並行下載多個抖音影片
19
+ * @param videoInfoList 影片資訊列表
20
+ * @param outputPath 輸出路徑
21
+ * @param options 下載選項
22
+ * @returns Promise<DownloadResult[]> 下載結果列表
23
+ */
24
+ export declare function downloadBatch(videoInfoList: VideoInfo[], // Use common VideoInfo
25
+ outputPath: string, options?: BatchDownloadOptions): Promise<CommonDownloadResult[]>;
@@ -0,0 +1,107 @@
1
+ "use strict";
2
+ // Copied from src/download/download-manager.ts
3
+ // Original file path: src/download/download-manager.ts
4
+ /**
5
+ * 並行下載管理器
6
+ * 實現多個影片的並行下載和進度追蹤
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.downloadBatch = downloadBatch;
10
+ const video_downloader_1 = require("./video-downloader");
11
+ const retry_1 = require("../../utils/retry"); // Updated path to shared utils
12
+ const logger_1 = require("../../utils/logger"); // Updated path to shared utils logger
13
+ /**
14
+ * 並行下載多個抖音影片
15
+ * @param videoInfoList 影片資訊列表
16
+ * @param outputPath 輸出路徑
17
+ * @param options 下載選項
18
+ * @returns Promise<DownloadResult[]> 下載結果列表
19
+ */
20
+ async function downloadBatch(videoInfoList, // Use common VideoInfo
21
+ outputPath, options = {}) {
22
+ const { concurrency = 3, onBatchProgress, ...videoOptions } = options;
23
+ const total = videoInfoList.length;
24
+ logger_1.downloadLogger.info(`開始下載 ${total} 個影片,並行數量: ${concurrency}`);
25
+ // 用於追蹤每個影片的進度
26
+ const progressMap = new Map();
27
+ // 更新總體進度的函數
28
+ const updateOverallProgress = () => {
29
+ if (!onBatchProgress)
30
+ return;
31
+ // 計算總體進度百分比
32
+ let totalProgress = 0;
33
+ progressMap.forEach((progress) => {
34
+ totalProgress += progress;
35
+ });
36
+ const overallProgress = progressMap.size > 0
37
+ ? Math.round(totalProgress / progressMap.size)
38
+ : 0;
39
+ // 回調總體進度
40
+ onBatchProgress(progressMap.size, total, overallProgress);
41
+ };
42
+ // 使用 withConcurrency 並行下載
43
+ // Use processBatch with correct types and handle its return value { results, errors }
44
+ const batchOutcome = await (0, retry_1.processBatch)(videoInfoList, async (videoInfo, index) => {
45
+ try {
46
+ // 為每個影片創建獨立的進度回調
47
+ const onProgress = (progress) => {
48
+ progressMap.set(index, progress);
49
+ updateOverallProgress();
50
+ };
51
+ // 下載影片
52
+ // Use onFileProgress from videoOptions if available
53
+ const filePath = await (0, video_downloader_1.downloadVideo)(videoInfo, outputPath, {
54
+ ...videoOptions,
55
+ onFileProgress: onProgress // Pass the per-item progress callback to onFileProgress
56
+ });
57
+ // Removed the download_url logic as it's not in common VideoInfo
58
+ // 下載成功,設置進度為 100%
59
+ progressMap.set(index, 100);
60
+ updateOverallProgress();
61
+ // Return structure matching CommonDownloadResult
62
+ const result = {
63
+ videoInfo,
64
+ success: true,
65
+ filePath
66
+ };
67
+ return result;
68
+ }
69
+ catch (error) {
70
+ // 下載失敗,記錄錯誤
71
+ const errorObj = error instanceof Error ? error : new Error(String(error));
72
+ logger_1.downloadLogger.error(`下載影片 ${videoInfo.id} 失敗:`, errorObj);
73
+ // Return structure matching CommonDownloadResult for failure case
74
+ const result = {
75
+ videoInfo,
76
+ success: false,
77
+ error: errorObj // Use the captured error object
78
+ };
79
+ return result;
80
+ }
81
+ }, {
82
+ concurrency,
83
+ retries: 0, // 在 downloadVideo 中已經有重試機制
84
+ onProgress: (current, total) => {
85
+ if (onBatchProgress) {
86
+ // 這裡只更新完成的影片數量,不包含進度百分比
87
+ const overallProgress = progressMap.size > 0
88
+ ? Math.round(Array.from(progressMap.values()).reduce((sum, p) => sum + p, 0) / progressMap.size)
89
+ : 0;
90
+ onBatchProgress(current, total, overallProgress);
91
+ }
92
+ }
93
+ }); // batchOutcome is { results: CommonDownloadResult[], errors: Error[] }
94
+ // 統計成功和失敗數量
95
+ // Extract results and errors
96
+ const successfulDownloads = batchOutcome.results;
97
+ const downloadErrors = batchOutcome.errors;
98
+ const successCount = successfulDownloads.length;
99
+ const failCount = total - successCount; // Or use downloadErrors.length
100
+ logger_1.downloadLogger.info(`下載完成,成功: ${successCount}/${total},失敗: ${failCount}/${total}`);
101
+ if (downloadErrors.length > 0) {
102
+ logger_1.downloadLogger.warn(`下載過程中發生 ${downloadErrors.length} 個錯誤`);
103
+ }
104
+ // Return the array of successful download results
105
+ return successfulDownloads;
106
+ }
107
+ //# sourceMappingURL=download-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"download-manager.js","sourceRoot":"","sources":["../../../../src/douyin/download/download-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * 錯誤處理和重試機制
3
+ * 提供下載錯誤處理和智能重試邏輯
4
+ */
5
+ /**
6
+ * 下載錯誤類型
7
+ */
8
+ export declare class DownloadError extends Error {
9
+ readonly code: string;
10
+ readonly retryable: boolean;
11
+ readonly url: string;
12
+ constructor(message: string, url: string, code?: string, retryable?: boolean);
13
+ /**
14
+ * 判斷錯誤是否可重試
15
+ */
16
+ isRetryable(): boolean;
17
+ }
18
+ /**
19
+ * 重試選項
20
+ */
21
+ export interface RetryOptions {
22
+ retries: number;
23
+ minDelay?: number;
24
+ maxDelay?: number;
25
+ factor?: number;
26
+ onRetry?: (error: Error, attempt: number) => void;
27
+ onProgress?: (progress: number) => void;
28
+ }
29
+ /**
30
+ * 帶重試機制的下載函數
31
+ * @param downloadFn 下載函數
32
+ * @param url 下載 URL
33
+ * @param options 重試選項
34
+ * @returns Promise<T> 下載結果
35
+ */
36
+ export declare function downloadWithRetry<T>(downloadFn: (onProgress?: (progress: number) => void) => Promise<T>, url: string, options: RetryOptions): Promise<T>;
37
+ /**
38
+ * 判斷錯誤是否可重試
39
+ * @param error 錯誤對象
40
+ * @returns 是否可重試
41
+ */
42
+ export declare function isRetryableError(error: Error): boolean;
43
+ /**
44
+ * 處理下載錯誤並返回友好的錯誤消息
45
+ * @param error 原始錯誤
46
+ * @param url 下載 URL
47
+ * @returns 友好的錯誤消息
48
+ */
49
+ export declare function getDownloadErrorMessage(error: unknown, url: string): string;