Files
nxxy335 f0ecfa6de0 chore: 初始化 123yunpan skill 仓库 (v1.3.0)
- 完整 skill 本体:SKILL.md / README.md / manifest.json / config.json
- scripts/123yunpan.py:零依赖 CLI(含空间双配额、QPS 限流、零依赖 XLSX)
- references/ 参考资料
- 排除 .workbuddy/ 开发目录与 __pycache__
2026-09-27 22:41:43 +08:00

41 KiB
Raw Permalink Blame History

name, description, version, author, license, metadata
name description version author license metadata
123yunpan Use when interacting with 123 Cloud Drive (123云盘) via its open API. Supports file management, upload, download, sharing, offline download, direct links, image hosting, and video transcoding. 1.3.0 暖心向阳335 MIT
hermes
tags related_skills
123yunpan
cloud-drive
file-management
api
storage
bulk-downloading
resource-sharing-platform

123云盘 (123 Cloud Drive) Skill

Agent Quick Start

脚本路径: scripts/123yunpan.py(相对于本 skill 目录) 首次使用: 先跑 config check 确认凭证有效,再操作文件 输出格式: 加 --json 获取单行 JSON,方便解析 文件 ID: 所有操作都基于 file_id(数字),先 file list 或 file search 获取 ID

⚠️ 操作规则:

  1. 删除规则: 用户要求删除文件时,必须先向用户展示文件列表(如"删除文件如下:A.txt、B.zip"),确认后再执行删除操作,删除后提醒"如需找回,请前往回收站恢复"
  2. 下载规则: 下载完成后告知用户保存位置,如"文件已保存到:/path/to/file.pdf"
  3. 分享规则: 分享少于 10 个文件时直接给出链接;超过 10 个时导出 Excel 文件并发送给用户(阈值可用 --excel-threshold 覆盖,或用 --no-excel 关闭自动导出)
  4. 搜索规则: 用户未给出具体云盘位置只给了文件名,搜索到多个匹配结果时,列出文件让用户选择,不要自行决定
  5. 批量规则: 批量操作前先告知用户数量和预计耗时,如"共 150 个文件,预计需要 2 分钟"
  6. 上传规则: 用户未指定目标文件夹时,先列出根目录让用户选择上传位置
  7. 错误规则: 遇到错误时给出解决方案,不要只报错。如"文件不存在"→提示检查 file_id 是否正确;"分享失败"→提示检查文件是否违规
# 1. 验证配置(--json 是全局选项,必须写在子命令之前)
python3 scripts/123yunpan.py --json config check

# 2. 查看根目录
python3 scripts/123yunpan.py --json file list --parent-id 0

# 3. 搜索文件
python3 scripts/123yunpan.py --json file search "关键词" --parent-id 0

# 4. 查看目录树(快速了解结构)
python3 scripts/123yunpan.py file tree --parent-id 0 --max-depth 2

Common Workflows

🔍 "帮我找某个文件"

1. file search "关键词" --parent-id 0 --json    → 获取 file_id
2. file detail --file-id {id} --json              → 确认文件信息
3. file download --file-id {id} -o ./             → 下载
4. 告知用户:文件已保存到:./xxx.pdf

🔗 "把这个文件夹分享出去"

1. file tree --parent-id {folder_id} --max-depth 2  → 确认内容
2. 少于 10 个:share create 逐个创建,直接给出链接
3. 超过 10 个:share create-batch --parent-id {folder_id} --expire 0 -o links.xlsx → 导出 Excel

⬆️ "上传文件到云盘"

1. 用户未指定位置 → file list --parent-id 0 --json → 列出根目录让用户选
2. upload --file /path/to/file --parent-id {folder_id}
3. 告知用户:文件已上传到:{folder_id}/xxx.pdf

⬇️ "批量下载这些文件"

1. file search "关键词" --parent-id {root} --json   → 获取 file_id 列表
2. file download-batch --file-ids "id1,id2,id3" -o ./downloads/  → 批量下载

📊 "看看空间占用情况"

1. space                                        → 专业空间 / 标准空间明细(双配额)
2. file storage-report --parent-id 0 --top 10  → 按文件夹分析+大文件排行

🗑️ "删除文件"

1. file list --parent-id {folder_id} --search "关键词" --json  → 找到 file_id
2. 向用户展示将删除的文件列表,格式:删除文件如下:XXX.txt、XXX.zip
3. file trash --file-ids "{id1},{id2}"                          → 移入回收站
4. 提醒用户:如需找回,请前往回收站恢复

⚠️ 删除操作必须先向用户展示文件列表,确认后再执行!

🔄 "把配置迁移到另一台机器"

# 机器 A:
config export -o config.json

# 机器 B:
config import --file config.json
config check   → 验证导入成功

Overview

This skill provides a complete CLI wrapper for the 123 Cloud Drive Open Platform API. It covers 70+ API endpoints across authentication, file management, upload, download, sharing, offline download, direct links, image hosting, and video transcoding.

Prerequisites

1. Purchase Developer Access Pack

Visit https://www.123pan.com/member and purchase a developer access pack. You will receive client_id and client_secret via in-app message.

2. Configuration

