Pārlūkot izejas kodu

feat: carouselShelvesChanged site event

Sv443 1 gadu atpakaļ
vecāks
revīzija
83f4c0fa0e
4 mainītis faili ar 41 papildinājumiem un 14 dzēšanām
  1. 2 2
      src/BetterYTM.user.ts
  2. 7 1
      src/features/layout.ts
  3. 3 0
      src/tools/post-build.ts
  4. 29 11
      src/utils.ts

+ 2 - 2
src/BetterYTM.user.ts

@@ -1,4 +1,4 @@
-import { getFeatures } from "./config";
+import { loadFeatureConf } from "./config";
 import { logLevel, scriptInfo } from "./constants";
 import { addGlobalStyle, error, getDomain, initSiteEvents, log, setLogLevel } from "./utils";
 import {
@@ -43,7 +43,7 @@ async function onDomLoad() {
   // post-build these double quotes are replaced by backticks
   addGlobalStyle("{{GLOBAL_STYLE}}", "global");
 
-  const features = await getFeatures();
+  const features = await loadFeatureConf();
 
   log(`Initializing features for domain '${domain}'`);
 

+ 7 - 1
src/features/layout.ts

@@ -74,6 +74,7 @@ export function setVolSliderStep() {
 
 //#MARKER queue buttons
 
+// TODO: account for the fact initially the elements might not exist, if the site was not opened directly with a video playing or via the /watch path
 export function initQueueButtons() {
   siteEvents.on("queueChanged", (evt) => {
     for(const queueItm of ((evt.data as HTMLElement).childNodes as NodeListOf<HTMLElement>)) {
@@ -94,13 +95,18 @@ function addQueueButtons(queueItem: HTMLElement) {
   queueBtnsCont.className = "bytm-queue-btn-container";
   queueBtnsCont.innerText = "ayo";
 
-  const songInfo = queueItem.querySelector(".song-info")!;
+  const songInfo = queueItem.querySelector(".song-info");
+  if(!songInfo)
+    return false;
+
   songInfo.appendChild(queueBtnsCont);
   queueItem.classList.add("bytm-has-queue-btns");
+  return true;
 }
 
 //#MARKER better clickable stuff
 
+// TODO: account for the fact initially the elements might not exist, if the site was opened directly with the /watch path
 export function addAnchorImprovements() {
   void 0;
 }

+ 3 - 0
src/tools/post-build.ts

@@ -71,10 +71,13 @@ ${matchDirectives}\
 
     console.info(`Successfully added the userscript header. Last commit SHA is ${lastCommitSha}`);
     console.info(`Final size is \x1b[32m${((await stat(scriptPath)).size / 1024).toFixed(2)} KiB\x1b[0m\n`);
+
+    setImmediate(() => process.exit(0));
   }
   catch(err) {
     console.error("Error while adding userscript header:");
     console.error(err);
+
     setImmediate(() => process.exit(1));
   }
 })();

+ 29 - 11
src/utils.ts

@@ -2,7 +2,7 @@ import { EventEmitter, EventHandler } from "@billjs/event-emitter";
 import type { Domain, LogLevel } from "./types";
 import { scriptInfo } from "./constants";
 
-//#SECTION BYTM-specific
+//#MARKER BYTM-specific
 
 let curLogLevel: LogLevel = 1;
 
@@ -17,13 +17,16 @@ function getLogLevel(...args: unknown[]): number {
   return 0;
 }
 
+/** Common prefix to be able to tell logged messages apart */
+const consPrefix = `[${scriptInfo.name}]`;
+
 /**
  * Logs string-compatible values to the console, as long as the log level is sufficient.  
  * @param args Last parameter is logLevel: 0 = Debug, 1/undefined = Info
  */
 export function log(...args: unknown[]): void {
   if(curLogLevel <= getLogLevel(...args))
-    console.log(`${scriptInfo.name}: `, ...args);
+    console.log(consPrefix, ...args);
 }
 
 /**
@@ -32,7 +35,7 @@ export function log(...args: unknown[]): void {
  */
 export function info(...args: unknown[]): void {
   if(curLogLevel <= getLogLevel(...args))
-    console.info(`${scriptInfo.name}: `, ...args);
+    console.info(consPrefix, ...args);
 }
 
 /**
@@ -41,12 +44,12 @@ export function info(...args: unknown[]): void {
  */
 export function warn(...args: unknown[]): void {
   if(curLogLevel <= getLogLevel(...args))
-    console.warn(`${scriptInfo.name}: `, ...args);
+    console.warn(consPrefix, ...args);
 }
 
 /** Logs string-compatible values to the console as an error. */
 export function error(...args: unknown[]): void {
-  console.error(`${scriptInfo.name}: `, ...args);
+  console.error(consPrefix, ...args);
 }
 
 /**
@@ -142,7 +145,7 @@ function ytForceShowVideoTime() {
   return true;
 }
 
-//#SECTION DOM
+//#MARKER DOM
 
 /**
  * Inserts `afterNode` as a sibling just after the provided `beforeNode`
@@ -172,11 +175,13 @@ export function addGlobalStyle(style: string, ref?: string) {
   log(`Inserted global style with ref '${ref}':`, styleElem);
 }
 
-//#SECTION site events
+//#MARKER site events
 
 export interface SiteEvents extends EventEmitter {
-  /** Emitted whenever a song is added to or removed from the queue */
+  /** Emitted whenever child nodes are added to or removed from the song queue */
   on(event: "queueChanged", listener: EventHandler): boolean;
+  /** Emitted whenever carousel shelf containers are added or removed from their parent container */
+  on(event: "carouselShelvesChanged", listener: EventHandler): boolean;
 }
 
 export const siteEvents = new EventEmitter() as SiteEvents;
@@ -186,21 +191,34 @@ let observers: MutationObserver[] = [];
 /** Creates MutationObservers that check if parts of the site have changed, then emit an event on the `siteEvents` instance */
 export function initSiteEvents() {
   try {
-    const queueObserver = new MutationObserver(([ { addedNodes, removedNodes, target } ]) => {
+    //#SECTION queue
+    const queueObs = new MutationObserver(([ { addedNodes, removedNodes, target } ]) => {
       if(addedNodes.length > 0 || removedNodes.length > 0) {
         info("Detected queue change - added nodes:", addedNodes.length, "- removed nodes:", removedNodes.length);
         siteEvents.fire("queueChanged", target);
       }
     });
     // only observe added or removed elements
-    queueObserver.observe(document.querySelector(".side-panel.modular #contents.ytmusic-player-queue")!, {
+    queueObs.observe(document.querySelector(".side-panel.modular #contents.ytmusic-player-queue")!, {
+      childList: true,
+    });
+
+    //#SECTION carousel shelves
+    const shelfContainerObs = new MutationObserver(([ { addedNodes, removedNodes } ]) => {
+      if(addedNodes.length > 0 || removedNodes.length > 0) {
+        info("Detected carousel shelf container change - added nodes:", addedNodes.length, "- removed nodes:", removedNodes.length);
+        siteEvents.fire("carouselShelvesChanged", { addedNodes, removedNodes });
+      }
+    });
+    shelfContainerObs.observe(document.querySelector("#contents.ytmusic-section-list-renderer")!, {
       childList: true,
     });
 
     info("Successfully initialized SiteEvents observers");
 
     observers = [
-      queueObserver,
+      queueObs,
+      shelfContainerObs,
     ];
   }
   catch(err) {