stormcloud-video-player 0.6.0 → 0.6.1

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/lib/index.js CHANGED
@@ -944,14 +944,16 @@ function resolveBidToVastAd(winner, logPrefix) {
944
944
  return Promise.resolve(null);
945
945
  }
946
946
  function createVastAdLayer(contentVideo, options) {
947
- var _ref, _ref1;
947
+ var _ref, _ref1, _ref2, _ref3;
948
948
  var adPlaying = false;
949
949
  var originalMutedState = false;
950
950
  var originalVolume = Math.max(0, Math.min(1, contentVideo.volume || 1));
951
951
  var listeners = /* @__PURE__ */ new Map();
952
952
  var mainHlsInstance = options === null || options === void 0 ? void 0 : options.mainHlsInstance;
953
953
  var continueLiveStreamDuringAds = (_ref = options === null || options === void 0 ? void 0 : options.continueLiveStreamDuringAds) !== null && _ref !== void 0 ? _ref : false;
954
- var debug = (_ref1 = options === null || options === void 0 ? void 0 : options.debug) !== null && _ref1 !== void 0 ? _ref1 : false;
954
+ var smartTVMode = (_ref1 = options === null || options === void 0 ? void 0 : options.smartTVMode) !== null && _ref1 !== void 0 ? _ref1 : false;
955
+ var singleElementMode = (_ref2 = options === null || options === void 0 ? void 0 : options.singleElementMode) !== null && _ref2 !== void 0 ? _ref2 : false;
956
+ var debug = (_ref3 = options === null || options === void 0 ? void 0 : options.debug) !== null && _ref3 !== void 0 ? _ref3 : false;
955
957
  var adVideoElement;
956
958
  var adHls;
957
959
  var adContainerEl;
@@ -960,6 +962,7 @@ function createVastAdLayer(contentVideo, options) {
960
962
  var destroyed = false;
961
963
  var tornDown = false;
962
964
  var trackingFired = createEmptyTrackingState();
965
+ var currentAdEventHandlers;
963
966
  var preloadSlots = /* @__PURE__ */ new Map();
964
967
  function emit(event, payload) {
965
968
  var set = listeners.get(event);
@@ -1062,63 +1065,86 @@ function createVastAdLayer(contentVideo, options) {
1062
1065
  video.volume = 1;
1063
1066
  return video;
1064
1067
  }
1068
+ function removeAdEventListeners() {
1069
+ if (!currentAdEventHandlers || !adVideoElement) return;
1070
+ var el = adVideoElement;
1071
+ el.removeEventListener("timeupdate", currentAdEventHandlers.timeupdate);
1072
+ el.removeEventListener("playing", currentAdEventHandlers.playing);
1073
+ el.removeEventListener("ended", currentAdEventHandlers.ended);
1074
+ el.removeEventListener("error", currentAdEventHandlers.error);
1075
+ el.removeEventListener("volumechange", currentAdEventHandlers.volumechange);
1076
+ el.removeEventListener("pause", currentAdEventHandlers.pause);
1077
+ el.removeEventListener("play", currentAdEventHandlers.play);
1078
+ currentAdEventHandlers = void 0;
1079
+ }
1065
1080
  function setupAdEventListeners() {
1066
1081
  if (!adVideoElement) return;
1067
- adVideoElement.addEventListener("timeupdate", function() {
1068
- var ad = currentAd;
1069
- if (!ad || !adVideoElement) return;
1070
- var progress = adVideoElement.currentTime / ad.duration;
1071
- if (progress >= 0.25 && !trackingFired.firstQuartile) {
1072
- trackingFired.firstQuartile = true;
1073
- fireTrackingPixels2(ad.trackingUrls.firstQuartile);
1074
- }
1075
- if (progress >= 0.5 && !trackingFired.midpoint) {
1076
- trackingFired.midpoint = true;
1077
- fireTrackingPixels2(ad.trackingUrls.midpoint);
1078
- }
1079
- if (progress >= 0.75 && !trackingFired.thirdQuartile) {
1080
- trackingFired.thirdQuartile = true;
1081
- fireTrackingPixels2(ad.trackingUrls.thirdQuartile);
1082
- }
1083
- });
1084
- adVideoElement.addEventListener("playing", function() {
1085
- var ad = currentAd;
1086
- if (!ad || trackingFired.start) return;
1087
- trackingFired.start = true;
1088
- fireTrackingPixels2(ad.trackingUrls.start);
1089
- if (debug) console.log("".concat(LOG, " Ad started playing"));
1090
- });
1091
- adVideoElement.addEventListener("ended", function() {
1092
- if (tornDown || !currentAd || trackingFired.complete) return;
1093
- trackingFired.complete = true;
1094
- fireTrackingPixels2(currentAd.trackingUrls.complete);
1095
- if (debug) console.log("".concat(LOG, " Ad completed"));
1096
- handleAdComplete();
1097
- });
1098
- adVideoElement.addEventListener("error", function(e) {
1099
- if (tornDown) return;
1100
- console.error("".concat(LOG, " Ad video error:"), e);
1101
- if (currentAd) fireTrackingPixels2(currentAd.trackingUrls.error);
1102
- handleAdError();
1103
- });
1104
- adVideoElement.addEventListener("volumechange", function() {
1105
- if (!currentAd || !adVideoElement) return;
1106
- if (adVideoElement.muted) {
1107
- fireTrackingPixels2(currentAd.trackingUrls.mute);
1108
- } else {
1109
- fireTrackingPixels2(currentAd.trackingUrls.unmute);
1110
- }
1111
- });
1112
- adVideoElement.addEventListener("pause", function() {
1113
- if (currentAd && adVideoElement && !adVideoElement.ended) {
1114
- fireTrackingPixels2(currentAd.trackingUrls.pause);
1115
- }
1116
- });
1117
- adVideoElement.addEventListener("play", function() {
1118
- if (currentAd && adVideoElement && adVideoElement.currentTime > 0) {
1119
- fireTrackingPixels2(currentAd.trackingUrls.resume);
1082
+ removeAdEventListeners();
1083
+ var handlers = {
1084
+ timeupdate: function timeupdate() {
1085
+ var ad = currentAd;
1086
+ if (!ad || !adVideoElement) return;
1087
+ var progress = adVideoElement.currentTime / ad.duration;
1088
+ if (progress >= 0.25 && !trackingFired.firstQuartile) {
1089
+ trackingFired.firstQuartile = true;
1090
+ fireTrackingPixels2(ad.trackingUrls.firstQuartile);
1091
+ }
1092
+ if (progress >= 0.5 && !trackingFired.midpoint) {
1093
+ trackingFired.midpoint = true;
1094
+ fireTrackingPixels2(ad.trackingUrls.midpoint);
1095
+ }
1096
+ if (progress >= 0.75 && !trackingFired.thirdQuartile) {
1097
+ trackingFired.thirdQuartile = true;
1098
+ fireTrackingPixels2(ad.trackingUrls.thirdQuartile);
1099
+ }
1100
+ },
1101
+ playing: function playing() {
1102
+ var ad = currentAd;
1103
+ if (!ad || trackingFired.start) return;
1104
+ trackingFired.start = true;
1105
+ fireTrackingPixels2(ad.trackingUrls.start);
1106
+ if (debug) console.log("".concat(LOG, " Ad started playing"));
1107
+ },
1108
+ ended: function ended() {
1109
+ if (tornDown || !currentAd || trackingFired.complete) return;
1110
+ trackingFired.complete = true;
1111
+ fireTrackingPixels2(currentAd.trackingUrls.complete);
1112
+ if (debug) console.log("".concat(LOG, " Ad completed"));
1113
+ handleAdComplete();
1114
+ },
1115
+ error: function error(e) {
1116
+ if (tornDown) return;
1117
+ console.error("".concat(LOG, " Ad video error:"), e);
1118
+ if (currentAd) fireTrackingPixels2(currentAd.trackingUrls.error);
1119
+ handleAdError();
1120
+ },
1121
+ volumechange: function volumechange() {
1122
+ if (!currentAd || !adVideoElement) return;
1123
+ if (adVideoElement.muted) {
1124
+ fireTrackingPixels2(currentAd.trackingUrls.mute);
1125
+ } else {
1126
+ fireTrackingPixels2(currentAd.trackingUrls.unmute);
1127
+ }
1128
+ },
1129
+ pause: function pause() {
1130
+ if (currentAd && adVideoElement && !adVideoElement.ended) {
1131
+ fireTrackingPixels2(currentAd.trackingUrls.pause);
1132
+ }
1133
+ },
1134
+ play: function play() {
1135
+ if (currentAd && adVideoElement && adVideoElement.currentTime > 0) {
1136
+ fireTrackingPixels2(currentAd.trackingUrls.resume);
1137
+ }
1120
1138
  }
1121
- });
1139
+ };
1140
+ adVideoElement.addEventListener("timeupdate", handlers.timeupdate);
1141
+ adVideoElement.addEventListener("playing", handlers.playing);
1142
+ adVideoElement.addEventListener("ended", handlers.ended);
1143
+ adVideoElement.addEventListener("error", handlers.error);
1144
+ adVideoElement.addEventListener("volumechange", handlers.volumechange);
1145
+ adVideoElement.addEventListener("pause", handlers.pause);
1146
+ adVideoElement.addEventListener("play", handlers.play);
1147
+ currentAdEventHandlers = handlers;
1122
1148
  }
1123
1149
  function setAdPlayingFlag(isPlaying) {
1124
1150
  if (isPlaying) {
@@ -1141,6 +1167,7 @@ function createVastAdLayer(contentVideo, options) {
1141
1167
  }
1142
1168
  function handleAdError() {
1143
1169
  if (tornDown) return;
1170
+ if (!adPlaying) return;
1144
1171
  if (debug) console.log("".concat(LOG, " Handling ad error"));
1145
1172
  adPlaying = false;
1146
1173
  setAdPlayingFlag(false);
@@ -1151,14 +1178,19 @@ function createVastAdLayer(contentVideo, options) {
1151
1178
  emit("ad_error");
1152
1179
  }
1153
1180
  function teardownCurrentPlayback() {
1181
+ removeAdEventListeners();
1154
1182
  if (adHls) {
1155
1183
  adHls.destroy();
1156
1184
  adHls = void 0;
1157
1185
  }
1158
1186
  if (adVideoElement) {
1159
- adVideoElement.pause();
1160
- adVideoElement.removeAttribute("src");
1161
- adVideoElement.load();
1187
+ if (singleElementMode && adVideoElement === contentVideo) {
1188
+ contentVideo.pause();
1189
+ } else {
1190
+ adVideoElement.pause();
1191
+ adVideoElement.removeAttribute("src");
1192
+ adVideoElement.load();
1193
+ }
1162
1194
  }
1163
1195
  }
1164
1196
  function startNativePlayback(mediaFile) {
@@ -1191,8 +1223,17 @@ function createVastAdLayer(contentVideo, options) {
1191
1223
  handleAdError();
1192
1224
  });
1193
1225
  });
1226
+ var nonFatalNetworkErrors = 0;
1194
1227
  adHls.on(Hls.Events.ERROR, function(_event, data) {
1195
- if (data.fatal) handleAdError();
1228
+ if (data.fatal) {
1229
+ handleAdError();
1230
+ } else if (data.type === Hls.ErrorTypes.NETWORK_ERROR) {
1231
+ nonFatalNetworkErrors++;
1232
+ if (nonFatalNetworkErrors >= 3) {
1233
+ if (debug) console.warn("".concat(LOG, " Too many non-fatal HLS network errors (").concat(nonFatalNetworkErrors, "), treating as fatal"));
1234
+ handleAdError();
1235
+ }
1236
+ }
1196
1237
  });
1197
1238
  } else if (adVideoElement.canPlayType("application/vnd.apple.mpegurl")) {
1198
1239
  adVideoElement.src = mediaFile.url;
@@ -1215,7 +1256,7 @@ function createVastAdLayer(contentVideo, options) {
1215
1256
  }
1216
1257
  function playAd(bids) {
1217
1258
  return _async_to_generator(function() {
1218
- var winner, ad, _contentVideo_parentElement, container, contentVolume, adVolume, mediaFile;
1259
+ var winner, ad, contentVolume, _contentVideo_parentElement, container, adVolume, mediaFile;
1219
1260
  return _ts_generator(this, function(_state) {
1220
1261
  switch(_state.label){
1221
1262
  case 0:
@@ -1257,32 +1298,40 @@ function createVastAdLayer(contentVideo, options) {
1257
1298
  trackingFired = _object_spread({}, createEmptyTrackingState());
1258
1299
  fireTrackingPixels2(ad.trackingUrls.impression);
1259
1300
  trackingFired.impression = true;
1260
- if (!adContainerEl) {
1261
- ;
1262
- container = document.createElement("div");
1263
- container.style.position = "absolute";
1264
- container.style.left = "0";
1265
- container.style.top = "0";
1266
- container.style.right = "0";
1267
- container.style.bottom = "0";
1268
- container.style.display = "none";
1269
- container.style.alignItems = "center";
1270
- container.style.justifyContent = "center";
1271
- container.style.pointerEvents = "none";
1272
- container.style.zIndex = "10";
1273
- container.style.backgroundColor = "#000";
1274
- (_contentVideo_parentElement = contentVideo.parentElement) === null || _contentVideo_parentElement === void 0 ? void 0 : _contentVideo_parentElement.appendChild(container);
1275
- adContainerEl = container;
1276
- }
1277
- if (!adVideoElement) {
1278
- adVideoElement = createAdVideoElement();
1279
- adContainerEl.appendChild(adVideoElement);
1301
+ contentVolume = contentVideo.volume;
1302
+ originalVolume = Math.max(0, Math.min(1, contentVolume || originalVolume));
1303
+ if (singleElementMode) {
1304
+ mainHlsInstance === null || mainHlsInstance === void 0 ? void 0 : mainHlsInstance.detachMedia();
1305
+ teardownCurrentPlayback();
1306
+ adVideoElement = contentVideo;
1307
+ adHls = void 0;
1280
1308
  setupAdEventListeners();
1281
1309
  } else {
1282
- teardownCurrentPlayback();
1310
+ if (!adContainerEl) {
1311
+ ;
1312
+ container = document.createElement("div");
1313
+ container.style.position = "absolute";
1314
+ container.style.left = "0";
1315
+ container.style.top = "0";
1316
+ container.style.right = "0";
1317
+ container.style.bottom = "0";
1318
+ container.style.display = "none";
1319
+ container.style.alignItems = "center";
1320
+ container.style.justifyContent = "center";
1321
+ container.style.pointerEvents = "none";
1322
+ container.style.zIndex = "10";
1323
+ container.style.backgroundColor = "#000";
1324
+ (_contentVideo_parentElement = contentVideo.parentElement) === null || _contentVideo_parentElement === void 0 ? void 0 : _contentVideo_parentElement.appendChild(container);
1325
+ adContainerEl = container;
1326
+ }
1327
+ if (!adVideoElement) {
1328
+ adVideoElement = createAdVideoElement();
1329
+ adContainerEl.appendChild(adVideoElement);
1330
+ setupAdEventListeners();
1331
+ } else {
1332
+ teardownCurrentPlayback();
1333
+ }
1283
1334
  }
1284
- contentVolume = contentVideo.volume;
1285
- originalVolume = Math.max(0, Math.min(1, contentVolume || originalVolume));
1286
1335
  if (!continueLiveStreamDuringAds) {
1287
1336
  contentVideo.pause();
1288
1337
  }
@@ -1293,7 +1342,7 @@ function createVastAdLayer(contentVideo, options) {
1293
1342
  adVolume = originalMutedState ? 1 : originalVolume;
1294
1343
  adVideoElement.volume = Math.max(0, Math.min(1, adVolume));
1295
1344
  adVideoElement.muted = false;
1296
- if (adContainerEl) {
1345
+ if (!singleElementMode && adContainerEl) {
1297
1346
  adContainerEl.style.display = "flex";
1298
1347
  adContainerEl.style.pointerEvents = "auto";
1299
1348
  }
@@ -1330,7 +1379,7 @@ function createVastAdLayer(contentVideo, options) {
1330
1379
  }
1331
1380
  function preloadAd(bids, token) {
1332
1381
  return _async_to_generator(function() {
1333
- var winner, ad, mediaFile, videoEl, container, hls, slot, slot1;
1382
+ var winner, ad, mediaFile, slot, videoEl, container, hls, slot1, slot2;
1334
1383
  return _ts_generator(this, function(_state) {
1335
1384
  switch(_state.label){
1336
1385
  case 0:
@@ -1355,6 +1404,20 @@ function createVastAdLayer(contentVideo, options) {
1355
1404
  if (!mediaFile) return [
1356
1405
  2
1357
1406
  ];
1407
+ if (smartTVMode || singleElementMode) {
1408
+ slot = {
1409
+ bids: bids,
1410
+ ad: ad,
1411
+ mediaFile: mediaFile,
1412
+ videoEl: null,
1413
+ ready: true
1414
+ };
1415
+ preloadSlots.set(token, slot);
1416
+ if (debug) console.log("".concat(LOG, " [preload] Metadata-only preload (smartTV/singleElement), token=").concat(token, ", url=").concat(mediaFile.url));
1417
+ return [
1418
+ 2
1419
+ ];
1420
+ }
1358
1421
  videoEl = createAdVideoElement();
1359
1422
  videoEl.style.visibility = "hidden";
1360
1423
  videoEl.style.pointerEvents = "none";
@@ -1368,7 +1431,7 @@ function createVastAdLayer(contentVideo, options) {
1368
1431
  });
1369
1432
  hls.loadSource(mediaFile.url);
1370
1433
  hls.attachMedia(videoEl);
1371
- slot = {
1434
+ slot1 = {
1372
1435
  bids: bids,
1373
1436
  ad: ad,
1374
1437
  mediaFile: mediaFile,
@@ -1376,7 +1439,7 @@ function createVastAdLayer(contentVideo, options) {
1376
1439
  hlsInstance: hls,
1377
1440
  ready: false
1378
1441
  };
1379
- preloadSlots.set(token, slot);
1442
+ preloadSlots.set(token, slot1);
1380
1443
  hls.on(Hls.Events.MANIFEST_PARSED, function() {
1381
1444
  var s = preloadSlots.get(token);
1382
1445
  if (s) s.ready = true;
@@ -1393,14 +1456,14 @@ function createVastAdLayer(contentVideo, options) {
1393
1456
  } else {
1394
1457
  videoEl.src = mediaFile.url;
1395
1458
  videoEl.load();
1396
- slot1 = {
1459
+ slot2 = {
1397
1460
  bids: bids,
1398
1461
  ad: ad,
1399
1462
  mediaFile: mediaFile,
1400
1463
  videoEl: videoEl,
1401
1464
  ready: false
1402
1465
  };
1403
- preloadSlots.set(token, slot1);
1466
+ preloadSlots.set(token, slot2);
1404
1467
  videoEl.addEventListener("canplay", function() {
1405
1468
  var s = preloadSlots.get(token);
1406
1469
  if (s) s.ready = true;
@@ -1419,7 +1482,7 @@ function createVastAdLayer(contentVideo, options) {
1419
1482
  }
1420
1483
  function playPreloaded(token) {
1421
1484
  return _async_to_generator(function() {
1422
- var slot, contentVolume, adVolume, container;
1485
+ var slot, contentVolume, adVolume2, videoEl, container2, adVolume21, adVolume, container;
1423
1486
  return _ts_generator(this, function(_state) {
1424
1487
  if (destroyed) return [
1425
1488
  2,
@@ -1434,6 +1497,68 @@ function createVastAdLayer(contentVideo, options) {
1434
1497
  }
1435
1498
  preloadSlots.delete(token);
1436
1499
  if (debug) console.log("".concat(LOG, " [preload] Playing preloaded ad, token=").concat(token, ", ready=").concat(slot.ready));
1500
+ contentVolume = contentVideo.volume;
1501
+ originalVolume = Math.max(0, Math.min(1, contentVolume || originalVolume));
1502
+ sessionId = generateSessionId();
1503
+ currentAd = slot.ad;
1504
+ trackingFired = _object_spread({}, createEmptyTrackingState());
1505
+ fireTrackingPixels2(slot.ad.trackingUrls.impression);
1506
+ trackingFired.impression = true;
1507
+ if (singleElementMode) {
1508
+ mainHlsInstance === null || mainHlsInstance === void 0 ? void 0 : mainHlsInstance.detachMedia();
1509
+ teardownCurrentPlayback();
1510
+ adVideoElement = contentVideo;
1511
+ adHls = void 0;
1512
+ setupAdEventListeners();
1513
+ if (!continueLiveStreamDuringAds) {
1514
+ contentVideo.pause();
1515
+ }
1516
+ contentVideo.muted = true;
1517
+ contentVideo.volume = 0;
1518
+ adPlaying = true;
1519
+ setAdPlayingFlag(true);
1520
+ adVolume2 = originalMutedState ? 1 : originalVolume;
1521
+ contentVideo.volume = Math.max(0, Math.min(1, adVolume2));
1522
+ contentVideo.muted = false;
1523
+ emit("content_pause");
1524
+ if (debug) console.log("".concat(LOG, " [preload] singleElementMode: attaching ad to contentVideo, url=").concat(slot.mediaFile.url));
1525
+ startPlayback(slot.mediaFile);
1526
+ return [
1527
+ 2
1528
+ ];
1529
+ }
1530
+ if (smartTVMode && !slot.videoEl) {
1531
+ teardownCurrentPlayback();
1532
+ if (adVideoElement) {
1533
+ adVideoElement.remove();
1534
+ adVideoElement = void 0;
1535
+ }
1536
+ videoEl = createAdVideoElement();
1537
+ videoEl.style.visibility = "visible";
1538
+ videoEl.style.pointerEvents = "none";
1539
+ container2 = ensureAdContainer();
1540
+ container2.appendChild(videoEl);
1541
+ adVideoElement = videoEl;
1542
+ setupAdEventListeners();
1543
+ if (!continueLiveStreamDuringAds) {
1544
+ contentVideo.pause();
1545
+ }
1546
+ contentVideo.muted = true;
1547
+ contentVideo.volume = 0;
1548
+ adPlaying = true;
1549
+ setAdPlayingFlag(true);
1550
+ adVolume21 = originalMutedState ? 1 : originalVolume;
1551
+ adVideoElement.volume = Math.max(0, Math.min(1, adVolume21));
1552
+ adVideoElement.muted = false;
1553
+ container2.style.display = "flex";
1554
+ container2.style.pointerEvents = "auto";
1555
+ emit("content_pause");
1556
+ if (debug) console.log("".concat(LOG, " [preload] smartTVMode deferred: creating video element and loading, url=").concat(slot.mediaFile.url));
1557
+ startPlayback(slot.mediaFile);
1558
+ return [
1559
+ 2
1560
+ ];
1561
+ }
1437
1562
  teardownCurrentPlayback();
1438
1563
  if (adVideoElement && adVideoElement !== slot.videoEl) {
1439
1564
  adVideoElement.remove();
@@ -1443,13 +1568,6 @@ function createVastAdLayer(contentVideo, options) {
1443
1568
  adVideoElement = slot.videoEl;
1444
1569
  adHls = slot.hlsInstance;
1445
1570
  setupAdEventListeners();
1446
- sessionId = generateSessionId();
1447
- currentAd = slot.ad;
1448
- trackingFired = _object_spread({}, createEmptyTrackingState());
1449
- fireTrackingPixels2(slot.ad.trackingUrls.impression);
1450
- trackingFired.impression = true;
1451
- contentVolume = contentVideo.volume;
1452
- originalVolume = Math.max(0, Math.min(1, contentVolume || originalVolume));
1453
1571
  if (!continueLiveStreamDuringAds) {
1454
1572
  contentVideo.pause();
1455
1573
  }
@@ -1464,17 +1582,10 @@ function createVastAdLayer(contentVideo, options) {
1464
1582
  container.style.display = "flex";
1465
1583
  container.style.pointerEvents = "auto";
1466
1584
  emit("content_pause");
1467
- if (slot.hlsInstance) {
1468
- adVideoElement.play().catch(function(error) {
1469
- console.error("".concat(LOG, " [preload] Error playing preloaded HLS ad:"), error);
1470
- handleAdError();
1471
- });
1472
- } else {
1473
- adVideoElement.play().catch(function(error) {
1474
- console.error("".concat(LOG, " [preload] Error playing preloaded ad:"), error);
1475
- handleAdError();
1476
- });
1477
- }
1585
+ adVideoElement.play().catch(function(error) {
1586
+ console.error("".concat(LOG, " [preload] Error playing preloaded ad:"), error);
1587
+ handleAdError();
1588
+ });
1478
1589
  return [
1479
1590
  2
1480
1591
  ];
@@ -1488,10 +1599,12 @@ function createVastAdLayer(contentVideo, options) {
1488
1599
  if (slot.hlsInstance) {
1489
1600
  slot.hlsInstance.destroy();
1490
1601
  }
1491
- slot.videoEl.pause();
1492
- slot.videoEl.removeAttribute("src");
1493
- slot.videoEl.load();
1494
- slot.videoEl.remove();
1602
+ if (slot.videoEl) {
1603
+ slot.videoEl.pause();
1604
+ slot.videoEl.removeAttribute("src");
1605
+ slot.videoEl.load();
1606
+ slot.videoEl.remove();
1607
+ }
1495
1608
  if (debug) console.log("".concat(LOG, " [preload] Cancelled and cleaned up token=").concat(token));
1496
1609
  }
1497
1610
  return {
@@ -1539,20 +1652,27 @@ function createVastAdLayer(contentVideo, options) {
1539
1652
  setAdPlayingFlag(false);
1540
1653
  contentVideo.muted = originalMutedState;
1541
1654
  contentVideo.volume = originalMutedState ? 0 : originalVolume;
1542
- if (adContainerEl) {
1543
- adContainerEl.style.display = "none";
1544
- adContainerEl.style.pointerEvents = "none";
1545
- }
1546
1655
  contentVideo.style.visibility = "visible";
1547
1656
  contentVideo.style.opacity = "1";
1548
- if (continueLiveStreamDuringAds) {
1549
- contentVideo.play().catch(function() {});
1550
- }
1551
- teardownCurrentPlayback();
1552
- if (adVideoElement) {
1553
- adVideoElement.pause();
1554
- adVideoElement.removeAttribute("src");
1555
- adVideoElement.load();
1657
+ if (singleElementMode) {
1658
+ teardownCurrentPlayback();
1659
+ contentVideo.removeAttribute("src");
1660
+ contentVideo.load();
1661
+ adVideoElement = void 0;
1662
+ } else {
1663
+ if (adContainerEl) {
1664
+ adContainerEl.style.display = "none";
1665
+ adContainerEl.style.pointerEvents = "none";
1666
+ }
1667
+ if (continueLiveStreamDuringAds) {
1668
+ contentVideo.play().catch(function() {});
1669
+ }
1670
+ teardownCurrentPlayback();
1671
+ if (adVideoElement) {
1672
+ adVideoElement.pause();
1673
+ adVideoElement.removeAttribute("src");
1674
+ adVideoElement.load();
1675
+ }
1556
1676
  }
1557
1677
  currentAd = void 0;
1558
1678
  tornDown = false;
@@ -1592,9 +1712,14 @@ function createVastAdLayer(contentVideo, options) {
1592
1712
  }
1593
1713
  teardownCurrentPlayback();
1594
1714
  if (adVideoElement) {
1595
- adVideoElement.pause();
1596
- adVideoElement.removeAttribute("src");
1597
- adVideoElement.remove();
1715
+ if (singleElementMode && adVideoElement === contentVideo) {
1716
+ contentVideo.removeAttribute("src");
1717
+ contentVideo.load();
1718
+ } else {
1719
+ adVideoElement.pause();
1720
+ adVideoElement.removeAttribute("src");
1721
+ adVideoElement.remove();
1722
+ }
1598
1723
  adVideoElement = void 0;
1599
1724
  }
1600
1725
  if (adContainerEl === null || adContainerEl === void 0 ? void 0 : adContainerEl.parentElement) {
@@ -2820,8 +2945,11 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
2820
2945
  this.vastManager = createVastManager(config.debugAdTiming !== void 0 ? {
2821
2946
  debug: !!config.debugAdTiming
2822
2947
  } : {});
2948
+ var browserForAdLayer = detectBrowser();
2823
2949
  this.adLayer = createVastAdLayer(this.video, {
2824
2950
  continueLiveStreamDuringAds: false,
2951
+ smartTVMode: browserForAdLayer.isSmartTV,
2952
+ singleElementMode: browserForAdLayer.isSmartTV,
2825
2953
  debug: !!config.debugAdTiming
2826
2954
  });
2827
2955
  }
@@ -4183,6 +4311,10 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4183
4311
  if (!this.isLiveStream) {
4184
4312
  return false;
4185
4313
  }
4314
+ var browser = detectBrowser();
4315
+ if (browser.isSmartTV) {
4316
+ return false;
4317
+ }
4186
4318
  return true;
4187
4319
  }
4188
4320
  },
@@ -4390,7 +4522,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4390
4522
  switch(_state.label){
4391
4523
  case 0:
4392
4524
  _loop = function() {
4393
- var remaining, prefetchContext, bids, err, bids1, remainingNow, delay, elapsed, remaining1, context, bids2, remainingNow1, err1;
4525
+ var remaining, prefetchContext, bids, err, bids1, remainingNow, urgentNeedAd, delay, elapsed, remaining1, context, bids2, remainingNow1, err1, sleepMs;
4394
4526
  return _ts_generator(this, function(_state) {
4395
4527
  switch(_state.label){
4396
4528
  case 0:
@@ -4526,7 +4658,8 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4526
4658
  "continue"
4527
4659
  ];
4528
4660
  case 12:
4529
- delay = _this.lastAdRequestTime ? _this.minAdRequestIntervalMs + (_this.consecutiveFailures > 0 ? backoffMs() : 0) : 0;
4661
+ urgentNeedAd = _this.inAdBreak && !_this.adLayer.isAdPlaying();
4662
+ delay = _this.lastAdRequestTime ? _this.minAdRequestIntervalMs + (!urgentNeedAd && _this.consecutiveFailures > 0 ? backoffMs() : 0) : 0;
4530
4663
  elapsed = Date.now() - _this.lastAdRequestTime;
4531
4664
  if (!(elapsed < delay && _this.lastAdRequestTime > 0)) return [
4532
4665
  3,
@@ -4645,10 +4778,11 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4645
4778
  24
4646
4779
  ];
4647
4780
  case 24:
4781
+ sleepMs = _this.inAdBreak && !_this.adLayer.isAdPlaying() ? 0 : backoffMs();
4648
4782
  return [
4649
4783
  4,
4650
4784
  new Promise(function(r) {
4651
- return setTimeout(r, backoffMs());
4785
+ return setTimeout(r, sleepMs);
4652
4786
  })
4653
4787
  ];
4654
4788
  case 25:
@@ -5329,40 +5463,45 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5329
5463
  var browser = detectBrowser();
5330
5464
  var isSmartTV = browser.tizenVersion !== void 0 || browser.webOSVersion !== void 0;
5331
5465
  if (isSmartTV && this.hls) {
5332
- if (!restoredMuted) {
5333
- var hlsRef = this.hls;
5334
- var savedMuted = restoredMuted;
5335
- var savedVolume = restoredVolume;
5336
- var onManifestParsedRestore = function onManifestParsedRestore1() {
5337
- hlsRef.off(Hls2.Events.MANIFEST_PARSED, onManifestParsedRestore);
5338
- if (!_this.inAdBreak && !_this.adLayer.isAdPlaying()) {
5339
- if (_this.video.muted !== savedMuted) _this.video.muted = savedMuted;
5340
- if (Math.abs(_this.video.volume - savedVolume) > 0.01) _this.video.volume = savedVolume;
5341
- if (_this.config.debugAdTiming) {
5342
- console.log("[StormcloudVideoPlayer] Smart TV: audio state restored on MANIFEST_PARSED after re-attach");
5343
- }
5466
+ var hlsRef = this.hls;
5467
+ var savedMuted = restoredMuted;
5468
+ var savedVolume = restoredVolume;
5469
+ var onManifestParsedRestore = function onManifestParsedRestore1() {
5470
+ hlsRef.off(Hls2.Events.MANIFEST_PARSED, onManifestParsedRestore);
5471
+ if (!_this.inAdBreak && !_this.adLayer.isAdPlaying()) {
5472
+ var _this_video_play;
5473
+ if (_this.video.muted !== savedMuted) _this.video.muted = savedMuted;
5474
+ if (Math.abs(_this.video.volume - savedVolume) > 0.01) _this.video.volume = savedVolume;
5475
+ if (_this.config.debugAdTiming) {
5476
+ console.log("[StormcloudVideoPlayer] Smart TV: audio state restored on MANIFEST_PARSED after re-attach");
5344
5477
  }
5345
- };
5346
- hlsRef.on(Hls2.Events.MANIFEST_PARSED, onManifestParsedRestore);
5347
- }
5478
+ hlsRef.startLoad(-1);
5479
+ (_this_video_play = _this.video.play()) === null || _this_video_play === void 0 ? void 0 : _this_video_play.catch(function() {});
5480
+ if (_this.config.debugAdTiming) {
5481
+ console.log("[StormcloudVideoPlayer] Smart TV: seeking to live edge and resuming playback after re-attach");
5482
+ }
5483
+ }
5484
+ };
5485
+ hlsRef.on(Hls2.Events.MANIFEST_PARSED, onManifestParsedRestore);
5348
5486
  this.hls.attachMedia(this.video);
5349
5487
  if (this.config.debugAdTiming) {
5350
5488
  console.log("[StormcloudVideoPlayer] Smart TV: re-attached HLS to video element after ad break to restore media pipeline");
5351
5489
  }
5352
- }
5353
- if (this.shouldContinueLiveStreamDuringAds()) {
5354
- var _this_video_play;
5355
- if (this.config.debugAdTiming) {
5356
- if (this.video.paused) {
5357
- console.log("[StormcloudVideoPlayer] Content video paused in live mode after ads, resuming playback");
5358
- } else {
5359
- console.log("[StormcloudVideoPlayer] Content video already playing in live mode after ads");
5490
+ } else {
5491
+ if (this.shouldContinueLiveStreamDuringAds()) {
5492
+ var _this_video_play;
5493
+ if (this.config.debugAdTiming) {
5494
+ if (this.video.paused) {
5495
+ console.log("[StormcloudVideoPlayer] Content video paused in live mode after ads, resuming playback");
5496
+ } else {
5497
+ console.log("[StormcloudVideoPlayer] Content video already playing in live mode after ads");
5498
+ }
5360
5499
  }
5500
+ (_this_video_play = this.video.play()) === null || _this_video_play === void 0 ? void 0 : _this_video_play.catch(function() {});
5501
+ } else if (this.video.paused) {
5502
+ var _this_video_play1;
5503
+ (_this_video_play1 = this.video.play()) === null || _this_video_play1 === void 0 ? void 0 : _this_video_play1.catch(function() {});
5361
5504
  }
5362
- (_this_video_play = this.video.play()) === null || _this_video_play === void 0 ? void 0 : _this_video_play.catch(function() {});
5363
- } else if (this.video.paused) {
5364
- var _this_video_play1;
5365
- (_this_video_play1 = this.video.play()) === null || _this_video_play1 === void 0 ? void 0 : _this_video_play1.catch(function() {});
5366
5505
  }
5367
5506
  this.syncMainContentAudioWhenVisible();
5368
5507
  if (!restoredMuted) {
@@ -5413,6 +5552,14 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5413
5552
  console.log("[CONTINUOUS-FETCH] \uD83D\uDED1 Max consecutive failures reached (".concat(this.consecutiveFailures, "), ending ad break gracefully"));
5414
5553
  }
5415
5554
  this.handleAdPodComplete();
5555
+ return;
5556
+ }
5557
+ if (this.inAdBreak && !this.config.disableFiller) {
5558
+ if (this.config.debugAdTiming) {
5559
+ console.log("[CONTINUOUS-FETCH] Ad failure in active break \u2014 showing filler while awaiting next ad");
5560
+ }
5561
+ this.showPlaceholderLayer();
5562
+ this.adLayer.showPlaceholder();
5416
5563
  }
5417
5564
  }
5418
5565
  },