273 lines
6.8 KiB
Go
273 lines
6.8 KiB
Go
package shows
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"git.quimbo.fr/odwrtw/canape/backend/models"
|
|
"git.quimbo.fr/odwrtw/canape/backend/web"
|
|
"github.com/odwrtw/errors"
|
|
polochon "github.com/odwrtw/polochon/lib"
|
|
"github.com/odwrtw/polochon/lib/papi"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
// 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"`
|
|
}
|
|
|
|
// 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.Banner,
|
|
FanartURL: s.Fanart,
|
|
PosterURL: s.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,
|
|
show: s,
|
|
})
|
|
}
|
|
return json.Marshal(showToMarshal)
|
|
}
|
|
|
|
// New returns a new Show with a polochon ShowConfig
|
|
func New(imdbID string) *Show {
|
|
return &Show{
|
|
Show: &polochon.Show{
|
|
ImdbID: imdbID,
|
|
},
|
|
}
|
|
}
|
|
|
|
// NewWithClient returns a new Show with a polochon ShowConfig
|
|
func NewWithClient(show *polochon.Show, client *papi.Client, pShow *papi.Show, wShow *models.WishedShow) *Show {
|
|
s := &Show{
|
|
Show: show,
|
|
client: client,
|
|
pShow: pShow,
|
|
}
|
|
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, log)
|
|
if err != nil {
|
|
if errors.IsFatal(err) {
|
|
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 models.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) {
|
|
return ""
|
|
}
|
|
return models.ImgURLPrefix + s.imgURL(imgType)
|
|
}
|
|
|
|
// downloadImages will download the show images
|
|
func (s *Show) downloadImages(env *web.Env) {
|
|
// Create the directory for the show if it doesn't exist
|
|
if _, err := os.Stat(s.imgDirectory()); err != nil {
|
|
if err = os.Mkdir(s.imgDirectory(), os.ModePerm); err != nil {
|
|
env.Log.Warnf("couldn't create show directory %s: %s", s.imgDirectory(), err)
|
|
return
|
|
}
|
|
}
|
|
// Download the show images
|
|
for _, img := range []struct {
|
|
url string
|
|
urlType string
|
|
scale bool
|
|
}{
|
|
{
|
|
url: s.Show.Banner,
|
|
urlType: "banner",
|
|
scale: false,
|
|
},
|
|
{
|
|
url: s.Show.Fanart,
|
|
urlType: "fanart",
|
|
scale: false,
|
|
},
|
|
{
|
|
url: s.Show.Poster,
|
|
urlType: "poster",
|
|
scale: true,
|
|
},
|
|
} {
|
|
if img.url == "" {
|
|
continue
|
|
}
|
|
// Don't download image if we already have it
|
|
if _, err := os.Stat(s.imgFile(img.urlType)); err == nil {
|
|
continue
|
|
}
|
|
if err := web.Download(img.url, s.imgFile(img.urlType), img.scale); err != nil {
|
|
env.Log.Errorf("failed to dowload %s: %s", img.urlType, err)
|
|
}
|
|
}
|
|
|
|
// Download episode thumbs
|
|
for _, e := range s.Episodes {
|
|
if e.Thumb == "" {
|
|
continue
|
|
}
|
|
|
|
fileName := s.imgFile(fmt.Sprintf("%d-%d", e.Season, e.Episode))
|
|
// Don't download image if we already have it
|
|
if _, err := os.Stat(fileName); err == nil {
|
|
continue
|
|
}
|
|
|
|
err := web.Download(e.Thumb, fileName, false)
|
|
if err != nil {
|
|
env.Log.Errorf("failed to dowload the thumb for season %d episode %d ( %s ) : %s", e.Season, e.Episode, e.Thumb, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
// imgURL returns the default image url
|
|
func (s *Show) imgURL(imgType string) string {
|
|
return fmt.Sprintf("shows/%s/%s.jpg", s.ImdbID, imgType)
|
|
}
|
|
|
|
// imgDirectory returns the directory containing all the show images
|
|
func (s *Show) imgDirectory() string {
|
|
return filepath.Join(models.PublicDir, "img", fmt.Sprintf("shows/%s", s.ImdbID))
|
|
}
|
|
|
|
// imgFile returns the image location on disk
|
|
func (s *Show) imgFile(imgType string) string {
|
|
return filepath.Join(models.PublicDir, "img", s.imgURL(imgType))
|
|
}
|
|
|
|
// getPolochonShows returns all the Shows from the polochon of a user
|
|
func getPolochonShows(env *web.Env, user *models.User) ([]*Show, error) {
|
|
shows := []*Show{}
|
|
|
|
client, err := user.NewPapiClient(env.Database)
|
|
if err != nil {
|
|
return shows, err
|
|
}
|
|
|
|
// Get the polochon's shows
|
|
pshows, err := client.GetShows()
|
|
if err != nil {
|
|
return shows, err
|
|
}
|
|
|
|
wShows, err := models.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(&polochon.Show{ImdbID: pShow.ImdbID}, client, pShow, wShow)
|
|
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]
|
|
}
|