stormcloud-video-player 0.8.2 → 0.8.4
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/dist/stormcloud-vp.min.js +3 -1
- package/lib/index.cjs +536 -341
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.cts +37 -2
- package/lib/index.d.ts +37 -2
- package/lib/index.js +477 -342
- package/lib/index.js.map +1 -1
- package/lib/player/StormcloudVideoPlayer.cjs +266 -206
- package/lib/player/StormcloudVideoPlayer.cjs.map +1 -1
- package/lib/player/StormcloudVideoPlayer.d.cts +5 -2
- package/lib/players/FilePlayer.cjs.map +1 -1
- package/lib/players/HlsPlayer.cjs +266 -206
- package/lib/players/HlsPlayer.cjs.map +1 -1
- package/lib/players/HlsPlayer.d.cts +1 -1
- package/lib/players/index.cjs +266 -206
- package/lib/players/index.cjs.map +1 -1
- package/lib/sdk/hlsAdPlayer.cjs.map +1 -1
- package/lib/sdk/hlsAdPlayer.d.cts +1 -1
- package/lib/sdk/pal.cjs.map +1 -1
- package/lib/{types-DDwAfBLt.d.cts → types-BmF_60m2.d.cts} +2 -0
- package/lib/ui/StormcloudVideoPlayer.cjs +450 -341
- package/lib/ui/StormcloudVideoPlayer.cjs.map +1 -1
- package/lib/ui/StormcloudVideoPlayer.d.cts +1 -1
- package/lib/utils/browserCompat.cjs.map +1 -1
- package/lib/utils/mqttClient.cjs +245 -0
- package/lib/utils/mqttClient.cjs.map +1 -0
- package/lib/utils/mqttClient.d.cts +13 -0
- package/lib/utils/mqttConfig.cjs +141 -0
- package/lib/utils/mqttConfig.cjs.map +1 -0
- package/lib/utils/mqttConfig.d.cts +20 -0
- package/lib/utils/polyfills.cjs.map +1 -1
- package/lib/utils/tracking.cjs +182 -170
- package/lib/utils/tracking.cjs.map +1 -1
- package/lib/utils/tracking.d.cts +1 -1
- package/package.json +3 -1
- package/src/certs/emqxsl-ca.crt +22 -0
|
@@ -1371,6 +1371,99 @@ function createPalNonceManager() {
|
|
|
1371
1371
|
}
|
|
1372
1372
|
};
|
|
1373
1373
|
}
|
|
1374
|
+
// src/utils/mqttConfig.ts
|
|
1375
|
+
var DEFAULT_MQTT_CONFIG = {
|
|
1376
|
+
enabled: true,
|
|
1377
|
+
brokerAddress: "vecbae77.ala.us-east-1.emqxsl.com",
|
|
1378
|
+
brokerPort: 8883,
|
|
1379
|
+
wsPort: 8084,
|
|
1380
|
+
username: "for-sonifi",
|
|
1381
|
+
password: "sonifi-mqtt",
|
|
1382
|
+
topicPrefix: "adstorm/players",
|
|
1383
|
+
qos: 1
|
|
1384
|
+
};
|
|
1385
|
+
var mqttConfig = _object_spread({}, DEFAULT_MQTT_CONFIG);
|
|
1386
|
+
function isMQTTEnabled() {
|
|
1387
|
+
return mqttConfig.enabled;
|
|
1388
|
+
}
|
|
1389
|
+
function buildMQTTBrokerUrl() {
|
|
1390
|
+
if (mqttConfig.brokerUrl) return mqttConfig.brokerUrl;
|
|
1391
|
+
return "wss://".concat(mqttConfig.brokerAddress, ":").concat(mqttConfig.wsPort, "/mqtt");
|
|
1392
|
+
}
|
|
1393
|
+
function buildPlayerTopic(licenseKey, channel) {
|
|
1394
|
+
return "".concat(mqttConfig.topicPrefix, "/").concat(licenseKey, "/").concat(channel);
|
|
1395
|
+
}
|
|
1396
|
+
// src/utils/mqttClient.ts
|
|
1397
|
+
var import_mqtt = __toESM(require("mqtt"), 1);
|
|
1398
|
+
var LOG = "[StormcloudVideoPlayer][MQTT]";
|
|
1399
|
+
var client = null;
|
|
1400
|
+
var status = "disconnected";
|
|
1401
|
+
function initMQTTClient() {
|
|
1402
|
+
if (client || !isMQTTEnabled()) return;
|
|
1403
|
+
var url = buildMQTTBrokerUrl();
|
|
1404
|
+
status = "connecting";
|
|
1405
|
+
var clientId = "stormcloud-vp-".concat(Math.random().toString(36).slice(2, 9));
|
|
1406
|
+
try {
|
|
1407
|
+
client = import_mqtt.default.connect(url, {
|
|
1408
|
+
clientId: clientId,
|
|
1409
|
+
username: mqttConfig.username,
|
|
1410
|
+
password: mqttConfig.password,
|
|
1411
|
+
keepalive: 60,
|
|
1412
|
+
clean: true,
|
|
1413
|
+
reconnectPeriod: 5e3,
|
|
1414
|
+
connectTimeout: 1e4,
|
|
1415
|
+
queueQoSZero: false
|
|
1416
|
+
});
|
|
1417
|
+
} catch (err) {
|
|
1418
|
+
status = "error";
|
|
1419
|
+
console.warn("".concat(LOG, " connect() threw:"), err);
|
|
1420
|
+
return;
|
|
1421
|
+
}
|
|
1422
|
+
client.on("connect", function() {
|
|
1423
|
+
status = "connected";
|
|
1424
|
+
console.info("".concat(LOG, " connected to ").concat(url));
|
|
1425
|
+
});
|
|
1426
|
+
client.on("reconnect", function() {
|
|
1427
|
+
status = "connecting";
|
|
1428
|
+
console.info("".concat(LOG, " reconnecting…"));
|
|
1429
|
+
});
|
|
1430
|
+
client.on("offline", function() {
|
|
1431
|
+
status = "disconnected";
|
|
1432
|
+
console.warn("".concat(LOG, " offline"));
|
|
1433
|
+
});
|
|
1434
|
+
client.on("error", function(err) {
|
|
1435
|
+
status = "error";
|
|
1436
|
+
console.warn("".concat(LOG, " error:"), err.message);
|
|
1437
|
+
});
|
|
1438
|
+
client.on("close", function() {
|
|
1439
|
+
if (status === "connected") {
|
|
1440
|
+
status = "disconnected";
|
|
1441
|
+
}
|
|
1442
|
+
});
|
|
1443
|
+
}
|
|
1444
|
+
function ensureMQTTClient() {
|
|
1445
|
+
if (isMQTTEnabled() && !client) {
|
|
1446
|
+
initMQTTClient();
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1449
|
+
function publishMQTT(topic, payload) {
|
|
1450
|
+
if (!isMQTTEnabled()) {
|
|
1451
|
+
return false;
|
|
1452
|
+
}
|
|
1453
|
+
ensureMQTTClient();
|
|
1454
|
+
if (!client) {
|
|
1455
|
+
return false;
|
|
1456
|
+
}
|
|
1457
|
+
try {
|
|
1458
|
+
client.publish(topic, JSON.stringify(payload), {
|
|
1459
|
+
qos: mqttConfig.qos
|
|
1460
|
+
});
|
|
1461
|
+
return true;
|
|
1462
|
+
} catch (err) {
|
|
1463
|
+
console.warn("".concat(LOG, " publish failed on ").concat(topic, ":"), err);
|
|
1464
|
+
return false;
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1374
1467
|
// src/utils/tracking.ts
|
|
1375
1468
|
var cachedBrowserId = null;
|
|
1376
1469
|
function getClientInfo() {
|
|
@@ -1517,7 +1610,7 @@ function getClientInfo() {
|
|
|
1517
1610
|
}
|
|
1518
1611
|
function getBrowserID(clientInfo) {
|
|
1519
1612
|
return _async_to_generator(function() {
|
|
1520
|
-
var fingerprintString, encodedData, utf8, buffer, i, hashBuffer,
|
|
1613
|
+
var _crypto_subtle, fingerprintString, encodedData, utf8, buffer, i, hashBuffer, hashHex, unused, hash, i1, char, fallbackHash, timestamp, random;
|
|
1521
1614
|
return _ts_generator(this, function(_state) {
|
|
1522
1615
|
switch(_state.label){
|
|
1523
1616
|
case 0:
|
|
@@ -1528,7 +1621,7 @@ function getBrowserID(clientInfo) {
|
|
|
1528
1621
|
];
|
|
1529
1622
|
}
|
|
1530
1623
|
fingerprintString = JSON.stringify(clientInfo);
|
|
1531
|
-
if (!(typeof crypto !== "undefined" && crypto.subtle
|
|
1624
|
+
if (!(typeof crypto !== "undefined" && ((_crypto_subtle = crypto.subtle) === null || _crypto_subtle === void 0 ? void 0 : _crypto_subtle.digest))) return [
|
|
1532
1625
|
3,
|
|
1533
1626
|
5
|
|
1534
1627
|
];
|
|
@@ -1566,8 +1659,7 @@ function getBrowserID(clientInfo) {
|
|
|
1566
1659
|
];
|
|
1567
1660
|
case 3:
|
|
1568
1661
|
hashBuffer = _state.sent();
|
|
1569
|
-
|
|
1570
|
-
hashHex = hashArray.map(function(b) {
|
|
1662
|
+
hashHex = Array.from(new Uint8Array(hashBuffer)).map(function(b) {
|
|
1571
1663
|
return b.toString(16).padStart(2, "0");
|
|
1572
1664
|
}).join("");
|
|
1573
1665
|
cachedBrowserId = hashHex;
|
|
@@ -1576,8 +1668,8 @@ function getBrowserID(clientInfo) {
|
|
|
1576
1668
|
hashHex
|
|
1577
1669
|
];
|
|
1578
1670
|
case 4:
|
|
1579
|
-
|
|
1580
|
-
console.warn("[StormcloudVideoPlayer] crypto.subtle
|
|
1671
|
+
unused = _state.sent();
|
|
1672
|
+
console.warn("[StormcloudVideoPlayer] crypto.subtle not supported, using fallback hash");
|
|
1581
1673
|
return [
|
|
1582
1674
|
3,
|
|
1583
1675
|
5
|
|
@@ -1601,177 +1693,91 @@ function getBrowserID(clientInfo) {
|
|
|
1601
1693
|
});
|
|
1602
1694
|
})();
|
|
1603
1695
|
}
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
var HEARTBEAT_URL = "".concat(PLAYER_TRACKING_BASE_URL, "/heartbeat");
|
|
1607
|
-
var IMPRESSIONS_URL = "".concat(PLAYER_TRACKING_BASE_URL, "/impressions/ingest");
|
|
1608
|
-
function buildHeaders(licenseKey) {
|
|
1609
|
-
var headers = {
|
|
1610
|
-
"Content-Type": "application/json"
|
|
1611
|
-
};
|
|
1612
|
-
if (licenseKey) {
|
|
1613
|
-
headers["Authorization"] = "Bearer ".concat(licenseKey);
|
|
1614
|
-
}
|
|
1615
|
-
return headers;
|
|
1616
|
-
}
|
|
1617
|
-
function sendTrackRequest(licenseKey, body) {
|
|
1618
|
-
return _async_to_generator(function() {
|
|
1619
|
-
var response;
|
|
1620
|
-
return _ts_generator(this, function(_state) {
|
|
1621
|
-
switch(_state.label){
|
|
1622
|
-
case 0:
|
|
1623
|
-
return [
|
|
1624
|
-
4,
|
|
1625
|
-
fetch(TRACK_URL, {
|
|
1626
|
-
method: "POST",
|
|
1627
|
-
headers: buildHeaders(licenseKey),
|
|
1628
|
-
body: JSON.stringify(body)
|
|
1629
|
-
})
|
|
1630
|
-
];
|
|
1631
|
-
case 1:
|
|
1632
|
-
response = _state.sent();
|
|
1633
|
-
if (!response.ok) {
|
|
1634
|
-
throw new Error("HTTP error! status: ".concat(response.status));
|
|
1635
|
-
}
|
|
1636
|
-
return [
|
|
1637
|
-
4,
|
|
1638
|
-
response.json()
|
|
1639
|
-
];
|
|
1640
|
-
case 2:
|
|
1641
|
-
_state.sent();
|
|
1642
|
-
return [
|
|
1643
|
-
2
|
|
1644
|
-
];
|
|
1645
|
-
}
|
|
1646
|
-
});
|
|
1647
|
-
})();
|
|
1696
|
+
function canPublish(licenseKey) {
|
|
1697
|
+
return Boolean(isMQTTEnabled() && licenseKey);
|
|
1648
1698
|
}
|
|
1649
|
-
function
|
|
1699
|
+
function buildPlayerMetricEvent() {
|
|
1650
1700
|
return _async_to_generator(function() {
|
|
1651
|
-
var
|
|
1652
|
-
return _ts_generator(this, function(_state) {
|
|
1653
|
-
switch(_state.label){
|
|
1654
|
-
case 0:
|
|
1655
|
-
return [
|
|
1656
|
-
4,
|
|
1657
|
-
fetch(url, {
|
|
1658
|
-
method: "POST",
|
|
1659
|
-
headers: buildHeaders(licenseKey),
|
|
1660
|
-
body: JSON.stringify(body)
|
|
1661
|
-
})
|
|
1662
|
-
];
|
|
1663
|
-
case 1:
|
|
1664
|
-
response = _state.sent();
|
|
1665
|
-
if (!response.ok) {
|
|
1666
|
-
throw new Error("HTTP error! status: ".concat(response.status));
|
|
1667
|
-
}
|
|
1668
|
-
return [
|
|
1669
|
-
4,
|
|
1670
|
-
response.json()
|
|
1671
|
-
];
|
|
1672
|
-
case 2:
|
|
1673
|
-
_state.sent();
|
|
1674
|
-
return [
|
|
1675
|
-
2
|
|
1676
|
-
];
|
|
1677
|
-
}
|
|
1678
|
-
});
|
|
1679
|
-
})();
|
|
1680
|
-
}
|
|
1681
|
-
function buildPlayerMetricEvent(_0) {
|
|
1682
|
-
return _async_to_generator(function(licenseKey) {
|
|
1683
|
-
var context, flags, _flags_captureAt, clientInfo, browserId, captureAt;
|
|
1701
|
+
var context, flags, _flags_captureAt, _flags_adLoaded, _flags_adDetect, clientInfo, playerId, captureAt;
|
|
1684
1702
|
var _arguments = arguments;
|
|
1685
1703
|
return _ts_generator(this, function(_state) {
|
|
1686
1704
|
switch(_state.label){
|
|
1687
1705
|
case 0:
|
|
1688
|
-
context = _arguments.length >
|
|
1706
|
+
context = _arguments.length > 0 && _arguments[0] !== void 0 ? _arguments[0] : {}, flags = _arguments.length > 1 && _arguments[1] !== void 0 ? _arguments[1] : {};
|
|
1689
1707
|
clientInfo = getClientInfo();
|
|
1690
1708
|
return [
|
|
1691
1709
|
4,
|
|
1692
1710
|
getBrowserID(clientInfo)
|
|
1693
1711
|
];
|
|
1694
1712
|
case 1:
|
|
1695
|
-
|
|
1713
|
+
playerId = _state.sent();
|
|
1696
1714
|
captureAt = (_flags_captureAt = flags.captureAt) !== null && _flags_captureAt !== void 0 ? _flags_captureAt : /* @__PURE__ */ new Date().toISOString();
|
|
1697
1715
|
return [
|
|
1698
1716
|
2,
|
|
1699
|
-
{
|
|
1700
|
-
player_id:
|
|
1701
|
-
browserId: browserId,
|
|
1717
|
+
_object_spread({
|
|
1718
|
+
player_id: playerId,
|
|
1702
1719
|
device_type: clientInfo.deviceType,
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
timestamp: captureAt
|
|
1711
|
-
}
|
|
1720
|
+
os: clientInfo.os.toLowerCase(),
|
|
1721
|
+
ad_loaded: (_flags_adLoaded = flags.adLoaded) !== null && _flags_adLoaded !== void 0 ? _flags_adLoaded : false,
|
|
1722
|
+
ad_detect: (_flags_adDetect = flags.adDetect) !== null && _flags_adDetect !== void 0 ? _flags_adDetect : false,
|
|
1723
|
+
capture_at: captureAt
|
|
1724
|
+
}, context.inputStreamType ? {
|
|
1725
|
+
input_stream_type: context.inputStreamType
|
|
1726
|
+
} : {})
|
|
1712
1727
|
];
|
|
1713
1728
|
}
|
|
1714
1729
|
});
|
|
1715
1730
|
}).apply(this, arguments);
|
|
1716
1731
|
}
|
|
1732
|
+
function publishTracking(licenseKey, channel, body) {
|
|
1733
|
+
ensureMQTTClient();
|
|
1734
|
+
publishMQTT(buildPlayerTopic(licenseKey, channel), body);
|
|
1735
|
+
}
|
|
1717
1736
|
function sendInitialTracking(_0) {
|
|
1718
1737
|
return _async_to_generator(function(licenseKey) {
|
|
1719
|
-
var context,
|
|
1738
|
+
var context, metricEvent, error;
|
|
1720
1739
|
var _arguments = arguments;
|
|
1721
1740
|
return _ts_generator(this, function(_state) {
|
|
1722
1741
|
switch(_state.label){
|
|
1723
1742
|
case 0:
|
|
1724
1743
|
context = _arguments.length > 1 && _arguments[1] !== void 0 ? _arguments[1] : {};
|
|
1744
|
+
if (!canPublish(licenseKey)) return [
|
|
1745
|
+
2
|
|
1746
|
+
];
|
|
1725
1747
|
_state.label = 1;
|
|
1726
1748
|
case 1:
|
|
1727
1749
|
_state.trys.push([
|
|
1728
1750
|
1,
|
|
1729
|
-
|
|
1751
|
+
3,
|
|
1730
1752
|
,
|
|
1731
|
-
|
|
1753
|
+
4
|
|
1732
1754
|
]);
|
|
1733
|
-
clientInfo = getClientInfo();
|
|
1734
1755
|
return [
|
|
1735
1756
|
4,
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
browserId = _state.sent();
|
|
1740
|
-
trackingData = _object_spread({
|
|
1741
|
-
browserId: browserId
|
|
1742
|
-
}, clientInfo);
|
|
1743
|
-
return [
|
|
1744
|
-
4,
|
|
1745
|
-
sendTrackRequest(licenseKey, {
|
|
1746
|
-
events: [
|
|
1747
|
-
{
|
|
1748
|
-
player_id: browserId,
|
|
1749
|
-
device_type: clientInfo.deviceType,
|
|
1750
|
-
input_stream_type: context.inputStreamType,
|
|
1751
|
-
os: clientInfo.os,
|
|
1752
|
-
ad_loaded: false,
|
|
1753
|
-
ad_detect: false,
|
|
1754
|
-
license_key: licenseKey,
|
|
1755
|
-
capture_at: /* @__PURE__ */ new Date().toISOString()
|
|
1756
|
-
}
|
|
1757
|
-
],
|
|
1758
|
-
trackingData: trackingData
|
|
1757
|
+
buildPlayerMetricEvent(context, {
|
|
1758
|
+
adLoaded: false,
|
|
1759
|
+
adDetect: false
|
|
1759
1760
|
})
|
|
1760
1761
|
];
|
|
1761
|
-
case
|
|
1762
|
-
_state.sent();
|
|
1762
|
+
case 2:
|
|
1763
|
+
metricEvent = _state.sent();
|
|
1764
|
+
publishTracking(licenseKey, "metrics", {
|
|
1765
|
+
events: [
|
|
1766
|
+
metricEvent
|
|
1767
|
+
]
|
|
1768
|
+
});
|
|
1763
1769
|
return [
|
|
1764
1770
|
3,
|
|
1765
|
-
|
|
1771
|
+
4
|
|
1766
1772
|
];
|
|
1767
|
-
case
|
|
1773
|
+
case 3:
|
|
1768
1774
|
error = _state.sent();
|
|
1769
1775
|
console.error("[StormcloudVideoPlayer] Error sending initial tracking data:", error);
|
|
1770
1776
|
return [
|
|
1771
1777
|
3,
|
|
1772
|
-
|
|
1778
|
+
4
|
|
1773
1779
|
];
|
|
1774
|
-
case
|
|
1780
|
+
case 4:
|
|
1775
1781
|
return [
|
|
1776
1782
|
2
|
|
1777
1783
|
];
|
|
@@ -1875,53 +1881,48 @@ function sendAdImpressionTracking(_0, _1) {
|
|
|
1875
1881
|
switch(_state.label){
|
|
1876
1882
|
case 0:
|
|
1877
1883
|
context = _arguments.length > 2 && _arguments[2] !== void 0 ? _arguments[2] : {};
|
|
1884
|
+
if (!canPublish(licenseKey)) return [
|
|
1885
|
+
2
|
|
1886
|
+
];
|
|
1878
1887
|
_state.label = 1;
|
|
1879
1888
|
case 1:
|
|
1880
1889
|
_state.trys.push([
|
|
1881
1890
|
1,
|
|
1882
|
-
|
|
1891
|
+
3,
|
|
1883
1892
|
,
|
|
1884
|
-
|
|
1893
|
+
4
|
|
1885
1894
|
]);
|
|
1886
1895
|
return [
|
|
1887
1896
|
4,
|
|
1888
|
-
buildPlayerMetricEvent(
|
|
1897
|
+
buildPlayerMetricEvent(context, {
|
|
1889
1898
|
captureAt: adImpressionInfo.timestamp
|
|
1890
1899
|
})
|
|
1891
1900
|
];
|
|
1892
1901
|
case 2:
|
|
1893
1902
|
metricEvent = _state.sent();
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
capture_at: adImpressionInfo.timestamp
|
|
1906
|
-
}
|
|
1907
|
-
]
|
|
1908
|
-
})
|
|
1909
|
-
])
|
|
1910
|
-
];
|
|
1911
|
-
case 3:
|
|
1912
|
-
_state.sent();
|
|
1903
|
+
publishTracking(licenseKey, "heartbeat", metricEvent);
|
|
1904
|
+
publishTracking(licenseKey, "impressions", {
|
|
1905
|
+
events: [
|
|
1906
|
+
{
|
|
1907
|
+
player_id: metricEvent.player_id,
|
|
1908
|
+
ad_played_count: 1,
|
|
1909
|
+
ad_url: adImpressionInfo.adUrl,
|
|
1910
|
+
capture_at: adImpressionInfo.timestamp
|
|
1911
|
+
}
|
|
1912
|
+
]
|
|
1913
|
+
});
|
|
1913
1914
|
return [
|
|
1914
1915
|
3,
|
|
1915
|
-
|
|
1916
|
+
4
|
|
1916
1917
|
];
|
|
1917
|
-
case
|
|
1918
|
+
case 3:
|
|
1918
1919
|
error = _state.sent();
|
|
1919
1920
|
console.error("[StormcloudVideoPlayer] Error sending ad impression tracking:", error);
|
|
1920
1921
|
return [
|
|
1921
1922
|
3,
|
|
1922
|
-
|
|
1923
|
+
4
|
|
1923
1924
|
];
|
|
1924
|
-
case
|
|
1925
|
+
case 4:
|
|
1925
1926
|
return [
|
|
1926
1927
|
2
|
|
1927
1928
|
];
|
|
@@ -1937,38 +1938,36 @@ function sendHeartbeat(_0) {
|
|
|
1937
1938
|
switch(_state.label){
|
|
1938
1939
|
case 0:
|
|
1939
1940
|
context = _arguments.length > 1 && _arguments[1] !== void 0 ? _arguments[1] : {}, flags = _arguments.length > 2 && _arguments[2] !== void 0 ? _arguments[2] : {};
|
|
1941
|
+
if (!canPublish(licenseKey)) return [
|
|
1942
|
+
2
|
|
1943
|
+
];
|
|
1940
1944
|
_state.label = 1;
|
|
1941
1945
|
case 1:
|
|
1942
1946
|
_state.trys.push([
|
|
1943
1947
|
1,
|
|
1944
|
-
|
|
1948
|
+
3,
|
|
1945
1949
|
,
|
|
1946
|
-
|
|
1950
|
+
4
|
|
1947
1951
|
]);
|
|
1948
1952
|
return [
|
|
1949
1953
|
4,
|
|
1950
|
-
buildPlayerMetricEvent(
|
|
1954
|
+
buildPlayerMetricEvent(context, flags)
|
|
1951
1955
|
];
|
|
1952
1956
|
case 2:
|
|
1953
1957
|
heartbeatData = _state.sent();
|
|
1954
|
-
|
|
1955
|
-
4,
|
|
1956
|
-
postJson(HEARTBEAT_URL, licenseKey, heartbeatData)
|
|
1957
|
-
];
|
|
1958
|
-
case 3:
|
|
1959
|
-
_state.sent();
|
|
1958
|
+
publishTracking(licenseKey, "heartbeat", heartbeatData);
|
|
1960
1959
|
return [
|
|
1961
1960
|
3,
|
|
1962
|
-
|
|
1961
|
+
4
|
|
1963
1962
|
];
|
|
1964
|
-
case
|
|
1963
|
+
case 3:
|
|
1965
1964
|
error = _state.sent();
|
|
1966
1965
|
console.error("[StormcloudVideoPlayer] Error sending heartbeat:", error);
|
|
1967
1966
|
return [
|
|
1968
1967
|
3,
|
|
1969
|
-
|
|
1968
|
+
4
|
|
1970
1969
|
];
|
|
1971
|
-
case
|
|
1970
|
+
case 4:
|
|
1972
1971
|
return [
|
|
1973
1972
|
2
|
|
1974
1973
|
];
|
|
@@ -2481,7 +2480,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
|
|
|
2481
2480
|
key: "load",
|
|
2482
2481
|
value: function load() {
|
|
2483
2482
|
return _async_to_generator(function() {
|
|
2484
|
-
var _this, _this_config_lowLatencyMode, error, _this_config_lowLatencyMode1, _this_video_play;
|
|
2483
|
+
var _this, _this_config_lowLatencyMode, error, _this_config_isLiveStream, _this_config_lowLatencyMode1, _this_video_play;
|
|
2485
2484
|
return _ts_generator(this, function(_state) {
|
|
2486
2485
|
switch(_state.label){
|
|
2487
2486
|
case 0:
|
|
@@ -2532,7 +2531,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
|
|
|
2532
2531
|
this.nativeHlsMode = true;
|
|
2533
2532
|
this.videoSrcProtection = this.config.src;
|
|
2534
2533
|
this.video.src = this.config.src;
|
|
2535
|
-
this.isLiveStream = (_this_config_lowLatencyMode1 = this.config.lowLatencyMode) !== null && _this_config_lowLatencyMode1 !== void 0 ? _this_config_lowLatencyMode1 : false;
|
|
2534
|
+
this.isLiveStream = (_this_config_isLiveStream = this.config.isLiveStream) !== null && _this_config_isLiveStream !== void 0 ? _this_config_isLiveStream : (_this_config_lowLatencyMode1 = this.config.lowLatencyMode) !== null && _this_config_lowLatencyMode1 !== void 0 ? _this_config_lowLatencyMode1 : false;
|
|
2536
2535
|
if (this.config.debugAdTiming) {
|
|
2537
2536
|
console.log("[StormcloudVideoPlayer] Using native HLS playback - VOD mode:", {
|
|
2538
2537
|
isLive: this.isLiveStream,
|
|
@@ -2583,15 +2582,15 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
|
|
|
2583
2582
|
});
|
|
2584
2583
|
this.hls.on(import_hls2.default.Events.MANIFEST_PARSED, function(_, data) {
|
|
2585
2584
|
return _async_to_generator(function() {
|
|
2586
|
-
var _ref, _this_config_minSegmentsBeforePlay, _this_hls_levels, _this_hls, prerollKey, adBehavior, minSegments, _this_video_play;
|
|
2585
|
+
var _this_config_isLiveStream, _ref, _this_config_minSegmentsBeforePlay, _this_hls_levels, _this_hls, prerollKey, adBehavior, minSegments, _this_video_play;
|
|
2587
2586
|
return _ts_generator(this, function(_state) {
|
|
2588
2587
|
switch(_state.label){
|
|
2589
2588
|
case 0:
|
|
2590
|
-
this.isLiveStream = (_ref = (_this_hls = this.hls) === null || _this_hls === void 0 ? void 0 : (_this_hls_levels = _this_hls.levels) === null || _this_hls_levels === void 0 ? void 0 : _this_hls_levels.some(function(level) {
|
|
2589
|
+
this.isLiveStream = (_this_config_isLiveStream = this.config.isLiveStream) !== null && _this_config_isLiveStream !== void 0 ? _this_config_isLiveStream : (_ref = (_this_hls = this.hls) === null || _this_hls === void 0 ? void 0 : (_this_hls_levels = _this_hls.levels) === null || _this_hls_levels === void 0 ? void 0 : _this_hls_levels.some(function(level) {
|
|
2591
2590
|
var _level_details, _level_details1;
|
|
2592
2591
|
return (level === null || level === void 0 ? void 0 : (_level_details = level.details) === null || _level_details === void 0 ? void 0 : _level_details.live) === true || (level === null || level === void 0 ? void 0 : (_level_details1 = level.details) === null || _level_details1 === void 0 ? void 0 : _level_details1.type) === "LIVE";
|
|
2593
2592
|
})) !== null && _ref !== void 0 ? _ref : false;
|
|
2594
|
-
if (!this.isLiveStream && this.vmapBreaks.length === 0 && this.apiVastTagUrl) {
|
|
2593
|
+
if (!this.isVmapEnabled() && !this.isLiveStream && this.vmapBreaks.length === 0 && this.apiVastTagUrl) {
|
|
2595
2594
|
prerollKey = "synthetic-vod-preroll";
|
|
2596
2595
|
if (!this.consumedVmapBreakIds.has(prerollKey)) {
|
|
2597
2596
|
this.vmapBreaks = [
|
|
@@ -3176,12 +3175,14 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
|
|
|
3176
3175
|
_this.palNonce.sendPlaybackStart();
|
|
3177
3176
|
}
|
|
3178
3177
|
});
|
|
3179
|
-
this.
|
|
3178
|
+
this.endedHandler = function() {
|
|
3180
3179
|
if (_this.palPlaybackStarted) {
|
|
3181
3180
|
_this.palPlaybackStarted = false;
|
|
3182
3181
|
_this.palNonce.sendPlaybackEnd();
|
|
3183
3182
|
}
|
|
3184
|
-
|
|
3183
|
+
_this.onVideoEnded();
|
|
3184
|
+
};
|
|
3185
|
+
this.video.addEventListener("ended", this.endedHandler);
|
|
3185
3186
|
this.video.addEventListener("mousedown", function(e) {
|
|
3186
3187
|
_this.palNonce.sendAdTouch(e);
|
|
3187
3188
|
});
|
|
@@ -4503,6 +4504,13 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
|
|
|
4503
4504
|
}
|
|
4504
4505
|
}
|
|
4505
4506
|
},
|
|
4507
|
+
{
|
|
4508
|
+
key: "isVmapEnabled",
|
|
4509
|
+
value: function isVmapEnabled() {
|
|
4510
|
+
var _this_config_vmapUrl;
|
|
4511
|
+
return !!(this.config.isVmap && ((_this_config_vmapUrl = this.config.vmapUrl) === null || _this_config_vmapUrl === void 0 ? void 0 : _this_config_vmapUrl.trim()));
|
|
4512
|
+
}
|
|
4513
|
+
},
|
|
4506
4514
|
{
|
|
4507
4515
|
key: "fetchAdConfiguration",
|
|
4508
4516
|
value: function fetchAdConfiguration() {
|
|
@@ -4511,7 +4519,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
|
|
|
4511
4519
|
return _ts_generator(this, function(_state) {
|
|
4512
4520
|
switch(_state.label){
|
|
4513
4521
|
case 0:
|
|
4514
|
-
if (!this.
|
|
4522
|
+
if (!this.isVmapEnabled()) return [
|
|
4515
4523
|
3,
|
|
4516
4524
|
2
|
|
4517
4525
|
];
|
|
@@ -4521,7 +4529,12 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
|
|
|
4521
4529
|
];
|
|
4522
4530
|
case 1:
|
|
4523
4531
|
_state.sent();
|
|
4524
|
-
|
|
4532
|
+
if (this.config.debugAdTiming) {
|
|
4533
|
+
console.log("[StormcloudVideoPlayer] VMAP mode enabled");
|
|
4534
|
+
}
|
|
4535
|
+
return [
|
|
4536
|
+
2
|
|
4537
|
+
];
|
|
4525
4538
|
case 2:
|
|
4526
4539
|
vastMode = this.config.vastMode || "default";
|
|
4527
4540
|
if (this.config.debugAdTiming) {
|
|
@@ -4689,7 +4702,16 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
|
|
|
4689
4702
|
}
|
|
4690
4703
|
return [];
|
|
4691
4704
|
}
|
|
4692
|
-
var
|
|
4705
|
+
var VMAP_NS = "http://www.iab.net/videosuite/vmap";
|
|
4706
|
+
var adBreakNodes = Array.from(doc.getElementsByTagNameNS(VMAP_NS, "AdBreak"));
|
|
4707
|
+
if (adBreakNodes.length === 0) {
|
|
4708
|
+
adBreakNodes = Array.from(doc.querySelectorAll("AdBreak, vmap\\:AdBreak"));
|
|
4709
|
+
}
|
|
4710
|
+
if (adBreakNodes.length === 0) {
|
|
4711
|
+
adBreakNodes = Array.from(doc.getElementsByTagName("*")).filter(function(el) {
|
|
4712
|
+
return el.localName === "AdBreak";
|
|
4713
|
+
});
|
|
4714
|
+
}
|
|
4693
4715
|
var parsed = [];
|
|
4694
4716
|
adBreakNodes.forEach(function(node, index) {
|
|
4695
4717
|
var timeOffsetRaw = (node.getAttribute("timeOffset") || "").trim();
|
|
@@ -4697,7 +4719,11 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
|
|
|
4697
4719
|
if (startTimeMs == null) {
|
|
4698
4720
|
return;
|
|
4699
4721
|
}
|
|
4700
|
-
var adTagNode = node.
|
|
4722
|
+
var adTagNode = node.getElementsByTagNameNS(VMAP_NS, "AdTagURI")[0];
|
|
4723
|
+
if (!adTagNode) {
|
|
4724
|
+
var _node_querySelector;
|
|
4725
|
+
adTagNode = (_node_querySelector = node.querySelector("AdTagURI, vmap\\:AdTagURI")) !== null && _node_querySelector !== void 0 ? _node_querySelector : void 0;
|
|
4726
|
+
}
|
|
4701
4727
|
var adTagUrl = ((adTagNode === null || adTagNode === void 0 ? void 0 : adTagNode.textContent) || "").trim();
|
|
4702
4728
|
if (!adTagUrl) {
|
|
4703
4729
|
return;
|
|
@@ -6254,23 +6280,49 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
|
|
|
6254
6280
|
key: "onTimeUpdate",
|
|
6255
6281
|
value: function onTimeUpdate(currentTimeSec) {
|
|
6256
6282
|
var _this = this;
|
|
6283
|
+
if (!this.isVmapEnabled() || this.vmapBreaks.length === 0) {
|
|
6284
|
+
return;
|
|
6285
|
+
}
|
|
6257
6286
|
if (this.adPlayer.isAdPlaying() || this.inAdBreak) return;
|
|
6258
6287
|
var nowMs = currentTimeSec * 1e3;
|
|
6259
6288
|
var breakToPlay = this.findBreakForTime(nowMs);
|
|
6260
6289
|
if (breakToPlay) {
|
|
6261
|
-
void this.
|
|
6290
|
+
void this.handleVmapAdBreak(breakToPlay, nowMs).catch(function(error) {
|
|
6291
|
+
if (_this.config.debugAdTiming) {
|
|
6292
|
+
console.warn("[StormcloudVideoPlayer] VMAP ad break failed gracefully:", error);
|
|
6293
|
+
}
|
|
6294
|
+
});
|
|
6295
|
+
}
|
|
6296
|
+
}
|
|
6297
|
+
},
|
|
6298
|
+
{
|
|
6299
|
+
key: "onVideoEnded",
|
|
6300
|
+
value: function onVideoEnded() {
|
|
6301
|
+
var _this = this;
|
|
6302
|
+
if (!this.isVmapEnabled() || this.vmapBreaks.length === 0) {
|
|
6303
|
+
return;
|
|
6304
|
+
}
|
|
6305
|
+
if (this.adPlayer.isAdPlaying() || this.inAdBreak) {
|
|
6306
|
+
return;
|
|
6307
|
+
}
|
|
6308
|
+
var durationMs = Number.isFinite(this.video.duration) ? Math.floor(this.video.duration * 1e3) : 0;
|
|
6309
|
+
var postroll = this.vmapBreaks.find(function(b) {
|
|
6310
|
+
return b.startTimeMs === -1 && !_this.consumedVmapBreakIds.has(_this.getAdBreakKey(b));
|
|
6311
|
+
});
|
|
6312
|
+
if (postroll) {
|
|
6313
|
+
void this.handleVmapAdBreak(postroll, durationMs).catch(function(error) {
|
|
6262
6314
|
if (_this.config.debugAdTiming) {
|
|
6263
|
-
console.warn("[StormcloudVideoPlayer]
|
|
6315
|
+
console.warn("[StormcloudVideoPlayer] VMAP post-roll failed gracefully:", error);
|
|
6264
6316
|
}
|
|
6265
6317
|
});
|
|
6266
6318
|
}
|
|
6267
6319
|
}
|
|
6268
6320
|
},
|
|
6269
6321
|
{
|
|
6270
|
-
key: "
|
|
6271
|
-
value: function
|
|
6322
|
+
key: "handleVmapAdBreak",
|
|
6323
|
+
value: function handleVmapAdBreak(adBreak, nowMs) {
|
|
6272
6324
|
return _async_to_generator(function() {
|
|
6273
|
-
var _adBreak_durationMs,
|
|
6325
|
+
var _adBreak_durationMs, key, breakStartMs, durationMs, endMs, inWindow, tags, first, rest, error;
|
|
6274
6326
|
return _ts_generator(this, function(_state) {
|
|
6275
6327
|
switch(_state.label){
|
|
6276
6328
|
case 0:
|
|
@@ -6288,25 +6340,28 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
|
|
|
6288
6340
|
}
|
|
6289
6341
|
durationMs = (_adBreak_durationMs = adBreak.durationMs) !== null && _adBreak_durationMs !== void 0 ? _adBreak_durationMs : 0;
|
|
6290
6342
|
endMs = breakStartMs + durationMs;
|
|
6291
|
-
|
|
6292
|
-
inWindow = durationMs > 0 ? nowMs > breakStartMs && nowMs < endMs : nowMs + tol >= breakStartMs;
|
|
6343
|
+
inWindow = durationMs > 0 ? nowMs >= breakStartMs && nowMs < endMs : nowMs >= breakStartMs;
|
|
6293
6344
|
if (!inWindow) return [
|
|
6294
6345
|
3,
|
|
6295
6346
|
4
|
|
6296
6347
|
];
|
|
6297
6348
|
this.consumedVmapBreakIds.add(key);
|
|
6298
|
-
|
|
6299
|
-
|
|
6300
|
-
|
|
6301
|
-
|
|
6302
|
-
|
|
6303
|
-
|
|
6304
|
-
4
|
|
6305
|
-
];
|
|
6349
|
+
tags = this.selectVastTagsForBreak(adBreak);
|
|
6350
|
+
if (!tags || tags.length === 0) {
|
|
6351
|
+
return [
|
|
6352
|
+
2
|
|
6353
|
+
];
|
|
6354
|
+
}
|
|
6306
6355
|
first = tags[0];
|
|
6307
6356
|
rest = tags.slice(1);
|
|
6308
6357
|
this.adPodQueue = rest;
|
|
6309
6358
|
this.adPlayer.updateOriginalMutedState(this.video.muted, this.video.volume);
|
|
6359
|
+
this.showAds = true;
|
|
6360
|
+
this.inAdBreak = true;
|
|
6361
|
+
this.currentAdBreakStartWallClockMs = Date.now();
|
|
6362
|
+
if (!this.video.paused) {
|
|
6363
|
+
this.video.pause();
|
|
6364
|
+
}
|
|
6310
6365
|
_state.label = 1;
|
|
6311
6366
|
case 1:
|
|
6312
6367
|
_state.trys.push([
|
|
@@ -6321,10 +6376,6 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
|
|
|
6321
6376
|
];
|
|
6322
6377
|
case 2:
|
|
6323
6378
|
_state.sent();
|
|
6324
|
-
this.inAdBreak = true;
|
|
6325
|
-
this.expectedAdBreakDurationMs = remainingMs;
|
|
6326
|
-
this.currentAdBreakStartWallClockMs = Date.now();
|
|
6327
|
-
this.scheduleAdStopCountdown(remainingMs);
|
|
6328
6379
|
return [
|
|
6329
6380
|
3,
|
|
6330
6381
|
4
|
|
@@ -6332,8 +6383,10 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
|
|
|
6332
6383
|
case 3:
|
|
6333
6384
|
error = _state.sent();
|
|
6334
6385
|
this.adPodQueue = [];
|
|
6386
|
+
this.inAdBreak = false;
|
|
6387
|
+
this.showAds = false;
|
|
6335
6388
|
if (this.config.debugAdTiming) {
|
|
6336
|
-
console.warn("[StormcloudVideoPlayer]
|
|
6389
|
+
console.warn("[StormcloudVideoPlayer] VMAP ad request failed:", error);
|
|
6337
6390
|
}
|
|
6338
6391
|
return [
|
|
6339
6392
|
3,
|
|
@@ -7045,9 +7098,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
|
|
|
7045
7098
|
{
|
|
7046
7099
|
key: "findBreakForTime",
|
|
7047
7100
|
value: function findBreakForTime(nowMs) {
|
|
7048
|
-
var _this_config_driftToleranceMs;
|
|
7049
7101
|
var schedule = this.vmapBreaks;
|
|
7050
|
-
var tol = (_this_config_driftToleranceMs = this.config.driftToleranceMs) !== null && _this_config_driftToleranceMs !== void 0 ? _this_config_driftToleranceMs : 1e3;
|
|
7051
7102
|
var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
|
|
7052
7103
|
try {
|
|
7053
7104
|
for(var _iterator = schedule[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
|
|
@@ -7059,9 +7110,14 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
|
|
|
7059
7110
|
if (breakStartMs == null) {
|
|
7060
7111
|
continue;
|
|
7061
7112
|
}
|
|
7062
|
-
|
|
7063
|
-
|
|
7064
|
-
|
|
7113
|
+
if (b.durationMs) {
|
|
7114
|
+
var end = breakStartMs + b.durationMs;
|
|
7115
|
+
if (nowMs >= breakStartMs && nowMs < end) {
|
|
7116
|
+
return b;
|
|
7117
|
+
}
|
|
7118
|
+
continue;
|
|
7119
|
+
}
|
|
7120
|
+
if (nowMs >= breakStartMs) {
|
|
7065
7121
|
return b;
|
|
7066
7122
|
}
|
|
7067
7123
|
}
|
|
@@ -7269,6 +7325,10 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
|
|
|
7269
7325
|
this.video.removeEventListener("timeupdate", this.timeUpdateHandler);
|
|
7270
7326
|
delete this.timeUpdateHandler;
|
|
7271
7327
|
}
|
|
7328
|
+
if (this.endedHandler) {
|
|
7329
|
+
this.video.removeEventListener("ended", this.endedHandler);
|
|
7330
|
+
delete this.endedHandler;
|
|
7331
|
+
}
|
|
7272
7332
|
if (this.emptiedHandler) {
|
|
7273
7333
|
this.video.removeEventListener("emptied", this.emptiedHandler);
|
|
7274
7334
|
delete this.emptiedHandler;
|
|
@@ -7297,7 +7357,9 @@ var import_jsx_runtime = require("react/jsx-runtime");
|
|
|
7297
7357
|
var CRITICAL_PROPS = [
|
|
7298
7358
|
"src",
|
|
7299
7359
|
"allowNativeHls",
|
|
7360
|
+
"isLiveStream",
|
|
7300
7361
|
"licenseKey",
|
|
7362
|
+
"isVmap",
|
|
7301
7363
|
"vmapUrl",
|
|
7302
7364
|
"lowLatencyMode",
|
|
7303
7365
|
"driftToleranceMs",
|
|
@@ -7306,12 +7368,13 @@ var CRITICAL_PROPS = [
|
|
|
7306
7368
|
var CONTROLS_HIDE_DELAY = 3e3;
|
|
7307
7369
|
var DEFAULT_PLAYER_ASPECT_RATIO = 16 / 9;
|
|
7308
7370
|
var StormcloudVideoPlayerComponent = import_react.default.memo(function(props) {
|
|
7309
|
-
var src = props.src, autoplay = props.autoplay, muted = props.muted, lowLatencyMode = props.lowLatencyMode, allowNativeHls = props.allowNativeHls, driftToleranceMs = props.driftToleranceMs, immediateManifestAds = props.immediateManifestAds, debugAdTiming = props.debugAdTiming, showCustomControls = props.showCustomControls, hideLoadingIndicator = props.hideLoadingIndicator, onVolumeToggle = props.onVolumeToggle, onFullscreenToggle = props.onFullscreenToggle, onControlClick = props.onControlClick, onReady = props.onReady, wrapperClassName = props.wrapperClassName, wrapperStyle = props.wrapperStyle, className = props.className, style = props.style, controls = props.controls, playsInline = props.playsInline, preload = props.preload, poster = props.poster, children = props.children, licenseKey = props.licenseKey, vastMode = props.vastMode, vastTagUrl = props.vastTagUrl, vmapUrl = props.vmapUrl, minSegmentsBeforePlay = props.minSegmentsBeforePlay, restVideoAttrs = _object_without_properties(props, [
|
|
7371
|
+
var src = props.src, autoplay = props.autoplay, muted = props.muted, lowLatencyMode = props.lowLatencyMode, allowNativeHls = props.allowNativeHls, isLiveStream = props.isLiveStream, driftToleranceMs = props.driftToleranceMs, immediateManifestAds = props.immediateManifestAds, debugAdTiming = props.debugAdTiming, showCustomControls = props.showCustomControls, hideLoadingIndicator = props.hideLoadingIndicator, onVolumeToggle = props.onVolumeToggle, onFullscreenToggle = props.onFullscreenToggle, onControlClick = props.onControlClick, onReady = props.onReady, wrapperClassName = props.wrapperClassName, wrapperStyle = props.wrapperStyle, className = props.className, style = props.style, controls = props.controls, playsInline = props.playsInline, preload = props.preload, poster = props.poster, children = props.children, licenseKey = props.licenseKey, vastMode = props.vastMode, vastTagUrl = props.vastTagUrl, isVmap = props.isVmap, vmapUrl = props.vmapUrl, minSegmentsBeforePlay = props.minSegmentsBeforePlay, restVideoAttrs = _object_without_properties(props, [
|
|
7310
7372
|
"src",
|
|
7311
7373
|
"autoplay",
|
|
7312
7374
|
"muted",
|
|
7313
7375
|
"lowLatencyMode",
|
|
7314
7376
|
"allowNativeHls",
|
|
7377
|
+
"isLiveStream",
|
|
7315
7378
|
"driftToleranceMs",
|
|
7316
7379
|
"immediateManifestAds",
|
|
7317
7380
|
"debugAdTiming",
|
|
@@ -7333,6 +7396,7 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(function(props) {
|
|
|
7333
7396
|
"licenseKey",
|
|
7334
7397
|
"vastMode",
|
|
7335
7398
|
"vastTagUrl",
|
|
7399
|
+
"isVmap",
|
|
7336
7400
|
"vmapUrl",
|
|
7337
7401
|
"minSegmentsBeforePlay"
|
|
7338
7402
|
]);
|
|
@@ -7465,7 +7529,7 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(function(props) {
|
|
|
7465
7529
|
setShowSpeedMenu(false);
|
|
7466
7530
|
};
|
|
7467
7531
|
var isHlsStream = (src === null || src === void 0 ? void 0 : src.toLowerCase().includes(".m3u8")) || (src === null || src === void 0 ? void 0 : src.toLowerCase().includes("/hls/"));
|
|
7468
|
-
var shouldShowEnhancedControls = showCustomControls && (isHlsStream ? allowNativeHls : true);
|
|
7532
|
+
var shouldShowEnhancedControls = showCustomControls && (isHlsStream ? allowNativeHls || isLiveStream === false : true);
|
|
7469
7533
|
var criticalPropsKey = (0, import_react.useMemo)(function() {
|
|
7470
7534
|
return CRITICAL_PROPS.map(function(prop) {
|
|
7471
7535
|
return "".concat(prop, ":").concat(props[prop]);
|
|
@@ -7473,7 +7537,9 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(function(props) {
|
|
|
7473
7537
|
}, [
|
|
7474
7538
|
src,
|
|
7475
7539
|
allowNativeHls,
|
|
7540
|
+
isLiveStream,
|
|
7476
7541
|
licenseKey,
|
|
7542
|
+
isVmap,
|
|
7477
7543
|
vmapUrl,
|
|
7478
7544
|
lowLatencyMode,
|
|
7479
7545
|
driftToleranceMs,
|
|
@@ -7507,6 +7573,7 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(function(props) {
|
|
|
7507
7573
|
if (muted !== void 0) cfg.muted = muted;
|
|
7508
7574
|
if (lowLatencyMode !== void 0) cfg.lowLatencyMode = lowLatencyMode;
|
|
7509
7575
|
if (allowNativeHls !== void 0) cfg.allowNativeHls = allowNativeHls;
|
|
7576
|
+
if (isLiveStream !== void 0) cfg.isLiveStream = isLiveStream;
|
|
7510
7577
|
if (driftToleranceMs !== void 0) cfg.driftToleranceMs = driftToleranceMs;
|
|
7511
7578
|
if (immediateManifestAds !== void 0) cfg.immediateManifestAds = immediateManifestAds;
|
|
7512
7579
|
if (debugAdTiming !== void 0) cfg.debugAdTiming = debugAdTiming;
|
|
@@ -7517,6 +7584,7 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(function(props) {
|
|
|
7517
7584
|
if (licenseKey !== void 0) cfg.licenseKey = licenseKey;
|
|
7518
7585
|
if (vastMode !== void 0) cfg.vastMode = vastMode;
|
|
7519
7586
|
if (vastTagUrl !== void 0) cfg.vastTagUrl = vastTagUrl;
|
|
7587
|
+
if (isVmap !== void 0) cfg.isVmap = isVmap;
|
|
7520
7588
|
if (vmapUrl !== void 0) cfg.vmapUrl = vmapUrl;
|
|
7521
7589
|
if (minSegmentsBeforePlay !== void 0) cfg.minSegmentsBeforePlay = minSegmentsBeforePlay;
|
|
7522
7590
|
var player = new StormcloudVideoPlayer(cfg);
|
|
@@ -8345,161 +8413,202 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(function(props) {
|
|
|
8345
8413
|
]
|
|
8346
8414
|
})
|
|
8347
8415
|
]
|
|
8348
|
-
}) : showCustomControls && !showLicenseWarning && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
8349
|
-
className: "sc-controls-bar",
|
|
8350
|
-
style: {
|
|
8351
|
-
position: "absolute",
|
|
8352
|
-
bottom: "".concat(10 * responsiveScale, "px"),
|
|
8353
|
-
right: "".concat(10 * responsiveScale, "px"),
|
|
8354
|
-
display: "flex",
|
|
8355
|
-
flexDirection: isPortrait ? "column" : "row",
|
|
8356
|
-
gap: "".concat(8 * responsiveScale, "px"),
|
|
8357
|
-
zIndex: 10,
|
|
8358
|
-
opacity: controlsVisible ? 1 : 0,
|
|
8359
|
-
transform: controlsVisible ? "translateY(0)" : "translateY(4px)",
|
|
8360
|
-
pointerEvents: controlsVisible ? "auto" : "none"
|
|
8361
|
-
},
|
|
8416
|
+
}) : showCustomControls && !showLicenseWarning && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, {
|
|
8362
8417
|
children: [
|
|
8363
8418
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
8364
8419
|
style: {
|
|
8420
|
+
position: "absolute",
|
|
8421
|
+
top: "".concat(10 * responsiveScale, "px"),
|
|
8422
|
+
left: "".concat(10 * responsiveScale, "px"),
|
|
8365
8423
|
display: "flex",
|
|
8366
8424
|
alignItems: "center",
|
|
8367
|
-
|
|
8368
|
-
|
|
8369
|
-
|
|
8370
|
-
|
|
8371
|
-
},
|
|
8372
|
-
onMouseEnter: function onMouseEnter() {
|
|
8373
|
-
return setShowVolumeSlider(true);
|
|
8425
|
+
gap: "6px",
|
|
8426
|
+
zIndex: 10,
|
|
8427
|
+
opacity: controlsVisible ? 1 : 0,
|
|
8428
|
+
transition: "opacity 0.35s ease"
|
|
8374
8429
|
},
|
|
8375
|
-
|
|
8376
|
-
|
|
8430
|
+
children: [
|
|
8431
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
8432
|
+
style: {
|
|
8433
|
+
width: "8px",
|
|
8434
|
+
height: "8px",
|
|
8435
|
+
borderRadius: "50%",
|
|
8436
|
+
background: "#ff3b30",
|
|
8437
|
+
animation: "sc-pulse 1.5s ease-in-out infinite",
|
|
8438
|
+
flexShrink: 0
|
|
8439
|
+
}
|
|
8440
|
+
}),
|
|
8441
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
8442
|
+
style: {
|
|
8443
|
+
fontSize: "".concat(12 * responsiveScale, "px"),
|
|
8444
|
+
fontFamily: "'SF Pro Display', 'Segoe UI', Arial, sans-serif",
|
|
8445
|
+
fontWeight: 700,
|
|
8446
|
+
letterSpacing: "0.08em",
|
|
8447
|
+
color: "#fff",
|
|
8448
|
+
textShadow: "0 1px 3px rgba(0,0,0,0.6)",
|
|
8449
|
+
userSelect: "none"
|
|
8450
|
+
},
|
|
8451
|
+
children: "LIVE"
|
|
8452
|
+
})
|
|
8453
|
+
]
|
|
8454
|
+
}),
|
|
8455
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
8456
|
+
className: "sc-controls-bar",
|
|
8457
|
+
style: {
|
|
8458
|
+
position: "absolute",
|
|
8459
|
+
bottom: "".concat(10 * responsiveScale, "px"),
|
|
8460
|
+
right: "".concat(10 * responsiveScale, "px"),
|
|
8461
|
+
display: "flex",
|
|
8462
|
+
flexDirection: isPortrait ? "column" : "row",
|
|
8463
|
+
gap: "".concat(8 * responsiveScale, "px"),
|
|
8464
|
+
zIndex: 10,
|
|
8465
|
+
opacity: controlsVisible ? 1 : 0,
|
|
8466
|
+
transform: controlsVisible ? "translateY(0)" : "translateY(4px)",
|
|
8467
|
+
pointerEvents: controlsVisible ? "auto" : "none"
|
|
8377
8468
|
},
|
|
8378
8469
|
children: [
|
|
8470
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
8471
|
+
style: {
|
|
8472
|
+
display: "flex",
|
|
8473
|
+
alignItems: "center",
|
|
8474
|
+
background: "rgba(0, 0, 0, 0.6)",
|
|
8475
|
+
borderRadius: "".concat(18 * responsiveScale, "px"),
|
|
8476
|
+
padding: "2px",
|
|
8477
|
+
paddingRight: "".concat(8 * responsiveScale, "px")
|
|
8478
|
+
},
|
|
8479
|
+
onMouseEnter: function onMouseEnter() {
|
|
8480
|
+
return setShowVolumeSlider(true);
|
|
8481
|
+
},
|
|
8482
|
+
onMouseLeave: function onMouseLeave() {
|
|
8483
|
+
return setShowVolumeSlider(false);
|
|
8484
|
+
},
|
|
8485
|
+
children: [
|
|
8486
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
|
|
8487
|
+
className: "sc-ctrl-btn",
|
|
8488
|
+
onClick: function onClick() {
|
|
8489
|
+
if (playerRef.current) playerRef.current.toggleMute();
|
|
8490
|
+
onVolumeToggle === null || onVolumeToggle === void 0 ? void 0 : onVolumeToggle();
|
|
8491
|
+
resetControlsTimer();
|
|
8492
|
+
},
|
|
8493
|
+
style: {
|
|
8494
|
+
padding: "".concat(8 * responsiveScale, "px"),
|
|
8495
|
+
borderRadius: "50%",
|
|
8496
|
+
minWidth: "".concat(36 * responsiveScale, "px"),
|
|
8497
|
+
minHeight: "".concat(36 * responsiveScale, "px")
|
|
8498
|
+
},
|
|
8499
|
+
title: isMuted ? "Unmute" : "Mute",
|
|
8500
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(VolumeIcon, {
|
|
8501
|
+
size: Math.max(14, 18 * responsiveScale)
|
|
8502
|
+
})
|
|
8503
|
+
}),
|
|
8504
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
8505
|
+
style: {
|
|
8506
|
+
width: showVolumeSlider ? "".concat(68 * responsiveScale, "px") : "0px",
|
|
8507
|
+
overflow: "hidden",
|
|
8508
|
+
transition: "width 0.2s cubic-bezier(0.4, 0, 0.2, 1)",
|
|
8509
|
+
display: "flex",
|
|
8510
|
+
alignItems: "center",
|
|
8511
|
+
paddingLeft: showVolumeSlider ? "".concat(3 * responsiveScale, "px") : "0",
|
|
8512
|
+
paddingRight: showVolumeSlider ? "".concat(10 * responsiveScale, "px") : "0"
|
|
8513
|
+
},
|
|
8514
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
8515
|
+
style: {
|
|
8516
|
+
position: "relative",
|
|
8517
|
+
width: "".concat(56 * responsiveScale, "px"),
|
|
8518
|
+
height: "3px",
|
|
8519
|
+
cursor: "pointer",
|
|
8520
|
+
borderRadius: "1.5px"
|
|
8521
|
+
},
|
|
8522
|
+
onMouseDown: function onMouseDown(e) {
|
|
8523
|
+
e.preventDefault();
|
|
8524
|
+
var el = e.currentTarget;
|
|
8525
|
+
var move = function move(ev) {
|
|
8526
|
+
var r2 = el.getBoundingClientRect();
|
|
8527
|
+
handleVolumeChange(Math.max(0, Math.min(1, (ev.clientX - r2.left) / r2.width)));
|
|
8528
|
+
};
|
|
8529
|
+
var up = function up1() {
|
|
8530
|
+
document.removeEventListener("mousemove", move);
|
|
8531
|
+
document.removeEventListener("mouseup", up);
|
|
8532
|
+
};
|
|
8533
|
+
document.addEventListener("mousemove", move);
|
|
8534
|
+
document.addEventListener("mouseup", up);
|
|
8535
|
+
var r = el.getBoundingClientRect();
|
|
8536
|
+
handleVolumeChange(Math.max(0, Math.min(1, (e.clientX - r.left) / r.width)));
|
|
8537
|
+
},
|
|
8538
|
+
onClick: function onClick(e) {
|
|
8539
|
+
e.stopPropagation();
|
|
8540
|
+
var r = e.currentTarget.getBoundingClientRect();
|
|
8541
|
+
handleVolumeChange(Math.max(0, Math.min(1, (e.clientX - r.left) / r.width)));
|
|
8542
|
+
},
|
|
8543
|
+
children: [
|
|
8544
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
8545
|
+
style: {
|
|
8546
|
+
position: "absolute",
|
|
8547
|
+
inset: 0,
|
|
8548
|
+
background: "rgba(255, 255, 255, 0.2)",
|
|
8549
|
+
borderRadius: "1.5px"
|
|
8550
|
+
}
|
|
8551
|
+
}),
|
|
8552
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
8553
|
+
style: {
|
|
8554
|
+
position: "absolute",
|
|
8555
|
+
top: 0,
|
|
8556
|
+
left: 0,
|
|
8557
|
+
bottom: 0,
|
|
8558
|
+
width: "".concat((isMuted ? 0 : volume) * 100, "%"),
|
|
8559
|
+
background: "#fff",
|
|
8560
|
+
borderRadius: "1.5px",
|
|
8561
|
+
transition: "width 0.1s ease-out"
|
|
8562
|
+
}
|
|
8563
|
+
}),
|
|
8564
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
8565
|
+
style: {
|
|
8566
|
+
position: "absolute",
|
|
8567
|
+
top: "50%",
|
|
8568
|
+
left: "".concat((isMuted ? 0 : volume) * 100, "%"),
|
|
8569
|
+
transform: "translate(-50%, -50%)",
|
|
8570
|
+
width: "12px",
|
|
8571
|
+
height: "12px",
|
|
8572
|
+
background: "#fff",
|
|
8573
|
+
borderRadius: "50%",
|
|
8574
|
+
boxShadow: "0 0 3px rgba(0, 0, 0, 0.3)",
|
|
8575
|
+
transition: "left 0.1s ease-out"
|
|
8576
|
+
}
|
|
8577
|
+
})
|
|
8578
|
+
]
|
|
8579
|
+
})
|
|
8580
|
+
})
|
|
8581
|
+
]
|
|
8582
|
+
}),
|
|
8379
8583
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
|
|
8380
8584
|
className: "sc-ctrl-btn",
|
|
8381
8585
|
onClick: function onClick() {
|
|
8382
|
-
if (
|
|
8383
|
-
|
|
8586
|
+
if (onFullscreenToggle) {
|
|
8587
|
+
onFullscreenToggle();
|
|
8588
|
+
} else if (wrapperRef.current) {
|
|
8589
|
+
if (!document.fullscreenElement) {
|
|
8590
|
+
wrapperRef.current.requestFullscreen().catch(function() {});
|
|
8591
|
+
} else {
|
|
8592
|
+
document.exitFullscreen().catch(function() {});
|
|
8593
|
+
}
|
|
8594
|
+
}
|
|
8384
8595
|
resetControlsTimer();
|
|
8385
8596
|
},
|
|
8386
8597
|
style: {
|
|
8387
8598
|
padding: "".concat(8 * responsiveScale, "px"),
|
|
8388
8599
|
borderRadius: "50%",
|
|
8389
8600
|
minWidth: "".concat(36 * responsiveScale, "px"),
|
|
8390
|
-
minHeight: "".concat(36 * responsiveScale, "px")
|
|
8601
|
+
minHeight: "".concat(36 * responsiveScale, "px"),
|
|
8602
|
+
background: "rgba(0, 0, 0, 0.6)"
|
|
8391
8603
|
},
|
|
8392
|
-
title:
|
|
8393
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
8604
|
+
title: isFullscreen ? "Exit Fullscreen" : "Enter Fullscreen",
|
|
8605
|
+
children: isFullscreen ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_fa.FaCompress, {
|
|
8606
|
+
size: Math.max(14, 18 * responsiveScale)
|
|
8607
|
+
}) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_fa.FaExpand, {
|
|
8394
8608
|
size: Math.max(14, 18 * responsiveScale)
|
|
8395
|
-
})
|
|
8396
|
-
}),
|
|
8397
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
8398
|
-
style: {
|
|
8399
|
-
width: showVolumeSlider ? "".concat(68 * responsiveScale, "px") : "0px",
|
|
8400
|
-
overflow: "hidden",
|
|
8401
|
-
transition: "width 0.2s cubic-bezier(0.4, 0, 0.2, 1)",
|
|
8402
|
-
display: "flex",
|
|
8403
|
-
alignItems: "center",
|
|
8404
|
-
paddingLeft: showVolumeSlider ? "".concat(3 * responsiveScale, "px") : "0",
|
|
8405
|
-
paddingRight: showVolumeSlider ? "".concat(10 * responsiveScale, "px") : "0"
|
|
8406
|
-
},
|
|
8407
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
8408
|
-
style: {
|
|
8409
|
-
position: "relative",
|
|
8410
|
-
width: "".concat(56 * responsiveScale, "px"),
|
|
8411
|
-
height: "3px",
|
|
8412
|
-
cursor: "pointer",
|
|
8413
|
-
borderRadius: "1.5px"
|
|
8414
|
-
},
|
|
8415
|
-
onMouseDown: function onMouseDown(e) {
|
|
8416
|
-
e.preventDefault();
|
|
8417
|
-
var el = e.currentTarget;
|
|
8418
|
-
var move = function move(ev) {
|
|
8419
|
-
var r2 = el.getBoundingClientRect();
|
|
8420
|
-
handleVolumeChange(Math.max(0, Math.min(1, (ev.clientX - r2.left) / r2.width)));
|
|
8421
|
-
};
|
|
8422
|
-
var up = function up1() {
|
|
8423
|
-
document.removeEventListener("mousemove", move);
|
|
8424
|
-
document.removeEventListener("mouseup", up);
|
|
8425
|
-
};
|
|
8426
|
-
document.addEventListener("mousemove", move);
|
|
8427
|
-
document.addEventListener("mouseup", up);
|
|
8428
|
-
var r = el.getBoundingClientRect();
|
|
8429
|
-
handleVolumeChange(Math.max(0, Math.min(1, (e.clientX - r.left) / r.width)));
|
|
8430
|
-
},
|
|
8431
|
-
onClick: function onClick(e) {
|
|
8432
|
-
e.stopPropagation();
|
|
8433
|
-
var r = e.currentTarget.getBoundingClientRect();
|
|
8434
|
-
handleVolumeChange(Math.max(0, Math.min(1, (e.clientX - r.left) / r.width)));
|
|
8435
|
-
},
|
|
8436
|
-
children: [
|
|
8437
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
8438
|
-
style: {
|
|
8439
|
-
position: "absolute",
|
|
8440
|
-
inset: 0,
|
|
8441
|
-
background: "rgba(255, 255, 255, 0.2)",
|
|
8442
|
-
borderRadius: "1.5px"
|
|
8443
|
-
}
|
|
8444
|
-
}),
|
|
8445
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
8446
|
-
style: {
|
|
8447
|
-
position: "absolute",
|
|
8448
|
-
top: 0,
|
|
8449
|
-
left: 0,
|
|
8450
|
-
bottom: 0,
|
|
8451
|
-
width: "".concat((isMuted ? 0 : volume) * 100, "%"),
|
|
8452
|
-
background: "#fff",
|
|
8453
|
-
borderRadius: "1.5px",
|
|
8454
|
-
transition: "width 0.1s ease-out"
|
|
8455
|
-
}
|
|
8456
|
-
}),
|
|
8457
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
8458
|
-
style: {
|
|
8459
|
-
position: "absolute",
|
|
8460
|
-
top: "50%",
|
|
8461
|
-
left: "".concat((isMuted ? 0 : volume) * 100, "%"),
|
|
8462
|
-
transform: "translate(-50%, -50%)",
|
|
8463
|
-
width: "12px",
|
|
8464
|
-
height: "12px",
|
|
8465
|
-
background: "#fff",
|
|
8466
|
-
borderRadius: "50%",
|
|
8467
|
-
boxShadow: "0 0 3px rgba(0, 0, 0, 0.3)",
|
|
8468
|
-
transition: "left 0.1s ease-out"
|
|
8469
|
-
}
|
|
8470
|
-
})
|
|
8471
|
-
]
|
|
8472
8609
|
})
|
|
8473
8610
|
})
|
|
8474
8611
|
]
|
|
8475
|
-
}),
|
|
8476
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
|
|
8477
|
-
className: "sc-ctrl-btn",
|
|
8478
|
-
onClick: function onClick() {
|
|
8479
|
-
if (onFullscreenToggle) {
|
|
8480
|
-
onFullscreenToggle();
|
|
8481
|
-
} else if (wrapperRef.current) {
|
|
8482
|
-
if (!document.fullscreenElement) {
|
|
8483
|
-
wrapperRef.current.requestFullscreen().catch(function() {});
|
|
8484
|
-
} else {
|
|
8485
|
-
document.exitFullscreen().catch(function() {});
|
|
8486
|
-
}
|
|
8487
|
-
}
|
|
8488
|
-
resetControlsTimer();
|
|
8489
|
-
},
|
|
8490
|
-
style: {
|
|
8491
|
-
padding: "".concat(8 * responsiveScale, "px"),
|
|
8492
|
-
borderRadius: "50%",
|
|
8493
|
-
minWidth: "".concat(36 * responsiveScale, "px"),
|
|
8494
|
-
minHeight: "".concat(36 * responsiveScale, "px"),
|
|
8495
|
-
background: "rgba(0, 0, 0, 0.6)"
|
|
8496
|
-
},
|
|
8497
|
-
title: isFullscreen ? "Exit Fullscreen" : "Enter Fullscreen",
|
|
8498
|
-
children: isFullscreen ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_fa.FaCompress, {
|
|
8499
|
-
size: Math.max(14, 18 * responsiveScale)
|
|
8500
|
-
}) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_fa.FaExpand, {
|
|
8501
|
-
size: Math.max(14, 18 * responsiveScale)
|
|
8502
|
-
})
|
|
8503
8612
|
})
|
|
8504
8613
|
]
|
|
8505
8614
|
}),
|