From 1b278cb33ac54ce363627a2f648a463c6d08bfca Mon Sep 17 00:00:00 2001 From: Evelyn Gravett Date: Sat, 4 Oct 2025 04:27:59 +0100 Subject: [PATCH] Feature: Add song and artist links to discord RPC (#1160) * Add song and artist links to discord RPC * use first artist name for artist link, full artist name for song link * use first album artist for song link * add discord rpc links setting * simplify discord link settings * fix setting description * add musicbrainz links * fix callback missing dependency * use encodeURIComponent for lastfm links Co-authored-by: Kendall Garner <17521368+kgarner7@users.noreply.github.com> * split musicbrainz ids * combine link settings --------- Co-authored-by: Kendall Garner <17521368+kgarner7@users.noreply.github.com> --- src/i18n/locales/en.json | 4 ++ .../features/discord-rpc/use-discord-rpc.ts | 30 ++++++++++++ .../components/window/discord-settings.tsx | 49 +++++++++++++++++++ src/renderer/store/settings.store.ts | 9 ++++ src/shared/api/jellyfin/jellyfin-normalize.ts | 2 + src/shared/api/jellyfin/jellyfin-types.ts | 12 +++-- .../api/navidrome/navidrome-normalize.ts | 2 + src/shared/api/navidrome/navidrome-types.ts | 2 +- src/shared/api/subsonic/subsonic-normalize.ts | 2 + src/shared/types/domain-types.ts | 2 + 10 files changed, 108 insertions(+), 6 deletions(-) diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json index 7580e53a..714743c4 100644 --- a/src/i18n/locales/en.json +++ b/src/i18n/locales/en.json @@ -544,6 +544,10 @@ "discordDisplayType_description": "changes what you are listening to in your status", "discordDisplayType_songname": "song name", "discordDisplayType_artistname": "artist name(s)", + "discordLinkType": "{{discord}} presence links", + "discordLinkType_description": "adds external links to {{lastfm}} or {{musicbrainz}} to the song and artist fields in {{discord}} rich presence. {{musicbrainz}} is the most accurate but requires tags and doesn't provide artist links while {{lastfm}} should always provide a link. makes no extra network requests", + "discordLinkType_none": "$t(common.none)", + "discordLinkType_mbz_lastfm": "{{musicbrainz}} with {{lastfm}} fallback", "doubleClickBehavior": "queue all searched tracks when double clicking", "doubleClickBehavior_description": "if true, all matching tracks in a track search will be queued. otherwise, only the clicked one will be queued", "enableRemote": "enable remote control server", diff --git a/src/renderer/features/discord-rpc/use-discord-rpc.ts b/src/renderer/features/discord-rpc/use-discord-rpc.ts index 63ba35bf..cfb7f015 100644 --- a/src/renderer/features/discord-rpc/use-discord-rpc.ts +++ b/src/renderer/features/discord-rpc/use-discord-rpc.ts @@ -5,6 +5,7 @@ import { useCallback, useEffect, useState } from 'react'; import { controller } from '/@/renderer/api/controller'; import { DiscordDisplayType, + DiscordLinkType, getServerById, useAppStore, useDiscordSettings, @@ -77,6 +78,34 @@ export const useDiscordRpc = () => { type: discordSettings.showAsListening ? 2 : 0, }; + if ( + (discordSettings.linkType == DiscordLinkType.LAST_FM || + discordSettings.linkType == DiscordLinkType.MBZ_LAST_FM) && + song?.artistName + ) { + activity.stateUrl = + 'https://www.last.fm/music/' + encodeURIComponent(song.artists[0].name); + activity.detailsUrl = + 'https://www.last.fm/music/' + + encodeURIComponent(song.albumArtists[0].name) + + '/' + + encodeURIComponent(song.album || '_') + + '/' + + encodeURIComponent(song.name); + } + + if ( + discordSettings.linkType == DiscordLinkType.MBZ || + discordSettings.linkType == DiscordLinkType.MBZ_LAST_FM + ) { + if (song?.mbzTrackId) { + activity.detailsUrl = 'https://musicbrainz.org/track/' + song.mbzTrackId; + } else if (song?.mbzRecordingId) { + activity.detailsUrl = + 'https://musicbrainz.org/recording/' + song.mbzRecordingId; + } + } + if ((current[2] as PlayerStatus) === PlayerStatus.PLAYING) { if (start && end) { activity.startTimestamp = start; @@ -145,6 +174,7 @@ export const useDiscordRpc = () => { generalSettings.lastfmApiKey, discordSettings.clientId, discordSettings.displayType, + discordSettings.linkType, lastUniqueId, ], ); diff --git a/src/renderer/features/settings/components/window/discord-settings.tsx b/src/renderer/features/settings/components/window/discord-settings.tsx index c721c57d..254f826c 100644 --- a/src/renderer/features/settings/components/window/discord-settings.tsx +++ b/src/renderer/features/settings/components/window/discord-settings.tsx @@ -7,6 +7,7 @@ import { } from '/@/renderer/features/settings/components/settings-section'; import { DiscordDisplayType, + DiscordLinkType, useDiscordSettings, useGeneralSettings, useSettingsStoreActions, @@ -162,6 +163,54 @@ export const DiscordSettings = () => { }), isHidden: !isElectron(), title: t('setting.discordDisplayType', { + discord: 'Discord', + musicbrainz: 'musicbrainz', + postProcess: 'sentenceCase', + }), + }, + { + control: ( +