Release Memby 0.2.64

This commit is contained in:
ponzischeme89
2026-08-14 13:32:14 +12:00
parent ad0c74f880
commit 05d95f51cd
33 changed files with 1142 additions and 112 deletions
+101 -13
View File
@@ -85,24 +85,78 @@ 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"`
Schedules []HeroSchedule `json:"schedules"`
PinnedItemIDs []string `json:"pinnedItemIds"`
LegacyPinnedMovieIDs []string `json:"pinnedMovieIds,omitempty"`
PrimeSubtitle string `json:"primeSubtitle"`
Placements map[string]HeroPlacementPolicy `json:"placements,omitempty"`
UpdatedAt time.Time `json:"updatedAt"`
Schedules []HeroSchedule `json:"schedules"`
}
// HeroPlacementPolicy is one independently resolved spotlight. Keeping the placement as
// a map key means another section can be added without changing the stored document.
type HeroPlacementPolicy struct {
PinnedItemIDs []string `json:"pinnedItemIds"`
PrimeSubtitle string `json:"primeSubtitle"`
}
// HeroSchedule is resolved by the gateway for every home response. Times are UTC RFC3339;
// weekdays use the local calendar day (Sunday=0) and an empty list means every day.
type HeroSchedule struct {
ID string `json:"id"`
ItemID string `json:"itemId"`
StartAt time.Time `json:"startAt"`
EndAt time.Time `json:"endAt"`
Weekdays []int `json:"weekdays,omitempty"`
Priority int `json:"priority"`
UserID string `json:"userId,omitempty"`
Enabled bool `json:"enabled"`
ID string `json:"id"`
ItemID string `json:"itemId"`
StartAt time.Time `json:"startAt"`
EndAt time.Time `json:"endAt"`
Weekdays []int `json:"weekdays,omitempty"`
Priority int `json:"priority"`
UserID string `json:"userId,omitempty"`
Enabled bool `json:"enabled"`
Placements []string `json:"placements,omitempty"`
}
const (
HeroPlacementHome = "home"
HeroPlacementMovies = "movies"
HeroPlacementTVShows = "tv_shows"
)
func ValidHeroPlacement(value string) bool {
switch strings.ToLower(strings.TrimSpace(value)) {
case HeroPlacementHome, HeroPlacementMovies, HeroPlacementTVShows:
return true
default:
return false
}
}
func normaliseHeroPlacementPolicy(policy HeroPlacementPolicy) HeroPlacementPolicy {
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.PrimeSubtitle = strings.TrimSpace(policy.PrimeSubtitle)
if runes := []rune(policy.PrimeSubtitle); len(runes) > 160 {
policy.PrimeSubtitle = string(runes[:160])
}
return policy
}
func (policy HeroPolicy) Placement(name string) HeroPlacementPolicy {
name = strings.ToLower(strings.TrimSpace(name))
if placement, ok := policy.Placements[name]; ok {
return placement
}
if name == HeroPlacementHome {
return HeroPlacementPolicy{PinnedItemIDs: policy.PinnedItemIDs, PrimeSubtitle: policy.PrimeSubtitle}
}
return HeroPlacementPolicy{PinnedItemIDs: []string{}}
}
func normalizeHeroPolicy(policy HeroPolicy) HeroPolicy {
@@ -126,6 +180,27 @@ func normalizeHeroPolicy(policy HeroPolicy) HeroPolicy {
if len(runes) > 160 {
policy.PrimeSubtitle = string(runes[:160])
}
if policy.Placements == nil {
policy.Placements = map[string]HeroPlacementPolicy{}
}
if _, exists := policy.Placements[HeroPlacementHome]; !exists {
policy.Placements[HeroPlacementHome] = HeroPlacementPolicy{PinnedItemIDs: policy.PinnedItemIDs, PrimeSubtitle: policy.PrimeSubtitle}
}
cleanPlacements := make(map[string]HeroPlacementPolicy, len(policy.Placements))
for name, placement := range policy.Placements {
name = strings.ToLower(strings.TrimSpace(name))
if ValidHeroPlacement(name) {
cleanPlacements[name] = normaliseHeroPlacementPolicy(placement)
}
}
for _, name := range []string{HeroPlacementHome, HeroPlacementMovies, HeroPlacementTVShows} {
if _, exists := cleanPlacements[name]; !exists {
cleanPlacements[name] = HeroPlacementPolicy{PinnedItemIDs: []string{}}
}
}
policy.Placements = cleanPlacements
home := policy.Placement(HeroPlacementHome)
policy.PinnedItemIDs, policy.PrimeSubtitle = home.PinnedItemIDs, home.PrimeSubtitle
cleanSchedules := make([]HeroSchedule, 0, len(policy.Schedules))
seenSchedules := map[string]bool{}
for _, schedule := range policy.Schedules {
@@ -149,6 +224,19 @@ func normalizeHeroPolicy(policy HeroPolicy) HeroPolicy {
}
}
schedule.Weekdays = weekdays
placements := make([]string, 0, len(schedule.Placements))
seenPlacements := map[string]bool{}
for _, placement := range schedule.Placements {
placement = strings.ToLower(strings.TrimSpace(placement))
if ValidHeroPlacement(placement) && !seenPlacements[placement] {
seenPlacements[placement] = true
placements = append(placements, placement)
}
}
if len(placements) == 0 {
placements = []string{HeroPlacementHome}
}
schedule.Placements = placements
cleanSchedules = append(cleanSchedules, schedule)
}
policy.Schedules = cleanSchedules