关于 youtube-to-bookplayer
youtube-to-bookplayer 是一项将 YouTube 音频下载并添加元数据,再通过 USB 传到 iPhone 上 BookPlayer 的技能。分阶段流程会检查设备,并验证文件是否传输到位。
主要功能
- 01将 YouTube 音频下载为 M4A
- 02编辑音频元数据
- 03通过 USB 传输到 BookPlayer
- 04检查设备和应用是否可用
- 05验证传输后的文件
适用场景
- 01在 BookPlayer 中收听 YouTube 讲座
- 02将长篇 YouTube 音频传到 iPhone
- 03用标题和艺人元数据整理下载的音频
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ terrylica/ cc-skills --skill youtube-to-bookplayer安装后在 Claude Code 中输入/youtube-to-bookplayer确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/evolution-log.mdtool-reference.mdtroubleshooting.md详细介绍
youtube-to-bookplayer
从 YouTube 视频下载音频、标记元数据,并通过 USB 推送到 iPhone 上的 BookPlayer。
BookPlayer 是一款 iOS 有声书播放器,可记住播放位置,适合收听较长的 YouTube 内容(讲座、有声书、播客)。推送到其 /Documents/ 目录的文件会在下次启动应用时自动导入。
自我迭代技能:此技能会在使用过程中不断改进。如果说明有误、参数发生偏移,或需要采用变通方法,请立即修复此文件,不要拖延。仅针对真实且可复现的问题进行更新。
任务模板
按顺序执行阶段 0–5。每个阶段都有 [Preflight]、[Ask]、[Execute] 或 [Verify] 标签,标明其性质。不要跳过阶段。
阶段 0:预检 [Preflight]
检查所有必需工具和设备连接。快速失败——如果任何检查失败,请勿继续。
# Tool availability
TOOLS_OK=true
for tool in yt-dlp ffmpeg exiftool; do
if command -v "$tool" &>/dev/null; then
echo "$tool: OK ($(command -v "$tool"))"
else
echo "$tool: MISSING"
TOOLS_OK=false
fi
done
# pymobiledevice3 (may only be available via uvx)
if command -v pymobiledevice3 &>/dev/null; then
echo "pymobiledevice3: OK ($(command -v pymobiledevice3))"
else
if uvx --python 3.14 --from pymobiledevice3 pymobiledevice3 --help &>/dev/null 2>&1; then
echo "pymobiledevice3: OK (via uvx)"
else
echo "pymobiledevice3: MISSING"
TOOLS_OK=false
fi
fi
echo "---"
[ "$TOOLS_OK" = true ] && echo "All tools OK" || echo "BLOCKED: Install missing tools (see table below)"
如果缺少工具:
| 工具 | 安装命令 |
|---|---|
yt-dlp | brew install yt-dlp |
ffmpeg | brew install ffmpeg |
exiftool | brew install exiftool |
pymobiledevice3 | uvx --python 3.14 --from pymobiledevice3 pymobiledevice3 --help |
设备检查(仅在工具检查通过后进行):
# Check for connected iOS device
pymobiledevice3 usbmux list 2>/dev/null || uvx --python 3.14 --from pymobiledevice3 pymobiledevice3 usbmux list
# Check BookPlayer is installed
pymobiledevice3 apps list --no-color 2>/dev/null | grep -i "audiobookplayer\|bookplayer" || \
uvx --python 3.14 --from pymobiledevice3 pymobiledevice3 apps list --no-color 2>/dev/null | grep -i "audiobookplayer\|bookplayer"
如果未找到设备:请用户通过 USB 连接 iPhone、解锁设备并轻点“信任此电脑”。 如果未找到 BookPlayer:请用户从 App Store 安装 BookPlayer。
阶段 1:接收 URL 并确认 [Ask]
如果提供了 $ARGUMENTS[0],将其用作 YouTube URL。否则,使用 AskUserQuestion 询问 URL。
继续之前预览元数据:
yt-dlp --dump-json --no-download "$URL" 2>/dev/null | python3 -c "
import json, sys
d = json.load(sys.stdin)
hrs, rem = divmod(int(d.get('duration', 0)), 3600)
mins, secs = divmod(rem, 60)
print(f\"Title: {d.get('title', 'Unknown')}\")
print(f\"Channel: {d.get('channel', 'Unknown')}\")
print(f\"Duration: {hrs}h {mins}m {secs}s\")
print(f\"Upload: {d.get('upload_date', 'Unknown')}\")
"
使用 AskUserQuestion 确认:
- 标题、频道和时长是否正确
- 是否要自定义元数据(标题/艺术家/专辑),还是使用 yt-dlp 提供的默认值
阶段 2:下载音频 [Execute]
WORK_DIR=$(mktemp -d)
echo "Working directory: $WORK_DIR"
yt-dlp -x --audio-format m4a --audio-quality 0 --no-playlist \
-o "$WORK_DIR/%(title).100B.%(ext)s" \
"$URL"
# Show result
ls -lh "$WORK_DIR"/*.m4a
说明:
--audio-quality 0= 可用的最佳质量%(title).100B将文件名截断为 100 字节(避免文件系统问题)--no-playlist确保即使 URL 指向播放列表,也只下载单个视频- yt-dlp 会自动调用 ffmpeg 转换为 M4A
阶段 3:标记元数据 [Execute]
从 yt-dlp JSON 中提取元数据,并应用到 M4A 文件:
# Get the downloaded file path
M4A_FILE=$(ls "$WORK_DIR"/*.m4a | head -1)
# Apply metadata (use values confirmed in Phase 1, or yt-dlp defaults)
exiftool -overwrite_original \
-Title="$TITLE" \
-Artist="$ARTIST" \
-Album="YouTube Audio" \
"$M4A_FILE"
# Verify tags
exiftool -Title -Artist -Album "$M4A_FILE"
变量(来自阶段 1 的确认):
$TITLE— 视频标题(或用户自定义的标题)$ARTIST— 频道名称(或用户自定义的名称)- 专辑默认为“YouTube Audio”,除非用户另有指定
阶段 4:推送到 BookPlayer [Execute]
重要:使用 Python API,并设置
documents_only=True。CLIpymobiledevice3 apps push使用 VendContainer 模式,无法用于 BookPlayer。
M4A_FILE=$(ls "$WORK_DIR"/*.m4a | head -1)
FILENAME=$(basename "$M4A_FILE")
uvx --python 3.14 --from pymobiledevice3 python3 << 'PYEOF'
import sys
from pathlib import Path
from pymobiledevice3.lockdown import create_using_usbmux
from pymobiledevice3.services.house_arrest import HouseArrestService
local_path = sys.argv[1] if len(sys.argv) > 1 else None
if not local_path:
# Find the m4a file from environment
import glob, os
work_dir = os.environ.get("WORK_DIR", "/tmp")
files = glob.glob(os.path.join(work_dir, "*.m4a"))
if not files:
print("ERROR: No .m4a file found in work directory")
sys.exit(1)
local_path = files[0]
file_path = Path(local_path)
filename = file_path.name
file_data = file_path.read_bytes()
size_mb = len(file_data) / (1024 * 1024)
print(f"Pushing: {filename} ({size_mb:.1f} MB)")
lockdown = create_using_usbmux()
service = HouseArrestService(
lockdown=lockdown,
bundle_id="com.tortugapower.audiobookplayer",
documents_only=True # CRITICAL: VendDocuments mode
)
service.set_file_contents(f"/Documents/{filename}", file_data)
print(f"SUCCESS: {filename} pushed to BookPlayer /Documents/")
PYEOF
反面示例——不要使用:
# WRONG: This uses VendContainer mode and fails silently on BookPlayer
pymobiledevice3 apps push com.tortugapower.audiobookplayer /path/to/file.m4a
阶段 5:验证 [Verify]
列出 BookPlayer 的 /Documents/ 目录,确认文件已传入:
uvx --python 3.14 --from pymobiledevice3 python3 << 'PYEOF'
from pymobiledevice3.lockdown import create_using_usbmux
from pymobiledevice3.services.house_arrest import HouseArrestService
lockdown = create_using_usbmux()
service = HouseArrestService(
lockdown=lockdown,
bundle_id="com.tortugapower.audiobookplayer",
documents_only=True
)
files = service.listdir("/Documents/")
print("BookPlayer /Documents/ contents:")
for f in sorted(files):
if f.startswith('.'):
continue
try:
info = service.stat(f"/Documents/{f}")
size_mb = info.get('st_size', 0) / (1024 * 1024)
print(f" {f} ({size_mb:.1f} MB)")
except Exception:
print(f" {f}")
PYEOF
向用户报告:
- BookPlayer 中的文件名和大小
- 时长(来自阶段 1 的元数据)
- 提醒用户:在 iPhone 上打开 BookPlayer 查看新文件(如果文件未显示,请强制退出并重新打开应用)
清理:
# Remove temp working directory
rm -rf "$WORK_DIR"
echo "Cleaned up: $WORK_DIR"
故障排除速查
| 问题 | 快速修复 |
|---|---|
| 未找到设备 | 解锁 iPhone,重新插拔 USB,轻点“信任” |
| 文件未显示在 BookPlayer 中 | 你使用了 CLI——必须使用设置了 documents_only=True 的 Python API |
| 显示的元数据有误 | 使用正确的 -Title/-Artist 值重新运行阶段 3 |
完整故障排除说明:references/troubleshooting.md
参考资料
变更后检查清单
修改此技能时,请确认:
- Phase 0 预检能识别所有缺失的工具,并提供正确的安装命令
- Phase 4 使用 Python API,并设置
documents_only=True(绝不使用 CLIapps push) - 不包含硬编码路径——使用
$HOME、mktemp、command -v、create_using_usbmux() - Python 命令使用
--python 3.14(遵循全局策略) - Phase 4 保留了反模式警告
执行后复盘
此技能运行完毕后,请在结束任务前进行复盘:
- 确认文件位置。 — 编辑前,通过 Glob 搜索此技能的名称,找到此 SKILL.md 的规范路径。所有修正都针对此文件及其同级的 references/——绝不修改其他文档。
- 出了什么问题? — 修复导致问题的指令。如果问题可能再次发生,将其列为反模式。
- 哪些做法比预期更有效? — 将其提升为推荐实践,并说明原因。
- 哪些内容已发生偏差? — 任何与实际情况不再一致的脚本、参考资料或外部依赖,都应立即修正。
- 记录下来。 — 每项变更都要在演进日志中记录触发原因、修复内容和证据。