diff --git a/videodb/__init__.py b/videodb/__init__.py index f5125e4..51225eb 100644 --- a/videodb/__init__.py +++ b/videodb/__init__.py @@ -12,6 +12,7 @@ SubtitleAlignment, SubtitleBorderStyle, SubtitleStyle, + TextStyle, ) from videodb.client import Connection from videodb.exceptions import ( @@ -23,7 +24,7 @@ logger: logging.Logger = logging.getLogger("videodb") -__version__ = "0.0.5" +__version__ = "0.1.0" __author__ = "videodb" __all__ = [ @@ -37,6 +38,7 @@ "SubtitleAlignment", "SubtitleBorderStyle", "SubtitleStyle", + "TextStyle", ] diff --git a/videodb/_constants.py b/videodb/_constants.py index 3befbc3..50fe068 100644 --- a/videodb/_constants.py +++ b/videodb/_constants.py @@ -1,5 +1,5 @@ """Constants used in the videodb package.""" - +from typing import Union from dataclasses import dataclass VIDEO_DB_API: str = "https://api.videodb.io" @@ -106,3 +106,32 @@ class SubtitleStyle: margin_l: int = 10 margin_r: int = 10 margin_v: int = 10 + + +@dataclass +class TextStyle: + fontsize: int = 24 + fontcolor: str = "black" + fontcolor_expr: str = "" + alpha: float = 1.0 + font: str = "Sans" + box: bool = True + boxcolor: str = "white" + boxborderw: str = "10" + boxw: int = 0 + boxh: int = 0 + line_spacing: int = 0 + text_align: str = "T" + y_align: str = "text" + borderw: int = 0 + bordercolor: str = "black" + expansion: str = "normal" + basetime: int = 0 + fix_bounds: bool = False + text_shaping: bool = True + shadowcolor: str = "black" + shadowx: int = 0 + shadowy: int = 0 + tabsize: int = 4 + x: Union[str, int] = "(main_w-text_w)/2" + y: Union[str, int] = "(main_h-text_h)/2" diff --git a/videodb/asset.py b/videodb/asset.py index e64a103..6061b4b 100644 --- a/videodb/asset.py +++ b/videodb/asset.py @@ -1,9 +1,10 @@ import copy import logging +import uuid from typing import Optional, Union -from videodb._constants import MaxSupported +from videodb._constants import MaxSupported, TextStyle logger = logging.getLogger(__name__) @@ -32,8 +33,8 @@ class VideoAsset(MediaAsset): def __init__( self, asset_id: str, - start: Optional[int] = 0, - end: Optional[Union[int, None]] = None, + start: Optional[float] = 0, + end: Optional[float] = None, ) -> None: super().__init__(asset_id) self.start: int = start @@ -55,8 +56,8 @@ class AudioAsset(MediaAsset): def __init__( self, asset_id: str, - start: Optional[int] = 0, - end: Optional[Union[int, None]] = None, + start: Optional[float] = 0, + end: Optional[float] = None, disable_other_tracks: Optional[bool] = True, fade_in_duration: Optional[Union[int, float]] = 0, fade_out_duration: Optional[Union[int, float]] = 0, @@ -117,3 +118,33 @@ def __repr__(self) -> str: f"y={self.y}, " f"duration={self.duration})" ) + + +class TextAsset(MediaAsset): + def __init__( + self, + text: str, + duration: Optional[int] = None, + style: TextStyle = TextStyle(), + ) -> None: + super().__init__(f"txt-{str(uuid.uuid4())}") + self.text = text + self.duration = duration + self.style: TextStyle = style + + def to_json(self) -> dict: + return { + "text": copy.deepcopy(self.text), + "asset_id": copy.deepcopy(self.asset_id), + "duration": copy.deepcopy(self.duration), + "style": copy.deepcopy(self.style.__dict__), + } + + def __repr__(self) -> str: + return ( + f"TextAsset(" + f"text={self.text}, " + f"asset_id={self.asset_id}, " + f"duration={self.duration}, " + f"style={self.style})" + ) diff --git a/videodb/timeline.py b/videodb/timeline.py index 96b66bf..c4b63ce 100644 --- a/videodb/timeline.py +++ b/videodb/timeline.py @@ -1,7 +1,7 @@ from typing import Union from videodb._constants import ApiPath -from videodb.asset import VideoAsset, AudioAsset, ImageAsset +from videodb.asset import VideoAsset, AudioAsset, ImageAsset, TextAsset class Timeline(object): @@ -23,14 +23,22 @@ def to_json(self) -> dict: timeline_json.append(asset.to_json()) return {"timeline": timeline_json} - def add_inline(self, asset: Union[VideoAsset]) -> None: + def add_inline(self, asset: VideoAsset) -> None: if not isinstance(asset, VideoAsset): raise ValueError("asset must be of type VideoAsset") self._timeline.append(asset) - def add_overlay(self, start: int, asset: Union[AudioAsset, ImageAsset]) -> None: - if not isinstance(asset, AudioAsset) and not isinstance(asset, ImageAsset): - raise ValueError("asset must be of type AudioAsset or ImageAsset") + def add_overlay( + self, start: int, asset: Union[AudioAsset, ImageAsset, TextAsset] + ) -> None: + if ( + not isinstance(asset, AudioAsset) + and not isinstance(asset, ImageAsset) + and not isinstance(asset, TextAsset) + ): + raise ValueError( + "asset must be of type AudioAsset, ImageAsset or TextAsset" + ) self._timeline.append((start, asset)) def generate_stream(self) -> str: