278 lines
6.3 KiB
Go
278 lines
6.3 KiB
Go
package shows
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"gitlab.quimbo.fr/odwrtw/canape-sql/sqly"
|
|
"gitlab.quimbo.fr/odwrtw/canape-sql/users"
|
|
|
|
"github.com/Sirupsen/logrus"
|
|
"github.com/jmoiron/sqlx"
|
|
"github.com/odwrtw/polochon/lib"
|
|
)
|
|
|
|
const (
|
|
addShowQuery = `
|
|
INSERT INTO shows (imdb_id, title, rating, plot, tvdb_id, year, first_aired)
|
|
VALUES (:imdbid, :title, :rating, :plot, :tvdbid, :year, :firstaired) RETURNING id;`
|
|
|
|
getShowQueryByImdbID = `
|
|
SELECT
|
|
id, imdb_id AS imdbid,
|
|
title, rating, plot,
|
|
tvdb_id AS tvdbid,
|
|
year, first_aired AS firstaired,
|
|
created_at, updated_at
|
|
FROM shows WHERE imdb_id=$1;`
|
|
|
|
getShowQueryByID = `
|
|
SELECT
|
|
id, imdb_id AS imdbid,
|
|
title, rating, plot,
|
|
tvdb_id AS tvdbid,
|
|
year, first_aired AS firstaired,
|
|
created_at, updated_at
|
|
FROM shows WHERE id=$1;`
|
|
|
|
deleteShowQuery = `DELETE FROM shows WHERE id=$1;`
|
|
|
|
addEpisodeQuery = `
|
|
INSERT INTO episodes (show_id, title, season, episode, tvdb_id, aired, plot, runtime, rating, imdb_id)
|
|
VALUES (:showid, :title, :season, :episode, :tvdbid, :aired, :plot, :runtime, :rating, :episodeimdbid) RETURNING id;`
|
|
|
|
getEpisodesQuery = `
|
|
SELECT title, season, episode, tvdb_id AS tvdbid, aired, plot, runtime, rating, imdb_id AS episodeimdbid, show_id AS showid
|
|
FROM episodes WHERE show_id=$1;`
|
|
|
|
getShowWithUserQueryByImdbID = `
|
|
SELECT
|
|
shows.id,
|
|
shows.imdb_id AS imdbid,
|
|
shows.title,
|
|
shows.rating,
|
|
shows.plot,
|
|
shows.tvdb_id AS tvdbid,
|
|
shows.year,
|
|
shows.first_aired AS firstaired,
|
|
shows.created_at,
|
|
shows.updated_at,
|
|
COALESCE(shows_tracked.season,0) AS trackedseason,
|
|
COALESCE(shows_tracked.episode,0) AS trackedepisode
|
|
FROM shows LEFT JOIN shows_tracked ON shows.id=shows_tracked.show_id AND shows_tracked.user_id=$2
|
|
WHERE shows.imdb_id=$1;`
|
|
|
|
getShowWithUserQueryByID = `
|
|
SELECT
|
|
shows.id,
|
|
shows.imdb_id AS imdbid,
|
|
shows.title,
|
|
shows.rating,
|
|
shows.plot,
|
|
shows.tvdb_id AS tvdbid,
|
|
shows.year,
|
|
shows.first_aired AS firstaired,
|
|
shows.created_at,
|
|
shows.updated_at,
|
|
COALESCE(shows_tracked.season,0) AS trackedseason,
|
|
COALESCE(shows_tracked.episode,0) AS trackedepisode
|
|
FROM shows LEFT JOIN shows_tracked ON shows.id=shows_tracked.show_id AND shows_tracked.user_id=$2
|
|
WHERE shows.id=$1;`
|
|
)
|
|
|
|
var (
|
|
// ErrNotFound error returned when show not found in database
|
|
ErrNotFound = fmt.Errorf("Not found")
|
|
)
|
|
|
|
// Show represents a show
|
|
type Show struct {
|
|
sqly.BaseModel
|
|
polochon.Show
|
|
Episodes []*Episode
|
|
TrackedSeason int
|
|
TrackedEpisode int
|
|
}
|
|
|
|
// New returns a new Show with a polochon ShowConfig
|
|
func New(conf polochon.ShowConfig) *Show {
|
|
return &Show{Show: polochon.Show{ShowConfig: conf}}
|
|
}
|
|
|
|
// Get returns show details in database from id or imdbid or an error
|
|
func (s *Show) Get(db *sqlx.DB) error {
|
|
var err error
|
|
if s.ID != "" {
|
|
err = db.QueryRowx(getShowQueryByID, s.ID).StructScan(s)
|
|
} else if s.ImdbID != "" {
|
|
err = db.QueryRowx(getShowQueryByImdbID, s.ImdbID).StructScan(s)
|
|
} else {
|
|
err = fmt.Errorf("Can't get show details, you have to specify an ID or ImdbID")
|
|
}
|
|
if err != nil {
|
|
if err.Error() == "sql: no rows in result set" {
|
|
return ErrNotFound
|
|
}
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// GetAsUser returns a show with user info like tracked
|
|
func (s *Show) GetAsUser(db *sqlx.DB, user *users.User) error {
|
|
var err error
|
|
if s.ID != "" {
|
|
err = db.QueryRowx(getShowWithUserQueryByID, s.ID, user.ID).StructScan(s)
|
|
} else if s.ImdbID != "" {
|
|
err = db.QueryRowx(getShowWithUserQueryByImdbID, s.ImdbID, user.ID).StructScan(s)
|
|
} else {
|
|
err = fmt.Errorf("Can't get show details, you have to specify an ID or ImdbID")
|
|
}
|
|
if err != nil {
|
|
if err.Error() == "sql: no rows in result set" {
|
|
return ErrNotFound
|
|
}
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// GetDetails retrieves details for the show, first try to
|
|
// get info from db, if not exists, use polochon.Detailer
|
|
// and save informations in the database for future use
|
|
func (s *Show) GetDetails(db *sqlx.DB, log *logrus.Entry) error {
|
|
var err error
|
|
err = s.Get(db)
|
|
if err == nil {
|
|
// found ok
|
|
return nil
|
|
}
|
|
if err != ErrNotFound {
|
|
// Unexpected error
|
|
return err
|
|
}
|
|
|
|
// so we got ErrNotFound so GetDetails from a detailer
|
|
err = s.Show.GetDetails(log)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
s.Episodes = []*Episode{}
|
|
for _, pe := range s.Show.Episodes {
|
|
s.Episodes = append(s.Episodes, &Episode{ShowEpisode: *pe})
|
|
}
|
|
|
|
err = s.Add(db)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// GetDetailsAsUser like GetDetails but with User context
|
|
func (s *Show) GetDetailsAsUser(db *sqlx.DB, user *users.User, log *logrus.Entry) error {
|
|
var err error
|
|
err = s.GetAsUser(db, user)
|
|
if err == nil {
|
|
// found ok
|
|
return nil
|
|
}
|
|
if err != ErrNotFound {
|
|
// Unexpected error
|
|
return err
|
|
}
|
|
err = s.Show.GetDetails(log)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
s.Episodes = []*Episode{}
|
|
for _, pe := range s.Show.Episodes {
|
|
s.Episodes = append(s.Episodes, &Episode{ShowEpisode: *pe})
|
|
}
|
|
|
|
err = s.Add(db)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// IsTracked returns true if the show is tracked use this function
|
|
// after retrieve the show with GetAsUser or other *AsUser functions
|
|
func (s *Show) IsTracked() bool {
|
|
if s.TrackedSeason != 0 && s.TrackedEpisode != 0 {
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
// Add a show in the database
|
|
func (s *Show) Add(db *sqlx.DB) error {
|
|
var id string
|
|
r, err := db.NamedQuery(addShowQuery, s)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for r.Next() {
|
|
r.Scan(&id)
|
|
}
|
|
s.ID = id
|
|
|
|
for _, e := range s.Episodes {
|
|
e.ShowID = s.ID
|
|
err = e.Add(db)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Delete show from database
|
|
func (s *Show) Delete(db *sqlx.DB) error {
|
|
r, err := db.Exec(deleteShowQuery, s.ID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
count, _ := r.RowsAffected()
|
|
if count != 1 {
|
|
return fmt.Errorf("Unexpected number of row deleted: %d", count)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// GetEpisodes from database
|
|
func (s *Show) GetEpisodes(db *sqlx.DB) error {
|
|
// When retrive episode's info from database populate the s.Episodes member
|
|
// and not s.Show.Episodes
|
|
s.Episodes = []*Episode{}
|
|
err := db.Select(&s.Episodes, getEpisodesQuery, s.ID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Episode represents an episode
|
|
type Episode struct {
|
|
sqly.BaseModel
|
|
polochon.ShowEpisode
|
|
ShowID string
|
|
}
|
|
|
|
// Add episode to the database
|
|
func (e *Episode) Add(db *sqlx.DB) error {
|
|
var id string
|
|
r, err := db.NamedQuery(addEpisodeQuery, e)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for r.Next() {
|
|
r.Scan(&id)
|
|
}
|
|
e.ID = id
|
|
return nil
|
|
}
|