Skip to content

Add sonilo-video-kit: Python companion package (ffmpeg video-soundtrack helpers) - #7

Merged
spencer-zqian merged 15 commits into
mainfrom
feat/py-video-kit
Jul 18, 2026
Merged

Add sonilo-video-kit: Python companion package (ffmpeg video-soundtrack helpers)#7
spencer-zqian merged 15 commits into
mainfrom
feat/py-video-kit

Conversation

@spencer-zqian

Copy link
Copy Markdown
Contributor

Add sonilo-video-kit — Python companion package

A faithful, sync Python port of the JavaScript sonilo-video-kit, added to this repo as a second, independently-published package. The core sonilo client is untouched.

What it is

sonilo-video-kit (import sonilo_video_kit) ships local ffmpeg-based video-soundtrack helpers on top of the sonilo client, giving Python the same three capabilities as the JS package:

  • generate_music_for_video — generate a soundtrack for a video (wraps video_to_music).
  • mix_with_video — loudness-matched local mix (ffmpeg), delivery-normalized to −14 LUFS.
  • duck_music_under_speech — ride the music under speech via the Sonilo ducking API.

Cross-language parity: pip install sonilo-video-kit mirrors npm install sonilo-video-kit.

Design

  • Lives at sonilo-video-kit/ with its own pyproject.toml (hatchling), version = 0.1.0, requires-python = ">=3.9", dependencies = ["sonilo>=0.3,<0.4"]. The published sonilo core is not modified.
  • Idiomatic Python: sync API, snake_case, keyword-only options, time in seconds (not ms); JS signal/fetch options dropped.
  • loudness.py constants are a byte-for-byte port of the JS loudness.ts. The ffmpeg layer shells out via subprocess (no extra runtime deps). The ducking transport is self-contained (the core client has no ducking resource), reusing the client's authenticated httpx transport for submit/poll and a separate unauthenticated client for the download.
  • Security guards ported and hardened: SSRF URL allow-rules (https-only; reject IP-literal — including decimal/hex/octal IPv4 encodings — localhost/.local/.internal), a streaming download byte cap with an expected-bytes floor and a per-attempt wall-clock timeout, a JSON body cap, and submit-never-retried (it charges the account).

Verification

Clean-room fresh-venv install; 52 companion tests pass and the 143 core tests remain green (core unaffected). python -m build sonilo-video-kit produces the sonilo_video_kit-0.1.0 sdist + wheel.

CI / release

  • ci.yml extended to install and test both packages (Python 3.9/3.12, ffmpeg).
  • New publish-video-kit.yml: tag-triggered (sonilo-video-kit-v*) publish to PyPI via OIDC trusted publishing, with a tag↔version guard and skip-existing. Merging this PR does not publish — only pushing the release tag does.

Required before the first publish (manual)

Configure a PyPI pending trusted publisher for the new project sonilo-video-kit (owner sonilo-ai, repo sonilo-python, workflow publish-video-kit.yml) — this lets OIDC create the new project tokenlessly. Then tag sonilo-video-kit-v0.1.0 to publish.

🤖 Generated with Claude Code

…t timeout

- assert_safe_download_url now canonicalizes decimal/hex/octal integer
  hosts and trailing-dot dotted-quads before the IP-literal check, matching
  what a WHATWG URL parser (JS's `new URL()`) does before ducking-api.ts's
  isIpLiteralHost ever runs. Previously urlsplit()+ipaddress.ip_address let
  0x7f000001 / 2130706433 / 017700000001 / 127.0.0.1. / 0xA9FEA9FE (169.254.169.254)
  straight through.
- download_ducked_mix now bounds each attempt's WALL-CLOCK lifetime inside
  the streaming loop, not just httpx's inter-chunk read timeout (which
  resets on every byte and never trips for a slow-loris server).
- download_ducked_mix now treats any response >= 300 (not just >= 400) as a
  download failure, since follow_redirects=False returns a 3xx as an
  ordinary response rather than raising (unlike JS's redirect:"error").
…es; note AAC container and refunded semantics
@sapient-app

sapient-app Bot commented Jul 18, 2026

Copy link
Copy Markdown

Sapient docs evals

Waiting for the staging docs URL before running evals.

Sapient will start the selected PR evals automatically when GitHub reports a successful docs deployment for this PR. This usually happens within 15 minutes.

Commit: 57eb7bb
Status: waiting for staging docs URL

@spencer-zqian
spencer-zqian merged commit 1e2c0db into main Jul 18, 2026
2 checks passed
@spencer-zqian
spencer-zqian deleted the feat/py-video-kit branch July 18, 2026 20:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant