@tivio/sdk-react 9.7.1 → 10.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -63,301 +63,6 @@ const config: Config = {
63
63
  };
64
64
  ```
65
65
 
66
- ### Create user with email and password
67
-
68
- Returns user's firebase uid or null if error occurs
69
-
70
- ```typescript
71
- tivio.createUserWithEmailAndPassword(email: string, password: string, username: string, phoneNumber?: string | undefined): Promise<string | null>
72
- ```
73
- **Example**
74
- ```typescript
75
- await tivio.createUserWithEmailAndPassword('test@example.com', 'password', 'Fist & Last Name', '+420777123456')
76
- ```
77
-
78
- ### Sign in with email and password
79
-
80
- Returns user's firebase uid or null if error occurs
81
-
82
- ```typescript
83
- tivio.signInWithEmailAndPassword(email: string, password: string): Promise<string | null>
84
- ```
85
- **Example**
86
- ```typescript
87
- await tivio.signInWithEmailAndPassword('test@example.com', 'password')
88
- ```
89
-
90
- ### Sign out
91
-
92
- ```typescript
93
- tivio.signOut(): Promise<void>
94
- ```
95
-
96
- ### Reset password
97
-
98
- Send email with password reset link to the user with given email address
99
-
100
- ```typescript
101
- tivio.resetPassword(email: string): Promise<void>
102
- ```
103
-
104
- ## User entity
105
-
106
- ### Get user
107
-
108
- Returns user object or null if user is not authenticated
109
-
110
- ```typescript
111
- tivio.getUser(): Promise<User | null>
112
- ```
113
-
114
- ### Essential Properties
115
-
116
- #### Basic Information
117
- - `id: string` - Unique Tivio user ID
118
- - `email?: string` - Email address
119
- - `name?: string` - Display name - could be nickname, first name and last name, etc.
120
-
121
- #### Authentication Status
122
- - `isSignedIn: boolean` - Whether the user is currently signed in
123
- - `isReady: boolean` - Whether user data is fully loaded
124
- - `isAnonymous: boolean` - Whether this is an anonymous user
125
-
126
- #### Content & Preferences
127
- - `purchases: Purchase[]` - Active purchases (excluding vouchers)
128
-
129
- #### User Profiles
130
- - `profiles: UserProfile[]` - Available user profiles (e.g. multiple people can use the same user account with different preferences)
131
- - `activeUserProfileId: string | null` - Currently active profile
132
-
133
- ### Essential Methods
134
-
135
- #### Authentication
136
- ```typescript
137
- changePassword(oldPassword: string, newPassword: string): Promise<void>
138
- ```
139
-
140
- #### Profile Management
141
-
142
- #### Create user profile
143
-
144
- ```typescript
145
- interface CreateUserProfileRequest {
146
- /**
147
- * Profile name - typically first name and last name, but users can fill in whatever they want.
148
- */
149
- name: string
150
- /**
151
- * Filled in values for user profile survey. See {@link OrganizationDocument} its configuration.
152
- */
153
- survey?: ProfileSurvey
154
- }
155
- interface ProfileSurvey {
156
- gender?: Translation
157
- age?: AgeRange
158
- }
159
- interface AgeRange {
160
- from: number
161
- /**
162
- * If not set, we assume the range is not closed and {@property to} is set to infinity
163
- * (there are no values to represent {@link Infinity} in firestore, so we use undefined instead).
164
- */
165
- to?: number
166
- /**
167
- * If set, we assume that this is a profile for kids only (e.g. 0-12).
168
- * This value can only be `true` or not specified (undefined).
169
- */
170
- kidsOnly?: true
171
- }
172
- createUserProfile(request: CreateUserProfileRequest): Promise<void>
173
- ```
174
- **Example**
175
- ```typescript
176
- await user.createUserProfile({
177
- name: 'John Doe',
178
- survey: {
179
- gender: {
180
- cs: "Žena",
181
- en: "Female",
182
- sk: "Žena"
183
- },
184
- age: {
185
- from: 18,
186
- to: 24
187
- }
188
- }
189
- })
190
- ```
191
-
192
- #### Set active user profile
193
-
194
- ```typescript
195
- user.setActiveUserProfileId(profileId: string): void
196
- ```
197
-
198
- #### Delete user profile
199
-
200
- ```typescript
201
- user.deleteUserProfile(profileId: string): Promise<void>
202
- ```
203
-
204
- ## Content
205
-
206
- ### Assets
207
-
208
- In order to obtain assets (images) from a Video or Tag, you can use these methods:
209
-
210
- #### Video or Tag
211
- - `video.cover` - cover image (landscape)
212
- - `video.banner` - banner image
213
- - `video.circled` - circled image
214
- - `video.detailBanner` - detail banner image (landscape)
215
- - `video.portrait` - portrait image (portrait)
216
-
217
- #### Tag only
218
- - `tag.bannerMobile` - banner image mobile
219
-
220
- __All of the assets fallback to type cover or empty string if cover is not available__
221
-
222
- ### Get content based on user profile
223
-
224
- ```typescript
225
- interface GetUserProfileDataOptions {
226
- /**
227
- * If true, the data will be returned for all user profiles.
228
- * If false, the data will be returned only for the active user profile.
229
- */
230
- ignoreActiveUserProfile?: boolean
231
- }
232
-
233
- getFavorites(options?: GetUserProfileDataOptions): Promise<FavoriteWithData[]>
234
- getWatchPositions(options?: GetUserProfileDataOptions): Promise<WatchPositionWithData[]>
235
- getWatchHistory(options?: GetUserProfileDataOptions): Promise<WatchPositionWithData[]>
236
- ```
237
-
238
- ### Get user favorites
239
-
240
- ```typescript
241
- interface FavoriteWithData {
242
- content: Video | Tag
243
- type: 'video' | 'tag' // Filtering by this type will set the content type to be Video or Tag
244
- profileId?: string
245
- }
246
-
247
- getFavorites(options?: GetUserProfileDataOptions): Promise<FavoriteWithData[]>
248
- ```
249
- **Example**
250
- ```typescript
251
- const favorites = await user.getFavorites()
252
- favorites.forEach(favorite => {
253
- console.log({
254
- name: favorite.name,
255
- cover: favorite.cover, // cover image (landscape)
256
- portrait: favorite.portrait, // portrait image (portrait)
257
- })
258
- })
259
- ```
260
-
261
- ### Get user watch positions
262
-
263
- ```typescript
264
- interface WatchPositionWithData {
265
- position: number
266
- video: Video
267
- tag?: Tag
268
- episodeNumber?: number
269
- seasonNumber?: number
270
- videoDuration?: number
271
- }
272
-
273
- getWatchPositions(options?: GetUserProfileDataOptions): Promise<WatchPositionWithData[]>
274
- ```
275
- **Example**
276
- ```typescript
277
- const watchPositions = await user.getWatchPositions()
278
- watchPositions.forEach(watchPosition => {
279
- console.log({
280
- position: watchPosition.position, // watch position in milliseconds
281
- videoName: watchPosition.video.name,
282
- videoCover: watchPosition.video.cover,
283
- tagName: watchPosition.tag?.name, // optional tag for series
284
- episodeNumber: watchPosition.episodeNumber, // optional episode number
285
- seasonNumber: watchPosition.seasonNumber, // optional season number
286
- videoDuration: watchPosition.videoDuration, // optional video duration
287
- })
288
- })
289
- ```
290
-
291
- ### Get user watch history
292
-
293
- ```typescript
294
- getWatchHistory(options?: GetUserProfileDataOptions): Promise<WatchPositionWithData[]>
295
- ```
296
- **Example**
297
- ```typescript
298
- const watchHistory = await user.getWatchHistory()
299
- watchHistory.forEach(watchPosition => {
300
- console.log({
301
- position: watchPosition.position, // watch position in milliseconds
302
- videoName: watchPosition.video.name,
303
- videoCover: watchPosition.video.cover,
304
- tagName: watchPosition.tag?.name, // optional tag for series
305
- episodeNumber: watchPosition.episodeNumber, // optional episode number
306
- seasonNumber: watchPosition.seasonNumber, // optional season number
307
- videoDuration: watchPosition.videoDuration, // optional video duration
308
- })
309
- })
310
- ```
311
-
312
- ### Add to/remove from favorites
313
-
314
- Simply call addToFavorites or removeFromFavorites on the Video or Tag.
315
- ```typescript
316
- const video = await tivio.getVideoById('videoId')
317
- await video.addToFavorites()
318
- await video.removeFromFavorites()
319
-
320
- const tag = await tivio.getTagById('tagId')
321
- await tag.addToFavorites()
322
- await tag.removeFromFavorites()
323
-
324
- // Remove a favorite from favorites
325
- const favorites = await tivio.getUser()?.favorites
326
- favorites[0]?.removeFromFavorites()
327
- ```
328
-
329
- > ℹ️ **_Note:_** When user saves favorite without profileId, it will only be shown if the app doesn't have any active user profile.
330
-
331
- ### Get screen by ID
332
-
333
- ```typescript
334
- getScreenById(screenId: string): Promise<Screen | null>
335
- ```
336
-
337
- ### Get row by ID
338
-
339
- ```typescript
340
- getRowById(rowId: string): Promise<Row | null>
341
- ```
342
-
343
- ### Get video by ID
344
-
345
- ```typescript
346
- getVideoById(videoId: string): Promise<Video | null>
347
- ```
348
-
349
- ### Get tag by ID
350
-
351
- ```typescript
352
- getTagById(tagId: string): Promise<Tag | null>
353
- ```
354
-
355
- ### Get TV Channel by ID
356
-
357
- ```typescript
358
- getTvChannelById(tvChannelId: string): Promise<TvChannel | null>
359
- ```
360
-
361
66
  ## Player
362
67
 
363
68
  You can choose whether you will use complete player component provided by Tivio or you will wrap your existing player
@@ -593,64 +298,10 @@ The VideoController returned by `renderWebPlayer` provides the following methods
593
298
 
594
299
  The Tivio player supports different types of sources:
595
300
 
596
- **PathSourceParams** - Path-based sources with ad configuration
597
- - Used for playing Tivio-hosted videos and TV channels with custom VAST ad configurations
598
- - Supports both `videos/ID` and `tvChannels/ID` paths
599
- - Includes `staticAdsConfig` for custom VAST ad insertion
600
- - Example usage:
601
- ```typescript
602
- const sourceWithAds = {
603
- path: 'videos/123', // or 'tvChannels/456'
604
- staticAdsConfig: [
605
- {
606
- type: 'preroll',
607
- url: 'https://example.com/vast-preroll-ad.xml',
608
- },
609
- {
610
- type: 'midroll',
611
- from: 30000, // 30 seconds
612
- url: 'https://example.com/vast-midroll-ad.xml',
613
- },
614
- {
615
- type: 'postroll',
616
- url: 'https://example.com/vast-postroll-ad.xml',
617
- },
618
- ],
619
- }
620
- ```
621
-
622
- **VOD_TIVIO** - Tivio-hosted video-on-demand content
623
- - Used for playing videos that are hosted within Tivio's infrastructure
624
- - Example usage:
625
- ```typescript
626
- const vodSource = {
627
- type: SourceType.VOD_TIVIO,
628
- videoPath: 'videos/123', // Video path
629
- sourcePlayMode: SourcePlayMode.ON_DEMAND,
630
- name: 'Tivio Video',
631
- autoplay: false,
632
- continuePositionMs: 10000, // Start at 10 seconds (optional)
633
- }
634
- ```
635
-
636
- **CHANNEL** - TV channel content (both classic and virtual channels)
637
- - Used for playing live TV channels
638
- - Example usage:
639
- ```typescript
640
- const channelSource = {
641
- type: SourceType.CHANNEL,
642
- path: 'tvChannels/456', // TV channel path
643
- sourcePlayMode: SourcePlayMode.LIVE,
644
- name: 'TV Channel',
645
- autoplay: true,
646
- }
647
- ```
648
-
649
301
  **VOD_EXTERNAL** - External video-on-demand content from third-party URLs
650
302
  - Used for playing videos that are hosted outside of Tivio's infrastructure
651
303
  - Supports various streaming protocols (HLS, DASH, MP4)
652
- - Optionally, you can include `staticAdsConfig` for custom ad insertion
653
- - Example usage (single url):
304
+ - Example usage:
654
305
  ```typescript
