canape/backend/shows/handlers.go

412 lines
11 KiB
Go

package shows
import (
"encoding/json"
"errors"
"fmt"
"log"
"strconv"
"net/http"
"git.quimbo.fr/odwrtw/canape/backend/auth"
"git.quimbo.fr/odwrtw/canape/backend/models"
"git.quimbo.fr/odwrtw/canape/backend/subtitles"
"git.quimbo.fr/odwrtw/canape/backend/web"
"github.com/gorilla/mux"
"github.com/odwrtw/papi"
polochon "github.com/odwrtw/polochon/lib"
)
// ErrPolochonUnavailable is an error returned if the polochon server is not available
var ErrPolochonUnavailable = fmt.Errorf("Invalid polochon address")
// GetDetailsHandler handles details of a show
func GetDetailsHandler(env *web.Env, w http.ResponseWriter, r *http.Request) error {
vars := mux.Vars(r)
id := vars["id"]
user := auth.GetCurrentUser(r, env.Log)
client, err := user.NewPapiClient(env.Database)
if err != nil {
return env.RenderError(w, err)
}
pShow, err := client.GetShow(id)
if err != nil && err != papi.ErrResourceNotFound {
log.Println("Got error getting show ", err)
}
wShow, err := models.IsShowWishlisted(env.Database, user.ID, id)
if err != nil && err != papi.ErrResourceNotFound {
log.Println("Got error getting wishlisted show ", err)
}
s := NewWithClient(id, client, pShow, wShow, env.Config.PublicDir, env.Config.ImgURLPrefix)
// First try from the db
first := []polochon.Detailer{env.Backend.Detailer}
// Then try from the polochon detailers
detailers := env.Config.Show.Detailers
err = s.GetAndFetch(env, first, detailers)
if err != nil {
env.Log.Error(err)
return err
}
env.Log.Debug("getting episodes torrents")
for _, e := range s.Show.Episodes {
// Get torrents from the db
backend := []polochon.Torrenter{env.Backend.Torrenter}
err := GetTorrents(env, e, backend)
if err != nil {
env.Log.Error(err)
}
}
return env.RenderJSON(w, s)
}
// RefreshShowHandler refreshes details of a show + torrents
func RefreshShowHandler(env *web.Env, w http.ResponseWriter, r *http.Request) error {
vars := mux.Vars(r)
id := vars["id"]
user := auth.GetCurrentUser(r, env.Log)
client, err := user.NewPapiClient(env.Database)
if err != nil {
return env.RenderError(w, err)
}
pShow, err := client.GetShow(id)
if err != nil && err != papi.ErrResourceNotFound {
log.Println("Got error getting show ", err)
}
wShow, err := models.IsShowWishlisted(env.Database, user.ID, id)
if err != nil && err != papi.ErrResourceNotFound {
log.Println("Got error getting wishlisted show ", err)
}
s := NewWithClient(id, client, pShow, wShow, env.Config.PublicDir, env.Config.ImgURLPrefix)
// Refresh the polochon detailers
detailers := env.Config.Show.Detailers
err = s.Refresh(env, detailers)
if err != nil {
env.Log.Error(err)
return err
}
env.Log.Debug("getting episodes torrents")
for _, e := range s.Episodes {
// Get torrents from the db
err := RefreshTorrents(env, e, env.Config.Show.Torrenters)
if err != nil {
env.Log.Error(err)
}
}
// Get everything from DB again
detailer := []polochon.Detailer{env.Backend.Detailer}
err = s.GetDetails(env, detailer)
if err != nil {
return env.RenderError(w, err)
}
return env.RenderJSON(w, s)
}
// SearchShow will search a show
func SearchShow(env *web.Env, w http.ResponseWriter, r *http.Request) error {
vars := mux.Vars(r)
search := vars["search"]
user := auth.GetCurrentUser(r, env.Log)
var shows []*polochon.Show
searchers := env.Config.Show.Searchers
// Iterate on all the searchers to search for the show
for _, searcher := range searchers {
result, err := searcher.SearchShow(search, env.Log)
if err != nil {
env.Log.Errorf("error while searching show : %s", err)
continue
}
// Add the results to the list of results
shows = append(shows, result...)
}
env.Log.Debugf("got %d shows doing search %q", len(shows), search)
client, err := user.NewPapiClient(env.Database)
if err != nil {
return env.RenderError(w, err)
}
// Get the polochon's shows
pShows, err := client.GetShows()
if err != nil {
return env.RenderError(w, err)
}
// Get the user's wishlisted shows
wShows, err := models.GetShowWishlist(env.Database, user.ID)
if err != nil {
return env.RenderError(w, err)
}
showList := []*Show{}
// Now iterate over all the shows to get details
for _, s := range shows {
pShow, _ := pShows.Has(s.ImdbID)
wShow, _ := wShows.IsShowInWishlist(s.ImdbID)
show := NewWithClient(s.ImdbID, client, pShow, wShow, env.Config.PublicDir, env.Config.ImgURLPrefix)
// First try from the db
first := []polochon.Detailer{env.Backend.Detailer}
// Then try from the polochon detailers
detailers := env.Config.Show.Detailers
err := show.GetAndFetch(env, first, detailers)
if err != nil {
env.Log.Error(err)
}
showList = append(showList, show)
}
return env.RenderJSON(w, showList)
}
// AddToWishlist adds a show to the user's wishlist
func AddToWishlist(env *web.Env, w http.ResponseWriter, r *http.Request) error {
vars := mux.Vars(r)
id := vars["id"]
var data struct {
Season int `json:"season"`
Episode int `json:"episode"`
}
if r.ContentLength > 0 {
if err := json.NewDecoder(r.Body).Decode(&data); err != nil {
return env.RenderError(w, errors.New("failed to get POST data season and episode "+err.Error()))
}
}
user := auth.GetCurrentUser(r, env.Log)
if err := models.AddShowToWishlist(env.Database, user.ID, id, data.Season, data.Episode); err != nil {
env.Log.Warnf("Error while adding to db : %s", err)
return env.RenderError(w, err)
}
return env.RenderOK(w, "Show added to wishlist")
}
// DeleteFromWishlist deletes a show from the user's wishlist
func DeleteFromWishlist(env *web.Env, w http.ResponseWriter, r *http.Request) error {
vars := mux.Vars(r)
id := vars["id"]
user := auth.GetCurrentUser(r, env.Log)
if err := models.DeleteShowFromWishlist(env.Database, user.ID, id); err != nil {
env.Log.Warnf("Error while deleting to db : %s", err)
return env.RenderError(w, err)
}
return env.RenderOK(w, "Show deleted from wishlist")
}
// GetWishlistHandler returns the tracked shows of a user
func GetWishlistHandler(env *web.Env, w http.ResponseWriter, r *http.Request) error {
user := auth.GetCurrentUser(r, env.Log)
client, err := user.NewPapiClient(env.Database)
if err != nil {
return env.RenderError(w, err)
}
// Get the polochon's shows
pShows, err := client.GetShows()
if err != nil {
return env.RenderError(w, err)
}
wShows, err := models.GetShowWishlist(env.Database, user.ID)
if err != nil {
return env.RenderError(w, err)
}
showList := []*Show{}
for _, wishedShow := range wShows.List() {
pShow, _ := pShows.Has(wishedShow.ImdbID)
show := NewWithClient(wishedShow.ImdbID, client, pShow, wishedShow, env.Config.PublicDir, env.Config.ImgURLPrefix)
// First check in the DB
before := []polochon.Detailer{env.Backend.Detailer}
// Then with the default detailers
after := env.Config.Show.Detailers
err := show.GetAndFetch(env, before, after)
if err != nil {
env.Log.Errorf("error while getting show details : %s", err)
continue
}
showList = append(showList, show)
}
return env.RenderJSON(w, showList)
}
// PolochonShowsHandler will returns shows from Polochon
func PolochonShowsHandler(env *web.Env, w http.ResponseWriter, r *http.Request) error {
user := auth.GetCurrentUser(r, env.Log)
// Get the polochon's shows
shows, err := getPolochonShows(env, user)
if err != nil {
return env.RenderError(w, err)
}
// Get details in DB for each shows
// Fetch the details if not found
for _, s := range shows {
// First try from the db
first := []polochon.Detailer{env.Backend.Detailer}
// Then try from the polochon detailer
detailers := env.Config.Show.Detailers
err := s.GetAndFetch(env, first, detailers)
if err != nil {
env.Log.Error(err)
}
}
return env.RenderJSON(w, shows)
}
// RefreshEpisodeHandler refresh details of an episode
func RefreshEpisodeHandler(env *web.Env, w http.ResponseWriter, r *http.Request) error {
vars := mux.Vars(r)
id := vars["id"]
// No need to check errors here as the router is making sure that season
// and episode are numbers
season, _ := strconv.Atoi(vars["season"])
episode, _ := strconv.Atoi(vars["episode"])
user := auth.GetCurrentUser(r, env.Log)
client, err := user.NewPapiClient(env.Database)
if err != nil {
return env.RenderError(w, err)
}
pShow, err := client.GetShow(id)
if err != nil && err != papi.ErrResourceNotFound {
env.Log.Warnf("Error getting show %q", err)
}
s := &Show{
Show: &polochon.Show{ImdbID: id},
client: client,
pShow: pShow,
publicDir: env.Config.PublicDir,
imgURLPrefix: env.Config.ImgURLPrefix,
}
e := NewEpisode(s, season, episode)
// Refresh the episode
err = e.Refresh(env, env.Config.Show.Detailers)
if err != nil {
env.Log.Error(err)
return env.RenderError(w, err)
}
// Refresh the torrents
err = e.RefreshTorrents(env, env.Config.Show.Torrenters)
if err != nil {
env.Log.Error(err)
}
// Get everything from DB again
detailer := []polochon.Detailer{env.Backend.Detailer}
err = e.GetEpisodeDetails(env, detailer)
if err != nil {
env.Log.Error(err)
return env.RenderError(w, err)
}
return env.RenderJSON(w, e)
}
// RefreshEpisodeSubtitlesHandler refreshes details for an episode
func RefreshEpisodeSubtitlesHandler(env *web.Env, w http.ResponseWriter, r *http.Request) error {
vars := mux.Vars(r)
id := vars["id"]
// No need to check errors here as the router is making sure that season
// and episode are numbers
season, _ := strconv.Atoi(vars["season"])
episode, _ := strconv.Atoi(vars["episode"])
// Get the user
user := auth.GetCurrentUser(r, env.Log)
// Create a new papi client
client, err := user.NewPapiClient(env.Database)
if err != nil {
return env.RenderError(w, err)
}
e := &papi.Episode{
ShowImdbID: id,
Season: season,
Episode: episode,
}
refreshedSubs, err := client.UpdateSubtitles(e)
if err != nil {
return env.RenderError(w, err)
}
subs := []subtitles.Subtitle{}
for _, lang := range refreshedSubs {
subtitleURL, _ := client.SubtitleURL(e, lang)
subs = append(subs, subtitles.Subtitle{
Language: lang,
URL: subtitleURL,
VVTFile: fmt.Sprintf("/shows/%s/seasons/%d/episodes/%d/subtitles/%s", e.ShowImdbID, e.Season, e.Episode, lang),
})
}
return env.RenderJSON(w, subs)
}
// DownloadVVTSubtitle returns a vvt subtitle for the movie
func DownloadVVTSubtitle(env *web.Env, w http.ResponseWriter, r *http.Request) error {
vars := mux.Vars(r)
id := vars["id"]
lang := vars["lang"]
season, _ := strconv.Atoi(vars["season"])
episode, _ := strconv.Atoi(vars["episode"])
// Get the user
user := auth.GetCurrentUser(r, env.Log)
// Create a new papi client
client, err := user.NewPapiClient(env.Database)
if err != nil {
return env.RenderError(w, err)
}
url, err := client.SubtitleURL(&papi.Episode{
ShowImdbID: id,
Season: season,
Episode: episode,
}, lang)
if err != nil {
return env.RenderError(w, err)
}
return subtitles.ConvertSubtitle(url, w)
}