feat: use Cover Art Archive for albums with MusicBrainz IDs #27

Merged
deluan merged 9 commits from feat/cover-art-archive into main 2026-03-20 18:34:11 -06:00
deluan commented 2026-03-20 18:22:53 -06:00 (Migrated from github.com)

Summary

Closes #10. Supersedes #12 with a simpler approach.

  • Adds a "Use artwork from Cover Art Archive" config toggle
  • When enabled, performs a HEAD request to coverartarchive.org/release/{MBZAlbumID}/front-500 to check for artwork
  • If the release has no art, falls back to the release-group endpoint (/release-group/{MBZReleaseGroupID}/front-500), which resolves to the best available release with art in the same group
  • Extracts the archive.org redirect URL from the Location header (using NoFollowRedirects) and passes it directly to Discord — no image download or re-upload needed
  • Results are cached (24h for hits, 4h for misses)
  • CAA takes priority over uguu.se and direct Navidrome URLs when enabled

Differences from #12

  • Uses a lightweight HEAD request instead of GET + JSON parsing of the full CAA API response
  • Adds release-group fallback (covers cases where a specific release lacks art but another in the group has it)
  • Does not require the track to have a MBZAlbumID — will also try MBZReleaseGroupID alone
  • Passes the resolved archive.org URL directly to Discord instead of constructing it from the API response

Test plan

  • headCoverArt: 307 with Location, 404, HTTP error, missing Location header
  • getImageViaCoverArt: cache hit/miss, release fallback to release-group, both fail, empty IDs
  • getImageURL integration: CAA hit skips other methods, CAA miss falls through to uguu/direct
  • Existing tests updated for new getImageURL(username, TrackInfo) signature
  • go test -race ./... passes
  • make build and make package succeed
## Summary Closes #10. Supersedes #12 with a simpler approach. - Adds a "Use artwork from Cover Art Archive" config toggle - When enabled, performs a HEAD request to `coverartarchive.org/release/{MBZAlbumID}/front-500` to check for artwork - If the release has no art, falls back to the release-group endpoint (`/release-group/{MBZReleaseGroupID}/front-500`), which resolves to the best available release with art in the same group - Extracts the `archive.org` redirect URL from the `Location` header (using `NoFollowRedirects`) and passes it directly to Discord — no image download or re-upload needed - Results are cached (24h for hits, 4h for misses) - CAA takes priority over uguu.se and direct Navidrome URLs when enabled ### Differences from #12 - Uses a lightweight HEAD request instead of GET + JSON parsing of the full CAA API response - Adds release-group fallback (covers cases where a specific release lacks art but another in the group has it) - Does not require the track to have a `MBZAlbumID` — will also try `MBZReleaseGroupID` alone - Passes the resolved `archive.org` URL directly to Discord instead of constructing it from the API response ## Test plan - [x] `headCoverArt`: 307 with Location, 404, HTTP error, missing Location header - [x] `getImageViaCoverArt`: cache hit/miss, release fallback to release-group, both fail, empty IDs - [x] `getImageURL` integration: CAA hit skips other methods, CAA miss falls through to uguu/direct - [x] Existing tests updated for new `getImageURL(username, TrackInfo)` signature - [x] `go test -race ./...` passes - [x] `make build` and `make package` succeed
gemini-code-assist[bot] commented 2026-03-20 18:23:12 -06:00 (Migrated from github.com)

Summary of Changes

Hello, 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 introduces a significant enhancement to how album artwork is retrieved and displayed. It integrates with the Cover Art Archive (CAA) using MusicBrainz IDs, providing a more robust and efficient method for sourcing high-quality cover art. The changes include a new configuration option, an intelligent fallback system for artwork discovery, and optimized handling of image URLs to minimize resource usage, ultimately improving the user experience by ensuring more accurate and readily available album art.

