0.2.48 - Tv calender fixes

This commit is contained in:
ponzischeme89
2026-08-11 12:08:51 +12:00
parent dd2dd497f2
commit f46d6596c5
47 changed files with 3415 additions and 125 deletions
+55 -7
View File
@@ -247,6 +247,7 @@ type sonarrScheduleItem struct {
MembyAirLabel string `json:"MembyAirLabel"`
MembyAvailability string `json:"MembyAvailability"`
MembyAvailabilityText string `json:"MembyAvailabilityText"`
MembyEpisodeEvent string `json:"MembyEpisodeEvent,omitempty"`
// Sonarr's lifecycle for the *show*, distinct from this episode's availability: one
// says whether more episodes are coming at all, the other whether this one is here yet.
MembyLifecycle string `json:"MembyLifecycle,omitempty"`
@@ -255,13 +256,20 @@ type sonarrScheduleItem struct {
// The Emby series this episode belongs to, when the library holds it. It is what lets
// the card open the show's own page; a show Sonarr follows but Emby has never imported
// simply carries none, and the card stays informational as it always was.
MembySeriesItemID string `json:"MembySeriesItemId,omitempty"`
MembySeriesItemID string `json:"MembySeriesItemId,omitempty"`
ParentLogoItemID string `json:"ParentLogoItemId,omitempty"`
ParentLogoImageTag string `json:"ParentLogoImageTag,omitempty"`
}
// seriesIndex resolves a Sonarr series title and year onto an Emby item id. It is a map
// rather than a store call per episode: one row can carry a dozen episodes of the same
// show, and the answer is the same for all of them.
type seriesIndex map[string]string
type seriesReference struct {
ID string
LogoTag string
}
type seriesIndex map[string]seriesReference
// embySeriesIndex builds the lookup for one row build. A failure is not fatal — the row
// is about what is *about* to air, and losing the link only costs the card its page.
@@ -282,13 +290,14 @@ func (s *Server) embySeriesIndex(ctx context.Context) seriesIndex {
}
// The year-qualified key is written first and never overwritten, so a remake
// cannot claim the original's page when both are in the library.
value := seriesReference{ID: ref.ID, LogoTag: ref.LogoTag}
if ref.Year > 0 {
if _, seen := index[seriesIndexKey(key, ref.Year)]; !seen {
index[seriesIndexKey(key, ref.Year)] = ref.ID
index[seriesIndexKey(key, ref.Year)] = value
}
}
if _, seen := index[key]; !seen {
index[key] = ref.ID
index[key] = value
}
}
return index
@@ -306,11 +315,28 @@ func (index seriesIndex) lookup(title string, year int) string {
return ""
}
if year > 0 {
if id, ok := index[seriesIndexKey(key, year)]; ok {
return id
if ref, ok := index[seriesIndexKey(key, year)]; ok {
return ref.ID
}
}
return index[key]
return index[key].ID
}
func (index seriesIndex) logo(title string, year int) (string, string) {
key := normalizedShowTitle(title)
if key == "" || len(index) == 0 {
return "", ""
}
ref := index[key]
if year > 0 {
if qualified, ok := index[seriesIndexKey(key, year)]; ok {
ref = qualified
}
}
if ref.ID == "" || ref.LogoTag == "" {
return "", ""
}
return ref.ID, ref.LogoTag
}
func (s *Server) sonarrAiringTodayRow(ctx context.Context) (*recommend.Row, error) {
@@ -438,6 +464,10 @@ func toSonarrScheduleItem(
MembyPlayable: false,
}
item.MembySeriesItemID = series.lookup(episode.Series.Title, episode.Series.Year)
item.ParentLogoItemID, item.ParentLogoImageTag = series.logo(
episode.Series.Title, episode.Series.Year,
)
item.MembyEpisodeEvent = scheduleEpisodeEvent(episode)
lifecycle := seriesLifecycleTag(episode.Series.Status)
item.MembyLifecycle, item.MembyLifecycleText = lifecycle.Status, lifecycle.Label
if hasCover(episode.Series.Images, "poster") {
@@ -483,6 +513,24 @@ func toSonarrScheduleItem(
return item
}
func scheduleEpisodeEvent(episode sonarr.Episode) string {
if episode.SeasonNumber <= 0 {
return ""
}
switch strings.ToLower(strings.TrimSpace(episode.FinaleType)) {
case "series", "seriesfinale":
return "Series finale"
case "season", "seasonfinale":
return "Season finale"
case "midseason", "midseasonfinale":
return "Mid-season finale"
}
if episode.EpisodeNumber == 1 {
return "Season premiere"
}
return ""
}
func scheduleAirDayLabel(airTime, now time.Time, location *time.Location) string {
airTime = airTime.In(location)
now = now.In(location)