Add uguu.se artwork upload for private Navidrome instances #4

Merged
deluan merged 5 commits from coverart-fallback into main 2026-02-07 12:27:32 -07:00
deluan commented 2026-02-04 13:35:59 -07:00 (Migrated from github.com)

NOTE: This version only works with the Navidrome version 0.60.2 and above.

Summary

  • Adds optional uguu.se image hosting so Discord can display album artwork when Navidrome is not publicly accessible (e.g. behind Tailscale/VPN)
  • When enabled, cover art is fetched via SubsonicAPICallRaw and uploaded to uguu.se, with cached URLs to avoid redundant uploads (2.5h cache TTL vs 3h provider expiry)
  • Simple boolean checkbox in the Navidrome UI to enable/disable the feature

Closes #1

Test plan

  • Verify go test -race ./... passes
  • Test with uguu upload disabled (existing behavior unchanged)
  • Test with uguu upload enabled: verify artwork uploads and caches correctly
  • Verify checkbox renders properly in Navidrome plugin config UI
## **NOTE:** This version only works with the Navidrome version 0.60.2 and above. ## Summary - Adds optional uguu.se image hosting so Discord can display album artwork when Navidrome is not publicly accessible (e.g. behind Tailscale/VPN) - When enabled, cover art is fetched via `SubsonicAPICallRaw` and uploaded to uguu.se, with cached URLs to avoid redundant uploads (2.5h cache TTL vs 3h provider expiry) - Simple boolean checkbox in the Navidrome UI to enable/disable the feature Closes #1 ## Test plan - [x] Verify `go test -race ./...` passes - [x] Test with uguu upload disabled (existing behavior unchanged) - [x] Test with uguu upload enabled: verify artwork uploads and caches correctly - [x] Verify checkbox renders properly in Navidrome plugin config UI
github-actions[bot] commented 2026-02-04 13:37:18 -07:00 (Migrated from github.com)

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

Built from 9a040c33df on 2026-02-07T19:22:52Z

