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.cjs CHANGED
@@ -1104,14 +1104,16 @@ function resolveBidToVastAd(winner, logPrefix) {
1104
1104
  return Promise.resolve(null);
1105
1105
  }
1106
1106
  function createVastAdLayer(contentVideo, options) {
1107
- var _ref, _ref1;
1107
+ var _ref, _ref1, _ref2, _ref3;
1108
1108
  var adPlaying = false;
1109
1109
  var originalMutedState = false;
1110
1110
  var originalVolume = Math.max(0, Math.min(1, contentVideo.volume || 1));
1111
1111
  var listeners = /* @__PURE__ */ new Map();
1112
1112
  var mainHlsInstance = options === null || options === void 0 ? void 0 : options.mainHlsInstance;
1113
1113
  var continueLiveStreamDuringAds = (_ref = options === null || options === void 0 ? void 0 : options.continueLiveStreamDuringAds) !== null && _ref !== void 0 ? _ref : false;
1114
- var debug = (_ref1 = options === null || options === void 0 ? void 0 : options.debug) !== null && _ref1 !== void 0 ? _ref1 : false;
1114
+ var smartTVMode = (_ref1 = options === null || options === void 0 ? void 0 : options.smartTVMode) !== null && _ref1 !== void 0 ? _ref1 : false;
1115
+ var singleElementMode = (_ref2 = options === null || options === void 0 ? void 0 : options.singleElementMode) !== null && _ref2 !== void 0 ? _ref2 : false;
1116
+ var debug = (_ref3 = options === null || options === void 0 ? void 0 : options.debug) !== null && _ref3 !== void 0 ? _ref3 : false;
1115
1117
  var adVideoElement;
1116
1118
  var adHls;
1117
1119
  var adContainerEl;
@@ -1120,6 +1122,7 @@ function createVastAdLayer(contentVideo, options) {
1120
1122
  var destroyed = false;
1121
1123
  var tornDown = false;
1122
1124
  var trackingFired = createEmptyTrackingState();
1125
+ var currentAdEventHandlers;
1123
1126
  var preloadSlots = /* @__PURE__ */ new Map();
1124
1127
  function emit(event, payload) {
1125
1128
  var set = listeners.get(event);
@@ -1222,63 +1225,86 @@ function createVastAdLayer(contentVideo, options) {
1222
1225
  video.volume = 1;
1223
1226
  return video;
1224
1227
  }
1228
+ function removeAdEventListeners() {
1229
+ if (!currentAdEventHandlers || !adVideoElement) return;
1230
+ var el = adVideoElement;
1231
+ el.removeEventListener("timeupdate", currentAdEventHandlers.timeupdate);
1232
+ el.removeEventListener("playing", currentAdEventHandlers.playing);
1233
+ el.removeEventListener("ended", currentAdEventHandlers.ended);
1234
+ el.removeEventListener("error", currentAdEventHandlers.error);
1235
+ el.removeEventListener("volumechange", currentAdEventHandlers.volumechange);
1236
+ el.removeEventListener("pause", currentAdEventHandlers.pause);
1237
+ el.removeEventListener("play", currentAdEventHandlers.play);
1238
+ currentAdEventHandlers = void 0;
1239
+ }
1225
1240
  function setupAdEventListeners() {
1226
1241
  if (!adVideoElement) return;
1227
- adVideoElement.addEventListener("timeupdate", function() {
1228
- var ad = currentAd;
1229
- if (!ad || !adVideoElement) return;
1230
- var progress = adVideoElement.currentTime / ad.duration;
1231
- if (progress >= 0.25 && !trackingFired.firstQuartile) {
1232
- trackingFired.firstQuartile = true;
1233
- fireTrackingPixels2(ad.trackingUrls.firstQuartile);
1234
- }
1235
- if (progress >= 0.5 && !trackingFired.midpoint) {
1236
- trackingFired.midpoint = true;
1237
- fireTrackingPixels2(ad.trackingUrls.midpoint);
1238
- }
1239
- if (progress >= 0.75 && !trackingFired.thirdQuartile) {
1240
- trackingFired.thirdQuartile = true;
1241
- fireTrackingPixels2(ad.trackingUrls.thirdQuartile);
1242
- }
1243
- });
1244
- adVideoElement.addEventListener("playing", function() {
1245
- var ad = currentAd;
1246
- if (!ad || trackingFired.start) return;
1247
- trackingFired.start = true;
1248
- fireTrackingPixels2(ad.trackingUrls.start);
1249
- if (debug) console.log("".concat(LOG, " Ad started playing"));
1250
- });
1251
- adVideoElement.addEventListener("ended", function() {
1252
- if (tornDown || !currentAd || trackingFired.complete) return;
1253
- trackingFired.complete = true;
1254
- fireTrackingPixels2(currentAd.trackingUrls.complete);
1255
- if (debug) console.log("".concat(LOG, " Ad completed"));
1256
- handleAdComplete();
1257
- });
1258
- adVideoElement.addEventListener("error", function(e) {
1259
- if (tornDown) return;
1260
- console.error("".concat(LOG, " Ad video error:"), e);
1261
- if (currentAd) fireTrackingPixels2(currentAd.trackingUrls.error);
1262
- handleAdError();
1263
- });
1264
- adVideoElement.addEventListener("volumechange", function() {
1265
- if (!currentAd || !adVideoElement) return;
1266
- if (adVideoElement.muted) {
1267
- fireTrackingPixels2(currentAd.trackingUrls.mute);
1268
- } else {
1269
- fireTrackingPixels2(currentAd.trackingUrls.unmute);
1270
- }
1271
- });
1272
- adVideoElement.addEventListener("pause", function() {
1273
- if (currentAd && adVideoElement && !adVideoElement.ended) {
1274
- fireTrackingPixels2(currentAd.trackingUrls.pause);
1275
- }
1276
- });
1277
- adVideoElement.addEventListener("play", function() {
1278
- if (currentAd && adVideoElement && adVideoElement.currentTime > 0) {
1279
- fireTrackingPixels2(currentAd.trackingUrls.resume);
1242
+ removeAdEventListeners();
1243
+ var handlers = {
1244
+ timeupdate: function timeupdate() {
1245
+ var ad = currentAd;
1246
+ if (!ad || !adVideoElement) return;
1247
+ var progress = adVideoElement.currentTime / ad.duration;
1248
+ if (progress >= 0.25 && !trackingFired.firstQuartile) {
1249
+ trackingFired.firstQuartile = true;
1250
+ fireTrackingPixels2(ad.trackingUrls.firstQuartile);
1251
+ }
1252
+ if (progress >= 0.5 && !trackingFired.midpoint) {
1253
+ trackingFired.midpoint = true;
1254
+ fireTrackingPixels2(ad.trackingUrls.midpoint);
1255
+ }
1256
+ if (progress >= 0.75 && !trackingFired.thirdQuartile) {
1257
+ trackingFired.thirdQuartile = true;
1258
+ fireTrackingPixels2(ad.trackingUrls.thirdQuartile);
1259
+ }
1260
+ },
1261
+ playing: function playing() {
1262
+ var ad = currentAd;
1263
+ if (!ad || trackingFired.start) return;
1264
+ trackingFired.start = true;
1265
+ fireTrackingPixels2(ad.trackingUrls.start);
1266
+ if (debug) console.log("".concat(LOG, " Ad started playing"));
1267
+ },
1268
+ ended: function ended() {
1269
+ if (tornDown || !currentAd || trackingFired.complete) return;
1270
+ trackingFired.complete = true;
1271
+ fireTrackingPixels2(currentAd.trackingUrls.complete);
1272
+ if (debug) console.log("".concat(LOG, " Ad completed"));
1273
+ handleAdComplete();
1274
+ },
1275
+ error: function error(e) {
1276
+ if (tornDown) return;
1277
+ console.error("".concat(LOG, " Ad video error:"), e);
1278
+ if (currentAd) fireTrackingPixels2(currentAd.trackingUrls.error);
1279
+ handleAdError();
1280
+ },
1281
+ volumechange: function volumechange() {
1282
+ if (!currentAd || !adVideoElement) return;
1283
+ if (adVideoElement.muted) {
1284
+ fireTrackingPixels2(currentAd.trackingUrls.mute);
1285
+ } else {
1286
+ fireTrackingPixels2(currentAd.trackingUrls.unmute);
1287
+ }
1288
+ },
1289
+ pause: function pause() {
1290
+ if (currentAd && adVideoElement && !adVideoElement.ended) {
1291
+ fireTrackingPixels2(currentAd.trackingUrls.pause);
1292
+ }
1293
+ },
1294
+ play: function play() {
1295
+ if (currentAd && adVideoElement && adVideoElement.currentTime > 0) {
1296
+ fireTrackingPixels2(currentAd.trackingUrls.resume);
1297
+ }
1280
1298
  }
1281
- });
1299
+ };
1300
+ adVideoElement.addEventListener("timeupdate", handlers.timeupdate);
1301
+ adVideoElement.addEventListener("playing", handlers.playing);
1302
+ adVideoElement.addEventListener("ended", handlers.ended);
1303
+ adVideoElement.addEventListener("error", handlers.error);
1304
+ adVideoElement.addEventListener("volumechange", handlers.volumechange);
1305
+ adVideoElement.addEventListener("pause", handlers.pause);
1306
+ adVideoElement.addEventListener("play", handlers.play);
1307
+ currentAdEventHandlers = handlers;
1282
1308
  }
1283
1309
  function setAdPlayingFlag(isPlaying) {
1284
1310
  if (isPlaying) {
@@ -1301,6 +1327,7 @@ function createVastAdLayer(contentVideo, options) {
1301
1327
  }
1302
1328
  function handleAdError() {
1303
1329
  if (tornDown) return;
1330
+ if (!adPlaying) return;
1304
1331
  if (debug) console.log("".concat(LOG, " Handling ad error"));
1305
1332
  adPlaying = false;
1306
1333
  setAdPlayingFlag(false);
@@ -1311,14 +1338,19 @@ function createVastAdLayer(contentVideo, options) {
1311
1338
  emit("ad_error");
1312
1339
  }
1313
1340
  function teardownCurrentPlayback() {
1341
+ removeAdEventListeners();
1314
1342
  if (adHls) {
1315
1343
  adHls.destroy();
1316
1344
  adHls = void 0;
1317
1345
  }
1318
1346
  if (adVideoElement) {
1319
- adVideoElement.pause();
1320
- adVideoElement.removeAttribute("src");
1321
- adVideoElement.load();
1347
+ if (singleElementMode && adVideoElement === contentVideo) {
1348
+ contentVideo.pause();
1349
+ } else {
1350
+ adVideoElement.pause();
1351
+ adVideoElement.removeAttribute("src");
1352
+ adVideoElement.load();
1353
+ }
1322
1354
  }
1323
1355
  }
1324
1356
  function startNativePlayback(mediaFile) {
@@ -1351,8 +1383,17 @@ function createVastAdLayer(contentVideo, options) {
1351
1383
  handleAdError();
1352
1384
  });
1353
1385
  });
1386
+ var nonFatalNetworkErrors = 0;
1354
1387
  adHls.on(import_hls.default.Events.ERROR, function(_event, data) {
1355
- if (data.fatal) handleAdError();
1388
+ if (data.fatal) {
1389
+ handleAdError();
1390
+ } else if (data.type === import_hls.default.ErrorTypes.NETWORK_ERROR) {
1391
+ nonFatalNetworkErrors++;
1392
+ if (nonFatalNetworkErrors >= 3) {
1393
+ if (debug) console.warn("".concat(LOG, " Too many non-fatal HLS network errors (").concat(nonFatalNetworkErrors, "), treating as fatal"));
1394
+ handleAdError();
1395
+ }
1396
+ }
1356
1397
  });
1357
1398
  } else if (adVideoElement.canPlayType("application/vnd.apple.mpegurl")) {
1358
1399
  adVideoElement.src = mediaFile.url;
@@ -1375,7 +1416,7 @@ function createVastAdLayer(contentVideo, options) {
1375
1416
  }
1376
1417
  function playAd(bids) {
1377
1418
  return _async_to_generator(function() {
1378
- var winner, ad, _contentVideo_parentElement, container, contentVolume, adVolume, mediaFile;
1419
+ var winner, ad, contentVolume, _contentVideo_parentElement, container, adVolume, mediaFile;
1379
1420
  return _ts_generator(this, function(_state) {
1380
1421
  switch(_state.label){
1381
1422
  case 0:
@@ -1417,32 +1458,40 @@ function createVastAdLayer(contentVideo, options) {
1417
1458
  trackingFired = _object_spread({}, createEmptyTrackingState());
1418
1459
  fireTrackingPixels2(ad.trackingUrls.impression);
1419
1460
  trackingFired.impression = true;
1420
- if (!adContainerEl) {
1421
- ;
1422
- container = document.createElement("div");
1423
- container.style.position = "absolute";
1424
- container.style.left = "0";
1425
- container.style.top = "0";
1426
- container.style.right = "0";
1427
- container.style.bottom = "0";
1428
- container.style.display = "none";
1429
- container.style.alignItems = "center";
1430
- container.style.justifyContent = "center";
1431
- container.style.pointerEvents = "none";
1432
- container.style.zIndex = "10";
1433
- container.style.backgroundColor = "#000";
1434
- (_contentVideo_parentElement = contentVideo.parentElement) === null || _contentVideo_parentElement === void 0 ? void 0 : _contentVideo_parentElement.appendChild(container);
1435
- adContainerEl = container;
1436
- }
1437
- if (!adVideoElement) {
1438
- adVideoElement = createAdVideoElement();
1439
- adContainerEl.appendChild(adVideoElement);
1461
+ contentVolume = contentVideo.volume;
1462
+ originalVolume = Math.max(0, Math.min(1, contentVolume || originalVolume));
1463
+ if (singleElementMode) {
1464
+ mainHlsInstance === null || mainHlsInstance === void 0 ? void 0 : mainHlsInstance.detachMedia();
1465
+ teardownCurrentPlayback();
1466
+ adVideoElement = contentVideo;
1467
+ adHls = void 0;
1440
1468
  setupAdEventListeners();
1441
1469
  } else {
1442
- teardownCurrentPlayback();
1470
+ if (!adContainerEl) {
1471
+ ;
1472
+ container = document.createElement("div");
1473
+ container.style.position = "absolute";
1474
+ container.style.left = "0";
1475
+ container.style.top = "0";
1476
+ container.style.right = "0";
1477
+ container.style.bottom = "0";
1478
+ container.style.display = "none";
1479
+ container.style.alignItems = "center";
1480
+ container.style.justifyContent = "center";
1481
+ container.style.pointerEvents = "none";
1482
+ container.style.zIndex = "10";
1483
+ container.style.backgroundColor = "#000";
1484
+ (_contentVideo_parentElement = contentVideo.parentElement) === null || _contentVideo_parentElement === void 0 ? void 0 : _contentVideo_parentElement.appendChild(container);
1485
+ adContainerEl = container;
1486
+ }
1487
+ if (!adVideoElement) {
1488
+ adVideoElement = createAdVideoElement();
1489
+ adContainerEl.appendChild(adVideoElement);
1490
+ setupAdEventListeners();
1491
+ } else {
1492
+ teardownCurrentPlayback();
1493
+ }
1443
1494
  }
1444
- contentVolume = contentVideo.volume;
1445
- originalVolume = Math.max(0, Math.min(1, contentVolume || originalVolume));
1446
1495
  if (!continueLiveStreamDuringAds) {
1447
1496
  contentVideo.pause();
1448
1497
  }
@@ -1453,7 +1502,7 @@ function createVastAdLayer(contentVideo, options) {
1453
1502
  adVolume = originalMutedState ? 1 : originalVolume;
1454
1503
  adVideoElement.volume = Math.max(0, Math.min(1, adVolume));
1455
1504
  adVideoElement.muted = false;
1456
- if (adContainerEl) {
1505
+ if (!singleElementMode && adContainerEl) {
1457
1506
  adContainerEl.style.display = "flex";
1458
1507
  adContainerEl.style.pointerEvents = "auto";
1459
1508
  }
@@ -1490,7 +1539,7 @@ function createVastAdLayer(contentVideo, options) {
1490
1539
  }
1491
1540
  function preloadAd(bids, token) {
1492
1541
  return _async_to_generator(function() {
1493
- var winner, ad, mediaFile, videoEl, container, hls, slot, slot1;
1542
+ var winner, ad, mediaFile, slot, videoEl, container, hls, slot1, slot2;
1494
1543
  return _ts_generator(this, function(_state) {
1495
1544
  switch(_state.label){
1496
1545
  case 0:
@@ -1515,6 +1564,20 @@ function createVastAdLayer(contentVideo, options) {
1515
1564
  if (!mediaFile) return [
1516
1565
  2
1517
1566
  ];
1567
+ if (smartTVMode || singleElementMode) {
1568
+ slot = {
1569
+ bids: bids,
1570
+ ad: ad,
1571
+ mediaFile: mediaFile,
1572
+ videoEl: null,
1573
+ ready: true
1574
+ };
1575
+ preloadSlots.set(token, slot);
1576
+ if (debug) console.log("".concat(LOG, " [preload] Metadata-only preload (smartTV/singleElement), token=").concat(token, ", url=").concat(mediaFile.url));
1577
+ return [
1578
+ 2
1579
+ ];
1580
+ }
1518
1581
  videoEl = createAdVideoElement();
1519
1582
  videoEl.style.visibility = "hidden";
1520
1583
  videoEl.style.pointerEvents = "none";
@@ -1528,7 +1591,7 @@ function createVastAdLayer(contentVideo, options) {
1528
1591
  });
1529
1592
  hls.loadSource(mediaFile.url);
1530
1593
  hls.attachMedia(videoEl);
1531
- slot = {
1594
+ slot1 = {
1532
1595
  bids: bids,
1533
1596
  ad: ad,
1534
1597
  mediaFile: mediaFile,
@@ -1536,7 +1599,7 @@ function createVastAdLayer(contentVideo, options) {
1536
1599
  hlsInstance: hls,
1537
1600
  ready: false
1538
1601
  };
1539
- preloadSlots.set(token, slot);
1602
+ preloadSlots.set(token, slot1);
1540
1603
  hls.on(import_hls.default.Events.MANIFEST_PARSED, function() {
1541
1604
  var s = preloadSlots.get(token);
1542
1605
  if (s) s.ready = true;
@@ -1553,14 +1616,14 @@ function createVastAdLayer(contentVideo, options) {
1553
1616
  } else {
1554
1617
  videoEl.src = mediaFile.url;
1555
1618
  videoEl.load();
1556
- slot1 = {
1619
+ slot2 = {
1557
1620
  bids: bids,
1558
1621
  ad: ad,
1559
1622
  mediaFile: mediaFile,
1560
1623
  videoEl: videoEl,
1561
1624
  ready: false
1562
1625
  };
1563
- preloadSlots.set(token, slot1);
1626
+ preloadSlots.set(token, slot2);
1564
1627
  videoEl.addEventListener("canplay", function() {
1565
1628
  var s = preloadSlots.get(token);
1566
1629
  if (s) s.ready = true;
@@ -1579,7 +1642,7 @@ function createVastAdLayer(contentVideo, options) {
1579
1642
  }
1580
1643
  function playPreloaded(token) {
1581
1644
  return _async_to_generator(function() {
1582
- var slot, contentVolume, adVolume, container;
1645
+ var slot, contentVolume, adVolume2, videoEl, container2, adVolume21, adVolume, container;
1583
1646
  return _ts_generator(this, function(_state) {
1584
1647
  if (destroyed) return [
1585
1648
  2,
@@ -1594,6 +1657,68 @@ function createVastAdLayer(contentVideo, options) {
1594
1657
  }
1595
1658
  preloadSlots.delete(token);
1596
1659
  if (debug) console.log("".concat(LOG, " [preload] Playing preloaded ad, token=").concat(token, ", ready=").concat(slot.ready));
1660
+ contentVolume = contentVideo.volume;
1661
+ originalVolume = Math.max(0, Math.min(1, contentVolume || originalVolume));
1662
+ sessionId = generateSessionId();
1663
+ currentAd = slot.ad;
1664
+ trackingFired = _object_spread({}, createEmptyTrackingState());
1665
+ fireTrackingPixels2(slot.ad.trackingUrls.impression);
1666
+ trackingFired.impression = true;
1667
+ if (singleElementMode) {
1668
+ mainHlsInstance === null || mainHlsInstance === void 0 ? void 0 : mainHlsInstance.detachMedia();
1669
+ teardownCurrentPlayback();
1670
+ adVideoElement = contentVideo;
1671
+ adHls = void 0;
1672
+ setupAdEventListeners();
1673
+ if (!continueLiveStreamDuringAds) {
1674
+ contentVideo.pause();
1675
+ }
1676
+ contentVideo.muted = true;
1677
+ contentVideo.volume = 0;
1678
+ adPlaying = true;
1679
+ setAdPlayingFlag(true);
1680
+ adVolume2 = originalMutedState ? 1 : originalVolume;
1681
+ contentVideo.volume = Math.max(0, Math.min(1, adVolume2));
1682
+ contentVideo.muted = false;
1683
+ emit("content_pause");
1684
+ if (debug) console.log("".concat(LOG, " [preload] singleElementMode: attaching ad to contentVideo, url=").concat(slot.mediaFile.url));
1685
+ startPlayback(slot.mediaFile);
1686
+ return [
1687
+ 2
1688
+ ];
1689
+ }
1690
+ if (smartTVMode && !slot.videoEl) {
1691
+ teardownCurrentPlayback();
1692
+ if (adVideoElement) {
1693
+ adVideoElement.remove();
1694
+ adVideoElement = void 0;
1695
+ }
1696
+ videoEl = createAdVideoElement();
1697
+ videoEl.style.visibility = "visible";
1698
+ videoEl.style.pointerEvents = "none";
1699
+ container2 = ensureAdContainer();
1700
+ container2.appendChild(videoEl);
1701
+ adVideoElement = videoEl;
1702
+ setupAdEventListeners();
1703
+ if (!continueLiveStreamDuringAds) {
1704
+ contentVideo.pause();
1705
+ }
1706
+ contentVideo.muted = true;
1707
+ contentVideo.volume = 0;
1708
+ adPlaying = true;
1709
+ setAdPlayingFlag(true);
1710
+ adVolume21 = originalMutedState ? 1 : originalVolume;
1711
+ adVideoElement.volume = Math.max(0, Math.min(1, adVolume21));
1712
+ adVideoElement.muted = false;
1713
+ container2.style.display = "flex";
1714
+ container2.style.pointerEvents = "auto";
1715
+ emit("content_pause");
1716
+ if (debug) console.log("".concat(LOG, " [preload] smartTVMode deferred: creating video element and loading, url=").concat(slot.mediaFile.url));
1717
+ startPlayback(slot.mediaFile);
1718
+ return [
1719
+ 2
1720
+ ];
1721
+ }
1597
1722
  teardownCurrentPlayback();
1598
1723
  if (adVideoElement && adVideoElement !== slot.videoEl) {
1599
1724
  adVideoElement.remove();
@@ -1603,13 +1728,6 @@ function createVastAdLayer(contentVideo, options) {
1603
1728
  adVideoElement = slot.videoEl;
1604
1729
  adHls = slot.hlsInstance;
1605
1730
  setupAdEventListeners();
1606
- sessionId = generateSessionId();
1607
- currentAd = slot.ad;
1608
- trackingFired = _object_spread({}, createEmptyTrackingState());
1609
- fireTrackingPixels2(slot.ad.trackingUrls.impression);
1610
- trackingFired.impression = true;
1611
- contentVolume = contentVideo.volume;
1612
- originalVolume = Math.max(0, Math.min(1, contentVolume || originalVolume));
1613
1731
  if (!continueLiveStreamDuringAds) {
1614
1732
  contentVideo.pause();
1615
1733
  }
@@ -1624,17 +1742,10 @@ function createVastAdLayer(contentVideo, options) {
1624
1742
  container.style.display = "flex";
1625
1743
  container.style.pointerEvents = "auto";
1626
1744
  emit("content_pause");
1627
- if (slot.hlsInstance) {
1628
- adVideoElement.play().catch(function(error) {
1629
- console.error("".concat(LOG, " [preload] Error playing preloaded HLS ad:"), error);
1630
- handleAdError();
1631
- });
1632
- } else {
1633
- adVideoElement.play().catch(function(error) {
1634
- console.error("".concat(LOG, " [preload] Error playing preloaded ad:"), error);
1635
- handleAdError();
1636
- });
1637
- }
1745
+ adVideoElement.play().catch(function(error) {
1746
+ console.error("".concat(LOG, " [preload] Error playing preloaded ad:"), error);
1747
+ handleAdError();
1748
+ });
1638
1749
  return [
1639
1750
  2
1640
1751
  ];
@@ -1648,10 +1759,12 @@ function createVastAdLayer(contentVideo, options) {
1648
1759
  if (slot.hlsInstance) {
1649
1760
  slot.hlsInstance.destroy();
1650
1761
  }
1651
- slot.videoEl.pause();
1652
- slot.videoEl.removeAttribute("src");
1653
- slot.videoEl.load();
1654
- slot.videoEl.remove();
1762
+ if (slot.videoEl) {
1763
+ slot.videoEl.pause();
1764
+ slot.videoEl.removeAttribute("src");
1765
+ slot.videoEl.load();
1766
+ slot.videoEl.remove();
1767
+ }
1655
1768
  if (debug) console.log("".concat(LOG, " [preload] Cancelled and cleaned up token=").concat(token));
1656
1769
  }
1657
1770
  return {
@@ -1699,20 +1812,27 @@ function createVastAdLayer(contentVideo, options) {
1699
1812
  setAdPlayingFlag(false);
1700
1813
  contentVideo.muted = originalMutedState;
1701
1814
  contentVideo.volume = originalMutedState ? 0 : originalVolume;
1702
- if (adContainerEl) {
1703
- adContainerEl.style.display = "none";
1704
- adContainerEl.style.pointerEvents = "none";
1705
- }
1706
1815
  contentVideo.style.visibility = "visible";
1707
1816
  contentVideo.style.opacity = "1";
1708
- if (continueLiveStreamDuringAds) {
1709
- contentVideo.play().catch(function() {});
1710
- }
1711
- teardownCurrentPlayback();
1712
- if (adVideoElement) {
1713
- adVideoElement.pause();
1714
- adVideoElement.removeAttribute("src");
1715
- adVideoElement.load();
1817
+ if (singleElementMode) {
1818
+ teardownCurrentPlayback();
1819
+ contentVideo.removeAttribute("src");
1820
+ contentVideo.load();
1821
+ adVideoElement = void 0;
1822
+ } else {
1823
+ if (adContainerEl) {
1824
+ adContainerEl.style.display = "none";
1825
+ adContainerEl.style.pointerEvents = "none";
1826
+ }
1827
+ if (continueLiveStreamDuringAds) {
1828
+ contentVideo.play().catch(function() {});
1829
+ }
1830
+ teardownCurrentPlayback();
1831
+ if (adVideoElement) {
1832
+ adVideoElement.pause();
1833
+ adVideoElement.removeAttribute("src");
1834
+ adVideoElement.load();
1835
+ }
1716
1836
  }
1717
1837
  currentAd = void 0;
1718
1838
  tornDown = false;
@@ -1752,9 +1872,14 @@ function createVastAdLayer(contentVideo, options) {
1752
1872
  }
1753
1873
  teardownCurrentPlayback();
1754
1874
  if (adVideoElement) {
1755
- adVideoElement.pause();
1756
- adVideoElement.removeAttribute("src");
1757
- adVideoElement.remove();
1875
+ if (singleElementMode && adVideoElement === contentVideo) {
1876
+ contentVideo.removeAttribute("src");
1877
+ contentVideo.load();
1878
+ } else {
1879
+ adVideoElement.pause();
1880
+ adVideoElement.removeAttribute("src");
1881
+ adVideoElement.remove();
1882
+ }
1758
1883
  adVideoElement = void 0;
1759
1884
  }
1760
1885
  if (adContainerEl === null || adContainerEl === void 0 ? void 0 : adContainerEl.parentElement) {
@@ -2977,8 +3102,11 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
2977
3102
  this.vastManager = createVastManager(config.debugAdTiming !== void 0 ? {
2978
3103
  debug: !!config.debugAdTiming
2979
3104
  } : {});
3105
+ var browserForAdLayer = detectBrowser();
2980
3106
  this.adLayer = createVastAdLayer(this.video, {
2981
3107
  continueLiveStreamDuringAds: false,
3108
+ smartTVMode: browserForAdLayer.isSmartTV,
3109
+ singleElementMode: browserForAdLayer.isSmartTV,
2982
3110
  debug: !!config.debugAdTiming
2983
3111
  });
2984
3112
  }
@@ -4340,6 +4468,10 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4340
4468
  if (!this.isLiveStream) {
4341
4469
  return false;
4342
4470
  }
4471
+ var browser = detectBrowser();
4472
+ if (browser.isSmartTV) {
4473
+ return false;
4474
+ }
4343
4475
  return true;
4344
4476
  }
4345
4477
  },
@@ -4547,7 +4679,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4547
4679
  switch(_state.label){
4548
4680
  case 0:
4549
4681
  _loop = function() {
4550
- var remaining, prefetchContext, bids, err, bids1, remainingNow, delay, elapsed, remaining1, context, bids2, remainingNow1, err1;
4682
+ var remaining, prefetchContext, bids, err, bids1, remainingNow, urgentNeedAd, delay, elapsed, remaining1, context, bids2, remainingNow1, err1, sleepMs;
4551
4683
  return _ts_generator(this, function(_state) {
4552
4684
  switch(_state.label){
4553
4685
  case 0:
@@ -4683,7 +4815,8 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4683
4815
  "continue"
4684
4816
  ];
4685
4817
  case 12:
4686
- delay = _this.lastAdRequestTime ? _this.minAdRequestIntervalMs + (_this.consecutiveFailures > 0 ? backoffMs() : 0) : 0;
4818
+ urgentNeedAd = _this.inAdBreak && !_this.adLayer.isAdPlaying();
4819
+ delay = _this.lastAdRequestTime ? _this.minAdRequestIntervalMs + (!urgentNeedAd && _this.consecutiveFailures > 0 ? backoffMs() : 0) : 0;
4687
4820
  elapsed = Date.now() - _this.lastAdRequestTime;
4688
4821
  if (!(elapsed < delay && _this.lastAdRequestTime > 0)) return [
4689
4822
  3,
@@ -4802,10 +4935,11 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4802
4935
  24
4803
4936
  ];
4804
4937
  case 24:
4938
+ sleepMs = _this.inAdBreak && !_this.adLayer.isAdPlaying() ? 0 : backoffMs();
4805
4939
  return [
4806
4940
  4,
4807
4941
  new Promise(function(r) {
4808
- return setTimeout(r, backoffMs());
4942
+ return setTimeout(r, sleepMs);
4809
4943
  })
4810
4944
  ];
4811
4945
  case 25:
@@ -5486,40 +5620,45 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5486
5620
  var browser = detectBrowser();
5487
5621
  var isSmartTV = browser.tizenVersion !== void 0 || browser.webOSVersion !== void 0;
5488
5622
  if (isSmartTV && this.hls) {
5489
- if (!restoredMuted) {
5490
- var hlsRef = this.hls;
5491
- var savedMuted = restoredMuted;
5492
- var savedVolume = restoredVolume;
5493
- var onManifestParsedRestore = function onManifestParsedRestore1() {
5494
- hlsRef.off(import_hls2.default.Events.MANIFEST_PARSED, onManifestParsedRestore);
5495
- if (!_this.inAdBreak && !_this.adLayer.isAdPlaying()) {
5496
- if (_this.video.muted !== savedMuted) _this.video.muted = savedMuted;
5497
- if (Math.abs(_this.video.volume - savedVolume) > 0.01) _this.video.volume = savedVolume;
5498
- if (_this.config.debugAdTiming) {
5499
- console.log("[StormcloudVideoPlayer] Smart TV: audio state restored on MANIFEST_PARSED after re-attach");
5500
- }
5623
+ var hlsRef = this.hls;
5624
+ var savedMuted = restoredMuted;
5625
+ var savedVolume = restoredVolume;
5626
+ var onManifestParsedRestore = function onManifestParsedRestore1() {
5627
+ hlsRef.off(import_hls2.default.Events.MANIFEST_PARSED, onManifestParsedRestore);
5628
+ if (!_this.inAdBreak && !_this.adLayer.isAdPlaying()) {
5629
+ var _this_video_play;
5630
+ if (_this.video.muted !== savedMuted) _this.video.muted = savedMuted;
5631
+ if (Math.abs(_this.video.volume - savedVolume) > 0.01) _this.video.volume = savedVolume;
5632
+ if (_this.config.debugAdTiming) {
5633
+ console.log("[StormcloudVideoPlayer] Smart TV: audio state restored on MANIFEST_PARSED after re-attach");
5501
5634
  }
5502
- };
5503
- hlsRef.on(import_hls2.default.Events.MANIFEST_PARSED, onManifestParsedRestore);
5504
- }
5635
+ hlsRef.startLoad(-1);
5636
+ (_this_video_play = _this.video.play()) === null || _this_video_play === void 0 ? void 0 : _this_video_play.catch(function() {});
5637
+ if (_this.config.debugAdTiming) {
5638
+ console.log("[StormcloudVideoPlayer] Smart TV: seeking to live edge and resuming playback after re-attach");
5639
+ }
5640
+ }
5641
+ };
5642
+ hlsRef.on(import_hls2.default.Events.MANIFEST_PARSED, onManifestParsedRestore);
5505
5643
  this.hls.attachMedia(this.video);
5506
5644
  if (this.config.debugAdTiming) {
5507
5645
  console.log("[StormcloudVideoPlayer] Smart TV: re-attached HLS to video element after ad break to restore media pipeline");
5508
5646
  }
5509
- }
5510
- if (this.shouldContinueLiveStreamDuringAds()) {
5511
- var _this_video_play;
5512
- if (this.config.debugAdTiming) {
5513
- if (this.video.paused) {
5514
- console.log("[StormcloudVideoPlayer] Content video paused in live mode after ads, resuming playback");
5515
- } else {
5516
- console.log("[StormcloudVideoPlayer] Content video already playing in live mode after ads");
5647
+ } else {
5648
+ if (this.shouldContinueLiveStreamDuringAds()) {
5649
+ var _this_video_play;
5650
+ if (this.config.debugAdTiming) {
5651
+ if (this.video.paused) {
5652
+ console.log("[StormcloudVideoPlayer] Content video paused in live mode after ads, resuming playback");
5653
+ } else {
5654
+ console.log("[StormcloudVideoPlayer] Content video already playing in live mode after ads");
5655
+ }
5517
5656
  }
5657
+ (_this_video_play = this.video.play()) === null || _this_video_play === void 0 ? void 0 : _this_video_play.catch(function() {});
5658
+ } else if (this.video.paused) {
5659
+ var _this_video_play1;
5660
+ (_this_video_play1 = this.video.play()) === null || _this_video_play1 === void 0 ? void 0 : _this_video_play1.catch(function() {});
5518
5661
  }
5519
- (_this_video_play = this.video.play()) === null || _this_video_play === void 0 ? void 0 : _this_video_play.catch(function() {});
5520
- } else if (this.video.paused) {
5521
- var _this_video_play1;
5522
- (_this_video_play1 = this.video.play()) === null || _this_video_play1 === void 0 ? void 0 : _this_video_play1.catch(function() {});
5523
5662
  }
5524
5663
  this.syncMainContentAudioWhenVisible();
5525
5664
  if (!restoredMuted) {
@@ -5570,6 +5709,14 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5570
5709
  console.log("[CONTINUOUS-FETCH] \uD83D\uDED1 Max consecutive failures reached (".concat(this.consecutiveFailures, "), ending ad break gracefully"));
5571
5710
  }
5572
5711
  this.handleAdPodComplete();
5712
+ return;
5713
+ }
5714
+ if (this.inAdBreak && !this.config.disableFiller) {
5715
+ if (this.config.debugAdTiming) {
5716
+ console.log("[CONTINUOUS-FETCH] Ad failure in active break \u2014 showing filler while awaiting next ad");
5717
+ }
5718
+ this.showPlaceholderLayer();
5719
+ this.adLayer.showPlaceholder();
5573
5720
  }
5574
5721
  }
5575
5722
  },