captionbob docs

Version 1.0.0
Contents ↓

Python: captionbob.effects

captionbob.effects.surge

Surge effect: heavy capitals that slide, zoom or spin into their place.

The effect clones the look of the source video Sydney:

  • A caption holds up to three words, and it also ends at each end mark, such as a comma. It shows its words in capitals with no end marks, all at once, in one line or in two lines by its letters.
  • In a caption of two lines the top line is small over a big line, when the turn of the caption allows it and the top line has enough letters. Else the two lines are big.
  • The big lines take the line colors in turn: white, yellow and white. A small top line is white.
  • The letters spread past the font in their own color, and a soft black shadow lies a little below them.
  • The captions take the turns in order: a slide in from the left, a slide in from the right, a zoom from a smaller size, a spin from a small size and a tilt, and an olive box. A box caption spins in with an olive box behind each line, and its letters are typed one by one while each word is spoken.
  • A caption with a keyword shows an emoji below it. The emoji slides in with a caption that slides, and it grows with a caption that zooms or spins.

The lines of a caption hang from the top of a caption of one line. The event of each line is placed by the middle of the line, so a line grows, shrinks and turns around the middle of its caption. libass moves an event only in a straight line at one speed, so a slide is cut into events that follow one another, and each event is one straight move.

Source file: captionbob/effects/surge.py

Settings

The command line and the HTTP API call this effect the style surge. Its settings class is SurgeSettings. Each setting has the default below.

Setting Type Default Description
most_words integer 3 The most words that one caption shows.
fewest_words integer 1 The fewest words that one caption shows, when its sentence is long enough for that.
font_name string "DejaVu Sans" Name of the font of the text.
font_size integer 100 Height of the font in pixels.
bold boolean true True for bold text.
primary_color string "#FFFFFF" Color of the text, as "#RRGGBB".
stroke_color string "#FFFFFF" Color of the outline of the text, as "#RRGGBB".
stroke_width number 1.0 Width of the outline in pixels. 0 gives no outline.
bottom_position number 0.5964 Where the bottom of the caption sits, as a part of the video height from the top. 0.75 is three quarters of the way down.
side_margin integer 54 Room in pixels that stays free on the left and on the right of the caption. A caption that is too wide for the room between the margins breaks into lines.
letter_width number 0.965 The width of the letters of a big line, as a part of the width that the font gives them, above 0.
word_gap number -2.0 Room in pixels that is added to each space of a big line. A value below 0 puts the words closer.
line_gap number -3.8 Room in pixels between the line boxes of two lines. A value below 0 lets them overlap.
capitals boolean true True to write the words in capitals.
end_at_marks boolean true True to end a caption also at each end mark, such as a comma.
line_letters integer 13 The most letters, with the spaces, of a caption that has one line, 1 or above.
widest_line_letters integer 18 The most letters, with the spaces, of a line at its full size, 1 or above. A line with more letters is made smaller in step.
line_colors list ["#FFFFFF", "#F5F82B", "#FFFFFF"] The colors of the big lines, as "#RRGGBB". The captions take them in turn.
small_top_turns list [true, true, false] True or False for each caption in turn: True lets the top line of a caption of two lines be small.
small_top_letters integer 7 The fewest letters, with the spaces, of a top line that is small, 1 or above.
small_line_scale number 0.565 The size of a small line as a part of the size of a big line, above 0.
small_letter_part number 0.93 The width of the letters of a small line as a part of the letter width, above 0.
turns list ["left", "right", "zoom", "spin", "box"] The turns that the captions take in order from the second caption, each one of KNOWN_TURNS. The first caption takes the first turn.
slide_seconds number 0.2 The time of a slide, 0 or above.
zoom_scale number 0.8 The size at the start of a zoom, as a part of the full size, above 0.
zoom_seconds number 0.12 The time of a zoom, 0 or above.
spin_scale number 0.2 The size at the start of a spin, and of a box caption, as a part of the full size, above 0.
spin_angle number 25.0 The tilt at the start of a spin, in degrees clockwise.
spin_seconds number 0.12 The time of a spin, 0 or above.
box_color string "#948806" The color of the box of a box caption, as "#RRGGBB".
box_scale number 0.86 The size of the text of a box caption as a part of the size of the other captions, above 0.
box_letter_part number 0.968 The width of the letters of a box caption as a part of the width of the letters of the other captions, above 0.
box_line_gap number 7.2 Room in pixels between the line boxes of two lines of a box caption.
box_side_padding number 35.0 Room in pixels at the full size between the text and the left and the right edge of the box, 0 or above.
box_vertical_padding number 11.6 Room in pixels at the full size between the line box and the top and the bottom edge of the box, 0 or above.
box_shift_x number 10.5 How far the box is to the right of its text, in pixels at the full size.
box_shift_y number 10.0 How far the box is below its text, in pixels at the full size.
letter_seconds number 0.07 The longest time between two typed letters of a box caption, 0 or above.
shadow_color string "#000000" The color of the shadow, as "#RRGGBB".
shadow_spread number 2.0 How far the shadow reaches past the spread of the letters, in pixels.
shadow_blur number 6.0 How far the edge of the shadow fades out, in pixels.
shadow_opacity number 0.4 The strength of the shadow, from 0 for no shadow to 1.
shadow_drop number 4.0 How far the shadow is below the letters, in pixels.
emoji_size number 128.0 The side of the emoji in pixels, above 0.
emoji_gap number 28.0 Room in pixels between the line box of the last line and the top of the emoji.
hold_seconds number 0.0 The longest time that a caption stays after its last word ends.