Download the plugin for this PR: [discord-rich-presence.zip](https://nightly.link/navidrome/discord-rich-presence-plugin/actions/runs/21785519758/discord-rich-presence.zip) Built from 9a040c33dffebc2cf52207dfea2c4467c8be086f on 2026-02-07T19:22:52Z <!-- Sticky Pull Request Comment -->
copilot-pull-request-reviewer[bot] (Migrated from github.com) reviewed 2026-02-04 13:39:27 -07:00
copilot-pull-request-reviewer[bot] (Migrated from github.com) left a comment

Pull request overview

This pull request adds optional image hosting integration to enable Discord to display album artwork when Navidrome instances are not publicly accessible (e.g., behind Tailscale or VPN). The implementation supports two image hosting providers (imgbb and uguu.se) with caching to avoid redundant uploads.

Changes:

  • Added image hosting integration with imgbb and uguu.se for uploading cover art
  • Implemented URL caching with provider-specific TTLs (23h for imgbb, 2.5h for uguu.se)
  • Added conditional UI field visibility in Navidrome configuration (imgbb API key shown only when imgbb is selected)

Reviewed changes

Copilot reviewed 7 out of 8 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
coverart.go New file implementing image hosting logic with upload functions for imgbb and uguu.se, including caching
coverart_test.go Comprehensive test coverage for the new image hosting functionality
main.go Updated getImageURL call to include username parameter for SubsonicAPI integration
main_test.go Added SubsonicAPIMock cleanup in BeforeEach, removed TestDiscordPlugin (moved to plugin_suite_test.go), added imageHostKey mock
plugin_suite_test.go New file containing the Ginkgo test suite setup (moved from main_test.go)
manifest.json Added permissions for new HTTP hosts and subsonicapi; added configuration schema for imagehost and imgbbapikey with conditional UI visibility
go.mod Updated PDK dependency version
go.sum Updated checksums for PDK dependency

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

## Pull request overview This pull request adds optional image hosting integration to enable Discord to display album artwork when Navidrome instances are not publicly accessible (e.g., behind Tailscale or VPN). The implementation supports two image hosting providers (imgbb and uguu.se) with caching to avoid redundant uploads. **Changes:** - Added image hosting integration with imgbb and uguu.se for uploading cover art - Implemented URL caching with provider-specific TTLs (23h for imgbb, 2.5h for uguu.se) - Added conditional UI field visibility in Navidrome configuration (imgbb API key shown only when imgbb is selected) ### Reviewed changes Copilot reviewed 7 out of 8 changed files in this pull request and generated 4 comments. <details> <summary>Show a summary per file</summary> | File | Description | | ---- | ----------- | | coverart.go | New file implementing image hosting logic with upload functions for imgbb and uguu.se, including caching | | coverart_test.go | Comprehensive test coverage for the new image hosting functionality | | main.go | Updated getImageURL call to include username parameter for SubsonicAPI integration | | main_test.go | Added SubsonicAPIMock cleanup in BeforeEach, removed TestDiscordPlugin (moved to plugin_suite_test.go), added imageHostKey mock | | plugin_suite_test.go | New file containing the Ginkgo test suite setup (moved from main_test.go) | | manifest.json | Added permissions for new HTTP hosts and subsonicapi; added configuration schema for imagehost and imgbbapikey with conditional UI visibility | | go.mod | Updated PDK dependency version | | go.sum | Updated checksums for PDK dependency | </details> --- 💡 <a href="/navidrome/discord-rich-presence-plugin/new/main/.github/instructions?filename=*.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>.
@@ -0,0 +1,110 @@
package main
copilot-pull-request-reviewer[bot] (Migrated from github.com) commented 2026-02-04 13:39:27 -07:00

The API key is directly interpolated into a URL-encoded form body without proper escaping. If the API key contains special characters like '&' or '=', this could break the request format. Consider using url.Values or proper URL encoding to safely construct the form body.

The API key is directly interpolated into a URL-encoded form body without proper escaping. If the API key contains special characters like '&' or '=', this could break the request format. Consider using url.Values or proper URL encoding to safely construct the form body.
copilot-pull-request-reviewer[bot] (Migrated from github.com) commented 2026-02-04 13:39:27 -07:00

When an empty string is provided for imagehost (e.g., user clears the field), the switch statement will fall through to the default case and use getImageDirect. This is acceptable behavior, but it might be clearer to explicitly handle the empty string case for better code readability and maintainability.

When an empty string is provided for imagehost (e.g., user clears the field), the switch statement will fall through to the default case and use getImageDirect. This is acceptable behavior, but it might be clearer to explicitly handle the empty string case for better code readability and maintainability.
@@ -0,0 +55,4 @@
}
// Fetch artwork data from Navidrome
contentType, data, err := host.SubsonicAPICallRaw(fmt.Sprintf("/getCoverArt?u=%s&id=%s&size=300", username, trackID))
copilot-pull-request-reviewer[bot] (Migrated from github.com) commented 2026-02-04 13:39:26 -07:00

The username and trackID parameters are directly interpolated into the URL without proper escaping. If a username contains special characters like '&' or '=', this could break the query string or potentially be exploited for parameter injection. Consider using url.QueryEscape or a proper URL builder to safely construct the query parameters.

The username and trackID parameters are directly interpolated into the URL without proper escaping. If a username contains special characters like '&' or '=', this could break the query string or potentially be exploited for parameter injection. Consider using url.QueryEscape or a proper URL builder to safely construct the query parameters.
@@ -39,6 +42,11 @@
"maxLength": 20,
copilot-pull-request-reviewer[bot] (Migrated from github.com) commented 2026-02-04 13:39:27 -07:00

The imagehost field uses an enum with only two values ("imgbb", "uguu"), but does not include an empty string option. This means users cannot explicitly unset this field once it's been set. Consider either making this field optional (not in the enum) or adding an empty string/null option to allow users to disable image hosting after enabling it.

          "enum": ["", "imgbb", "uguu"]
The imagehost field uses an enum with only two values ("imgbb", "uguu"), but does not include an empty string option. This means users cannot explicitly unset this field once it's been set. Consider either making this field optional (not in the enum) or adding an empty string/null option to allow users to disable image hosting after enabling it. ```suggestion "enum": ["", "imgbb", "uguu"] ```
Sign in to join this conversation.