diff --git a/src/content/mutationObserver.js b/src/content/mutationObserver.js new file mode 100644 index 0000000..bf47260 --- /dev/null +++ b/src/content/mutationObserver.js @@ -0,0 +1,19 @@ +async function find(root, selector) { + return new Promise(resolve => { + const observer = new MutationObserver((_, observer) => { + tryResolve(observer) + }) + + const config = { childList: true } + observer.observe(root, config) + tryResolve(observer) + + function tryResolve(observer) { + const node = root.querySelector(selector) + if (node) { + observer.disconnect() + resolve(node) + } + } + }) +} \ No newline at end of file diff --git a/src/content/top/top.js b/src/content/top/top.js index 3955977..96fd861 100644 --- a/src/content/top/top.js +++ b/src/content/top/top.js @@ -2,8 +2,10 @@ const HIDDEN_CLASS = "x-hidden" addEventListener("load", async () => { const cssRoot = document.querySelector(":root") - const container = await queryNode(document, "ytd-watch-flexy"); - const chat = await queryNode(container, "#chat"); + const root = document.querySelector("#content #page-manager"); + const videoContainer = await find(root, "ytd-watch-flexy"); + const chatContainer = videoContainer.querySelector("#secondary #secondary-inner"); + const chat = await find(chatContainer, "#chat"); options.enabled(enabled => { document.body.classList.toggle("overlay", enabled) diff --git a/src/manifest.json b/src/manifest.json index 0eba2b1..760007d 100644 --- a/src/manifest.json +++ b/src/manifest.json @@ -32,9 +32,7 @@ "https://www.youtube.com/*" ], "js": [ - "util/fadingPromise.js", - "util/nodeObservers.js", - "util/queryNode.js", + "content/mutationObserver.js", "content/top/top.js" ], "css": [ diff --git a/src/util/fadingPromise.js b/src/util/fadingPromise.js deleted file mode 100644 index 67d0eec..0000000 --- a/src/util/fadingPromise.js +++ /dev/null @@ -1,27 +0,0 @@ -function randomId() { - return (37e16 * Math.random() + 37e16).toString(32); -} - -/** - * @param {number} timeout - time after which callback will be canceled - * @param {function} callback - cancelable promise-like function - * - * @returns promise which will will be automatically rejected after given timeout - * @throws string message (non-Error) when timeout occurred - */ -function fadingPromise(timeout, callback) { - const promiseId = randomId(); - console.debug(`Starting promise [${promiseId}]`); - - let tearDown; - return new Promise((resolve, reject) => { - const cancel = callback(resolve); - const timeoutId = setTimeout(() => reject(`Timeout after ${timeout} ms`), timeout); - - tearDown = () => { - if (cancel) cancel(); - clearTimeout(timeoutId); - console.debug(`Promise [${promiseId}] finished`); - } - }).finally(tearDown); -} \ No newline at end of file diff --git a/src/util/nodeObservers.js b/src/util/nodeObservers.js deleted file mode 100644 index 71e5a46..0000000 --- a/src/util/nodeObservers.js +++ /dev/null @@ -1,41 +0,0 @@ -function randomId() { - return (37e16 * Math.random() + 37e16).toString(32); -} - -// TODO try to use query selector in order to find nodes instead checking nodes by hand -function elementInsertedCallback(observedNode, elementSelector, callback) { - let canceled = false; - const observerId = randomId(); - const observer = new MutationObserver(onNewMutations); - - console.debug(`Starting one-shot observer [${observerId}] for selector [${elementSelector}]`); - observer.observe(observedNode, { - subtree: true, - childList: true, - }); - - return disconnect; - - function onNewMutations(mutations) { - console.debug(`Observer [${observerId}] detected added nodes`); - const result = mutations - .map(mutation => mutation.addedNodes) - .flatMap(addedNodes => Array.from(addedNodes)) - .filter(s => s instanceof Element) - .find(node => node.matches(elementSelector)); - - if (result) { - callback(result); - disconnect(); - } - } - - function disconnect() { - if (canceled) { - return; - } - canceled = true; - observer.disconnect(); - console.debug(`Disconnected observer [${observerId}]`); - } -} \ No newline at end of file diff --git a/src/util/queryNode.js b/src/util/queryNode.js deleted file mode 100644 index ad4c677..0000000 --- a/src/util/queryNode.js +++ /dev/null @@ -1,31 +0,0 @@ -const queryNode = async (parent, selector, required = true, timeout = 15_000) => { - const awaitGroup = `Await ${selector}`; - console.groupCollapsed(awaitGroup); - console.time(`Query ${selector}`); - - try { - return await fadingPromise(timeout, callback); - } catch (e) { - if (required) { - throw e; - } - console.info(e); - } finally { - console.timeEnd(`Query ${selector}`); - console.groupEnd(awaitGroup); - } - - function callback(resolve) { - const cancel = elementInsertedCallback(parent, selector, (node) => { - resolve(node); - console.debug("Resolved promise using observer"); - }); - const node = parent.querySelector(selector); - if (node) { - cancel(); - resolve(node); - console.debug("Resolved promise using selector"); - } - return cancel; - } -} \ No newline at end of file