@tivio/sdk-react 9.7.0 → 9.8.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.bak CHANGED
@@ -203,21 +203,44 @@ user.deleteUserProfile(profileId: string): Promise<void>
203
203
 
204
204
  ## Content
205
205
 
206
- ### Assets
206
+ ### Tiles and assets
207
207
 
208
- In order to obtain assets (images) from a Video or Tag, you can use these methods:
208
+ A **tile** is a single item rendered inside a content row. The tile is the
209
+ same entity the row points to (a `Video`, `Tag`, `TvChannel`, `Series`,
210
+ `Article` or `Application`), so anything you can read off the entity (name,
211
+ description, ids, monetization flags, …) is also available directly on the
212
+ tile returned by `useItemsInRow` / `row.tiles`.
209
213
 
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)
214
+ Each tile carries several named image **assets** so the same entity can be
215
+ rendered in different shapes without an extra fetch. Every named getter is a
216
+ shortcut into the underlying `tile.assets` map use the map directly if you
217
+ need a custom asset that does not have a dedicated getter.
216
218
 
217
- #### Tag only
218
- - `tag.bannerMobile` - banner image mobile
219
+ **Shared across all entity types**
219
220
 
220
- __All of the assets fallback to type cover or empty string if cover is not available__
221
+ - `tile.landscape` 16:9 thumbnail (standard rows)
222
+ - `tile.portrait` — 2:3 poster (portrait rows)
223
+ - `tile.circled` — 1:1 circular crop (e.g. creators)
224
+ - `tile.square` — 1:1 square (square rows)
225
+ - `tile.banner` — 16:9 hero banner (banner rows / top of screens)
226
+ - `tile.bannerMobile` — narrow 16:9 banner variant for phones
227
+ - `tile.assets` — raw `{ [assetName]: ScalableAsset }` map behind the getters
228
+
229
+ **Extras by entity type (on top of the shared set above)**
230
+
231
+ - `Video` — `detailBanner` (backdrop above the player), `image`, `cover`
232
+ (deprecated, kept for compatibility), `backgroundBlurBannerMobile`
233
+ - `Tag` / `Article` / `Series` — `detailBanner`, `cover`
234
+ - `TvChannel` — `logo`, `logoPendingOverlayWidth`, `cover`
235
+ - `Application` — read via `tile.application`: `logo`, `logoLandscape`,
236
+ `profilePhoto`
237
+
238
+ If an asset is not set on the entity, the getter returns `null` rather than
239
+ throwing, so it's safe to fall back from a specific variant to a more
240
+ generic one (for example `tile.landscape ?? tile.banner ?? tile.cover`).
241
+
242
+ A live example that renders the same video through every getter is included
243
+ in `examples/sdk-react/src/index.tsx` (`createAssetsShowcaseDemo`).
221
244
 
222
245
  ### Get content based on user profile
223
246
 
@@ -326,6 +349,19 @@ const favorites = await tivio.getUser()?.favorites
326
349
  favorites[0]?.removeFromFavorites()
