0.2.52
This commit is contained in:
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user