Skip to main content

PodClipper

Give it a podcast. Get vertical reels with captions.

PodClipper transcribes your video, picks and reviews useful moments, follows the speakers in a 9:16 crop, and exports captioned MP4s. One command runs the whole podcast-to-reels flow.

podclipper "podcast.mp4"

Video and audio processing run locally. One configured LLM endpoint handles clip selection, title review, caption correction, and content scoring.

Watch the demo

Get started

1. Install

Apple Silicon Mac, macOS 14 or newer: one command installs PodClipper, Python 3.12, and FFmpeg:

brew install loukiknaik/tap/podclipper

Upgrade with brew update && brew upgrade podclipper.

Other platforms or an existing Python environment: use Python 3.10–3.12 and install FFmpeg (which includes ffprobe):

# macOS
brew install ffmpeg
# Ubuntu / Debian
sudo apt install ffmpeg

Inside an activated virtual environment, install the published package:

pip install podclipper

Alternatively, pipx manages the virtual environment for you. For example, on macOS:

brew install ffmpeg pipx python@3.12
pipx ensurepath
pipx install --python python3.12 podclipper

Reopen your terminal if pipx ensurepath asks you to. Upgrade later with pipx upgrade podclipper.

Developing locally? Install from source
git clone https://github.com/LoukikNaik/PodClipper.git
cd PodClipper
python3 -m venv .venv
source .venv/bin/activate
pip install -e .

2. Set your API key once

podclipper init

This creates a small podclipper.yaml and a .env file. Existing files are kept. The starter config uses the OpenAI endpoint; put your key in .env:

LLM_API_KEY=your-api-key

The same LLM_API_KEY name works for every supported host. Already using another OpenAI-compatible endpoint? Set its endpoint and model in .env or podclipper.yaml. See LLM configuration.

3. Make reels

podclipper "path/to/podcast.mp4"

That's the full flow. Podcast mode, vertical cropping, and classic captions are already enabled. The CLI automatically reads podclipper.yaml and .env from your working directory. No -c or extra mode flags are needed.

The first run downloads the local transcription and detection models. Those models are reused on later runs. Processing can take a while, especially on CPU.

Finished clips appear in a new folder:

outputs/<timestamp>/
  reel_01_<title>.mp4
  reel_01_<title>.txt
  reel_02_<title>.mp4
  reel_02_<title>.txt

MP4s are vertical 1080 × 1920 with audio and burned-in captions. Text sidecars contain source timestamps, selection reasons, and review scores. The CLI prints the saved file paths when it finishes. It aims for the configured clip count; it may export fewer when candidates are rejected or processing fails.

For podcasts with edited split screens, the cropper detects thin light/dark vertical divider lines and keeps each crop inside its source panel. It shows at most two views, resets framing when the panel layout changes, and excludes the divider itself. Stacked views fill the frame. Detected camera and column changes reset tracking to a fresh crop, even for the same person, with a brief crossfade and no added zoom animation. Advanced overrides are under crop.panel_dividers and crop.scene_cuts; set crop.scene_cuts.crossfade_seconds: 0 for hard cuts. Choosing views uses visible person size, not active-speaker identification. Faint, broken, or decorative dividers may not be recognized.

Everyday commands

# Run everything, asking for three clips
podclipper podcast.mp4 --clips 3

# Use pop captions instead of classic karaoke captions
podclipper podcast.mp4 --captions pop

# Choose an output location
podclipper podcast.mp4 --output-dir outputs/my-podcast

Want to review the picks before exporting?

podclipper podcast.mp4 --clips 3 --select-only

Read outputs/<timestamp>/selection.md for titles, source timestamps, full transcript excerpts, and the opening and ending of each clip. No reels are rendered yet. A matching selection.json is saved alongside it.

Then export those exact picks:

podclipper podcast.mp4 --selection outputs/<timestamp>/selection.json