The skill requires three credentials stored in environment variables:

# Required for API authentication
export TWOPAN_CLIENT_ID="your_client_id_here"
export TWOPAN_CLIENT_SECRET="your_client_secret_here"
export TWOPAN_ACCESS_TOKEN="your_access_token_here"

If these are not set when the skill is first used, the CLI will output a clear reminder:

⚠️  123云盘技能需要配置以下环境变量才能使用:
    export TWOPAN_CLIENT_ID="your_client_id"
    export TWOPAN_CLIENT_SECRET="your_client_secret"
    export TWOPAN_ACCESS_TOKEN="your_access_token"

    获取方式:
    1. 访问 https://www.123pan.com/member 购买开发者权益包
    2. 通过 client_id + client_secret 调用 /api/v1/access_token 获取 access_token
    3. 将三个值设置为环境变量

    或运行: 123yunpan.py setup

Run 123yunpan.py setup without arguments for interactive credential entry:

$ python3 scripts/123yunpan.py setup
⚠️  未检测到 client_id
   获取方式:访问 https://www.123pan.com/member 购买开发者权益包
请输入 client_id: █
⚠️  未检测到 client_secret
请输入 client_secret: █
正在获取 access_token...
✅ 配置已保存!

If config already exists (from a previous setup or env vars), it skips prompting and uses the existing values. Non-interactive mode also works: setup --client-id ID --client-secret SECRET.

CLI Usage

# === Global Options ===
# Add --no-color to disable colored output, --json to output raw JSON

# Setup / get token
python3 scripts/123yunpan.py setup --client-id YOUR_ID --client-secret YOUR_SECRET

# Check config status
python3 scripts/123yunpan.py config
python3 scripts/123yunpan.py config check     # 验证 token 有效性
python3 scripts/123yunpan.py config export --output config.json
python3 scripts/123yunpan.py config import --file config.json

# === File Management ===
python3 scripts/123yunpan.py file list --parent-id 0 --limit 100
python3 scripts/123yunpan.py file list --parent-id 0 --trashed        # 只看回收站
python3 scripts/123yunpan.py file list --parent-id 0 --show-trashed   # 含回收站
python3 scripts/123yunpan.py file search "Photoshop" --parent-id 27172609 --max-depth 3
python3 scripts/123yunpan.py file tree --parent-id 0 --max-depth 3
python3 scripts/123yunpan.py file storage-report --parent-id 0 --top 10
python3 scripts/123yunpan.py file detail --file-id 12345
python3 scripts/123yunpan.py file details-multi --file-ids "1,2,3"
python3 scripts/123yunpan.py file list --search "keyword"
python3 scripts/123yunpan.py file mkdir --name "New Folder" --parent-id 0
python3 scripts/123yunpan.py file rename --file-id 12345 --new-name "renamed.txt"
python3 scripts/123yunpan.py file rename-batch --file-ids "1,2,3" --new-names "a.txt,b.txt,c.txt"
python3 scripts/123yunpan.py file move --file-ids "1,2,3" --target-parent-id 0
python3 scripts/123yunpan.py file copy --file-id 12345 --target-parent-id 0
python3 scripts/123yunpan.py file copy-batch --file-ids "1,2,3" --target-parent-id 0
python3 scripts/123yunpan.py file copy-progress --task-id abc123
python3 scripts/123yunpan.py file trash --file-ids "12345"
python3 scripts/123yunpan.py file recover --file-id 12345
python3 scripts/123yunpan.py file recover-by-path --file-id 12345 --target-parent-id 0 --filename "restored.txt"
python3 scripts/123yunpan.py file download --file-id 12345 --output /path/to/save
python3 scripts/123yunpan.py file download-batch --file-ids "1,2,3" --output-dir /path/to/save

# === Upload (V2 Recommended) ===
python3 scripts/123yunpan.py upload --file /path/to/file.txt --parent-id 0

# === Space / User ===
python3 scripts/123yunpan.py space                 # 空间占用报告(专业 + 标准,双配额)
python3 scripts/123yunpan.py --json space           # 机器可读版本
python3 scripts/123yunpan.py user-info

# === Share Management ===
python3 scripts/123yunpan.py share create --name "My Share" --file-ids "1,2,3" --expire 7
# 超过 10 个链接自动生成 Excel(三列:文件名称 / 链接 / 路径)
python3 scripts/123yunpan.py share create-batch --parent-id 27172609 --expire 0 -o result.xlsx
# 覆盖自动导出阈值 / 关闭自动导出 / 断点续跑
python3 scripts/123yunpan.py share create-batch --parent-id 27172609 --excel-threshold 50
python3 scripts/123yunpan.py share create-batch --parent-id 27172609 --no-excel
python3 scripts/123yunpan.py share create-batch --parent-id 27172609 --resume
python3 scripts/123yunpan.py share list --limit 10
python3 scripts/123yunpan.py share list --all-pages
python3 scripts/123yunpan.py share stats --top 10
# 注意:--share-ids / --file-ids 只接受单个值,多个 ID 必须写成一个逗号分隔的字符串
python3 scripts/123yunpan.py share delete-batch --share-ids "1,2,3"
python3 scripts/123yunpan.py share delete-batch --all -y          # 删除全部(跳过确认)
python3 scripts/123yunpan.py share update --share-ids "1,2" --traffic-switch 2
python3 scripts/123yunpan.py share export --output shares.xlsx
python3 scripts/123yunpan.py share export --output shares.json     # 按扩展名自动判断格式
python3 scripts/123yunpan.py share pay-create --name "Paid Share" --file-ids "1,2" --amount 10
python3 scripts/123yunpan.py share pay-list --limit 10
python3 scripts/123yunpan.py share pay-update --share-ids "1" --traffic-switch 1