Highlights

  • Cover Art Archive (CAA) Integration: Added a new configuration toggle 'Use artwork from Cover Art Archive' to enable fetching album artwork using MusicBrainz IDs.
  • Efficient Artwork Retrieval: Implemented a lightweight HEAD request to coverartarchive.org to check for artwork, avoiding full API responses.
  • Artwork Fallback Mechanism: Introduced a fallback system that first tries the release endpoint, then the release-group endpoint, to find available artwork.
  • Direct URL Handling: The resolved archive.org redirect URL is now passed directly to Discord, eliminating the need for image download or re-upload.
  • Caching for Performance: Results from CAA lookups are cached for 24 hours for hits and 4 hours for misses to improve performance.
  • Artwork Priority: When enabled, CAA takes precedence over existing artwork methods like uguu.se and direct Navidrome URLs.

🧠 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.

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.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

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.


  1. 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. ↩︎

## Summary of Changes Hello, I'm Gemini Code Assist[^1]! 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 introduces a significant enhancement to how album artwork is retrieved and displayed. It integrates with the Cover Art Archive (CAA) using MusicBrainz IDs, providing a more robust and efficient method for sourcing high-quality cover art. The changes include a new configuration option, an intelligent fallback system for artwork discovery, and optimized handling of image URLs to minimize resource usage, ultimately improving the user experience by ensuring more accurate and readily available album art. ### Highlights * **Cover Art Archive (CAA) Integration**: Added a new configuration toggle 'Use artwork from Cover Art Archive' to enable fetching album artwork using MusicBrainz IDs. * **Efficient Artwork Retrieval**: Implemented a lightweight HEAD request to `coverartarchive.org` to check for artwork, avoiding full API responses. * **Artwork Fallback Mechanism**: Introduced a fallback system that first tries the release endpoint, then the release-group endpoint, to find available artwork. * **Direct URL Handling**: The resolved `archive.org` redirect URL is now passed directly to Discord, eliminating the need for image download or re-upload. * **Caching for Performance**: Results from CAA lookups are cached for 24 hours for hits and 4 hours for misses to improve performance. * **Artwork Priority**: When enabled, CAA takes precedence over existing artwork methods like uguu.se and direct Navidrome URLs. 🧠 **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](https://codeassist.google/code-review/login) to enable Memory in your admin console.** <details> <summary><b>Using Gemini Code Assist</b></summary> <br> The full guide for Gemini Code Assist can be found on our [documentation page](https://developers.google.com/gemini-code-assist/docs/review-github-code), here are some quick tips. <b>Invoking Gemini</b> 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. Feature | Command | Description --- | --- | --- Code Review | `/gemini review` | Performs a code review for the current pull request in its current state. Pull Request Summary | `/gemini summary` | Provides a summary of the current pull request in its current state. Comment | @gemini-code-assist | Responds in comments when explicitly tagged, both in pull request comments and review comments. Help | `/gemini help` | Displays a list of available commands. <b>Customization</b> 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](https://developers.google.com/gemini-code-assist/docs/customize-gemini-behavior-github). <b>Limitations & Feedback</b> Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with :thumbsup: and :thumbsdown: 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](https://google.qualtrics.com/jfe/form/SV_2cyuGuTWsEw84yG). </details> [^1]: Review the [Privacy Notices](https://policies.google.com/privacy), [Generative AI Prohibited Use Policy](https://policies.google.com/terms/generative-ai/use-policy), [Terms of Service](https://policies.google.com/terms), and learn how to configure Gemini Code Assist in GitHub [here](https://developers.google.com/gemini-code-assist/docs/customize-gemini-behavior-github). Gemini can make mistakes, so double check it and [use code with caution](https://support.google.com/legal/answer/13505487).
github-actions[bot] commented 2026-03-20 18:24:18 -06:00 (Migrated from github.com)

Download the plugin for this PR: discord-rich-presence.zip

Built from 76d4074ca1 on 2026-03-21T00:33:56Z

