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=Falseswitches both knobs to plain absolute gains.normalize=Falseskips 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.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| sonilo_video_kit-0.1.2.tar.gz | 30.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| sonilo_video_kit-0.1.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 59.5 kB
Release files / sonilo_video_kit-0.1.2.tar.gz
| Download URL | sonilo_video_kit-0.1.2.tar.gz |
|---|---|
| Size | 30.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
1665f13ea5dce8761dde7c5411761b6301e42a2e98482e83efc2008c53f210f1
|
|
BLAKE2b-256 checksum How to use checksums |
4b0b66c2ec360551c4a72bf2188812dadf08c51f85776c8b034c5a6dae6a15b4
|
| 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 23, 2026.
Transparency logRelease files / sonilo_video_kit-0.1.2-py3-none-any.whl
| Download URL | sonilo_video_kit-0.1.2-py3-none-any.whl |
|---|---|
| Size | 29.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
7fa15b3ad8800e18f02f99083a1829f95cb7278abc3a19a1d86448980cf55743
|
|
BLAKE2b-256 checksum How to use checksums |
45fffcb8061728e1d0974bb9609800ed3399eebf4c5e87581eae36ac01f2746c
|
| 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 23, 2026.
Transparency log