# === Offline Download ===
python3 scripts/123yunpan.py offline create --url "https://example.com/file.zip" --parent-id 0
python3 scripts/123yunpan.py offline progress --task-id abc123
python3 scripts/123yunpan.py offline list

# === Direct Link ===
python3 scripts/123yunpan.py direct-link enable --file-id 12345
python3 scripts/123yunpan.py direct-link disable --file-id 12345
python3 scripts/123yunpan.py direct-link url --file-id 12345
python3 scripts/123yunpan.py direct-link short-url --file-id 12345  # 短直链(更隐私)
python3 scripts/123yunpan.py direct-link cache-refresh --file-id 12345
python3 scripts/123yunpan.py direct-link ip-list
python3 scripts/123yunpan.py direct-link ip-switch --switch 1
python3 scripts/123yunpan.py direct-link ip-update --ips "1.1.1.1,2.2.2.2"
python3 scripts/123yunpan.py direct-link offline-logs
python3 scripts/123yunpan.py direct-link traffic-logs

# === Image Hosting (OSS) ===
python3 scripts/123yunpan.py oss list --parent-id 0 --limit 100
python3 scripts/123yunpan.py oss detail --file-id 12345
python3 scripts/123yunpan.py oss delete --file-id 12345
python3 scripts/123yunpan.py oss move --file-id 12345 --target-parent-id 0
python3 scripts/123yunpan.py oss copy --file-ids "1,2,3" --target-parent-id 0
python3 scripts/123yunpan.py oss copy-process --task-id abc123
python3 scripts/123yunpan.py oss copy-fail --task-id abc123

# === Video Transcode ===
# 注意:transcode 系列用 --parent-file-id,不是 --parent-id
python3 scripts/123yunpan.py transcode list --parent-file-id 0 --limit 100
python3 scripts/123yunpan.py transcode folder --parent-file-id 0
python3 scripts/123yunpan.py transcode resolutions --file-id 12345
python3 scripts/123yunpan.py transcode transcode --file-id 12345 --resolution 1080p
python3 scripts/123yunpan.py transcode record --file-id 12345
python3 scripts/123yunpan.py transcode result --file-id 12345
python3 scripts/123yunpan.py transcode delete --file-id 12345
python3 scripts/123yunpan.py transcode download --file-id 12345 --output /path/
python3 scripts/123yunpan.py transcode download-m3u8 --file-id 12345 --output /path/
python3 scripts/123yunpan.py transcode download-all --file-id 12345 --output /path/
python3 scripts/123yunpan.py transcode upload-cloud --file-id 12345 --parent-id 0

# === Safebox ===
python3 scripts/123yunpan.py safebox unlock --password "your_password"

# === Cache Management ===
python3 scripts/123yunpan.py cache list           # 列出所有缓存文件
python3 scripts/123yunpan.py cache clear           # 清除全部缓存
python3 scripts/123yunpan.py cache clear --root-id 12345  # 清除指定文件夹的缓存
python3 scripts/123yunpan.py cache info            # 显示缓存目录信息

JSON Output Fields (--json)

加 --json 后所有命令输出单行 JSON,以下是主要命令的字段说明:

file list --json

{"code":0, "data":{"fileList":[
  {"fileId":12345, "filename":"报告.pdf", "size":1048576, "type":0,
   "parentFileID":0, "createAt":"2026-01-01T00:00:00Z", "trashed":0}
], "lastFileId":12345}}
  • type: 0=文件, 1=文件夹
  • trashed: 0=正常, 1=已删除
  • size: 字节数

file detail --json

{"fileId":12345, "filename":"报告.pdf", "size":1048576,
 "md5":"abc123...", "type":0, "parentFileID":0,
 "downloadUrl":"https://...", "createAt":"2026-01-01T00:00:00Z"}

space --json

{"nickname": "暖心向阳335",
 "total_quota": 21474836480, "total_used": 9223372036854775807,
 "professional": {"used": 1.5e10, "quota": 2.0e10, "remain_days": 0,
                  "permanent": true, "used_pct": 75.0},
 "standard":     {"used": 1.2e9,  "quota": 5.0e9,  "remain_days": 0,
                  "permanent": true, "used_pct": 24.0}}
  • professional 满 → 开放平台上传 / 离线下载 / 转码入口被阻断
  • remain_days > 0 表示官方给的清理倒计时,超出后配额不可恢复

user-info --json

{"uid":1812749510, "nickname":"暖心向阳335",
 "spaceUsed":9223372036854775807, "spacePermanent":9223372036854775807,
 "vip":1}
  • spaceUsed/spacePermanent: 字节数,用 human_size() 转换

