Extract the best short clips from podcast episodes automatically.
- uv (
brew install uvon macOS,curl -LsSf https://astral.sh/uv/install.sh | shon Linux) - FFmpeg (
brew install ffmpegon macOS,apt install ffmpegon Linux) - An API key for your LLM provider (Anthropic or OpenAI)
# Clone the repo
git clone <repo-url> && cd clip-creator
# Install dependencies (creates .venv, installs Python 3.11 if needed)
uv syncSet your API key as an environment variable (or in a .env file):
export ANTHROPIC_API_KEY=sk-...
# or
export OPENAI_API_KEY=sk-...Go from video to clips in one command:
# Produces clips in ./clips and prints JSON output
uv run clip-creator run video.mp4 --output-dir ./clips
# Debug mode — also saves transcript and segments JSON files next to the video
uv run clip-creator run video.mp4 --output-dir ./clips --debug
# Override LLM or Whisper settings
uv run clip-creator run video.mp4 --llm-provider openai --whisper-model large-v3This extracts audio from the video, transcribes it with Whisper, detects jingle boundaries, picks the best moments via LLM, and cuts the clips with FFmpeg.
You can also run each step separately:
uv run clip-creator extract video.mp4uv run clip-creator detect-intro episode.mp3uv run clip-creator transcribe episode.mp3
# Use Fireflies instead of local Whisper
uv run clip-creator transcribe episode.mp3 --whisper-mode fireflies --audio-url https://example.com/episode.mp3# From a transcript JSON file
uv run clip-creator select transcript.json
# Use OpenAI instead of Anthropic
uv run clip-creator select transcript.json --llm-provider openaiThe transcript is split into ~10-minute windows, and the LLM picks the best candidate from each window. A final pass selects the top 3 across all windows. This avoids hallucination from sending the full transcript in a single prompt.
uv run clip-creator cut video.mp4 --segments segments.json --output-dir ./clipsThe --segments flag accepts either the full JSON output from select or a bare list of segments.
A separate, self-contained flow turns the channel's latest livestream into
vertical clips for social media. It is designed to run as a daily scheduled
agent — the agent reads the transcript and chooses the moments (its own
judgment); the scripts do the mechanical download and cutting. Full procedure
and selection criteria are in scripts/DAILY_RUNBOOK.md.
uv run python scripts/fetch_episode.py --output-dir clipsFinds the most recent livestream on @elclubdelastresdelatarde, skips it if
already processed, downloads the 720p VOD plus YouTube auto-subs, and writes a
readable clips/<id>/transcript.txt. Prints a JSON summary.
uv run python scripts/make_clips.py \
--vod clips/<id>/vod.mp4 \
--segments clips/<id>/segments.json \
--output-dir clips/<id>/verticalsegments.json is a list of {"name": "...", "start": "HH:MM:SS", "end": "HH:MM:SS"}.
For each segment the script snaps the boundaries to nearby silences (clean cuts,
never mid-word), center-crops to vertical 9:16 (1080x1920), and removes internal
silences (jump cuts) for a social-media pace. No subtitles.
Requires ffmpeg on the system; yt-dlp is installed as a dependency.
Generated clips land in clips/<id>/vertical/. Sending to WhatsApp is done on
demand via the WhatsApp desktop app (assisted), not automatically — see the
runbook.
Pulls per-video metrics (views, retention, watch time, subscribers, revenue)
from the YouTube Analytics API, split by type (live / clip / short). Needs a
one-time OAuth setup. The tool, the setup steps, and the data-driven learnings
(where the money is, which titles work, retention vs. views) are documented in
docs/youtube-analytics.md.
Settings are loaded in this order (later overrides earlier):
- Pydantic defaults
config.yaml- Environment variables (API keys only)
- CLI flags
See config.yaml for available options.