SurgeEmojiLayer

class SurgeEmojiLayer(NamedTuple)

The emoji below one caption, as the ffmpeg filters draw it.

The emoji is a square with its middle at a column and its top at a row. It comes in as its caption comes in: it slides in from a side, or it grows from a part of its full size and keeps its top row.

Args:

  • image_path: The emoji image. An animated image plays from its first frame at the start of the caption.
  • start_seconds: Time at which the caption starts.
  • end_seconds: Time at which the caption ends.
  • size: The side of the emoji in pixels at its full size.
  • middle_x: The column of the middle of the emoji at its place.
  • top_y: The top row of the emoji.
  • slide_side: FROM_THE_LEFT or FROM_THE_RIGHT for an emoji that slides in from that side, NO_SLIDE for an emoji that does not slide.
  • slide_distance: How far from its place the emoji starts a slide, in pixels.
  • slide_seconds: The time of the slide.
  • pop_scale: The size of the emoji at its start, as a part of its full size.
  • pop_seconds: The time in which the emoji grows to its full size.

SurgeEmojiLayer.size_expression

def size_expression(self) -> str

Write the side of the emoji at the time t as ffmpeg reads it.

Returns:

An ffmpeg expression of a whole number of pixels, 1 or above.

SurgeEmojiLayer.left_expression

def left_expression(self) -> str

Write the left column of the emoji as the overlay filter reads it.

An emoji that slides moves from the slide distance to its place, fast at the start and slow at the end, on the curve of the slide of its caption.

Returns:

An ffmpeg expression with the width w of the emoji frame.

SurgeEmojiLayer.top_expression

def top_expression(self) -> str

Write the top row of the emoji as the overlay filter reads it.

Returns:

An ffmpeg expression with the height h of the emoji frame.

SurgeLayers

class SurgeLayers(NamedTuple)

What the effect gives for the words of one video.

Args:

  • ass_text: The text of the ASS script.
  • emojis: One emoji layer for each caption with a keyword, in time order.

SurgeCaption

class SurgeCaption(NamedTuple)

One caption of the surge effect.

