Metadata-Version: 2.4
Name: bdds
Version: 0.2.0
Summary: Baidu Disk SDK - 百度网盘 Python SDK
Author: hochenggang
License-Expression: MIT
Project-URL: Homepage, https://github.com/hochenggang/bdds
Project-URL: Repository, https://github.com/hochenggang/bdds
Project-URL: Bug Tracker, https://github.com/hochenggang/bdds/issues
Keywords: baidu,pan,netdisk,sdk,baidupan,baidu-disk
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Typing :: Typed
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: requests>=2.20
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: pytest-mock>=3.0; extra == "dev"
Requires-Dist: responses>=0.23; extra == "dev"
Requires-Dist: build>=1.0; extra == "dev"
Requires-Dist: twine>=4.0; extra == "dev"
Dynamic: license-file

# bdds

Baidu Disk SDK - 简单、有效、报错清晰的百度网盘 Python SDK。

基于 [百度网盘开放平台 API](https://pan.baidu.com/union/doc/) 封装，核心依赖仅 `requests`。

## 安装

```bash
pip install bdds
```

## 快速开始

### 1. 获取应用凭证

在 [百度网盘开放平台](https://pan.baidu.com/union/doc/) 创建应用，获取 `client_id`、`client_secret` 和 `app_name`。

### 2. 初始化客户端

```python
from pathlib import Path
from bdds import BaiduPanClient

with BaiduPanClient(
    client_id="your_client_id",
    client_secret="your_client_secret",
    app_name="your_app_name",
) as client:
    if not client.is_authenticated:
        print(f"请在浏览器打开: {client.auth_url}")
        code = input("请输入授权码: ")
        client.fetch_token(code)
```

Token 会自动保存到 `~/.baidupan/` 目录，下次启动无需重新授权。

### 3. 使用 API

```python
# 查询空间配额
q = client.quota()
print(f"已用: {q.used / 1024**3:.1f} GB / 总计: {q.total / 1024**3:.1f} GB")

# 上传文件 - 支持 Path / bytes / Generator
result = client.upload(Path("local_file.txt"))
result = client.upload(Path("data.bin"), remote_path="/backup/data.bin")
result = client.upload(b"hello world", remote_path="/hello.txt")

# 获取文件元信息
metas = client.file_metas([result.fs_id])
dlink = metas[0].dlink

# 下载文件到本地路径
client.download_to_file(dlink, Path("downloaded.txt"))

# 流式下载（适合大文件或自定义处理）
for chunk in client.download_stream(dlink):
    process(chunk)

# 带断点续传的流式下载
for chunk in client.download_stream_with_range(dlink, range=(1024, None)):
    process(chunk)

# 列出文件
items = client.list_files("/apps/your_app_name/")
for item in items:
    print(f"{'[DIR]' if item.is_dir else '     '} {item.filename} ({item.size} bytes)")

# 删除文件
client.delete(["/apps/your_app_name/old_file.txt"])
```

## API 参考

### BaiduPanClient

| 方法 | 说明 |
|------|------|
| `upload(source, remote_path="")` | 上传数据。`source` 支持 `Path` / `bytes` / `Generator[bytes]`；`remote_path` 为远程路径字符串 |
| `download_to_file(dlink, local_path, *, chunk_size=1048576)` | 下载文件到本地路径，返回 `Path` |
| `download_stream(dlink, *, chunk_size=1048576)` | 流式下载，返回 `Generator[bytes]` |
| `download_stream_with_range(dlink, range, *, chunk_size=1048576, max_retries=5)` | 带断点续传的流式下载，`range` 为 `(start, end)` 元组 |
| `quota()` | 获取空间配额，返回 `ApiQuotaInfo` |
| `file_metas(fsids)` | 获取文件元信息（含 dlink），返回 `list[ApiFileMeta]` |
| `list_files(path="/")` | 列出目录文件，返回 `list[ApiFileListItem]` |
| `delete(paths)` | 批量删除文件 |
| `fetch_token(code)` | 通过授权码获取 Token |
| `refresh_token()` | 刷新 Token |
| `is_authenticated` | 是否已认证（属性） |
| `close()` | 关闭客户端 |

### 异常体系

```
BaiduPanError
├── BaiduPanNetworkError    # 网络通信异常
├── BaiduPanAPIError        # API 业务异常 (errno, errmsg, request_id)
└── TokenExpiredError       # Token 过期或无效
```

所有异常均继承自 `BaiduPanError`，方便统一捕获。

### 特性

- **自动重试** — 网络请求自动重试（可配置次数），支持指数退避
- **Token 管理** — 自动持久化、自动刷新、文件权限限制
- **分片上传** — 大文件自动分片上传（4MB 分片）
- **流式下载** — 支持断点续传、Range 分片、指数重试
- **类型安全** — 完整类型标注，支持 PEP 561 (`py.typed`)
- **报错清晰** — 异常包含 `errno`、`errmsg`、`request_id`、`url` 等上下文

## 开发

```bash
# 安装开发依赖
pip install -e ".[dev]"

# 运行测试
python -m pytest -v

# 构建
pip install build twine
python -m build
```

## License

MIT
