ckplayer-plus 1.0.5 → 1.0.7
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/README.md +1 -1
- package/dist/ckplayer.js +278 -58
- package/dist/ckplayer.min.js +2 -2
- package/dist/index.cjs +245 -52
- package/dist/index.js +245 -52
- package/dist/react.cjs +245 -52
- package/dist/react.js +245 -52
- package/dist/vue.cjs +245 -52
- package/dist/vue.js +245 -52
- package/package.json +1 -1
package/dist/vue.cjs
CHANGED
|
@@ -212,7 +212,7 @@ var require_ckplayer = __commonJS({
|
|
|
212
212
|
cdnFallback: true
|
|
213
213
|
// getPath 失败时是否回退到 jsDelivr(内网可设 false,并配置 pluginPath)
|
|
214
214
|
};
|
|
215
|
-
var ckplayerPlusDefaultCdn = "https://cdn.jsdelivr.net/npm/ckplayer-plus@1.0.
|
|
215
|
+
var ckplayerPlusDefaultCdn = "https://cdn.jsdelivr.net/npm/ckplayer-plus@1.0.7/dist/";
|
|
216
216
|
function ckplayerEmbed(videoObj) {
|
|
217
217
|
var rightMenu = [
|
|
218
218
|
{
|
|
@@ -237,6 +237,11 @@ var require_ckplayer = __commonJS({
|
|
|
237
237
|
var paused = true;
|
|
238
238
|
var loadTime = 0;
|
|
239
239
|
var seekTime = 0;
|
|
240
|
+
var seekRetryTimer = null;
|
|
241
|
+
var seekRetryCount = 0;
|
|
242
|
+
var seekApplyLock = false;
|
|
243
|
+
var decodeRecoverCount = 0;
|
|
244
|
+
var hlsStartPositionUsed = false;
|
|
240
245
|
var oldTime = 0, playTime = 0, firstSeekTime = -1, maxSeeTime = 0;
|
|
241
246
|
var isChangeDef = true;
|
|
242
247
|
var playType = "";
|
|
@@ -402,7 +407,7 @@ var require_ckplayer = __commonJS({
|
|
|
402
407
|
}
|
|
403
408
|
var allowCdn = !vars || vars["cdnFallback"] !== false;
|
|
404
409
|
var cdn = typeof window !== "undefined" && window.ckplayerPlusCdn ? window.ckplayerPlusCdn : ckplayerPlusDefaultCdn;
|
|
405
|
-
if (!allowCdn || !cdn || cdn.indexOf("1.0.
|
|
410
|
+
if (!allowCdn || !cdn || cdn.indexOf("1.0.7") > -1) {
|
|
406
411
|
return folder + "/" + file;
|
|
407
412
|
}
|
|
408
413
|
if (cdn.slice(-1) !== "/") {
|
|
@@ -560,9 +565,86 @@ var require_ckplayer = __commonJS({
|
|
|
560
565
|
changeVideo(video.attr("src"));
|
|
561
566
|
}
|
|
562
567
|
return player;
|
|
568
|
+
}, parseResumeSeekFromVars = function() {
|
|
569
|
+
if (isUndefined(vars["seek"])) {
|
|
570
|
+
return 0;
|
|
571
|
+
}
|
|
572
|
+
if (valType(vars["seek"]) == "number" && vars["seek"] > 0) {
|
|
573
|
+
return vars["seek"];
|
|
574
|
+
}
|
|
575
|
+
if (valType(vars["seek"]) == "string" && vars["seek"] == "cookie" && cookieName) {
|
|
576
|
+
var cke = player.cookie(cookieName);
|
|
577
|
+
if (cke && cke["time"]) {
|
|
578
|
+
return cke["time"];
|
|
579
|
+
}
|
|
580
|
+
return 0;
|
|
581
|
+
}
|
|
582
|
+
if (valType(vars["seek"]) == "string" && vars["seek"] !== "" && !isNaN(parseFloat(vars["seek"]))) {
|
|
583
|
+
return parseFloat(vars["seek"]);
|
|
584
|
+
}
|
|
585
|
+
return 0;
|
|
586
|
+
}, applyResumeSeekState = function(t) {
|
|
587
|
+
if (!t || t <= 0) {
|
|
588
|
+
return;
|
|
589
|
+
}
|
|
590
|
+
seekTime = t;
|
|
591
|
+
maxSeeTime = Math.max(maxSeeTime, t);
|
|
592
|
+
if (firstSeekTime < 0) {
|
|
593
|
+
firstSeekTime = t;
|
|
594
|
+
}
|
|
595
|
+
}, prepareCookieAndSeek = function() {
|
|
596
|
+
if (vars["cookie"]) {
|
|
597
|
+
if (valType(vars["cookie"]) == "array" && vars["cookie"].length >= 2) {
|
|
598
|
+
if (vars["cookie"][0] && valType(vars["cookie"][0]) == "string") {
|
|
599
|
+
cookieName = vars["cookie"][0];
|
|
600
|
+
}
|
|
601
|
+
if (vars["cookie"][1] && valType(vars["cookie"][1]) == "number") {
|
|
602
|
+
cookieTime = vars["cookie"][1];
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
if (valType(vars["cookie"]) == "object" && !isUndefined(vars["cookie"]["name"])) {
|
|
606
|
+
cookieName = vars["cookie"]["name"];
|
|
607
|
+
if (!isUndefined(vars["cookie"]["hour"]) && valType(vars["cookie"]["hour"]) == "number") {
|
|
608
|
+
cookieTime = vars["cookie"]["hour"];
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
if (valType(vars["cookie"]) == "string") {
|
|
612
|
+
cookieName = vars["cookie"];
|
|
613
|
+
}
|
|
614
|
+
if (cookieName) {
|
|
615
|
+
cookieName = cookieName.replace(/[ ]*,[ ]*|[ ]+/g, "").replace(/[ ]*;[ ]*|[ ]+/g, "");
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
if (!seekTime) {
|
|
619
|
+
applyResumeSeekState(parseResumeSeekFromVars());
|
|
620
|
+
}
|
|
621
|
+
}, destroyStreamPlayers = function() {
|
|
622
|
+
clearSeekRetry();
|
|
623
|
+
seekApplyLock = false;
|
|
624
|
+
hlsStartPositionUsed = false;
|
|
625
|
+
decodeRecoverCount = 0;
|
|
626
|
+
if (hls) {
|
|
627
|
+
try {
|
|
628
|
+
hls.destroy();
|
|
629
|
+
} catch (event2) {
|
|
630
|
+
}
|
|
631
|
+
hls = null;
|
|
632
|
+
}
|
|
633
|
+
if (pugPlayer) {
|
|
634
|
+
try {
|
|
635
|
+
pugPlayer.pause();
|
|
636
|
+
pugPlayer.unload();
|
|
637
|
+
pugPlayer.detachMediaElement();
|
|
638
|
+
pugPlayer.destroy();
|
|
639
|
+
} catch (event2) {
|
|
640
|
+
}
|
|
641
|
+
pugPlayer = null;
|
|
642
|
+
}
|
|
563
643
|
}, changeVideo = function(vstr) {
|
|
564
644
|
var i2 = 0;
|
|
565
645
|
ensureAutoPlug(vstr);
|
|
646
|
+
prepareCookieAndSeek();
|
|
647
|
+
destroyStreamPlayers();
|
|
566
648
|
if (video.attr("src") || video.htm()) {
|
|
567
649
|
player.pause();
|
|
568
650
|
}
|
|
@@ -647,46 +729,6 @@ var require_ckplayer = __commonJS({
|
|
|
647
729
|
if (isChangeDef) {
|
|
648
730
|
checkDefinition();
|
|
649
731
|
}
|
|
650
|
-
if (vars["cookie"]) {
|
|
651
|
-
if (valType(vars["cookie"]) == "array" && vars["cookie"].length >= 2) {
|
|
652
|
-
if (vars["cookie"][0] && valType(vars["cookie"][0]) == "string") {
|
|
653
|
-
cookieName = vars["cookie"][0];
|
|
654
|
-
}
|
|
655
|
-
if (vars["cookie"][1] && valType(vars["cookie"][1]) == "number") {
|
|
656
|
-
cookieTime = vars["cookie"][1];
|
|
657
|
-
}
|
|
658
|
-
}
|
|
659
|
-
if (valType(vars["cookie"]) == "object" && !isUndefined(vars["cookie"]["name"])) {
|
|
660
|
-
cookieName = vars["cookie"]["name"];
|
|
661
|
-
if (!isUndefined(vars["cookie"]["hour"]) && valType(vars["cookie"]["hour"]) == "number") {
|
|
662
|
-
cookieTime = vars["cookie"]["hour"];
|
|
663
|
-
}
|
|
664
|
-
}
|
|
665
|
-
if (valType(vars["cookie"]) == "string") {
|
|
666
|
-
cookieName = vars["cookie"];
|
|
667
|
-
}
|
|
668
|
-
if (cookieName) {
|
|
669
|
-
cookieName = cookieName.replace(/[ ]*,[ ]*|[ ]+/g, "").replace(/[ ]*;[ ]*|[ ]+/g, "");
|
|
670
|
-
}
|
|
671
|
-
}
|
|
672
|
-
if (!isUndefined(vars["seek"]) && !seekTime) {
|
|
673
|
-
if (valType(vars["seek"]) == "number" && vars["seek"] > 0) {
|
|
674
|
-
seekTime = vars["seek"];
|
|
675
|
-
} else if (valType(vars["seek"]) == "string" && vars["seek"] == "cookie" && cookieName) {
|
|
676
|
-
var cke = player.cookie(cookieName);
|
|
677
|
-
if (cke) {
|
|
678
|
-
seekTime = cke["time"];
|
|
679
|
-
}
|
|
680
|
-
} else if (valType(vars["seek"]) == "string" && vars["seek"] !== "" && !isNaN(parseFloat(vars["seek"]))) {
|
|
681
|
-
seekTime = parseFloat(vars["seek"]);
|
|
682
|
-
}
|
|
683
|
-
if (seekTime && seekTime > 0) {
|
|
684
|
-
maxSeeTime = Math.max(maxSeeTime, seekTime);
|
|
685
|
-
if (firstSeekTime < 0) {
|
|
686
|
-
firstSeekTime = seekTime;
|
|
687
|
-
}
|
|
688
|
-
}
|
|
689
|
-
}
|
|
690
732
|
}, plugPlayer = function(url) {
|
|
691
733
|
switch (vars["plug"]) {
|
|
692
734
|
case "hls.js":
|
|
@@ -716,11 +758,39 @@ var require_ckplayer = __commonJS({
|
|
|
716
758
|
}, hlsPlayer = function(url) {
|
|
717
759
|
var startHls = function() {
|
|
718
760
|
if (typeof Hls !== "undefined" && !isUndefined(Hls) && Hls.isSupported()) {
|
|
719
|
-
|
|
761
|
+
if (hls) {
|
|
762
|
+
try {
|
|
763
|
+
hls.destroy();
|
|
764
|
+
} catch (event2) {
|
|
765
|
+
}
|
|
766
|
+
hls = null;
|
|
767
|
+
}
|
|
768
|
+
var hlsConf = {
|
|
769
|
+
// 10s 分片流在续播点附近需要略大缓冲,减少卡住转圈
|
|
770
|
+
maxBufferLength: 30,
|
|
771
|
+
maxMaxBufferLength: 60
|
|
772
|
+
};
|
|
773
|
+
var resumeAt = seekTime;
|
|
774
|
+
if (!resumeAt) {
|
|
775
|
+
resumeAt = parseResumeSeekFromVars();
|
|
776
|
+
}
|
|
777
|
+
if (resumeAt && resumeAt > 0 && (isUndefined(vars["live"]) || !vars["live"])) {
|
|
778
|
+
hlsConf.startPosition = resumeAt;
|
|
779
|
+
maxSeeTime = Math.max(maxSeeTime, resumeAt);
|
|
780
|
+
if (firstSeekTime < 0) {
|
|
781
|
+
firstSeekTime = resumeAt;
|
|
782
|
+
}
|
|
783
|
+
seekTime = 0;
|
|
784
|
+
hlsStartPositionUsed = true;
|
|
785
|
+
clearSeekRetry();
|
|
786
|
+
}
|
|
787
|
+
hls = new Hls(hlsConf);
|
|
720
788
|
hls.loadSource(url);
|
|
721
789
|
hls.attachMedia(video);
|
|
722
790
|
hls.on(Hls.Events.MANIFEST_PARSED, function() {
|
|
723
|
-
|
|
791
|
+
if (!hlsStartPositionUsed) {
|
|
792
|
+
applyPendingSeek();
|
|
793
|
+
}
|
|
724
794
|
});
|
|
725
795
|
hls.on(Hls.Events.ERROR, function(event2, data) {
|
|
726
796
|
var code = 9;
|
|
@@ -738,6 +808,13 @@ var require_ckplayer = __commonJS({
|
|
|
738
808
|
}
|
|
739
809
|
}
|
|
740
810
|
}
|
|
811
|
+
if (fatal && data.type === Hls.ErrorTypes.MEDIA_ERROR && hls && typeof hls.recoverMediaError === "function") {
|
|
812
|
+
try {
|
|
813
|
+
hls.recoverMediaError();
|
|
814
|
+
fatal = false;
|
|
815
|
+
} catch (errRecover) {
|
|
816
|
+
}
|
|
817
|
+
}
|
|
741
818
|
CT.error = { code, message: message2 };
|
|
742
819
|
eventTarget("error", CT.error);
|
|
743
820
|
if (fatal) {
|
|
@@ -1419,8 +1496,28 @@ var require_ckplayer = __commonJS({
|
|
|
1419
1496
|
checkTrack();
|
|
1420
1497
|
}
|
|
1421
1498
|
}
|
|
1422
|
-
},
|
|
1423
|
-
if (!
|
|
1499
|
+
}, timeInBuffered = function(t) {
|
|
1500
|
+
if (!video || isUndefined(video.buffered)) {
|
|
1501
|
+
return false;
|
|
1502
|
+
}
|
|
1503
|
+
try {
|
|
1504
|
+
var buf = video.buffered;
|
|
1505
|
+
for (var i2 = 0; i2 < buf.length; i2++) {
|
|
1506
|
+
if (t >= buf.start(i2) - 0.35 && t <= buf.end(i2) + 0.15) {
|
|
1507
|
+
return true;
|
|
1508
|
+
}
|
|
1509
|
+
}
|
|
1510
|
+
} catch (event2) {
|
|
1511
|
+
}
|
|
1512
|
+
return false;
|
|
1513
|
+
}, clearSeekRetry = function() {
|
|
1514
|
+
if (seekRetryTimer) {
|
|
1515
|
+
clearTimeout(seekRetryTimer);
|
|
1516
|
+
seekRetryTimer = null;
|
|
1517
|
+
}
|
|
1518
|
+
seekRetryCount = 0;
|
|
1519
|
+
}, applyPendingSeek = function(force) {
|
|
1520
|
+
if (!seekTime || !video || seekApplyLock) {
|
|
1424
1521
|
return;
|
|
1425
1522
|
}
|
|
1426
1523
|
if (!isUndefined(vars["live"]) && (valType(vars["live"]) == "boolean" && vars["live"] || valType(vars["live"]) == "number")) {
|
|
@@ -1431,18 +1528,96 @@ var require_ckplayer = __commonJS({
|
|
|
1431
1528
|
if (dur && isFinite(dur) && dur > 0 && t >= dur) {
|
|
1432
1529
|
t = Math.max(0, dur - 0.3);
|
|
1433
1530
|
}
|
|
1531
|
+
if (t <= 0) {
|
|
1532
|
+
seekTime = 0;
|
|
1533
|
+
clearSeekRetry();
|
|
1534
|
+
return;
|
|
1535
|
+
}
|
|
1434
1536
|
if (t > 0) {
|
|
1435
1537
|
maxSeeTime = Math.max(maxSeeTime, t);
|
|
1436
1538
|
if (firstSeekTime < 0) {
|
|
1437
1539
|
firstSeekTime = t;
|
|
1438
1540
|
}
|
|
1439
1541
|
}
|
|
1542
|
+
if (hls && typeof hls.startLoad === "function") {
|
|
1543
|
+
clearSeekRetry();
|
|
1544
|
+
seekTime = 0;
|
|
1545
|
+
try {
|
|
1546
|
+
hls.startLoad(t);
|
|
1547
|
+
} catch (event2) {
|
|
1548
|
+
seekTime = t;
|
|
1549
|
+
}
|
|
1550
|
+
return;
|
|
1551
|
+
}
|
|
1552
|
+
var readyEnough = !isUndefined(video.readyState) && video.readyState >= 2;
|
|
1553
|
+
var bufferedOk = timeInBuffered(t);
|
|
1554
|
+
if (!force && !bufferedOk && (!readyEnough || video.readyState < 3)) {
|
|
1555
|
+
seekRetryCount++;
|
|
1556
|
+
if (seekRetryCount <= 50) {
|
|
1557
|
+
if (seekRetryTimer) {
|
|
1558
|
+
clearTimeout(seekRetryTimer);
|
|
1559
|
+
}
|
|
1560
|
+
seekRetryTimer = setTimeout(function() {
|
|
1561
|
+
applyPendingSeek(false);
|
|
1562
|
+
}, 200);
|
|
1563
|
+
return;
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1566
|
+
clearSeekRetry();
|
|
1567
|
+
seekApplyLock = true;
|
|
1440
1568
|
seekTime = 0;
|
|
1441
1569
|
try {
|
|
1442
1570
|
video.currentTime = t;
|
|
1443
1571
|
} catch (event2) {
|
|
1444
1572
|
seekTime = t;
|
|
1573
|
+
seekApplyLock = false;
|
|
1445
1574
|
}
|
|
1575
|
+
setTimeout(function() {
|
|
1576
|
+
seekApplyLock = false;
|
|
1577
|
+
}, 800);
|
|
1578
|
+
}, recoverDecodeError = function() {
|
|
1579
|
+
if (decodeRecoverCount >= 2) {
|
|
1580
|
+
return false;
|
|
1581
|
+
}
|
|
1582
|
+
decodeRecoverCount++;
|
|
1583
|
+
var resumeAt = playTime > 0 ? playTime : vars["seek"] ? parseFloat(vars["seek"]) : 0;
|
|
1584
|
+
if (isNaN(resumeAt) || resumeAt < 0) {
|
|
1585
|
+
resumeAt = 0;
|
|
1586
|
+
}
|
|
1587
|
+
try {
|
|
1588
|
+
if (hls && typeof hls.recoverMediaError === "function") {
|
|
1589
|
+
hls.recoverMediaError();
|
|
1590
|
+
if (resumeAt > 0) {
|
|
1591
|
+
seekTime = resumeAt;
|
|
1592
|
+
seekApplyLock = false;
|
|
1593
|
+
setTimeout(function() {
|
|
1594
|
+
applyPendingSeek(true);
|
|
1595
|
+
}, 300);
|
|
1596
|
+
}
|
|
1597
|
+
return true;
|
|
1598
|
+
}
|
|
1599
|
+
} catch (event2) {
|
|
1600
|
+
}
|
|
1601
|
+
try {
|
|
1602
|
+
var soft = Math.max(0, resumeAt - 1.5);
|
|
1603
|
+
seekTime = resumeAt;
|
|
1604
|
+
seekApplyLock = false;
|
|
1605
|
+
if (video) {
|
|
1606
|
+
video.currentTime = soft;
|
|
1607
|
+
}
|
|
1608
|
+
setTimeout(function() {
|
|
1609
|
+
applyPendingSeek(true);
|
|
1610
|
+
if (video && video.paused && vars["autoplay"]) {
|
|
1611
|
+
try {
|
|
1612
|
+
video.play();
|
|
1613
|
+
} catch (e2) {
|
|
1614
|
+
}
|
|
1615
|
+
}
|
|
1616
|
+
}, 400);
|
|
1617
|
+
return true;
|
|
1618
|
+
} catch (event2) {
|
|
1619
|
+
}
|
|
1620
|
+
return false;
|
|
1446
1621
|
}, loadedMetaData = function() {
|
|
1447
1622
|
eventTarget("loadedMetaData", {
|
|
1448
1623
|
width: CK.getWidth(),
|
|
@@ -1619,6 +1794,11 @@ var require_ckplayer = __commonJS({
|
|
|
1619
1794
|
if (!isUndefined(errorInfo.message)) {
|
|
1620
1795
|
msg = errorInfo.message;
|
|
1621
1796
|
}
|
|
1797
|
+
if (code === 3 && recoverDecodeError()) {
|
|
1798
|
+
CT.error = { code, message: msg };
|
|
1799
|
+
eventTarget("error", CT.error);
|
|
1800
|
+
return;
|
|
1801
|
+
}
|
|
1622
1802
|
CT.error = { code, message: msg };
|
|
1623
1803
|
showError();
|
|
1624
1804
|
} else {
|
|
@@ -1668,6 +1848,8 @@ var require_ckplayer = __commonJS({
|
|
|
1668
1848
|
eventTarget("error", CT.error);
|
|
1669
1849
|
},
|
|
1670
1850
|
seeked: function() {
|
|
1851
|
+
seekApplyLock = false;
|
|
1852
|
+
decodeRecoverCount = 0;
|
|
1671
1853
|
if (paused) {
|
|
1672
1854
|
player.play();
|
|
1673
1855
|
}
|
|
@@ -2045,7 +2227,8 @@ var require_ckplayer = __commonJS({
|
|
|
2045
2227
|
ad["frontPlay"] = false;
|
|
2046
2228
|
C["ad"].hide();
|
|
2047
2229
|
allBarShow();
|
|
2048
|
-
seekTime =
|
|
2230
|
+
seekTime = 0;
|
|
2231
|
+
applyResumeSeekState(parseResumeSeekFromVars());
|
|
2049
2232
|
if (ad["front"]["video"]) {
|
|
2050
2233
|
changeVideo(vars["video"]);
|
|
2051
2234
|
} else {
|
|
@@ -2619,10 +2802,6 @@ var require_ckplayer = __commonJS({
|
|
|
2619
2802
|
firstSeekTime = target;
|
|
2620
2803
|
}
|
|
2621
2804
|
}
|
|
2622
|
-
try {
|
|
2623
|
-
video.currentTime = target;
|
|
2624
|
-
} catch (event2) {
|
|
2625
|
-
}
|
|
2626
2805
|
return player;
|
|
2627
2806
|
}
|
|
2628
2807
|
if (duration && isFinite(duration) && duration > 0 && target > duration) {
|
|
@@ -2634,6 +2813,20 @@ var require_ckplayer = __commonJS({
|
|
|
2634
2813
|
if (vars["timeScheduleAdjust"] == 5 && target > maxSeeTime && seekTime && Math.abs(seekTime - target) < 0.5) {
|
|
2635
2814
|
maxSeeTime = Math.max(maxSeeTime, target);
|
|
2636
2815
|
}
|
|
2816
|
+
if (target > 0.5 && !timeInBuffered(target) && video.readyState < 3 && !hls) {
|
|
2817
|
+
seekTime = target;
|
|
2818
|
+
applyPendingSeek(false);
|
|
2819
|
+
return player;
|
|
2820
|
+
}
|
|
2821
|
+
if (hls && typeof hls.startLoad === "function") {
|
|
2822
|
+
seekTime = 0;
|
|
2823
|
+
try {
|
|
2824
|
+
hls.startLoad(target);
|
|
2825
|
+
} catch (event2) {
|
|
2826
|
+
seekTime = target;
|
|
2827
|
+
}
|
|
2828
|
+
return player;
|
|
2829
|
+
}
|
|
2637
2830
|
try {
|
|
2638
2831
|
video.currentTime = target;
|
|
2639
2832
|
seekTime = 0;
|
|
@@ -5848,7 +6041,7 @@ var require_ckplayer = __commonJS({
|
|
|
5848
6041
|
if (!isRetry && (!vars || vars["cdnFallback"] !== false)) {
|
|
5849
6042
|
var cdn = typeof window !== "undefined" && window.ckplayerPlusCdn ? window.ckplayerPlusCdn : ckplayerPlusDefaultCdn;
|
|
5850
6043
|
var m2 = String(file).match(/\/(hls\.js|flv\.js|mpegts\.js|language)\/([^/?#]+)(?:[?#].*)?$/i);
|
|
5851
|
-
if (cdn && cdn.indexOf("1.0.
|
|
6044
|
+
if (cdn && cdn.indexOf("1.0.7") === -1 && m2) {
|
|
5852
6045
|
if (cdn.slice(-1) !== "/") {
|
|
5853
6046
|
cdn += "/";
|
|
5854
6047
|
}
|