From c4e857822e412af01ccfc6418377a871732e1223 Mon Sep 17 00:00:00 2001 From: Niki Wix Skaarup Date: Wed, 2 Apr 2025 22:38:28 +0200 Subject: [PATCH] cleanup logging --- .../manga-reading/manga-reading.user.ts | 737 ++++++++---------- 1 file changed, 306 insertions(+), 431 deletions(-) diff --git a/src/userscripts/manga-reading/manga-reading.user.ts b/src/userscripts/manga-reading/manga-reading.user.ts index 14e92bb..8d6a3e5 100644 --- a/src/userscripts/manga-reading/manga-reading.user.ts +++ b/src/userscripts/manga-reading/manga-reading.user.ts @@ -50,45 +50,41 @@ // @noframes // ==/UserScript== -import mangaReadingLibFrame from "./templates/manga-reading-lib-frame.html"; -import mangaReadingConfig from "./templates/manga-reading-config.html"; -import mangaReadingNotificationButton from "./templates/manga-reading-notification-button.html"; -import mangaReadingNotificationContainer from "./templates/manga-reading-notification-container.html"; -import mangaReadingNotification from "./templates/manga-reading-notification.html"; +import mangaReadingLibFrame from './templates/manga-reading-lib-frame.html'; +import mangaReadingConfig from './templates/manga-reading-config.html'; +import mangaReadingNotificationButton from './templates/manga-reading-notification-button.html'; +import mangaReadingNotificationContainer from './templates/manga-reading-notification-container.html'; +import mangaReadingNotification from './templates/manga-reading-notification.html'; async function initMangaReading() { function disableScrolling() { document.documentElement.style.top = `${-document.documentElement.scrollTop}px`; - document.documentElement.style.position = "fixed"; - document.documentElement.style.overflowY = "scroll"; - document.body.style.overflowY = "scroll"; - document.documentElement.style.width = "100vw"; + document.documentElement.style.position = 'fixed'; + document.documentElement.style.overflowY = 'scroll'; + document.body.style.overflowY = 'scroll'; + document.documentElement.style.width = '100vw'; } function enableScrolling() { const top = Number.parseInt(document.documentElement.style.top, 10); const scrollTop = Math.abs(top); - document.documentElement.style.position = ""; - document.documentElement.style.overflowY = ""; - document.body.style.overflowY = ""; + document.documentElement.style.position = ''; + document.documentElement.style.overflowY = ''; + document.body.style.overflowY = ''; document.documentElement.scrollTop = scrollTop; document.body.scrollTop = scrollTop; } - function loadStyle( - name: string, - inline: boolean, - shadowRoot: ShadowRoot | null, - ) { + function loadStyle(name: string, inline: boolean, shadowRoot: ShadowRoot | null) { const data = GM_getResourceText(name); if (!data) { console.warn(`Resource ${name} not found`); return; } - const style = document.createElement("style"); - style.setAttribute("type", "text/css"); - style.setAttribute("data-mr-style", ""); - style.setAttribute("data-name", name); + const style = document.createElement('style'); + style.setAttribute('type', 'text/css'); + style.setAttribute('data-mr-style', ''); + style.setAttribute('data-name', name); style.innerHTML = data; if (inline) document.head.append(style); @@ -97,60 +93,55 @@ async function initMangaReading() { function getMr() { const focusableSelector = - "a[href].nws, area[href].nws, input:not([disabled]).nws, select:not([disabled]).nws, textarea:not([disabled]).nws, button:not([disabled]).nws, [tabindex].nws, [contenteditable].nws"; + 'a[href].nws, area[href].nws, input:not([disabled]).nws, select:not([disabled]).nws, textarea:not([disabled]).nws, button:not([disabled]).nws, [tabindex].nws, [contenteditable].nws'; const configGlobals: configuration_ui.globalsType = { uiInitialized: false, - configurationWindowOpen: false, + configurationWindowOpen: false }; function createHTMLElement( tag: string, className: string | undefined = undefined, - innerHTML: string | undefined = undefined, + innerHTML: string | undefined = undefined ) { const element = document.createElement(tag); if (className) element.className = className; if (innerHTML) element.innerHTML = innerHTML; - element.classList.add("nws"); + element.classList.add('nws'); return element; } - const frameTemplate = createHTMLElement("div", "mr-lib-outer-frame"); + const frameTemplate = createHTMLElement('div', 'mr-lib-outer-frame'); frameTemplate.innerHTML = atob(mangaReadingLibFrame); const customElementRegistry = window.customElements; customElementRegistry.define( - "mr-config-container", + 'mr-config-container', class extends HTMLElement { constructor() { super(); - this.attachShadow({ mode: "open" }).appendChild( - frameTemplate.cloneNode(true), - ); + this.attachShadow({ mode: 'open' }).appendChild(frameTemplate.cloneNode(true)); } - }, + } ); - const outerFrame = document.createElement("mr-config-container"); + const outerFrame = document.createElement('mr-config-container'); const shadowRoot = outerFrame.shadowRoot; if (!shadowRoot) return; - loadStyle("stylesheet", false, shadowRoot); + loadStyle('stylesheet', false, shadowRoot); const frame = shadowRoot.children[0]; if (!frame) return; - const backdrop = frame.querySelector("[data-mr-backdrop]"); + const backdrop = frame.querySelector('[data-mr-backdrop]'); if (!backdrop) return; backdrop.onclick = closeConfig; - const subConfigTarget = frame.querySelector( - "[data-mr-sub-config-target]", - ); - const closeConfigButtons = - frame.querySelectorAll("[data-mr-close]"); + const subConfigTarget = frame.querySelector('[data-mr-sub-config-target]'); + const closeConfigButtons = frame.querySelectorAll('[data-mr-close]'); for (let i = 0; i < closeConfigButtons.length; i++) { const button = closeConfigButtons[i]; @@ -164,7 +155,7 @@ async function initMangaReading() { outerFrame, shadowRoot, frame, - subConfigTarget, + subConfigTarget }; const registeredConfigurations: { @@ -175,15 +166,11 @@ async function initMangaReading() { }; } = {}; - function registerConfig( - info: vm_infoType, - container: HTMLElement, - callback: () => void, - ) { + function registerConfig(info: vm_infoType, container: HTMLElement, callback: () => void) { registeredConfigurations[info.script.name] = { name: info.script.name, container, - callback, + callback }; ui.subConfigTarget?.appendChild(container); @@ -213,7 +200,7 @@ async function initMangaReading() { disableScrolling(); - shadowRoot?.querySelector("input")?.focus(); + shadowRoot?.querySelector('input')?.focus(); } function closeConfig() { @@ -224,34 +211,29 @@ async function initMangaReading() { function tabSwitch(event: KeyboardEvent) { const target = event.target; - const elements = - ui.frame.querySelectorAll(focusableSelector); + const elements = ui.frame.querySelectorAll(focusableSelector); if (elements.length === 0) return; const firstElement = elements[0]; const lastElement = elements[elements.length - 1]; - if (event.code === "Tab" && event.shiftKey && target === firstElement) { + if (event.code === 'Tab' && event.shiftKey && target === firstElement) { event.preventDefault(); setTimeout(() => lastElement?.focus(), 0); - } else if ( - event.code === "Tab" && - !event.shiftKey && - target === lastElement - ) { + } else if (event.code === 'Tab' && !event.shiftKey && target === lastElement) { event.preventDefault(); setTimeout(() => firstElement?.focus(), 0); } } function keydownEventListener(event: KeyboardEvent) { - if (event.code === "Tab") { + if (event.code === 'Tab') { tabSwitch(event); return true; } - if (event.code === "Tab" && event.shiftKey) { + if (event.code === 'Tab' && event.shiftKey) { tabSwitch(event); return true; } @@ -260,9 +242,9 @@ async function initMangaReading() { } function attachFocusEvent() { - console.log("MR - Attaching focus event..."); - ui.frame?.addEventListener("keydown", keydownEventListener as any); - console.log("MR - Attached focus events."); + console.log(`${GM.info.script.name} - Attaching focus event...`); + ui.frame?.addEventListener('keydown', keydownEventListener as any); + console.log(`${GM.info.script.name} - Attached focus events.`); } function noModifier(e: KeyboardEvent) { @@ -283,11 +265,11 @@ async function initMangaReading() { async function globalShortcuts(event: KeyboardEvent) { switch (true) { - case event.code === "Backslash" && ctrlModifier(event): + case event.code === 'Backslash' && ctrlModifier(event): // setDebugging(!configGlobals.debugging); // ui.debuggingCheckbox.checked = configGlobals.debugging; return true; - case event.code === "Semicolon" && ctrlModifier(event): + case event.code === 'Semicolon' && ctrlModifier(event): // reloadResources(); return true; } @@ -295,7 +277,7 @@ async function initMangaReading() { } async function configOpenShortcuts(event: KeyboardEvent) { - if (event.code === "Escape" && noModifier(event)) { + if (event.code === 'Escape' && noModifier(event)) { closeConfig(); return true; } @@ -303,7 +285,7 @@ async function initMangaReading() { } async function configClosedShortcuts(event: KeyboardEvent) { - if (event.code === "Slash" && ctrlModifier(event)) { + if (event.code === 'Slash' && ctrlModifier(event)) { openConfig(); return true; } @@ -314,16 +296,16 @@ async function initMangaReading() { function filterRegisteredShortcut(shortcutType: shortcutType) { return registeredKeyUpShortCuts.filter( - (registered) => registered.shortcutType === shortcutType, + (registered) => registered.shortcutType === shortcutType ); } async function keyupEventListener(event: KeyboardEvent) { const shortcuts = [ - ...filterRegisteredShortcut("Global"), + ...filterRegisteredShortcut('Global'), ...(configGlobals.configurationWindowOpen - ? filterRegisteredShortcut("ConfigOpen") - : filterRegisteredShortcut("ConfigClosed")), + ? filterRegisteredShortcut('ConfigOpen') + : filterRegisteredShortcut('ConfigClosed')) ]; for (const registered of shortcuts) { @@ -334,15 +316,12 @@ async function initMangaReading() { } function attachShortcutEvents() { - console.log("MR - Attaching shortcut events..."); - document.addEventListener("keyup", keyupEventListener); - console.log("MR - Attached shortcut events."); + console.log(`${GM.info.script.name} - Attaching shortcut events...`); + document.addEventListener('keyup', keyupEventListener); + console.log(`${GM.info.script.name} - Attached shortcut events.`); } - function registerKeyUp( - shortcutType: shortcutType, - ...shortcuts: shortcut[] - ) { + function registerKeyUp(shortcutType: shortcutType, ...shortcuts: shortcut[]) { for (const shortcut of shortcuts) { registeredKeyUpShortCuts.unshift({ shortcutType, shortcut }); } @@ -350,7 +329,7 @@ async function initMangaReading() { function unregisterKeyUp(name: string) { const index = registeredKeyUpShortCuts.findIndex( - (registered) => registered.shortcut.name === name, + (registered) => registered.shortcut.name === name ); if (index > -1) { registeredKeyUpShortCuts.splice(index, 1); @@ -358,59 +337,50 @@ async function initMangaReading() { } function registerKeyUps() { - const namePrefix = "nwsLib"; - registerKeyUp("Global", { + const namePrefix = 'nwsLib'; + registerKeyUp('Global', { name: `${namePrefix} - global`, - callback: globalShortcuts, + callback: globalShortcuts }); - registerKeyUp("ConfigOpen", { + registerKeyUp('ConfigOpen', { name: `${namePrefix} - config open`, - callback: configOpenShortcuts, + callback: configOpenShortcuts }); - registerKeyUp("ConfigClosed", { + registerKeyUp('ConfigClosed', { name: `${namePrefix} - config closed`, - callback: configClosedShortcuts, + callback: configClosedShortcuts }); } - async function onInit( - callback: () => Promise, - postCallback: () => Promise, - ) { + async function onInit(callback: () => Promise, postCallback: () => Promise) { try { - console.log(`MR - ${GM.info.script.name} - Loading...`); - const id = GM.registerMenuCommand( - `Configure ${GM.info.script.name}`, - () => { - openConfig(); - }, - ); + console.log(`${GM.info.script.name} - Loading...`); + const id = GM.registerMenuCommand(`Configure ${GM.info.script.name}`, () => { + openConfig(); + }); registerKeyUps(); attachFocusEvent(); attachShortcutEvents(); - console.log(`MR - ${GM.info.script.name} - Loaded.`); + console.log(`${GM.info.script.name} - Loaded.`); await callback(); if (postCallback !== undefined) { await postCallback(); } } catch (e) { - console.error("MR - Error:", e); + console.error(`${GM.info.script.name} - Error:`, e); } } - async function init( - callback: () => Promise, - postCallback: () => Promise, - ) { - console.log("MR - Initializing..."); + async function init(callback: () => Promise, postCallback: () => Promise) { + console.log(`${GM.info.script.name} - Initializing...`); switch (document.readyState) { - case "complete": + case 'complete': await onInit(callback, postCallback); break; - case "interactive": + case 'interactive': await onInit(callback, postCallback); break; - case "loading": + case 'loading': setTimeout(init, 10, callback, postCallback); break; } @@ -420,177 +390,155 @@ async function initMangaReading() { config: { register: registerConfig, unregister: unregisterConfig, - isOpen: () => configGlobals.configurationWindowOpen, + isOpen: () => configGlobals.configurationWindowOpen }, shortcut: { keyUp: { register: registerKeyUp, - unregister: unregisterKeyUp, + unregister: unregisterKeyUp }, helpers: { noModifier, shiftModifier, ctrlModifier, - altModifier, - }, + altModifier + } }, createHTMLElement, outerFrame, shadowRoot, frame, - init, + init }; } const mr = getMr(); if (!mr) return; const globals: manga_reading.globalsType = { - nextUrl: "", - prevUrl: "", - currentTitle: "", + nextUrl: '', + prevUrl: '', + currentTitle: '', uiInitialized: false, - at: "neither", + at: 'neither', titleList: [], ptApi: { - url: "", - bearerToken: "", - }, + url: '', + bearerToken: '' + } }; const key = { - firstRun: "firstRun", - titleList: "titleList", - ptAPi: "ptApi", + firstRun: 'firstRun', + titleList: 'titleList', + ptAPi: 'ptApi' }; - const containerTemplate = document.createElement("section"); + const containerTemplate = document.createElement('section'); containerTemplate.innerHTML = atob(mangaReadingNotificationContainer); const customElementRegistry = window.customElements; customElementRegistry.define( - "mr-notification-container", + 'mr-notification-container', class extends HTMLElement { constructor() { super(); - this.attachShadow({ mode: "open" }).appendChild( - containerTemplate.cloneNode(true), - ); + this.attachShadow({ mode: 'open' }).appendChild(containerTemplate.cloneNode(true)); } - }, + } ); - const outerFrame = document.createElement("mr-notification-container"); + const outerFrame = document.createElement('mr-notification-container'); if (!outerFrame.shadowRoot) return; const shadowRoot = outerFrame.shadowRoot; const container = shadowRoot.children[0] as HTMLDivElement; - const notificationList = container.querySelector("ol"); + const notificationList = container.querySelector('ol'); if (!notificationList) return; - notificationList.style.setProperty("--offset", "32px"); - notificationList.style.setProperty("--width", "356px"); - notificationList.style.setProperty("--gap", "14px"); - notificationList.style.setProperty("--border-radius", "8px"); - notificationList.style.setProperty("--z-index", "999999999"); + notificationList.style.setProperty('--offset', '32px'); + notificationList.style.setProperty('--width', '356px'); + notificationList.style.setProperty('--gap', '14px'); + notificationList.style.setProperty('--border-radius', '8px'); + notificationList.style.setProperty('--z-index', '999999999'); function initToastContainer() { - console.log("MR - Initializing Toast Container."); + console.log(`${GM.info.script.name} - Initializing Toast Container.`); if (!mr) return; for (let i = 0; i < mr.shadowRoot.children.length; i++) { const element = mr.shadowRoot.children[i]; - if (element?.tagName.toLowerCase() === "style") { + if (element?.tagName.toLowerCase() === 'style') { shadowRoot.appendChild(element.cloneNode(true)); } } - console.log("MR - Initialized Toast Container."); + console.log(`${GM.info.script.name} - Initialized Toast Container.`); } function insertToastContainer() { - console.log("MR - Inserting Toast Container."); + console.log(`${GM.info.script.name} - Inserting Toast Container.`); document.body.appendChild(outerFrame); - console.log("MR - Inserted Toast Container."); + console.log(`${GM.info.script.name} - Inserted Toast Container.`); } - const notificationTemp = document.createElement("div"); + const notificationTemp = document.createElement('div'); notificationTemp.innerHTML = atob(mangaReadingNotification); const notificationElement = notificationTemp.children[0] as HTMLDivElement; - const notificationButtonTemp = document.createElement("div"); + const notificationButtonTemp = document.createElement('div'); notificationButtonTemp.innerHTML = atob(mangaReadingNotificationButton); - const notificationButton = notificationButtonTemp - .children[0] as HTMLDivElement; + const notificationButton = notificationButtonTemp.children[0] as HTMLDivElement; - const temp = document.createElement("div"); + const temp = document.createElement('div'); temp.innerHTML = atob(mangaReadingConfig); const configElement = temp.children[0] as HTMLDivElement; const ui = { - ptApiUrl: configElement.querySelector( - "[data-mr-pt-api-url]", - ), + ptApiUrl: configElement.querySelector('[data-mr-pt-api-url]'), ptApiBearerToken: configElement.querySelector( - "[data-mr-pt-api-bearer-token]", - ), - titleList: configElement.querySelector( - "[data-mr-title-list]", - ), - subTitle: configElement.querySelector( - "[data-mr-title-current]", - ), - btnAdd: configElement.querySelector( - "[data-mr-title-current-add]", - ), - btnRemove: configElement.querySelector( - "[data-mr-title-current-remove]", - ), - btnSave: configElement.querySelector( - "[data-mr-title-list-save]", - ), - btnReset: configElement.querySelector( - "[data-mr-title-list-reset]", + '[data-mr-pt-api-bearer-token]' ), + titleList: configElement.querySelector('[data-mr-title-list]'), + subTitle: configElement.querySelector('[data-mr-title-current]'), + btnAdd: configElement.querySelector('[data-mr-title-current-add]'), + btnRemove: configElement.querySelector('[data-mr-title-current-remove]'), + btnSave: configElement.querySelector('[data-mr-title-list-save]'), + btnReset: configElement.querySelector('[data-mr-title-list-reset]') }; function escapeRegExp(input: string) { - return input.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&"); + return input.replace(/[.*+\-?^${}()|[\]\\]/g, '\\$&'); } function setLocation(url: string) { window.location = url as string & Location; } function setTitleList() { if (!ui.titleList) return; - ui.titleList.value = globals.titleList.join("\r\n"); + ui.titleList.value = globals.titleList.join('\r\n'); } function setPTUi() { if (ui.ptApiUrl) ui.ptApiUrl.value = globals.ptApi.url; - if (ui.ptApiBearerToken) - ui.ptApiBearerToken.value = globals.ptApi.bearerToken; + if (ui.ptApiBearerToken) ui.ptApiBearerToken.value = globals.ptApi.bearerToken; } function atNeither() { - return globals.at === "neither"; + return globals.at === 'neither'; } function atChapter() { - return globals.at === "chapter"; + return globals.at === 'chapter'; } function atManga() { - return globals.at === "manga"; + return globals.at === 'manga'; } function atChapterOrManga() { return atChapter() || atManga(); } function getChapterList() { - return document.querySelector("div.chapter-list"); + return document.querySelector('div.chapter-list'); } - function setStyle( - arr: NodeListOf, - style: string, - value: string, - ) { + function setStyle(arr: NodeListOf, style: string, value: string) { for (let i = 0; i < arr.length; i++) { const item = arr[i]; if (!item) continue; @@ -601,21 +549,19 @@ async function initMangaReading() { function resize() { if (!atChapter()) return; - const title = "Image Width / %"; + const title = 'Image Width / %'; const height = "'auto h' to fit images to page height,"; const width = "'auto w' to fit images to page width."; const inp = prompt(`${title}\n${height}\n${width}`); const input = inp?.valueOf().toLowerCase(); - if (input === null || input === "0") return; + if (input === null || input === '0') return; const pageWidth = document.body.clientWidth; - const images = document.querySelectorAll( - ".container-chapter-reader img", - ); + const images = document.querySelectorAll('.container-chapter-reader img'); - if (input === "auto w" || input === "w") { + if (input === 'auto w' || input === 'w') { for (let i = 0; i < images.length; i++) { const image = images[i]; if (!image) continue; @@ -625,7 +571,7 @@ async function initMangaReading() { return; } - if (input === "auto h" || input === "h") { + if (input === 'auto h' || input === 'h') { for (let i = 0; i < images.length; i++) { const image = images[i]; if (!image) continue; @@ -645,9 +591,7 @@ async function initMangaReading() { function setSubTitle() { if (!ui.subTitle) return; - ui.subTitle.innerText = atChapterOrManga() - ? globals.currentTitle - : "No title"; + ui.subTitle.innerText = atChapterOrManga() ? globals.currentTitle : 'No title'; } function registerConfig() { @@ -666,7 +610,7 @@ async function initMangaReading() { ui.btnReset.onclick = () => { if (!ui.titleList) return; - ui.titleList.value = globals.titleList.join("\r\n"); + ui.titleList.value = globals.titleList.join('\r\n'); }; ui.btnSave.onclick = () => { @@ -687,21 +631,19 @@ async function initMangaReading() { } function addTitle() { - const trimmedValue = ui.titleList?.value.trim() ?? ""; + const trimmedValue = ui.titleList?.value.trim() ?? ''; const taTitleListValue = trimmedValue.split(/\r?\n/); if (taTitleListValue.includes(globals.currentTitle)) return; - const curTAVal = trimmedValue.length > 0 ? `${trimmedValue}\r\n` : ""; + const curTAVal = trimmedValue.length > 0 ? `${trimmedValue}\r\n` : ''; if (!ui.titleList) return; ui.titleList.value = curTAVal + globals.currentTitle; } async function saveTitles() { - globals.titleList = [ - ...new Set(ui.titleList?.value.trim().split(/\r?\n/).sort()), - ]; + globals.titleList = [...new Set(ui.titleList?.value.trim().split(/\r?\n/).sort())]; await GM.setValue(key.titleList, JSON.stringify(globals.titleList)); if (atChapter()) { @@ -710,27 +652,22 @@ async function initMangaReading() { } async function savePtApi() { - globals.ptApi.url = ui.ptApiUrl?.value.trim() ?? ""; - globals.ptApi.bearerToken = ui.ptApiBearerToken?.value.trim() ?? ""; + globals.ptApi.url = ui.ptApiUrl?.value.trim() ?? ''; + globals.ptApi.bearerToken = ui.ptApiBearerToken?.value.trim() ?? ''; await GM.setValue(key.ptAPi, JSON.stringify(globals.ptApi)); } function removeTitle() { if (!ui.titleList) return; - const curTAVal = ui.titleList.value.trim() ?? ""; - const regex = new RegExp( - `${escapeRegExp(globals.currentTitle)}\\r?\\n?`, - "gi", - ); - ui.titleList.value = curTAVal.replace(regex, ""); + const curTAVal = ui.titleList.value.trim() ?? ''; + const regex = new RegExp(`${escapeRegExp(globals.currentTitle)}\\r?\\n?`, 'gi'); + ui.titleList.value = curTAVal.replace(regex, ''); } function goToFirstChapter() { - const firstChapter = getChapterList() - ?.lastElementChild as HTMLDivElement | null; - const firstChapterLink = - firstChapter?.querySelector("& > span > a"); + const firstChapter = getChapterList()?.lastElementChild as HTMLDivElement | null; + const firstChapterLink = firstChapter?.querySelector('& > span > a'); if (!firstChapterLink) return; @@ -738,10 +675,8 @@ async function initMangaReading() { } function goToLatestChapter() { - const latestChapter = getChapterList() - ?.firstElementChild as HTMLDivElement | null; - const latestChapterLink = - latestChapter?.querySelector("& > span > a"); + const latestChapter = getChapterList()?.firstElementChild as HTMLDivElement | null; + const latestChapterLink = latestChapter?.querySelector('& > span > a'); if (!latestChapterLink) return; setLocation(latestChapterLink.href); @@ -750,38 +685,32 @@ async function initMangaReading() { function removeMargins() { if (!atChapter()) return; - let margin = "5px auto 0"; + let margin = '5px auto 0'; if (globals.titleList.includes(globals.currentTitle)) { - margin = "0 auto"; + margin = '0 auto'; } - setStyle( - document.querySelectorAll(".container-chapter-reader > img"), - "margin", - margin, - ); + setStyle(document.querySelectorAll('.container-chapter-reader > img'), 'margin', margin); } function findUrls() { - console.log("MR - Finding URLs..."); + console.log(`${GM.info.script.name} - Finding URLs...`); - const links = document.querySelectorAll( - "div.breadcrumb > p > span > a", - ); + const links = document.querySelectorAll('div.breadcrumb > p > span > a'); const titleLink = links[1]; - globals.currentTitle = titleLink?.innerText.trim().toLowerCase() ?? "None"; + globals.currentTitle = titleLink?.innerText.trim().toLowerCase() ?? 'None'; setSubTitle(); if (!atChapter() || titleLink === undefined) { - console.log("MR - Found URLs."); + console.log(`${GM.info.script.name} - Found URLs.`); return; } const nextChapterLink = document.querySelector( - ".btn-navigation-chap a.back", + '.btn-navigation-chap a.back' ); if (nextChapterLink) { @@ -791,7 +720,7 @@ async function initMangaReading() { } const prevChapterLink = document.querySelector( - ".btn-navigation-chap a.next", + '.btn-navigation-chap a.next' ); if (prevChapterLink) { @@ -800,68 +729,60 @@ async function initMangaReading() { globals.prevUrl = titleLink.href; } - console.log("MR - Found URLs."); + console.log(`${GM.info.script.name} - Found URLs.`); } async function loadTitleList() { - console.log("MR - Loading title list..."); + console.log(`${GM.info.script.name} - Loading title list...`); - const value = await GM.getValue( - key.titleList, - JSON.stringify({ titleList: [] }), - ); + const value = await GM.getValue(key.titleList, JSON.stringify({ titleList: [] })); - if (typeof value !== "string") { - console.error("Invalid titleList value:", value); + if (typeof value !== 'string') { + console.error('Invalid titleList value:', value); globals.titleList = []; return; } globals.titleList = JSON.parse(value); - console.log("MR - Loaded title list."); + console.log(`${GM.info.script.name} - Loaded title list.`); } async function loadPtApi() { - console.log("MR - Loading progress tracker api..."); + console.log(`${GM.info.script.name} - Loading progress tracker api...`); - const value = await GM.getValue( - key.ptAPi, - JSON.stringify({ url: "", bearerToken: "" }), - ); + const value = await GM.getValue(key.ptAPi, JSON.stringify({ url: '', bearerToken: '' })); - if (typeof value !== "string") { - console.error("Invalid ptApi value:", value); - globals.ptApi = { url: "", bearerToken: "" }; + if (typeof value !== 'string') { + console.error('Invalid ptApi value:', value); + globals.ptApi = { url: '', bearerToken: '' }; return; } globals.ptApi = JSON.parse(value); - console.log("MR - Loaded progress tracker api."); + console.log(`${GM.info.script.name} - Loaded progress tracker api.`); } function manganatoSiteOverrides() { - document.querySelector("body .comments")?.remove(); - document.querySelector("#fb-root")?.remove(); - const div = document.createElement("div"); - div.id = "current-time"; - div.style.display = "none"; + document.querySelector('body .comments')?.remove(); + document.querySelector('#fb-root')?.remove(); + const div = document.createElement('div'); + div.id = 'current-time'; + div.style.display = 'none'; document.body.appendChild(div); - document.querySelector("body > footer")?.remove(); + document.querySelector('body > footer')?.remove(); - const containers = document.querySelectorAll(".ads-contain"); + const containers = document.querySelectorAll('.ads-contain'); containers.forEach((container) => container.remove()); if (atChapter()) { - const chapterContainer = document.querySelector( - ".container-chapter-reader", - ); + const chapterContainer = document.querySelector('.container-chapter-reader'); chapterContainer?.nextSibling?.remove(); chapterContainer?.nextSibling?.remove(); const removables = document.querySelectorAll( - "body > div.info-top-chapter > p.info-top-chapter-text", + 'body > div.info-top-chapter > p.info-top-chapter-text' ); removables.forEach((removable) => removable.remove()); } @@ -872,50 +793,47 @@ async function initMangaReading() { } function siteOverrides() { - console.log("MR - Applying site overrides..."); + console.log(`${GM.info.script.name} - Applying site overrides...`); manganatoSiteOverrides(); - console.log("MR - Applied site overrides."); + console.log(`${GM.info.script.name} - Applied site overrides.`); } function setAt() { const path = window.location.pathname; - const atChapter = new RegExp(/\/manga\/[\w.\-~%]+\/chapter-[\d.-]+/).test( - path, - ); + const atChapter = new RegExp(/\/manga\/[\w.\-~%]+\/chapter-[\d.-]+/).test(path); const atManga = new RegExp(/\/manga\/[\w.\-~%]+$/).test(path); - console.log("MR - Setting at...", { atChapter, atManga }); + console.log(`${GM.info.script.name} - Setting at...`, { atChapter, atManga }); - if (atChapter) globals.at = "chapter"; - else if (atManga) globals.at = "manga"; - else globals.at = "neither"; + if (atChapter) globals.at = 'chapter'; + else if (atManga) globals.at = 'manga'; + else globals.at = 'neither'; } let genreAllItems: NodeListOf; let genreAllItemsIndex = 0; - const genreAllActiveItemClass = "mr-genre-all-active-item"; + const genreAllActiveItemClass = 'mr-genre-all-active-item'; function genreAllGoToPage(direction: string) { const pageSelected = document.querySelector( - ".panel_page_number > .group_page > a.page_select", + '.panel_page_number > .group_page > a.page_select' ); - console.log("pageSelected", pageSelected); + console.log('pageSelected', pageSelected); if (!pageSelected) return; - const previous = - pageSelected.previousElementSibling as HTMLAnchorElement | null; + const previous = pageSelected.previousElementSibling as HTMLAnchorElement | null; const next = pageSelected.nextElementSibling as HTMLAnchorElement | null; switch (direction) { - case "ArrowLeft": - if (!previous || previous.classList.contains("page_blue")) return; + case 'ArrowLeft': + if (!previous || previous.classList.contains('page_blue')) return; setLocation(previous.href); break; - case "ArrowRight": - if (!next || next.classList.contains("page_blue")) return; + case 'ArrowRight': + if (!next || next.classList.contains('page_blue')) return; setLocation(next.href); break; } @@ -923,7 +841,7 @@ async function initMangaReading() { function genreAllSetFirstActive() { genreAllItems = document.querySelectorAll( - "div.truyen-list > div.list-truyen-item-wrap", + 'div.truyen-list > div.list-truyen-item-wrap' ); if (genreAllItems.length > 0) { @@ -934,9 +852,7 @@ async function initMangaReading() { function genreAllOpenMangaInNewTab() { const anchor = - genreAllItems[genreAllItemsIndex]?.querySelector( - ".list-story-item", - ); + genreAllItems[genreAllItemsIndex]?.querySelector('.list-story-item'); if (!anchor) return; @@ -945,51 +861,35 @@ async function initMangaReading() { function genreAllBrowse(direction: string) { switch (direction) { - case "ArrowUp": + case 'ArrowUp': if (genreAllItemsIndex < 2) return; - genreAllItems[genreAllItemsIndex]?.classList.remove( - genreAllActiveItemClass, - ); + genreAllItems[genreAllItemsIndex]?.classList.remove(genreAllActiveItemClass); genreAllItemsIndex = genreAllItemsIndex - 2; - genreAllItems[genreAllItemsIndex]?.classList.add( - genreAllActiveItemClass, - ); + genreAllItems[genreAllItemsIndex]?.classList.add(genreAllActiveItemClass); break; - case "ArrowDown": + case 'ArrowDown': if (genreAllItemsIndex + 2 > genreAllItems.length - 1) return; - genreAllItems[genreAllItemsIndex]?.classList.remove( - genreAllActiveItemClass, - ); + genreAllItems[genreAllItemsIndex]?.classList.remove(genreAllActiveItemClass); genreAllItemsIndex = genreAllItemsIndex + 2; - genreAllItems[genreAllItemsIndex]?.classList.add( - genreAllActiveItemClass, - ); + genreAllItems[genreAllItemsIndex]?.classList.add(genreAllActiveItemClass); break; - case "ArrowLeft": + case 'ArrowLeft': if (genreAllItemsIndex === 0) return; - genreAllItems[genreAllItemsIndex]?.classList.remove( - genreAllActiveItemClass, - ); + genreAllItems[genreAllItemsIndex]?.classList.remove(genreAllActiveItemClass); genreAllItemsIndex = genreAllItemsIndex - 1; - genreAllItems[genreAllItemsIndex]?.classList.add( - genreAllActiveItemClass, - ); + genreAllItems[genreAllItemsIndex]?.classList.add(genreAllActiveItemClass); break; - case "ArrowRight": + case 'ArrowRight': if (genreAllItemsIndex === genreAllItems.length - 1) return; - genreAllItems[genreAllItemsIndex]?.classList.remove( - genreAllActiveItemClass, - ); + genreAllItems[genreAllItemsIndex]?.classList.remove(genreAllActiveItemClass); genreAllItemsIndex = genreAllItemsIndex + 1; - genreAllItems[genreAllItemsIndex]?.classList.add( - genreAllActiveItemClass, - ); + genreAllItems[genreAllItemsIndex]?.classList.add(genreAllActiveItemClass); break; } genreAllItems[genreAllItemsIndex]?.scrollIntoView({ - behavior: "smooth", - block: "center", + behavior: 'smooth', + block: 'center' }); window.getSelection()?.removeAllRanges(); @@ -997,9 +897,9 @@ async function initMangaReading() { function parseHeaders(headersString: string) { const headers = new Headers(); - const arr = headersString.trim().split("\n"); + const arr = headersString.trim().split('\n'); for (const header of arr) { - const [key, value] = header.split(":"); + const [key, value] = header.split(':'); if (!key || !value) continue; headers.append(key, value); } @@ -1008,19 +908,19 @@ async function initMangaReading() { async function nwsFetch( input: string | URL | globalThis.Request, - init: RequestInit | undefined = undefined, + init: RequestInit | undefined = undefined ) { - const method = init?.method ?? "GET"; + const method = init?.method ?? 'GET'; const headers: { [key: string]: string } = - method !== "GET" ? { "content-type": "application/json" } : {}; + method !== 'GET' ? { 'content-type': 'application/json' } : {}; if (init?.headers !== undefined) { if (init.headers instanceof Headers) { init.headers.forEach((value, key) => { headers[key.toLowerCase()] = value; }); - } else if (typeof init.headers === "object") { + } else if (typeof init.headers === 'object') { for (const [key, value] of Object.entries(init.headers)) { headers[key.toLowerCase()] = value; } @@ -1032,9 +932,9 @@ async function initMangaReading() { method, headers, timeout: 5000, - responseType: "json", + responseType: 'json', anonymous: true, - data: init?.body ?? undefined, + data: init?.body ?? undefined }); const respHeaders = parseHeaders(resp.responseHeaders); @@ -1042,7 +942,7 @@ async function initMangaReading() { return new Response(resp.responseText, { status: resp.status, statusText: resp.statusText, - headers: respHeaders, + headers: respHeaders }); } @@ -1050,45 +950,42 @@ async function initMangaReading() { async function query( options: { input: string; headers: HeadersInit }, - q: string | undefined = undefined, + q: string | undefined = undefined ): Promise { try { const input = q !== undefined ? `${options.input}?q=${q}` : options.input; const response = await nwsFetch(input, { - method: "GET", - headers: options.headers, + method: 'GET', + headers: options.headers }); if (!response.ok) { - console.error("Failed to fetch bookmarks"); + console.error('Failed to fetch bookmarks'); return []; } return response.json(); } catch (e) { - console.error("Failed to fetch bookmarks"); + console.error('Failed to fetch bookmarks'); console.error(e); return []; } } - async function remove( - options: { input: string; headers: HeadersInit }, - id: number, - ) { + async function remove(options: { input: string; headers: HeadersInit }, id: number) { try { const response = await nwsFetch(`${options.input}/${id}`, { - method: "DELETE", - headers: options.headers, + method: 'DELETE', + headers: options.headers }); if (!response.ok) { - console.error("Failed to delete bookmark"); + console.error('Failed to delete bookmark'); return false; } return true; } catch (e) { - console.error("Failed to delete bookmarks"); + console.error('Failed to delete bookmarks'); console.error(e); return false; } @@ -1096,33 +993,32 @@ async function initMangaReading() { async function createOrUpdate( options: { input: string; headers: HeadersInit }, - body: { name: string; href: string }, + body: { name: string; href: string } ) { try { - console.log("MR - Creating or updating bookmark", options.input, body); + console.log(`${GM.info.script.name} - Creating or updating bookmark`, options.input, body); const response = await nwsFetch(options.input, { - method: "PUT", + method: 'PUT', body: JSON.stringify(body), - headers: options.headers, + headers: options.headers }); if (!response.ok) { - console.error("MR - Failed to create or update bookmark"); + console.error(`${GM.info.script.name} - Failed to create or update bookmark`); return { success: false, created: false }; } try { - const json: { success: boolean; created: boolean } = - await response.json(); + const json: { success: boolean; created: boolean } = await response.json(); json.success = true; return json; } catch (e) { - console.error("MR - Failed to parse response"); + console.error(`${GM.info.script.name} - Failed to parse response`); console.error(e); return { success: false, created: false }; } } catch (e) { - console.error("MR - Failed to create or update bookmarks"); + console.error(`${GM.info.script.name} - Failed to create or update bookmarks`); console.error(e); return { success: false, created: false }; } @@ -1131,24 +1027,21 @@ async function initMangaReading() { async function check( options: { input: string; headers: HeadersInit }, id: number, - finished: boolean, + finished: boolean ) { try { - const response = await nwsFetch( - `${options.input}/${id}/check/${finished}`, - { - method: "PUT", - headers: options.headers, - }, - ); + const response = await nwsFetch(`${options.input}/${id}/check/${finished}`, { + method: 'PUT', + headers: options.headers + }); if (!response.ok) { - console.error("MR - Failed to check bookmark"); + console.error(`${GM.info.script.name} - Failed to check bookmark`); return false; } return true; } catch (e) { - console.error("MR - Failed to check bookmark"); + console.error(`${GM.info.script.name} - Failed to check bookmark`); console.error(e); return false; } @@ -1159,12 +1052,12 @@ async function initMangaReading() { const input = `${baseUrl}/bookmarks`; const bearerToken = globals.ptApi.bearerToken; const noBodyHeaders = new Headers({ - "Content-Type": "application/json", - Authorization: `Bearer ${bearerToken}`, + 'Content-Type': 'application/json', + Authorization: `Bearer ${bearerToken}` }); const bodyHeaders = new Headers({ - "Content-Type": "application/json", - Authorization: `Bearer ${bearerToken}`, + 'Content-Type': 'application/json', + Authorization: `Bearer ${bearerToken}` }); return { baseUrl, input, bearerToken, noBodyHeaders, bodyHeaders }; @@ -1201,19 +1094,17 @@ async function initMangaReading() { }) { const notification = getNotificationElement(); - const title = notification.querySelector("[data-title]"); - const description = - notification.querySelector("[data-description]"); - const content = - notification.querySelector("[data-content]"); + const title = notification.querySelector('[data-title]'); + const description = notification.querySelector('[data-description]'); + const content = notification.querySelector('[data-content]'); if (title === null || description === null || content === null) { - console.error("MR - Notification elements not found."); + console.error(`${GM.info.script.name} - Notification elements not found.`); return; } title.innerText = options.title; - description.innerText = options.description ?? ""; + description.innerText = options.description ?? ''; if (Array.isArray(options.buttons)) { for (const button of options.buttons) { @@ -1256,10 +1147,10 @@ async function initMangaReading() { if (!chapterOrManga) return; - if (globals.ptApi.url === "" || globals.ptApi.bearerToken === "") { + if (globals.ptApi.url === '' || globals.ptApi.bearerToken === '') { triggerNotification({ - title: "Configuration Error", - description: "Progress Tracker API URL and Bearer Token must be set.", + title: 'Configuration Error', + description: 'Progress Tracker API URL and Bearer Token must be set.' }); return; } @@ -1278,16 +1169,16 @@ async function initMangaReading() { const id = bookmarks[0].id; await remove({ input, headers: bodyHeaders }, id); triggerNotification({ - title: "Bookmark Removed", - description: title, + title: 'Bookmark Removed', + description: title }); } else { const bookmark = bookmarks.find((b) => b.name === title); if (bookmark === undefined) { triggerNotification({ - title: "No bookmark found for title.", - description: title, + title: 'No bookmark found for title.', + description: title }); return; } @@ -1297,8 +1188,8 @@ async function initMangaReading() { const id = bookmark.id; await remove({ input, headers: bodyHeaders }, id); triggerNotification({ - title: "Bookmark Removed", - description: title, + title: 'Bookmark Removed', + description: title }); } } @@ -1310,10 +1201,10 @@ async function initMangaReading() { if (!chapterOrManga) return; - if (globals.ptApi.url === "" || globals.ptApi.bearerToken === "") { + if (globals.ptApi.url === '' || globals.ptApi.bearerToken === '') { triggerNotification({ - title: "Configuration Error", - description: "Progress Tracker API URL and Bearer Token must be set.", + title: 'Configuration Error', + description: 'Progress Tracker API URL and Bearer Token must be set.' }); return; } @@ -1323,7 +1214,7 @@ async function initMangaReading() { const body: { name: string; href: string } = { name: title.trim().toLocaleLowerCase(), - href: window.location.href, + href: window.location.href }; const result = await createOrUpdate({ input, headers: bodyHeaders }, body); @@ -1331,8 +1222,8 @@ async function initMangaReading() { if (!result.success) return; triggerNotification({ - title: `Bookmark ${result.created ? "created" : "updated"}`, - description: title, + title: `Bookmark ${result.created ? 'created' : 'updated'}`, + description: title }); } @@ -1341,144 +1232,128 @@ async function initMangaReading() { const manga = atManga(); const chapterOrManga = chapter || manga; - if (e.code === "ArrowLeft" && shortcutHelpers.noModifier(e) && chapter) { + if (e.code === 'ArrowLeft' && shortcutHelpers.noModifier(e) && chapter) { setLocation(globals.prevUrl); return true; } - if (e.code === "ArrowLeft" && shortcutHelpers.noModifier(e) && manga) { + if (e.code === 'ArrowLeft' && shortcutHelpers.noModifier(e) && manga) { goToLatestChapter(); return true; } if ( - e.code === "ArrowLeft" && + e.code === 'ArrowLeft' && shortcutHelpers.noModifier(e) && !chapterOrManga && - (window.location.pathname.startsWith("/genre/all") || - window.location.pathname.startsWith("/manga-list/latest-manga")) + (window.location.pathname.startsWith('/genre/all') || + window.location.pathname.startsWith('/manga-list/latest-manga')) ) { genreAllGoToPage(e.code); return true; } - if (e.code === "ArrowRight" && shortcutHelpers.noModifier(e) && chapter) { + if (e.code === 'ArrowRight' && shortcutHelpers.noModifier(e) && chapter) { setLocation(globals.nextUrl); return true; } - if (e.code === "ArrowRight" && shortcutHelpers.noModifier(e) && manga) { + if (e.code === 'ArrowRight' && shortcutHelpers.noModifier(e) && manga) { goToFirstChapter(); return true; } if ( - e.code === "ArrowRight" && + e.code === 'ArrowRight' && shortcutHelpers.noModifier(e) && !chapterOrManga && - (window.location.pathname.startsWith("/genre/all") || - window.location.pathname.startsWith("/manga-list/latest-manga")) + (window.location.pathname.startsWith('/genre/all') || + window.location.pathname.startsWith('/manga-list/latest-manga')) ) { genreAllGoToPage(e.code); return true; } if ( - e.code === "ArrowUp" && + e.code === 'ArrowUp' && shortcutHelpers.shiftModifier(e) && !chapterOrManga && - (window.location.pathname.startsWith("/genre/all") || - window.location.pathname.startsWith("/manga-list/latest-manga")) + (window.location.pathname.startsWith('/genre/all') || + window.location.pathname.startsWith('/manga-list/latest-manga')) ) { genreAllBrowse(e.code); return true; } if ( - e.code === "ArrowDown" && + e.code === 'ArrowDown' && shortcutHelpers.shiftModifier(e) && !chapterOrManga && - (window.location.pathname.startsWith("/genre/all") || - window.location.pathname.startsWith("/manga-list/latest-manga")) + (window.location.pathname.startsWith('/genre/all') || + window.location.pathname.startsWith('/manga-list/latest-manga')) ) { genreAllBrowse(e.code); return true; } if ( - e.code === "ArrowLeft" && + e.code === 'ArrowLeft' && shortcutHelpers.shiftModifier(e) && !chapterOrManga && - (window.location.pathname.startsWith("/genre/all") || - window.location.pathname.startsWith("/manga-list/latest-manga")) + (window.location.pathname.startsWith('/genre/all') || + window.location.pathname.startsWith('/manga-list/latest-manga')) ) { genreAllBrowse(e.code); return true; } if ( - e.code === "ArrowRight" && + e.code === 'ArrowRight' && shortcutHelpers.shiftModifier(e) && !chapterOrManga && - (window.location.pathname.startsWith("/genre/all") || - window.location.pathname.startsWith("/manga-list/latest-manga")) + (window.location.pathname.startsWith('/genre/all') || + window.location.pathname.startsWith('/manga-list/latest-manga')) ) { genreAllBrowse(e.code); return true; } if ( - e.code === "Enter" && + e.code === 'Enter' && shortcutHelpers.shiftModifier(e) && !chapterOrManga && - (window.location.pathname.startsWith("/genre/all") || - window.location.pathname.startsWith("/manga-list/latest-manga")) + (window.location.pathname.startsWith('/genre/all') || + window.location.pathname.startsWith('/manga-list/latest-manga')) ) { genreAllOpenMangaInNewTab(); return true; } - if (e.code === "Quote" && shortcutHelpers.shiftModifier(e) && chapter) { + if (e.code === 'Quote' && shortcutHelpers.shiftModifier(e) && chapter) { resize(); return true; } - if ( - e.code === "BracketLeft" && - shortcutHelpers.shiftModifier(e) && - chapterOrManga - ) { + if (e.code === 'BracketLeft' && shortcutHelpers.shiftModifier(e) && chapterOrManga) { setTitleList(); removeTitle(); await saveTitles(); return true; } - if ( - e.code === "BracketRight" && - shortcutHelpers.shiftModifier(e) && - chapterOrManga - ) { + if (e.code === 'BracketRight' && shortcutHelpers.shiftModifier(e) && chapterOrManga) { setTitleList(); addTitle(); await saveTitles(); return true; } - if ( - e.code === "BracketLeft" && - shortcutHelpers.altModifier(e) && - chapterOrManga - ) { + if (e.code === 'BracketLeft' && shortcutHelpers.altModifier(e) && chapterOrManga) { setTimeout(removeMangaFromProgressTracker, 0); return true; } - if ( - e.code === "BracketRight" && - shortcutHelpers.altModifier(e) && - chapterOrManga - ) { + if (e.code === 'BracketRight' && shortcutHelpers.altModifier(e) && chapterOrManga) { setTimeout(updateOrAddMangaToProgressTracker, 0); return true; } @@ -1487,28 +1362,28 @@ async function initMangaReading() { } function registerKeyUps() { - mr?.shortcut.keyUp.register("ConfigClosed", { + mr?.shortcut.keyUp.register('ConfigClosed', { name: `${GM.info.script.name} - config closed`, - callback: configClosedShortcuts, + callback: configClosedShortcuts }); } async function checkFirstRun() { - console.log("MR - First run check..."); + console.log(`${GM.info.script.name} - First run check...`); const value = await GM.getValue(key.firstRun, true); if (value) { - console.log("MR - First run detected."); + console.log(`${GM.info.script.name} - First run detected.`); GM.setValue(key.firstRun, false); GM.notification( - "First run setup complete", - `MR - ${GM.info.script.name}`, + 'First run setup complete', + `${GM.info.script.name} - ${GM.info.script.name}` ); } - console.log("MR - First run checked."); + console.log(`${GM.info.script.name} - First run checked.`); } async function onInit() { - console.log(`MR - ${GM.info.script.name} - Loading...`); + console.log(`${GM.info.script.name} - ${GM.info.script.name} - Loading...`); await checkFirstRun(); registerKeyUps(); setAt(); @@ -1519,15 +1394,15 @@ async function initMangaReading() { removeMargins(); } siteOverrides(); - console.log(`MR - ${GM.info.script.name} - Loaded.`); + console.log(`${GM.info.script.name} - ${GM.info.script.name} - Loaded.`); } async function postInit() { - console.log(`MR - ${GM.info.script.name} - Post Loading...`); + console.log(`${GM.info.script.name} - ${GM.info.script.name} - Post Loading...`); initToastContainer(); insertToastContainer(); - loadStyle("stylesheet", false, shadowRoot); - loadStyle("overrides", true, shadowRoot); - console.log(`MR - ${GM.info.script.name} - Post Loaded.`); + loadStyle('stylesheet', false, shadowRoot); + loadStyle('overrides', true, shadowRoot); + console.log(`${GM.info.script.name} - ${GM.info.script.name} - Post Loaded.`); } registerConfig();