bili-dl 1.0.0__py3-none-any.whl
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.
- bili_dl-1.0.0.dist-info/METADATA +257 -0
- bili_dl-1.0.0.dist-info/RECORD +14 -0
- bili_dl-1.0.0.dist-info/WHEEL +5 -0
- bili_dl-1.0.0.dist-info/entry_points.txt +2 -0
- bili_dl-1.0.0.dist-info/licenses/LICENSE +21 -0
- bili_dl-1.0.0.dist-info/top_level.txt +4 -0
- config/config.json +34 -0
- config/config_manager.py +154 -0
- main.py +91 -0
- modules/ffmpeg_integration.py +229 -0
- modules/login_manager.py +261 -0
- modules/stream_downloader.py +207 -0
- modules/video_info.py +315 -0
- utils/common_utils.py +199 -0
@@ -0,0 +1,257 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: bili-dl
|
3
|
+
Version: 1.0.0
|
4
|
+
Summary: 一个功能强大的B站视频下载工具,支持最高清晰度下载和自动合并
|
5
|
+
Home-page: https://github.com/WavesMan/bili-download
|
6
|
+
Author: B站视频下载器
|
7
|
+
Author-email:
|
8
|
+
License: MIT License
|
9
|
+
Project-URL: Homepage, https://github.com/WavesMan/bili-downloader
|
10
|
+
Project-URL: BugTracker, https://github.com/WavesMan/bili-downloader/issues
|
11
|
+
Project-URL: Source, https://github.com/WavesMan/bili-downloader
|
12
|
+
Keywords: bilibili,video,download,b站,视频下载
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
14
|
+
Classifier: Intended Audience :: End Users/Desktop
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
17
|
+
Classifier: Programming Language :: Python :: 3.7
|
18
|
+
Classifier: Programming Language :: Python :: 3.8
|
19
|
+
Classifier: Programming Language :: Python :: 3.9
|
20
|
+
Classifier: Programming Language :: Python :: 3.10
|
21
|
+
Classifier: Operating System :: OS Independent
|
22
|
+
Requires-Python: >=3.8
|
23
|
+
Description-Content-Type: text/markdown
|
24
|
+
License-File: LICENSE
|
25
|
+
Requires-Dist: requests>=2.28.0
|
26
|
+
Requires-Dist: qrcode>=7.3.1
|
27
|
+
Requires-Dist: Pillow>=9.3.0
|
28
|
+
Provides-Extra: dev
|
29
|
+
Requires-Dist: black>=22.10.0; extra == "dev"
|
30
|
+
Requires-Dist: flake8>=5.0.0; extra == "dev"
|
31
|
+
Requires-Dist: mypy>=0.991; extra == "dev"
|
32
|
+
Requires-Dist: pytest>=7.2.0; extra == "dev"
|
33
|
+
Dynamic: home-page
|
34
|
+
Dynamic: license-file
|
35
|
+
Dynamic: requires-python
|
36
|
+
|
37
|
+
# B站视频下载器 (bili-downloader)
|
38
|
+
|
39
|
+
[](https://pypi.org/project/bili-dl/)
|
40
|
+
[](https://pypi.org/project/bili-dl/)
|
41
|
+
[](https://opensource.org/licenses/MIT)
|
42
|
+
|
43
|
+
一个功能强大的B站视频下载工具,支持最高清晰度下载和自动合并。
|
44
|
+
|
45
|
+
## ✨ 功能特性
|
46
|
+
|
47
|
+
- 🎯 **智能清晰度选择**: 自动获取账号权限内的最高清晰度视频
|
48
|
+
- 🔐 **多种登录方式**: 支持二维码登录和Cookie登录
|
49
|
+
- 🔍 **Cookie状态检查**: 自动验证Cookie可用性,失效时提示重新登录
|
50
|
+
- 📦 **自动合并**: 支持DASH格式视频的自动音视频合并
|
51
|
+
- 🚀 **多线程下载**: 支持多线程并发下载,提高下载速度
|
52
|
+
- 📁 **智能文件管理**: 按BV号自动组织文件结构
|
53
|
+
- 📊 **元数据保存**: 自动保存视频信息和下载元数据
|
54
|
+
- ⚡ **断点续传**: 支持下载中断后继续下载
|
55
|
+
- 🏗️ **模块化架构**: 清晰的命令分离和职责划分
|
56
|
+
|
57
|
+
## 📦 安装
|
58
|
+
|
59
|
+
### 通过 pip 安装
|
60
|
+
|
61
|
+
```bash
|
62
|
+
pip install bili-dl
|
63
|
+
```
|
64
|
+
|
65
|
+
### 从源码安装
|
66
|
+
|
67
|
+
```bash
|
68
|
+
git clone https://github.com/WavesMan/bili-download.git
|
69
|
+
cd bili-downloader
|
70
|
+
pip install -e .
|
71
|
+
```
|
72
|
+
|
73
|
+
## 🚀 快速开始
|
74
|
+
|
75
|
+
### 基本使用
|
76
|
+
|
77
|
+
```bash
|
78
|
+
# 查看帮助信息
|
79
|
+
bili-dl --help
|
80
|
+
|
81
|
+
# 查看特定命令帮助
|
82
|
+
bili-dl download --help
|
83
|
+
bili-dl login --help
|
84
|
+
bili-dl status --help
|
85
|
+
|
86
|
+
# 下载单个视频(需要先登录)
|
87
|
+
bili-dl download BV1A6aRz4EBU
|
88
|
+
|
89
|
+
# 指定输出目录
|
90
|
+
bili-dl download BV1A6aRz4EBU --output ./my_videos
|
91
|
+
|
92
|
+
# 指定清晰度 (80=1080P, 112=1080P+, 120=4K)
|
93
|
+
bili-dl download BV1A6aRz4EBU --quality 112
|
94
|
+
|
95
|
+
# 禁用自动合并
|
96
|
+
bili-dl download BV1A6aRz4EBU --no-merge
|
97
|
+
|
98
|
+
# 登录B站账号
|
99
|
+
bili-dl login
|
100
|
+
|
101
|
+
# 检查登录状态
|
102
|
+
bili-dl status
|
103
|
+
```
|
104
|
+
|
105
|
+
### 配置说明
|
106
|
+
|
107
|
+
首次运行会自动创建配置文件 `~/.bili-downloader/config.json`,您可以编辑此文件来自定义设置:
|
108
|
+
|
109
|
+
```json
|
110
|
+
{
|
111
|
+
"user": {
|
112
|
+
"cookies": {},
|
113
|
+
"session_data": {}
|
114
|
+
},
|
115
|
+
"download": {
|
116
|
+
"output_dir": "downloads",
|
117
|
+
"timeout": 30,
|
118
|
+
"retry_times": 3,
|
119
|
+
"chunk_size": 8192
|
120
|
+
},
|
121
|
+
"ffmpeg": {
|
122
|
+
"auto_merge": true,
|
123
|
+
"ffmpeg_path": "ffmpeg"
|
124
|
+
},
|
125
|
+
"debug": {
|
126
|
+
"enable_logging": false,
|
127
|
+
"log_level": "INFO"
|
128
|
+
}
|
129
|
+
}
|
130
|
+
```
|
131
|
+
|
132
|
+
## 🔧 高级用法
|
133
|
+
|
134
|
+
### 作为Python模块使用
|
135
|
+
|
136
|
+
```python
|
137
|
+
from bili_downloader.commands import handle_download_command, handle_login_command
|
138
|
+
from bili_downloader.services.login_manager import login_manager
|
139
|
+
|
140
|
+
# 初始化配置
|
141
|
+
from bili_downloader.config.config_manager import init_config
|
142
|
+
init_config()
|
143
|
+
|
144
|
+
# 登录
|
145
|
+
login_manager.init_login()
|
146
|
+
|
147
|
+
# 下载视频
|
148
|
+
success = handle_download_command("BV1A6aRz4EBU", output_dir="./videos")
|
149
|
+
if success:
|
150
|
+
print("下载成功!")
|
151
|
+
```
|
152
|
+
|
153
|
+
### 批量下载
|
154
|
+
|
155
|
+
```python
|
156
|
+
from bili_downloader.commands import handle_download_command
|
157
|
+
|
158
|
+
video_list = [
|
159
|
+
"BV1A6aRz4EBU",
|
160
|
+
"BV1B6bRz5FCV",
|
161
|
+
"BV1C7cSx6GDW"
|
162
|
+
]
|
163
|
+
|
164
|
+
for bvid in video_list:
|
165
|
+
handle_download_command(bvid)
|
166
|
+
```
|
167
|
+
|
168
|
+
## 📁 文件结构
|
169
|
+
|
170
|
+
下载完成后,文件会按以下结构组织:
|
171
|
+
|
172
|
+
```
|
173
|
+
downloads/
|
174
|
+
└── BV1A6aRz4EBU/
|
175
|
+
├── 视频标题_video.m4s # 视频流文件
|
176
|
+
├── 视频标题_audio.m4s # 音频流文件
|
177
|
+
├── 视频标题.mp4 # 最终合并的视频文件
|
178
|
+
└── metadata.json # 视频元数据信息
|
179
|
+
```
|
180
|
+
|
181
|
+
项目代码结构:
|
182
|
+
|
183
|
+
```
|
184
|
+
bili-downloader/
|
185
|
+
├── commands/ # 命令处理模块
|
186
|
+
│ ├── download_command.py # 下载命令处理
|
187
|
+
│ ├── login_command.py # 登录命令处理
|
188
|
+
│ └── status_command.py # 状态检查命令
|
189
|
+
├── modules/ # 核心功能模块
|
190
|
+
│ ├── login_manager.py # 登录管理
|
191
|
+
│ ├── video_info.py # 视频信息获取
|
192
|
+
│ ├── stream_downloader.py # 流下载器
|
193
|
+
│ └── ffmpeg_integration.py # FFmpeg集成
|
194
|
+
├── services/ # 服务层
|
195
|
+
│ └── __init__.py
|
196
|
+
├── utils/ # 工具函数
|
197
|
+
│ └── common_utils.py
|
198
|
+
├── config/ # 配置管理
|
199
|
+
│ └── config_manager.py
|
200
|
+
└── main.py # 主入口点
|
201
|
+
```
|
202
|
+
|
203
|
+
## ⚙️ 依赖要求
|
204
|
+
|
205
|
+
- Python 3.7+
|
206
|
+
- requests >= 2.28.0
|
207
|
+
- qrcode >= 7.3.1
|
208
|
+
- Pillow >= 9.3.0
|
209
|
+
- ffmpeg (用于视频合并,可选但推荐)
|
210
|
+
|
211
|
+
## 🔍 常见问题
|
212
|
+
|
213
|
+
### Q: 如何安装 ffmpeg?
|
214
|
+
|
215
|
+
**Windows:**
|
216
|
+
1. 下载 ffmpeg: https://ffmpeg.org/download.html
|
217
|
+
2. 解压并添加 bin 目录到系统 PATH
|
218
|
+
|
219
|
+
**macOS:**
|
220
|
+
```bash
|
221
|
+
brew install ffmpeg
|
222
|
+
```
|
223
|
+
|
224
|
+
**Linux (Ubuntu/Debian):**
|
225
|
+
```bash
|
226
|
+
sudo apt install ffmpeg
|
227
|
+
```
|
228
|
+
|
229
|
+
### Q: 登录失败怎么办?
|
230
|
+
|
231
|
+
使用 login 命令重新登录:
|
232
|
+
```bash
|
233
|
+
bili-dl login
|
234
|
+
```
|
235
|
+
|
236
|
+
### Q: Cookie失效怎么办?
|
237
|
+
|
238
|
+
程序会自动检测Cookie状态,如果失效会在下载时提示重新登录。
|
239
|
+
|
240
|
+
### Q: 下载速度慢怎么办?
|
241
|
+
|
242
|
+
可以尝试:
|
243
|
+
1. 检查网络连接
|
244
|
+
2. 使用更好的网络环境
|
245
|
+
3. 调整配置中的超时和重试参数
|
246
|
+
|
247
|
+
## 📄 许可证
|
248
|
+
|
249
|
+
本项目采用 MIT 许可证 - 查看 [LICENSE](LICENSE) 文件了解详情。
|
250
|
+
|
251
|
+
## 🤝 贡献
|
252
|
+
|
253
|
+
欢迎提交 Issue 和 Pull Request!
|
254
|
+
|
255
|
+
## ⚠️ 免责声明
|
256
|
+
|
257
|
+
本项目仅用于学习和研究目的,请勿用于商业用途。下载的视频请遵守相关法律法规和B站用户协议。
|
@@ -0,0 +1,14 @@
|
|
1
|
+
main.py,sha256=YcX98BLpByL7m0osEO4yKgeu5Ee-OIRHXVsFaO7bbKs,3579
|
2
|
+
bili_dl-1.0.0.dist-info/licenses/LICENSE,sha256=vWcRnXHr_5GmXiWCFQztXd-j0KDZRORLfhAzuaSBn9U,1088
|
3
|
+
config/config.json,sha256=T4yCazds-_cDDrBZrpy-cTs6PdUzi4e1dEPFAFr8J5Q,994
|
4
|
+
config/config_manager.py,sha256=6j2KxWZyJ9BJ8ip_1cq9lZbrzML3QKxdq4zx61GJKbk,5336
|
5
|
+
modules/ffmpeg_integration.py,sha256=NA-3m8dP8USpB3_q8sNdDmuFLmtLtvvMyMdS6PgLpl4,8832
|
6
|
+
modules/login_manager.py,sha256=tdtLzXwP4iAncrtQUM7mQgPWnZzRreD2xmHqta9E78w,10317
|
7
|
+
modules/stream_downloader.py,sha256=zi96yNHWUbfa8NwiIXYUogbmHyAGZTQDjoA1U0V-R7k,9164
|
8
|
+
modules/video_info.py,sha256=zxoQtHxdX4SwFvDAYo-OgL0vHNUOWVdCTpEidqiY8CU,12770
|
9
|
+
utils/common_utils.py,sha256=VTs2mNc5hswlSR8AxucLvzZCC7XeHJ1zIMQ8oBlIwyE,6635
|
10
|
+
bili_dl-1.0.0.dist-info/METADATA,sha256=uiMY1wywHyQv_AXS5IQagLt0LJJTp5eVXqoi2M6NCiE,7039
|
11
|
+
bili_dl-1.0.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
12
|
+
bili_dl-1.0.0.dist-info/entry_points.txt,sha256=-gPMZPZ_lKR0X9M_JJJpo5bSSCa0YsyNUB4ljJrE220,38
|
13
|
+
bili_dl-1.0.0.dist-info/top_level.txt,sha256=st8kmeGbQ-50d_WZ4f3vn7SpHlQeBgSU2BYiJaCJYLc,26
|
14
|
+
bili_dl-1.0.0.dist-info/RECORD,,
|
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) [2025] [WavesMan]
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
config/config.json
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
{
|
2
|
+
"user": {
|
3
|
+
"username": "",
|
4
|
+
"password": "",
|
5
|
+
"cookies": {
|
6
|
+
"SESSDATA": "0fc465a8%2C1772935699%2Cbd375%2A92CjBRcIhnkNlH1YLbAV8BuxHVYDMZC7yPPPKJQsc2hkBJUe7TkgDMsCtlDOos28Pi-PgSVkxIX0RkUWQtU3FnWHdjLWJEd3dPMUU1M3VKWk05Mlp1V1dFdVJjdlpvXzFUMlBfclVVOG9OSW94YTRRdnl3REtQS3dSUHlrUGxrbmRYZ1hZaW9fbGNBIIEC",
|
7
|
+
"bili_jct": "dca7ec9993c6431dd525d57ce54f5b8b",
|
8
|
+
"DedeUserID": "478191001"
|
9
|
+
},
|
10
|
+
"login_method": "qrcode"
|
11
|
+
},
|
12
|
+
"download": {
|
13
|
+
"output_dir": "downloads",
|
14
|
+
"quality": "auto",
|
15
|
+
"format": "mp4",
|
16
|
+
"threads": 4,
|
17
|
+
"retry_times": 3,
|
18
|
+
"timeout": 30
|
19
|
+
},
|
20
|
+
"ffmpeg": {
|
21
|
+
"path": "auto",
|
22
|
+
"auto_merge": true,
|
23
|
+
"delete_temp_files": true
|
24
|
+
},
|
25
|
+
"network": {
|
26
|
+
"proxy": "",
|
27
|
+
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
|
28
|
+
},
|
29
|
+
"debug": {
|
30
|
+
"enable_logging": false,
|
31
|
+
"log_level": "INFO",
|
32
|
+
"save_response": false
|
33
|
+
}
|
34
|
+
}
|
config/config_manager.py
ADDED
@@ -0,0 +1,154 @@
|
|
1
|
+
import json
|
2
|
+
import os
|
3
|
+
from typing import Dict, Any, Optional
|
4
|
+
import logging
|
5
|
+
|
6
|
+
class ConfigManager:
|
7
|
+
def __init__(self, config_path: str = "config/config.json"):
|
8
|
+
self.config_path = config_path
|
9
|
+
self.config: Dict[str, Any] = {}
|
10
|
+
self.logger = logging.getLogger(__name__)
|
11
|
+
|
12
|
+
def load_config(self) -> bool:
|
13
|
+
"""加载配置文件"""
|
14
|
+
try:
|
15
|
+
if not os.path.exists(self.config_path):
|
16
|
+
self.logger.warning(f"配置文件不存在: {self.config_path}")
|
17
|
+
return False
|
18
|
+
|
19
|
+
with open(self.config_path, 'r', encoding='utf-8') as f:
|
20
|
+
self.config = json.load(f)
|
21
|
+
self.logger.info("配置文件加载成功")
|
22
|
+
return True
|
23
|
+
except json.JSONDecodeError as e:
|
24
|
+
self.logger.error(f"配置文件格式错误: {e}")
|
25
|
+
return False
|
26
|
+
except Exception as e:
|
27
|
+
self.logger.error(f"加载配置文件失败: {e}")
|
28
|
+
return False
|
29
|
+
|
30
|
+
def save_config(self) -> bool:
|
31
|
+
"""保存配置文件"""
|
32
|
+
try:
|
33
|
+
os.makedirs(os.path.dirname(self.config_path), exist_ok=True)
|
34
|
+
with open(self.config_path, 'w', encoding='utf-8') as f:
|
35
|
+
json.dump(self.config, f, indent=2, ensure_ascii=False)
|
36
|
+
self.logger.info("配置文件保存成功")
|
37
|
+
return True
|
38
|
+
except Exception as e:
|
39
|
+
self.logger.error(f"保存配置文件失败: {e}")
|
40
|
+
return False
|
41
|
+
|
42
|
+
def get(self, key: str, default: Any = None) -> Any:
|
43
|
+
"""获取配置项"""
|
44
|
+
keys = key.split('.')
|
45
|
+
value = self.config
|
46
|
+
|
47
|
+
for k in keys:
|
48
|
+
if isinstance(value, dict) and k in value:
|
49
|
+
value = value[k]
|
50
|
+
else:
|
51
|
+
return default
|
52
|
+
|
53
|
+
return value
|
54
|
+
|
55
|
+
def set(self, key: str, value: Any) -> bool:
|
56
|
+
"""设置配置项"""
|
57
|
+
keys = key.split('.')
|
58
|
+
config_ref = self.config
|
59
|
+
|
60
|
+
# 遍历到最后一个键之前
|
61
|
+
for k in keys[:-1]:
|
62
|
+
if k not in config_ref or not isinstance(config_ref[k], dict):
|
63
|
+
config_ref[k] = {}
|
64
|
+
config_ref = config_ref[k]
|
65
|
+
|
66
|
+
# 设置最后一个键的值
|
67
|
+
config_ref[keys[-1]] = value
|
68
|
+
return self.save_config()
|
69
|
+
|
70
|
+
def get_user_cookies(self) -> Dict[str, str]:
|
71
|
+
"""获取用户Cookie"""
|
72
|
+
cookies = self.get('user.cookies', {})
|
73
|
+
return {k: v for k, v in cookies.items() if v} # 过滤空值
|
74
|
+
|
75
|
+
def update_user_cookies(self, cookies: Dict[str, str]) -> bool:
|
76
|
+
"""更新用户Cookie"""
|
77
|
+
current_cookies = self.get('user.cookies', {})
|
78
|
+
current_cookies.update(cookies)
|
79
|
+
return self.set('user.cookies', current_cookies)
|
80
|
+
|
81
|
+
def get_download_config(self) -> Dict[str, Any]:
|
82
|
+
"""获取下载配置"""
|
83
|
+
return self.get('download', {})
|
84
|
+
|
85
|
+
def get_ffmpeg_config(self) -> Dict[str, Any]:
|
86
|
+
"""获取ffmpeg配置"""
|
87
|
+
return self.get('ffmpeg', {})
|
88
|
+
|
89
|
+
def get_network_config(self) -> Dict[str, Any]:
|
90
|
+
"""获取网络配置"""
|
91
|
+
return self.get('network', {})
|
92
|
+
|
93
|
+
def create_default_config(self) -> bool:
|
94
|
+
"""创建默认配置文件"""
|
95
|
+
default_config = {
|
96
|
+
"user": {
|
97
|
+
"username": "",
|
98
|
+
"password": "",
|
99
|
+
"cookies": {
|
100
|
+
"SESSDATA": "",
|
101
|
+
"bili_jct": "",
|
102
|
+
"DedeUserID": "",
|
103
|
+
"buvid3": ""
|
104
|
+
},
|
105
|
+
"login_method": "qrcode"
|
106
|
+
},
|
107
|
+
"download": {
|
108
|
+
"output_dir": "downloads",
|
109
|
+
"quality": "auto",
|
110
|
+
"format": "mp4",
|
111
|
+
"threads": 4,
|
112
|
+
"retry_times": 3,
|
113
|
+
"timeout": 30
|
114
|
+
},
|
115
|
+
"ffmpeg": {
|
116
|
+
"path": "auto",
|
117
|
+
"auto_merge": true,
|
118
|
+
"delete_temp_files": true
|
119
|
+
},
|
120
|
+
"network": {
|
121
|
+
"proxy": "",
|
122
|
+
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
|
123
|
+
},
|
124
|
+
"debug": {
|
125
|
+
"enable_logging": false,
|
126
|
+
"log_level": "INFO",
|
127
|
+
"save_response": false
|
128
|
+
}
|
129
|
+
}
|
130
|
+
|
131
|
+
self.config = default_config
|
132
|
+
return self.save_config()
|
133
|
+
|
134
|
+
# 全局配置实例
|
135
|
+
config_manager = ConfigManager()
|
136
|
+
|
137
|
+
def init_config() -> bool:
|
138
|
+
"""初始化配置"""
|
139
|
+
if not os.path.exists(config_manager.config_path):
|
140
|
+
return config_manager.create_default_config()
|
141
|
+
return config_manager.load_config()
|
142
|
+
|
143
|
+
# 配置访问快捷方式
|
144
|
+
def get_config(key: str, default: Any = None) -> Any:
|
145
|
+
return config_manager.get(key, default)
|
146
|
+
|
147
|
+
def set_config(key: str, value: Any) -> bool:
|
148
|
+
return config_manager.set(key, value)
|
149
|
+
|
150
|
+
def get_user_cookies() -> Dict[str, str]:
|
151
|
+
return config_manager.get_user_cookies()
|
152
|
+
|
153
|
+
def update_user_cookies(cookies: Dict[str, str]) -> bool:
|
154
|
+
return config_manager.update_user_cookies(cookies)
|
main.py
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
|
4
|
+
"""
|
5
|
+
B站视频下载器 - 模块化重构版本
|
6
|
+
功能:通过JSON配置控制登录 -> 获取最高清晰度视频 -> 自动合并DASH格式视频
|
7
|
+
"""
|
8
|
+
|
9
|
+
import argparse
|
10
|
+
import logging
|
11
|
+
import sys
|
12
|
+
import os
|
13
|
+
|
14
|
+
# 添加项目根目录到Python路径
|
15
|
+
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
16
|
+
|
17
|
+
from config.config_manager import init_config
|
18
|
+
from utils.common_utils import setup_logging
|
19
|
+
from commands import handle_download_command, handle_login_command, handle_status_command
|
20
|
+
|
21
|
+
def setup_argparse() -> argparse.ArgumentParser:
|
22
|
+
"""设置命令行参数解析"""
|
23
|
+
parser = argparse.ArgumentParser(description='B站视频下载器')
|
24
|
+
subparsers = parser.add_subparsers(dest='command', help='子命令', required=True)
|
25
|
+
|
26
|
+
# download 子命令
|
27
|
+
dl_parser = subparsers.add_parser('download', help='下载视频')
|
28
|
+
dl_parser.add_argument('video_id', help='B站视频BV号或AV号,例如:BV1Ab411C7Q9 或 av123456789')
|
29
|
+
dl_parser.add_argument('--output', '-o', default=None, help='输出目录')
|
30
|
+
dl_parser.add_argument('--quality', '-q', type=int, default=None, help='指定清晰度(可选)')
|
31
|
+
dl_parser.add_argument('--no-merge', action='store_true', help='不自动合并DASH视频')
|
32
|
+
dl_parser.add_argument('--no-login', '--guest', action='store_true',
|
33
|
+
help='忽略登录状态,使用游客模式下载(可能只能下载较低清晰度)')
|
34
|
+
dl_parser.add_argument('--config', '-c', default='config/config.json', help='配置文件路径')
|
35
|
+
dl_parser.add_argument('--debug', '-d', action='store_true', help='启用调试模式')
|
36
|
+
|
37
|
+
# login 子命令
|
38
|
+
login_parser = subparsers.add_parser('login', help='登录B站账号')
|
39
|
+
login_parser.add_argument('--force', '-f', action='store_true', help='强制重新登录')
|
40
|
+
login_parser.add_argument('--config', '-c', default='config/config.json', help='配置文件路径')
|
41
|
+
login_parser.add_argument('--debug', '-d', action='store_true', help='启用调试模式')
|
42
|
+
|
43
|
+
# status 子命令
|
44
|
+
status_parser = subparsers.add_parser('status', help='检查登录状态')
|
45
|
+
status_parser.add_argument('--config', '-c', default='config/config.json', help='配置文件路径')
|
46
|
+
status_parser.add_argument('--debug', '-d', action='store_true', help='启用调试模式')
|
47
|
+
|
48
|
+
return parser
|
49
|
+
|
50
|
+
def initialize_system(config_path: str, debug: bool = False) -> bool:
|
51
|
+
"""初始化系统配置"""
|
52
|
+
try:
|
53
|
+
# 设置日志
|
54
|
+
log_level = "DEBUG" if debug else "INFO"
|
55
|
+
setup_logging(level=log_level)
|
56
|
+
|
57
|
+
# 初始化配置
|
58
|
+
if not init_config():
|
59
|
+
print("配置文件初始化失败")
|
60
|
+
return False
|
61
|
+
|
62
|
+
print("系统初始化完成")
|
63
|
+
return True
|
64
|
+
|
65
|
+
except Exception as e:
|
66
|
+
print(f"系统初始化失败: {e}")
|
67
|
+
return False
|
68
|
+
|
69
|
+
|
70
|
+
def main():
|
71
|
+
"""主函数"""
|
72
|
+
parser = setup_argparse()
|
73
|
+
args = parser.parse_args()
|
74
|
+
|
75
|
+
# 初始化系统
|
76
|
+
if not initialize_system(args.config, args.debug):
|
77
|
+
return 1
|
78
|
+
|
79
|
+
# 处理子命令
|
80
|
+
if args.command == 'download':
|
81
|
+
return handle_download_command(args)
|
82
|
+
elif args.command == 'login':
|
83
|
+
return handle_login_command(args)
|
84
|
+
elif args.command == 'status':
|
85
|
+
return handle_status_command(args)
|
86
|
+
else:
|
87
|
+
parser.print_help()
|
88
|
+
return 1
|
89
|
+
|
90
|
+
if __name__ == "__main__":
|
91
|
+
sys.exit(main())
|