aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/utils.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/utils.ts')
-rw-r--r--src/utils.ts123
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:";
}