share create --json

{"code":0, "data":{"shareID":5193007, "shareKey":"JyAKVv-o6bI"},
 "_shareUrl":"https://www.123pan.com/s/JyAKVv-o6bI"}
  • _shareUrl 是 CLI 自动拼接的,不是 API 返回的

share list --json

{"code":0, "data":{"shareList":[
  {"shareId":5193007, "shareName":"分享",
   "shareKey":"JyAKVv-o6bI", "shareExpire":7,
   "previewCount":10, "downloadCount":5, "saveCount":2,
   "createAt":"2026-01-01T00:00:00Z"}
], "lastShareId":5193007}}

upload --json

{"code":0, "data":{"fileID":12345, "completed":true, "reuse":false}}
  • reuse: true=秒传成功(文件已存在)

通用规则

  • 所有 API 返回格式: {"code":0, "message":"ok", "data":{...}}
  • code=0 表示成功,非 0 为错误
  • file list 和 share list 使用 lastFileId/lastShareId 做游标分页
  • 错误时返回: {"code":错误码, "message":"错误描述"}

API Reference Summary

Category Endpoint Method
Cache cache list CLI
Cache cache clear CLI
Cache cache info CLI
Auth /api/v1/access_token POST
Auth (OAuth2) /api/v1/oauth2/access_token POST
File List (v2) /api/v2/file/list GET
File List (v1) /api/v1/file/list GET
File Detail /api/v1/file/detail GET
File Details (multi) /api/v1/file/infos POST
Create Dir /upload/v1/file/mkdir POST
Rename (single) /api/v1/file/name PUT
Rename (batch) /api/v1/file/rename POST
Move /api/v1/file/move POST
Copy (single) /api/v1/file/copy POST
Copy (batch) /api/v1/file/async/copy POST
Copy Progress /api/v1/file/async/copy/process GET
Trash /api/v1/file/trash POST
Recover /api/v1/file/recover POST
Recover (by path) /api/v1/file/recover/by_path POST
Download Info /api/v1/file/download_info GET
Upload V1 /upload/v1/file/create POST
Upload V2 /upload/v2/file/create POST
Upload Slice /upload/v2/file/slice POST
Upload Complete /upload/v2/file/upload_complete POST
Upload Domain /upload/v2/file/domain GET
SHA1 Reuse /upload/v2/file/sha1_reuse POST
Single Upload /upload/v2/file/single/create POST
Share Create /api/v1/share/create POST
Share List /api/v1/share/list GET
Share Delete /api/v1/share/delete POST
Share Update /api/v1/share/list/info PUT
Pay Share Create /api/v1/share/content-payment/create POST
Pay Share List /api/v1/share/payment/list GET
Pay Share Update /api/v1/share/list/payment/info PUT
Offline Download /api/v1/offline/download POST
Offline Progress /api/v1/offline/download/process GET
User Info /api/v1/user/info GET
Direct Link Enable /api/v1/direct-link/enable POST
Direct Link Disable /api/v1/direct-link/disable POST
Direct Link URL /api/v1/direct-link/url GET
Direct Link Cache /api/v1/direct-link/cache/refresh POST
IP Blacklist Switch /api/v1/developer/config/forbide-ip/switch POST
IP Blacklist Update /api/v1/developer/config/forbide-ip/update POST
IP Blacklist List /api/v1/developer/config/forbide-ip/list GET
Direct Link Logs /api/v1/direct-link/offline/logs GET
Direct Link Traffic /api/v1/direct-link/log GET
Image Upload Flow /upload/v1/oss/file/mkdir POST
Image Create Dir /upload/v1/oss/file/mkdir POST
Image Create /upload/v1/oss/file/create POST
Image Upload URL /upload/v1/oss/file/get_upload_url POST
Image Upload Done /upload/v1/oss/file/upload_complete POST
Image Upload Result /upload/v1/oss/file/upload_async_result POST
Image Copy /api/v1/oss/source/copy POST
Image Copy Process /api/v1/oss/source/copy/process GET
Image Copy Fail /api/v1/oss/source/copy/fail GET
Image Move /api/v1/oss/file/move POST
Image Delete /api/v1/oss/file/delete POST
Image Detail /api/v1/oss/file/detail GET
Image List /api/v1/oss/file/list POST
Image Offline /api/v1/oss/offline/download POST
Image Offline Process /api/v1/oss/offline/download/process GET
Video Upload Cloud /api/v1/transcode/upload/from_cloud_disk POST
Video Folder Info /api/v1/transcode/folder/info POST
Video Resolutions /api/v1/transcode/video/resolutions POST
Video Transcode List /api/v1/video/transcode/list GET
Video Transcode /api/v1/transcode/video POST
Video Record /api/v1/transcode/video/record POST
Video Result /api/v1/transcode/video/result POST
Video Delete /api/v1/transcode/delete POST
Video Download /api/v1/transcode/file/download POST
Video M3U8 Download /api/v1/transcode/m3u8_ts/download POST
Video All Download /api/v1/transcode/file/download/all POST
Safebox Unlock /api/v1/safebox/id GET

