vidply 1.0.8 → 1.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/vidply.css +113 -44
- package/dist/vidply.esm.js +806 -70
- package/dist/vidply.esm.js.map +2 -2
- package/dist/vidply.esm.min.js +3 -3
- package/dist/vidply.esm.min.meta.json +7 -7
- package/dist/vidply.js +806 -70
- package/dist/vidply.js.map +2 -2
- package/dist/vidply.min.css +1 -1
- package/dist/vidply.min.js +3 -3
- package/dist/vidply.min.meta.json +7 -7
- package/package.json +1 -1
- package/src/controls/TranscriptManager.js +328 -27
- package/src/core/Player.js +682 -56
- package/src/i18n/translations.js +10 -5
- package/src/icons/Icons.js +2 -2
- package/src/styles/vidply.css +113 -44
package/dist/vidply.js
CHANGED
|
@@ -520,7 +520,8 @@ var VidPly = (() => {
|
|
|
520
520
|
resizeWindow: "Resize Window",
|
|
521
521
|
styleTranscript: "Open transcript style settings",
|
|
522
522
|
closeMenu: "Close Menu",
|
|
523
|
-
styleTitle: "Transcript Style"
|
|
523
|
+
styleTitle: "Transcript Style",
|
|
524
|
+
autoscroll: "Autoscroll"
|
|
524
525
|
},
|
|
525
526
|
settings: {
|
|
526
527
|
title: "Settings",
|
|
@@ -641,7 +642,8 @@ var VidPly = (() => {
|
|
|
641
642
|
resizeWindow: "Fenster vergr\xF6\xDFern/verkleinern",
|
|
642
643
|
styleTranscript: "Transkript-Stileinstellungen \xF6ffnen",
|
|
643
644
|
closeMenu: "Men\xFC schlie\xDFen",
|
|
644
|
-
styleTitle: "Transkript-Stil"
|
|
645
|
+
styleTitle: "Transkript-Stil",
|
|
646
|
+
autoscroll: "Automatisches Scrollen"
|
|
645
647
|
},
|
|
646
648
|
settings: {
|
|
647
649
|
title: "Einstellungen",
|
|
@@ -762,7 +764,8 @@ var VidPly = (() => {
|
|
|
762
764
|
resizeWindow: "Cambiar tama\xF1o de ventana",
|
|
763
765
|
styleTranscript: "Abrir configuraci\xF3n de estilo de transcripci\xF3n",
|
|
764
766
|
closeMenu: "Cerrar men\xFA",
|
|
765
|
-
styleTitle: "Estilo de Transcripci\xF3n"
|
|
767
|
+
styleTitle: "Estilo de Transcripci\xF3n",
|
|
768
|
+
autoscroll: "Desplazamiento autom\xE1tico"
|
|
766
769
|
},
|
|
767
770
|
settings: {
|
|
768
771
|
title: "Configuraci\xF3n",
|
|
@@ -883,7 +886,8 @@ var VidPly = (() => {
|
|
|
883
886
|
resizeWindow: "Redimensionner la fen\xEAtre",
|
|
884
887
|
styleTranscript: "Ouvrir les param\xE8tres de style de transcription",
|
|
885
888
|
closeMenu: "Fermer le menu",
|
|
886
|
-
styleTitle: "Style de Transcription"
|
|
889
|
+
styleTitle: "Style de Transcription",
|
|
890
|
+
autoscroll: "D\xE9filement automatique"
|
|
887
891
|
},
|
|
888
892
|
settings: {
|
|
889
893
|
title: "Param\xE8tres",
|
|
@@ -1004,7 +1008,8 @@ var VidPly = (() => {
|
|
|
1004
1008
|
resizeWindow: "\u30A6\u30A3\u30F3\u30C9\u30A6\u306E\u30B5\u30A4\u30BA\u5909\u66F4",
|
|
1005
1009
|
styleTranscript: "\u6587\u5B57\u8D77\u3053\u3057\u30B9\u30BF\u30A4\u30EB\u8A2D\u5B9A\u3092\u958B\u304F",
|
|
1006
1010
|
closeMenu: "\u30E1\u30CB\u30E5\u30FC\u3092\u9589\u3058\u308B",
|
|
1007
|
-
styleTitle: "\u6587\u5B57\u8D77\u3053\u3057\u30B9\u30BF\u30A4\u30EB"
|
|
1011
|
+
styleTitle: "\u6587\u5B57\u8D77\u3053\u3057\u30B9\u30BF\u30A4\u30EB",
|
|
1012
|
+
autoscroll: "\u81EA\u52D5\u30B9\u30AF\u30ED\u30FC\u30EB"
|
|
1008
1013
|
},
|
|
1009
1014
|
settings: {
|
|
1010
1015
|
title: "\u8A2D\u5B9A",
|
|
@@ -1183,8 +1188,8 @@ var VidPly = (() => {
|
|
|
1183
1188
|
language: `<path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zm6.93 6h-2.95c-.32-1.25-.78-2.45-1.38-3.56 1.84.63 3.37 1.91 4.33 3.56zM12 4.04c.83 1.2 1.48 2.53 1.91 3.96h-3.82c.43-1.43 1.08-2.76 1.91-3.96zM4.26 14C4.1 13.36 4 12.69 4 12s.1-1.36.26-2h3.38c-.08.66-.14 1.32-.14 2 0 .68.06 1.34.14 2H4.26zm.82 2h2.95c.32 1.25.78 2.45 1.38 3.56-1.84-.63-3.37-1.9-4.33-3.56zm2.95-8H5.08c.96-1.66 2.49-2.93 4.33-3.56C8.81 5.55 8.35 6.75 8.03 8zM12 19.96c-.83-1.2-1.48-2.53-1.91-3.96h3.82c-.43 1.43-1.08 2.76-1.91 3.96zM14.34 14H9.66c-.09-.66-.16-1.32-.16-2 0-.68.07-1.35.16-2h4.68c.09.65.16 1.32.16 2 0 .68-.07 1.34-.16 2zm.25 5.56c.6-1.11 1.06-2.31 1.38-3.56h2.95c-.96 1.65-2.49 2.93-4.33 3.56zM16.36 14c.08-.66.14-1.32.14-2 0-.68-.06-1.34-.14-2h3.38c.16.64.26 1.31.26 2s-.1 1.36-.26 2h-3.38z"/>`,
|
|
1184
1189
|
hd: `<path d="M19 3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.11 0 2-.9 2-2V5c0-1.1-.89-2-2-2zm-8 12H9.5v-2h-2v2H6V9h1.5v2.5h2V9H11v6zm7-1c0 .55-.45 1-1 1h-.75v1.5h-1.5V15H14c-.55 0-1-.45-1-1v-4c0-.55.45-1 1-1h3c.55 0 1 .45 1 1v4zm-3.5-.5h2v-3h-2v3z"/>`,
|
|
1185
1190
|
transcript: `<path d="M14 2H6c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8l-6-6zm2 16H8v-2h8v2zm0-4H8v-2h8v2zm-3-5V3.5L18.5 9H13z"/>`,
|
|
1186
|
-
audioDescription: `<rect x="2" y="5" width="20" height="14" rx="2" fill="
|
|
1187
|
-
audioDescriptionOn: `<rect x="2" y="5" width="20" height="14" rx="2" fill="
|
|
1191
|
+
audioDescription: `<rect x="2" y="5" width="20" height="14" rx="2" fill="#ffffff" stroke="#ffffff" stroke-width="2"/><text x="12" y="16" font-family="Arial, sans-serif" font-size="10" font-weight="bold" text-anchor="middle" fill="#1a1a1a">AD</text>`,
|
|
1192
|
+
audioDescriptionOn: `<rect x="2" y="5" width="20" height="14" rx="2" fill="none" stroke="currentColor" stroke-width="2"/><text x="12" y="16" font-family="Arial, sans-serif" font-size="10" font-weight="bold" text-anchor="middle" fill="currentColor">AD</text>`,
|
|
1188
1193
|
signLanguage: `<g transform="scale(1.5)"><path d="M16 11.3c-.1-.9-4.8 1.3-5.4 1.1-2.6-1 5.8-1.3 5.1-2.9s-5.1 1.5-6 1.4C6.5 9.4 16.5 9.1 13.5 8c-1.9-.6-8.8 2.9-6.8.4.7-.6.7-1.9-.7-1.7-9.7 7.2-.7 12.2 8.8 7 0-1.3-3.5.4-4.1.4-2.6 0 5.6-2 5.4-3ZM3.9 7.8c3.2-4.2 3.7 1.2 6 .1s.2-.2.2-.3c.7-2.7 2.5-7.5-1.5-1.3-1.6 0 1.1-4 1-4.6C8.9-1 7.3 4.4 7.2 4.9c-1.6.7-.9-1.4-.7-1.5 3-6-.6-3.1-.9.4-2.5 1.8 0-2.8 0-3.5C2.8-.9 4 9.4 1.1 4.9S.1 4.6 0 5c-.4 2.7 2.6 7.2 3.9 2.8Z"/></g>`,
|
|
1189
1194
|
signLanguageOn: `<g transform="scale(1.5)"><path d="M16 11.3c-.1-.9-4.8 1.3-5.4 1.1-2.6-1 5.8-1.3 5.1-2.9s-5.1 1.5-6 1.4C6.5 9.4 16.5 9.1 13.5 8c-1.9-.6-8.8 2.9-6.8.4.7-.6.7-1.9-.7-1.7-9.7 7.2-.7 12.2 8.8 7 0-1.3-3.5.4-4.1.4-2.6 0 5.6-2 5.4-3ZM3.9 7.8c3.2-4.2 3.7 1.2 6 .1s.2-.2.2-.3c.7-2.7 2.5-7.5-1.5-1.3-1.6 0 1.1-4 1-4.6C8.9-1 7.3 4.4 7.2 4.9c-1.6.7-.9-1.4-.7-1.5 3-6-.6-3.1-.9.4-2.5 1.8 0-2.8 0-3.5C2.8-.9 4 9.4 1.1 4.9S.1 4.6 0 5c-.4 2.7 2.6 7.2 3.9 2.8Z"/></g>`,
|
|
1190
1195
|
speaker: `<path d="M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02z"/>`,
|
|
@@ -3341,7 +3346,12 @@ var VidPly = (() => {
|
|
|
3341
3346
|
this.styleDialog = null;
|
|
3342
3347
|
this.styleDialogVisible = false;
|
|
3343
3348
|
this.styleDialogJustOpened = false;
|
|
3349
|
+
this.languageSelector = null;
|
|
3350
|
+
this.currentTranscriptLanguage = null;
|
|
3351
|
+
this.availableTranscriptLanguages = [];
|
|
3352
|
+
this.languageSelectorHandler = null;
|
|
3344
3353
|
const savedPreferences = this.storage.getTranscriptPreferences();
|
|
3354
|
+
this.autoscrollEnabled = (savedPreferences == null ? void 0 : savedPreferences.autoscroll) !== void 0 ? savedPreferences.autoscroll : true;
|
|
3345
3355
|
this.transcriptStyle = {
|
|
3346
3356
|
fontSize: (savedPreferences == null ? void 0 : savedPreferences.fontSize) || this.player.options.transcriptFontSize || "100%",
|
|
3347
3357
|
fontFamily: (savedPreferences == null ? void 0 : savedPreferences.fontFamily) || this.player.options.transcriptFontFamily || "sans-serif",
|
|
@@ -3364,13 +3374,15 @@ var VidPly = (() => {
|
|
|
3364
3374
|
documentClick: null,
|
|
3365
3375
|
styleDialogKeydown: null
|
|
3366
3376
|
};
|
|
3377
|
+
this.timeouts = /* @__PURE__ */ new Set();
|
|
3367
3378
|
this.init();
|
|
3368
3379
|
}
|
|
3369
3380
|
init() {
|
|
3381
|
+
this.setupMetadataHandlingOnLoad();
|
|
3370
3382
|
this.player.on("timeupdate", this.handlers.timeupdate);
|
|
3371
3383
|
this.player.on("fullscreenchange", () => {
|
|
3372
3384
|
if (this.isVisible) {
|
|
3373
|
-
|
|
3385
|
+
this.setManagedTimeout(() => this.positionTranscript(), 100);
|
|
3374
3386
|
}
|
|
3375
3387
|
});
|
|
3376
3388
|
}
|
|
@@ -3391,7 +3403,7 @@ var VidPly = (() => {
|
|
|
3391
3403
|
if (this.transcriptWindow) {
|
|
3392
3404
|
this.transcriptWindow.style.display = "flex";
|
|
3393
3405
|
this.isVisible = true;
|
|
3394
|
-
|
|
3406
|
+
this.setManagedTimeout(() => {
|
|
3395
3407
|
if (this.settingsButton) {
|
|
3396
3408
|
this.settingsButton.focus();
|
|
3397
3409
|
}
|
|
@@ -3402,8 +3414,8 @@ var VidPly = (() => {
|
|
|
3402
3414
|
this.loadTranscriptData();
|
|
3403
3415
|
if (this.transcriptWindow) {
|
|
3404
3416
|
this.transcriptWindow.style.display = "flex";
|
|
3405
|
-
|
|
3406
|
-
|
|
3417
|
+
this.setManagedTimeout(() => this.positionTranscript(), 0);
|
|
3418
|
+
this.setManagedTimeout(() => {
|
|
3407
3419
|
if (this.settingsButton) {
|
|
3408
3420
|
this.settingsButton.focus();
|
|
3409
3421
|
}
|
|
@@ -3480,8 +3492,41 @@ var VidPly = (() => {
|
|
|
3480
3492
|
const title = DOMUtils.createElement("h3", {
|
|
3481
3493
|
textContent: i18n.t("transcript.title")
|
|
3482
3494
|
});
|
|
3495
|
+
const autoscrollLabel = DOMUtils.createElement("label", {
|
|
3496
|
+
className: `${this.player.options.classPrefix}-transcript-autoscroll-label`,
|
|
3497
|
+
attributes: {
|
|
3498
|
+
"title": i18n.t("transcript.autoscroll")
|
|
3499
|
+
}
|
|
3500
|
+
});
|
|
3501
|
+
this.autoscrollCheckbox = DOMUtils.createElement("input", {
|
|
3502
|
+
attributes: {
|
|
3503
|
+
"type": "checkbox",
|
|
3504
|
+
"checked": this.autoscrollEnabled,
|
|
3505
|
+
"aria-label": i18n.t("transcript.autoscroll")
|
|
3506
|
+
}
|
|
3507
|
+
});
|
|
3508
|
+
const autoscrollText = DOMUtils.createElement("span", {
|
|
3509
|
+
textContent: i18n.t("transcript.autoscroll"),
|
|
3510
|
+
className: `${this.player.options.classPrefix}-transcript-autoscroll-text`
|
|
3511
|
+
});
|
|
3512
|
+
autoscrollLabel.appendChild(this.autoscrollCheckbox);
|
|
3513
|
+
autoscrollLabel.appendChild(autoscrollText);
|
|
3514
|
+
this.autoscrollCheckbox.addEventListener("change", (e) => {
|
|
3515
|
+
this.autoscrollEnabled = e.target.checked;
|
|
3516
|
+
this.saveAutoscrollPreference();
|
|
3517
|
+
});
|
|
3483
3518
|
this.headerLeft.appendChild(this.settingsButton);
|
|
3484
3519
|
this.headerLeft.appendChild(title);
|
|
3520
|
+
this.headerLeft.appendChild(autoscrollLabel);
|
|
3521
|
+
this.languageSelector = DOMUtils.createElement("select", {
|
|
3522
|
+
className: `${this.player.options.classPrefix}-transcript-language-select`,
|
|
3523
|
+
attributes: {
|
|
3524
|
+
"aria-label": i18n.t("settings.language") || "Language",
|
|
3525
|
+
"style": "display: none;"
|
|
3526
|
+
// Hidden until we detect multiple languages
|
|
3527
|
+
}
|
|
3528
|
+
});
|
|
3529
|
+
this.headerLeft.appendChild(this.languageSelector);
|
|
3485
3530
|
const closeButton = DOMUtils.createElement("button", {
|
|
3486
3531
|
className: `${this.player.options.classPrefix}-transcript-close`,
|
|
3487
3532
|
attributes: {
|
|
@@ -3524,8 +3569,10 @@ var VidPly = (() => {
|
|
|
3524
3569
|
this.documentClickHandlerAdded = false;
|
|
3525
3570
|
let resizeTimeout;
|
|
3526
3571
|
this.handlers.resize = () => {
|
|
3527
|
-
|
|
3528
|
-
|
|
3572
|
+
if (resizeTimeout) {
|
|
3573
|
+
this.clearManagedTimeout(resizeTimeout);
|
|
3574
|
+
}
|
|
3575
|
+
resizeTimeout = this.setManagedTimeout(() => this.positionTranscript(), 100);
|
|
3529
3576
|
};
|
|
3530
3577
|
window.addEventListener("resize", this.handlers.resize);
|
|
3531
3578
|
}
|
|
@@ -3595,17 +3642,94 @@ var VidPly = (() => {
|
|
|
3595
3642
|
}
|
|
3596
3643
|
}
|
|
3597
3644
|
}
|
|
3645
|
+
/**
|
|
3646
|
+
* Get available transcript languages from tracks
|
|
3647
|
+
*/
|
|
3648
|
+
getAvailableTranscriptLanguages() {
|
|
3649
|
+
const textTracks = this.player.textTracks;
|
|
3650
|
+
const languages = /* @__PURE__ */ new Map();
|
|
3651
|
+
textTracks.forEach((track) => {
|
|
3652
|
+
if ((track.kind === "captions" || track.kind === "subtitles") && track.language) {
|
|
3653
|
+
if (!languages.has(track.language)) {
|
|
3654
|
+
languages.set(track.language, {
|
|
3655
|
+
language: track.language,
|
|
3656
|
+
label: track.label || track.language,
|
|
3657
|
+
track
|
|
3658
|
+
});
|
|
3659
|
+
}
|
|
3660
|
+
}
|
|
3661
|
+
});
|
|
3662
|
+
return Array.from(languages.values());
|
|
3663
|
+
}
|
|
3664
|
+
/**
|
|
3665
|
+
* Update language selector dropdown
|
|
3666
|
+
*/
|
|
3667
|
+
updateLanguageSelector() {
|
|
3668
|
+
if (!this.languageSelector) return;
|
|
3669
|
+
this.availableTranscriptLanguages = this.getAvailableTranscriptLanguages();
|
|
3670
|
+
this.languageSelector.innerHTML = "";
|
|
3671
|
+
if (this.availableTranscriptLanguages.length < 2) {
|
|
3672
|
+
this.languageSelector.style.display = "none";
|
|
3673
|
+
return;
|
|
3674
|
+
}
|
|
3675
|
+
this.languageSelector.style.display = "block";
|
|
3676
|
+
this.availableTranscriptLanguages.forEach((langInfo, index) => {
|
|
3677
|
+
const option = DOMUtils.createElement("option", {
|
|
3678
|
+
textContent: langInfo.label,
|
|
3679
|
+
attributes: {
|
|
3680
|
+
"value": langInfo.language
|
|
3681
|
+
}
|
|
3682
|
+
});
|
|
3683
|
+
this.languageSelector.appendChild(option);
|
|
3684
|
+
});
|
|
3685
|
+
if (this.currentTranscriptLanguage) {
|
|
3686
|
+
this.languageSelector.value = this.currentTranscriptLanguage;
|
|
3687
|
+
} else if (this.availableTranscriptLanguages.length > 0) {
|
|
3688
|
+
const activeTrack = this.player.textTracks.find(
|
|
3689
|
+
(track) => (track.kind === "captions" || track.kind === "subtitles") && track.mode === "showing"
|
|
3690
|
+
);
|
|
3691
|
+
this.currentTranscriptLanguage = activeTrack ? activeTrack.language : this.availableTranscriptLanguages[0].language;
|
|
3692
|
+
this.languageSelector.value = this.currentTranscriptLanguage;
|
|
3693
|
+
}
|
|
3694
|
+
if (this.languageSelectorHandler) {
|
|
3695
|
+
this.languageSelector.removeEventListener("change", this.languageSelectorHandler);
|
|
3696
|
+
}
|
|
3697
|
+
this.languageSelectorHandler = (e) => {
|
|
3698
|
+
this.currentTranscriptLanguage = e.target.value;
|
|
3699
|
+
this.loadTranscriptData();
|
|
3700
|
+
};
|
|
3701
|
+
this.languageSelector.addEventListener("change", this.languageSelectorHandler);
|
|
3702
|
+
}
|
|
3598
3703
|
/**
|
|
3599
3704
|
* Load transcript data from caption/subtitle tracks
|
|
3600
3705
|
*/
|
|
3601
3706
|
loadTranscriptData() {
|
|
3602
3707
|
this.transcriptEntries = [];
|
|
3603
3708
|
this.transcriptContent.innerHTML = "";
|
|
3604
|
-
const textTracks =
|
|
3605
|
-
|
|
3606
|
-
|
|
3607
|
-
|
|
3608
|
-
|
|
3709
|
+
const textTracks = this.player.textTracks;
|
|
3710
|
+
let captionTrack = null;
|
|
3711
|
+
if (this.currentTranscriptLanguage) {
|
|
3712
|
+
captionTrack = textTracks.find(
|
|
3713
|
+
(track) => (track.kind === "captions" || track.kind === "subtitles") && track.language === this.currentTranscriptLanguage
|
|
3714
|
+
);
|
|
3715
|
+
}
|
|
3716
|
+
if (!captionTrack) {
|
|
3717
|
+
captionTrack = textTracks.find(
|
|
3718
|
+
(track) => track.kind === "captions" || track.kind === "subtitles"
|
|
3719
|
+
);
|
|
3720
|
+
if (captionTrack) {
|
|
3721
|
+
this.currentTranscriptLanguage = captionTrack.language;
|
|
3722
|
+
}
|
|
3723
|
+
}
|
|
3724
|
+
let descriptionTrack = null;
|
|
3725
|
+
if (this.currentTranscriptLanguage) {
|
|
3726
|
+
descriptionTrack = textTracks.find(
|
|
3727
|
+
(track) => track.kind === "descriptions" && track.language === this.currentTranscriptLanguage
|
|
3728
|
+
);
|
|
3729
|
+
}
|
|
3730
|
+
if (!descriptionTrack) {
|
|
3731
|
+
descriptionTrack = textTracks.find((track) => track.kind === "descriptions");
|
|
3732
|
+
}
|
|
3609
3733
|
const metadataTrack = textTracks.find((track) => track.kind === "metadata");
|
|
3610
3734
|
if (!captionTrack && !descriptionTrack && !metadataTrack) {
|
|
3611
3735
|
this.showNoTranscriptMessage();
|
|
@@ -3634,7 +3758,7 @@ var VidPly = (() => {
|
|
|
3634
3758
|
tracksToLoad.forEach((track) => {
|
|
3635
3759
|
track.addEventListener("load", onLoad, { once: true });
|
|
3636
3760
|
});
|
|
3637
|
-
|
|
3761
|
+
this.setManagedTimeout(() => {
|
|
3638
3762
|
this.loadTranscriptData();
|
|
3639
3763
|
}, 500);
|
|
3640
3764
|
return;
|
|
@@ -3667,24 +3791,61 @@ var VidPly = (() => {
|
|
|
3667
3791
|
this.transcriptContent.appendChild(entry);
|
|
3668
3792
|
});
|
|
3669
3793
|
this.applyTranscriptStyles();
|
|
3794
|
+
this.updateLanguageSelector();
|
|
3795
|
+
}
|
|
3796
|
+
/**
|
|
3797
|
+
* Setup metadata handling on player load
|
|
3798
|
+
* This runs independently of transcript loading
|
|
3799
|
+
*/
|
|
3800
|
+
setupMetadataHandlingOnLoad() {
|
|
3801
|
+
const setupMetadata = () => {
|
|
3802
|
+
const textTracks = this.player.textTracks;
|
|
3803
|
+
const metadataTrack = textTracks.find((track) => track.kind === "metadata");
|
|
3804
|
+
if (metadataTrack) {
|
|
3805
|
+
if (metadataTrack.mode === "disabled") {
|
|
3806
|
+
metadataTrack.mode = "hidden";
|
|
3807
|
+
}
|
|
3808
|
+
if (this.metadataCueChangeHandler) {
|
|
3809
|
+
metadataTrack.removeEventListener("cuechange", this.metadataCueChangeHandler);
|
|
3810
|
+
}
|
|
3811
|
+
this.metadataCueChangeHandler = () => {
|
|
3812
|
+
const activeCues = Array.from(metadataTrack.activeCues || []);
|
|
3813
|
+
if (activeCues.length > 0) {
|
|
3814
|
+
if (this.player.options.debug) {
|
|
3815
|
+
console.log("[VidPly Metadata] Active cues:", activeCues.map((c) => ({
|
|
3816
|
+
start: c.startTime,
|
|
3817
|
+
end: c.endTime,
|
|
3818
|
+
text: c.text
|
|
3819
|
+
})));
|
|
3820
|
+
}
|
|
3821
|
+
}
|
|
3822
|
+
activeCues.forEach((cue) => {
|
|
3823
|
+
this.handleMetadataCue(cue);
|
|
3824
|
+
});
|
|
3825
|
+
};
|
|
3826
|
+
metadataTrack.addEventListener("cuechange", this.metadataCueChangeHandler);
|
|
3827
|
+
if (this.player.options.debug) {
|
|
3828
|
+
const cueCount = metadataTrack.cues ? metadataTrack.cues.length : 0;
|
|
3829
|
+
console.log("[VidPly Metadata] Track enabled,", cueCount, "cues available");
|
|
3830
|
+
}
|
|
3831
|
+
} else if (this.player.options.debug) {
|
|
3832
|
+
console.warn("[VidPly Metadata] No metadata track found");
|
|
3833
|
+
}
|
|
3834
|
+
};
|
|
3835
|
+
setupMetadata();
|
|
3836
|
+
this.player.on("loadedmetadata", setupMetadata);
|
|
3670
3837
|
}
|
|
3671
3838
|
/**
|
|
3672
3839
|
* Setup metadata handling
|
|
3673
3840
|
* Metadata cues are not displayed but can be used programmatically
|
|
3841
|
+
* This is called when transcript data is loaded (for storing cues)
|
|
3674
3842
|
*/
|
|
3675
3843
|
setupMetadataHandling() {
|
|
3676
3844
|
if (!this.metadataCues || this.metadataCues.length === 0) {
|
|
3677
3845
|
return;
|
|
3678
3846
|
}
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
if (metadataTrack) {
|
|
3682
|
-
metadataTrack.addEventListener("cuechange", () => {
|
|
3683
|
-
const activeCues = Array.from(metadataTrack.activeCues || []);
|
|
3684
|
-
activeCues.forEach((cue) => {
|
|
3685
|
-
this.handleMetadataCue(cue);
|
|
3686
|
-
});
|
|
3687
|
-
});
|
|
3847
|
+
if (this.player.options.debug) {
|
|
3848
|
+
console.log("[VidPly Metadata]", this.metadataCues.length, "cues stored from transcript load");
|
|
3688
3849
|
}
|
|
3689
3850
|
}
|
|
3690
3851
|
/**
|
|
@@ -3693,6 +3854,12 @@ var VidPly = (() => {
|
|
|
3693
3854
|
*/
|
|
3694
3855
|
handleMetadataCue(cue) {
|
|
3695
3856
|
const text = cue.text.trim();
|
|
3857
|
+
if (this.player.options.debug) {
|
|
3858
|
+
console.log("[VidPly Metadata] Processing cue:", {
|
|
3859
|
+
time: cue.startTime,
|
|
3860
|
+
text
|
|
3861
|
+
});
|
|
3862
|
+
}
|
|
3696
3863
|
this.player.emit("metadata", {
|
|
3697
3864
|
time: cue.startTime,
|
|
3698
3865
|
endTime: cue.endTime,
|
|
@@ -3700,18 +3867,40 @@ var VidPly = (() => {
|
|
|
3700
3867
|
cue
|
|
3701
3868
|
});
|
|
3702
3869
|
if (text.includes("PAUSE")) {
|
|
3870
|
+
if (!this.player.state.paused) {
|
|
3871
|
+
if (this.player.options.debug) {
|
|
3872
|
+
console.log("[VidPly Metadata] Pausing video at", cue.startTime);
|
|
3873
|
+
}
|
|
3874
|
+
this.player.pause();
|
|
3875
|
+
}
|
|
3703
3876
|
this.player.emit("metadata:pause", { time: cue.startTime, text });
|
|
3704
3877
|
}
|
|
3705
3878
|
const focusMatch = text.match(/FOCUS:([\w#-]+)/);
|
|
3706
3879
|
if (focusMatch) {
|
|
3880
|
+
const targetSelector = focusMatch[1];
|
|
3881
|
+
const targetElement = document.querySelector(targetSelector);
|
|
3882
|
+
if (targetElement) {
|
|
3883
|
+
if (this.player.options.debug) {
|
|
3884
|
+
console.log("[VidPly Metadata] Focusing element:", targetSelector);
|
|
3885
|
+
}
|
|
3886
|
+
this.setManagedTimeout(() => {
|
|
3887
|
+
targetElement.focus();
|
|
3888
|
+
}, 10);
|
|
3889
|
+
} else if (this.player.options.debug) {
|
|
3890
|
+
console.warn("[VidPly Metadata] Element not found:", targetSelector);
|
|
3891
|
+
}
|
|
3707
3892
|
this.player.emit("metadata:focus", {
|
|
3708
3893
|
time: cue.startTime,
|
|
3709
|
-
target:
|
|
3894
|
+
target: targetSelector,
|
|
3895
|
+
element: targetElement,
|
|
3710
3896
|
text
|
|
3711
3897
|
});
|
|
3712
3898
|
}
|
|
3713
3899
|
const hashtags = text.match(/#[\w-]+/g);
|
|
3714
3900
|
if (hashtags) {
|
|
3901
|
+
if (this.player.options.debug) {
|
|
3902
|
+
console.log("[VidPly Metadata] Hashtags found:", hashtags);
|
|
3903
|
+
}
|
|
3715
3904
|
this.player.emit("metadata:hashtags", {
|
|
3716
3905
|
time: cue.startTime,
|
|
3717
3906
|
hashtags,
|
|
@@ -3805,7 +3994,7 @@ var VidPly = (() => {
|
|
|
3805
3994
|
* Scroll transcript window to show active entry
|
|
3806
3995
|
*/
|
|
3807
3996
|
scrollToEntry(entryElement) {
|
|
3808
|
-
if (!this.transcriptContent) return;
|
|
3997
|
+
if (!this.transcriptContent || !this.autoscrollEnabled) return;
|
|
3809
3998
|
const contentRect = this.transcriptContent.getBoundingClientRect();
|
|
3810
3999
|
const entryRect = entryElement.getBoundingClientRect();
|
|
3811
4000
|
if (entryRect.top < contentRect.top || entryRect.bottom > contentRect.bottom) {
|
|
@@ -3816,6 +4005,14 @@ var VidPly = (() => {
|
|
|
3816
4005
|
});
|
|
3817
4006
|
}
|
|
3818
4007
|
}
|
|
4008
|
+
/**
|
|
4009
|
+
* Save autoscroll preference to localStorage
|
|
4010
|
+
*/
|
|
4011
|
+
saveAutoscrollPreference() {
|
|
4012
|
+
const savedPreferences = this.storage.getTranscriptPreferences() || {};
|
|
4013
|
+
savedPreferences.autoscroll = this.autoscrollEnabled;
|
|
4014
|
+
this.storage.saveTranscriptPreferences(savedPreferences);
|
|
4015
|
+
}
|
|
3819
4016
|
/**
|
|
3820
4017
|
* Setup drag and drop functionality
|
|
3821
4018
|
*/
|
|
@@ -3828,6 +4025,9 @@ var VidPly = (() => {
|
|
|
3828
4025
|
if (e.target.closest(`.${this.player.options.classPrefix}-transcript-settings`)) {
|
|
3829
4026
|
return;
|
|
3830
4027
|
}
|
|
4028
|
+
if (e.target.closest(`.${this.player.options.classPrefix}-transcript-language-select`)) {
|
|
4029
|
+
return;
|
|
4030
|
+
}
|
|
3831
4031
|
if (e.target.closest(`.${this.player.options.classPrefix}-transcript-settings-menu`)) {
|
|
3832
4032
|
return;
|
|
3833
4033
|
}
|
|
@@ -3854,6 +4054,9 @@ var VidPly = (() => {
|
|
|
3854
4054
|
if (e.target.closest(`.${this.player.options.classPrefix}-transcript-settings`)) {
|
|
3855
4055
|
return;
|
|
3856
4056
|
}
|
|
4057
|
+
if (e.target.closest(`.${this.player.options.classPrefix}-transcript-language-select`)) {
|
|
4058
|
+
return;
|
|
4059
|
+
}
|
|
3857
4060
|
if (e.target.closest(`.${this.player.options.classPrefix}-transcript-settings-menu`)) {
|
|
3858
4061
|
return;
|
|
3859
4062
|
}
|
|
@@ -4608,6 +4811,30 @@ var VidPly = (() => {
|
|
|
4608
4811
|
entry.style.fontFamily = this.transcriptStyle.fontFamily;
|
|
4609
4812
|
});
|
|
4610
4813
|
}
|
|
4814
|
+
/**
|
|
4815
|
+
* Set a managed timeout that will be cleaned up on destroy
|
|
4816
|
+
* @param {Function} callback - Callback function
|
|
4817
|
+
* @param {number} delay - Delay in milliseconds
|
|
4818
|
+
* @returns {number} Timeout ID
|
|
4819
|
+
*/
|
|
4820
|
+
setManagedTimeout(callback, delay) {
|
|
4821
|
+
const timeoutId = setTimeout(() => {
|
|
4822
|
+
this.timeouts.delete(timeoutId);
|
|
4823
|
+
callback();
|
|
4824
|
+
}, delay);
|
|
4825
|
+
this.timeouts.add(timeoutId);
|
|
4826
|
+
return timeoutId;
|
|
4827
|
+
}
|
|
4828
|
+
/**
|
|
4829
|
+
* Clear a managed timeout
|
|
4830
|
+
* @param {number} timeoutId - Timeout ID to clear
|
|
4831
|
+
*/
|
|
4832
|
+
clearManagedTimeout(timeoutId) {
|
|
4833
|
+
if (timeoutId) {
|
|
4834
|
+
clearTimeout(timeoutId);
|
|
4835
|
+
this.timeouts.delete(timeoutId);
|
|
4836
|
+
}
|
|
4837
|
+
}
|
|
4611
4838
|
/**
|
|
4612
4839
|
* Cleanup
|
|
4613
4840
|
*/
|
|
@@ -4661,6 +4888,8 @@ var VidPly = (() => {
|
|
|
4661
4888
|
if (this.handlers.resize) {
|
|
4662
4889
|
window.removeEventListener("resize", this.handlers.resize);
|
|
4663
4890
|
}
|
|
4891
|
+
this.timeouts.forEach((timeoutId) => clearTimeout(timeoutId));
|
|
4892
|
+
this.timeouts.clear();
|
|
4664
4893
|
this.handlers = null;
|
|
4665
4894
|
if (this.transcriptWindow && this.transcriptWindow.parentNode) {
|
|
4666
4895
|
this.transcriptWindow.parentNode.removeChild(this.transcriptWindow);
|
|
@@ -5332,7 +5561,7 @@ var VidPly = (() => {
|
|
|
5332
5561
|
};
|
|
5333
5562
|
|
|
5334
5563
|
// src/core/Player.js
|
|
5335
|
-
var Player = class extends EventEmitter {
|
|
5564
|
+
var Player = class _Player extends EventEmitter {
|
|
5336
5565
|
constructor(element, options = {}) {
|
|
5337
5566
|
super();
|
|
5338
5567
|
this.element = typeof element === "string" ? document.querySelector(element) : element;
|
|
@@ -5440,6 +5669,8 @@ var VidPly = (() => {
|
|
|
5440
5669
|
screenReaderAnnouncements: true,
|
|
5441
5670
|
highContrast: false,
|
|
5442
5671
|
focusHighlight: true,
|
|
5672
|
+
metadataAlerts: {},
|
|
5673
|
+
metadataHashtags: {},
|
|
5443
5674
|
// Languages
|
|
5444
5675
|
language: "en",
|
|
5445
5676
|
languages: ["en"],
|
|
@@ -5458,6 +5689,8 @@ var VidPly = (() => {
|
|
|
5458
5689
|
onError: null,
|
|
5459
5690
|
...options
|
|
5460
5691
|
};
|
|
5692
|
+
this.options.metadataAlerts = this.options.metadataAlerts || {};
|
|
5693
|
+
this.options.metadataHashtags = this.options.metadataHashtags || {};
|
|
5461
5694
|
this.storage = new StorageManager("vidply");
|
|
5462
5695
|
const savedPrefs = this.storage.getPlayerPreferences();
|
|
5463
5696
|
if (savedPrefs) {
|
|
@@ -5492,12 +5725,21 @@ var VidPly = (() => {
|
|
|
5492
5725
|
this.audioDescriptionSourceElement = null;
|
|
5493
5726
|
this.originalAudioDescriptionSource = null;
|
|
5494
5727
|
this.audioDescriptionCaptionTracks = [];
|
|
5728
|
+
this._textTracksCache = null;
|
|
5729
|
+
this._textTracksDirty = true;
|
|
5730
|
+
this._sourceElementsCache = null;
|
|
5731
|
+
this._sourceElementsDirty = true;
|
|
5732
|
+
this._trackElementsCache = null;
|
|
5733
|
+
this._trackElementsDirty = true;
|
|
5734
|
+
this.timeouts = /* @__PURE__ */ new Set();
|
|
5495
5735
|
this.container = null;
|
|
5496
5736
|
this.renderer = null;
|
|
5497
5737
|
this.controlBar = null;
|
|
5498
5738
|
this.captionManager = null;
|
|
5499
5739
|
this.keyboardManager = null;
|
|
5500
5740
|
this.settingsDialog = null;
|
|
5741
|
+
this.metadataCueChangeHandler = null;
|
|
5742
|
+
this.metadataAlertHandlers = /* @__PURE__ */ new Map();
|
|
5501
5743
|
this.init();
|
|
5502
5744
|
}
|
|
5503
5745
|
async init() {
|
|
@@ -5529,6 +5771,7 @@ var VidPly = (() => {
|
|
|
5529
5771
|
if (this.options.transcript || this.options.transcriptButton) {
|
|
5530
5772
|
this.transcriptManager = new TranscriptManager(this);
|
|
5531
5773
|
}
|
|
5774
|
+
this.setupMetadataHandling();
|
|
5532
5775
|
if (this.options.keyboard) {
|
|
5533
5776
|
this.keyboardManager = new KeyboardManager(this);
|
|
5534
5777
|
}
|
|
@@ -5614,6 +5857,8 @@ var VidPly = (() => {
|
|
|
5614
5857
|
if (this.element.tagName === "VIDEO") {
|
|
5615
5858
|
this.createPlayButtonOverlay();
|
|
5616
5859
|
}
|
|
5860
|
+
this.element.vidply = this;
|
|
5861
|
+
_Player.instances.push(this);
|
|
5617
5862
|
this.element.style.cursor = "pointer";
|
|
5618
5863
|
this.element.addEventListener("click", (e) => {
|
|
5619
5864
|
if (e.target === this.element) {
|
|
@@ -5646,7 +5891,7 @@ var VidPly = (() => {
|
|
|
5646
5891
|
if (!src) {
|
|
5647
5892
|
throw new Error("No media source found");
|
|
5648
5893
|
}
|
|
5649
|
-
const sourceElements = this.
|
|
5894
|
+
const sourceElements = this.sourceElements;
|
|
5650
5895
|
for (const sourceEl of sourceElements) {
|
|
5651
5896
|
const descSrc = sourceEl.getAttribute("data-desc-src");
|
|
5652
5897
|
const origSrc = sourceEl.getAttribute("data-orig-src");
|
|
@@ -5675,7 +5920,7 @@ var VidPly = (() => {
|
|
|
5675
5920
|
}
|
|
5676
5921
|
}
|
|
5677
5922
|
}
|
|
5678
|
-
const trackElements = this.
|
|
5923
|
+
const trackElements = this.trackElements;
|
|
5679
5924
|
trackElements.forEach((trackEl) => {
|
|
5680
5925
|
const trackKind = trackEl.getAttribute("kind");
|
|
5681
5926
|
const trackDescSrc = trackEl.getAttribute("data-desc-src");
|
|
@@ -5709,6 +5954,106 @@ var VidPly = (() => {
|
|
|
5709
5954
|
this.log(`Using ${renderer.name} renderer`);
|
|
5710
5955
|
this.renderer = new renderer(this);
|
|
5711
5956
|
await this.renderer.init();
|
|
5957
|
+
this.invalidateTrackCache();
|
|
5958
|
+
}
|
|
5959
|
+
/**
|
|
5960
|
+
* Get cached text tracks array
|
|
5961
|
+
* @returns {Array} Array of text tracks
|
|
5962
|
+
*/
|
|
5963
|
+
get textTracks() {
|
|
5964
|
+
if (!this._textTracksCache || this._textTracksDirty) {
|
|
5965
|
+
this._textTracksCache = Array.from(this.element.textTracks || []);
|
|
5966
|
+
this._textTracksDirty = false;
|
|
5967
|
+
}
|
|
5968
|
+
return this._textTracksCache;
|
|
5969
|
+
}
|
|
5970
|
+
/**
|
|
5971
|
+
* Get cached source elements array
|
|
5972
|
+
* @returns {Array} Array of source elements
|
|
5973
|
+
*/
|
|
5974
|
+
get sourceElements() {
|
|
5975
|
+
if (!this._sourceElementsCache || this._sourceElementsDirty) {
|
|
5976
|
+
this._sourceElementsCache = Array.from(this.element.querySelectorAll("source"));
|
|
5977
|
+
this._sourceElementsDirty = false;
|
|
5978
|
+
}
|
|
5979
|
+
return this._sourceElementsCache;
|
|
5980
|
+
}
|
|
5981
|
+
/**
|
|
5982
|
+
* Get cached track elements array
|
|
5983
|
+
* @returns {Array} Array of track elements
|
|
5984
|
+
*/
|
|
5985
|
+
get trackElements() {
|
|
5986
|
+
if (!this._trackElementsCache || this._trackElementsDirty) {
|
|
5987
|
+
this._trackElementsCache = Array.from(this.element.querySelectorAll("track"));
|
|
5988
|
+
this._trackElementsDirty = false;
|
|
5989
|
+
}
|
|
5990
|
+
return this._trackElementsCache;
|
|
5991
|
+
}
|
|
5992
|
+
/**
|
|
5993
|
+
* Invalidate DOM query cache (call when tracks/sources change)
|
|
5994
|
+
*/
|
|
5995
|
+
invalidateTrackCache() {
|
|
5996
|
+
this._textTracksDirty = true;
|
|
5997
|
+
this._trackElementsDirty = true;
|
|
5998
|
+
this._sourceElementsDirty = true;
|
|
5999
|
+
}
|
|
6000
|
+
/**
|
|
6001
|
+
* Find a text track by kind and optionally language
|
|
6002
|
+
* @param {string} kind - Track kind (captions, subtitles, descriptions, chapters, metadata)
|
|
6003
|
+
* @param {string} [language] - Optional language code
|
|
6004
|
+
* @returns {TextTrack|null} Found track or null
|
|
6005
|
+
*/
|
|
6006
|
+
findTextTrack(kind, language = null) {
|
|
6007
|
+
const tracks = this.textTracks;
|
|
6008
|
+
if (language) {
|
|
6009
|
+
return tracks.find((t) => t.kind === kind && t.language === language);
|
|
6010
|
+
}
|
|
6011
|
+
return tracks.find((t) => t.kind === kind);
|
|
6012
|
+
}
|
|
6013
|
+
/**
|
|
6014
|
+
* Find a source element by attribute
|
|
6015
|
+
* @param {string} attribute - Attribute name (e.g., 'data-desc-src')
|
|
6016
|
+
* @param {string} [value] - Optional attribute value
|
|
6017
|
+
* @returns {Element|null} Found source element or null
|
|
6018
|
+
*/
|
|
6019
|
+
findSourceElement(attribute, value = null) {
|
|
6020
|
+
const sources = this.sourceElements;
|
|
6021
|
+
if (value) {
|
|
6022
|
+
return sources.find((el) => el.getAttribute(attribute) === value);
|
|
6023
|
+
}
|
|
6024
|
+
return sources.find((el) => el.hasAttribute(attribute));
|
|
6025
|
+
}
|
|
6026
|
+
/**
|
|
6027
|
+
* Find a track element by its associated TextTrack
|
|
6028
|
+
* @param {TextTrack} track - The TextTrack object
|
|
6029
|
+
* @returns {Element|null} Found track element or null
|
|
6030
|
+
*/
|
|
6031
|
+
findTrackElement(track) {
|
|
6032
|
+
return this.trackElements.find((el) => el.track === track);
|
|
6033
|
+
}
|
|
6034
|
+
/**
|
|
6035
|
+
* Set a managed timeout that will be cleaned up on destroy
|
|
6036
|
+
* @param {Function} callback - Callback function
|
|
6037
|
+
* @param {number} delay - Delay in milliseconds
|
|
6038
|
+
* @returns {number} Timeout ID
|
|
6039
|
+
*/
|
|
6040
|
+
setManagedTimeout(callback, delay) {
|
|
6041
|
+
const timeoutId = setTimeout(() => {
|
|
6042
|
+
this.timeouts.delete(timeoutId);
|
|
6043
|
+
callback();
|
|
6044
|
+
}, delay);
|
|
6045
|
+
this.timeouts.add(timeoutId);
|
|
6046
|
+
return timeoutId;
|
|
6047
|
+
}
|
|
6048
|
+
/**
|
|
6049
|
+
* Clear a managed timeout
|
|
6050
|
+
* @param {number} timeoutId - Timeout ID to clear
|
|
6051
|
+
*/
|
|
6052
|
+
clearManagedTimeout(timeoutId) {
|
|
6053
|
+
if (timeoutId) {
|
|
6054
|
+
clearTimeout(timeoutId);
|
|
6055
|
+
this.timeouts.delete(timeoutId);
|
|
6056
|
+
}
|
|
5712
6057
|
}
|
|
5713
6058
|
/**
|
|
5714
6059
|
* Load new media source (for playlists)
|
|
@@ -5724,8 +6069,9 @@ var VidPly = (() => {
|
|
|
5724
6069
|
if (this.renderer) {
|
|
5725
6070
|
this.pause();
|
|
5726
6071
|
}
|
|
5727
|
-
const existingTracks = this.
|
|
6072
|
+
const existingTracks = this.trackElements;
|
|
5728
6073
|
existingTracks.forEach((track) => track.remove());
|
|
6074
|
+
this.invalidateTrackCache();
|
|
5729
6075
|
this.element.src = config.src;
|
|
5730
6076
|
if (config.type) {
|
|
5731
6077
|
this.element.type = config.type;
|
|
@@ -5745,6 +6091,7 @@ var VidPly = (() => {
|
|
|
5745
6091
|
}
|
|
5746
6092
|
this.element.appendChild(track);
|
|
5747
6093
|
});
|
|
6094
|
+
this.invalidateTrackCache();
|
|
5748
6095
|
}
|
|
5749
6096
|
const shouldChangeRenderer = this.shouldChangeRenderer(config.src);
|
|
5750
6097
|
if (shouldChangeRenderer && this.renderer) {
|
|
@@ -5992,7 +6339,7 @@ var VidPly = (() => {
|
|
|
5992
6339
|
}
|
|
5993
6340
|
// Audio Description
|
|
5994
6341
|
async enableAudioDescription() {
|
|
5995
|
-
const hasSourceElementsWithDesc =
|
|
6342
|
+
const hasSourceElementsWithDesc = this.sourceElements.some((el) => el.getAttribute("data-desc-src"));
|
|
5996
6343
|
const hasTracksWithDesc = this.audioDescriptionCaptionTracks.length > 0;
|
|
5997
6344
|
if (!this.audioDescriptionSrc && !hasSourceElementsWithDesc && !hasTracksWithDesc) {
|
|
5998
6345
|
console.warn("VidPly: No audio description source, source elements, or tracks provided");
|
|
@@ -6003,7 +6350,7 @@ var VidPly = (() => {
|
|
|
6003
6350
|
let swappedTracksForTranscript = [];
|
|
6004
6351
|
if (this.audioDescriptionSourceElement) {
|
|
6005
6352
|
const currentSrc = this.element.currentSrc || this.element.src;
|
|
6006
|
-
const sourceElements =
|
|
6353
|
+
const sourceElements = this.sourceElements;
|
|
6007
6354
|
let sourceElementToUpdate = null;
|
|
6008
6355
|
let descSrc = this.audioDescriptionSrc;
|
|
6009
6356
|
for (const sourceEl of sourceElements) {
|
|
@@ -6100,8 +6447,9 @@ var VidPly = (() => {
|
|
|
6100
6447
|
trackInfo.trackElement = newTrackElement;
|
|
6101
6448
|
});
|
|
6102
6449
|
this.element.load();
|
|
6450
|
+
this.invalidateTrackCache();
|
|
6103
6451
|
const setupNewTracks = () => {
|
|
6104
|
-
|
|
6452
|
+
this.setManagedTimeout(() => {
|
|
6105
6453
|
swappedTracksForTranscript.forEach((trackInfo) => {
|
|
6106
6454
|
const trackElement = trackInfo.trackElement;
|
|
6107
6455
|
const newTextTrack = trackElement.track;
|
|
@@ -6137,7 +6485,7 @@ var VidPly = (() => {
|
|
|
6137
6485
|
const skippedCount = validationResults.length - tracksToSwap.length;
|
|
6138
6486
|
}
|
|
6139
6487
|
}
|
|
6140
|
-
const allSourceElements =
|
|
6488
|
+
const allSourceElements = this.sourceElements;
|
|
6141
6489
|
const sourcesToUpdate = [];
|
|
6142
6490
|
allSourceElements.forEach((sourceEl) => {
|
|
6143
6491
|
const descSrcAttr = sourceEl.getAttribute("data-desc-src");
|
|
@@ -6315,7 +6663,7 @@ var VidPly = (() => {
|
|
|
6315
6663
|
}, 100);
|
|
6316
6664
|
}
|
|
6317
6665
|
}
|
|
6318
|
-
const fallbackSourceElements =
|
|
6666
|
+
const fallbackSourceElements = this.sourceElements;
|
|
6319
6667
|
const hasSourceElementsWithDesc2 = fallbackSourceElements.some((el) => el.getAttribute("data-desc-src"));
|
|
6320
6668
|
if (hasSourceElementsWithDesc2) {
|
|
6321
6669
|
const fallbackSourcesToUpdate = [];
|
|
@@ -6363,6 +6711,7 @@ var VidPly = (() => {
|
|
|
6363
6711
|
this.element.appendChild(newSource);
|
|
6364
6712
|
});
|
|
6365
6713
|
this.element.load();
|
|
6714
|
+
this.invalidateTrackCache();
|
|
6366
6715
|
} else {
|
|
6367
6716
|
this.element.src = this.audioDescriptionSrc;
|
|
6368
6717
|
}
|
|
@@ -6377,7 +6726,7 @@ var VidPly = (() => {
|
|
|
6377
6726
|
if (this.element.tagName === "VIDEO" && currentTime === 0 && !wasPlaying) {
|
|
6378
6727
|
if (this.element.readyState >= 1) {
|
|
6379
6728
|
this.element.currentTime = 1e-3;
|
|
6380
|
-
|
|
6729
|
+
this.setManagedTimeout(() => {
|
|
6381
6730
|
this.element.currentTime = 0;
|
|
6382
6731
|
}, 10);
|
|
6383
6732
|
}
|
|
@@ -6417,7 +6766,8 @@ var VidPly = (() => {
|
|
|
6417
6766
|
const swappedTracks = typeof swappedTracksForTranscript !== "undefined" ? swappedTracksForTranscript : [];
|
|
6418
6767
|
if (swappedTracks.length > 0) {
|
|
6419
6768
|
const onMetadataLoaded = () => {
|
|
6420
|
-
|
|
6769
|
+
this.invalidateTrackCache();
|
|
6770
|
+
const allTextTracks = this.textTracks;
|
|
6421
6771
|
const freshTracks = swappedTracks.map((trackInfo) => {
|
|
6422
6772
|
const trackEl = trackInfo.trackElement;
|
|
6423
6773
|
const expectedSrc = trackEl.getAttribute("src");
|
|
@@ -6427,9 +6777,7 @@ var VidPly = (() => {
|
|
|
6427
6777
|
if (!foundTrack) {
|
|
6428
6778
|
foundTrack = allTextTracks.find((track) => {
|
|
6429
6779
|
if (track.language === srclang && (track.kind === kind || kind === "captions" && track.kind === "subtitles")) {
|
|
6430
|
-
const trackElementForTrack =
|
|
6431
|
-
(el) => el.track === track
|
|
6432
|
-
);
|
|
6780
|
+
const trackElementForTrack = this.findTrackElement(track);
|
|
6433
6781
|
if (trackElementForTrack) {
|
|
6434
6782
|
const actualSrc = trackElementForTrack.getAttribute("src");
|
|
6435
6783
|
if (actualSrc === expectedSrc) {
|
|
@@ -6441,9 +6789,7 @@ var VidPly = (() => {
|
|
|
6441
6789
|
});
|
|
6442
6790
|
}
|
|
6443
6791
|
if (foundTrack) {
|
|
6444
|
-
const trackElement =
|
|
6445
|
-
(el) => el.track === foundTrack
|
|
6446
|
-
);
|
|
6792
|
+
const trackElement = this.findTrackElement(foundTrack);
|
|
6447
6793
|
if (trackElement && trackElement.getAttribute("src") !== expectedSrc) {
|
|
6448
6794
|
return null;
|
|
6449
6795
|
}
|
|
@@ -6451,7 +6797,7 @@ var VidPly = (() => {
|
|
|
6451
6797
|
return foundTrack;
|
|
6452
6798
|
}).filter(Boolean);
|
|
6453
6799
|
if (freshTracks.length === 0) {
|
|
6454
|
-
|
|
6800
|
+
this.setManagedTimeout(() => {
|
|
6455
6801
|
if (this.transcriptManager && this.transcriptManager.loadTranscriptData) {
|
|
6456
6802
|
this.transcriptManager.loadTranscriptData();
|
|
6457
6803
|
}
|
|
@@ -6467,14 +6813,13 @@ var VidPly = (() => {
|
|
|
6467
6813
|
const checkLoaded = () => {
|
|
6468
6814
|
loadedCount++;
|
|
6469
6815
|
if (loadedCount >= freshTracks.length) {
|
|
6470
|
-
|
|
6816
|
+
this.setManagedTimeout(() => {
|
|
6471
6817
|
if (this.transcriptManager && this.transcriptManager.loadTranscriptData) {
|
|
6472
|
-
|
|
6818
|
+
this.invalidateTrackCache();
|
|
6819
|
+
const allTextTracks2 = this.textTracks;
|
|
6473
6820
|
const swappedTrackSrcs = swappedTracks.map((t) => t.describedSrc);
|
|
6474
6821
|
const hasCorrectTracks = freshTracks.some((track) => {
|
|
6475
|
-
const trackEl =
|
|
6476
|
-
(el) => el.track === track
|
|
6477
|
-
);
|
|
6822
|
+
const trackEl = this.findTrackElement(track);
|
|
6478
6823
|
return trackEl && swappedTrackSrcs.includes(trackEl.getAttribute("src"));
|
|
6479
6824
|
});
|
|
6480
6825
|
if (hasCorrectTracks || freshTracks.length > 0) {
|
|
@@ -6488,9 +6833,7 @@ var VidPly = (() => {
|
|
|
6488
6833
|
if (track.mode === "disabled") {
|
|
6489
6834
|
track.mode = "hidden";
|
|
6490
6835
|
}
|
|
6491
|
-
const trackElementForTrack =
|
|
6492
|
-
(el) => el.track === track
|
|
6493
|
-
);
|
|
6836
|
+
const trackElementForTrack = this.findTrackElement(track);
|
|
6494
6837
|
const actualSrc = trackElementForTrack ? trackElementForTrack.getAttribute("src") : null;
|
|
6495
6838
|
const expectedTrackInfo = swappedTracks.find((t) => {
|
|
6496
6839
|
const tEl = t.trackElement;
|
|
@@ -6508,10 +6851,10 @@ var VidPly = (() => {
|
|
|
6508
6851
|
track.mode = "hidden";
|
|
6509
6852
|
}
|
|
6510
6853
|
const onTrackLoad = () => {
|
|
6511
|
-
|
|
6854
|
+
this.setManagedTimeout(checkLoaded, 300);
|
|
6512
6855
|
};
|
|
6513
6856
|
if (track.readyState >= 2) {
|
|
6514
|
-
|
|
6857
|
+
this.setManagedTimeout(() => {
|
|
6515
6858
|
if (track.cues && track.cues.length > 0) {
|
|
6516
6859
|
checkLoaded();
|
|
6517
6860
|
} else {
|
|
@@ -6528,12 +6871,12 @@ var VidPly = (() => {
|
|
|
6528
6871
|
});
|
|
6529
6872
|
};
|
|
6530
6873
|
const waitForTracks = () => {
|
|
6531
|
-
|
|
6874
|
+
this.setManagedTimeout(() => {
|
|
6532
6875
|
if (this.element.readyState >= 1) {
|
|
6533
6876
|
onMetadataLoaded();
|
|
6534
6877
|
} else {
|
|
6535
6878
|
this.element.addEventListener("loadedmetadata", onMetadataLoaded, { once: true });
|
|
6536
|
-
|
|
6879
|
+
this.setManagedTimeout(onMetadataLoaded, 2e3);
|
|
6537
6880
|
}
|
|
6538
6881
|
}, 500);
|
|
6539
6882
|
};
|
|
@@ -6567,7 +6910,7 @@ var VidPly = (() => {
|
|
|
6567
6910
|
}
|
|
6568
6911
|
});
|
|
6569
6912
|
}
|
|
6570
|
-
const allSourceElements =
|
|
6913
|
+
const allSourceElements = this.sourceElements;
|
|
6571
6914
|
const hasSourceElementsToSwap = allSourceElements.some((el) => el.getAttribute("data-orig-src"));
|
|
6572
6915
|
if (hasSourceElementsToSwap) {
|
|
6573
6916
|
const sourcesToRestore = [];
|
|
@@ -6630,7 +6973,7 @@ var VidPly = (() => {
|
|
|
6630
6973
|
this.play();
|
|
6631
6974
|
}
|
|
6632
6975
|
if (this.transcriptManager && this.transcriptManager.isVisible) {
|
|
6633
|
-
|
|
6976
|
+
this.setManagedTimeout(() => {
|
|
6634
6977
|
if (this.transcriptManager && this.transcriptManager.loadTranscriptData) {
|
|
6635
6978
|
this.transcriptManager.loadTranscriptData();
|
|
6636
6979
|
}
|
|
@@ -6640,16 +6983,37 @@ var VidPly = (() => {
|
|
|
6640
6983
|
this.emit("audiodescriptiondisabled");
|
|
6641
6984
|
}
|
|
6642
6985
|
async toggleAudioDescription() {
|
|
6643
|
-
const
|
|
6644
|
-
const
|
|
6645
|
-
const hasAudioDescriptionSrc = this.audioDescriptionSrc || Array.from(this.element.querySelectorAll("source")).some((el) => el.getAttribute("data-desc-src"));
|
|
6986
|
+
const descriptionTrack = this.findTextTrack("descriptions");
|
|
6987
|
+
const hasAudioDescriptionSrc = this.audioDescriptionSrc || this.sourceElements.some((el) => el.getAttribute("data-desc-src"));
|
|
6646
6988
|
if (descriptionTrack && hasAudioDescriptionSrc) {
|
|
6647
6989
|
if (this.state.audioDescriptionEnabled) {
|
|
6648
6990
|
descriptionTrack.mode = "hidden";
|
|
6649
6991
|
await this.disableAudioDescription();
|
|
6650
6992
|
} else {
|
|
6651
6993
|
await this.enableAudioDescription();
|
|
6652
|
-
|
|
6994
|
+
const enableDescriptionTrack = () => {
|
|
6995
|
+
this.invalidateTrackCache();
|
|
6996
|
+
const descTrack = this.findTextTrack("descriptions");
|
|
6997
|
+
if (descTrack) {
|
|
6998
|
+
if (descTrack.mode === "disabled") {
|
|
6999
|
+
descTrack.mode = "hidden";
|
|
7000
|
+
this.setManagedTimeout(() => {
|
|
7001
|
+
descTrack.mode = "showing";
|
|
7002
|
+
}, 50);
|
|
7003
|
+
} else {
|
|
7004
|
+
descTrack.mode = "showing";
|
|
7005
|
+
}
|
|
7006
|
+
} else if (this.element.readyState < 2) {
|
|
7007
|
+
this.setManagedTimeout(enableDescriptionTrack, 100);
|
|
7008
|
+
}
|
|
7009
|
+
};
|
|
7010
|
+
if (this.element.readyState >= 1) {
|
|
7011
|
+
this.setManagedTimeout(enableDescriptionTrack, 200);
|
|
7012
|
+
} else {
|
|
7013
|
+
this.element.addEventListener("loadedmetadata", () => {
|
|
7014
|
+
this.setManagedTimeout(enableDescriptionTrack, 200);
|
|
7015
|
+
}, { once: true });
|
|
7016
|
+
}
|
|
6653
7017
|
}
|
|
6654
7018
|
} else if (descriptionTrack) {
|
|
6655
7019
|
if (descriptionTrack.mode === "showing") {
|
|
@@ -7062,9 +7426,25 @@ var VidPly = (() => {
|
|
|
7062
7426
|
}
|
|
7063
7427
|
}
|
|
7064
7428
|
// Logging
|
|
7065
|
-
log(
|
|
7066
|
-
if (this.options.debug) {
|
|
7067
|
-
|
|
7429
|
+
log(...messages) {
|
|
7430
|
+
if (!this.options.debug) {
|
|
7431
|
+
return;
|
|
7432
|
+
}
|
|
7433
|
+
let type = "log";
|
|
7434
|
+
if (messages.length > 0) {
|
|
7435
|
+
const potentialType = messages[messages.length - 1];
|
|
7436
|
+
if (typeof potentialType === "string" && console[potentialType]) {
|
|
7437
|
+
type = potentialType;
|
|
7438
|
+
messages = messages.slice(0, -1);
|
|
7439
|
+
}
|
|
7440
|
+
}
|
|
7441
|
+
if (messages.length === 0) {
|
|
7442
|
+
messages = [""];
|
|
7443
|
+
}
|
|
7444
|
+
if (typeof console[type] === "function") {
|
|
7445
|
+
console[type]("[VidPly]", ...messages);
|
|
7446
|
+
} else {
|
|
7447
|
+
console.log("[VidPly]", ...messages);
|
|
7068
7448
|
}
|
|
7069
7449
|
}
|
|
7070
7450
|
// Setup responsive handlers
|
|
@@ -7124,7 +7504,7 @@ var VidPly = (() => {
|
|
|
7124
7504
|
this.controlBar.updateFullscreenButton();
|
|
7125
7505
|
}
|
|
7126
7506
|
if (this.signLanguageWrapper && this.signLanguageWrapper.style.display !== "none") {
|
|
7127
|
-
|
|
7507
|
+
this.setManagedTimeout(() => {
|
|
7128
7508
|
requestAnimationFrame(() => {
|
|
7129
7509
|
this.storage.saveSignLanguagePreferences({ size: null });
|
|
7130
7510
|
this.signLanguageDesiredPosition = "bottom-right";
|
|
@@ -7187,12 +7567,368 @@ var VidPly = (() => {
|
|
|
7187
7567
|
document.removeEventListener("MSFullscreenChange", this.fullscreenChangeHandler);
|
|
7188
7568
|
this.fullscreenChangeHandler = null;
|
|
7189
7569
|
}
|
|
7570
|
+
this.timeouts.forEach((timeoutId) => clearTimeout(timeoutId));
|
|
7571
|
+
this.timeouts.clear();
|
|
7572
|
+
if (this.metadataCueChangeHandler) {
|
|
7573
|
+
const textTracks = this.textTracks;
|
|
7574
|
+
const metadataTrack = textTracks.find((track) => track.kind === "metadata");
|
|
7575
|
+
if (metadataTrack) {
|
|
7576
|
+
metadataTrack.removeEventListener("cuechange", this.metadataCueChangeHandler);
|
|
7577
|
+
}
|
|
7578
|
+
this.metadataCueChangeHandler = null;
|
|
7579
|
+
}
|
|
7580
|
+
if (this.metadataAlertHandlers && this.metadataAlertHandlers.size > 0) {
|
|
7581
|
+
this.metadataAlertHandlers.forEach(({ button, handler }) => {
|
|
7582
|
+
if (button && handler) {
|
|
7583
|
+
button.removeEventListener("click", handler);
|
|
7584
|
+
}
|
|
7585
|
+
});
|
|
7586
|
+
this.metadataAlertHandlers.clear();
|
|
7587
|
+
}
|
|
7190
7588
|
if (this.container && this.container.parentNode) {
|
|
7191
7589
|
this.container.parentNode.insertBefore(this.element, this.container);
|
|
7192
7590
|
this.container.parentNode.removeChild(this.container);
|
|
7193
7591
|
}
|
|
7194
7592
|
this.removeAllListeners();
|
|
7195
7593
|
}
|
|
7594
|
+
/**
|
|
7595
|
+
* Setup metadata track handling
|
|
7596
|
+
* This enables metadata tracks and listens for cue changes to trigger actions
|
|
7597
|
+
*/
|
|
7598
|
+
setupMetadataHandling() {
|
|
7599
|
+
const setupMetadata = () => {
|
|
7600
|
+
const textTracks = this.textTracks;
|
|
7601
|
+
const metadataTrack = textTracks.find((track) => track.kind === "metadata");
|
|
7602
|
+
if (metadataTrack) {
|
|
7603
|
+
if (metadataTrack.mode === "disabled") {
|
|
7604
|
+
metadataTrack.mode = "hidden";
|
|
7605
|
+
}
|
|
7606
|
+
if (this.metadataCueChangeHandler) {
|
|
7607
|
+
metadataTrack.removeEventListener("cuechange", this.metadataCueChangeHandler);
|
|
7608
|
+
}
|
|
7609
|
+
this.metadataCueChangeHandler = () => {
|
|
7610
|
+
const activeCues = Array.from(metadataTrack.activeCues || []);
|
|
7611
|
+
if (activeCues.length > 0) {
|
|
7612
|
+
if (this.options.debug) {
|
|
7613
|
+
this.log("[Metadata] Active cues:", activeCues.map((c) => ({
|
|
7614
|
+
start: c.startTime,
|
|
7615
|
+
end: c.endTime,
|
|
7616
|
+
text: c.text
|
|
7617
|
+
})));
|
|
7618
|
+
}
|
|
7619
|
+
}
|
|
7620
|
+
activeCues.forEach((cue) => {
|
|
7621
|
+
this.handleMetadataCue(cue);
|
|
7622
|
+
});
|
|
7623
|
+
};
|
|
7624
|
+
metadataTrack.addEventListener("cuechange", this.metadataCueChangeHandler);
|
|
7625
|
+
if (this.options.debug) {
|
|
7626
|
+
const cueCount = metadataTrack.cues ? metadataTrack.cues.length : 0;
|
|
7627
|
+
this.log("[Metadata] Track enabled,", cueCount, "cues available");
|
|
7628
|
+
}
|
|
7629
|
+
} else if (this.options.debug) {
|
|
7630
|
+
this.log("[Metadata] No metadata track found");
|
|
7631
|
+
}
|
|
7632
|
+
};
|
|
7633
|
+
setupMetadata();
|
|
7634
|
+
this.on("loadedmetadata", setupMetadata);
|
|
7635
|
+
}
|
|
7636
|
+
normalizeMetadataSelector(selector) {
|
|
7637
|
+
if (!selector) {
|
|
7638
|
+
return null;
|
|
7639
|
+
}
|
|
7640
|
+
const trimmed = selector.trim();
|
|
7641
|
+
if (!trimmed) {
|
|
7642
|
+
return null;
|
|
7643
|
+
}
|
|
7644
|
+
if (trimmed.startsWith("#") || trimmed.startsWith(".") || trimmed.startsWith("[")) {
|
|
7645
|
+
return trimmed;
|
|
7646
|
+
}
|
|
7647
|
+
return `#${trimmed}`;
|
|
7648
|
+
}
|
|
7649
|
+
resolveMetadataConfig(map, key) {
|
|
7650
|
+
if (!map || !key) {
|
|
7651
|
+
return null;
|
|
7652
|
+
}
|
|
7653
|
+
if (Object.prototype.hasOwnProperty.call(map, key)) {
|
|
7654
|
+
return map[key];
|
|
7655
|
+
}
|
|
7656
|
+
const withoutHash = key.replace(/^#/, "");
|
|
7657
|
+
if (Object.prototype.hasOwnProperty.call(map, withoutHash)) {
|
|
7658
|
+
return map[withoutHash];
|
|
7659
|
+
}
|
|
7660
|
+
return null;
|
|
7661
|
+
}
|
|
7662
|
+
cacheMetadataAlertContent(element, config = {}) {
|
|
7663
|
+
if (!element) {
|
|
7664
|
+
return;
|
|
7665
|
+
}
|
|
7666
|
+
const titleSelector = config.titleSelector || "[data-vidply-alert-title], h3, header";
|
|
7667
|
+
const messageSelector = config.messageSelector || "[data-vidply-alert-message], p";
|
|
7668
|
+
const titleEl = element.querySelector(titleSelector);
|
|
7669
|
+
if (titleEl && !titleEl.dataset.vidplyAlertTitleOriginal) {
|
|
7670
|
+
titleEl.dataset.vidplyAlertTitleOriginal = titleEl.textContent.trim();
|
|
7671
|
+
}
|
|
7672
|
+
const messageEl = element.querySelector(messageSelector);
|
|
7673
|
+
if (messageEl && !messageEl.dataset.vidplyAlertMessageOriginal) {
|
|
7674
|
+
messageEl.dataset.vidplyAlertMessageOriginal = messageEl.textContent.trim();
|
|
7675
|
+
}
|
|
7676
|
+
}
|
|
7677
|
+
restoreMetadataAlertContent(element, config = {}) {
|
|
7678
|
+
if (!element) {
|
|
7679
|
+
return;
|
|
7680
|
+
}
|
|
7681
|
+
const titleSelector = config.titleSelector || "[data-vidply-alert-title], h3, header";
|
|
7682
|
+
const messageSelector = config.messageSelector || "[data-vidply-alert-message], p";
|
|
7683
|
+
const titleEl = element.querySelector(titleSelector);
|
|
7684
|
+
if (titleEl && titleEl.dataset.vidplyAlertTitleOriginal) {
|
|
7685
|
+
titleEl.textContent = titleEl.dataset.vidplyAlertTitleOriginal;
|
|
7686
|
+
}
|
|
7687
|
+
const messageEl = element.querySelector(messageSelector);
|
|
7688
|
+
if (messageEl && messageEl.dataset.vidplyAlertMessageOriginal) {
|
|
7689
|
+
messageEl.textContent = messageEl.dataset.vidplyAlertMessageOriginal;
|
|
7690
|
+
}
|
|
7691
|
+
}
|
|
7692
|
+
focusMetadataTarget(target, fallbackElement = null) {
|
|
7693
|
+
var _a, _b;
|
|
7694
|
+
if (!target || target === "none") {
|
|
7695
|
+
return;
|
|
7696
|
+
}
|
|
7697
|
+
if (target === "alert" && fallbackElement) {
|
|
7698
|
+
fallbackElement.focus();
|
|
7699
|
+
return;
|
|
7700
|
+
}
|
|
7701
|
+
if (target === "player") {
|
|
7702
|
+
if (this.container) {
|
|
7703
|
+
this.container.focus();
|
|
7704
|
+
}
|
|
7705
|
+
return;
|
|
7706
|
+
}
|
|
7707
|
+
if (target === "media") {
|
|
7708
|
+
this.element.focus();
|
|
7709
|
+
return;
|
|
7710
|
+
}
|
|
7711
|
+
if (target === "playButton") {
|
|
7712
|
+
const playButton = (_b = (_a = this.controlBar) == null ? void 0 : _a.controls) == null ? void 0 : _b.playPause;
|
|
7713
|
+
if (playButton) {
|
|
7714
|
+
playButton.focus();
|
|
7715
|
+
}
|
|
7716
|
+
return;
|
|
7717
|
+
}
|
|
7718
|
+
if (typeof target === "string") {
|
|
7719
|
+
const targetElement = document.querySelector(target);
|
|
7720
|
+
if (targetElement) {
|
|
7721
|
+
if (targetElement.tabIndex === -1 && !targetElement.hasAttribute("tabindex")) {
|
|
7722
|
+
targetElement.setAttribute("tabindex", "-1");
|
|
7723
|
+
}
|
|
7724
|
+
targetElement.focus();
|
|
7725
|
+
}
|
|
7726
|
+
}
|
|
7727
|
+
}
|
|
7728
|
+
handleMetadataAlert(selector, options = {}) {
|
|
7729
|
+
if (!selector) {
|
|
7730
|
+
return;
|
|
7731
|
+
}
|
|
7732
|
+
const config = this.resolveMetadataConfig(this.options.metadataAlerts, selector) || {};
|
|
7733
|
+
const element = options.element || document.querySelector(selector);
|
|
7734
|
+
if (!element) {
|
|
7735
|
+
if (this.options.debug) {
|
|
7736
|
+
this.log("[Metadata] Alert element not found:", selector);
|
|
7737
|
+
}
|
|
7738
|
+
return;
|
|
7739
|
+
}
|
|
7740
|
+
if (this.options.debug) {
|
|
7741
|
+
this.log("[Metadata] Handling alert", selector, { reason: options.reason, config });
|
|
7742
|
+
}
|
|
7743
|
+
this.cacheMetadataAlertContent(element, config);
|
|
7744
|
+
if (!element.dataset.vidplyAlertOriginalDisplay) {
|
|
7745
|
+
element.dataset.vidplyAlertOriginalDisplay = element.style.display || "";
|
|
7746
|
+
}
|
|
7747
|
+
if (!element.dataset.vidplyAlertDisplay) {
|
|
7748
|
+
element.dataset.vidplyAlertDisplay = config.display || "block";
|
|
7749
|
+
}
|
|
7750
|
+
const shouldShow = options.show !== void 0 ? options.show : config.show !== false;
|
|
7751
|
+
if (shouldShow) {
|
|
7752
|
+
const displayValue = config.display || element.dataset.vidplyAlertDisplay || "block";
|
|
7753
|
+
element.style.display = displayValue;
|
|
7754
|
+
element.hidden = false;
|
|
7755
|
+
element.removeAttribute("hidden");
|
|
7756
|
+
element.setAttribute("aria-hidden", "false");
|
|
7757
|
+
element.setAttribute("data-vidply-alert-active", "true");
|
|
7758
|
+
}
|
|
7759
|
+
const shouldReset = config.resetContent !== false && options.reason === "focus";
|
|
7760
|
+
if (shouldReset) {
|
|
7761
|
+
this.restoreMetadataAlertContent(element, config);
|
|
7762
|
+
}
|
|
7763
|
+
const shouldFocus = options.focus !== void 0 ? options.focus : config.focusOnShow ?? options.reason !== "focus";
|
|
7764
|
+
if (shouldShow && shouldFocus) {
|
|
7765
|
+
if (element.tabIndex === -1 && !element.hasAttribute("tabindex")) {
|
|
7766
|
+
element.setAttribute("tabindex", "-1");
|
|
7767
|
+
}
|
|
7768
|
+
element.focus();
|
|
7769
|
+
}
|
|
7770
|
+
if (shouldShow && config.autoScroll !== false && options.autoScroll !== false) {
|
|
7771
|
+
element.scrollIntoView({ behavior: "smooth", block: "nearest" });
|
|
7772
|
+
}
|
|
7773
|
+
const continueSelector = config.continueButton;
|
|
7774
|
+
if (continueSelector) {
|
|
7775
|
+
let continueButton = null;
|
|
7776
|
+
if (continueSelector === "self") {
|
|
7777
|
+
continueButton = element;
|
|
7778
|
+
} else if (element.matches(continueSelector)) {
|
|
7779
|
+
continueButton = element;
|
|
7780
|
+
} else {
|
|
7781
|
+
continueButton = element.querySelector(continueSelector) || document.querySelector(continueSelector);
|
|
7782
|
+
}
|
|
7783
|
+
if (continueButton && !this.metadataAlertHandlers.has(selector)) {
|
|
7784
|
+
const handler = () => {
|
|
7785
|
+
const hideOnContinue = config.hideOnContinue !== false;
|
|
7786
|
+
if (hideOnContinue) {
|
|
7787
|
+
const originalDisplay = element.dataset.vidplyAlertOriginalDisplay || "";
|
|
7788
|
+
element.style.display = config.hideDisplay || originalDisplay || "none";
|
|
7789
|
+
element.setAttribute("aria-hidden", "true");
|
|
7790
|
+
element.removeAttribute("data-vidply-alert-active");
|
|
7791
|
+
}
|
|
7792
|
+
if (config.resume !== false && this.state.paused) {
|
|
7793
|
+
this.play();
|
|
7794
|
+
}
|
|
7795
|
+
const focusTarget = config.focusTarget || "playButton";
|
|
7796
|
+
this.setManagedTimeout(() => {
|
|
7797
|
+
this.focusMetadataTarget(focusTarget, element);
|
|
7798
|
+
}, config.focusDelay ?? 100);
|
|
7799
|
+
};
|
|
7800
|
+
continueButton.addEventListener("click", handler);
|
|
7801
|
+
this.metadataAlertHandlers.set(selector, { button: continueButton, handler });
|
|
7802
|
+
}
|
|
7803
|
+
}
|
|
7804
|
+
return element;
|
|
7805
|
+
}
|
|
7806
|
+
handleMetadataHashtags(hashtags) {
|
|
7807
|
+
if (!Array.isArray(hashtags) || hashtags.length === 0) {
|
|
7808
|
+
return;
|
|
7809
|
+
}
|
|
7810
|
+
const configMap = this.options.metadataHashtags;
|
|
7811
|
+
if (!configMap) {
|
|
7812
|
+
return;
|
|
7813
|
+
}
|
|
7814
|
+
hashtags.forEach((tag) => {
|
|
7815
|
+
const config = this.resolveMetadataConfig(configMap, tag);
|
|
7816
|
+
if (!config) {
|
|
7817
|
+
return;
|
|
7818
|
+
}
|
|
7819
|
+
const selector = this.normalizeMetadataSelector(config.alert || config.selector || config.target);
|
|
7820
|
+
if (!selector) {
|
|
7821
|
+
return;
|
|
7822
|
+
}
|
|
7823
|
+
const element = document.querySelector(selector);
|
|
7824
|
+
if (!element) {
|
|
7825
|
+
if (this.options.debug) {
|
|
7826
|
+
this.log("[Metadata] Hashtag target not found:", selector);
|
|
7827
|
+
}
|
|
7828
|
+
return;
|
|
7829
|
+
}
|
|
7830
|
+
if (this.options.debug) {
|
|
7831
|
+
this.log("[Metadata] Handling hashtag", tag, { selector, config });
|
|
7832
|
+
}
|
|
7833
|
+
this.cacheMetadataAlertContent(element, config);
|
|
7834
|
+
if (config.title) {
|
|
7835
|
+
const titleSelector = config.titleSelector || "[data-vidply-alert-title], h3, header";
|
|
7836
|
+
const titleEl = element.querySelector(titleSelector);
|
|
7837
|
+
if (titleEl) {
|
|
7838
|
+
titleEl.textContent = config.title;
|
|
7839
|
+
}
|
|
7840
|
+
}
|
|
7841
|
+
if (config.message) {
|
|
7842
|
+
const messageSelector = config.messageSelector || "[data-vidply-alert-message], p";
|
|
7843
|
+
const messageEl = element.querySelector(messageSelector);
|
|
7844
|
+
if (messageEl) {
|
|
7845
|
+
messageEl.textContent = config.message;
|
|
7846
|
+
}
|
|
7847
|
+
}
|
|
7848
|
+
const show = config.show !== false;
|
|
7849
|
+
const focus = config.focus !== void 0 ? config.focus : false;
|
|
7850
|
+
this.handleMetadataAlert(selector, {
|
|
7851
|
+
element,
|
|
7852
|
+
show,
|
|
7853
|
+
focus,
|
|
7854
|
+
autoScroll: config.autoScroll,
|
|
7855
|
+
reason: "hashtag"
|
|
7856
|
+
});
|
|
7857
|
+
});
|
|
7858
|
+
}
|
|
7859
|
+
/**
|
|
7860
|
+
* Handle individual metadata cues
|
|
7861
|
+
* Parses metadata text and emits events or triggers actions
|
|
7862
|
+
*/
|
|
7863
|
+
handleMetadataCue(cue) {
|
|
7864
|
+
const text = cue.text.trim();
|
|
7865
|
+
if (this.options.debug) {
|
|
7866
|
+
this.log("[Metadata] Processing cue:", {
|
|
7867
|
+
time: cue.startTime,
|
|
7868
|
+
text
|
|
7869
|
+
});
|
|
7870
|
+
}
|
|
7871
|
+
this.emit("metadata", {
|
|
7872
|
+
time: cue.startTime,
|
|
7873
|
+
endTime: cue.endTime,
|
|
7874
|
+
text,
|
|
7875
|
+
cue
|
|
7876
|
+
});
|
|
7877
|
+
if (text.includes("PAUSE")) {
|
|
7878
|
+
if (!this.state.paused) {
|
|
7879
|
+
if (this.options.debug) {
|
|
7880
|
+
this.log("[Metadata] Pausing video at", cue.startTime);
|
|
7881
|
+
}
|
|
7882
|
+
this.pause();
|
|
7883
|
+
}
|
|
7884
|
+
this.emit("metadata:pause", { time: cue.startTime, text });
|
|
7885
|
+
}
|
|
7886
|
+
const focusMatch = text.match(/FOCUS:([\w#-]+)/);
|
|
7887
|
+
if (focusMatch) {
|
|
7888
|
+
const targetSelector = focusMatch[1];
|
|
7889
|
+
const normalizedSelector = this.normalizeMetadataSelector(targetSelector);
|
|
7890
|
+
const targetElement = normalizedSelector ? document.querySelector(normalizedSelector) : null;
|
|
7891
|
+
if (targetElement) {
|
|
7892
|
+
if (this.options.debug) {
|
|
7893
|
+
this.log("[Metadata] Focusing element:", normalizedSelector);
|
|
7894
|
+
}
|
|
7895
|
+
if (targetElement.tabIndex === -1 && !targetElement.hasAttribute("tabindex")) {
|
|
7896
|
+
targetElement.setAttribute("tabindex", "-1");
|
|
7897
|
+
}
|
|
7898
|
+
this.setManagedTimeout(() => {
|
|
7899
|
+
targetElement.focus();
|
|
7900
|
+
targetElement.scrollIntoView({ behavior: "smooth", block: "nearest" });
|
|
7901
|
+
}, 10);
|
|
7902
|
+
} else if (this.options.debug) {
|
|
7903
|
+
this.log("[Metadata] Element not found:", normalizedSelector || targetSelector);
|
|
7904
|
+
}
|
|
7905
|
+
this.emit("metadata:focus", {
|
|
7906
|
+
time: cue.startTime,
|
|
7907
|
+
target: targetSelector,
|
|
7908
|
+
selector: normalizedSelector,
|
|
7909
|
+
element: targetElement,
|
|
7910
|
+
text
|
|
7911
|
+
});
|
|
7912
|
+
if (normalizedSelector) {
|
|
7913
|
+
this.handleMetadataAlert(normalizedSelector, {
|
|
7914
|
+
element: targetElement,
|
|
7915
|
+
reason: "focus"
|
|
7916
|
+
});
|
|
7917
|
+
}
|
|
7918
|
+
}
|
|
7919
|
+
const hashtags = text.match(/#[\w-]+/g);
|
|
7920
|
+
if (hashtags) {
|
|
7921
|
+
if (this.options.debug) {
|
|
7922
|
+
this.log("[Metadata] Hashtags found:", hashtags);
|
|
7923
|
+
}
|
|
7924
|
+
this.emit("metadata:hashtags", {
|
|
7925
|
+
time: cue.startTime,
|
|
7926
|
+
hashtags,
|
|
7927
|
+
text
|
|
7928
|
+
});
|
|
7929
|
+
this.handleMetadataHashtags(hashtags);
|
|
7930
|
+
}
|
|
7931
|
+
}
|
|
7196
7932
|
};
|
|
7197
7933
|
Player.instances = [];
|
|
7198
7934
|
|