Skip to content

Commit

Permalink
Fixes #2919 Fixes #2673 Fixes #2641 Hide Youtube fixes (#3394)
Browse files Browse the repository at this point in the history
* Hide Youtube overlays in immersive


Rebase fixes


wip

* Fix for the player chrome controls fast forwarding

* Use the parent container for chrome controls event handling

* Ensure player chrome controls are always visible in any resolution
  • Loading branch information
keianhzo committed May 28, 2020
1 parent 3e06922 commit a9b58ee
Showing 1 changed file with 82 additions and 20 deletions.
102 changes: 82 additions & 20 deletions app/src/main/assets/web_extensions/webcompat_youtube/main.js
Expand Up @@ -10,11 +10,13 @@ const YT_SELECTORS = {
thumbnail: '.ytp-cued-thumbnail-overlay-image',
embedTitle: '.ytp-title-text',
queueHandle: 'ytd-playlist-panel-video-renderer',
playbackControls: '.ytp-left-controls'
playbackControls: '.ytp-chrome-bottom',
overlays: '.videowall-endscreen, .ytp-upnext, .ytp-ce-element'
};
const ENABLE_LOGS = true;
const logDebug = (...args) => ENABLE_LOGS && console.log(LOGTAG, ...args);
const logError = (...args) => ENABLE_LOGS && console.error(LOGTAG, ...args);
const CHROME_CONTROLS_MIN_WIDTH = 480;

