diff --git a/model/share.go b/model/share.go index aa31711f..6d676761 100644 --- a/model/share.go +++ b/model/share.go @@ -1,7 +1,10 @@ package model import ( + "strings" "time" + + "github.com/navidrome/navidrome/utils/number" ) type Share struct { @@ -21,6 +24,25 @@ type Share struct { UpdatedAt time.Time `structs:"updated_at" json:"updatedAt,omitempty"` Tracks MediaFiles `structs:"-" json:"tracks,omitempty" orm:"-"` Albums Albums `structs:"-" json:"albums,omitempty" orm:"-"` + URL string `structs:"-" json:"-" orm:"-"` + ImageURL string `structs:"-" json:"-" orm:"-"` +} + +func (s Share) CoverArtID() ArtworkID { + ids := strings.SplitN(s.ResourceIDs, ",", 2) + if len(ids) == 0 { + return ArtworkID{} + } + switch s.ResourceType { + case "album": + return Album{ID: ids[0]}.CoverArtID() + case "playlist": + return Playlist{ID: ids[0]}.CoverArtID() + case "artist": + return Artist{ID: ids[0]}.CoverArtID() + } + rnd := number.RandomInt64(int64(len(s.Tracks))) + return s.Tracks[rnd].CoverArtID() } type Shares []Share diff --git a/server/public/handle_shares.go b/server/public/handle_shares.go index add6e29a..776b4067 100644 --- a/server/public/handle_shares.go +++ b/server/public/handle_shares.go @@ -4,6 +4,7 @@ import ( "errors" "net/http" + "github.com/navidrome/navidrome/consts" "github.com/navidrome/navidrome/log" "github.com/navidrome/navidrome/model" "github.com/navidrome/navidrome/server" @@ -41,17 +42,15 @@ func (p *Router) handleShares(w http.ResponseWriter, r *http.Request) { return } - s = p.mapShareInfo(*s) + s = p.mapShareInfo(r, *s) server.IndexWithShare(p.ds, ui.BuildAssets(), s)(w, r) } -func (p *Router) mapShareInfo(s model.Share) *model.Share { - mapped := &model.Share{ - Description: s.Description, - Tracks: s.Tracks, - } +func (p *Router) mapShareInfo(r *http.Request, s model.Share) *model.Share { + s.URL = ShareURL(r, s.ID) + s.ImageURL = ImageURL(r, s.CoverArtID(), consts.UICoverArtSize) for i := range s.Tracks { - mapped.Tracks[i].ID = encodeMediafileShare(s, s.Tracks[i].ID) + s.Tracks[i].ID = encodeMediafileShare(s, s.Tracks[i].ID) } - return mapped + return &s } diff --git a/server/public/public_endpoints.go b/server/public/public_endpoints.go index c0f9858b..34361b13 100644 --- a/server/public/public_endpoints.go +++ b/server/public/public_endpoints.go @@ -41,6 +41,7 @@ func (p *Router) routes() http.Handler { if conf.Server.DevEnableShare { r.HandleFunc("/s/{id}", p.handleStream) r.HandleFunc("/{id}", p.handleShares) + r.HandleFunc("/", p.handleShares) r.Handle("/*", p.assetsHandler) } }) diff --git a/server/serve_index.go b/server/serve_index.go index 35e3d9ae..fae93759 100644 --- a/server/serve_index.go +++ b/server/serve_index.go @@ -1,7 +1,6 @@ package server import ( - "context" "encoding/json" "html/template" "io" @@ -80,8 +79,6 @@ func serveIndex(ds model.DataStore, fs fs.FS, shareInfo *model.Share) http.Handl log.Trace(r, "Injecting config in index.html", "config", string(appConfigJson)) } - shareInfoJson := marshalShareData(r.Context(), shareInfo) - log.Debug("UI configuration", "appConfig", appConfig) version := consts.Version if version != "dev" { @@ -89,9 +86,10 @@ func serveIndex(ds model.DataStore, fs fs.FS, shareInfo *model.Share) http.Handl } data := map[string]interface{}{ "AppConfig": string(appConfigJson), - "ShareInfo": string(shareInfoJson), "Version": version, } + addShareData(r, data, shareInfo) + w.Header().Set("Content-Type", "text/html") err = t.Execute(w, data) if err != nil { @@ -134,14 +132,15 @@ type shareTrack struct { Duration float32 `json:"duration,omitempty"` } -func marshalShareData(ctx context.Context, shareInfo *model.Share) []byte { - if shareInfo == nil { - return nil +func addShareData(r *http.Request, data map[string]interface{}, shareInfo *model.Share) { + ctx := r.Context() + if shareInfo == nil || shareInfo.ID == "" { + return } - data := shareData{ + sd := shareData{ Description: shareInfo.Description, } - data.Tracks = slice.Map(shareInfo.Tracks, func(mf model.MediaFile) shareTrack { + sd.Tracks = slice.Map(shareInfo.Tracks, func(mf model.MediaFile) shareTrack { return shareTrack{ ID: mf.ID, Title: mf.Title, @@ -152,11 +151,19 @@ func marshalShareData(ctx context.Context, shareInfo *model.Share) []byte { } }) - shareInfoJson, err := json.Marshal(data) + shareInfoJson, err := json.Marshal(sd) if err != nil { log.Error(ctx, "Error converting shareInfo to JSON", "config", shareInfo, err) } else { log.Trace(ctx, "Injecting shareInfo in index.html", "config", string(shareInfoJson)) } - return shareInfoJson + + if shareInfo.Description != "" { + data["ShareDescription"] = shareInfo.Description + } else { + data["ShareDescription"] = shareInfo.Contents + } + data["ShareURL"] = shareInfo.URL + data["ShareImageURL"] = shareInfo.ImageURL + data["ShareInfo"] = string(shareInfoJson) } diff --git a/ui/public/index.html b/ui/public/index.html index d4edcb16..e11abd37 100644 --- a/ui/public/index.html +++ b/ui/public/index.html @@ -29,6 +29,12 @@ work correctly both with client-side routing and a non-root public URL. Learn how to configure a non-root public URL by running `npm run build`. --> + + + + + + Navidrome