Download the plugin for this PR: [discord-rich-presence.zip](https://nightly.link/navidrome/discord-rich-presence-plugin/actions/runs/23368036081/discord-rich-presence.zip) Built from 76d4074ca1e2f4540c0601f98e01c4ca580e8d25 on 2026-03-21T00:33:56Z <!-- Sticky Pull Request Comment -->
gemini-code-assist[bot] (Migrated from github.com) reviewed 2026-03-20 18:24:36 -06:00
gemini-code-assist[bot] (Migrated from github.com) left a comment

Code Review

This pull request introduces a great new feature to fetch cover art from the Cover Art Archive. The implementation is clean, efficient by using HEAD requests, and includes thoughtful features like release-group fallback and caching. The accompanying tests are comprehensive and cover many scenarios. My feedback includes a couple of minor suggestions to improve code maintainability.

## Code Review This pull request introduces a great new feature to fetch cover art from the Cover Art Archive. The implementation is clean, efficient by using HEAD requests, and includes thoughtful features like release-group fallback and caching. The accompanying tests are comprehensive and cover many scenarios. My feedback includes a couple of minor suggestions to improve code maintainability.
@@ -7,10 +7,94 @@ import (
gemini-code-assist[bot] (Migrated from github.com) commented 2026-03-20 18:24:36 -06:00

medium

To improve maintainability and avoid magic numbers, it's better to define 5000 as a constant, for example const caaRequestTimeoutMs = 5000, and use it here. You could define it with the other constants in this file.

![medium](https://www.gstatic.com/codereviewagent/medium-priority.svg) To improve maintainability and avoid magic numbers, it's better to define `5000` as a constant, for example `const caaRequestTimeoutMs = 5000`, and use it here. You could define it with the other constants in this file.
@@ -30,2 +30,4 @@
activityNameKey = "activityname"
spotifyLinksKey = "spotifylinks"
caaEnabledKey = "caaenabled"
uguuEnabledKey = "uguuenabled"
gemini-code-assist[bot] (Migrated from github.com) commented 2026-03-20 18:24:36 -06:00

medium

These constants are only used in coverart.go. To improve code organization and maintainability, it's best to define constants in the file where they are used. Please consider moving caaEnabledKey and uguuEnabledKey to coverart.go. This would also be consistent with how uguuEnabledKey was defined before this change.

![medium](https://www.gstatic.com/codereviewagent/medium-priority.svg) These constants are only used in `coverart.go`. To improve code organization and maintainability, it's best to define constants in the file where they are used. Please consider moving `caaEnabledKey` and `uguuEnabledKey` to `coverart.go`. This would also be consistent with how `uguuEnabledKey` was defined before this change.
copilot-pull-request-reviewer[bot] (Migrated from github.com) reviewed 2026-03-20 18:28:21 -06:00
copilot-pull-request-reviewer[bot] (Migrated from github.com) left a comment

Pull request overview

Adds optional Cover Art Archive (CAA) lookups for album artwork when MusicBrainz IDs are available, prioritizing CAA over existing artwork sources and caching results to reduce repeated network calls.

Changes:

  • Introduces a caaenabled config toggle and allows HTTP access to coverartarchive.org.
  • Implements CAA artwork resolution via HEAD requests (release, then release-group fallback) and caches hits/misses.
  • Updates getImageURL to accept TrackInfo (so it can use MBZ IDs) and adjusts tests/dependencies accordingly.

Reviewed changes

Copilot reviewed 6 out of 7 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
manifest.json Adds coverartarchive.org to allowed HTTP hosts and introduces the caaenabled config option/UI control.
main.go Adds config key constants and updates NowPlaying to call the new getImageURL(username, TrackInfo) signature.
main_test.go Updates mocks to include the new caaenabled config access.
coverart.go Adds CAA HEAD resolution + caching and updates image selection priority/signature.
coverart_test.go Adds unit/integration tests for headCoverArt, getImageViaCoverArt, and updated getImageURL behavior.
go.mod / go.sum Bumps Navidrome PDK dependency to a newer revision.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

## Pull request overview Adds optional Cover Art Archive (CAA) lookups for album artwork when MusicBrainz IDs are available, prioritizing CAA over existing artwork sources and caching results to reduce repeated network calls. **Changes:** - Introduces a `caaenabled` config toggle and allows HTTP access to `coverartarchive.org`. - Implements CAA artwork resolution via HEAD requests (release, then release-group fallback) and caches hits/misses. - Updates `getImageURL` to accept `TrackInfo` (so it can use MBZ IDs) and adjusts tests/dependencies accordingly. ### Reviewed changes Copilot reviewed 6 out of 7 changed files in this pull request and generated 1 comment. <details> <summary>Show a summary per file</summary> | File | Description | | ---- | ----------- | | manifest.json | Adds `coverartarchive.org` to allowed HTTP hosts and introduces the `caaenabled` config option/UI control. | | main.go | Adds config key constants and updates `NowPlaying` to call the new `getImageURL(username, TrackInfo)` signature. | | main_test.go | Updates mocks to include the new `caaenabled` config access. | | coverart.go | Adds CAA HEAD resolution + caching and updates image selection priority/signature. | | coverart_test.go | Adds unit/integration tests for `headCoverArt`, `getImageViaCoverArt`, and updated `getImageURL` behavior. | | go.mod / go.sum | Bumps Navidrome PDK dependency to a newer revision. | </details> --- 💡 <a href="/navidrome/discord-rich-presence-plugin/new/main?filename=.github/instructions/*.instructions.md" class="Link--inTextBlock" target="_blank" rel="noopener noreferrer">Add Copilot custom instructions</a> for smarter, more guided reviews. <a href="https://docs.github.com/en/copilot/customizing-copilot/adding-repository-custom-instructions-for-github-copilot" class="Link--inTextBlock" target="_blank" rel="noopener noreferrer">Learn how to get started</a>.
@@ -7,10 +7,94 @@ import (
copilot-pull-request-reviewer[bot] (Migrated from github.com) commented 2026-03-20 18:28:21 -06:00

getImageViaCoverArt caches an empty string for caaCacheTTLMiss whenever imageURL == "", including when headCoverArt failed due to transient conditions (network error, 429/5xx, etc.). This can suppress retries for 4 hours after a temporary outage or rate-limit response. Consider distinguishing “definite miss” (e.g., 404) from “request failure” and only caching the former (or using a much shorter TTL for failures).

`getImageViaCoverArt` caches an empty string for `caaCacheTTLMiss` whenever `imageURL == ""`, including when `headCoverArt` failed due to transient conditions (network error, 429/5xx, etc.). This can suppress retries for 4 hours after a temporary outage or rate-limit response. Consider distinguishing “definite miss” (e.g., 404) from “request failure” and only caching the former (or using a much shorter TTL for failures).
deluan (Migrated from github.com) reviewed 2026-03-20 18:33:03 -06:00
@@ -7,10 +7,94 @@ import (
deluan (Migrated from github.com) commented 2026-03-20 18:33:03 -06:00

Already extracted to caaTimeOut constant in a subsequent commit.

Already extracted to `caaTimeOut` constant in a subsequent commit.
deluan (Migrated from github.com) reviewed 2026-03-20 18:33:16 -06:00
@@ -30,2 +30,4 @@
activityNameKey = "activityname"
spotifyLinksKey = "spotifylinks"
caaEnabledKey = "caaenabled"
uguuEnabledKey = "uguuenabled"
deluan (Migrated from github.com) commented 2026-03-20 18:33:16 -06:00

Intentional — all config keys are grouped together in main.go for discoverability. Having them scattered across files makes it harder to audit which config keys exist.

Intentional — all config keys are grouped together in `main.go` for discoverability. Having them scattered across files makes it harder to audit which config keys exist.
deluan (Migrated from github.com) reviewed 2026-03-20 18:33:28 -06:00
@@ -7,10 +7,94 @@ import (
deluan (Migrated from github.com) commented 2026-03-20 18:33:28 -06:00

Fixed in 76d4074. headCoverArt now returns (url, definitive) — transient failures (network errors, unexpected status codes) return definitive=false and are not cached, allowing immediate retries on the next track event. Only 404s are cached as misses.

Fixed in 76d4074. `headCoverArt` now returns `(url, definitive)` — transient failures (network errors, unexpected status codes) return `definitive=false` and are not cached, allowing immediate retries on the next track event. Only 404s are cached as misses.
Sign in to join this conversation.