canape/src/internal/shows/handlers.go
Grégoire Delattre 1c7421b182 Add srt to vvt converter in the backend
The HTML5 videos can only ready subtitles in the VVT format, let's
convert the srt files on the fly to make the browser happy
2017-05-21 13:31:34 +02:00

421 lines
11 KiB
Go

package shows
import (
"encoding/json"
"errors"
"fmt"
"log"
"strconv"
"gitlab.quimbo.fr/odwrtw/canape-sql/src/internal/auth"
"gitlab.quimbo.fr/odwrtw/canape-sql/src/internal/backend"
"gitlab.quimbo.fr/odwrtw/canape-sql/src/internal/subtitles"
"gitlab.quimbo.fr/odwrtw/canape-sql/src/internal/users"
"gitlab.quimbo.fr/odwrtw/canape-sql/src/internal/web"
"net/http"
"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"]
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)
}
err = client.UpdateSubtitles(&papi.Episode{
ShowImdbID: id,
Season: season,
Episode: episode,
})
if err != nil {
return env.RenderError(w, err)
}
return env.RenderOK(w, "Subtitles refreshed")
}
// 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)
}