youtube-to-bookplayer

v2026.09.24

Download YouTube audio and push to BookPlayer on iPhone via USB. TRIGGERS - youtube audio, bookplayer, download youtube

GitHub
安装命令
npx skhub add terrylica/youtube-to-bookplayer
Markdown
SKILL.md

youtube-to-bookplayer

Download audio from a YouTube video, tag metadata, and push to BookPlayer on iPhone via USB.

BookPlayer is an iOS audiobook player that resumes playback position — ideal for long-form YouTube content (lectures, audiobooks, podcasts). Files pushed to its /Documents/ directory are auto-imported on next app launch.


Self-Evolving Skill: This skill improves through use. If instructions are wrong, parameters drifted, or a workaround was needed — fix this file immediately, don't defer. Only update for real, reproducible issues.

Task Template

Execute phases 0–5 sequentially. Each phase has a [Preflight], [Ask], [Execute], or [Verify] tag indicating its nature. Do not skip phases.


Phase 0: Preflight [Preflight]

Check all required tools and device connectivity. Fail fast — do not proceed if any check fails.

# 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)"

If tools are missing:

ToolInstall Command
yt-dlpbrew install yt-dlp
ffmpegbrew install ffmpeg
exiftoolbrew install exiftool
pymobiledevice3uvx --python 3.14 --from pymobiledevice3 pymobiledevice3 --help

Device check (only after tools pass):

# 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"

If no device found: ask user to connect iPhone via USB, unlock it, and tap "Trust This Computer". If BookPlayer not found: ask user to install BookPlayer from the App Store.


Phase 1: Accept URL & Confirm [Ask]

If $ARGUMENTS[0] is provided, use it as the YouTube URL. Otherwise, use AskUserQuestion to ask for the URL.

Preview metadata before proceeding:

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')}\")
"

Use AskUserQuestion to confirm:

  • Title, channel, duration look correct
  • Whether to customize the metadata (title/artist/album) or use defaults from yt-dlp

Phase 2: Download Audio [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

Notes:

  • --audio-quality 0 = best available quality
  • %(title).100B truncates filename to 100 bytes (prevents filesystem issues)
  • --no-playlist ensures single video download even from playlist URLs
  • ffmpeg is auto-invoked by yt-dlp for M4A conversion

Phase 3: Tag Metadata [Execute]

Extract metadata from yt-dlp JSON and apply to the M4A file:

# 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"

Variables (from Phase 1 confirmation):

  • $TITLE — Video title (or user-customized)
  • $ARTIST — Channel name (or user-customized)
  • Album defaults to "YouTube Audio" unless user specifies otherwise

Phase 4: Push to BookPlayer [Execute]

CRITICAL: Use the Python API with documents_only=True. The CLI pymobiledevice3 apps push uses VendContainer mode and will not work with 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

Anti-pattern — DO NOT USE:

# WRONG: This uses VendContainer mode and fails silently on BookPlayer
pymobiledevice3 apps push com.tortugapower.audiobookplayer /path/to/file.m4a

Phase 5: Verify [Verify]

List BookPlayer's /Documents/ directory to confirm the file arrived:

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

Report to user:

  • File name and size in BookPlayer
  • Duration (from Phase 1 metadata)
  • Remind: open BookPlayer on iPhone to see the new file (force-quit and reopen if it doesn't appear)

Cleanup:

# Remove temp working directory
rm -rf "$WORK_DIR"
echo "Cleaned up: $WORK_DIR"

Troubleshooting Quick Reference

ProblemQuick Fix
No device foundUnlock iPhone, re-plug USB, tap "Trust"
File not in BookPlayerYou used the CLI — must use Python API with documents_only=True
Wrong metadata shownRe-run Phase 3 with correct -Title/-Artist values

Full troubleshooting: references/troubleshooting.md


References


Post-Change Checklist

When modifying this skill, verify:

  • Phase 0 preflight catches all missing tools with correct install commands
  • Phase 4 uses Python API with documents_only=True (never CLI apps push)
  • No hardcoded paths — uses $HOME, mktemp, command -v, create_using_usbmux()
  • Python commands use --python 3.14 (per global policy)
  • Anti-pattern warning is preserved in Phase 4

Post-Execution Reflection

After this skill completes, reflect before closing the task:

  1. Locate yourself. — Find this SKILL.md's canonical path (Glob for this skill's name) before editing. All corrections target THIS file and its sibling references/ — never other documentation.
  2. What failed? — Fix the instruction that caused it. If it could recur, add it as an anti-pattern.
  3. What worked better than expected? — Promote it to recommended practice. Document why.
  4. What drifted? — Any script, reference, or external dependency that no longer matches reality gets fixed now.
  5. Log it. — Every change gets an evolution-log entry with trigger, fix, and evidence.

Do NOT defer. The next invocation inherits whatever you leave behind

发现
标签

此技能尚未发布标签。

版本
最新版本元数据

版本

v2026.09.24

发布时间

2026年9月24日

分类

未分类

许可证

MIT

源路径

plugins/media-tools/skills/youtube-to-bookplayer

默认分支

main

最新提交

b657cca

Tree SHA

906e003