diff options
Diffstat (limited to 'src/utils.ts')
-rw-r--r-- | src/utils.ts | 123 |
1 files changed, 84 insertions, 39 deletions
diff --git a/src/utils.ts b/src/utils.ts index d7e6fcf8..081e014e 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -2,7 +2,7 @@ import Config, { VideoDownvotes } from "./config"; import { CategorySelection, SponsorTime, FetchResponse, BackgroundScriptContainer, Registration, HashedValue, VideoID, SponsorHideType } from "./types"; import * as CompileConfig from "../config.json"; -import { findValidElementFromSelector } from "./utils/pageUtils"; +import { findValidElement, findValidElementFromSelector } from "./utils/pageUtils"; import { GenericUtils } from "./utils/genericUtils"; export default class Utils { @@ -22,8 +22,9 @@ export default class Utils { ]; /* Used for waitForElement */ - waitingMutationObserver:MutationObserver = null; - waitingElements: { selector: string, callback: (element: Element) => void }[] = []; + creatingWaitingMutationObserver = false; + waitingMutationObserver: MutationObserver = null; + waitingElements: { selector: string, visibleCheck: boolean, callback: (element: Element) => void }[] = []; constructor(backgroundScriptContainer: BackgroundScriptContainer = null) { this.backgroundScriptContainer = backgroundScriptContainer; @@ -34,40 +35,66 @@ export default class Utils { } /* Uses a mutation observer to wait asynchronously */ - async waitForElement(selector: string): Promise<Element> { + async waitForElement(selector: string, visibleCheck = false): Promise<Element> { return await new Promise((resolve) => { + const initialElement = this.getElement(selector, visibleCheck); + if (initialElement) { + resolve(initialElement); + return; + } + this.waitingElements.push({ selector, + visibleCheck, callback: resolve }); - if (!this.waitingMutationObserver) { - this.waitingMutationObserver = new MutationObserver(() => { - const foundSelectors = []; - for (const { selector, callback } of this.waitingElements) { - const element = document.querySelector(selector); - if (element) { - callback(element); - foundSelectors.push(selector); - } - } - - this.waitingElements = this.waitingElements.filter((element) => !foundSelectors.includes(element.selector)); - - if (this.waitingElements.length === 0) { - this.waitingMutationObserver.disconnect(); - this.waitingMutationObserver = null; - } - }); + if (!this.creatingWaitingMutationObserver) { + this.creatingWaitingMutationObserver = true; - this.waitingMutationObserver.observe(document.body, { - childList: true, - subtree: true - }); + if (document.body) { + this.setupWaitingMutationListener(); + } else { + window.addEventListener("DOMContentLoaded", () => { + this.setupWaitingMutationListener(); + }); + } } }); } + private setupWaitingMutationListener(): void { + if (!this.waitingMutationObserver) { + this.waitingMutationObserver = new MutationObserver(() => { + const foundSelectors = []; + for (const { selector, visibleCheck, callback } of this.waitingElements) { + const element = this.getElement(selector, visibleCheck); + if (element) { + callback(element); + foundSelectors.push(selector); + } + } + + this.waitingElements = this.waitingElements.filter((element) => !foundSelectors.includes(element.selector)); + + if (this.waitingElements.length === 0) { + this.waitingMutationObserver.disconnect(); + this.waitingMutationObserver = null; + this.creatingWaitingMutationObserver = false; + } + }); + + this.waitingMutationObserver.observe(document.body, { + childList: true, + subtree: true + }); + } + } + + private getElement(selector: string, visibleCheck: boolean) { + return visibleCheck ? findValidElement(document.querySelectorAll(selector)) : document.querySelector(selector); + } + containsPermission(permissions: chrome.permissions.Permissions): Promise<boolean> { return new Promise((resolve) => { chrome.permissions.contains(permissions, resolve) @@ -183,6 +210,37 @@ export default class Utils { }); } + applyInvidiousPermissions(enable: boolean, option = "supportInvidious"): Promise<boolean> { + return new Promise((resolve) => { + if (enable) { + this.setupExtraSitePermissions((granted) => { + if (!granted) { + Config.config[option] = false; + } + + resolve(granted); + }); + } else { + this.removeExtraSiteRegistration(); + resolve(false); + } + }); + } + + containsInvidiousPermission(): Promise<boolean> { + return new Promise((resolve) => { + let permissions = ["declarativeContent"]; + if (this.isFirefox()) permissions = []; + + chrome.permissions.contains({ + origins: this.getPermissionRegex(), + permissions: permissions + }, function (result) { + resolve(result); + }); + }) + } + /** * Merges any overlapping timestamp ranges into single segments and returns them as a new array. */ @@ -358,19 +416,6 @@ export default class Utils { return referenceNode; } - objectToURI<T>(url: string, data: T, includeQuestionMark: boolean): string { - let counter = 0; - for (const key in data) { - const seperator = (url.includes("?") || counter > 0) ? "&" : (includeQuestionMark ? "?" : ""); - const value = (typeof(data[key]) === "string") ? data[key] as unknown as string : JSON.stringify(data[key]); - url += seperator + encodeURIComponent(key) + "=" + encodeURIComponent(value); - - counter++; - } - - return url; - } - isContentScript(): boolean { return window.location.protocol === "http:" || window.location.protocol === "https:"; } |