stormcloud-video-player 0.6.11 → 0.6.12

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.
@@ -1,4 +1,4 @@
1
- import { V as VastBidResponse } from '../types-DSKC4ySr.cjs';
1
+ import { V as VastBidResponse } from '../types-FjAlGhAL.cjs';
2
2
  import Hls from 'hls.js';
3
3
 
4
4
  interface VastAdLayerOptions {
@@ -1,4 +1,4 @@
1
- import { a as VastManager } from '../types-DSKC4ySr.cjs';
1
+ import { a as VastManager } from '../types-FjAlGhAL.cjs';
2
2
 
3
3
  interface VastManagerOptions {
4
4
  debug?: boolean;
@@ -22,6 +22,7 @@ interface StormcloudVideoPlayerConfig {
22
22
  disableFiller?: boolean;
23
23
  adTransitionGapMs?: number;
24
24
  singlePipelineMode?: boolean;
25
+ mqttBrokerUrl?: string;
25
26
  }
26
27
  interface ClientInfo {
27
28
  brand: string;
@@ -2046,6 +2046,79 @@ function createVastAdLayer(contentVideo, options) {
2046
2046
  }
2047
2047
  };
2048
2048
  }
2049
+ // src/utils/mqttClient.ts
2050
+ var import_mqtt = __toESM(require("mqtt"), 1);
2051
+ var LOG2 = "[StormcloudVideoPlayer][MQTT]";
2052
+ var client = null;
2053
+ var status = "disconnected";
2054
+ var brokerUrl = "";
2055
+ function isMQTTConfigured() {
2056
+ return client !== null;
2057
+ }
2058
+ function initMQTTClient(url) {
2059
+ var _topicPrefix = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : "adstorm";
2060
+ if (client) return;
2061
+ brokerUrl = url;
2062
+ status = "connecting";
2063
+ var clientId = "stormcloud-vp-".concat(Math.random().toString(36).slice(2, 9));
2064
+ try {
2065
+ client = import_mqtt.default.connect(url, {
2066
+ clientId: clientId,
2067
+ keepalive: 60,
2068
+ clean: true,
2069
+ reconnectPeriod: 5e3,
2070
+ connectTimeout: 1e4,
2071
+ queueQoSZero: false
2072
+ });
2073
+ } catch (err) {
2074
+ status = "error";
2075
+ console.warn("".concat(LOG2, " connect() threw:"), err);
2076
+ return;
2077
+ }
2078
+ client.on("connect", function() {
2079
+ status = "connected";
2080
+ console.info("".concat(LOG2, " connected to ").concat(url));
2081
+ });
2082
+ client.on("reconnect", function() {
2083
+ status = "connecting";
2084
+ console.info("".concat(LOG2, " reconnecting…"));
2085
+ });
2086
+ client.on("offline", function() {
2087
+ status = "disconnected";
2088
+ console.warn("".concat(LOG2, " offline"));
2089
+ });
2090
+ client.on("error", function(err) {
2091
+ status = "error";
2092
+ console.warn("".concat(LOG2, " error:"), err.message);
2093
+ });
2094
+ client.on("close", function() {
2095
+ if (status === "connected") {
2096
+ status = "disconnected";
2097
+ }
2098
+ });
2099
+ }
2100
+ function publishMQTT(topic, payload) {
2101
+ if (!client) {
2102
+ return false;
2103
+ }
2104
+ try {
2105
+ client.publish(topic, JSON.stringify(payload), {
2106
+ qos: 1
2107
+ });
2108
+ return true;
2109
+ } catch (err) {
2110
+ console.warn("".concat(LOG2, " publish failed on ").concat(topic, ":"), err);
2111
+ return false;
2112
+ }
2113
+ }
2114
+ function disconnectMQTT() {
2115
+ if (client) {
2116
+ client.end(true);
2117
+ client = null;
2118
+ status = "disconnected";
2119
+ brokerUrl = "";
2120
+ }
2121
+ }
2049
2122
  // src/utils/tracking.ts
2050
2123
  var cachedBrowserId = null;
2051
2124
  function getClientInfo() {
@@ -2077,8 +2150,8 @@ function getClientInfo() {
2077
2150
  os = "webOS";
2078
2151
  isSmartTV = true;
2079
2152
  deviceType = "tv";
2080
- var webosMatch = ua.match(/Web0S\/([^\s]+)/);
2081
- model = webosMatch ? "webOS ".concat(webosMatch[1]) : "webOS TV";
2153
+ var m = ua.match(/Web0S\/([^\s]+)/);
2154
+ model = m ? "webOS ".concat(m[1]) : "webOS TV";
2082
2155
  } else if (ua.includes("Tizen")) {
2083
2156
  brand = "Samsung";
2084
2157
  os = "Tizen";
@@ -2122,23 +2195,19 @@ function getClientInfo() {
2122
2195
  isAndroid = true;
2123
2196
  os = "Android";
2124
2197
  deviceType = /Mobile/.test(ua) ? "mobile" : "tablet";
2125
- if (ua.includes("Android") && (maxTouchPoints === 0 || ua.includes("Google TV") || ua.includes("XiaoMi"))) {
2198
+ if (maxTouchPoints === 0 || ua.includes("Google TV") || ua.includes("XiaoMi")) {
2126
2199
  deviceType = "tv";
2127
2200
  isSmartTV = true;
2128
2201
  brand = brand === "Unknown" ? "Android TV" : brand;
2129
2202
  }
2130
2203
  var androidModelMatch = ua.match(/\(([^)]*Android[^)]*)\)/);
2131
- if (androidModelMatch && androidModelMatch[1]) {
2132
- model = androidModelMatch[1];
2133
- }
2204
+ if (androidModelMatch === null || androidModelMatch === void 0 ? void 0 : androidModelMatch[1]) model = androidModelMatch[1];
2134
2205
  }
2135
2206
  if (/iPad|iPhone|iPod/.test(ua)) {
2136
2207
  os = "iOS";
2137
2208
  deviceType = "mobile";
2138
2209
  brand = "Apple";
2139
- if (navigator.maxTouchPoints > 1 && /iPad/.test(ua)) {
2140
- deviceType = "tablet";
2141
- }
2210
+ if (navigator.maxTouchPoints > 1 && /iPad/.test(ua)) deviceType = "tablet";
2142
2211
  }
2143
2212
  if (!isAndroid && !isSmartTV && !/Mobile/.test(ua)) {
2144
2213
  if (ua.includes("Windows")) {
@@ -2159,9 +2228,7 @@ function getClientInfo() {
2159
2228
  if (vendor.includes("Samsung") || ua.includes("SM-")) brand = "Samsung";
2160
2229
  }
2161
2230
  isWebView = /wv|WebView|Linux; U;/.test(ua);
2162
- if (((_window = window) === null || _window === void 0 ? void 0 : _window.outerHeight) === 0 && ((_window1 = window) === null || _window1 === void 0 ? void 0 : _window1.outerWidth) === 0) {
2163
- isWebView = true;
2164
- }
2231
+ if (((_window = window) === null || _window === void 0 ? void 0 : _window.outerHeight) === 0 && ((_window1 = window) === null || _window1 === void 0 ? void 0 : _window1.outerWidth) === 0) isWebView = true;
2165
2232
  isWebApp = window.matchMedia("(display-mode: standalone)").matches || window.navigator.standalone === true || ((_window_screen = window.screen) === null || _window_screen === void 0 ? void 0 : (_window_screen_orientation = _window_screen.orientation) === null || _window_screen_orientation === void 0 ? void 0 : _window_screen_orientation.angle) !== void 0;
2166
2233
  return {
2167
2234
  brand: brand,
@@ -2192,18 +2259,16 @@ function getClientInfo() {
2192
2259
  }
2193
2260
  function getBrowserID(clientInfo) {
2194
2261
  return _async_to_generator(function() {
2195
- var fingerprintString, encodedData, utf8, buffer, i, hashBuffer, hashArray, hashHex, error, hash, i1, char, fallbackHash, timestamp, random;
2262
+ var _crypto_subtle, fingerprintString, encodedData, utf8, buffer, i, hashBuffer, hashHex, unused, hash, i1, char, fallbackHash, timestamp, random;
2196
2263
  return _ts_generator(this, function(_state) {
2197
2264
  switch(_state.label){
2198
2265
  case 0:
2199
- if (cachedBrowserId) {
2200
- return [
2201
- 2,
2202
- cachedBrowserId
2203
- ];
2204
- }
2266
+ if (cachedBrowserId) return [
2267
+ 2,
2268
+ cachedBrowserId
2269
+ ];
2205
2270
  fingerprintString = JSON.stringify(clientInfo);
2206
- if (!(typeof crypto !== "undefined" && crypto.subtle && crypto.subtle.digest)) return [
2271
+ if (!(typeof crypto !== "undefined" && ((_crypto_subtle = crypto.subtle) === null || _crypto_subtle === void 0 ? void 0 : _crypto_subtle.digest))) return [
2207
2272
  3,
2208
2273
  5
2209
2274
  ];
@@ -2230,9 +2295,7 @@ function getBrowserID(clientInfo) {
2230
2295
  } else {
2231
2296
  utf8 = unescape(encodeURIComponent(fingerprintString));
2232
2297
  buffer = new Uint8Array(utf8.length);
2233
- for(i = 0; i < utf8.length; i++){
2234
- buffer[i] = utf8.charCodeAt(i);
2235
- }
2298
+ for(i = 0; i < utf8.length; i++)buffer[i] = utf8.charCodeAt(i);
2236
2299
  encodedData = buffer;
2237
2300
  }
2238
2301
  return [
@@ -2241,8 +2304,7 @@ function getBrowserID(clientInfo) {
2241
2304
  ];
2242
2305
  case 3:
2243
2306
  hashBuffer = _state.sent();
2244
- hashArray = Array.from(new Uint8Array(hashBuffer));
2245
- hashHex = hashArray.map(function(b) {
2307
+ hashHex = Array.from(new Uint8Array(hashBuffer)).map(function(b) {
2246
2308
  return b.toString(16).padStart(2, "0");
2247
2309
  }).join("");
2248
2310
  cachedBrowserId = hashHex;
@@ -2251,8 +2313,8 @@ function getBrowserID(clientInfo) {
2251
2313
  hashHex
2252
2314
  ];
2253
2315
  case 4:
2254
- error = _state.sent();
2255
- console.warn("[StormcloudVideoPlayer] crypto.subtle.digest not supported, using fallback hash");
2316
+ unused = _state.sent();
2317
+ console.warn("[StormcloudVideoPlayer] crypto.subtle not supported, using fallback hash");
2256
2318
  return [
2257
2319
  3,
2258
2320
  5
@@ -2276,6 +2338,10 @@ function getBrowserID(clientInfo) {
2276
2338
  });
2277
2339
  })();
2278
2340
  }
2341
+ var mqttTopicPrefix = "adstorm";
2342
+ function setMQTTTopicPrefix(prefix) {
2343
+ mqttTopicPrefix = prefix || "adstorm";
2344
+ }
2279
2345
  var PLAYER_TRACKING_BASE_URL = "https://adstorm.co/api-adstorm-dev/adstorm/player-tracking";
2280
2346
  var TRACK_URL = "".concat(PLAYER_TRACKING_BASE_URL, "/metrics/ingest");
2281
2347
  var HEARTBEAT_URL = "".concat(PLAYER_TRACKING_BASE_URL, "/heartbeat");
@@ -2284,43 +2350,9 @@ function buildHeaders(licenseKey) {
2284
2350
  var headers = {
2285
2351
  "Content-Type": "application/json"
2286
2352
  };
2287
- if (licenseKey) {
2288
- headers["Authorization"] = "Bearer ".concat(licenseKey);
2289
- }
2353
+ if (licenseKey) headers["Authorization"] = "Bearer ".concat(licenseKey);
2290
2354
  return headers;
2291
2355
  }
2292
- function sendTrackRequest(licenseKey, body) {
2293
- return _async_to_generator(function() {
2294
- var response;
2295
- return _ts_generator(this, function(_state) {
2296
- switch(_state.label){
2297
- case 0:
2298
- return [
2299
- 4,
2300
- fetch(TRACK_URL, {
2301
- method: "POST",
2302
- headers: buildHeaders(licenseKey),
2303
- body: JSON.stringify(body)
2304
- })
2305
- ];
2306
- case 1:
2307
- response = _state.sent();
2308
- if (!response.ok) {
2309
- throw new Error("HTTP error! status: ".concat(response.status));
2310
- }
2311
- return [
2312
- 4,
2313
- response.json()
2314
- ];
2315
- case 2:
2316
- _state.sent();
2317
- return [
2318
- 2
2319
- ];
2320
- }
2321
- });
2322
- })();
2323
- }
2324
2356
  function postJson(url, licenseKey, body) {
2325
2357
  return _async_to_generator(function() {
2326
2358
  var response;
@@ -2337,9 +2369,7 @@ function postJson(url, licenseKey, body) {
2337
2369
  ];
2338
2370
  case 1:
2339
2371
  response = _state.sent();
2340
- if (!response.ok) {
2341
- throw new Error("HTTP error! status: ".concat(response.status));
2342
- }
2372
+ if (!response.ok) throw new Error("HTTP error! status: ".concat(response.status));
2343
2373
  return [
2344
2374
  4,
2345
2375
  response.json()
@@ -2389,9 +2419,33 @@ function buildPlayerMetricEvent(_0) {
2389
2419
  });
2390
2420
  }).apply(this, arguments);
2391
2421
  }
2422
+ function publishOrPost(mqttTopic, httpUrl, licenseKey, body) {
2423
+ return _async_to_generator(function() {
2424
+ return _ts_generator(this, function(_state) {
2425
+ switch(_state.label){
2426
+ case 0:
2427
+ if (isMQTTConfigured()) {
2428
+ publishMQTT(mqttTopic, body);
2429
+ return [
2430
+ 2
2431
+ ];
2432
+ }
2433
+ return [
2434
+ 4,
2435
+ postJson(httpUrl, licenseKey, body)
2436
+ ];
2437
+ case 1:
2438
+ _state.sent();
2439
+ return [
2440
+ 2
2441
+ ];
2442
+ }
2443
+ });
2444
+ })();
2445
+ }
2392
2446
  function sendInitialTracking(_0) {
2393
2447
  return _async_to_generator(function(licenseKey) {
2394
- var context, clientInfo, browserId, trackingData, error;
2448
+ var context, clientInfo, browserId, captureAt, trackingData, metricsBody, error;
2395
2449
  var _arguments = arguments;
2396
2450
  return _ts_generator(this, function(_state) {
2397
2451
  switch(_state.label){
@@ -2412,26 +2466,28 @@ function sendInitialTracking(_0) {
2412
2466
  ];
2413
2467
  case 2:
2414
2468
  browserId = _state.sent();
2469
+ captureAt = /* @__PURE__ */ new Date().toISOString();
2415
2470
  trackingData = _object_spread({
2416
2471
  browserId: browserId
2417
2472
  }, clientInfo);
2473
+ metricsBody = {
2474
+ events: [
2475
+ {
2476
+ player_id: browserId,
2477
+ device_type: clientInfo.deviceType,
2478
+ input_stream_type: context.inputStreamType,
2479
+ os: clientInfo.os,
2480
+ ad_loaded: false,
2481
+ ad_detect: false,
2482
+ license_key: licenseKey,
2483
+ capture_at: captureAt
2484
+ }
2485
+ ],
2486
+ trackingData: trackingData
2487
+ };
2418
2488
  return [
2419
2489
  4,
2420
- sendTrackRequest(licenseKey, {
2421
- events: [
2422
- {
2423
- player_id: browserId,
2424
- device_type: clientInfo.deviceType,
2425
- input_stream_type: context.inputStreamType,
2426
- os: clientInfo.os,
2427
- ad_loaded: false,
2428
- ad_detect: false,
2429
- license_key: licenseKey,
2430
- capture_at: /* @__PURE__ */ new Date().toISOString()
2431
- }
2432
- ],
2433
- trackingData: trackingData
2434
- })
2490
+ publishOrPost("".concat(mqttTopicPrefix, "/tracking/metrics"), TRACK_URL, licenseKey, metricsBody)
2435
2491
  ];
2436
2492
  case 3:
2437
2493
  _state.sent();
@@ -2544,7 +2600,7 @@ function sendAdLoadedTracking(_0, _1) {
2544
2600
  }
2545
2601
  function sendAdImpressionTracking(_0, _1) {
2546
2602
  return _async_to_generator(function(licenseKey, adImpressionInfo) {
2547
- var context, metricEvent, error;
2603
+ var context, metricEvent, heartbeatBody, impressionsBody, error;
2548
2604
  var _arguments = arguments;
2549
2605
  return _ts_generator(this, function(_state) {
2550
2606
  switch(_state.label){
@@ -2566,21 +2622,23 @@ function sendAdImpressionTracking(_0, _1) {
2566
2622
  ];
2567
2623
  case 2:
2568
2624
  metricEvent = _state.sent();
2625
+ heartbeatBody = metricEvent;
2626
+ impressionsBody = {
2627
+ events: [
2628
+ {
2629
+ player_id: metricEvent.player_id,
2630
+ ad_played_count: 1,
2631
+ ad_url: adImpressionInfo.adUrl,
2632
+ license_key: licenseKey,
2633
+ capture_at: adImpressionInfo.timestamp
2634
+ }
2635
+ ]
2636
+ };
2569
2637
  return [
2570
2638
  4,
2571
2639
  Promise.all([
2572
- postJson(HEARTBEAT_URL, licenseKey, metricEvent),
2573
- postJson(IMPRESSIONS_URL, licenseKey, {
2574
- events: [
2575
- {
2576
- player_id: metricEvent.player_id,
2577
- ad_played_count: 1,
2578
- ad_url: adImpressionInfo.adUrl,
2579
- license_key: licenseKey,
2580
- capture_at: adImpressionInfo.timestamp
2581
- }
2582
- ]
2583
- })
2640
+ publishOrPost("".concat(mqttTopicPrefix, "/tracking/heartbeat"), HEARTBEAT_URL, licenseKey, heartbeatBody),
2641
+ publishOrPost("".concat(mqttTopicPrefix, "/tracking/impressions"), IMPRESSIONS_URL, licenseKey, impressionsBody)
2584
2642
  ])
2585
2643
  ];
2586
2644
  case 3:
@@ -2628,7 +2686,7 @@ function sendHeartbeat(_0) {
2628
2686
  heartbeatData = _state.sent();
2629
2687
  return [
2630
2688
  4,
2631
- postJson(HEARTBEAT_URL, licenseKey, heartbeatData)
2689
+ publishOrPost("".concat(mqttTopicPrefix, "/tracking/heartbeat"), HEARTBEAT_URL, licenseKey, heartbeatData)
2632
2690
  ];
2633
2691
  case 3:
2634
2692
  _state.sent();
@@ -4557,6 +4615,11 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4557
4615
  key: "initializeTracking",
4558
4616
  value: function initializeTracking() {
4559
4617
  var _this = this;
4618
+ if (this.config.mqttBrokerUrl) {
4619
+ var topicPrefix = "adstorm";
4620
+ setMQTTTopicPrefix(topicPrefix);
4621
+ initMQTTClient(this.config.mqttBrokerUrl, topicPrefix);
4622
+ }
4560
4623
  sendInitialTracking(this.config.licenseKey, this.getAnalyticsContext()).then(function() {
4561
4624
  _this.heartbeatInterval = window.setInterval(function() {
4562
4625
  _this.sendHeartbeatIfNeeded();
@@ -6236,6 +6299,9 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6236
6299
  clearInterval(this.heartbeatInterval);
6237
6300
  this.heartbeatInterval = void 0;
6238
6301
  }
6302
+ if (this.config.mqttBrokerUrl) {
6303
+ disconnectMQTT();
6304
+ }
6239
6305
  (_this_hls = this.hls) === null || _this_hls === void 0 ? void 0 : _this_hls.destroy();
6240
6306
  (_this_adLayer = this.adLayer) === null || _this_adLayer === void 0 ? void 0 : _this_adLayer.destroy();
6241
6307
  this.consecutiveFailures = 0;
@@ -6257,7 +6323,7 @@ var CRITICAL_PROPS = [
6257
6323
  var CONTROLS_HIDE_DELAY = 3e3;
6258
6324
  var DEFAULT_PLAYER_ASPECT_RATIO = 16 / 9;
6259
6325
  var StormcloudVideoPlayerComponent = import_react.default.memo(function(props) {
6260
- var src = props.src, autoplay = props.autoplay, muted = props.muted, lowLatencyMode = props.lowLatencyMode, allowNativeHls = props.allowNativeHls, driftToleranceMs = props.driftToleranceMs, immediateManifestAds = props.immediateManifestAds, debugAdTiming = props.debugAdTiming, showCustomControls = props.showCustomControls, hideLoadingIndicator = props.hideLoadingIndicator, onVolumeToggle = props.onVolumeToggle, onFullscreenToggle = props.onFullscreenToggle, onControlClick = props.onControlClick, onReady = props.onReady, wrapperClassName = props.wrapperClassName, wrapperStyle = props.wrapperStyle, className = props.className, style = props.style, controls = props.controls, playsInline = props.playsInline, preload = props.preload, poster = props.poster, children = props.children, licenseKey = props.licenseKey, minSegmentsBeforePlay = props.minSegmentsBeforePlay, disableAds = props.disableAds, disableFiller = props.disableFiller, restVideoAttrs = _object_without_properties(props, [
6326
+ var src = props.src, autoplay = props.autoplay, muted = props.muted, lowLatencyMode = props.lowLatencyMode, allowNativeHls = props.allowNativeHls, driftToleranceMs = props.driftToleranceMs, immediateManifestAds = props.immediateManifestAds, debugAdTiming = props.debugAdTiming, showCustomControls = props.showCustomControls, hideLoadingIndicator = props.hideLoadingIndicator, onVolumeToggle = props.onVolumeToggle, onFullscreenToggle = props.onFullscreenToggle, onControlClick = props.onControlClick, onReady = props.onReady, wrapperClassName = props.wrapperClassName, wrapperStyle = props.wrapperStyle, className = props.className, style = props.style, controls = props.controls, playsInline = props.playsInline, preload = props.preload, poster = props.poster, children = props.children, licenseKey = props.licenseKey, minSegmentsBeforePlay = props.minSegmentsBeforePlay, disableAds = props.disableAds, disableFiller = props.disableFiller, mqttBrokerUrl = props.mqttBrokerUrl, restVideoAttrs = _object_without_properties(props, [
6261
6327
  "src",
6262
6328
  "autoplay",
6263
6329
  "muted",
@@ -6284,7 +6350,8 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(function(props) {
6284
6350
  "licenseKey",
6285
6351
  "minSegmentsBeforePlay",
6286
6352
  "disableAds",
6287
- "disableFiller"
6353
+ "disableFiller",
6354
+ "mqttBrokerUrl"
6288
6355
  ]);
6289
6356
  var videoRef = (0, import_react.useRef)(null);
6290
6357
  var playerRef = (0, import_react.useRef)(null);
@@ -6444,6 +6511,7 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(function(props) {
6444
6511
  if (minSegmentsBeforePlay !== void 0) cfg.minSegmentsBeforePlay = minSegmentsBeforePlay;
6445
6512
  if (disableAds !== void 0) cfg.disableAds = disableAds;
6446
6513
  cfg.disableFiller = disableFiller !== null && disableFiller !== void 0 ? disableFiller : true;
6514
+ if (mqttBrokerUrl !== void 0) cfg.mqttBrokerUrl = mqttBrokerUrl;
6447
6515
  var player = new StormcloudVideoPlayer(cfg);
6448
6516
  playerRef.current = player;
6449
6517
  player.load().then(function() {