package shows import ( "encoding/json" "fmt" "os" "path/filepath" "strings" "github.com/odwrtw/papi" "github.com/odwrtw/polochon/lib" "github.com/sirupsen/logrus" "gitlab.quimbo.fr/odwrtw/canape/backend/backend" "gitlab.quimbo.fr/odwrtw/canape/backend/users" "gitlab.quimbo.fr/odwrtw/canape/backend/web" ) // Show represents a show type Show struct { client *papi.Client pShow *papi.Show *polochon.Show TrackedSeason *int `json:"tracked_season"` TrackedEpisode *int `json:"tracked_episode"` publicDir string imgURLPrefix string } // MarshalJSON implements the Marshal interface func (s *Show) MarshalJSON() ([]byte, error) { type alias Show // Create the structure that we want to marshal showToMarshal := &struct { *alias Episodes []Episode `json:"episodes"` BannerURL string `json:"banner_url"` FanartURL string `json:"fanart_url"` PosterURL string `json:"poster_url"` }{ alias: (*alias)(s), BannerURL: s.GetImageURL("banner"), FanartURL: s.GetImageURL("fanart"), PosterURL: s.GetImageURL("poster"), } // Create Episode obj from polochon.Episodes and add them to the object to // marshal for _, e := range s.Show.Episodes { showToMarshal.Episodes = append(showToMarshal.Episodes, Episode{ ShowEpisode: e, client: s.client, pShow: s.pShow, }) } return json.Marshal(showToMarshal) } // New returns a new Show with a polochon ShowConfig func New(imdbID string, publicDir, imgURLPrefix string) *Show { return &Show{ Show: &polochon.Show{ ImdbID: imdbID, }, publicDir: publicDir, imgURLPrefix: imgURLPrefix, } } // NewWithClient returns a new Show with a polochon ShowConfig func NewWithClient(imdbID string, client *papi.Client, pShow *papi.Show, wShow *backend.WishedShow, publicDir, imgURLPrefix string) *Show { s := &Show{ Show: &polochon.Show{ ImdbID: imdbID, }, client: client, pShow: pShow, publicDir: publicDir, imgURLPrefix: imgURLPrefix, } if wShow != nil { s.TrackedSeason = &wShow.Season s.TrackedEpisode = &wShow.Episode } return s } // GetDetails retrieves details for the show with the given detailers func (s *Show) GetDetails(env *web.Env, detailers []polochon.Detailer) error { log := env.Log.WithFields(logrus.Fields{ "imdb_id": s.ImdbID, "function": "shows.GetDetails", }) var detailersName []string for _, d := range detailers { detailersName = append(detailersName, d.Name()) } log.Debugf("getting details with %s", strings.Join(detailersName, ", ")) s.Detailers = detailers // Get the details err := polochon.GetDetails(s.Show, env.Log) if err != nil { return err } log.Debugf("got details from detailers") return nil } // GetAndFetch retrieves details for the show with the given // detailers 'before' // If found, return // If not, retrives details with the detailers 'after' and update them in // database func (s *Show) GetAndFetch(env *web.Env, before []polochon.Detailer, after []polochon.Detailer) error { log := env.Log.WithFields(logrus.Fields{ "imdb_id": s.ImdbID, "function": "shows.GetAndFetch", }) // Try to get details with the first batch of Detailers err := s.GetDetails(env, before) if err == nil { log.Debug("show found in first try") return nil } log.Debugf("show not found in database: %s", err) // If not found, try the second batch and upsert return s.Refresh(env, after) } // Refresh retrieves details for the show with the given detailers // and update them in database func (s *Show) Refresh(env *web.Env, detailers []polochon.Detailer) error { // Refresh err := s.GetDetails(env, detailers) if err != nil { return err } // Download show images s.downloadImages(env) env.Log.Debug("images downloaded") // If found, update in database return backend.UpsertShow(env.Database, s.Show) } // GetImageURL returns the image URL or the default image if the poster is not yet downloaded func (s *Show) GetImageURL(imgType string) string { // Check if the show image exists if _, err := os.Stat(s.imgFile(imgType)); os.IsNotExist(err) { // TODO image in the config ? return s.imgURLPrefix + "noimage.png" } return s.imgURLPrefix + s.imgURL(imgType) } // downloadImages will download the show images func (s *Show) downloadImages(env *web.Env) { // Download the banner err := web.Download(s.Show.Banner, s.imgFile("banner")) if err != nil { env.Log.Errorf("failed to dowload banner: %s", err) } err = web.Download(s.Show.Fanart, s.imgFile("fanart")) if err != nil { env.Log.Errorf("failed to dowload fanart: %s", err) } err = web.Download(s.Show.Poster, s.imgFile("poster")) if err != nil { env.Log.Errorf("failed to dowload poster: %s", err) } } // imgURL returns the default image url func (s *Show) imgURL(imgType string) string { return fmt.Sprintf("shows/%s-%s.jpg", s.ImdbID, imgType) } // imgFile returns the image location on disk func (s *Show) imgFile(imgType string) string { return filepath.Join(s.publicDir, "img", s.imgURL(imgType)) } // getPolochonShows returns all the Shows from the polochon of a user func getPolochonShows(env *web.Env, user *users.User) ([]*Show, error) { shows := []*Show{} client, err := user.NewPapiClient() if err != nil { return shows, err } // Get the polochon's shows pshows, err := client.GetShows() if err != nil { return shows, err } wShows, err := backend.GetShowWishlist(env.Database, user.ID) if err != nil { return shows, err } // Create Shows objects from the shows retrieved for _, pShow := range pshows.List() { wShow, _ := wShows.IsShowInWishlist(pShow.ImdbID) show := NewWithClient(pShow.ImdbID, client, pShow, wShow, env.Config.PublicDir, env.Config.ImgURLPrefix) shows = append(shows, show) } return shows, nil } // LastSeasonEpisodes will return the episodes of the last season of the show func (s *Show) LastSeasonEpisodes() []*polochon.ShowEpisode { episodes := make(map[int][]*polochon.ShowEpisode) lastSeason := 0 for _, e := range s.Episodes { if lastSeason < e.Season { lastSeason = e.Season } episodes[e.Season] = append(episodes[e.Season], e) } return episodes[lastSeason] }