0.3.01
This commit is contained in:
@@ -366,6 +366,9 @@ func TestServiceStatusCarriesEmbyHealthAndPreferenceRevision(t *testing.T) {
|
||||
if !ok || len(metadataOrder) == 0 {
|
||||
t.Fatalf("status response carried no global metadata hero order: %v", body)
|
||||
}
|
||||
if body["metadataHeroTimeRemainingColour"] != store.MetadataHeroTimeRemainingColourGreen {
|
||||
t.Fatalf("status response carried no global time-remaining colour: %v", body)
|
||||
}
|
||||
// Likewise present with no store behind it. This is the whole delivery channel for an
|
||||
// operator's hero change: a television comparing against a missing field would go on
|
||||
// drawing yesterday's hero until it was next restarted.
|
||||
|
||||
@@ -42,7 +42,7 @@ type embyHealthState struct {
|
||||
retryEvery time.Duration
|
||||
consecutive int
|
||||
// version is what Emby last said it was. Kept across a failed probe on purpose: the
|
||||
// About page reads it, and blanking it during an outage would replace a fact that is
|
||||
// The Settings rail reads it, and blanking it during an outage would replace a fact that is
|
||||
// still true with nothing.
|
||||
version string
|
||||
}
|
||||
@@ -65,7 +65,7 @@ func (h *embyHealth) begin(interval time.Duration, now time.Time) {
|
||||
|
||||
// retune follows the operator changing the probe's cadence, or switching it off, without
|
||||
// disturbing what the probe has already found. It is deliberately not `begin`: that
|
||||
// starts a fresh watch and drops the Emby version with it, which the About page reads and
|
||||
// starts a fresh watch and drops the Emby version with it, which the Settings rail reads and
|
||||
// which is still true whatever the interval is now.
|
||||
func (h *embyHealth) retune(interval time.Duration, now time.Time) {
|
||||
h.mu.Lock()
|
||||
@@ -119,7 +119,7 @@ type embyHealthPayload struct {
|
||||
Since string `json:"since,omitempty"`
|
||||
CheckedAt string `json:"checkedAt,omitempty"`
|
||||
RetrySeconds int `json:"retrySeconds"`
|
||||
// Version is Emby's own, for the television's About page. Omitted rather than sent
|
||||
// Version is Emby's own, for the television's Settings rail. Omitted rather than sent
|
||||
// empty, so a client can tell "not known yet" from "known to be blank" — the first
|
||||
// probe may not have completed, and with the probe switched off none ever will.
|
||||
Version string `json:"version,omitempty"`
|
||||
|
||||
@@ -94,7 +94,7 @@ func TestEmbyHealthPayloadCarriesTheRetryInterval(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// The About page prints Emby's version beside the gateway's, so it has to survive the
|
||||
// The Settings rail prints Emby's version beside the gateway's, so it has to survive the
|
||||
// outage that is exactly when somebody goes looking at that page. A probe that fails
|
||||
// carries no version, and blanking the last known one would replace a fact that is still
|
||||
// true with nothing.
|
||||
|
||||
@@ -130,6 +130,7 @@ func (s *Server) handleServiceStatus(w http.ResponseWriter, r *http.Request, ses
|
||||
}
|
||||
compatible, compatibilityMessage := compatibilityFor(r)
|
||||
featurePolicy := s.currentFeaturePolicy(r.Context())
|
||||
metadataHero := s.metadataHeroSettings.get()
|
||||
writeJSON(w, http.StatusOK, map[string]any{
|
||||
"maintenance": state.Enabled,
|
||||
"quietTime": quiet.Active,
|
||||
@@ -153,10 +154,11 @@ func (s *Server) handleServiceStatus(w http.ResponseWriter, r *http.Request, ses
|
||||
// fetches /v1/preferences when they differ. That is what turns this poll into the
|
||||
// delivery channel for an operator pushing someone's settings.
|
||||
"preferencesRevision": s.preferenceRevisionFor(r, sess),
|
||||
// Four small ids are the complete household-wide metadata hero composition. They
|
||||
// ride the existing poll so a saved layout reaches an open launcher immediately,
|
||||
// without manufacturing a per-user preference revision for a global change.
|
||||
"metadataHeroContentOrder": s.metadataHeroSettings.get().ContentOrder,
|
||||
// The small metadata hero presentation document rides the existing poll so a saved
|
||||
// layout or colour reaches an open launcher immediately, without manufacturing a
|
||||
// per-user preference revision for a global change.
|
||||
"metadataHeroContentOrder": metadataHero.ContentOrder,
|
||||
"metadataHeroTimeRemainingColour": metadataHero.TimeRemainingColour,
|
||||
// The theme, as an id and a revision rather than the palette itself — the
|
||||
// preferencesRevision precedent, for the same reason. The set refetches /v1/theme
|
||||
// only when one of these moves, which is what makes a season arriving at midnight
|
||||
|
||||
@@ -86,12 +86,13 @@ func (s *Server) handleAdminMetadataHeroSettings(w http.ResponseWriter, r *http.
|
||||
return
|
||||
}
|
||||
s.metadataHeroSettings.set(stored)
|
||||
if !slices.Equal(previous.ContentOrder, stored.ContentOrder) {
|
||||
if !slices.Equal(previous.ContentOrder, stored.ContentOrder) ||
|
||||
previous.TimeRemainingColour != stored.TimeRemainingColour {
|
||||
s.publishAdmin(r.Context(), adminevents.Event{
|
||||
Type: adminevents.TypeSettingsChanged,
|
||||
Severity: adminevents.SeverityInfo,
|
||||
Title: "Metadata hero changed",
|
||||
Summary: "The household-wide metadata hero content order was changed",
|
||||
Summary: "The household-wide metadata hero presentation was changed",
|
||||
Actor: operator,
|
||||
Link: "/admin/metadata-hero",
|
||||
})
|
||||
|
||||
@@ -9,17 +9,27 @@ import (
|
||||
|
||||
func TestMetadataHeroSettingsStateHasAUsableGlobalDefault(t *testing.T) {
|
||||
var state metadataHeroSettingsState
|
||||
got := state.get().ContentOrder
|
||||
settings := state.get()
|
||||
got := settings.ContentOrder
|
||||
if !reflect.DeepEqual(got, store.DefaultMetadataHeroContentOrder) {
|
||||
t.Fatalf("content order = %v, want %v", got, store.DefaultMetadataHeroContentOrder)
|
||||
}
|
||||
if settings.TimeRemainingColour != store.MetadataHeroTimeRemainingColourGreen {
|
||||
t.Fatalf("time remaining colour = %q, want green", settings.TimeRemainingColour)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMetadataHeroSettingsStateNormalisesEveryWrite(t *testing.T) {
|
||||
var state metadataHeroSettingsState
|
||||
state.set(store.MetadataHeroSettings{ContentOrder: []string{"summary", "unknown", "summary", "title"}})
|
||||
state.set(store.MetadataHeroSettings{
|
||||
ContentOrder: []string{"summary", "unknown", "summary", "title"},
|
||||
TimeRemainingColour: " WHITE ",
|
||||
})
|
||||
want := []string{"summary", "title"}
|
||||
if got := state.get().ContentOrder; !reflect.DeepEqual(got, want) {
|
||||
t.Fatalf("content order = %v, want %v", got, want)
|
||||
}
|
||||
if got := state.get().TimeRemainingColour; got != store.MetadataHeroTimeRemainingColourWhite {
|
||||
t.Fatalf("time remaining colour = %q, want white", got)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user