From 5e00accc7ff921d127315229d9bb67779243cb07 Mon Sep 17 00:00:00 2001 From: meowarex Date: Mon, 2 Mar 2026 14:32:32 +1100 Subject: [PATCH] Fix Race Condition --- plugins/radiant-lyrics-luna/src/index.ts | 49 +++++++++++++++++++++++- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/plugins/radiant-lyrics-luna/src/index.ts b/plugins/radiant-lyrics-luna/src/index.ts index 4d388bb..961cb24 100644 --- a/plugins/radiant-lyrics-luna/src/index.ts +++ b/plugins/radiant-lyrics-luna/src/index.ts @@ -1495,7 +1495,38 @@ const buildInjectedLyricsShell = (panel: HTMLElement): void => { panel.replaceChildren(trackLyrics); }; -const ensureLyricsTab = (): boolean => { +const waitForNativeTab = (): Promise => { + if ( + document.querySelector( + '[data-test="tabs-lyrics"]:not([data-rl-injected])', + ) + ) { + return Promise.resolve(true); + } + + return new Promise((resolve) => { + const localUnloads = new Set(); + let settled = false; + const settle = (result: boolean): void => { + if (settled) return; + settled = true; + for (const fn of localUnloads) fn(); + localUnloads.clear(); + resolve(result); + }; + + observe( + localUnloads, + '[data-test="tabs-lyrics"]:not([data-rl-injected])', + () => settle(true), + ); + + const timer = window.setTimeout(() => settle(false), 200); + localUnloads.add(() => clearTimeout(timer)); + }); +}; + +const ensureLyricsTab = async (): Promise => { const existingLyricsTab = document.querySelector( '[data-test="tabs-lyrics"]', ) as HTMLElement; @@ -1508,6 +1539,9 @@ const ensureLyricsTab = (): boolean => { return true; } + // resolves instantly if native tab already exists (fallback to 200ms for slow ass tidal re renders) + if (await waitForNativeTab()) return true; + const root = getTabsRoot(); if (!root) return false; const tabList = root.querySelector('ul[role="tablist"]') as HTMLElement; @@ -1631,6 +1665,16 @@ function setupStickyLyricsObserver(): void { // Re-create dropdown whenever lyrics tab is back from the ether observe(unloads, '[data-test="tabs-lyrics"]', () => { + // If a native lyrics tab appeared while an injected one exists, remove the duplicate + if (injectedTabEl) { + const nativeTab = document.querySelector( + '[data-test="tabs-lyrics"]:not([data-rl-injected])', + ); + if (nativeTab) { + clearInjectedLyricsTab(); + } + } + const tab = document.querySelector('[data-test="tabs-lyrics"]'); if (tab && !tab.querySelector(".sticky-lyrics-trigger")) { createStickyLyricsDropdown(); @@ -3629,11 +3673,12 @@ const onTrackChange = async (): Promise => { ); lyricsMode = response.type === "Word" ? "word" : "line-api"; - if (!ensureLyricsTab()) { + if (!(await ensureLyricsTab())) { trace.log("Could not create/find lyrics tab container"); teardown(); return; } + if (token !== trackChangeToken) return; if (injectedTabEl && settings.stickyLyrics) { showInjectedLyricsTab(); }