|
@@ -1,4 +1,3 @@
|
|
|
-import { Event as EventParam, EventEmitter, EventHandler } from "@billjs/event-emitter";
|
|
|
import { branch, scriptInfo } from "./constants";
|
|
|
import type { Domain, LogLevel } from "./types";
|
|
|
|
|
@@ -177,7 +176,7 @@ export function openInNewTab(href: string) {
|
|
|
});
|
|
|
document.body.appendChild(openElem);
|
|
|
openElem.click();
|
|
|
- // just to be safe
|
|
|
+ // timeout just to be safe
|
|
|
setTimeout(() => openElem.remove(), 200);
|
|
|
}
|
|
|
|
|
@@ -222,104 +221,3 @@ export function addGlobalStyle(style: string, ref?: string) {
|
|
|
|
|
|
log(`Inserted global style with ref '${ref}':`, styleElem);
|
|
|
}
|
|
|
-
|
|
|
-//#MARKER site events
|
|
|
-
|
|
|
-export interface SiteEvents extends EventEmitter {
|
|
|
- /** 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;
|
|
|
- /** Emitted once the home page is filled with content */
|
|
|
- on(event: "homePageLoaded", listener: EventHandler): boolean;
|
|
|
-}
|
|
|
-
|
|
|
-export const siteEvents = new EventEmitter() as SiteEvents;
|
|
|
-
|
|
|
-/**
|
|
|
- * Returns the data of an event from the `@billjs/event-emitter` library.
|
|
|
- * This function is used to assert the type passed in `<T>`
|
|
|
- * @param evt Event object from the `.on()` or `.once()` method
|
|
|
- * @template T Type of the data passed by `.fire(type: string, data: T)`
|
|
|
- */
|
|
|
-export function getEvtData<T>(evt: EventParam): T {
|
|
|
- return evt.data as T;
|
|
|
-}
|
|
|
-
|
|
|
-let observers: MutationObserver[] = [];
|
|
|
-
|
|
|
-/** Disconnects and deletes all observers. Run `initSiteEvents()` again to create new ones. */
|
|
|
-export function removeAllObservers() {
|
|
|
- observers.forEach((observer) => observer.disconnect());
|
|
|
- observers = [];
|
|
|
-}
|
|
|
-
|
|
|
-/** 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
|
|
|
- // the queue container always exists so it doesn't need the 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}`);
|
|
|
- siteEvents.fire("queueChanged", target);
|
|
|
- }
|
|
|
- });
|
|
|
- // only observe added or removed elements
|
|
|
- queueObs.observe(document.querySelector(".side-panel.modular #contents.ytmusic-player-queue")!, {
|
|
|
- childList: true,
|
|
|
- });
|
|
|
-
|
|
|
- //#SECTION home page observers
|
|
|
- initHomeObservers();
|
|
|
-
|
|
|
- info("Successfully initialized SiteEvents observers");
|
|
|
-
|
|
|
- observers = [
|
|
|
- queueObs,
|
|
|
- ];
|
|
|
- }
|
|
|
- catch(err) {
|
|
|
- error("Couldn't initialize SiteEvents observers due to an error:\n", err);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * The home page might not exist yet if the site was accessed through any path like /watch directly.
|
|
|
- * This function will keep waiting for when the home page exists, then create the necessary MutationObservers.
|
|
|
- */
|
|
|
-async function initHomeObservers() {
|
|
|
- let interval: NodeJS.Timer | undefined;
|
|
|
-
|
|
|
- // hidden="" attribute is only present if the content of the page doesn't exist yet
|
|
|
- // so this resolves only once that attribute is removed
|
|
|
- if(document.querySelector("ytmusic-browse-response#browse-page")?.hasAttribute("hidden")) {
|
|
|
- await new Promise<void>((res) => {
|
|
|
- interval = setInterval(() => {
|
|
|
- if(!document.querySelector("ytmusic-browse-response#browse-page")?.hasAttribute("hidden")) {
|
|
|
- info("found home page");
|
|
|
- res();
|
|
|
- }
|
|
|
- }, 50);
|
|
|
- });
|
|
|
- }
|
|
|
- interval && clearInterval(interval);
|
|
|
-
|
|
|
- siteEvents.fire("homePageLoaded");
|
|
|
-
|
|
|
- info("Initialized home page observers");
|
|
|
-
|
|
|
- //#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,
|
|
|
- });
|
|
|
-
|
|
|
- observers = observers.concat([ shelfContainerObs ]);
|
|
|
-}
|