vidply 1.0.31 → 1.0.33
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 +708 -708
- package/dist/dev/{vidply.HLSRenderer-ENLZE4QS.js → vidply.HLSRenderer-LIFBU6UD.js} +61 -10
- package/dist/dev/vidply.HLSRenderer-LIFBU6UD.js.map +7 -0
- package/dist/dev/{vidply.HTML5Renderer-6SBDI6S2.js → vidply.HTML5Renderer-YWMVYWFS.js} +2 -2
- package/dist/dev/{vidply.TranscriptManager-T677KF4N.js → vidply.TranscriptManager-R7NJRU7E.js} +2 -2
- package/dist/dev/{vidply.chunk-GS2JX5RQ.js → vidply.chunk-PMRKJBGH.js} +5 -2
- package/dist/dev/vidply.chunk-PMRKJBGH.js.map +7 -0
- package/dist/dev/{vidply.chunk-W2LSBD6Y.js → vidply.chunk-UVO24MXU.js} +33 -3
- package/dist/dev/vidply.chunk-UVO24MXU.js.map +7 -0
- package/dist/dev/{vidply.de-SNL6AJ4D.js → vidply.de-CEGBLV67.js} +4 -1
- package/dist/dev/vidply.de-CEGBLV67.js.map +7 -0
- package/dist/dev/vidply.esm.js +374 -64
- package/dist/dev/vidply.esm.js.map +2 -2
- package/dist/legacy/vidply.js +483 -71
- package/dist/legacy/vidply.js.map +3 -3
- package/dist/legacy/vidply.min.js +1 -1
- package/dist/legacy/vidply.min.meta.json +15 -15
- package/dist/prod/vidply.HLSRenderer-ESR6NAMI.min.js +6 -0
- package/dist/prod/{vidply.HTML5Renderer-KKW3OLHM.min.js → vidply.HTML5Renderer-6ROXQSQY.min.js} +1 -1
- package/dist/prod/{vidply.TranscriptManager-WFZSW6NR.min.js → vidply.TranscriptManager-B65LKXGG.min.js} +1 -1
- package/dist/prod/vidply.chunk-7HVHEUHH.min.js +6 -0
- package/dist/prod/vidply.chunk-IQKD4GUB.min.js +6 -0
- package/dist/prod/vidply.de-IHKC573T.min.js +6 -0
- package/dist/prod/vidply.esm.min.js +9 -9
- package/dist/vidply.esm.min.meta.json +33 -33
- package/package.json +1 -1
- package/src/controls/ControlBar.js +120 -71
- package/src/core/Player.js +5087 -4868
- package/src/features/PlaylistManager.js +1669 -1511
- package/src/i18n/languages/de.js +3 -0
- package/src/i18n/languages/en.js +3 -0
- package/src/renderers/HLSRenderer.js +77 -8
- package/src/renderers/HTML5Renderer.js +43 -5
- package/dist/dev/vidply.HLSRenderer-ENLZE4QS.js.map +0 -7
- package/dist/dev/vidply.HLSRenderer-UMPUDSYL.js +0 -266
- package/dist/dev/vidply.HLSRenderer-UMPUDSYL.js.map +0 -7
- package/dist/dev/vidply.HTML5Renderer-FXBZQL6Y.js +0 -12
- package/dist/dev/vidply.HTML5Renderer-FXBZQL6Y.js.map +0 -7
- package/dist/dev/vidply.chunk-BCOFCT6U.js +0 -246
- package/dist/dev/vidply.chunk-BCOFCT6U.js.map +0 -7
- package/dist/dev/vidply.chunk-GS2JX5RQ.js.map +0 -7
- package/dist/dev/vidply.chunk-W2LSBD6Y.js.map +0 -7
- package/dist/dev/vidply.de-SNL6AJ4D.js.map +0 -7
- package/dist/prod/vidply.HLSRenderer-3CG7BZKA.min.js +0 -6
- package/dist/prod/vidply.HLSRenderer-CBXZ4RF2.min.js +0 -6
- package/dist/prod/vidply.HTML5Renderer-MY7XDV7R.min.js +0 -6
- package/dist/prod/vidply.chunk-34RH2THY.min.js +0 -6
- package/dist/prod/vidply.chunk-LGTJRPUL.min.js +0 -6
- package/dist/prod/vidply.chunk-OXXPY2XB.min.js +0 -6
- package/dist/prod/vidply.de-FR3XX54P.min.js +0 -6
- /package/dist/dev/{vidply.HTML5Renderer-6SBDI6S2.js.map → vidply.HTML5Renderer-YWMVYWFS.js.map} +0 -0
- /package/dist/dev/{vidply.TranscriptManager-T677KF4N.js.map → vidply.TranscriptManager-R7NJRU7E.js.map} +0 -0
package/dist/dev/vidply.esm.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import {
|
|
7
7
|
HTML5Renderer
|
|
8
|
-
} from "./vidply.chunk-
|
|
8
|
+
} from "./vidply.chunk-UVO24MXU.js";
|
|
9
9
|
import {
|
|
10
10
|
DOMUtils,
|
|
11
11
|
DraggableResizable,
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
focusFirstMenuItem,
|
|
22
22
|
i18n,
|
|
23
23
|
preventDragOnElement
|
|
24
|
-
} from "./vidply.chunk-
|
|
24
|
+
} from "./vidply.chunk-PMRKJBGH.js";
|
|
25
25
|
|
|
26
26
|
// src/utils/EventEmitter.js
|
|
27
27
|
var EventEmitter = class {
|
|
@@ -189,6 +189,8 @@ var ControlBar = class {
|
|
|
189
189
|
init() {
|
|
190
190
|
this.createElement();
|
|
191
191
|
this.createControls();
|
|
192
|
+
this.updateDuration();
|
|
193
|
+
this.updateProgress();
|
|
192
194
|
this.attachEvents();
|
|
193
195
|
this.setupAutoHide();
|
|
194
196
|
this.setupOverflowDetection();
|
|
@@ -667,7 +669,11 @@ var ControlBar = class {
|
|
|
667
669
|
btn.dataset.overflowPriorityMobile = "3";
|
|
668
670
|
this.rightButtons.appendChild(btn);
|
|
669
671
|
}
|
|
670
|
-
|
|
672
|
+
const src = this.player.currentSource || this.player.element?.getAttribute?.("src") || this.player.element?.currentSrc || this.player.element?.src || this.player.element?.querySelector?.("source")?.getAttribute?.("src") || this.player.element?.querySelector?.("source")?.src || "";
|
|
673
|
+
const isHlsSource = typeof src === "string" && src.includes(".m3u8");
|
|
674
|
+
const isVideoElement = this.player.element?.tagName?.toLowerCase() === "video";
|
|
675
|
+
const hideSpeedForThisPlayer = !!this.player.options.hideSpeedForHls && isHlsSource || !!this.player.options.hideSpeedForHlsVideo && isHlsSource && isVideoElement;
|
|
676
|
+
if (this.player.options.speedButton && !hideSpeedForThisPlayer) {
|
|
671
677
|
const btn = this.createSpeedButton();
|
|
672
678
|
btn.dataset.overflowPriority = "1";
|
|
673
679
|
btn.dataset.overflowPriorityMobile = "3";
|
|
@@ -751,18 +757,28 @@ var ControlBar = class {
|
|
|
751
757
|
hasChapterTracks() {
|
|
752
758
|
const textTracks = this.player.element.textTracks;
|
|
753
759
|
for (let i = 0; i < textTracks.length; i++) {
|
|
754
|
-
if (textTracks[i].kind === "chapters")
|
|
755
|
-
|
|
756
|
-
|
|
760
|
+
if (textTracks[i].kind === "chapters") return true;
|
|
761
|
+
}
|
|
762
|
+
const trackEls = Array.from(this.player.element.querySelectorAll('track[kind="chapters"]'));
|
|
763
|
+
if (trackEls.length > 0) return true;
|
|
764
|
+
const current = this.player.playlistManager?.getCurrentTrack?.();
|
|
765
|
+
if (current?.tracks && Array.isArray(current.tracks)) {
|
|
766
|
+
return current.tracks.some((t) => t?.kind === "chapters");
|
|
757
767
|
}
|
|
758
768
|
return false;
|
|
759
769
|
}
|
|
760
770
|
hasCaptionTracks() {
|
|
761
771
|
const textTracks = this.player.element.textTracks;
|
|
762
772
|
for (let i = 0; i < textTracks.length; i++) {
|
|
763
|
-
if (textTracks[i].kind === "captions" || textTracks[i].kind === "subtitles")
|
|
764
|
-
|
|
765
|
-
|
|
773
|
+
if (textTracks[i].kind === "captions" || textTracks[i].kind === "subtitles") return true;
|
|
774
|
+
}
|
|
775
|
+
const trackEls = Array.from(this.player.element.querySelectorAll("track"));
|
|
776
|
+
if (trackEls.some((el) => el.getAttribute("kind") === "captions" || el.getAttribute("kind") === "subtitles")) {
|
|
777
|
+
return true;
|
|
778
|
+
}
|
|
779
|
+
const current = this.player.playlistManager?.getCurrentTrack?.();
|
|
780
|
+
if (current?.tracks && Array.isArray(current.tracks)) {
|
|
781
|
+
return current.tracks.some((t) => t?.kind === "captions" || t?.kind === "subtitles");
|
|
766
782
|
}
|
|
767
783
|
return false;
|
|
768
784
|
}
|
|
@@ -837,55 +853,64 @@ var ControlBar = class {
|
|
|
837
853
|
this.currentPreviewTime = null;
|
|
838
854
|
this.previewThumbnailTimeout = null;
|
|
839
855
|
this.previewSupported = false;
|
|
856
|
+
this.previewVideoReady = false;
|
|
857
|
+
this.previewVideoInitialized = false;
|
|
840
858
|
const isVideo = this.player.element && this.player.element.tagName === "VIDEO";
|
|
841
859
|
if (!isVideo) {
|
|
842
860
|
return;
|
|
843
861
|
}
|
|
862
|
+
}
|
|
863
|
+
/**
|
|
864
|
+
* Lazily create the hidden preview video (only after playback started once)
|
|
865
|
+
*/
|
|
866
|
+
ensurePreviewVideoInitialized() {
|
|
867
|
+
if (this.previewVideoInitialized) return;
|
|
868
|
+
if (!this.player?.state?.hasStartedPlayback) return;
|
|
844
869
|
const renderer = this.player.renderer;
|
|
845
870
|
const hasVideoMedia = renderer && renderer.media && renderer.media.tagName === "VIDEO";
|
|
846
871
|
const isHTML5Renderer = hasVideoMedia && renderer.media === this.player.element && !renderer.hls && typeof renderer.seek === "function";
|
|
847
872
|
this.previewSupported = isHTML5Renderer && hasVideoMedia;
|
|
848
|
-
if (this.previewSupported)
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
this.previewVideo.style.top = "-9999px";
|
|
858
|
-
const mainVideo = renderer.media || this.player.element;
|
|
859
|
-
let videoSrc = null;
|
|
860
|
-
if (mainVideo.src) {
|
|
861
|
-
videoSrc = mainVideo.src;
|
|
862
|
-
} else {
|
|
863
|
-
const source = mainVideo.querySelector("source");
|
|
864
|
-
if (source) {
|
|
865
|
-
videoSrc = source.src;
|
|
866
|
-
}
|
|
867
|
-
}
|
|
868
|
-
if (!videoSrc) {
|
|
869
|
-
this.player.log("No video source found for preview", "warn");
|
|
870
|
-
this.previewSupported = false;
|
|
871
|
-
return;
|
|
872
|
-
}
|
|
873
|
-
if (mainVideo.crossOrigin) {
|
|
874
|
-
this.previewVideo.crossOrigin = mainVideo.crossOrigin;
|
|
875
|
-
}
|
|
876
|
-
this.previewVideo.addEventListener("error", (e) => {
|
|
877
|
-
this.player.log("Preview video failed to load:", e, "warn");
|
|
878
|
-
this.previewSupported = false;
|
|
879
|
-
});
|
|
880
|
-
this.previewVideo.addEventListener("loadedmetadata", () => {
|
|
881
|
-
this.previewVideoReady = true;
|
|
882
|
-
}, { once: true });
|
|
883
|
-
if (this.player.container) {
|
|
884
|
-
this.player.container.appendChild(this.previewVideo);
|
|
873
|
+
if (!this.previewSupported) return;
|
|
874
|
+
const mainVideo = renderer.media || this.player.element;
|
|
875
|
+
let videoSrc = null;
|
|
876
|
+
if (mainVideo.src) {
|
|
877
|
+
videoSrc = mainVideo.src;
|
|
878
|
+
} else {
|
|
879
|
+
const source = mainVideo.querySelector("source");
|
|
880
|
+
if (source) {
|
|
881
|
+
videoSrc = source.src;
|
|
885
882
|
}
|
|
886
|
-
this.previewVideo.src = videoSrc;
|
|
887
|
-
this.previewVideoReady = false;
|
|
888
883
|
}
|
|
884
|
+
if (!videoSrc) {
|
|
885
|
+
this.player.log("No video source found for preview", "warn");
|
|
886
|
+
this.previewSupported = false;
|
|
887
|
+
return;
|
|
888
|
+
}
|
|
889
|
+
this.previewVideo = document.createElement("video");
|
|
890
|
+
this.previewVideo.muted = true;
|
|
891
|
+
this.previewVideo.preload = "auto";
|
|
892
|
+
this.previewVideo.playsInline = true;
|
|
893
|
+
this.previewVideo.style.position = "absolute";
|
|
894
|
+
this.previewVideo.style.visibility = "hidden";
|
|
895
|
+
this.previewVideo.style.width = "1px";
|
|
896
|
+
this.previewVideo.style.height = "1px";
|
|
897
|
+
this.previewVideo.style.top = "-9999px";
|
|
898
|
+
if (mainVideo.crossOrigin) {
|
|
899
|
+
this.previewVideo.crossOrigin = mainVideo.crossOrigin;
|
|
900
|
+
}
|
|
901
|
+
this.previewVideo.addEventListener("error", (e) => {
|
|
902
|
+
this.player.log("Preview video failed to load:", e, "warn");
|
|
903
|
+
this.previewSupported = false;
|
|
904
|
+
});
|
|
905
|
+
this.previewVideo.addEventListener("loadedmetadata", () => {
|
|
906
|
+
this.previewVideoReady = true;
|
|
907
|
+
}, { once: true });
|
|
908
|
+
if (this.player.container) {
|
|
909
|
+
this.player.container.appendChild(this.previewVideo);
|
|
910
|
+
}
|
|
911
|
+
this.previewVideo.src = videoSrc;
|
|
912
|
+
this.previewVideoReady = false;
|
|
913
|
+
this.previewVideoInitialized = true;
|
|
889
914
|
}
|
|
890
915
|
/**
|
|
891
916
|
* Generate preview thumbnail for a specific time
|
|
@@ -1018,8 +1043,17 @@ var ControlBar = class {
|
|
|
1018
1043
|
this.controls.progressTooltipTime.textContent = TimeUtils.formatTime(time);
|
|
1019
1044
|
this.controls.progressTooltip.style.left = `${left}px`;
|
|
1020
1045
|
this.controls.progressTooltip.style.display = "block";
|
|
1046
|
+
if (!this.player?.state?.hasStartedPlayback) {
|
|
1047
|
+
if (this.controls.progressPreview) {
|
|
1048
|
+
this.controls.progressPreview.style.display = "none";
|
|
1049
|
+
}
|
|
1050
|
+
return;
|
|
1051
|
+
}
|
|
1052
|
+
this.ensurePreviewVideoInitialized();
|
|
1021
1053
|
if (this.previewSupported) {
|
|
1022
1054
|
this.updatePreviewThumbnail(time);
|
|
1055
|
+
} else if (this.controls.progressPreview) {
|
|
1056
|
+
this.controls.progressPreview.style.display = "none";
|
|
1023
1057
|
}
|
|
1024
1058
|
}
|
|
1025
1059
|
});
|
|
@@ -4863,6 +4897,17 @@ var Player = class _Player extends EventEmitter {
|
|
|
4863
4897
|
volume: 0.8,
|
|
4864
4898
|
playbackSpeed: 1,
|
|
4865
4899
|
preload: "metadata",
|
|
4900
|
+
// Optional initial duration (seconds) so UI can show duration
|
|
4901
|
+
// before media metadata is loaded (useful with deferLoad/preload=none).
|
|
4902
|
+
initialDuration: 0,
|
|
4903
|
+
// When enabled, VidPly will not start network loading during init().
|
|
4904
|
+
// - HTML5: does not call element.load() until the first user-initiated play()
|
|
4905
|
+
// - HLS (hls.js): does not load manifest/segments until the first play()
|
|
4906
|
+
// This is useful for pages with many players to avoid high initial bandwidth.
|
|
4907
|
+
deferLoad: false,
|
|
4908
|
+
// When enabled, clicking Audio Description / Sign Language before playback will show
|
|
4909
|
+
// a notice instead of implicitly starting playback/loading.
|
|
4910
|
+
requirePlaybackForAccessibilityToggles: false,
|
|
4866
4911
|
startTime: 0,
|
|
4867
4912
|
playsInline: true,
|
|
4868
4913
|
// Enable inline playback on iOS (prevents native fullscreen)
|
|
@@ -4879,6 +4924,11 @@ var Player = class _Player extends EventEmitter {
|
|
|
4879
4924
|
qualityButton: true,
|
|
4880
4925
|
captionStyleButton: true,
|
|
4881
4926
|
speedButton: true,
|
|
4927
|
+
// When enabled, the playback speed UI is suppressed for ALL HLS streams (audio + video).
|
|
4928
|
+
hideSpeedForHls: false,
|
|
4929
|
+
// When enabled, the playback speed UI is suppressed for HLS *video* streams only.
|
|
4930
|
+
// This is useful for live streams where speed controls don't make sense.
|
|
4931
|
+
hideSpeedForHlsVideo: false,
|
|
4882
4932
|
captionsButton: true,
|
|
4883
4933
|
transcriptButton: true,
|
|
4884
4934
|
fullscreenButton: true,
|
|
@@ -4956,6 +5006,8 @@ var Player = class _Player extends EventEmitter {
|
|
|
4956
5006
|
};
|
|
4957
5007
|
this.options.metadataAlerts = this.options.metadataAlerts || {};
|
|
4958
5008
|
this.options.metadataHashtags = this.options.metadataHashtags || {};
|
|
5009
|
+
this.noticeElement = null;
|
|
5010
|
+
this.noticeTimeout = null;
|
|
4959
5011
|
this.storage = new StorageManager("vidply");
|
|
4960
5012
|
const savedPrefs = this.storage.getPlayerPreferences();
|
|
4961
5013
|
if (savedPrefs) {
|
|
@@ -4970,10 +5022,11 @@ var Player = class _Player extends EventEmitter {
|
|
|
4970
5022
|
ended: false,
|
|
4971
5023
|
buffering: false,
|
|
4972
5024
|
seeking: false,
|
|
5025
|
+
hasStartedPlayback: false,
|
|
4973
5026
|
muted: this.options.muted,
|
|
4974
5027
|
volume: this.options.volume,
|
|
4975
5028
|
currentTime: 0,
|
|
4976
|
-
duration: 0,
|
|
5029
|
+
duration: Number(this.options.initialDuration) > 0 ? Number(this.options.initialDuration) : 0,
|
|
4977
5030
|
playbackSpeed: this.options.playbackSpeed,
|
|
4978
5031
|
fullscreen: false,
|
|
4979
5032
|
pip: false,
|
|
@@ -5062,6 +5115,51 @@ var Player = class _Player extends EventEmitter {
|
|
|
5062
5115
|
});
|
|
5063
5116
|
this.init();
|
|
5064
5117
|
}
|
|
5118
|
+
/**
|
|
5119
|
+
* Show a small in-player notice (non-blocking), also announced to screen readers.
|
|
5120
|
+
*/
|
|
5121
|
+
showNotice(message, { timeout = 2500, priority = "polite" } = {}) {
|
|
5122
|
+
try {
|
|
5123
|
+
if (!message) return;
|
|
5124
|
+
if (!this.container) return;
|
|
5125
|
+
if (this.keyboardManager?.announce) {
|
|
5126
|
+
this.keyboardManager.announce(message, priority);
|
|
5127
|
+
}
|
|
5128
|
+
if (!this.noticeElement) {
|
|
5129
|
+
const el = document.createElement("div");
|
|
5130
|
+
el.className = `${this.options.classPrefix}-notice`;
|
|
5131
|
+
el.setAttribute("role", "status");
|
|
5132
|
+
el.setAttribute("aria-live", priority);
|
|
5133
|
+
el.setAttribute("aria-atomic", "true");
|
|
5134
|
+
el.style.position = "absolute";
|
|
5135
|
+
el.style.left = "0.75rem";
|
|
5136
|
+
el.style.right = "0.75rem";
|
|
5137
|
+
el.style.top = "0.75rem";
|
|
5138
|
+
el.style.zIndex = "9999";
|
|
5139
|
+
el.style.padding = "0.5rem 0.75rem";
|
|
5140
|
+
el.style.borderRadius = "0.5rem";
|
|
5141
|
+
el.style.background = "rgba(0, 0, 0, 0.75)";
|
|
5142
|
+
el.style.color = "#fff";
|
|
5143
|
+
el.style.fontSize = "0.875rem";
|
|
5144
|
+
el.style.lineHeight = "1.3";
|
|
5145
|
+
el.style.pointerEvents = "none";
|
|
5146
|
+
this.noticeElement = el;
|
|
5147
|
+
this.container.appendChild(el);
|
|
5148
|
+
}
|
|
5149
|
+
this.noticeElement.textContent = message;
|
|
5150
|
+
this.noticeElement.style.display = "block";
|
|
5151
|
+
if (this.noticeTimeout) {
|
|
5152
|
+
clearTimeout(this.noticeTimeout);
|
|
5153
|
+
this.noticeTimeout = null;
|
|
5154
|
+
}
|
|
5155
|
+
this.noticeTimeout = setTimeout(() => {
|
|
5156
|
+
if (this.noticeElement) {
|
|
5157
|
+
this.noticeElement.style.display = "none";
|
|
5158
|
+
}
|
|
5159
|
+
}, timeout);
|
|
5160
|
+
} catch (e) {
|
|
5161
|
+
}
|
|
5162
|
+
}
|
|
5065
5163
|
async init() {
|
|
5066
5164
|
try {
|
|
5067
5165
|
this.log("Initializing VidPly player");
|
|
@@ -5153,7 +5251,7 @@ var Player = class _Player extends EventEmitter {
|
|
|
5153
5251
|
if (!this.options.transcript && !this.options.transcriptButton) {
|
|
5154
5252
|
return null;
|
|
5155
5253
|
}
|
|
5156
|
-
const module = await import("./vidply.TranscriptManager-
|
|
5254
|
+
const module = await import("./vidply.TranscriptManager-R7NJRU7E.js");
|
|
5157
5255
|
const Manager = module.TranscriptManager || module.default;
|
|
5158
5256
|
if (!Manager) {
|
|
5159
5257
|
return null;
|
|
@@ -5237,8 +5335,23 @@ var Player = class _Player extends EventEmitter {
|
|
|
5237
5335
|
if (this.options.height) {
|
|
5238
5336
|
this.container.style.height = typeof this.options.height === "number" ? `${this.options.height}px` : this.options.height;
|
|
5239
5337
|
}
|
|
5338
|
+
if (this.element.tagName === "VIDEO" && !this.options.height) {
|
|
5339
|
+
const wAttr = parseInt(this.element.getAttribute("width") || "", 10);
|
|
5340
|
+
const hAttr = parseInt(this.element.getAttribute("height") || "", 10);
|
|
5341
|
+
if (Number.isFinite(wAttr) && Number.isFinite(hAttr) && wAttr > 0 && hAttr > 0) {
|
|
5342
|
+
if (!this.container.style.aspectRatio) {
|
|
5343
|
+
this.container.style.aspectRatio = `${wAttr} / ${hAttr}`;
|
|
5344
|
+
}
|
|
5345
|
+
if (this.videoWrapper && !this.videoWrapper.style.aspectRatio) {
|
|
5346
|
+
this.videoWrapper.style.aspectRatio = `${wAttr} / ${hAttr}`;
|
|
5347
|
+
this.videoWrapper.style.height = "auto";
|
|
5348
|
+
}
|
|
5349
|
+
}
|
|
5350
|
+
}
|
|
5240
5351
|
if (this.options.poster && this.element.tagName === "VIDEO") {
|
|
5241
|
-
|
|
5352
|
+
const resolvedPoster = this.resolvePosterPath(this.options.poster);
|
|
5353
|
+
this.element.poster = resolvedPoster;
|
|
5354
|
+
this.applyPosterAspectRatio(resolvedPoster);
|
|
5242
5355
|
}
|
|
5243
5356
|
if (this.element.tagName === "VIDEO") {
|
|
5244
5357
|
this.createPlayButtonOverlay();
|
|
@@ -5252,6 +5365,7 @@ var Player = class _Player extends EventEmitter {
|
|
|
5252
5365
|
}
|
|
5253
5366
|
});
|
|
5254
5367
|
this.on("play", () => {
|
|
5368
|
+
this.state.hasStartedPlayback = true;
|
|
5255
5369
|
this.hidePosterOverlay();
|
|
5256
5370
|
});
|
|
5257
5371
|
this.on("timeupdate", () => {
|
|
@@ -5265,6 +5379,34 @@ var Player = class _Player extends EventEmitter {
|
|
|
5265
5379
|
}
|
|
5266
5380
|
}, { once: true });
|
|
5267
5381
|
}
|
|
5382
|
+
/**
|
|
5383
|
+
* Apply aspect ratio to the video wrapper based on the poster's intrinsic size.
|
|
5384
|
+
* This helps render correct poster sizing before media metadata is available.
|
|
5385
|
+
*/
|
|
5386
|
+
applyPosterAspectRatio(posterUrl) {
|
|
5387
|
+
try {
|
|
5388
|
+
if (!posterUrl) return;
|
|
5389
|
+
if (this.element.tagName !== "VIDEO") return;
|
|
5390
|
+
if (!this.videoWrapper) return;
|
|
5391
|
+
if (this.options.width || this.options.height) return;
|
|
5392
|
+
if (this._posterAspectAppliedFor === posterUrl) return;
|
|
5393
|
+
this._posterAspectAppliedFor = posterUrl;
|
|
5394
|
+
const img = new Image();
|
|
5395
|
+
img.decoding = "async";
|
|
5396
|
+
img.onload = () => {
|
|
5397
|
+
const w = img.naturalWidth;
|
|
5398
|
+
const h = img.naturalHeight;
|
|
5399
|
+
if (!w || !h) return;
|
|
5400
|
+
this.videoWrapper.style.aspectRatio = `${w} / ${h}`;
|
|
5401
|
+
this.videoWrapper.style.height = "auto";
|
|
5402
|
+
if (this.container && !this.container.style.aspectRatio) {
|
|
5403
|
+
this.container.style.aspectRatio = `${w} / ${h}`;
|
|
5404
|
+
}
|
|
5405
|
+
};
|
|
5406
|
+
img.src = posterUrl;
|
|
5407
|
+
} catch (e) {
|
|
5408
|
+
}
|
|
5409
|
+
}
|
|
5268
5410
|
createPlayButtonOverlay() {
|
|
5269
5411
|
this.playButtonOverlay = createPlayOverlay();
|
|
5270
5412
|
this.playButtonOverlay.addEventListener("click", () => {
|
|
@@ -5332,7 +5474,7 @@ var Player = class _Player extends EventEmitter {
|
|
|
5332
5474
|
const module = await import("./vidply.VimeoRenderer-VPH4RNES.js");
|
|
5333
5475
|
rendererClass = module.VimeoRenderer || module.default;
|
|
5334
5476
|
} else if (src.includes(".m3u8")) {
|
|
5335
|
-
const module = await import("./vidply.HLSRenderer-
|
|
5477
|
+
const module = await import("./vidply.HLSRenderer-LIFBU6UD.js");
|
|
5336
5478
|
rendererClass = module.HLSRenderer || module.default;
|
|
5337
5479
|
} else if (src.includes("soundcloud.com") || src.includes("api.soundcloud.com")) {
|
|
5338
5480
|
const module = await import("./vidply.SoundCloudRenderer-CD7VJKNS.js");
|
|
@@ -5661,7 +5803,25 @@ var Player = class _Player extends EventEmitter {
|
|
|
5661
5803
|
await this.initializeRenderer();
|
|
5662
5804
|
} else {
|
|
5663
5805
|
this.renderer.media = this.element;
|
|
5664
|
-
this.
|
|
5806
|
+
if (this.options.deferLoad) {
|
|
5807
|
+
try {
|
|
5808
|
+
this.element.preload = this.options.preload || "metadata";
|
|
5809
|
+
} catch (e) {
|
|
5810
|
+
}
|
|
5811
|
+
if (this.renderer) {
|
|
5812
|
+
if (typeof this.renderer._didDeferredLoad === "boolean") {
|
|
5813
|
+
this.renderer._didDeferredLoad = false;
|
|
5814
|
+
}
|
|
5815
|
+
if (typeof this.renderer._hlsSourceLoaded === "boolean") {
|
|
5816
|
+
this.renderer._hlsSourceLoaded = false;
|
|
5817
|
+
}
|
|
5818
|
+
if ("_pendingSrc" in this.renderer) {
|
|
5819
|
+
this.renderer._pendingSrc = this._pendingSource || this.currentSource || null;
|
|
5820
|
+
}
|
|
5821
|
+
}
|
|
5822
|
+
} else {
|
|
5823
|
+
this.element.load();
|
|
5824
|
+
}
|
|
5665
5825
|
}
|
|
5666
5826
|
if (isExternalRenderer) {
|
|
5667
5827
|
setTimeout(() => {
|
|
@@ -5706,6 +5866,20 @@ var Player = class _Player extends EventEmitter {
|
|
|
5706
5866
|
this.handleError(error);
|
|
5707
5867
|
}
|
|
5708
5868
|
}
|
|
5869
|
+
/**
|
|
5870
|
+
* Ensure the current renderer has started its initial load (metadata/manifest)
|
|
5871
|
+
* without starting playback. This is useful for playlists to behave like
|
|
5872
|
+
* single videos on selection, while still keeping autoplay off.
|
|
5873
|
+
*/
|
|
5874
|
+
ensureLoaded() {
|
|
5875
|
+
try {
|
|
5876
|
+
if (!this.renderer) return;
|
|
5877
|
+
if (typeof this.renderer.ensureLoaded === "function") {
|
|
5878
|
+
this.renderer.ensureLoaded();
|
|
5879
|
+
}
|
|
5880
|
+
} catch (e) {
|
|
5881
|
+
}
|
|
5882
|
+
}
|
|
5709
5883
|
/**
|
|
5710
5884
|
* Check if we need to change renderer type
|
|
5711
5885
|
* @param {string} src - New source URL
|
|
@@ -5741,6 +5915,11 @@ var Player = class _Player extends EventEmitter {
|
|
|
5741
5915
|
play() {
|
|
5742
5916
|
if (this.renderer) {
|
|
5743
5917
|
this.renderer.play();
|
|
5918
|
+
return;
|
|
5919
|
+
}
|
|
5920
|
+
if (this.playlistManager && Array.isArray(this.playlistManager.tracks) && this.playlistManager.tracks.length > 0) {
|
|
5921
|
+
const index = this.playlistManager.currentIndex >= 0 ? this.playlistManager.currentIndex : 0;
|
|
5922
|
+
this.playlistManager.play(index, true);
|
|
5744
5923
|
}
|
|
5745
5924
|
}
|
|
5746
5925
|
pause() {
|
|
@@ -7069,6 +7248,17 @@ var Player = class _Player extends EventEmitter {
|
|
|
7069
7248
|
this.emit("audiodescriptiondisabled");
|
|
7070
7249
|
}
|
|
7071
7250
|
async toggleAudioDescription() {
|
|
7251
|
+
if (this.options.requirePlaybackForAccessibilityToggles && !this.renderer && this.playlistManager?.tracks?.length) {
|
|
7252
|
+
this.showNotice(i18n.t("player.startPlaybackForAudioDescription"));
|
|
7253
|
+
return;
|
|
7254
|
+
}
|
|
7255
|
+
if (!this.renderer && this.playlistManager && this.playlistManager.tracks?.length) {
|
|
7256
|
+
this.audioDescriptionManager.desiredState = !this.audioDescriptionManager.desiredState;
|
|
7257
|
+
this.state.audioDescriptionEnabled = this.audioDescriptionManager.desiredState;
|
|
7258
|
+
this.emit(this.audioDescriptionManager.desiredState ? "audiodescriptionenabled" : "audiodescriptiondisabled");
|
|
7259
|
+
this.play();
|
|
7260
|
+
return;
|
|
7261
|
+
}
|
|
7072
7262
|
return this.audioDescriptionManager.toggle();
|
|
7073
7263
|
}
|
|
7074
7264
|
// Sign Language (delegated to SignLanguageManager)
|
|
@@ -7330,6 +7520,18 @@ var Player = class _Player extends EventEmitter {
|
|
|
7330
7520
|
return this.signLanguageManager.disable();
|
|
7331
7521
|
}
|
|
7332
7522
|
toggleSignLanguage() {
|
|
7523
|
+
if (this.options.requirePlaybackForAccessibilityToggles && !this.renderer && this.playlistManager?.tracks?.length) {
|
|
7524
|
+
this.showNotice(i18n.t("player.startPlaybackForSignLanguage"));
|
|
7525
|
+
return;
|
|
7526
|
+
}
|
|
7527
|
+
if (!this.renderer && this.playlistManager && this.playlistManager.tracks?.length) {
|
|
7528
|
+
const wasEnabled = this.signLanguageManager.enabled;
|
|
7529
|
+
const result = this.signLanguageManager.toggle();
|
|
7530
|
+
if (!wasEnabled && this.signLanguageManager.enabled) {
|
|
7531
|
+
this.play();
|
|
7532
|
+
}
|
|
7533
|
+
return result;
|
|
7534
|
+
}
|
|
7333
7535
|
return this.signLanguageManager.toggle();
|
|
7334
7536
|
}
|
|
7335
7537
|
setupSignLanguageInteraction() {
|
|
@@ -8457,6 +8659,7 @@ var PlaylistManager = class {
|
|
|
8457
8659
|
if (this.playlistPanel && this.playlistPanel.parentNode) {
|
|
8458
8660
|
this.playlistPanel.parentNode.removeChild(this.playlistPanel);
|
|
8459
8661
|
}
|
|
8662
|
+
const preservedPlayerOptions = this.player?.options ? { ...this.player.options } : {};
|
|
8460
8663
|
if (this.player) {
|
|
8461
8664
|
this.player.off("ended", this.handleTrackEnd);
|
|
8462
8665
|
this.player.off("error", this.handleTrackError);
|
|
@@ -8464,7 +8667,8 @@ var PlaylistManager = class {
|
|
|
8464
8667
|
}
|
|
8465
8668
|
this.hostElement.innerHTML = "";
|
|
8466
8669
|
const mediaElement = document.createElement(elementType);
|
|
8467
|
-
|
|
8670
|
+
const preloadValue = preservedPlayerOptions.preload || "metadata";
|
|
8671
|
+
mediaElement.setAttribute("preload", preloadValue);
|
|
8468
8672
|
if (elementType === "video" && track.poster && (mediaType === "video" || mediaType === "hls")) {
|
|
8469
8673
|
mediaElement.setAttribute("poster", track.poster);
|
|
8470
8674
|
}
|
|
@@ -8498,6 +8702,7 @@ var PlaylistManager = class {
|
|
|
8498
8702
|
audioDescriptionDuration: track.audioDescriptionDuration || null,
|
|
8499
8703
|
signLanguageSrc: track.signLanguageSrc || null
|
|
8500
8704
|
};
|
|
8705
|
+
Object.assign(playerOptions, preservedPlayerOptions);
|
|
8501
8706
|
this.player = new this.PlayerClass(mediaElement, playerOptions);
|
|
8502
8707
|
this.player.playlistManager = this;
|
|
8503
8708
|
await new Promise((resolve) => {
|
|
@@ -8660,13 +8865,17 @@ var PlaylistManager = class {
|
|
|
8660
8865
|
if (this.options.autoPlayFirst) {
|
|
8661
8866
|
this.play(0);
|
|
8662
8867
|
} else {
|
|
8663
|
-
this.loadTrack(0)
|
|
8868
|
+
void this.loadTrack(0).catch(() => {
|
|
8869
|
+
});
|
|
8664
8870
|
}
|
|
8665
8871
|
}
|
|
8666
8872
|
this.updatePlaylistVisibilityInFullscreen();
|
|
8667
8873
|
}
|
|
8668
8874
|
/**
|
|
8669
8875
|
* Load a track without playing
|
|
8876
|
+
* This is the playlist equivalent of a "single video initialized but not started yet":
|
|
8877
|
+
* it updates UI selection and loads the media into the player so metadata/manifests
|
|
8878
|
+
* and feature managers can be ready, but it does not start playback.
|
|
8670
8879
|
* @param {number} index - Track index
|
|
8671
8880
|
*/
|
|
8672
8881
|
async loadTrack(index) {
|
|
@@ -8675,16 +8884,15 @@ var PlaylistManager = class {
|
|
|
8675
8884
|
return;
|
|
8676
8885
|
}
|
|
8677
8886
|
const track = this.tracks[index];
|
|
8887
|
+
this.selectTrack(index);
|
|
8678
8888
|
this.isChangingTrack = true;
|
|
8679
|
-
this.currentIndex = index;
|
|
8680
8889
|
if (this.options.recreatePlayers && this.hostElement && this.PlayerClass) {
|
|
8681
8890
|
const currentMediaType = this.player ? this.player.element.tagName === "AUDIO" ? "audio" : "video" : null;
|
|
8682
8891
|
const newMediaType = this.getTrackMediaType(track);
|
|
8683
8892
|
const newElementType = newMediaType === "audio" || newMediaType === "soundcloud" ? "audio" : "video";
|
|
8684
8893
|
if (currentMediaType !== newElementType) {
|
|
8685
8894
|
await this.recreatePlayerForTrack(track, false);
|
|
8686
|
-
this.
|
|
8687
|
-
this.updatePlaylistUI();
|
|
8895
|
+
this.selectTrack(index);
|
|
8688
8896
|
this.player.emit("playlisttrackchange", {
|
|
8689
8897
|
index,
|
|
8690
8898
|
item: track,
|
|
@@ -8696,16 +8904,19 @@ var PlaylistManager = class {
|
|
|
8696
8904
|
return;
|
|
8697
8905
|
}
|
|
8698
8906
|
}
|
|
8699
|
-
this.player.load({
|
|
8907
|
+
const loadPromise = this.player.load({
|
|
8700
8908
|
src: track.src,
|
|
8701
8909
|
type: track.type,
|
|
8702
8910
|
poster: track.poster,
|
|
8703
8911
|
tracks: track.tracks || [],
|
|
8704
8912
|
audioDescriptionSrc: track.audioDescriptionSrc || null,
|
|
8705
|
-
signLanguageSrc: track.signLanguageSrc || null
|
|
8913
|
+
signLanguageSrc: track.signLanguageSrc || null,
|
|
8914
|
+
signLanguageSources: track.signLanguageSources || {}
|
|
8706
8915
|
});
|
|
8707
|
-
this.
|
|
8708
|
-
|
|
8916
|
+
if (this.player?.options?.deferLoad && typeof this.player.ensureLoaded === "function") {
|
|
8917
|
+
Promise.resolve(loadPromise).then(() => this.player?.ensureLoaded?.()).catch(() => {
|
|
8918
|
+
});
|
|
8919
|
+
}
|
|
8709
8920
|
this.player.emit("playlisttrackchange", {
|
|
8710
8921
|
index,
|
|
8711
8922
|
item: track,
|
|
@@ -8715,6 +8926,97 @@ var PlaylistManager = class {
|
|
|
8715
8926
|
this.isChangingTrack = false;
|
|
8716
8927
|
}, 150);
|
|
8717
8928
|
}
|
|
8929
|
+
/**
|
|
8930
|
+
* Select a track (UI/selection only; does NOT set the media src / does NOT initialize renderer)
|
|
8931
|
+
*
|
|
8932
|
+
* In "B always" playlist mode, you typically want `loadTrack()` on selection so the
|
|
8933
|
+
* selected item behaves like a single video (metadata/manifest loaded, features ready)
|
|
8934
|
+
* without auto-playing.
|
|
8935
|
+
* @param {number} index - Track index
|
|
8936
|
+
*/
|
|
8937
|
+
selectTrack(index) {
|
|
8938
|
+
if (index < 0 || index >= this.tracks.length) {
|
|
8939
|
+
console.warn("VidPly Playlist: Invalid track index", index);
|
|
8940
|
+
return;
|
|
8941
|
+
}
|
|
8942
|
+
const track = this.tracks[index];
|
|
8943
|
+
this.currentIndex = index;
|
|
8944
|
+
try {
|
|
8945
|
+
if (this.player?.element?.tagName === "VIDEO") {
|
|
8946
|
+
if (track.poster) {
|
|
8947
|
+
const posterUrl = typeof this.player.resolvePosterPath === "function" ? this.player.resolvePosterPath(track.poster) : track.poster;
|
|
8948
|
+
this.player.element.poster = posterUrl;
|
|
8949
|
+
this.player.applyPosterAspectRatio?.(posterUrl);
|
|
8950
|
+
} else {
|
|
8951
|
+
this.player.element.removeAttribute("poster");
|
|
8952
|
+
}
|
|
8953
|
+
}
|
|
8954
|
+
this.player.audioDescriptionSrc = track.audioDescriptionSrc || null;
|
|
8955
|
+
this.player.signLanguageSrc = track.signLanguageSrc || null;
|
|
8956
|
+
this.player.signLanguageSources = track.signLanguageSources || {};
|
|
8957
|
+
if (track.duration && Number(track.duration) > 0) {
|
|
8958
|
+
this.player.state.duration = Number(track.duration);
|
|
8959
|
+
}
|
|
8960
|
+
if (this.player.audioDescriptionManager) {
|
|
8961
|
+
this.player.audioDescriptionManager.src = track.audioDescriptionSrc || null;
|
|
8962
|
+
this.player.audioDescriptionManager.originalSource = track.src || this.player.originalSrc || null;
|
|
8963
|
+
}
|
|
8964
|
+
if (this.player.signLanguageManager) {
|
|
8965
|
+
this.player.signLanguageManager.src = track.signLanguageSrc || null;
|
|
8966
|
+
this.player.signLanguageManager.sources = track.signLanguageSources || {};
|
|
8967
|
+
this.player.signLanguageManager.currentLanguage = null;
|
|
8968
|
+
}
|
|
8969
|
+
if (track.src && !this.player.originalSrc) {
|
|
8970
|
+
this.player.originalSrc = track.src;
|
|
8971
|
+
}
|
|
8972
|
+
const existing = Array.from(this.player.element.querySelectorAll("track"));
|
|
8973
|
+
existing.forEach((t) => t.remove());
|
|
8974
|
+
if (Array.isArray(track.tracks)) {
|
|
8975
|
+
track.tracks.forEach((tc) => {
|
|
8976
|
+
if (!tc?.src) return;
|
|
8977
|
+
const el = document.createElement("track");
|
|
8978
|
+
el.src = tc.src;
|
|
8979
|
+
el.kind = tc.kind || "captions";
|
|
8980
|
+
el.srclang = tc.srclang || "en";
|
|
8981
|
+
el.label = tc.label || tc.srclang || "Track";
|
|
8982
|
+
if (tc.default) el.default = true;
|
|
8983
|
+
if (tc.describedSrc) {
|
|
8984
|
+
el.setAttribute("data-desc-src", tc.describedSrc);
|
|
8985
|
+
}
|
|
8986
|
+
this.player.element.appendChild(el);
|
|
8987
|
+
});
|
|
8988
|
+
}
|
|
8989
|
+
if (typeof this.player.invalidateTrackCache === "function") {
|
|
8990
|
+
this.player.invalidateTrackCache();
|
|
8991
|
+
}
|
|
8992
|
+
if (this.player.audioDescriptionManager && typeof this.player.audioDescriptionManager.initFromSourceElements === "function") {
|
|
8993
|
+
try {
|
|
8994
|
+
this.player.audioDescriptionManager.captionTracks = [];
|
|
8995
|
+
this.player.audioDescriptionManager.initFromSourceElements(this.player.sourceElements, this.player.trackElements);
|
|
8996
|
+
} catch (e) {
|
|
8997
|
+
}
|
|
8998
|
+
}
|
|
8999
|
+
if (this.player.captionManager && typeof this.player.captionManager.loadTracks === "function") {
|
|
9000
|
+
try {
|
|
9001
|
+
this.player.captionManager.tracks = [];
|
|
9002
|
+
this.player.captionManager.currentTrack = null;
|
|
9003
|
+
this.player.captionManager.loadTracks();
|
|
9004
|
+
} catch (e) {
|
|
9005
|
+
}
|
|
9006
|
+
}
|
|
9007
|
+
if (typeof this.player.updateControlBar === "function") {
|
|
9008
|
+
this.player.updateControlBar();
|
|
9009
|
+
}
|
|
9010
|
+
} catch (e) {
|
|
9011
|
+
}
|
|
9012
|
+
this.updateTrackInfo(track);
|
|
9013
|
+
this.updatePlaylistUI();
|
|
9014
|
+
this.player.emit("playlisttrackselect", {
|
|
9015
|
+
index,
|
|
9016
|
+
item: track,
|
|
9017
|
+
total: this.tracks.length
|
|
9018
|
+
});
|
|
9019
|
+
}
|
|
8718
9020
|
/**
|
|
8719
9021
|
* Play a specific track
|
|
8720
9022
|
* @param {number} index - Track index
|
|
@@ -8747,13 +9049,21 @@ var PlaylistManager = class {
|
|
|
8747
9049
|
return;
|
|
8748
9050
|
}
|
|
8749
9051
|
}
|
|
9052
|
+
let srcToLoad = track.src;
|
|
9053
|
+
if (this.player?.audioDescriptionManager?.desiredState && track.audioDescriptionSrc) {
|
|
9054
|
+
this.player.originalSrc = track.src;
|
|
9055
|
+
this.player.audioDescriptionManager.originalSource = track.src;
|
|
9056
|
+
this.player.audioDescriptionManager.src = track.audioDescriptionSrc;
|
|
9057
|
+
srcToLoad = track.audioDescriptionSrc;
|
|
9058
|
+
}
|
|
8750
9059
|
this.player.load({
|
|
8751
|
-
src:
|
|
9060
|
+
src: srcToLoad,
|
|
8752
9061
|
type: track.type,
|
|
8753
9062
|
poster: track.poster,
|
|
8754
9063
|
tracks: track.tracks || [],
|
|
8755
9064
|
audioDescriptionSrc: track.audioDescriptionSrc || null,
|
|
8756
|
-
signLanguageSrc: track.signLanguageSrc || null
|
|
9065
|
+
signLanguageSrc: track.signLanguageSrc || null,
|
|
9066
|
+
signLanguageSources: track.signLanguageSources || {}
|
|
8757
9067
|
});
|
|
8758
9068
|
this.updateTrackInfo(track);
|
|
8759
9069
|
this.updatePlaylistUI();
|