mcpField
W
wjs-uploading-video

wjs-uploading-video

github.com/jianshuo创意与媒体137157 次安装今天更新
代码仓库

关于 wjs-uploading-video

wjs-uploading-video 是将完成的 MP4 上传到 YouTube 的技能,适用于单个视频或含多个视频及元数据的目录。它通过 requests 手动执行分块续传,并支持失败重试及跳过已上传文件。

主要功能

  1. 01上传单个视频或批量上传目录
  2. 02从 UPLOAD_META.md 读取视频元数据
  3. 03通过分块请求执行续传
  4. 04对网络错误和服务器错误重试
  5. 05记录结果并跳过已上传视频

适用场景

  1. 01将剪辑完成的视频发布到 YouTube
  2. 02批量上传带有标题和描述的系列视频
  3. 03为视频设置隐私、播放列表或定时发布

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/jianshuo/claude-skills --skill wjs-uploading-video

安装后在 Claude Code 中输入/wjs-uploading-video确认已加载。

附带文件references/credentials-setup.mdscripts/upload_youtube.py

详细介绍

wjs-uploading-video

将已完成的视频上传到 YouTube。默认设置针对该用户的工作流进行了优化(王建硕频道、中国网络环境下使用本地代理、来自 Riverside / 多机位剪辑的 1080p 横屏录制)。

适用场景

  • 用户有一个或多个已完成的 .mp4 文件,并希望上传到 YouTube
  • 用户指定了包含多个片段和 UPLOAD_META.md 的 final/ 目录
  • 用户需要指定隐私设置 / 播放列表 / 定时发布

不适用于:

  • 微信视频号上传(没有公开 API;用户通过网页手动上传)
  • 抖音 / 小红书 / B 站(使用不同的 API,此处尚未实现)
  • 从横屏源制作 YouTube Shorts 版本(先使用 wjs-reframing-video 生成 9:16 版本,再通过此技能上传)

前置条件(每台机器只需设置一次)

  1. Google Cloud OAuth 客户端:必须存在 ~/.config/youtube/credentials.json。如果缺少,请参阅 references/credentials-setup.md,按其中的 5 分钟设置指南操作。
  2. Python 依赖:pip3 install google-auth-oauthlib google-api-python-client requests(上传时严格来说只需要 google-auth + requests,但 OAuth 库会一并安装它们)。
  3. 首次上传会打开浏览器以获取 Google 授权,并写入 ~/.config/youtube/token.json。后续运行会静默复用该令牌。

工作原理(以及为何不用常规的 youtube-uploader)

YouTube 的可续传上传协议会在元数据 POST 后返回一个 Location: URL,随后通过分块 PUT 请求接收数据。常规的 google-api-python-client 会通过 httplib2 执行此操作;在该用户的本地 SOCKS+HTTP 代理环境中,后续 PUT 请求会抛出 [Errno 65] No route to host 或 socket.timeout,并无限期卡住。

此技能绕过 httplib2:通过 google-auth 进行 OAuth,然后使用 requests 手动执行可续传上传,并显式传入代理。分块大小为 8 MB(而非常规的 256 KB),以减少通过代理的往返次数。遇到 socket.timeout / ConnectionError / 5xx 时会采用指数退避重试。

如果你想“直接调用 YouTube API 客户端”,不要这么做——它在此环境中会失败。

ModuleNotFoundError: No module named 'google.oauth2' — Homebrew 升级 Python 大版本后,site-packages 可能会丢失(2026-08 从 3.13→3.14 时实际发生过)。不要重新执行 pip install,直接使用 uvx 携带依赖运行(已验证):

uvx --with google-auth --with requests python \
  ~/.claude/skills/wjs-uploading-video/scripts/upload_youtube.py --dir "/path/to/final"

用法

批量上传 final/ 目录
python3 ~/.claude/skills/wjs-uploading-video/scripts/upload_youtube.py \
  --dir "/path/to/final" \
  --meta "/path/to/final/UPLOAD_META.md"

脚本会:

  1. 读取 UPLOAD_META.md,并将每个 ## NN · filename.mp4 区块与 --dir 中的视频文件配对
  2. 跳过已记录在 --results-file 中的视频(默认值为 <dir>/.youtube_upload_results.json)——失败后可以安全地重新运行
  3. 按顺序上传,每 8 MB 显示一次进度
  4. 将最终 URL 列表写入 --results-file
单个文件
python3 ~/.claude/skills/wjs-uploading-video/scripts/upload_youtube.py \
  --video /path/to/clip.mp4 \
  --title "My Title" \
  --description "Body text" \
  --tags "tag1,tag2,tag3"