class YoutubeExtension {
// We set a custom UA to force Youtube to display the most optimal
Expand Down Expand Up @@ -75,11 +77,27 @@ class YoutubeExtension {
return text.includes('360');
}

is360Video() {
const targets = [
document.querySelector(YT_SELECTORS.disclaimer),
document.querySelector(YT_SELECTORS.embedTitle)
];
return targets.some((node) => node && this.is360(node.textContent));;
}

isStereo(text) {
const words = text.toLowerCase().split(/\s+|\./);
return words.includes('stereo') || words.includes('3d') || words.includes('vr');
}

isStereoVideo() {
const targets = [
document.querySelector(YT_SELECTORS.disclaimer),
document.querySelector(YT_SELECTORS.embedTitle)
];
return targets.some((node) => node && this.isStereo(node.textContent));;
}

// Automatically select a video projection if needed
overrideVideoProjection() {
if (!this.isWatchingPage()) {
Expand All @@ -94,14 +112,8 @@ class YoutubeExtension {
}
// There is no standard API to detect video projection yet.
// Try to infer it from the video disclaimer or title for now.
const targets = [
document.querySelector(YT_SELECTORS.disclaimer),
document.querySelector(YT_SELECTORS.embedTitle)
];
const is360 = targets.some((node) => node && this.is360(node.textContent));
if (is360) {
const stereo = targets.some((node) => node && this.isStereo(node.textContent));
qs.set('mozVideoProjection', stereo ? '360s_auto' : '360_auto');
if (this.is360Video()) {
qs.set('mozVideoProjection', this.isStereoVideo() ? '360s_auto' : '360_auto');
this.updateURL(qs);
this.updateVideoStyle();
logDebug(`Video projection set to: ${qs.get(VIDEO_PROJECTION_PARAM)}`);
Expand All @@ -119,7 +131,7 @@ class YoutubeExtension {
}

overrideClick(event) {
this.overrideVideoProjection();
this.playerFixes();
const player = this.getPlayer();
if (!this.isWatchingPage() || !this.hasVideoProjection() || document.fullscreenElement || !player) {
return; // Only override click in the Youtube watching page for 360 videos.
Expand All @@ -146,7 +158,8 @@ class YoutubeExtension {

// Fix for the draggable items to continue being draggable when a context menu is displayed.
// https://github.com/MozillaReality/FirefoxReality/issues/2611
fixQueueContextMenu() {
queueContextMenuFix() {
logDebug('queueContextMenuFix');
const handles = document.querySelectorAll(YT_SELECTORS.queueHandle);
for (var i=0; i<handles.length; i++) {
handles[i].removeEventListener('contextmenu', this.onContextMenu);
Expand All @@ -169,9 +182,10 @@ class YoutubeExtension {
}

// Prevent the double click to reach the player to avoid double clicking
// to trigger a playback forward event.
// to trigger a playback forward/backward event.
// https://github.com/MozillaReality/FirefoxReality/issues/2947
videoControlsForwardFix() {
logDebug('videoControlsForwardFix');
const playbackControls = document.querySelector(YT_SELECTORS.playbackControls);
playbackControls.removeEventListener("touchstart", this.videoControlsOnTouchStart);
playbackControls.addEventListener("touchstart", this.videoControlsOnTouchStart);
Expand All @@ -189,9 +203,28 @@ class YoutubeExtension {
return false;
}

playerControlsMarginFix() {
if (youtube.isInFullscreen()) {
if (window.innerHeight < CHROME_CONTROLS_MIN_WIDTH) {
var of = CHROME_CONTROLS_MIN_WIDTH - window.innerHeight;
console.log(of)
document.querySelector(".ytp-chrome-bottom").style.setProperty("margin-bottom", `${of}px`)
} else {
document.querySelector(".ytp-chrome-bottom").style.removeProperty("margin-bottom")
}

} else {
document.querySelector(".ytp-chrome-bottom").style.removeProperty("margin-bottom")
}
}

playerFixes() {
this.fixQueueContextMenu();
this.overrideVideoProjection();
this.overrideQualityRetry();
this.hideOverlaysFix();
this.queueContextMenuFix();
this.videoControlsForwardFix();
this.playerControlsMarginFix();
}

// Runs the callback when the video is ready (has loaded the first frame).
Expand Down Expand Up @@ -252,13 +285,41 @@ class YoutubeExtension {
return video && video.readyState >=2;
}

// Hide overlays when in immersive mode
// https://github.com/MozillaReality/FirefoxReality/issues/2673
hideOverlaysFix() {
if (youtube.is360Video() || youtube.isStereoVideo()) {
logDebug('hideOverlaysFix');
var overlays = document.querySelectorAll(YT_SELECTORS.overlays);
var observer = new MutationObserver((mutations) => {
if (youtube.isInFullscreen()) {
for (const mutation of mutations) {
if (mutation.target) {
mutation.target.style.display = 'none';
}
}
}
});
for(const overlay of overlays) {
observer.observe(overlay, { attributes: true });
}
}
}

isInFullscreen() {
return !((document.fullScreenElement !== undefined && document.fullScreenElement === null) ||
(document.msFullscreenElement !== undefined && document.msFullscreenElement === null) ||
(document.mozFullScreen !== undefined && !document.mozFullScreen) ||
(document.webkitIsFullScreen !== undefined && !document.webkitIsFullScreen));
}

// Utility function to retry tasks max n times until the execution is successful.
retry(taskName, task, attempts = 10, interval = 200) {
let succeeded = false;
try {
succeeded = task();
} catch (ex) {
logError(`Got exception runnning ${taskName} task: ${ex}`);
logError(`Got exception running ${taskName} task: ${ex}`);
}
if (succeeded) {
logDebug(`${taskName} succeeded`);
Expand All @@ -278,6 +339,8 @@ class YoutubeExtension {
window.history.replaceState({}, document.title, newUrl);
logDebug(`update URL to ${newUrl}`);
}


}

logDebug(`Initializing youtube extension in frame: ${window.location.href}`);
Expand All @@ -286,18 +349,17 @@ youtube.overrideUA();
youtube.overrideViewport();
window.addEventListener('load', () => {
logDebug('page load');
youtube.overrideVideoProjection();
youtube.fixQueueContextMenu();
// Wait until video has loaded the first frame to force quality change.
// This prevents the infinite spinner problem.
// See https://github.com/MozillaReality/FirefoxReality/issues/1433
if (youtube.isWatchingPage()) {
youtube.waitForVideoReady(() => youtube.overrideQualityRetry());
youtube.waitForVideoReady(() => youtube.playerFixes());
}
});

window.addEventListener("resize", () => youtube.playerControlsMarginFix());
document.addEventListener("fullscreenchange", () => youtube.playerControlsMarginFix());
window.addEventListener('pushstate', () => youtube.overrideVideoProjection());
window.addEventListener('popstate', () => youtube.overrideVideoProjection());
window.addEventListener('click', event => youtube.overrideClick(event));
window.addEventListener('mouseup', event => youtube.playerFixes());
window.addEventListener("yt-navigate-start", () => youtube.playerFixes());
window.addEventListener('mouseup', event => youtube.queueContextMenuFix());
window.addEventListener("yt-navigate-finish", () => youtube.playerFixes());

0 comments on commit a9b58ee

Please sign in to comment.