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.
@@ -2008,6 +2008,79 @@ function createVastAdLayer(contentVideo, options) {
2008
2008
  }
2009
2009
  };
2010
2010
  }
2011
+ // src/utils/mqttClient.ts
2012
+ var import_mqtt = __toESM(require("mqtt"), 1);
2013
+ var LOG2 = "[StormcloudVideoPlayer][MQTT]";
2014
+ var client = null;
2015
+ var status = "disconnected";
2016
+ var brokerUrl = "";
2017
+ function isMQTTConfigured() {
2018
+ return client !== null;
2019
+ }
2020
+ function initMQTTClient(url) {
2021
+ var _topicPrefix = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : "adstorm";
2022
+ if (client) return;
2023
+ brokerUrl = url;
2024
+ status = "connecting";
2025
+ var clientId = "stormcloud-vp-".concat(Math.random().toString(36).slice(2, 9));
2026
+ try {
2027
+ client = import_mqtt.default.connect(url, {
2028
+ clientId: clientId,
2029
+ keepalive: 60,
2030
+ clean: true,
2031
+ reconnectPeriod: 5e3,
2032
+ connectTimeout: 1e4,
2033
+ queueQoSZero: false
2034
+ });
2035
+ } catch (err) {
2036
+ status = "error";
2037
+ console.warn("".concat(LOG2, " connect() threw:"), err);
2038
+ return;
2039
+ }
2040
+ client.on("connect", function() {
2041
+ status = "connected";
2042
+ console.info("".concat(LOG2, " connected to ").concat(url));
2043
+ });
2044
+ client.on("reconnect", function() {
2045
+ status = "connecting";
2046
+ console.info("".concat(LOG2, " reconnecting…"));
2047
+ });
2048
+ client.on("offline", function() {
2049
+ status = "disconnected";
2050
+ console.warn("".concat(LOG2, " offline"));
2051
+ });
2052
+ client.on("error", function(err) {
2053
+ status = "error";
2054
+ console.warn("".concat(LOG2, " error:"), err.message);
2055
+ });
2056
+ client.on("close", function() {
2057
+ if (status === "connected") {
2058
+ status = "disconnected";
2059
+ }
2060
+ });
2061
+ }
2062
+ function publishMQTT(topic, payload) {
2063
+ if (!client) {
2064
+ return false;
2065
+ }
2066
+ try {
2067
+ client.publish(topic, JSON.stringify(payload), {
2068
+ qos: 1
2069
+ });
2070
+ return true;
2071
+ } catch (err) {
2072
+ console.warn("".concat(LOG2, " publish failed on ").concat(topic, ":"), err);
2073
+ return false;
2074
+ }
2075
+ }
2076
+ function disconnectMQTT() {
2077
+ if (client) {
2078
+ client.end(true);
2079
+ client = null;
2080
+ status = "disconnected";
2081
+ brokerUrl = "";
2082
+ }
2083
+ }
2011
2084
  // src/utils/tracking.ts
2012
2085
  var cachedBrowserId = null;
