observers.ts 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. import { SelectorListenerOptions, SelectorObserver, SelectorObserverOptions } from "@sv443-network/userutils";
  2. import type { ObserverName } from "./types";
  3. import { emitInterface } from "./interface";
  4. import { error, log } 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: () => {
  28. log("#DBG-UU enabling playerBar observer");
  29. globservers.playerBar.enable();
  30. },
  31. });
  32. // #SECTION playerBarInfo = song title, artist, album, etc. inside the player bar
  33. const playerBarInfoSelector = `${playerBarSelector} .middle-controls .content-info-wrapper`;
  34. globservers.playerBarInfo = new SelectorObserver(playerBarInfoSelector, {
  35. ...defaultObserverOptions,
  36. attributes: true,
  37. attributeFilter: ["title"],
  38. });
  39. globservers.playerBarInfo.addListener(playerBarInfoSelector, {
  40. listener: () => {
  41. log("#DBG-UU enabling playerBarTitle observer");
  42. globservers.playerBarInfo.enable();
  43. },
  44. });
  45. // #DEBUG example: listen for title change:
  46. globservers.playerBarInfo.addListener("yt-formatted-string.title", {
  47. continuous: true,
  48. listener: (titleElem) => {
  49. log("#DBG-UU >>>>> title changed", titleElem.title);
  50. },
  51. });
  52. emitInterface("bytm:observersReady");
  53. }
  54. catch(err) {
  55. error("Failed to initialize observers:", err);
  56. }
  57. }
  58. /** Interface function for adding listeners to the already present observers */
  59. export function addSelectorListener<TElem extends Element>(observerName: ObserverName, selector: string, options: SelectorListenerOptions<TElem>) {
  60. globservers[observerName].addListener(selector, options);
  61. }