0.1.52 Gateway
This commit is contained in:
@@ -273,6 +273,66 @@ func (s *Syncer) credentials(ctx context.Context) (emby.Credentials, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Find searches Emby for a term and imports whatever comes back, answering with the
|
||||
// payloads as they were stored.
|
||||
//
|
||||
// The catalogue is a copy, and a copy is only ever as fresh as the last import — up to
|
||||
// MEMBY_SYNC_INTERVAL behind, an hour by default. That is invisible to a viewer, whose
|
||||
// rows are read from Emby live, and very visible to an operator, who cannot pin a film to
|
||||
// the hero until the gateway has heard of it. So the picker asks Emby itself, and what it
|
||||
// finds is *adopted* rather than merely displayed: an id that came back from here resolves
|
||||
// through LibraryItemsByID immediately, which is what the policy validation and the hero
|
||||
// row both read, so nothing downstream has to know the title arrived early.
|
||||
//
|
||||
// It imports with exactly the fields a scheduled pass uses. Writing a thinner payload
|
||||
// would leave an adopted title missing People, MediaStreams and ProviderIds until Emby
|
||||
// next reported it changed — which for a film nobody edits again is never.
|
||||
func (s *Syncer) Find(ctx context.Context, term string, limit int) ([]json.RawMessage, error) {
|
||||
trimmed := strings.TrimSpace(term)
|
||||
if trimmed == "" || limit <= 0 {
|
||||
return nil, nil
|
||||
}
|
||||
cred, err := s.credentials(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
page, err := s.emby.Items(ctx, cred, url.Values{
|
||||
"SearchTerm": {trimmed},
|
||||
"IncludeItemTypes": {syncItemTypes},
|
||||
"Recursive": {"true"},
|
||||
"Limit": {strconv.Itoa(limit)},
|
||||
"Fields": {syncFields},
|
||||
"ImageTypeLimit": {"1"},
|
||||
"EnableImages": {"true"},
|
||||
"EnableImageTypes": {syncImageTypes},
|
||||
"EnableTotalRecordCount": {"false"},
|
||||
"EnableUserData": {"false"},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("library: search emby: %w", err)
|
||||
}
|
||||
items := make([]store.LibraryItem, 0, len(page.Items))
|
||||
found := make([]json.RawMessage, 0, len(page.Items))
|
||||
for _, raw := range page.Items {
|
||||
item, ok := toLibraryItem(raw)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
items = append(items, item)
|
||||
found = append(found, item.Payload)
|
||||
}
|
||||
if len(items) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
// Stamped now, like any other import. A full pass sweeps rows carrying a stamp older
|
||||
// than the pass itself, so a title adopted while one is running is never its victim.
|
||||
if _, err := s.store.UpsertLibraryItems(ctx, items, time.Now().UTC()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.log.Info("library search adopted titles", "term", trimmed, "found", len(found))
|
||||
return found, nil
|
||||
}
|
||||
|
||||
// Schedule runs an incremental import on an interval until ctx is cancelled.
|
||||
//
|
||||
// New episodes tend to land through the day and films weekly; an hourly incremental pass
|
||||
|
||||
Reference in New Issue
Block a user