Skip to main content

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=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

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sonilo_video_kit-0.1.0.tar.gz (29.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sonilo_video_kit-0.1.0-py3-none-any.whl (29.1 kB view details)

Uploaded Python 3

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

Hashes for sonilo_video_kit-0.1.0.tar.gz
Algorithm Hash digest
SHA256 037b0e96e25548f7dfd73c2f945a001bffa3f1ce4c682f607ac2e57aa0c14add
MD5 947e61dd2e6b2f7ded9f7f206bfc5578
BLAKE2b-256 be2e7bc09d5210bed73e2217b25c869be719608ef9b6a51daf364fbf5dc54f8f

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file sonilo_video_kit-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for sonilo_video_kit-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 402a7f1ff58b8e8e1257ca42ba2d53d105a08ec360be3d711f6dd9e6c9a40a6f
MD5 a077eb7b39798a1a4e826480840318b1
BLAKE2b-256 00f05b28bf82bae0510ba11886ec4618dac20b0e610327dc5fc83c48f91aa8a9

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page