Sv443 11 mesi fa
parent
commit
dd9c0050cc
2 ha cambiato i file con 380 aggiunte e 177 eliminazioni
  1. 63 16
      dist/BetterYTM.css
  2. 317 161
      dist/BetterYTM.user.js

+ 63 - 16
dist/BetterYTM.css

@@ -588,15 +588,49 @@ hr {
   white-space: nowrap;
 }
 
-#bytm-toast {
+:root html body .bytm-ripple {
+  position: relative;
+  width: var(--bytm-ripple-width, 100%);
+  height: var(--bytm-ripple-height, 100%);
+  overflow: hidden;
+  white-space: nowrap;
+  text-overflow: ellipsis;
+}
+
+.bytm-ripple-area {
+  position: absolute;
+  background: rgba(255, 255, 255, 0.7);
+  transform: translate(-50%, -50%);
+  pointer-events: none;
+  border-radius: 50%;
+  animation: bytm-scale-ripple 0.25s ease-in;
+}
+
+@keyframes bytm-scale-ripple {
+  0% {
+    width: 0;
+    height: 0;
+    opacity: 0.5;
+  }
+  100% {
+    width: 400px;
+    height: 400px;
+    opacity: 0;
+  }
+}
+
+:root {
   --bytm-toast-bg-color: #323232;
   --bytm-toast-text-color: #fff;
-  --bytm-toast-offset: 25px;
-  --bytm-toast-transform-distance: 100px;
+  --bytm-toast-offset-ver: 80px;
+  --bytm-toast-offset-hor: 25px;
   --bytm-toast-transition-time: 0.5s;
+  --bytm-toast-transform-distance: 175px;
+}
 
+#bytm-toast {
   position: fixed;
-  z-index: 100;
+  z-index: 1042069;
   opacity: 0.000001;
   pointer-events: none;
   padding: 10px 20px;
@@ -615,26 +649,26 @@ hr {
 }
 
 #bytm-toast.pos-tl {
-  top: var(--bytm-toast-offset);
-  left: var(--bytm-toast-offset);
+  top: var(--bytm-toast-offset-ver);
+  left: var(--bytm-toast-offset-hor);
   transform: translate(0, calc(var(--bytm-toast-transform-distance) * -1));
 }
 
 #bytm-toast.pos-tr {
-  top: var(--bytm-toast-offset);
-  right: var(--bytm-toast-offset);
+  top: var(--bytm-toast-offset-ver);
+  right: var(--bytm-toast-offset-hor);
   transform: translate(0, calc(var(--bytm-toast-transform-distance) * -1));
 }
 
 #bytm-toast.pos-br {
-  bottom: var(--bytm-toast-offset);
-  right: var(--bytm-toast-offset);
+  bottom: var(--bytm-toast-offset-ver);
+  right: var(--bytm-toast-offset-hor);
   transform: translate(0, var(--bytm-toast-transform-distance));
 }
 
 #bytm-toast.pos-bl {
-  bottom: var(--bytm-toast-offset);
-  left: var(--bytm-toast-offset);
+  bottom: var(--bytm-toast-offset-ver);
+  left: var(--bytm-toast-offset-hor);
   transform: translate(0, var(--bytm-toast-transform-distance));
 }
 
@@ -1576,6 +1610,15 @@ ytmusic-player#player #bezel {
   --bytm-auto-like-btn-color: #bf87f0;
 }
 
+#bytm-auto-like-channels-list {
+  display: flex;
+  flex-direction: column;
+  overflow-x: hidden;
+  overflow-y: auto;
+  white-space: nowrap;
+  text-overflow: ellipsis;
+}
+
 .bytm-auto-like-channel-row-left-cont {
   display: flex;
   align-items: center;
@@ -1597,10 +1640,9 @@ ytmusic-player#player #bezel {
   margin-bottom: 15px;
 }
 
-#bytm-auto-like-channels-add-new {
-  padding: 4px 15px;
-  margin-top: 20px;
-  margin-bottom: 10px;
+#bytm-auto-like-channels-add-new-wrapper {
+  margin: 15px;
+  margin-top: 5px;
 }
 
 .bytm-auto-like-channel-row:hover {
@@ -1639,6 +1681,11 @@ ytmusic-player#player #bezel {
   animation: none;
 }
 
+.bytm-auto-like-toggle-btn.left-margin {
+  margin: 0;
+  margin-left: 8px;
+}
+
 .bytm-auto-like-toggle-btn:active {
   background-color: rgba(255, 255, 255, 0.1);
 }

+ 317 - 161
dist/BetterYTM.user.js

@@ -17,7 +17,7 @@
 // @license           AGPL-3.0-only
 // @author            Sv443
 // @copyright         Sv443 (https://github.com/Sv443)
-// @icon              https://raw.githubusercontent.com/Sv443/BetterYTM/a4a8a78/assets/images/logo/logo_dev_48.png
+// @icon              https://raw.githubusercontent.com/Sv443/BetterYTM/6a5a9a63/assets/images/logo/logo_dev_48.png
 // @match             https://music.youtube.com/*
 // @match             https://www.youtube.com/*
 // @run-at            document-start
@@ -35,47 +35,47 @@
 // @grant             GM.openInTab
 // @grant             unsafeWindow
 // @noframes
-// @resource          css-bundle              https://raw.githubusercontent.com/Sv443/BetterYTM/a4a8a78/dist/BetterYTM.css
-// @resource          css-above_queue_btns    https://raw.githubusercontent.com/Sv443/BetterYTM/a4a8a78/assets/style/aboveQueueBtns.css
-// @resource          css-anchor_improvements https://raw.githubusercontent.com/Sv443/BetterYTM/a4a8a78/assets/style/anchorImprovements.css
-// @resource          css-fix_hdr             https://raw.githubusercontent.com/Sv443/BetterYTM/a4a8a78/assets/style/fixHDR.css
-// @resource          css-fix_spacing         https://raw.githubusercontent.com/Sv443/BetterYTM/a4a8a78/assets/style/fixSpacing.css
-// @resource          css-vol_slider_size     https://raw.githubusercontent.com/Sv443/BetterYTM/a4a8a78/assets/style/volSliderSize.css
-// @resource          doc-changelog           https://raw.githubusercontent.com/Sv443/BetterYTM/a4a8a78/changelog.md
-// @resource          icon-advanced_mode      https://raw.githubusercontent.com/Sv443/BetterYTM/a4a8a78/assets/icons/plus_circle_small.svg
-// @resource          icon-arrow_down         https://raw.githubusercontent.com/Sv443/BetterYTM/a4a8a78/assets/icons/arrow_down.svg
-// @resource          icon-auto_like_enabled  https://raw.githubusercontent.com/Sv443/BetterYTM/a4a8a78/assets/icons/auto_like_enabled.svg
-// @resource          icon-auto_like          https://raw.githubusercontent.com/Sv443/BetterYTM/a4a8a78/assets/icons/auto_like.svg
-// @resource          icon-clear_list         https://raw.githubusercontent.com/Sv443/BetterYTM/a4a8a78/assets/icons/clear_list.svg
-// @resource          icon-delete             https://raw.githubusercontent.com/Sv443/BetterYTM/a4a8a78/assets/icons/delete.svg
-// @resource          icon-error              https://raw.githubusercontent.com/Sv443/BetterYTM/a4a8a78/assets/icons/error.svg
-// @resource          icon-experimental       https://raw.githubusercontent.com/Sv443/BetterYTM/a4a8a78/assets/icons/beaker_small.svg
-// @resource          icon-globe_small        https://raw.githubusercontent.com/Sv443/BetterYTM/a4a8a78/assets/icons/globe_small.svg
-// @resource          icon-globe              https://raw.githubusercontent.com/Sv443/BetterYTM/a4a8a78/assets/icons/globe.svg
-// @resource          icon-help               https://raw.githubusercontent.com/Sv443/BetterYTM/a4a8a78/assets/icons/help.svg
-// @resource          icon-image_filled       https://raw.githubusercontent.com/Sv443/BetterYTM/a4a8a78/assets/icons/image_filled.svg
-// @resource          icon-image              https://raw.githubusercontent.com/Sv443/BetterYTM/a4a8a78/assets/icons/image.svg
-// @resource          icon-link               https://raw.githubusercontent.com/Sv443/BetterYTM/a4a8a78/assets/icons/link.svg
-// @resource          icon-lyrics             https://raw.githubusercontent.com/Sv443/BetterYTM/a4a8a78/assets/icons/lyrics.svg
-// @resource          icon-reload             https://raw.githubusercontent.com/Sv443/BetterYTM/a4a8a78/assets/icons/refresh.svg
-// @resource          icon-skip_to            https://raw.githubusercontent.com/Sv443/BetterYTM/a4a8a78/assets/icons/skip_to.svg
-// @resource          icon-spinner            https://raw.githubusercontent.com/Sv443/BetterYTM/a4a8a78/assets/icons/spinner.svg
-// @resource          img-close               https://raw.githubusercontent.com/Sv443/BetterYTM/a4a8a78/assets/images/close.png
-// @resource          img-discord             https://raw.githubusercontent.com/Sv443/BetterYTM/a4a8a78/assets/images/external/discord.png
-// @resource          img-github              https://raw.githubusercontent.com/Sv443/BetterYTM/a4a8a78/assets/images/external/github.png
-// @resource          img-greasyfork          https://raw.githubusercontent.com/Sv443/BetterYTM/a4a8a78/assets/images/external/greasyfork.png
-// @resource          img-logo_dev            https://raw.githubusercontent.com/Sv443/BetterYTM/a4a8a78/assets/images/logo/logo_dev_48.png
-// @resource          img-logo                https://raw.githubusercontent.com/Sv443/BetterYTM/a4a8a78/assets/images/logo/logo_48.png
-// @resource          img-openuserjs          https://raw.githubusercontent.com/Sv443/BetterYTM/a4a8a78/assets/images/external/openuserjs.png
-// @resource          trans-de_DE             https://raw.githubusercontent.com/Sv443/BetterYTM/a4a8a78/assets/translations/de_DE.json
-// @resource          trans-en_US             https://raw.githubusercontent.com/Sv443/BetterYTM/a4a8a78/assets/translations/en_US.json
-// @resource          trans-en_UK             https://raw.githubusercontent.com/Sv443/BetterYTM/a4a8a78/assets/translations/en_UK.json
-// @resource          trans-es_ES             https://raw.githubusercontent.com/Sv443/BetterYTM/a4a8a78/assets/translations/es_ES.json
-// @resource          trans-fr_FR             https://raw.githubusercontent.com/Sv443/BetterYTM/a4a8a78/assets/translations/fr_FR.json
-// @resource          trans-hi_IN             https://raw.githubusercontent.com/Sv443/BetterYTM/a4a8a78/assets/translations/hi_IN.json
-// @resource          trans-ja_JA             https://raw.githubusercontent.com/Sv443/BetterYTM/a4a8a78/assets/translations/ja_JA.json
-// @resource          trans-pt_BR             https://raw.githubusercontent.com/Sv443/BetterYTM/a4a8a78/assets/translations/pt_BR.json
-// @resource          trans-zh_CN             https://raw.githubusercontent.com/Sv443/BetterYTM/a4a8a78/assets/translations/zh_CN.json
+// @resource          css-bundle              https://raw.githubusercontent.com/Sv443/BetterYTM/6a5a9a63/dist/BetterYTM.css
+// @resource          css-above_queue_btns    https://raw.githubusercontent.com/Sv443/BetterYTM/6a5a9a63/assets/style/aboveQueueBtns.css
+// @resource          css-anchor_improvements https://raw.githubusercontent.com/Sv443/BetterYTM/6a5a9a63/assets/style/anchorImprovements.css
+// @resource          css-fix_hdr             https://raw.githubusercontent.com/Sv443/BetterYTM/6a5a9a63/assets/style/fixHDR.css
+// @resource          css-fix_spacing         https://raw.githubusercontent.com/Sv443/BetterYTM/6a5a9a63/assets/style/fixSpacing.css
+// @resource          css-vol_slider_size     https://raw.githubusercontent.com/Sv443/BetterYTM/6a5a9a63/assets/style/volSliderSize.css
+// @resource          doc-changelog           https://raw.githubusercontent.com/Sv443/BetterYTM/6a5a9a63/changelog.md
+// @resource          icon-advanced_mode      https://raw.githubusercontent.com/Sv443/BetterYTM/6a5a9a63/assets/icons/plus_circle_small.svg
+// @resource          icon-arrow_down         https://raw.githubusercontent.com/Sv443/BetterYTM/6a5a9a63/assets/icons/arrow_down.svg
+// @resource          icon-auto_like_enabled  https://raw.githubusercontent.com/Sv443/BetterYTM/6a5a9a63/assets/icons/auto_like_enabled.svg
+// @resource          icon-auto_like          https://raw.githubusercontent.com/Sv443/BetterYTM/6a5a9a63/assets/icons/auto_like.svg
+// @resource          icon-clear_list         https://raw.githubusercontent.com/Sv443/BetterYTM/6a5a9a63/assets/icons/clear_list.svg
+// @resource          icon-delete             https://raw.githubusercontent.com/Sv443/BetterYTM/6a5a9a63/assets/icons/delete.svg
+// @resource          icon-error              https://raw.githubusercontent.com/Sv443/BetterYTM/6a5a9a63/assets/icons/error.svg
+// @resource          icon-experimental       https://raw.githubusercontent.com/Sv443/BetterYTM/6a5a9a63/assets/icons/beaker_small.svg
+// @resource          icon-globe_small        https://raw.githubusercontent.com/Sv443/BetterYTM/6a5a9a63/assets/icons/globe_small.svg
+// @resource          icon-globe              https://raw.githubusercontent.com/Sv443/BetterYTM/6a5a9a63/assets/icons/globe.svg
+// @resource          icon-help               https://raw.githubusercontent.com/Sv443/BetterYTM/6a5a9a63/assets/icons/help.svg
+// @resource          icon-image_filled       https://raw.githubusercontent.com/Sv443/BetterYTM/6a5a9a63/assets/icons/image_filled.svg
+// @resource          icon-image              https://raw.githubusercontent.com/Sv443/BetterYTM/6a5a9a63/assets/icons/image.svg
+// @resource          icon-link               https://raw.githubusercontent.com/Sv443/BetterYTM/6a5a9a63/assets/icons/link.svg
+// @resource          icon-lyrics             https://raw.githubusercontent.com/Sv443/BetterYTM/6a5a9a63/assets/icons/lyrics.svg
+// @resource          icon-reload             https://raw.githubusercontent.com/Sv443/BetterYTM/6a5a9a63/assets/icons/refresh.svg
+// @resource          icon-skip_to            https://raw.githubusercontent.com/Sv443/BetterYTM/6a5a9a63/assets/icons/skip_to.svg
+// @resource          icon-spinner            https://raw.githubusercontent.com/Sv443/BetterYTM/6a5a9a63/assets/icons/spinner.svg
+// @resource          img-close               https://raw.githubusercontent.com/Sv443/BetterYTM/6a5a9a63/assets/images/close.png
+// @resource          img-discord             https://raw.githubusercontent.com/Sv443/BetterYTM/6a5a9a63/assets/images/external/discord.png
+// @resource          img-github              https://raw.githubusercontent.com/Sv443/BetterYTM/6a5a9a63/assets/images/external/github.png
+// @resource          img-greasyfork          https://raw.githubusercontent.com/Sv443/BetterYTM/6a5a9a63/assets/images/external/greasyfork.png
+// @resource          img-logo_dev            https://raw.githubusercontent.com/Sv443/BetterYTM/6a5a9a63/assets/images/logo/logo_dev_48.png
+// @resource          img-logo                https://raw.githubusercontent.com/Sv443/BetterYTM/6a5a9a63/assets/images/logo/logo_48.png
+// @resource          img-openuserjs          https://raw.githubusercontent.com/Sv443/BetterYTM/6a5a9a63/assets/images/external/openuserjs.png
+// @resource          trans-de_DE             https://raw.githubusercontent.com/Sv443/BetterYTM/6a5a9a63/assets/translations/de_DE.json
+// @resource          trans-en_US             https://raw.githubusercontent.com/Sv443/BetterYTM/6a5a9a63/assets/translations/en_US.json
+// @resource          trans-en_UK             https://raw.githubusercontent.com/Sv443/BetterYTM/6a5a9a63/assets/translations/en_UK.json
+// @resource          trans-es_ES             https://raw.githubusercontent.com/Sv443/BetterYTM/6a5a9a63/assets/translations/es_ES.json
+// @resource          trans-fr_FR             https://raw.githubusercontent.com/Sv443/BetterYTM/6a5a9a63/assets/translations/fr_FR.json
+// @resource          trans-hi_IN             https://raw.githubusercontent.com/Sv443/BetterYTM/6a5a9a63/assets/translations/hi_IN.json
+// @resource          trans-ja_JA             https://raw.githubusercontent.com/Sv443/BetterYTM/6a5a9a63/assets/translations/ja_JA.json
+// @resource          trans-pt_BR             https://raw.githubusercontent.com/Sv443/BetterYTM/6a5a9a63/assets/translations/pt_BR.json
+// @resource          trans-zh_CN             https://raw.githubusercontent.com/Sv443/BetterYTM/6a5a9a63/assets/translations/zh_CN.json
 // @require           https://cdn.jsdelivr.net/npm/@sv443-network/[email protected]/dist/index.global.js
 // @require           https://cdn.jsdelivr.net/npm/[email protected]/dist/fuse.basic.js
 // @require           https://cdn.jsdelivr.net/npm/[email protected]/lib/marked.umd.js