327
350
  ```
328
351
 
352
+ ### Add to/remove from favorites by path
353
+
354
+ You can also add or remove favorites using content paths directly:
355
+ ```typescript
356
+ // Add to favorites by path
357
+ await tivio.addToFavoritesByPath('videos/videoId')
358
+ await tivio.addToFavoritesByPath('tags/tagId')
359
+
360
+ // Remove from favorites by path
361
+ await tivio.removeFromFavoritesByPath('videos/videoId')
362
+ await tivio.removeFromFavoritesByPath('tags/tagId')
363
+ ```
364
+
329
365
  > ℹ️ **_Note:_** When user saves favorite without profileId, it will only be shown if the app doesn't have any active user profile.
330
366
 
331
367
  ### Get screen by ID
@@ -799,6 +835,22 @@ The `sourcePlayMode` property determines how the content is played:
799
835
  - **LIVE** - Live stream mode with no seeking
800
836
  - **HYBRID** - Combines LIVE with seeking
801
837
 
838
+ #### Player Authentication Configuration
839
+
840
+ Use `disableTvChannelsForAnonymousUsers` property to show overlay to sign in when user is anonymous and tries to play a TV channel (free or monetized).
841
+ Set the property to `true` inside the `player` property in Tivio config.
842
+
843
+ Tivio config:
844
+ ```typescript
845
+ const config = {
846
+ // ... other config properties
847
+ player: {
848
+ // ... other player properties
849
+ disableTvChannelsForAnonymousUsers: true, // or false
850
+ },
851
+ }
852
+ ```
853
+
802
854
  #### User Authentication Callbacks
803
855
 
804
856
  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).
@@ -906,11 +958,115 @@ The `setSource` method is particularly useful for:
906
958
  - Implementing playlists
907
959
  - Dynamic content loading
908
960
 
961
+ #### Minimal OSD / Sticky Mini Player
962
+
963
+ The player supports a minimal OSD mode designed for small or pinned containers such as a
964
+ scroll-fixed "mini" player. When enabled, only the essential controls are rendered:
965
+
966
+ - `play` / `pause` (small button in the bottom-left corner)
967
+ - `volume`
968
+ - `fullscreen`
969
+
970
+ The mode can be toggled in two ways:
971
+
972
+ 1. Declaratively, via the `isMinimal` prop on `WebPlayerProps`.
973
+ 2. Imperatively, via the vanilla controller's `setIsMinimal(isMinimal: boolean)` method — useful
974
+ for switching on/off at runtime (e.g. when the player becomes pinned after the user scrolls
975
+ past it).
976
+
977
+ **Example: scroll-pinned mini player**
978
+
979
+ The layout is driven entirely by CSS — the JS only toggles an `is-floating` class and calls
980
+ `setIsMinimal(true|false)` accordingly. Responsive behavior (desktop corner vs. mobile
981
+ top-full-width) is handled with a media query, so there is no need to watch viewport size from
982
+ React/JS.
983
+
984
+ ```html
985
+ <section class="mini-player-demo">
986
+ <div class="mini-player-anchor">
987
+ <div class="mini-player" id="mini-player"></div>
988
+ </div>
989
+ <!-- ...page content... -->
990
+ </section>
991
+ ```
992
+
993
+ ```css
994
+ .mini-player-anchor {
995
+ position: relative;
996
+ width: 100%;
997
+ aspect-ratio: 16 / 9;
998
+ }
999
+
1000
+ .mini-player {
1001
+ position: absolute;
1002
+ inset: 0;
1003
+ background: #000;
1004
+ }
1005
+
1006
+ /* Floating (desktop): pinned to bottom-right. */
1007
+ .mini-player.is-floating {
1008
+ position: fixed;
1009
+ inset: auto 24px 24px auto;
1010
+ width: 360px;
1011
+ aspect-ratio: 16 / 9;
1012
+ z-index: 1000;
1013
+ border-radius: 8px;
1014
+ overflow: hidden;
1015
+ box-shadow: 0 12px 32px rgba(0, 0, 0, 0.45);
1016
+ }
1017
+
1018
+ /* Floating (narrow viewports): pinned to top, full width. */
1019
+ @media (max-width: 600px) {
1020
+ .mini-player.is-floating {
1021
+ inset: 0 0 auto 0;
1022
+ width: 100%;
1023
+ border-radius: 0;
1024
+ }
1025
+ }
1026
+ ```
1027
+
1028
+ ```ts
1029
+ import { renderWebPlayer } from '@tivio/sdk-react'
1030
+
1031
+ const container = document.getElementById('mini-player')!
1032
+ const anchor = document.querySelector('.mini-player-anchor')!
1033
+
1034
+ const controller = await renderWebPlayer(container, {
1035
+ id: 'mini-player',
1036
+ source: 'videos/YOUR_VIDEO_ID',
1037
+ isSameSizeAsParent: true,
1038
+ isMutedByDefault: true,
1039
+ autoplay: true,
1040
+ })
1041
+
1042
+ // Pop out of the flow once the inline anchor leaves the viewport,
1043
+ // and switch the OSD between minimal and default accordingly.
1044
+ new IntersectionObserver(
1045
+ ([entry]) => {
1046
+ const isFloating = !entry.isIntersecting
1047
+ container.classList.toggle('is-floating', isFloating)
1048
+ controller.setIsMinimal(isFloating)
1049
+ },
1050
+ { threshold: 0.1 },
1051
+ ).observe(anchor)
1052
+ ```
1053
+
1054
+ Notes:
1055
+ - The anchor stays in the flow with its original 16:9 size, so the page layout does not jump
1056
+ when the player detaches.
1057
+ - The desktop/mobile floating layout is fully CSS-driven; resizing the browser window
1058
+ updates it live with no extra JS.
1059
+
1060
+ You can see this pattern in action in `examples/sdk-react/src/index.tsx` (the
1061
+ `createStickyMiniPlayerDemo` function) with styles in `examples/sdk-react/src/index.css`.
1062
+
909
1063
  **Event Handling:**
910
1064
  - `addEventListener(event: string, callback: (value: T) => void)` - Add event listener
911
1065
  - `removeEventListener(event: string, callback: (value: T) => void)` - Remove event listener
912
1066
 
913
1067
  **Utility:**
1068
+ - `setIsMinimal(isMinimal: boolean)` - Toggle the minimal OSD mode at runtime (see
1069
+ [Minimal OSD / Sticky Mini Player](#minimal-osd--sticky-mini-player))
914
1070
  - `destroy()` - Destroy player and clean up resources
915
1071
 
916
1072
  #### Playback Events
@@ -1111,6 +1267,11 @@ The `WebPlayerProps` interface defines the properties that can be passed to the
1111
1267
  - **`showTvStreamType`** (optional): Whether to show TV stream type indicator
1112
1268
  - **`showCookiesSettings`** (optional): Whether to show cookies settings
1113
1269
  - **`showOsd`** (optional, default: `true`): Whether to show the On-Screen Display (OSD)
1270
+ - **`isMinimal`** (optional, default: `false`): If `true`, the player uses a minimal OSD that
1271
+ exposes only `play`/`pause`, `volume` and `fullscreen` controls. A small center play/pause
1272
+ icon flashes briefly when the state toggles and then fades out.
1273
+ Designed for small/pinned containers such as scroll-fixed mini players. See
1274
+ [Minimal OSD / Sticky Mini Player](#minimal-osd--sticky-mini-player) for usage details.
1114
1275
  - **`showBufferingSpinner`** (optional, default: `true`): Whether to show buffering spinner
1115
1276
 
1116
1277
  ### Audio Properties
package/dist/index.d.ts CHANGED
@@ -104,6 +104,7 @@ export declare type AdMetadata = {
104
104
  isSkippable: boolean;
105
105
  order: number | null;
106
106
  totalCount: number | null;
107
+ adPlacementStrategy: AdPlacementStrategy;
107
108
  customAdMetadata?: Record<string, unknown>;
108
109
  skip: () => void;
109
110
  } | null;
@@ -118,7 +119,10 @@ export declare interface AdPackInfo {
118
119
  total: number;
119
120
  }
120
121
 
122
+ export declare type AdPlacementStrategy = 'preroll' | 'midroll' | 'postroll' | 'replacement';
123
+
121
124
  export declare interface AdSegment {
125
+ adPlacementStrategy: AdPlacementStrategy;
122
126
  id: string;
123
127
  /**
124
128
  * @deprecated alias to secondsToEnd * 1000
@@ -183,6 +187,7 @@ export declare interface AdSourceActions {
183
187
  */
184
188
  export declare interface AdSourceInterface extends CommonSourceInterface<SourceType.ADVERTISEMENT> {
185
189
  adType: AdType;
190
+ adPlacementStrategy: AdPlacementStrategy;
186
191
  durationMs: number;
187
192
  skipDelayMs: number | null;
188
193
  /**
@@ -233,6 +238,7 @@ export declare interface AdSourceInterface extends CommonSourceInterface<SourceT
233
238
  */
234
239
  export declare interface AdSourceParams extends CommonSourceParams<SourceType.ADVERTISEMENT> {
235
240
  id: string;
241
+ adPlacementStrategy: AdPlacementStrategy;
236
242
  adType?: AdType;
237
243
  actions?: AdSourceActions | null;
238
244
  apiFramework?: VastApiFramework | null;
@@ -737,6 +743,7 @@ export declare interface ChannelSourceInterface extends PlayerSourceInterface<So
737
743
  to: Date;
738
744
  poster: string | null;
739
745
  tvMode: TvMode | 'live' | null;
746
+ clone: (params?: Partial<ChannelSourceParams>) => ChannelSourceInterface;
740
747
  }
741
748
 
742
749
  /**
@@ -1319,6 +1326,9 @@ export declare interface DidomiWindow {
1319
1326
  * https://developers.didomi.io/cmp/web-sdk/reference/api
1320
1327
  */
1321
1328
  didomiOnReady: (() => void)[];
1329
+ Didomi?: {
1330
+ getUserConsentStatusForPurpose: (category: string) => boolean;
1331
+ };
1322
1332
  }
1323
1333
 
1324
1334
  /**
@@ -1643,7 +1653,8 @@ export declare enum ForbiddenReason {
1643
1653
  NAME_CONTAINS_INVALID_CHAR = "NAME_CONTAINS_INVALID_CHAR",
1644
1654
  USER_ACCOUNT_LOCKED = "USER_ACCOUNT_LOCKED",
1645
1655
  USER_NOT_FOUND = "USER_NOT_FOUND",
1646
- UNSUPPORTED_BROWSER = "UNSUPPORTED_BROWSER"
1656
+ UNSUPPORTED_BROWSER = "UNSUPPORTED_BROWSER",
1657
+ ANONYMOUS_USER = "ANONYMOUS_USER"
1647
1658
  }
1648
1659
 
1649
1660
  /**
@@ -1869,6 +1880,10 @@ export declare interface GetSourceUrlResponse {
1869
1880
  * Determines session type generated for source. If no provided it will be considered 'ondemand' session type.
1870
1881
  */
1871
1882
  sessionType?: VideoSourceField['sessionType'];
1883
+ /**
1884
+ * Language of the source.
1885
+ */
1886
+ language?: LangCode;
1872
1887
  }
1873
1888
 
1874
1889
  export declare type GetTilesInRowResponse<U extends NextPageParamType = NextPageParamType> = PaginatedResponse<TileData, U>;
@@ -3277,6 +3292,11 @@ export declare type PlayerConfig = {
3277
3292
  */
3278
3293
  name: 'IMA SDK' | 'TIVIO AD SERVICE';
3279
3294
  };
3295
+ /**
3296
+ * If true, then TV channels are not available for anonymous users and they will be shown an overlay to sign in.
3297
+ * @default false
3298
+ */
3299
+ disableTvChannelsForAnonymousUsers?: boolean;
3280
3300
  };
3281
3301
 
3282
3302
  /**
@@ -3400,6 +3420,11 @@ export declare interface PlayerEngineInterface {
3400
3420
  */
3401
3421
  setPlaysInline(value: boolean): void;
3402
3422
  setControlsList(value: string[]): void;
3423
+ /** Gets resolution of the video element in pixels - container size, not the actual source quality resolution */
3424
+ getVideoResolution(): {
3425
+ width: number;
3426
+ height: number;
3427
+ };
3403
3428
  }
3404
3429
 
3405
3430
  /**
@@ -3495,6 +3520,11 @@ export declare interface PlayerInterface {
3495
3520
  */
3496
3521
  setPlaysInline?: (value: boolean) => void;
3497
3522
  setControlsList?: (value: string[]) => void;
3523
+ /** Gets resolution of the video element in pixels - container size, not the actual source quality resolution */
3524
+ getVideoResolution(): {
3525
+ width: number;
3526
+ height: number;
3527
+ };
3498
3528
  }
3499
3529
 
3500
3530
  /**
@@ -3597,6 +3627,13 @@ export declare type PlayerState = 'idle' | 'playing' | 'paused';
3597
3627
  * @public
3598
3628
  */
3599
3629
  export declare interface PlayerWrapper {
3630
+ /**
3631
+ * Unique id of the player wrapper instance, set at construction time
3632
+ * (e.g. by `tivio.getPlayerWrapper(id)`). Used to scope DOM ids of
3633
+ * player-owned elements (IMA ad containers, content video element, …)
3634
+ * so multiple players on the same page don't collide.
3635
+ */
3636
+ readonly id: string;
3600
3637
  /**
3601
3638
  * Report that playback of video has finished
3602
3639
  */
@@ -3701,6 +3738,10 @@ export declare interface PlayerWrapper {
3701
3738
  setCanPlay: (canPlay: boolean) => void;
3702
3739
  toggleMuted: () => void;
3703
3740
  getQualities: () => Track[];
3741
+ getVideoResolution: () => {
3742
+ width: number;
3743
+ height: number;
3744
+ };
3704
3745
  playNativeImaAd: (url: string) => void;
3705
3746
  playSourceAfterAdsRun: () => void;
3706
3747
  putAd: (ad: AdSourceInterface) => void;
@@ -5485,6 +5526,18 @@ export declare interface SimplifiedVideoController {
5485
5526
  */
5486
5527
  setSource(source: WebPlayerProps['source']): void;
5487
5528
  setAdsConfig(adsConfig: StaticAdsBreak[]): void;
5529
+ /**
5530
+ * Toggle the minimal OSD mode.
5531
+ *
5532
+ * When enabled, the player shows only a minimal set of controls (play/pause,
5533
+ * volume and fullscreen) and a small center play/pause icon that briefly
5534
+ * flashes when the state changes. Intended for small/pinned containers such
5535
+ * as a scroll-fixed mini player in the corner of the page or a full-width
5536
+ * mobile player pinned to the top of the viewport.
5537
+ *
5538
+ * @param isMinimal - Whether the minimal OSD should be used
5539
+ */
5540
+ setIsMinimal(isMinimal: boolean): void;
5488
5541
  /**
5489
5542
  * Destroy the player and clean up all resources
5490
5543
  */
@@ -5604,7 +5657,7 @@ export declare interface StartLiveStreamResponse {
5604
5657
  error?: string;
5605
5658
  }
5606
5659
 
5607
- export declare type StaticAdsBreak = StaticAdsBreakPostrollPreroll | StaticAdsBreakMidroll;
5660
+ export declare type StaticAdsBreak = StaticAdsBreakPostrollPreroll | StaticAdsBreakMidroll | StaticAdsBreakReplacement;
5608
5661
 
5609
5662
  export declare interface StaticAdsBreakMidroll {
5610
5663
  type: 'midroll';
@@ -5617,6 +5670,11 @@ declare interface StaticAdsBreakPostrollPreroll {
5617
5670
  url: string;
5618
5671
  }
5619
5672
 
5673
+ export declare interface StaticAdsBreakReplacement {
5674
+ type: 'replacement';
5675
+ url: string;
5676
+ }
5677
+
5620
5678
  /**
5621
5679
  * @public
5622
5680
  */
@@ -6421,6 +6479,8 @@ export declare type TivioReactBundle = {
6421
6479
  */
6422
6480
  internal: TivioInternalBundle;
6423
6481
  analytics: TivioAnalytics;
6482
+ addToFavoritesByPath: (path: string) => Promise<void>;
6483
+ removeFromFavoritesByPath: (path: string) => Promise<void>;
6424
6484
  destroy: () => Promise<void>;
6425
6485
  } & Pick<TivioSetters, 'setBundleVersion' | 'setUser' | 'setLanguage' | 'setStorageManager'> & Omit<Partial<TivioJsBundleExposedApi>, 'createPlayerWrapper'>;
6426
6486
 
@@ -7820,7 +7880,7 @@ export declare interface ViewCountItem {
7820
7880
  /**
7821
7881
  * @public
7822
7882
  */
7823
- export declare interface VirtualChannelSourceInterface extends ChannelSourceInterface {
7883
+ export declare interface VirtualChannelSourceInterface extends Omit<ChannelSourceInterface, 'clone'> {
7824
7884
  tvChannelType: TvChannelType.VIRTUAL;
7825
7885
  program?: TvProgram | null;
7826
7886
  video?: Video | null;
@@ -8330,6 +8390,14 @@ export declare interface WebPlayerProps {
8330
8390
  * If true then OSD is shown based on condition resolved in HidableOsdContainer, e.g. on pause, on mouse move etc.
8331
8391
  */
8332
8392
  showOsd?: boolean;
8393
+ /**
8394
+ * If true, then only a minimal set of OSD controls is shown (play/pause, volume, fullscreen)
8395
+ * and the big center play/pause button only flashes briefly on state change.
8396
+ *
8397
+ * Intended for small fixed containers (e.g. a scroll-pinned mini player in the corner
8398
+ * of the page, or a full-width mobile player pinned to the top of the viewport).
8399
+ */
8400
+ isMinimal?: boolean;
8333
8401
  /**
8334
8402
  * If false, then buffering spinner is never shown.
8335
8403
  * If true then buffering spinner is shown while buffering.