package providers import ( "context" "errors" "strings" ) // Looker is implemented by providers that can fetch one entry again by its // ID, to refresh metadata that changed at the source. type Looker interface { Lookup(ctx context.Context, providerID string) (Result, error) } // ErrGone means the source no longer has the entry (deleted or merged). var ErrGone = errors.New("the source no longer has this entry") // ErrNoSource means the entry wasn't added from a service that can be // refreshed. var ErrNoSource = errors.New("no source to refresh from") // Lookup fetches an entry again from the service it came from. The // provider is the one saved with the entry, whatever the current setting. func (r *Registry) Lookup(ctx context.Context, category, provider, providerID string) (Result, error) { var l Looker c := r.creds(ctx) switch provider { case "tmdb": if c.TMDBKey == "" { return Result{}, NotConfiguredError{"TMDB", "Add a TMDB API key under Settings → Integrations."} } kind, _, _ := strings.Cut(providerID, ":") l = &tmdb{r: r, key: c.TMDBKey, kind: kind} case "tvdb": if c.TVDBKey == "" { return Result{}, NotConfiguredError{"TheTVDB", "Add a TheTVDB API key under Settings → Integrations."} } l = &tvdb{r: r, key: c.TVDBKey, pin: c.TVDBPin} case "igdb": if c.IGDBClientID == "" || c.IGDBClientSecret == "" { return Result{}, NotConfiguredError{"IGDB", "Add your Twitch client ID and secret under Settings → Integrations."} } l = &igdb{r: r, id: c.IGDBClientID, secret: c.IGDBClientSecret} case "deezer": l = &deezer{r: r, kind: category} case "musicbrainz": l = &musicbrainz{r: r, kind: category} case "wikipedia": l = &wikipedia{r: r, stage: category == "theater"} default: return Result{}, ErrNoSource } return l.Lookup(ctx, providerID) } // SameThing reports whether a refreshed title plausibly names the same // entry: the titles share at least one word, ignoring bracketed qualifiers // like "(Remastered)". A refresh that comes back with an unrelated title // usually means a bad or reused ID, and shouldn't overwrite the entry. func SameThing(a, b string) bool { wa, wb := strings.Fields(baseTitle(a)), strings.Fields(baseTitle(b)) if len(wa) == 0 || len(wb) == 0 { return true } seen := map[string]bool{} for _, w := range wa { seen[w] = true } for _, w := range wb { if seen[w] { return true } } return false }