This commit is contained in:
ponzischeme89
2026-08-22 21:47:54 +12:00
parent d2f7f84cbf
commit 9a1f44da46
27 changed files with 452 additions and 110 deletions
+30 -4
View File
@@ -17,13 +17,14 @@ const GatewaySettingsKey = "gateway_settings"
// GatewaySettings is the handful of server-level decisions an operator can change
// without a redeployment.
//
// Every field is an *override* of the value the container was started with, and the zero
// value means "whatever was deployed". That is the whole design: `.env` remains the
// Most fields are an *override* of the value the container was started with, and their
// zero value means "whatever was deployed". That is the whole design: `.env` remains the
// configuration — it is what a fresh container comes up with, what deploy-server.ps1
// writes and what an operator locked out of the console still has — and this row is a
// runtime amendment to it, so the console can always show the deployed value beside the
// one in force and an operator can put a setting back by clearing it rather than by
// remembering what it used to be.
// remembering what it used to be. NotificationDisplay is the exception: it is a native
// server policy with a Home-only default rather than an environment-backed value.
//
// A window that can legitimately be *off* therefore needs a value distinct from "not
// overridden", which is why the two alert windows and the health interval take -1 for off
@@ -44,6 +45,10 @@ type GatewaySettings struct {
// added" banner stays on offer to a television that was switched off at the time.
SonarrAlertMinutes int `json:"sonarrAlertMinutes"`
RadarrAlertMinutes int `json:"radarrAlertMinutes"`
// NotificationDisplay is where informational banners may be drawn across every
// viewer and television. It is server-owned rather than a per-viewer preference:
// one household should not have different interruption rules on different sets.
NotificationDisplay string `json:"notificationDisplay"`
// EmbyHealthSeconds is how often the reachability probe asks Emby whether it is there.
EmbyHealthSeconds int `json:"embyHealthSeconds"`
// SlowRequestMillis is how long a request must take before its log line carries a
@@ -74,6 +79,20 @@ const GatewaySettingsOff = -1
// and refusing is worth nothing if the list it refuses against lives somewhere else.
var GatewayLogLevels = []string{"trace", "debug", "info", "warn", "error"}
const (
NotificationDisplayEverywhere = "everywhere"
NotificationDisplayHomeOnly = "home_only"
NotificationDisplayOff = "off"
)
// GatewayNotificationDisplays is the complete wire vocabulary, served to the console so
// it cannot offer a value the gateway would refuse.
var GatewayNotificationDisplays = []string{
NotificationDisplayEverywhere,
NotificationDisplayHomeOnly,
NotificationDisplayOff,
}
func normalizeGatewaySettings(settings GatewaySettings) GatewaySettings {
settings.Timezone = strings.TrimSpace(settings.Timezone)
if settings.Timezone != "" {
@@ -91,6 +110,13 @@ func normalizeGatewaySettings(settings GatewaySettings) GatewaySettings {
settings.SessionIdleDays = clampOverride(settings.SessionIdleDays, 1, 3650, false)
settings.SonarrAlertMinutes = clampOverride(settings.SonarrAlertMinutes, 1, 24*60, true)
settings.RadarrAlertMinutes = clampOverride(settings.RadarrAlertMinutes, 1, 7*24*60, true)
settings.NotificationDisplay = strings.ToLower(strings.TrimSpace(settings.NotificationDisplay))
if !containsString(GatewayNotificationDisplays, settings.NotificationDisplay) {
// Missing covers both a new installation and a row written by an older gateway.
// Unknown is equally conservative: silence from the setting must never authorise
// an interruption over active playback.
settings.NotificationDisplay = NotificationDisplayHomeOnly
}
settings.EmbyHealthSeconds = clampOverride(settings.EmbyHealthSeconds, 10, 3600, true)
// The floor is 1ms rather than 0 because "breakdown on everything" is a real thing to
// want for a few minutes, and off is a real thing to want too — this is the one
@@ -133,7 +159,7 @@ func (s *Store) GatewaySettings(ctx context.Context) (GatewaySettings, error) {
err := s.pool.QueryRow(ctx,
`SELECT value FROM app_settings WHERE key = $1`, GatewaySettingsKey).Scan(&raw)
if errors.Is(err, pgx.ErrNoRows) {
return GatewaySettings{}, nil
return normalizeGatewaySettings(GatewaySettings{}), nil
}
if err != nil {
return GatewaySettings{}, fmt.Errorf("store: read gateway settings: %w", err)