fix: address code review issues for Spotify and Discord RPC
- Use MD5 hashing for image and Spotify cache keys instead of raw hex encoding (rpc.go) and SHA-256 (spotify.go) - Validate Spotify track IDs with base-62 regex before using in URLs - Fix buildSpotifySearchURL parameter order to match (artist, title) usage - Tighten test mock matchers with shared helpers for cache keys and external-assets URLs, replacing broad mock.Anything usage - Update test Spotify IDs to use valid base-62 identifiers
This commit is contained in:
+13
-5
@@ -1,11 +1,12 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/navidrome/navidrome/plugins/pdk/go/host"
|
||||
@@ -26,7 +27,7 @@ type listenBrainzResult struct {
|
||||
|
||||
// buildSpotifySearchURL constructs a Spotify search URL using artist and title.
|
||||
// Used as the ultimate fallback when ListenBrainz resolution fails.
|
||||
func buildSpotifySearchURL(title, artist string) string {
|
||||
func buildSpotifySearchURL(artist, title string) string {
|
||||
query := strings.TrimSpace(strings.Join([]string{artist, title}, " "))
|
||||
if query == "" {
|
||||
return "https://open.spotify.com/search/"
|
||||
@@ -45,7 +46,7 @@ func spotifySearch(term string) string {
|
||||
|
||||
// spotifyCacheKey returns a deterministic cache key for a track's Spotify URL.
|
||||
func spotifyCacheKey(artist, title, album string) string {
|
||||
h := sha256.Sum256([]byte(strings.ToLower(artist) + "\x00" + strings.ToLower(title) + "\x00" + strings.ToLower(album)))
|
||||
h := md5.Sum([]byte(strings.ToLower(artist) + "\x00" + strings.ToLower(title) + "\x00" + strings.ToLower(album)))
|
||||
return "spotify.url." + hex.EncodeToString(h[:8])
|
||||
}
|
||||
|
||||
@@ -101,7 +102,7 @@ func parseSpotifyID(body []byte) string {
|
||||
}
|
||||
for _, r := range results {
|
||||
for _, id := range r.SpotifyTrackIDs {
|
||||
if id != "" {
|
||||
if isValidSpotifyID(id) {
|
||||
return id
|
||||
}
|
||||
}
|
||||
@@ -109,6 +110,13 @@ func parseSpotifyID(body []byte) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// isValidSpotifyID checks that a Spotify track ID contains only base-62 characters.
|
||||
var spotifyIDRegex = regexp.MustCompile(`^[0-9A-Za-z]+$`)
|
||||
|
||||
func isValidSpotifyID(id string) bool {
|
||||
return spotifyIDRegex.MatchString(id)
|
||||
}
|
||||
|
||||
// resolveSpotifyURL resolves a direct Spotify track URL via ListenBrainz Labs,
|
||||
// falling back to a search URL. Results are cached.
|
||||
func resolveSpotifyURL(track scrobbler.TrackInfo) string {
|
||||
@@ -150,7 +158,7 @@ func resolveSpotifyURL(track scrobbler.TrackInfo) string {
|
||||
}
|
||||
|
||||
// 3. Fallback to search URL
|
||||
searchURL := buildSpotifySearchURL(track.Title, track.Artist)
|
||||
searchURL := buildSpotifySearchURL(track.Artist, track.Title)
|
||||
_ = host.CacheSetString(cacheKey, searchURL, spotifyCacheTTLMiss)
|
||||
pdk.Log(pdk.LogInfo, fmt.Sprintf("Spotify resolution missed, falling back to search URL for %q - %q: %s", primary, track.Title, searchURL))
|
||||
return searchURL
|
||||
|
||||
Reference in New Issue
Block a user