stormcloud-video-player 0.3.57 → 0.3.58

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.
Files changed (2) hide show
  1. package/README.md +243 -10
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,16 +1,18 @@
1
1
  # Stormcloud Video Player
2
2
 
3
- A professional video player with advanced ad integration for web applications. Built with precision ad break alignment, SCTE-35 signal parsing, custom VAST ad serving, and optional Google IMA SDK integration for seamless ad playback. Now featuring a modern, extensible architecture inspired by react-player.
3
+ A professional video player with advanced ad integration for web applications. Built with precision ad break alignment, SCTE-35 signal parsing, VMAP ad-break scheduling, custom VAST ad serving, and optional Google IMA SDK integration for seamless ad playback. Now featuring a modern, extensible architecture inspired by react-player.
4
4
 
5
5
  ## 🎯 Key Features
6
6
 
7
7
  - **Multi-Format Support**: Automatic detection and playback of HLS streams and regular video files
8
8
  - **Precision Ad Alignment**: Tight synchronization with SCTE-35 CUE-OUT signals
9
+ - **VMAP 1.0 Support**: Schedule pre-roll, mid-roll, and post-roll ad breaks via a VMAP manifest
9
10
  - **Smart Mid-Roll Handling**: Automatic detection and playback of remaining ad portions when joining late
10
- - **Flexible Ad Scheduling**: Support for both SCTE-35 markers and external ad schedules
11
+ - **Flexible Ad Scheduling**: Support for SCTE-35 markers, VMAP manifests, and external ad schedules
11
12
  - **Enhanced UI Controls**: Beautiful, adaptive video controls that work on any background color
12
13
  - **Live Mode Support**: Specialized controls for live streaming with volume adjustment
13
- - **Cross-Platform**: Works on desktop, mobile, tablets, and smart TVs
14
+ - **Cross-Platform & Smart TV Ready**: Desktop, mobile, tablets, LG WebOS, Samsung Tizen, Sony BRAVIA, Android TV, Roku, Apple TV
15
+ - **Automatic Browser Compatibility**: Built-in browser detection, polyfills, and automatic ad-player selection for legacy Smart TVs
14
16
  - **React Ready**: Multiple React components for different use cases
15
17
  - **TypeScript Support**: Full type definitions included
16
18
  - **Professional Architecture**: Modular player system with lazy loading
