Skip to content

Commit d2c86d1

Browse files
committed
trakt: add start of show support
1 parent 8d27251 commit d2c86d1

File tree

1 file changed

+226
-5
lines changed

1 file changed

+226
-5
lines changed

provider/trakt.go

+226-5
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,41 @@ type TraktMoviesResponse struct {
6666
Movie *TraktMovie `json:"movie"`
6767
}
6868

69+
type TraktShowIds struct {
70+
Trakt int `json:"trakt"`
71+
Slug string `json:"slug"`
72+
Tvdb int `json:"tvdb"`
73+
Imdb string `json:"imdb"`
74+
Tmdb int `json:"tmdb"`
75+
}
76+
77+
type TraktShow struct {
78+
Title string `json:"title"`
79+
Year int `json:"year"`
80+
Ids TraktShowIds `json:"ids"`
81+
Overview string `json:"overview"`
82+
FirstAired time.Time `json:"first_aired"`
83+
Runtime int `json:"runtime"`
84+
Certification string `json:"certification"`
85+
Network string `json:"network"`
86+
Country string `json:"country"`
87+
Trailer string `json:"trailer"`
88+
Homepage string `json:"homepage"`
89+
Status string `json:"status"`
90+
Rating float64 `json:"rating"`
91+
Votes int `json:"votes"`
92+
CommentCount int `json:"comment_count"`
93+
Language string `json:"language"`
94+
AvailableTranslations []string `json:"available_translations"`
95+
Genres []string `json:"genres"`
96+
AiredEpisodes int `json:"aired_episodes"`
97+
}
98+
99+
type TraktShowsResponse struct {
100+
TraktShow
101+
Show *TraktShow `json:"show"`
102+
}
103+
69104
/* Initializer */
70105

