//# sourceURL=__InjectedScript_YouTubeCaptionQuirk.js (function () { "use strict"; class CaptionMirror { static _instances = new WeakMap(); constructor(video) { let oldMirror = CaptionMirror._instances.get(video); if (oldMirror) { oldMirror.invalidate(); CaptionMirror._instances.delete(video); } CaptionMirror._instances.set(video, this); this._video = video; this._player = video.parentElement.parentElement; this._captionWindowSelector = ".ytp-caption-window-container"; this._mirrorTrack = video.addTextTrack("forced", "YouTube Captions"); this._mirrorTrack.mode = "hidden"; this._captionObserver = null; this._waitObserver = null; this._onCaptionsTrackListChanged = () => this._syncTrackList(); this._onCaptionsChanged = () => this._syncTrackList(); this._player.addEventListener( "onCaptionsTrackListChanged", this._onCaptionsTrackListChanged, ); this._player.addEventListener("captionschanged", this._onCaptionsChanged); navigator.mediaSession.setActionHandler("togglecaptions", (details) => this._handleMediaSessionAction(details), ); navigator.mediaSession.setActionHandler("selectcaptiontrack", (details) => this._handleMediaSessionAction(details), ); this._onPresentationModeChanged = () => this._handlePresentationModeChanged(); this._video.addEventListener( "webkitpresentationmodechanged", this._onPresentationModeChanged, ); this._attachCaptionWindowObserver(); this._syncTrackList(); } invalidate() { if (this._captionObserver) { this._captionObserver.disconnect(); this._captionObserver = null; } if (this._waitObserver) { this._waitObserver.disconnect(); this._waitObserver = null; } this._mirrorTrack.mode = "disabled"; this._player.removeEventListener( "onCaptionsTrackListChanged", this._onCaptionsTrackListChanged, ); this._player.removeEventListener( "captionschanged", this._onCaptionsChanged, ); this._video.removeEventListener( "webkitpresentationmodechanged", this._onPresentationModeChanged, ); } _syncTrackList() { var trackList = this._getTrackList(); var activeTrack = this._getActiveTrack(); navigator.mediaSession.captionTracks = trackList?.map((track) => { return { label: track.displayName, language: track.languageCode, enabled: this._areTracksEqual(track, activeTrack), }; }) ?? []; navigator.mediaSession.captionsEnabled = this._player.isSubtitlesOn(); } _syncCues(captionWindowContainer) { while (this._mirrorTrack.cues?.length) this._mirrorTrack.removeCue(this._mirrorTrack.cues[0]); for (var captionWindow of captionWindowContainer.querySelectorAll( ".caption-window", )) { var text = Array.from( captionWindow.querySelectorAll(".captions-text > span"), ) .map((span) => span.textContent) .join("\n"); if (!text) continue; var cue = new VTTCue(0, 10e7, text); switch (captionWindow.style.textAlign) { case "left": case "start": cue.align = "start"; cue.positionAlign = "line-left"; break; case "end": case "right": cue.align = "end"; cue.positionAlign = "line-right"; break; default: cue.align = "center"; cue.positionAlign = "center"; } var topPercent = parseFloat(captionWindow.style.top); var bottomPercent = parseFloat(captionWindow.style.bottom); var leftPercent = parseFloat(captionWindow.style.left); var rightPercent = parseFloat(captionWindow.style.right); if (!isNaN(topPercent)) { cue.snapToLines = false; cue.line = topPercent; } else if (!isNaN(bottomPercent)) { cue.snapToLines = false; cue.line = 100 - bottomPercent; } if (!isNaN(leftPercent)) cue.position = leftPercent; else if (!isNaN(rightPercent)) cue.position = 100 - rightPercent; this._mirrorTrack.addCue(cue); } } _attachCaptionWindowObserver() { var container = this._player.querySelector(this._captionWindowSelector); if (container) this._attachCaptionObserver(container); else { this._waitObserver = new MutationObserver(() => { var container = this._player.querySelector( this._captionWindowSelector, ); if (container) { this._attachCaptionObserver(container); this._waitObserver.disconnect(); this._waitObserver = null; } }); this._waitObserver.observe(this._player, { childList: true, subtree: true, }); } } _attachCaptionObserver(container) { if (this._captionObserver) this._captionObserver.disconnect(); this._captionObserver = new MutationObserver(() => { var container = this._player.querySelector(this._captionWindowSelector); if (container) this._syncCues(container); }); this._captionObserver.observe(container, { childList: true, subtree: true, characterData: true, }); } _getIsInline() { if (typeof this._video.webkitPresentationMode === "undefined") return !this._video.webkitDisplayingFullscreen; return this._video.webkitPresentationMode == "inline"; } _handlePresentationModeChanged() { var captionContainer = this._player.querySelector( this._captionWindowSelector, ); if (this._getIsInline()) { this._mirrorTrack.mode = "hidden"; if (captionContainer) captionContainer.style.removeProperty("visibility"); return; } this._player.loadModule("captions"); this._mirrorTrack.mode = "showing"; if (captionContainer) captionContainer.style.setProperty("visibility", "hidden", "important"); } _handleMediaSessionAction(details) { switch (details.action) { case "togglecaptions": this._player.toggleSubtitles(); break; case "selectcaptiontrack": { var list = this._getTrackList(); var index = details.trackIndex; if (index >= 0 && index < list.length) this._player.setOption("captions", "track", list[index]); else this._player.setOption("captions", "track", {}); break; } } } _getTrackList() { return this._player.getOption("captions", "tracklist") || []; } _getActiveTrack() { return this._player.getOption("captions", "track"); } _areTracksEqual(a, b) { return a && b && a.vss_id === b.vss_id; } } window.setupCaptionMirroring = function (video) { new CaptionMirror(video); }; })();