From a13d9077d1956034cb663c30e2d8da78e3434bdf Mon Sep 17 00:00:00 2001 From: Brandon-T Date: Tue, 28 Nov 2023 10:19:57 -0500 Subject: [PATCH] Fix: #8479 - Fix long-press and video detection (#8483) --- .../Scripts/Paged/PlaylistScript.js | 152 ++++++++---------- 1 file changed, 64 insertions(+), 88 deletions(-) diff --git a/Sources/Brave/Frontend/UserContent/UserScripts/Scripts_Dynamic/Scripts/Paged/PlaylistScript.js b/Sources/Brave/Frontend/UserContent/UserScripts/Scripts_Dynamic/Scripts/Paged/PlaylistScript.js index 8340bcf6854..d172dc9422f 100644 --- a/Sources/Brave/Frontend/UserContent/UserScripts/Scripts_Dynamic/Scripts/Paged/PlaylistScript.js +++ b/Sources/Brave/Frontend/UserContent/UserScripts/Scripts_Dynamic/Scripts/Paged/PlaylistScript.js @@ -93,6 +93,18 @@ window.__firefox__.includeOnce("Playlist", function($) { })(); }); + function isVideoNode(node) { + return node.constructor.name === 'HTMLVideoElement' || node.tagName === 'VIDEO'; + } + + function isAudioNode(node) { + return node.constructor.name === 'HTMLAudioElement' || node.tagName === 'AUDIO'; + } + + function isSourceNode(node) { + return node.constructor.name === 'HTMLSourceElement' || node.tagName === "SOURCE"; + } + function notifyNode(target, type, detected, ignoreSource) { if (target) { var name = target.title; @@ -105,16 +117,16 @@ window.__firefox__.includeOnce("Playlist", function($) { } if (!type || type == "") { - if (target.constructor.name == 'HTMLVideoElement') { + if (isVideoNode(target)) { type = 'video'; } - if (target.constructor.name == 'HTMLAudioElement') { + if (isAudioNode(target)) { type = 'audio'; } - if (target.constructor.name == 'HTMLSourceElement') { - if (target.parentNode.constructor.name == "HTMLVideoElement") { + if (isSourceNode(target)) { + if (isVideoNode(target.parentNode)) { type = 'video' } else { type = 'audio' @@ -128,7 +140,7 @@ window.__firefox__.includeOnce("Playlist", function($) { } else { for (node of target.children) { - if (node.constructor.name == "HTMLSourceElement") { + if (isSourceNode(node)) { if (node.src && node.src !== "") { tagNode(target); sendMessage(name, node, target, type, detected); @@ -139,8 +151,17 @@ window.__firefox__.includeOnce("Playlist", function($) { } } - function notify(target, type, detected) { - notifyNode(target, type, detected, false); + function isElementVisible(e) { + if (!!(e.offsetWidth && e.offsetHeight && e.getClientRects().length)) { + return true; + } + + var style = page.getComputedStyle(e); + return style.width != 0 && + style.height !== 0 && + style.opacity > 0 && + style.display !== 'none' && + style.visibility !== 'hidden'; } function setupLongPress() { @@ -155,73 +176,26 @@ window.__firefox__.includeOnce("Playlist", function($) { } function execute(page, offsetX, offsetY) { - var target = page.document.elementFromPoint(localX - offsetX, localY - offsetY); - var targetVideo = target ? target.closest("video") : null; - var targetAudio = target ? target.closest("audio") : null; - - // Video or Audio might have some sort of overlay.. - // Like player controls for pause/play, etc.. - // So we search for video/audio elements relative to touch position. - if (!targetVideo && !targetAudio) { - var touchX = localX + (page.scrollX + offsetX); - var touchY = localY + (page.scrollY + offsetY); - - var videoElements = page.document.querySelectorAll('video'); - for (element of videoElements) { - var rect = element.getBoundingClientRect(); - var x = rect.left + (page.scrollX + offsetX); - var y = rect.top + (page.scrollY + offsetY); - var w = rect.right - rect.left; - var h = rect.bottom - rect.top; - - if (touchX >= x && touchX <= (x + w) && touchY >= y && touchY <= (y + h)) { - targetVideo = element; - break; - } - } - - var audioElements = page.document.querySelectorAll('audio'); - for (element of audioElements) { - var rect = element.getBoundingClientRect(); - var x = rect.left + (page.scrollX + offsetX); - var y = rect.top + (page.scrollY + offsetY); - var w = rect.right - rect.left; - var h = rect.bottom - rect.top; - - if (touchX >= x && touchX <= (x + w) && touchY >= y && touchY <= (y + h)) { - targetAudio = element; - break; - } - } - - // No elements found nearby - // Select the first of each IF found because some websites can have video elements with zero size. - // In such cases, the gesture would not be on or inside the element, so this is a fallback. - if (!targetVideo && !targetAudio) { - if (videoElements.length > 0) { - targetVideo = videoElements[0]; - } - - if (audioElements.length > 0) { - targetAudio = audioElements[0]; - } - } - - // No elements found nearby so do nothing.. - if (!targetVideo && !targetAudio) { - return; + var targets = page.document.elementsFromPoint(localX - offsetX, localY - offsetY).filter((e) => { + return isVideoNode(e) || isAudioNode(e); + }).filter((e) => { + return isElementVisible(e); + }); + + + if (targets.length == 0) { + var targetAudio = page.document.querySelector('audio'); + if (targetAudio) { + tagNode(targetAudio); + notifyNode(targetAudio, 'audio', false, false); } + return; } - // Elements found + var targetVideo = targets[0]; if (targetVideo) { tagNode(targetVideo); - notify(targetVideo, 'video', false); - } - - if (targetAudio) { - tagNode(targetAudio); - notify(targetAudio, 'audio', false); + notifyNode(targetVideo, 'video', false, false); } } @@ -232,11 +206,13 @@ window.__firefox__.includeOnce("Playlist", function($) { // Any videos in a `iframe.contentWindow.document` // will have an offset of (0, 0) relative to its contentWindow. // However, it will have an offset of (X, Y) relative to the current window. - for (frame of document.querySelectorAll('iframe')) { - // Get the frame's bounds relative to the current window. - var bounds = frame.getBoundingClientRect(); - execute(frame.contentWindow, bounds.left, bounds.top); - } + try { + for (frame of document.querySelectorAll('iframe')) { + // Get the frame's bounds relative to the current window. + var bounds = frame.getBoundingClientRect(); + execute(frame.contentWindow, bounds.left, bounds.top); + } + } catch {} } }); } @@ -245,11 +221,11 @@ window.__firefox__.includeOnce("Playlist", function($) { function setupDetector() { function getAllVideoElements() { - return document.querySelectorAll('video'); + return [...document.querySelectorAll('video')].reverse(); } function getAllAudioElements() { - return document.querySelectorAll('audio'); + return [...document.querySelectorAll('audio')].reverse(); } function requestWhenIdleShim(fn) { @@ -286,20 +262,20 @@ window.__firefox__.includeOnce("Playlist", function($) { let observeNode = function(node) { function processNode(node) { // Observe video or audio elements - let isVideoElement = (node.constructor.name == "HTMLVideoElement"); - let isAudioElement = (node.constructor.name == "HTMLAudioElement"); + let isVideoElement = isVideoNode(node); + let isAudioElement = isAudioNode(node); if (isVideoElement || isAudioElement) { let type = isVideoElement ? 'video' : 'audio'; node.observer = new MutationObserver(function (mutations) { - notify(node, type, true); + notifyNode(node, type, true, false); }); node.observer.observe(node, { attributes: true, attributeFilter: ["src"] }); node.addEventListener('loadedmetadata', function() { - notify(node, type, true); + notifyNode(node, type, true, false); }); - notify(node, type, true); + notifyNode(node, type, true, false); } } @@ -344,7 +320,7 @@ window.__firefox__.includeOnce("Playlist", function($) { HTMLVideoElement.prototype.setAttribute = $(function(key, value) { setVideoAttribute.call(this, key, value); if (key.toLowerCase() == 'src') { - notify(this, 'video', true); + notifyNode(this, 'video', true, false); } }); @@ -352,7 +328,7 @@ window.__firefox__.includeOnce("Playlist", function($) { HTMLAudioElement.prototype.setAttribute = $(function(key, value) { setAudioAttribute.call(this, key, value); if (key.toLowerCase() == 'src') { - notify(this, 'audio', true); + notifyNode(this, 'audio', true, false); } }); } @@ -362,7 +338,7 @@ window.__firefox__.includeOnce("Playlist", function($) { if (tag === 'audio' || tag === 'video') { var node = document_createElement.call(this, tag); observeNode(node); - notify(node, tag, true); + notifyNode(node, tag, true, false); return node; } return document_createElement.call(this, tag); @@ -469,13 +445,13 @@ window.__firefox__.includeOnce("Playlist", function($) { return; } - for (element of document.querySelectorAll('video')) { + for (const element of getAllVideoElements()) { if (element.$ == tag) { return clamp_duration(element.currentTime); } } - for (element of document.querySelectorAll('audio')) { + for (const element of getAllAudioElements()) { if (element.$ == tag) { return clamp_duration(element.currentTime); } @@ -495,11 +471,11 @@ window.__firefox__.includeOnce("Playlist", function($) { return; } - for (element of document.querySelectorAll('video')) { + for (element of getAllVideoElements()) { element.pause(); } - for (element of document.querySelectorAll('audio')) { + for (element of getAllAudioElements()) { element.pause(); }