feat: fallback to TMDB external_ids when Trakt rejects tmdbId
All checks were successful
Docker / docker (push) Successful in 1m49s
All checks were successful
Docker / docker (push) Successful in 1m49s
When Trakt returns a non-404 error (e.g. 403) for a tmdbId lookup, fetch the imdbId from TMDB's /external_ids endpoint and retry the Trakt call using the imdbId. Trakt often knows a movie/show by its imdbId even when it does not recognise the tmdbId. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/l3uddz/nabarr/media/trakt"
|
"github.com/l3uddz/nabarr/media/trakt"
|
||||||
@@ -22,7 +23,24 @@ func (c *Client) GetMovieInfo(item *FeedItem) (*Item, error) {
|
|||||||
if errors.Is(err, trakt.ErrItemNotFound) {
|
if errors.Is(err, trakt.ErrItemNotFound) {
|
||||||
return nil, fmt.Errorf("trakt: get movie: movie with %sId %q: %w", mdp, mdi, ErrItemNotFound)
|
return nil, fmt.Errorf("trakt: get movie: movie with %sId %q: %w", mdp, mdi, ErrItemNotFound)
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("trakt: get movie: movie with %sId %q: %w", mdp, mdi, err)
|
|
||||||
|
// fallback: if we queried by tmdbId and have TMDB configured, try fetching
|
||||||
|
// the imdbId from TMDB and retry Trakt — Trakt may know the movie by imdbId
|
||||||
|
// even when it doesn't recognise the tmdbId (returns 403).
|
||||||
|
if c.tmdb != nil && mdp == "tmdb" {
|
||||||
|
if tmdbIdInt, convErr := strconv.Atoi(mdi); convErr == nil {
|
||||||
|
if imdbId, extErr := c.tmdb.GetMovieExternalIds(tmdbIdInt); extErr == nil && strings.HasPrefix(imdbId, "tt") {
|
||||||
|
t, err = c.trakt.GetMovie("imdb", imdbId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, trakt.ErrItemNotFound) {
|
||||||
|
return nil, fmt.Errorf("trakt: get movie: movie with %sId %q: %w", mdp, mdi, ErrItemNotFound)
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("trakt: get movie: movie with %sId %q: %w", mdp, mdi, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// transform trakt info
|
// transform trakt info
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/l3uddz/nabarr/media/trakt"
|
"github.com/l3uddz/nabarr/media/trakt"
|
||||||
)
|
)
|
||||||
@@ -21,7 +22,24 @@ func (c *Client) GetShowInfo(item *FeedItem) (*Item, error) {
|
|||||||
if errors.Is(err, trakt.ErrItemNotFound) {
|
if errors.Is(err, trakt.ErrItemNotFound) {
|
||||||
return nil, fmt.Errorf("trakt: get show: show with %sId %q: %w", mdp, mdi, ErrItemNotFound)
|
return nil, fmt.Errorf("trakt: get show: show with %sId %q: %w", mdp, mdi, ErrItemNotFound)
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("trakt: get show: show with %sId %q: %w", mdp, mdi, err)
|
|
||||||
|
// fallback: if we queried by tmdbId and have TMDB configured, try fetching
|
||||||
|
// the imdbId from TMDB and retry Trakt — Trakt may know the show by imdbId
|
||||||
|
// even when it doesn't recognise the tmdbId (returns 403).
|
||||||
|
if c.tmdb != nil && mdp == "tmdb" {
|
||||||
|
if tmdbIdInt, convErr := strconv.Atoi(mdi); convErr == nil {
|
||||||
|
if imdbId, extErr := c.tmdb.GetShowExternalIds(tmdbIdInt); extErr == nil && strings.HasPrefix(imdbId, "tt") {
|
||||||
|
t, err = c.trakt.GetShow("imdb", imdbId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, trakt.ErrItemNotFound) {
|
||||||
|
return nil, fmt.Errorf("trakt: get show: show with %sId %q: %w", mdp, mdi, ErrItemNotFound)
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("trakt: get show: show with %sId %q: %w", mdp, mdi, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// transform trakt info to MediaItem
|
// transform trakt info to MediaItem
|
||||||
|
|||||||
@@ -50,6 +50,48 @@ func (c *Client) SearchMovies(title string, year int) (int, error) {
|
|||||||
return b.Results[0].Id, nil
|
return b.Results[0].Id, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetMovieExternalIds(tmdbId int) (string, error) {
|
||||||
|
reqUrl := util.JoinURL(c.apiURL, "movie", strconv.Itoa(tmdbId), "external_ids") + "?api_key=" + c.apiKey
|
||||||
|
|
||||||
|
resp, err := rek.Get(reqUrl, rek.Client(c.http))
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("request movie external ids: %w", err)
|
||||||
|
}
|
||||||
|
defer resp.Body().Close()
|
||||||
|
|
||||||
|
if resp.StatusCode() != 200 {
|
||||||
|
return "", fmt.Errorf("validate movie external ids response: %s", resp.Status())
|
||||||
|
}
|
||||||
|
|
||||||
|
b := new(externalIdsResponse)
|
||||||
|
if err := json.NewDecoder(resp.Body()).Decode(b); err != nil {
|
||||||
|
return "", fmt.Errorf("decode movie external ids response: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return b.ImdbId, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetShowExternalIds(tmdbId int) (string, error) {
|
||||||
|
reqUrl := util.JoinURL(c.apiURL, "tv", strconv.Itoa(tmdbId), "external_ids") + "?api_key=" + c.apiKey
|
||||||
|
|
||||||
|
resp, err := rek.Get(reqUrl, rek.Client(c.http))
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("request show external ids: %w", err)
|
||||||
|
}
|
||||||
|
defer resp.Body().Close()
|
||||||
|
|
||||||
|
if resp.StatusCode() != 200 {
|
||||||
|
return "", fmt.Errorf("validate show external ids response: %s", resp.Status())
|
||||||
|
}
|
||||||
|
|
||||||
|
b := new(externalIdsResponse)
|
||||||
|
if err := json.NewDecoder(resp.Body()).Decode(b); err != nil {
|
||||||
|
return "", fmt.Errorf("decode show external ids response: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return b.ImdbId, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Client) SearchShows(title string, year int) (int, error) {
|
func (c *Client) SearchShows(title string, year int) (int, error) {
|
||||||
vals := url.Values{
|
vals := url.Values{
|
||||||
"api_key": []string{c.apiKey},
|
"api_key": []string{c.apiKey},
|
||||||
|
|||||||
@@ -11,3 +11,7 @@ type tvSearchResponse struct {
|
|||||||
Id int `json:"id"`
|
Id int `json:"id"`
|
||||||
} `json:"results"`
|
} `json:"results"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type externalIdsResponse struct {
|
||||||
|
ImdbId string `json:"imdb_id"`
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user