observers.ts 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. import { SelectorListenerOptions, SelectorObserver, SelectorObserverOptions } from "@sv443-network/userutils";
  2. import type { ObserverName } from "./types";
  3. import { emitInterface } from "./interface";
  4. import { error } from "./utils";
  5. /** Options that are applied to every SelectorObserver instance */
  6. const defaultObserverOptions: SelectorObserverOptions = {
  7. defaultDebounce: 100,
  8. };
  9. /** Global SelectorObserver instances usable throughout the script for improved performance */
  10. export const globservers = {} as Record<ObserverName, SelectorObserver>;
  11. /** Call after DOM load to initialize all SelectorObserver instances */
  12. export function initObservers() {
  13. try {
  14. // #SECTION body = the entire <body> element - use sparingly due to performance impacts!
  15. globservers.body = new SelectorObserver(document.body, {
  16. ...defaultObserverOptions,
  17. subtree: false,
  18. });
  19. globservers.body.enable();
  20. // #SECTION playerBar = media controls bar at the bottom of the page
  21. const playerBarSelector = "ytmusic-app-layout ytmusic-player-bar.ytmusic-app";
  22. globservers.playerBar = new SelectorObserver(playerBarSelector, {
  23. ...defaultObserverOptions,
  24. defaultDebounce: 200,
  25. });
  26. globservers.body.addListener(playerBarSelector, {
  27. listener: () => globservers.playerBar.enable(),
  28. });
  29. // #SECTION playerBarInfo = song title, artist, album, etc. inside the player bar
  30. const playerBarInfoSelector = `${playerBarSelector} .middle-controls .content-info-wrapper`;
  31. globservers.playerBarInfo = new SelectorObserver(playerBarInfoSelector, {
  32. ...defaultObserverOptions,
  33. attributes: true,
  34. attributeFilter: ["title"],
  35. });
  36. globservers.playerBarInfo.addListener(playerBarInfoSelector, {
  37. listener: () => globservers.playerBarInfo.enable(),
  38. });
  39. //#SECTION finalize
  40. emitInterface("bytm:observersReady");
  41. }
  42. catch(err) {
  43. error("Failed to initialize observers:", err);
  44. }
  45. }
  46. /** Interface function for adding listeners to the already present observers */
  47. export function addSelectorListener<TElem extends Element>(observerName: ObserverName, selector: string, options: SelectorListenerOptions<TElem>) {
  48. globservers[observerName].addListener(selector, options);
  49. }