71106
func NewTrakt() *Trakt {
@@ -79,7 +114,9 @@ func NewTrakt() *Trakt {
79114

80115
genres: make(map[int]string, 0),
81116

82-
supportedShowsSearchTypes: []string{},
117+
supportedShowsSearchTypes: []string{
118+
SearchTypePopular,
119+
},
83120
supportedMoviesSearchTypes: []string{
84121
SearchTypeTrending,
85122
SearchTypeUpcoming,
@@ -94,7 +131,7 @@ func NewTrakt() *Trakt {
94131
func (p *Trakt) Init(mediaType MediaType, cfg map[string]string) error {
95132
// validate we support this media type
96133
switch mediaType {
97-
case Movie:
134+
case Movie, Show:
98135
break
99136
default:
100137
return errors.New("unsupported media type")
@@ -142,7 +179,15 @@ func (p *Trakt) SupportsMoviesSearchType(searchType string) bool {
142179
}
143180

144181
func (p *Trakt) GetShows(searchType string, logic map[string]interface{}, params map[string]string) (map[string]config.MediaItem, error) {
145-
return nil, errors.New("unsupported media type")
182+
183+
switch searchType {
184+
case SearchTypePopular:
185+
return p.getShows("/shows/popular", logic, params)
186+
default:
187+
break
188+
}
189+
190+
return nil, fmt.Errorf("unsupported search_type: %q", searchType)
146191
}
147192

148193
func (p *Trakt) GetMovies(searchType string, logic map[string]interface{}, params map[string]string) (map[string]config.MediaItem, error) {
@@ -197,7 +242,7 @@ func (p *Trakt) getRequestParams(params map[string]string) req.Param {
197242
return reqParams
198243
}
199244

200-
func (p *Trakt) translateTraktMovie(response TraktMoviesResponse) *TraktMovie {
245+
func (p *Trakt) translateMovie(response TraktMoviesResponse) *TraktMovie {
201246
if response.Movie != nil {
202247
return response.Movie
203248
}
@@ -229,6 +274,40 @@ func (p *Trakt) translateTraktMovie(response TraktMoviesResponse) *TraktMovie {
229274
}
230275
}
231276

277+
func (p *Trakt) translateShow(response TraktShowsResponse) *TraktShow {
278+
if response.Show != nil {
279+
return response.Show
280+
}
281+
282+
return &TraktShow{
283+
Title: response.Title,
284+
Year: response.Year,
285+
Ids: TraktShowIds{
286+
Trakt: response.Ids.Trakt,
287+
Slug: response.Ids.Slug,
288+
Tvdb: response.Ids.Tvdb,
289+
Imdb: response.Ids.Imdb,
290+
Tmdb: response.Ids.Tmdb,
291+
},
292+
Overview: response.Overview,
293+
FirstAired: response.FirstAired,
294+
Runtime: response.Runtime,
295+
Certification: response.Certification,
296+
Network: response.Network,
297+
Country: response.Country,
298+
Trailer: response.Trailer,
299+
Homepage: response.Homepage,
300+
Status: response.Status,
301+
Rating: response.Rating,
302+
Votes: response.Votes,
303+
CommentCount: response.CommentCount,
304+
Language: response.Language,
305+
AvailableTranslations: response.AvailableTranslations,
306+
Genres: response.Genres,
307+
AiredEpisodes: response.AiredEpisodes,
308+
}
309+
}
310+
232311
func (p *Trakt) getMovies(endpoint string, logic map[string]interface{}, params map[string]string) (map[string]config.MediaItem, error) {
233312
// set request params
234313
reqParams := p.getRequestParams(params)
@@ -279,7 +358,7 @@ func (p *Trakt) getMovies(endpoint string, logic map[string]interface{}, params
279358
// process response
280359
for _, item := range s {
281360
// set movie item
282-
var movieItem *TraktMovie = p.translateTraktMovie(item)
361+
var movieItem *TraktMovie = p.translateMovie(item)
283362
if movieItem == nil {
284363
p.log.Tracef("Failed translating trakt movie: %#v", item)
285364
continue
@@ -377,3 +456,145 @@ func (p *Trakt) getMovies(endpoint string, logic map[string]interface{}, params
377456
p.log.WithField("accepted_items", mediaItemsSize).Info("Retrieved media items")
378457
return mediaItems, nil
379458
}
459+
460+
func (p *Trakt) getShows(endpoint string, logic map[string]interface{}, params map[string]string) (map[string]config.MediaItem, error) {
461+
// set request params
462+
reqParams := p.getRequestParams(params)
463+
464+
p.log.Tracef("Request params: %+v", params)
465+
466+
// parse logic params
467+
limit := 0
468+
limitReached := false
469+
470+
if v := getLogicParam(logic, "limit"); v != nil {
471+
limit = v.(int)
472+
}
473+
474+
// fetch all page results
475+
mediaItems := make(map[string]config.MediaItem, 0)
476+
mediaItemsSize := 0
477+
ignoredItemsSize := 0
478+
479+
page := 1
480+
481+
for {
482+
// set params
483+
reqParams["page"] = page
484+
485+
// send request
486+
resp, err := web.GetResponse(web.GET, web.JoinURL(p.apiUrl, endpoint), providerDefaultTimeout, p.apiHeaders,
487+
reqParams, &p.reqRetry, p.reqRatelimit)
488+
if err != nil {
489+
return nil, errors.WithMessage(err, "failed retrieving shows api response")
490+
}
491+
492+
// validate response
493+
if resp.Response().StatusCode != 200 {
494+
_ = resp.Response().Body.Close()
495+
return nil, fmt.Errorf("failed retrieving valid shows api response: %s", resp.Response().Status)
496+
}
497+
498+
// decode response
499+
var s []TraktShowsResponse
500+
if err := resp.ToJSON(&s); err != nil {
501+
_ = resp.Response().Body.Close()
502+
return nil, errors.WithMessage(err, "failed decoding shows api response")
503+
}
504+
505+
_ = resp.Response().Body.Close()
506+
507+
// process response
508+
for _, item := range s {
509+
// set movie item
510+
var showItem *TraktShow = p.translateShow(item)
511+
if showItem == nil {
512+
p.log.Tracef("Failed translating trakt show: %#v", item)
513+
continue
514+
}
515+
516+
// skip this item?
517+
if showItem.Ids.Slug == "" {
518+
continue
519+
} else if showItem.Runtime == 0 {
520+
continue
521+
} else if showItem.FirstAired.IsZero() {
522+
continue
523+
}
524+
525+
// does item already exist?
526+
itemId := strconv.Itoa(showItem.Ids.Tvdb)
527+
if _, exists := mediaItems[itemId]; exists {
528+
continue
529+
} else if _, exists := mediaItems[showItem.Ids.Imdb]; exists {
530+
continue
531+
}
532+
533+
// init media item
534+
mediaItem := config.MediaItem{
535+
Provider: "trakt",
536+
TvdbId: itemId,
537+
TmdbId: strconv.Itoa(showItem.Ids.Tmdb),
538+
ImdbId: showItem.Ids.Imdb,
539+
Slug: showItem.Ids.Slug,
540+
Title: showItem.Title,
541+
Country: showItem.Country,
542+
Network: showItem.Network,
543+
Date: showItem.FirstAired,
544+
Year: showItem.FirstAired.Year(),
545+
Runtime: showItem.Runtime,
546+
Genres: showItem.Genres,
547+
Languages: []string{showItem.Language},
548+
}
549+
550+
// media item wanted?
551+
if p.fnAcceptMediaItem != nil && !p.fnAcceptMediaItem(&mediaItem) {
552+
p.log.Tracef("Ignoring: %+v", mediaItem)
553+
ignoredItemsSize += 1
554+
continue
555+
} else {
556+
p.log.Debugf("Accepted: %+v", mediaItem)
557+
}
558+
559+
// set media item
560+
mediaItems[itemId] = mediaItem
561+
mediaItemsSize += 1
562+
563+
// stop when limit reached
564+
if limit > 0 && mediaItemsSize >= limit {
565+
// limit was supplied via cli and we have reached this limit
566+
limitReached = true
567+
break
568+
}
569+
}
570+
571+
// parse pages information
572+
totalPages := 0
573+
tmp := resp.Response().Header.Get("X-Pagination-Page-Count")
574+
if v, err := strconv.Atoi(tmp); err == nil {
575+
totalPages = v
576+
}
577+
578+
p.log.WithFields(logrus.Fields{
579+
"page": page,
580+
"pages": totalPages,
581+
"accepted": mediaItemsSize,
582+
"ignored": ignoredItemsSize,
583+
}).Info("Retrieved")
584+
585+
// loop logic
586+
if limitReached {
587+
// the limit has been reached for accepted items
588+
break
589+
}
590+
591+
if page >= totalPages {
592+
break
593+
} else {
594+
page += 1
595+
}
596+
}
597+
598+
p.log.WithField("accepted_items", mediaItemsSize).Info("Retrieved media items")
599+
return mediaItems, nil
600+
}

0 commit comments

Comments
 (0)