Timeline body from a cut list in TypeScript: starts and coverage

Turn a cut list of source ranges into Timeline slots: starts are running sums rounded to 3 decimals, and 3 ranges of 3.55, 4.68 and 3.36 s make 11.59 s.

4 min readSume
All posts

A pause cut is a list of source ranges, but a Timeline body needs output-timeline start values and an audio.duration_seconds that agrees with them. Compute the starts as running sums of range lengths, round to 3 decimals, and floor the total so the audio never claims more than the parts hold; three ranges of 3.55, 4.68 and 3.36 s start at 0, 3.55 and 8.23 and total 11.59 s.

The mapping

Limits to enforce before you send: at most 20 audio.parts[], at most 200 video slots, and each slot duration at least 0.2 s. Past 20 ranges use a two-level concat.

Cut list to slots (hypothetical ranges, arithmetic only)
Range (source)DurationOutput start
0.55 to 4.103.55 s0
4.62 to 9.304.68 s3.55
9.84 to 13.203.36 s8.23
Total11.59 s

TypeScript

Pass the same source and detached wav URLs for every entry; the function keeps picture and audio parts aligned by construction.

type Range = { start: number; end: number };
const r3 = (n: number) => Math.round(n * 1000) / 1000;

export function timelineBody(ranges: Range[], videoUrl: string, wavUrl: string) {
  if (ranges.length > 20) throw new Error("audio.parts is capped at 20");
  let at = 0;
  const video: object[] = [], parts: object[] = [];
  for (const { start, end } of ranges) {
    const duration = r3(end - start);
    if (duration < 0.2) throw new Error("slot under 0.2 s");
    video.push({ source_url: videoUrl, source_in: start, start: r3(at), duration });
    parts.push({ url: wavUrl, source_in: start, duration });
    at += duration;
  }
  const total = Math.floor(at * 1000) / 1000;  // never claim more than parts hold
  return { audio: { parts, duration_seconds: total }, video };
}

Gotchas

  • Keep one rounding rule for starts and durations, or a 1 ms gap appears between slots.
  • Coverage can stop at most 0.5 s before the end of the spine, so the last slot must reach nearly to the end of the audio.
  • Run POST /v1/timeline-1.0/plan (unbilled) to read duration_seconds and billable_minutes before the render.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume