Skip to content
This repository has been archived by the owner on May 10, 2024. It is now read-only.

Fix: #8479 - Fix long-press and video detection #8483

Merged
merged 2 commits into from
Nov 28, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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'
Expand All @@ -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);
Expand All @@ -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() {
Expand All @@ -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);
}
}

Expand All @@ -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 {}
}
});
}
Expand All @@ -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) {
Expand Down Expand Up @@ -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);
}
}

Expand Down Expand Up @@ -344,15 +320,15 @@ 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);
}
});

var setAudioAttribute = HTMLAudioElement.prototype.setAttribute;
HTMLAudioElement.prototype.setAttribute = $(function(key, value) {
setAudioAttribute.call(this, key, value);
if (key.toLowerCase() == 'src') {
notify(this, 'audio', true);
notifyNode(this, 'audio', true, false);
}
});
}
Expand All @@ -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);
Expand Down Expand Up @@ -469,13 +445,13 @@ window.__firefox__.includeOnce("Playlist", function($) {
return;
}

for (element of document.querySelectorAll('video')) {
for (const element of getAllVideoElements()) {
if (element.$<tagUUID> == tag) {
return clamp_duration(element.currentTime);
}
}

for (element of document.querySelectorAll('audio')) {
for (const element of getAllAudioElements()) {
if (element.$<tagUUID> == tag) {
return clamp_duration(element.currentTime);
}
Expand All @@ -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();
}

Expand Down