@eluvio/elv-player-js 1.0.85 → 1.0.87
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/package.json +1 -1
- package/src/PlayerControls.js +124 -84
- package/src/index.js +318 -146
- package/src/static/icons/arrow-left.svg +4 -0
- package/src/static/stylesheets/player.scss +43 -13
package/package.json
CHANGED
package/src/PlayerControls.js
CHANGED
|
@@ -8,6 +8,7 @@ import MutedIcon from "./static/icons/media/no volume icon.svg";
|
|
|
8
8
|
import VolumeLowIcon from "./static/icons/media/low volume icon.svg";
|
|
9
9
|
import VolumeHighIcon from "./static/icons/media/Volume icon.svg";
|
|
10
10
|
import MultiViewIcon from "./static/icons/multiview.svg";
|
|
11
|
+
import LeftArrow from "./static/icons/arrow-left.svg";
|
|
11
12
|
|
|
12
13
|
import Logo from "./static/images/ELUV.IO white 20 px V2.png";
|
|
13
14
|
|
|
@@ -122,7 +123,6 @@ class PlayerControls {
|
|
|
122
123
|
};
|
|
123
124
|
}
|
|
124
125
|
|
|
125
|
-
this.settingsMenuContent = "none";
|
|
126
126
|
this.timeouts = {};
|
|
127
127
|
this.played = false;
|
|
128
128
|
this.controlsHover = false;
|
|
@@ -487,7 +487,11 @@ class PlayerControls {
|
|
|
487
487
|
classes: ["eluvio-player__controls__slider-container__input", "eluvio-player__controls__progress-slider"]
|
|
488
488
|
});
|
|
489
489
|
|
|
490
|
-
progressSlider.addEventListener("input", () =>
|
|
490
|
+
progressSlider.addEventListener("input", () => {
|
|
491
|
+
if(!this.video.duration) { return; }
|
|
492
|
+
|
|
493
|
+
this.video.currentTime = this.video.duration * parseFloat(progressSlider.value || 0);
|
|
494
|
+
});
|
|
491
495
|
|
|
492
496
|
// Progress Bar
|
|
493
497
|
const progressBar = CreateElement({
|
|
@@ -561,6 +565,7 @@ class PlayerControls {
|
|
|
561
565
|
type: "div",
|
|
562
566
|
classes: ["eluvio-player__controls__settings-menu", "eluvio-player__controls__settings-menu-hidden"]
|
|
563
567
|
});
|
|
568
|
+
this.settingsMenu.setAttribute("data-mode", "hidden");
|
|
564
569
|
|
|
565
570
|
this.target.addEventListener("keydown", event => event && (event.key || "").toLowerCase() === "escape" && this.HideSettingsMenu());
|
|
566
571
|
|
|
@@ -658,93 +663,83 @@ class PlayerControls {
|
|
|
658
663
|
}
|
|
659
664
|
}
|
|
660
665
|
|
|
661
|
-
|
|
662
|
-
if(
|
|
663
|
-
this.settingsButton.focus();
|
|
664
|
-
} else if(this.settingsMenuContent === "multiview") {
|
|
665
|
-
this.multiviewButton.focus();
|
|
666
|
-
}
|
|
667
|
-
|
|
668
|
-
this.settingsMenu.innerHTML = "";
|
|
669
|
-
this.settingsMenu.classList.add("eluvio-player__controls__settings-menu-hidden");
|
|
670
|
-
this.settingsMenuContent = "none";
|
|
671
|
-
}
|
|
666
|
+
AddSetting({Retrieve, Set}) {
|
|
667
|
+
if(!Retrieve) { return; }
|
|
672
668
|
|
|
673
|
-
|
|
674
|
-
this.settingsMenu.innerHTML = "";
|
|
669
|
+
const { label, options } = Retrieve();
|
|
675
670
|
|
|
676
|
-
|
|
677
|
-
this.HideSettingsMenu();
|
|
678
|
-
return;
|
|
679
|
-
}
|
|
671
|
+
const currentOption = options.find(option => option.active);
|
|
680
672
|
|
|
681
|
-
|
|
682
|
-
|
|
673
|
+
const optionSelectionButton = CreateElement({
|
|
674
|
+
parent: this.settingsMenu,
|
|
675
|
+
type: Set ? "button" : "div",
|
|
676
|
+
classes: ["eluvio-player__controls__settings-menu__option"]
|
|
677
|
+
});
|
|
683
678
|
|
|
684
|
-
|
|
685
|
-
if(this.GetLevels) {
|
|
686
|
-
const levels = this.GetLevels();
|
|
679
|
+
optionSelectionButton.innerHTML = currentOption && currentOption.activeLabel || label;
|
|
687
680
|
|
|
688
|
-
|
|
681
|
+
if(Set) {
|
|
682
|
+
optionSelectionButton.addEventListener("click", () => {
|
|
683
|
+
this.settingsMenu.innerHTML = "";
|
|
684
|
+
this.settingsMenu.setAttribute("data-mode", "settings-submenu");
|
|
689
685
|
|
|
690
|
-
|
|
691
|
-
const resolutionButton = CreateElement({
|
|
686
|
+
const backButton = CreateElement({
|
|
692
687
|
parent: this.settingsMenu,
|
|
693
|
-
type:
|
|
694
|
-
classes: ["eluvio-player__controls__settings-menu__option"]
|
|
688
|
+
type: "button",
|
|
689
|
+
classes: ["eluvio-player__controls__settings-menu__option", "eluvio-player__controls__settings-menu__option-back"],
|
|
695
690
|
});
|
|
696
691
|
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
}
|
|
692
|
+
CreateElement({
|
|
693
|
+
parent: backButton,
|
|
694
|
+
type: "svg"
|
|
695
|
+
}).innerHTML = LeftArrow;
|
|
702
696
|
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
697
|
+
CreateElement({
|
|
698
|
+
parent: backButton,
|
|
699
|
+
}).innerHTML = label;
|
|
706
700
|
|
|
707
|
-
|
|
701
|
+
backButton.addEventListener("click", () => this.ShowSettingsMenu());
|
|
702
|
+
|
|
703
|
+
options
|
|
704
|
+
.forEach(option => {
|
|
705
|
+
const optionButton = CreateElement({
|
|
708
706
|
parent: this.settingsMenu,
|
|
709
707
|
type: "button",
|
|
710
|
-
classes: ["eluvio-player__controls__settings-menu__option"]
|
|
708
|
+
classes: ["eluvio-player__controls__settings-menu__option", option.active ? "eluvio-player__controls__settings-menu__option-selected" : ""]
|
|
711
709
|
});
|
|
712
710
|
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
711
|
+
optionButton.innerHTML = option.label;
|
|
712
|
+
|
|
713
|
+
optionButton.addEventListener("click", () => {
|
|
714
|
+
Set(option.index);
|
|
716
715
|
this.HideSettingsMenu();
|
|
717
716
|
});
|
|
718
|
-
|
|
719
|
-
levels
|
|
720
|
-
.sort((a, b) => a.bitrate < b.bitrate ? 1 : -1)
|
|
721
|
-
.forEach(level => {
|
|
722
|
-
const levelOption = CreateElement({
|
|
723
|
-
parent: this.settingsMenu,
|
|
724
|
-
type: "button",
|
|
725
|
-
classes: ["eluvio-player__controls__settings-menu__option", level.active ? "eluvio-player__controls__settings-menu__option-selected" : ""]
|
|
726
|
-
});
|
|
727
|
-
|
|
728
|
-
if(level.audioTrack) {
|
|
729
|
-
levelOption.innerHTML = `${level.bitrate / 1000}kbps`;
|
|
730
|
-
} else {
|
|
731
|
-
levelOption.innerHTML = `${level.resolution} (${(level.bitrate / 1000 / 1000).toFixed(1)}Mbps)`;
|
|
732
|
-
}
|
|
733
|
-
|
|
734
|
-
levelOption.addEventListener("click", () => {
|
|
735
|
-
this.SetLevel(level.index);
|
|
736
|
-
this.HideSettingsMenu();
|
|
737
|
-
});
|
|
738
|
-
});
|
|
739
|
-
|
|
740
|
-
// Focus on first element in list when menu opened
|
|
741
|
-
const firstItem = this.settingsMenu.querySelector("button");
|
|
742
|
-
if(firstItem) {
|
|
743
|
-
firstItem.focus();
|
|
744
|
-
}
|
|
745
717
|
});
|
|
718
|
+
|
|
719
|
+
// Focus on first element in list when menu opened
|
|
720
|
+
const firstItem = this.settingsMenu.querySelector("button");
|
|
721
|
+
if(firstItem) {
|
|
722
|
+
firstItem.focus();
|
|
746
723
|
}
|
|
747
|
-
}
|
|
724
|
+
});
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
ShowSettingsMenu() {
|
|
729
|
+
this.settingsMenu.innerHTML = "";
|
|
730
|
+
this.settingsMenu.classList.remove("eluvio-player__controls__settings-menu-hidden");
|
|
731
|
+
this.settingsMenu.setAttribute("data-mode", "settings");
|
|
732
|
+
|
|
733
|
+
if(this.GetLevels) {
|
|
734
|
+
this.AddSetting({Retrieve: this.GetLevels, Set: this.SetLevel});
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
if(this.GetAudioTracks) {
|
|
738
|
+
this.AddSetting({Retrieve: this.GetAudioTracks, Set: this.SetAudioTrack});
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
if(this.GetTextTracks) {
|
|
742
|
+
this.AddSetting({Retrieve: this.GetTextTracks, Set: this.SetTextTrack});
|
|
748
743
|
}
|
|
749
744
|
|
|
750
745
|
// Focus on first element in list when menu opened
|
|
@@ -754,30 +749,75 @@ class PlayerControls {
|
|
|
754
749
|
}
|
|
755
750
|
}
|
|
756
751
|
|
|
757
|
-
|
|
758
|
-
|
|
752
|
+
HideSettingsMenu() {
|
|
753
|
+
const mode = this.settingsMenu.dataset.mode;
|
|
754
|
+
if(mode === "settings") {
|
|
755
|
+
this.settingsButton.focus();
|
|
756
|
+
} else if(mode === "multiview") {
|
|
757
|
+
this.multiviewButton.focus();
|
|
758
|
+
}
|
|
759
759
|
|
|
760
|
-
this.
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
760
|
+
this.settingsMenu.innerHTML = "";
|
|
761
|
+
this.settingsMenu.classList.add("eluvio-player__controls__settings-menu-hidden");
|
|
762
|
+
this.settingsMenu.setAttribute("data-mode", "hidden");
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
UpdateSettings() {
|
|
766
|
+
if(!this.settingsButton) {
|
|
767
|
+
this.settingsButton = CreateImageButton({
|
|
768
|
+
parent: this.rightButtonsContainer,
|
|
769
|
+
svg: SettingsIcon,
|
|
770
|
+
classes: ["eluvio-player__controls__button-settings"],
|
|
771
|
+
prepend: true,
|
|
772
|
+
label: "Settings"
|
|
773
|
+
});
|
|
774
|
+
|
|
775
|
+
this.settingsButton.addEventListener("click", () => {
|
|
776
|
+
this.settingsMenu.dataset.mode === "hidden" ?
|
|
777
|
+
this.ShowSettingsMenu() :
|
|
778
|
+
this.HideSettingsMenu();
|
|
779
|
+
});
|
|
780
|
+
}
|
|
767
781
|
|
|
768
|
-
this.
|
|
782
|
+
if(this.settingsMenu.dataset.mode === "settings") {
|
|
783
|
+
this.ShowSettingsMenu();
|
|
784
|
+
}
|
|
769
785
|
}
|
|
770
786
|
|
|
771
|
-
|
|
787
|
+
SetAudioTrackControls({GetAudioTracks, SetAudioTrack}) {
|
|
772
788
|
if([EluvioPlayerParameters.controls.OFF, EluvioPlayerParameters.controls.OFF_WITH_VOLUME_TOGGLE, EluvioPlayerParameters.controls.DEFAULT].includes(this.playerOptions.controls)) {
|
|
773
789
|
// Controls disabled
|
|
774
790
|
return;
|
|
775
791
|
}
|
|
776
792
|
|
|
777
|
-
this.
|
|
793
|
+
this.GetAudioTracks = GetAudioTracks;
|
|
794
|
+
this.SetAudioTrack = SetAudioTrack;
|
|
795
|
+
|
|
796
|
+
this.UpdateSettings();
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
SetTextTrackControls({GetTextTracks, SetTextTrack}) {
|
|
800
|
+
if([EluvioPlayerParameters.controls.OFF, EluvioPlayerParameters.controls.OFF_WITH_VOLUME_TOGGLE, EluvioPlayerParameters.controls.DEFAULT].includes(this.playerOptions.controls)) {
|
|
801
|
+
// Controls disabled
|
|
802
|
+
return;
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
this.GetTextTracks = GetTextTracks;
|
|
806
|
+
this.SetTextTrack = SetTextTrack;
|
|
807
|
+
|
|
808
|
+
this.UpdateSettings();
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
SetQualityControls({GetLevels, SetLevel}) {
|
|
812
|
+
if([EluvioPlayerParameters.controls.OFF, EluvioPlayerParameters.controls.OFF_WITH_VOLUME_TOGGLE, EluvioPlayerParameters.controls.DEFAULT].includes(this.playerOptions.controls)) {
|
|
813
|
+
// Controls disabled
|
|
814
|
+
return;
|
|
815
|
+
}
|
|
778
816
|
|
|
779
817
|
this.GetLevels = GetLevels;
|
|
780
818
|
this.SetLevel = SetLevel;
|
|
819
|
+
|
|
820
|
+
this.UpdateSettings();
|
|
781
821
|
}
|
|
782
822
|
|
|
783
823
|
InitializeMultiViewControls({AvailableViews, SwitchView}) {
|
|
@@ -823,12 +863,12 @@ class PlayerControls {
|
|
|
823
863
|
async ToggleMultiviewControls({AvailableViews, SwitchView}={}) {
|
|
824
864
|
this.settingsMenu.innerHTML = "";
|
|
825
865
|
|
|
826
|
-
if(this.
|
|
866
|
+
if(this.settingsMenu.dataset.mode === "multiview") {
|
|
827
867
|
this.HideSettingsMenu();
|
|
828
868
|
return;
|
|
829
869
|
}
|
|
830
870
|
|
|
831
|
-
this.
|
|
871
|
+
this.settingsMenu.setAttribute("data-mode", "multiview");
|
|
832
872
|
this.settingsMenu.classList.remove("eluvio-player__controls__settings-menu-hidden");
|
|
833
873
|
|
|
834
874
|
const views = await AvailableViews();
|
package/src/index.js
CHANGED
|
@@ -118,7 +118,7 @@ const DefaultParameters = {
|
|
|
118
118
|
hlsjsOptions: undefined,
|
|
119
119
|
dashjsOptions: undefined,
|
|
120
120
|
// eslint-disable-next-line no-unused-vars
|
|
121
|
-
playerCallback: ({videoElement, hlsPlayer, dashPlayer, posterUrl}) => {},
|
|
121
|
+
playerCallback: ({player, videoElement, hlsPlayer, dashPlayer, posterUrl}) => {},
|
|
122
122
|
errorCallback: (error) => {
|
|
123
123
|
// eslint-disable-next-line no-console
|
|
124
124
|
console.error("ELUVIO PLAYER: Error");
|
|
@@ -138,6 +138,8 @@ export class EluvioPlayer {
|
|
|
138
138
|
this.DetectRemoval = this.DetectRemoval.bind(this);
|
|
139
139
|
|
|
140
140
|
this.Initialize(target, parameters);
|
|
141
|
+
|
|
142
|
+
window.EluvioPlayer = this;
|
|
141
143
|
}
|
|
142
144
|
|
|
143
145
|
Log(message, error=false) {
|
|
@@ -269,6 +271,7 @@ export class EluvioPlayer {
|
|
|
269
271
|
const imageMetadata = await client.ContentObjectMetadata({
|
|
270
272
|
versionHash: targetHash,
|
|
271
273
|
metadataSubtree: "public",
|
|
274
|
+
authorizationToken: this.sourceOptions.playoutParameters.authorizationToken,
|
|
272
275
|
select: [
|
|
273
276
|
"display_image",
|
|
274
277
|
"asset_metadata/nft/image"
|
|
@@ -319,8 +322,6 @@ export class EluvioPlayer {
|
|
|
319
322
|
offeringURI,
|
|
320
323
|
options
|
|
321
324
|
});
|
|
322
|
-
|
|
323
|
-
window.playoutOptions = this.sourceOptions.playoutOptions;
|
|
324
325
|
}
|
|
325
326
|
} else {
|
|
326
327
|
if(!this.sourceOptions.playoutOptions) {
|
|
@@ -328,8 +329,6 @@ export class EluvioPlayer {
|
|
|
328
329
|
...this.sourceOptions.playoutParameters,
|
|
329
330
|
options
|
|
330
331
|
});
|
|
331
|
-
|
|
332
|
-
window.playoutOptions = this.sourceOptions.playoutOptions;
|
|
333
332
|
}
|
|
334
333
|
}
|
|
335
334
|
|
|
@@ -584,186 +583,359 @@ export class EluvioPlayer {
|
|
|
584
583
|
this.sourceOptions.playoutParameters.authorizationToken ||
|
|
585
584
|
playoutUrl.query(true).authorization;
|
|
586
585
|
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
InitializeFairPlayStream({playoutOptions: this.sourceOptions.playoutOptions, video: this.video});
|
|
586
|
+
if(protocol === "hls") {
|
|
587
|
+
await this.InitializeHLS({playoutUrl, authorizationToken, drm, drms, multiviewOptions, controlsPromise});
|
|
588
|
+
} else {
|
|
589
|
+
await this.InitializeDash({playoutUrl, authorizationToken, drm, drms, multiviewOptions, controlsPromise});
|
|
590
|
+
}
|
|
593
591
|
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
592
|
+
if(this.playerOptions.playerCallback) {
|
|
593
|
+
this.playerOptions.playerCallback({
|
|
594
|
+
player: this,
|
|
595
|
+
videoElement: this.video,
|
|
596
|
+
hlsPlayer: this.hlsPlayer,
|
|
597
|
+
dashPlayer: this.dashPlayer,
|
|
598
|
+
posterUrl: this.posterUrl
|
|
599
|
+
});
|
|
600
|
+
}
|
|
597
601
|
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
playoutUrl.removeQuery("authorization");
|
|
602
|
+
if(this.playerOptions.autoplay === EluvioPlayerParameters.autoplay.ON) {
|
|
603
|
+
this.video.play();
|
|
601
604
|
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
xhr.setRequestHeader("Authorization", `Bearer ${authorizationToken}`);
|
|
605
|
+
setTimeout(() => {
|
|
606
|
+
if(this.playerOptions.muted === EluvioPlayerParameters.muted.OFF_IF_POSSIBLE && this.video.paused && !this.video.muted) {
|
|
607
|
+
this.video.muted = true;
|
|
608
|
+
this.video.play();
|
|
609
|
+
}
|
|
610
|
+
}, 250);
|
|
611
|
+
}
|
|
610
612
|
|
|
611
|
-
|
|
612
|
-
this.playerOptions.hlsjsOptions.xhrSetup(xhr);
|
|
613
|
-
}
|
|
613
|
+
this.RegisterVisibilityCallback();
|
|
614
614
|
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
615
|
+
if(this.__destroyed) {
|
|
616
|
+
// If Destroy was called during the initialization process, ensure that the player is properly destroyed
|
|
617
|
+
this.Destroy();
|
|
618
|
+
}
|
|
619
|
+
} catch (error) {
|
|
620
|
+
this.playerOptions.errorCallback(error);
|
|
621
621
|
|
|
622
|
-
|
|
623
|
-
|
|
622
|
+
if(error.status === 500) {
|
|
623
|
+
this.HardReload(error, 10000);
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
}
|
|
624
627
|
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
hlsPlayer.nextLevel = hlsPlayer.currentLevel;
|
|
628
|
-
};
|
|
628
|
+
async InitializeHLS({playoutUrl, authorizationToken, drm, multiviewOptions, controlsPromise}) {
|
|
629
|
+
const HLSPlayer = (await import("hls-fix")).default;
|
|
629
630
|
|
|
630
|
-
|
|
631
|
-
|
|
631
|
+
if(drm === "fairplay") {
|
|
632
|
+
InitializeFairPlayStream({playoutOptions: this.sourceOptions.playoutOptions, video: this.video});
|
|
632
633
|
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
index,
|
|
638
|
-
active: index === hlsPlayer.currentLevel,
|
|
639
|
-
resolution: level.attrs.RESOLUTION,
|
|
640
|
-
bitrate: level.bitrate,
|
|
641
|
-
audioTrack: !level.videoCodec
|
|
642
|
-
})),
|
|
643
|
-
SetLevel: levelIndex => hlsPlayer.nextLevel = levelIndex
|
|
644
|
-
});
|
|
645
|
-
}
|
|
634
|
+
if(multiviewOptions.enabled) { controlsPromise.then(() => this.controls.InitializeMultiViewControls(multiviewOptions)); }
|
|
635
|
+
this.UpdateTextTracks();
|
|
636
|
+
} else if(!HLSPlayer.isSupported() || drm === "sample-aes") {
|
|
637
|
+
this.video.src = playoutUrl.toString();
|
|
646
638
|
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
639
|
+
if(multiviewOptions.enabled) { controlsPromise.then(() => this.controls.InitializeMultiViewControls(multiviewOptions)); }
|
|
640
|
+
} else {
|
|
641
|
+
playoutUrl.removeQuery("authorization");
|
|
642
|
+
|
|
643
|
+
// Inject
|
|
644
|
+
const hlsPlayer = new HLSPlayer({
|
|
645
|
+
maxBufferLength: 30,
|
|
646
|
+
maxBufferSize: 300,
|
|
647
|
+
enableWorker: true,
|
|
648
|
+
capLevelToPlayerSize: this.playerOptions.capLevelToPlayerSize,
|
|
649
|
+
xhrSetup: xhr => {
|
|
650
|
+
xhr.setRequestHeader("Authorization", `Bearer ${authorizationToken}`);
|
|
651
|
+
|
|
652
|
+
if((this.playerOptions.hlsjsOptions || {}).xhrSetup) {
|
|
653
|
+
this.playerOptions.hlsjsOptions.xhrSetup(xhr);
|
|
654
|
+
}
|
|
651
655
|
|
|
652
|
-
|
|
653
|
-
|
|
656
|
+
return xhr;
|
|
657
|
+
},
|
|
658
|
+
...(this.playerOptions.hlsjsOptions || {})
|
|
659
|
+
});
|
|
660
|
+
hlsPlayer.loadSource(playoutUrl.toString());
|
|
661
|
+
hlsPlayer.attachMedia(this.video);
|
|
654
662
|
|
|
655
|
-
|
|
656
|
-
|
|
663
|
+
if(multiviewOptions.enabled) {
|
|
664
|
+
const Switch = multiviewOptions.SwitchView;
|
|
657
665
|
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
}, 3000);
|
|
663
|
-
}
|
|
666
|
+
multiviewOptions.SwitchView = async (view) => {
|
|
667
|
+
await Switch(view);
|
|
668
|
+
hlsPlayer.nextLevel = hlsPlayer.currentLevel;
|
|
669
|
+
};
|
|
664
670
|
|
|
665
|
-
|
|
666
|
-
|
|
671
|
+
controlsPromise.then(() => this.controls.InitializeMultiViewControls(multiviewOptions));
|
|
672
|
+
}
|
|
667
673
|
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
674
|
+
if(this.controls) {
|
|
675
|
+
const UpdateQualityOptions = () => {
|
|
676
|
+
try {
|
|
677
|
+
this.controls.SetQualityControls({
|
|
678
|
+
GetLevels: () => {
|
|
679
|
+
let levels = hlsPlayer.levels
|
|
680
|
+
.map((level, index) => ({
|
|
681
|
+
index,
|
|
682
|
+
active: hlsPlayer.currentLevel === index,
|
|
683
|
+
resolution: level.attrs.RESOLUTION,
|
|
684
|
+
bitrate: level.bitrate,
|
|
685
|
+
audioTrack: !level.videoCodec,
|
|
686
|
+
label:
|
|
687
|
+
level.audioTrack ?
|
|
688
|
+
`${level.bitrate / 1000}kbps` :
|
|
689
|
+
`${level.attrs.RESOLUTION} (${(level.bitrate / 1000 / 1000).toFixed(1)}Mbps)`,
|
|
690
|
+
activeLabel:
|
|
691
|
+
level.audioTrack ?
|
|
692
|
+
`Quality: ${level.bitrate / 1000}kbps` :
|
|
693
|
+
`Quality: ${level.attrs.RESOLUTION}`
|
|
694
|
+
}))
|
|
695
|
+
.sort((a, b) => a.bitrate < b.bitrate ? 1 : -1);
|
|
696
|
+
|
|
697
|
+
levels.unshift({index: -1, label: "Auto"});
|
|
698
|
+
|
|
699
|
+
return {label: "Quality", options: levels};
|
|
700
|
+
},
|
|
701
|
+
SetLevel: levelIndex => {
|
|
702
|
+
hlsPlayer.nextLevel = levelIndex;
|
|
703
|
+
hlsPlayer.streamController.immediateLevelSwitch();
|
|
671
704
|
}
|
|
672
|
-
}
|
|
705
|
+
});
|
|
706
|
+
} catch (error) {
|
|
707
|
+
// eslint-disable-next-line no-console
|
|
708
|
+
console.error("ELUVIO PLAYER:", error);
|
|
673
709
|
}
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
710
|
+
};
|
|
711
|
+
|
|
712
|
+
hlsPlayer.on(HLSPlayer.Events.SUBTITLE_TRACKS_UPDATED, () => this.UpdateTextTracks());
|
|
713
|
+
hlsPlayer.on(HLSPlayer.Events.LEVEL_LOADED, () => UpdateQualityOptions());
|
|
714
|
+
hlsPlayer.on(HLSPlayer.Events.LEVEL_SWITCHED, () => UpdateQualityOptions());
|
|
715
|
+
hlsPlayer.on(HLSPlayer.Events.SUBTITLE_TRACK_SWITCH, () => this.UpdateTextTracks());
|
|
716
|
+
hlsPlayer.on(HLSPlayer.Events.AUDIO_TRACKS_UPDATED, () => {
|
|
717
|
+
this.controls.SetAudioTrackControls({
|
|
718
|
+
GetAudioTracks: () => {
|
|
719
|
+
const tracks = hlsPlayer.audioTracks.map(track => ({
|
|
720
|
+
index: track.id,
|
|
721
|
+
label: track.name,
|
|
722
|
+
active: track.id === hlsPlayer.audioTrack,
|
|
723
|
+
activeLabel: `Audio: ${track.name}`
|
|
724
|
+
}));
|
|
725
|
+
|
|
726
|
+
return {label: "Audio Track", options: tracks};
|
|
727
|
+
},
|
|
728
|
+
SetAudioTrack: index => {
|
|
729
|
+
hlsPlayer.audioTrack = index;
|
|
730
|
+
hlsPlayer.streamController.immediateLevelSwitch();
|
|
681
731
|
}
|
|
682
|
-
}
|
|
732
|
+
});
|
|
683
733
|
});
|
|
734
|
+
}
|
|
684
735
|
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
736
|
+
hlsPlayer.on(HLSPlayer.Events.FRAG_LOADED, () => {
|
|
737
|
+
this.errors = 0;
|
|
738
|
+
clearTimeout(this.bufferFullRestartTimeout);
|
|
739
|
+
});
|
|
740
|
+
|
|
741
|
+
hlsPlayer.on(HLSPlayer.Events.ERROR, async (event, error) => {
|
|
742
|
+
this.errors += 1;
|
|
743
|
+
|
|
744
|
+
this.Log(`Encountered ${error.details}`);
|
|
745
|
+
this.Log(error);
|
|
746
|
+
|
|
747
|
+
if(error.details === "bufferFullError") {
|
|
748
|
+
this.bufferFullRestartTimeout = setTimeout(() => {
|
|
749
|
+
this.Log("Buffer full error - Restarting player", true);
|
|
750
|
+
this.HardReload(error, 5000);
|
|
751
|
+
}, 3000);
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
if(error.details === "bufferStalledError") {
|
|
755
|
+
const stallTime = this.video.currentTime;
|
|
756
|
+
|
|
757
|
+
setTimeout(() => {
|
|
758
|
+
if(!this.video.paused && this.video.currentTime === stallTime) {
|
|
759
|
+
this.Log("Buffer stalled error, no progress in 5 seconds - Restarting player", true);
|
|
696
760
|
}
|
|
697
|
-
});
|
|
761
|
+
}, 5000);
|
|
698
762
|
}
|
|
699
763
|
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
764
|
+
if(error.fatal || this.errors === 3) {
|
|
765
|
+
if(error.response.code === 403) {
|
|
766
|
+
// Not allowed to access
|
|
767
|
+
this.Destroy();
|
|
768
|
+
} else {
|
|
769
|
+
this.HardReload(error);
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
});
|
|
705
773
|
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
});
|
|
774
|
+
this.hlsPlayer = hlsPlayer;
|
|
775
|
+
this.player = hlsPlayer;
|
|
776
|
+
}
|
|
777
|
+
}
|
|
711
778
|
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
779
|
+
async InitializeDash({playoutUrl, authorizationToken, drm, drms, multiviewOptions, controlsPromise}) {
|
|
780
|
+
const DashPlayer = (await import("dashjs")).default;
|
|
781
|
+
const dashPlayer = DashPlayer.MediaPlayer().create();
|
|
715
782
|
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
783
|
+
if(this.playerOptions.capLevelToPlayerSize) {
|
|
784
|
+
dashPlayer.updateSettings({
|
|
785
|
+
"streaming": {
|
|
786
|
+
"fastSwitchEnabled": true,
|
|
787
|
+
"abr": {
|
|
788
|
+
"limitBitrateByPortal": true
|
|
789
|
+
}
|
|
721
790
|
}
|
|
791
|
+
});
|
|
792
|
+
}
|
|
722
793
|
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
794
|
+
playoutUrl.removeQuery("authorization");
|
|
795
|
+
dashPlayer.extend("RequestModifier", function () {
|
|
796
|
+
return {
|
|
797
|
+
modifyRequestHeader: xhr => {
|
|
798
|
+
xhr.setRequestHeader("Authorization", `Bearer ${authorizationToken}`);
|
|
728
799
|
|
|
729
|
-
|
|
800
|
+
return xhr;
|
|
801
|
+
},
|
|
802
|
+
modifyRequestURL: url => url
|
|
803
|
+
};
|
|
804
|
+
});
|
|
730
805
|
|
|
731
|
-
|
|
732
|
-
|
|
806
|
+
// Widevine
|
|
807
|
+
if(drm === EluvioPlayerParameters.drms.WIDEVINE) {
|
|
808
|
+
const widevineUrl = drms.widevine.licenseServers[0];
|
|
733
809
|
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
810
|
+
dashPlayer.setProtectionData({
|
|
811
|
+
"com.widevine.alpha": {
|
|
812
|
+
"serverURL": widevineUrl
|
|
813
|
+
}
|
|
814
|
+
});
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
dashPlayer.initialize(
|
|
818
|
+
this.video,
|
|
819
|
+
playoutUrl.toString(),
|
|
820
|
+
this.playerOptions.autoplay === EluvioPlayerParameters.autoplay.ON
|
|
821
|
+
);
|
|
822
|
+
|
|
823
|
+
if(multiviewOptions.enabled) { controlsPromise.then(() => this.controls.InitializeMultiViewControls(multiviewOptions)); }
|
|
824
|
+
|
|
825
|
+
const UpdateQualityOptions = () => {
|
|
826
|
+
try {
|
|
827
|
+
this.controls.SetQualityControls({
|
|
828
|
+
GetLevels: () => {
|
|
829
|
+
let levels = dashPlayer.getBitrateInfoListFor("video")
|
|
830
|
+
.map((level) => ({
|
|
831
|
+
index: level.qualityIndex,
|
|
832
|
+
active: level.qualityIndex === this.player.getQualityFor("video"),
|
|
833
|
+
resolution: `${level.width}x${level.height}`,
|
|
834
|
+
bitrate: level.bitrate,
|
|
835
|
+
label: `${level.width}x${level.height} (${(level.bitrate / 1000 / 1000).toFixed(1)}Mbps)`,
|
|
836
|
+
activeLabel: `Quality: ${level.width}x${level.height}`,
|
|
837
|
+
}))
|
|
838
|
+
.sort((a, b) => a.bitrate < b.bitrate ? 1 : -1);
|
|
839
|
+
|
|
840
|
+
levels.unshift({index: -1, label: "Auto"});
|
|
841
|
+
|
|
842
|
+
return { label: "Quality", options: levels };
|
|
843
|
+
},
|
|
844
|
+
SetLevel: levelIndex => {
|
|
845
|
+
dashPlayer.setQualityFor("video", levelIndex);
|
|
846
|
+
dashPlayer.updateSettings({
|
|
847
|
+
streaming: {
|
|
848
|
+
trackSwitchMode: "alwaysReplace",
|
|
849
|
+
fastSwitchEnabled: true,
|
|
850
|
+
abr: {
|
|
851
|
+
autoSwitchBitrate: {
|
|
852
|
+
video: levelIndex === -1
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
});
|
|
857
|
+
}
|
|
740
858
|
});
|
|
859
|
+
} catch (error) {
|
|
860
|
+
// eslint-disable-next-line no-console
|
|
861
|
+
console.error("ELUVIO PLAYER:", error);
|
|
741
862
|
}
|
|
863
|
+
};
|
|
742
864
|
|
|
743
|
-
|
|
744
|
-
|
|
865
|
+
const UpdateAudioTracks = () => {
|
|
866
|
+
this.controls.SetAudioTrackControls({
|
|
867
|
+
GetAudioTracks: () => {
|
|
868
|
+
const tracks = this.player.getTracksFor("audio").map(track => ({
|
|
869
|
+
index: track.index,
|
|
870
|
+
label: track.labels && track.labels.length > 0 ? track.labels[0].text : track.lang,
|
|
871
|
+
active: track.index === dashPlayer.getCurrentTrackFor("audio").index,
|
|
872
|
+
activeLabel: `Audio: ${track.labels && track.labels.length > 0 ? track.labels[0].text : track.lang}`
|
|
873
|
+
}));
|
|
874
|
+
|
|
875
|
+
return { label: "Audio Track", options: tracks };
|
|
876
|
+
},
|
|
877
|
+
SetAudioTrack: index => {
|
|
878
|
+
const track = dashPlayer.getTracksFor("audio").find(track => track.index === index);
|
|
879
|
+
dashPlayer.setCurrentTrack(track);
|
|
880
|
+
}
|
|
881
|
+
});
|
|
882
|
+
};
|
|
745
883
|
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
884
|
+
dashPlayer.on(DashPlayer.MediaPlayer.events.QUALITY_CHANGE_RENDERED, () => UpdateQualityOptions());
|
|
885
|
+
dashPlayer.on(DashPlayer.MediaPlayer.events.TRACK_CHANGE_RENDERED, () => {
|
|
886
|
+
UpdateAudioTracks();
|
|
887
|
+
this.UpdateTextTracks({dashPlayer});
|
|
888
|
+
});
|
|
889
|
+
dashPlayer.on(DashPlayer.MediaPlayer.events.MANIFEST_LOADED, () => {
|
|
890
|
+
UpdateQualityOptions();
|
|
891
|
+
UpdateAudioTracks();
|
|
892
|
+
this.UpdateTextTracks({dashPlayer});
|
|
893
|
+
});
|
|
894
|
+
|
|
895
|
+
this.player = dashPlayer;
|
|
896
|
+
this.dashPlayer = dashPlayer;
|
|
897
|
+
}
|
|
753
898
|
|
|
754
|
-
|
|
899
|
+
UpdateTextTracks({dashPlayer}={}) {
|
|
900
|
+
this.controls.SetTextTrackControls({
|
|
901
|
+
GetTextTracks: () => {
|
|
902
|
+
const activeTrackIndex = Array.from(this.video.textTracks).findIndex(track => track.mode === "showing");
|
|
903
|
+
|
|
904
|
+
let tracks;
|
|
905
|
+
if(dashPlayer) {
|
|
906
|
+
tracks = dashPlayer.getTracksFor("text").map((track, index) => ({
|
|
907
|
+
index: index,
|
|
908
|
+
label: track.labels && track.labels.length > 0 ? track.labels[0].text : track.lang,
|
|
909
|
+
active: index === activeTrackIndex,
|
|
910
|
+
activeLabel: `Subtitles: ${track.labels && track.labels.length > 0 ? track.labels[0].text : track.lang}`
|
|
911
|
+
}));
|
|
912
|
+
} else {
|
|
913
|
+
tracks = Array.from(this.video.textTracks).map((track, index) => ({
|
|
914
|
+
index: index,
|
|
915
|
+
label: track.label || track.language,
|
|
916
|
+
active: track.mode === "showing",
|
|
917
|
+
activeLabel: `Subtitles: ${track.label || track.language}`
|
|
918
|
+
}));
|
|
919
|
+
}
|
|
755
920
|
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
921
|
+
tracks.unshift({
|
|
922
|
+
index: -1,
|
|
923
|
+
label: "Disabled",
|
|
924
|
+
active: activeTrackIndex < 0,
|
|
925
|
+
activeLabel: "Subtitles: Disabled"
|
|
926
|
+
});
|
|
762
927
|
|
|
763
|
-
|
|
764
|
-
|
|
928
|
+
return { label: "Subtitles", options: tracks };
|
|
929
|
+
},
|
|
930
|
+
SetTextTrack: index => {
|
|
931
|
+
const tracks = Array.from(this.video.textTracks);
|
|
932
|
+
tracks.map(track => track.mode = "disabled");
|
|
933
|
+
|
|
934
|
+
if(index >= 0) {
|
|
935
|
+
tracks[index].mode = "showing";
|
|
936
|
+
}
|
|
765
937
|
}
|
|
766
|
-
}
|
|
938
|
+
});
|
|
767
939
|
}
|
|
768
940
|
}
|
|
769
941
|
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
<svg width="25" height="16" viewBox="0 0 25 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path d="M1.5 8L24 8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
3
|
+
<path d="M8.5 1L1.5 8L8.5 15" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
4
|
+
</svg>
|
|
@@ -6,6 +6,8 @@ $black: #000;
|
|
|
6
6
|
|
|
7
7
|
$background-color: $black;
|
|
8
8
|
$controls-color: rgba(0, 0, 0, 0.4);
|
|
9
|
+
$menu-color: rgba(0, 0, 0, 0.8);
|
|
10
|
+
$menu-active-color: rgba(255, 255, 255, 0.1);
|
|
9
11
|
$button-color: rgba($white, 0.8);
|
|
10
12
|
$progress-color: #0885fb;
|
|
11
13
|
$slider-color: rgba($gray, 0.5);
|
|
@@ -343,7 +345,7 @@ $button-height: 35px;
|
|
|
343
345
|
}
|
|
344
346
|
|
|
345
347
|
&__settings-menu {
|
|
346
|
-
background: $
|
|
348
|
+
background: $menu-color;
|
|
347
349
|
border-radius: 3px;
|
|
348
350
|
bottom: 45px;
|
|
349
351
|
color: $button-color;
|
|
@@ -352,7 +354,7 @@ $button-height: 35px;
|
|
|
352
354
|
overflow-y: auto;
|
|
353
355
|
position: absolute;
|
|
354
356
|
right: 10px;
|
|
355
|
-
width:
|
|
357
|
+
width: 250px;
|
|
356
358
|
z-index: 100;
|
|
357
359
|
|
|
358
360
|
&-hidden {
|
|
@@ -369,16 +371,34 @@ $button-height: 35px;
|
|
|
369
371
|
cursor: pointer;
|
|
370
372
|
display: block;
|
|
371
373
|
font-size: 14px;
|
|
372
|
-
height:
|
|
374
|
+
height: max-content;
|
|
375
|
+
line-height: 1.4;
|
|
373
376
|
padding: 9px 20px;
|
|
377
|
+
text-align: left;
|
|
374
378
|
width: 100%;
|
|
375
379
|
|
|
380
|
+
&-back {
|
|
381
|
+
display: flex;
|
|
382
|
+
font-weight: 500;
|
|
383
|
+
width: 100%;
|
|
384
|
+
|
|
385
|
+
svg {
|
|
386
|
+
height: 15px;
|
|
387
|
+
margin-right: 5px;
|
|
388
|
+
width: 15px;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
div {
|
|
392
|
+
width: 100%;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
376
396
|
&-selected {
|
|
377
397
|
color: $button-color;
|
|
378
398
|
}
|
|
379
399
|
|
|
380
400
|
&:hover {
|
|
381
|
-
background: $
|
|
401
|
+
background: $menu-active-color;
|
|
382
402
|
color: $button-color;
|
|
383
403
|
}
|
|
384
404
|
|
|
@@ -592,11 +612,13 @@ $button-height: 35px;
|
|
|
592
612
|
}
|
|
593
613
|
|
|
594
614
|
.eluvio-player__controls__button {
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
615
|
+
&:not(.eluvio-player__big-play-button) {
|
|
616
|
+
height: CALC(#{$button-height} * 0.9);
|
|
617
|
+
max-height: CALC(#{$button-height} * 0.9);
|
|
618
|
+
max-width: CALC(#{$button-height} * 0.9);
|
|
619
|
+
min-height: CALC(#{$button-height} * 0.9);
|
|
620
|
+
min-width: CALC(#{$button-height} * 0.9);
|
|
621
|
+
}
|
|
600
622
|
}
|
|
601
623
|
|
|
602
624
|
.eluvio-player__controls__volume-container {
|
|
@@ -604,10 +626,10 @@ $button-height: 35px;
|
|
|
604
626
|
}
|
|
605
627
|
|
|
606
628
|
.eluvio-player__big-play-button {
|
|
607
|
-
max-height:
|
|
608
|
-
max-width:
|
|
609
|
-
min-height:
|
|
610
|
-
min-width:
|
|
629
|
+
max-height: 55px;
|
|
630
|
+
max-width: 55px;
|
|
631
|
+
min-height: 55px;
|
|
632
|
+
min-width: 55px;
|
|
611
633
|
}
|
|
612
634
|
|
|
613
635
|
.eluvio-player__ticket-modal {
|
|
@@ -645,6 +667,14 @@ $button-height: 35px;
|
|
|
645
667
|
}
|
|
646
668
|
}
|
|
647
669
|
|
|
670
|
+
.eluvio-player__controls__settings-menu {
|
|
671
|
+
height: 100%;
|
|
672
|
+
padding: 20px 0;
|
|
673
|
+
right: 0;
|
|
674
|
+
top: 0;
|
|
675
|
+
width: 100%;
|
|
676
|
+
}
|
|
677
|
+
|
|
648
678
|
.eluvio-player__hotspot-overlay {
|
|
649
679
|
.eluvio-player__hotspot-overlay__target {
|
|
650
680
|
.eluvio-player__hotspot-overlay__target__title {
|