vidply 1.2.0 → 1.2.3
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 +974 -946
- package/dist/dev/{vidply.AudioDescriptionManager-R47Q4YR4.js → vidply.AudioDescriptionManager-JYYLK5KB.js} +275 -19
- package/dist/dev/vidply.AudioDescriptionManager-JYYLK5KB.js.map +7 -0
- package/dist/dev/{vidply.CaptionStyleMenu-7XHRBWUM.js → vidply.CaptionStyleMenu-47RCKQF5.js} +4 -4
- package/dist/dev/{vidply.DASHRenderer-PWEMC3BT.js → vidply.DASHRenderer-VEJ4HDHO.js} +3 -3
- package/dist/dev/vidply.DASHRenderer-VEJ4HDHO.js.map +7 -0
- package/dist/dev/{vidply.FloatingPlayerManager-PKNNNAS2.js → vidply.FloatingPlayerManager-C2UVRPZY.js} +5 -5
- package/dist/dev/vidply.FloatingPlayerManager-C2UVRPZY.js.map +7 -0
- package/dist/dev/{vidply.HLSRenderer-E7RQ74HI.js → vidply.HLSRenderer-ZVBK2TNQ.js} +4 -4
- package/dist/dev/vidply.HLSRenderer-ZVBK2TNQ.js.map +7 -0
- package/dist/dev/vidply.HTML5Renderer-HLRQUOCU.js +12 -0
- package/dist/dev/{vidply.SignLanguageManager-FET5FQZ7.js → vidply.SignLanguageManager-FLUCBW5H.js} +8 -8
- package/dist/dev/vidply.SignLanguageManager-FLUCBW5H.js.map +7 -0
- package/dist/dev/{vidply.SoundCloudRenderer-RVSJZODO.js → vidply.SoundCloudRenderer-MGMAJ7NK.js} +3 -3
- package/dist/dev/vidply.SoundCloudRenderer-MGMAJ7NK.js.map +7 -0
- package/dist/dev/{vidply.TranscriptManager-5GXOQCLX.js → vidply.TranscriptManager-Y2RYXHJW.js} +10 -10
- package/dist/dev/vidply.TranscriptManager-Y2RYXHJW.js.map +7 -0
- package/dist/dev/{vidply.VimeoRenderer-ER2LSBBW.js → vidply.VimeoRenderer-RQFQD7OE.js} +3 -3
- package/dist/dev/vidply.VimeoRenderer-RQFQD7OE.js.map +7 -0
- package/dist/dev/{vidply.YouTubeRenderer-NFTOWJAB.js → vidply.YouTubeRenderer-EU2BARZF.js} +3 -3
- package/dist/dev/vidply.YouTubeRenderer-EU2BARZF.js.map +7 -0
- package/dist/dev/{vidply.chunk-BNFIUL2Z.js → vidply.chunk-6LYZYI5G.js} +3 -3
- package/dist/dev/vidply.chunk-6LYZYI5G.js.map +7 -0
- package/dist/dev/{vidply.chunk-NQPURMQY.js → vidply.chunk-A4ESEOQ2.js} +6 -6
- package/dist/dev/vidply.chunk-A4ESEOQ2.js.map +7 -0
- package/dist/dev/{vidply.chunk-W25HUCHS.js → vidply.chunk-CGYIED2I.js} +2 -2
- package/dist/dev/vidply.chunk-CGYIED2I.js.map +7 -0
- package/dist/dev/{vidply.chunk-SK4V2DAU.js → vidply.chunk-HZ7UOKOU.js} +3 -3
- package/dist/dev/{vidply.chunk-RZWZGDV7.js → vidply.chunk-I6EDRYGJ.js} +33 -6
- package/dist/dev/vidply.chunk-I6EDRYGJ.js.map +7 -0
- package/dist/dev/{vidply.chunk-64WXMTGL.js → vidply.chunk-JKMQGLCJ.js} +5 -5
- package/dist/dev/vidply.chunk-JKMQGLCJ.js.map +7 -0
- package/dist/dev/{vidply.chunk-DZSDO3B7.js → vidply.chunk-JZNZX32Z.js} +2 -2
- package/dist/dev/{vidply.chunk-VMSQAZM7.js → vidply.chunk-P25MRJ6O.js} +2 -2
- package/dist/dev/{vidply.chunk-6RQA4ROD.js → vidply.chunk-PRFNESYA.js} +2 -2
- package/dist/dev/{vidply.chunk-KI7C3QVL.js → vidply.chunk-UI3RYCVF.js} +4 -3
- package/dist/dev/vidply.chunk-UI3RYCVF.js.map +7 -0
- package/dist/dev/{vidply.chunk-JJ47NO24.js → vidply.chunk-UNFGMABP.js} +2 -2
- package/dist/dev/vidply.chunk-UNFGMABP.js.map +7 -0
- package/dist/dev/{vidply.de-4YAT7FFM.js → vidply.de-VAUVSQXC.js} +29 -2
- package/dist/dev/vidply.de-VAUVSQXC.js.map +7 -0
- package/dist/dev/{vidply.es-LEWIRUBH.js → vidply.es-G65HFWO6.js} +29 -2
- package/dist/dev/vidply.es-G65HFWO6.js.map +7 -0
- package/dist/dev/vidply.esm.js +648 -35
- package/dist/dev/vidply.esm.js.map +3 -3
- package/dist/dev/{vidply.fr-Q4GV2NOE.js → vidply.fr-MJNOZELM.js} +29 -2
- package/dist/dev/vidply.fr-MJNOZELM.js.map +7 -0
- package/dist/dev/{vidply.ja-S6ITA6WU.js → vidply.ja-INMDHIYJ.js} +29 -2
- package/dist/dev/vidply.ja-INMDHIYJ.js.map +7 -0
- package/dist/legacy/vidply.js +1062 -34
- package/dist/legacy/vidply.js.map +3 -3
- package/dist/legacy/vidply.min.js +2 -2
- package/dist/legacy/vidply.min.meta.json +127 -55
- package/dist/prod/vidply.AudioDescriptionManager-EKWUNOPE.min.js +6 -0
- package/dist/prod/{vidply.CaptionStyleMenu-M3KVQWB5.min.js → vidply.CaptionStyleMenu-JTWSNHRQ.min.js} +2 -2
- package/dist/prod/{vidply.DASHRenderer-DN3S27AV.min.js → vidply.DASHRenderer-CIDAHFWM.min.js} +2 -2
- package/dist/prod/{vidply.FloatingPlayerManager-SKAZ4J43.min.js → vidply.FloatingPlayerManager-VZXHPCPM.min.js} +2 -2
- package/dist/prod/{vidply.HLSRenderer-62HH4YTK.min.js → vidply.HLSRenderer-Q6EFYKID.min.js} +2 -2
- package/dist/prod/vidply.HTML5Renderer-XRDJUTOO.min.js +6 -0
- package/dist/prod/{vidply.SignLanguageManager-V3OBTSSF.min.js → vidply.SignLanguageManager-JUOSA5AM.min.js} +2 -2
- package/dist/prod/{vidply.SoundCloudRenderer-CXRVZIAJ.min.js → vidply.SoundCloudRenderer-7ODD46PO.min.js} +2 -2
- package/dist/prod/{vidply.TranscriptManager-SYM3DFUY.min.js → vidply.TranscriptManager-4B2QKYGQ.min.js} +2 -2
- package/dist/prod/{vidply.VimeoRenderer-72TWRYFQ.min.js → vidply.VimeoRenderer-MR3UYLY7.min.js} +2 -2
- package/dist/prod/{vidply.YouTubeRenderer-UMHEV3KD.min.js → vidply.YouTubeRenderer-ITRTC7NR.min.js} +2 -2
- package/dist/prod/{vidply.chunk-YEENJS3Q.min.js → vidply.chunk-3EEDXU4T.min.js} +2 -2
- package/dist/prod/{vidply.chunk-P4UXOHWA.min.js → vidply.chunk-5HTX5QXW.min.js} +1 -1
- package/dist/prod/{vidply.chunk-ABPXVDLZ.min.js → vidply.chunk-6OGHHIYP.min.js} +2 -2
- package/dist/prod/{vidply.chunk-UK7YGOB5.min.js → vidply.chunk-GUPGMFUZ.min.js} +2 -2
- package/dist/prod/{vidply.chunk-WX3MVEAL.min.js → vidply.chunk-MWEBITCP.min.js} +1 -1
- package/dist/prod/{vidply.chunk-2TB6MUHO.min.js → vidply.chunk-PL3P3JHR.min.js} +1 -1
- package/dist/prod/{vidply.chunk-EKEYJWMG.min.js → vidply.chunk-QQZGV7TD.min.js} +2 -2
- package/dist/prod/{vidply.chunk-Z3YDSA7O.min.js → vidply.chunk-U5IRRYG5.min.js} +1 -1
- package/dist/prod/{vidply.chunk-TM6AXJVD.min.js → vidply.chunk-VKHV4QHA.min.js} +2 -2
- package/dist/prod/{vidply.chunk-P3PQBY7N.min.js → vidply.chunk-XA4M574A.min.js} +1 -1
- package/dist/prod/{vidply.chunk-RI3X7WHK.min.js → vidply.chunk-ZPTV4JEP.min.js} +2 -2
- package/dist/prod/{vidply.de-BCHXRQ53.min.js → vidply.de-UZHFCEZU.min.js} +2 -2
- package/dist/prod/{vidply.es-PICAKMZD.min.js → vidply.es-BOISUV2S.min.js} +2 -2
- package/dist/prod/vidply.esm.min.js +2 -2
- package/dist/prod/{vidply.fr-ZILI7CDR.min.js → vidply.fr-ICSMKPFM.min.js} +2 -2
- package/dist/prod/{vidply.ja-5WQ4OK4J.min.js → vidply.ja-VQ2HKGAY.min.js} +2 -2
- package/dist/vidply.css +5852 -5796
- package/dist/vidply.esm.min.meta.json +204 -149
- package/dist/vidply.min.css +1 -1
- package/package.json +11 -11
- package/src/controls/CaptionManager.ts +598 -598
- package/src/controls/ControlBar.ts +4191 -4159
- package/src/controls/KeyboardHelp.ts +326 -0
- package/src/controls/KeyboardManager.ts +387 -383
- package/src/controls/SettingsDialog.ts +488 -488
- package/src/controls/TranscriptManager.ts +2426 -2426
- package/src/core/AudioDescriptionManager.ts +863 -774
- package/src/core/DescriptionSpeechManager.ts +232 -0
- package/src/core/FloatingPlayerManager.ts +674 -674
- package/src/core/LazyInit.ts +80 -80
- package/src/core/MediaSessionManager.ts +341 -0
- package/src/core/MetadataAlertsManager.ts +514 -514
- package/src/core/Player.ts +2973 -2872
- package/src/core/PosterManager.ts +169 -169
- package/src/core/PseudoFullscreen.ts +179 -179
- package/src/core/ResponsiveManager.ts +231 -231
- package/src/core/ResumeManager.ts +236 -236
- package/src/core/SignLanguageManager.ts +1308 -1308
- package/src/core/ThemeManager.ts +157 -157
- package/src/features/PlaylistManager.ts +1838 -1827
- package/src/i18n/i18n.ts +223 -223
- package/src/i18n/languages/de.ts +244 -217
- package/src/i18n/languages/en.ts +245 -218
- package/src/i18n/languages/es.ts +241 -214
- package/src/i18n/languages/fr.ts +241 -214
- package/src/i18n/languages/ja.ts +241 -214
- package/src/icons/Icons.ts +168 -167
- package/src/index.ts +196 -193
- package/src/renderers/DASHRenderer.ts +1077 -1077
- package/src/renderers/HLSRenderer.ts +944 -944
- package/src/renderers/HTML5Renderer.ts +389 -389
- package/src/renderers/SoundCloudRenderer.ts +437 -437
- package/src/renderers/VimeoRenderer.ts +298 -298
- package/src/renderers/YouTubeRenderer.ts +290 -290
- package/src/styles/vidply.css +5852 -5796
- package/src/types/events.ts +128 -122
- package/src/types/globals.d.ts +313 -313
- package/src/types/options.ts +199 -182
- package/src/types/renderer.ts +58 -58
- package/src/utils/DOMUtils.ts +281 -281
- package/src/utils/DownloadInfo.ts +171 -171
- package/src/utils/DraggablePanel.ts +539 -539
- package/src/utils/DraggablePanelMenu.ts +195 -195
- package/src/utils/DraggableResizable.ts +997 -997
- package/src/utils/EventEmitter.ts +59 -59
- package/src/utils/FormUtils.ts +95 -95
- package/src/utils/MenuFactory.ts +483 -483
- package/src/utils/Sanitize.ts +70 -70
- package/src/utils/SettingsMenuFactory.ts +289 -289
- package/src/utils/StorageManager.ts +287 -287
- package/src/utils/TrackLabelUtils.ts +52 -52
- package/src/utils/UrlSafe.ts +69 -69
- package/src/utils/VideoFrameCapture.ts +114 -114
- package/src/utils/WindowComponents.ts +250 -250
- package/dist/dev/vidply.AudioDescriptionManager-R47Q4YR4.js.map +0 -7
- package/dist/dev/vidply.DASHRenderer-PWEMC3BT.js.map +0 -7
- package/dist/dev/vidply.FloatingPlayerManager-PKNNNAS2.js.map +0 -7
- package/dist/dev/vidply.HLSRenderer-E7RQ74HI.js.map +0 -7
- package/dist/dev/vidply.HTML5Renderer-BU4QJJJY.js +0 -12
- package/dist/dev/vidply.SignLanguageManager-FET5FQZ7.js.map +0 -7
- package/dist/dev/vidply.SoundCloudRenderer-RVSJZODO.js.map +0 -7
- package/dist/dev/vidply.TranscriptManager-5GXOQCLX.js.map +0 -7
- package/dist/dev/vidply.VimeoRenderer-ER2LSBBW.js.map +0 -7
- package/dist/dev/vidply.YouTubeRenderer-NFTOWJAB.js.map +0 -7
- package/dist/dev/vidply.chunk-64WXMTGL.js.map +0 -7
- package/dist/dev/vidply.chunk-BNFIUL2Z.js.map +0 -7
- package/dist/dev/vidply.chunk-JJ47NO24.js.map +0 -7
- package/dist/dev/vidply.chunk-KI7C3QVL.js.map +0 -7
- package/dist/dev/vidply.chunk-NQPURMQY.js.map +0 -7
- package/dist/dev/vidply.chunk-RZWZGDV7.js.map +0 -7
- package/dist/dev/vidply.chunk-W25HUCHS.js.map +0 -7
- package/dist/dev/vidply.de-4YAT7FFM.js.map +0 -7
- package/dist/dev/vidply.es-LEWIRUBH.js.map +0 -7
- package/dist/dev/vidply.fr-Q4GV2NOE.js.map +0 -7
- package/dist/dev/vidply.ja-S6ITA6WU.js.map +0 -7
- package/dist/prod/vidply.AudioDescriptionManager-RHLIJW5C.min.js +0 -6
- package/dist/prod/vidply.HTML5Renderer-IU5T3WEW.min.js +0 -6
- /package/dist/dev/{vidply.CaptionStyleMenu-7XHRBWUM.js.map → vidply.CaptionStyleMenu-47RCKQF5.js.map} +0 -0
- /package/dist/dev/{vidply.HTML5Renderer-BU4QJJJY.js.map → vidply.HTML5Renderer-HLRQUOCU.js.map} +0 -0
- /package/dist/dev/{vidply.chunk-SK4V2DAU.js.map → vidply.chunk-HZ7UOKOU.js.map} +0 -0
- /package/dist/dev/{vidply.chunk-DZSDO3B7.js.map → vidply.chunk-JZNZX32Z.js.map} +0 -0
- /package/dist/dev/{vidply.chunk-VMSQAZM7.js.map → vidply.chunk-P25MRJ6O.js.map} +0 -0
- /package/dist/dev/{vidply.chunk-6RQA4ROD.js.map → vidply.chunk-PRFNESYA.js.map} +0 -0
package/dist/dev/vidply.esm.js
CHANGED
|
@@ -1,39 +1,39 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* VidPly v1.2.
|
|
2
|
+
* VidPly v1.2.3 - Universal, Accessible Video Player
|
|
3
3
|
* (c) 2026 Matthias Peltzer
|
|
4
4
|
* Released under GPL-2.0-or-later License
|
|
5
5
|
*/
|
|
6
6
|
import {
|
|
7
7
|
TimeUtils
|
|
8
|
-
} from "./vidply.chunk-
|
|
8
|
+
} from "./vidply.chunk-HZ7UOKOU.js";
|
|
9
9
|
import {
|
|
10
10
|
createIconElement,
|
|
11
11
|
createPlayOverlay
|
|
12
|
-
} from "./vidply.chunk-
|
|
12
|
+
} from "./vidply.chunk-UI3RYCVF.js";
|
|
13
13
|
import {
|
|
14
14
|
focusElement
|
|
15
|
-
} from "./vidply.chunk-
|
|
15
|
+
} from "./vidply.chunk-P25MRJ6O.js";
|
|
16
16
|
import {
|
|
17
17
|
HTML5Renderer
|
|
18
|
-
} from "./vidply.chunk-
|
|
18
|
+
} from "./vidply.chunk-CGYIED2I.js";
|
|
19
19
|
import {
|
|
20
20
|
CaptionManager
|
|
21
|
-
} from "./vidply.chunk-
|
|
21
|
+
} from "./vidply.chunk-JKMQGLCJ.js";
|
|
22
22
|
import {
|
|
23
23
|
StorageManager
|
|
24
|
-
} from "./vidply.chunk-
|
|
24
|
+
} from "./vidply.chunk-6LYZYI5G.js";
|
|
25
25
|
import {
|
|
26
26
|
debounce,
|
|
27
27
|
isMobile,
|
|
28
28
|
rafWithTimeout,
|
|
29
29
|
reducedMotionScrollOptions,
|
|
30
30
|
throttle
|
|
31
|
-
} from "./vidply.chunk-
|
|
31
|
+
} from "./vidply.chunk-PRFNESYA.js";
|
|
32
32
|
import {
|
|
33
33
|
DOMUtils,
|
|
34
34
|
i18n,
|
|
35
35
|
isForbiddenKey
|
|
36
|
-
} from "./vidply.chunk-
|
|
36
|
+
} from "./vidply.chunk-I6EDRYGJ.js";
|
|
37
37
|
|
|
38
38
|
// src/utils/EventEmitter.ts
|
|
39
39
|
var EventEmitter = class {
|
|
@@ -960,6 +960,12 @@ var ControlBar = class {
|
|
|
960
960
|
}
|
|
961
961
|
this.rightButtons.appendChild(btn);
|
|
962
962
|
}
|
|
963
|
+
if (this.player.options.helpButton && this.player.options.keyboard) {
|
|
964
|
+
const btn = this.createHelpButton();
|
|
965
|
+
btn.dataset.overflowPriority = "3";
|
|
966
|
+
btn.dataset.overflowPriorityMobile = "3";
|
|
967
|
+
this.rightButtons.appendChild(btn);
|
|
968
|
+
}
|
|
963
969
|
this.overflowMenuButton = this.createOverflowMenuButton();
|
|
964
970
|
this.overflowMenuButton.style.display = "none";
|
|
965
971
|
this.rightButtons.appendChild(this.overflowMenuButton);
|
|
@@ -2051,7 +2057,7 @@ var ControlBar = class {
|
|
|
2051
2057
|
return button;
|
|
2052
2058
|
}
|
|
2053
2059
|
showCaptionStyleMenu(button) {
|
|
2054
|
-
import("./vidply.CaptionStyleMenu-
|
|
2060
|
+
import("./vidply.CaptionStyleMenu-47RCKQF5.js").then(({ showCaptionStyleMenu }) => showCaptionStyleMenu(this, button)).catch((error) => this.player.log("Failed to load caption style menu:", error, "error"));
|
|
2055
2061
|
}
|
|
2056
2062
|
createSpeedButton() {
|
|
2057
2063
|
const button = DOMUtils.createElement("button", {
|
|
@@ -2274,6 +2280,24 @@ var ControlBar = class {
|
|
|
2274
2280
|
const isVisible = this.player.transcriptManager && this.player.transcriptManager.isVisible;
|
|
2275
2281
|
this.controls.transcript.setAttribute("aria-expanded", isVisible ? "true" : "false");
|
|
2276
2282
|
}
|
|
2283
|
+
createHelpButton() {
|
|
2284
|
+
const ariaLabel = i18n.t("help.button");
|
|
2285
|
+
const button = DOMUtils.createElement("button", {
|
|
2286
|
+
className: `${this.player.options.classPrefix}-button ${this.player.options.classPrefix}-help`,
|
|
2287
|
+
attributes: {
|
|
2288
|
+
"type": "button",
|
|
2289
|
+
"aria-label": ariaLabel,
|
|
2290
|
+
"aria-haspopup": "dialog"
|
|
2291
|
+
}
|
|
2292
|
+
});
|
|
2293
|
+
button.appendChild(createIconElement("help"));
|
|
2294
|
+
DOMUtils.attachTooltip(button, ariaLabel, this.player.options.classPrefix);
|
|
2295
|
+
button.addEventListener("click", () => {
|
|
2296
|
+
this.player.toggleKeyboardHelp();
|
|
2297
|
+
});
|
|
2298
|
+
this.controls.help = button;
|
|
2299
|
+
return button;
|
|
2300
|
+
}
|
|
2277
2301
|
createAudioDescriptionButton() {
|
|
2278
2302
|
const ariaLabel = i18n.t("player.audioDescription");
|
|
2279
2303
|
const button = DOMUtils.createElement("button", {
|
|
@@ -3507,6 +3531,9 @@ var KeyboardManager = class {
|
|
|
3507
3531
|
return true;
|
|
3508
3532
|
}
|
|
3509
3533
|
return false;
|
|
3534
|
+
case "help":
|
|
3535
|
+
this.player.toggleKeyboardHelp();
|
|
3536
|
+
return true;
|
|
3510
3537
|
default:
|
|
3511
3538
|
return false;
|
|
3512
3539
|
}
|
|
@@ -3594,6 +3621,252 @@ var KeyboardManager = class {
|
|
|
3594
3621
|
}
|
|
3595
3622
|
};
|
|
3596
3623
|
|
|
3624
|
+
// src/core/MediaSessionManager.ts
|
|
3625
|
+
var POSITION_THROTTLE_MS = 1e3;
|
|
3626
|
+
var activeManager = null;
|
|
3627
|
+
var MediaSessionManager = class {
|
|
3628
|
+
player;
|
|
3629
|
+
supported;
|
|
3630
|
+
handlers = {};
|
|
3631
|
+
boundActions = [];
|
|
3632
|
+
lastPositionUpdate = 0;
|
|
3633
|
+
constructor(player) {
|
|
3634
|
+
this.player = player;
|
|
3635
|
+
this.supported = typeof navigator !== "undefined" && "mediaSession" in navigator;
|
|
3636
|
+
if (!this.supported) return;
|
|
3637
|
+
this.attachEvents();
|
|
3638
|
+
if (activeManager === null) {
|
|
3639
|
+
this.claimSession();
|
|
3640
|
+
}
|
|
3641
|
+
}
|
|
3642
|
+
/** Does this manager currently own the global media session? */
|
|
3643
|
+
isActive() {
|
|
3644
|
+
return activeManager === this;
|
|
3645
|
+
}
|
|
3646
|
+
/**
|
|
3647
|
+
* Take ownership of the global session: (re)register the action handlers so
|
|
3648
|
+
* the OS controls drive this player, and refresh metadata/state/position.
|
|
3649
|
+
*/
|
|
3650
|
+
claimSession() {
|
|
3651
|
+
if (!this.supported) return;
|
|
3652
|
+
activeManager = this;
|
|
3653
|
+
this.setupActionHandlers();
|
|
3654
|
+
this.updateMetadata();
|
|
3655
|
+
this.updatePlaybackState();
|
|
3656
|
+
this.updatePositionState(true);
|
|
3657
|
+
}
|
|
3658
|
+
get session() {
|
|
3659
|
+
return navigator.mediaSession;
|
|
3660
|
+
}
|
|
3661
|
+
setActionHandler(action, handler) {
|
|
3662
|
+
try {
|
|
3663
|
+
this.session.setActionHandler(action, handler);
|
|
3664
|
+
if (handler && !this.boundActions.includes(action)) {
|
|
3665
|
+
this.boundActions.push(action);
|
|
3666
|
+
}
|
|
3667
|
+
} catch {
|
|
3668
|
+
}
|
|
3669
|
+
}
|
|
3670
|
+
setupActionHandlers() {
|
|
3671
|
+
this.setActionHandler("play", () => this.player.play());
|
|
3672
|
+
this.setActionHandler("pause", () => this.player.pause());
|
|
3673
|
+
this.setActionHandler("stop", () => this.player.stop());
|
|
3674
|
+
this.setActionHandler("seekbackward", (details) => {
|
|
3675
|
+
this.player.seekBackward(this.offsetFrom(details));
|
|
3676
|
+
});
|
|
3677
|
+
this.setActionHandler("seekforward", (details) => {
|
|
3678
|
+
this.player.seekForward(this.offsetFrom(details));
|
|
3679
|
+
});
|
|
3680
|
+
this.setActionHandler("seekto", (details) => {
|
|
3681
|
+
if (details && typeof details.seekTime === "number") {
|
|
3682
|
+
this.player.seek(details.seekTime);
|
|
3683
|
+
}
|
|
3684
|
+
});
|
|
3685
|
+
this.updateTrackHandlers();
|
|
3686
|
+
}
|
|
3687
|
+
offsetFrom(details) {
|
|
3688
|
+
const offset = details && typeof details.seekOffset === "number" ? details.seekOffset : void 0;
|
|
3689
|
+
return typeof offset === "number" && offset > 0 ? offset : void 0;
|
|
3690
|
+
}
|
|
3691
|
+
/**
|
|
3692
|
+
* previous/next track only make sense with a multi-item playlist; bind
|
|
3693
|
+
* or clear them whenever the playlist state changes so the OS shows the
|
|
3694
|
+
* correct affordances.
|
|
3695
|
+
*/
|
|
3696
|
+
updateTrackHandlers() {
|
|
3697
|
+
const pm = this.player.playlistManager;
|
|
3698
|
+
const hasPlaylist = Boolean(pm && Array.isArray(pm.tracks) && pm.tracks.length > 1);
|
|
3699
|
+
if (hasPlaylist && pm) {
|
|
3700
|
+
this.setActionHandler("previoustrack", () => pm.previous());
|
|
3701
|
+
this.setActionHandler("nexttrack", () => pm.next());
|
|
3702
|
+
} else {
|
|
3703
|
+
this.setActionHandler("previoustrack", null);
|
|
3704
|
+
this.setActionHandler("nexttrack", null);
|
|
3705
|
+
}
|
|
3706
|
+
}
|
|
3707
|
+
attachEvents() {
|
|
3708
|
+
this.handlers = {
|
|
3709
|
+
// Starting playback makes this player the session owner, taking over
|
|
3710
|
+
// the OS controls from any other player on the page.
|
|
3711
|
+
play: () => this.claimSession(),
|
|
3712
|
+
pause: () => {
|
|
3713
|
+
if (!this.isActive()) return;
|
|
3714
|
+
this.updatePlaybackState();
|
|
3715
|
+
this.updatePositionState(true);
|
|
3716
|
+
},
|
|
3717
|
+
ended: () => {
|
|
3718
|
+
if (!this.isActive()) return;
|
|
3719
|
+
this.updatePlaybackState();
|
|
3720
|
+
},
|
|
3721
|
+
timeupdate: () => {
|
|
3722
|
+
if (!this.isActive()) return;
|
|
3723
|
+
this.updatePositionState();
|
|
3724
|
+
},
|
|
3725
|
+
durationchange: () => {
|
|
3726
|
+
if (!this.isActive()) return;
|
|
3727
|
+
this.updatePositionState(true);
|
|
3728
|
+
},
|
|
3729
|
+
ratechange: () => {
|
|
3730
|
+
if (!this.isActive()) return;
|
|
3731
|
+
this.updatePositionState(true);
|
|
3732
|
+
},
|
|
3733
|
+
loadedmetadata: () => {
|
|
3734
|
+
if (!this.isActive()) return;
|
|
3735
|
+
this.updateMetadata();
|
|
3736
|
+
this.updatePositionState(true);
|
|
3737
|
+
},
|
|
3738
|
+
playlisttrackchange: () => {
|
|
3739
|
+
if (!this.isActive()) return;
|
|
3740
|
+
this.updateMetadata();
|
|
3741
|
+
this.updateTrackHandlers();
|
|
3742
|
+
this.updatePositionState(true);
|
|
3743
|
+
}
|
|
3744
|
+
};
|
|
3745
|
+
for (const [event, handler] of Object.entries(this.handlers)) {
|
|
3746
|
+
if (handler) {
|
|
3747
|
+
this.player.on(event, handler);
|
|
3748
|
+
}
|
|
3749
|
+
}
|
|
3750
|
+
}
|
|
3751
|
+
resolveMetadata() {
|
|
3752
|
+
const opts = this.player.options;
|
|
3753
|
+
let title = opts.title || "";
|
|
3754
|
+
let artist = opts.artist || "";
|
|
3755
|
+
const album = opts.album || "";
|
|
3756
|
+
let poster = opts.poster || null;
|
|
3757
|
+
const pm = this.player.playlistManager;
|
|
3758
|
+
if (pm && Array.isArray(pm.tracks) && pm.currentIndex >= 0) {
|
|
3759
|
+
const track = pm.tracks[pm.currentIndex];
|
|
3760
|
+
if (track) {
|
|
3761
|
+
if (track.title) title = track.title;
|
|
3762
|
+
if (track.artist) artist = track.artist;
|
|
3763
|
+
if (track.poster) poster = track.poster;
|
|
3764
|
+
}
|
|
3765
|
+
}
|
|
3766
|
+
if (!title && typeof document !== "undefined") {
|
|
3767
|
+
title = document.title || "VidPly";
|
|
3768
|
+
}
|
|
3769
|
+
return { title, artist, album, poster };
|
|
3770
|
+
}
|
|
3771
|
+
updateMetadata() {
|
|
3772
|
+
if (!this.supported || typeof window === "undefined" || typeof window.MediaMetadata === "undefined") {
|
|
3773
|
+
return;
|
|
3774
|
+
}
|
|
3775
|
+
const { title, artist, album, poster } = this.resolveMetadata();
|
|
3776
|
+
const artwork = [];
|
|
3777
|
+
if (poster) {
|
|
3778
|
+
try {
|
|
3779
|
+
const src = this.player.resolvePosterPath(poster);
|
|
3780
|
+
if (src) {
|
|
3781
|
+
artwork.push({ src });
|
|
3782
|
+
}
|
|
3783
|
+
} catch {
|
|
3784
|
+
}
|
|
3785
|
+
}
|
|
3786
|
+
try {
|
|
3787
|
+
this.session.metadata = new window.MediaMetadata({
|
|
3788
|
+
title,
|
|
3789
|
+
artist,
|
|
3790
|
+
album,
|
|
3791
|
+
artwork
|
|
3792
|
+
});
|
|
3793
|
+
} catch {
|
|
3794
|
+
}
|
|
3795
|
+
}
|
|
3796
|
+
updatePlaybackState() {
|
|
3797
|
+
if (!this.supported) return;
|
|
3798
|
+
try {
|
|
3799
|
+
this.session.playbackState = this.player.state.playing ? "playing" : "paused";
|
|
3800
|
+
} catch {
|
|
3801
|
+
}
|
|
3802
|
+
}
|
|
3803
|
+
/**
|
|
3804
|
+
* Push the current position to the OS scrubber. `timeupdate` fires
|
|
3805
|
+
* several times a second, so non-forced updates are throttled.
|
|
3806
|
+
*/
|
|
3807
|
+
updatePositionState(force = false) {
|
|
3808
|
+
if (!this.supported || typeof this.session.setPositionState !== "function") {
|
|
3809
|
+
return;
|
|
3810
|
+
}
|
|
3811
|
+
const now = Date.now();
|
|
3812
|
+
if (!force && now - this.lastPositionUpdate < POSITION_THROTTLE_MS) {
|
|
3813
|
+
return;
|
|
3814
|
+
}
|
|
3815
|
+
this.lastPositionUpdate = now;
|
|
3816
|
+
const duration = this.player.state.duration;
|
|
3817
|
+
if (!Number.isFinite(duration) || duration <= 0) {
|
|
3818
|
+
try {
|
|
3819
|
+
this.session.setPositionState();
|
|
3820
|
+
} catch {
|
|
3821
|
+
}
|
|
3822
|
+
return;
|
|
3823
|
+
}
|
|
3824
|
+
const playbackRate = this.player.state.playbackSpeed || 1;
|
|
3825
|
+
const position = Math.min(Math.max(0, this.player.state.currentTime || 0), duration);
|
|
3826
|
+
try {
|
|
3827
|
+
this.session.setPositionState({
|
|
3828
|
+
duration,
|
|
3829
|
+
playbackRate: playbackRate > 0 ? playbackRate : 1,
|
|
3830
|
+
position
|
|
3831
|
+
});
|
|
3832
|
+
} catch {
|
|
3833
|
+
}
|
|
3834
|
+
}
|
|
3835
|
+
destroy() {
|
|
3836
|
+
if (!this.supported) return;
|
|
3837
|
+
for (const [event, handler] of Object.entries(this.handlers)) {
|
|
3838
|
+
if (handler) {
|
|
3839
|
+
this.player.off(event, handler);
|
|
3840
|
+
}
|
|
3841
|
+
}
|
|
3842
|
+
this.handlers = {};
|
|
3843
|
+
if (this.isActive()) {
|
|
3844
|
+
for (const action of this.boundActions) {
|
|
3845
|
+
try {
|
|
3846
|
+
this.session.setActionHandler(action, null);
|
|
3847
|
+
} catch {
|
|
3848
|
+
}
|
|
3849
|
+
}
|
|
3850
|
+
try {
|
|
3851
|
+
this.session.metadata = null;
|
|
3852
|
+
} catch {
|
|
3853
|
+
}
|
|
3854
|
+
try {
|
|
3855
|
+
if (typeof this.session.setPositionState === "function") {
|
|
3856
|
+
this.session.setPositionState();
|
|
3857
|
+
}
|
|
3858
|
+
} catch {
|
|
3859
|
+
}
|
|
3860
|
+
try {
|
|
3861
|
+
this.session.playbackState = "none";
|
|
3862
|
+
} catch {
|
|
3863
|
+
}
|
|
3864
|
+
activeManager = null;
|
|
3865
|
+
}
|
|
3866
|
+
this.boundActions = [];
|
|
3867
|
+
}
|
|
3868
|
+
};
|
|
3869
|
+
|
|
3597
3870
|
// src/utils/UrlSafe.ts
|
|
3598
3871
|
function sanitizePosterUrl(input) {
|
|
3599
3872
|
if (typeof input !== "string" || input.length === 0 || input.length > 4096) {
|
|
@@ -4694,27 +4967,280 @@ var MetadataAlertsManager = class {
|
|
|
4694
4967
|
}
|
|
4695
4968
|
};
|
|
4696
4969
|
|
|
4970
|
+
// src/controls/KeyboardHelp.ts
|
|
4971
|
+
var ACTION_ORDER = [
|
|
4972
|
+
"play-pause",
|
|
4973
|
+
"seek-backward",
|
|
4974
|
+
"seek-forward",
|
|
4975
|
+
"volume-up",
|
|
4976
|
+
"volume-down",
|
|
4977
|
+
"mute",
|
|
4978
|
+
"captions",
|
|
4979
|
+
"caption-style-menu",
|
|
4980
|
+
"speed-down",
|
|
4981
|
+
"speed-up",
|
|
4982
|
+
"speed-menu",
|
|
4983
|
+
"quality-menu",
|
|
4984
|
+
"chapters-menu",
|
|
4985
|
+
"transcript-toggle",
|
|
4986
|
+
"fullscreen",
|
|
4987
|
+
"help"
|
|
4988
|
+
];
|
|
4989
|
+
var ACTION_REQUIRES_CONTROL = {
|
|
4990
|
+
captions: "captions",
|
|
4991
|
+
"caption-style-menu": "captionStyle",
|
|
4992
|
+
"speed-down": "speed",
|
|
4993
|
+
"speed-up": "speed",
|
|
4994
|
+
"speed-menu": "speed",
|
|
4995
|
+
"quality-menu": "quality",
|
|
4996
|
+
"chapters-menu": "chapters",
|
|
4997
|
+
"transcript-toggle": "transcript",
|
|
4998
|
+
fullscreen: "fullscreen"
|
|
4999
|
+
};
|
|
5000
|
+
var KeyboardHelp = class {
|
|
5001
|
+
player;
|
|
5002
|
+
isOpen = false;
|
|
5003
|
+
overlay = null;
|
|
5004
|
+
_triggerElement = null;
|
|
5005
|
+
_keydownHandler = null;
|
|
5006
|
+
_content = null;
|
|
5007
|
+
constructor(player) {
|
|
5008
|
+
this.player = player;
|
|
5009
|
+
}
|
|
5010
|
+
get prefix() {
|
|
5011
|
+
return this.player.options.classPrefix;
|
|
5012
|
+
}
|
|
5013
|
+
/**
|
|
5014
|
+
* Turn a raw KeyboardEvent.key value into a human-readable label. Arrow
|
|
5015
|
+
* keys become universally understood glyphs; the space bar and single
|
|
5016
|
+
* letters are normalised for legibility.
|
|
5017
|
+
*/
|
|
5018
|
+
formatKey(key) {
|
|
5019
|
+
switch (key) {
|
|
5020
|
+
case " ":
|
|
5021
|
+
return i18n.t("help.keys.space");
|
|
5022
|
+
case "ArrowUp":
|
|
5023
|
+
return "↑";
|
|
5024
|
+
case "ArrowDown":
|
|
5025
|
+
return "↓";
|
|
5026
|
+
case "ArrowLeft":
|
|
5027
|
+
return "←";
|
|
5028
|
+
case "ArrowRight":
|
|
5029
|
+
return "→";
|
|
5030
|
+
case "Escape":
|
|
5031
|
+
return "Esc";
|
|
5032
|
+
default:
|
|
5033
|
+
return key.length === 1 ? key.toUpperCase() : key;
|
|
5034
|
+
}
|
|
5035
|
+
}
|
|
5036
|
+
createElement() {
|
|
5037
|
+
const titleId = `${this.prefix}-help-title-${this.player.instanceId}`;
|
|
5038
|
+
const overlay = DOMUtils.createElement("div", {
|
|
5039
|
+
className: `${this.prefix}-settings-overlay ${this.prefix}-help-overlay`,
|
|
5040
|
+
attributes: {
|
|
5041
|
+
role: "dialog",
|
|
5042
|
+
"aria-modal": "true",
|
|
5043
|
+
"aria-labelledby": titleId
|
|
5044
|
+
}
|
|
5045
|
+
});
|
|
5046
|
+
overlay.style.display = "none";
|
|
5047
|
+
const dialog = DOMUtils.createElement("div", {
|
|
5048
|
+
className: `${this.prefix}-settings-dialog ${this.prefix}-help-dialog`
|
|
5049
|
+
});
|
|
5050
|
+
const header = DOMUtils.createElement("div", {
|
|
5051
|
+
className: `${this.prefix}-settings-header`
|
|
5052
|
+
});
|
|
5053
|
+
const title = DOMUtils.createElement("h2", {
|
|
5054
|
+
textContent: i18n.t("help.title"),
|
|
5055
|
+
attributes: { id: titleId }
|
|
5056
|
+
});
|
|
5057
|
+
const closeButton = DOMUtils.createElement("button", {
|
|
5058
|
+
className: `${this.prefix}-button ${this.prefix}-settings-close`,
|
|
5059
|
+
attributes: {
|
|
5060
|
+
type: "button",
|
|
5061
|
+
"aria-label": i18n.t("help.close")
|
|
5062
|
+
}
|
|
5063
|
+
});
|
|
5064
|
+
closeButton.appendChild(createIconElement("close"));
|
|
5065
|
+
closeButton.addEventListener("click", () => this.hide());
|
|
5066
|
+
header.appendChild(title);
|
|
5067
|
+
header.appendChild(closeButton);
|
|
5068
|
+
const content = DOMUtils.createElement("div", {
|
|
5069
|
+
className: `${this.prefix}-settings-content`
|
|
5070
|
+
});
|
|
5071
|
+
this._content = content;
|
|
5072
|
+
content.appendChild(this.buildShortcutList());
|
|
5073
|
+
dialog.appendChild(header);
|
|
5074
|
+
dialog.appendChild(content);
|
|
5075
|
+
overlay.appendChild(dialog);
|
|
5076
|
+
overlay.addEventListener("click", (e) => {
|
|
5077
|
+
if (e.target === overlay) {
|
|
5078
|
+
this.hide();
|
|
5079
|
+
}
|
|
5080
|
+
});
|
|
5081
|
+
this._keydownHandler = (e) => {
|
|
5082
|
+
if (!this.isOpen || !this.overlay) return;
|
|
5083
|
+
if (e.key === "Escape") {
|
|
5084
|
+
e.preventDefault();
|
|
5085
|
+
this.hide();
|
|
5086
|
+
return;
|
|
5087
|
+
}
|
|
5088
|
+
if (e.key === "Tab") {
|
|
5089
|
+
const focusable = Array.from(
|
|
5090
|
+
this.overlay.querySelectorAll(
|
|
5091
|
+
'button, [href], select, input, textarea, [tabindex]:not([tabindex="-1"])'
|
|
5092
|
+
)
|
|
5093
|
+
).filter((el) => !el.hasAttribute("disabled") && el.offsetParent !== null);
|
|
5094
|
+
if (focusable.length === 0) return;
|
|
5095
|
+
const first = focusable[0];
|
|
5096
|
+
const last = focusable[focusable.length - 1];
|
|
5097
|
+
if (!first || !last) return;
|
|
5098
|
+
const active = document.activeElement;
|
|
5099
|
+
if (e.shiftKey && (active === first || !this.overlay.contains(active))) {
|
|
5100
|
+
e.preventDefault();
|
|
5101
|
+
last.focus({ preventScroll: true });
|
|
5102
|
+
} else if (!e.shiftKey && active === last) {
|
|
5103
|
+
e.preventDefault();
|
|
5104
|
+
first.focus({ preventScroll: true });
|
|
5105
|
+
}
|
|
5106
|
+
}
|
|
5107
|
+
};
|
|
5108
|
+
const lifecycleSignal = this.player.lifecycleSignal;
|
|
5109
|
+
document.addEventListener(
|
|
5110
|
+
"keydown",
|
|
5111
|
+
this._keydownHandler,
|
|
5112
|
+
lifecycleSignal ? { signal: lifecycleSignal } : void 0
|
|
5113
|
+
);
|
|
5114
|
+
return overlay;
|
|
5115
|
+
}
|
|
5116
|
+
/**
|
|
5117
|
+
* Whether a shortcut row is worth showing for *this* player. Feature actions
|
|
5118
|
+
* are hidden when their control isn't present (e.g. no captions track, an
|
|
5119
|
+
* audio-only player with no fullscreen). Core actions are always relevant.
|
|
5120
|
+
*
|
|
5121
|
+
* When the player has no control bar we can't infer availability, so nothing
|
|
5122
|
+
* is hidden — the shortcuts still work and we'd rather over-show than mislead.
|
|
5123
|
+
*/
|
|
5124
|
+
isActionRelevant(action) {
|
|
5125
|
+
const requiredControl = ACTION_REQUIRES_CONTROL[action];
|
|
5126
|
+
if (!requiredControl) return true;
|
|
5127
|
+
const controlBar = this.player.controlBar;
|
|
5128
|
+
if (!controlBar || !controlBar.controls) return true;
|
|
5129
|
+
return Boolean(controlBar.controls[requiredControl]);
|
|
5130
|
+
}
|
|
5131
|
+
buildShortcutList() {
|
|
5132
|
+
const list = DOMUtils.createElement("dl", {
|
|
5133
|
+
className: `${this.prefix}-help-list`
|
|
5134
|
+
});
|
|
5135
|
+
const shortcuts = this.player.options.keyboardShortcuts;
|
|
5136
|
+
for (const action of ACTION_ORDER) {
|
|
5137
|
+
const keys = shortcuts[action];
|
|
5138
|
+
if (!Array.isArray(keys) || keys.length === 0) continue;
|
|
5139
|
+
if (!this.isActionRelevant(action)) continue;
|
|
5140
|
+
const term = DOMUtils.createElement("dt", {
|
|
5141
|
+
className: `${this.prefix}-help-action`,
|
|
5142
|
+
textContent: i18n.t(`help.actions.${action}`)
|
|
5143
|
+
});
|
|
5144
|
+
const desc = DOMUtils.createElement("dd", {
|
|
5145
|
+
className: `${this.prefix}-help-keys`
|
|
5146
|
+
});
|
|
5147
|
+
keys.forEach((key, index) => {
|
|
5148
|
+
if (index > 0) {
|
|
5149
|
+
desc.appendChild(
|
|
5150
|
+
DOMUtils.createElement("span", {
|
|
5151
|
+
className: `${this.prefix}-help-key-sep`,
|
|
5152
|
+
textContent: i18n.t("help.or")
|
|
5153
|
+
})
|
|
5154
|
+
);
|
|
5155
|
+
}
|
|
5156
|
+
desc.appendChild(
|
|
5157
|
+
DOMUtils.createElement("kbd", {
|
|
5158
|
+
className: `${this.prefix}-help-key`,
|
|
5159
|
+
textContent: this.formatKey(key)
|
|
5160
|
+
})
|
|
5161
|
+
);
|
|
5162
|
+
});
|
|
5163
|
+
list.appendChild(term);
|
|
5164
|
+
list.appendChild(desc);
|
|
5165
|
+
}
|
|
5166
|
+
return list;
|
|
5167
|
+
}
|
|
5168
|
+
show() {
|
|
5169
|
+
if (this.isOpen) return;
|
|
5170
|
+
if (!this.overlay) {
|
|
5171
|
+
this.overlay = this.createElement();
|
|
5172
|
+
this.player.container.appendChild(this.overlay);
|
|
5173
|
+
} else if (this._content) {
|
|
5174
|
+
this._content.replaceChildren(this.buildShortcutList());
|
|
5175
|
+
}
|
|
5176
|
+
const active = typeof document !== "undefined" ? document.activeElement : null;
|
|
5177
|
+
this._triggerElement = active && typeof active.focus === "function" ? active : null;
|
|
5178
|
+
this.overlay.style.display = "flex";
|
|
5179
|
+
this.isOpen = true;
|
|
5180
|
+
const closeButton = this.overlay.querySelector(`.${this.prefix}-settings-close`);
|
|
5181
|
+
closeButton?.focus({ preventScroll: true });
|
|
5182
|
+
this.player.emit("keyboardhelpopen");
|
|
5183
|
+
}
|
|
5184
|
+
hide() {
|
|
5185
|
+
if (!this.overlay) return;
|
|
5186
|
+
this.overlay.style.display = "none";
|
|
5187
|
+
this.isOpen = false;
|
|
5188
|
+
const trigger = this._triggerElement;
|
|
5189
|
+
this._triggerElement = null;
|
|
5190
|
+
if (trigger && document.contains(trigger)) {
|
|
5191
|
+
try {
|
|
5192
|
+
trigger.focus({ preventScroll: true });
|
|
5193
|
+
} catch {
|
|
5194
|
+
this.player.container?.focus();
|
|
5195
|
+
}
|
|
5196
|
+
} else {
|
|
5197
|
+
this.player.container?.focus();
|
|
5198
|
+
}
|
|
5199
|
+
this.player.emit("keyboardhelpclose");
|
|
5200
|
+
}
|
|
5201
|
+
toggle() {
|
|
5202
|
+
if (this.isOpen) {
|
|
5203
|
+
this.hide();
|
|
5204
|
+
} else {
|
|
5205
|
+
this.show();
|
|
5206
|
+
}
|
|
5207
|
+
}
|
|
5208
|
+
destroy() {
|
|
5209
|
+
if (this._keydownHandler) {
|
|
5210
|
+
document.removeEventListener("keydown", this._keydownHandler);
|
|
5211
|
+
this._keydownHandler = null;
|
|
5212
|
+
}
|
|
5213
|
+
if (this.overlay && this.overlay.parentNode) {
|
|
5214
|
+
this.overlay.parentNode.removeChild(this.overlay);
|
|
5215
|
+
}
|
|
5216
|
+
this.overlay = null;
|
|
5217
|
+
this._content = null;
|
|
5218
|
+
this._triggerElement = null;
|
|
5219
|
+
this.isOpen = false;
|
|
5220
|
+
}
|
|
5221
|
+
};
|
|
5222
|
+
|
|
4697
5223
|
// src/core/Player.ts
|
|
4698
5224
|
var AudioDescriptionManagerModule = null;
|
|
4699
5225
|
var SignLanguageManagerModule = null;
|
|
4700
5226
|
var FloatingPlayerManagerModule = null;
|
|
4701
5227
|
async function loadAudioDescriptionManager() {
|
|
4702
5228
|
if (!AudioDescriptionManagerModule) {
|
|
4703
|
-
const module = await import("./vidply.AudioDescriptionManager-
|
|
5229
|
+
const module = await import("./vidply.AudioDescriptionManager-JYYLK5KB.js");
|
|
4704
5230
|
AudioDescriptionManagerModule = module.AudioDescriptionManager;
|
|
4705
5231
|
}
|
|
4706
5232
|
return AudioDescriptionManagerModule;
|
|
4707
5233
|
}
|
|
4708
5234
|
async function loadSignLanguageManager() {
|
|
4709
5235
|
if (!SignLanguageManagerModule) {
|
|
4710
|
-
const module = await import("./vidply.SignLanguageManager-
|
|
5236
|
+
const module = await import("./vidply.SignLanguageManager-FLUCBW5H.js");
|
|
4711
5237
|
SignLanguageManagerModule = module.SignLanguageManager;
|
|
4712
5238
|
}
|
|
4713
5239
|
return SignLanguageManagerModule;
|
|
4714
5240
|
}
|
|
4715
5241
|
async function loadFloatingPlayerManager() {
|
|
4716
5242
|
if (!FloatingPlayerManagerModule) {
|
|
4717
|
-
const module = await import("./vidply.FloatingPlayerManager-
|
|
5243
|
+
const module = await import("./vidply.FloatingPlayerManager-C2UVRPZY.js");
|
|
4718
5244
|
FloatingPlayerManagerModule = module.FloatingPlayerManager;
|
|
4719
5245
|
}
|
|
4720
5246
|
return FloatingPlayerManagerModule;
|
|
@@ -4777,9 +5303,11 @@ var Player = class _Player extends EventEmitter {
|
|
|
4777
5303
|
controlBar = null;
|
|
4778
5304
|
captionManager = null;
|
|
4779
5305
|
keyboardManager = null;
|
|
5306
|
+
mediaSessionManager = null;
|
|
4780
5307
|
transcriptManager = null;
|
|
4781
5308
|
playlistManager = null;
|
|
4782
5309
|
settingsDialog = null;
|
|
5310
|
+
keyboardHelp = null;
|
|
4783
5311
|
audioDescriptionManager = null;
|
|
4784
5312
|
signLanguageManager = null;
|
|
4785
5313
|
floatingPlayerManager = null;
|
|
@@ -4895,6 +5423,11 @@ var Player = class _Player extends EventEmitter {
|
|
|
4895
5423
|
poster: null,
|
|
4896
5424
|
responsive: true,
|
|
4897
5425
|
fillContainer: false,
|
|
5426
|
+
// Media metadata + OS media controls (Media Session API)
|
|
5427
|
+
title: null,
|
|
5428
|
+
artist: null,
|
|
5429
|
+
album: null,
|
|
5430
|
+
mediaSession: true,
|
|
4898
5431
|
// Playback
|
|
4899
5432
|
autoplay: false,
|
|
4900
5433
|
loop: false,
|
|
@@ -4942,6 +5475,7 @@ var Player = class _Player extends EventEmitter {
|
|
|
4942
5475
|
captionsButton: true,
|
|
4943
5476
|
transcriptButton: true,
|
|
4944
5477
|
fullscreenButton: true,
|
|
5478
|
+
helpButton: true,
|
|
4945
5479
|
pipButton: false,
|
|
4946
5480
|
floating: false,
|
|
4947
5481
|
floatingPosition: "bottom-right",
|
|
@@ -4967,6 +5501,9 @@ var Player = class _Player extends EventEmitter {
|
|
|
4967
5501
|
audioDescriptionSrc: null,
|
|
4968
5502
|
// URL to audio-described version
|
|
4969
5503
|
audioDescriptionButton: true,
|
|
5504
|
+
audioDescriptionMode: "auto",
|
|
5505
|
+
audioDescriptionSpeech: true,
|
|
5506
|
+
audioDescriptionExtended: true,
|
|
4970
5507
|
// Sign Language
|
|
4971
5508
|
signLanguage: true,
|
|
4972
5509
|
signLanguageSrc: null,
|
|
@@ -4997,7 +5534,8 @@ var Player = class _Player extends EventEmitter {
|
|
|
4997
5534
|
"speed-menu": ["s"],
|
|
4998
5535
|
"quality-menu": ["q"],
|
|
4999
5536
|
"chapters-menu": ["j"],
|
|
5000
|
-
"transcript-toggle": ["t"]
|
|
5537
|
+
"transcript-toggle": ["t"],
|
|
5538
|
+
"help": ["?"]
|
|
5001
5539
|
},
|
|
5002
5540
|
// Accessibility
|
|
5003
5541
|
ariaLabels: {},
|
|
@@ -5320,6 +5858,9 @@ var Player = class _Player extends EventEmitter {
|
|
|
5320
5858
|
if (this.options.keyboard) {
|
|
5321
5859
|
this.keyboardManager = new KeyboardManager(this);
|
|
5322
5860
|
}
|
|
5861
|
+
if (this.options.mediaSession) {
|
|
5862
|
+
this.mediaSessionManager = new MediaSessionManager(this);
|
|
5863
|
+
}
|
|
5323
5864
|
this.setupResponsiveHandlers();
|
|
5324
5865
|
if (this.options.startTime > 0) {
|
|
5325
5866
|
this.seek(this.options.startTime);
|
|
@@ -5364,7 +5905,7 @@ var Player = class _Player extends EventEmitter {
|
|
|
5364
5905
|
if (!this.options.transcript && !this.options.transcriptButton) {
|
|
5365
5906
|
return null;
|
|
5366
5907
|
}
|
|
5367
|
-
const module = await import("./vidply.TranscriptManager-
|
|
5908
|
+
const module = await import("./vidply.TranscriptManager-Y2RYXHJW.js");
|
|
5368
5909
|
const fallbackDefault = module.default;
|
|
5369
5910
|
const Manager = module.TranscriptManager || fallbackDefault;
|
|
5370
5911
|
if (!Manager) {
|
|
@@ -5392,15 +5933,33 @@ var Player = class _Player extends EventEmitter {
|
|
|
5392
5933
|
if (this.audioDescriptionManager) {
|
|
5393
5934
|
return this.audioDescriptionManager;
|
|
5394
5935
|
}
|
|
5395
|
-
|
|
5396
|
-
const hasAudioDescButton = this.options.audioDescriptionButton;
|
|
5397
|
-
if (!hasAudioDescSrc && !hasAudioDescButton) {
|
|
5936
|
+
if (!this.hasAudioDescriptionContent()) {
|
|
5398
5937
|
return null;
|
|
5399
5938
|
}
|
|
5400
5939
|
const AudioDescManager = await loadAudioDescriptionManager();
|
|
5401
5940
|
this.audioDescriptionManager = new AudioDescManager(this);
|
|
5402
5941
|
return this.audioDescriptionManager;
|
|
5403
5942
|
}
|
|
5943
|
+
/**
|
|
5944
|
+
* True when the current media actually exposes audio-description content:
|
|
5945
|
+
* an explicit described-audio source, `<source>` elements carrying
|
|
5946
|
+
* `data-desc-src` / `data-orig-src`, or a `descriptions` text track.
|
|
5947
|
+
* Mirrors `ControlBar.hasAudioDescription()` so the chunk load and the
|
|
5948
|
+
* button visibility stay in lock-step.
|
|
5949
|
+
*/
|
|
5950
|
+
hasAudioDescriptionContent() {
|
|
5951
|
+
if (this.options.audioDescriptionSrc || this.audioDescriptionSrc) {
|
|
5952
|
+
return true;
|
|
5953
|
+
}
|
|
5954
|
+
const hasSourceElementsWithDesc = this.sourceElements.some(
|
|
5955
|
+
(el) => el.getAttribute("data-desc-src") || el.getAttribute("data-orig-src")
|
|
5956
|
+
);
|
|
5957
|
+
if (hasSourceElementsWithDesc) {
|
|
5958
|
+
return true;
|
|
5959
|
+
}
|
|
5960
|
+
const textTracks = this.element ? Array.from(this.element.textTracks || []) : [];
|
|
5961
|
+
return textTracks.some((track) => track.kind === "descriptions");
|
|
5962
|
+
}
|
|
5404
5963
|
// ============================================
|
|
5405
5964
|
// Resume Playback Methods
|
|
5406
5965
|
// ============================================
|
|
@@ -5412,16 +5971,24 @@ var Player = class _Player extends EventEmitter {
|
|
|
5412
5971
|
if (this.signLanguageManager) {
|
|
5413
5972
|
return this.signLanguageManager;
|
|
5414
5973
|
}
|
|
5415
|
-
|
|
5416
|
-
const hasSignLangSources = this.options.signLanguageSources && Object.keys(this.options.signLanguageSources).length > 0;
|
|
5417
|
-
const hasSignLangButton = this.options.signLanguageButton;
|
|
5418
|
-
if (!hasSignLangSrc && !hasSignLangSources && !hasSignLangButton) {
|
|
5974
|
+
if (!this.hasSignLanguageContent()) {
|
|
5419
5975
|
return null;
|
|
5420
5976
|
}
|
|
5421
5977
|
const SignLangManager = await loadSignLanguageManager();
|
|
5422
5978
|
this.signLanguageManager = new SignLangManager(this);
|
|
5423
5979
|
return this.signLanguageManager;
|
|
5424
5980
|
}
|
|
5981
|
+
/**
|
|
5982
|
+
* True when a sign-language video source (single `signLanguageSrc` or a
|
|
5983
|
+
* `signLanguageSources` map) is configured. Mirrors
|
|
5984
|
+
* `ControlBar.hasSignLanguage()`.
|
|
5985
|
+
*/
|
|
5986
|
+
hasSignLanguageContent() {
|
|
5987
|
+
if (this.options.signLanguageSrc || this.signLanguageSrc) {
|
|
5988
|
+
return true;
|
|
5989
|
+
}
|
|
5990
|
+
return !!(this.options.signLanguageSources && Object.keys(this.options.signLanguageSources).length > 0);
|
|
5991
|
+
}
|
|
5425
5992
|
/**
|
|
5426
5993
|
* Lazy-load and instantiate the floating (in-page PiP) manager. Only
|
|
5427
5994
|
* created when `options.floating === true` and the media element is a
|
|
@@ -5446,13 +6013,10 @@ var Player = class _Player extends EventEmitter {
|
|
|
5446
6013
|
*/
|
|
5447
6014
|
async initFeatureManagers() {
|
|
5448
6015
|
const promises = [];
|
|
5449
|
-
|
|
5450
|
-
(el) => el.getAttribute("data-desc-src") || el.getAttribute("data-orig-src")
|
|
5451
|
-
);
|
|
5452
|
-
if (this.options.audioDescriptionButton || this.options.audioDescriptionSrc || this.audioDescriptionSrc || hasSourceElementsWithDesc) {
|
|
6016
|
+
if (this.hasAudioDescriptionContent()) {
|
|
5453
6017
|
promises.push(this.ensureAudioDescriptionManager());
|
|
5454
6018
|
}
|
|
5455
|
-
if (this.
|
|
6019
|
+
if (this.hasSignLanguageContent()) {
|
|
5456
6020
|
promises.push(this.ensureSignLanguageManager());
|
|
5457
6021
|
}
|
|
5458
6022
|
if (this.options.floating && this.element && this.element.tagName === "VIDEO") {
|
|
@@ -5782,6 +6346,9 @@ var Player = class _Player extends EventEmitter {
|
|
|
5782
6346
|
}
|
|
5783
6347
|
this.currentSource = src;
|
|
5784
6348
|
this._pendingSource = null;
|
|
6349
|
+
if (this.hasAudioDescriptionContent()) {
|
|
6350
|
+
await this.ensureAudioDescriptionManager();
|
|
6351
|
+
}
|
|
5785
6352
|
this.audioDescriptionManager?.initFromSourceElements(this.sourceElements, this.trackElements);
|
|
5786
6353
|
if (!this.originalSrc) {
|
|
5787
6354
|
this.originalSrc = src;
|
|
@@ -5807,19 +6374,19 @@ var Player = class _Player extends EventEmitter {
|
|
|
5807
6374
|
}
|
|
5808
6375
|
async _detectRendererClass(src) {
|
|
5809
6376
|
if (src.includes("youtube.com") || src.includes("youtu.be")) {
|
|
5810
|
-
const module = await import("./vidply.YouTubeRenderer-
|
|
6377
|
+
const module = await import("./vidply.YouTubeRenderer-EU2BARZF.js");
|
|
5811
6378
|
return module.YouTubeRenderer ?? module.default;
|
|
5812
6379
|
} else if (src.includes("vimeo.com")) {
|
|
5813
|
-
const module = await import("./vidply.VimeoRenderer-
|
|
6380
|
+
const module = await import("./vidply.VimeoRenderer-RQFQD7OE.js");
|
|
5814
6381
|
return module.VimeoRenderer ?? module.default;
|
|
5815
6382
|
} else if (src.includes(".m3u8")) {
|
|
5816
|
-
const module = await import("./vidply.HLSRenderer-
|
|
6383
|
+
const module = await import("./vidply.HLSRenderer-ZVBK2TNQ.js");
|
|
5817
6384
|
return module.HLSRenderer ?? module.default;
|
|
5818
6385
|
} else if (src.includes(".mpd")) {
|
|
5819
|
-
const module = await import("./vidply.DASHRenderer-
|
|
6386
|
+
const module = await import("./vidply.DASHRenderer-VEJ4HDHO.js");
|
|
5820
6387
|
return module.DASHRenderer ?? module.default;
|
|
5821
6388
|
} else if (src.includes("soundcloud.com") || src.includes("api.soundcloud.com")) {
|
|
5822
|
-
const module = await import("./vidply.SoundCloudRenderer-
|
|
6389
|
+
const module = await import("./vidply.SoundCloudRenderer-MGMAJ7NK.js");
|
|
5823
6390
|
return module.SoundCloudRenderer ?? module.default;
|
|
5824
6391
|
}
|
|
5825
6392
|
return HTML5Renderer;
|
|
@@ -6611,6 +7178,26 @@ var Player = class _Player extends EventEmitter {
|
|
|
6611
7178
|
}
|
|
6612
7179
|
hideSettings() {
|
|
6613
7180
|
}
|
|
7181
|
+
/**
|
|
7182
|
+
* Lazily build (on first use) and toggle the keyboard-shortcuts help
|
|
7183
|
+
* dialog. Reflects the live `keyboardShortcuts` bindings, including any
|
|
7184
|
+
* consumer overrides.
|
|
7185
|
+
*/
|
|
7186
|
+
toggleKeyboardHelp() {
|
|
7187
|
+
if (!this.keyboardHelp) {
|
|
7188
|
+
this.keyboardHelp = new KeyboardHelp(this);
|
|
7189
|
+
}
|
|
7190
|
+
this.keyboardHelp.toggle();
|
|
7191
|
+
}
|
|
7192
|
+
showKeyboardHelp() {
|
|
7193
|
+
if (!this.keyboardHelp) {
|
|
7194
|
+
this.keyboardHelp = new KeyboardHelp(this);
|
|
7195
|
+
}
|
|
7196
|
+
this.keyboardHelp.show();
|
|
7197
|
+
}
|
|
7198
|
+
hideKeyboardHelp() {
|
|
7199
|
+
this.keyboardHelp?.hide();
|
|
7200
|
+
}
|
|
6614
7201
|
// Utility methods
|
|
6615
7202
|
getCurrentTime() {
|
|
6616
7203
|
return this.state.currentTime;
|
|
@@ -6750,6 +7337,22 @@ var Player = class _Player extends EventEmitter {
|
|
|
6750
7337
|
}
|
|
6751
7338
|
this.settingsDialog = null;
|
|
6752
7339
|
}
|
|
7340
|
+
if (this.keyboardHelp && typeof this.keyboardHelp.destroy === "function") {
|
|
7341
|
+
try {
|
|
7342
|
+
this.keyboardHelp.destroy();
|
|
7343
|
+
} catch (err) {
|
|
7344
|
+
this.log(`KeyboardHelp.destroy failed: ${err}`, "warn");
|
|
7345
|
+
}
|
|
7346
|
+
this.keyboardHelp = null;
|
|
7347
|
+
}
|
|
7348
|
+
if (this.mediaSessionManager && typeof this.mediaSessionManager.destroy === "function") {
|
|
7349
|
+
try {
|
|
7350
|
+
this.mediaSessionManager.destroy();
|
|
7351
|
+
} catch (err) {
|
|
7352
|
+
this.log(`MediaSessionManager.destroy failed: ${err}`, "warn");
|
|
7353
|
+
}
|
|
7354
|
+
this.mediaSessionManager = null;
|
|
7355
|
+
}
|
|
6753
7356
|
if (this.floatingPlayerManager) {
|
|
6754
7357
|
try {
|
|
6755
7358
|
this.floatingPlayerManager.destroy();
|
|
@@ -7285,12 +7888,19 @@ var PlaylistManager = class {
|
|
|
7285
7888
|
if (typeof this.player.invalidateTrackCache === "function") {
|
|
7286
7889
|
this.player.invalidateTrackCache();
|
|
7287
7890
|
}
|
|
7288
|
-
|
|
7891
|
+
const reinitAudioDescription = (adm) => {
|
|
7892
|
+
if (!adm || typeof adm.initFromSourceElements !== "function") return;
|
|
7289
7893
|
try {
|
|
7290
|
-
|
|
7291
|
-
|
|
7894
|
+
adm.captionTracks = [];
|
|
7895
|
+
adm.initFromSourceElements(this.player.sourceElements, this.player.trackElements);
|
|
7292
7896
|
} catch {
|
|
7293
7897
|
}
|
|
7898
|
+
};
|
|
7899
|
+
if (this.player.audioDescriptionManager) {
|
|
7900
|
+
reinitAudioDescription(this.player.audioDescriptionManager);
|
|
7901
|
+
} else if (this.player.hasAudioDescriptionContent?.()) {
|
|
7902
|
+
void this.player.ensureAudioDescriptionManager().then(reinitAudioDescription).catch(() => {
|
|
7903
|
+
});
|
|
7294
7904
|
}
|
|
7295
7905
|
if (this.player.captionManager && typeof this.player.captionManager.loadTracks === "function") {
|
|
7296
7906
|
try {
|
|
@@ -8152,6 +8762,9 @@ function parseDataAttributes(dataset) {
|
|
|
8152
8762
|
signLanguageDisplayMode: "signLanguageDisplayMode",
|
|
8153
8763
|
audioDescriptionSrc: "audioDescriptionSrc",
|
|
8154
8764
|
audioDescriptionButton: "audioDescriptionButton",
|
|
8765
|
+
audioDescriptionMode: "audioDescriptionMode",
|
|
8766
|
+
audioDescriptionSpeech: "audioDescriptionSpeech",
|
|
8767
|
+
audioDescriptionExtended: "audioDescriptionExtended",
|
|
8155
8768
|
autoplay: "autoplay",
|
|
8156
8769
|
loop: "loop",
|
|
8157
8770
|
muted: "muted",
|