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.
@@ -922,14 +922,16 @@ function resolveBidToVastAd(winner, logPrefix) {
922
922
  return Promise.resolve(null);
923
923
  }
924
924
  function createVastAdLayer(contentVideo, options) {
925
- var _ref, _ref1;
925
+ var _ref, _ref1, _ref2, _ref3;
926
926
  var adPlaying = false;
927
927
  var originalMutedState = false;
928
928
  var originalVolume = Math.max(0, Math.min(1, contentVideo.volume || 1));
929
929
  var listeners = /* @__PURE__ */ new Map();
930
930
  var mainHlsInstance = options === null || options === void 0 ? void 0 : options.mainHlsInstance;
931
931
  var continueLiveStreamDuringAds = (_ref = options === null || options === void 0 ? void 0 : options.continueLiveStreamDuringAds) !== null && _ref !== void 0 ? _ref : false;
932
- var debug = (_ref1 = options === null || options === void 0 ? void 0 : options.debug) !== null && _ref1 !== void 0 ? _ref1 : false;
932
+ var smartTVMode = (_ref1 = options === null || options === void 0 ? void 0 : options.smartTVMode) !== null && _ref1 !== void 0 ? _ref1 : false;
933
+ var singleElementMode = (_ref2 = options === null || options === void 0 ? void 0 : options.singleElementMode) !== null && _ref2 !== void 0 ? _ref2 : false;
934
+ var debug = (_ref3 = options === null || options === void 0 ? void 0 : options.debug) !== null && _ref3 !== void 0 ? _ref3 : false;
933
935
  var adVideoElement;
934
936
  var adHls;
935
937
  var adContainerEl;
@@ -938,6 +940,7 @@ function createVastAdLayer(contentVideo, options) {
938
940
  var destroyed = false;
939
941
  var tornDown = false;
940
942
  var trackingFired = createEmptyTrackingState();
943
+ var currentAdEventHandlers;
941
944
  var preloadSlots = /* @__PURE__ */ new Map();
942
945
  function emit(event, payload) {
943
946
  var set = listeners.get(event);
@@ -1040,63 +1043,86 @@ function createVastAdLayer(contentVideo, options) {
1040
1043
  video.volume = 1;
1041
1044
  return video;
1042
1045
  }
1046
+ function removeAdEventListeners() {
1047
+ if (!currentAdEventHandlers || !adVideoElement) return;
1048
+ var el = adVideoElement;
1049
+ el.removeEventListener("timeupdate", currentAdEventHandlers.timeupdate);
1050
+ el.removeEventListener("playing", currentAdEventHandlers.playing);
1051
+ el.removeEventListener("ended", currentAdEventHandlers.ended);
1052
+ el.removeEventListener("error", currentAdEventHandlers.error);
1053
+ el.removeEventListener("volumechange", currentAdEventHandlers.volumechange);
1054
+ el.removeEventListener("pause", currentAdEventHandlers.pause);
1055
+ el.removeEventListener("play", currentAdEventHandlers.play);
1056
+ currentAdEventHandlers = void 0;
1057
+ }
1043
1058
  function setupAdEventListeners() {
1044
1059
  if (!adVideoElement) return;
1045
- adVideoElement.addEventListener("timeupdate", function() {
1046
- var ad = currentAd;
1047
- if (!ad || !adVideoElement) return;
1048
- var progress = adVideoElement.currentTime / ad.duration;
1049
- if (progress >= 0.25 && !trackingFired.firstQuartile) {
1050
- trackingFired.firstQuartile = true;
1051
- fireTrackingPixels2(ad.trackingUrls.firstQuartile);
1052
- }
1053
- if (progress >= 0.5 && !trackingFired.midpoint) {
1054
- trackingFired.midpoint = true;
1055
- fireTrackingPixels2(ad.trackingUrls.midpoint);
1056
- }
1057
- if (progress >= 0.75 && !trackingFired.thirdQuartile) {
1058
- trackingFired.thirdQuartile = true;
1059
- fireTrackingPixels2(ad.trackingUrls.thirdQuartile);
1060
- }
1061
- });
1062
- adVideoElement.addEventListener("playing", function() {
1063
- var ad = currentAd;
1064
- if (!ad || trackingFired.start) return;
1065
- trackingFired.start = true;
1066
- fireTrackingPixels2(ad.trackingUrls.start);
1067
- if (debug) console.log("".concat(LOG, " Ad started playing"));
1068
- });
1069
- adVideoElement.addEventListener("ended", function() {
1070
- if (tornDown || !currentAd || trackingFired.complete) return;
1071
- trackingFired.complete = true;
1072
- fireTrackingPixels2(currentAd.trackingUrls.complete);
1073
- if (debug) console.log("".concat(LOG, " Ad completed"));
1074
- handleAdComplete();
1075
- });
1076
- adVideoElement.addEventListener("error", function(e) {
1077
- if (tornDown) return;
1078
- console.error("".concat(LOG, " Ad video error:"), e);
1079
- if (currentAd) fireTrackingPixels2(currentAd.trackingUrls.error);
1080
- handleAdError();
1081
- });
1082
- adVideoElement.addEventListener("volumechange", function() {
1083
- if (!currentAd || !adVideoElement) return;
1084
- if (adVideoElement.muted) {
1085
- fireTrackingPixels2(currentAd.trackingUrls.mute);
1086
- } else {
1087
- fireTrackingPixels2(currentAd.trackingUrls.unmute);
1088
- }
1089
- });
1090
- adVideoElement.addEventListener("pause", function() {
1091
- if (currentAd && adVideoElement && !adVideoElement.ended) {
1092
- fireTrackingPixels2(currentAd.trackingUrls.pause);
1093
- }
1094
- });
1095
- adVideoElement.addEventListener("play", function() {
1096
- if (currentAd && adVideoElement && adVideoElement.currentTime > 0) {
1097
- fireTrackingPixels2(currentAd.trackingUrls.resume);
1060
+ removeAdEventListeners();
1061
+ var handlers = {
1062
+ timeupdate: function timeupdate() {
1063
+ var ad = currentAd;
1064
+ if (!ad || !adVideoElement) return;
1065
+ var progress = adVideoElement.currentTime / ad.duration;
1066
+ if (progress >= 0.25 && !trackingFired.firstQuartile) {
1067
+ trackingFired.firstQuartile = true;
1068
+ fireTrackingPixels2(ad.trackingUrls.firstQuartile);
1069
+ }
1070
+ if (progress >= 0.5 && !trackingFired.midpoint) {
1071
+ trackingFired.midpoint = true;
1072
+ fireTrackingPixels2(ad.trackingUrls.midpoint);
1073
+ }
1074
+ if (progress >= 0.75 && !trackingFired.thirdQuartile) {
1075
+ trackingFired.thirdQuartile = true;
1076
+ fireTrackingPixels2(ad.trackingUrls.thirdQuartile);
1077
+ }
1078
+ },
1079
+ playing: function playing() {
1080
+ var ad = currentAd;
1081
+ if (!ad || trackingFired.start) return;
1082
+ trackingFired.start = true;
1083
+ fireTrackingPixels2(ad.trackingUrls.start);
1084
+ if (debug) console.log("".concat(LOG, " Ad started playing"));
1085
+ },
1086
+ ended: function ended() {
1087
+ if (tornDown || !currentAd || trackingFired.complete) return;
1088
+ trackingFired.complete = true;
1089
+ fireTrackingPixels2(currentAd.trackingUrls.complete);
1090
+ if (debug) console.log("".concat(LOG, " Ad completed"));
1091
+ handleAdComplete();
1092
+ },
1093
+ error: function error(e) {
1094
+ if (tornDown) return;
1095
+ console.error("".concat(LOG, " Ad video error:"), e);
1096
+ if (currentAd) fireTrackingPixels2(currentAd.trackingUrls.error);
1097
+ handleAdError();
1098
+ },
1099
+ volumechange: function volumechange() {
1100
+ if (!currentAd || !adVideoElement) return;
1101
+ if (adVideoElement.muted) {
1102
+ fireTrackingPixels2(currentAd.trackingUrls.mute);
1103
+ } else {
1104
+ fireTrackingPixels2(currentAd.trackingUrls.unmute);
1105
+ }
1106
+ },
1107
+ pause: function pause() {
1108
+ if (currentAd && adVideoElement && !adVideoElement.ended) {
1109
+ fireTrackingPixels2(currentAd.trackingUrls.pause);
1110
+ }
1111
+ },
1112
+ play: function play() {
1113
+ if (currentAd && adVideoElement && adVideoElement.currentTime > 0) {
1114
+ fireTrackingPixels2(currentAd.trackingUrls.resume);
1115
+ }
1098
1116
  }
1099
- });
1117
+ };
1118
+ adVideoElement.addEventListener("timeupdate", handlers.timeupdate);
1119
+ adVideoElement.addEventListener("playing", handlers.playing);
1120
+ adVideoElement.addEventListener("ended", handlers.ended);
1121
+ adVideoElement.addEventListener("error", handlers.error);
1122
+ adVideoElement.addEventListener("volumechange", handlers.volumechange);
1123
+ adVideoElement.addEventListener("pause", handlers.pause);
1124
+ adVideoElement.addEventListener("play", handlers.play);
1125
+ currentAdEventHandlers = handlers;
1100
1126
  }
1101
1127
  function setAdPlayingFlag(isPlaying) {
1102
1128
  if (isPlaying) {
@@ -1119,6 +1145,7 @@ function createVastAdLayer(contentVideo, options) {
1119
1145
  }
1120
1146
  function handleAdError() {
1121
1147
  if (tornDown) return;
1148
+ if (!adPlaying) return;
1122
1149
  if (debug) console.log("".concat(LOG, " Handling ad error"));
1123
1150
  adPlaying = false;
1124
1151
  setAdPlayingFlag(false);
@@ -1129,14 +1156,19 @@ function createVastAdLayer(contentVideo, options) {
1129
1156
  emit("ad_error");
1130
1157
  }
1131
1158
  function teardownCurrentPlayback() {
1159
+ removeAdEventListeners();
1132
1160
  if (adHls) {
1133
1161
  adHls.destroy();
1134
1162
  adHls = void 0;
1135
1163
  }
1136
1164
  if (adVideoElement) {
1137
- adVideoElement.pause();
1138
- adVideoElement.removeAttribute("src");
1139
- adVideoElement.load();
1165
+ if (singleElementMode && adVideoElement === contentVideo) {
1166
+ contentVideo.pause();
1167
+ } else {
1168
+ adVideoElement.pause();
1169
+ adVideoElement.removeAttribute("src");
1170
+ adVideoElement.load();
1171
+ }
1140
1172
  }
1141
1173
  }
1142
1174
  function startNativePlayback(mediaFile) {
@@ -1169,8 +1201,17 @@ function createVastAdLayer(contentVideo, options) {
1169
1201
  handleAdError();
1170
1202
  });
1171
1203
  });
1204
+ var nonFatalNetworkErrors = 0;
1172
1205
  adHls.on(import_hls.default.Events.ERROR, function(_event, data) {
1173
- if (data.fatal) handleAdError();
1206
+ if (data.fatal) {
1207
+ handleAdError();
1208
+ } else if (data.type === import_hls.default.ErrorTypes.NETWORK_ERROR) {
1209
+ nonFatalNetworkErrors++;
1210
+ if (nonFatalNetworkErrors >= 3) {
1211
+ if (debug) console.warn("".concat(LOG, " Too many non-fatal HLS network errors (").concat(nonFatalNetworkErrors, "), treating as fatal"));
1212
+ handleAdError();
1213
+ }
1214
+ }
1174
1215
  });
1175
1216
  } else if (adVideoElement.canPlayType("application/vnd.apple.mpegurl")) {
1176
1217
  adVideoElement.src = mediaFile.url;
@@ -1193,7 +1234,7 @@ function createVastAdLayer(contentVideo, options) {
1193
1234
  }
1194
1235
  function playAd(bids) {
1195
1236
  return _async_to_generator(function() {
1196
- var winner, ad, _contentVideo_parentElement, container, contentVolume, adVolume, mediaFile;
1237
+ var winner, ad, contentVolume, _contentVideo_parentElement, container, adVolume, mediaFile;
1197
1238
  return _ts_generator(this, function(_state) {
1198
1239
  switch(_state.label){
1199
1240
  case 0:
@@ -1235,32 +1276,40 @@ function createVastAdLayer(contentVideo, options) {
1235
1276
  trackingFired = _object_spread({}, createEmptyTrackingState());
1236
1277
  fireTrackingPixels2(ad.trackingUrls.impression);
1237
1278
  trackingFired.impression = true;
1238
- if (!adContainerEl) {
1239
- ;
1240
- container = document.createElement("div");
1241
- container.style.position = "absolute";
1242
- container.style.left = "0";
1243
- container.style.top = "0";
1244
- container.style.right = "0";
1245
- container.style.bottom = "0";
1246
- container.style.display = "none";
1247
- container.style.alignItems = "center";
1248
- container.style.justifyContent = "center";
1249
- container.style.pointerEvents = "none";
1250
- container.style.zIndex = "10";
1251
- container.style.backgroundColor = "#000";
1252
- (_contentVideo_parentElement = contentVideo.parentElement) === null || _contentVideo_parentElement === void 0 ? void 0 : _contentVideo_parentElement.appendChild(container);
1253
- adContainerEl = container;
1254
- }
1255
- if (!adVideoElement) {
1256
- adVideoElement = createAdVideoElement();
1257
- adContainerEl.appendChild(adVideoElement);
1279
+ contentVolume = contentVideo.volume;
1280
+ originalVolume = Math.max(0, Math.min(1, contentVolume || originalVolume));
1281
+ if (singleElementMode) {
1282
+ mainHlsInstance === null || mainHlsInstance === void 0 ? void 0 : mainHlsInstance.detachMedia();
1283
+ teardownCurrentPlayback();
1284
+ adVideoElement = contentVideo;
1285
+ adHls = void 0;
1258
1286
  setupAdEventListeners();
1259
1287
  } else {
1260
- teardownCurrentPlayback();
1288
+ if (!adContainerEl) {
1289
+ ;
1290
+ container = document.createElement("div");
1291
+ container.style.position = "absolute";
1292
+ container.style.left = "0";
1293
+ container.style.top = "0";
1294
+ container.style.right = "0";
1295
+ container.style.bottom = "0";
1296
+ container.style.display = "none";
1297
+ container.style.alignItems = "center";
1298
+ container.style.justifyContent = "center";
1299
+ container.style.pointerEvents = "none";
1300
+ container.style.zIndex = "10";
1301
+ container.style.backgroundColor = "#000";
1302
+ (_contentVideo_parentElement = contentVideo.parentElement) === null || _contentVideo_parentElement === void 0 ? void 0 : _contentVideo_parentElement.appendChild(container);
1303
+ adContainerEl = container;
1304
+ }
1305
+ if (!adVideoElement) {
1306
+ adVideoElement = createAdVideoElement();
1307
+ adContainerEl.appendChild(adVideoElement);
1308
+ setupAdEventListeners();
1309
+ } else {
1310
+ teardownCurrentPlayback();
1311
+ }
1261
1312
  }
1262
- contentVolume = contentVideo.volume;
1263
- originalVolume = Math.max(0, Math.min(1, contentVolume || originalVolume));
1264
1313
  if (!continueLiveStreamDuringAds) {
1265
1314
  contentVideo.pause();
1266
1315
  }
@@ -1271,7 +1320,7 @@ function createVastAdLayer(contentVideo, options) {
1271
1320
  adVolume = originalMutedState ? 1 : originalVolume;
1272
1321
  adVideoElement.volume = Math.max(0, Math.min(1, adVolume));
1273
1322
  adVideoElement.muted = false;
1274
- if (adContainerEl) {
1323
+ if (!singleElementMode && adContainerEl) {
1275
1324
  adContainerEl.style.display = "flex";
1276
1325
  adContainerEl.style.pointerEvents = "auto";
1277
1326
  }
@@ -1308,7 +1357,7 @@ function createVastAdLayer(contentVideo, options) {
1308
1357
  }
1309
1358
  function preloadAd(bids, token) {
1310
1359
  return _async_to_generator(function() {
1311
- var winner, ad, mediaFile, videoEl, container, hls, slot, slot1;
1360
+ var winner, ad, mediaFile, slot, videoEl, container, hls, slot1, slot2;
1312
1361
  return _ts_generator(this, function(_state) {
1313
1362
  switch(_state.label){
1314
1363
  case 0:
@@ -1333,6 +1382,20 @@ function createVastAdLayer(contentVideo, options) {
1333
1382
  if (!mediaFile) return [
1334
1383
  2
1335
1384
  ];
1385
+ if (smartTVMode || singleElementMode) {
1386
+ slot = {
1387
+ bids: bids,
1388
+ ad: ad,
1389
+ mediaFile: mediaFile,
1390
+ videoEl: null,
1391
+ ready: true
1392
+ };
1393
+ preloadSlots.set(token, slot);
1394
+ if (debug) console.log("".concat(LOG, " [preload] Metadata-only preload (smartTV/singleElement), token=").concat(token, ", url=").concat(mediaFile.url));
1395
+ return [
1396
+ 2
1397
+ ];
1398
+ }
1336
1399
  videoEl = createAdVideoElement();
1337
1400
  videoEl.style.visibility = "hidden";
1338
1401
  videoEl.style.pointerEvents = "none";
@@ -1346,7 +1409,7 @@ function createVastAdLayer(contentVideo, options) {
1346
1409
  });
1347
1410
  hls.loadSource(mediaFile.url);
1348
1411
  hls.attachMedia(videoEl);
1349
- slot = {
1412
+ slot1 = {
1350
1413
  bids: bids,
1351
1414
  ad: ad,
1352
1415
  mediaFile: mediaFile,
@@ -1354,7 +1417,7 @@ function createVastAdLayer(contentVideo, options) {
1354
1417
  hlsInstance: hls,
1355
1418
  ready: false
1356
1419
  };
1357
- preloadSlots.set(token, slot);
1420
+ preloadSlots.set(token, slot1);
1358
1421
  hls.on(import_hls.default.Events.MANIFEST_PARSED, function() {
1359
1422
  var s = preloadSlots.get(token);
1360
1423
  if (s) s.ready = true;
@@ -1371,14 +1434,14 @@ function createVastAdLayer(contentVideo, options) {
1371
1434
  } else {
1372
1435
  videoEl.src = mediaFile.url;
1373
1436
  videoEl.load();
1374
- slot1 = {
1437
+ slot2 = {
1375
1438
  bids: bids,
1376
1439
  ad: ad,
1377
1440
  mediaFile: mediaFile,
1378
1441
  videoEl: videoEl,
1379
1442
  ready: false
1380
1443
  };
1381
- preloadSlots.set(token, slot1);
1444
+ preloadSlots.set(token, slot2);
1382
1445
  videoEl.addEventListener("canplay", function() {
1383
1446
  var s = preloadSlots.get(token);
1384
1447
  if (s) s.ready = true;
@@ -1397,7 +1460,7 @@ function createVastAdLayer(contentVideo, options) {
1397
1460
  }
1398
1461
  function playPreloaded(token) {
1399
1462
  return _async_to_generator(function() {
1400
- var slot, contentVolume, adVolume, container;
1463
+ var slot, contentVolume, adVolume2, videoEl, container2, adVolume21, adVolume, container;
1401
1464
  return _ts_generator(this, function(_state) {
1402
1465
  if (destroyed) return [
1403
1466
  2,
@@ -1412,6 +1475,68 @@ function createVastAdLayer(contentVideo, options) {
1412
1475
  }
1413
1476
  preloadSlots.delete(token);
1414
1477
  if (debug) console.log("".concat(LOG, " [preload] Playing preloaded ad, token=").concat(token, ", ready=").concat(slot.ready));
1478
+ contentVolume = contentVideo.volume;
1479
+ originalVolume = Math.max(0, Math.min(1, contentVolume || originalVolume));
1480
+ sessionId = generateSessionId();
1481
+ currentAd = slot.ad;
1482
+ trackingFired = _object_spread({}, createEmptyTrackingState());
1483
+ fireTrackingPixels2(slot.ad.trackingUrls.impression);
1484
+ trackingFired.impression = true;
1485
+ if (singleElementMode) {
1486
+ mainHlsInstance === null || mainHlsInstance === void 0 ? void 0 : mainHlsInstance.detachMedia();
1487
+ teardownCurrentPlayback();
1488
+ adVideoElement = contentVideo;
1489
+ adHls = void 0;
1490
+ setupAdEventListeners();
1491
+ if (!continueLiveStreamDuringAds) {
1492
+ contentVideo.pause();
1493
+ }
1494
+ contentVideo.muted = true;
1495
+ contentVideo.volume = 0;
1496
+ adPlaying = true;
1497
+ setAdPlayingFlag(true);
1498
+ adVolume2 = originalMutedState ? 1 : originalVolume;
1499
+ contentVideo.volume = Math.max(0, Math.min(1, adVolume2));
1500
+ contentVideo.muted = false;
1501
+ emit("content_pause");
1502
+ if (debug) console.log("".concat(LOG, " [preload] singleElementMode: attaching ad to contentVideo, url=").concat(slot.mediaFile.url));
1503
+ startPlayback(slot.mediaFile);
1504
+ return [
1505
+ 2
1506
+ ];
1507
+ }
1508
+ if (smartTVMode && !slot.videoEl) {
1509
+ teardownCurrentPlayback();
1510
+ if (adVideoElement) {
1511
+ adVideoElement.remove();
1512
+ adVideoElement = void 0;
1513
+ }
1514
+ videoEl = createAdVideoElement();
1515
+ videoEl.style.visibility = "visible";
1516
+ videoEl.style.pointerEvents = "none";
1517
+ container2 = ensureAdContainer();
1518
+ container2.appendChild(videoEl);
1519
+ adVideoElement = videoEl;
1520
+ setupAdEventListeners();
1521
+ if (!continueLiveStreamDuringAds) {
1522
+ contentVideo.pause();
1523
+ }
1524
+ contentVideo.muted = true;
1525
+ contentVideo.volume = 0;
1526
+ adPlaying = true;
1527
+ setAdPlayingFlag(true);
1528
+ adVolume21 = originalMutedState ? 1 : originalVolume;
1529
+ adVideoElement.volume = Math.max(0, Math.min(1, adVolume21));
1530
+ adVideoElement.muted = false;
1531
+ container2.style.display = "flex";
1532
+ container2.style.pointerEvents = "auto";
1533
+ emit("content_pause");
1534
+ if (debug) console.log("".concat(LOG, " [preload] smartTVMode deferred: creating video element and loading, url=").concat(slot.mediaFile.url));
1535
+ startPlayback(slot.mediaFile);
1536
+ return [
1537
+ 2
1538
+ ];
1539
+ }
1415
1540
  teardownCurrentPlayback();
1416
1541
  if (adVideoElement && adVideoElement !== slot.videoEl) {
1417
1542
  adVideoElement.remove();
@@ -1421,13 +1546,6 @@ function createVastAdLayer(contentVideo, options) {
1421
1546
  adVideoElement = slot.videoEl;
1422
1547
  adHls = slot.hlsInstance;
1423
1548
  setupAdEventListeners();
1424
- sessionId = generateSessionId();
1425
- currentAd = slot.ad;
1426
- trackingFired = _object_spread({}, createEmptyTrackingState());
1427
- fireTrackingPixels2(slot.ad.trackingUrls.impression);
1428
- trackingFired.impression = true;
1429
- contentVolume = contentVideo.volume;
1430
- originalVolume = Math.max(0, Math.min(1, contentVolume || originalVolume));
1431
1549
  if (!continueLiveStreamDuringAds) {
1432
1550
  contentVideo.pause();
1433
1551
  }
@@ -1442,17 +1560,10 @@ function createVastAdLayer(contentVideo, options) {
1442
1560
  container.style.display = "flex";
1443
1561
  container.style.pointerEvents = "auto";
1444
1562
  emit("content_pause");
1445
- if (slot.hlsInstance) {
1446
- adVideoElement.play().catch(function(error) {
1447
- console.error("".concat(LOG, " [preload] Error playing preloaded HLS ad:"), error);
1448
- handleAdError();
1449
- });
1450
- } else {
1451
- adVideoElement.play().catch(function(error) {
1452
- console.error("".concat(LOG, " [preload] Error playing preloaded ad:"), error);
1453
- handleAdError();
1454
- });
1455
- }
1563
+ adVideoElement.play().catch(function(error) {
1564
+ console.error("".concat(LOG, " [preload] Error playing preloaded ad:"), error);
1565
+ handleAdError();
1566
+ });
1456
1567
  return [
1457
1568
  2
1458
1569
  ];
@@ -1466,10 +1577,12 @@ function createVastAdLayer(contentVideo, options) {
1466
1577
  if (slot.hlsInstance) {
1467
1578
  slot.hlsInstance.destroy();
1468
1579
  }
1469
- slot.videoEl.pause();
1470
- slot.videoEl.removeAttribute("src");
1471
- slot.videoEl.load();
1472
- slot.videoEl.remove();
1580
+ if (slot.videoEl) {
1581
+ slot.videoEl.pause();
1582
+ slot.videoEl.removeAttribute("src");
1583
+ slot.videoEl.load();
1584
+ slot.videoEl.remove();
1585
+ }
1473
1586
  if (debug) console.log("".concat(LOG, " [preload] Cancelled and cleaned up token=").concat(token));
1474
1587
  }
1475
1588
  return {
@@ -1517,20 +1630,27 @@ function createVastAdLayer(contentVideo, options) {
1517
1630
  setAdPlayingFlag(false);
1518
1631
  contentVideo.muted = originalMutedState;
1519
1632
  contentVideo.volume = originalMutedState ? 0 : originalVolume;
1520
- if (adContainerEl) {
1521
- adContainerEl.style.display = "none";
1522
- adContainerEl.style.pointerEvents = "none";
1523
- }
1524
1633
  contentVideo.style.visibility = "visible";
1525
1634
  contentVideo.style.opacity = "1";
1526
- if (continueLiveStreamDuringAds) {
1527
- contentVideo.play().catch(function() {});
1528
- }
1529
- teardownCurrentPlayback();
1530
- if (adVideoElement) {
1531
- adVideoElement.pause();
1532
- adVideoElement.removeAttribute("src");
1533
- adVideoElement.load();
1635
+ if (singleElementMode) {
1636
+ teardownCurrentPlayback();
1637
+ contentVideo.removeAttribute("src");
1638
+ contentVideo.load();
1639
+ adVideoElement = void 0;
1640
+ } else {
1641
+ if (adContainerEl) {
1642
+ adContainerEl.style.display = "none";
1643
+ adContainerEl.style.pointerEvents = "none";
1644
+ }
1645
+ if (continueLiveStreamDuringAds) {
1646
+ contentVideo.play().catch(function() {});
1647
+ }
1648
+ teardownCurrentPlayback();
1649
+ if (adVideoElement) {
1650
+ adVideoElement.pause();
1651
+ adVideoElement.removeAttribute("src");
1652
+ adVideoElement.load();
1653
+ }
1534
1654
  }
1535
1655
  currentAd = void 0;
1536
1656
  tornDown = false;
@@ -1570,9 +1690,14 @@ function createVastAdLayer(contentVideo, options) {
1570
1690
  }
1571
1691
  teardownCurrentPlayback();
1572
1692
  if (adVideoElement) {
1573
- adVideoElement.pause();
1574
- adVideoElement.removeAttribute("src");
1575
- adVideoElement.remove();
1693
+ if (singleElementMode && adVideoElement === contentVideo) {
1694
+ contentVideo.removeAttribute("src");
1695
+ contentVideo.load();
1696
+ } else {
1697
+ adVideoElement.pause();
1698
+ adVideoElement.removeAttribute("src");
1699
+ adVideoElement.remove();
1700
+ }
1576
1701
  adVideoElement = void 0;
1577
1702
  }
1578
1703
  if (adContainerEl === null || adContainerEl === void 0 ? void 0 : adContainerEl.parentElement) {
@@ -2770,8 +2895,11 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
2770
2895
  this.vastManager = createVastManager(config.debugAdTiming !== void 0 ? {
2771
2896
  debug: !!config.debugAdTiming
2772
2897
  } : {});
2898
+ var browserForAdLayer = detectBrowser();
2773
2899
  this.adLayer = createVastAdLayer(this.video, {
2774
2900
  continueLiveStreamDuringAds: false,
2901
+ smartTVMode: browserForAdLayer.isSmartTV,
2902
+ singleElementMode: browserForAdLayer.isSmartTV,
2775
2903
  debug: !!config.debugAdTiming
2776
2904
  });
2777
2905
  }
@@ -4133,6 +4261,10 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4133
4261
  if (!this.isLiveStream) {
4134
4262
  return false;
4135
4263
  }
4264
+ var browser = detectBrowser();
4265
+ if (browser.isSmartTV) {
4266
+ return false;
4267
+ }
4136
4268
  return true;
4137
4269
  }
4138
4270
  },
@@ -4340,7 +4472,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4340
4472
  switch(_state.label){
4341
4473
  case 0:
4342
4474
  _loop = function() {
4343
- var remaining, prefetchContext, bids, err, bids1, remainingNow, delay, elapsed, remaining1, context, bids2, remainingNow1, err1;
4475
+ var remaining, prefetchContext, bids, err, bids1, remainingNow, urgentNeedAd, delay, elapsed, remaining1, context, bids2, remainingNow1, err1, sleepMs;
4344
4476
  return _ts_generator(this, function(_state) {
4345
4477
  switch(_state.label){
4346
4478
  case 0:
@@ -4476,7 +4608,8 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4476
4608
  "continue"
4477
4609
  ];
4478
4610
  case 12:
4479
- delay = _this.lastAdRequestTime ? _this.minAdRequestIntervalMs + (_this.consecutiveFailures > 0 ? backoffMs() : 0) : 0;
4611
+ urgentNeedAd = _this.inAdBreak && !_this.adLayer.isAdPlaying();
4612
+ delay = _this.lastAdRequestTime ? _this.minAdRequestIntervalMs + (!urgentNeedAd && _this.consecutiveFailures > 0 ? backoffMs() : 0) : 0;
4480
4613
  elapsed = Date.now() - _this.lastAdRequestTime;
4481
4614
  if (!(elapsed < delay && _this.lastAdRequestTime > 0)) return [
4482
4615
  3,
@@ -4595,10 +4728,11 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4595
4728
  24
4596
4729
  ];
4597
4730
  case 24:
4731
+ sleepMs = _this.inAdBreak && !_this.adLayer.isAdPlaying() ? 0 : backoffMs();
4598
4732
  return [
4599
4733
  4,
4600
4734
  new Promise(function(r) {
4601
- return setTimeout(r, backoffMs());
4735
+ return setTimeout(r, sleepMs);
4602
4736
  })
4603
4737
  ];
4604
4738
  case 25:
@@ -5279,40 +5413,45 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5279
5413
  var browser = detectBrowser();
5280
5414
  var isSmartTV = browser.tizenVersion !== void 0 || browser.webOSVersion !== void 0;
5281
5415
  if (isSmartTV && this.hls) {
5282
- if (!restoredMuted) {
5283
- var hlsRef = this.hls;
5284
- var savedMuted = restoredMuted;
5285
- var savedVolume = restoredVolume;
5286
- var onManifestParsedRestore = function onManifestParsedRestore1() {
5287
- hlsRef.off(import_hls2.default.Events.MANIFEST_PARSED, onManifestParsedRestore);
5288
- if (!_this.inAdBreak && !_this.adLayer.isAdPlaying()) {
5289
- if (_this.video.muted !== savedMuted) _this.video.muted = savedMuted;
5290
- if (Math.abs(_this.video.volume - savedVolume) > 0.01) _this.video.volume = savedVolume;
5291
- if (_this.config.debugAdTiming) {
5292
- console.log("[StormcloudVideoPlayer] Smart TV: audio state restored on MANIFEST_PARSED after re-attach");
5293
- }
5416
+ var hlsRef = this.hls;
5417
+ var savedMuted = restoredMuted;
5418
+ var savedVolume = restoredVolume;
5419
+ var onManifestParsedRestore = function onManifestParsedRestore1() {
5420
+ hlsRef.off(import_hls2.default.Events.MANIFEST_PARSED, onManifestParsedRestore);
5421
+ if (!_this.inAdBreak && !_this.adLayer.isAdPlaying()) {
5422
+ var _this_video_play;
5423
+ if (_this.video.muted !== savedMuted) _this.video.muted = savedMuted;
5424
+ if (Math.abs(_this.video.volume - savedVolume) > 0.01) _this.video.volume = savedVolume;
5425
+ if (_this.config.debugAdTiming) {
5426
+ console.log("[StormcloudVideoPlayer] Smart TV: audio state restored on MANIFEST_PARSED after re-attach");
5294
5427
  }
5295
- };
5296
- hlsRef.on(import_hls2.default.Events.MANIFEST_PARSED, onManifestParsedRestore);
5297
- }
5428
+ hlsRef.startLoad(-1);
5429
+ (_this_video_play = _this.video.play()) === null || _this_video_play === void 0 ? void 0 : _this_video_play.catch(function() {});
5430
+ if (_this.config.debugAdTiming) {
5431
+ console.log("[StormcloudVideoPlayer] Smart TV: seeking to live edge and resuming playback after re-attach");
5432
+ }
5433
+ }
5434
+ };
5435
+ hlsRef.on(import_hls2.default.Events.MANIFEST_PARSED, onManifestParsedRestore);
5298
5436
  this.hls.attachMedia(this.video);
5299
5437
  if (this.config.debugAdTiming) {
5300
5438
  console.log("[StormcloudVideoPlayer] Smart TV: re-attached HLS to video element after ad break to restore media pipeline");
5301
5439
  }
5302
- }
5303
- if (this.shouldContinueLiveStreamDuringAds()) {
5304
- var _this_video_play;
5305
- if (this.config.debugAdTiming) {
5306
- if (this.video.paused) {
5307
- console.log("[StormcloudVideoPlayer] Content video paused in live mode after ads, resuming playback");
5308
- } else {
5309
- console.log("[StormcloudVideoPlayer] Content video already playing in live mode after ads");
5440
+ } else {
5441
+ if (this.shouldContinueLiveStreamDuringAds()) {
5442
+ var _this_video_play;
5443
+ if (this.config.debugAdTiming) {
5444
+ if (this.video.paused) {
5445
+ console.log("[StormcloudVideoPlayer] Content video paused in live mode after ads, resuming playback");
5446
+ } else {
5447
+ console.log("[StormcloudVideoPlayer] Content video already playing in live mode after ads");
5448
+ }
5310
5449
  }
5450
+ (_this_video_play = this.video.play()) === null || _this_video_play === void 0 ? void 0 : _this_video_play.catch(function() {});
5451
+ } else if (this.video.paused) {
5452
+ var _this_video_play1;
5453
+ (_this_video_play1 = this.video.play()) === null || _this_video_play1 === void 0 ? void 0 : _this_video_play1.catch(function() {});
5311
5454
  }
5312
- (_this_video_play = this.video.play()) === null || _this_video_play === void 0 ? void 0 : _this_video_play.catch(function() {});
5313
- } else if (this.video.paused) {
5314
- var _this_video_play1;
5315
- (_this_video_play1 = this.video.play()) === null || _this_video_play1 === void 0 ? void 0 : _this_video_play1.catch(function() {});
5316
5455
  }
5317
5456
  this.syncMainContentAudioWhenVisible();
5318
5457
  if (!restoredMuted) {
@@ -5363,6 +5502,14 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5363
5502
  console.log("[CONTINUOUS-FETCH] \uD83D\uDED1 Max consecutive failures reached (".concat(this.consecutiveFailures, "), ending ad break gracefully"));
5364
5503
  }
5365
5504
  this.handleAdPodComplete();
5505
+ return;
5506
+ }
5507
+ if (this.inAdBreak && !this.config.disableFiller) {
5508
+ if (this.config.debugAdTiming) {
5509
+ console.log("[CONTINUOUS-FETCH] Ad failure in active break \u2014 showing filler while awaiting next ad");
5510
+ }
5511
+ this.showPlaceholderLayer();
5512
+ this.adLayer.showPlaceholder();
5366
5513
  }
5367
5514
  }
5368
5515
  },