Skip to main content

sonilo-video-kit

Video helpers for the Sonilo API: generate a soundtrack for a video and mix it in locally with ffmpeg. Python ≥ 3.9.

Requires ffmpeg + ffprobe on your PATH (macOS: brew install ffmpeg, Debian/Ubuntu: apt-get install ffmpeg) — or pass ffmpeg_path/ffprobe_path to any function.

Installation

pip install sonilo sonilo-video-kit

sonilo (the core client) is a required dependency — it is installed automatically alongside the kit, but is shown here for clarity.

Quickstart

from sonilo_video_kit import generate_music_for_video, mix_with_video

track = generate_music_for_video("./clip.mp4", prompt="upbeat, energetic")  # uses SONILO_API_KEY

mix_with_video(
    video="./clip.mp4",
    audio=track.audio,
    output="./clip.scored.mp4",
)

Loudness-matched mixing

By default the kit measures the loudness (LUFS) of your video's own audio and of the generated music, then sits the music 4 LU below the original — so dialogue stays intelligible without hand-tuning. The final file is normalized to −14 LUFS (streaming-platform delivery level) with a −1 dBFS peak limiter. The delivery-normalize boost is capped at +12 dB; attenuation (bringing an overly loud render down to target) is uncapped.

  • music_volume (0–1, default 0.5): 0.5 is the matched level; each step of 0.25 shifts ±6 dB (full range ±12 dB). 0 mutes the music.
  • original_volume (0–1, default 1): absolute — 1 keeps the original exactly as recorded, 0 removes it entirely.
  • loudness_match=False switches both knobs to plain absolute gains.
  • normalize=False skips the delivery-loudness pass.

If loudness measurement fails (exotic codecs, unreadable audio), the kit silently falls back to absolute-gain behavior rather than failing your render.

Ducking

mix_with_video sits the music at a fixed level under the original audio. duck_music_under_speech goes further: it rides the music down whenever someone speaks and back up in the gaps.

from sonilo_video_kit import duck_music_under_speech

duck_music_under_speech(
    video="./interview.mp4",
    audio=track.audio,
    output="./interview.ducked.mp4",
)

Unlike mix_with_video, which is entirely local and free, this calls the Sonilo ducking API and is billed on your video's duration. The kit uploads only the video's extracted audio track — your picture never leaves the machine and is copied into the result untouched. The API sets the ducking curve itself (speech gate, duck depth, −14 LUFS delivery, −1 dBTP ceiling), so there are no volume knobs to pass.

Requirements are enforced locally, before anything is uploaded or charged: the video must have an audio track and a real picture, it must run no longer than 360 s, output must carry a file extension and live in a directory that already exists and is writable, and your picture must be stream-copyable into output's container. The ducked audio is always written as AAC, so output must be a container that can carry AAC — .webm (Vorbis/Opus only) is rejected before the API call whatever your picture codec. Both the 360 s limit and the amount billed are measured on the picture, not the container (a video whose audio outlives its picture is billed for the picture's length). Any failure raises before the API is called; the kit never quietly falls back to an un-ducked mix. Use mix_with_video for silent or longer videos.

Nothing you have paid for is thrown away

The API charges when the job is submitted, and the task then runs to completion server-side whatever happens to your process — so every failure after that point keeps the mix you paid for reachable. Transient failures are retried with backoff (a 5xx while polling, a dropped connection, a 503 from the storage host mid-download).

If a failure after submit is not locally recoverable — the poll fails terminally, the download can't complete, or the wait times out — the raised VideoKitError names the task id and tells you the charge was already made and the task is still finishing server-side. No local rescue file is written in this case. Recover by polling GET /v1/tasks/<task_id> yourself until it reports succeeded, then download the output_url it returns: that re-fetches the mix you already paid for, instead of calling duck_music_under_speech again and being billed twice.

If instead a final, purely-local step fails after the API call — remuxing the ducked audio onto your picture, or placing the file at output (e.g. the disk fills mid-mux) — the kit saves the downloaded ducked audio to <output>.ducked.wav and raises a VideoKitError naming that path, so you can fix the local problem and finish locally. A rescue never overwrites an earlier one (<output>.ducked.1.wav, …), and output is always placed atomically.

Errors

VideoKitError (invalid arguments, unreadable video), FfmpegNotFoundError (ffmpeg/ffprobe missing — message includes install hints), FfmpegError (ffmpeg failed — carries exit_code and stderr_tail), DuckingFailedError (the ducking API accepted the job but could not finish it — carries code and refunded). Errors from the Sonilo API pass through as the sonilo package's typed errors.

refunded reports what the server said at the moment the task was polled, not a final verdict: the backend marks a task failed before it reverses the charge (and retries a failed reversal), so refunded: False means the reversal had not landed yet, not that you were definitely billed.

License

MIT

Release files for sonilo-video-kit 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 sonilo-video-kit 0.1.3
File Size Uploaded
sonilo_video_kit-0.1.3.tar.gz 30.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for sonilo-video-kit 0.1.3
File Interpreter ABI Platform
sonilo_video_kit-0.1.3-py3-none-any.whl Python 3 none any Details

Total release size: 59.5 kB

Release files / sonilo_video_kit-0.1.3.tar.gz

Download URL sonilo_video_kit-0.1.3.tar.gz
Size 30.0 kB
Tags Source
SHA-256 checksum
How to use checksums
e3d9498a8b55a6c44a5595a7d957196dd69e114449b511bcf77b0fcdf86adec5
BLAKE2b-256 checksum
How to use checksums
9d48995ddc6539c3cb71ff7c4490d4d689d83f181cdbed830a18941fceb67a1e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.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 Jul 24, 2026.

Transparency log

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

Download URL sonilo_video_kit-0.1.3-py3-none-any.whl
Size 29.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
9371d7189046057d47fb7ed9d4bfb457c2b1b70ad1bc993187e40b09a5136f8d
BLAKE2b-256 checksum
How to use checksums
d79b737737a0d8078d01731e105c2fa32fec436b7658edb39035b496ebd59379
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.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 Jul 24, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.3 This release

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

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