除了分享链接和完整直链外,还可以生成短直链 — 格式为 https://{user_id}.v.123pan.cn/{user_id}/{file_id},不暴露文件名,更隐私友好。

生成短直链

# CLI 命令
python3 scripts/123yunpan.py direct-link short-url --file-id 12345

# 输出示例
{
  "short_url": "https://1812749510.v.123pan.cn/1812749510/12345",
  "user_id": 1812749510,
  "file_id": 12345
}

手动拼接(Python)

import base64, json

def get_user_id_from_token(token):
    """从 JWT token 解析 user_id,无需额外 API 调用"""
    parts = token.split(".")
    payload = parts[1] + "=" * (4 - len(parts[1]) % 4)
    return json.loads(base64.b64decode(payload)).get("id", 0)

user_id = get_user_id_from_token(access_token)
short_url = f"https://{user_id}.v.123pan.cn/{user_id}/{file_id}"

三种链接格式对比

格式 示例 特点
分享链接 https://www.123pan.com/s/JyAKVv-o6bI 需要登录/跳转,最常用
完整直链 https://xxx.v.123pan.cn/xxx/xxx/filename.zip 直接下载,暴露文件名
短直链 https://1812749510.v.123pan.cn/1812749510/12345 直接下载,不暴露文件名

⚠️ 短直链需要文件已在开启了直链功能的文件夹中,否则无法使用。

Share URL Construction

The share create API returns shareID and shareKey — it does NOT return a full shareUrl. You must construct the URL yourself. The CLI supports two formats via --url-format:

Format CLI 参数 URL 模式 示例
short (默认) --url-format short https://www.123pan.com/s/{shareKey} https://www.123pan.com/s/JyAKVv-o6bI
uid --url-format uid https://{user_id}.share.123pan.cn/123pan/{shareKey} https://666666666.share.123pan.cn/123pan/JyAKVv-o6bI

uid 格式自动从 JWT token 解析 user_id,无需额外 API 调用。解析失败时自动回退到 short。

# 默认 short 格式
python3 scripts/123yunpan.py share create --name "分享" --file-ids 123,456 --expire 7

# UID 格式
python3 scripts/123yunpan.py share create --name "分享" --file-ids 123,456 --url-format uid

# 批量分享也支持
python3 scripts/123yunpan.py share create-batch --parent-id 27172609 --url-format uid -o result.xlsx

Example response from POST /api/v1/share/create:

{
  "code": 0,
  "message": "ok",
  "data": {
    "shareID": 5193007,
    "shareKey": "JyAKVv-o6bI"
  }
}

The skill supports two types of direct links:

Full direct link (contains filename in URL):

https://{user_id}.v.123pan.cn/{user_id}/{file_id}/{filename}

Short direct link (privacy-friendlier, no filename):

https://{user_id}.v.123pan.cn/{user_id}/{file_id}

To generate short direct links, parse user_id from the JWT access token (no extra API call needed):

import base64, json
parts = token.split(".")
payload = parts[1] + "=" * (4 - len(parts[1]) % 4)
user_id = json.loads(base64.b64decode(payload))["id"]
short_link = f"https://{user_id}.v.123pan.cn/{user_id}/{file_id}"

See references/competitor-upload-patterns.md for full upload workflow, SHA1 reuse, and WebDAV patterns.

空间规则:专业空间 / 标准空间(双配额)

根据官方 2026-09-24 公告,账号空间已拆分为两套独立配额,各有各的容量池与剩余天数:

空间类型 存放内容 与开放平台的关系
专业空间 本人持有的文件;≥10GB 文件;直链文件;转码文件;图床文件 任一项超额都会阻断开放平台的上传 / 离线下载 / 转码入口
标准空间 转存(保存)的文件,<10GB;重复文件与回收站文件不计入容量 超额同样阻断上传

用 space 命令查看明细,CLI 会自动做两件事:

  1. 使用率 ≥ 90% → 红色预警,提示随时可能出现写入失败
  2. 专业空间剩余天数 > 0(官方给定的清理倒计时,超出后配额不可恢复)→ 明确打印倒计时天数并标红
python3 scripts/123yunpan.py --json space   # 机器可读:professional / standard / total 三段

config check 与 upload 命令在执行前都会做空间预检,专业空间已满时会直接给出阻断提示,避免上传中途才失败。

⚠️ 排查要点:上传失败、离线下载任务创建失败,先看是专业空间还是标准空间超限 —— 两者是独立的,不能互相顶替。

分享链接 Excel 导出(三列)

share create-batch 在**有效链接数 > 阈值(默认 10)**时会自动生成 Excel 文件,列结构固定为三列:

列名 含义 示例
文件名称 不含分类前缀、不含扩展名的干净文件名 Cinema 4D R20(原 Cinema 4D/Cinema 4D R20.zip)
链接 该文件的分享/直链 URL,单元格为可点击超链接 https://www.123pan.com/s/JyAKVv-o6bI
路径 文件在云盘内的完整相对路径(含文件名与扩展名) 软件/office/离线安装包/2021/ProPlus2021Retail.img

