123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127 |
- import * as UserUtils from "@sv443-network/userutils";
- import { mode, branch, host, buildNumber, compressionFormat, scriptInfo } from "./constants";
- import { getResourceUrl, getSessionId, getVideoTime, log, setLocale, getLocale, hasKey, hasKeyFor, NanoEmitter, t, tp, type TrLocale } from "./utils";
- import { addSelectorListener } from "./observers";
- import { getFeatures, saveFeatures } from "./config";
- import { featInfo, fetchLyricsUrlTop, getLyricsCacheEntry, sanitizeArtists, sanitizeSong, type LyricsCache } from "./features";
- import type { SiteEventsMap } from "./siteEvents";
- import type { FeatureConfig, FeatureInfo, LyricsCacheEntry } from "./types";
- import { BytmDialog, createHotkeyInput, createToggleInput } from "./components";
- const { getUnsafeWindow } = UserUtils;
- /** All events that can be emitted on the BYTM interface and the data they provide */
- export type InterfaceEvents = {
- /** Emitted when BYTM has finished initializing all features */
- "bytm:ready": undefined;
- /**
- * Emitted whenever the SelectorObserver instances have been initialized
- * Use `unsafeWindow.BYTM.addObserverListener()` to add custom listener functions to the observers
- */
- "bytm:observersReady": undefined;
- /** Emitted as soon as the feature config has been loaded */
- "bytm:configReady": FeatureConfig;
- /** Emitted whenever the locale is changed */
- "bytm:setLocale": { locale: TrLocale };
- /** Emitted when a dialog was opened - returns the dialog's instance */
- "bytm:dialogOpened": BytmDialog;
- /** Emitted when the dialog with the specified ID was opened - returns the dialog's instance - use `as "bytm:dialogOpened:id"` in TS to make the error go away */
- "bytm:dialogOpened:id": BytmDialog;
- /** Emitted whenever the lyrics URL for a song is loaded */
- "bytm:lyricsLoaded": { type: "current" | "queue", artists: string, title: string, url: string };
- /** Emitted when the lyrics cache has been loaded */
- "bytm:lyricsCacheReady": LyricsCache;
- /** Emitted when the lyrics cache has been cleared */
- "bytm:lyricsCacheCleared": undefined;
- /** Emitted when an entry is added to the lyrics cache - "penalized" entries have a lower TTL because they were less related in lyrics lookups, as opposed to the "best" entries */
- "bytm:lyricsCacheEntryAdded": { type: "best" | "penalized", entry: LyricsCacheEntry };
- // additionally all events from SiteEventsMap in `src/siteEvents.ts`
- // are emitted in this format: "bytm:siteEvent:nameOfSiteEvent"
- };
- const globalFuncs = {
- addSelectorListener,
- getResourceUrl,
- getSessionId,
- getVideoTime,
- setLocale,
- getLocale,
- hasKey,
- hasKeyFor,
- t,
- tp,
- getFeatures: getFeaturesInterface,
- saveFeatures,
- fetchLyricsUrlTop,
- getLyricsCacheEntry,
- sanitizeArtists,
- sanitizeSong,
- };
- /** Initializes the BYTM interface */
- export function initInterface() {
- const props = {
- mode,
- branch,
- host,
- buildNumber,
- compressionFormat,
- ...scriptInfo,
- ...globalFuncs,
- UserUtils,
- NanoEmitter,
- BytmDialog,
- createHotkeyInput,
- createToggleInput,
- };
- for(const [key, value] of Object.entries(props))
- setGlobalProp(key, value);
- log("Initialized BYTM interface");
- }
- /** Sets a global property on the unsafeWindow.BYTM object */
- export function setGlobalProp<
- TKey extends keyof Window["BYTM"],
- TValue = Window["BYTM"][TKey],
- > (
- key: TKey | (string & {}),
- value: TValue,
- ) {
- // use unsafeWindow so the properties are available to plugins outside of the userscript's scope
- const win = getUnsafeWindow();
- if(typeof win.BYTM !== "object")
- win.BYTM = {} as typeof window.BYTM;
- win.BYTM[key] = value;
- }
- /** Emits an event on the BYTM interface */
- export function emitInterface<
- TEvt extends keyof InterfaceEvents,
- TDetail extends InterfaceEvents[TEvt],
- >(
- type: TEvt | `bytm:siteEvent:${keyof SiteEventsMap}`,
- ...data: (TDetail extends undefined ? [undefined?] : [TDetail])
- ) {
- getUnsafeWindow().dispatchEvent(new CustomEvent(type, { detail: data[0] }));
- }
- //#MARKER proxy functions
- /** Returns the current feature config, with sensitive values replaced by `undefined` */
- export function getFeaturesInterface() {
- const features = getFeatures();
- for(const ftKey of Object.keys(features)) {
- const info = featInfo[ftKey as keyof typeof featInfo] as FeatureInfo[keyof FeatureInfo];
- if(info && info.valueHidden) // @ts-ignore
- features[ftKey as keyof typeof features] = undefined;
- }
- return features as FeatureConfig;
- }
|