This commit is contained in:
ponzischeme89
2026-08-11 23:41:10 +12:00
parent 0e183cf560
commit 5fed3360c2
42 changed files with 1340 additions and 130 deletions
+71 -1
View File
@@ -18,14 +18,84 @@ const MaintenanceKey = "maintenance"
// RequestPolicyKey controls which Emby users may send titles to Sonarr/Radarr.
const RequestPolicyKey = "request_policy"
// PlaybackPolicyKey controls presentation behavior that should be adjustable without
// PlaybackPolicyKey controls presentation behaviour that should be adjustable without
// shipping a new TV build.
const PlaybackPolicyKey = "playback_policy"
// HeroPolicyKey stores the operator's explicit choices for the launcher hero.
const HeroPolicyKey = "hero_policy"
// MDBListSettingsKey stores the optional movie-ratings integration. The API key stays
// in this server-owned document and is never included in client or admin status payloads.
const MDBListSettingsKey = "mdblist_settings"
// HeroPolicy stores only Emby ids and the optional prime-card copy. Names and artwork
// remain library data, so a metadata correction appears without rewriting operator policy.
type HeroPolicy struct {
PinnedItemIDs []string `json:"pinnedItemIds"`
LegacyPinnedMovieIDs []string `json:"pinnedMovieIds,omitempty"`
PrimeSubtitle string `json:"primeSubtitle"`
UpdatedAt time.Time `json:"updatedAt"`
}
func normalizeHeroPolicy(policy HeroPolicy) HeroPolicy {
if len(policy.PinnedItemIDs) == 0 && len(policy.LegacyPinnedMovieIDs) > 0 {
policy.PinnedItemIDs = policy.LegacyPinnedMovieIDs
}
seen := map[string]bool{}
ids := make([]string, 0, min(len(policy.PinnedItemIDs), 4))
for _, id := range policy.PinnedItemIDs {
id = strings.TrimSpace(id)
if id == "" || seen[id] || len(ids) == 4 {
continue
}
seen[id] = true
ids = append(ids, id)
}
policy.PinnedItemIDs = ids
policy.LegacyPinnedMovieIDs = nil
policy.PrimeSubtitle = strings.TrimSpace(policy.PrimeSubtitle)
runes := []rune(policy.PrimeSubtitle)
if len(runes) > 160 {
policy.PrimeSubtitle = string(runes[:160])
}
return policy
}
func (s *Store) HeroPolicy(ctx context.Context) (HeroPolicy, error) {
var raw []byte
err := s.pool.QueryRow(ctx, `SELECT value FROM app_settings WHERE key = $1`, HeroPolicyKey).Scan(&raw)
if errors.Is(err, pgx.ErrNoRows) {
return HeroPolicy{PinnedItemIDs: []string{}}, nil
}
if err != nil {
return HeroPolicy{}, fmt.Errorf("store: read hero policy: %w", err)
}
var policy HeroPolicy
if err := json.Unmarshal(raw, &policy); err != nil {
return HeroPolicy{}, fmt.Errorf("store: decode hero policy: %w", err)
}
return normalizeHeroPolicy(policy), nil
}
func (s *Store) SetHeroPolicy(ctx context.Context, policy HeroPolicy) error {
policy = normalizeHeroPolicy(policy)
policy.UpdatedAt = time.Now().UTC()
raw, err := json.Marshal(policy)
if err != nil {
return err
}
_, err = s.pool.Exec(ctx, `
INSERT INTO app_settings (key, value, updated_at)
VALUES ($1, $2::jsonb, now())
ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value, updated_at = now()`,
HeroPolicyKey, string(raw))
if err != nil {
return fmt.Errorf("store: write hero policy: %w", err)
}
return nil
}
var defaultMDBListSources = []string{
"imdb", "tomatoes", "audience", "metacritic", "letterboxd", "rogerebert",
"tmdb", "trakt", "mal", "anilist", "anidb", "kitsu", "score", "score_average",