// ==UserScript==
// @name Video Overlay Vanisher
// @namespace http://tampermonkey.net/
// @version 1.2.3
// @description A tool to eliminate web video player overlays with Shift+D.
// @author CY Fung
// @icon https://upload.cc/i1/2021/07/04/xVgQrq.png
// @match https://*/*
// @exclude https://www.youtube.com/live_chat*
// @exclude /^https?://\S+\.(txt|png|jpg|jpeg|gif|xml|svg|manifest|log|ini)[^\/]*$/
// @exclude https://chat.openai.com/*
// @exclude https://login.*/*
// @exclude https://account.*/*
// @grant none
// @run-at document-start
// @license MIT
// ==/UserScript==
(function $$() {
'use strict';
const keyCombination = {
key: 'KeyD',
shift: true
}
if (document.documentElement == null) return window.requestAnimationFrame($$);
console.log("userscript enabled - Don't Overlay Video Player !")
function addStyle(styleText) {
const styleNode = document.createElement('style');
styleNode.textContent = styleText;
document.documentElement.appendChild(styleNode);
return styleNode;
}
// Your code here...
addStyle(`
[userscript-no-overlay-on] [userscript-no-overlay-hoverable], [userscript-no-overlay-on] [userscript-no-overlay-hoverable] *:not([userscript-no-overlay-hoverable]){
visibility: collapse !important;
}
`);
var qElm_PossibleHoverByPosition = new WeakMap();
let callbackA_cid = 0;
let doList = [];
// Callback function to execute when mutations are observed
const callbackA = function (mutations, observer) {
// Use traditional 'for loops' for IE 11
for (const mutation of mutations) {
const {
addedNodes
} = mutation;
for (const s of addedNodes) {
if (s.nodeType === 1) doList.push(s);
}
}
if (doList.length == 0) return;
if (callbackA_cid) return;
callbackA_cid = setTimeout(callbackB, 100);
};
// Create an observer instance linked to the callback function
const observer = new MutationObserver(callbackA);
doList = [document.documentElement];
callbackB();
// Start observing the target node for configured mutations
observer.observe(document.documentElement, {
childList: true,
subtree: true
});
function callbackBmicro1(qElm) {
const qElmComputedStyle = getComputedStyle(qElm)
const {
position
} = qElmComputedStyle;
if (position == 'absolute' || position == 'fixed') {
qElm_PossibleHoverByPosition.set(qElm, position);
} else {
qElm_PossibleHoverByPosition.delete(qElm);
}
}
function callbackB() {
if (!doList.length || !callbackA_cid) return;
let doListCopy = [...doList]
doList.length = 0;
let elements = null;
function allParents(elm) {
let res = [];
while (elm = elm.parentNode) res.push(elm);
return res;
}
let possibleContainer = null;
for (const addedNode of doListCopy) {
if (!addedNode || !addedNode.parentNode) continue;
let parents = allParents(addedNode);
if (possibleContainer == null) {
possibleContainer = parents;
} else {
possibleContainer = possibleContainer.filter(possibleParent => parents.indexOf(possibleParent) >= 0);
}
if (possibleContainer.length <= 1) break;
}
doListCopy.length = 0;
possibleContainer = (possibleContainer ? possibleContainer[0] : null) || null;
Promise.resolve().then(() => {
//console.log('possibleContainer',possibleContainer)
if (possibleContainer) elements = [...possibleContainer.querySelectorAll('*')]; else elements = [];
}).then(() => new Promise(resolve => setTimeout(resolve, 100))).then(() => {
return Promise.all(elements.map(qElm => Promise.resolve(qElm).then(callbackBmicro1)));
}).then(() => {
//console.log('done', doList.length)
if (doList.length > 0) {
callbackA_cid = setTimeout(callbackB, 100);
} else {
callbackA_cid = 0;
}
})
}
let overlayHoverTID = 0;
let resizeObserver = null;
function resizeCallback(mutations) {
//document.documentElement.removeAttribute('userscript-no-overlay-on')
//overlayHoverTID=(overlayHoverTID+1)%2;
if (!document.documentElement.hasAttribute('userscript-no-overlay-on')) {
if (resizeObserver) {
resizeObserver.disconnect();
resizeObserver = null;
}
return;
}
let video = mutations[0].target;
if (!video) return;
makeHide(video);
}
function makeHide(videoElm) {
if (!videoElm) return;
videoElm.setAttribute('ve291', '');
let _overlayHoverTID = overlayHoverTID;
overlayHoverTID = (overlayHoverTID + 1) % 2;
let rElms = [];
for (const qElm of document.querySelectorAll('*')) {
if (qElm_PossibleHoverByPosition.has(qElm)) rElms.push(qElm);
}
let replacementTexts = [];
function replaceAll(str) {
for (const s of replacementTexts) {
if (str.length < s.length) continue;
str = str.replace(s, '');
}
return str.trim();
}
var finalBoundaries = [];
function getBoundaryElm() {
finalBoundaries.length = 0;
let _boundaryElm = videoElm;
let boundaryElm = videoElm;
while (_boundaryElm && replaceAll(_boundaryElm.textContent || '') == replaceAll(videoElm.textContent || '')) {
boundaryElm = _boundaryElm;
finalBoundaries.push(boundaryElm);
_boundaryElm = _boundaryElm.parentNode;
}
return boundaryElm;
}
for (const s of rElms) {
if (s.contains(videoElm)) continue;
let sText = s.textContent;
if (sText && sText.length > 0) replacementTexts.push(sText);
}
replacementTexts.sort((b, a) => a.length > b.length ? 1 : a.length < b.length ? -1 : 0);
getBoundaryElm();
let breakControl = false;
while (!breakControl) {
// youtube: boundary element (parent container) with no size.
// ensure boundary element is larger than the child.
var finalBoundaries_entries = finalBoundaries.map(elm => ({
elm,
rect: elm.getBoundingClientRect()
}))
for (const entry of finalBoundaries_entries) entry.size = Math.round(entry.rect.width * entry.rect.height || 0);
let maxSize = Math.max(...finalBoundaries_entries.map(entry => entry.size))
if (!maxSize) continue;
finalBoundaries_entries = finalBoundaries_entries.filter(entry => entry.size == maxSize);
let bmElm = finalBoundaries_entries[finalBoundaries_entries.length - 1].elm; // outest largest size
let bRect = bmElm.getBoundingClientRect();
for (const s of rElms) {
if (s.contains(videoElm)) continue;
let sRect = s.getBoundingClientRect();
if (bRect && sRect) {
if (sRect.width * sRect.height > 0) {
if (sRect.left > bRect.right) continue;
if (sRect.top > bRect.bottom) continue;
if (sRect.right < bRect.left) continue;
if (sRect.bottom < bRect.top) continue;
} else {
continue;
}
}
s.setAttribute('userscript-no-overlay-hoverable', overlayHoverTID);
}
breakControl = true;
}
for (const s of document.querySelectorAll(`[userscript-no-overlay-hoverable="${_overlayHoverTID}"]`)) s.removeAttribute('userscript-no-overlay-hoverable');
}
function getVideoState() {
let video = null;
let videoElms = document.querySelectorAll('video');
if (!videoElms.length) {
return null;
}
let videos = [...videoElms].map(elm => ({
elm,
width: elm.offsetWidth,
height: elm.offsetHeight
}));
let maxWidth = Math.max(...videos.map(item => item.width));
let maxHeight = Math.max(...videos.map(item => item.height));
if (maxWidth > 0 && maxHeight > 0) {
video = videos.filter(item => item.width == maxWidth && item.height == maxHeight)[0] || null;
}
return video;
}
function postMessage(target, message, origin){
let win = null;
if(target instanceof HTMLIFrameElement){
win = target.contentWindow;
}else if( target && 'postMessage' in target){
win = target;
}
if(!origin) origin = '*';
if(win && typeof win.postMessage == 'function' ){
try{
win.postMessage(message, origin);
}catch(e){}
}
}
function spreadMessage() {
for (const iframe of document.getElementsByTagName('iframe')) {
if(+iframe.getAttribute('ve944')===mouseEnteredIframeIId ){
postMessage(iframe, 'do-video-controls-hidden991');
}
}
}
function tryUnhide(){
if (document.documentElement.hasAttribute('userscript-no-overlay-on')) {
document.documentElement.removeAttribute('userscript-no-overlay-on')
for (const s of document.querySelectorAll('[userscript-no-overlay-hoverable]')) {
s.removeAttribute('userscript-no-overlay-hoverable');
}
const videoTarget = document.querySelector('[ve291]');
if (videoTarget) {
videoTarget.removeAttribute('ve291');
/*
requestAnimationFrame(() => {
console.log(12321);
// Create a new mouse event
let event = new MouseEvent('mousemove', {
bubbles: true,
cancelable: true,
clientX: 100,
clientY: 100
});
// Dispatch the event to the element
videoTarget.dispatchEvent(event);
})
*/
return true;
}
}
return false;
}
document.addEventListener('keydown', function (evt) {
if (evt && evt.code == keyCombination.key && evt.shiftKey === keyCombination.shift) {
let evtTarget = evt.target
if (evtTarget.nodeType == 1) {
if (evtTarget.nodeName == 'INPUT' || evtTarget.nodeName == 'TEXTAREA' || evtTarget.hasAttribute('contenteditable')) return;
}
evtTarget = null;
evt.preventDefault();
evt.stopPropagation();
evt.stopImmediatePropagation();
if (!tryUnhide()) {
let videoState = getVideoState();
if (videoState === null) {
//
// console.log('Unable to find any video element. If it is inside Iframe, please click the video inside iframe first.')
spreadMessage();
}
if (videoState && videoState.elm instanceof HTMLVideoElement) {
videoState.elm.dispatchEvent(new CustomEvent('video-controls-hidden675'))
}
}
}
}, true)
document.addEventListener('video-controls-hidden675', (evt) => {
let targetVideo = evt.target;
if (!(targetVideo instanceof HTMLVideoElement)) return;
if (resizeObserver) {
resizeObserver.disconnect();
resizeObserver = null;
}
resizeObserver = new ResizeObserver(resizeCallback)
resizeObserver.observe(targetVideo)
requestAnimationFrame(() => makeHide(targetVideo))
//for(const s of document.querySelectorAll(`[userscript-no-overlay-hoverable]:not([userscript-no-overlay-hoverable="${overlayHoverTID}"])`)) s.removeAttribute('userscript-no-overlay-hoverable');
document.documentElement.setAttribute('userscript-no-overlay-on', '')
}, true);
let mouseEnteredVideoVId = 0;
let mouseEnteredIframeIId = 0;
let di = 0;
let domWeakHash = new WeakMap();
document.addEventListener('mouseenter', (evt) => {
if (evt && evt.target instanceof HTMLVideoElement) {
const videoElm = evt.target;
if (!domWeakHash.has(videoElm)) {
let vid = ++di;
domWeakHash.set(videoElm, vid);
videoElm.setAttribute('ve944', vid);
}
mouseEnteredVideoVId = domWeakHash.get(videoElm);
}else if(evt && evt.target instanceof HTMLIFrameElement){
const iframeTarget = evt.target;
if (!domWeakHash.has(iframeTarget)) {
let vid = ++di;
domWeakHash.set(iframeTarget, vid);
iframeTarget.setAttribute('ve944', vid);
}
mouseEnteredIframeIId = +iframeTarget.getAttribute('ve944') || 0;
postMessage(iframeTarget, 've761-iframe-entered')
}
}, true)
document.addEventListener('mouseleave', (evt) => {
if (evt && evt.target instanceof HTMLVideoElement) {
const videoElm = evt.target;
if (domWeakHash.has(videoElm)) {
mouseEnteredVideoVId = 0;
}
}else if(evt && evt.target instanceof HTMLIFrameElement){
const iframeTarget = evt.target;
if (domWeakHash.has(iframeTarget)) {
mouseEnteredIframeIId = 0;
}
postMessage(iframeTarget, 've762-iframe-leaved')
}
}, true)
let isInIframeWindow = false;
function receiveMessage(event) {
if(!event) return;
if (event.data === 'do-video-controls-hidden991') {
let videoTarget = null;
if (mouseEnteredVideoVId > 0 && isInIframeWindow > 0) {
videoTarget = document.querySelector(`video[ve944="${mouseEnteredVideoVId}"]`);
}
if (!videoTarget) {
if(isInIframeWindow){
spreadMessage();
}
} else {
if(!tryUnhide()){
videoTarget.dispatchEvent(new CustomEvent('video-controls-hidden675'));
}
}
}else if(event.data === 've761-iframe-entered'){
isInIframeWindow = true;
}else if(event.data === 've761-iframe-leaved'){
isInIframeWindow = false;
}
}
window.addEventListener('message', receiveMessage, false);
})();