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