mirror of
https://github.com/NohamR/safari-internal-js.git
synced 2026-10-10 18:39:42 +00:00
203 lines
7.0 KiB
JavaScript
203 lines
7.0 KiB
JavaScript
//# 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);
|
|
};
|
|
})();
|