diff --git a/src/equicordplugins/richPresence/SettingsPanel.tsx b/src/equicordplugins/richPresence/SettingsPanel.tsx
index 40fefc4db..15793f914 100644
--- a/src/equicordplugins/richPresence/SettingsPanel.tsx
+++ b/src/equicordplugins/richPresence/SettingsPanel.tsx
@@ -141,29 +141,6 @@ function JellyfinSettings() {
);
}
-function ListenBrainzSettings() {
- return (
- <>
-
-
-
-
-
-
-
-
-
-
-
-
-
- >
- );
-}
-
function GensokyoRadioSettings() {
const [value, setValue] = useState(settings.store.gr_refreshInterval ?? 15);
return (
@@ -239,7 +216,6 @@ const TAB_COMPONENTS: Record = {
[ServiceTab.Tosu]: TosuSettings,
[ServiceTab.StatsFm]: StatsFmSettings,
[ServiceTab.Jellyfin]: JellyfinSettings,
- [ServiceTab.ListenBrainz]: ListenBrainzSettings,
[ServiceTab.GensokyoRadio]: GensokyoRadioSettings,
[ServiceTab.Navidrome]: NavidromeSettings,
};
@@ -249,7 +225,6 @@ const TAB_LABELS: Record = {
[ServiceTab.Tosu]: "osu!",
[ServiceTab.StatsFm]: "stats.fm",
[ServiceTab.Jellyfin]: "Jellyfin",
- [ServiceTab.ListenBrainz]: "ListenBrainz",
[ServiceTab.GensokyoRadio]: "Gensokyo Radio",
[ServiceTab.Navidrome]: "Navidrome",
};
@@ -259,7 +234,6 @@ const ENABLE_KEYS: Record = {
[ServiceTab.Tosu]: "tosu_enabled",
[ServiceTab.StatsFm]: "sfm_enabled",
[ServiceTab.Jellyfin]: "jf_enabled",
- [ServiceTab.ListenBrainz]: "lb_enabled",
[ServiceTab.GensokyoRadio]: "gr_enabled",
[ServiceTab.Navidrome]: "nd_enabled",
};
diff --git a/src/equicordplugins/richPresence/index.tsx b/src/equicordplugins/richPresence/index.tsx
index ecda47809..a60412dfa 100644
--- a/src/equicordplugins/richPresence/index.tsx
+++ b/src/equicordplugins/richPresence/index.tsx
@@ -12,7 +12,6 @@ import { migrateOldSettings } from "./migration";
import * as abs from "./services/audiobookshelf";
import * as gensokyoRadio from "./services/gensokyoRadio";
import * as jellyfin from "./services/jellyfin";
-import * as listenbrainz from "./services/listenbrainz";
import * as navidrome from "./services/navidrome";
import * as statsfm from "./services/statsfm";
import * as tosu from "./services/tosu";
@@ -28,7 +27,6 @@ const services: Record = {
[ServiceTab.Tosu]: "tosu_enabled",
[ServiceTab.StatsFm]: "sfm_enabled",
[ServiceTab.Jellyfin]: "jf_enabled",
- [ServiceTab.ListenBrainz]: "lb_enabled",
[ServiceTab.GensokyoRadio]: "gr_enabled",
[ServiceTab.Navidrome]: "nd_enabled",
};
@@ -77,7 +74,7 @@ function stopAllServices() {
export default definePlugin({
name: "RichPresence",
- description: "Unified rich presence hub for AudioBookShelf, osu!, stats.fm, Jellyfin, ListenBrainz, Navidrome, and Gensokyo Radio.",
+ description: "Unified rich presence hub for AudioBookShelf, osu!, stats.fm, Jellyfin, Navidrome, and Gensokyo Radio.",
tags: ["Activity"],
authors: [
EquicordDevs.vmohammad,
diff --git a/src/equicordplugins/richPresence/migration.ts b/src/equicordplugins/richPresence/migration.ts
index 49f35b2ba..fe18b5bc4 100644
--- a/src/equicordplugins/richPresence/migration.ts
+++ b/src/equicordplugins/richPresence/migration.ts
@@ -63,24 +63,6 @@ const migrations: MigrationMapping[] = [
privacyMode: "jf_privacyMode",
},
},
- {
- oldPlugin: "ListenBrainzRPC",
- enableKey: "lb_enabled",
- keys: {
- username: "lb_username",
- mbContact: "lb_mbContact",
- shareUsername: "lb_shareUsername",
- shareSong: "lb_shareSong",
- hideWithSpotify: "lb_hideWithSpotify",
- hideWithActivity: "lb_hideWithActivity",
- useTimeBar: "lb_useTimeBar",
- statusName: "lb_statusName",
- nameFormat: "lb_nameFormat",
- useListeningStatus: "lb_useListeningStatus",
- missingArt: "lb_missingArt",
- useLogo: "lb_useLogo",
- },
- },
{
oldPlugin: "GensokyoRadioRPC",
enableKey: "gr_enabled",
@@ -97,7 +79,7 @@ function setStoreValue(key: SettingsKey, value: boolean | string | number) {
export function migrateOldSettings() {
if (Settings.plugins.RichPresence._migrated) return;
- migratePluginSettings("RichPresence", "AudioBookShelfRichPresence", "GensokyoRadioRPC", "JellyfinRichPresence", "ListenBrainzRPC", "StatsfmPresence", "TosuRPC");
+ migratePluginSettings("RichPresence", "AudioBookShelfRichPresence", "GensokyoRadioRPC", "JellyfinRichPresence", "StatsfmPresence", "TosuRPC");
for (const migration of migrations) {
const oldSettings = Settings.plugins[migration.oldPlugin];
diff --git a/src/equicordplugins/richPresence/services/listenbrainz.ts b/src/equicordplugins/richPresence/services/listenbrainz.ts
deleted file mode 100644
index 72d132b64..000000000
--- a/src/equicordplugins/richPresence/services/listenbrainz.ts
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2026 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import { Logger } from "@utils/Logger";
-import { Activity, ActivityButton } from "@vencord/discord-types";
-import { ActivityFlags, ActivityType } from "@vencord/discord-types/enums";
-import { findByPropsLazy } from "@webpack";
-import { ApplicationAssetUtils, FluxDispatcher } from "@webpack/common";
-
-import { settings } from "../settings";
-import { NameFormat } from "../types";
-import { LbTrackData } from "../types/listenbrainz";
-
-const APPLICATION_ID = "1090155131007406132";
-const PLACEHOLDER_ID = "2a96cbd8b46e442fc41c2b86b821562f";
-const SOCKET_ID = "RichPresence_LB";
-const logger = new Logger("RichPresence:ListenBrainz");
-const PresenceStore = findByPropsLazy("getLocalPresence");
-
-let updateInterval: NodeJS.Timeout | undefined;
-let currentRecordingMBID = "";
-let currentStart = 0;
-
-async function getAsset(key: string): Promise {
- return (await ApplicationAssetUtils.fetchAssetIds(APPLICATION_ID, [key]))[0];
-}
-
-function setActivity(activity: Activity | null) {
- FluxDispatcher.dispatch({ type: "LOCAL_ACTIVITY_UPDATE", activity, socketId: SOCKET_ID });
-}
-
-async function fetchTrackData(): Promise {
- if (!settings.store.lb_username) {
- logger.warn("ListenBrainz username is not set.");
- return null;
- }
-
- try {
- const lbRes = await fetch(`https://api.listenbrainz.org/1/user/${settings.store.lb_username}/playing-now`);
- if (!lbRes.ok) throw `${lbRes.status} ${lbRes.statusText}`;
-
- const lbJson = await lbRes.json();
- if (lbJson.error) {
- logger.error("Error from ListenBrainz API", `${lbJson.error}: ${lbJson.message}`);
- return null;
- }
-
- const listen = lbJson.payload?.listens?.[0];
- if (!listen?.playing_now) return null;
-
- const trackMetadata = listen.track_metadata;
- const albumName = trackMetadata.release_name || "Unknown";
- const artistName = trackMetadata.artist_name || "Unknown";
-
- const mbRes = await fetch(
- `https://musicbrainz.org/ws/2/release/?query=release:${encodeURIComponent(albumName)}%20AND%20artist:${encodeURIComponent(artistName)}&fmt=json`
- );
- if (!mbRes.ok) throw `${mbRes.status} ${mbRes.statusText}`;
-
- const mbJson = await mbRes.json();
- const releases = mbJson.releases || [];
- const releaseGroup = releases[0]?.["release-group"]?.id;
-
- let url = "";
- let imageUrl = "";
-
- if (releaseGroup) {
- const caaRes = await fetch(`https://coverartarchive.org/release-group/${releaseGroup}`);
- if (caaRes.ok) {
- const caaJson = await caaRes.json();
- url = caaJson.release ?? "";
- for (const image of caaJson.images) {
- imageUrl = image.thumbnails.large || "";
- if (imageUrl) break;
- }
- }
- }
-
- return {
- name: trackMetadata.track_name || "Unknown",
- album: albumName,
- artist: artistName,
- durationMs: trackMetadata.additional_info?.duration_ms,
- recordingMBID: trackMetadata.additional_info?.recording_mbid,
- url,
- imageUrl,
- };
- } catch (e) {
- logger.error("Failed to query ListenBrainz API", e);
- return null;
- }
-}
-
-function getLargeImage(track: LbTrackData): string | undefined {
- if (track.imageUrl && !track.imageUrl.includes(PLACEHOLDER_ID)) return track.imageUrl;
- if (settings.store.lb_missingArt === "placeholder") return "placeholder";
-}
-
-async function getActivity(): Promise {
- if (settings.store.lb_hideWithActivity) {
- if (PresenceStore.getActivities().some(a => a.application_id !== APPLICATION_ID)) return null;
- }
-
- if (settings.store.lb_hideWithSpotify) {
- if (PresenceStore.getActivities().some(a => a.type === ActivityType.LISTENING && a.application_id !== APPLICATION_ID))
- return null;
- }
-
- const trackData = await fetchTrackData();
- if (!trackData) return null;
-
- const largeImage = getLargeImage(trackData);
- const assets = largeImage
- ? {
- large_image: await getAsset(largeImage),
- large_text: trackData.album || undefined,
- small_image: settings.store.lb_useLogo ? await getAsset("listenbrainz") : undefined,
- small_text: "ListenBrainz",
- }
- : {
- large_image: await getAsset("listenbrainz"),
- large_text: trackData.album || undefined,
- };
-
- const buttons: ActivityButton[] = [];
- if (settings.store.lb_shareUsername)
- buttons.push({ label: "ListenBrainz Profile", url: `https://www.listenbrainz.org/user/${settings.store.lb_username}` });
- if (settings.store.lb_shareSong && trackData.url)
- buttons.push({ label: "View Song", url: trackData.url });
-
- const statusName = (() => {
- switch (settings.store.lb_nameFormat) {
- case NameFormat.ArtistFirst: return trackData.artist + " - " + trackData.name;
- case NameFormat.SongFirst: return trackData.name + " - " + trackData.artist;
- case NameFormat.ArtistOnly: return trackData.artist;
- case NameFormat.SongOnly: return trackData.name;
- case NameFormat.AlbumName: return trackData.album || settings.store.lb_statusName;
- default: return settings.store.lb_statusName;
- }
- })();
-
- if (trackData.recordingMBID && trackData.recordingMBID !== currentRecordingMBID) {
- currentRecordingMBID = trackData.recordingMBID;
- currentStart = Date.now();
- }
-
- return {
- application_id: APPLICATION_ID,
- name: statusName,
- details: trackData.name,
- state: trackData.artist,
- assets,
- timestamps: settings.store.lb_useTimeBar && currentStart
- ? { start: currentStart, end: trackData.durationMs ? currentStart + trackData.durationMs : undefined }
- : undefined,
- buttons: buttons.length ? buttons.map(v => v.label) : undefined,
- metadata: buttons.length ? { button_urls: buttons.map(v => v.url) } : undefined,
- type: settings.store.lb_useListeningStatus ? ActivityType.LISTENING : ActivityType.PLAYING,
- flags: ActivityFlags.INSTANCE,
- };
-}
-
-async function updatePresence() {
- try {
- setActivity(await getActivity());
- } catch (e) {
- logger.error("Failed to update presence", e);
- setActivity(null);
- }
-}
-
-export function start() {
- currentRecordingMBID = "";
- currentStart = 0;
- updatePresence();
- updateInterval = setInterval(updatePresence, 16000);
-}
-
-export function stop() {
- clearInterval(updateInterval);
- updateInterval = undefined;
- setActivity(null);
-}
diff --git a/src/equicordplugins/richPresence/settings.ts b/src/equicordplugins/richPresence/settings.ts
index 048bd3f69..6566bd0dd 100644
--- a/src/equicordplugins/richPresence/settings.ts
+++ b/src/equicordplugins/richPresence/settings.ts
@@ -56,13 +56,6 @@ export const settings = definePluginSettings({
hidden: true,
onChange: () => onServiceChange?.(),
},
- lb_enabled: {
- description: "Enable ListenBrainz presence.",
- type: OptionType.BOOLEAN,
- default: false,
- hidden: true,
- onChange: () => onServiceChange?.(),
- },
gr_enabled: {
description: "Enable Gensokyo Radio presence.",
type: OptionType.BOOLEAN,
@@ -261,90 +254,6 @@ export const settings = definePluginSettings({
hidden: true,
},
- // ListenBrainz
- lb_username: {
- description: "ListenBrainz username.",
- type: OptionType.STRING,
- default: "",
- hidden: true,
- },
- lb_mbContact: {
- description: "MusicBrainz contact for user agent.",
- type: OptionType.STRING,
- default: "",
- hidden: true,
- },
- lb_shareUsername: {
- description: "Show link to ListenBrainz profile.",
- type: OptionType.BOOLEAN,
- default: false,
- hidden: true,
- },
- lb_shareSong: {
- description: "Show link to song on ListenBrainz.",
- type: OptionType.BOOLEAN,
- default: true,
- hidden: true,
- },
- lb_hideWithSpotify: {
- description: "Hide presence if Spotify is running.",
- type: OptionType.BOOLEAN,
- default: true,
- hidden: true,
- },
- lb_hideWithActivity: {
- description: "Hide presence if any other presence exists.",
- type: OptionType.BOOLEAN,
- default: false,
- hidden: true,
- },
- lb_useTimeBar: {
- description: "Use track duration to display a time bar.",
- type: OptionType.BOOLEAN,
- default: true,
- hidden: true,
- },
- lb_statusName: {
- description: "Custom status text.",
- type: OptionType.STRING,
- default: "some music",
- hidden: true,
- },
- lb_nameFormat: {
- description: "Name format.",
- type: OptionType.SELECT,
- options: [
- { label: "Use custom status name", value: NameFormat.StatusName, default: true },
- { label: "Use format 'artist - song'", value: NameFormat.ArtistFirst },
- { label: "Use format 'song - artist'", value: NameFormat.SongFirst },
- { label: "Use artist name only", value: NameFormat.ArtistOnly },
- { label: "Use song name only", value: NameFormat.SongOnly },
- { label: "Use album name", value: NameFormat.AlbumName },
- ],
- hidden: true,
- },
- lb_useListeningStatus: {
- description: "Show listening status.",
- type: OptionType.BOOLEAN,
- default: true,
- hidden: true,
- },
- lb_missingArt: {
- description: "Fallback when art is missing.",
- type: OptionType.SELECT,
- options: [
- { label: "Use large ListenBrainz logo", value: "listenbrainzLogo", default: true },
- { label: "Use generic placeholder", value: "placeholder" },
- ],
- hidden: true,
- },
- lb_useLogo: {
- description: "Show ListenBrainz logo on album art.",
- type: OptionType.BOOLEAN,
- default: true,
- hidden: true,
- },
-
// Gensokyo Radio
gr_refreshInterval: {
description: "Refresh interval in seconds.",
diff --git a/src/equicordplugins/richPresence/types/index.ts b/src/equicordplugins/richPresence/types/index.ts
index bfeba0172..e6937ea61 100644
--- a/src/equicordplugins/richPresence/types/index.ts
+++ b/src/equicordplugins/richPresence/types/index.ts
@@ -9,7 +9,6 @@ export enum ServiceTab {
Tosu = "tosu",
StatsFm = "statsfm",
Jellyfin = "jellyfin",
- ListenBrainz = "listenbrainz",
GensokyoRadio = "gensokyoRadio",
Navidrome = "navidrome",
}