2013
2086
  function getClientInfo() {
@@ -2039,8 +2112,8 @@ function getClientInfo() {
2039
2112
  os = "webOS";
2040
2113
  isSmartTV = true;
2041
2114
  deviceType = "tv";
2042
- var webosMatch = ua.match(/Web0S\/([^\s]+)/);
2043
- model = webosMatch ? "webOS ".concat(webosMatch[1]) : "webOS TV";
2115
+ var m = ua.match(/Web0S\/([^\s]+)/);
2116
+ model = m ? "webOS ".concat(m[1]) : "webOS TV";
2044
2117
  } else if (ua.includes("Tizen")) {
2045
2118
  brand = "Samsung";
2046
2119
  os = "Tizen";
@@ -2084,23 +2157,19 @@ function getClientInfo() {
2084
2157
  isAndroid = true;
2085
2158
  os = "Android";
2086
2159
  deviceType = /Mobile/.test(ua) ? "mobile" : "tablet";
2087
- if (ua.includes("Android") && (maxTouchPoints === 0 || ua.includes("Google TV") || ua.includes("XiaoMi"))) {
2160
+ if (maxTouchPoints === 0 || ua.includes("Google TV") || ua.includes("XiaoMi")) {
2088
2161
  deviceType = "tv";
2089
2162
  isSmartTV = true;
2090
2163
  brand = brand === "Unknown" ? "Android TV" : brand;
2091
2164
  }
2092
2165
  var androidModelMatch = ua.match(/\(([^)]*Android[^)]*)\)/);
2093
- if (androidModelMatch && androidModelMatch[1]) {
2094
- model = androidModelMatch[1];
2095
- }
2166
+ if (androidModelMatch === null || androidModelMatch === void 0 ? void 0 : androidModelMatch[1]) model = androidModelMatch[1];
2096
2167
  }
2097
2168
  if (/iPad|iPhone|iPod/.test(ua)) {
2098
2169
  os = "iOS";
2099
2170
  deviceType = "mobile";
2100
2171
  brand = "Apple";
2101
- if (navigator.maxTouchPoints > 1 && /iPad/.test(ua)) {
2102
- deviceType = "tablet";
2103
- }
2172
+ if (navigator.maxTouchPoints > 1 && /iPad/.test(ua)) deviceType = "tablet";
2104
2173
  }
2105
2174
  if (!isAndroid && !isSmartTV && !/Mobile/.test(ua)) {
2106
2175
  if (ua.includes("Windows")) {
@@ -2121,9 +2190,7 @@ function getClientInfo() {
2121
2190
  if (vendor.includes("Samsung") || ua.includes("SM-")) brand = "Samsung";
2122
2191
  }
2123
2192
  isWebView = /wv|WebView|Linux; U;/.test(ua);
2124
- if (((_window = window) === null || _window === void 0 ? void 0 : _window.outerHeight) === 0 && ((_window1 = window) === null || _window1 === void 0 ? void 0 : _window1.outerWidth) === 0) {
2125
- isWebView = true;
2126
- }
2193
+ 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;
2127
2194
  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;
2128
2195
  return {
2129
2196
  brand: brand,
@@ -2154,18 +2221,16 @@ function getClientInfo() {
2154
2221
  }
2155
2222
  function getBrowserID(clientInfo) {
2156
2223
  return _async_to_generator(function() {
2157
- var fingerprintString, encodedData, utf8, buffer, i, hashBuffer, hashArray, hashHex, error, hash, i1, char, fallbackHash, timestamp, random;
2224
+ var _crypto_subtle, fingerprintString, encodedData, utf8, buffer, i, hashBuffer, hashHex, unused, hash, i1, char, fallbackHash, timestamp, random;
2158
2225
  return _ts_generator(this, function(_state) {
2159
2226
  switch(_state.label){
2160
2227
  case 0:
2161
- if (cachedBrowserId) {
2162
- return [
2163
- 2,
2164
- cachedBrowserId
2165
- ];
2166
- }
2228
+ if (cachedBrowserId) return [
2229
+ 2,
2230
+ cachedBrowserId
2231
+ ];
2167
2232
  fingerprintString = JSON.stringify(clientInfo);
2168
- if (!(typeof crypto !== "undefined" && crypto.subtle && crypto.subtle.digest)) return [
2233
+ if (!(typeof crypto !== "undefined" && ((_crypto_subtle = crypto.subtle) === null || _crypto_subtle === void 0 ? void 0 : _crypto_subtle.digest))) return [
2169
2234
  3,
2170
2235
  5
2171
2236
  ];
@@ -2192,9 +2257,7 @@ function getBrowserID(clientInfo) {
2192
2257
  } else {
2193
2258
  utf8 = unescape(encodeURIComponent(fingerprintString));
2194
2259
  buffer = new Uint8Array(utf8.length);
2195
- for(i = 0; i < utf8.length; i++){
2196
- buffer[i] = utf8.charCodeAt(i);
2197
- }
2260
+ for(i = 0; i < utf8.length; i++)buffer[i] = utf8.charCodeAt(i);
2198
2261
  encodedData = buffer;
2199
2262
  }
2200
2263
  return [
@@ -2203,8 +2266,7 @@ function getBrowserID(clientInfo) {
2203
2266
  ];
2204
2267
  case 3:
2205
2268
  hashBuffer = _state.sent();
2206
- hashArray = Array.from(new Uint8Array(hashBuffer));
2207
- hashHex = hashArray.map(function(b) {
2269
+ hashHex = Array.from(new Uint8Array(hashBuffer)).map(function(b) {
2208
2270
  return b.toString(16).padStart(2, "0");
2209
2271
  }).join("");
2210
2272
  cachedBrowserId = hashHex;
@@ -2213,8 +2275,8 @@ function getBrowserID(clientInfo) {
2213
2275
  hashHex
2214
2276
  ];
2215
2277
  case 4:
2216
- error = _state.sent();
2217
- console.warn("[StormcloudVideoPlayer] crypto.subtle.digest not supported, using fallback hash");
2278
+ unused = _state.sent();
2279
+ console.warn("[StormcloudVideoPlayer] crypto.subtle not supported, using fallback hash");
2218
2280
  return [
2219
2281
  3,
2220
2282
  5
@@ -2238,6 +2300,10 @@ function getBrowserID(clientInfo) {
2238
2300
  });
2239
2301
  })();
2240
2302
  }
2303
+ var mqttTopicPrefix = "adstorm";
2304
+ function setMQTTTopicPrefix(prefix) {
2305
+ mqttTopicPrefix = prefix || "adstorm";
2306
+ }
2241
2307
  var PLAYER_TRACKING_BASE_URL = "https://adstorm.co/api-adstorm-dev/adstorm/player-tracking";
2242
2308
  var TRACK_URL = "".concat(PLAYER_TRACKING_BASE_URL, "/metrics/ingest");
2243
2309
  var HEARTBEAT_URL = "".concat(PLAYER_TRACKING_BASE_URL, "/heartbeat");
@@ -2246,43 +2312,9 @@ function buildHeaders(licenseKey) {
2246
2312
  var headers = {
2247
2313
  "Content-Type": "application/json"
2248
2314
  };
2249
- if (licenseKey) {
2250
- headers["Authorization"] = "Bearer ".concat(licenseKey);
2251
- }
2315
+ if (licenseKey) headers["Authorization"] = "Bearer ".concat(licenseKey);
2252
2316
  return headers;
2253
2317
  }
2254
- function sendTrackRequest(licenseKey, body) {
2255
- return _async_to_generator(function() {
2256
- var response;
2257
- return _ts_generator(this, function(_state) {
2258
- switch(_state.label){
2259
- case 0:
2260
- return [
2261
- 4,
2262
- fetch(TRACK_URL, {
2263
- method: "POST",
2264
- headers: buildHeaders(licenseKey),
2265
- body: JSON.stringify(body)
2266
- })
2267
- ];
2268
- case 1:
2269
- response = _state.sent();
2270
- if (!response.ok) {
2271
- throw new Error("HTTP error! status: ".concat(response.status));
2272
- }
2273
- return [
2274
- 4,
2275
- response.json()
2276
- ];
2277
- case 2:
2278
- _state.sent();
2279
- return [
2280
- 2
2281
- ];
2282
- }
2283
- });
2284
- })();
2285
- }
2286
2318
  function postJson(url, licenseKey, body) {
2287
2319
  return _async_to_generator(function() {
2288
2320
  var response;
@@ -2299,9 +2331,7 @@ function postJson(url, licenseKey, body) {
2299
2331
  ];
2300
2332
  case 1:
2301
2333
  response = _state.sent();
2302
- if (!response.ok) {
2303
- throw new Error("HTTP error! status: ".concat(response.status));
2304
- }
2334
+ if (!response.ok) throw new Error("HTTP error! status: ".concat(response.status));
2305
2335
  return [
2306
2336
  4,
2307
2337
  response.json()
@@ -2351,9 +2381,33 @@ function buildPlayerMetricEvent(_0) {
2351
2381
  });
2352
2382
  }).apply(this, arguments);
2353
2383
  }
2384
+ function publishOrPost(mqttTopic, httpUrl, licenseKey, body) {
2385
+ return _async_to_generator(function() {
2386
+ return _ts_generator(this, function(_state) {
2387
+ switch(_state.label){
2388
+ case 0:
2389
+ if (isMQTTConfigured()) {
2390
+ publishMQTT(mqttTopic, body);
2391
+ return [
2392
+ 2
2393
+ ];
2394
+ }
2395
+ return [
2396
+ 4,
2397
+ postJson(httpUrl, licenseKey, body)
2398
+ ];
2399
+ case 1:
2400
+ _state.sent();
2401
+ return [
2402
+ 2
2403
+ ];
2404
+ }
2405
+ });
2406
+ })();
2407
+ }
2354
2408
  function sendInitialTracking(_0) {
2355
2409
  return _async_to_generator(function(licenseKey) {
2356
- var context, clientInfo, browserId, trackingData, error;
2410
+ var context, clientInfo, browserId, captureAt, trackingData, metricsBody, error;
2357
2411
  var _arguments = arguments;
2358
2412
  return _ts_generator(this, function(_state) {
2359
2413
  switch(_state.label){
@@ -2374,26 +2428,28 @@ function sendInitialTracking(_0) {
2374
2428
  ];
2375
2429
  case 2:
2376
2430
  browserId = _state.sent();
2431
+ captureAt = /* @__PURE__ */ new Date().toISOString();
2377
2432
  trackingData = _object_spread({
2378
2433
  browserId: browserId
2379
2434
  }, clientInfo);
2435
+ metricsBody = {
2436
+ events: [
2437
+ {
2438
+ player_id: browserId,
2439
+ device_type: clientInfo.deviceType,
2440
+ input_stream_type: context.inputStreamType,
2441
+ os: clientInfo.os,
2442
+ ad_loaded: false,
2443
+ ad_detect: false,
2444
+ license_key: licenseKey,
2445
+ capture_at: captureAt
2446
+ }
2447
+ ],
2448
+ trackingData: trackingData
2449
+ };
2380
2450
  return [
2381
2451
  4,
2382
- sendTrackRequest(licenseKey, {
2383
- events: [
2384
- {
2385
- player_id: browserId,
2386
- device_type: clientInfo.deviceType,
2387
- input_stream_type: context.inputStreamType,
2388
- os: clientInfo.os,
2389
- ad_loaded: false,
2390
- ad_detect: false,
2391
- license_key: licenseKey,
2392
- capture_at: /* @__PURE__ */ new Date().toISOString()
2393
- }
2394
- ],
2395
- trackingData: trackingData
2396
- })
2452
+ publishOrPost("".concat(mqttTopicPrefix, "/tracking/metrics"), TRACK_URL, licenseKey, metricsBody)
2397
2453
  ];
2398
2454
  case 3:
2399
2455
  _state.sent();
@@ -2506,7 +2562,7 @@ function sendAdLoadedTracking(_0, _1) {
2506
2562
  }
2507
2563
  function sendAdImpressionTracking(_0, _1) {
2508
2564
  return _async_to_generator(function(licenseKey, adImpressionInfo) {
2509
- var context, metricEvent, error;
2565
+ var context, metricEvent, heartbeatBody, impressionsBody, error;
2510
2566
  var _arguments = arguments;
2511
2567
  return _ts_generator(this, function(_state) {
2512
2568
  switch(_state.label){
@@ -2528,21 +2584,23 @@ function sendAdImpressionTracking(_0, _1) {
2528
2584
  ];
2529
2585
  case 2:
2530
2586
  metricEvent = _state.sent();
2587
+ heartbeatBody = metricEvent;
2588
+ impressionsBody = {
2589
+ events: [
2590
+ {
2591
+ player_id: metricEvent.player_id,
2592
+ ad_played_count: 1,
2593
+ ad_url: adImpressionInfo.adUrl,
2594
+ license_key: licenseKey,
2595
+ capture_at: adImpressionInfo.timestamp
2596
+ }
2597
+ ]
2598
+ };
2531
2599
  return [
2532
2600
  4,
2533
2601
  Promise.all([
2534
- postJson(HEARTBEAT_URL, licenseKey, metricEvent),
2535
- postJson(IMPRESSIONS_URL, licenseKey, {
2536
- events: [
2537
- {
2538
- player_id: metricEvent.player_id,
2539
- ad_played_count: 1,
2540
- ad_url: adImpressionInfo.adUrl,
2541
- license_key: licenseKey,
2542
- capture_at: adImpressionInfo.timestamp
2543
- }
2544
- ]
2545
- })
2602
+ publishOrPost("".concat(mqttTopicPrefix, "/tracking/heartbeat"), HEARTBEAT_URL, licenseKey, heartbeatBody),
2603
+ publishOrPost("".concat(mqttTopicPrefix, "/tracking/impressions"), IMPRESSIONS_URL, licenseKey, impressionsBody)
2546
2604
  ])
2547
2605
  ];
2548
2606
  case 3:
@@ -2590,7 +2648,7 @@ function sendHeartbeat(_0) {
2590
2648
  heartbeatData = _state.sent();
2591
2649
  return [
2592
2650
  4,
2593
- postJson(HEARTBEAT_URL, licenseKey, heartbeatData)
2651
+ publishOrPost("".concat(mqttTopicPrefix, "/tracking/heartbeat"), HEARTBEAT_URL, licenseKey, heartbeatData)
2594
2652
  ];
2595
2653
  case 3:
2596
2654
  _state.sent();
@@ -4519,6 +4577,11 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4519
4577
  key: "initializeTracking",
4520
4578
  value: function initializeTracking() {
4521
4579
  var _this = this;
4580
+ if (this.config.mqttBrokerUrl) {
4581
+ var topicPrefix = "adstorm";
4582
+ setMQTTTopicPrefix(topicPrefix);
4583
+ initMQTTClient(this.config.mqttBrokerUrl, topicPrefix);
4584
+ }
4522
4585
  sendInitialTracking(this.config.licenseKey, this.getAnalyticsContext()).then(function() {
4523
4586
  _this.heartbeatInterval = window.setInterval(function() {
4524
4587
  _this.sendHeartbeatIfNeeded();
@@ -6198,6 +6261,9 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6198
6261
  clearInterval(this.heartbeatInterval);
6199
6262
  this.heartbeatInterval = void 0;
6200
6263
  }
6264
+ if (this.config.mqttBrokerUrl) {
6265
+ disconnectMQTT();
6266
+ }
6201
6267
  (_this_hls = this.hls) === null || _this_hls === void 0 ? void 0 : _this_hls.destroy();
6202
6268
  (_this_adLayer = this.adLayer) === null || _this_adLayer === void 0 ? void 0 : _this_adLayer.destroy();
6203
6269
  this.consecutiveFailures = 0;