diff --git a/core/agents/placeholders.go b/core/agents/placeholders.go index 45ab5f591..1210b8db9 100644 --- a/core/agents/placeholders.go +++ b/core/agents/placeholders.go @@ -3,21 +3,22 @@ package agents import ( "context" + "github.com/navidrome/navidrome/consts" "github.com/navidrome/navidrome/model" ) const PlaceholderAgentName = "placeholder" const ( - placeholderArtistImageSmallUrl = "https://lastfm.freetls.fastly.net/i/u/64s/2a96cbd8b46e442fc41c2b86b821562f.png" - placeholderArtistImageMediumUrl = "https://lastfm.freetls.fastly.net/i/u/174s/2a96cbd8b46e442fc41c2b86b821562f.png" - placeholderArtistImageLargeUrl = "https://lastfm.freetls.fastly.net/i/u/300x300/2a96cbd8b46e442fc41c2b86b821562f.png" + placeholderArtistImageSmallUrl = consts.URLPathUI + "/artist-placeholder.webp" + placeholderArtistImageMediumUrl = consts.URLPathUI + "/artist-placeholder.webp" + placeholderArtistImageLargeUrl = consts.URLPathUI + "/artist-placeholder.webp" placeholderBiography = "Biography not available" ) type placeholderAgent struct{} -func placeholdersConstructor(ds model.DataStore) Interface { +func placeholdersConstructor(_ model.DataStore) Interface { return &placeholderAgent{} } diff --git a/server/middlewares.go b/server/middlewares.go index effed7721..1c374fa2b 100644 --- a/server/middlewares.go +++ b/server/middlewares.go @@ -115,7 +115,7 @@ func compressMiddleware() func(http.Handler) http.Handler { ) } -func clientUniqueIdAdder(next http.Handler) http.Handler { +func clientUniqueIDMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() clientUniqueId := r.Header.Get(consts.UIClientUniqueIDHeader) @@ -145,3 +145,57 @@ func clientUniqueIdAdder(next http.Handler) http.Handler { next.ServeHTTP(w, r) }) } + +func serverAddressMiddleware(h http.Handler) http.Handler { + fn := func(w http.ResponseWriter, r *http.Request) { + if rScheme, rHost := serverAddress(r); rHost != "" { + r.Host = rHost + r.URL.Scheme = rScheme + } + h.ServeHTTP(w, r) + } + + return http.HandlerFunc(fn) +} + +var ( + xForwardedHost = http.CanonicalHeaderKey("X-Forwarded-Host") + xForwardedProto = http.CanonicalHeaderKey("X-Forwarded-Scheme") + xForwardedScheme = http.CanonicalHeaderKey("X-Forwarded-Proto") +) + +func serverAddress(r *http.Request) (scheme, host string) { + origHost := r.Host + protocol := "http" + if r.TLS != nil { + protocol = "https" + } + xfh := r.Header.Get(xForwardedHost) + if xfh != "" { + i := strings.Index(xfh, ",") + if i == -1 { + i = len(xfh) + } + xfh = xfh[:i] + } + scheme = firstOr( + protocol, + r.Header.Get(xForwardedProto), + r.Header.Get(xForwardedScheme), + r.URL.Scheme, + ) + host = firstOr(r.Host, xfh) + if host != origHost { + log.Trace(r.Context(), "Request host has changed", "origHost", origHost, "host", host, "scheme", scheme, "url", r.URL) + } + return scheme, host +} + +func firstOr(or string, strings ...string) string { + for _, s := range strings { + if s != "" { + return s + } + } + return or +} diff --git a/server/server.go b/server/server.go index d095d586c..f96b1c3d3 100644 --- a/server/server.go +++ b/server/server.go @@ -6,6 +6,7 @@ import ( "fmt" "net/http" "path" + "strings" "time" "github.com/go-chi/chi/v5" @@ -94,7 +95,8 @@ func (s *Server) initRoutes() { r.Use(middleware.Recoverer) r.Use(compressMiddleware()) r.Use(middleware.Heartbeat("/ping")) - r.Use(clientUniqueIdAdder) + r.Use(serverAddressMiddleware) + r.Use(clientUniqueIDMiddleware) r.Use(loggerInjector) r.Use(requestLogger) r.Use(robotsTXT(ui.BuildAssets())) @@ -135,3 +137,11 @@ func (s *Server) frontendAssetsHandler() http.Handler { r.Handle("/*", http.StripPrefix(s.appRoot, http.FileServer(http.FS(ui.BuildAssets())))) return r } + +func AbsoluteURL(r *http.Request, url string) string { + if strings.HasPrefix(url, "/") { + appRoot := path.Join(r.Host, conf.Server.BaseURL, url) + url = r.URL.Scheme + "://" + appRoot + } + return url +} diff --git a/server/subsonic/browsing.go b/server/subsonic/browsing.go index 9d17dcd47..044a535b2 100644 --- a/server/subsonic/browsing.go +++ b/server/subsonic/browsing.go @@ -10,6 +10,7 @@ import ( "github.com/navidrome/navidrome/conf" "github.com/navidrome/navidrome/log" "github.com/navidrome/navidrome/model" + "github.com/navidrome/navidrome/server" "github.com/navidrome/navidrome/server/subsonic/filter" "github.com/navidrome/navidrome/server/subsonic/responses" "github.com/navidrome/navidrome/utils" @@ -231,9 +232,9 @@ func (api *Router) GetArtistInfo(r *http.Request) (*responses.Subsonic, error) { response := newResponse() response.ArtistInfo = &responses.ArtistInfo{} response.ArtistInfo.Biography = artist.Biography - response.ArtistInfo.SmallImageUrl = artist.SmallImageUrl - response.ArtistInfo.MediumImageUrl = artist.MediumImageUrl - response.ArtistInfo.LargeImageUrl = artist.LargeImageUrl + response.ArtistInfo.SmallImageUrl = server.AbsoluteURL(r, artist.SmallImageUrl) + response.ArtistInfo.MediumImageUrl = server.AbsoluteURL(r, artist.MediumImageUrl) + response.ArtistInfo.LargeImageUrl = server.AbsoluteURL(r, artist.LargeImageUrl) response.ArtistInfo.LastFmUrl = artist.ExternalUrl response.ArtistInfo.MusicBrainzID = artist.MbzArtistID for _, s := range artist.SimilarArtists { @@ -259,7 +260,7 @@ func (api *Router) GetArtistInfo2(r *http.Request) (*responses.Subsonic, error) similar.AlbumCount = s.AlbumCount similar.Starred = s.Starred similar.UserRating = s.UserRating - similar.ArtistImageUrl = s.ArtistImageUrl + similar.ArtistImageUrl = server.AbsoluteURL(r, s.ArtistImageUrl) response.ArtistInfo2.SimilarArtist = append(response.ArtistInfo2.SimilarArtist, similar) } return response, nil diff --git a/server/subsonic/responses/responses.go b/server/subsonic/responses/responses.go index 9593f6706..795e1290f 100644 --- a/server/subsonic/responses/responses.go +++ b/server/subsonic/responses/responses.go @@ -78,8 +78,9 @@ type Artist struct { Starred *time.Time `xml:"starred,attr,omitempty" json:"starred,omitempty"` UserRating int `xml:"userRating,attr,omitempty" json:"userRating,omitempty"` ArtistImageUrl string `xml:"artistImageUrl,attr,omitempty" json:"artistImageUrl,omitempty"` - /* - + /* TODO: + + */ } diff --git a/ui/public/artist-placeholder.webp b/ui/public/artist-placeholder.webp new file mode 100644 index 000000000..2729158d2 Binary files /dev/null and b/ui/public/artist-placeholder.webp differ