Args:

  • caption: The caption with the times of its events and its words as spoken.
  • lines: The lines of the caption from the top, with the words as the effect shows them.
  • turn: The turn of the caption, one of KNOWN_TURNS.
  • line_color: The color of the big lines of the caption.
  • small_top: True when the top line is small.
  • keywords: The places of the keywords in the words of the caption.

SurgeLine

class SurgeLine(NamedTuple)

One line of a caption at its place.

Args:

  • words: The words of the line, as the effect shows them.
  • first_word: The place of the first word of the line in the words of the caption.
  • scale: The size of the line as a part of the font size.
  • letter_width: The width of the letters as a part of the width that the font gives them.
  • middle_y: The row of the middle of the line box.
  • look: The tags of the colors of the letters and of their spread.

SurgeLayout

class SurgeLayout(NamedTuple)

The lines of a caption at their places.

Args:

  • lines: The lines from the top.
  • middle_y: The row of the middle of the caption, around which its lines grow, shrink and turn.
  • bottom: The row of the bottom of the line box of the last line.

Entrance

class Entrance(NamedTuple)

How a caption that does not slide comes in.

Args:

  • scale: The size of the caption at its start, as a part of its full size.
  • angle: The tilt of the caption at its start, in degrees clockwise.
  • seconds: The time in which the caption grows to its full size and turns level.

SurgeSettings

@dataclass(frozen=True)
class SurgeSettings(CaptionSettings)

The look and the timing of the surge effect.

The settings of CaptionSettings come first: the word counts, the font, the colors, the stroke, the bottom position and the side margin. The stroke is a spread of the letters in their own color. The bottom position is the bottom of the line box of a caption of one line, and the lines of a caption of two lines hang from the top of that line box. These settings follow them.

Args:

  • letter_width: The width of the letters of a big line, as a part of the width that the font gives them, above 0.
  • word_gap: Room in pixels that is added to each space of a big line. A value below 0 puts the words closer.
  • line_gap: Room in pixels between the line boxes of two lines. A value below 0 lets them overlap.
  • capitals: True to write the words in capitals.
  • end_at_marks: True to end a caption also at each end mark, such as a comma.
  • line_letters: The most letters, with the spaces, of a caption that has one line, 1 or above.
  • widest_line_letters: The most letters, with the spaces, of a line at its full size, 1 or above. A line with more letters is made smaller in step.
  • line_colors: The colors of the big lines, as "#RRGGBB". The captions take them in turn.
  • small_top_turns: True or False for each caption in turn: True lets the top line of a caption of two lines be small.
  • small_top_letters: The fewest letters, with the spaces, of a top line that is small, 1 or above.
  • small_line_scale: The size of a small line as a part of the size of a big line, above 0.
  • small_letter_part: The width of the letters of a small line as a part of the letter width, above 0.
  • turns: The turns that the captions take in order from the second caption, each one of KNOWN_TURNS. The first caption takes the first turn.
  • slide_seconds: The time of a slide, 0 or above.
  • zoom_scale: The size at the start of a zoom, as a part of the full size, above 0.
  • zoom_seconds: The time of a zoom, 0 or above.
  • spin_scale: The size at the start of a spin, and of a box caption, as a part of the full size, above 0.
  • spin_angle: The tilt at the start of a spin, in degrees clockwise.
  • spin_seconds: The time of a spin, 0 or above.
  • box_color: The color of the box of a box caption, as "#RRGGBB".
  • box_scale: The size of the text of a box caption as a part of the size of the other captions, above 0.
  • box_letter_part: The width of the letters of a box caption as a part of the width of the letters of the other captions, above 0.
  • box_line_gap: Room in pixels between the line boxes of two lines of a box caption.
  • box_side_padding: Room in pixels at the full size between the text and the left and the right edge of the box, 0 or above.
  • box_vertical_padding: Room in pixels at the full size between the line box and the top and the bottom edge of the box, 0 or above.
  • box_shift_x: How far the box is to the right of its text, in pixels at the full size.
  • box_shift_y: How far the box is below its text, in pixels at the full size.
  • letter_seconds: The longest time between two typed letters of a box caption, 0 or above.
  • shadow_color: The color of the shadow, as "#RRGGBB".
  • shadow_spread: How far the shadow reaches past the spread of the letters, in pixels.
  • shadow_blur: How far the edge of the shadow fades out, in pixels.
  • shadow_opacity: The strength of the shadow, from 0 for no shadow to 1.
  • shadow_drop: How far the shadow is below the letters, in pixels.
  • emoji_size: The side of the emoji in pixels, above 0.
  • emoji_gap: Room in pixels between the line box of the last line and the top of the emoji.
  • hold_seconds: The longest time that a caption stays after its last word ends.

Raises:

  • TypeError: When a count of letters is not a whole number.
  • ValueError: When a setting is outside its range, when a color is not in the form "#RRGGBB", or when a turn is not known.

SurgeSettings.box_style_line

def box_style_line(self, margin_vertical: int) -> str

Write the ASS style line of the box of a box caption.

Args:

  • margin_vertical: Room in pixels between the bottom of a caption and the bottom edge of the video.

Returns:

The style line of the box, with the border style of a box.

SurgeSettings.turn_of

def turn_of(self, caption_index: int) -> str

Give the turn of a caption.

Args:

  • caption_index: The place of the caption in the captions of the video, 0 for the first.

Returns:

The first turn for the first caption. Else the turns in order from the second caption.

SurgeSettings.entrance

def entrance(self, turn: str) -> Entrance

Give how a caption of a turn that does not slide comes in.

Args:

  • turn: The turn of the caption.

Returns:

The zoom for a zoom, the spin for a spin and a box caption, and no change for a slide.

SurgeEffect

class SurgeEffect
    def __init__(
            self, settings: SurgeSettings,
            keyword_picker: KeywordPicker = DEFAULT_KEYWORD_PICKER) -> None

Builds the ASS script and the emoji layers of heavy capitals that slide, zoom or spin in, in one line or two, with a yellow line every third caption and an olive box with typed letters every fifth caption.

Args:

  • settings: The look and the timing of the effect.
  • keyword_picker: Names the keywords of each caption. A caption with a keyword has an emoji. With no value, the keyword of a caption is its longest word when that word has seven letters or more.

SurgeEffect.build_ass_text

def build_ass_text(self, words: Sequence[Word], video: VideoInfo) -> str

Build the ASS script of the effect for the words of one video.

Each caption starts with its first word. It ends when the next caption starts, and at the latest the hold time after its last word and at the end of the video. Each line of a caption has a text event on the higher layer, and a shadow event or a box event on the lower layer. A caption that slides has these events for each piece of its slide and once more for the rest of its time.

Args:

  • words: The words of the video in time order, each with its times.
  • video: The frame size and the duration of the video.

Returns:

The text of the ASS script. It has no event when there are no words.

Raises:

  • ValueError: When the side margins leave no room for the caption in the width of the video, or when the keyword picker gives a place that is not a word of its caption.

SurgeEffect.build_layers

def build_layers(
        self, words: Sequence[Word], video: VideoInfo,
        emoji_path: Path) -> SurgeLayers

Build the ASS script and the emoji layers for one video.

The script is the script of build_ass_text. Each caption with a keyword has one emoji layer with the times of the caption.

Args:

  • words: The words of the video in time order, each with its times.
  • video: The frame size and the duration of the video.
  • emoji_path: The emoji image, such as an animated GIF or a PNG with a see-through background. The effect does not read the image. ffmpeg reads it when it draws the layers.

Returns:

The script and the emoji layers.

Raises:

  • TypeError: When the emoji path is not a Path.
  • FileNotFoundError: When the emoji image is not a file.
  • ValueError: When the side margins leave no room for the caption in the width of the video, or when the keyword picker gives a place that is not a word of its caption.