103 lines
2.6 KiB
Go
103 lines
2.6 KiB
Go
package api
|
|||
|
|
|
||
|
|
import (
|
||
|
|
"context"
|
||
|
|
"encoding/json"
|
||
|
|
"strconv"
|
||
|
|
"strings"
|
||
|
|
)
|
||
|
|
|
||
|
|
// decorateSeriesStatuses makes Status on an ordinary Emby series the canonical detail
|
||
|
|
// answer. Sonarr's daily observation wins when it is recognised; otherwise Emby's field
|
||
|
|
// is left untouched as the fallback.
|
||
|
|
func (s *Server) decorateSeriesStatuses(ctx context.Context, collections ...[]json.RawMessage) {
|
||
|
|
if s.store == nil {
|
||
|
|
return
|
||
|
|
}
|
||
|
|
tvdbIDs := []int{}
|
||
|
|
seen := map[int]bool{}
|
||
|
|
identities := make([]map[int]int, len(collections))
|
||
|
|
for collectionIndex, items := range collections {
|
||
|
|
identities[collectionIndex] = map[int]int{}
|
||
|
|
for itemIndex, raw := range items {
|
||
|
|
tvdbID := seriesTVDBID(raw)
|
||
|
|
if tvdbID <= 0 {
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
identities[collectionIndex][itemIndex] = tvdbID
|
||
|
|
if !seen[tvdbID] {
|
||
|
|
seen[tvdbID] = true
|
||
|
|
tvdbIDs = append(tvdbIDs, tvdbID)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if len(tvdbIDs) == 0 {
|
||
|
|
return
|
||
|
|
}
|
||
|
|
statuses, err := s.store.LatestSonarrSeriesStatuses(ctx, tvdbIDs)
|
||
|
|
if err != nil {
|
||
|
|
s.loggerFor(ctx).Warn("stored Sonarr series statuses unavailable", "error", err)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
for collectionIndex, itemIndexes := range identities {
|
||
|
|
for itemIndex, tvdbID := range itemIndexes {
|
||
|
|
status := canonicalSonarrSeriesStatus(statuses[tvdbID])
|
||
|
|
if status != "" {
|
||
|
|
collections[collectionIndex][itemIndex] = injectSeriesStatus(
|
||
|
|
collections[collectionIndex][itemIndex], status,
|
||
|
|
)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func seriesTVDBID(raw json.RawMessage) int {
|
||
|
|
var item struct {
|
||
|
|
Type string `json:"Type"`
|
||
|
|
ProviderIDs map[string]string `json:"ProviderIds"`
|
||
|
|
}
|
||
|
|
if json.Unmarshal(raw, &item) != nil || !strings.EqualFold(item.Type, "Series") {
|
||
|
|
return 0
|
||
|
|
}
|
||
|
|
id, _ := strconv.Atoi(providerID(item.ProviderIDs, "tvdb"))
|
||
|
|
return id
|
||
|
|
}
|
||
|
|
|
||
|
|
// canonicalSonarrSeriesStatus is deliberately conservative. Unknown values are not
|
||
|
|
// copied over a usable Emby status, and American spelling is normalised at the render
|
||
|
|
// boundary before it can become viewer-facing text.
|
||
|
|
func canonicalSonarrSeriesStatus(status string) string {
|
||
|
|
switch strings.ToLower(strings.TrimSpace(status)) {
|
||
|
|
case "continuing":
|
||
|
|
return "Continuing"
|
||
|
|
case "ended":
|
||
|
|
return "Ended"
|
||
|
|
case "cancelled", "canceled":
|
||
|
|
return "Cancelled"
|
||
|
|
case "upcoming":
|
||
|
|
return "Upcoming"
|
||
|
|
default:
|
||
|
|
return ""
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func injectSeriesStatus(raw json.RawMessage, status string) json.RawMessage {
|
||
|
|
if status == "" {
|
||
|
|
return raw
|
||
|
|
}
|
||
|
|
var members map[string]json.RawMessage
|
||
|
|
if json.Unmarshal(raw, &members) != nil || members == nil {
|
||
|
|
return raw
|
||
|
|
}
|
||
|
|
encoded, err := json.Marshal(status)
|
||
|
|
if err != nil {
|
||
|
|
return raw
|
||
|
|
}
|
||
|
|
members["Status"] = encoded
|
||
|
|
out, err := json.Marshal(members)
|
||
|
|
if err != nil {
|
||
|
|
return raw
|
||
|
|
}
|
||
|
|
return out
|
||
|
|
}
|