Files
memby/server/internal/api/metadata_hero_settings.go
T

102 lines
3.5 KiB
Go
Raw Normal View History

2026-08-22 08:26:10 +12:00
package api
import (
"context"
"encoding/json"
"net/http"
"slices"
"sync"
"github.com/ponzischeme89/memby/server/internal/adminevents"
"github.com/ponzischeme89/memby/server/internal/store"
)
type metadataHeroSettingsState struct {
mu sync.RWMutex
value store.MetadataHeroSettings
}
func (state *metadataHeroSettingsState) get() store.MetadataHeroSettings {
state.mu.RLock()
defer state.mu.RUnlock()
return store.NormalizeMetadataHeroSettings(state.value)
}
func (state *metadataHeroSettingsState) set(value store.MetadataHeroSettings) {
state.mu.Lock()
state.value = store.NormalizeMetadataHeroSettings(value)
state.mu.Unlock()
}
// LoadMetadataHeroSettings primes the household-wide presentation setting before the
// status endpoint starts telling televisions what to draw.
func (s *Server) LoadMetadataHeroSettings(ctx context.Context) error {
settings, err := s.store.MetadataHeroSettings(ctx)
if err != nil {
return err
}
s.metadataHeroSettings.set(settings)
return nil
}
type metadataHeroOption struct {
Value string `json:"value"`
Label string `json:"label"`
Description string `json:"description"`
}
var metadataHeroOptions = []metadataHeroOption{
{store.MetadataHeroTitle, "Movie logo or title", "The focused title's logo artwork, with a text title as the fallback."},
{store.MetadataHeroRatings, "Ratings", "The available third-party and community ratings."},
{store.MetadataHeroFacts, "Metadata information", "Year, runtime, classification, genres and outlined media badges."},
{store.MetadataHeroSummary, "Plot summary", "A short overview of the focused title."},
{store.MetadataHeroReason, "Why this was recommended", "The gateway's short explanation, such as Because you watched a related title."},
{store.MetadataHeroTime, "Time remaining", "A resume progress bar followed by the number of minutes remaining."},
}
type metadataHeroSettingsResponse struct {
Settings store.MetadataHeroSettings `json:"settings"`
Options []metadataHeroOption `json:"options"`
}
func (s *Server) metadataHeroSettingsResponse() metadataHeroSettingsResponse {
return metadataHeroSettingsResponse{
Settings: s.metadataHeroSettings.get(),
Options: metadataHeroOptions,
}
}
func (s *Server) handleAdminMetadataHeroSettings(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodGet {
writeJSON(w, http.StatusOK, s.metadataHeroSettingsResponse())
return
}
var req store.MetadataHeroSettings
if err := json.NewDecoder(http.MaxBytesReader(w, r.Body, 8<<10)).Decode(&req); err != nil {
writeError(w, http.StatusBadRequest, "malformed request body")
return
}
previous := s.metadataHeroSettings.get()
_, operator, _ := s.browserSession(r, adminSessionPurpose)
req.UpdatedBy = operator
stored, err := s.store.SetMetadataHeroSettings(r.Context(), req)
if err != nil {
s.loggerFor(r.Context()).Error("metadata hero settings write failed", "error", err)
writeError(w, http.StatusInternalServerError, "could not save metadata hero settings")
return
}
s.metadataHeroSettings.set(stored)
2026-08-22 11:32:50 +12:00
if !slices.Equal(previous.ContentOrder, stored.ContentOrder) ||
previous.TimeRemainingColour != stored.TimeRemainingColour {
2026-08-22 08:26:10 +12:00
s.publishAdmin(r.Context(), adminevents.Event{
Type: adminevents.TypeSettingsChanged,
Severity: adminevents.SeverityInfo,
Title: "Metadata hero changed",
2026-08-22 11:32:50 +12:00
Summary: "The household-wide metadata hero presentation was changed",
2026-08-22 08:26:10 +12:00
Actor: operator,
Link: "/admin/metadata-hero",
})
}
writeJSON(w, http.StatusOK, s.metadataHeroSettingsResponse())
}