Local tool · sprint 0.21 Tools / video / segmentation

MP4 to loopable clips.

Split a long video into N segments whose boundaries land on musical beats — each clip plays forward then mirrors back, so dropped into a loop slot it cycles without a visible seam. Beat detection via librosa; rendering via MoviePy. Falls back to equal-time slices when the video has no usable audio. Everything runs locally.

gradio 5 + MoviePy + librosa CLI + UI local-first · no uploads MIT
Segments 1–20default 4
Alignment On the beatlibrosa.beat.beat_track
Loop build Fwd + revvfx.time_mirror
Runtime 100% localno uploads, ever
Fig. 01 — the mirror bench

Watch the loop form itself.

api · not checked

A live illustration of what the CLI does: beat grid in, N windows out, each window built as forward + reversed. Move the controls and the segmentation re-divides. Illustrative — this is a simulation of the documented algorithm, not a video render.

Path beat detection
Segment 01 / 04
Window 0:00.000 → 0:00.000
Loop seamless

Segment windows produced by the current bench settings
SegmentStartEndBuilt

What it does

01 / 06
A — beat-aligned cuts

Every cut lands on a downbeat

Audio is extracted (22.05 kHz mono), beats are detected with librosa.beat.beat_track, and the beat list is split into N contiguous groups — so every segment starts and ends on a musical downbeat.

B — seamless loops

Forward, then back

Each segment is built as [forward, reverse] (vfx.time_mirror) — the tail mirrors back to the head, no visible seam.

C — never refuses

Always produces output

No audio or too few beats? Equal-duration fallback kicks in instead of failing. The pipeline does not return empty-handed.

D — one archive

ZIP download

segment_01.mp4 … segment_NN.mp4 in one archive, handed back through the UI file widget or written by --out.

How to run it

02 / 06

Setup is a one-time uv sync (same pattern as the CLIP Interrogator). ffmpeg must be on PATH — MoviePy shells out to it for encode/decode.

bash · setup (once)
$ brew install ffmpeg        # if not already installed
$ npm run lvs:setup           # uv sync --project lib/loopable-video-segmenter
$ npm run lvs:check           # imports + deps + ffmpeg presence, no model downloads
bash · ui
$ npm run lvs:ui
# gradio app on http://127.0.0.1:7861  (7860 is the CLIP Interrogator's port)
bash · cli
$ npm run lvs:segment -- video.mp4 --segments 4
$ npm run lvs:segment -- video.mp4 --segments 8 --no-loopable --json
$ npm run lvs:segment -- video.mp4 --segments 2 --out /path/to/out.zip

--json emits the zip path, segment count and which segmentation path ran (beat detection or equal-time fallback). Exit codes: 0 ok, 2 bad input, 3 runtime failure.

Parameters

03 / 06
ParameterRange / defaultMeaning
Number of segments 1–20 · --segments, default 4 How many loopable clips to produce from the source. Make each segment loopable
Make each segment loopable on by default · --no-loopable Forward + reverse mirror build; off = plain cuts.
Input MP4 (h264 + aac works best) Audio is extracted for beat tracking; silent video falls back to equal time.
Try these on the bench ↑

How it works

04 / 06
  1. 01 — Extract

    Audio to temp WAV

    22.05 kHz mono, written to a temp file via MoviePy.

    moviepy · wav
  2. 02 — Detect

    Beat list

    Beats detected with librosa; only times inside the video duration are kept.

    librosa.beat.beat_track
  3. 03 — Divide

    N contiguous groups

    The beat list is split into N groups → N (start, end) windows that begin and end on downbeats.

    beats → (start, end)
  4. 04 — Build

    Forward + mirror

    Each clip is subclip(start, end) concatenated with its own time mirror, encoded h264 + aac.

    concatenate([sub, sub.fx(time_mirror)])
  5. 05 — Zip

    One archive

    Segments are zipped and handed back — UI file widget, or written by --out.

    segment_01…NN.zip
Note

Quality depends on the audio. Live or percussive music gives the cleanest splits. Spoken word and ambient tracks fall through to the equal-time fallback — the pipeline never refuses to produce output.

Notes

05 / 06
Caution

The mirrored half plays audio backwards. The time_mirror trick makes visuals loop seamlessly, but the second half of each clip's audio is reversed. Fine for visual loops; for music-video work, mute the second half in your DAW or cross-fade.

Source code: lib/loopable-video-segmenter/ (uv-managed, src/loopable_video_segmenter/).

MoviePy is pinned to 1.x — the code uses the 1.x API (moviepy.editor, subclip, vfx.time_mirror).

Docs: docs/LOOPABLE-VIDEO-SEGMENTER.md. Source repo: github.com/kajica2/loopable-video-segmenter.

Attribution

06 / 06
Port of kajica2/loopable-video-segmenter
MIT, © 2026 Kai Djuric / kajica2
Stack Gradio · MoviePy · librosa · soundfile