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.