常用覆盖选项
标志默认值说明
--privacypublicprivate / unlisted / public
--category2828 = 科技。27 = 教育。24 = 娱乐。
--made-for-kidsfalseYouTube 要求对此进行声明
--playlist <ID>无将每个已上传的视频添加到播放列表
--publish-at <ISO8601>无定时发布(需要 --privacy private)
--credentials~/.config/youtube/credentials.jsonOAuth 客户端 JSON
--token~/.config/youtube/token.json缓存的 OAuth 令牌
--chunk-mb8如果上传过程中持续失败,可使用更小的分块
--dry-run关闭解析元数据并列出待上传内容,不访问网络

UPLOAD_META.md 格式

解析器期望用户使用以下标准结构:

## 01 · segment_01_no-bugs.mp4

**短标题**
代码没有错误,只有意图不一致

**视频描述**
AI 时代屎山的重新定义...

—— 王建硕 × 任鑫《...》第 1 集

#王建硕 #AI编程 #ClaudeCode

---

映射关系:

  • ## NN · <filename> → 此区块描述的视频
  • **短标题**(或 **Title**)区块 → YouTube 标题,原文照录。短标题也可以,但请注意,YouTube 标题最多可包含 100 个字符——如果想加入系列名称,让标题更丰富,请直接写在 **短标题** 中
  • **视频描述**(或 **Description**)区块 → YouTube 描述,原文照录,并保留末尾的 #tag 主题标签
  • 视频描述中的所有 #word 标记 → 以逗号分隔的 YouTube 标签(去掉每个标记开头的 #;按照全局说明,用户的频道名称 王建硕 会自动添加在最前面)

标题中的文件名必须与 --dir 中的实际文件匹配。如果文件存在但没有对应的元数据区块,脚本会报错;传入 --allow-missing-meta,即可使用 --title <basename> 和空描述上传该文件。

此技能采用的合理默认值

  • 隐私 = 公开:视频会立即发布,并显示在订阅者的信息流和搜索结果中。需要先审核时,可在每次调用时通过 --privacy unlisted(仅持链接者可观看)或 --privacy private(仅所有者可观看)覆盖此设置
  • 类别 = 28(科学与技术):符合王建硕频道的主要内容;可在每次上传时通过 --category 覆盖此设置
  • selfDeclaredMadeForKids = false:YouTube 要求设置此项;用户的内容面向成人
  • 分块大小 = 8 MB:经验证,此大小在用户的本地代理下可正常工作(256 KB 会卡住)
  • 跳过已上传文件:结果文件是唯一依据;删除该文件会强制重新上传

频道名称 CTA 规则

如果要在视频元数据中撰写描述页脚、署名或“订阅我的频道”之类的内容,请使用 王建硕(用户的频道名称)。不要在这些位置填写嘉宾姓名——像任鑫这样的嘉宾应出现在描述正文中,作为对话对象,而不是频道 CTA 栏位中的名称。

故障排除

症状解决方法
同意页面出现 access_denied 403在 Google Cloud Console 中,将用户的 Google 账号添加到 OAuth 客户端的测试用户列表
上传过程中出现 [Errno 65] No route to host几乎总是代理问题——验证 curl --max-time 10 https://upload.googleapis.com/upload/youtube/v3/videos 是否返回 4xx(任何 4xx 都表示代理可连接);如果返回 000,则代理已关闭
上传停滞,没有进度行代理正在静默缓冲。降低 --chunk-mb 4,或重启代理守护进程
quotaExceeded(API 单位)YouTube Data API 的默认配额为每天 10,000 个单位,每次上传消耗 1,600 个单位——因此每天约可上传 6 个视频。可在 Google Cloud Console 中申请提高配额,或分几天上传
429 rateLimitExceeded · Video Uploads per day这是与 API 单位配额不同的另一项独立限制——YouTube 每个项目的每日视频上传数量(反滥用限制,与项目验证状态有关;上限可能很低)。达到上限后,该批次中的每次上传都会因 init session failed: 429 而失败,全部无法成功。这不是代理或身份验证问题,也无法绕过。该限制会在美国太平洋时间午夜重置(不是你所在地的午夜)。可选方案:等待 PT 时间重置后重新运行(结果文件已清空,因此会重试全部上传);或通过 YouTube Studio 网页界面上传,此方式不会消耗此 API 限制;也可以验证 GCP 项目以提高上限。同一 PT 日内此前的上传(包括手动 API 上传)也会计入此数量。
令牌刷新失败删除 ~/.config/youtube/token.json 并重新运行;OAuth 浏览器流程会重新启动

上传后

  • 结果保存到 --results-file(JSON:文件、标题、视频 ID、URL)
  • 以 Markdown 表格形式将 URL 列表返回给用户
  • 视频默认设为 public——上传完成后会立即发布。如果用户希望先预留审核时间,请告知他们可以使用 --privacy unlisted 重新上传(或在 YouTube Studio 中改回仅持链接者可观看)
  • 如果用户提到合集或系列,可提出创建 YouTube 播放列表并将新上传的视频批量添加进去(用户必须提供播放列表 ID,或允许你创建一个)

评论

支持 Markdown