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.
- package/README.md +114 -0
- package/dist/bin/dydl.d.ts +2 -0
- package/dist/bin/dydl.js +17 -0
- package/dist/bin/dydl.js.map +1 -0
- package/dist/src/cli/commands/check.d.ts +10 -0
- package/dist/src/cli/commands/check.js +102 -0
- package/dist/src/cli/commands/check.js.map +1 -0
- package/dist/src/cli/commands/info.d.ts +10 -0
- package/dist/src/cli/commands/info.js +106 -0
- package/dist/src/cli/commands/info.js.map +1 -0
- package/dist/src/cli/commands/list.d.ts +10 -0
- package/dist/src/cli/commands/list.js +85 -0
- package/dist/src/cli/commands/list.js.map +1 -0
- package/dist/src/cli/commands/login.d.ts +10 -0
- package/dist/src/cli/commands/login.js +158 -0
- package/dist/src/cli/commands/login.js.map +1 -0
- package/dist/src/cli/commands/open.d.ts +10 -0
- package/dist/src/cli/commands/open.js +141 -0
- package/dist/src/cli/commands/open.js.map +1 -0
- package/dist/src/cli/commands/video.d.ts +10 -0
- package/dist/src/cli/commands/video.js +209 -0
- package/dist/src/cli/commands/video.js.map +1 -0
- package/dist/src/cli/index.d.ts +15 -0
- package/dist/src/cli/index.js +134 -0
- package/dist/src/cli/index.js.map +1 -0
- package/dist/src/cli/progress-display.d.ts +80 -0
- package/dist/src/cli/progress-display.js +225 -0
- package/dist/src/cli/progress-display.js.map +1 -0
- package/dist/src/cli/utils.d.ts +31 -0
- package/dist/src/cli/utils.js +171 -0
- package/dist/src/cli/utils.js.map +1 -0
- package/dist/src/douyin/auth/cookie-path.d.ts +22 -0
- package/dist/src/douyin/auth/cookie-path.js +72 -0
- package/dist/src/douyin/auth/cookie-path.js.map +1 -0
- package/dist/src/douyin/auth/cookie-storage.d.ts +19 -0
- package/dist/src/douyin/auth/cookie-storage.js +65 -0
- package/dist/src/douyin/auth/cookie-storage.js.map +1 -0
- package/dist/src/douyin/auth/errors.d.ts +28 -0
- package/dist/src/douyin/auth/errors.js +49 -0
- package/dist/src/douyin/auth/errors.js.map +1 -0
- package/dist/src/douyin/auth/getDefaultCookiePath.d.ts +24 -0
- package/dist/src/douyin/auth/getDefaultCookiePath.js +90 -0
- package/dist/src/douyin/auth/getDefaultCookiePath.js.map +1 -0
- package/dist/src/douyin/auth/index.d.ts +16 -0
- package/dist/src/douyin/auth/index.js +68 -0
- package/dist/src/douyin/auth/index.js.map +1 -0
- package/dist/src/douyin/auth/isValidCookie.d.ts +18 -0
- package/dist/src/douyin/auth/isValidCookie.js +60 -0
- package/dist/src/douyin/auth/isValidCookie.js.map +1 -0
- package/dist/src/douyin/auth/loadAndValidateCookie.d.ts +17 -0
- package/dist/src/douyin/auth/loadAndValidateCookie.js +45 -0
- package/dist/src/douyin/auth/loadAndValidateCookie.js.map +1 -0
- package/dist/src/douyin/auth/loadCookie.d.ts +17 -0
- package/dist/src/douyin/auth/loadCookie.js +79 -0
- package/dist/src/douyin/auth/loadCookie.js.map +1 -0
- package/dist/src/douyin/auth/login.d.ts +33 -0
- package/dist/src/douyin/auth/login.js +157 -0
- package/dist/src/douyin/auth/login.js.map +1 -0
- package/dist/src/douyin/auth/saveCookie.d.ts +17 -0
- package/dist/src/douyin/auth/saveCookie.js +89 -0
- package/dist/src/douyin/auth/saveCookie.js.map +1 -0
- package/dist/src/douyin/auth/validate.d.ts +11 -0
- package/dist/src/douyin/auth/validate.js +104 -0
- package/dist/src/douyin/auth/validate.js.map +1 -0
- package/dist/src/douyin/browser/manager.d.ts +54 -0
- package/dist/src/douyin/browser/manager.js +344 -0
- package/dist/src/douyin/browser/manager.js.map +1 -0
- package/dist/src/douyin/download/download-manager.d.ts +25 -0
- package/dist/src/douyin/download/download-manager.js +107 -0
- package/dist/src/douyin/download/download-manager.js.map +1 -0
- package/dist/src/douyin/download/error-handler.d.ts +49 -0
- package/dist/src/douyin/download/error-handler.js +160 -0
- package/dist/src/douyin/download/error-handler.js.map +1 -0
- package/dist/src/douyin/download/index.d.ts +39 -0
- package/dist/src/douyin/download/index.js +156 -0
- package/dist/src/douyin/download/index.js.map +1 -0
- package/dist/src/douyin/download/path-formatter.d.ts +42 -0
- package/dist/src/douyin/download/path-formatter.js +107 -0
- package/dist/src/douyin/download/path-formatter.js.map +1 -0
- package/dist/src/douyin/download/video-downloader.d.ts +35 -0
- package/dist/src/douyin/download/video-downloader.js +223 -0
- package/dist/src/douyin/download/video-downloader.js.map +1 -0
- package/dist/src/douyin/index.d.ts +19 -0
- package/dist/src/douyin/index.js +52 -0
- package/dist/src/douyin/index.js.map +1 -0
- package/dist/src/douyin/info/batch-processor.d.ts +15 -0
- package/dist/src/douyin/info/batch-processor.js +65 -0
- package/dist/src/douyin/info/batch-processor.js.map +1 -0
- package/dist/src/douyin/info/browser-manager.d.ts +56 -0
- package/dist/src/douyin/info/browser-manager.js +225 -0
- package/dist/src/douyin/info/browser-manager.js.map +1 -0
- package/dist/src/douyin/info/error-handler.d.ts +36 -0
- package/dist/src/douyin/info/error-handler.js +172 -0
- package/dist/src/douyin/info/error-handler.js.map +1 -0
- package/dist/src/douyin/info/fetch-video-detail.d.ts +14 -0
- package/dist/src/douyin/info/fetch-video-detail.js +247 -0
- package/dist/src/douyin/info/fetch-video-detail.js.map +1 -0
- package/dist/src/douyin/info/index.d.ts +29 -0
- package/dist/src/douyin/info/index.js +85 -0
- package/dist/src/douyin/info/index.js.map +1 -0
- package/dist/src/douyin/info/text-processor.d.ts +15 -0
- package/dist/src/douyin/info/text-processor.js +47 -0
- package/dist/src/douyin/info/text-processor.js.map +1 -0
- package/dist/src/douyin/info/user.d.ts +26 -0
- package/dist/src/douyin/info/user.js +237 -0
- package/dist/src/douyin/info/user.js.map +1 -0
- package/dist/src/douyin/parser/containsDouyinLink.d.ts +18 -0
- package/dist/src/douyin/parser/containsDouyinLink.js +27 -0
- package/dist/src/douyin/parser/containsDouyinLink.js.map +1 -0
- package/dist/src/douyin/parser/extract-links.d.ts +23 -0
- package/dist/src/douyin/parser/extract-links.js +79 -0
- package/dist/src/douyin/parser/extract-links.js.map +1 -0
- package/dist/src/douyin/parser/extractDouyinLinks.d.ts +18 -0
- package/dist/src/douyin/parser/extractDouyinLinks.js +58 -0
- package/dist/src/douyin/parser/extractDouyinLinks.js.map +1 -0
- package/dist/src/douyin/parser/index.d.ts +35 -0
- package/dist/src/douyin/parser/index.js +70 -0
- package/dist/src/douyin/parser/index.js.map +1 -0
- package/dist/src/douyin/parser/link-patterns.d.ts +34 -0
- package/dist/src/douyin/parser/link-patterns.js +121 -0
- package/dist/src/douyin/parser/link-patterns.js.map +1 -0
- package/dist/src/douyin/parser/parse-batch.d.ts +26 -0
- package/dist/src/douyin/parser/parse-batch.js +67 -0
- package/dist/src/douyin/parser/parse-batch.js.map +1 -0
- package/dist/src/douyin/parser/parseDouyinLinks.d.ts +30 -0
- package/dist/src/douyin/parser/parseDouyinLinks.js +164 -0
- package/dist/src/douyin/parser/parseDouyinLinks.js.map +1 -0
- package/dist/src/douyin/parser/resolve-links.d.ts +25 -0
- package/dist/src/douyin/parser/resolve-links.js +131 -0
- package/dist/src/douyin/parser/resolve-links.js.map +1 -0
- package/dist/src/index.d.ts +16 -0
- package/dist/src/index.js +72 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/types.d.ts +217 -0
- package/dist/src/types.js +6 -0
- package/dist/src/types.js.map +1 -0
- package/dist/src/utils/browser.d.ts +73 -0
- package/dist/src/utils/browser.js +96 -0
- package/dist/src/utils/browser.js.map +1 -0
- package/dist/src/utils/error.d.ts +160 -0
- package/dist/src/utils/error.js +334 -0
- package/dist/src/utils/error.js.map +1 -0
- package/dist/src/utils/fetch.d.ts +41 -0
- package/dist/src/utils/fetch.js +155 -0
- package/dist/src/utils/fetch.js.map +1 -0
- package/dist/src/utils/file.d.ts +46 -0
- package/dist/src/utils/file.js +189 -0
- package/dist/src/utils/file.js.map +1 -0
- package/dist/src/utils/index.d.ts +11 -0
- package/dist/src/utils/index.js +29 -0
- package/dist/src/utils/index.js.map +1 -0
- package/dist/src/utils/logger.d.ts +161 -0
- package/dist/src/utils/logger.js +286 -0
- package/dist/src/utils/logger.js.map +1 -0
- package/dist/src/utils/performance.d.ts +98 -0
- package/dist/src/utils/performance.js +292 -0
- package/dist/src/utils/performance.js.map +1 -0
- package/dist/src/utils/retry.d.ts +56 -0
- package/dist/src/utils/retry.js +127 -0
- package/dist/src/utils/retry.js.map +1 -0
- package/package.json +61 -0
@@ -0,0 +1,225 @@
|
|
1
|
+
"use strict";
|
2
|
+
// Copied from src/info/browser-manager.ts
|
3
|
+
// Original file path: src/info/browser-manager.ts
|
4
|
+
/**
|
5
|
+
* 瀏覽器管理模組
|
6
|
+
* 使用 Puppeteer 提供瀏覽器實例管理
|
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.browserManager = exports.BrowserManager = void 0;
|
13
|
+
exports.cleanupBrowser = cleanupBrowser;
|
14
|
+
const logger_1 = require("../../utils/logger"); // Updated path to shared utils logger
|
15
|
+
const puppeteer_extra_1 = __importDefault(require("puppeteer-extra"));
|
16
|
+
const puppeteer_extra_plugin_stealth_1 = __importDefault(require("puppeteer-extra-plugin-stealth"));
|
17
|
+
// Apply the stealth plugin
|
18
|
+
puppeteer_extra_1.default.use((0, puppeteer_extra_plugin_stealth_1.default)());
|
19
|
+
/**
|
20
|
+
* 瀏覽器管理器
|
21
|
+
* 使用單例模式管理 Puppeteer 瀏覽器實例
|
22
|
+
*/
|
23
|
+
class BrowserManager {
|
24
|
+
static instance;
|
25
|
+
browser = null;
|
26
|
+
browserInitPromise = null;
|
27
|
+
options;
|
28
|
+
/**
|
29
|
+
* 獲取 BrowserManager 單例
|
30
|
+
* @param options 瀏覽器選項
|
31
|
+
* @returns BrowserManager 實例
|
32
|
+
*/
|
33
|
+
static getInstance(options = {}) {
|
34
|
+
if (!BrowserManager.instance) {
|
35
|
+
BrowserManager.instance = new BrowserManager(options);
|
36
|
+
}
|
37
|
+
return BrowserManager.instance;
|
38
|
+
}
|
39
|
+
/**
|
40
|
+
* 私有構造函數,防止直接創建實例
|
41
|
+
* @param options 瀏覽器選項
|
42
|
+
*/
|
43
|
+
constructor(options) {
|
44
|
+
this.options = {
|
45
|
+
headless: options.headless !== false, // 默認為 true (無頭模式)
|
46
|
+
timeout: options.timeout || 30000,
|
47
|
+
userAgent: options.userAgent ||
|
48
|
+
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36',
|
49
|
+
};
|
50
|
+
}
|
51
|
+
/**
|
52
|
+
* 獲取瀏覽器實例
|
53
|
+
* 如果實例不存在,則創建新實例
|
54
|
+
* @returns Promise<Browser>
|
55
|
+
*/
|
56
|
+
async getBrowser() {
|
57
|
+
// 如果瀏覽器存在且已連接,直接返回
|
58
|
+
if (this.browser && this.browser.isConnected()) {
|
59
|
+
return this.browser;
|
60
|
+
}
|
61
|
+
// 如果瀏覽器存在但已斷開連接,清除引用
|
62
|
+
if (this.browser && !this.browser.isConnected()) {
|
63
|
+
logger_1.infoLogger.debug('瀏覽器已斷開連接,將創建新實例');
|
64
|
+
this.browser = null;
|
65
|
+
this.browserInitPromise = null;
|
66
|
+
}
|
67
|
+
// 如果有正在進行的初始化,返回該 Promise
|
68
|
+
if (this.browserInitPromise) {
|
69
|
+
return this.browserInitPromise;
|
70
|
+
}
|
71
|
+
logger_1.infoLogger.debug('初始化 Puppeteer 瀏覽器...');
|
72
|
+
// 配置啟動選項
|
73
|
+
const launchOptions = {
|
74
|
+
headless: this.options.headless,
|
75
|
+
args: [
|
76
|
+
'--no-sandbox',
|
77
|
+
'--disable-setuid-sandbox',
|
78
|
+
'--disable-dev-shm-usage',
|
79
|
+
'--disable-accelerated-2d-canvas',
|
80
|
+
'--no-first-run',
|
81
|
+
'--no-zygote',
|
82
|
+
'--disable-gpu',
|
83
|
+
'--disable-extensions',
|
84
|
+
'--disable-background-networking',
|
85
|
+
'--disable-background-timer-throttling',
|
86
|
+
'--disable-backgrounding-occluded-windows',
|
87
|
+
'--disable-breakpad',
|
88
|
+
'--disable-component-extensions-with-background-pages',
|
89
|
+
'--disable-default-apps',
|
90
|
+
'--disable-translate',
|
91
|
+
'--metrics-recording-only'
|
92
|
+
],
|
93
|
+
defaultViewport: { width: 1920, height: 1080 },
|
94
|
+
timeout: this.options.timeout,
|
95
|
+
};
|
96
|
+
// 使用 Promise 處理初始化,避免多次初始化
|
97
|
+
this.browserInitPromise = (async () => {
|
98
|
+
try {
|
99
|
+
const browser = await puppeteer_extra_1.default.launch(launchOptions);
|
100
|
+
// 監聽斷開連接事件
|
101
|
+
browser.on('disconnected', () => {
|
102
|
+
logger_1.infoLogger.debug('Puppeteer 瀏覽器已斷開連接');
|
103
|
+
this.browser = null;
|
104
|
+
this.browserInitPromise = null;
|
105
|
+
});
|
106
|
+
this.browser = browser;
|
107
|
+
logger_1.infoLogger.debug('Puppeteer 瀏覽器已成功初始化');
|
108
|
+
return browser;
|
109
|
+
}
|
110
|
+
catch (error) {
|
111
|
+
const err = error;
|
112
|
+
logger_1.infoLogger.error('初始化 Puppeteer 瀏覽器失敗:', err);
|
113
|
+
this.browserInitPromise = null;
|
114
|
+
throw err;
|
115
|
+
}
|
116
|
+
})();
|
117
|
+
return this.browserInitPromise;
|
118
|
+
}
|
119
|
+
/**
|
120
|
+
* 創建新的頁面
|
121
|
+
* @param cookies 可選的 Cookie 字符串
|
122
|
+
* @returns Promise<Page>
|
123
|
+
*/
|
124
|
+
async newPage(cookies) {
|
125
|
+
const browser = await this.getBrowser();
|
126
|
+
const page = await browser.newPage();
|
127
|
+
// 設置用戶代理
|
128
|
+
await page.setUserAgent(this.options.userAgent || '');
|
129
|
+
// 如果提供了 Cookie,則設置
|
130
|
+
if (cookies) {
|
131
|
+
await this.setCookies(page, cookies);
|
132
|
+
}
|
133
|
+
// 設置請求攔截(優化性能)
|
134
|
+
await page.setRequestInterception(true);
|
135
|
+
page.on('request', (request) => {
|
136
|
+
const resourceType = request.resourceType();
|
137
|
+
// 阻止加載不必要的資源
|
138
|
+
if (['image', 'stylesheet', 'font', 'media'].includes(resourceType)) {
|
139
|
+
request.abort();
|
140
|
+
}
|
141
|
+
else {
|
142
|
+
request.continue();
|
143
|
+
}
|
144
|
+
});
|
145
|
+
return page;
|
146
|
+
}
|
147
|
+
/**
|
148
|
+
* 設置頁面的 Cookie
|
149
|
+
* @param page Puppeteer 頁面實例
|
150
|
+
* @param cookieString Cookie 字符串
|
151
|
+
*/
|
152
|
+
async setCookies(page, cookieString) {
|
153
|
+
if (!cookieString)
|
154
|
+
return;
|
155
|
+
try {
|
156
|
+
// 解析 Cookie 字符串
|
157
|
+
const cookies = cookieString.split(';')
|
158
|
+
.map(pair => {
|
159
|
+
const parts = pair.trim().split('=');
|
160
|
+
if (parts.length >= 2) {
|
161
|
+
return {
|
162
|
+
name: parts[0],
|
163
|
+
value: parts.slice(1).join('='),
|
164
|
+
domain: '.douyin.com' // 設置 domain 以確保 Cookie 生效
|
165
|
+
};
|
166
|
+
}
|
167
|
+
return null;
|
168
|
+
})
|
169
|
+
.filter(cookie => cookie !== null);
|
170
|
+
if (cookies.length > 0) {
|
171
|
+
await page.setCookie(...cookies);
|
172
|
+
logger_1.infoLogger.debug(`已設置 ${cookies.length} 個 Cookie`);
|
173
|
+
}
|
174
|
+
}
|
175
|
+
catch (error) {
|
176
|
+
const err = error;
|
177
|
+
logger_1.infoLogger.error('設置 Cookie 失敗:', err);
|
178
|
+
}
|
179
|
+
}
|
180
|
+
/**
|
181
|
+
* 關閉瀏覽器實例
|
182
|
+
*/
|
183
|
+
async close() {
|
184
|
+
if (this.browser) {
|
185
|
+
try {
|
186
|
+
await this.browser.close();
|
187
|
+
logger_1.infoLogger.debug('Puppeteer 瀏覽器已關閉');
|
188
|
+
}
|
189
|
+
catch (error) {
|
190
|
+
const err = error;
|
191
|
+
logger_1.infoLogger.error('關閉 Puppeteer 瀏覽器失敗:', err);
|
192
|
+
}
|
193
|
+
finally {
|
194
|
+
this.browser = null;
|
195
|
+
this.browserInitPromise = null;
|
196
|
+
}
|
197
|
+
}
|
198
|
+
}
|
199
|
+
}
|
200
|
+
exports.BrowserManager = BrowserManager;
|
201
|
+
// 導出默認的瀏覽器管理器實例
|
202
|
+
exports.browserManager = BrowserManager.getInstance();
|
203
|
+
// 清理函數,用於在進程退出時關閉瀏覽器
|
204
|
+
async function cleanupBrowser() {
|
205
|
+
logger_1.infoLogger.debug('執行瀏覽器清理...');
|
206
|
+
await exports.browserManager.close();
|
207
|
+
}
|
208
|
+
// 處理進程退出
|
209
|
+
process.on('exit', () => {
|
210
|
+
// 同步操作,無法使用 await
|
211
|
+
logger_1.infoLogger.debug('進程退出,開始清理瀏覽器資源');
|
212
|
+
});
|
213
|
+
// 處理信號中斷(如 Ctrl+C)
|
214
|
+
process.on('SIGINT', async () => {
|
215
|
+
logger_1.infoLogger.debug('收到 SIGINT 信號,開始清理瀏覽器資源');
|
216
|
+
await cleanupBrowser();
|
217
|
+
process.exit(0);
|
218
|
+
});
|
219
|
+
// 處理終止信號
|
220
|
+
process.on('SIGTERM', async () => {
|
221
|
+
logger_1.infoLogger.debug('收到 SIGTERM 信號,開始清理瀏覽器資源');
|
222
|
+
await cleanupBrowser();
|
223
|
+
process.exit(0);
|
224
|
+
});
|
225
|
+
//# sourceMappingURL=browser-manager.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"browser-manager.js","sourceRoot":"","sources":["../../../../src/douyin/info/browser-manager.ts"],"names":[],"mappings":"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"}
|
@@ -0,0 +1,36 @@
|
|
1
|
+
/**
|
2
|
+
* 錯誤處理和重試機制
|
3
|
+
* 處理影片資訊獲取過程中的錯誤,實現智能重試
|
4
|
+
*/
|
5
|
+
export interface RetryConfig {
|
6
|
+
maxRetries: number;
|
7
|
+
baseDelay: number;
|
8
|
+
maxDelay: number;
|
9
|
+
factor: number;
|
10
|
+
}
|
11
|
+
/**
|
12
|
+
* 判斷錯誤是否可重試
|
13
|
+
* @param error 錯誤對象
|
14
|
+
* @returns boolean 是否可重試
|
15
|
+
*/
|
16
|
+
export declare function isRetryableError(error: Error): boolean;
|
17
|
+
/**
|
18
|
+
* 計算重試延遲時間
|
19
|
+
* @param attempt 當前嘗試次數(從 1 開始)
|
20
|
+
* @param config 重試配置
|
21
|
+
* @returns number 延遲時間(毫秒)
|
22
|
+
*/
|
23
|
+
export declare function calculateRetryDelay(attempt: number, config?: RetryConfig): number;
|
24
|
+
/**
|
25
|
+
* 帶退避策略的重試函數
|
26
|
+
* @param fetcher 執行的函數
|
27
|
+
* @param config 重試配置
|
28
|
+
* @returns Promise<T> 函數執行結果
|
29
|
+
*/
|
30
|
+
export declare function fetchWithRetry<T>(fetcher: () => Promise<T>, config?: Partial<RetryConfig>): Promise<T>;
|
31
|
+
/**
|
32
|
+
* 處理特定的抖音 API 錯誤
|
33
|
+
* @param error 錯誤對象
|
34
|
+
* @returns Error 包含有用診斷信息的錯誤
|
35
|
+
*/
|
36
|
+
export declare function handleDouyinApiError(error: any): Error;
|
@@ -0,0 +1,172 @@
|
|
1
|
+
"use strict";
|
2
|
+
// Copied from src/info/error-handler.ts
|
3
|
+
// Original file path: src/info/error-handler.ts
|
4
|
+
/**
|
5
|
+
* 錯誤處理和重試機制
|
6
|
+
* 處理影片資訊獲取過程中的錯誤,實現智能重試
|
7
|
+
*/
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
9
|
+
exports.isRetryableError = isRetryableError;
|
10
|
+
exports.calculateRetryDelay = calculateRetryDelay;
|
11
|
+
exports.fetchWithRetry = fetchWithRetry;
|
12
|
+
exports.handleDouyinApiError = handleDouyinApiError;
|
13
|
+
const logger_1 = require("../../utils/logger"); // Updated path to shared utils logger
|
14
|
+
// No need to import withRetry here
|
15
|
+
// 可重試的錯誤類型
|
16
|
+
const RETRYABLE_ERROR_TYPES = [
|
17
|
+
'TimeoutError',
|
18
|
+
'NetworkError',
|
19
|
+
'ConnectionError',
|
20
|
+
'NavigationError',
|
21
|
+
'AbortError'
|
22
|
+
];
|
23
|
+
// 默認重試配置
|
24
|
+
const DEFAULT_RETRY_CONFIG = {
|
25
|
+
maxRetries: 3,
|
26
|
+
baseDelay: 1000,
|
27
|
+
maxDelay: 15000,
|
28
|
+
factor: 2
|
29
|
+
};
|
30
|
+
/**
|
31
|
+
* 判斷錯誤是否可重試
|
32
|
+
* @param error 錯誤對象
|
33
|
+
* @returns boolean 是否可重試
|
34
|
+
*/
|
35
|
+
function isRetryableError(error) {
|
36
|
+
// 檢查錯誤類型
|
37
|
+
if (RETRYABLE_ERROR_TYPES.some(type => error.name.includes(type))) {
|
38
|
+
return true;
|
39
|
+
}
|
40
|
+
// 檢查錯誤消息中的關鍵詞
|
41
|
+
const errorMessage = error.message.toLowerCase();
|
42
|
+
const retryableMessages = [
|
43
|
+
'timeout',
|
44
|
+
'network',
|
45
|
+
'connection',
|
46
|
+
'temporarily unavailable',
|
47
|
+
'rate limit',
|
48
|
+
'too many requests',
|
49
|
+
'server error',
|
50
|
+
'internal error',
|
51
|
+
'socket hang up',
|
52
|
+
'econnreset',
|
53
|
+
'econnrefused',
|
54
|
+
'etimedout'
|
55
|
+
];
|
56
|
+
if (retryableMessages.some(msg => errorMessage.includes(msg))) {
|
57
|
+
return true;
|
58
|
+
}
|
59
|
+
// 檢查 HTTP 狀態碼(如果存在)
|
60
|
+
if ('statusCode' in error && typeof error.statusCode === 'number') {
|
61
|
+
const statusCode = error.statusCode;
|
62
|
+
// 5xx 錯誤和一些 4xx 錯誤可以重試
|
63
|
+
return statusCode >= 500 || statusCode === 429 || statusCode === 408;
|
64
|
+
}
|
65
|
+
// 默認不重試
|
66
|
+
return false;
|
67
|
+
}
|
68
|
+
/**
|
69
|
+
* 計算重試延遲時間
|
70
|
+
* @param attempt 當前嘗試次數(從 1 開始)
|
71
|
+
* @param config 重試配置
|
72
|
+
* @returns number 延遲時間(毫秒)
|
73
|
+
*/
|
74
|
+
function calculateRetryDelay(attempt, config = DEFAULT_RETRY_CONFIG) {
|
75
|
+
// 指數退避策略: baseDelay * (factor ^ (attempt - 1))
|
76
|
+
let delay = config.baseDelay * Math.pow(config.factor, attempt - 1);
|
77
|
+
// 添加隨機抖動,避免多個請求同時重試
|
78
|
+
delay = delay * (0.8 + Math.random() * 0.4);
|
79
|
+
// 限制在最大延遲時間內
|
80
|
+
return Math.min(delay, config.maxDelay);
|
81
|
+
}
|
82
|
+
/**
|
83
|
+
* 帶退避策略的重試函數
|
84
|
+
* @param fetcher 執行的函數
|
85
|
+
* @param config 重試配置
|
86
|
+
* @returns Promise<T> 函數執行結果
|
87
|
+
*/
|
88
|
+
async function fetchWithRetry(fetcher, config = {}) {
|
89
|
+
const retryConfig = { ...DEFAULT_RETRY_CONFIG, ...config };
|
90
|
+
let attempt = 0;
|
91
|
+
let lastError = null;
|
92
|
+
while (attempt <= retryConfig.maxRetries) {
|
93
|
+
try {
|
94
|
+
// 嘗試執行操作
|
95
|
+
return await fetcher();
|
96
|
+
}
|
97
|
+
catch (error) {
|
98
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
99
|
+
lastError = err;
|
100
|
+
attempt++;
|
101
|
+
// 如果已達到最大重試次數或錯誤不可重試,則拋出錯誤
|
102
|
+
if (attempt > retryConfig.maxRetries || !isRetryableError(err)) {
|
103
|
+
if (attempt > retryConfig.maxRetries) {
|
104
|
+
logger_1.infoLogger.debug(`達到最大重試次數: ${err.message}`);
|
105
|
+
}
|
106
|
+
else {
|
107
|
+
logger_1.infoLogger.debug(`錯誤不可重試: ${err.message}`);
|
108
|
+
}
|
109
|
+
throw err;
|
110
|
+
}
|
111
|
+
// 計算延遲時間
|
112
|
+
const delay = calculateRetryDelay(attempt, retryConfig);
|
113
|
+
logger_1.infoLogger.debug(`操作失敗,${delay}ms 後重試 (嘗試 ${attempt}/${retryConfig.maxRetries}): ${err.message}`);
|
114
|
+
// 等待後重試
|
115
|
+
await new Promise(resolve => setTimeout(resolve, delay));
|
116
|
+
}
|
117
|
+
}
|
118
|
+
// 理論上不應該執行到這裡,但為了類型安全
|
119
|
+
throw lastError || new Error('重試失敗');
|
120
|
+
}
|
121
|
+
/**
|
122
|
+
* 處理特定的抖音 API 錯誤
|
123
|
+
* @param error 錯誤對象
|
124
|
+
* @returns Error 包含有用診斷信息的錯誤
|
125
|
+
*/
|
126
|
+
function handleDouyinApiError(error) {
|
127
|
+
// 原始錯誤
|
128
|
+
const originalError = error instanceof Error ? error : new Error(String(error));
|
129
|
+
// 嘗試解析抖音特定錯誤
|
130
|
+
try {
|
131
|
+
// 檢查是否包含 JSON 響應
|
132
|
+
if (error.response && typeof error.response.json === 'function') {
|
133
|
+
const responseData = error.response.json();
|
134
|
+
if (responseData && responseData.statusCode) {
|
135
|
+
// 處理特定的抖音 API 錯誤碼
|
136
|
+
switch (responseData.statusCode) {
|
137
|
+
case 8:
|
138
|
+
return new Error('抖音 API 請求頻率超過限制,請稍後再試');
|
139
|
+
case 2101:
|
140
|
+
return new Error('抖音 Cookie 已失效,請重新登入');
|
141
|
+
case 2154:
|
142
|
+
return new Error('該影片需要登入後才能查看');
|
143
|
+
case 2190:
|
144
|
+
return new Error('該影片不存在或已被刪除');
|
145
|
+
default:
|
146
|
+
return new Error(`抖音 API 錯誤: ${responseData.statusCode} - ${responseData.statusMsg || '未知錯誤'}`);
|
147
|
+
}
|
148
|
+
}
|
149
|
+
}
|
150
|
+
}
|
151
|
+
catch (parseError) {
|
152
|
+
// 解析錯誤,返回原始錯誤
|
153
|
+
logger_1.infoLogger.debug('解析抖音 API 錯誤失敗:', parseError);
|
154
|
+
}
|
155
|
+
// 預處理常見的抖音錯誤信息
|
156
|
+
const errorMessage = originalError.message.toLowerCase();
|
157
|
+
if (errorMessage.includes('cookie') && (errorMessage.includes('invalid') || errorMessage.includes('expired'))) {
|
158
|
+
return new Error('抖音 Cookie 已失效,請重新登入');
|
159
|
+
}
|
160
|
+
if (errorMessage.includes('captcha') || errorMessage.includes('人機驗證')) {
|
161
|
+
return new Error('遇到抖音人機驗證,請稍後再試或更新 Cookie');
|
162
|
+
}
|
163
|
+
if (errorMessage.includes('rate limit') || errorMessage.includes('too many requests')) {
|
164
|
+
return new Error('請求頻率過高,已被抖音限制,請稍後再試');
|
165
|
+
}
|
166
|
+
if (errorMessage.includes('not found') || errorMessage.includes('404')) {
|
167
|
+
return new Error('影片不存在或已被刪除');
|
168
|
+
}
|
169
|
+
// 返回原始錯誤
|
170
|
+
return originalError;
|
171
|
+
}
|
172
|
+
//# sourceMappingURL=error-handler.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"error-handler.js","sourceRoot":"","sources":["../../../../src/douyin/info/error-handler.ts"],"names":[],"mappings":"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"}
|
@@ -0,0 +1,14 @@
|
|
1
|
+
/**
|
2
|
+
* 影片詳情提取核心功能
|
3
|
+
* 從抖音影片頁面獲取詳細資訊 (基於 reference/DouyinParser.ts 邏輯)
|
4
|
+
*/
|
5
|
+
import { Page } from 'puppeteer';
|
6
|
+
import { VideoInfo } from '../../types';
|
7
|
+
/**
|
8
|
+
* 從抖音影片頁面獲取詳細資訊
|
9
|
+
* @param videoUrl 標準的抖音影片 URL
|
10
|
+
* @param cookie 抖音 Cookie 字串
|
11
|
+
* @returns Promise<VideoInfo | null> 影片資訊或 null
|
12
|
+
*/
|
13
|
+
export declare function fetchVideoDetail(page: Page, // Changed: Accept Page object
|
14
|
+
videoUrl: string): Promise<VideoInfo | null>;
|