Cut long podcast or episode footage into hook-first vertical clips for Shorts, Reels, and TikTok: score moments from the transcript, reframe 16:9 to 9:16, burn word-level captions, and export upload-ready MP4s. Triggers on 'make clips from this episode', 'podcast to shorts', 'cut vertical highlights', 'add karaoke captions to a clip'.
./install.sh podcast-video-clipsname: "podcast_video_clips" description: "Cut long podcast or episode footage into hook-first vertical clips for Shorts, Reels, and TikTok: score moments from the transcript, reframe 16:9 to 9:16, burn word-level captions, and export upload-ready MP4s. Triggers on 'make clips from this episode', 'podcast to shorts', 'cut vertical highlights', 'add karaoke captions to a clip'."
Turn a long video episode into 3-6 standalone vertical clips (21-60s each) that hold the feed: pick the strongest moments from the transcript, reframe 16:9 to 9:16, burn in word-level highlighted captions, and export 1080x1920 MP4s. Every command below is real; the bin/ helpers are tested with py_compile plus an end-to-end ffmpeg run.
If you already have a transcript without timestamps, generate one with word-level timing. faster-whisper on CPU is the practical default:
bash
ffmpeg -hide_banner -y -i episode.mp4 -vn -acodec pcm_s16le -ar 16000 -ac 1 episode.wav
python3 -m faster_whisper episode.wav --language en --word_timestamps True --output_format json --output_dir .
Read the transcript and score candidate segments against references/scoring-rubric.md: hook strength, emotion/energy, quotability, concrete value. Ship only clips that clear the bar and pass the standalone veto. Write the result as a clip plan:
json
[
{"start": 862.5, "end": 905.0, "title": "second-hire-decides-company"},
{"start": 1360.0, "end": 1395.0, "title": "40k-retainer-mistake"}
]
Times are seconds (or HH:MM:SS). Each clip must start on its strongest line and end on a resolved thought.
Clips without burned captions underperform in the feed. Convert word timestamps into karaoke ASS:
bash
python3 bin/words_to_ass.py words.json clip1.ass --chunk-size 3
Current word highlights yellow while the sweep advances; style lives in the script's style args (--font, --fontsize, --margin-v).
Dry-run first (prints exact ffmpeg commands), then run:
bash
python3 bin/clip.py episode.mp4 plan.json --outdir clips --ass clip1.ass
python3 bin/clip.py episode.mp4 plan.json --outdir clips --ass clip1.ass --run
Reframe strategies: --reframe center (default, talking head), --reframe center-offset --x-offset 100 (subject off-center), --reframe blur (blurred-background letterbox, keeps full frame). Full recipe details: references/ffmpeg-recipes.md.
bash
ffprobe -v error -select_streams v:0 -show_entries stream=width,height,duration \
-of csv=p=0 clips/second-hire-decides-company.mp4
Expect 1080,1920,<clip duration>. Watch the first 3 seconds of each clip: the hook line must land immediately. If a clip feels soft, re-score it instead of posting it.
--outdir, named <title>.mp4libx264), AAC 128k, yuv420p, +faststart--ass was givenstart/end comes from the real transcript.libx264); never -c copy for cuts, it lands on keyframes and slips timing.publisher key 2e43c913833850e6d80f939677e3de76e806d47785c0f1caaca90f9d18c98e1e
No ratings yet — be the first to rate it.