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(&polochon.Show{ImdbID: 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(&polochon.Show{ImdbID: 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 { log := env.Log.WithField("searcher", searcher.Name()) result, err := searcher.SearchShow(search, log) if err != nil { log.Errorf("error while searching show : %s", err) continue } log.Debug("found show") // 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, 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) poloShow := &polochon.Show{ImdbID: wishedShow.ImdbID} show := NewWithClient(poloShow, 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) }