Use the same source video. Saved titles, order, and cut boundaries are preserved; per-clip transcription, cropping, captions, and evaluation still run normally.

Small config, sensible defaults

The starter config contains only the settings most people need:

llm:
  endpoint: https://api.openai.com/v1
  model: gpt-5-mini
content:
  clips: 8
output:
  captions: classic

Change content.clips to ask for fewer or more clips. Captions can be classic, pop, or off. Optional settings include content.duration: [15, 90] (seconds) and output.directory: outputs.

Omitted settings inherit the packaged defaults. You can still override internal settings without copying the whole default config—for example:

crop:
  stacked_transition_frames: 24

Config loading order is packaged defaults → explicit -c file or local podclipper.yaml → environment overrides → CLI flags. Nested mappings merge; lists and scalar values replace defaults. Explicit internal settings take precedence over their public shortcuts. Unknown settings and invalid value types produce an error.

# See the effective config, including inherited defaults
podclipper config --resolved

# Use a different config (and load its sibling .env as a fallback)
podclipper podcast.mp4 -c another-config.yaml

LLM_ENDPOINT and LLM_MODEL in your environment override YAML settings. Blank endpoint/model variables leave the YAML values in place. Shell environment variables take precedence over .env; the working-directory .env takes precedence over a config file's sibling .env. Keep API keys in .env or your shell, rather than the YAML file.

LLM configuration

Every LLM stage uses the same OpenAI-compatible endpoint through LiteLLM. There is no Claude CLI dependency or reasoning-effort override.

Use one host, one model, and one key. For example, our OpenRouter setup can be configured entirely in .env:

LLM_ENDPOINT=https://openrouter.ai/api/v1
LLM_MODEL=z-ai/glm-5.3-flash
LLM_API_KEY=your-api-key

Or keep the endpoint and model in YAML and only LLM_API_KEY in .env:

llm:
  endpoint: https://openrouter.ai/api/v1
  model: z-ai/glm-5.3-flash

There are no provider-specific key variables or api_key_env setting. Existing setups should rename their API key variable to LLM_API_KEY and remove llm.api_key_env from YAML. Optional provider routing:

llm:
  routing:
    order: [deepinfra]
    allow_fallbacks: true

This prefers DeepInfra while allowing other hosts. only: [deepinfra] restricts requests to that host. Model and provider availability depend on your endpoint.

LLM calls default to llm.max_tokens: 32768 (32k). Incomplete responses are never accepted. The retry ceiling also defaults to 32k, so a truncated response at that limit fails. To allow one larger retry, raise llm.retry_max_tokens above max_tokens; the retry uses up to twice the requested budget, capped by that ceiling. A retry can increase API cost, and your endpoint must support the larger budget. These settings are optional overrides; they don't need to appear in the minimal config.

What happens under the hood

  1. Validate the video and extract audio.
  2. Transcribe the podcast locally with Whisper.
  3. Ask the LLM for clips, refine their boundaries, and review each cut and title.
  4. For each accepted clip, detect speakers and transcribe again for caption timing. Check local speech coverage against the audio and available first-pass words, then retry suspicious sections with surrounding context. Cached captions get the same checks. Unresolved gaps stop that clip before export; the default cache saves retry details in words.quality.json.
  5. Correct caption words, crop to 9:16, and burn in captions and the title.
  6. Export the MP4 and a content scorecard.

Selection checks for an understandable opening, a complete ending, supported titles, valid duration, and overlapping clips. Overlong titles get one shortening retry. Review decisions are saved in the analysis cache's 04_final.json.

Caption correction can join wrongly split words or split wrongly joined words. Original word indices stay attached; split timing is estimated within the original word span. Invalid corrections preserve the original transcript.

