mirror of
https://github.com/meowarex/TidaLuna-Plugins.git
synced 2026-06-18 03:43:10 +10:00
@@ -537,11 +537,10 @@ function updateCoverArtBackground(method: number = 0): void {
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
background: #000;
|
background: #000;
|
||||||
z-index: -2;
|
z-index: -2;
|
||||||
pointer-events: none;
|
|
||||||
`;
|
`;
|
||||||
nowPlayingBackgroundContainer.appendChild(nowPlayingBlackBg);
|
nowPlayingBackgroundContainer.appendChild(nowPlayingBlackBg);
|
||||||
|
|
||||||
// Create background image
|
// Create image element
|
||||||
nowPlayingBackgroundImage = document.createElement("img");
|
nowPlayingBackgroundImage = document.createElement("img");
|
||||||
nowPlayingBackgroundImage.className = "now-playing-background-image";
|
nowPlayingBackgroundImage.className = "now-playing-background-image";
|
||||||
nowPlayingBackgroundImage.style.cssText = `
|
nowPlayingBackgroundImage.style.cssText = `
|
||||||
@@ -551,6 +550,7 @@ function updateCoverArtBackground(method: number = 0): void {
|
|||||||
transform: translate(-50%, -50%);
|
transform: translate(-50%, -50%);
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
z-index: -1;
|
z-index: -1;
|
||||||
|
will-change: transform;
|
||||||
transform-origin: center center;
|
transform-origin: center center;
|
||||||
`;
|
`;
|
||||||
nowPlayingBackgroundContainer.appendChild(nowPlayingBackgroundImage);
|
nowPlayingBackgroundContainer.appendChild(nowPlayingBackgroundImage);
|
||||||
@@ -1327,7 +1327,7 @@ const getPlaybackMs = (): number => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// get title + artist from media item (Used everywhere now <3)
|
// get title + artist from media item (Used everywhere now <3)
|
||||||
const getTrackInfo = async (): Promise<{ title: string; artist: string } | null> => {
|
const getTrackInfo = async (): Promise<{ title: string; artist: string; isrc?: string } | null> => {
|
||||||
const mi = await MediaItem.fromPlaybackContext();
|
const mi = await MediaItem.fromPlaybackContext();
|
||||||
if (!mi?.tidalItem) return null;
|
if (!mi?.tidalItem) return null;
|
||||||
|
|
||||||
@@ -1335,9 +1335,10 @@ const getTrackInfo = async (): Promise<{ title: string; artist: string } | null>
|
|||||||
const version = mi.tidalItem.version; // REMIX Detection
|
const version = mi.tidalItem.version; // REMIX Detection
|
||||||
const title = version ? `${baseTitle} (${version})` : baseTitle;
|
const title = version ? `${baseTitle} (${version})` : baseTitle;
|
||||||
const artist = mi.tidalItem.artist?.name ?? mi.tidalItem.artists?.[0]?.name ?? ""; // REMIX Detection
|
const artist = mi.tidalItem.artist?.name ?? mi.tidalItem.artists?.[0]?.name ?? ""; // REMIX Detection
|
||||||
|
const isrc = mi.tidalItem.isrc ?? undefined;
|
||||||
|
|
||||||
if (!baseTitle || !artist) return null;
|
if (!baseTitle || !artist) return null;
|
||||||
return { title, artist };
|
return { title, artist, isrc };
|
||||||
};
|
};
|
||||||
|
|
||||||
// fetch syllables from the API (wiped on track change)
|
// fetch syllables from the API (wiped on track change)
|
||||||
@@ -1346,43 +1347,72 @@ let cachedLyricsData: WordLyricsResponse | null = null;
|
|||||||
const fetchWordLyrics = async (
|
const fetchWordLyrics = async (
|
||||||
title: string,
|
title: string,
|
||||||
artist: string,
|
artist: string,
|
||||||
|
isrc?: string,
|
||||||
): Promise<WordLyricsResponse | null> => {
|
): Promise<WordLyricsResponse | null> => {
|
||||||
const cacheKey = `${title}\0${artist}`;
|
const cacheKey = `${title}\0${artist}\0${isrc ?? ""}`;
|
||||||
if (cachedLyricsKey === cacheKey) {
|
if (cachedLyricsKey === cacheKey) {
|
||||||
sylLog(`[RL-Syllable] Cache hit for "${title}" by "${artist}"`);
|
sylLog(`[RL-Syllable] Cache hit for "${title}" by "${artist}"`);
|
||||||
return cachedLyricsData;
|
return cachedLyricsData;
|
||||||
}
|
}
|
||||||
|
|
||||||
const params = `lyrics?title=${encodeURIComponent(title)}&artist=${encodeURIComponent(artist)}`;
|
let params = `lyrics?title=${encodeURIComponent(title)}&artist=${encodeURIComponent(artist)}`;
|
||||||
const urls = [
|
if (isrc) params += `&isrc=${encodeURIComponent(isrc)}`;
|
||||||
|
|
||||||
|
const primaryUrls = [
|
||||||
`https://rl-api.atomix.one/${params}`,
|
`https://rl-api.atomix.one/${params}`,
|
||||||
`https://lyricsplus-api.atomix.one/${params}`,
|
`https://lyricsplus-api.atomix.one/${params}`,
|
||||||
`https://rl-api.kineticsand.net/${params}`,
|
|
||||||
];
|
];
|
||||||
|
const fallbackUrl = `https://rl-api.kineticsand.net/${params}`;
|
||||||
|
|
||||||
for (const url of urls) {
|
// "ok" = got a response (data may still be null if type != Word)
|
||||||
|
// "500" = serverless timeout, skip remaining primaries and go to fallback
|
||||||
|
// "err" = network/other error, try next host
|
||||||
|
type FetchOutcome =
|
||||||
|
| { status: "ok"; data: WordLyricsResponse | null }
|
||||||
|
| { status: "500" }
|
||||||
|
| { status: "err" };
|
||||||
|
|
||||||
|
const tryFetch = async (url: string): Promise<FetchOutcome> => {
|
||||||
try {
|
try {
|
||||||
sylTrace(`RL API: Fetching word/syllable lyrics: ${url}`);
|
sylTrace(`RL API: Fetching word/syllable lyrics: ${url}`);
|
||||||
const res = await fetch(url);
|
const res = await fetch(url);
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
trace.log(`RL API: fetch failed: ${res.status} from ${url}`);
|
trace.log(`RL API: fetch failed: ${res.status} from ${url}`);
|
||||||
continue;
|
return res.status === 500 ? { status: "500" } : { status: "err" };
|
||||||
}
|
}
|
||||||
const data: WordLyricsResponse = await res.json();
|
const data: WordLyricsResponse = await res.json();
|
||||||
if (data.type !== "Word" || !data.data) {
|
if (data.type !== "Word" || !data.data) {
|
||||||
trace.log(`Word/Syllable lyrics not available (type: ${data.type})`);
|
trace.log(`Word/Syllable lyrics not available (type: ${data.type})`);
|
||||||
cachedLyricsKey = cacheKey;
|
return { status: "ok", data: null };
|
||||||
cachedLyricsData = null;
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
return { status: "ok", data };
|
||||||
|
} catch (err) {
|
||||||
|
trace.log(`RL API: fetch error from ${url}: ${err}`);
|
||||||
|
return { status: "err" };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const finish = (data: WordLyricsResponse | null): WordLyricsResponse | null => {
|
||||||
cachedLyricsKey = cacheKey;
|
cachedLyricsKey = cacheKey;
|
||||||
cachedLyricsData = data;
|
cachedLyricsData = data;
|
||||||
return data;
|
return data;
|
||||||
} catch (err) {
|
};
|
||||||
trace.log(`RL API: fetch error from ${url}: ${err}`);
|
|
||||||
|
// Try primary hosts; bail to fallback immediately on 500
|
||||||
|
for (const url of primaryUrls) {
|
||||||
|
const outcome = await tryFetch(url);
|
||||||
|
if (outcome.status === "ok") return finish(outcome.data);
|
||||||
|
if (outcome.status === "500") {
|
||||||
|
trace.log("RL API: 500 from primary host — skipping to fallback");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
// "err" → try next primary
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fallback: kineticsand (no serverless timeout)
|
||||||
|
const fallback = await tryFetch(fallbackUrl);
|
||||||
|
if (fallback.status === "ok") return finish(fallback.data);
|
||||||
|
|
||||||
trace.log("RL API: All Endpoints Failed");
|
trace.log("RL API: All Endpoints Failed");
|
||||||
cachedLyricsKey = cacheKey;
|
cachedLyricsKey = cacheKey;
|
||||||
cachedLyricsData = null;
|
cachedLyricsData = null;
|
||||||
@@ -2066,12 +2096,13 @@ const onTrackChange = async (): Promise<void> => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sylTrace(
|
sylTrace(
|
||||||
`RL API: looking up "${trackInfo.title}" by "${trackInfo.artist}"`,
|
`RL API: looking up "${trackInfo.title}" by "${trackInfo.artist}"${trackInfo.isrc ? ` (ISRC: ${trackInfo.isrc})` : ""}`,
|
||||||
);
|
);
|
||||||
|
|
||||||
const response = await fetchWordLyrics(
|
const response = await fetchWordLyrics(
|
||||||
trackInfo.title,
|
trackInfo.title,
|
||||||
trackInfo.artist,
|
trackInfo.artist,
|
||||||
|
trackInfo.isrc,
|
||||||
);
|
);
|
||||||
if (token !== trackChangeToken) return;
|
if (token !== trackChangeToken) return;
|
||||||
if (!response) {
|
if (!response) {
|
||||||
|
|||||||
Reference in New Issue
Block a user