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,223 @@
|
|
1
|
+
"use strict";
|
2
|
+
// Copied from src/download/video-downloader.ts
|
3
|
+
// Original file path: src/download/video-downloader.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.downloadVideo = downloadVideo;
|
13
|
+
exports.getVideoSize = getVideoSize;
|
14
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
15
|
+
const path_1 = __importDefault(require("path"));
|
16
|
+
const logger_1 = require("../../utils/logger"); // Updated path to shared utils logger
|
17
|
+
const file_1 = require("../../utils/file"); // Updated path to shared utils
|
18
|
+
const path_formatter_1 = require("./path-formatter"); // Keep formatOutputPath, remove ensureDirectoryExists
|
19
|
+
const error_handler_1 = require("./error-handler"); // Keep local error types for now
|
20
|
+
const retry_1 = require("../../utils/retry"); // Import withRetry from shared utils
|
21
|
+
/**
|
22
|
+
* 下載單個抖音影片
|
23
|
+
* @param videoInfo 影片資訊
|
24
|
+
* @param destPath 目標路徑(檔案或目錄)
|
25
|
+
* @param options 下載選項
|
26
|
+
* @returns Promise<string> 下載完成的檔案路徑
|
27
|
+
*/
|
28
|
+
async function downloadVideo(videoInfo, // Use common VideoInfo
|
29
|
+
destPath, options = {}, downloadUrls // 下載URL列表參數,可以是單個URL或URL列表
|
30
|
+
) {
|
31
|
+
const { retries = 3, timeout = 60000, headers = {}, onProgress, // Keep for backward compatibility? Or remove? Let's keep for now but prioritize onFileProgress
|
32
|
+
onFileProgress, // Add the new option
|
33
|
+
checkExisting = true, overwrite = false, useSubfolders = true, filenameTemplate = "{date}-{title}" } = options;
|
34
|
+
let finalPath = ''; // Declare finalPath outside the try block
|
35
|
+
try {
|
36
|
+
// 檢查視頻播放 URL 是否存在
|
37
|
+
if (!videoInfo.videoPlayUrl) {
|
38
|
+
throw new error_handler_1.DownloadError(`影片 ${videoInfo.id} 無有效的播放 URL`, videoInfo.id, 'INVALID_URL', false);
|
39
|
+
}
|
40
|
+
// --- 確定最終的檔案路徑 ---
|
41
|
+
// finalPath is already declared above
|
42
|
+
const destPathStats = await fs_extra_1.default.stat(destPath).catch(() => null);
|
43
|
+
if (destPathStats && destPathStats.isDirectory()) {
|
44
|
+
// destPath 是現有目錄,使用 formatOutputPath
|
45
|
+
logger_1.downloadLogger.debug(`destPath (${destPath}) 是現有目錄。使用 formatOutputPath。`);
|
46
|
+
finalPath = (0, path_formatter_1.formatOutputPath)(videoInfo, destPath, { useSubfolders, filenameTemplate });
|
47
|
+
}
|
48
|
+
else if (!destPathStats && (destPath.endsWith(path_1.default.sep) || destPath.endsWith('/'))) {
|
49
|
+
// destPath 不存在但以分隔符結尾,視為目錄
|
50
|
+
logger_1.downloadLogger.debug(`destPath (${destPath}) 不存在但以分隔符結尾。視為目錄並使用 formatOutputPath。`);
|
51
|
+
finalPath = (0, path_formatter_1.formatOutputPath)(videoInfo, destPath, { useSubfolders, filenameTemplate });
|
52
|
+
}
|
53
|
+
else if (destPathStats && destPathStats.isFile()) {
|
54
|
+
// destPath 是現有檔案 (可能來自 -f 或先前下載)
|
55
|
+
logger_1.downloadLogger.debug(`destPath (${destPath}) 是現有檔案。直接使用。`);
|
56
|
+
finalPath = destPath; // 直接使用路徑
|
57
|
+
}
|
58
|
+
else if (!destPathStats) {
|
59
|
+
// destPath 不存在,檢查父目錄
|
60
|
+
const parentDir = path_1.default.dirname(destPath);
|
61
|
+
// 檢查父目錄是否為空或根目錄,避免對根目錄調用 fs.stat
|
62
|
+
let parentDirExists = false;
|
63
|
+
if (parentDir && parentDir !== destPath) { // 確保 parentDir 不是自身 (例如 "/")
|
64
|
+
try {
|
65
|
+
const parentDirStats = await fs_extra_1.default.stat(parentDir);
|
66
|
+
parentDirExists = parentDirStats.isDirectory();
|
67
|
+
}
|
68
|
+
catch {
|
69
|
+
parentDirExists = false;
|
70
|
+
}
|
71
|
+
}
|
72
|
+
else if (parentDir === path_1.default.dirname(parentDir)) { // 檢查是否為根目錄 (e.g., '/' or 'C:\')
|
73
|
+
parentDirExists = true; // 根目錄總是存在
|
74
|
+
}
|
75
|
+
if (parentDirExists) {
|
76
|
+
// 父目錄存在,假定 destPath 是檔案路徑 (來自 -f)
|
77
|
+
logger_1.downloadLogger.debug(`destPath (${destPath}) 不存在,但父目錄存在。假定為檔案路徑並直接使用。`);
|
78
|
+
finalPath = destPath; // 直接使用路徑
|
79
|
+
}
|
80
|
+
else {
|
81
|
+
// 父目錄不存在,假定 destPath 是目錄路徑 (來自 -d 指定新目錄)
|
82
|
+
logger_1.downloadLogger.debug(`destPath (${destPath}) 及其父目錄不存在。視為目錄並使用 formatOutputPath。`);
|
83
|
+
finalPath = (0, path_formatter_1.formatOutputPath)(videoInfo, destPath, { useSubfolders, filenameTemplate });
|
84
|
+
}
|
85
|
+
}
|
86
|
+
else {
|
87
|
+
// 不應發生,但預設為目錄行為
|
88
|
+
logger_1.downloadLogger.warn(`無法確定 destPath (${destPath}) 的類型。預設為目錄行為。`);
|
89
|
+
finalPath = (0, path_formatter_1.formatOutputPath)(videoInfo, destPath, { useSubfolders, filenameTemplate });
|
90
|
+
}
|
91
|
+
// ---
|
92
|
+
// 確保最終 finalPath 的父目錄存在
|
93
|
+
await (0, file_1.ensureDirectoryExists)(path_1.default.dirname(finalPath));
|
94
|
+
// 檢查檔案是否已存在
|
95
|
+
if (checkExisting) {
|
96
|
+
const fileExists = await fs_extra_1.default.pathExists(finalPath);
|
97
|
+
if (fileExists && !overwrite) {
|
98
|
+
logger_1.downloadLogger.info(`檔案已存在且不覆蓋: ${finalPath}`);
|
99
|
+
return finalPath;
|
100
|
+
}
|
101
|
+
else if (fileExists) {
|
102
|
+
logger_1.downloadLogger.warn(`檔案已存在,將被覆蓋: ${finalPath}`);
|
103
|
+
}
|
104
|
+
}
|
105
|
+
// 下載影片
|
106
|
+
logger_1.downloadLogger.info(`開始下載影片: ${videoInfo.title || videoInfo.id}`);
|
107
|
+
logger_1.downloadLogger.debug(`下載 URL: ${videoInfo.videoPlayUrl}`);
|
108
|
+
logger_1.downloadLogger.debug(`保存路徑: ${finalPath}`);
|
109
|
+
// 設置請求頭
|
110
|
+
const downloadHeaders = {
|
111
|
+
'Referer': `https://www.douyin.com/video/${videoInfo.id}`,
|
112
|
+
...headers
|
113
|
+
};
|
114
|
+
// 使用重試機制下載
|
115
|
+
// Use the imported withRetry from shared utils
|
116
|
+
await (0, retry_1.withRetry)(
|
117
|
+
// Add type for progressCallback (assuming it's (progress: number) => void based on usage)
|
118
|
+
// The function passed to withRetry doesn't receive progressCallback directly.
|
119
|
+
// Progress should be handled via the options passed to downloadFile.
|
120
|
+
async () => {
|
121
|
+
await (0, file_1.downloadFile)(videoInfo.videoPlayUrl, finalPath, {
|
122
|
+
headers: downloadHeaders,
|
123
|
+
timeout,
|
124
|
+
// Pass the correct callback (onFileProgress or onProgress) to downloadFile's onProgress
|
125
|
+
onProgress: (downloaded, total) => {
|
126
|
+
const progress = (total && total > 0) ? Math.round((downloaded / total) * 100) : 0;
|
127
|
+
const fileProgressCallback = onFileProgress || onProgress; // Prioritize onFileProgress
|
128
|
+
if (fileProgressCallback) {
|
129
|
+
fileProgressCallback(progress);
|
130
|
+
}
|
131
|
+
}
|
132
|
+
});
|
133
|
+
return true;
|
134
|
+
},
|
135
|
+
// Options for withRetry
|
136
|
+
{
|
137
|
+
retries,
|
138
|
+
onRetry: (error, attempt) => {
|
139
|
+
logger_1.downloadLogger.warn(`下載影片 ${videoInfo.id} 失敗,重試 #${attempt}/${retries}:`, error.message);
|
140
|
+
},
|
141
|
+
// Example: Only retry on specific errors if needed
|
142
|
+
shouldRetry: (error) => {
|
143
|
+
if (error instanceof error_handler_1.DownloadError) {
|
144
|
+
return error.isRetryable();
|
145
|
+
}
|
146
|
+
// Optionally retry other generic errors based on message, etc.
|
147
|
+
return true; // Default: retry most errors
|
148
|
+
}
|
149
|
+
});
|
150
|
+
logger_1.downloadLogger.info(`影片下載完成: ${finalPath}`);
|
151
|
+
return finalPath;
|
152
|
+
}
|
153
|
+
catch (error) {
|
154
|
+
const errorMessage = (0, error_handler_1.getDownloadErrorMessage)(error, videoInfo.videoPlayUrl || videoInfo.id);
|
155
|
+
logger_1.downloadLogger.error(`下載影片 ${videoInfo.id} 失敗:`, new Error(errorMessage));
|
156
|
+
// 如果檔案已經部分寫入,則刪除它
|
157
|
+
// 使用上面已確定的 finalPath 變數
|
158
|
+
try {
|
159
|
+
// const finalPath = formatOutputPath(videoInfo, destPath, { // 不再需要重新計算
|
160
|
+
// useSubfolders,
|
161
|
+
// filenameTemplate
|
162
|
+
// });
|
163
|
+
if (await fs_extra_1.default.pathExists(finalPath)) {
|
164
|
+
await fs_extra_1.default.unlink(finalPath);
|
165
|
+
logger_1.downloadLogger.debug(`刪除不完整的下載檔案: ${finalPath}`);
|
166
|
+
}
|
167
|
+
}
|
168
|
+
catch (unlinkError) {
|
169
|
+
logger_1.downloadLogger.warn(`刪除不完整的檔案失敗:`, unlinkError);
|
170
|
+
}
|
171
|
+
// 嘗試使用下載URL列表
|
172
|
+
if (downloadUrls && downloadUrls.length > 0) {
|
173
|
+
// 使用第一個下載URL,並將剩餘的URL傳遞給遞迴調用
|
174
|
+
const nextUrl = downloadUrls[0];
|
175
|
+
const remainingUrls = downloadUrls.slice(1);
|
176
|
+
logger_1.downloadLogger.info(`嘗試使用其他下載URL下載影片 ${videoInfo.id},剩餘 ${downloadUrls.length} 個下載URL`);
|
177
|
+
// 創建一個新的videoInfo對象,使用下一個下載URL
|
178
|
+
const newVideoInfo = { ...videoInfo, videoPlayUrl: nextUrl };
|
179
|
+
// 遞迴調用自身,嘗試使用其他下載URL
|
180
|
+
return await downloadVideo(newVideoInfo, destPath, options, remainingUrls);
|
181
|
+
}
|
182
|
+
throw new error_handler_1.DownloadError(errorMessage, videoInfo.id, 'DOWNLOAD_FAILED', false);
|
183
|
+
}
|
184
|
+
}
|
185
|
+
/**
|
186
|
+
* 獲取影片的下載大小
|
187
|
+
* @param url 影片 URL
|
188
|
+
* @param headers 請求頭
|
189
|
+
* @returns Promise<number> 檔案大小(位元組)
|
190
|
+
*/
|
191
|
+
async function getVideoSize(url, headers = {}) {
|
192
|
+
try {
|
193
|
+
// 發送 HEAD 請求獲取檔案大小
|
194
|
+
const response = await fetch(url, {
|
195
|
+
method: 'HEAD',
|
196
|
+
headers
|
197
|
+
});
|
198
|
+
if (!response.ok) {
|
199
|
+
throw new error_handler_1.DownloadError(`獲取影片大小失敗: ${response.status} ${response.statusText}`, url, 'HEAD_REQUEST_FAILED', true);
|
200
|
+
}
|
201
|
+
// 讀取 Content-Length 頭
|
202
|
+
const contentLength = response.headers.get('content-length');
|
203
|
+
if (!contentLength) {
|
204
|
+
logger_1.downloadLogger.warn(`無法獲取影片大小,伺服器未返回 Content-Length 頭: ${url}`);
|
205
|
+
return 0;
|
206
|
+
}
|
207
|
+
// 轉換為數字
|
208
|
+
const size = parseInt(contentLength, 10);
|
209
|
+
if (isNaN(size)) {
|
210
|
+
logger_1.downloadLogger.warn(`無法解析影片大小: ${contentLength}, ${url}`);
|
211
|
+
return 0;
|
212
|
+
}
|
213
|
+
return size;
|
214
|
+
}
|
215
|
+
catch (error) {
|
216
|
+
if (error instanceof error_handler_1.DownloadError) {
|
217
|
+
throw error;
|
218
|
+
}
|
219
|
+
logger_1.downloadLogger.error(`獲取影片大小失敗: ${url}`, error instanceof Error ? error : new Error(String(error)));
|
220
|
+
throw new error_handler_1.DownloadError(`獲取影片大小失敗: ${error.message}`, url, 'GET_SIZE_FAILED', true);
|
221
|
+
}
|
222
|
+
}
|
223
|
+
//# sourceMappingURL=video-downloader.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"video-downloader.js","sourceRoot":"","sources":["../../../../src/douyin/download/video-downloader.ts"],"names":[],"mappings":"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"}
|
@@ -0,0 +1,19 @@
|
|
1
|
+
/**
|
2
|
+
* 抖音影片解析與下載套件
|
3
|
+
* 提供對抖音平台視頻的解析和下載功能
|
4
|
+
*
|
5
|
+
* @packageDocumentation
|
6
|
+
*
|
7
|
+
* @remarks
|
8
|
+
* 免責聲明:本套件僅供學習和個人使用。請遵守抖音平台的服務條款和相關法規。
|
9
|
+
* 用戶須對使用本套件的行為負責,開發者不對任何濫用行為或因此產生的後果負責。
|
10
|
+
* 請尊重原創作者的著作權,不要未經授權分發下載的內容。
|
11
|
+
*
|
12
|
+
* 參考來源:此模組改寫自原本存放於 src/ 下的抖音相關功能
|
13
|
+
* 但架構已重新組織並與 TikTok 功能相互平行
|
14
|
+
* 需要驗證:整體 API 設計是否符合用戶需求和最佳實踐
|
15
|
+
*/
|
16
|
+
export { login, isValidCookie, loadAndValidateCookie, getDefaultCookiePath, saveCookie, loadCookie, getAppDataDir } from './auth';
|
17
|
+
export { extractDouyinLinks, containsDouyinLink, parseDouyinLinks, resolveShortUrl } from './parser';
|
18
|
+
export { fetchVideosInfoText, fetchVideosInfoUrls, fetchVideoDetail, extractSecUserId, fetchUserVideos } from './info';
|
19
|
+
export { downloadVideo, downloadVideos, downloadVideosFromText } from './download';
|
@@ -0,0 +1,52 @@
|
|
1
|
+
"use strict";
|
2
|
+
/**
|
3
|
+
* 抖音影片解析與下載套件
|
4
|
+
* 提供對抖音平台視頻的解析和下載功能
|
5
|
+
*
|
6
|
+
* @packageDocumentation
|
7
|
+
*
|
8
|
+
* @remarks
|
9
|
+
* 免責聲明:本套件僅供學習和個人使用。請遵守抖音平台的服務條款和相關法規。
|
10
|
+
* 用戶須對使用本套件的行為負責,開發者不對任何濫用行為或因此產生的後果負責。
|
11
|
+
* 請尊重原創作者的著作權,不要未經授權分發下載的內容。
|
12
|
+
*
|
13
|
+
* 參考來源:此模組改寫自原本存放於 src/ 下的抖音相關功能
|
14
|
+
* 但架構已重新組織並與 TikTok 功能相互平行
|
15
|
+
* 需要驗證:整體 API 設計是否符合用戶需求和最佳實踐
|
16
|
+
*/
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
18
|
+
exports.downloadVideosFromText = exports.downloadVideos = exports.downloadVideo = exports.fetchUserVideos = exports.extractSecUserId = exports.fetchVideoDetail = exports.fetchVideosInfoUrls = exports.fetchVideosInfoText = exports.resolveShortUrl = exports.parseDouyinLinks = exports.containsDouyinLink = exports.extractDouyinLinks = exports.getAppDataDir = exports.loadCookie = exports.saveCookie = exports.getDefaultCookiePath = exports.loadAndValidateCookie = exports.isValidCookie = exports.login = void 0;
|
19
|
+
// ================= 認證與登入模組 (implements AuthService implicitly) =================
|
20
|
+
// 導出 auth 子模組中的所有功能
|
21
|
+
var auth_1 = require("./auth");
|
22
|
+
Object.defineProperty(exports, "login", { enumerable: true, get: function () { return auth_1.login; } });
|
23
|
+
Object.defineProperty(exports, "isValidCookie", { enumerable: true, get: function () { return auth_1.isValidCookie; } });
|
24
|
+
Object.defineProperty(exports, "loadAndValidateCookie", { enumerable: true, get: function () { return auth_1.loadAndValidateCookie; } });
|
25
|
+
Object.defineProperty(exports, "getDefaultCookiePath", { enumerable: true, get: function () { return auth_1.getDefaultCookiePath; } });
|
26
|
+
Object.defineProperty(exports, "saveCookie", { enumerable: true, get: function () { return auth_1.saveCookie; } });
|
27
|
+
Object.defineProperty(exports, "loadCookie", { enumerable: true, get: function () { return auth_1.loadCookie; } });
|
28
|
+
Object.defineProperty(exports, "getAppDataDir", { enumerable: true, get: function () { return auth_1.getAppDataDir; } }); // Moved from utils
|
29
|
+
// ================= 解析模組 (implements ParserService implicitly) =================
|
30
|
+
// 導出 parser 子模組中的所有功能
|
31
|
+
var parser_1 = require("./parser");
|
32
|
+
Object.defineProperty(exports, "extractDouyinLinks", { enumerable: true, get: function () { return parser_1.extractDouyinLinks; } });
|
33
|
+
Object.defineProperty(exports, "containsDouyinLink", { enumerable: true, get: function () { return parser_1.containsDouyinLink; } });
|
34
|
+
Object.defineProperty(exports, "parseDouyinLinks", { enumerable: true, get: function () { return parser_1.parseDouyinLinks; } });
|
35
|
+
Object.defineProperty(exports, "resolveShortUrl", { enumerable: true, get: function () { return parser_1.resolveShortUrl; } });
|
36
|
+
// ================= 影片資訊模組 (implements InfoService implicitly) =================
|
37
|
+
// 導出 info 子模組中的所有功能
|
38
|
+
var info_1 = require("./info");
|
39
|
+
Object.defineProperty(exports, "fetchVideosInfoText", { enumerable: true, get: function () { return info_1.fetchVideosInfoText; } });
|
40
|
+
Object.defineProperty(exports, "fetchVideosInfoUrls", { enumerable: true, get: function () { return info_1.fetchVideosInfoUrls; } });
|
41
|
+
Object.defineProperty(exports, "fetchVideoDetail", { enumerable: true, get: function () { return info_1.fetchVideoDetail; } });
|
42
|
+
Object.defineProperty(exports, "extractSecUserId", { enumerable: true, get: function () { return info_1.extractSecUserId; } });
|
43
|
+
Object.defineProperty(exports, "fetchUserVideos", { enumerable: true, get: function () { return info_1.fetchUserVideos; } });
|
44
|
+
// ================= 下載模組 (implements DownloadService implicitly) =================
|
45
|
+
// 導出 download 子模組中的所有功能
|
46
|
+
var download_1 = require("./download");
|
47
|
+
Object.defineProperty(exports, "downloadVideo", { enumerable: true, get: function () { return download_1.downloadVideo; } });
|
48
|
+
Object.defineProperty(exports, "downloadVideos", { enumerable: true, get: function () { return download_1.downloadVideos; } });
|
49
|
+
Object.defineProperty(exports, "downloadVideosFromText", { enumerable: true, get: function () { return download_1.downloadVideosFromText; } });
|
50
|
+
// ================= 工具函數 (Moved to src/utils) =================
|
51
|
+
// Removed export block for './utils'
|
52
|
+
//# sourceMappingURL=index.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/douyin/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG;;;AAEH,kFAAkF;AAClF,oBAAoB;AACpB,+BAQgB;AAPd,6FAAA,KAAK,OAAA;AACL,qGAAA,aAAa,OAAA;AACb,6GAAA,qBAAqB,OAAA;AACrB,4GAAA,oBAAoB,OAAA;AACpB,kGAAA,UAAU,OAAA;AACV,kGAAA,UAAU,OAAA;AACV,qGAAA,aAAa,OAAA,CAAC,mBAAmB;AAGnC,iFAAiF;AACjF,sBAAsB;AACtB,mCAKkB;AAJhB,4GAAA,kBAAkB,OAAA;AAClB,4GAAA,kBAAkB,OAAA;AAClB,0GAAA,gBAAgB,OAAA;AAChB,yGAAA,eAAe,OAAA;AAGjB,iFAAiF;AACjF,oBAAoB;AACpB,+BAMgB;AALd,2GAAA,mBAAmB,OAAA;AACnB,2GAAA,mBAAmB,OAAA;AACnB,wGAAA,gBAAgB,OAAA;AAChB,wGAAA,gBAAgB,OAAA;AAChB,uGAAA,eAAe,OAAA;AAGjB,mFAAmF;AACnF,wBAAwB;AACxB,uCAIoB;AAHlB,yGAAA,aAAa,OAAA;AACb,0GAAA,cAAc,OAAA;AACd,kHAAA,sBAAsB,OAAA;AAGxB,gEAAgE;AAChE,qCAAqC"}
|
@@ -0,0 +1,15 @@
|
|
1
|
+
/**
|
2
|
+
* 批量處理功能
|
3
|
+
* 處理多個影片URL的順序獲取(一個接一個)
|
4
|
+
*/
|
5
|
+
import { VideoInfo, FetchVideoOptions } from '../../types';
|
6
|
+
import { Page } from 'puppeteer';
|
7
|
+
/**
|
8
|
+
* 批量處理多個影片 URL 的資訊獲取(順序處理,非並行)
|
9
|
+
* @param videoUrls 影片 URL 陣列
|
10
|
+
* @param cookie 抖音 Cookie 字串
|
11
|
+
* @param options 獲取選項
|
12
|
+
* @returns Promise<VideoInfoResult[]> 影片資訊結果陣列
|
13
|
+
*/
|
14
|
+
export declare function processBatch(videoUrls: string[], page: Page, // Changed: Accept Page object
|
15
|
+
options?: FetchVideoOptions): Promise<VideoInfo[]>;
|
@@ -0,0 +1,65 @@
|
|
1
|
+
"use strict";
|
2
|
+
// Copied from src/info/batch-processor.ts
|
3
|
+
// Original file path: src/info/batch-processor.ts
|
4
|
+
/**
|
5
|
+
* 批量處理功能
|
6
|
+
* 處理多個影片URL的順序獲取(一個接一個)
|
7
|
+
*/
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
9
|
+
exports.processBatch = processBatch;
|
10
|
+
const logger_1 = require("../../utils/logger"); // Updated path to shared utils logger
|
11
|
+
const retry_1 = require("../../utils/retry"); // Updated path to shared utils
|
12
|
+
const fetch_video_detail_1 = require("./fetch-video-detail");
|
13
|
+
/**
|
14
|
+
* 批量處理多個影片 URL 的資訊獲取(順序處理,非並行)
|
15
|
+
* @param videoUrls 影片 URL 陣列
|
16
|
+
* @param cookie 抖音 Cookie 字串
|
17
|
+
* @param options 獲取選項
|
18
|
+
* @returns Promise<VideoInfoResult[]> 影片資訊結果陣列
|
19
|
+
*/
|
20
|
+
async function processBatch(videoUrls, page, // Changed: Accept Page object
|
21
|
+
// cookie: string, // Removed
|
22
|
+
options = {}) {
|
23
|
+
const { onProgress } = options;
|
24
|
+
if (!videoUrls || videoUrls.length === 0) {
|
25
|
+
logger_1.infoLogger.warn('沒有提供要處理的影片 URL');
|
26
|
+
return [];
|
27
|
+
}
|
28
|
+
// Removed: Cookie check, assuming page is valid
|
29
|
+
logger_1.infoLogger.info(`[processBatch] 開始順序處理 ${videoUrls.length} 個影片 URL(一個接一個)`);
|
30
|
+
const results = []; // Use common VideoInfo
|
31
|
+
// 順序處理每個 URL(一個接一個)
|
32
|
+
for (let index = 0; index < videoUrls.length; index++) {
|
33
|
+
const url = videoUrls[index];
|
34
|
+
logger_1.infoLogger.debug(`[processBatch] 處理第 ${index + 1}/${videoUrls.length} 個影片 URL: ${url}`);
|
35
|
+
try {
|
36
|
+
// 使用 withRetry 為每個任務添加重試機制
|
37
|
+
const result = await (0, retry_1.withRetry)(async () => {
|
38
|
+
// Pass page instead of cookie to fetchVideoDetail
|
39
|
+
return await (0, fetch_video_detail_1.fetchVideoDetail)(page, url);
|
40
|
+
}, { retries: 2 });
|
41
|
+
// 在此記錄每個單獨的結果,方便調試
|
42
|
+
if (result) {
|
43
|
+
logger_1.infoLogger.debug(`[processBatch] 成功獲取影片資訊: ${result.title}`);
|
44
|
+
}
|
45
|
+
else {
|
46
|
+
logger_1.infoLogger.debug(`[processBatch] 無法獲取影片資訊: ${url}`);
|
47
|
+
}
|
48
|
+
results.push(result);
|
49
|
+
}
|
50
|
+
catch (error) {
|
51
|
+
logger_1.infoLogger.error(`[processBatch] 處理影片 URL 失敗: ${url}`, error instanceof Error ? error : new Error(String(error)));
|
52
|
+
results.push(null);
|
53
|
+
}
|
54
|
+
// 更新進度
|
55
|
+
if (onProgress) {
|
56
|
+
logger_1.infoLogger.debug(`[processBatch] 批量處理進度: ${index + 1}/${videoUrls.length}`);
|
57
|
+
onProgress(index + 1, videoUrls.length);
|
58
|
+
}
|
59
|
+
}
|
60
|
+
// 過濾掉 null 結果
|
61
|
+
const validResults = results.filter((result) => result !== null); // Use type predicate for filtering
|
62
|
+
logger_1.infoLogger.info(`[processBatch] 批量處理完成,成功獲取 ${validResults.length}/${videoUrls.length} 個影片的資訊`);
|
63
|
+
return validResults;
|
64
|
+
}
|
65
|
+
//# sourceMappingURL=batch-processor.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"batch-processor.js","sourceRoot":"","sources":["../../../../src/douyin/info/batch-processor.ts"],"names":[],"mappings":";AAAA,0CAA0C;AAC1C,kDAAkD;AAClD;;;GAGG;;AAeH,oCAyDC;AAtED,+CAA0D,CAAC,sCAAsC;AACjG,6CAA8C,CAAC,+BAA+B;AAC9E,6DAAwD;AAIxD;;;;;;GAMG;AACI,KAAK,UAAU,YAAY,CAChC,SAAmB,EACnB,IAAU,EAAE,8BAA8B;AAC1C,6BAA6B;AAC7B,UAA6B,EAAE;IAE/B,MAAM,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC;IAE/B,IAAI,CAAC,SAAS,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzC,mBAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;QAC9B,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,gDAAgD;IAEhD,mBAAM,CAAC,IAAI,CAAC,yBAAyB,SAAS,CAAC,MAAM,iBAAiB,CAAC,CAAC;IAExE,MAAM,OAAO,GAAyB,EAAE,CAAC,CAAC,uBAAuB;IAEjE,oBAAoB;IACpB,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,SAAS,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC;QACtD,MAAM,GAAG,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;QAC7B,mBAAM,CAAC,KAAK,CAAC,sBAAsB,KAAK,GAAG,CAAC,IAAI,SAAS,CAAC,MAAM,aAAa,GAAG,EAAE,CAAC,CAAC;QAEpF,IAAI,CAAC;YACH,2BAA2B;YAC3B,MAAM,MAAM,GAAG,MAAM,IAAA,iBAAS,EAAC,KAAK,IAAI,EAAE;gBACxC,kDAAkD;gBAClD,OAAO,MAAM,IAAA,qCAAgB,EAAC,IAAI,EAAE,GAAG,CAAC,CAAC;YAC3C,CAAC,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;YAEnB,mBAAmB;YACnB,IAAI,MAAM,EAAE,CAAC;gBACX,mBAAM,CAAC,KAAK,CAAC,4BAA4B,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;YAC3D,CAAC;iBAAM,CAAC;gBACN,mBAAM,CAAC,KAAK,CAAC,4BAA4B,GAAG,EAAE,CAAC,CAAC;YAClD,CAAC;YAED,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACvB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,mBAAM,CAAC,KAAK,CAAC,+BAA+B,GAAG,EAAE,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAC9G,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrB,CAAC;QAED,OAAO;QACP,IAAI,UAAU,EAAE,CAAC;YACf,mBAAM,CAAC,KAAK,CAAC,0BAA0B,KAAK,GAAG,CAAC,IAAI,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC;YACxE,UAAU,CAAC,KAAK,GAAG,CAAC,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC;QAC1C,CAAC;IACH,CAAC;IAED,cAAc;IACd,MAAM,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,EAAuB,EAAE,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,mCAAmC;IAE1H,mBAAM,CAAC,IAAI,CAAC,8BAA8B,YAAY,CAAC,MAAM,IAAI,SAAS,CAAC,MAAM,SAAS,CAAC,CAAC;IAE5F,OAAO,YAAY,CAAC;AACtB,CAAC"}
|
@@ -0,0 +1,56 @@
|
|
1
|
+
/**
|
2
|
+
* 瀏覽器管理模組
|
3
|
+
* 使用 Puppeteer 提供瀏覽器實例管理
|
4
|
+
*/
|
5
|
+
import { Browser, Page } from 'puppeteer';
|
6
|
+
interface BrowserManagerOptions {
|
7
|
+
headless?: boolean;
|
8
|
+
timeout?: number;
|
9
|
+
userAgent?: string;
|
10
|
+
}
|
11
|
+
/**
|
12
|
+
* 瀏覽器管理器
|
13
|
+
* 使用單例模式管理 Puppeteer 瀏覽器實例
|
14
|
+
*/
|
15
|
+
export declare class BrowserManager {
|
16
|
+
private static instance;
|
17
|
+
private browser;
|
18
|
+
private browserInitPromise;
|
19
|
+
private options;
|
20
|
+
/**
|
21
|
+
* 獲取 BrowserManager 單例
|
22
|
+
* @param options 瀏覽器選項
|
23
|
+
* @returns BrowserManager 實例
|
24
|
+
*/
|
25
|
+
static getInstance(options?: BrowserManagerOptions): BrowserManager;
|
26
|
+
/**
|
27
|
+
* 私有構造函數,防止直接創建實例
|
28
|
+
* @param options 瀏覽器選項
|
29
|
+
*/
|
30
|
+
private constructor();
|
31
|
+
/**
|
32
|
+
* 獲取瀏覽器實例
|
33
|
+
* 如果實例不存在,則創建新實例
|
34
|
+
* @returns Promise<Browser>
|
35
|
+
*/
|
36
|
+
getBrowser(): Promise<Browser>;
|
37
|
+
/**
|
38
|
+
* 創建新的頁面
|
39
|
+
* @param cookies 可選的 Cookie 字符串
|
40
|
+
* @returns Promise<Page>
|
41
|
+
*/
|
42
|
+
newPage(cookies?: string): Promise<Page>;
|
43
|
+
/**
|
44
|
+
* 設置頁面的 Cookie
|
45
|
+
* @param page Puppeteer 頁面實例
|
46
|
+
* @param cookieString Cookie 字符串
|
47
|
+
*/
|
48
|
+
setCookies(page: Page, cookieString: string): Promise<void>;
|
49
|
+
/**
|
50
|
+
* 關閉瀏覽器實例
|
51
|
+
*/
|
52
|
+
close(): Promise<void>;
|
53
|
+
}
|
54
|
+
export declare const browserManager: BrowserManager;
|
55
|
+
export declare function cleanupBrowser(): Promise<void>;
|
56
|
+
export {};
|