11import { z } from 'https://deno.land/x/zod@v3.9.0/mod.ts'
22import * as t from '../template_input.zod.ts'
3- import { assert } from '../../ type-equality.ts'
3+ import { assert } from '../type-equality.ts'
44
55
6- const Id = z . string ( ) . regex ( / [ a - z A - Z 0 - 9 - _ ] / )
6+ const ClipId = z . string ( ) . regex ( / [ a - z A - Z 0 - 9 - _ ] / )
77
88const Pixels = z . string ( ) . regex ( / \d + p x / )
99
@@ -16,29 +16,49 @@ const Color = z.string()
1616const Timestamp = z . string ( ) // I think we will delay parsing this till after we probe files because we need access to full file durations to resolve variables
1717
1818const Size = z . object ( {
19- width : z . union ( [ Pixels , Percentage ] ) . optional ( ) ,
20- height : z . union ( [ Pixels , Percentage ] ) . optional ( ) ,
21- relative_to : Id . optional ( ) ,
22- } )
19+ width : z . union ( [ Pixels , Percentage ] ) . default ( '100%' ) ,
20+ height : z . union ( [ Pixels , Percentage ] ) . default ( '100%' ) ,
21+ relative_to : ClipId . optional ( ) ,
22+ } ) . strict ( )
2323
2424const AlignX = z . union ( [ z . literal ( 'left' ) , z . literal ( 'right' ) , z . literal ( 'center' ) ] )
2525const AlignY = z . union ( [ z . literal ( 'top' ) , z . literal ( 'bottom' ) , z . literal ( 'center' ) ] )
2626const Layout = Size . extend ( {
27- x : z . union ( [ AlignX , z . object ( { offset : z . union ( [ Pixels , Percentage ] ) . optional ( ) , align : AlignX . optional ( ) } ) ] ) . optional ( ) ,
28- y : z . union ( [ AlignY , z . object ( { offset : z . union ( [ Pixels , Percentage ] ) . optional ( ) , align : AlignY . optional ( ) } ) ] ) . optional ( ) ,
29- } )
27+ x : z . union ( [ AlignX , z . object ( { offset : z . union ( [ Pixels , Percentage ] ) . optional ( ) , align : AlignX . optional ( ) } ) ] ) . default ( 'left' ) . transform ( val => typeof val === 'object' ? val : { offset : '0px' , align : val } ) ,
28+ y : z . union ( [ AlignY , z . object ( { offset : z . union ( [ Pixels , Percentage ] ) . optional ( ) , align : AlignY . optional ( ) } ) ] ) . default ( 'top' ) . transform ( val => typeof val === 'object' ? val : { offset : '0px' , align : val } ) ,
29+ } ) . strict ( )
3030
3131const ClipBase = z . object ( {
32- id : Id . optional ( ) ,
32+ id : ClipId . optional ( ) ,
3333 layout : Layout . optional ( ) ,
3434 crop : Layout . optional ( ) ,
35+ zoompan : z . object ( {
36+ keyframe : Timestamp ,
37+ zoom : Percentage . optional ( ) ,
38+ x : z . union ( [ Pixels , Percentage ] ) . optional ( ) ,
39+ y : z . union ( [ Pixels , Percentage ] ) . optional ( ) ,
40+ } ) . strict ( ) . array ( ) . optional ( ) ,
3541 rotate : Degrees . optional ( ) ,
42+ speed : Percentage . default ( '100%' ) ,
43+ framerate : z . object ( {
44+ fps : z . number ( ) . min ( 0 ) ,
45+ smooth : z . boolean ( ) . default ( false ) ,
46+ } ) . strict ( ) . optional ( ) ,
47+ transition : z . object ( {
48+ fade_in : Timestamp . optional ( ) ,
49+ fade_out : Timestamp . optional ( ) ,
50+ } ) . strict ( ) . optional ( ) ,
51+ trim : z . object ( {
52+ start : Timestamp . optional ( ) ,
53+ stop : Timestamp . optional ( ) ,
54+ variable_length : z . union ( [ z . literal ( 'start' ) , z . literal ( 'stop' ) ] ) ,
55+ } ) . strict ( ) . optional ( ) ,
3656} ) . strict ( )
3757
3858const MediaClip = ClipBase . extend ( {
3959 file : z . string ( ) ,
40- volume : z . number ( ) . min ( 0 ) . optional ( ) ,
41- } )
60+ volume : Percentage . default ( '100%' ) ,
61+ } ) . strict ( )
4262
4363const TextClip = ClipBase . extend ( {
4464 text : z . string ( ) ,
@@ -51,15 +71,28 @@ const TextClip = ClipBase.extend({
5171 background_color : Color . optional ( ) ,
5272 outline_color : Color . optional ( ) ,
5373 outline_size : z . number ( ) . optional ( ) ,
54- } ) . strict ( ) . optional ( )
55- } )
74+ } ) . strict ( ) . optional ( ) ,
75+
76+ duration : Timestamp . optional ( ) ,
77+ } ) . strict ( )
78+
79+ const TimelineClip : z . ZodSchema < t . TimelineClip > = z . lazy ( ( ) => z . object ( {
80+ id : ClipId . optional ( ) ,
81+ offset : Timestamp . default ( '0' ) ,
82+ z_index : z . number ( ) . default ( 0 ) ,
83+ type : z . union ( [ z . literal ( 'parallel' ) , z . literal ( 'sequence' ) ] ) . default ( 'parallel' ) ,
84+ next : TimelineClip . array ( ) . optional ( ) ,
85+ } ) )
5686
5787const Template = z . object ( {
5888 size : Size . optional ( ) ,
5989 clips : MediaClip . array ( ) . min ( 1 ) ,
6090 captions : TextClip . array ( ) . min ( 1 ) . optional ( ) ,
91+ timeline : TimelineClip . array ( ) . min ( 1 ) . optional ( ) ,
6192 preview : Timestamp . optional ( ) ,
6293} )
6394
6495// this is a typescript exacty type assertion. It does nothing at runtime
6596assert ( { } as z . input < typeof Template > , { } as t . Template )
97+
98+ export { Template }
0 commit comments