名称解析规则(split_name_and_path()):

  1. 去掉扩展名 → Cinema 4D R20.zip → Cinema 4D R20
  2. 若去掉扩展名后的名字以「父目录名」开头,则补回父目录名避免歧义 → Cinema 4D/Cinema 4D R20.zip → Cinema 4D R20(而不是 R20)

阈值控制:

--excel-threshold N   # 覆盖默认阈值(默认 10)
--no-excel            # 关闭自动导出,超过阈值也只在终端打印链接
--resume              # 断点续跑:读取 ~/.123yunpan_cache/share_batch_{root_id}.json,只处理未完成的文件

✅ 零依赖:xlsx 由 zipfile + 手写 OOXML XML 直接生成,不再需要 openpyxl。任何 Python 3 标准库环境都能出文件,不会出现"静默降级成 JSON"的情况。

限流与重试(QPS 保护)

官方开发须知明确给出各端点 QPS 上限,CLI 内置 QPS_RULES 表自动做节奏控制:

端点 QPS
/api/v2/file/list 1.5(最严格)
/api/v1/user/info 10
/api/v1/access_token 10
/api/v1/share/create 3
其他 默认 1.39(保守兜底)

配套行为:

  • 自动节流:每个端点按自己的 QPS 计算最小请求间隔,超限时 sleep 等待
  • 指数退避重试:HTTP 429 或 5xx → 2^attempt 秒后重试,最多 4 次
  • 401 自动刷新 Token:带 client_id/secret 时自动刷新后重试一次
  • 审核驳回文件过滤:status > 100 的文件无法分享,遍历阶段直接剔除,避免逐个试错

Recursive File Listing

The file list API only returns direct children of a folder. To find all files in a multi-level directory tree, you must traverse recursively. See references/bulk-operations.md for BFS and layered traversal patterns.

Quick pattern — find all files under a root folder:

from collections import deque

def find_all_files(root_id, list_folder_fn):
    queue = deque([(root_id, [])])
    all_files = []
    while queue:
        pid, path = queue.popleft()
        for item in list_folder_fn(pid):
            if item.get("trashed"):
                continue
            if item["type"] == 1:  # folder
                queue.append((item["fileId"], path + [item["filename"]]))
            else:  # file
                all_files.append({
                    "fileId": item["fileId"],
                    "filename": item["filename"],
                    "path": "/".join(path),
                })
    return all_files

⚠️ Deep traversal can involve hundreds of API calls. For 100+ folders, expect 5-10 minutes. Use checkpoint/resume (save progress to JSON every N items) to handle interruptions.

Common Pitfalls

  1. API response format (CRITICAL): The 123yunpan API returns {code: 0, message: "ok", data: {...}} — NOT {result: {...}}. Always parse the data field. Use client._extract(resp) — the CLI script handles both formats.

  2. Token expiry & auto-refresh: access_token expires after a period. The CLI automatically refreshes on 401 responses using client_id/secret. For manual refresh, run setup or call /api/v1/access_token.

  3. File name restrictions: Filenames must be <256 chars and cannot contain: \\\\\\\"/:*?|><

  4. Upload size: Single file upload limit is 10GB via the API.

  5. fileIDList must be a string (CRITICAL): When calling the share create API directly, fileIDList must be a comma-separated string ("123,456"), NOT a JSON array ([123, 456]). Passing an array causes the API to return "文件列表不能为空". The CLI handles this internally via ",".join(str(x) for x in file_ids). Max 100 file IDs per share. shareExpire must be 0, 1, 7, or 30.

  6. Share response has no shareUrl: The share create response only returns shareID + shareKey. You must construct the URL. Use --url-format short (default, https://www.123pan.com/s/{shareKey}) or --url-format uid (https://{user_id}.share.123pan.cn/123pan/{shareKey}). See "Share URL Construction" section above.

  7. Pagination: Use lastFileId/lastShareId for cursor-based pagination. When value is -1, you've reached the last page.

  8. Upload API domain routing (CRITICAL): Upload endpoints are split across two domains:

    • Main API domain (https://open-api.123pan.com): /upload/v2/file/create (chunked create), /upload/v1/file/create (v1 create)
    • Upload domain (https://openapi-upload.123242.com): /upload/v2/file/single/create (single upload), /upload/v2/file/slice (chunked slice), /upload/v2/file/upload_complete (chunked complete)
    • Upload domain is obtained via GET /upload/v2/file/domain — it returns a list ["https://..."], not an object with host field.
  9. Single upload requires multipart/form-data (CRITICAL): The /upload/v2/file/single/create endpoint does NOT accept JSON body. It requires Content-Type: multipart/form-data with fields parentFileID, filename, etag, size as text parts and the file content as a file part. Sending JSON results in a 500 server crash.

  10. duplicate parameter (CRITICAL): The duplicate field in upload create causes "duplicate参数错误" when set to 0 (skip). Do not send duplicate at all (defaults to overwrite), or use 2 (overwrite) or 1 (rename). The value 0 is rejected by the API. The CLI now defaults to not sending this parameter (overwrite behavior).

  11. Trash behavior: The v2 file list includes trashed files — filter by trashed field yourself. trashed: 1 means the file is in trash.

  12. Batch operations rate limit: The CLI now enforces per-endpoint QPS automatically via the built-in QPS_RULES table (see "限流与重试" section) — do NOT add manual time.sleep() on top of it, or you'll halve the throughput. For very long batches (2500+ files) still use checkpoint/resume: --resume reads ~/.123yunpan_cache/share_batch_{root_id}.json and skips already-done files.

  13. Deep directory traversal: Folders can be 4-5 levels deep. Use BFS with a queue for unknown structures, or layered traversal when structure is known. Each level requires a separate API call — 1400+ folders may take 10+ minutes. Use BFS caching (~/.123yunpan_cache/) to avoid repeated traversals — 57s → 0.15s on cache hit. CLI commands file search and share create-batch auto-use cache; add --no-cache to force refresh.

  14. Common error responses:

code message Meaning
code HTTP message
-------- ------ -----------
0 200 ok
1 200 文件列表不能为空
1 200 duplicate参数错误
1 200 分片MD5不能为空
1 200 该目录下文件名重复无法创建
2 200 分享ID非法
10 200 文件名已存在
16 200 文件不存在
20 200 分享文件涉嫌违规,禁止分享
401 401 —
429 429 —
5066 200 —
5113 200 —

CLI 内置 ERROR_HINTS 表,以上错误码会以中文人话 + 处置建议的形式打印,不会只丢一个裸错误码。

  1. 审核驳回文件无法分享 (CRITICAL): Files with status > 100 are rejected by content review and can never be shared. share create-batch filters them out during traversal instead of failing one-by-one. If a file you expect to share silently disappears from the result, check its status field first.

  2. 专业空间 / 标准空间是两套独立配额 (CRITICAL): Per the 2026-09-24 announcement, exceeding either blocks open-platform uploads / offline downloads / transcoding. Standard space does not count duplicate files or trash files. Run space before a large upload to see which pool is actually full.

  3. Excel 导出是三列结构,不是「文件名 + 链接」: Columns are fixed as 文件名称 / 链接 / 路径. The name column strips the folder prefix and extension (Cinema 4D/Cinema 4D R20.zip → Cinema 4D R20), while 路径 keeps the full relative path with filename (软件/office/离线安装包/2021/ProPlus2021Retail.img). Don't re-derive these columns downstream — read them as-is.

  4. Excel 导出零依赖,不要再去装 openpyxl: xlsx is generated by hand via zipfile + OOXML XML (write_xlsx()). There is no import openpyxl anywhere in the script. Previously a missing openpyxl would silently degrade export to JSON — that can no longer happen.

  5. Packaging & versioning: Version must be updated in two places: (1) scripts/123yunpan.py VERSION = "X.Y.Z", (2) SKILL.md frontmatter (version: X.Y.Z), plus (3) manifest.json (version). No zip/unzip CLI — use Python's zipfile module. Package includes SKILL.md + README.md + scripts/ + references/ (no LICENSE per user preference). Exclude __pycache__/. Extraction for patching: python3 -c "import zipfile; zipfile.ZipFile('pkg.zip').extractall('_tmp')". Repackaging: cd _tmp && python3 -c "import zipfile,os; [zipfile.ZipFile('out.zip','w',zipfile.ZIP_DEFLATED).write(f, os.path.relpath(f,'.')) for r,d,fs in os.walk('.') for f in fs if '__pycache__' not in r]".

⚠️ Remember to also update the version in scripts/123yunpan.py VERSION when bumping the version in SKILL.md frontmatter and manifest.json.

  1. Argparse parameter names must match SKILL.md exactly: Before adding/changing argparse arguments, cross-check every --flag in SKILL.md CLI examples. Mismatches (e.g. --name in code vs --new-name in docs) silently break user workflows. Use parse_int_list() (not type=int, nargs="+") for all file-ID arguments to support comma-separated input (--file-ids "1,2,3").
  • ⚠️ --file-ids / --share-ids / --name 只接受一个值。多 ID 必须写成一个带引号的逗号分隔字符串 --file-ids "1,2,3";写成 --file-ids 1 2 3 会报 unrecognized arguments: 2 3,因为 1 2 3 会被当成多余的位置参数。
  • ⚠️ --json / --no-color 是全局选项,必须写在子命令之前(--json config check),写在后面报 unrecognized arguments: --json。
  • ⚠️ transcode 系列用 --parent-file-id,与 file 系列的 --parent-id 不是同一个参数。
  • 可用 .workbuddy/verify_doc_flags.py 一键回归:它对文档里每一条 CLI 示例跑一遍 argparse 解析,找出「文档写了但代码没有」的选择器。
  1. _refresh_token uses imported names, not module paths: The ApiClient methods use Request and urlopen (from from urllib.request import ...), NOT urllib.request.Request. Using the module path will crash with NameError since urllib is not imported as a module.

  2. BFS traversal optional params: bfs_list_files() accepts max_depth, use_cache, max_age — always forward these from callers (e.g. cmd_file_search). Unused parameters silently cause unbounded traversal.

  3. Global options placement: --no-color and --json must appear before the subcommand (e.g., --json file list --parent-id 0), not after. Placing them after the subcommand will cause argparse to ignore them.

  4. file tree vs recursive traversal: file tree is a display-only convenience command that shows directory structure. For bulk operations (downloading, moving, sharing), use recursive BFS traversal or file list with pagination — file tree does not return file IDs suitable for batch operations.

  5. Share name is auto-truncated to 35 chars: Paid shares require names < 35 characters; the CLI truncates automatically to avoid a 400 from the API. Don't pass a name longer than that expecting it round-trip.

  6. share export format is inferred from the file extension: --output shares.xlsx → Excel, --output shares.json → JSON. There is no --format flag on share export (passing it yields unrecognized arguments). Both go through the same zero-dependency write_xlsx() / JSON path.

  7. share pay-update has no --amount: Paid-share updates accept --traffic-switch / --traffic-limit-switch / --traffic-limit only. To change the price, recreate the share (or check the current API doc) rather than trying to patch --amount.

  8. config import safety: Importing config will overwrite your current ~/.123yunpan_config.json. Back up your existing config before importing. The CLI warns before overwriting if the file exists.

See references/bulk-operations.md for batch operation code patterns, BFS traversal, and background execution tips.

Verification Checklist

  • Environment variables TWOPAN_CLIENT_ID, TWOPAN_CLIENT_SECRET, TWOPAN_ACCESS_TOKEN are set
  • Run 123yunpan.py setup to validate credentials and fetch token
  • Test with 123yunpan.py file list --parent-id 0 --limit 5
  • Confirm token refresh works by checking ~/.123yunpan_config.json
  • Run 123yunpan.py space — two quotas (professional / standard) both reported
  • Run 123yunpan.py share create-batch --parent-id {id} with > 10 files → xlsx auto-generated, 3 columns correct
  • Confirm no openpyxl dependency: grep -c "import openpyxl" scripts/123yunpan.py → 0(脚本里只剩一句注释提到它)

Changelog

v1.3.0

  • 适配新空间规则: 新增 space 命令,按官方 2026-09-24 公告拆分为专业空间 / 标准空间双配额展示;使用率 ≥90% 红色预警;专业空间剩余天数倒计时提示;config check 与 upload 增加空间预检
  • 改: 分享链接 Excel 导出阈值 20 → 10(超过 10 个即自动生成 Excel),新增 --excel-threshold 覆盖与 --no-excel 关闭
  • 改: Excel 列结构改为三列 —— 文件名称(去分类前缀、去扩展名)/ 链接(超链接)/ 路径(云盘内完整相对路径)
  • 新增: --resume 断点续跑,读取 ~/.123yunpan_cache/share_batch_{root_id}.json 只处理未完成文件
  • 重写: Excel 写入器改为零依赖(zipfile + 手写 OOXML),彻底移除 openpyxl 依赖,不再有"缺库静默降级 JSON"的问题
  • 重构: API 客户端加入 QPS_RULES 端点级限流(/api/v2/file/list = 1.5 QPS 最严格)+ 429/5xx 指数退避重试(最多 4 次)+ 401 自动刷新 Token 重试一次
  • 新增: ERROR_HINTS 中文错误码映射(401 / 429 / 5066 / 5113 / 20 等),失败时给出原因与处置建议
  • 修复: 分享名称超 35 字符导致 API 400 → 主动截断;status > 100(审核驳回)文件在遍历阶段过滤,不再逐个试错

v1.2.0 (2026-05-09)

  • 新增: --no-color 和 --json 全局选项,支持禁用彩色输出和 JSON 格式输出
  • 新增: file tree 命令 — 目录树展示,支持 --parent-id 和 --max-depth 参数
  • 新增: file download-batch 命令 — 批量下载文件,支持 --file-ids 和 --output-dir 参数
  • 新增: file storage-report 命令 — 存储分析,支持 --parent-id 和 --top 参数
  • 新增: offline list 命令 — 列出离线下载任务(占位,待完善)
  • 新增: share export 命令 — 导出分享记录到 Excel/JSON,支持 --output 和 --format 参数
  • 新增: config export 命令 — 导出配置到 JSON,支持 --output 参数
  • 新增: config import 命令 — 从 JSON 导入配置,支持 --file 参数

v1.1.5 (2026-05-09)

  • 修复: upload 命令的 --duplicate 参数默认值从 0(跳过)改为不发送(默认覆盖),避免API报错
  • 修复: _refresh_token 方法使用了未导入的 urllib.request 模块,导致自动刷新Token时崩溃
  • 修复: file search --max-depth 参数未实际生效,BFS遍历无深度限制
  • 修复: 代码参数名与文档不一致(--new-name、--target-parent-id、--ips),统一到文档标准
  • 优化: 所有 --file-ids/--share-ids 参数同时支持逗号分隔和空格分隔格式(如 1,2,3 或 1 2 3)
  • 新增: cache list 命令 - 列出所有BFS缓存文件
  • 新增: cache clear 命令 - 清除缓存(支持指定文件夹或全部清除)
  • 新增: cache info 命令 - 显示缓存目录信息
  • 优化: 批量操作进度显示增加ETA(预计剩余时间)估算
  • 优化: 清理重复的import语句

v1.1.4

  • 初始版本,支持70+ API端点