@@ -39,9 +41,11 @@ function MyVideoApp() {
39
41
  muted={true}
40
42
  controls={true}
41
43
  showCustomControls={true} // Enable enhanced UI controls
44
+ hideLoadingIndicator={false} // Hide the built-in loading spinner
42
45
  allowNativeHls={true} // Allow native HLS for better performance
43
46
  licenseKey="your_license_key_here"
44
47
  vastMode="adstorm" // Use AdStorm mode with HLS ad player
48
+ vmapUrl="https://your-cdn.com/ads.vmap" // Optional VMAP manifest for scheduled breaks
45
49
  style={{ width: "100%", aspectRatio: "16/9" }}
46
50
  wrapperStyle={{ borderRadius: "12px", overflow: "hidden" }}
47
51
  onReady={(player) => {
@@ -77,8 +81,10 @@ function MyVideoApp() {
77
81
  // Stormcloud-specific props
78
82
  allowNativeHls={true}
79
83
  showCustomControls={true}
84
+ hideLoadingIndicator={false}
80
85
  licenseKey="your_license_key_here"
81
86
  vastMode="adstorm" // Use AdStorm mode (or omit for default mode)
87
+ vmapUrl="https://your-cdn.com/ads.vmap" // Optional: VMAP manifest URL
82
88
  onReady={(player) => {
83
89
  console.log("Player is ready!", player);
84
90
  }}
@@ -114,9 +120,12 @@ const player = new StormcloudVideoPlayer({
114
120
  muted: true,
115
121
  allowNativeHls: true, // Enable native HLS when supported
116
122
  showCustomControls: true, // Enable enhanced UI controls
123
+ hideLoadingIndicator: false, // Hide built-in loading spinner
117
124
  lowLatencyMode: false, // Set to true for live streams
118
125
  driftToleranceMs: 3000, // Drift tolerance for live streams
119
126
  licenseKey: "your_license_key_here",
127
+ vastMode: "default", // "adstorm" | "default"
128
+ vmapUrl: "https://your-cdn.com/ads.vmap", // Optional VMAP manifest for scheduled ad breaks
120
129
  onVolumeToggle: () => console.log("Volume toggled"),
121
130
  onFullscreenToggle: () => console.log("Fullscreen toggled"),
122
131
  });
@@ -264,6 +273,7 @@ interface StormcloudPlayerProps {
264
273
  immediateManifestAds?: boolean;
265
274
  debugAdTiming?: boolean;
266
275
  showCustomControls?: boolean;
276
+ hideLoadingIndicator?: boolean; // Hide the built-in loading spinner (default: false)
267
277
  licenseKey?: string;
268
278
  adFailsafeTimeoutMs?: number;
269
279
  minSegmentsBeforePlay?: number; // Number of segments to buffer before starting playback (default: 2)
@@ -271,6 +281,7 @@ interface StormcloudPlayerProps {
271
281
  // Ad player configuration
272
282
  vastMode?: 'adstorm' | 'default'; // VAST mode: 'adstorm' (HLS player + AdStorm VAST endpoint) or 'default' (IMA SDK + /ads/web endpoint) (default: 'default')
273
283
  vastTagUrl?: string; // Custom VAST URL (used in default mode if provided; when not provided, uses /ads/web endpoint)
284
+ vmapUrl?: string; // Optional VMAP 1.0 manifest URL used to schedule pre/mid/post-roll ad breaks
274
285
  adPlayerType?: 'ima' | 'hls'; // Manual override for ad player type (auto-determined by vastMode if not specified)
275
286
 
276
287
  // Event handlers
@@ -347,6 +358,7 @@ interface StormcloudVideoPlayerConfig {
347
358
  muted?: boolean; // Start muted (default: false)
348
359
  allowNativeHls?: boolean; // Use native HLS when available (default: false)
349
360
  showCustomControls?: boolean; // Enable enhanced UI controls (default: false)
361
+ hideLoadingIndicator?: boolean; // Hide the built-in loading spinner (default: false)
350
362
  lowLatencyMode?: boolean; // Enable low-latency mode for live streams (default: false)
351
363
  driftToleranceMs?: number; // Drift tolerance for live streams (default: 1000)
352
364
  immediateManifestAds?: boolean; // Load ads immediately from manifest (default: true)
@@ -355,10 +367,15 @@ interface StormcloudVideoPlayerConfig {
355
367
  adFailsafeTimeoutMs?: number; // Ad timeout in milliseconds (default: 10000)
356
368
  minSegmentsBeforePlay?: number; // Number of segments to buffer before starting playback (default: 2)
357
369
 
370
+ // Ad break timing
371
+ adBreakCheckIntervalMs?: number; // Interval used to re-check an active ad break (default: 1000, min: 250)
372
+ maxAdBreakExtensionMs?: number; // Max time an ad break may be extended past its SCTE-35 duration when ads are still playing/queued (default: 60000)
373
+
358
374
  // Ad configuration
359
375
  vastMode?: 'adstorm' | 'default'; // VAST mode: 'adstorm' (uses HLS player + AdStorm VAST endpoint) or 'default' (uses Google IMA SDK + /ads/web endpoint) (default: 'default')
360
376
  vastTagUrl?: string; // Custom VAST tag URL (used in default mode if provided; when not provided, defaults to /ads/web endpoint)
361
- adPlayerType?: 'ima' | 'hls'; // Manual override for ad player type (auto-determined by vastMode if not specified)
377
+ vmapUrl?: string; // Optional VMAP 1.0 manifest URL used to schedule pre/mid/post-roll ad breaks
378
+ adPlayerType?: 'ima' | 'hls'; // Manual override for ad player type (auto-determined by vastMode/browser if not specified)
362
379
 
363
380
  onVolumeToggle?: () => void; // Callback for volume toggle
364
381
  onFullscreenToggle?: () => void; // Callback for fullscreen toggle
@@ -621,6 +638,94 @@ Final: 3 ads played (perfectly fills 120 seconds)
621
638
  - ✅ **Smart**: Improves calculation as more data is gathered (uses average of fetched durations)
622
639
  - ✅ **Self-Correcting**: Automatically adjusts if actual ad lengths differ from expectations
623
640
 
641
+ ### VMAP Ad Break Scheduling
642
+
643
+ In addition to SCTE-35 markers and continuous-ad-fetch, the player supports **VMAP 1.0** manifests for scheduling ad breaks at specific positions in the timeline. This is ideal for VOD content where you want to declaratively define pre-roll, mid-roll, and post-roll breaks with explicit time offsets.
644
+
645
+ #### Usage
646
+
647
+ Provide a `vmapUrl` in addition to (or instead of) a VAST/AdStorm configuration:
648
+
649
+ ```javascript
650
+ const player = new StormcloudVideoPlayer({
651
+ videoElement: video,
652
+ src: "https://your-stream.com/video.m3u8",
653
+ licenseKey: "your-license-key",
654
+
655
+ vastMode: 'default',
656
+ vmapUrl: 'https://your-cdn.com/schedule.vmap', // VMAP 1.0 manifest
657
+
658
+ debugAdTiming: true,
659
+ });
660
+ ```
661
+
662
+ Or with React:
663
+
664
+ ```jsx
665
+ <StormcloudPlayer
666
+ src="https://your-stream.com/video.m3u8"
667
+ licenseKey="your-license-key"
668
+ vmapUrl="https://your-cdn.com/schedule.vmap"
669
+ playing={true}
670
+ />
671
+ ```
672
+
673
+ #### Supported `timeOffset` Formats
674
+
675
+ The VMAP parser recognizes all standard `timeOffset` values:
676
+
677
+ | Value | Meaning |
678
+ | --------------------- | ---------------------------------------------------- |
679
+ | `start` | Pre-roll (playback position 0) |
680
+ | `end` | Post-roll (resolved at runtime using media duration) |
681
+ | `HH:MM:SS` / `HH:MM:SS.mmm` | Absolute timestamp mid-roll |
682
+ | `NN%` | Percentage of media duration (resolved at runtime) |
683
+
684
+ #### Example VMAP Manifest
685
+
686
+ ```xml
687
+ <?xml version="1.0" encoding="UTF-8"?>
688
+ <vmap:VMAP xmlns:vmap="http://www.iab.net/videosuite/vmap" version="1.0">
689
+ <vmap:AdBreak timeOffset="start" breakType="linear" breakId="preroll">
690
+ <vmap:AdSource>
691
+ <vmap:AdTagURI templateType="vast3">
692
+ <![CDATA[https://your-ad-server.com/vast?position=preroll]]>
693
+ </vmap:AdTagURI>
694
+ </vmap:AdSource>
695
+ </vmap:AdBreak>
696
+
697
+ <vmap:AdBreak timeOffset="00:05:00" breakType="linear" breakId="midroll-1">
698
+ <vmap:AdSource>
699
+ <vmap:AdTagURI templateType="vast3">
700
+ <![CDATA[https://your-ad-server.com/vast?position=midroll-1]]>
701
+ </vmap:AdTagURI>
702
+ </vmap:AdSource>
703
+ </vmap:AdBreak>
704
+
705
+ <vmap:AdBreak timeOffset="end" breakType="linear" breakId="postroll">
706
+ <vmap:AdSource>
707
+ <vmap:AdTagURI templateType="vast3">
708
+ <![CDATA[https://your-ad-server.com/vast?position=postroll]]>
709
+ </vmap:AdTagURI>
710
+ </vmap:AdSource>
711
+ </vmap:AdBreak>
712
+ </vmap:VMAP>
713
+ ```
714
+
715
+ #### How It Works
716
+
717
+ 1. The player fetches the VMAP manifest on load (before playback starts).
718
+ 2. Each `<AdBreak>` is parsed into an `AdBreak` object with a resolved `startTimeMs` and the associated `vastTagUrl` from `<AdTagURI>`.
719
+ 3. During playback, the player matches the current time against each scheduled break and triggers the ad request at the correct offset.
720
+ 4. **Mid-roll join behavior**: If the viewer joins mid-stream and has already passed a scheduled break, the player will honor the configured late-join policy (e.g., play the remaining portion or skip to content).
721
+ 5. Each break is only consumed once per session to avoid replaying breaks after seeking.
722
+
723
+ **Benefits:**
724
+ - ✅ Declarative ad scheduling — no custom code needed per break
725
+ - ✅ Works alongside `vastMode: 'adstorm'` and `vastMode: 'default'`
726
+ - ✅ Supports pre-roll, mid-roll, percentage-based, and post-roll breaks
727
+ - ✅ Gracefully handles malformed XML and fetch failures (logged when `debugAdTiming` is enabled)
728
+
624
729
  ### Manual Ad Player Override
625
730
 
626
731
  You can still manually override the ad player type if needed:
@@ -819,6 +924,52 @@ Authenticated requests are sent to:
819
924
  - **Player Tracking** (both modes):
820
925
  - Player tracking: `POST https://adstorm.co/api-adstorm-dev/adstorm/player-tracking/track` (requires `Authorization: Bearer {licenseKey}` header)
821
926
  - Heartbeat monitoring: `POST https://adstorm.co/api-adstorm-dev/adstorm/player-tracking/heartbeat` (requires `Authorization: Bearer {licenseKey}` header)
927
+ - Ad-detect, ad-loaded, and ad-impression events are automatically emitted during ad breaks.
928
+
929
+ ### Tracking Utilities
930
+
931
+ The player exposes low-level tracking helpers if you want to fire events manually or build custom analytics:
932
+
933
+ ```javascript
934
+ import {
935
+ getClientInfo,
936
+ getBrowserID,
937
+ sendInitialTracking,
938
+ sendHeartbeat,
939
+ sendAdDetectTracking,
940
+ sendAdLoadedTracking,
941
+ sendAdImpressionTracking,
942
+ } from "stormcloud-video-player";
943
+
944
+ const clientInfo = getClientInfo();
945
+ const browserId = getBrowserID();
946
+
947
+ await sendInitialTracking(licenseKey, clientInfo);
948
+ await sendHeartbeat(licenseKey, { browserId, timestamp: new Date().toISOString() });
949
+
950
+ // Ad lifecycle tracking
951
+ await sendAdDetectTracking(licenseKey, {
952
+ source: "scte35",
953
+ durationSeconds: 30,
954
+ ptsSeconds: 120.5,
955
+ detectedAtFragmentSn: 1234,
956
+ timestamp: new Date().toISOString(),
957
+ });
958
+
959
+ await sendAdLoadedTracking(licenseKey, {
960
+ source: "ima", // 'prebid' | 'ima' | 'hls'
961
+ vastUrl: "https://...",
962
+ durationSeconds: 15,
963
+ timestamp: new Date().toISOString(),
964
+ });
965
+
966
+ await sendAdImpressionTracking(licenseKey, {
967
+ source: "ima",
968
+ adIndex: 0,
969
+ durationSeconds: 15,
970
+ timestamp: new Date().toISOString(),
971
+ });
972
+ ```
822
973
 
823
974
  ## 🔧 Advanced Configuration
824
975
 
@@ -927,11 +1078,74 @@ console.log("Supports PIP:", canPIP); // true for file player
927
1078
  />
928
1079
  ```
929
1080
 
930
- ## 🌐 Browser Support
1081
+ ## 🌐 Browser & Smart TV Support
931
1082
 
932
1083
  - **Desktop**: Chrome 60+, Firefox 55+, Safari 12+, Edge 79+
933
1084
  - **Mobile**: iOS Safari 12+, Chrome Mobile 60+
934
- - **Smart TV**: WebOS, Tizen, Android TV, Roku, Apple TV
1085
+ - **Smart TV**: LG WebOS (v2+), Samsung Tizen (v2+), Sony BRAVIA, Android TV, Roku, Apple TV, generic Smart TV user-agents
1086
+
1087
+ ### Automatic Browser Detection & Ad Player Selection
1088
+
1089
+ The player automatically detects the runtime environment and chooses the optimal ad-player configuration. This is especially useful for Smart TVs where the Google IMA SDK may not be available on older devices.
1090
+
1091
+ ```javascript
1092
+ import {
1093
+ detectBrowser,
1094
+ supportsGoogleIMA,
1095
+ getRecommendedAdPlayer,
1096
+ supportsModernJS,
1097
+ logBrowserInfo,
1098
+ getBrowserConfigOverrides,
1099
+ supportsFeature,
1100
+ } from "stormcloud-video-player";
1101
+
1102
+ const info = detectBrowser();
1103
+ // {
1104
+ // name: 'LG WebOS',
1105
+ // version: '5.0',
1106
+ // majorVersion: 5,
1107
+ // isSmartTV: true,
1108
+ // isLegacyTV: false,
1109
+ // supportsIMA: true,
1110
+ // supportsModernJS: true,
1111
+ // recommendedAdPlayer: 'ima',
1112
+ // webOSVersion: 5,
1113
+ // chromeVersion: 79,
1114
+ // ...
1115
+ // }
1116
+
1117
+ console.log(supportsGoogleIMA()); // true | false
1118
+ console.log(getRecommendedAdPlayer()); // 'ima' | 'hls'
1119
+ console.log(supportsFeature('fetch')); // true | false
1120
+ ```
1121
+
1122
+ **What happens automatically:**
1123
+
1124
+ - **Legacy Smart TVs** (LG NetCast, old WebOS < 3, old Tizen): `adPlayerType` is forced to `'hls'` and `allowNativeHls` is enabled.
1125
+ - **Modern Smart TVs**: `allowNativeHls` is enabled by default (TVs generally play HLS better natively).
1126
+ - **If IMA SDK is unsupported**: the player falls back to the HLS ad player automatically.
1127
+ - **Browser overrides** are merged with your config — user-provided options always take precedence.
1128
+
1129
+ Call `logBrowserInfo(true)` (or enable `debugAdTiming`) to print a detailed compatibility report to the console.
1130
+
1131
+ ### Automatic Polyfills for Legacy Devices
1132
+
1133
+ On older Smart TVs and browsers, `initializePolyfills()` is invoked automatically at construction time. It adds missing primitives needed for the player to run:
1134
+
1135
+ - `URLSearchParams`
1136
+ - `TextEncoder`
1137
+ - `Promise.prototype.finally`
1138
+ - `Object.assign`
1139
+ - `Array.from`
1140
+ - `String.prototype.startsWith` / `endsWith` / `includes`
1141
+
1142
+ You can also run it manually before bootstrapping anything else:
1143
+
1144
+ ```javascript
1145
+ import { initializePolyfills } from "stormcloud-video-player";
1146
+
1147
+ initializePolyfills();
1148
+ ```
935
1149
 
936
1150
  ### Format Support by Player
937
1151
 
@@ -980,16 +1194,19 @@ src/
980
1194
  │ ├── HlsPlayer.tsx # HLS stream handler
981
1195
  │ └── FilePlayer.tsx # Regular video handler
982
1196
  ├── player/
983
- │ └── StormcloudVideoPlayer.ts # Core player class
1197
+ │ └── StormcloudVideoPlayer.ts # Core player class (SCTE-35, VMAP, ad pods)
984
1198
  ├── ui/
985
1199
  │ └── StormcloudVideoPlayer.tsx # Legacy React component
986
1200
  ├── sdk/
987
- └── ima.ts # Google IMA integration
1201
+ ├── ima.ts # Google IMA integration
1202
+ │ └── hlsAdPlayer.ts # Native HLS ad player (AdStorm mode, legacy TVs)
988
1203
  ├── utils/
989
- │ ├── tracking.ts # Analytics and tracking
990
- └── index.ts # Utility functions
1204
+ │ ├── tracking.ts # Analytics and ad tracking
1205
+ ├── browserCompat.ts # Browser / Smart TV detection & auto-overrides
1206
+ │ └── polyfills.ts # Legacy browser polyfills
991
1207
  ├── props.ts # Centralized props system
992
1208
  ├── patterns.ts # URL pattern matching
1209
+ ├── utils.ts # Shared utilities
993
1210
  └── types.ts # TypeScript definitions
994
1211
  ```
995
1212
 
@@ -1102,6 +1319,22 @@ MIT License - see [LICENSE](LICENSE) file for details.
1102
1319
 
1103
1320
  Built with ❤️ by the Stormcloud team
1104
1321
 
1322
+ ### What's New in v0.5
1323
+
1324
+ - 🗓️ **VMAP 1.0 Support**: New `vmapUrl` config/prop loads a VMAP manifest and schedules pre-roll, mid-roll, percentage-based, and post-roll breaks automatically
1325
+ - Supports `start`, `end`, `HH:MM:SS[.mmm]`, and `NN%` `timeOffset` values
1326
+ - Namespaced (`vmap:AdBreak`) and non-namespaced manifests both supported
1327
+ - Breaks are consumed-once-per-session and integrate with the existing late-join policy
1328
+ - 📺 **Smart TV First-Class Support**: New browser-compat layer auto-detects LG WebOS, Samsung Tizen, Sony BRAVIA, LG NetCast and generic Smart TV UAs
1329
+ - Exports `detectBrowser`, `supportsGoogleIMA`, `getRecommendedAdPlayer`, `supportsModernJS`, `logBrowserInfo`, `getBrowserConfigOverrides`, `supportsFeature`
1330
+ - Automatically forces HLS ad player on legacy TVs where IMA SDK is not available
1331
+ - Automatically enables `allowNativeHls` on Smart TVs for more reliable playback
1332
+ - 🧩 **Automatic Polyfills**: `initializePolyfills()` runs at construction time and backfills `URLSearchParams`, `TextEncoder`, `Promise.prototype.finally`, `Object.assign`, `Array.from`, and `String.prototype.startsWith/endsWith/includes` for legacy environments
1333
+ - 📊 **Expanded Ad Tracking**: New `sendAdDetectTracking`, `sendAdLoadedTracking`, and `sendAdImpressionTracking` helpers (plus `AdDetectInfo`, `AdLoadedInfo`, `AdImpressionInfo`, and `AdTrackingSource` types) for prebid/IMA/HLS ad lifecycle events
1334
+ - ⚙️ **Ad-Break Timing Controls**: New `adBreakCheckIntervalMs` (default 1000ms, min 250ms) and `maxAdBreakExtensionMs` (default 60000ms) options give you precise control over how long the player is allowed to extend an ad break past its SCTE-35 duration when ads are still playing or queued
1335
+ - 🙈 **Hide Loading Indicator**: New `hideLoadingIndicator` prop/config hides the built-in buffering spinner when you want to render your own overlay
1336
+ - 🔌 **Expanded Public API**: `createImaController`, `createHlsAdPlayer`, and `initializePolyfills` are now exported alongside the new browser-compat utilities, making it easier to build custom integrations on top of the player core
1337
+
1105
1338
  ### What's New in v0.4
1106
1339
 
1107
1340
  - 🚀 **Early Ad Prefetching**: Detects SCTE-35 markers in manifest fragments before playback reaches them, prefetching ads in advance for zero-delay ad starts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stormcloud-video-player",
3
- "version": "0.3.57",
3
+ "version": "0.3.58",
4
4
  "main": "lib/index.js",
5
5
  "typings": "lib/index.d.ts",
6
6
  "scripts": {