video-podcast
Turn any video URL into a podcast episode. Publishes a valid RSS feed to Cloudflare R2 that can be subscribed to in Apple Podcasts, Overcast, Pocket Casts, and any podcast app.
Supports YouTube, X (Twitter), and the ~1,000 other sites that yt-dlp supports.
First-time Setup
1. Install dependencies
CODEBLOCK0
2. Create a Cloudflare R2 bucket
- 1. Sign up at cloudflare.com (free tier is sufficient)
- Go to R2 Object Storage → Create bucket
- Name it anything — e.g. INLINECODE0
- Enable Public access on the bucket (R2 → bucket → Settings → Public Access → Enable)
- Note the r2.dev public URL shown (e.g.
https://pub-abc123.r2.dev)
3. Create an R2 API token
- 1. R2 → Manage R2 API Tokens → Create token
- Set permissions: Object Read & Write on your bucket
- Note the Access Key ID and Secret Access Key
- Note your Account ID from the dashboard top-right
4. Configure the skill
Run the interactive setup:
CODEBLOCK1
Or add these to ~/.openclaw/.env manually:
CODEBLOCK2
5. Add a cover image (optional but recommended)
Podcast apps display a 1400×1400px JPEG as artwork. Upload one to your bucket:
CODEBLOCK3
The image must be named cover.jpg in the root of your bucket.
Usage
Add a single video
CODEBLOCK4
Sync a YouTube playlist
Add all videos from a playlist that aren't already in the feed:
CODEBLOCK5
The playlist ID is the part after list= in the YouTube URL.
List episodes
CODEBLOCK6
Get the RSS feed URL
CODEBLOCK7
Remove an episode
CODEBLOCK8
How It Works
- 1. yt-dlp fetches the best available audio stream from the source URL — no browser automation, no screen capture.
- ffmpeg converts the audio to MP3 (VBR ~130kbps).
- The MP3 is uploaded to your Cloudflare R2 bucket with a 7-day public cache header.
- INLINECODE5 is rebuilt and uploaded with
no-cache headers so podcast apps always see the latest version. - Your podcast app polls the feed URL periodically and downloads new episodes automatically.
Storage & State
| Location | Purpose |
|---|
| INLINECODE7 | Episode list + processed URL GUIDs (deduplication) |
| R2 INLINECODE8 |
Audio files (public, 7-day cache) |
| R2
feed.xml | Podcast RSS feed (public, no-cache) |
| R2
cover.jpg | Podcast artwork (optional) |
Supported Sources
Any URL that yt-dlp supports, including:
Troubleshooting
ffmpeg not found
CODEBLOCK9
SSL errors with R2
Make sure you're using Python 3.10+ with OpenSSL 3.x. On macOS the system Python (/usr/bin/python3) uses LibreSSL which may not work. Install Python via Homebrew:
CODEBLOCK10
Age-restricted YouTube videos
yt-dlp needs your browser cookies:
yt-dlp --cookies-from-browser chrome "https://youtube.com/watch?v=..."
Then run
add again — yt-dlp caches the cookies.
X/Twitter videos fail
Public tweets work without auth. Private accounts require cookies:
CODEBLOCK12
Episode not appearing in podcast app
Most podcast apps cache the feed for 1–24 hours. Force a refresh in the app, or check the feed directly: python3 video_podcast.py feed
OpenClaw Agent Usage
When used via the OpenClaw agent, trigger phrases include:
- - "Add this to my podcast feed: [URL]"
- "Add this video to my podcast"
- "Sync my podcast from playlist [ID]"
- "What's in my podcast feed?"
- "Remove [URL] from my podcast"
The agent will run the appropriate subcommand and report back the result.
video-podcast
将任何视频URL转换为播客剧集。向Cloudflare R2发布一个有效的RSS订阅源,可在Apple Podcasts、Overcast、Pocket Casts以及任何播客应用中订阅。
支持YouTube、X(Twitter)以及yt-dlp支持的其他约1000个网站。
首次设置
1. 安装依赖
bash
Python包
pip3 install yt-dlp boto3
ffmpeg(音频转换必需)
brew install ffmpeg # macOS
sudo apt install ffmpeg # Linux
2. 创建Cloudflare R2存储桶
- 1. 在cloudflare.com注册(免费版即可)
- 进入R2对象存储 → 创建存储桶
- 任意命名——例如podcast-feed
- 启用存储桶的公共访问(R2 → 存储桶 → 设置 → 公共访问 → 启用)
- 记下显示的r2.dev公共URL(例如https://pub-abc123.r2.dev)
3. 创建R2 API令牌
- 1. R2 → 管理R2 API令牌 → 创建令牌
- 设置权限:对存储桶的对象读写
- 记下访问密钥ID和秘密访问密钥
- 从仪表盘右上角记下您的账户ID
4. 配置技能
运行交互式设置:
bash
python3 /path/to/skills/video-podcast/scripts/video_podcast.py setup
或手动将这些添加到~/.openclaw/.env:
VIDPODR2ACCESSKEY=youraccesskeyid
VIDPODR2SECRET=yoursecretaccess_key
VIDPODR2ENDPOINT=https://.r2.cloudflarestorage.com
VIDPODR2BUCKET=podcast-feed
VIDPODPUBLICBASE=https://pub-.r2.dev
可选
VIDPOD
FEEDTITLE=我的视频播客
VIDPOD
FEEDAUTHOR=您的姓名
5. 添加封面图片(可选但推荐)
播客应用会显示1400×1400像素的JPEG作为封面图。上传一张到您的存储桶:
bash
使用AWS CLI(如果已安装)
aws s3 cp cover.jpg s3://podcast-feed/cover.jpg \
--endpoint-url https://
.r2.cloudflarestorage.com \
--content-type image/jpeg
或通过Cloudflare R2仪表盘——将cover.jpg拖放到存储桶中
图片必须命名为cover.jpg并放在存储桶的根目录。
使用方法
添加单个视频
bash
python3 video_podcast.py add https://www.youtube.com/watch?v=...
python3 video_podcast.py add https://x.com/user/status/123456789
python3 video_podcast.py add https://vimeo.com/...
同步YouTube播放列表
添加播放列表中尚未在订阅源中的所有视频:
bash
python3 video_podcast.py sync-youtube PLxxxxxxxxxxxxxxxx
播放列表ID是YouTube URL中list=后面的部分。
列出剧集
bash
python3 video_podcast.py list
获取RSS订阅源URL
bash
python3 video_podcast.py feed
删除剧集
bash
python3 video_podcast.py remove https://www.youtube.com/watch?v=...
工作原理
- 1. yt-dlp从源URL获取最佳可用音频流——无需浏览器自动化,无需屏幕录制。
- ffmpeg将音频转换为MP3(VBR约130kbps)。
- MP3文件上传到您的Cloudflare R2存储桶,带有7天公共缓存头。
- feed.xml被重建并上传,带有no-cache头,以便播客应用始终看到最新版本。
- 您的播客应用定期轮询订阅源URL并自动下载新剧集。
存储与状态
| 位置 | 用途 |
|---|
| ~/.openclaw/video-podcast-state.json | 剧集列表 + 已处理的URL GUID(去重) |
| R2 <guid>.mp3 |
音频文件(公共,7天缓存) |
| R2 feed.xml | 播客RSS订阅源(公共,无缓存) |
| R2 cover.jpg | 播客封面图(可选) |
支持的来源
任何yt-dlp支持的URL,包括:
- - YouTube — 视频和播放列表
- X(Twitter) — 公开视频推文
- Vimeo、SoundCloud、Twitch片段、Reddit视频
- 完整支持的1000+网站列表
故障排除
ffmpeg not found
bash
brew install ffmpeg # macOS
sudo apt install ffmpeg # Linux
R2的SSL错误
确保您使用的是Python 3.10+和OpenSSL 3.x。在macOS上,系统Python(/usr/bin/python3)使用LibreSSL,可能无法正常工作。通过Homebrew安装Python:
bash
brew install python@3.13
年龄限制的YouTube视频
yt-dlp需要您的浏览器cookies:
bash
yt-dlp --cookies-from-browser chrome https://youtube.com/watch?v=...
然后再次运行add——yt-dlp会缓存cookies。
X/Twitter视频失败
公开推文无需认证即可工作。私人账户需要cookies:
bash
yt-dlp --cookies-from-browser chrome https://x.com/user/status/...
剧集未在播客应用中显示
大多数播客应用会缓存订阅源1-24小时。在应用中强制刷新,或直接检查订阅源:python3 video_podcast.py feed
OpenClaw代理使用
通过OpenClaw代理使用时,触发短语包括:
- - 将此添加到我的播客订阅源:[URL]
- 将此视频添加到我的播客
- 从播放列表[ID]同步我的播客
- 我的播客订阅源里有什么?
- 从我的播客中删除[URL]
代理将运行相应的子命令并报告结果。