mirror of
https://github.com/meowarex/TidaLuna-Plugins.git
synced 2026-06-18 03:43:10 +10:00
Rewrite Timeouts + Bug Fixes
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
// MARKER: Core Setup
|
// MARKER: Core Setup
|
||||||
import { LunaUnload, Tracer, ftch } from "@luna/core";
|
import { LunaUnload, Tracer, ftch } from "@luna/core";
|
||||||
import { StyleTag, PlayState, MediaItem, observePromise, observe } from "@luna/lib";
|
import { StyleTag, PlayState, MediaItem, observePromise, observe, safeInterval, safeTimeout } from "@luna/lib";
|
||||||
import { settings, Settings } from "./Settings";
|
import { settings, Settings } from "./Settings";
|
||||||
// Interpret integer backgroundScale (e.g., 10=1.0x, 20=2.0x)
|
// Interpret integer backgroundScale (e.g., 10=1.0x, 20=2.0x)
|
||||||
const getScaledMultiplier = (): number => {
|
const getScaledMultiplier = (): number => {
|
||||||
@@ -235,7 +235,7 @@ const updateButtonStates = function (): void {
|
|||||||
if (settings.hideUIEnabled && !isHidden) {
|
if (settings.hideUIEnabled && !isHidden) {
|
||||||
hideButton.style.display = "flex";
|
hideButton.style.display = "flex";
|
||||||
// Small delay to ensure display is set first, then fade in
|
// Small delay to ensure display is set first, then fade in
|
||||||
setTimeout(() => {
|
safeTimeout(unloads, () => {
|
||||||
hideButton.style.opacity = "1";
|
hideButton.style.opacity = "1";
|
||||||
hideButton.style.visibility = "visible";
|
hideButton.style.visibility = "visible";
|
||||||
hideButton.style.pointerEvents = "auto";
|
hideButton.style.pointerEvents = "auto";
|
||||||
@@ -261,7 +261,7 @@ const updateButtonStates = function (): void {
|
|||||||
unhideButton.classList.remove("hide-immediately");
|
unhideButton.classList.remove("hide-immediately");
|
||||||
unhideButton.classList.remove("auto-faded");
|
unhideButton.classList.remove("auto-faded");
|
||||||
// Small delay to ensure display is set first, then fade in - (Works for unhide button.. but not hide button.. because uhh idk)
|
// Small delay to ensure display is set first, then fade in - (Works for unhide button.. but not hide button.. because uhh idk)
|
||||||
setTimeout(() => {
|
safeTimeout(unloads, () => {
|
||||||
unhideButton.style.opacity = "1";
|
unhideButton.style.opacity = "1";
|
||||||
unhideButton.style.visibility = "visible";
|
unhideButton.style.visibility = "visible";
|
||||||
unhideButton.style.pointerEvents = "auto";
|
unhideButton.style.pointerEvents = "auto";
|
||||||
@@ -284,11 +284,11 @@ const updateButtonStates = function (): void {
|
|||||||
unhideButton.style.pointerEvents = "none";
|
unhideButton.style.pointerEvents = "none";
|
||||||
unhideButton.classList.remove("auto-faded");
|
unhideButton.classList.remove("auto-faded");
|
||||||
// Keep display: flex to maintain transitions, then hide after fade
|
// Keep display: flex to maintain transitions, then hide after fade
|
||||||
setTimeout(() => {
|
safeTimeout(unloads, () => {
|
||||||
if (unhideButton.style.opacity === "0") {
|
if (unhideButton.style.opacity === "0") {
|
||||||
unhideButton.style.display = "none";
|
unhideButton.style.display = "none";
|
||||||
}
|
}
|
||||||
}, 500); // Wait for transition to complete
|
}, 500);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -307,7 +307,7 @@ const toggleRadiantLyrics = function (): void {
|
|||||||
if (nowPlayingContainer)
|
if (nowPlayingContainer)
|
||||||
nowPlayingContainer.classList.remove("radiant-lyrics-ui-hidden");
|
nowPlayingContainer.classList.remove("radiant-lyrics-ui-hidden");
|
||||||
document.body.classList.remove("radiant-lyrics-ui-hidden");
|
document.body.classList.remove("radiant-lyrics-ui-hidden");
|
||||||
setTimeout(() => {
|
safeTimeout(unloads, () => {
|
||||||
if (!isHidden) {
|
if (!isHidden) {
|
||||||
updateRadiantLyricsStyles();
|
updateRadiantLyricsStyles();
|
||||||
}
|
}
|
||||||
@@ -316,7 +316,7 @@ const toggleRadiantLyrics = function (): void {
|
|||||||
} else {
|
} else {
|
||||||
isHidden = !isHidden;
|
isHidden = !isHidden;
|
||||||
updateButtonStates();
|
updateButtonStates();
|
||||||
setTimeout(() => {
|
safeTimeout(unloads, () => {
|
||||||
updateRadiantLyricsStyles();
|
updateRadiantLyricsStyles();
|
||||||
if (nowPlayingContainer)
|
if (nowPlayingContainer)
|
||||||
nowPlayingContainer.classList.add("radiant-lyrics-ui-hidden");
|
nowPlayingContainer.classList.add("radiant-lyrics-ui-hidden");
|
||||||
@@ -327,13 +327,13 @@ const toggleRadiantLyrics = function (): void {
|
|||||||
|
|
||||||
// Create buttons
|
// Create buttons
|
||||||
const createHideUIButton = function (): void {
|
const createHideUIButton = function (): void {
|
||||||
setTimeout(() => {
|
safeTimeout(unloads, () => {
|
||||||
if (!settings.hideUIEnabled) return;
|
if (!settings.hideUIEnabled) return;
|
||||||
const fullscreenButton = document.querySelector(
|
const fullscreenButton = document.querySelector(
|
||||||
'[data-test="request-fullscreen"]',
|
'[data-test="request-fullscreen"]',
|
||||||
);
|
);
|
||||||
if (!fullscreenButton || !fullscreenButton.parentElement) {
|
if (!fullscreenButton || !fullscreenButton.parentElement) {
|
||||||
setTimeout(() => createHideUIButton(), 1000);
|
safeTimeout(unloads, () => createHideUIButton(), 1000);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (document.querySelector(".hide-ui-button")) return;
|
if (document.querySelector(".hide-ui-button")) return;
|
||||||
@@ -370,7 +370,7 @@ const createHideUIButton = function (): void {
|
|||||||
});
|
});
|
||||||
hideUIButton.onclick = toggleRadiantLyrics;
|
hideUIButton.onclick = toggleRadiantLyrics;
|
||||||
buttonContainer.insertBefore(hideUIButton, fullscreenButton.nextSibling);
|
buttonContainer.insertBefore(hideUIButton, fullscreenButton.nextSibling);
|
||||||
setTimeout(() => {
|
safeTimeout(unloads, () => {
|
||||||
if (settings.hideUIEnabled && !isHidden) {
|
if (settings.hideUIEnabled && !isHidden) {
|
||||||
hideUIButton.style.opacity = "1";
|
hideUIButton.style.opacity = "1";
|
||||||
hideUIButton.style.visibility = "visible";
|
hideUIButton.style.visibility = "visible";
|
||||||
@@ -381,14 +381,14 @@ const createHideUIButton = function (): void {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const createUnhideUIButton = function (): void {
|
const createUnhideUIButton = function (): void {
|
||||||
setTimeout(() => {
|
safeTimeout(unloads, () => {
|
||||||
if (!settings.hideUIEnabled) return;
|
if (!settings.hideUIEnabled) return;
|
||||||
if (document.querySelector(".unhide-ui-button")) return;
|
if (document.querySelector(".unhide-ui-button")) return;
|
||||||
const nowPlayingContainer = document.querySelector(
|
const nowPlayingContainer = document.querySelector(
|
||||||
'[class*="_nowPlayingContainer"]',
|
'[class*="_nowPlayingContainer"]',
|
||||||
) as HTMLElement;
|
) as HTMLElement;
|
||||||
if (!nowPlayingContainer) {
|
if (!nowPlayingContainer) {
|
||||||
setTimeout(() => createUnhideUIButton(), 1000);
|
safeTimeout(unloads, () => createUnhideUIButton(), 1000);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const unhideUIButton = document.createElement("button");
|
const unhideUIButton = document.createElement("button");
|
||||||
@@ -405,7 +405,7 @@ const createUnhideUIButton = function (): void {
|
|||||||
unhideUIButton.addEventListener("mouseleave", () => {
|
unhideUIButton.addEventListener("mouseleave", () => {
|
||||||
unhideUIButton.style.backgroundColor = "rgba(255,255,255,0.2)";
|
unhideUIButton.style.backgroundColor = "rgba(255,255,255,0.2)";
|
||||||
unhideUIButton.style.transform = "scale(1)";
|
unhideUIButton.style.transform = "scale(1)";
|
||||||
window.setTimeout(() => {
|
safeTimeout(unloads, () => {
|
||||||
if (isHidden && !unhideUIButton.matches(":hover")) {
|
if (isHidden && !unhideUIButton.matches(":hover")) {
|
||||||
unhideUIButton.classList.add("auto-faded");
|
unhideUIButton.classList.add("auto-faded");
|
||||||
}
|
}
|
||||||
@@ -462,10 +462,10 @@ const applyScaledPixelSize = (img: HTMLImageElement | null): void => {
|
|||||||
// Update Cover Art background for Now Playing and Global
|
// Update Cover Art background for Now Playing and Global
|
||||||
function updateCoverArtBackground(method: number = 0): void {
|
function updateCoverArtBackground(method: number = 0): void {
|
||||||
if (method === 1) {
|
if (method === 1) {
|
||||||
setTimeout(() => {
|
safeTimeout(unloads, () => {
|
||||||
updateCoverArtBackground();
|
updateCoverArtBackground();
|
||||||
return;
|
|
||||||
}, 2000);
|
}, 2000);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let coverArtImageElement = document.querySelector(
|
let coverArtImageElement = document.querySelector(
|
||||||
@@ -1130,7 +1130,7 @@ const createStickyLyricsDropdown = (): void => {
|
|||||||
// Navigate to Lyrics & open dropdown
|
// Navigate to Lyrics & open dropdown
|
||||||
lyricsTab.click();
|
lyricsTab.click();
|
||||||
// Delay to let the tab activate
|
// Delay to let the tab activate
|
||||||
setTimeout(() => openDropdown(), 150);
|
safeTimeout(unloads, () => openDropdown(), 150);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Toggle dropdown
|
// Toggle dropdown
|
||||||
@@ -1202,7 +1202,7 @@ const handleStickyLyricsTrackChange = (): void => {
|
|||||||
|
|
||||||
// Process the track change and update tab state
|
// Process the track change and update tab state
|
||||||
// Tidal takes a while to process the track change sometimes :(
|
// Tidal takes a while to process the track change sometimes :(
|
||||||
setTimeout(() => {
|
safeTimeout(unloads, () => {
|
||||||
if (!settings.stickyLyrics) return;
|
if (!settings.stickyLyrics) return;
|
||||||
|
|
||||||
const lyricsTab = document.querySelector(
|
const lyricsTab = document.querySelector(
|
||||||
@@ -1213,23 +1213,20 @@ const handleStickyLyricsTrackChange = (): void => {
|
|||||||
) as HTMLElement;
|
) as HTMLElement;
|
||||||
|
|
||||||
if (!lyricsTab) {
|
if (!lyricsTab) {
|
||||||
// fall back to play queue
|
|
||||||
if (playQueueTab) playQueueTab.click();
|
if (playQueueTab) playQueueTab.click();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attempt to switch to lyrics
|
|
||||||
lyricsTab.click();
|
lyricsTab.click();
|
||||||
|
|
||||||
// Verify we actually stayed on lyrics after a short delay
|
// Verify we actually stayed on lyrics after a short delay
|
||||||
// TODO: Make not shitty (one day maybe)
|
// TODO: Make not shitty (one day maybe)
|
||||||
setTimeout(() => {
|
safeTimeout(unloads, () => {
|
||||||
if (!settings.stickyLyrics) return;
|
if (!settings.stickyLyrics) return;
|
||||||
const onLyrics = document.querySelector(
|
const onLyrics = document.querySelector(
|
||||||
'[data-test="tabs-lyrics"][aria-selected="true"]',
|
'[data-test="tabs-lyrics"][aria-selected="true"]',
|
||||||
);
|
);
|
||||||
if (!onLyrics && playQueueTab) {
|
if (!onLyrics && playQueueTab) {
|
||||||
// Got redirected away from lyrics - fall back to play queue
|
|
||||||
playQueueTab.click();
|
playQueueTab.click();
|
||||||
}
|
}
|
||||||
}, 800);
|
}, 800);
|
||||||
@@ -1252,6 +1249,15 @@ function setupStickyLyricsObserver(): void {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Apply word lyrics when lyrics container appears or reappears
|
||||||
|
observe<HTMLElement>(unloads, '[data-test="lyrics-lines"]', () => {
|
||||||
|
if (lyricsData) {
|
||||||
|
reapplyWordLyrics();
|
||||||
|
} else if (settings.lyricsStyle !== 0) {
|
||||||
|
onTrackChange();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// sticky lyrics track changes
|
// sticky lyrics track changes
|
||||||
onGlobalTrackChange(() => {
|
onGlobalTrackChange(() => {
|
||||||
if (settings.stickyLyrics) {
|
if (settings.stickyLyrics) {
|
||||||
@@ -1300,7 +1306,7 @@ interface WordLyricsResponse {
|
|||||||
// syllable state
|
// syllable state
|
||||||
let trackChangeToken = 0;
|
let trackChangeToken = 0;
|
||||||
let lyricsData: WordLine[] | null = null;
|
let lyricsData: WordLine[] | null = null;
|
||||||
let tickLoopId: number | null = null;
|
let tickLoopUnload: LunaUnload | null = null;
|
||||||
let isActive = false;
|
let isActive = false;
|
||||||
let savedTidalClasses: string[] | null = null;
|
let savedTidalClasses: string[] | null = null;
|
||||||
|
|
||||||
@@ -1687,11 +1693,10 @@ const unwatchRerender = (): void => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// clear tick loop
|
|
||||||
const clearTickLoop = (): void => {
|
const clearTickLoop = (): void => {
|
||||||
if (tickLoopId !== null) {
|
if (tickLoopUnload !== null) {
|
||||||
clearInterval(tickLoopId);
|
tickLoopUnload();
|
||||||
tickLoopId = null;
|
tickLoopUnload = null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1866,7 +1871,7 @@ const startTickLoop = (): void => {
|
|||||||
|
|
||||||
let lastLogTime = 0;
|
let lastLogTime = 0;
|
||||||
|
|
||||||
tickLoopId = window.setInterval(() => {
|
tickLoopUnload = safeInterval(unloads, () => {
|
||||||
if (!isActive || lines.length === 0) return;
|
if (!isActive || lines.length === 0) return;
|
||||||
|
|
||||||
const nowMs = getPlaybackMs();
|
const nowMs = getPlaybackMs();
|
||||||
@@ -2041,6 +2046,28 @@ const onTrackChange = async (): Promise<void> => {
|
|||||||
startTickLoop();
|
startTickLoop();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Reapply word lyrics (for tab switch back)
|
||||||
|
const reapplyWordLyrics = (): void => {
|
||||||
|
if (settings.lyricsStyle === 0 || !lyricsData) return;
|
||||||
|
|
||||||
|
clearTickLoop();
|
||||||
|
unwatchRerender();
|
||||||
|
unhookUserScroll();
|
||||||
|
unhookSyncButton();
|
||||||
|
unlockScroll();
|
||||||
|
activeWordEl = null;
|
||||||
|
activeLineIdx = -1;
|
||||||
|
|
||||||
|
isActive = true;
|
||||||
|
hideTidalLyrics();
|
||||||
|
const result = buildWordSpans();
|
||||||
|
allWords = result.words;
|
||||||
|
lines = result.lines;
|
||||||
|
watchForRerender();
|
||||||
|
startTickLoop();
|
||||||
|
console.log("[RL-Syllable] Reapplied word lyrics (cached)");
|
||||||
|
};
|
||||||
|
|
||||||
// Called by Settings or dropdown
|
// Called by Settings or dropdown
|
||||||
const toggle = (): void => {
|
const toggle = (): void => {
|
||||||
teardown();
|
teardown();
|
||||||
@@ -2063,10 +2090,21 @@ const setupTrackChangeListener = (): void => {
|
|||||||
for (const listener of trackChangeListeners) listener();
|
for (const listener of trackChangeListeners) listener();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Fire if already playing
|
// Applies on app reopen (most ppl close the app while smthn playing)
|
||||||
|
let hasFiredInitial = false;
|
||||||
if (PlayState.playbackContext?.actualProductId) {
|
if (PlayState.playbackContext?.actualProductId) {
|
||||||
|
hasFiredInitial = true;
|
||||||
for (const listener of trackChangeListeners) listener();
|
for (const listener of trackChangeListeners) listener();
|
||||||
}
|
}
|
||||||
|
if (!hasFiredInitial) {
|
||||||
|
PlayState.onState(unloads, (state) => {
|
||||||
|
if (hasFiredInitial) return;
|
||||||
|
if (state === "PLAYING" && PlayState.playbackContext?.actualProductId) {
|
||||||
|
hasFiredInitial = true;
|
||||||
|
for (const listener of trackChangeListeners) listener();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function setupHeaderObserver(): void {
|
function setupHeaderObserver(): void {
|
||||||
|
|||||||
Reference in New Issue
Block a user