canape/backend/movies/movies.go
Grégoire Delattre 502bf88feb Update asset management in webpack
This hashes every file and forces the browser to download updated
assets.
2019-06-26 14:08:25 +02:00

290 lines
7.5 KiB
Go

package movies
import (
"database/sql"
"encoding/json"
"fmt"
"os"
"path/filepath"
"time"
"git.quimbo.fr/odwrtw/canape/backend/backend"
"git.quimbo.fr/odwrtw/canape/backend/subtitles"
"git.quimbo.fr/odwrtw/canape/backend/users"
"git.quimbo.fr/odwrtw/canape/backend/web"
"github.com/odwrtw/papi"
polochon "github.com/odwrtw/polochon/lib"
"github.com/sirupsen/logrus"
)
// Movie represents a movie
type Movie struct {
*polochon.Movie
client *papi.Client
pMovie *papi.Movie
publicDir string
imgURLPrefix string
Wishlisted bool `json:"wishlisted"`
}
// MarshalJSON implements the Marshal interface
func (m *Movie) MarshalJSON() ([]byte, error) {
type Alias Movie
// Marshal the movie with its polochon_url
movieToMarshal := &struct {
*Alias
PolochonURL string `json:"polochon_url"`
PosterURL string `json:"poster_url"`
Subtitles []subtitles.Subtitle `json:"subtitles"`
DateAdded time.Time `json:"date_added"`
Quality string `json:"quality"`
AudioCodec string `json:"audio_codec"`
VideoCodec string `json:"video_codec"`
Container string `json:"container"`
}{
Alias: (*Alias)(m),
PosterURL: m.PosterURL(),
Subtitles: []subtitles.Subtitle{},
}
if m.pMovie != nil {
// Get the DownloadURL
movieToMarshal.PolochonURL, _ = m.client.DownloadURL(m.pMovie)
// Get the metadata
movieToMarshal.DateAdded = m.pMovie.DateAdded
movieToMarshal.Quality = m.pMovie.Quality
movieToMarshal.AudioCodec = m.pMovie.AudioCodec
movieToMarshal.VideoCodec = m.pMovie.VideoCodec
movieToMarshal.Container = m.pMovie.Container
// Append the Subtitles
for _, l := range m.pMovie.Subtitles {
subtitleURL, _ := m.client.SubtitleURL(m.pMovie, l)
movieToMarshal.Subtitles = append(movieToMarshal.Subtitles, subtitles.Subtitle{
Language: l,
URL: subtitleURL,
VVTFile: fmt.Sprintf("/movies/%s/subtitles/%s", m.ImdbID, l),
})
}
}
return json.Marshal(movieToMarshal)
}
// New returns a new Movie with all the needed infos
func New(imdbID string, client *papi.Client, pMovie *papi.Movie, isWishlisted bool, publicDir, imgURLPrefix string) *Movie {
return &Movie{
client: client,
pMovie: pMovie,
publicDir: publicDir,
imgURLPrefix: imgURLPrefix,
Wishlisted: isWishlisted,
Movie: &polochon.Movie{
ImdbID: imdbID,
},
}
}
// GetDetails retrieves details for the movie with the given detailers
func (m *Movie) GetDetails(env *web.Env, detailers []polochon.Detailer) error {
log := env.Log.WithFields(logrus.Fields{
"imdb_id": m.ImdbID,
"function": "movies.GetDetails",
})
log.Debugf("getting details")
m.Detailers = detailers
// GetDetail
err := polochon.GetDetails(m.Movie, env.Log)
if err != nil {
return err
}
log.Debug("got details from detailers")
return nil
}
// GetAndFetch retrieves details for the movie with the given
// detailers 'before'
// If found, return
// If not, retrives details with the detailers 'after' and update them in
// database
func (m *Movie) GetAndFetch(env *web.Env, before []polochon.Detailer, after []polochon.Detailer) error {
log := env.Log.WithFields(logrus.Fields{
"imdb_id": m.ImdbID,
"function": "movies.GetAndFetch",
})
// Try to get details with the first batch of Detailers
err := m.GetDetails(env, before)
if err == nil {
log.Debug("movie found in first try")
return nil
}
log.Debugf("movie not found in database: %s", err)
// If not found, try the second batch and upsert
return m.Refresh(env, after)
}
// Refresh retrieves details for the movie with the given detailers
// and update them in database
func (m *Movie) Refresh(env *web.Env, detailers []polochon.Detailer) error {
log := env.Log.WithFields(logrus.Fields{
"imdb_id": m.ImdbID,
"function": "movies.Refresh",
})
// Refresh
err := m.GetDetails(env, detailers)
if err != nil {
return err
}
// Download poster
err = web.Download(m.Thumb, m.imgFile(), true)
if err != nil {
log.Errorf("got error trying to download the poster %q", err)
}
// If found, update in database
return backend.UpsertMovie(env.Database, m.Movie)
}
// GetTorrents retrieves torrents for the movie with the given torrenters
func (m *Movie) GetTorrents(env *web.Env, torrenters []polochon.Torrenter) error {
log := env.Log.WithFields(logrus.Fields{
"imdb_id": m.ImdbID,
"function": "movies.GetTorrents",
})
log.Debugf("getting torrents")
m.Torrenters = torrenters
err := polochon.GetTorrents(m.Movie, env.Log)
if err != nil {
return err
}
log.Debugf("got %d torrents from torrenters", len(m.Movie.Torrents))
return nil
}
// GetAndFetchTorrents retrieves torrents for the movie with the given
// torrenters 'before'
// If found, return
// If not, retrives torrents with the torrenters 'after' and update them in
// database
func (m *Movie) GetAndFetchTorrents(env *web.Env, before []polochon.Torrenter, after []polochon.Torrenter) error {
log := env.Log.WithFields(logrus.Fields{
"imdb_id": m.ImdbID,
"function": "movies.GetAndFetchTorrents",
})
// Try to get torrents with the first batch of Torrenters
err := m.GetTorrents(env, before)
switch err {
case nil:
log.Debug("movie torrent's found in first try")
return nil
case sql.ErrNoRows:
log.Debug("movie's torrents not found in database")
default:
// Unexpected error
return err
}
// If not found, try the second batch and upsert
return m.RefreshTorrents(env, after)
}
// RefreshTorrents retrieves torrents for the movie with the given torrenters
// and update them in database
func (m *Movie) RefreshTorrents(env *web.Env, torrenters []polochon.Torrenter) error {
log := env.Log.WithFields(logrus.Fields{
"imdb_id": m.ImdbID,
"function": "movies.RefreshTorrents",
})
// Get torrents with de torrenters
err := m.GetTorrents(env, torrenters)
if err != nil {
return err
}
log.Debugf("got %d torrents from torrenters", len(m.Movie.Torrents))
// Update them in database
for _, t := range m.Movie.Torrents {
err = backend.UpsertMovieTorrent(env.Database, &t, m.ImdbID)
if err != nil {
log.Error("error while adding torrent", err)
continue
}
}
return nil
}
// imgURL returns the default image url
func (m *Movie) imgURL() string {
return fmt.Sprintf("movies/%s.jpg", m.ImdbID)
}
// imgFile returns the image location on disk
func (m *Movie) imgFile() string {
return filepath.Join(m.publicDir, "img", m.imgURL())
}
// PosterURL returns the image URL or the default image if the poster is not yet downloaded
func (m *Movie) PosterURL() string {
// Check if the movie image exists
if _, err := os.Stat(m.imgFile()); os.IsNotExist(err) {
return ""
}
return m.imgURLPrefix + m.imgURL()
}
// getPolochonMovies returns an array of the user's polochon movies
func getPolochonMovies(user *users.User, env *web.Env) ([]*Movie, error) {
movies := []*Movie{}
// Create a papi client
client, err := user.NewPapiClient()
if err != nil {
return movies, err
}
// Retrieve the user's polochon movies
pmovies, err := client.GetMovies()
if err != nil {
return movies, err
}
// Get the user's wishlisted movies
moviesWishlist, err := backend.GetMovieWishlist(env.Database, user.ID)
if err != nil {
return movies, err
}
// Create Movies objects from the movies retrieved
for _, pmovie := range pmovies.List() {
movie := New(
pmovie.ImdbID,
client,
pmovie,
moviesWishlist.IsMovieInWishlist(pmovie.ImdbID),
env.Config.PublicDir,
env.Config.ImgURLPrefix,
)
movies = append(movies, movie)
}
return movies, nil
}