Add optional MDBList movie ratings
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/jackc/pgx/v5"
|
||||
@@ -21,6 +22,93 @@ const RequestPolicyKey = "request_policy"
|
||||
// shipping a new TV build.
|
||||
const PlaybackPolicyKey = "playback_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"
|
||||
|
||||
var defaultMDBListSources = []string{
|
||||
"imdb", "tomatoes", "audience", "metacritic", "letterboxd", "rogerebert",
|
||||
"tmdb", "trakt", "mal", "score", "score_average",
|
||||
}
|
||||
|
||||
type MDBListSettings struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
APIKey string `json:"apiKey"`
|
||||
Sources []string `json:"sources"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
}
|
||||
|
||||
func DefaultMDBListSettings() MDBListSettings {
|
||||
return MDBListSettings{Sources: append([]string(nil), defaultMDBListSources...)}
|
||||
}
|
||||
|
||||
func MDBListSources() []string {
|
||||
return append([]string(nil), defaultMDBListSources...)
|
||||
}
|
||||
|
||||
func ValidMDBListSource(source string) bool {
|
||||
source = strings.ToLower(strings.TrimSpace(source))
|
||||
for _, supported := range defaultMDBListSources {
|
||||
if source == supported {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func normalizeMDBListSettings(settings MDBListSettings) MDBListSettings {
|
||||
settings.APIKey = strings.TrimSpace(settings.APIKey)
|
||||
seen := map[string]bool{}
|
||||
sources := make([]string, 0, len(settings.Sources))
|
||||
for _, source := range settings.Sources {
|
||||
source = strings.ToLower(strings.TrimSpace(source))
|
||||
if !ValidMDBListSource(source) || seen[source] {
|
||||
continue
|
||||
}
|
||||
seen[source] = true
|
||||
sources = append(sources, source)
|
||||
}
|
||||
if len(sources) == 0 {
|
||||
sources = append(sources, defaultMDBListSources...)
|
||||
}
|
||||
settings.Sources = sources
|
||||
return settings
|
||||
}
|
||||
|
||||
func (s *Store) MDBListSettings(ctx context.Context) (MDBListSettings, error) {
|
||||
var raw []byte
|
||||
err := s.pool.QueryRow(ctx, `SELECT value FROM app_settings WHERE key = $1`, MDBListSettingsKey).Scan(&raw)
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
return DefaultMDBListSettings(), nil
|
||||
}
|
||||
if err != nil {
|
||||
return DefaultMDBListSettings(), fmt.Errorf("store: read MDBList settings: %w", err)
|
||||
}
|
||||
var settings MDBListSettings
|
||||
if err := json.Unmarshal(raw, &settings); err != nil {
|
||||
return DefaultMDBListSettings(), fmt.Errorf("store: decode MDBList settings: %w", err)
|
||||
}
|
||||
return normalizeMDBListSettings(settings), nil
|
||||
}
|
||||
|
||||
func (s *Store) SetMDBListSettings(ctx context.Context, settings MDBListSettings) error {
|
||||
settings = normalizeMDBListSettings(settings)
|
||||
settings.UpdatedAt = time.Now().UTC()
|
||||
raw, err := json.Marshal(settings)
|
||||
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()`,
|
||||
MDBListSettingsKey, string(raw))
|
||||
if err != nil {
|
||||
return fmt.Errorf("store: write MDBList settings: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// FeaturePolicyKey is the durable operator control plane for optional behaviour.
|
||||
// The catalogue of valid flags lives in the API; the store only persists overrides so
|
||||
// removing or renaming a feature does not strand an unreadable database row.
|
||||
|
||||
Reference in New Issue
Block a user