package shows import ( "encoding/json" "errors" "fmt" "log" "strconv" "net/http" "github.com/gorilla/mux" "github.com/odwrtw/papi" polochon "github.com/odwrtw/polochon/lib" "gitlab.quimbo.fr/odwrtw/canape/backend/auth" "gitlab.quimbo.fr/odwrtw/canape/backend/backend" "gitlab.quimbo.fr/odwrtw/canape/backend/subtitles" "gitlab.quimbo.fr/odwrtw/canape/backend/users" "gitlab.quimbo.fr/odwrtw/canape/backend/web" ) // 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"] v := auth.GetCurrentUser(r, env.Log) user, ok := v.(*users.User) if !ok { return env.RenderError(w, errors.New("invalid user type")) } client, err := user.NewPapiClient() 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 := backend.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.ShowDetailers 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"] v := auth.GetCurrentUser(r, env.Log) user, ok := v.(*users.User) if !ok { return env.RenderError(w, errors.New("invalid user type")) } client, err := user.NewPapiClient() 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 := backend.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.ShowDetailers 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.ShowTorrenters) if err != nil { env.Log.Error(err) } } env.Log.Debug("getting polochon show") 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"] 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 // 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() 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 := backend.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.ShowDetailers 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())) } } v := auth.GetCurrentUser(r, env.Log) user, ok := v.(*users.User) if !ok { return env.RenderError(w, errors.New("invalid user type")) } if err := backend.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"] v := auth.GetCurrentUser(r, env.Log) user, ok := v.(*users.User) if !ok { return env.RenderError(w, errors.New("invalid user type")) } if err := backend.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 { v := auth.GetCurrentUser(r, env.Log) user, ok := v.(*users.User) if !ok { return env.RenderError(w, errors.New("invalid user type")) } client, err := user.NewPapiClient() 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 := backend.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.ShowDetailers 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 { v := auth.GetCurrentUser(r, env.Log) user, ok := v.(*users.User) if !ok { return env.RenderError(w, errors.New("invalid user type")) } // 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.ShowDetailers 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"]) v := auth.GetCurrentUser(r, env.Log) user, ok := v.(*users.User) if !ok { return env.RenderError(w, errors.New("invalid user type")) } client, err := user.NewPapiClient() 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 ", err) } e := NewEpisode(client, pShow, id, season, episode) // Refresh the episode err = e.Refresh(env, env.Config.ShowDetailers) if err != nil { env.Log.Error(err) return env.RenderError(w, err) } // Refresh the torrents err = e.RefreshTorrents(env, env.Config.ShowTorrenters) if err != nil { env.Log.Error(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 v := auth.GetCurrentUser(r, env.Log) user, ok := v.(*users.User) if !ok { return fmt.Errorf("invalid user type") } // Create a new papi client client, err := user.NewPapiClient() 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 v := auth.GetCurrentUser(r, env.Log) user, ok := v.(*users.User) if !ok { return fmt.Errorf("invalid user type") } // Create a new papi client client, err := user.NewPapiClient() 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) }