One 6-minute b-roll, twelve Shorts episodes: source_in offsets
Slice one imported b-roll into twelve non-repeating 30-second episode backgrounds with Timeline 1.0 source_in, and plan the whole season unbilled in Python.

Give every episode its own slice of the same footage
A season of Shorts needs a background for each episode, and twelve separate stock clips is twelve things to import and keep track of. The alternative is one long b-roll file and a different source_in for each episode. In Timeline 1.0, video[].source_in is the in-point into the file, so episode 1 can start at second 0 of the b-roll, episode 2 at second 30, and so on, with no frame shown twice across the season.
This matters now because YouTube's Shorts series feature, with seasons, episodes, custom thumbnails and sequential playback, began rolling out on 23 September per the October platform roundup. A season is a set of near-identical episodes, and a pattern that generates twelve bodies from one file is easier to maintain than twelve hand-built ones.
The math, so the last episode does not run out
With a 360-second b-roll and 30-second episodes, episode n uses seconds (n-1)*30 to n*30, and episode 12 ends exactly at 360. If the b-roll is any shorter, the last slices run past the end of the file. Sume does not fail that: it pads or loops a short source and reports it as a soft warning, and the plan cannot predict it because the plan never downloads media. That is why the script below asserts the arithmetic in your own code instead of finding out from a warning on episode 12.
Read the real length of the b-roll first. Video inspect returns a probe for any clip in your workspace, and frames: false returns only the probe with no stills, the lightest form of the call (Sume bills probe and stills by their Modal compute, so it is cheap rather than free). Use that number for BROLL_SECONDS so the assertion compares against the file, not against your memory of it.
Slicing numbers for a season
Every figure here is derived from the slice size; the render bills by output minute, not by source length.
| Episodes | b-roll needed | Source minutes read | Render minutes at $0.10 |
|---|---|---|---|
| 6 | 180 s | 3 | 6 minutes = $0.60 |
| 12 | 360 s | 6 | 12 minutes = $1.20 |
| 24 | 720 s | 12 | 24 minutes = $2.40 |
Python: plan twelve episodes from one file
The helper at the top posts JSON to the API with your key. The loop builds one body per episode, each with its own spine file and its own source_in, and posts it to the unbilled plan endpoint. Replace the example URLs with your imported artifacts. Once the numbers look right, post each body to /v1/timeline-1.0/render with Idempotency-Key: season1-ep<N>-v1.
import json, os, time, urllib.request
def sume(method, path, body=None, key=None):
h = {"Authorization": "Bearer " + os.environ["SUME_API_KEY"],
"Content-Type": "application/json", "User-Agent": "sume-example/1.0"}
if key:
h["Idempotency-Key"] = key
data = json.dumps(body).encode() if body is not None else None
req = urllib.request.Request("https://api.sume.com" + path, data, h, method=method)
with urllib.request.urlopen(req) as r:
return json.load(r)
BROLL = "https://media.sume.com/artifacts/artf_demo/broll-360s.mp4"
BROLL_SECONDS, EP_SECONDS = 360, 30
for ep in range(12):
start = ep * EP_SECONDS
assert start + EP_SECONDS <= BROLL_SECONDS, "b-roll is too short"
body = {"audio": {"url": f"https://media.sume.com/artifacts/artf_demo/ep{ep + 1}.wav",
"duration_seconds": EP_SECONDS},
"video": [{"source_url": BROLL, "start": 0, "duration": EP_SECONDS,
"source_in": start}]}
plan = sume("POST", "/v1/timeline-1.0/plan", body)
print(ep + 1, plan["billable_minutes"], plan["estimated_cost_usd_micros"])Things that are not covered by this pattern
A source slice has no audio of its own in this design: the spine is the episode's voice file. If you want the b-roll's sound instead, detach it first. Looping is also not a style choice here; if you want a short clip repeated on purpose, say so with several slots rather than relying on the pad or loop warning. And the b-roll must be on media.sume.com, so import it once with POST /v1/media-imports before you plan anything.
One more reason to prefer this over twelve stock clips is consistency: the same lighting, the same color and the same grain in every episode means your captions and your voice carry the identity of the series, not the background. If you do want variety, change the fit value or crop with the video filter on a copy of the b-roll rather than hunting for new footage.
If your season is not a clean multiple, the same arithmetic still works. For ten episodes of 45 seconds you need 450 seconds of b-roll, with source_in values of 0, 45, 90 and so on. For variable lengths, keep a running offset in the loop instead of multiplying: add each episode's length to the offset after you build its body. That also makes it obvious when the total exceeds the file, which is the case the assertion above is there to catch before any request is sent.
A last practical point is cost visibility. The plan returns billable_minutes and estimated_cost_usd_micros for each body, so the loop above prints a line per episode that you can sum into a season budget before spending anything. The render itself bills per whole output minute at the documented $0.10 rate, so twelve 30-second episodes are twelve minutes, not six, because each episode is its own job and rounds up on its own. Confirm the live rate in GET /v1/catalog before you quote a number to anyone.
Sources
Related posts
More in Developers
- One Sume API key per service: what it isolates and what it does not
Sume request budgets are per key and reads and writes are already separate. A key per service isolates revocation and scope, not generation capacity.
- OpenAI images.generate to Sume /v1/images: field by field map
Move a gpt-image-1 images.generate call to Sume POST /v1/images: which fields carry over, which return 400, and why size becomes image_size. Python mapper.
- opencode remote MCP entry for Sume: env syntax and a longer timeout
The hosted Sume server in opencode.json: type remote, a bearer header from an env variable, a timeout above jobs_wait's 55 s cap. Checked by a script.
- Fade out the end of a Short: Timeline fade_out_seconds limits
Sume Timeline fades video and audio at the ends with output.fade_in_seconds and fade_out_seconds, 0 to 5 each, summing to at most the length. Setup for Shorts.
Written by Sume