From fb1017f551c9f5433af8215e37830d31473da26c Mon Sep 17 00:00:00 2001 From: IRHM Date: Sun, 2 Aug 2026 22:22:58 +0100 Subject: [PATCH] tmdb: Make req local, Movie/Show details funcs now accept struct options --- server/feature/content/router.go | 20 +++++------ server/feature/search/search.go | 8 +++-- server/media/tmdb/tmdb.go | 8 ++--- server/media/tmdb/tmdb_discover.go | 4 +-- server/media/tmdb/tmdb_movie.go | 42 ++++++++++++++++------ server/media/tmdb/tmdb_person.go | 6 ++-- server/media/tmdb/tmdb_search.go | 10 +++--- server/media/tmdb/tmdb_show.go | 44 ++++++++++++++++------- server/media/tmdb/tmdb_trending.go | 2 +- server/media/tmdb/tmdb_watch_providers.go | 2 +- 10 files changed, 95 insertions(+), 51 deletions(-) diff --git a/server/feature/content/router.go b/server/feature/content/router.go index d6619898..2caf0bef 100644 --- a/server/feature/content/router.go +++ b/server/feature/content/router.go @@ -76,13 +76,13 @@ func (r *Router) GetMovieDetails(c *gin.Context) { c.JSON(http.StatusBadRequest, router.ErrorResponse{Error: "an id was not provided"}) return } - content, err := r.tmdb.MovieDetails( - c.Param("id"), - c.MustGet("userCountry").(string), - map[string]string{ + content, err := r.tmdb.MovieDetails(tmdb.MovieDetailsOptions{ + ID: c.Param("id"), + Country: c.MustGet("userCountry").(string), + Params: map[string]string{ "append_to_response": "videos,watch/providers,similar", }, - ) + }) if err != nil { c.JSON(http.StatusBadRequest, router.ErrorResponse{Error: err.Error()}) return @@ -134,13 +134,13 @@ func (r *Router) GetTvDetails(c *gin.Context) { return } // 1. Get details - content, err := r.tmdb.ShowDetails( - c.Param("id"), - c.MustGet("userCountry").(string), - map[string]string{ + content, err := r.tmdb.ShowDetails(tmdb.ShowDetailsOptions{ + ID: c.Param("id"), + Country: c.MustGet("userCountry").(string), + Params: map[string]string{ "append_to_response": "videos,watch/providers,similar,external_ids,keywords", }, - ) + }) if err != nil { c.JSON(http.StatusBadRequest, router.ErrorResponse{Error: err.Error()}) return diff --git a/server/feature/search/search.go b/server/feature/search/search.go index 7fab8660..20b42015 100644 --- a/server/feature/search/search.go +++ b/server/feature/search/search.go @@ -194,7 +194,9 @@ func (s *Service) searchMovieById( resp *domain.SearchResponse, ) error { slog.Debug("searchMovieById: Running.", "id", id) - details, err := s.tmdb.MovieDetails(id, "", map[string]string{}) + details, err := s.tmdb.MovieDetails(tmdb.MovieDetailsOptions{ + ID: id, + }) if err != nil { slog.Error("searchMovieById: Failed to search tmdb!", "error", err) return errors.New("content request failed") @@ -236,7 +238,9 @@ func (s *Service) searchTvById( resp *domain.SearchResponse, ) error { slog.Debug("searchTvById: Running.", "id", id) - details, err := s.tmdb.ShowDetails(id, "", map[string]string{}) + details, err := s.tmdb.ShowDetails(tmdb.ShowDetailsOptions{ + ID: id, + }) if err != nil { slog.Error("searchTvById: Failed to search tmdb!", "error", err) return errors.New("content request failed") diff --git a/server/media/tmdb/tmdb.go b/server/media/tmdb/tmdb.go index e5cecc2d..37cb19a5 100644 --- a/server/media/tmdb/tmdb.go +++ b/server/media/tmdb/tmdb.go @@ -19,7 +19,7 @@ import ( var ContentStore = gocache.New(time.Hour*24, time.Minute) type ContentProvider interface { - CacheContentTv(content TMDBShowDetails, onlyUpdate bool) (entity.Content, error) + CacheContentShow(content TMDBShowDetails, onlyUpdate bool) (entity.Content, error) CacheContentMovie(content TMDBMovieDetails, onlyUpdate bool) (entity.Content, error) } @@ -45,7 +45,7 @@ func (t *TMDB) GetKey() string { return "d047fa61d926371f277e7a83c9c4ff2c" } -func (t *TMDB) APIRequest(ep string, p map[string]string) ([]byte, error) { +func (t *TMDB) apiRequest(ep string, p map[string]string) ([]byte, error) { slog.Debug("tmdbAPIRequest", "endpoint", ep, "params", p) base, err := url.Parse("https://api.themoviedb.org/3") if err != nil { @@ -83,8 +83,8 @@ func (t *TMDB) APIRequest(ep string, p map[string]string) ([]byte, error) { return body, nil } -func (t *TMDB) Request(ep string, p map[string]string, resp interface{}) error { - body, err := t.APIRequest(ep, p) +func (t *TMDB) req(ep string, p map[string]string, resp interface{}) error { + body, err := t.apiRequest(ep, p) if err != nil { return err } diff --git a/server/media/tmdb/tmdb_discover.go b/server/media/tmdb/tmdb_discover.go index ecfe29d7..ee9391f1 100644 --- a/server/media/tmdb/tmdb_discover.go +++ b/server/media/tmdb/tmdb_discover.go @@ -28,7 +28,7 @@ func (t *TMDB) DiscoverMovies( slog.Debug("DiscoverMovies: Returning cache.") return *resp, nil } - err := t.Request("/discover/movie", reqParams, &resp) + err := t.req("/discover/movie", reqParams, &resp) if err != nil { slog.Error("DiscoverMovies: Request failed!", "error", err) return TMDBDiscoverMovies{}, errors.New("request failed") @@ -56,7 +56,7 @@ func (t *TMDB) DiscoverShows( slog.Debug("DiscoverShows: Returning cache.") return *resp, nil } - err := t.Request("/discover/tv", reqParams, &resp) + err := t.req("/discover/tv", reqParams, &resp) if err != nil { slog.Error("DiscoverShows: Request failed!", "error", err) return TMDBDiscoverShows{}, errors.New("request failed") diff --git a/server/media/tmdb/tmdb_movie.go b/server/media/tmdb/tmdb_movie.go index cf5ec46f..67b17781 100644 --- a/server/media/tmdb/tmdb_movie.go +++ b/server/media/tmdb/tmdb_movie.go @@ -8,32 +8,52 @@ import ( "github.com/sbondCo/Watcharr/cache" ) -func (t *TMDB) MovieDetails( - id string, - country string, - rParams map[string]string, -) (TMDBMovieDetails, error) { +type MovieDetailsOptions struct { + // TMDB ID + ID string + // Country (currently used for watch providers) + Country string + // Request params map. + Params map[string]string + + // If CacheContentMovie should be ran or not. + // If the caller wants to do its own caching to the db, it can use this + // to avoid multiple calls to CacheContentMovie. + DontRunDBCache bool +} + +func (t *TMDB) MovieDetails(o MovieDetailsOptions) (TMDBMovieDetails, error) { resp := new(TMDBMovieDetails) - cacheKey := cache.CreateCacheKey("MovieDetails", id, country, rParams) + cacheKey := cache.CreateCacheKey( + "MovieDetails", + o.ID, + o.Country, + o.Params) if cache.GetCache(ContentStore, cacheKey, &resp) { slog.Debug("MovieDetails: Returning cache.") return *resp, nil } - err := t.Request("/movie/"+id, rParams, &resp) + err := t.req("/movie/"+o.ID, o.Params, &resp) if err != nil { slog.Error("MovieDetails: Request failed!", "error", err) return TMDBMovieDetails{}, errors.New("request failed") } - resp.WatchProvidersTransformed = transformProviders(&resp.WatchProviders, country) - resp.WatchProviders = nil // We don't want this to linger around (in cache) since we have the transformed version now.. - go t.contentProvider.CacheContentMovie(*resp, true) + resp.WatchProvidersTransformed = transformProviders( + &resp.WatchProviders, + o.Country) + // We don't want this to linger around (in cache) since we have the + // transformed version now.. + resp.WatchProviders = nil + if !o.DontRunDBCache { + go t.contentProvider.CacheContentMovie(*resp, true) + } ContentStore.Set(cacheKey, resp, time.Hour*24) return *resp, nil } func (t *TMDB) MovieCredits(id string) (TMDBContentCredits, error) { resp := new(TMDBContentCredits) - err := t.Request("/movie/"+id+"/credits", map[string]string{}, &resp) + err := t.req("/movie/"+id+"/credits", map[string]string{}, &resp) if err != nil { slog.Error("MovieCredits: Request failed!", "error", err) return TMDBContentCredits{}, errors.New("request failed") diff --git a/server/media/tmdb/tmdb_person.go b/server/media/tmdb/tmdb_person.go index 0d3d2a1c..8e1e6c54 100644 --- a/server/media/tmdb/tmdb_person.go +++ b/server/media/tmdb/tmdb_person.go @@ -11,7 +11,7 @@ import ( func (t *TMDB) PersonDetails(id string) (TMDBPersonDetails, error) { resp := new(TMDBPersonDetails) - err := t.Request("/person/"+id, map[string]string{}, &resp) + err := t.req("/person/"+id, map[string]string{}, &resp) if err != nil { slog.Error("PersonDetails: Request failed!", "error", err) return TMDBPersonDetails{}, errors.New("request failed") @@ -26,7 +26,7 @@ func (t *TMDB) PersonCredits(id string) (TMDBPersonCombinedCredits, error) { slog.Debug("PersonCredits: Returning cache.") return *resp, nil } - err := t.Request( + err := t.req( "/person/"+id+"/combined_credits", map[string]string{}, &resp) @@ -45,7 +45,7 @@ func (t *TMDB) PopularPeople(pageNum int) (TMDBPopularPeople, error) { slog.Debug("PopularPeople: Returning cache.") return *resp, nil } - err := t.Request( + err := t.req( "/person/popular", map[string]string{"page": strconv.Itoa(pageNum)}, &resp) diff --git a/server/media/tmdb/tmdb_search.go b/server/media/tmdb/tmdb_search.go index c3fdb6da..45414cf3 100644 --- a/server/media/tmdb/tmdb_search.go +++ b/server/media/tmdb/tmdb_search.go @@ -65,7 +65,7 @@ func (t *TMDB) SearchMulti( slog.Debug("SearchMulti: Returning cache.") return *resp, nil } - err := t.Request( + err := t.req( "/search/multi", o.AsParamsMap(), &resp) @@ -112,7 +112,7 @@ func (t *TMDB) SearchMovies( slog.Debug("SearchMovies: Returning cache.") return *resp, nil } - err := t.Request( + err := t.req( "/search/movie", o.AsParamsMap(), &resp) @@ -162,7 +162,7 @@ func (t *TMDB) SearchShows( slog.Debug("SearchShows: Returning cache.") return *resp, nil } - err := t.Request( + err := t.req( "/search/tv", o.AsParamsMap(), &resp) @@ -193,7 +193,7 @@ func (t *TMDB) SearchPeople( slog.Debug("SearchPeople: Returning cache.") return *resp, nil } - err := t.Request( + err := t.req( "/search/person", o.AsParamsMap(), &resp) @@ -223,7 +223,7 @@ func (t *TMDB) SearchByExternalId( slog.Debug("SearchByExternalId: Got cache.") } else { // If not found in cache, request data from tmdb. - err := t.Request( + err := t.req( "/find/"+id, map[string]string{"external_source": source + "_id"}, &resp) diff --git a/server/media/tmdb/tmdb_show.go b/server/media/tmdb/tmdb_show.go index 2ac9b572..1fa0b9c4 100644 --- a/server/media/tmdb/tmdb_show.go +++ b/server/media/tmdb/tmdb_show.go @@ -8,32 +8,52 @@ import ( "github.com/sbondCo/Watcharr/cache" ) -func (t *TMDB) ShowDetails( - id string, - country string, - rParams map[string]string, -) (TMDBShowDetails, error) { - cacheKey := cache.CreateCacheKey("ShowDetails", id, country, rParams) +type ShowDetailsOptions struct { + // TMDB ID + ID string + // Country (currently used for watch providers) + Country string + // Request params map. + Params map[string]string + + // If CacheContentShow should be ran or not. + // If the caller wants to do its own caching to the db, it can use this + // to avoid multiple calls to CacheContentShow. + DontRunDBCache bool +} + +func (t *TMDB) ShowDetails(o ShowDetailsOptions) (TMDBShowDetails, error) { + cacheKey := cache.CreateCacheKey( + "ShowDetails", + o.ID, + o.Country, + o.Params) resp := new(TMDBShowDetails) if cache.GetCache(ContentStore, cacheKey, &resp) { slog.Debug("ShowDetails: Returning cache.") return *resp, nil } - err := t.Request("/tv/"+id, rParams, &resp) + err := t.req("/tv/"+o.ID, o.Params, &resp) if err != nil { slog.Error("ShowDetails: Request failed!", "error", err) return TMDBShowDetails{}, errors.New("request failed") } - resp.WatchProvidersTransformed = transformProviders(&resp.WatchProviders, country) - resp.WatchProviders = nil // We don't want this to linger around (in cache) since we have the transformed version now.. - go t.contentProvider.CacheContentTv(*resp, true) + resp.WatchProvidersTransformed = transformProviders( + &resp.WatchProviders, + o.Country) + // We don't want this to linger around (in cache) since we have the + // transformed version now.. + resp.WatchProviders = nil + if !o.DontRunDBCache { + go t.contentProvider.CacheContentShow(*resp, true) + } ContentStore.Set(cacheKey, resp, time.Hour*24) return *resp, nil } func (t *TMDB) ShowCredits(id string) (TMDBContentCredits, error) { resp := new(TMDBContentCredits) - err := t.Request("/tv/"+id+"/credits", map[string]string{}, &resp) + err := t.req("/tv/"+id+"/credits", map[string]string{}, &resp) if err != nil { slog.Error("ShowCredits: Request failed!", "error", err) return TMDBContentCredits{}, errors.New("request failed") @@ -51,7 +71,7 @@ func (t *TMDB) SeasonDetails( slog.Debug("SeasonDetails: Returning cache.") return *resp, nil } - err := t.Request( + err := t.req( "/tv/"+showId+"/season/"+seasonNumber, map[string]string{}, &resp) diff --git a/server/media/tmdb/tmdb_trending.go b/server/media/tmdb/tmdb_trending.go index 5e1a1cde..06622c74 100644 --- a/server/media/tmdb/tmdb_trending.go +++ b/server/media/tmdb/tmdb_trending.go @@ -34,7 +34,7 @@ func (t *TMDB) Trending( slog.Debug("Trending: Returning cache.") return *resp, nil } - err := t.Request( + err := t.req( "/trending/"+string(ttype)+"/day", map[string]string{ "page": strconv.Itoa(pageNum), diff --git a/server/media/tmdb/tmdb_watch_providers.go b/server/media/tmdb/tmdb_watch_providers.go index 9e28f9be..e3f44114 100644 --- a/server/media/tmdb/tmdb_watch_providers.go +++ b/server/media/tmdb/tmdb_watch_providers.go @@ -7,7 +7,7 @@ import ( func (t *TMDB) Regions() (TMDBRegions, error) { resp := new(TMDBRegions) - err := t.Request( + err := t.req( "/watch/providers/regions", map[string]string{}, &resp)