Skip to content

CueNodes: a tale of a shared structure

Alexander Cerutti edited this page Mar 11, 2023 · 1 revision

Of course, a subtitle system could not be considered one without a structure to which cues of several formats could be converted into.

The issue is exactly that: supporting several formats of subtitles requires a solid central point to rely on to perform several operations. So, here are the CueNodes.

CueNode is a data structure, and a class, thought to support the most common features of the subtitles world, starting with WebVTT but without leaving on the side other formats. So, the aim was to create a complete but flexible structure to which adapters could convert.

CueNodes will get inserted inside an IBT (Interval Binary Tree, as we discussed in the previous page), one tree per track.

It is composed of the following properties, plus some methods/getters/setters that are not that important at the moment:

class CueNode {
	public startTime: number;
	public endTime: number;
	public id: string;
	public content: string;
	public renderingModifiers?: RenderingModifiers;
	public entities?: Entity.GenericEntity[];
	public region?: Region;
}

So, in addition to startTime, endTime, and content, we have some more properties, with a defined interface, each one with a specific role.

Entities

Entities are whatever is part of the content but is not the content.

Might be counterintuitive, but that's it. If you have some tags, like WebVTT's <v Fred> tag or some <b>s / <i>s, these will be belonging to Entities.

For those familiar with the format, Entities interface has been created by taking inspiration from Telegram Bot API. In fact, each entity owns an offset (from the first character), a length (the length of the content inside tags), and the kind of entity. At the moment, the Tag entity and Style entity have been inserted, but Styles are not used and might be removed.

Styles get usually associated with the tags or might create new tags.

entities

Bring Your Own X

To allow for being dynamic enough, CueNode introduces the support to some properties such as every adapter can set their own by just being compliant with the contract. Such systems are commonly called Bring You Own X.

It is the case of Region and RenderingModifiers.

Region

Regions are boxes that will contain cues and will allow them to be organized on the viewport according to several rules. For example, the maximum amount of lines before hiding the previous exceeding ones, or the maximum width before wrapping down.

It is a matter of fact that @sub37/captions-renderer will handle all the cues as they are in regions and will style them according to Region BYO, instead of using different styles for Region-boxed cues and non-boxed cues.

A Region BYO is described below. The id is needed for association with the region id contained inside RenderingModifiers. The other properties can be getters and used just as an access point to the final value. Also, adapters could use this structure and add their own properties so they can perform calculations in a private manner.

export interface Region {
	id: string;
	width: number;
	lines: number;

	/**
	 * Allows each parser how to express
	 * the position of the region.
	 */

	getOrigin(): [x: number | string, y: number | string];

	/**
	 * Allows each parser how to express
	 * the position of the region based on runtime data
	 *
	 * @param viewportWidth
	 * @param viewportHeight
	 */

	getOrigin(
		viewportWidth: number,
		viewportHeight: number,
	): [x: number | string, y: number | string];
}

RenderingModifiers

RenderingModifiers are a set of properties that will change how a cue will get rendered. It might be its text alignment, its width, and its position in its cuebox (which, in @sub37/captions-renderer is equivalent to the region box).

For example, in the case of WebVTT, a position:60%,line-right property might be available. This means that the cue should be aligned on 60% on its right side. This means that its cuebox's width will be 60%. In the case of position:30%,line-left, the cue should be placed at 30% on its left side. This means that there will be a left offset of the cuebox of 30% and then the cue, whatever will it be its width.

So, RenderingModifiers allow, by being compliant with this interface, to change how the cue and its box will actually show up.

It is described below. id should be a predictable and generated id that adapters should implement, such as two cues with the same final most important properties will have the same id. This will allow @sub37/captions-renderer to create a different region for a set of cues with different rendering modifiers.

interface RenderingModifiers {
	/**
	 * A unique id that uses the required props
	 * to allow us comparing two RenderingModifiers
	 * with some common properties, e.g. regionIdentifier
	 */
	id: number;
	width: number;
	leftOffset: number;
	textAlignment: "start" | "left" | "center" | "right" | "end";
	regionIdentifier?: string;
}