bdpan-cli 0.1.0__tar.gz → 0.2.0__tar.gz

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.
Files changed (45) hide show
  1. {bdpan_cli-0.1.0 → bdpan_cli-0.2.0}/PKG-INFO +26 -11
  2. {bdpan_cli-0.1.0 → bdpan_cli-0.2.0}/README.md +25 -10
  3. {bdpan_cli-0.1.0 → bdpan_cli-0.2.0}/pyproject.toml +1 -1
  4. {bdpan_cli-0.1.0 → bdpan_cli-0.2.0}/pyproject.toml.orig +1 -1
  5. {bdpan_cli-0.1.0 → bdpan_cli-0.2.0}/src/bdpan_cli/__init__.py +16 -2
  6. {bdpan_cli-0.1.0 → bdpan_cli-0.2.0}/src/bdpan_cli/_version.py +1 -1
  7. {bdpan_cli-0.1.0 → bdpan_cli-0.2.0}/src/bdpan_cli/auth.py +18 -6
  8. {bdpan_cli-0.1.0 → bdpan_cli-0.2.0}/src/bdpan_cli/cli.py +114 -5
  9. bdpan_cli-0.2.0/src/bdpan_cli/config.py +81 -0
  10. {bdpan_cli-0.1.0 → bdpan_cli-0.2.0}/src/bdpan_cli/mcp_server.py +2 -1
  11. bdpan_cli-0.1.0/src/bdpan_cli/config.py +0 -26
  12. {bdpan_cli-0.1.0 → bdpan_cli-0.2.0}/src/bdpan_cli/_vendor/__init__.py +0 -0
  13. {bdpan_cli-0.1.0 → bdpan_cli-0.2.0}/src/bdpan_cli/_vendor/openapi_client/__init__.py +0 -0
  14. {bdpan_cli-0.1.0 → bdpan_cli-0.2.0}/src/bdpan_cli/_vendor/openapi_client/api/__init__.py +0 -0
  15. {bdpan_cli-0.1.0 → bdpan_cli-0.2.0}/src/bdpan_cli/_vendor/openapi_client/api/auth_api.py +0 -0
  16. {bdpan_cli-0.1.0 → bdpan_cli-0.2.0}/src/bdpan_cli/_vendor/openapi_client/api/fileinfo_api.py +0 -0
  17. {bdpan_cli-0.1.0 → bdpan_cli-0.2.0}/src/bdpan_cli/_vendor/openapi_client/api/filemanager_api.py +0 -0
  18. {bdpan_cli-0.1.0 → bdpan_cli-0.2.0}/src/bdpan_cli/_vendor/openapi_client/api/fileupload_api.py +0 -0
  19. {bdpan_cli-0.1.0 → bdpan_cli-0.2.0}/src/bdpan_cli/_vendor/openapi_client/api/multimediafile_api.py +0 -0
  20. {bdpan_cli-0.1.0 → bdpan_cli-0.2.0}/src/bdpan_cli/_vendor/openapi_client/api/userinfo_api.py +0 -0
  21. {bdpan_cli-0.1.0 → bdpan_cli-0.2.0}/src/bdpan_cli/_vendor/openapi_client/api_client.py +0 -0
  22. {bdpan_cli-0.1.0 → bdpan_cli-0.2.0}/src/bdpan_cli/_vendor/openapi_client/configuration.py +0 -0
  23. {bdpan_cli-0.1.0 → bdpan_cli-0.2.0}/src/bdpan_cli/_vendor/openapi_client/exceptions.py +0 -0
  24. {bdpan_cli-0.1.0 → bdpan_cli-0.2.0}/src/bdpan_cli/_vendor/openapi_client/model/__init__.py +0 -0
  25. {bdpan_cli-0.1.0 → bdpan_cli-0.2.0}/src/bdpan_cli/_vendor/openapi_client/model/oauth_token_authorization_code_response.py +0 -0
  26. {bdpan_cli-0.1.0 → bdpan_cli-0.2.0}/src/bdpan_cli/_vendor/openapi_client/model/oauth_token_device_code_response.py +0 -0
  27. {bdpan_cli-0.1.0 → bdpan_cli-0.2.0}/src/bdpan_cli/_vendor/openapi_client/model/oauth_token_device_token_response.py +0 -0
  28. {bdpan_cli-0.1.0 → bdpan_cli-0.2.0}/src/bdpan_cli/_vendor/openapi_client/model/oauth_token_refresh_token_response.py +0 -0
  29. {bdpan_cli-0.1.0 → bdpan_cli-0.2.0}/src/bdpan_cli/_vendor/openapi_client/model/quotaresponse.py +0 -0
  30. {bdpan_cli-0.1.0 → bdpan_cli-0.2.0}/src/bdpan_cli/_vendor/openapi_client/model/uinforesponse.py +0 -0
  31. {bdpan_cli-0.1.0 → bdpan_cli-0.2.0}/src/bdpan_cli/_vendor/openapi_client/model_utils.py +0 -0
  32. {bdpan_cli-0.1.0 → bdpan_cli-0.2.0}/src/bdpan_cli/_vendor/openapi_client/rest.py +0 -0
  33. {bdpan_cli-0.1.0 → bdpan_cli-0.2.0}/src/bdpan_cli/account.py +0 -0
  34. {bdpan_cli-0.1.0 → bdpan_cli-0.2.0}/src/bdpan_cli/apply_scrape_rename.py +0 -0
  35. {bdpan_cli-0.1.0 → bdpan_cli-0.2.0}/src/bdpan_cli/dedup.py +0 -0
  36. {bdpan_cli-0.1.0 → bdpan_cli-0.2.0}/src/bdpan_cli/downloader.py +0 -0
  37. {bdpan_cli-0.1.0 → bdpan_cli-0.2.0}/src/bdpan_cli/file_manager.py +0 -0
  38. {bdpan_cli-0.1.0 → bdpan_cli-0.2.0}/src/bdpan_cli/foldering.py +0 -0
  39. {bdpan_cli-0.1.0 → bdpan_cli-0.2.0}/src/bdpan_cli/logger.py +0 -0
  40. {bdpan_cli-0.1.0 → bdpan_cli-0.2.0}/src/bdpan_cli/media_info.py +0 -0
  41. {bdpan_cli-0.1.0 → bdpan_cli-0.2.0}/src/bdpan_cli/ops.py +0 -0
  42. {bdpan_cli-0.1.0 → bdpan_cli-0.2.0}/src/bdpan_cli/organize.py +0 -0
  43. {bdpan_cli-0.1.0 → bdpan_cli-0.2.0}/src/bdpan_cli/preview_scrape.py +0 -0
  44. {bdpan_cli-0.1.0 → bdpan_cli-0.2.0}/src/bdpan_cli/scraper.py +0 -0
  45. {bdpan_cli-0.1.0 → bdpan_cli-0.2.0}/src/bdpan_cli/uploader.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: bdpan-cli
3
- Version: 0.1.0
3
+ Version: 0.2.0
4
4
  Summary: 百度网盘工程化 CLI 管理工具
5
5
  Keywords: baidu-pan,netdisk,cli,scraper,backup,cloud-storage
6
6
  Author: CodingRookie98
@@ -57,11 +57,23 @@ pip install bdpan-cli
57
57
 
58
58
  ### 方式 4:跨平台单文件二进制(免 Python 运行时)
59
59
  前往 [GitHub Releases](https://github.com/CodingRookie98/bdpan-cli/releases) 直接下载对应平台单文件二进制可执行包,加入 `PATH` 即可运行:
60
- - `bdpan-linux-amd64`
61
- - `bdpan-linux-arm64`
62
- - `bdpan-macos-arm64` (Apple Silicon)
63
- - `bdpan-macos-x86_64` (Intel)
64
- - `bdpan-windows-amd64.exe`
60
+ - `bdpan-linux-amd64` (Linux x86_64)
61
+ - `bdpan-macos-arm64` (macOS Apple Silicon)
62
+ - `bdpan-windows-amd64.exe` (Windows x86_64)
63
+
64
+ ### 快速开始 (Quickstart)
65
+
66
+ ```bash
67
+ # 1. 配置百度开放平台凭证(仅需一次,保存在 ~/.config/bdpan/.env)
68
+ bdpan auth config --app-key <YOUR_APP_KEY> --secret-key <YOUR_SECRET_KEY>
69
+
70
+ # 2. 授权登录网盘账号(自动唤起默认浏览器打开授权页)
71
+ bdpan auth login
72
+
73
+ # 3. 立即使用
74
+ bdpan whoami
75
+ bdpan ls /
76
+ ```
65
77
 
66
78
  ---
67
79
 
@@ -96,11 +108,14 @@ bdpan ops list [--limit 20] # 查看关键变更操作流水审计
96
108
  bdpan ops show <op_id> # 查看某次操作的明细与映射清单
97
109
  bdpan undo <op_id> [--dry-run] [-y] # 逆向撤销回滚指定批次操作(支持预演)
98
110
 
99
- # 多账号认证与隔离 (Multi-Account Auth)
100
- bdpan auth list # 查看本地保存的网盘账号及凭证有效性
101
- bdpan auth switch <alias> # 切换当前默认活跃账号
102
- bdpan auth login [--account <alias>] # 登录/重新授权指定账号别名
103
- bdpan --account <alias> <subcommand> # 临时以指定账号执行单次命令(多租户并发隔离)
111
+ # 认证配置与多账号管理 (Auth & Multi-Account)
112
+ bdpan auth config --app-key <key> --secret-key <secret> # 快速写入全局开发者凭据 (~/.config/bdpan/.env)
113
+ bdpan auth config --show # 查看当前凭据来源与脱敏信息
114
+ bdpan auth config --path # 打印全局配置文件物理路径
115
+ bdpan auth login [--account <alias>] # 启动设备码授权(自动唤起默认浏览器并高亮授权码)
116
+ bdpan auth list # 查看本地保存的网盘账号及凭证有效性
117
+ bdpan auth switch <alias> # 切换当前默认活跃账号
118
+ bdpan --account <alias> <subcommand> # 临时以指定账号执行单次命令(多租户并发隔离)
104
119
 
105
120
  # 媒体可观测性与全局选项 (Media Insights & Global Options)
106
121
  bdpan info /影视/电影/Inception.mkv # 探测视频精准分辨率(4K/1080P)、时长、HEVC编码与音轨
@@ -29,11 +29,23 @@ pip install bdpan-cli
29
29
 
30
30
  ### 方式 4:跨平台单文件二进制(免 Python 运行时)
31
31
  前往 [GitHub Releases](https://github.com/CodingRookie98/bdpan-cli/releases) 直接下载对应平台单文件二进制可执行包,加入 `PATH` 即可运行:
32
- - `bdpan-linux-amd64`
33
- - `bdpan-linux-arm64`
34
- - `bdpan-macos-arm64` (Apple Silicon)
35
- - `bdpan-macos-x86_64` (Intel)
36
- - `bdpan-windows-amd64.exe`
32
+ - `bdpan-linux-amd64` (Linux x86_64)
33
+ - `bdpan-macos-arm64` (macOS Apple Silicon)
34
+ - `bdpan-windows-amd64.exe` (Windows x86_64)
35
+
36
+ ### 快速开始 (Quickstart)
37
+
38
+ ```bash
39
+ # 1. 配置百度开放平台凭证(仅需一次,保存在 ~/.config/bdpan/.env)
40
+ bdpan auth config --app-key <YOUR_APP_KEY> --secret-key <YOUR_SECRET_KEY>
41
+
42
+ # 2. 授权登录网盘账号(自动唤起默认浏览器打开授权页)
43
+ bdpan auth login
44
+
45
+ # 3. 立即使用
46
+ bdpan whoami
47
+ bdpan ls /
48
+ ```
37
49
 
38
50
  ---
39
51
 
@@ -68,11 +80,14 @@ bdpan ops list [--limit 20] # 查看关键变更操作流水审计
68
80
  bdpan ops show <op_id> # 查看某次操作的明细与映射清单
69
81
  bdpan undo <op_id> [--dry-run] [-y] # 逆向撤销回滚指定批次操作(支持预演)
70
82
 
71
- # 多账号认证与隔离 (Multi-Account Auth)
72
- bdpan auth list # 查看本地保存的网盘账号及凭证有效性
73
- bdpan auth switch <alias> # 切换当前默认活跃账号
74
- bdpan auth login [--account <alias>] # 登录/重新授权指定账号别名
75
- bdpan --account <alias> <subcommand> # 临时以指定账号执行单次命令(多租户并发隔离)
83
+ # 认证配置与多账号管理 (Auth & Multi-Account)
84
+ bdpan auth config --app-key <key> --secret-key <secret> # 快速写入全局开发者凭据 (~/.config/bdpan/.env)
85
+ bdpan auth config --show # 查看当前凭据来源与脱敏信息
86
+ bdpan auth config --path # 打印全局配置文件物理路径
87
+ bdpan auth login [--account <alias>] # 启动设备码授权(自动唤起默认浏览器并高亮授权码)
88
+ bdpan auth list # 查看本地保存的网盘账号及凭证有效性
89
+ bdpan auth switch <alias> # 切换当前默认活跃账号
90
+ bdpan --account <alias> <subcommand> # 临时以指定账号执行单次命令(多租户并发隔离)
76
91
 
77
92
  # 媒体可观测性与全局选项 (Media Insights & Global Options)
78
93
  bdpan info /影视/电影/Inception.mkv # 探测视频精准分辨率(4K/1080P)、时长、HEVC编码与音轨
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "bdpan-cli"
3
- version = "0.1.0"
3
+ version = "0.2.0"
4
4
  description = "百度网盘工程化 CLI 管理工具"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12"
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "bdpan-cli"
3
- version = "0.1.0"
3
+ version = "0.2.0"
4
4
  description = "百度网盘工程化 CLI 管理工具"
5
5
  readme = "README.md"
6
6
  license = { text = "MIT" }
@@ -7,9 +7,23 @@ from bdpan_cli._vendor.openapi_client.api.fileinfo_api import FileinfoApi
7
7
  from bdpan_cli._vendor.openapi_client.rest import ApiException
8
8
 
9
9
  from bdpan_cli.auth import TokenManager
10
- from bdpan_cli.config import load_config
10
+ from bdpan_cli.config import (
11
+ AppConfig,
12
+ ConfigError,
13
+ get_global_config_path,
14
+ load_config,
15
+ save_global_config,
16
+ )
11
17
  from bdpan_cli._version import __version__
12
18
 
13
19
  from bdpan_cli.cli import main
14
20
 
15
- __all__ = ["main", "__version__"]
21
+ __all__ = [
22
+ "main",
23
+ "__version__",
24
+ "AppConfig",
25
+ "ConfigError",
26
+ "load_config",
27
+ "get_global_config_path",
28
+ "save_global_config",
29
+ ]
@@ -1,3 +1,3 @@
1
1
  """Version definition for bdpan-cli."""
2
2
 
3
- __version__ = "0.1.0"
3
+ __version__ = "0.2.0"
@@ -16,7 +16,7 @@ from bdpan_cli._vendor.openapi_client.rest import ApiException
16
16
  from bdpan_cli.config import AppConfig
17
17
 
18
18
  # 默认用户端 Token 凭据路径遵循 XDG 规范 (~/.config/bdpan/tokens.json)
19
- DEFAULT_CONFIG_DIR = Path.home() / ".config" / "bdpan"
19
+ DEFAULT_CONFIG_DIR = Path(os.environ.get("XDG_CONFIG_HOME", Path.home() / ".config")) / "bdpan"
20
20
  DEFAULT_TOKEN_FILE = DEFAULT_CONFIG_DIR / "tokens.json"
21
21
  LEGACY_TOKEN_CACHE = Path(__file__).resolve().parents[2] / ".baidupan_tokens.json"
22
22
 
@@ -193,10 +193,22 @@ class TokenManager:
193
193
  device = auth.oauth_token_device_code(self._config.app_key, SCOPE)
194
194
  interval = max(int(device.interval or 5), 3)
195
195
  deadline = time.time() + int(device.expires_in or 300)
196
- print(
197
- f"请打开 {device.verification_url} ,输入用户码 {device.user_code} 并确认授权",
198
- flush=True,
199
- )
196
+
197
+ # 尝试自动在默认浏览器中打开授权页面
198
+ try:
199
+ import webbrowser
200
+ webbrowser.open(device.verification_url)
201
+ except Exception:
202
+ pass
203
+
204
+ print("\n" + "=" * 66, flush=True)
205
+ print("🔗 请在浏览器中打开授权页面完成登录:", flush=True)
206
+ print(f" {device.verification_url}", flush=True)
207
+ print("\n🔑 您的设备授权码 (User Code):", flush=True)
208
+ print(f" 👉 {device.user_code} 👈", flush=True)
209
+ print("\n(系统已尝试唤起默认浏览器;如未弹出,请手动复制上述链接访问并输入授权码)", flush=True)
210
+ print("=" * 66 + "\n", flush=True)
211
+ print("⏳ 正在等待网页端授权确认...", flush=True)
200
212
  while time.time() < deadline:
201
213
  time.sleep(interval)
202
214
  try:
@@ -213,6 +225,6 @@ class TokenManager:
213
225
  interval += 5
214
226
  continue
215
227
  raise RuntimeError(f"设备码授权失败:{body}") from e
216
- print("授权成功", flush=True)
228
+ print("🎉 授权成功!", flush=True)
217
229
  return self._save_cache(self._to_cache(response))
218
230
  raise AuthorizationNeeded("设备码已过期,请重新运行")
@@ -8,11 +8,17 @@ import logging
8
8
  import os
9
9
  import sys
10
10
  from datetime import datetime
11
+ from pathlib import Path
11
12
  from typing import Any
12
13
 
13
14
  from bdpan_cli.account import AccountClient, AccountError
14
15
  from bdpan_cli.auth import TOKEN_CACHE, TokenManager
15
- from bdpan_cli.config import load_config
16
+ from bdpan_cli.config import (
17
+ ConfigError,
18
+ get_global_config_path,
19
+ load_config,
20
+ save_global_config,
21
+ )
16
22
  from bdpan_cli.dedup import execute_dedup, plan_dedup
17
23
  from bdpan_cli.downloader import DownloadError, Downloader
18
24
  from bdpan_cli.file_manager import FileManager, FileManagerError
@@ -761,6 +767,85 @@ def cmd_undo(args: argparse.Namespace) -> int:
761
767
  def cmd_auth(args: argparse.Namespace) -> int:
762
768
  """网盘账号认证与多租户管理。"""
763
769
  subcmd = getattr(args, "auth_subcmd", None)
770
+
771
+ if subcmd == "config":
772
+ # 1. 打印全局配置文件路径
773
+ if getattr(args, "path", False):
774
+ print(str(get_global_config_path()))
775
+ return 0
776
+
777
+ # 2. 显示当前配置状态(脱敏)
778
+ if getattr(args, "show", False):
779
+ global_path = get_global_config_path()
780
+ local_path = Path.cwd() / ".env"
781
+ has_env = bool(os.getenv("BAIDU_APP_KEY") and os.getenv("BAIDU_SECRET_KEY"))
782
+
783
+ try:
784
+ cfg = load_config()
785
+ app_key = cfg.app_key
786
+ secret_key = cfg.secret_key
787
+ masked_app = app_key[:3] + "..." + app_key[-3:] if len(app_key) > 6 else "***"
788
+ masked_secret = secret_key[:3] + "..." + secret_key[-3:] if len(secret_key) > 6 else "***"
789
+
790
+ source = "环境变量" if has_env else ("当前目录 .env" if local_path.exists() else f"全局配置 ({global_path})")
791
+ if getattr(args, "json", False):
792
+ return _output_envelope({
793
+ "source": source,
794
+ "global_path": str(global_path),
795
+ "app_key": masked_app,
796
+ "secret_key": masked_secret,
797
+ })
798
+ print("\n📋 百度网盘开放平台开发者凭证配置状态:")
799
+ print(f" • 配置来源: {source}")
800
+ print(f" • BAIDU_APP_KEY: {masked_app}")
801
+ print(f" • BAIDU_SECRET_KEY: {masked_secret}")
802
+ print(f" • 全局配置文件位置: {global_path}\n")
803
+ return 0
804
+ except ConfigError as e:
805
+ if getattr(args, "json", False):
806
+ return _output_envelope(None, success=False, code=1, error=str(e))
807
+ print("\n⚠️ 尚未检测到有效开发者凭证配置。", file=sys.stderr)
808
+ print(f" 全局配置文件位置: {global_path}", file=sys.stderr)
809
+ print(" 提示:请运行 'bdpan auth config --app-key <KEY> --secret-key <SECRET>' 写入全局配置。\n", file=sys.stderr)
810
+ return 1
811
+
812
+ # 3. 写入配置
813
+ app_key = getattr(args, "app_key", None)
814
+ secret_key = getattr(args, "secret_key", None)
815
+
816
+ if not app_key or not secret_key:
817
+ if sys.stdin.isatty() and not getattr(args, "json", False):
818
+ print("请输入百度网盘开放平台的开发者凭证(可从 https://pan.baidu.com/union 获取):")
819
+ if not app_key:
820
+ try:
821
+ app_key = input(" BAIDU_APP_KEY: ").strip()
822
+ except (EOFError, KeyboardInterrupt):
823
+ print("\n操作已取消。")
824
+ return 1
825
+ if not secret_key:
826
+ try:
827
+ secret_key = input(" BAIDU_SECRET_KEY: ").strip()
828
+ except (EOFError, KeyboardInterrupt):
829
+ print("\n操作已取消。")
830
+ return 1
831
+
832
+ if not app_key or not secret_key:
833
+ msg = (
834
+ "缺少凭据参数。请提供 --app-key 与 --secret-key,例如:\n"
835
+ " bdpan auth config --app-key YOUR_APP_KEY --secret-key YOUR_SECRET_KEY"
836
+ )
837
+ if getattr(args, "json", False):
838
+ return _output_envelope(None, success=False, code=1, error=msg)
839
+ print(f"❌ {msg}", file=sys.stderr)
840
+ return 1
841
+
842
+ saved_path = save_global_config(app_key, secret_key)
843
+ if getattr(args, "json", False):
844
+ return _output_envelope({"saved_path": str(saved_path)})
845
+ print(f"✅ 开发者凭证已成功保存至全局配置: {saved_path}")
846
+ print("💡 您现在可以在任意目录直接运行 'bdpan auth login' 或其他 bdpan 命令。")
847
+ return 0
848
+
764
849
  tm = _get_token_manager(args)
765
850
 
766
851
  if subcmd == "switch":
@@ -1320,14 +1405,32 @@ def build_parser() -> argparse.ArgumentParser:
1320
1405
  p_auth = subparsers.add_parser(
1321
1406
  "auth",
1322
1407
  help="网盘账号认证与多账号管理",
1323
- description="百度网盘多账号认证管理系统,支持多租户凭证隔离存储、活跃账号切换与单独授权。",
1408
+ description="百度网盘多账号认证管理系统,支持多租户凭证隔离存储、活跃账号切换、快速配置与单独授权。",
1324
1409
  epilog="""示例:
1410
+ bdpan auth config --app-key YOUR_KEY --secret-key YOUR_SECRET
1411
+ bdpan auth config --show
1412
+ bdpan auth login
1325
1413
  bdpan auth list
1326
- bdpan auth switch work_pan
1327
- bdpan auth login --account personal_pan""",
1414
+ bdpan auth switch work_pan""",
1328
1415
  formatter_class=argparse.RawDescriptionHelpFormatter,
1329
1416
  )
1330
1417
  auth_sub = p_auth.add_subparsers(dest="auth_subcmd", help="认证子命令")
1418
+ p_auth_config = auth_sub.add_parser(
1419
+ "config",
1420
+ help="配置或查看百度网盘开发者凭据 (AppKey / SecretKey)",
1421
+ description="配置或查看百度网盘开放平台开发者凭据。凭据将安全保存在用户全局配置目录中 (~/.config/bdpan/.env)。",
1422
+ epilog="""示例:
1423
+ bdpan auth config --app-key YOUR_KEY --secret-key YOUR_SECRET
1424
+ bdpan auth config --show
1425
+ bdpan auth config --path""",
1426
+ formatter_class=argparse.RawDescriptionHelpFormatter,
1427
+ )
1428
+ p_auth_config.add_argument("--app-key", help="百度开放平台 App Key (Client ID)")
1429
+ p_auth_config.add_argument("--secret-key", help="百度开放平台 Secret Key (Client Secret)")
1430
+ p_auth_config.add_argument("--show", action="store_true", help="显示当前配置来源与脱敏凭证")
1431
+ p_auth_config.add_argument("--path", action="store_true", help="输出全局配置文件存储路径")
1432
+ p_auth_config.set_defaults(func=cmd_auth)
1433
+
1331
1434
  p_auth_list = auth_sub.add_parser(
1332
1435
  "list",
1333
1436
  help="列出本地所有网盘账号与到期状态",
@@ -1421,7 +1524,13 @@ def main(argv: list[str] | None = None) -> int:
1421
1524
  parser.print_help()
1422
1525
  return 0
1423
1526
 
1424
- return args.func(args)
1527
+ try:
1528
+ return args.func(args)
1529
+ except ConfigError as e:
1530
+ if getattr(args, "json", False):
1531
+ return _output_envelope(None, success=False, code=1, error=str(e))
1532
+ print(f"\n❌ 配置缺失: {e}\n", file=sys.stderr)
1533
+ return 1
1425
1534
 
1426
1535
 
1427
1536
  if __name__ == "__main__":
@@ -0,0 +1,81 @@
1
+ """应用配置:从环境变量、本地 .env 或 XDG 全局配置读取百度网盘开放平台凭证。"""
2
+
3
+ import os
4
+ from dataclasses import dataclass
5
+ from pathlib import Path
6
+
7
+ from dotenv import load_dotenv
8
+
9
+ # XDG 全局配置目录与文件 (~/.config/bdpan/.env)
10
+ DEFAULT_CONFIG_DIR = Path(os.environ.get("XDG_CONFIG_HOME", Path.home() / ".config")) / "bdpan"
11
+ DEFAULT_CONFIG_FILE = DEFAULT_CONFIG_DIR / ".env"
12
+
13
+
14
+ class ConfigError(RuntimeError):
15
+ """应用配置缺失或无效异常。"""
16
+
17
+
18
+ @dataclass(frozen=True)
19
+ class AppConfig:
20
+ app_key: str
21
+ secret_key: str
22
+
23
+
24
+ def get_global_config_path() -> Path:
25
+ """获取全局 .env 配置文件的实际路径。"""
26
+ custom = os.environ.get("BDPAN_CONFIG_PATH")
27
+ if custom:
28
+ return Path(custom)
29
+ return DEFAULT_CONFIG_FILE
30
+
31
+
32
+ def load_config() -> AppConfig:
33
+ """按优先级检索并加载百度开放平台凭证:
34
+ 1. 进程内既有环境变量 (os.environ)
35
+ 2. 当前工作目录下的 .env 文件
36
+ 3. 全局 XDG 配置文件 (~/.config/bdpan/.env)
37
+
38
+ 若全部未配置,抛出友好的 ConfigError。
39
+ """
40
+ # 1. 尝试从当前目录加载 .env (override=False 保护已存在的环境变量)
41
+ local_env = Path.cwd() / ".env"
42
+ if local_env.is_file():
43
+ load_dotenv(dotenv_path=local_env, override=False)
44
+
45
+ # 2. 尝试从全局 XDG 配置加载 .env (override=False 保护优先由本地 .env 或环境变量指定的值)
46
+ global_env = get_global_config_path()
47
+ if global_env.is_file():
48
+ load_dotenv(dotenv_path=global_env, override=False)
49
+
50
+ values = {
51
+ "BAIDU_APP_KEY": os.getenv("BAIDU_APP_KEY", "").strip(),
52
+ "BAIDU_SECRET_KEY": os.getenv("BAIDU_SECRET_KEY", "").strip(),
53
+ }
54
+ missing = [name for name, value in values.items() if not value]
55
+ if missing:
56
+ raise ConfigError(
57
+ f"缺少必要配置项:{'、'.join(missing)}。\n"
58
+ "请通过以下任一方式配置:\n"
59
+ " 1. 快速配置(推荐):bdpan auth config --app-key <KEY> --secret-key <SECRET>\n"
60
+ f" 2. 全局配置文件:在 {global_env} 中填写\n"
61
+ " 3. 当前目录:在当前工作目录下 .env 中填写\n"
62
+ " 4. 环境变量:export BAIDU_APP_KEY=... BAIDU_SECRET_KEY=..."
63
+ )
64
+ return AppConfig(values["BAIDU_APP_KEY"], values["BAIDU_SECRET_KEY"])
65
+
66
+
67
+ def save_global_config(app_key: str, secret_key: str, path: Path | None = None) -> Path:
68
+ """将 AppKey 和 SecretKey 保存至全局 .env 配置文件(强制权限 0o600)。"""
69
+ target_path = path or get_global_config_path()
70
+ target_path.parent.mkdir(parents=True, exist_ok=True)
71
+ content = (
72
+ f"# 百度网盘开放平台开发者凭证 (XDG 全局配置)\n"
73
+ f"BAIDU_APP_KEY={app_key.strip()}\n"
74
+ f"BAIDU_SECRET_KEY={secret_key.strip()}\n"
75
+ )
76
+ target_path.write_text(content, encoding="utf-8")
77
+ try:
78
+ target_path.chmod(0o600)
79
+ except OSError:
80
+ pass
81
+ return target_path
@@ -12,6 +12,7 @@ import os
12
12
  import sys
13
13
  from typing import Any, Callable
14
14
 
15
+ from bdpan_cli._version import __version__
15
16
  from bdpan_cli.account import AccountClient
16
17
  from bdpan_cli.file_manager import FileManager, FileManagerError
17
18
  from bdpan_cli.media_info import MediaInfoClient, MediaInfoError
@@ -39,7 +40,7 @@ class BdpanMcpServer:
39
40
  self.protocol_version = "2024-11-05"
40
41
  self.server_info = {
41
42
  "name": "bdpan-mcp",
42
- "version": "0.1.0",
43
+ "version": __version__,
43
44
  }
44
45
 
45
46
  def _get_file_manager(self) -> FileManager:
@@ -1,26 +0,0 @@
1
- """应用配置:从 .env 读取百度网盘开放平台凭证。"""
2
-
3
- import os
4
- from dataclasses import dataclass
5
-
6
- from dotenv import load_dotenv
7
-
8
-
9
- @dataclass(frozen=True)
10
- class AppConfig:
11
- app_key: str
12
- secret_key: str
13
-
14
-
15
- def load_config() -> AppConfig:
16
- load_dotenv()
17
- values = {
18
- "BAIDU_APP_KEY": os.getenv("BAIDU_APP_KEY", "").strip(),
19
- "BAIDU_SECRET_KEY": os.getenv("BAIDU_SECRET_KEY", "").strip(),
20
- }
21
- missing = [name for name, value in values.items() if not value]
22
- if missing:
23
- raise RuntimeError(
24
- f"缺少配置项:{'、'.join(missing)},请在 .env 中填写(参考 .env.example)"
25
- )
26
- return AppConfig(values["BAIDU_APP_KEY"], values["BAIDU_SECRET_KEY"])