فهرست منبع

Merge branch 'develop' of https://github.com/Sv443/BetterYTM into develop

Sven 3 سال پیش
والد
کامیت
eb7cf84ff1

+ 5 - 0
.vscode/settings.json

@@ -0,0 +1,5 @@
+{
+    "[markdown]": {
+        "editor.formatOnSave": false,
+    }
+}

+ 315 - 60
BetterYTM.user.js

@@ -1,6 +1,5 @@
 // ==UserScript==
 // @name            BetterYTM
-// @name:de         BetterYTM
 // @namespace       https://github.com/Sv443/BetterYTM#readme
 // @version         1.0.0
 // @license         MIT
@@ -10,7 +9,7 @@
 // @description:de  Verbesserungen für YouTube Music
 // @match           https://music.youtube.com/*
 // @match           https://www.youtube.com/*
-// @icon            https://www.google.com/s2/favicons?domain=music.youtube.com
+// @icon            https://raw.githubusercontent.com/Sv443/BetterYTM/main/resources/icon/v2.1_200.png
 // @run-at          document-start
 // @grant           GM.getValue
 // @grant           GM.setValue
@@ -27,36 +26,74 @@
 /* C&D this, Susan 🖕 */
 
 
-(async () => {
 "use-strict";
 
-
+(async () => {
 /** Set to true to enable debug mode for more output in the JS console */
 const dbg = true;
 
-
-const defaultFeatures = {
-    /** Whether arrow keys should skip forwards and backwards by 10 seconds */
-    arrowKeySupport: true,
-    /** Whether to remove the "Upgrade" / YT Music Premium tab */
-    removeUpgradeTab: true,
-
-    /** Whether to add a key combination to switch between the YT and YTM sites on a video */
-    switchBetweenSites: true,
-    /** Adds a button to the media controls bar to search for the current song's lyrics on genius.com in a new tab */
-    geniusLyrics: true,
-    /** Adds a lyrics button to each song in the queue ("up next" tab) */
-    lyricsButtonsOnSongQueue: true,
-
-    /** Set to true to remove the watermark under the YTM logo */
-    removeWatermark: false,
+// const branch = "main";
+const branch = "develop"; // #DEBUG#
+
+const featInfo = {
+    arrowKeySupport: {
+        desc: "Arrow keys should skip forwards and backwards by 10 seconds?",
+        type: "toggle",
+        default: true,
+    },
+    removeUpgradeTab: {
+        desc: "Remove the \"Upgrade\" / YT Music Premium tab?",
+        type: "toggle",
+        default: true,
+    },
+    switchBetweenSites: {
+        desc: "Add F9 as a hotkey to switch between the YT and YTM sites on a video / song?",
+        type: "toggle",
+        default: true,
+    },
+    geniusLyrics: {
+        desc: "Add a button to the media controls bar to search for the current song's lyrics on genius.com in a new tab?",
+        type: "toggle",
+        default: true,
+    },
+    lyricsButtonsOnSongQueue: {
+        desc: "TODO: Add a lyrics button to each song in the queue (\"up next\" tab)?",
+        type: "toggle",
+        default: true,
+    },
+    volumeSliderSize: {
+        desc: "The width of the volume slider in px",
+        type: "number",
+        min: 10,
+        max: 1000,
+        default: 175,
+    },
+    volumeSliderStep: {
+        desc: "Volume slider sensitivity - the smaller this number, the finer the volume control",
+        type: "slider",
+        min: 1,
+        max: 20,
+        default: 2,
+    },
+    removeWatermark: {
+        desc: "Remove the watermark under the YTM logo?",
+        type: "toggle",
+        default: false,
+    },
 };
 
+/** @type {FeatureConfig} */
+const defaultFeatures = Object.keys(featInfo).reduce((acc, key) => {
+    acc[key] = featInfo[key].default;
+    return acc;
+}, {});
+
 const featureConf = await loadFeatureConf();
 
 console.log("bytm load", featureConf);
 
 const features = { ...defaultFeatures, ...featureConf };
+// const features = { ...defaultFeatures };
 
 console.log("bytm save", features);
 
@@ -68,6 +105,8 @@ await saveFeatureConf(features);
 
 /** @typedef {"yt"|"ytm"} Domain Constant string representation of which domain this script is currently running on */
 
+/** @typedef {typeof defaultFeatures} FeatureConfig */
+
 
 //#MARKER init
 
@@ -76,10 +115,10 @@ await saveFeatureConf(features);
 const triesLimit = 40;
 
 /** Base URL of geniURL */
-const geniURLBaseUrl = "https://api.sv443.net/geniurl";
+const geniUrlBase = "https://api.sv443.net/geniurl";
 
 /** GeniURL endpoint that gives song metadata when provided with a `?q` parameter - [more info](https://api.sv443.net/geniurl) */
-const geniURLSearchTopUrl = `${geniURLBaseUrl}/search/top`;
+const geniURLSearchTopUrl = `${geniUrlBase}/search/top`;
 
 const info = Object.freeze({
     name: GM.info.script.name, // eslint-disable-line no-undef
@@ -92,7 +131,7 @@ function init()
     try
     {
         console.log(`${info.name} v${info.version} - ${info.namespace}`);
-        console.log(`Powered by lots of ambition and my song metadata API called geniURL: ${geniURLBaseUrl}`);
+        console.log(`Powered by lots of ambition and my song metadata API called geniURL: ${geniUrlBase}`);
 
         document.addEventListener("DOMContentLoaded", onDomLoad);
     }
@@ -136,6 +175,11 @@ async function onDomLoad()
 
             if(features.lyricsButtonsOnSongQueue)
                 await addQueueGeniusBtns();
+
+            if(typeof features.volumeSliderSize === "number")
+                setVolSliderSize(features.volumeSliderSize);
+
+            setVolSliderStep();
         }
 
         if(["ytm", "yt"].includes(domain))
@@ -188,15 +232,19 @@ function addMenu()
     const menuContainer = document.createElement("div");
     menuContainer.title = "";
     menuContainer.id = "betterytm-menu";
+    menuContainer.style.borderRadius = "15px";
 
 
     // title
     const titleCont = document.createElement("div");
+    titleCont.style.padding = "8px 20px 20px 8px";
+    titleCont.style.display = "flex";
+    titleCont.style.justifyContent = "space-between";
     titleCont.id = "betterytm-menu-titlecont";
 
     const titleElem = document.createElement("h2");
     titleElem.id = "betterytm-menu-title";
-    titleElem.innerText = "BetterYTM - Menu";
+    titleElem.innerText = "BetterYTM - Configuration";
 
     const linksCont = document.createElement("div");
     linksCont.id = "betterytm-menu-linkscont";
@@ -208,32 +256,185 @@ function addMenu()
         anchorElem.target = "_blank";
         anchorElem.href = href;
         anchorElem.title = title;
-
-        const linkElem = document.createElement("img");
-        linkElem.className = "betterytm-menu-img";
-        linkElem.src = imgSrc;
-
-        anchorElem.appendChild(linkElem);
+        anchorElem.style.marginLeft = "10px";
+        
+        const imgElem = document.createElement("img");
+        imgElem.className = "betterytm-menu-img";
+        imgElem.src = imgSrc;
+        imgElem.style.width = "32px";
+        imgElem.style.height = "32px";
+
+        anchorElem.appendChild(imgElem);
         linksCont.appendChild(anchorElem);
     };
 
-    addLink("TODO:github.png", info.namespace, `${info.name} on GitHub`);
-    addLink("TODO:greasyfork.png", "https://greasyfork.org/", `${info.name} on GreasyFork`);
+    addLink(`https://raw.githubusercontent.com/Sv443/BetterYTM/${branch}/resources/external/github.png`, info.namespace, `${info.name} on GitHub`);
+    addLink(`https://raw.githubusercontent.com/Sv443/BetterYTM/${branch}/resources/external/greasyfork.png`, "https://greasyfork.org/xyz", `${info.name} on GreasyFork`);
 
     const closeElem = document.createElement("img");
     closeElem.id = "betterytm-menu-close";
-    closeElem.src = "TODO:close.png";
+    closeElem.src = `https://raw.githubusercontent.com/Sv443/BetterYTM/${branch}/resources/icon/close.png`;
     closeElem.title = "Click to close the menu";
+    closeElem.style.marginLeft = "50px";
+    closeElem.style.width = "32px";
+    closeElem.style.height = "32px";
     closeElem.addEventListener("click", closeMenu);
 
+    linksCont.appendChild(closeElem);
+
     titleCont.appendChild(titleElem);
     titleCont.appendChild(linksCont);
-    titleCont.appendChild(closeElem);
 
 
     // TODO: features
     const featuresCont = document.createElement("div");
     featuresCont.id = "betterytm-menu-opts";
+    featuresCont.style.display = "flex";
+    featuresCont.style.flexDirection = "column";
+
+    /**
+     * Gets called whenever the feature config is changed
+     * @param {keyof typeof defaultFeatures} key
+     * @param {number|boolean} initialVal
+     * @param {number|boolean} newVal
+     */
+    const confChanged = async (key, initialVal, newVal) => {
+        dbg && console.info(`BetterYTM: Feature config changed, key '${key}' from value '${initialVal}' to '${newVal}'`);
+
+        /** @type {FeatureConfig} */
+        const featConf = {...(await loadFeatureConf())};
+
+        featConf[key] = newVal;
+
+        await saveFeatureConf(featConf);
+
+        dbg && console.log("BetterYTM: Saved feature config changes");
+
+        console.log("#DEBUG", await GM.getValue("bytm-config")); // eslint-disable-line no-undef
+    };
+
+    const featKeys = Object.keys(features);
+    for(const key of featKeys)
+    {
+        const ftInfo = featInfo[key];
+
+        if(!ftInfo)
+            continue;
+
+        const { desc, type, default: ftDef } = ftInfo;
+        const val = features[key];
+
+        const initialVal = val || ftDef;
+
+        const ftConfElem = document.createElement("div");
+        ftConfElem.id = `bytm-ftconf-${key}`;
+        ftConfElem.style.display = "flex";
+        ftConfElem.style.flexDirection = "row";
+        ftConfElem.style.justifyContent = "space-between";
+        ftConfElem.style.padding = "8px 20px";
+
+        {
+            const textElem = document.createElement("span");
+            textElem.style.display = "inline-block";
+            textElem.style.fontSize = "15px";
+            textElem.innerText = desc;
+
+            ftConfElem.appendChild(textElem);
+        }
+
+        {
+            let inputType;
+            switch(type)
+            {
+                case "toggle":
+                    inputType = "checkbox";
+                    break;
+                case "slider":
+                    inputType = "range";
+                    break;
+                case "number":
+                    inputType = "number";
+                    break;
+            }
+
+            const inputElemId = `bytm-ftconf-${key}-input`;
+
+            const ctrlElem = document.createElement("span");
+            ctrlElem.style.display = "inline-block";
+            ctrlElem.style.whiteSpace = "nowrap";
+
+            const inputElem = document.createElement("input");
+            inputElem.id = inputElemId;
+            inputElem.style.marginRight = "20px";
+            inputElem.type = inputType;
+            inputElem.value = initialVal;
+
+            if(ftInfo.min && ftInfo.max)
+            {
+                inputElem.min = ftInfo.min;
+                inputElem.max = ftInfo.max;
+            }
+
+            if(type === "toggle")
+                inputElem.checked = initialVal;
+
+            const fmtVal = v => String(v);
+
+            let labelElem;
+            if(type === "slider")
+            {
+                labelElem = document.createElement("label");
+                labelElem.style.marginRight = "20px";
+                labelElem.style.fontSize = "16px";
+                labelElem["for"] = inputElemId;
+                labelElem.innerText = fmtVal(initialVal);
+
+                inputElem.addEventListener("change", () => labelElem.innerText = fmtVal(parseInt(inputElem.value)));
+            }
+
+            inputElem.addEventListener("change", ({ currentTarget }) => {
+                let v = parseInt(currentTarget.value);
+                if(isNaN(v))
+                    v = currentTarget.value;
+                confChanged(key, initialVal, (type !== "toggle" ? v : currentTarget.checked));
+            });
+
+            const resetElem = document.createElement("button");
+            resetElem.innerText = "Reset";
+            resetElem.addEventListener("click", () => {
+                inputElem[type !== "toggle" ? "value" : "checked"] = ftDef;
+
+                if(labelElem)
+                    labelElem.innerText = fmtVal(parseInt(inputElem.value));
+
+                confChanged(key, initialVal, ftDef);
+            });
+
+            labelElem && ctrlElem.appendChild(labelElem);
+            ctrlElem.appendChild(inputElem);
+            ctrlElem.appendChild(resetElem);
+
+            ftConfElem.appendChild(ctrlElem);
+        }
+
+        featuresCont.appendChild(ftConfElem);
+    }
+
+    const footerElem = document.createElement("div");
+    footerElem.style.marginTop = "40px";
+    footerElem.style.fontSize = "17px";
+    footerElem.style.textDecoration = "underline";
+    footerElem.style.padding = "8px 20px";
+    footerElem.innerText = "You need to reload the page to apply changes.";
+
+    const reloadElem = document.createElement("button");
+    reloadElem.style.marginLeft = "20px";
+    reloadElem.innerText = "Reload now";
+    reloadElem.title = "Click to reload the page";
+    reloadElem.addEventListener("click", () => location.reload());
+
+    footerElem.appendChild(reloadElem);
+    featuresCont.appendChild(footerElem);
 
 
     // finalize
@@ -261,7 +462,7 @@ function addMenu()
         display: inline-block;
         position: fixed;
         width: 50vw;
-        height: 50vh;
+        height: auto;
         min-height: 500px;
         left: 25vw;
         top: 25vh;
@@ -301,7 +502,7 @@ function addMenu()
 
     dbg && console.log("BetterYTM: Added menu elem:", backgroundElem);
 
-    /* #DEBUG */ //openMenu();
+    /* #DEBUG */ openMenu();
 
     addGlobalStyle(menuStyle, "menu");
 }
@@ -314,13 +515,13 @@ function closeMenu()
     menuBg.style.display = "none";
 }
 
-// function openMenu()
-// {
-//     const menuBg = document.querySelector("#betterytm-menu-bg");
+function openMenu()
+{
+    const menuBg = document.querySelector("#betterytm-menu-bg");
 
-//     menuBg.style.visibility = "visible";
-//     menuBg.style.display = "block";
-// }
+    menuBg.style.visibility = "visible";
+    menuBg.style.display = "block";
+}
 
 
 //#MARKER features
@@ -495,24 +696,22 @@ function removeUpgradeTab()
 function addWatermark()
 {
     const watermark = document.createElement("a");
-
     watermark.id = "betterytm-watermark";
     watermark.className = "style-scope ytmusic-nav-bar";
-
     watermark.innerText = info.name;
-    watermark.title = `${info.name} v${info.version}`;
+    watermark.title = "Open menu";
+    watermark.href = "#";
 
-    watermark.href = info.namespace;
-    watermark.target = "_blank";
-    watermark.rel = "noopener noreferrer";
+    watermark.addEventListener("click", () => openMenu());
 
 
     const style = `\
     #betterytm-watermark {
+        font-size: 10px;
         display: inline-block;
         position: absolute;
         left: 45px;
-        top: 43px;
+        top: 46px;
         z-index: 10;
         color: white;
         text-decoration: none;
@@ -665,8 +864,6 @@ async function addQueueGeniusBtns()
  */
 async function getCurrentGeniusUrl()
 {
-    return null; //#DEBUG TODO: test how button reacts to API error
-
     try
     {
         // In videos the video title contains both artist and song title, in "regular" YTM songs, the video title only contains the song title
@@ -758,6 +955,35 @@ async function getGeniusUrl(query)
     }
 }
 
+// #SECTION volume slider
+
+/**
+ * Sets the volume slider to a set size
+ */
+function setVolSliderSize()
+{
+    const { volumeSliderSize: size } = features;
+
+    if(typeof size !== "number" || isNaN(parseInt(size)))
+        return;
+
+const style = `\
+.volume-slider.ytmusic-player-bar, .expand-volume-slider.ytmusic-player-bar {
+    width: ${size}px !important;
+}`;
+
+    addGlobalStyle(style, "vol_slider_size");
+}
+
+/**
+ * Sets the `step` attribute of the volume slider
+ */
+function setVolSliderStep()
+{
+    const sliderElem = document.querySelector("tp-yt-paper-slider#volume-slider");
+
+    sliderElem.setAttribute("step", features.volumeSliderStep);
+}
 
 //#MARKER other
 
@@ -820,14 +1046,17 @@ function insertAfter(beforeNode, afterNode)
 }
 
 /**
- * Adds global CSS style through a <style> element in the document's <head>
+ * Adds global CSS style through a `<style>` element in the document's `<head>`
  * @param {string} style CSS string
- * @param {string} ref Reference name that is included in the &lt;style&gt;'s ID
+ * @param {string} [ref] Reference name that is included in the `<style>`'s ID - defaults to a random number if left undefined
  */
 function addGlobalStyle(style, ref)
 {
+    if(typeof ref !== "string" || ref.length === 0)
+        ref = String(Math.floor(Math.random() * 1000));
+
     const styleElem = document.createElement("style");
-    styleElem.id = `betterytm-${ref}-style`;
+    styleElem.id = `bytm-style-${ref}`;
 
     if(styleElem.styleSheet)
         styleElem.styleSheet.cssText = style;
@@ -839,21 +1068,39 @@ function addGlobalStyle(style, ref)
     dbg && console.log(`BetterYTM: Inserted global style with ref '${ref}':`, styleElem);
 }
 
+//#SECTION feature config
+
 /**
  * Loads a feature configuration saved persistently, returns an empty object if no feature configuration was saved
- * @returns {Promise<Readonly<typeof defaultFeatures | {}>>}
+ * @returns {Promise<Readonly<FeatureConfig | {}>>}
  */
 async function loadFeatureConf()
 {
-    /** @type {string} */
-    const featureConf = await GM.getValue("bytm-featureconf"); // eslint-disable-line no-undef
+    const defConf = Object.freeze({...defaultFeatures});
+
+    try
+    {
+        /** @type {string} */
+        const featureConf = await GM.getValue("bytm-config"); // eslint-disable-line no-undef
+
+        if(!featureConf)
+        {
+            await setDefaultFeatConf();
+            return defConf;
+        }
 
-    return Object.freeze(featureConf ? JSON.parse(featureConf) : {});
+        return Object.freeze(featureConf ? JSON.parse(featureConf) : {});
+    }
+    catch(err)
+    {
+        await setDefaultFeatConf();
+        return defConf;
+    }
 }
 
 /**
  * Saves a feature configuration saved persistently
- * @param {typeof defaultFeatures} featureConf
+ * @param {FeatureConfig} featureConf
  * @returns {Promise<void>}
  */
 function saveFeatureConf(featureConf)
@@ -861,7 +1108,15 @@ function saveFeatureConf(featureConf)
     if(!featureConf || typeof featureConf != "object")
         throw new TypeError("Feature config not provided or invalid");
 
-    return GM.setValue("bytm-featureconf", JSON.stringify(featureConf)); // eslint-disable-line no-undef
+    return GM.setValue("bytm-config", JSON.stringify(featureConf)); // eslint-disable-line no-undef
+}
+
+/**
+ * @returns {Promise<void>}
+ */
+function setDefaultFeatConf()
+{
+    return GM.setValue("bytm-config", JSON.stringify(defaultFeatures)); // eslint-disable-line no-undef
 }
 
 init(); // call init() when script is loaded

+ 1 - 1
README.md

@@ -19,7 +19,7 @@ Once this script is more finished, I might add a menu to toggle these more easil
 <br><br>
 
 ## Installation:
-**Requires a userscript manager extension:**
+**Requires a userscript manager browser extension:**
 > Firefox: [GreaseMonkey](https://addons.mozilla.org/en-US/firefox/addon/greasemonkey/)  
 > Chrome: [TamperMonkey](https://chrome.google.com/webstore/detail/tampermonkey/dhdgffkkebhmkfjojejmpbldmpobfkfo?hl=en)  
 > Edge: [TamperMonkey](https://microsoftedge.microsoft.com/addons/detail/tampermonkey/iikmkjmpaadaobahmlepeloendndfphd)

+ 24 - 9
changelog.md

@@ -1,26 +1,41 @@
 # BetterYTM Changelog
-Current version: **[v0.2.0](#020)**
 
 <br>
 
 ## History:
 
-- **[v0.1.0](#010)**
-- **[v0.2.0 (current)](#020)**
+- **[v1.0.0](#100)**
+- [v0.2.0](#020)
+- [v0.1.0](#010)
 
 ---
 
 <br><br>
 
-## 0.1.0
-- Added support for arrow keys to skip forward or backward (currently only by fixed 10 second interval)
+## 1.0.0
+
+- Added menu to configure features
+- New configurable features:
+  - Make volume slider bigger
+  - Choose step of volume slider for finer control
+  - TODO: Add lyrics button to each song in a playlist
+- Changes / Fixes:
+  - Now the lyrics button will directly link to the lyrics (using my API [geniURL](https://github.com/Sv443/geniURL))
+  - TODO: Site switch with <kbd>F9</kbd> will now keep the video time
 
 <br>
 
 ## 0.2.0
+
 - Added Features:
-    - Switch between YT and YTM (F9 by default)
-    - Search for song lyrics with new button in media controls
-    - Remove "Upgrade to YTM Premium" tab
+  - Switch between YouTube and YT Music (with <kbd>F9</kbd> by default)
+  - Search for song lyrics with new button in media controls
+  - Remove "Upgrade to YTM Premium" tab
+
+<br>
+
+## 0.1.0
+
+- Added support for arrow keys to skip forward or backward (currently only by fixed 10 second interval)
 
-<br>
+<br><br><br><br><br><br><br><br><br>

+ 0 - 30
dev/GM_config.js

@@ -1,30 +0,0 @@
-/* eslint-disable no-undef */
-
-
-// ==UserScript==
-// @require       https://openuserjs.org/src/libs/sizzle/GM_config.js
-// @grant         GM_getValue
-// @grant         GM_setValue
-// ==/UserScript==
-
-
-GM_config.init(
-{
-    "id": "MyConfig", // The id used for this instance of GM_config
-    "title": "ayo",
-    "fields": // Fields object
-    {
-        "name": // This is the id of the field
-        {
-            "label": "Name", // Appears next to field
-            "type": "text", // Makes this setting a text field
-            "default": "Sizzle McTwizzle" // Default value if user doesn"t change it
-        }
-    }
-});
-
-
-GM_config.open();
-
-
-GM_config.get("name");

+ 0 - 91
dev/domrect_visualizer.js

@@ -1,91 +0,0 @@
-/**
- * @author mlewand
- * @see https://gist.github.com/mlewand/56237c19050d27f61b807ed384dff2db
- * 
- * A helper function to visualize DOMRect or set of DOMRect instances.
- * 
- * Subsequent calls will remove previously marked elements.
- * 
- *     Debug a element currently focused in your devtools inspector.
- *     window.markRect( $0.getBoundingClientRect() );
- *     // Debug a selection.
- *     window.markRect( document.getSelection().getRangeAt( 0 ).getClientRects() );
- * 
- * 
- * Original source: https://gist.github.com/mlewand/56237c19050d27f61b807ed384dff2db
- * Updated by [Sv443](https://github.com/Sv443)
- * 
- * Styling example:
- * ```js
- * const [ mark ] = window.markRect(new DOMRect());
- * markElem.style.backgroundColor = "red";
- * ```
- */
-( () => {
-    const drawnRect = [];
-
-    const createRectDraw = () => {
-        const ret = document.createElement( 'div' );
-        ret.style.position = 'absolute';
-        ret.style.outline = '2px solid red';
-        ret.classList.add('debug-rect-marker');
-        document.body.appendChild( ret );
-
-        return ret;
-    };
-
-    /**
-     * Creates an element that marks the passed DOMRectangle(s)  
-     * These elements get the class `debug-rect-marker`
-     * @param {DOMRect|DOMRect[]} rectangles Accepts a DOMRectangle or an array of them
-     * @returns {HTMLElement[]} Returns array of marker elements
-     */
-    const markRect = ( rectangles ) => {
-        const marks = [];
-
-        // Cleanup.
-        drawnRect.forEach( ( oldRect ) => oldRect.remove() );
-
-        // Unify format.
-        if ( !Array.isArray(rectangles) ) {
-            rectangles = [ rectangles ];
-        }
-
-        rectangles.forEach( ( rect ) => {
-            const curDrawing = createRectDraw(),
-                dims = [ 'top', 'left', 'width', 'height' ];
-
-            dims.forEach( ( property ) => {
-                curDrawing.style[ property ] = `${rect[ property ]}px`;
-            } );
-
-            console.info( 'created debug rect:', curDrawing );
-
-            drawnRect.push( curDrawing );
-            marks.push( curDrawing );
-        } );
-
-        return marks;
-    };
-
-    /**
-     * Deletes all rectangles that have been previously created
-     * @returns {void}
-     * @author Sv443
-     */
-    const deleteRects = () => {
-        const markers = document.querySelectorAll(".debug-rect-marker");
-
-        markers.forEach(elem => {
-            elem.innerHTML = "";
-            elem.outerHTML = "";
-        });
-
-        console.warn(`Deleted ${markers.length} markers`);
-    };
-
-
-    window.markRect = markRect;
-
-    window.deleteRects = deleteRects;
-} )();

BIN
dev/icon/png/v1.0.png


BIN
dev/icon/png/v1.1.png


BIN
dev/icon/png/v2.0.png


+ 0 - 41
dev/theme_feature.js

@@ -1,41 +0,0 @@
-//# SECTION theme
-
-// /**
-//  * Applies the set theme color
-//  */
-// function applyTheme()
-// {
-//     const formatRegex = /^(\d{3}){1,2}$/;
-
-//     const color = features.themeColor.match(formatRegex) ? `#${color}` : color;
-
-//     /**
-//      * A list of changes to be made to the page to apply the theme color
-//      */
-//     const themeChanges = [
-//         {
-//             elem: document.querySelector("#progressContainer > #primaryProgress"),
-//             prop: "background",
-//             important: false,
-//         },
-//         {
-//             elem: document.querySelector(),
-//             prop: "",
-//             important: false,
-//         },
-//         {
-//             elem: document.querySelector(),
-//             prop: "",
-//             important: false,
-//         },
-//     ];
-
-//     themeChanges.forEach(change => {
-//         if(change.elem)
-//         {
-//             const value = change.important === true ? `${color} !important` : color;
-
-//             change.elem.style[change.prop] = value;
-//         }
-//     });
-// }

BIN
resources/external/github.png


BIN
resources/external/greasyfork.png


+ 0 - 0
dev/icon/png/v2.1.png → resources/icon/1000.png


+ 0 - 0
resources/icon/v2.1_200.png → resources/icon/200.png


BIN
resources/icon/close.png


+ 0 - 0
dev/icon/pdn/v1.0.pdn → resources/icon/pdn/v1.0.pdn


+ 0 - 0
dev/icon/pdn/v1.1.pdn → resources/icon/pdn/v1.1.pdn


+ 0 - 0
dev/icon/pdn/v2.0.pdn → resources/icon/pdn/v2.0.pdn


+ 0 - 0
dev/icon/pdn/v2.1.pdn → resources/icon/pdn/v2.1.pdn


BIN
resources/icon/v2.0_200.png