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
421 lines
11 KiB
Go
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)
|
|
}
|