Video editing from Python, without FFmpeg on your machine.
Trim, resize, compress, convert, caption and transcribe by calling one HTTP endpoint per operation. Parameters are validated before anything renders, so a bad call fails as a typed error rather than a broken encode.
What running FFmpeg from Python usually costs
- A binary to install on every machine that runs the code, including the container that gets rebuilt at three in the morning.
- subprocess with a list of arguments you build by hand, where a wrong flag surfaces as a non-zero exit code and a wall of stderr.
- The encode happens in your process, so a long render holds a worker and the memory that goes with it.
Trim a clip and wait for the file
Python
import os, time, requests
KINOPIPE = "https://kinopipe.com/api/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['KINOPIPE_API_KEY']}"}
def run(tool, inputs, options=None):
started = requests.post(
f"{KINOPIPE}/tools/{tool}",
headers=HEADERS,
json={"inputs": inputs, "options": options or {}},
timeout=30,
)
started.raise_for_status()
job_id = started.json()["jobId"]
while True:
job = requests.get(f"{KINOPIPE}/jobs/{job_id}", headers=HEADERS, timeout=30).json()
if job["status"] in ("succeeded", "failed"):
return job
time.sleep(2)
job = run(
"trim-video",
[{"id": "main", "url": "https://example.com/interview.mp4"}],
{"start": 12, "end": 48},
)
if job["status"] == "failed":
raise RuntimeError(job.get("errorMessage", "the job did not finish"))
print(job["result"]["output"]["downloadUrl"])- The tool slug is the only thing that changes between operations: swap trim-video for resize-video, compress-video or add-subtitles-to-video and keep the same function.
- Send an Idempotency-Key header when you retry, and the retry returns the original job instead of paying for a second render.
- For a file on disk, POST to /api/v1/uploads with the filename, content type and byte size, submit the file to the URL it returns, then use the media URL as the input.
FAQ
How is this different from ffmpeg-python?
ffmpeg-python builds a command line for a binary you install and run yourself. Here the parameters are validated server-side before anything renders, and your process never holds an encode.
Does it block my worker?
Only if you want it to. The call returns a job id immediately; the polling loop above is a convenience, and a webhook is the alternative when you would rather not wait.
Can I compose several operations in one render?
Yes. POST /api/v1/jobs takes a recipe of bounded operations and compiles them into a single FFmpeg pass, so trim plus resize plus watermark is one decode and one encode.