Add meta tags to show cover and share description in social platforms

This commit is contained in:
Deluan 2023-01-24 15:35:23 -05:00
parent cab43c89e6
commit 69b36c75a5
5 changed files with 54 additions and 19 deletions

View File

@ -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

View File

@ -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
}

View File

@ -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)
}
})

View File

@ -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)
}

View File

@ -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`.
-->
<meta property="og:site_name" content="Navidrome">
<meta property="og:url" content="{{ .ShareURL }}">
<meta property="og:title" content="{{ .ShareDescription }}">
<meta property="og:image" content="{{ .ShareImageURL }}">
<meta property="og:image:width" content="300">
<meta property="og:image:height" content="300">
<title>Navidrome</title>
<script>
window.__APP_CONFIG__ = {{ .AppConfig }}