655
306
  const externalSource = {
656
307
  type: SourceType.VOD_EXTERNAL,
@@ -660,137 +311,9 @@ const externalSource = {
660
311
  name: 'External Video',
661
312
  autoplay: false,
662
313
  continuePositionMs: 10000, // Start at 10 seconds (optional)
663
- staticAdsConfig: [
664
- {
665
- type: 'preroll',
666
- url: 'https://example.com/preroll-ad.xml',
667
- },
668
- {
669
- type: 'midroll',
670
- from: 20000, // 20 seconds
671
- url: 'https://example.com/midroll-ad.xml',
672
- },
673
- ],
674
- }
675
- ```
676
-
677
- **Path-Based Sources**
678
- You can also use simple path strings for both video and TV channel sources:
679
- ```typescript
680
- // Video path
681
- videoController.setSource('videos/123')
682
-
683
- // TV channel path
684
- videoController.setSource('tvChannels/456')
685
- ```
686
-
687
- #### Static Ads Configuration
688
-
689
- > ℹ️ **_Note:_** To enable ad functionality, you must configure the IMA ad service in your Tivio configuration:
690
- > ```typescript
691
- > import { AD_SERVICE_PROXY_NAME } from '@tivio/sdk-react'
692
- >
693
- > const config = {
694
- > // ... other config properties
695
- > player: {
696
- > adService: {
697
- > name: AD_SERVICE_PROXY_NAME.IMA,
698
- > },
699
- > },
700
- > }
701
- > ```
702
-
703
- The `staticAdsConfig` property lets you specify custom ad insertion points within your content.
704
- If multiple ads are set for the same entry point, they will be played one after another in sequence. For example, if you have two preroll ads, the first will play, followed by the second. Similarly, midroll ads that share the same `from` time will be grouped and played sequentially.
705
-
706
- It supports the following ad types:
707
-
708
- **Preroll Ads** - Play before the main content starts
709
- ```typescript
710
- {
711
- type: 'preroll',
712
- url: 'https://example.com/preroll-ad.xml',
713
314
  }
714
315
  ```
715
316
 
716
- **Midroll Ads** - Play during the main content at specified time
717
- ```typescript
718
- {
719
- type: 'midroll',
720
- from: 30000, // Time in milliseconds (30 seconds)
721
- url: 'https://example.com/midroll-ad.xml',
722
- }
723
- ```
724
-
725
- **Postroll Ads** - Play after the main content ends
726
- ```typescript
727
- {
728
- type: 'postroll',
729
- url: 'https://example.com/postroll-ad.xml',
730
- }
731
- ```
732
-
733
- **Complete Example:**
734
- ```typescript
735
- const sourceWithAds = {
736
- path: 'videos/123',
737
- name: 'Video with Multiple Ad Types',
738
- staticAdsConfig: [
739
- // multiple preroll ads
740
- {
741
- type: 'preroll',
742
- url: 'https://vasterix.joj.sk/api/v1/creative?id=0c5d96fd-2ab9-4207-a325-4607437965e3&vast=4.0',
743
- },
744
- {
745
- type: 'preroll',
746
- url: 'https://example.com/preroll-ad.xml',
747
- },
748
- // multiple midroll ads (with same from time)
749
- {
750
- type: 'midroll',
751
- from: 30000, // 30 seconds
752
- url: 'https://example.com/midroll-ad-1.xml',
753
- },
754
- {
755
- type: 'midroll',
756
- from: 30000, // 30 seconds
757
- url: 'https://example.com/midroll-ad-2.xml',
758
- },
759
- // one midroll ad with different from time
760
- {
761
- type: 'midroll',
762
- from: 60000, // 1 minute
763
- url: 'https://example.com/midroll-ad-2.xml',
764
- },
765
- // postroll ad
766
- {
767
- type: 'postroll',
768
- url: 'https://example.com/postroll-ad.xml',
769
- },
770
- ],
771
- }
772
- ```
773
- - It is also possible to set multiple urls for external source type, e.g. when you want to use both DASH and HLS formats. Player then automatically will pick most suitable format to play depending on device capabilities.
774
- - Example usage (multiple urls):
775
- ```typescript
776
- const externalSource = {
777
- type: SourceType.VOD_EXTERNAL,
778
- urls: ['https://example.com/video.m3u8', 'https://example.com/video.mpd'],
779
- sourcePlayMode: SourcePlayMode.ON_DEMAND,
780
- }
781
- ```
782
-
783
- **VOD_TIVIO** - Internal source type for playing content managed by Tivio
784
- - Used for playing videos and tv channels managed by Tivio infrastructure, e.g. everything that is uploaded through Tivio Admin application
785
- - For convenience, it is recommended to use shortcut format and pass the source as string in `${'videos' | 'tvChannels'}/{id}` format
786
- - Ids of corresponding videos and tv channel could be found in Tivio admin application
787
- - Example usage:
788
- ```typescript
789
- const tivioVideoSource = 'videos/2BzH4xsTXW8vqYKJegXj'
790
- const tivioTvChannelSource = 'tvChannels/Ct4UcK6ozX3VfxaL5yP5'
791
- ```
792
- - Otherwise, it is also possible to pass internal tivio source as an object with `type: SourceType.VOD_TIVIO` and additional parameters, similarly to external source type.
793
-
794
317
  #### Source Play Modes
795
318
 
796
319
  The `sourcePlayMode` property determines how the content is played:
@@ -799,56 +322,6 @@ The `sourcePlayMode` property determines how the content is played:
799
322
  - **LIVE** - Live stream mode with no seeking
800
323
  - **HYBRID** - Combines LIVE with seeking
801
324
 
802
- #### User Authentication Callbacks
803
-
804
- The `userAuthCallbacks` property allows you to handle user authentication flows when the player requires user login or registration. This is particularly useful for content that requires authentication (e.g., premium content).
805
-
806
- ```typescript
807
- interface UserAuthCallbacks {
808
- onGoToLogin: () => void
809
- onGoToRegistration: () => void
810
- }
811
- ```
812
-
813
- **Example Implementation:**
814
-
815
- ```typescript
816
- // Usage with renderWebPlayer
817
- const videoController = await renderWebPlayer(
818
- document.getElementById('video-player'),
819
- {
820
- id: 'player-main',
821
- source: 'videos/PREMIUM_VIDEO_ID',
822
- userAuthCallbacks: {
823
- onGoToLogin: () => {
824
- // Show your login modal
825
- setShowLoginModal(true)
826
- },
827
- onGoToRegistration: () => {
828
- // Show your registration modal
829
- setShowRegistrationModal(true)
830
- },
831
- },
832
- }
833
- )
834
-
835
- // Handle login in your modal
836
- const handleLogin = async (email: string, password: string) => {
837
- try {
838
- await tivio.signInWithEmailAndPassword(email, password)
839
- console.log('Login successful')
840
- } catch (error) {
841
- console.error('Login failed:', error)
842
- throw error
843
- }
844
- }
845
- ```
846
-
847
- **When are these callbacks triggered?**
848
-
849
- - **`onGoToLogin`**: Called when the player is trying to play content behind a paywall and user clicks on the login button in the overlay
850
- - **`onGoToRegistration`**: Called when the player is trying to play content behind a paywall and user clicks on the registration button in the overlay
851
-
852
325
  #### Using setSource with VideoController
853
326
 
854
327
  The `setSource` method allows you to dynamically change what's playing:
@@ -857,23 +330,6 @@ The `setSource` method allows you to dynamically change what's playing:
857
330
  // Change to a different video
858
331
  videoController.setSource('videos/newVideoId')
859
332
 
860
- // Change to a video with custom ads
861
- videoController.setSource({
862
- path: 'videos/newVideoId',
863
- name: 'Video with Ads',
864
- staticAdsConfig: [
865
- {
866
- type: 'preroll',
867
- url: 'https://example.com/preroll-ad.xml',
868
- },
869
- {
870
- type: 'midroll',
871
- from: 30000,
872
- url: 'https://example.com/midroll-ad.xml',
873
- },
874
- ],
875
- })
876
-
877
333
  // Change to an external video
878
334
  videoController.setSource({
879
335
  type: SourceType.VOD_EXTERNAL,
@@ -885,18 +341,6 @@ videoController.setSource({
885
341
  // Change to a TV channel
886
342
  videoController.setSource('tvChannels/channelId')
887
343
 
888
- // Change to a TV channel with custom ads
889
- videoController.setSource({
890
- path: 'tvChannels/channelId',
891
- name: 'TV Channel with Ads',
892
- staticAdsConfig: [
893
- {
894
- type: 'preroll',
895
- url: 'https://example.com/tv-preroll-ad.xml',
896
- },
897
- ],
898
- })
899
-
900
344
  // Stop playback
901
345
  videoController.setSource(null)
902
346
  ```
@@ -917,123 +361,6 @@ The `setSource` method is particularly useful for:
917
361
 
918
362
  The VideoController emits various events that you can listen to:
919
363
 
920
- #### Ad events
921
-
922
- ```typescript
923
- videoController.addEventListener('ad-started', (adMetadata: AdMetadata | null) => {
924
- if (!adMetadata) {
925
- console.log('Ad started playing (no metadata available)')
926
- return
927
- }
928
-
929
- console.log('Ad started playing', adMetadata)
930
-
931
- if ('customAdMetadata' in adMetadata && adMetadata.customAdMetadata) {
932
- console.log('Ad custom metadata:', adMetadata.customAdMetadata)
933
- // customAdMetadata contains VAST trafficking parameters (from VAST AdParameters tag)
934
- }
935
-
936
- // Access CTA element for rendering custom call-to-action buttons
937
- const { ctaElement } = adMetadata
938
- if (ctaElement) {
939
- console.log('CTA element available for rendering custom buttons', ctaElement)
940
-
941
- const { customAdMetadata } = adMetadata
942
- if (!customAdMetadata) {
943
- console.log('No custom ad metadata available')
944
- return
945
- }
946
-
947
- const { extensions } = customAdMetadata
948
- if (!extensions) {
949
- console.log('No extensions available')
950
- return
951
- }
952
-
953
- const { parameters } = extensions[0]
954
- if (!parameters) {
955
- console.log('No parameters available')
956
- return
957
- }
958
-
959
- const metadataParameters = parameters as {
960
- main_title?: string
961
- subtitle?: string
962
- image?: string
963
- button_text: string
964
- url: string
965
- }
966
-
967
- const buttonText = metadataParameters.button_text as string | undefined
968
-
969
- if (!buttonText) {
970
- console.log('No button text available')
971
- return
972
- }
973
-
974
- // Example: Create a custom CTA button using React portal
975
- const CTAButton = () => (
976
- <div style={{
977
- position: 'absolute',
978
- bottom: '20px',
979
- right: '20px',
980
- backgroundColor: 'rgba(0, 0, 0, 0.8)',
981
- color: 'white',
982
- padding: '12px 24px',
983
- borderRadius: '6px',
984
- cursor: 'pointer',
985
- fontSize: '16px',
986
- fontWeight: 'bold',
987
- pointerEvents: 'auto',
988
- }}>
989
- Learn More
990
- </div>
991
- )
992
-
993
- // Render the CTA button using React portal
994
- const root = ReactDOM.createRoot(ctaElement)
995
- root.render(<CTAButton />)
996
- }
997
-
998
- // adMetadata contains information like:
999
- // - ctaElement?: HTMLElement (for rendering custom CTA buttons)
1000
- // - customAdMetadata?: Record<string, unknown> (for IMA ads with rich metadata)
1001
- // - type: 'ad'
1002
- // - subType: 'inserted' | 'original'
1003
- // - secondsToEnd: number
1004
- // - secondsToSkippable: number | null
1005
- // - canTriggerSkip: boolean
1006
- // - isSkippable: boolean
1007
- // - order: number | null
1008
- // - totalCount: number | null
1009
- // - skip: () => void
1010
- // Update UI, show ad overlay, etc.
1011
- })
1012
-
1013
- videoController.addEventListener('ad-ended', () => {
1014
- console.log('Ad finished playing')
1015
- })
1016
-
1017
- // Companion ads event - fires when companion ads are available for the current ad
1018
- videoController.addEventListener('companion-ads', (companionAds) => {
1019
- console.log('Companion ads available:', companionAds)
1020
-
1021
- // Access companion ad properties using IMA methods
1022
- companionAds.forEach((companionAd, index) => {
1023
- console.log(`Companion Ad ${index + 1}:`, {
1024
- width: companionAd.getWidth(),
1025
- height: companionAd.getHeight(),
1026
- contentType: companionAd.getContentType(),
1027
- // HTML content as string
1028
- content: companionAd.getContent()
1029
- })
1030
- })
1031
- })
1032
- ```
1033
-
1034
- > ℹ️ **_Note:_** The CTA overlay element is visible in the WebPlayer only while an ad is playing and is automatically cleaned up on source changes.
1035
-
1036
- #### Video state changes
1037
364
  ```typescript
1038
365
  // Video state changes
1039
366
  videoController.addEventListener('statechange', (state) => {
@@ -1121,7 +448,7 @@ The `WebPlayerProps` interface defines the properties that can be passed to the
1121
448
 
1122
449
  - **`enableKeyboardShortcuts`** (optional, default: `true`): Whether to enable keyboard shortcuts
1123
450
  - **`customShortcuts`** (optional): Custom keyboard shortcuts configuration:
1124
- ```typescript
451
+ ```typescript
1125
452
  {
1126
453
  toggleFullscreen: number[], // Array of key codes
1127
454
  togglePause: number[],
@@ -1131,7 +458,7 @@ The `WebPlayerProps` interface defines the properties that can be passed to the
1131
458
  volumeUp: number[],
1132
459
  volumeDown: number[]
1133
460
  }
1134
- ```
461
+ ```
1135
462
 
1136
463
  ### Ad Block Properties
1137
464