Navigation

Python

Render videos in PythonBeta

Render a video template as an MP4 and follow its progress with the Python SDK.

A video template renders as an MP4. Each second of the video counts as one generation, and as two at 60 fps. Generate videos explains how to design one.

render_video and render_and_wait_video take a template id and keyword arguments.

#template_idstrrequired

The id of a video template, for example tpl_xxx.

#modificationslist[dict]

The values to put into the template’s layers. A video layer takes a src, and an audio track takes a src with its name. Modifications lists the fields each layer accepts.

Render and wait for the URL

render_and_wait_video returns {"result": url} or {"error": {...}}.

result = client.render_and_wait_video(
    "tpl_xxx",
    modifications=[
        {"name": "headline", "text": "Summer sale"},
        {"name": "music", "src": "https://example.com/song.mp3"},
    ],
)

if "error" in result:
    raise RuntimeError(result["error"]["message"])

print(result["result"])

Follow the progress

render_video yields event dicts. The last event is done or error.

for event in client.render_video("tpl_xxx", modifications=[{"name": "headline", "text": "Summer sale"}]):
    if event["type"] == "queued":
        print(f"{event['ahead']} videos before this one")
    elif event["type"] == "progress":
        print(f"{event['progress']:.0%}")
    elif event["type"] == "done":
        print(event["url"])
    elif event["type"] == "error":
        print(event["error"]["message"])
Event Fields
created id: the id of the video, for example vid_xxx
queued ahead: the number of videos before this one
progress frame, totalFrames, and progress from 0 to 1
done url: the URL of the MP4
error error: code, message, and requestId

A refused request, such as an invalid API key or a used-up quota, gives one error event. The client timeout applies only to the connection, because a video can wait in line for minutes.

Reconnect after a dropped connection

The video renders to its end, even when the connection drops. Then render_video reads the same video again by the id from the created event, and it continues to yield events. It never sends the render again, so you do not pay for a second video.

Attempt Wait before it
1 1 second
2 2 seconds
3 4 seconds
4 8 seconds

When the attempts run out, or the connection drops before the created event, the last event is an error with the code TIMEOUT_ERROR. render_and_wait_video reconnects in the same way.

Start a video without waiting

create_video starts the video and returns its id at once. It does not wait for the render. Then read the video with get_video or watch_video.

result = client.create_video("tpl_xxxxxxxxx", modifications=[{"name": "title", "text": "Hi"}])

if "error" in result:
    raise RuntimeError(result["error"]["message"])

print(result["result"]["id"])  # vid_xxx, with the status queued

create_video sends the render only once. A second request renders a second video.

Read a video again

Keep the id from the created event. get_video returns the status of the video, and its URL when it is done.

result = client.get_video("vid_xxx")

if "error" in result:
    raise RuntimeError(result["error"]["message"])

video = result["result"]
print(video["status"], video.get("url"))

status is queued, rendering, done, or failed. A failed video has an error string. An unknown id gives an error with the code NOT_FOUND.

watch_video yields the events of the video again, from the latest one. It has no created event, and it reconnects as render_video does.

for event in client.watch_video("vid_xxx"):
    if event["type"] == "done":
        print(event["url"])