11from typing import List , Optional , Union
22from enum import Enum
33
4+ from videodb ._constants import ApiPath
5+
46
57class AssetType (str , Enum ):
68 """The type of asset to display for the duration of the Clip."""
@@ -93,11 +95,10 @@ class CaptionAlignment(str, Enum):
9395class CaptionAnimation (str , Enum ):
9496 """Caption animation properties for caption assets."""
9597
96- # float_in_bottom = "float_in_bottom"
9798 box_highlight = "box_highlight"
9899 color_highlight = "color_highlight"
99100 reveal = "reveal"
100- karioke = "karioke "
101+ karaoke = "karaoke "
101102 impact = "impact"
102103 supersize = "supersize"
103104
@@ -139,14 +140,16 @@ def to_json(self):
139140
140141
141142class Transition :
142- def __init__ (self , in_ : str = None , out : str = None ):
143+ def __init__ (self , in_ : str = None , out : str = None , duration : int = 0.5 ):
143144 self .in_ = in_
144145 self .out = out
146+ self .duration = duration
145147
146148 def to_json (self ):
147149 return {
148150 "in" : self .in_ ,
149151 "out" : self .out ,
152+ "duration" : self .duration ,
150153 }
151154
152155
@@ -164,25 +167,25 @@ class VideoAsset(BaseAsset):
164167 def __init__ (
165168 self ,
166169 id : str ,
167- trim : int = 0 ,
170+ start : int = 0 ,
168171 volume : float = 1 ,
169172 crop : Optional [Crop ] = None ,
170173 ):
171- if trim < 0 :
172- raise ValueError ("trim must be non-negative" )
174+ if start < 0 :
175+ raise ValueError ("start must be non-negative" )
173176 if not (0 <= volume <= 5 ):
174177 raise ValueError ("volume must be between 0 and 5" )
175178
176179 self .id = id
177- self .trim = trim
180+ self .start = start
178181 self .volume = volume
179182 self .crop = crop if crop is not None else Crop ()
180183
181184 def to_json (self ):
182185 return {
183186 "type" : self .type ,
184187 "id" : self .id ,
185- "trim " : self .trim ,
188+ "start " : self .start ,
186189 "volume" : self .volume ,
187190 "crop" : self .crop .to_json (),
188191 }
@@ -193,12 +196,8 @@ class ImageAsset(BaseAsset):
193196
194197 type = AssetType .image
195198
196- def __init__ (self , id : str , trim : int = 0 , crop : Optional [Crop ] = None ):
197- if trim < 0 :
198- raise ValueError ("trim must be non-negative" )
199-
199+ def __init__ (self , id : str , crop : Optional [Crop ] = None ):
200200 self .id = id
201- self .trim = trim
202201 self .crop = crop if crop is not None else Crop ()
203202
204203 def to_json (self ):
@@ -214,16 +213,16 @@ class AudioAsset(BaseAsset):
214213
215214 type = AssetType .audio
216215
217- def __init__ (self , id : str , trim : int = 0 , volume : float = 1 ):
216+ def __init__ (self , id : str , start : int = 0 , volume : float = 1 ):
218217 self .id = id
219- self .trim = trim
218+ self .start = start
220219 self .volume = volume
221220
222221 def to_json (self ):
223222 return {
224223 "type" : self .type ,
225224 "id" : self .id ,
226- "trim " : self .trim ,
225+ "start " : self .start ,
227226 "volume" : self .volume ,
228227 }
229228
@@ -558,8 +557,7 @@ class Clip:
558557 def __init__ (
559558 self ,
560559 asset : AnyAsset ,
561- start : Union [float , int ],
562- length : Union [float , int ],
560+ duration : Union [float , int ],
563561 transition : Optional [Transition ] = None ,
564562 effect : Optional [str ] = None ,
565563 filter : Optional [Filter ] = None ,
@@ -568,19 +566,15 @@ def __init__(
568566 fit : Optional [Fit ] = Fit .crop ,
569567 position : Position = Position .center ,
570568 offset : Optional [Offset ] = None ,
569+ z_index : int = 0 ,
571570 ):
572- if start < 0 :
573- raise ValueError ("start must be non-negative" )
574- if length <= 0 :
575- raise ValueError ("length must be positive" )
576571 if not (0 <= scale <= 10 ):
577572 raise ValueError ("scale must be between 0 and 10" )
578573 if not (0 <= opacity <= 1 ):
579574 raise ValueError ("opacity must be between 0 and 1" )
580575
581576 self .asset = asset
582- self .start = start
583- self .length = length
577+ self .duration = duration
584578 self .transition = transition
585579 self .effect = effect
586580 self .filter = filter
@@ -589,18 +583,19 @@ def __init__(
589583 self .fit = fit
590584 self .position = position
591585 self .offset = offset if offset is not None else Offset ()
586+ self .z_index = z_index
592587
593588 def to_json (self ):
594589 json = {
595590 "asset" : self .asset .to_json (),
596- "start" : self .start ,
597- "length" : self .length ,
591+ "duration" : self .duration ,
598592 "effect" : self .effect ,
599593 "scale" : self .scale ,
600594 "opacity" : self .opacity ,
601595 "fit" : self .fit ,
602596 "position" : self .position ,
603597 "offset" : self .offset .to_json (),
598+ "z_index" : self .z_index ,
604599 }
605600
606601 if self .transition :
@@ -611,16 +606,30 @@ def to_json(self):
611606 return json
612607
613608
609+ class TrackItem :
610+ def __init__ (self , start : int , clip : Clip ):
611+ self .start = start
612+ self .clip = clip
613+
614+ def to_json (self ):
615+ return {
616+ "start" : self .start ,
617+ "clip" : self .clip .to_json (),
618+ }
619+
620+
614621class Track :
615- def __init__ (self , clips : List [Clip ] = []):
616- self .clips = clips
622+ def __init__ (self , z_index : int = 0 ):
623+ self .clips : List [TrackItem ] = []
624+ self .z_index : int = z_index
617625
618- def add_clip (self , clip : Clip ):
619- self .clips .append (clip )
626+ def add_clip (self , start : int , clip : Clip ):
627+ self .clips .append (TrackItem ( start , clip ) )
620628
621629 def to_json (self ):
622630 return {
623631 "clips" : [clip .to_json () for clip in self .clips ],
632+ "z_index" : self .z_index ,
624633 }
625634
626635
@@ -636,9 +645,6 @@ def __init__(self, connection):
636645 def add_track (self , track : Track ):
637646 self .tracks .append (track )
638647
639- def add_clip (self , track_index : int , clip : Clip ):
640- self .tracks [track_index ].clips .append (clip )
641-
642648 def to_json (self ):
643649 return {
644650 "timeline" : {
@@ -649,15 +655,19 @@ def to_json(self):
649655 }
650656
651657 def generate_stream (self ):
658+ """Generate a stream from the timeline."""
659+
652660 stream_data = self .connection .post (
653- path = " editor" ,
661+ path = ApiPath . editor ,
654662 data = self .to_json (),
655663 )
656664 self .stream_url = stream_data .get ("stream_url" )
657665 self .player_url = stream_data .get ("player_url" )
658666 return stream_data .get ("stream_url" , None )
659667
660668 def download_stream (self , stream_url : str ):
669+ """Download a stream from the timeline."""
670+
661671 return self .connection .post (
662- path = "timeline_v2/ download" , data = {"stream_url" : stream_url }
672+ path = f" { ApiPath . editor } / { ApiPath . download } " , data = {"stream_url" : stream_url }
663673 )
0 commit comments