浏览代码

ref: implement new vsc //#region comments

Sv443 1 年之前
父节点
当前提交
35353c0990

+ 6 - 12
.vscode/settings.json

@@ -18,21 +18,15 @@
       "color": "black",
       "overviewRulerColor": "#ed0",
     },
-    "(#MARKER)": { // #MARKER test
-      "backgroundColor": "#c31",
+    "((//\\s?)?#region ([^\\S\\r\\n]*[\\w,.\\-_&]+)*[:]*)": { //#region test
+      "backgroundColor": "#069",
       "color": "#fff",
-      "isWholeLine": true,
-      "overviewRulerColor": "#c31",
-    },
-    "(#SECTION ([^\\S\\r\\n]*[\\w,.\\-_&]+)*[:]*)": { // #SECTION test, 123 & foo
-      "backgroundColor": "#44f",
-      "color": "white",
-      "overviewRulerColor": "#44f",
+      "overviewRulerColor": "#069",
     },
     "((<!--\\s*)?</?\\{\\{[A-Z_-]+\\}\\}>(\\s*-->)?)": { // <!-- <{{FOO}}> --> and <!-- </{{FOO}}> --> or <{{BAR}}> and </{{BAR}}>
-      "overviewRulerColor": "#2ae",
-      "backgroundColor": "#2ae",
-      "color": "#002",
+      "backgroundColor": "#9af",
+      "overviewRulerColor": "#9af",
+      "color": "#000",
     },
     "(#?(DEBUG|DBG)#?)": { // #DEBUG or DEBUG or #DBG or #DBG#
       "backgroundColor": "#ff0",

+ 4 - 4
contributing.md

@@ -18,7 +18,7 @@ If you have any questions or need help, feel free to contact me, [see my homepag
 
 <br><br>
 
-<!-- #MARKER translations -->
+<!-- #region translations -->
 
 ### Submitting translations:
 Thank you so much for your interest in translating BetterYTM!  
@@ -62,7 +62,7 @@ To edit an existing translation, please follow these steps:
 
 <br><br><br>
 
-<!-- #MARKER local dev -->
+<!-- #region local dev -->
 
 ### Setting up the project for local development:
 #### Requirements:
@@ -133,7 +133,7 @@ Note: the tab needs to stay open on Firefox or the script will not update itself
 
 <br><br><br>
 
-<!-- #MARKER plugin interface -->
+<!-- #region plugin interface -->
 
 ### Developing a plugin that interfaces with BetterYTM:
 BetterYTM has a built-in interface based on events and exposed global constants and functions that allows other userscripts to benefit from its features.  
@@ -252,7 +252,7 @@ An easy way to do this might be to include BetterYTM as a Git submodule, as long
 
 <br><br>
 
-<!-- #MARKER global interface functions -->
+<!-- #region global interface functions -->
 
 ### Global functions:
 These are the global functions that are exposed by BetterYTM through the `unsafeWindow.BYTM` object.  

+ 7 - 7
src/components/BytmDialog.ts

@@ -69,7 +69,7 @@ export class BytmDialog extends NanoEmitter<{
     this.id = options.id;
   }
 
-  //#MARKER public
+  //#region public
 
   /** Call after DOMContentLoaded to pre-render the dialog and invisibly mount it in the DOM */
   public async mount() {
@@ -210,14 +210,14 @@ export class BytmDialog extends NanoEmitter<{
     this.unsubscribeAll();
   }
 
-  //#MARKER static
+  //#region static
 
   /** Returns the ID of the top-most dialog (the dialog that has been opened last) */
   public static getCurrentDialogId() {
     return currentDialogId;
   }
 
-  //#MARKER protected
+  //#region protected
 
   /** Called once to attach all generic event listeners */
   protected attachListeners(bgElem: HTMLElement) {
@@ -236,7 +236,7 @@ export class BytmDialog extends NanoEmitter<{
     }
   }
 
-  //#MARKER private
+  //#region private
 
   /** Returns the dialog content element and all its children */
   private async getDialogContent() {
@@ -251,7 +251,7 @@ export class BytmDialog extends NanoEmitter<{
     dialogWrapperEl.setAttribute("aria-labelledby", `bytm-${this.id}-dialog-title`);
     dialogWrapperEl.setAttribute("aria-describedby", `bytm-${this.id}-dialog-body`);
 
-    //#SECTION header
+    //#region header
 
     const headerWrapperEl = document.createElement("div");
     headerWrapperEl.classList.add("bytm-dialog-header");
@@ -288,7 +288,7 @@ export class BytmDialog extends NanoEmitter<{
 
     dialogWrapperEl.appendChild(headerWrapperEl);
 
-    //#SECTION body
+    //#region body
 
     const dialogBodyElem = document.createElement("div");
     dialogBodyElem.id = `bytm-${this.id}-dialog-body`;
@@ -300,7 +300,7 @@ export class BytmDialog extends NanoEmitter<{
     dialogBodyElem.appendChild(body instanceof Promise ? await body : body);
     dialogWrapperEl.appendChild(dialogBodyElem);
 
-    //#SECTION footer
+    //#region footer
 
     if(footer) {
       const footerWrapper = document.createElement("div");

+ 4 - 4
src/features/behavior.ts

@@ -4,7 +4,7 @@ import { LogLevel } from "../types";
 import { getFeatures } from "src/config";
 import { addSelectorListener } from "src/observers";
 
-//#MARKER beforeunload popup
+//#region beforeunload popup
 
 let beforeUnloadEnabled = true;
 
@@ -25,7 +25,7 @@ export async function initBeforeUnloadHook() {
   interceptWindowEvent("beforeunload", () => !beforeUnloadEnabled);
 }
 
-//#MARKER auto close toasts
+//#region auto close toasts
 
 /** Closes toasts after a set amount of time */
 export async function initAutoCloseToasts() {
@@ -65,7 +65,7 @@ export async function initAutoCloseToasts() {
   }
 }
 
-//#MARKER remember song time
+//#region remember song time
 
 interface RemSongObj {
   /** Watch ID */
@@ -184,7 +184,7 @@ async function delRemSongData(watchID: string) {
   await GM.setValue("bytm-rem-songs", JSON.stringify(remSongsCache));
 }
 
-//#MARKER disable darkreader
+//#region disable darkreader
 
 /** Disables Dark Reader if it is enabled */
 export function disableDarkReader() {

+ 9 - 9
src/features/index.ts

@@ -18,7 +18,7 @@ export * from "./volume";
 
 type SelectOption = { value: number | string, label: string };
 
-//#MARKER feature dependencies
+//#region dependencies
 
 /** List of all available locale SelectOptions */
 const localeOptions = Object.entries(langMapping).reduce((a, [locale, { name }]) => {
@@ -49,7 +49,7 @@ const options = {
   ],
 };
 
-//#MARKER features
+//#region features
 
 /**
  * Contains all possible features with their default values and other configuration.  
@@ -84,7 +84,7 @@ const options = {
  * - If no `disable()` or `change()` function is present, the page needs to be reloaded for the changes to take effect
  */
 export const featInfo = {
-  //#SECTION layout
+  //#region layout
   watermarkEnabled: {
     type: "toggle",
     category: "layout",
@@ -191,7 +191,7 @@ export const featInfo = {
     textAdornment: adornments.advanced,
   },
 
-  //#SECTION volume
+  //#region volume
   volumeSliderLabel: {
     type: "toggle",
     category: "volume",
@@ -258,7 +258,7 @@ export const featInfo = {
     textAdornment: () => getFeatures().volumeSharedBetweenTabs ? adornments.warning(t("feature_warning_setInitialTabVolume_volumeSharedBetweenTabs_incompatible").replace(/"/g, "'")) : undefined,
   },
 
-  //#SECTION song lists
+  //#region song lists
   lyricsQueueButton: {
     type: "toggle",
     category: "songLists",
@@ -285,7 +285,7 @@ export const featInfo = {
     disable: noop,
   },
 
-  //#SECTION behavior
+  //#region behavior
   disableBeforeUnloadPopup: {
     type: "toggle",
     category: "behavior",
@@ -359,7 +359,7 @@ export const featInfo = {
     textAdornment: adornments.advanced,
   },
 
-  //#SECTION input
+  //#region input
   arrowKeySupport: {
     type: "toggle",
     category: "input",
@@ -411,7 +411,7 @@ export const featInfo = {
     disable: noop,
   },
 
-  //#SECTION lyrics
+  //#region lyrics
   geniusLyrics: {
     type: "toggle",
     category: "lyrics",
@@ -487,7 +487,7 @@ export const featInfo = {
     textAdornment: adornments.experimental,
   },
 
-  //#SECTION general
+  //#region general
   locale: {
     type: "select",
     category: "general",

+ 3 - 3
src/features/input.ts

@@ -9,7 +9,7 @@ import { getFeatures } from "../config";
 
 export const inputIgnoreTagNames = ["INPUT", "TEXTAREA", "SELECT", "BUTTON", "A"];
 
-//#MARKER arrow key skip
+//#region arrow key skip
 
 export async function initArrowKeySkip() {
   document.addEventListener("keydown", (evt) => {
@@ -36,7 +36,7 @@ export async function initArrowKeySkip() {
   log("Added arrow key press listener");
 }
 
-//#MARKER site switch
+//#region site switch
 
 /** switch sites only if current video time is greater than this value */
 const videoTimeThreshold = 3;
@@ -100,7 +100,7 @@ async function switchSite(newDomain: Domain) {
   }
 }
 
-//#MARKER number keys skip to time
+//#region num key skip to
 
 const numKeysIgnoreTagNames = [...inputIgnoreTagNames, "TP-YT-PAPER-TAB"];
 const numKeysIgnoreIds = ["progress-bar", "song-media-window"];

+ 5 - 5
src/features/layout.css

@@ -1,4 +1,4 @@
-/* #MARKER misc */
+/* #region misc */
 
 .bytm-disable-scroll {
   overflow: hidden !important;
@@ -140,7 +140,7 @@ button[disabled].bytm-busy {
   cursor: progress;
 }
 
-/* #MARKER menu */
+/* #region menu */
 
 .bytm-cfg-menu-option {
   display: block;
@@ -183,7 +183,7 @@ yt-multi-page-menu-section-renderer.ytd-multi-page-menu-renderer {
   border-bottom: 1px solid var(--yt-spec-10-percent-layer, #3e3e3e);
 }
 
-/* #MARKER watermark */
+/* #region watermark */
 
 #bytm-watermark {
   font-size: 10px;
@@ -201,7 +201,7 @@ yt-multi-page-menu-section-renderer.ytd-multi-page-menu-renderer {
   text-decoration: underline;
 }
 
-/* #MARKER scroll to active */
+/* #region scroll to active */
 
 #bytm-scroll-to-active-btn-cont {
   display: flex;
@@ -235,7 +235,7 @@ yt-multi-page-menu-section-renderer.ytd-multi-page-menu-renderer {
   padding: 4px;
 }
 
-/** #MARKER thumbnail */
+/** #region thumbnail */
 
 #bytm-thumbnail-overlay {
   position: absolute;

+ 10 - 10
src/features/layout.ts

@@ -8,7 +8,7 @@ import { openCfgMenu } from "../menu/menu_old";
 import { createGenericBtn } from "../components";
 import "./layout.css";
 
-//#MARKER BYTM-Config buttons
+//#region cfg menu buttons
 
 let logoExchanged = false, improveLogoCalled = false;
 
@@ -167,7 +167,7 @@ export async function addConfigMenuOptionYT(container: HTMLElement) {
   }
 }
 
-//#MARKER remove upgrade tab
+//#region rem upgrade tab
 
 /** Removes the "Upgrade" / YT Music Premium tab from the sidebar */
 export async function removeUpgradeTab() {
@@ -185,7 +185,7 @@ export async function removeUpgradeTab() {
   });
 }
 
-//#MARKER anchor improvements
+//#region anchor improvements
 
 /** Adds anchors around elements and tweaks existing ones so songs are easier to open in a new tab */
 export async function addAnchorImprovements() {
@@ -198,7 +198,7 @@ export async function addAnchorImprovements() {
     error("Couldn't add anchor improvements CSS due to an error:", err);
   }
 
-  //#SECTION carousel shelves
+  //#region carousel shelves
   try {
     const preventDefault = (e: MouseEvent) => e.preventDefault();
 
@@ -266,7 +266,7 @@ export async function addAnchorImprovements() {
     error("Couldn't improve carousel shelf anchors due to an error:", err);
   }
 
-  //#SECTION sidebar
+  //#region sidebar
 
   try {
     const addSidebarAnchors = (sidebarCont: HTMLElement) => {
@@ -320,7 +320,7 @@ function improveSidebarAnchors(sidebarItems: NodeListOf<HTMLElement>) {
   });
 }
 
-//#MARKER remove share tracking param
+//#region rem tracking param
 
 /** Removes the ?si tracking parameter from share URLs */
 export async function initRemShareTrackParam() {
@@ -363,7 +363,7 @@ export async function initRemShareTrackParam() {
   });
 }
 
-//#MARKER fix margins
+//#region fix spacing
 
 /** Applies global CSS to fix various spacings */
 export async function fixSpacing() {
@@ -377,7 +377,7 @@ export async function fixSpacing() {
   }
 }
 
-//#MARKER scroll to active song
+//#region scroll to active
 
 /** Adds a button to the queue to scroll to the active song */
 export async function addScrollToActiveBtn() {
@@ -425,7 +425,7 @@ export async function addScrollToActiveBtn() {
   });
 }
 
-//#MARKER thumbnail overlay
+//#region thumbnail overlay
 
 /** To be changed when the toggle button is pressed - used to invert the state of "showOverlay" */
 let invertOverlay = false;
@@ -589,7 +589,7 @@ export async function initThumbnailOverlay() {
   });
 }
 
-//#MARKER hide cursor on idle
+//#region hide cursor on idle
 
 export async function initHideCursorOnIdle() {
   addSelectorListener("mainPanel", "ytmusic-player#player", {

+ 2 - 2
src/features/lyrics.ts

@@ -11,7 +11,7 @@ import { addSelectorListener } from "src/observers";
 /** Ratelimit budget timeframe in seconds - should reflect what's in geniURL's docs */
 const geniUrlRatelimitTimeframe = 30;
 
-//#MARKER media control bar
+//#region media control bar
 
 let currentSongTitle = "";
 
@@ -110,7 +110,7 @@ async function addActualMediaCtrlLyricsBtn(likeContainer: HTMLElement) {
   obs.observe(songTitleElem, { attributes: true, attributeFilter: [ "title" ] });
 }
 
-//#MARKER utils
+//#region lyrics utils
 
 /** Removes everything in parentheses from the passed song name */
 export function sanitizeSong(songName: string) {

+ 1 - 1
src/features/songLists.css

@@ -1,4 +1,4 @@
-/* #MARKER queue buttons */
+/* #region queue buttons */
 
 #side-panel ytmusic-player-queue-item .song-info.ytmusic-player-queue-item {
   position: relative;

+ 2 - 5
src/features/songLists.ts

@@ -84,14 +84,13 @@ async function addQueueButtons(
   listType: "currentQueue" | "genericQueue" = "currentQueue",
   classes: string[] = [],
 ) {
-  //#SECTION general queue item stuff
   const queueBtnsCont = document.createElement("div");
   queueBtnsCont.classList.add("bytm-queue-btn-container", ...classes);
 
   const lyricsIconUrl = await getResourceUrl("icon-lyrics");
   const deleteIconUrl = await getResourceUrl("icon-delete");
 
-  //#SECTION lyrics btn
+  //#region lyrics
   let lyricsBtnElem: HTMLAnchorElement | undefined;
 
   if(getFeatures().lyricsQueueButton) {
@@ -196,7 +195,7 @@ async function addQueueButtons(
     });
   }
 
-  //#SECTION delete from queue btn
+  //#region delete from queue
   let deleteBtnElem: HTMLAnchorElement | undefined;
 
   if(getFeatures().deleteFromQueueButton) {
@@ -265,8 +264,6 @@ async function addQueueButtons(
     deleteBtnElem.appendChild(imgElem);
   }
 
-  //#SECTION append elements to DOM
-
   lyricsBtnElem && queueBtnsCont.appendChild(lyricsBtnElem);
   deleteBtnElem && queueBtnsCont.appendChild(deleteBtnElem);
 

+ 1 - 1
src/features/volume.css

@@ -1,4 +1,4 @@
-/* #MARKER volume slider */
+/* #region volume slider */
 
 #bytm-vol-slider-cont {
   position: relative;

+ 7 - 9
src/features/volume.ts

@@ -6,7 +6,7 @@ import { featInfo } from ".";
 import "./volume.css";
 import { addSelectorListener } from "src/observers";
 
-//#MARKER init
+//#region init vol features
 
 /** Initializes all volume-related features */
 export async function initVolumeFeatures() {
@@ -40,7 +40,7 @@ export async function initVolumeFeatures() {
   });
 }
 
-//#MARKER scroll step
+//#region scroll step
 
 /** Initializes the volume slider scroll step features */
 function initScrollStep(volSliderCont: HTMLDivElement, sliderElem: HTMLInputElement) {
@@ -65,9 +65,7 @@ function initScrollStep(volSliderCont: HTMLDivElement, sliderElem: HTMLInputElem
   }
 }
 
-// #MARKER volume slider
-
-//#SECTION label
+//#region volume slider label
 
 /** Adds a percentage label to the volume slider and tooltip */
 async function addVolumeSliderLabel(sliderElem: HTMLInputElement, sliderContainer: HTMLDivElement) {
@@ -150,7 +148,7 @@ async function addVolumeSliderLabel(sliderElem: HTMLInputElement, sliderContaine
   });
 }
 
-//#SECTION size
+//#region volume slider size
 
 /** Sets the volume slider to a set size */
 function setVolSliderSize() {
@@ -165,14 +163,14 @@ function setVolSliderSize() {
 }`, "vol-slider-size");
 }
 
-//#SECTION step
+//#region volume slider step
 
 /** Sets the `step` attribute of the volume slider */
 function setVolSliderStep(sliderElem: HTMLInputElement) {
   sliderElem.setAttribute("step", String(getFeatures().volumeSliderStep));
 }
 
-//#MARKER shared volume
+//#region shared volume
 
 /** Saves the shared volume level to persistent storage */
 async function sharedVolumeChanged(vol: number) {
@@ -214,7 +212,7 @@ export async function volumeSharedBetweenTabsDisabled() {
   await GM.deleteValue("bytm-shared-volume");
 }
 
-//#MARKER initial volume
+//#region initial volume
 
 /** Sets the volume slider to a set volume level when the session starts */
 async function setInitialTabVolume(sliderElem: HTMLInputElement) {

+ 10 - 8
src/interface.ts

@@ -11,6 +11,8 @@ import { BytmDialog, createHotkeyInput, createToggleInput } from "./components";
 
 const { getUnsafeWindow } = UserUtils;
 
+//#region interface globals
+
 /** All events that can be emitted on the BYTM interface and the data they provide */
 export type InterfaceEvents = {
   /** Emitted whenever the plugins should be registered using `unsafeWindow.BYTM.registerPlugin()` */
@@ -74,12 +76,6 @@ const globalFuncs = {
   compareVersionArrays,
 };
 
-/** Plugins that are queued up for registration */
-const pluginQueue = new Map<string, PluginItem>();
-
-/** Registered plugins including their event listener instance */
-const pluginMap = new Map<string, PluginItem>();
-
 /** Initializes the BYTM interface */
 export function initInterface() {
   const props = {
@@ -131,7 +127,13 @@ export function emitInterface<
   getUnsafeWindow().dispatchEvent(new CustomEvent(type, { detail: data[0] }));
 }
 
-//#MARKER register plugins
+//#region register plugins
+
+/** Plugins that are queued up for registration */
+const pluginQueue = new Map<string, PluginItem>();
+
+/** Registered plugins including their event listener instance */
+const pluginMap = new Map<string, PluginItem>();
 
 /** Initializes plugins that have been registered already. Needs to be run after `bytm:ready`! */
 export function initPlugins() {
@@ -243,7 +245,7 @@ export function registerPlugin(def: PluginDef): PluginRegisterResult {
   };
 }
 
-//#MARKER proxy functions
+//#region proxy funcs
 
 /** Returns the current feature config, with sensitive values replaced by `undefined` */
 export function getFeaturesInterface() {

+ 12 - 8
src/menu/menu_old.ts

@@ -10,7 +10,7 @@ import "./menu_old.css";
 import { createHotkeyInput, createToggleInput } from "../components";
 import pkg from "../../package.json" assert { type: "json" };
 
-//#MARKER create menu elements
+//#region create menu
 
 let isCfgMenuAdded = false;
 export let isCfgMenuOpen = false;
@@ -38,7 +38,7 @@ async function addCfgMenu() {
 
   const initLangReloadText = t("lang_changed_prompt_reload");
 
-  //#SECTION backdrop & menu container
+  //#region bg & container
   const backgroundElem = document.createElement("div");
   backgroundElem.id = "bytm-cfg-menu-bg";
   backgroundElem.classList.add("bytm-menu-bg");
@@ -60,7 +60,7 @@ async function addCfgMenu() {
   menuContainer.id = "bytm-cfg-menu";
 
 
-  //#SECTION title bar
+  //#region title bar
   const headerElem = document.createElement("div");
   headerElem.classList.add("bytm-menu-header");
 
@@ -145,7 +145,7 @@ async function addCfgMenu() {
   headerElem.appendChild(titleCont);
   headerElem.appendChild(closeElem);
 
-  //#SECTION footer
+  //#region footer
   const footerCont = document.createElement("div");
   footerCont.className = "bytm-menu-footer-cont";
 
@@ -215,7 +215,7 @@ async function addCfgMenu() {
   footerCont.appendChild(buttonsCont);
 
 
-  //#SECTION feature list
+  //#region feature list
   const featuresCont = document.createElement("div");
   featuresCont.id = "bytm-menu-opts";
 
@@ -607,7 +607,7 @@ async function addCfgMenu() {
     }
   }
 
-  //#SECTION set values of inputs on external change
+  //#region reset inputs on external change
   siteEvents.on("rebuildCfgMenu", (newConfig) => {
     for(const ftKey in featInfo) {
       const ftElem = document.querySelector<HTMLInputElement>(`#bytm-ftconf-${ftKey}-input`);
@@ -641,7 +641,7 @@ async function addCfgMenu() {
     info("Rebuilt config menu");
   });
 
-  //#SECTION scroll indicator
+  //#region scroll indicator
   const scrollIndicator = document.createElement("img");
   scrollIndicator.id = "bytm-menu-scroll-indicator";
   scrollIndicator.src = await getResourceUrl("icon-arrow_down");
@@ -677,7 +677,7 @@ async function addCfgMenu() {
   featuresCont.appendChild(bottomAnchor);
 
 
-  //#SECTION finalize
+  //#region finalize
   menuContainer.appendChild(headerElem);
   menuContainer.appendChild(featuresCont);
 
@@ -735,6 +735,8 @@ async function addCfgMenu() {
   backgroundElem.style.display = "none";
 }
 
+//#region open & close
+
 /** Closes the config menu if it is open. If a bubbling event is passed, its propagation will be prevented. */
 export function closeCfgMenu(evt?: MouseEvent | KeyboardEvent, enableScroll = true) {
   if(!isCfgMenuOpen)
@@ -781,6 +783,8 @@ export async function openCfgMenu() {
   checkToggleScrollIndicator();
 }
 
+//#region chk scroll indicator
+
 /** Checks if the features container is scrollable and toggles the scroll indicator accordingly */
 function checkToggleScrollIndicator() {
   const featuresCont = document.querySelector<HTMLElement>("#bytm-menu-opts");

+ 30 - 17
src/observers.ts

@@ -43,9 +43,10 @@ export const globservers = {} as Record<ObserverName, SelectorObserver>;
 /** Call after DOM load to initialize all SelectorObserver instances */
 export function initObservers() {
   try {
-    //#MARKER both sites
+    //#region both sites
 
-    // #SECTION body = the entire <body> element - use sparingly due to performance impacts!
+    //#region body
+    // -> the entire <body> element - use sparingly due to performance impacts!
     globservers.body = new SelectorObserver(document.body, {
       ...defaultObserverOptions,
       defaultDebounce: 150,
@@ -56,9 +57,10 @@ export function initObservers() {
 
     switch(getDomain()) {
     case "ytm": {
-      //#MARKER YTM
+      //#region YTM
 
-      //#SECTION navBar = the navigation / title bar at the top of the page
+      //#region navBar
+      // -> the navigation / title bar at the top of the page
       const navBarSelector = "ytmusic-nav-bar";
       globservers.navBar = new SelectorObserver(navBarSelector, {
         ...defaultObserverOptions,
@@ -69,7 +71,8 @@ export function initObservers() {
         listener: () => globservers.navBar.enable(),
       });
 
-      // #SECTION mainPanel = the main content panel - includes things like the video element
+      //#region mainPanel
+      // -> the main content panel - includes things like the video element
       const mainPanelSelector = "ytmusic-player-page #main-panel";
       globservers.mainPanel = new SelectorObserver(mainPanelSelector, {
         ...defaultObserverOptions,
@@ -80,7 +83,8 @@ export function initObservers() {
         listener: () => globservers.mainPanel.enable(),
       });
 
-      // #SECTION sideBar = the sidebar on the left side of the page
+      //#region sideBar
+      // -> the sidebar on the left side of the page
       const sidebarSelector = "ytmusic-app-layout tp-yt-app-drawer";
       globservers.sideBar = new SelectorObserver(sidebarSelector, {
         ...defaultObserverOptions,
@@ -91,7 +95,8 @@ export function initObservers() {
         listener: () => globservers.sideBar.enable(),
       });
 
-      // #SECTION sideBarMini = the minimized sidebar on the left side of the page
+      //#region sideBarMini
+      // -> the minimized sidebar on the left side of the page
       const sideBarMiniSelector = "ytmusic-app-layout #mini-guide";
       globservers.sideBarMini = new SelectorObserver(sideBarMiniSelector, {
         ...defaultObserverOptions,
@@ -102,7 +107,8 @@ export function initObservers() {
         listener: () => globservers.sideBarMini.enable(),
       });
 
-      // #SECTION sidePanel = the side panel on the right side of the /watch page
+      //#region sidePanel
+      // -> the side panel on the right side of the /watch page
       const sidePanelSelector = "#side-panel";
       globservers.sidePanel = new SelectorObserver(sidePanelSelector, {
         ...defaultObserverOptions,
@@ -113,7 +119,8 @@ export function initObservers() {
         listener: () => globservers.sidePanel.enable(),
       });
 
-      // #SECTION playerBar = media controls bar at the bottom of the page
+      //#region playerBar
+      // -> media controls bar at the bottom of the page
       const playerBarSelector = "ytmusic-app-layout ytmusic-player-bar.ytmusic-app";
       globservers.playerBar = new SelectorObserver(playerBarSelector, {
         ...defaultObserverOptions,
@@ -126,7 +133,8 @@ export function initObservers() {
         },
       });
 
-      // #SECTION playerBarInfo = song title, artist, album, etc. inside the player bar
+      //#region playerBarInfo
+      // -> song title, artist, album, etc. inside the player bar
       const playerBarInfoSelector = `${playerBarSelector} .middle-controls .content-info-wrapper`;
       globservers.playerBarInfo = new SelectorObserver(playerBarInfoSelector, {
         ...defaultObserverOptions,
@@ -138,7 +146,8 @@ export function initObservers() {
         listener: () => globservers.playerBarInfo.enable(),
       });
 
-      // #SECTION playerBarMiddleButtons = the buttons inside the player bar (like, dislike, lyrics, etc.)
+      //#region playerBarMiddleButtons
+      // -> the buttons inside the player bar (like, dislike, lyrics, etc.)
       const playerBarMiddleButtonsSelector = ".middle-controls .middle-controls-buttons";
       globservers.playerBarMiddleButtons = new SelectorObserver(playerBarMiddleButtonsSelector, {
         ...defaultObserverOptions,
@@ -149,7 +158,8 @@ export function initObservers() {
         listener: () => globservers.playerBarMiddleButtons.enable(),
       });
 
-      // #SECTION playerBarRightControls = the controls on the right side of the player bar (volume, repeat, shuffle, etc.)
+      //#region playerBarRightControls
+      // -> the controls on the right side of the player bar (volume, repeat, shuffle, etc.)
       const playerBarRightControls = "#right-controls";
       globservers.playerBarRightControls = new SelectorObserver(playerBarRightControls, {
         ...defaultObserverOptions,
@@ -160,7 +170,8 @@ export function initObservers() {
         listener: () => globservers.playerBarRightControls.enable(),
       });
 
-      // #SECTION popupContainer = the container for popups (e.g. the queue popup)
+      //#region popupContainer
+      // -> the container for popups (e.g. the queue popup)
       const popupContainerSelector = "ytmusic-app ytmusic-popup-container";
       globservers.popupContainer = new SelectorObserver(popupContainerSelector, {
         ...defaultObserverOptions,
@@ -174,9 +185,10 @@ export function initObservers() {
       break;
     }
     case "yt": {
-      //#MARKER YT
+      //#region YT
 
-      // #SECTION ytGuide = the left sidebar menu
+      //#region ytGuide
+      // -> the left sidebar menu
       const ytGuideSelector = "#content tp-yt-app-drawer#guide #guide-inner-content";
       globservers.ytGuide = new SelectorObserver(ytGuideSelector, {
         ...defaultObserverOptions,
@@ -187,7 +199,8 @@ export function initObservers() {
         listener: () => globservers.ytGuide.enable(),
       });
 
-      // // #SECTION ytMasthead = the masthead at the top of the page
+      // //#region ytMasthead
+      // -> the masthead (title bar) at the top of the page
       // const mastheadSelector = "#content ytd-masthead#masthead";
       // globservers.ytMasthead = new SelectorObserver(mastheadSelector, {
       //   ...defaultObserverOptions,
@@ -200,7 +213,7 @@ export function initObservers() {
     }
     }
 
-    //#SECTION finalize
+    //#region finalize
 
     emitInterface("bytm:observersReady");
   }

+ 4 - 4
src/siteEvents.ts

@@ -69,7 +69,7 @@ export function removeAllObservers() {
 /** Creates MutationObservers that check if parts of the site have changed, then emit an event on the `siteEvents` instance. */
 export async function initSiteEvents() {
   try {
-    //#SECTION queue
+    //#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) {
@@ -102,7 +102,7 @@ export async function initSiteEvents() {
       },
     });
 
-    //#SECTION player bar
+    //#region player bar
 
     let lastTitle: string | null = null;
     let initialPlay = true;
@@ -128,7 +128,7 @@ export async function initSiteEvents() {
       autoplayObs,
     ]);
 
-    //#SECTION player
+    //#region player
 
     const playerFullscreenObs = new MutationObserver(([{ target }]) => {
       const isFullscreen = (target as HTMLElement).getAttribute("player-ui-state")?.toUpperCase() === "FULLSCREEN";
@@ -143,7 +143,7 @@ export async function initSiteEvents() {
       },
     });
 
-    //#SECTION other
+    //#region other
 
     let lastWatchId: string | null = null;
 

+ 1 - 0
src/tools/gen-readme.ts

@@ -64,6 +64,7 @@ async function modifyReadme(readmeLines: string[], changes: Record<string, () =>
     // replace the content between the two lines
     const newContent = await getContent();
     retLines.push(...lines.splice(0, beginLine + 1));
+    retLines.push("<!-- THIS IS GENERATED CONTENT - DO NOT MODIFY DIRECTLY -->");
     retLines.push(...newContent.split(/\r?\n/gm));
     retLines.push(...lines.splice(endLine - beginLine - 1));
 

+ 4 - 4
src/tools/tr-progress.ts

@@ -18,7 +18,7 @@ interface TrFile {
 async function run() {
   console.log("\n\x1b[34mUpdating translation progress...\x1b[0m\n");
 
-  //#SECTION parse
+  //#region parse
 
   const translations = {} as Record<TrLocale, Record<string, string>>;
   const trFiles = {} as Record<TrLocale, TrFile>;
@@ -41,7 +41,7 @@ async function run() {
   const { en_US, ...restLocs } = translations;
   const progress = {} as Record<TrLocale, number>;
 
-  //#SECTION progress table
+  //#region progress table
 
   const progTableLines: string[] = [];
 
@@ -74,7 +74,7 @@ async function run() {
     console.log(`  ${sym} ${locale}: ${trKeys}/${origKeys} (${percent}%)${baseTr ? ` (base: ${baseTr})`: ""}`);
   }
 
-  //#SECTION missing keys
+  //#region missing keys
 
   const missingKeys = [] as string[];
 
@@ -94,7 +94,7 @@ ${lines.join("\n")}\n
     }
   }
 
-  //#SECTION finalize
+  //#region finalize
 
   const banner = `\
 <!--

+ 10 - 10
src/types.ts

@@ -51,7 +51,7 @@ export type LyricsCacheEntry = {
   added: number;
 };
 
-//#MARKER global
+//#region global
 
 // shim for the BYTM interface properties
 export type BytmObject =
@@ -80,7 +80,7 @@ declare global {
   }
 }
 
-//#MARKER plugins
+//#region plugins
 
 /**
  * Intents (permissions) BYTM has to grant your plugin for it to be able to access certain features.  
@@ -204,7 +204,7 @@ export type InterfaceFunctions = {
   saveFeatures: typeof setFeatures;
 };
 
-//#MARKER features
+//#region features
 
 export type FeatureKey = keyof FeatureConfig;
 
@@ -306,7 +306,7 @@ export type FeatureInfo = Record<
 
 /** Feature configuration */
 export interface FeatureConfig {
-  //#SECTION layout
+  //#region layout
   /** Show a BetterYTM watermark under the YTM logo */
   watermarkEnabled: boolean;
   /** Remove the "si" tracking parameter from links in the share menu? */
@@ -332,7 +332,7 @@ export interface FeatureConfig {
   /** Delay in seconds after which the cursor should be hidden */
   hideCursorOnIdleDelay: number;
 
-  //#SECTION volume
+  //#region volume
   /** Add a percentage label to the volume slider */
   volumeSliderLabel: boolean;
   /** The width of the volume slider in pixels */
@@ -348,7 +348,7 @@ export interface FeatureConfig {
   /** The initial volume level to set for each new session */
   initialTabVolumeLevel: number;
 
-  //#SECTION song lists
+  //#region song lists
   /** Add a button to each song in the queue to quickly open its lyrics page */
   lyricsQueueButton: boolean;
   /** Add a button to each song in the queue to quickly remove it */
@@ -358,7 +358,7 @@ export interface FeatureConfig {
   /** Add a button to the queue to scroll to the currently playing song */
   scrollToActiveSongBtn: boolean;
 
-  //#SECTION behavior
+  //#region behavior
   /** Whether to completely disable the popup that sometimes appears before leaving the site */
   disableBeforeUnloadPopup: boolean;
   /** After how many milliseconds to close permanent toasts */
@@ -374,7 +374,7 @@ export interface FeatureConfig {
   /** Minimum time in seconds the song needs to be played before it is remembered */
   rememberSongTimeMinPlayTime: number;
 
-  //#SECTION input
+  //#region input
   /** Arrow keys skip forwards and backwards */
   arrowKeySupport: boolean;
   /** By how many seconds to skip when pressing the arrow keys */
@@ -386,7 +386,7 @@ export interface FeatureConfig {
   /** Make it so middle clicking a song to open it in a new tab (through thumbnail and song title) is easier */
   anchorImprovements: boolean;
 
-  //#SECTION lyrics
+  //#region lyrics
   /** Add a button to the media controls to open the current song's lyrics on genius.com in a new tab */
   geniusLyrics: boolean;
   /** Base URL to use for GeniURL */
@@ -402,7 +402,7 @@ export interface FeatureConfig {
   /** Whether to use advanced filtering when searching for lyrics (exact, exact-ish) */
   advancedLyricsFilter: boolean;
 
-  //#SECTION misc
+  //#region misc
   /** The locale to use for translations */
   locale: TrLocale;
   /** Whether to check for updates to the script */

+ 2 - 2
src/utils/dom.ts

@@ -2,7 +2,7 @@ import { addGlobalStyle, getUnsafeWindow, randomId } from "@sv443-network/userut
 import { error, getDomain } from ".";
 import { addSelectorListener } from "src/observers";
 
-//#MARKER video time & volume
+//#region video time, volume
 
 export const videoSelector = getDomain() === "ytm" ? "ytmusic-player video" : "#player-container ytd-player video";
 
@@ -121,7 +121,7 @@ export function waitVideoElementReady(): Promise<HTMLVideoElement> {
   });
 }
 
-//#MARKER other
+//#region other
 
 /** Whether the DOM has finished loading and elements can be added or modified */
 export let domLoaded = false;

+ 2 - 2
src/utils/misc.ts

@@ -5,7 +5,7 @@ import { type Domain, type ResourceKey } from "../types";
 import { error, type TrLocale, warn } from ".";
 import langMapping from "../../assets/locales.json" assert { type: "json" };
 
-//#SECTION misc
+//#region misc
 
 /**
  * Returns the current domain as a constant string representation
@@ -105,7 +105,7 @@ export function reserialize<T>(data: T): T {
   return JSON.parse(JSON.stringify(data));
 }
 
-//#SECTION resources
+//#region resources
 
 /**
  * Returns the URL of a resource by its name, as defined in `assets/resources.json`, from GM resource cache - [see GM.getResourceUrl docs](https://wiki.greasespot.net/GM.getResourceUrl)