canape/src/internal/shows/handlers.go

336 lines
8.7 KiB
Go

package shows
import (
"encoding/json"
"errors"
"fmt"
"net"
"net/http"
"net/url"
"strconv"
"github.com/gorilla/mux"
customError "github.com/odwrtw/errors"
"github.com/odwrtw/papi"
polochon "github.com/odwrtw/polochon/lib"
"github.com/odwrtw/polochon/modules/pam"
"gitlab.quimbo.fr/odwrtw/canape-sql/src/internal/auth"
"gitlab.quimbo.fr/odwrtw/canape-sql/src/internal/config"
"gitlab.quimbo.fr/odwrtw/canape-sql/src/internal/users"
"gitlab.quimbo.fr/odwrtw/canape-sql/src/internal/web"
)
// ErrPolochonUnavailable is an error returned if the polochon server is not available
var ErrPolochonUnavailable = fmt.Errorf("Invalid polochon address")
// GetDetailsHandler retrieves details of a show
func GetDetailsHandler(env *web.Env, w http.ResponseWriter, r *http.Request) error {
return DetailsHandler(env, w, r, false)
}
// RefreahDetailsHandler refresh details of a show
func RefreshDetailsHandler(env *web.Env, w http.ResponseWriter, r *http.Request) error {
return DetailsHandler(env, w, r, true)
}
// DetailsHandler handles details of an episode
func DetailsHandler(env *web.Env, w http.ResponseWriter, r *http.Request, force bool) error {
vars := mux.Vars(r)
id := vars["id"]
v := auth.GetCurrentUser(r, env.Log)
user, ok := v.(*users.User)
if !ok {
return env.RenderError(w, errors.New("invalid user type"))
}
s := New(id)
if err := s.GetDetails(env, user, force); err != nil {
return env.RenderError(w, err)
}
if err := s.GetEpisodes(env, force); err != nil {
return env.RenderError(w, err)
}
// Get the show from the polochon of the user
pShow, err := getPolochonShow(user, s.ImdbID)
if err != nil {
env.Log.Warnf("error while getting polochon show %s : %s", s.ImdbID, err)
}
// For each of the user's polochon episodes, add a direct link to it
for _, pEpisode := range pShow.Episodes {
for _, e := range s.Episodes {
if e.Season != pEpisode.Season || e.Episode != pEpisode.Episode {
continue
}
e.PolochonURL = pEpisode.PolochonURL
}
}
return env.RenderJSON(w, s)
}
// SearchShow will search a show
func SearchShow(env *web.Env, w http.ResponseWriter, r *http.Request) error {
var data struct {
Key string `json:"key"`
}
if err := json.NewDecoder(r.Body).Decode(&data); err != nil {
return env.RenderError(w, errors.New("failed to get the search key"))
}
if data.Key == "" {
return env.RenderError(w, errors.New("no given key"))
}
v := auth.GetCurrentUser(r, env.Log)
user, ok := v.(*users.User)
if !ok {
return env.RenderError(w, errors.New("invalid user type"))
}
var shows []*polochon.Show
searchers := env.Config.ShowSearchers
for _, searcher := range searchers {
result, err := searcher.SearchShow(data.Key, env.Log)
if err != nil {
env.Log.Errorf("error while searching show : %s", err)
continue
}
shows = append(shows, result...)
}
env.Log.Debugf("got %d shows doing search %q", len(shows), data.Key)
showList := []*Show{}
for _, s := range shows {
show := New(s.ImdbID)
err := show.GetDetails(env, user, false)
if err != nil {
env.Log.Errorf("error while getting show details : %s", err)
continue
}
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()))
}
}
v := auth.GetCurrentUser(r, env.Log)
user, ok := v.(*users.User)
if !ok {
return env.RenderError(w, errors.New("invalid user type"))
}
s := New(id)
if err := s.AddToWishlist(env, user, 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"]
v := auth.GetCurrentUser(r, env.Log)
user, ok := v.(*users.User)
if !ok {
return env.RenderError(w, errors.New("invalid user type"))
}
s := New(id)
if err := s.DeleteFromWishlist(env, user); 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 {
v := auth.GetCurrentUser(r, env.Log)
user, ok := v.(*users.User)
if !ok {
return env.RenderError(w, errors.New("invalid user type"))
}
shows, err := GetWishlist(env, user)
if err != nil {
return env.RenderError(w, err)
}
return env.RenderJSON(w, shows)
}
// getPolochonShows returns all the Shows from the polochon of a user
func getPolochonShows(user *users.User) ([]*Show, error) {
shows := []*Show{}
var polochonConfig config.UserPolochon
err := user.GetConfig("polochon", &polochonConfig)
if err != nil {
return shows, err
}
client, err := papi.New(polochonConfig.URL)
if err != nil {
return shows, err
}
if polochonConfig.Token != "" {
client.SetToken(polochonConfig.Token)
}
pshows, err := client.GetShows()
if err != nil {
// Catch network error for accessing specified polochon address
if uerr, ok := err.(*url.Error); ok {
if nerr, ok := uerr.Err.(*net.OpError); ok {
if nerr.Op == "dial" {
return shows, ErrPolochonUnavailable
}
}
}
return shows, err
}
for _, pshow := range pshows {
show := New(pshow.ImdbID)
for _, season := range pshow.Seasons {
for _, episode := range season.Episodes {
e := NewEpisode()
e.Season = episode.Season
e.Episode = episode.Episode
e.ShowImdbID = episode.ShowImdbID
e.PolochonURL, _ = client.DownloadURL(
&papi.Episode{
ShowImdbID: show.ImdbID,
Episode: e.Episode,
Season: e.Season,
},
)
show.Episodes = append(show.Episodes, e)
}
}
shows = append(shows, show)
}
return shows, nil
}
// getPolochonShow returns a Show with its epidodes from the polochon of a user
func getPolochonShow(user *users.User, imdbID string) (Show, error) {
shows, err := getPolochonShows(user)
if err != nil {
return Show{}, err
}
for _, s := range shows {
if s.ImdbID == imdbID {
return *s, nil
}
}
return Show{}, nil
}
// FromPolochon will returns shows from Polochon
func FromPolochon(env *web.Env, w http.ResponseWriter, r *http.Request) error {
v := auth.GetCurrentUser(r, env.Log)
user, ok := v.(*users.User)
if !ok {
return env.RenderError(w, errors.New("invalid user type"))
}
shows, err := getPolochonShows(user)
if err != nil {
return env.RenderError(w, err)
}
var polochonConfig config.UserPolochon
err = user.GetConfig("polochon", &polochonConfig)
if err != nil {
return env.RenderError(w, err)
}
detailer, err := pam.New(&pam.Params{
Endpoint: polochonConfig.URL,
Token: polochonConfig.Token,
})
for _, s := range shows {
s.Detailers = []polochon.Detailer{detailer}
err := s.GetDetails(env, user, false)
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 {
return EpisodeDetailsHandler(env, w, r, true)
}
// EpisodeDetailsHandler handles details of a show
func EpisodeDetailsHandler(env *web.Env, w http.ResponseWriter, r *http.Request, force bool) 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"])
v := auth.GetCurrentUser(r, env.Log)
user, ok := v.(*users.User)
if !ok {
return env.RenderError(w, errors.New("invalid user type"))
}
s := New(id)
e, err := s.GetEpisodeDetails(env, season, episode, force)
if err != nil {
return env.RenderError(w, err)
}
err = e.GetTorrents(env, force)
if err != nil && customError.IsFatal(err) {
return env.RenderError(w, err)
}
// Get the show from the polochon of the user
pShow, err := getPolochonShow(user, id)
if err != nil {
env.Log.Warnf("error while getting polochon episode %s S%02dE%02d : %s", id, season, episode, err)
}
// Find if the user has a the episode in its polochon to add the
// DownloadURL
for _, pEpisode := range pShow.Episodes {
if e.Season == pEpisode.Season && e.Episode == pEpisode.Episode {
e.PolochonURL = pEpisode.PolochonURL
break
}
}
return env.RenderJSON(w, e)
}