Spotify Link-Through & Navidrome Logo Overlay #15
Reference in New Issue
Block a user
Delete Branch "main"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
First off — huge thanks for building this plugin. It's a great piece of work and exactly the kind of thing that makes self-hosting music actually fun.
Background
I've been in the middle of migrating away from Spotify to Navidrome and this plugin was a brilliant find. It meant the Discord presence experience I was used to carried over almost perfectly — my friends could still see what I was listening to, which was one of the things I'd quietly miss about Spotify. The plugin covered everything I needed, except for one thing my friends kept pointing out: they couldn't easily get to what I was listening to. On Spotify, clicking the track in someone's status opens it straight away — there was no equivalent here.
What I've Added
Spotify Link-Through (ListenBrainz-powered)
The track title, artist name, and album art in the Discord presence are now all clickable and link through to Spotify.
I deliberately went with ListenBrainz Labs for the resolution rather than just building a Spotify search URL: a search URL opens Spotify's search results page — you still have to find and click the right track yourself. What my friends actually wanted was to click and have it play, not have to go hunting. ListenBrainz maps MusicBrainz recording IDs (and track metadata as a fallback) directly to Spotify track IDs, so clicking the link opens the exact track ready to play.
The resolution chain is:
Resolved URLs are cached (30 days for direct track links, 4 hours for search fallbacks) to keep things snappy and avoid hammering the API.
Navidrome Logo Overlay
(The example screenshot shows as purple, this is just in my deployment the code references the official blue logo.)
A small Navidrome logo badge is shown in the corner of the album art. Purely aesthetic — it gives the presence a bit of identity and makes it clear the music is coming from Navidrome rather than looking like a generic status. It's on by default but can be disabled in the plugin settings for anyone who prefers a clean album art display.
I understand this is a navidrome official repo, however I thought best to contribute the work I have done on the project to make it useable for me.
Happy to tweak anything — open to feedback!
Summary of Changes
Hello @Woahai321, I'm Gemini Code Assist1 ! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!
This pull request significantly enhances the Discord Rich Presence plugin for Navidrome by adding interactive Spotify linking and a visual branding element. Users can now click on the track title, artist, or album art in their Discord status to directly open the corresponding song on Spotify, powered by intelligent resolution via ListenBrainz. Additionally, a subtle Navidrome logo overlay has been introduced to the album art, providing clear identification of the music source. These changes aim to improve the user experience by making shared music more accessible and visually distinct.
Highlights
🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.
Changelog
navidrome.webpand reflectmain.go's new responsibilities.crypto/sha256,encoding/hex, andnet/urlfor Spotify URL resolution and caching.navLogoOverlayKeyconstant andnavidromeLogoURL.buildSpotifySearchURL,spotifySearch,spotifyCacheKey,listenBrainzResultstruct,trySpotifyFromMBID,trySpotifyFromMetadata,parseSpotifyID,resolveSpotifyURL, andparsePrimaryArtistfunctions for Spotify integration.NowPlayingfunction to incorporate Navidrome logo overlay logic and pass Spotify URLs torpc.sendActivity.GetConfigmocks to includenavLogoOverlayKey.httppermission reasons andrequiredHoststo includelabs.api.listenbrainz.organdraw.githubusercontent.com.navlogooverlayboolean property to the plugin configuration schema with a default oftrue.navlogooverlay.activitystruct to includeDetailsURL,StateURL, andStatusDisplayTypefields for clickable links.activityAssetsstruct to includeLargeURL,SmallImage, andSmallTextfor clickable album art and logo overlay.sendActivityto process and send the small image for the logo overlay.parsePrimaryArtist,buildSpotifySearchURL,spotifyCacheKey,parseSpotifyID, and ListenBrainz request payload construction.Activity
Using Gemini Code Assist
The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.
Invoking Gemini
You can request assistance from Gemini at any point by creating a comment using either
/gemini <command>or@gemini-code-assist <command>. Below is a summary of the supported commands on the current page./gemini review/gemini summary/gemini helpCustomization
To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a
.gemini/folder in the base of the repository. Detailed instructions can be found here.Limitations & Feedback
Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.
You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.
Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩︎
Code Review
This is a fantastic contribution that adds valuable new features to the plugin. The Spotify link-through powered by ListenBrainz is a great idea, and the implementation with caching and fallbacks is well-executed. The Navidrome logo overlay is a nice aesthetic touch. The code is generally clean and well-structured, and the addition of unit tests for the new logic is much appreciated. I've identified a few areas for improvement, including a minor bug in the manifest that would prevent the logo from loading, and a discrepancy between the described and implemented behavior for the track title link. My feedback aims to align the implementation with the feature description and improve robustness.
For consistency and improved robustness, it's better to use the
%qformat verb to safely quote thembidstring, just as you've done intrySpotifyFromMetadata. While MBIDs are UUIDs and unlikely to contain special characters that need escaping in a JSON string, this change would prevent any potential JSON injection issues and make the code more resilient.The PR description and README state that the track title should link directly to the Spotify track. However,
DetailsURLis currently being set to a generic Spotify search URL usingspotifySearch(input.Track.Title), while the more sophisticatedresolveSpotifyURLis used forLargeURL.To align with the described functionality and improve efficiency, you can call
resolveSpotifyURLonce before sending the activity and reuse its result for bothDetailsURLandLargeURL. This ensures the track title links directly to the song and avoids a redundant API call.@@ -17,3 +17,4 @@"labs.api.listenbrainz.org"]},"websocket": {The Navidrome logo overlay is fetched from
cdn.jsdelivr.net, but this host is missing from therequiredHostslist. This will prevent the logo from being displayed due to security restrictions. Please addcdn.jsdelivr.netto the list.Additionally,
raw.githubusercontent.comis included but doesn't appear to be used by the plugin. If it's not needed, you could remove it to keep the required permissions minimal.Download the plugin for this PR: discord-rich-presence.zip
Built from
56b449b23aon 2026-02-28T00:34:31ZHey, thanks for the contribution! I tried to implement this overlay and link, but could not find any docs or examples on how to do it. Thanks!
I have some ideas of refactoring this, so it would be easier if I could just commit some changes directly to your PR, is that ok?
I actually prefer the overlay to always be applied, but the link should be optional, specially because most of self-hosters don't want their servers pinging Spotify servers.
Hey, thanks for getting back to me on this.
I am more than happy for you to make changes to the pr please go ahead. My goal was to replicate what I had before as close as possible functionality wise and share my implementation of what I'm using everyday to provide inspiration.
I agree with the sentiment of logo always on and linking optional, this makes more sense for the wider community, especially people trying to move away from Spotify.
For clarity we would only be pining listenbrainz API on every change in order to construct a Spotify URL that's hyperlinked to the respective items.
Currently it's set:
(Album Cover) links to the crafted open.spotify url resolved through the listenbrainz API
(Title & Artist) link to a crafted to a crafted open.spotify search URL of the respective content.
(Album) has to be the same link as the artwork.
My initial thoughts on making linking an optional setting in the configuration leads me to enhancing this to offer the user Spotify / YTmusic / etc URLs linked to the items (this was a route I initially went down)
Let me know your thoughts
Any reason why we can't try to find title and artist links from LB API as well? Is it a limitation of LB or Spotify?
By the way, where did you find information about these undocumented options?
I thought about that as well, we can enhance the plugin later with this functionality
Ok, I finished my changes. Let me know what do you think. Once you review it, I'm ready to release it.
For the documentation on these abilities I will have to go on a hunt and may not be able to provide exact documentation. for context I also previously built a "music notify" app that pinged the spotify API every 30m for selected artists to send a discord notification about new releases. I recently migrated this to use Deezer but it still delivers the notifications through a discord webhook. I applied some of the logic used in webhook formatting to the presence to see if it would work, and it did, so I think these are undocumented capabilities.
This PR has the same issue as #12: ListenBrainz calls fails and we can't handle this due to limitations of the Extism http client:
We may need to implement a new HTTP host function in Navidrome for better error handling.
Understood thanks for the update
Fixed! Will use this version for a couple of days, to spot any remaining issues, before merging. Please do the same if you can.
hi looking to test the changes and received the below error on enablement of the plugin.
Error creating instance: instantiating module: "http_send" is not exported in module "extism:host/user"i assume this is related to the change in http request mechanism can you confirm how to resolve on my end for testing?
Ah yes, forgot about this. You'll need the latest navidrome from the
developbuild. The change will be included in the next Navidrome version, due end of next month.If you prefer not to use the develop build, unfortunately you'll have to wait.
ahha makes sense no problem thanks for letting me know.
im due to migrate all my homelab to new hardware this weekend so i shall move to the develop build then and give it a whirl!
This is working as expected. I'll merge it now, but will only release a new plugin after the next Navidrome release, as this requires the new HTTP host service