- // ==UserScript==
- // @name Video Overlay Vanisher
- // @namespace http://tampermonkey.net/
- // @version 1.4.0
- // @description A tool to eliminate web video player overlays with Shift+D.
- // @author CY Fung
- // @icon https://na.cx/i/Hh10VGs.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://*.openai.com/*
- // @exclude https://jsfiddle.net/*
- // @exclude https://*.jsfiddle.net/*
- // @exclude https://fiddle.*.net/*
- // @exclude https://*.jshell.net/*
- // @exclude https://fiddle.jshell.net/*
- // @exclude https://login.*/*
- // @exclude https://account.*/*
- // @grant GM.getValue
- // @run-at document-start
- // @inject-into content
- // @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();
- var qElm_Cache = new WeakMap();
-
- 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;
- callbackB(100);
- };
-
-
- function callbackBmicro1(qElm) {
- if (!(qElm instanceof HTMLElement)) return;
- if (qElm.isConnected === false) return;
- let qElmComputedStyle = qElm_Cache.get(qElm);
- if (!qElmComputedStyle) {
- qElmComputedStyle = getComputedStyle(qElm)
- qElm_Cache.set(qElm, qElmComputedStyle);
- }
- const {
- position
- } = qElmComputedStyle;
-
- if (position == 'absolute' || position == 'fixed') {
- qElm_PossibleHoverByPosition.set(qElm, position);
- } else {
- qElm_PossibleHoverByPosition.delete(qElm);
- }
-
- }
-
-
- const createPipeline = () => {
- let pipelineMutex = Promise.resolve();
- const pipelineExecution = fn => {
- return new Promise((resolve, reject) => {
- pipelineMutex = pipelineMutex.then(async () => {
- let res;
- try {
- res = await fn();
- } catch (e) {
- console.log("Pipeline Error", e);
- reject(e);
- }
- resolve(res);
- }).catch(console.warn);
- });
- };
- return pipelineExecution;
- }
-
- const pipeline = createPipeline();
-
-
- async function callbackB(delay) {
-
- let res;
- do {
- res = await pipeline(async () => {
-
- if (!doList.length) return;
-
- if (delay > 0) {
- await new Promise(resolve => setTimeout(resolve, delay));
- }
-
- if (!doList.length) return;
-
- let doListCopy = doList.slice(0);
- doList.length = 0;
-
- function allParents(elm) {
- let res = [];
- while ((elm = elm.parentNode) instanceof HTMLElement) res.push(elm);
- return res;
- }
- let possibleContainerSet = null;
- const proceeded = new Set();
- for (const addedNode of doListCopy) {
- if (!addedNode || !addedNode.parentNode) continue;
- if (addedNode.isConnected === false) continue;
- if (proceeded.has(addedNode)) continue;
- proceeded.add(addedNode);
- const parentsSet = new Set(allParents(addedNode));
- if (possibleContainerSet == null) {
- possibleContainerSet = parentsSet;
- } else {
- for (const possibleParent of possibleContainerSet) {
- if (!parentsSet.has(possibleParent)) possibleContainerSet.delete(possibleParent);
- }
- parentsSet.clear();
- }
- if (possibleContainerSet.size <= 1) break;
- }
- if(!possibleContainerSet) return;
- proceeded.clear();
- doListCopy.length = 0;
-
- const possibleContainerSetIt = possibleContainerSet.values();
- const possibleContainer = possibleContainerSetIt.next().value;
-
- await Promise.resolve();
-
- //console.log('possibleContainer',possibleContainer)
-
- const elements = possibleContainer ? [...possibleContainer.querySelectorAll('*')] : null;
-
- if (elements && elements.length >= 1) {
- await new Promise(resolve => setTimeout(resolve, 100));
- await Promise.all(elements.map(qElm => Promise.resolve(qElm).then(callbackBmicro1)));
- }
-
- //console.log('done', doList.length)
-
- if (doList.length > 0) {
- delay = 100;
- return true;
- }
-
- });
- } while (res === true);
-
- }
-
-
-
- // Create an observer instance linked to the callback function
- const observer = new MutationObserver(callbackA);
-
- doList = [document.documentElement];
- callbackB(0);
-
- // Start observing the target node for configured mutations
- observer.observe(document.documentElement, {
- childList: true,
- subtree: true
- });
-
- 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;
-
- }
-
- function keydownAsync() {
- if (!tryUnhide()) {
- const 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();
- } else if (videoState && videoState.elm instanceof HTMLVideoElement) {
- videoState.elm.dispatchEvent(new CustomEvent('video-controls-hidden675'))
- }
- }
- }
-
- document.addEventListener('keydown', function (evt) {
-
- if (evt && evt.code == keyCombination.key && evt.shiftKey === keyCombination.shift) {
-
- if (evt.isComposing) return;
- 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();
-
- Promise.resolve().then(keydownAsync);
-
- }
- }, true);
-
-
-
- let rafPromise = null;
-
- const getRafPromise = () => rafPromise || (rafPromise = new Promise(resolve => {
- requestAnimationFrame(hRes => {
- rafPromise = null;
- resolve(hRes);
- });
- }));
-
-
- const controlsHidden675Async = async (targetVideo)=>{
-
- if (resizeObserver) {
- resizeObserver.disconnect();
- resizeObserver = null;
- }
- resizeObserver = new ResizeObserver(resizeCallback)
- resizeObserver.observe(targetVideo)
-
- await getRafPromise();
- makeHide(targetVideo);
-
- document.documentElement.setAttribute('userscript-no-overlay-on', '');
-
- }
-
-
-
-
- document.addEventListener('video-controls-hidden675', (evt) => {
- let targetVideo = evt.target;
- if (!(targetVideo instanceof HTMLVideoElement)) return;
-
- Promise.resolve(targetVideo).then(controlsHidden675Async);
-
- }, 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 controlsHidden991Async() {
- 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'));
- }
- }
- }
- function receiveMessage(event) {
- if (!event) return;
- if (event.data === 'do-video-controls-hidden991') {
- Promise.resolve().then(controlsHidden991Async);
- } else if (event.data === 've761-iframe-entered') {
- isInIframeWindow = true;
- } else if (event.data === 've761-iframe-leaved') {
- isInIframeWindow = false;
- }
- }
-
-
- window.addEventListener('message', receiveMessage, false);
-
- GM.getValue("dummy"); // dummy
-
-
- })();