@@ -205,7 +205,7 @@ var PluginIntent;
 })(PluginIntent || (PluginIntent = {}));const modeRaw = "development";
 const branchRaw = "develop";
 const hostRaw = "github";
-const buildNumberRaw = "a4a8a78";
+const buildNumberRaw = "6a5a9a63";
 /** The mode in which the script was built (production or development) */
 const mode = (modeRaw.match(/^#{{.+}}$/) ? "production" : modeRaw);
 /** The branch to use in various URLs that point to the GitHub repo */
@@ -790,70 +790,72 @@ let lastFullscreen;
 function initSiteEvents() {
     return __awaiter(this, void 0, void 0, function* () {
         try {
-            //#region queue
-            // the queue container always exists so it doesn't need an extra init function
-            const queueObs = new MutationObserver(([{ addedNodes, removedNodes, target }]) => {
-                if (addedNodes.length > 0 || removedNodes.length > 0) {
-                    info(`Detected queue change - added nodes: ${[...addedNodes.values()].length} - removed nodes: ${[...removedNodes.values()].length}`);
-                    emitSiteEvent("queueChanged", target);
-                }
-            });
-            // only observe added or removed elements
-            addSelectorListener("sidePanel", "#contents.ytmusic-player-queue", {
-                listener: (el) => {
-                    queueObs.observe(el, {
-                        childList: true,
-                    });
-                },
-            });
-            const autoplayObs = new MutationObserver(([{ addedNodes, removedNodes, target }]) => {
-                if (addedNodes.length > 0 || removedNodes.length > 0) {
-                    info(`Detected autoplay queue change - added nodes: ${[...addedNodes.values()].length} - removed nodes: ${[...removedNodes.values()].length}`);
-                    emitSiteEvent("autoplayQueueChanged", target);
-                }
-            });
-            addSelectorListener("sidePanel", "ytmusic-player-queue #automix-contents", {
-                listener: (el) => {
-                    autoplayObs.observe(el, {
-                        childList: true,
-                    });
-                },
-            });
-            //#region player bar
-            let lastTitle = null;
-            addSelectorListener("playerBarInfo", "yt-formatted-string.title", {
-                continuous: true,
-                listener: (titleElem) => {
-                    const oldTitle = lastTitle;
-                    const newTitle = titleElem.textContent;
-                    if (newTitle === lastTitle || !newTitle)
-                        return;
-                    lastTitle = newTitle;
-                    info(`Detected song change - old title: "${oldTitle}" - new title: "${newTitle}"`);
-                    emitSiteEvent("songTitleChanged", newTitle, oldTitle);
-                },
-            });
-            info("Successfully initialized SiteEvents observers");
-            observers = observers.concat([
-                queueObs,
-                autoplayObs,
-            ]);
-            //#region player
-            const playerFullscreenObs = new MutationObserver(([{ target }]) => {
-                var _a;
-                const isFullscreen = ((_a = target.getAttribute("player-ui-state")) === null || _a === void 0 ? void 0 : _a.toUpperCase()) === "FULLSCREEN";
-                if (lastFullscreen !== isFullscreen || typeof lastFullscreen === "undefined") {
-                    emitSiteEvent("fullscreenToggled", isFullscreen);
-                    lastFullscreen = isFullscreen;
-                }
-            });
-            addSelectorListener("mainPanel", "ytmusic-player#player", {
-                listener: (el) => {
-                    playerFullscreenObs.observe(el, {
-                        attributeFilter: ["player-ui-state"],
-                    });
-                },
-            });
+            if (getDomain() === "ytm") {
+                //#region queue
+                // the queue container always exists so it doesn't need an extra init function
+                const queueObs = new MutationObserver(([{ addedNodes, removedNodes, target }]) => {
+                    if (addedNodes.length > 0 || removedNodes.length > 0) {
+                        info(`Detected queue change - added nodes: ${[...addedNodes.values()].length} - removed nodes: ${[...removedNodes.values()].length}`);
+                        emitSiteEvent("queueChanged", target);
+                    }
+                });
+                // only observe added or removed elements
+                addSelectorListener("sidePanel", "#contents.ytmusic-player-queue", {
+                    listener: (el) => {
+                        queueObs.observe(el, {
+                            childList: true,
+                        });
+                    },
+                });
+                const autoplayObs = new MutationObserver(([{ addedNodes, removedNodes, target }]) => {
+                    if (addedNodes.length > 0 || removedNodes.length > 0) {
+                        info(`Detected autoplay queue change - added nodes: ${[...addedNodes.values()].length} - removed nodes: ${[...removedNodes.values()].length}`);
+                        emitSiteEvent("autoplayQueueChanged", target);
+                    }
+                });
+                addSelectorListener("sidePanel", "ytmusic-player-queue #automix-contents", {
+                    listener: (el) => {
+                        autoplayObs.observe(el, {
+                            childList: true,
+                        });
+                    },
+                });
+                //#region player bar
+                let lastTitle = null;
+                addSelectorListener("playerBarInfo", "yt-formatted-string.title", {
+                    continuous: true,
+                    listener: (titleElem) => {
+                        const oldTitle = lastTitle;
+                        const newTitle = titleElem.textContent;
+                        if (newTitle === lastTitle || !newTitle)
+                            return;
+                        lastTitle = newTitle;
+                        info(`Detected song change - old title: "${oldTitle}" - new title: "${newTitle}"`);
+                        emitSiteEvent("songTitleChanged", newTitle, oldTitle);
+                    },
+                });
+                info("Successfully initialized SiteEvents observers");
+                observers = observers.concat([
+                    queueObs,
+                    autoplayObs,
+                ]);
+                //#region player
+                const playerFullscreenObs = new MutationObserver(([{ target }]) => {
+                    var _a;
+                    const isFullscreen = ((_a = target.getAttribute("player-ui-state")) === null || _a === void 0 ? void 0 : _a.toUpperCase()) === "FULLSCREEN";
+                    if (lastFullscreen !== isFullscreen || typeof lastFullscreen === "undefined") {
+                        emitSiteEvent("fullscreenToggled", isFullscreen);
+                        lastFullscreen = isFullscreen;
+                    }
+                });
+                addSelectorListener("mainPanel", "ytmusic-player#player", {
+                    listener: (el) => {
+                        playerFullscreenObs.observe(el, {
+                            attributeFilter: ["player-ui-state"],
+                        });
+                    },
+                });
+            }
             //#region other
             const runIntervalChecks = () => {
                 if (location.pathname.startsWith("/watch")) {
@@ -1092,10 +1094,34 @@ function createLongBtn(_a) {
         iconPosition === "right" && btnElem.appendChild(imgElem);
         return btnElem;
     });
+}/**
+ * Creates an element with a ripple effect on click.
+ * @param clickEl If passed, this element will be modified to have the ripple effect. Otherwise, a new element will be created.
+ * @returns The passed element or the newly created element with the ripple effect.
+ */
+function createRipple(rippleElement) {
+    const rippleEl = rippleElement !== null && rippleElement !== void 0 ? rippleElement : document.createElement("div");
+    rippleEl.classList.add("bytm-ripple");
+    rippleEl.addEventListener("click", (e) => {
+        var _a, _b, _c, _d;
+        const x = (_b = e.clientX - ((_a = e.target) === null || _a === void 0 ? void 0 : _a.offsetLeft)) !== null && _b !== void 0 ? _b : 0;
+        const y = (_d = e.clientY - ((_c = e.target) === null || _c === void 0 ? void 0 : _c.offsetTop)) !== null && _d !== void 0 ? _d : 0;
+        const rippleAreaEl = document.createElement("span");
+        rippleAreaEl.classList.add("bytm-ripple-area");
+        rippleAreaEl.style.left = x + "px";
+        rippleAreaEl.style.top = y + "px";
+        if (rippleEl.firstChild)
+            rippleEl.insertBefore(rippleAreaEl, rippleEl.firstChild);
+        else
+            rippleEl.appendChild(rippleAreaEl);
+        // setTimeout(() => rippleAreaEl.remove(), 250);
+    });
+    return rippleEl;
 }let timeout;
 /** Shows a toast message with an icon */
-function showIconToast(message_1, icon_1) {
-    return __awaiter(this, arguments, void 0, function* (message, icon, duration = 3000, position = "tr") {
+function showIconToast(_a) {
+    return __awaiter(this, void 0, void 0, function* () {
+        var { icon, duration = 3000, position = "tr" } = _a, rest = __rest(_a, ["icon", "duration", "position"]);
         const toastWrapper = document.createElement("div");
         toastWrapper.classList.add("bytm-toast-flex-wrapper");
         const toastIcon = document.createElement("div");
@@ -1105,14 +1131,17 @@ function showIconToast(message_1, icon_1) {
             toastIcon.innerHTML = iconHtml;
         const toastMessage = document.createElement("div");
         toastMessage.classList.add("bytm-toast-message");
-        toastMessage.textContent = message;
+        if ("message" in rest)
+            toastMessage.textContent = rest.message;
+        else
+            toastMessage.appendChild(rest.element);
         toastWrapper.appendChild(toastIcon);
         toastWrapper.appendChild(toastMessage);
         yield showToast({
             duration,
             position,
             element: toastWrapper,
-            title: message,
+            title: "message" in rest ? rest.message : rest.title,
         });
     });
 }
@@ -1128,6 +1157,7 @@ function showToast(_a) {
         toastElem.role = "alert";
         toastElem.ariaLive = "assertive";
         toastElem.ariaAtomic = "true";
+        toastElem.addEventListener("click", () => __awaiter(this, void 0, void 0, function* () { return yield closeToast(); }), { once: true });
         if ("message" in rest)
             toastElem.title = toastElem.ariaLabel = toastElem.textContent = rest.message;
         else {
@@ -1229,7 +1259,7 @@ function initAutoLikeChannelsStore() {
     if (isLoaded)
         return;
     isLoaded = true;
-    return autoLikeChannelsStore.loadData();
+    return autoLikeStore.loadData();
 }
 function renderHeader$6() {
     return __awaiter(this, void 0, void 0, function* () {
@@ -1250,6 +1280,7 @@ function renderBody$6() {
         descriptionEl.tabIndex = 0;
         contElem.appendChild(descriptionEl);
         const addNewWrapper = document.createElement("div");
+        addNewWrapper.id = "bytm-auto-like-channels-add-new-wrapper";
         const addNewEl = document.createElement("span");
         addNewEl.id = "bytm-auto-like-channels-add-new";
         addNewEl.role = "button";
@@ -1259,29 +1290,34 @@ function renderBody$6() {
         addNewEl.classList.add("bytm-link", "bytm-no-select");
         addNewWrapper.appendChild(addNewEl);
         onInteraction(addNewEl, () => __awaiter(this, void 0, void 0, function* () {
-            var _a, _b;
-            const id = (_a = prompt(t("add_auto_like_channel_id_prompt"))) === null || _a === void 0 ? void 0 : _a.trim();
-            if (!id)
+            var _a, _b, _c;
+            const idPrompt = (_a = prompt(t("add_auto_like_channel_id_prompt"))) === null || _a === void 0 ? void 0 : _a.trim();
+            if (!idPrompt)
                 return;
-            if (!id.match(/^[a-zA-Z0-9_-]{20,}$/))
+            const isId = idPrompt.match(/^@?.+$/);
+            const isUrl = idPrompt.match(/^(?:https?:\/\/)?(?:www\.)?(?:music\.)?youtube\.com\/(?:channel\/|@)([a-zA-Z0-9_-]+)/);
+            if ((_b = isId === null || isId === void 0 ? void 0 : isId[0]) === null || _b === void 0 ? void 0 : _b.startsWith("@"))
+                isId[0] = isId[0].slice(1);
+            const id = ((isId === null || isId === void 0 ? void 0 : isId[0]) || (isUrl === null || isUrl === void 0 ? void 0 : isUrl[1]) || "").trim();
+            if (!id || id.length <= 0)
                 return alert(t("add_auto_like_channel_invalid_id"));
             let overwriteName = false;
-            if (autoLikeChannelsStore.getData().channels.some((ch) => ch.id === id)) {
+            if (autoLikeStore.getData().channels.some((ch) => ch.id === id)) {
                 if (!confirm(t("add_auto_like_channel_already_exists_prompt_new_name")))
                     return;
                 overwriteName = true;
             }
-            const name = (_b = prompt(t("add_auto_like_channel_name_prompt"))) === null || _b === void 0 ? void 0 : _b.trim();
+            const name = (_c = prompt(t("add_auto_like_channel_name_prompt"))) === null || _c === void 0 ? void 0 : _c.trim();
             if (!name || name.length === 0)
                 return;
-            yield autoLikeChannelsStore.setData(overwriteName
+            yield autoLikeStore.setData(overwriteName
                 ? {
-                    channels: autoLikeChannelsStore.getData().channels
+                    channels: autoLikeStore.getData().channels
                         .map((ch) => ch.id === id ? Object.assign(Object.assign({}, ch), { name }) : ch),
                 }
                 : {
                     channels: [
-                        ...autoLikeChannelsStore.getData().channels,
+                        ...autoLikeStore.getData().channels,
                         { id, name, enabled: true },
                     ],
                 });
@@ -1294,14 +1330,14 @@ function renderBody$6() {
         contElem.appendChild(addNewWrapper);
         const channelListCont = document.createElement("div");
         channelListCont.id = "bytm-auto-like-channels-list";
-        const removeChannel = (id) => autoLikeChannelsStore.setData({
-            channels: autoLikeChannelsStore.getData().channels.filter((ch) => ch.id !== id),
+        const removeChannel = (id) => autoLikeStore.setData({
+            channels: autoLikeStore.getData().channels.filter((ch) => ch.id !== id),
         });
-        const setChannelEnabled = (id, enabled) => UserUtils.debounce(() => autoLikeChannelsStore.setData({
-            channels: autoLikeChannelsStore.getData().channels
+        const setChannelEnabled = (id, enabled) => UserUtils.debounce(() => autoLikeStore.setData({
+            channels: autoLikeStore.getData().channels
                 .map((ch) => ch.id === id ? Object.assign(Object.assign({}, ch), { enabled }) : ch),
         }), 250, "rising");
-        const sortedChannels = autoLikeChannelsStore
+        const sortedChannels = autoLikeStore
             .getData().channels
             .sort((a, b) => a.name.localeCompare(b.name));
         for (const { name, id, enabled } of sortedChannels) {
@@ -3752,7 +3788,7 @@ function initArrowKeySkip() {
     return __awaiter(this, void 0, void 0, function* () {
         document.addEventListener("keydown", (evt) => {
             var _a, _b, _c, _d, _e, _f;
-            if (!getFeatures().arrowKeySupport)
+            if (!getFeature("arrowKeySupport"))
                 return;
             if (!["ArrowLeft", "ArrowRight"].includes(evt.code))
                 return;
@@ -3763,7 +3799,7 @@ function initArrowKeySkip() {
                 return info(`Captured valid key to skip forward or backward but the current active element is <${(_e = document.activeElement) === null || _e === void 0 ? void 0 : _e.tagName.toLowerCase()}>, so the keypress is ignored`);
             evt.preventDefault();
             evt.stopImmediatePropagation();
-            let skipBy = (_f = getFeatures().arrowKeySkipBy) !== null && _f !== void 0 ? _f : featInfo.arrowKeySkipBy.default;
+            let skipBy = (_f = getFeature("arrowKeySkipBy")) !== null && _f !== void 0 ? _f : featInfo.arrowKeySkipBy.default;
             if (evt.code === "ArrowLeft")
                 skipBy *= -1;
             log(`Captured arrow key '${evt.code}' - skipping by ${skipBy} seconds`);
@@ -3782,14 +3818,14 @@ let siteSwitchEnabled = true;
 function initSiteSwitch(domain) {
     return __awaiter(this, void 0, void 0, function* () {
         document.addEventListener("keydown", (e) => {
-            if (!getFeatures().switchBetweenSites)
+            if (!getFeature("switchBetweenSites"))
                 return;
-            const hk = getFeatures().switchSitesHotkey;
+            const hk = getFeature("switchSitesHotkey");
             if (siteSwitchEnabled && e.code === hk.code && e.shiftKey === hk.shift && e.ctrlKey === hk.ctrl && e.altKey === hk.alt)
                 switchSite(domain === "yt" ? "ytm" : "yt");
         });
         siteEvents.on("hotkeyInputActive", (state) => {
-            if (!getFeatures().switchBetweenSites)
+            if (!getFeature("switchBetweenSites"))
                 return;
             siteSwitchEnabled = !state;
         });
@@ -3840,7 +3876,7 @@ function initNumKeysSkip() {
     return __awaiter(this, void 0, void 0, function* () {
         document.addEventListener("keydown", (e) => {
             var _a, _b, _c, _d;
-            if (!getFeatures().numKeysSkipToTime)
+            if (!getFeature("numKeysSkipToTime"))
                 return;
             if (!e.key.trim().match(/^[0-9]$/))
                 return;
@@ -3866,7 +3902,8 @@ function initNumKeysSkip() {
 }
 //#region auto-like channels
 let canCompress$1 = false;
-const autoLikeChannelsStore = new UserUtils.DataStore({
+/** DataStore instance for all auto-liked channels */
+const autoLikeStore = new UserUtils.DataStore({
     id: "bytm-auto-like-channels",
     formatVersion: 1,
     defaultData: {
@@ -3883,14 +3920,14 @@ function initAutoLikeChannels() {
             yield initAutoLikeChannelsStore();
             if (getDomain() === "ytm") {
                 let timeout;
-                // TODO:FIXME: needs actual fix instead of timeout
                 siteEvents.on("songTitleChanged", () => {
+                    var _a;
                     timeout && clearTimeout(timeout);
                     timeout = setTimeout(() => {
                         // TODO: support multiple artists
                         const artistEls = document.querySelectorAll("ytmusic-player-bar .content-info-wrapper .subtitle a.yt-formatted-string[href]");
                         const channelIds = [...artistEls].map(a => a.href.split("/").pop()).filter(a => typeof a === "string");
-                        const likeChan = autoLikeChannelsStore.getData().channels.find((ch) => channelIds.includes(ch.id));
+                        const likeChan = autoLikeStore.getData().channels.find((ch) => channelIds.includes(ch.id));
                         if (!likeChan || !likeChan.enabled)
                             return;
                         if (artistEls.length === 0)
@@ -3903,38 +3940,104 @@ function initAutoLikeChannels() {
                             likeBtn.click();
                             log(`Auto-liked channel '${likeChan.name}' (ID: '${likeChan.id}')`);
                         }
-                    }, 5000);
+                    }, ((_a = getFeature("autoLikeTimeout")) !== null && _a !== void 0 ? _a : 5) * 1000);
                 });
                 siteEvents.on("pathChanged", (path) => {
-                    if (path.match(/\/channel\/.+/)) {
+                    if (getFeature("autoLikeChannelToggleBtn") && path.match(/\/channel\/.+/)) {
                         const chanId = path.split("/").pop();
                         if (!chanId)
                             return error("Couldn't extract channel ID from URL");
                         document.querySelectorAll(".bytm-auto-like-toggle-btn").forEach((btn) => clearNode(btn));
-                        addSelectorListener("browseResponse", "ytmusic-browse-response #header .actions .buttons", {
-                            listener(buttonsCont) {
-                                var _a, _b;
-                                const lastBtn = buttonsCont.querySelector("ytmusic-subscribe-button-renderer");
-                                const chanName = (_b = (_a = document.querySelector("ytmusic-immersive-header-renderer .content-container yt-formatted-string[role=\"heading\"]")) === null || _a === void 0 ? void 0 : _a.textContent) !== null && _b !== void 0 ? _b : null;
-                                lastBtn && addAutoLikeToggleBtn(lastBtn, chanId, chanName);
+                        addSelectorListener("browseResponse", "ytmusic-browse-response #header.ytmusic-browse-response", {
+                            listener(headerCont) {
+                                var _a, _b, _c, _d;
+                                const buttonsCont = headerCont.querySelector(".buttons");
+                                if (buttonsCont) {
+                                    const lastBtn = buttonsCont.querySelector("ytmusic-subscribe-button-renderer");
+                                    const chanName = (_b = (_a = document.querySelector("ytmusic-immersive-header-renderer .content-container yt-formatted-string[role=\"heading\"]")) === null || _a === void 0 ? void 0 : _a.textContent) !== null && _b !== void 0 ? _b : null;
+                                    lastBtn && addAutoLikeToggleBtn(lastBtn, chanId, chanName);
+                                }
+                                else {
+                                    // some channels don't have a subscribe button and instead only have a "share" button for some bullshit reason
+                                    // (this is only the case on YTM, on YT the subscribe button exists and works perfectly fine)
+                                    const shareBtnEl = headerCont.querySelector("ytmusic-menu-renderer #top-level-buttons yt-button-renderer:last-of-type");
+                                    const chanName = (_d = (_c = headerCont.querySelector("ytmusic-visual-header-renderer .content-container h2 yt-formatted-string")) === null || _c === void 0 ? void 0 : _c.textContent) !== null && _d !== void 0 ? _d : null;
+                                    shareBtnEl && chanName && addAutoLikeToggleBtn(shareBtnEl, chanId, chanName);
+                                }
                             }
                         });
                     }
                 });
             }
             else if (getDomain() === "yt") {
-                // TODO:
+                let timeout;
+                siteEvents.on("watchIdChanged", () => {
+                    var _a;
+                    timeout && clearTimeout(timeout);
+                    timeout = setTimeout(() => {
+                        addSelectorListener("watchMetadata", "#owner ytd-channel-name yt-formatted-string a", {
+                            listener(chanElem) {
+                                let chanId = chanElem.href.split("/").pop();
+                                if (chanId === null || chanId === void 0 ? void 0 : chanId.startsWith("@"))
+                                    chanId = chanId.slice(1);
+                                const likeChan = autoLikeStore.getData().channels.find((ch) => ch.id === chanId);
+                                if (!likeChan || !likeChan.enabled)
+                                    return;
+                                const likeBtn = document.querySelector("#actions ytd-menu-renderer like-button-view-model button");
+                                if (!likeBtn)
+                                    return error("Couldn't auto-like channel because the like button couldn't be found");
+                                if (likeBtn.getAttribute("aria-pressed") !== "true") {
+                                    likeBtn.click();
+                                    showIconToast({
+                                        message: t("auto_liked_video"),
+                                        icon: "icon-auto_like",
+                                    });
+                                    log(`Auto-liked channel '${likeChan.name}' (ID: '${likeChan.id}')`);
+                                }
+                            }
+                        });
+                    }, ((_a = getFeature("autoLikeTimeout")) !== null && _a !== void 0 ? _a : 5) * 1000);
+                });
+                siteEvents.on("pathChanged", (path) => {
+                    var _a;
+                    if (path.match(/(\/?@|\/channel\/).+/)) {
+                        const chanId = (_a = path.split("/").pop()) === null || _a === void 0 ? void 0 : _a.replace(/@/g, "");
+                        if (!chanId)
+                            return error("Couldn't extract channel ID from URL");
+                        document.querySelectorAll(".bytm-auto-like-toggle-btn").forEach((btn) => clearNode(btn));
+                        addSelectorListener("ytChannelHeader", "#channel-header-container", {
+                            listener(headerCont) {
+                                var _a, _b;
+                                const titleCont = headerCont.querySelector("ytd-channel-name #container");
+                                if (!titleCont)
+                                    return;
+                                const chanName = (_b = (_a = titleCont.querySelector("yt-formatted-string")) === null || _a === void 0 ? void 0 : _a.textContent) !== null && _b !== void 0 ? _b : null;
+                                const buttonsCont = headerCont.querySelector("#inner-header-container #buttons");
+                                if (buttonsCont) {
+                                    addSelectorListener("ytChannelHeader", "#channel-header-container #other-buttons", {
+                                        listener(otherBtns) {
+                                            addAutoLikeToggleBtn(otherBtns, chanId, chanName, ["left-margin"]);
+                                        }
+                                    });
+                                }
+                                else if (titleCont)
+                                    addAutoLikeToggleBtn(titleCont, chanId, chanName);
+                            }
+                        });
+                    }
+                });
             }
+            log("Initialized auto-like channels feature");
         }
         catch (err) {
             error("Error while auto-liking channel:", err);
         }
     });
 }
-function addAutoLikeToggleBtn(siblingEl, channelId, channelName) {
+function addAutoLikeToggleBtn(siblingEl, channelId, channelName, extraClasses) {
     return __awaiter(this, void 0, void 0, function* () {
         var _a;
-        const chan = autoLikeChannelsStore.getData().channels.find((ch) => ch.id === channelId);
+        const chan = autoLikeStore.getData().channels.find((ch) => ch.id === channelId);
         const buttonEl = yield createLongBtn({
             resourceName: `icon-auto_like${(chan === null || chan === void 0 ? void 0 : chan.enabled) ? "_enabled" : ""}`,
             text: t("auto_like"),
@@ -3955,25 +4058,28 @@ function addAutoLikeToggleBtn(siblingEl, channelId, channelName) {
                     const imgHtml = yield resourceToHTMLString(`icon-auto_like${toggled ? "_enabled" : ""}`);
                     if (imgEl && imgHtml)
                         imgEl.innerHTML = imgHtml;
-                    showIconToast(toggled ? t("auto_like_enabled_toast") : t("auto_like_disabled_toast"), `icon-auto_like${toggled ? "_enabled" : ""}`);
-                    if (autoLikeChannelsStore.getData().channels.find((ch) => ch.id === chanId) === undefined) {
-                        yield autoLikeChannelsStore.setData({
+                    showIconToast({
+                        message: toggled ? t("auto_like_enabled_toast") : t("auto_like_disabled_toast"),
+                        icon: `icon-auto_like${toggled ? "_enabled" : ""}`,
+                    });
+                    if (autoLikeStore.getData().channels.find((ch) => ch.id === chanId) === undefined) {
+                        yield autoLikeStore.setData({
                             channels: [
-                                ...autoLikeChannelsStore.getData().channels,
+                                ...autoLikeStore.getData().channels,
                                 { id: chanId, name: channelName !== null && channelName !== void 0 ? channelName : "", enabled: toggled },
                             ],
                         });
                     }
                     else {
-                        yield autoLikeChannelsStore.setData({
-                            channels: autoLikeChannelsStore.getData().channels
+                        yield autoLikeStore.setData({
+                            channels: autoLikeStore.getData().channels
                                 .map((ch) => ch.id === chanId ? Object.assign(Object.assign({}, ch), { enabled: toggled }) : ch),
                         });
                     }
                 });
             }
         });
-        buttonEl.classList.add("bytm-auto-like-toggle-btn");
+        buttonEl.classList.add(...["bytm-auto-like-toggle-btn", ...(extraClasses !== null && extraClasses !== void 0 ? extraClasses : [])]);
         buttonEl.dataset.channelId = channelId;
         siblingEl.insertAdjacentElement("afterend", buttonEl);
     });
@@ -5112,16 +5218,36 @@ const featInfo = {
     autoLikeChannels: {
         type: "toggle",
         category: "input",
-        default: false,
+        default: true,
         textAdornment: adornments.reloadRequired,
     },
-    autoLikeChannelToggleButtons: {
+    autoLikeChannelToggleBtn: {
         type: "toggle",
         category: "input",
         default: true,
+        reloadRequired: false,
+        enable: noop,
+    },
+    autoLikePlayerBarToggleBtn: {
+        type: "toggle",
+        category: "input",
+        default: false,
+        textAdornment: adornments.reloadRequired,
+    },
+    autoLikeTimeout: {
+        type: "slider",
+        category: "input",
+        min: 3,
+        max: 30,
+        step: 0.5,
+        default: 5,
+        unit: "s",
+        advanced: true,
+        reloadRequired: false,
+        enable: noop,
         textAdornment: adornments.reloadRequired,
     },
-    openAutoLikeChannelsDialog: {
+    autoLikeOpenMgmtDialog: {
         type: "button",
         category: "input",
         click: () => getAutoLikeChannelsDialog().then(d => d.open()),
@@ -5265,7 +5391,7 @@ function noop() {
 const formatVersion = 5;
 /** Config data format migration dictionary */
 const migrations = {
-    // 1 -> 2 (v1.0)
+    // 1 -> 2 (<=v1.0)
     2: (oldData) => {
         const queueBtnsEnabled = Boolean(oldData.queueButtons);
         delete oldData.queueButtons;
@@ -5307,8 +5433,8 @@ const migrations = {
     ]),
     // 5 -> 6 (v2.1)
     6: (oldData) => useDefaultConfig(oldData, [
-        "autoLikeChannels", "openAutoLikeChannelsDialog",
-        "autoLikeChannelToggleButtons",
+        "autoLikeChannels", "autoLikeChannelToggleBtn", "autoLikePlayerBarToggleBtn",
+        "autoLikeTimeout", "autoLikeOpenMgmtDialog",
     ]),
     // TODO: once advanced filtering is fully implemented, clear cache on migration to fv6
     // 6 -> 7 (v2.x)
@@ -5437,6 +5563,7 @@ const globalFuncs = {
     // TODO: document
     showToast,
     showIconToast,
+    createRipple,
 };
 /** Initializes the BYTM interface */
 function initInterface() {
@@ -5723,6 +5850,34 @@ function initObservers() {
                 globservers.body.addListener(ytGuideSelector, {
                     listener: () => globservers.ytGuide.enable(),
                 });
+                //#region ytdBrowse
+                // -> channel pages for example
+                const ytdBrowseSelector = "ytd-app ytd-page-manager ytd-browse";
+                globservers.ytdBrowse = new UserUtils.SelectorObserver(ytdBrowseSelector, Object.assign(Object.assign({}, defaultObserverOptions), { subtree: true }));
+                globservers.body.addListener(ytdBrowseSelector, {
+                    listener: () => globservers.ytdBrowse.enable(),
+                });
+                //#region ytChannelHeader
+                // -> header of a channel page
+                const ytChannelHeaderSelector = "#header tp-yt-app-header #channel-header";
+                globservers.ytChannelHeader = new UserUtils.SelectorObserver(ytChannelHeaderSelector, Object.assign(Object.assign({}, defaultObserverOptions), { subtree: true }));
+                globservers.ytdBrowse.addListener(ytChannelHeaderSelector, {
+                    listener: () => globservers.ytChannelHeader.enable(),
+                });
+                //#region watchFlexy
+                // -> the main content of the /watch page
+                const watchFlexySelector = "ytd-app ytd-watch-flexy";
+                globservers.watchFlexy = new UserUtils.SelectorObserver(watchFlexySelector, Object.assign(Object.assign({}, defaultObserverOptions), { subtree: true }));
+                globservers.body.addListener(watchFlexySelector, {
+                    listener: () => globservers.watchFlexy.enable(),
+                });
+                //#region watchMetadata
+                // -> the metadata section of the /watch page (title, channel, views, description, buttons, etc. but not comments)
+                const watchMetadataSelector = "#columns #primary-inner ytd-watch-metadata";
+                globservers.watchMetadata = new UserUtils.SelectorObserver(watchMetadataSelector, Object.assign(Object.assign({}, defaultObserverOptions), { subtree: true }));
+                globservers.watchFlexy.addListener(watchMetadataSelector, {
+                    listener: () => globservers.watchMetadata.enable(),
+                });
                 // //#region ytMasthead
                 // -> the masthead (title bar) at the top of the page
                 // const mastheadSelector = "#content ytd-masthead#masthead";
@@ -6277,6 +6432,7 @@ function onDomLoad() {
         const domain = getDomain();
         const features = getFeatures();
         const ftInit = [];
+        document.body.classList.add(`bytm-dom-${domain}`);
         try {
             initObservers();
             yield Promise.allSettled([
@@ -6291,8 +6447,6 @@ function onDomLoad() {
         log(`DOM loaded and feature pre-init finished, now initializing all features for domain "${domain}"...`);
         try {
             if (domain === "ytm") {
-                //#region (ytm) misc
-                ftInit.push(["initSiteEvents", initSiteEvents()]);
                 //#region (ytm) welcome dlg
                 if (typeof (yield GM.getValue("bytm-installed")) !== "string") {
                     // open welcome menu with language selector
@@ -6349,6 +6503,8 @@ function onDomLoad() {
                 error("Couldn't add config menu option:", err);
             }
             if (["ytm", "yt"].includes(domain)) {
+                //#region general
+                ftInit.push(["initSiteEvents", initSiteEvents()]);
                 //#region (ytm+yt) layout
                 if (features.disableDarkReaderSites !== "none")
                     disableDarkReader();