Troubleshooting and advanced options

  • Missing API key or FFmpeg: the CLI checks these before transcription and tells you what to set or install. This checks key presence, not whether the endpoint will accept the key or whether your account has credit.
  • Config error: fix the named setting in podclipper.yaml. Use podclipper config --resolved to see inherited defaults.
  • Need details about a failure? Add --verbose.
  • First run is slow: model downloads and local video processing take time.
  • Rerunning: intermediate audio, transcripts, and clips are cached in .cache/. Stages may still run again; this isn't a resume from the exact point of failure. Use --no-cache to rebuild intermediates.
podclipper --help        # everyday podcast options
podclipper --help-all    # all options, including advanced and other modes

The default transcription engine is faster-whisper (CPU/CUDA), using base for initial transcription and large-v3 per clip. Apple Silicon users can opt into --whisper-engine mlx; it falls back to faster-whisper if unavailable. Whisper, YOLO, and MediaPipe models download automatically on first use.

Trailer and comedy options remain available under advanced help. The main onboarding and examples above focus on podcast reels.

Full defaults: src/podclipper/config/default.yaml. Developer notes: CLAUDE.md. Local crop iteration:

python dev/regen_crops.py .cache/<video_stem>-<hash> outputs/regen_run sidecar_dir/

Current limitations

Review exports before posting. Clip selection uses transcript text; it can miss visual moments or choose a cut that needs more context. Content scores aren't an audiovisual quality check or an independent fact check.

The latest full run also exposed occasional duplicate speaker panels and titles covering faces. Those crop/layout issues are still outstanding.

Demo reels

Three reels generated end-to-end from a single ~60-minute podcast episode. Previews loop silently below — click any tile to open the full MP4 with audio.

Reel 1 preview
"Confidence Is an Output, Not Input"
▶ play with audio
Reel 2 preview
"Make Anxiety Sit in the Back Seat"
▶ play with audio
Reel 3 preview
"How Hanuman Knew It Was Sita"
▶ play with audio

For full-screen playback with audio inline, visit the live demo site.

Project

The Python package is in src/podclipper/; local development scripts are in dev/. The demo site lives in landing/ and deploys to GitHub Pages separately.

License

PodClipper is licensed under AGPL-3.0-only. See LICENSE for the full terms and NOTICE for copyright and third-party attribution.

Person detection uses Ultralytics YOLO under its AGPL license. Other dependencies and downloaded models retain their own licenses. The project source is available in this repository.

Publishing releases

See the release guide for one-time PyPI setup and the exact commands. A new vX.Y.Z tag publishes version X.Y.Z automatically; there is no version number to edit in the code. Existing published versions and tags must not be reused for new fixes.

Metadata

Release files for podclipper 0.1.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for podclipper 0.1.3
File Size Uploaded Provenance Actions
podclipper-0.1.3.tar.gz 119.2 kB With provenance Details for podclipper-0.1.3.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for podclipper 0.1.3
File Interpreter ABI Platform Actions
podclipper-0.1.3-py3-none-any.whl Python 3 none any Details for podclipper-0.1.3-py3-none-any.whl

Total release size: 241.8 kB

Release files / podclipper-0.1.3.tar.gz

Download URL podclipper-0.1.3.tar.gz
Size 119.2 kB
Tags Source
SHA-256 checksum
How to use checksums
7584ba25fb626e80815320d4a5f87a52936755d8515296520987a83ec966b5ec
BLAKE2b-256 checksum
How to use checksums
af145055342e4a24e973f37f222285701de8a1a0c4cc66f60c103a3ac9d0b02b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.

Transparency log

Release files / podclipper-0.1.3-py3-none-any.whl

Download URL podclipper-0.1.3-py3-none-any.whl
Size 122.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ee7684affc4f16a9e28985eeeee48e2ab06c2621287989877cce2e792276f1d4
BLAKE2b-256 checksum
How to use checksums
fc91e9034a791a803e397a3e127f2812ffa4f395c95fa759632f046933435348
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.

Transparency log

Security for podclipper 0.1.3

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for podclipper-0.1.3.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page