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.
@@ -1010,14 +1010,16 @@ function resolveBidToVastAd(winner, logPrefix) {
1010
1010
  return Promise.resolve(null);
1011
1011
  }
1012
1012
  function createVastAdLayer(contentVideo, options) {
1013
- var _ref, _ref1;
1013
+ var _ref, _ref1, _ref2, _ref3;
1014
1014
  var adPlaying = false;
1015
1015
  var originalMutedState = false;
1016
1016
  var originalVolume = Math.max(0, Math.min(1, contentVideo.volume || 1));
1017
1017
  var listeners = /* @__PURE__ */ new Map();
1018
1018
  var mainHlsInstance = options === null || options === void 0 ? void 0 : options.mainHlsInstance;
1019
1019
  var continueLiveStreamDuringAds = (_ref = options === null || options === void 0 ? void 0 : options.continueLiveStreamDuringAds) !== null && _ref !== void 0 ? _ref : false;
1020
- var debug = (_ref1 = options === null || options === void 0 ? void 0 : options.debug) !== null && _ref1 !== void 0 ? _ref1 : false;
1020
+ var smartTVMode = (_ref1 = options === null || options === void 0 ? void 0 : options.smartTVMode) !== null && _ref1 !== void 0 ? _ref1 : false;
1021
+ var singleElementMode = (_ref2 = options === null || options === void 0 ? void 0 : options.singleElementMode) !== null && _ref2 !== void 0 ? _ref2 : false;
1022
+ var debug = (_ref3 = options === null || options === void 0 ? void 0 : options.debug) !== null && _ref3 !== void 0 ? _ref3 : false;
1021
1023
  var adVideoElement;
1022
1024
  var adHls;
1023
1025
  var adContainerEl;
@@ -1026,6 +1028,7 @@ function createVastAdLayer(contentVideo, options) {
1026
1028
  var destroyed = false;
1027
1029
  var tornDown = false;
1028
1030
  var trackingFired = createEmptyTrackingState();
1031
+ var currentAdEventHandlers;
1029
1032
  var preloadSlots = /* @__PURE__ */ new Map();
1030
1033
  function emit(event, payload) {
1031
1034
  var set = listeners.get(event);
@@ -1128,63 +1131,86 @@ function createVastAdLayer(contentVideo, options) {
1128
1131
  video.volume = 1;
1129
1132
  return video;
1130
1133
  }
1134
+ function removeAdEventListeners() {
1135
+ if (!currentAdEventHandlers || !adVideoElement) return;
1136
+ var el = adVideoElement;
1137
+ el.removeEventListener("timeupdate", currentAdEventHandlers.timeupdate);
1138
+ el.removeEventListener("playing", currentAdEventHandlers.playing);
1139
+ el.removeEventListener("ended", currentAdEventHandlers.ended);
1140
+ el.removeEventListener("error", currentAdEventHandlers.error);
1141
+ el.removeEventListener("volumechange", currentAdEventHandlers.volumechange);
1142
+ el.removeEventListener("pause", currentAdEventHandlers.pause);
1143
+ el.removeEventListener("play", currentAdEventHandlers.play);
1144
+ currentAdEventHandlers = void 0;
1145
+ }
1131
1146
  function setupAdEventListeners() {
1132
1147
  if (!adVideoElement) return;
1133
- adVideoElement.addEventListener("timeupdate", function() {
1134
- var ad = currentAd;
1135
- if (!ad || !adVideoElement) return;
1136
- var progress = adVideoElement.currentTime / ad.duration;
1137
- if (progress >= 0.25 && !trackingFired.firstQuartile) {
1138
- trackingFired.firstQuartile = true;
1139
- fireTrackingPixels2(ad.trackingUrls.firstQuartile);
1140
- }
1141
- if (progress >= 0.5 && !trackingFired.midpoint) {
1142
- trackingFired.midpoint = true;
1143
- fireTrackingPixels2(ad.trackingUrls.midpoint);
1144
- }
1145
- if (progress >= 0.75 && !trackingFired.thirdQuartile) {
1146
- trackingFired.thirdQuartile = true;
1147
- fireTrackingPixels2(ad.trackingUrls.thirdQuartile);
1148
- }
1149
- });
1150
- adVideoElement.addEventListener("playing", function() {
1151
- var ad = currentAd;
1152
- if (!ad || trackingFired.start) return;
1153
- trackingFired.start = true;
1154
- fireTrackingPixels2(ad.trackingUrls.start);
1155
- if (debug) console.log("".concat(LOG, " Ad started playing"));
1156
- });
1157
- adVideoElement.addEventListener("ended", function() {
1158
- if (tornDown || !currentAd || trackingFired.complete) return;
1159
- trackingFired.complete = true;
1160
- fireTrackingPixels2(currentAd.trackingUrls.complete);
1161
- if (debug) console.log("".concat(LOG, " Ad completed"));
1162
- handleAdComplete();
1163
- });
1164
- adVideoElement.addEventListener("error", function(e) {
1165
- if (tornDown) return;
1166
- console.error("".concat(LOG, " Ad video error:"), e);
1167
- if (currentAd) fireTrackingPixels2(currentAd.trackingUrls.error);
1168
- handleAdError();
1169
- });
1170
- adVideoElement.addEventListener("volumechange", function() {
1171
- if (!currentAd || !adVideoElement) return;
1172
- if (adVideoElement.muted) {
1173
- fireTrackingPixels2(currentAd.trackingUrls.mute);
1174
- } else {
1175
- fireTrackingPixels2(currentAd.trackingUrls.unmute);
1176
- }
1177
- });
1178
- adVideoElement.addEventListener("pause", function() {
1179
- if (currentAd && adVideoElement && !adVideoElement.ended) {
1180
- fireTrackingPixels2(currentAd.trackingUrls.pause);
1181
- }
1182
- });
1183
- adVideoElement.addEventListener("play", function() {
1184
- if (currentAd && adVideoElement && adVideoElement.currentTime > 0) {
1185
- fireTrackingPixels2(currentAd.trackingUrls.resume);
1148
+ removeAdEventListeners();
1149
+ var handlers = {
1150
+ timeupdate: function timeupdate() {
1151
+ var ad = currentAd;
1152
+ if (!ad || !adVideoElement) return;
1153
+ var progress = adVideoElement.currentTime / ad.duration;
1154
+ if (progress >= 0.25 && !trackingFired.firstQuartile) {
1155
+ trackingFired.firstQuartile = true;
1156
+ fireTrackingPixels2(ad.trackingUrls.firstQuartile);
1157
+ }
1158
+ if (progress >= 0.5 && !trackingFired.midpoint) {
1159
+ trackingFired.midpoint = true;
1160
+ fireTrackingPixels2(ad.trackingUrls.midpoint);
1161
+ }
1162
+ if (progress >= 0.75 && !trackingFired.thirdQuartile) {
1163
+ trackingFired.thirdQuartile = true;
1164
+ fireTrackingPixels2(ad.trackingUrls.thirdQuartile);
1165
+ }
1166
+ },
1167
+ playing: function playing() {
1168
+ var ad = currentAd;
1169
+ if (!ad || trackingFired.start) return;
1170
+ trackingFired.start = true;
1171
+ fireTrackingPixels2(ad.trackingUrls.start);
1172
+ if (debug) console.log("".concat(LOG, " Ad started playing"));
1173
+ },
1174
+ ended: function ended() {
1175
+ if (tornDown || !currentAd || trackingFired.complete) return;
1176
+ trackingFired.complete = true;
1177
+ fireTrackingPixels2(currentAd.trackingUrls.complete);
1178
+ if (debug) console.log("".concat(LOG, " Ad completed"));
1179
+ handleAdComplete();
1180
+ },
1181
+ error: function error(e) {
1182
+ if (tornDown) return;
1183
+ console.error("".concat(LOG, " Ad video error:"), e);
1184
+ if (currentAd) fireTrackingPixels2(currentAd.trackingUrls.error);
1185
+ handleAdError();
1186
+ },
1187
+ volumechange: function volumechange() {
1188
+ if (!currentAd || !adVideoElement) return;
1189
+ if (adVideoElement.muted) {
1190
+ fireTrackingPixels2(currentAd.trackingUrls.mute);
1191
+ } else {
1192
+ fireTrackingPixels2(currentAd.trackingUrls.unmute);
1193
+ }
1194
+ },
1195
+ pause: function pause() {
1196
+ if (currentAd && adVideoElement && !adVideoElement.ended) {
1197
+ fireTrackingPixels2(currentAd.trackingUrls.pause);
1198
+ }
1199
+ },
1200
+ play: function play() {
1201
+ if (currentAd && adVideoElement && adVideoElement.currentTime > 0) {
1202
+ fireTrackingPixels2(currentAd.trackingUrls.resume);
1203
+ }
1186
1204
  }
1187
- });
1205
+ };
1206
+ adVideoElement.addEventListener("timeupdate", handlers.timeupdate);
1207
+ adVideoElement.addEventListener("playing", handlers.playing);
1208
+ adVideoElement.addEventListener("ended", handlers.ended);
1209
+ adVideoElement.addEventListener("error", handlers.error);
1210
+ adVideoElement.addEventListener("volumechange", handlers.volumechange);
1211
+ adVideoElement.addEventListener("pause", handlers.pause);
1212
+ adVideoElement.addEventListener("play", handlers.play);
1213
+ currentAdEventHandlers = handlers;
1188
1214
  }
1189
1215
  function setAdPlayingFlag(isPlaying) {
1190
1216
  if (isPlaying) {
@@ -1207,6 +1233,7 @@ function createVastAdLayer(contentVideo, options) {
1207
1233
  }
1208
1234
  function handleAdError() {
1209
1235
  if (tornDown) return;
1236
+ if (!adPlaying) return;
1210
1237
  if (debug) console.log("".concat(LOG, " Handling ad error"));
1211
1238
  adPlaying = false;
1212
1239
  setAdPlayingFlag(false);
@@ -1217,14 +1244,19 @@ function createVastAdLayer(contentVideo, options) {
1217
1244
  emit("ad_error");
1218
1245
  }
1219
1246
  function teardownCurrentPlayback() {
1247
+ removeAdEventListeners();
1220
1248
  if (adHls) {
1221
1249
  adHls.destroy();
1222
1250
  adHls = void 0;
1223
1251
  }
1224
1252
  if (adVideoElement) {
1225
- adVideoElement.pause();
1226
- adVideoElement.removeAttribute("src");
1227
- adVideoElement.load();
1253
+ if (singleElementMode && adVideoElement === contentVideo) {
1254
+ contentVideo.pause();
1255
+ } else {
1256
+ adVideoElement.pause();
1257
+ adVideoElement.removeAttribute("src");
1258
+ adVideoElement.load();
1259
+ }
1228
1260
  }
1229
1261
  }
1230
1262
  function startNativePlayback(mediaFile) {
@@ -1257,8 +1289,17 @@ function createVastAdLayer(contentVideo, options) {
1257
1289
  handleAdError();
1258
1290
  });
1259
1291
  });
1292
+ var nonFatalNetworkErrors = 0;
1260
1293
  adHls.on(import_hls.default.Events.ERROR, function(_event, data) {
1261
- if (data.fatal) handleAdError();
1294
+ if (data.fatal) {
1295
+ handleAdError();
1296
+ } else if (data.type === import_hls.default.ErrorTypes.NETWORK_ERROR) {
1297
+ nonFatalNetworkErrors++;
1298
+ if (nonFatalNetworkErrors >= 3) {
1299
+ if (debug) console.warn("".concat(LOG, " Too many non-fatal HLS network errors (").concat(nonFatalNetworkErrors, "), treating as fatal"));
1300
+ handleAdError();
1301
+ }
1302
+ }
1262
1303
  });
1263
1304
  } else if (adVideoElement.canPlayType("application/vnd.apple.mpegurl")) {
1264
1305
  adVideoElement.src = mediaFile.url;
@@ -1281,7 +1322,7 @@ function createVastAdLayer(contentVideo, options) {
1281
1322
  }
1282
1323
  function playAd(bids) {
1283
1324
  return _async_to_generator(function() {
1284
- var winner, ad, _contentVideo_parentElement, container, contentVolume, adVolume, mediaFile;
1325
+ var winner, ad, contentVolume, _contentVideo_parentElement, container, adVolume, mediaFile;
1285
1326
  return _ts_generator(this, function(_state) {
1286
1327
  switch(_state.label){
1287
1328
  case 0:
@@ -1323,32 +1364,40 @@ function createVastAdLayer(contentVideo, options) {
1323
1364
  trackingFired = _object_spread({}, createEmptyTrackingState());
1324
1365
  fireTrackingPixels2(ad.trackingUrls.impression);
1325
1366
  trackingFired.impression = true;
1326
- if (!adContainerEl) {
1327
- ;
1328
- container = document.createElement("div");
1329
- container.style.position = "absolute";
1330
- container.style.left = "0";
1331
- container.style.top = "0";
1332
- container.style.right = "0";
1333
- container.style.bottom = "0";
1334
- container.style.display = "none";
1335
- container.style.alignItems = "center";
1336
- container.style.justifyContent = "center";
1337
- container.style.pointerEvents = "none";
1338
- container.style.zIndex = "10";
1339
- container.style.backgroundColor = "#000";
1340
- (_contentVideo_parentElement = contentVideo.parentElement) === null || _contentVideo_parentElement === void 0 ? void 0 : _contentVideo_parentElement.appendChild(container);
1341
- adContainerEl = container;
1342
- }
1343
- if (!adVideoElement) {
1344
- adVideoElement = createAdVideoElement();
1345
- adContainerEl.appendChild(adVideoElement);
1367
+ contentVolume = contentVideo.volume;
1368
+ originalVolume = Math.max(0, Math.min(1, contentVolume || originalVolume));
1369
+ if (singleElementMode) {
1370
+ mainHlsInstance === null || mainHlsInstance === void 0 ? void 0 : mainHlsInstance.detachMedia();
1371
+ teardownCurrentPlayback();
1372
+ adVideoElement = contentVideo;
1373
+ adHls = void 0;
1346
1374
  setupAdEventListeners();
1347
1375
  } else {
1348
- teardownCurrentPlayback();
1376
+ if (!adContainerEl) {
1377
+ ;
1378
+ container = document.createElement("div");
1379
+ container.style.position = "absolute";
1380
+ container.style.left = "0";
1381
+ container.style.top = "0";
1382
+ container.style.right = "0";
1383
+ container.style.bottom = "0";
1384
+ container.style.display = "none";
1385
+ container.style.alignItems = "center";
1386
+ container.style.justifyContent = "center";
1387
+ container.style.pointerEvents = "none";
1388
+ container.style.zIndex = "10";
1389
+ container.style.backgroundColor = "#000";
1390
+ (_contentVideo_parentElement = contentVideo.parentElement) === null || _contentVideo_parentElement === void 0 ? void 0 : _contentVideo_parentElement.appendChild(container);
1391
+ adContainerEl = container;
1392
+ }
1393
+ if (!adVideoElement) {
1394
+ adVideoElement = createAdVideoElement();
1395
+ adContainerEl.appendChild(adVideoElement);
1396
+ setupAdEventListeners();
1397
+ } else {
1398
+ teardownCurrentPlayback();
1399
+ }
1349
1400
  }
1350
- contentVolume = contentVideo.volume;
1351
- originalVolume = Math.max(0, Math.min(1, contentVolume || originalVolume));
1352
1401
  if (!continueLiveStreamDuringAds) {
1353
1402
  contentVideo.pause();
1354
1403
  }
@@ -1359,7 +1408,7 @@ function createVastAdLayer(contentVideo, options) {
1359
1408
  adVolume = originalMutedState ? 1 : originalVolume;
1360
1409
  adVideoElement.volume = Math.max(0, Math.min(1, adVolume));
1361
1410
  adVideoElement.muted = false;
1362
- if (adContainerEl) {
1411
+ if (!singleElementMode && adContainerEl) {
1363
1412
  adContainerEl.style.display = "flex";
1364
1413
  adContainerEl.style.pointerEvents = "auto";
1365
1414
  }
@@ -1396,7 +1445,7 @@ function createVastAdLayer(contentVideo, options) {
1396
1445
  }
1397
1446
  function preloadAd(bids, token) {
1398
1447
  return _async_to_generator(function() {
1399
- var winner, ad, mediaFile, videoEl, container, hls, slot, slot1;
1448
+ var winner, ad, mediaFile, slot, videoEl, container, hls, slot1, slot2;
1400
1449
  return _ts_generator(this, function(_state) {
1401
1450
  switch(_state.label){
1402
1451
  case 0:
@@ -1421,6 +1470,20 @@ function createVastAdLayer(contentVideo, options) {
1421
1470
  if (!mediaFile) return [
1422
1471
  2
1423
1472
  ];
1473
+ if (smartTVMode || singleElementMode) {
1474
+ slot = {
1475
+ bids: bids,
1476
+ ad: ad,
1477
+ mediaFile: mediaFile,
1478
+ videoEl: null,
1479
+ ready: true
1480
+ };
1481
+ preloadSlots.set(token, slot);
1482
+ if (debug) console.log("".concat(LOG, " [preload] Metadata-only preload (smartTV/singleElement), token=").concat(token, ", url=").concat(mediaFile.url));
1483
+ return [
1484
+ 2
1485
+ ];
1486
+ }
1424
1487
  videoEl = createAdVideoElement();
1425
1488
  videoEl.style.visibility = "hidden";
1426
1489
  videoEl.style.pointerEvents = "none";
@@ -1434,7 +1497,7 @@ function createVastAdLayer(contentVideo, options) {
1434
1497
  });
1435
1498
  hls.loadSource(mediaFile.url);
1436
1499
  hls.attachMedia(videoEl);
1437
- slot = {
1500
+ slot1 = {
1438
1501
  bids: bids,
1439
1502
  ad: ad,
1440
1503
  mediaFile: mediaFile,
@@ -1442,7 +1505,7 @@ function createVastAdLayer(contentVideo, options) {
1442
1505
  hlsInstance: hls,
1443
1506
  ready: false
1444
1507
  };
1445
- preloadSlots.set(token, slot);
1508
+ preloadSlots.set(token, slot1);
1446
1509
  hls.on(import_hls.default.Events.MANIFEST_PARSED, function() {
1447
1510
  var s = preloadSlots.get(token);
1448
1511
  if (s) s.ready = true;
@@ -1459,14 +1522,14 @@ function createVastAdLayer(contentVideo, options) {
1459
1522
  } else {
1460
1523
  videoEl.src = mediaFile.url;
1461
1524
  videoEl.load();
1462
- slot1 = {
1525
+ slot2 = {
1463
1526
  bids: bids,
1464
1527
  ad: ad,
1465
1528
  mediaFile: mediaFile,
1466
1529
  videoEl: videoEl,
1467
1530
  ready: false
1468
1531
  };
1469
- preloadSlots.set(token, slot1);
1532
+ preloadSlots.set(token, slot2);
1470
1533
  videoEl.addEventListener("canplay", function() {
1471
1534
  var s = preloadSlots.get(token);
1472
1535
  if (s) s.ready = true;
@@ -1485,7 +1548,7 @@ function createVastAdLayer(contentVideo, options) {
1485
1548
  }
1486
1549
  function playPreloaded(token) {
1487
1550
  return _async_to_generator(function() {
1488
- var slot, contentVolume, adVolume, container;
1551
+ var slot, contentVolume, adVolume2, videoEl, container2, adVolume21, adVolume, container;
1489
1552
  return _ts_generator(this, function(_state) {
1490
1553
  if (destroyed) return [
1491
1554
  2,
@@ -1500,6 +1563,68 @@ function createVastAdLayer(contentVideo, options) {
1500
1563
  }
1501
1564
  preloadSlots.delete(token);
1502
1565
  if (debug) console.log("".concat(LOG, " [preload] Playing preloaded ad, token=").concat(token, ", ready=").concat(slot.ready));
1566
+ contentVolume = contentVideo.volume;
1567
+ originalVolume = Math.max(0, Math.min(1, contentVolume || originalVolume));
1568
+ sessionId = generateSessionId();
1569
+ currentAd = slot.ad;
1570
+ trackingFired = _object_spread({}, createEmptyTrackingState());
1571
+ fireTrackingPixels2(slot.ad.trackingUrls.impression);
1572
+ trackingFired.impression = true;
1573
+ if (singleElementMode) {
1574
+ mainHlsInstance === null || mainHlsInstance === void 0 ? void 0 : mainHlsInstance.detachMedia();
1575
+ teardownCurrentPlayback();
1576
+ adVideoElement = contentVideo;
1577
+ adHls = void 0;
1578
+ setupAdEventListeners();
1579
+ if (!continueLiveStreamDuringAds) {
1580
+ contentVideo.pause();
1581
+ }
1582
+ contentVideo.muted = true;
1583
+ contentVideo.volume = 0;
1584
+ adPlaying = true;
1585
+ setAdPlayingFlag(true);
1586
+ adVolume2 = originalMutedState ? 1 : originalVolume;
1587
+ contentVideo.volume = Math.max(0, Math.min(1, adVolume2));
1588
+ contentVideo.muted = false;
1589
+ emit("content_pause");
1590
+ if (debug) console.log("".concat(LOG, " [preload] singleElementMode: attaching ad to contentVideo, url=").concat(slot.mediaFile.url));
1591
+ startPlayback(slot.mediaFile);
1592
+ return [
1593
+ 2
1594
+ ];
1595
+ }
1596
+ if (smartTVMode && !slot.videoEl) {
1597
+ teardownCurrentPlayback();
1598
+ if (adVideoElement) {
1599
+ adVideoElement.remove();
1600
+ adVideoElement = void 0;
1601
+ }
1602
+ videoEl = createAdVideoElement();
1603
+ videoEl.style.visibility = "visible";
1604
+ videoEl.style.pointerEvents = "none";
1605
+ container2 = ensureAdContainer();
1606
+ container2.appendChild(videoEl);
1607
+ adVideoElement = videoEl;
1608
+ setupAdEventListeners();
1609
+ if (!continueLiveStreamDuringAds) {
1610
+ contentVideo.pause();
1611
+ }
1612
+ contentVideo.muted = true;
1613
+ contentVideo.volume = 0;
1614
+ adPlaying = true;
1615
+ setAdPlayingFlag(true);
1616
+ adVolume21 = originalMutedState ? 1 : originalVolume;
1617
+ adVideoElement.volume = Math.max(0, Math.min(1, adVolume21));
1618
+ adVideoElement.muted = false;
1619
+ container2.style.display = "flex";
1620
+ container2.style.pointerEvents = "auto";
1621
+ emit("content_pause");
1622
+ if (debug) console.log("".concat(LOG, " [preload] smartTVMode deferred: creating video element and loading, url=").concat(slot.mediaFile.url));
1623
+ startPlayback(slot.mediaFile);
1624
+ return [
1625
+ 2
1626
+ ];
1627
+ }
1503
1628
  teardownCurrentPlayback();
1504
1629
  if (adVideoElement && adVideoElement !== slot.videoEl) {
1505
1630
  adVideoElement.remove();
@@ -1509,13 +1634,6 @@ function createVastAdLayer(contentVideo, options) {
1509
1634
  adVideoElement = slot.videoEl;
1510
1635
  adHls = slot.hlsInstance;
1511
1636
  setupAdEventListeners();
1512
- sessionId = generateSessionId();
1513
- currentAd = slot.ad;
1514
- trackingFired = _object_spread({}, createEmptyTrackingState());
1515
- fireTrackingPixels2(slot.ad.trackingUrls.impression);
1516
- trackingFired.impression = true;
1517
- contentVolume = contentVideo.volume;
1518
- originalVolume = Math.max(0, Math.min(1, contentVolume || originalVolume));
1519
1637
  if (!continueLiveStreamDuringAds) {
1520
1638
  contentVideo.pause();
1521
1639
  }
@@ -1530,17 +1648,10 @@ function createVastAdLayer(contentVideo, options) {
1530
1648
  container.style.display = "flex";
1531
1649
  container.style.pointerEvents = "auto";
1532
1650
  emit("content_pause");
1533
- if (slot.hlsInstance) {
1534
- adVideoElement.play().catch(function(error) {
1535
- console.error("".concat(LOG, " [preload] Error playing preloaded HLS ad:"), error);
1536
- handleAdError();
1537
- });
1538
- } else {
1539
- adVideoElement.play().catch(function(error) {
1540
- console.error("".concat(LOG, " [preload] Error playing preloaded ad:"), error);
1541
- handleAdError();
1542
- });
1543
- }
1651
+ adVideoElement.play().catch(function(error) {
1652
+ console.error("".concat(LOG, " [preload] Error playing preloaded ad:"), error);
1653
+ handleAdError();
1654
+ });
1544
1655
  return [
1545
1656
  2
1546
1657
  ];
@@ -1554,10 +1665,12 @@ function createVastAdLayer(contentVideo, options) {
1554
1665
  if (slot.hlsInstance) {
1555
1666
  slot.hlsInstance.destroy();
1556
1667
  }
1557
- slot.videoEl.pause();
1558
- slot.videoEl.removeAttribute("src");
1559
- slot.videoEl.load();
1560
- slot.videoEl.remove();
1668
+ if (slot.videoEl) {
1669
+ slot.videoEl.pause();
1670
+ slot.videoEl.removeAttribute("src");
1671
+ slot.videoEl.load();
1672
+ slot.videoEl.remove();
1673
+ }
1561
1674
  if (debug) console.log("".concat(LOG, " [preload] Cancelled and cleaned up token=").concat(token));
1562
1675
  }
1563
1676
  return {
@@ -1605,20 +1718,27 @@ function createVastAdLayer(contentVideo, options) {
1605
1718
  setAdPlayingFlag(false);
1606
1719
  contentVideo.muted = originalMutedState;
1607
1720
  contentVideo.volume = originalMutedState ? 0 : originalVolume;
1608
- if (adContainerEl) {
1609
- adContainerEl.style.display = "none";
1610
- adContainerEl.style.pointerEvents = "none";
1611
- }
1612
1721
  contentVideo.style.visibility = "visible";
1613
1722
  contentVideo.style.opacity = "1";
1614
- if (continueLiveStreamDuringAds) {
1615
- contentVideo.play().catch(function() {});
1616
- }
1617
- teardownCurrentPlayback();
1618
- if (adVideoElement) {
1619
- adVideoElement.pause();
1620
- adVideoElement.removeAttribute("src");
1621
- adVideoElement.load();
1723
+ if (singleElementMode) {
1724
+ teardownCurrentPlayback();
1725
+ contentVideo.removeAttribute("src");
1726
+ contentVideo.load();
1727
+ adVideoElement = void 0;
1728
+ } else {
1729
+ if (adContainerEl) {
1730
+ adContainerEl.style.display = "none";
1731
+ adContainerEl.style.pointerEvents = "none";
1732
+ }
1733
+ if (continueLiveStreamDuringAds) {
1734
+ contentVideo.play().catch(function() {});
1735
+ }
1736
+ teardownCurrentPlayback();
1737
+ if (adVideoElement) {
1738
+ adVideoElement.pause();
1739
+ adVideoElement.removeAttribute("src");
1740
+ adVideoElement.load();
1741
+ }
1622
1742
  }
1623
1743
  currentAd = void 0;
1624
1744
  tornDown = false;
@@ -1658,9 +1778,14 @@ function createVastAdLayer(contentVideo, options) {
1658
1778
  }
1659
1779
  teardownCurrentPlayback();
1660
1780
  if (adVideoElement) {
1661
- adVideoElement.pause();
1662
- adVideoElement.removeAttribute("src");
1663
- adVideoElement.remove();
1781
+ if (singleElementMode && adVideoElement === contentVideo) {
1782
+ contentVideo.removeAttribute("src");
1783
+ contentVideo.load();
1784
+ } else {
1785
+ adVideoElement.pause();
1786
+ adVideoElement.removeAttribute("src");
1787
+ adVideoElement.remove();
1788
+ }
1664
1789
  adVideoElement = void 0;
1665
1790
  }
1666
1791
  if (adContainerEl === null || adContainerEl === void 0 ? void 0 : adContainerEl.parentElement) {
@@ -2858,8 +2983,11 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
2858
2983
  this.vastManager = createVastManager(config.debugAdTiming !== void 0 ? {
2859
2984
  debug: !!config.debugAdTiming
2860
2985
  } : {});
2986
+ var browserForAdLayer = detectBrowser();
2861
2987
  this.adLayer = createVastAdLayer(this.video, {
2862
2988
  continueLiveStreamDuringAds: false,
2989
+ smartTVMode: browserForAdLayer.isSmartTV,
2990
+ singleElementMode: browserForAdLayer.isSmartTV,
2863
2991
  debug: !!config.debugAdTiming
2864
2992
  });
2865
2993
  }
@@ -4221,6 +4349,10 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4221
4349
  if (!this.isLiveStream) {
4222
4350
  return false;
4223
4351
  }
4352
+ var browser = detectBrowser();
4353
+ if (browser.isSmartTV) {
4354
+ return false;
4355
+ }
4224
4356
  return true;
4225
4357
  }
4226
4358
  },
@@ -4428,7 +4560,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4428
4560
  switch(_state.label){
4429
4561
  case 0:
4430
4562
  _loop = function() {
4431
- var remaining, prefetchContext, bids, err, bids1, remainingNow, delay, elapsed, remaining1, context, bids2, remainingNow1, err1;
4563
+ var remaining, prefetchContext, bids, err, bids1, remainingNow, urgentNeedAd, delay, elapsed, remaining1, context, bids2, remainingNow1, err1, sleepMs;
4432
4564
  return _ts_generator(this, function(_state) {
4433
4565
  switch(_state.label){
4434
4566
  case 0:
@@ -4564,7 +4696,8 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4564
4696
  "continue"
4565
4697
  ];
4566
4698
  case 12:
4567
- delay = _this.lastAdRequestTime ? _this.minAdRequestIntervalMs + (_this.consecutiveFailures > 0 ? backoffMs() : 0) : 0;
4699
+ urgentNeedAd = _this.inAdBreak && !_this.adLayer.isAdPlaying();
4700
+ delay = _this.lastAdRequestTime ? _this.minAdRequestIntervalMs + (!urgentNeedAd && _this.consecutiveFailures > 0 ? backoffMs() : 0) : 0;
4568
4701
  elapsed = Date.now() - _this.lastAdRequestTime;
4569
4702
  if (!(elapsed < delay && _this.lastAdRequestTime > 0)) return [
4570
4703
  3,
@@ -4683,10 +4816,11 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4683
4816
  24
4684
4817
  ];
4685
4818
  case 24:
4819
+ sleepMs = _this.inAdBreak && !_this.adLayer.isAdPlaying() ? 0 : backoffMs();
4686
4820
  return [
4687
4821
  4,
4688
4822
  new Promise(function(r) {
4689
- return setTimeout(r, backoffMs());
4823
+ return setTimeout(r, sleepMs);
4690
4824
  })
4691
4825
  ];
4692
4826
  case 25:
@@ -5367,40 +5501,45 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5367
5501
  var browser = detectBrowser();
5368
5502
  var isSmartTV = browser.tizenVersion !== void 0 || browser.webOSVersion !== void 0;
5369
5503
  if (isSmartTV && this.hls) {
5370
- if (!restoredMuted) {
5371
- var hlsRef = this.hls;
5372
- var savedMuted = restoredMuted;
5373
- var savedVolume = restoredVolume;
5374
- var onManifestParsedRestore = function onManifestParsedRestore1() {
5375
- hlsRef.off(import_hls2.default.Events.MANIFEST_PARSED, onManifestParsedRestore);
5376
- if (!_this.inAdBreak && !_this.adLayer.isAdPlaying()) {
5377
- if (_this.video.muted !== savedMuted) _this.video.muted = savedMuted;
5378
- if (Math.abs(_this.video.volume - savedVolume) > 0.01) _this.video.volume = savedVolume;
5379
- if (_this.config.debugAdTiming) {
5380
- console.log("[StormcloudVideoPlayer] Smart TV: audio state restored on MANIFEST_PARSED after re-attach");
5381
- }
5504
+ var hlsRef = this.hls;
5505
+ var savedMuted = restoredMuted;
5506
+ var savedVolume = restoredVolume;
5507
+ var onManifestParsedRestore = function onManifestParsedRestore1() {
5508
+ hlsRef.off(import_hls2.default.Events.MANIFEST_PARSED, onManifestParsedRestore);
5509
+ if (!_this.inAdBreak && !_this.adLayer.isAdPlaying()) {
5510
+ var _this_video_play;
5511
+ if (_this.video.muted !== savedMuted) _this.video.muted = savedMuted;
5512
+ if (Math.abs(_this.video.volume - savedVolume) > 0.01) _this.video.volume = savedVolume;
5513
+ if (_this.config.debugAdTiming) {
5514
+ console.log("[StormcloudVideoPlayer] Smart TV: audio state restored on MANIFEST_PARSED after re-attach");
5382
5515
  }
5383
- };
5384
- hlsRef.on(import_hls2.default.Events.MANIFEST_PARSED, onManifestParsedRestore);
5385
- }
5516
+ hlsRef.startLoad(-1);
5517
+ (_this_video_play = _this.video.play()) === null || _this_video_play === void 0 ? void 0 : _this_video_play.catch(function() {});
5518
+ if (_this.config.debugAdTiming) {
5519
+ console.log("[StormcloudVideoPlayer] Smart TV: seeking to live edge and resuming playback after re-attach");
5520
+ }
5521
+ }
5522
+ };
5523
+ hlsRef.on(import_hls2.default.Events.MANIFEST_PARSED, onManifestParsedRestore);
5386
5524
  this.hls.attachMedia(this.video);
5387
5525
  if (this.config.debugAdTiming) {
5388
5526
  console.log("[StormcloudVideoPlayer] Smart TV: re-attached HLS to video element after ad break to restore media pipeline");
5389
5527
  }
5390
- }
5391
- if (this.shouldContinueLiveStreamDuringAds()) {
5392
- var _this_video_play;
5393
- if (this.config.debugAdTiming) {
5394
- if (this.video.paused) {
5395
- console.log("[StormcloudVideoPlayer] Content video paused in live mode after ads, resuming playback");
5396
- } else {
5397
- console.log("[StormcloudVideoPlayer] Content video already playing in live mode after ads");
5528
+ } else {
5529
+ if (this.shouldContinueLiveStreamDuringAds()) {
5530
+ var _this_video_play;
5531
+ if (this.config.debugAdTiming) {
5532
+ if (this.video.paused) {
5533
+ console.log("[StormcloudVideoPlayer] Content video paused in live mode after ads, resuming playback");
5534
+ } else {
5535
+ console.log("[StormcloudVideoPlayer] Content video already playing in live mode after ads");
5536
+ }
5398
5537
  }
5538
+ (_this_video_play = this.video.play()) === null || _this_video_play === void 0 ? void 0 : _this_video_play.catch(function() {});
5539
+ } else if (this.video.paused) {
5540
+ var _this_video_play1;
5541
+ (_this_video_play1 = this.video.play()) === null || _this_video_play1 === void 0 ? void 0 : _this_video_play1.catch(function() {});
5399
5542
  }
5400
- (_this_video_play = this.video.play()) === null || _this_video_play === void 0 ? void 0 : _this_video_play.catch(function() {});
5401
- } else if (this.video.paused) {
5402
- var _this_video_play1;
5403
- (_this_video_play1 = this.video.play()) === null || _this_video_play1 === void 0 ? void 0 : _this_video_play1.catch(function() {});
5404
5543
  }
5405
5544
  this.syncMainContentAudioWhenVisible();
5406
5545
  if (!restoredMuted) {
@@ -5451,6 +5590,14 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5451
5590
  console.log("[CONTINUOUS-FETCH] \uD83D\uDED1 Max consecutive failures reached (".concat(this.consecutiveFailures, "), ending ad break gracefully"));
5452
5591
  }
5453
5592
  this.handleAdPodComplete();
5593
+ return;
5594
+ }
5595
+ if (this.inAdBreak && !this.config.disableFiller) {
5596
+ if (this.config.debugAdTiming) {
5597
+ console.log("[CONTINUOUS-FETCH] Ad failure in active break \u2014 showing filler while awaiting next ad");
5598
+ }
5599
+ this.showPlaceholderLayer();
5600
+ this.adLayer.showPlaceholder();
5454
5601
  }
5455
5602
  }
5456
5603
  },