Greasy Fork

VoidVerified

Display a verified sign next to user's name in AniList.

目前为 2023-11-18 提交的版本。查看 最新版本

// ==UserScript==
// @name          VoidVerified
// @version       1.1.1
// @namespace     http://tampermonkey.net/
// @author        voidnyan
// @description   Display a verified sign next to user's name in AniList.
// @homepageURL   https://github.com/voidnyan/void-verified#voidverified
// @supportURL    https://github.com/voidnyan/void-verified/issues
// @grant         none
// @match         https://anilist.co/*
// @license MIT
// ==/UserScript==

(function () {
	'use strict';

	class StyleHandler {
		Settings;
		usernameStyles = "";
		highlightStyles = "";
		otherStyles = "";

		profileLink = this.createStyleLink("", "profile");

		constructor(settings) {
			this.Settings = settings;
		}

		refreshStyles() {
			this.createStyles();
			this.createStyleLink(this.usernameStyles, "username");
			this.createStyleLink(this.highlightStyles, "highlight");
			this.createStyleLink(this.otherStyles, "other");
		}

		createStyles() {
			this.usernameStyles = "";
			this.otherStyles = `a[href="/settings/developer" i]::after{content: " & Void"}`;

			for (const user of this.Settings.VerifiedUsers) {
				if (
					this.Settings.getOptionValue(
						this.Settings.Options.enabledForUsername
					) ||
					user.enabledForUsername
				) {
					this.createUsernameCSS(user);
				}
			}

			if (
				this.Settings.getOptionValue(
					this.Settings.Options.moveSubscribeButtons
				)
			) {
				this.otherStyles += `
                .has-label::before {
                top: -30px !important;
                left: unset !important;
                right: -10px;
                }
    
                .has-label[label="Unsubscribe"],
                .has-label[label="Subscribe"] {
                font-size: 0.875em !important;
                }
    
                .has-label[label="Unsubscribe"] {
                color: rgba(var(--color-green),.8);
                }
                `;
			}

			this.createHighlightStyles();

			if (this.Settings.getOptionValue(this.Settings.Options.hideLikeCount)) {
				this.otherStyles += `
                    .like-wrap .count {
                        display: none;
                    }
                `;
			}
		}

		createHighlightStyles() {
			this.highlightStyles = "";
			for (const user of this.Settings.VerifiedUsers) {
				if (
					this.Settings.getOptionValue(
						this.Settings.Options.highlightEnabled
					) ||
					user.highlightEnabled
				) {
					this.createHighlightCSS(
						user,
						`div.wrap:has( div.header > a.name[href*="${user.username}" i] )`
					);
					this.createHighlightCSS(
						user,
						`div.wrap:has( div.details > a.name[href*="${user.username}" i] )`
					);
				}

				if (
					this.Settings.getOptionValue(
						this.Settings.Options.highlightEnabledForReplies
					) ||
					user.highlightEnabledForReplies
				) {
					this.createHighlightCSS(
						user,
						`div.reply:has( a.name[href*="${user.username}" i] )`
					);
				}
			}

			this.disableHighlightOnSmallCards();
		}

		createUsernameCSS(user) {
			this.usernameStyles += `
                a.name[href*="${user.username}" i]::after {
                    content: "${
						this.stringIsEmpty(user.sign) ??
						this.Settings.getOptionValue(
							this.Settings.Options.defaultSign
						)
					}";
                    color: ${
						this.getUserColor(user) ?? "rgb(var(--color-blue))"
					}
                }
                `;
		}

		createHighlightCSS(user, selector) {
			this.highlightStyles += `
                ${selector} {
                    margin-right: -${this.Settings.getOptionValue(
						this.Settings.Options.highlightSize
					)};
                    border-right: ${this.Settings.getOptionValue(
						this.Settings.Options.highlightSize
					)} solid ${
			this.getUserColor(user) ?? this.getDefaultHighlightColor()
		};
                    border-radius: 5px;
                }
                `;
		}

		disableHighlightOnSmallCards() {
			this.highlightStyles += `
                div.wrap:has(div.small) {
                margin-right: 0px !important;
                border-right: 0px solid black !important;
                }
                `;
		}

		refreshHomePage() {
			if (
				!this.Settings.getOptionValue(
					this.Settings.Options.highlightEnabled
				)
			) {
				return;
			}
			this.createHighlightStyles();
			this.createStyleLink(this.highlightStyles, "highlight");
		}

		clearProfileVerify() {
			this.profileLink.href =
				"data:text/css;charset=UTF-8," + encodeURIComponent("");
		}

		clearStyles(id) {
			const styles = document.getElementById(`void-verified-${id}-styles`);
			styles?.remove();
		}

		verifyProfile() {
			if (
				!this.Settings.getOptionValue(
					this.Settings.Options.enabledForProfileName
				)
			) {
				return;
			}

			const usernameHeader = document.querySelector("h1.name");
			const username = usernameHeader.innerHTML.trim();

			const user = this.Settings.VerifiedUsers.find(
				(u) => u.username === username
			);
			if (!user) {
				this.clearProfileVerify();
				return;
			}

			const profileStyle = `
                    h1.name::after {
                    content: "${
						this.stringIsEmpty(user.sign) ??
						this.Settings.getOptionValue(
							this.Settings.Options.defaultSign
						)
					}"
                    }
                `;
			this.profileLink.href =
				"data:text/css;charset=UTF-8," + encodeURIComponent(profileStyle);
		}

		copyUserColor() {
			const usernameHeader = document.querySelector("h1.name");
			const username = usernameHeader.innerHTML.trim();
			const user = this.Settings.VerifiedUsers.find(
				(u) => u.username === username
			);

			if (!user) {
				return;
			}

			if (
				!(
					user.copyColorFromProfile ||
					this.Settings.getOptionValue(
						this.Settings.Options.copyColorFromProfile
					)
				)
			) {
				return;
			}

			const color =
				getComputedStyle(usernameHeader).getPropertyValue("--color-blue");

			this.Settings.updateUserOption(user.username, "color", color);
		}

		getUserColor(user) {
			return (
				user.colorOverride ??
				(user.color &&
				(user.copyColorFromProfile ||
					this.Settings.getOptionValue(
						this.Settings.Options.copyColorFromProfile
					))
					? `rgb(${user.color})`
					: undefined)
			);
		}

		getDefaultHighlightColor() {
			if (
				this.Settings.getOptionValue(
					this.Settings.Options.useDefaultHighlightColor
				)
			) {
				return this.Settings.getOptionValue(
					this.Settings.Options.defaultHighlightColor
				);
			}
			return "rgb(var(--color-blue))";
		}

		createStyleLink(styles, id) {
			const oldLink = document.getElementById(`void-verified-${id}-styles`);
			const link = document.createElement("link");
			link.setAttribute("id", `void-verified-${id}-styles`);
			link.setAttribute("rel", "stylesheet");
			link.setAttribute("type", "text/css");
			link.setAttribute(
				"href",
				"data:text/css;charset=UTF-8," + encodeURIComponent(styles)
			);
			document.head?.append(link);
			oldLink?.remove();
			return link;
		}

		stringIsEmpty(string) {
			if (!string || string.length === 0) {
				return undefined;
			}
			return string;
		}
	}

	class GlobalCSS {
		settings;
		styleHandler;

		styleId = "global-css";
		isCleared = false;

		cssInLocalStorage = "void-verified-global-css";
		constructor(settings) {
			this.settings = settings;
			this.styleHandler = new StyleHandler(settings);

			this.css = localStorage.getItem(this.cssInLocalStorage) ?? "";
		}

		createCss() {
			if (
				!this.settings.getOptionValue(
					this.settings.Options.globalCssEnabled
				)
			) {
				this.styleHandler.clearStyles(this.styleId);
				return;
			}

			if (!this.shouldRender()) {
				return;
			}

			this.isCleared = false;
			this.styleHandler.createStyleLink(this.css, this.styleId);
		}

		updateCss(css) {
			this.css = css;
			this.createCss();
			localStorage.setItem(this.cssInLocalStorage, css);
		}

		clearCssForProfile() {
			if (this.isCleared) {
				return;
			}
			if (!this.shouldRender()) {
				this.styleHandler.clearStyles(this.styleId);
				this.isCleared = true;
			}
		}

		shouldRender() {
			if (window.location.pathname.startsWith("/settings/")) {
				return false;
			}

			if (
				!this.settings.getOptionValue(
					this.settings.Options.globalCssAutoDisable
				)
			) {
				return true;
			}

			const profileCustomCss = document.getElementById(
				"customCSS-automail-styles"
			);

			if (!profileCustomCss) {
				return true;
			}

			const shouldRender = profileCustomCss.innerHTML.trim().length === 0;
			return shouldRender;
		}
	}

	class Settings {
		LocalStorageUsers = "void-verified-users";
		LocalStorageSettings = "void-verified-settings";
		Version = "1.1.1";

		Options = {
			copyColorFromProfile: {
				defaultValue: true,
				description: "Copy user color from their profile when visited.",
			},
			moveSubscribeButtons: {
				defaultValue: false,
				description:
					"Move activity subscribe button next to comments and likes.",
			},
			hideLikeCount: {
				defaultValue: false,
				description: "Hide activity and reply like counts.",
			},
			enabledForUsername: {
				defaultValue: true,
				description: "Display a verified sign next to usernames.",
			},
			enabledForProfileName: {
				defaultValue: false,
				description: "Display a verified sign next to a profile name.",
			},
			defaultSign: {
				defaultValue: "✔",
				description: "The default sign displayed next to a username.",
			},
			highlightEnabled: {
				defaultValue: true,
				description: "Highlight user activity with a border.",
			},
			highlightEnabledForReplies: {
				defaultValue: true,
				description: "Highlight replies with a border.",
			},
			highlightSize: {
				defaultValue: "5px",
				description: "Width of the highlight border.",
			},
			useDefaultHighlightColor: {
				defaultValue: false,
				description:
					"Use fallback highlight color when user color is not specified.",
			},
			defaultHighlightColor: {
				defaultValue: "#FFFFFF",
				description: "Fallback highlight color.",
			},
			globalCssEnabled: {
				defaultValue: false,
				description: "Enable custom global CSS.",
			},
			globalCssAutoDisable: {
				defaultValue: true,
				description: "Disable global CSS when a profile has custom CSS.",
			},
		};

		VerifiedUsers = [];

		constructor() {
			this.VerifiedUsers =
				JSON.parse(localStorage.getItem(this.LocalStorageUsers)) ?? [];

			const settingsInLocalStorage =
				JSON.parse(localStorage.getItem(this.LocalStorageSettings)) ?? {};

			for (const [key, value] of Object.entries(settingsInLocalStorage)) {
				if (!this.Options[key]) {
					continue;
				}
				this.Options[key].value = value.value;
			}
		}

		getOptionValue(object) {
			if (object.value === "") {
				return object.defaultValue;
			}
			return object.value ?? object.defaultValue;
		}

		verifyUser(username) {
			if (this.VerifiedUsers.find((user) => user.username === username)) {
				return;
			}

			this.VerifiedUsers.push({ username });
			localStorage.setItem(
				this.LocalStorageUsers,
				JSON.stringify(this.VerifiedUsers)
			);
		}

		updateUserOption(username, key, value) {
			this.VerifiedUsers = this.VerifiedUsers.map((u) =>
				u.username === username
					? {
							...u,
							[key]: value,
					  }
					: u
			);
			localStorage.setItem(
				this.LocalStorageUsers,
				JSON.stringify(this.VerifiedUsers)
			);
		}

		removeUser(username) {
			this.VerifiedUsers = this.VerifiedUsers.filter(
				(user) => user.username !== username
			);
			localStorage.setItem(
				this.LocalStorageUsers,
				JSON.stringify(this.VerifiedUsers)
			);
		}

		saveSettingToLocalStorage(key, value) {
			let localSettings = JSON.parse(
				localStorage.getItem(this.LocalStorageSettings)
			);

			this.Options[key].value = value;

			if (localSettings === null) {
				const settings = {
					[key]: value,
				};
				localStorage.setItem(
					this.LocalStorageSettings,
					JSON.stringify(settings)
				);
				return;
			}

			localSettings[key] = { value };
			localStorage.setItem(
				this.LocalStorageSettings,
				JSON.stringify(localSettings)
			);
		}
	}

	class ActivityHandler {
		settings;
		constructor(settings) {
			this.settings = settings;
		}

		moveAndDisplaySubscribeButton() {
			if (
				!this.settings.getOptionValue(
					this.settings.Options.moveSubscribeButtons
				)
			) {
				return;
			}

			const subscribeButtons = document.querySelectorAll(
				"span[label='Unsubscribe'], span[label='Subscribe']"
			);
			for (const subscribeButton of subscribeButtons) {
				if (subscribeButton.parentNode.classList.contains("actions")) {
					continue;
				}

				const container = subscribeButton.parentNode.parentNode;
				const actions = container.querySelector(".actions");
				actions.append(subscribeButton);
			}
		}
	}

	class SettingsUserInterface {
		Settings;
		StyleHandler;
		globalCSS;
		AnilistBlue = "120, 180, 255";

		constructor(settings, styleHandler, globalCSS) {
			this.Settings = settings;
			this.StyleHandler = styleHandler;
			this.globalCSS = globalCSS;
		}

		renderSettingsUi() {
			const container = document.querySelector(
				".settings.container > .content"
			);
			const settingsContainer = document.createElement("div");
			settingsContainer.setAttribute("id", "voidverified-settings");
			this.renderSettingsHeader(settingsContainer);

			const settingsListContainer = document.createElement("div");
			settingsListContainer.style.display = "flex";
			settingsListContainer.style.flexDirection = "column";
			settingsListContainer.style.gap = "5px";
			for (const [key, setting] of Object.entries(this.Settings.Options)) {
				this.renderSetting(setting, settingsListContainer, key);
			}

			settingsContainer.append(settingsListContainer);

			this.renderUserTable(settingsContainer);

			this.renderCustomCssEditor(settingsContainer);

			container.append(settingsContainer);
		}

		removeSettingsUi() {
			const settings = document.querySelector("#voidverified-settings");
			settings?.remove();
		}

		renderSettingsHeader(settingsContainer) {
			const headerContainer = document.createElement("div");
			const header = document.createElement("h1");
			header.style.marginTop = "30px";
			header.innerText = "VoidVerified Settings";

			const versionInfo = document.createElement("p");
			versionInfo.append("Version: ");
			const versionNumber = document.createElement("span");
			versionNumber.style.color = `rgb(${this.AnilistBlue})`;
			versionNumber.append(this.Settings.Version);

			versionInfo.append(versionNumber);

			headerContainer.append(header);
			headerContainer.append(versionInfo);
			settingsContainer.append(headerContainer);
		}

		renderUserTable(settingsContainer) {
			const oldTableContainer = document.querySelector(
				"#void-verified-user-table"
			);
			const tableContainer =
				oldTableContainer ?? document.createElement("div");
			tableContainer.innerHTML = "";

			tableContainer.setAttribute("id", "void-verified-user-table");

			const table = document.createElement("table");
			const head = document.createElement("thead");
			const headrow = document.createElement("tr");
			headrow.append(this.createCell("Username", "th"));
			headrow.append(this.createCell("Sign", "th"));
			headrow.append(this.createCell("Color", "th"));

			head.append(headrow);

			const body = document.createElement("tbody");

			for (const user of this.Settings.VerifiedUsers) {
				body.append(this.createUserRow(user));
			}

			table.append(head);
			table.append(body);
			tableContainer.append(table);

			const inputForm = document.createElement("form");
			inputForm.addEventListener("submit", (event) =>
				this.handleVerifyUserForm(event, this.Settings)
			);
			const label = document.createElement("label");
			label.innerText = "Add user";
			inputForm.append(label);
			const textInput = document.createElement("input");
			textInput.setAttribute("id", "voidverified-add-user");

			inputForm.append(textInput);
			tableContainer.append(inputForm);

			oldTableContainer || settingsContainer.append(tableContainer);
		}

		createUserRow(user) {
			const row = document.createElement("tr");
			const userLink = document.createElement("a");
			userLink.innerText = user.username;
			userLink.setAttribute(
				"href",
				`https://anilist.co/user/${user.username}/`
			);
			userLink.setAttribute("target", "_blank");
			row.append(this.createCell(userLink));

			const signInput = document.createElement("input");
			signInput.value = user.sign ?? "";
			signInput.style.width = "100px";
			signInput.addEventListener("input", (event) =>
				this.updateUserOption(user.username, "sign", event.target.value)
			);
			const signCell = this.createCell(signInput);
			signCell.append(
				this.createUserCheckbox(
					user.enabledForUsername,
					user.username,
					"enabledForUsername",
					this.Settings.getOptionValue(
						this.Settings.Options.enabledForUsername
					)
				)
			);

			row.append(this.createCell(signCell));

			const colorInput = document.createElement("input");
			colorInput.setAttribute("type", "color");
			colorInput.style.border = "0";
			colorInput.style.height = "24px";
			colorInput.style.width = "40px";
			colorInput.style.padding = "0";
			colorInput.style.backgroundColor = "unset";
			colorInput.value = this.getUserColorPickerColor(user);
			colorInput.addEventListener(
				"change",
				(event) => this.handleUserColorChange(event, user.username),
				false
			);

			const colorInputContainer = document.createElement("span");

			const colorCell = this.createCell(colorInput);

			colorInputContainer.append(
				this.createUserCheckbox(
					user.copyColorFromProfile,
					user.username,
					"copyColorFromProfile",
					this.Settings.getOptionValue(
						this.Settings.Options.copyColorFromProfile
					)
				)
			);

			colorInputContainer.append(
				this.createUserCheckbox(
					user.highlightEnabled,
					user.username,
					"highlightEnabled",
					this.Settings.getOptionValue(
						this.Settings.Options.highlightEnabled
					)
				)
			);

			colorInputContainer.append(
				this.createUserCheckbox(
					user.highlightEnabledForReplies,
					user.username,
					"highlightEnabledForReplies",
					this.Settings.getOptionValue(
						this.Settings.Options.highlightEnabledForReplies
					)
				)
			);

			colorCell.append(colorInputContainer);

			const resetColorBtn = document.createElement("button");
			resetColorBtn.innerText = "🔄";
			resetColorBtn.addEventListener("click", () =>
				this.handleUserColorReset(user.username)
			);

			colorCell.append(resetColorBtn);
			row.append(colorCell);

			const deleteButton = document.createElement("button");
			deleteButton.innerText = "❌";
			deleteButton.addEventListener("click", () =>
				this.removeUser(user.username)
			);
			row.append(this.createCell(deleteButton));
			return row;
		}

		getUserColorPickerColor(user) {
			if (user.colorOverride) {
				return user.colorOverride;
			}

			if (
				user.color &&
				(user.copyColorFromProfile ||
					this.Settings.getOptionValue(
						this.Settings.Options.copyColorFromProfile
					))
			) {
				return this.rgbToHex(user.color);
			}

			if (
				this.Settings.getOptionValue(
					this.Settings.Options.useDefaultHighlightColor
				)
			) {
				return this.Settings.getOptionValue(
					this.Settings.Options.defaultHighlightColor
				);
			}

			return this.rgbToHex(this.AnilistBlue);
		}

		createUserCheckbox(isChecked, username, settingKey, disabled) {
			const checkbox = document.createElement("input");
			if (disabled) {
				checkbox.setAttribute("disabled", "");
			}

			checkbox.setAttribute("type", "checkbox");
			checkbox.checked = isChecked;
			checkbox.addEventListener("change", (event) => {
				this.updateUserOption(username, settingKey, event.target.checked);
				this.refreshUserTable();
			});

			checkbox.style.marginLeft = "5px";

			checkbox.title = this.Settings.Options[settingKey].description;
			return checkbox;
		}

		handleUserColorReset(username) {
			this.updateUserOption(username, "colorOverride", undefined);
			this.refreshUserTable();
		}

		handleUserColorChange(event, username) {
			const color = event.target.value;
			this.updateUserOption(username, "colorOverride", color);
		}

		handleVerifyUserForm(event, settings) {
			event.preventDefault();

			const usernameInput = document.getElementById("voidverified-add-user");
			const username = usernameInput.value;
			settings.verifyUser(username);
			usernameInput.value = "";
			this.refreshUserTable();
		}

		refreshUserTable() {
			const container = document.querySelector(
				".settings.container > .content"
			);
			this.renderUserTable(container);
		}

		updateUserOption(username, key, value) {
			this.Settings.updateUserOption(username, key, value);
			this.StyleHandler.refreshStyles();
		}

		removeUser(username) {
			this.Settings.removeUser(username);
			this.refreshUserTable();
			this.StyleHandler.refreshStyles();
		}

		verifyUser(username) {
			this.Settings.verifyUser(username);
			this.StyleHandler.refreshStyles();
		}

		createCell(content, elementType = "td") {
			const cell = document.createElement(elementType);
			cell.append(content);
			return cell;
		}

		renderSetting(setting, settingsContainer, settingKey, disabled = false) {
			const value = this.Settings.getOptionValue(setting);
			const type = typeof value;

			const container = document.createElement("div");
			const input = document.createElement("input");

			if (type === "boolean") {
				input.setAttribute("type", "checkbox");
			} else if (settingKey == "defaultHighlightColor") {
				input.setAttribute("type", "color");
				input.style.border = "0";
				input.style.height = "15px";
				input.style.width = "25px";
				input.style.padding = "0";
				input.style.backgroundColor = "unset";
			} else if (type === "string") {
				input.setAttribute("type", "text");
				input.style.width = "50px";
			}

			if (disabled) {
				input.setAttribute("disabled", "");
			}

			input.setAttribute("id", settingKey);
			input.addEventListener("change", (event) =>
				this.handleOption(event, settingKey, type)
			);

			if (type === "boolean" && value) {
				input.setAttribute("checked", true);
			} else if (type === "string") {
				input.value = value;
			}

			container.append(input);

			const label = document.createElement("label");
			label.setAttribute("for", settingKey);
			label.innerText = setting.description;
			label.style.marginLeft = "5px";
			container.append(label);
			settingsContainer.append(container);
		}

		handleOption(event, settingKey, type) {
			const value =
				type === "boolean" ? event.target.checked : event.target.value;
			this.Settings.saveSettingToLocalStorage(settingKey, value);
			this.StyleHandler.refreshStyles();
			this.refreshUserTable();
		}

		renderCustomCssEditor(settingsContainer) {
			const container = document.createElement("div");
			const label = document.createElement("label");
			label.innerText = "Custom Global CSS";
			label.setAttribute("for", "void-verified-global-css-editor");
			label.style.marginTop = "20px";
			label.style.fontSize = "2rem";
			label.style.display = "inline-block";
			container.append(label);

			const textarea = document.createElement("textarea");
			textarea.setAttribute("id", "void-verified-global-css-editor");

			textarea.value = this.globalCSS.css;
			textarea.style.width = "100%";
			textarea.style.height = "200px";
			textarea.style.resize = "vertical";
			textarea.style.background = "#14191f";
			textarea.style.color = "white";

			textarea.addEventListener("change", (event) => {
				this.handleCustomCssEditor(event, this);
			});

			container.append(textarea);

			const notice = document.createElement("div");
			notice.innerText =
				"Please note that Custom CSS is disabled in the settings. \nIn the event that you accidentally disable rendering of critical parts of AniList, navigate to the settings by URL";
			notice.style.fontSize = "11px";
			container.append(notice);

			settingsContainer.append(container);
		}

		handleCustomCssEditor(event, settingsUi) {
			const value = event.target.value;
			settingsUi.globalCSS.updateCss(value);
		}

		rgbToHex(rgb) {
			const [r, g, b] = rgb.split(",");
			const hex = this.generateHex(r, g, b);
			return hex;
		}

		generateHex(r, g, b) {
			return (
				"#" +
				[r, g, b]
					.map((x) => {
						const hex = Number(x).toString(16);
						return hex.length === 1 ? "0" + hex : hex;
					})
					.join("")
			);
		}
	}

	class IntervalScriptHandler {
		styleHandler;
		settingsUi;
		activityHandler;
		settings;
		globalCSS;
		constructor(settings) {
			this.settings = settings;

			this.styleHandler = new StyleHandler(settings);
			this.globalCSS = new GlobalCSS(settings);
			this.settingsUi = new SettingsUserInterface(
				settings,
				this.styleHandler,
				this.globalCSS
			);
			this.activityHandler = new ActivityHandler(settings);
		}

		currentPath = "";
		evaluationIntervalInSeconds = 1;
		hasPathChanged(path) {
			if (path === this.currentPath) {
				return false;
			}
			this.currentPath = path;
			return true;
		}

		handleIntervalScripts(intervalScriptHandler) {
			const path = window.location.pathname;

			intervalScriptHandler.activityHandler.moveAndDisplaySubscribeButton();
			intervalScriptHandler.globalCSS.clearCssForProfile();

			if (path === "/home") {
				intervalScriptHandler.styleHandler.refreshHomePage();
			}

			if (!path.startsWith("/settings/developer")) {
				intervalScriptHandler.settingsUi.removeSettingsUi();
			}

			if (!intervalScriptHandler.hasPathChanged(path)) {
				return;
			}

			intervalScriptHandler.styleHandler.clearProfileVerify();
			intervalScriptHandler.globalCSS.createCss();

			if (path.startsWith("/user/")) {
				intervalScriptHandler.styleHandler.verifyProfile();
				intervalScriptHandler.styleHandler.copyUserColor();
				return;
			}

			if (path.startsWith("/settings/developer")) {
				intervalScriptHandler.settingsUi.renderSettingsUi();
				return;
			}
		}

		enableScriptIntervalHandling() {
			setInterval(() => {
				this.handleIntervalScripts(this);
			}, this.evaluationIntervalInSeconds * 1000);
		}
	}

	const settings = new Settings();
	const styleHandler = new StyleHandler(settings);
	const intervalScriptHandler = new IntervalScriptHandler(settings);

	styleHandler.refreshStyles();
	intervalScriptHandler.enableScriptIntervalHandling();

	console.log(`VoidVerified ${settings.Version} loaded.`);

})();