From 8ad745d5cb0d37d4b04e34847c541b67dc07b685 Mon Sep 17 00:00:00 2001
From: Ape <60411288+Aperre@users.noreply.github.com>
Date: Fri, 27 Mar 2026 13:50:32 +0100
Subject: [PATCH] feat(musicControls): add lyrics custom provider settings
(#931)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* feat(musicControls): add lyrics custom provider settings
* 😳
---
.../musicControls/settings.tsx | 69 +++++++++++++++++--
.../musicControls/spotify/lyrics/api.tsx | 2 +-
.../lyrics/providers/SpotifyAPI/index.ts | 15 +++-
src/utils/constants.ts | 4 ++
4 files changed, 81 insertions(+), 9 deletions(-)
diff --git a/src/equicordplugins/musicControls/settings.tsx b/src/equicordplugins/musicControls/settings.tsx
index d79fe73dd..aaebfe179 100644
--- a/src/equicordplugins/musicControls/settings.tsx
+++ b/src/equicordplugins/musicControls/settings.tsx
@@ -6,10 +6,12 @@
import { definePluginSettings } from "@api/Settings";
import { disableStyle, enableStyle } from "@api/Styles";
+import { ButtonCompat } from "@components/Button";
import { HeadingSecondary } from "@components/Heading";
import { Paragraph } from "@components/Paragraph";
+import { SettingsSection } from "@components/settings/tabs/plugins/components/Common";
import { makeRange, OptionType } from "@utils/types";
-import { Button, MaskedLink, showToast, Toasts } from "@webpack/common";
+import { MaskedLink, Select, showToast, TextInput, Toasts } from "@webpack/common";
import hoverOnlyStyle from "./hoverOnly.css?managed";
import { clearLyricsCache, removeTranslations } from "./spotify/lyrics/api";
@@ -36,6 +38,46 @@ function InstallInstructions() {
);
}
+function LyricsProviderSettings() {
+ const { store } = settings;
+
+ return (
+ <>
+
+
+
+ {store.lyricsProvider === Provider.Spotify && (
+
+ {
+ store.spotifyLyricsApiUrl = v;
+ void clearLyricsCache();
+ showToast("Lyrics cache purged", Toasts.Type.SUCCESS);
+ }}
+ placeholder="https://spotify-lyrics-api-pi.vercel.app"
+ maxLength={null}
+ />
+
+ )}
+ >
+ );
+}
+
export const settings = definePluginSettings({
hoverControls: {
description: "Show controls on hover",
@@ -60,9 +102,24 @@ export const settings = definePluginSettings({
description: "Where lyrics are fetched from",
type: OptionType.SELECT,
options: [
- { value: Provider.Spotify, label: "Spotify (Musixmatch)", default: true },
- { value: Provider.Lrclib, label: "LRCLIB" },
+ { value: Provider.Lrclib, label: "LRCLIB", default: true },
+ { value: Provider.Spotify, label: "Spotify (Musixmatch)" },
],
+ hidden: true,
+ },
+ spotifyLyricsApiUrl: {
+ type: OptionType.STRING,
+ description: "Spotify lyrics API base URL.",
+ hidden: true,
+ default: "https://spotify-lyrics-api-pi.vercel.app",
+ onChange: async () => {
+ await clearLyricsCache();
+ showToast("Lyrics cache purged", Toasts.Type.SUCCESS);
+ }
+ },
+ lyricsProviderSettings: {
+ type: OptionType.COMPONENT,
+ component: LyricsProviderSettings,
},
translateTo: {
description: "Translate lyrics to - Changing this will clear existing translations",
@@ -102,15 +159,15 @@ export const settings = definePluginSettings({
description: "Purge the lyrics cache",
type: OptionType.COMPONENT,
component: () => (
-
+
),
},
spotifySectionTitle: {
diff --git a/src/equicordplugins/musicControls/spotify/lyrics/api.tsx b/src/equicordplugins/musicControls/spotify/lyrics/api.tsx
index ef73bf706..16e021ed9 100644
--- a/src/equicordplugins/musicControls/spotify/lyrics/api.tsx
+++ b/src/equicordplugins/musicControls/spotify/lyrics/api.tsx
@@ -22,7 +22,7 @@ interface NullLyricCacheEntry {
const nullLyricCache = new Map();
export const lyricFetchers = {
- [Provider.Spotify]: async (track: Track) => await getLyricsSpotify(track.id),
+ [Provider.Spotify]: async (track: Track) => await getLyricsSpotify(track.id, settings.store.spotifyLyricsApiUrl),
[Provider.Lrclib]: getLyricsLrclib,
};
diff --git a/src/equicordplugins/musicControls/spotify/lyrics/providers/SpotifyAPI/index.ts b/src/equicordplugins/musicControls/spotify/lyrics/providers/SpotifyAPI/index.ts
index e3fe48d58..7fc387c2d 100644
--- a/src/equicordplugins/musicControls/spotify/lyrics/providers/SpotifyAPI/index.ts
+++ b/src/equicordplugins/musicControls/spotify/lyrics/providers/SpotifyAPI/index.ts
@@ -19,8 +19,17 @@ interface Line {
endTimeMs: string;
}
-export async function getLyricsSpotify(trackId: string): Promise {
- const resp = await fetch("https://spotify-lyrics-api-pi.vercel.app/?trackid=" + trackId);
+const defaultSpotifyLyricsApiUrl = "https://spotify-lyrics-api-pi.vercel.app";
+
+function makeSpotifyLyricsApiUrl(trackId: string, customBaseUrl?: string): string {
+ const normalizedBaseUrl = customBaseUrl?.trim().replace(/\/+$/, "") || defaultSpotifyLyricsApiUrl;
+ const url = new URL(normalizedBaseUrl);
+ url.searchParams.set("trackid", trackId);
+ return url.toString();
+}
+
+export async function getLyricsSpotify(trackId: string, customBaseUrl?: string): Promise {
+ const resp = await fetch(makeSpotifyLyricsApiUrl(trackId, customBaseUrl));
if (!resp.ok) return null;
let data: LyricsAPIResp;
@@ -30,6 +39,8 @@ export async function getLyricsSpotify(trackId: string): Promise);
// iife so #__PURE__ works correctly