Video helpers for the Sonilo API: generate a soundtrack and mix it into your video with ffmpeg
Project description
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
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sonilo_video_kit-0.1.0.tar.gz.
File metadata
- Download URL: sonilo_video_kit-0.1.0.tar.gz
- Upload date:
- Size: 29.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
037b0e96e25548f7dfd73c2f945a001bffa3f1ce4c682f607ac2e57aa0c14add
|
|
| MD5 |
947e61dd2e6b2f7ded9f7f206bfc5578
|
|
| BLAKE2b-256 |
be2e7bc09d5210bed73e2217b25c869be719608ef9b6a51daf364fbf5dc54f8f
|
Provenance
The following attestation bundles were made for sonilo_video_kit-0.1.0.tar.gz:
Publisher:
publish-video-kit.yml on sonilo-ai/sonilo-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sonilo_video_kit-0.1.0.tar.gz -
Subject digest:
037b0e96e25548f7dfd73c2f945a001bffa3f1ce4c682f607ac2e57aa0c14add - Sigstore transparency entry: 2195043846
- Sigstore integration time:
-
Permalink:
sonilo-ai/sonilo-python@1e2c0dbc64c9b4090f416c030fa15d39798819c4 -
Branch / Tag:
refs/tags/sonilo-video-kit-v0.1.0 - Owner: https://github.com/sonilo-ai
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-video-kit.yml@1e2c0dbc64c9b4090f416c030fa15d39798819c4 -
Trigger Event:
push
-
Statement type:
File details
Details for the file sonilo_video_kit-0.1.0-py3-none-any.whl.
File metadata
- Download URL: sonilo_video_kit-0.1.0-py3-none-any.whl
- Upload date:
- Size: 29.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
402a7f1ff58b8e8e1257ca42ba2d53d105a08ec360be3d711f6dd9e6c9a40a6f
|
|
| MD5 |
a077eb7b39798a1a4e826480840318b1
|
|
| BLAKE2b-256 |
00f05b28bf82bae0510ba11886ec4618dac20b0e610327dc5fc83c48f91aa8a9
|
Provenance
The following attestation bundles were made for sonilo_video_kit-0.1.0-py3-none-any.whl:
Publisher:
publish-video-kit.yml on sonilo-ai/sonilo-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sonilo_video_kit-0.1.0-py3-none-any.whl -
Subject digest:
402a7f1ff58b8e8e1257ca42ba2d53d105a08ec360be3d711f6dd9e6c9a40a6f - Sigstore transparency entry: 2195043851
- Sigstore integration time:
-
Permalink:
sonilo-ai/sonilo-python@1e2c0dbc64c9b4090f416c030fa15d39798819c4 -
Branch / Tag:
refs/tags/sonilo-video-kit-v0.1.0 - Owner: https://github.com/sonilo-ai
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-video-kit.yml@1e2c0dbc64c9b4090f416c030fa15d39798819c4 -
Trigger Event:
push
-
Statement type: