diff --git a/src/internal/movies/handlers.go b/src/internal/movies/handlers.go index fda3117..49cc7b1 100644 --- a/src/internal/movies/handlers.go +++ b/src/internal/movies/handlers.go @@ -14,6 +14,7 @@ import ( "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/config" + "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" ) @@ -331,3 +332,30 @@ func RefreshMovieSubtitlesHandler(env *web.Env, w http.ResponseWriter, r *http.R 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"] + + // 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.Movie{ImdbID: id}, lang) + if err != nil { + return env.RenderError(w, err) + } + + return subtitles.ConvertSubtitle(url, w) +} diff --git a/src/internal/movies/movies.go b/src/internal/movies/movies.go index e4147c4..9b07363 100644 --- a/src/internal/movies/movies.go +++ b/src/internal/movies/movies.go @@ -34,6 +34,7 @@ func (m *Movie) MarshalJSON() ([]byte, error) { type Subtitle struct { Language string `json:"language"` URL string `json:"url"` + VVTFile string `json:"vvt_file"` } var subtitles []Subtitle // If the episode is present, fill the downloadURL @@ -46,6 +47,7 @@ func (m *Movie) MarshalJSON() ([]byte, error) { subtitles = append(subtitles, Subtitle{ Language: l, URL: subtitleURL, + VVTFile: fmt.Sprintf("/movies/%s/subtitles/%s", m.ImdbID, l), }) } } diff --git a/src/internal/shows/episodes.go b/src/internal/shows/episodes.go index b3535e7..269e59f 100644 --- a/src/internal/shows/episodes.go +++ b/src/internal/shows/episodes.go @@ -2,6 +2,7 @@ package shows import ( "encoding/json" + "fmt" "github.com/Sirupsen/logrus" "github.com/odwrtw/papi" @@ -26,6 +27,7 @@ func (e *Episode) MarshalJSON() ([]byte, error) { type Subtitle struct { Language string `json:"language"` URL string `json:"url"` + VVTFile string `json:"vvt_file"` } var subtitles []Subtitle // If the episode is present, fill the downloadURL @@ -46,6 +48,7 @@ func (e *Episode) MarshalJSON() ([]byte, error) { subtitles = append(subtitles, Subtitle{ Language: l, URL: subtitleURL, + VVTFile: fmt.Sprintf("/shows/%s/seasons/%d/episodes/%d/subtitles/%s", e.ShowImdbID, e.Season, e.Episode, l), }) } } diff --git a/src/internal/shows/handlers.go b/src/internal/shows/handlers.go index 3d3a011..5a3b9fe 100644 --- a/src/internal/shows/handlers.go +++ b/src/internal/shows/handlers.go @@ -9,6 +9,7 @@ import ( "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" @@ -384,3 +385,36 @@ func RefreshEpisodeSubtitlesHandler(env *web.Env, w http.ResponseWriter, r *http 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) +} diff --git a/src/internal/subtitles/handler.go b/src/internal/subtitles/handler.go new file mode 100644 index 0000000..6cb79b9 --- /dev/null +++ b/src/internal/subtitles/handler.go @@ -0,0 +1,43 @@ +package subtitles + +import ( + "fmt" + "net/http" + + "github.com/gregdel/srt2vtt" +) + +// ConvertSubtitle downloads and converts a subtitle from srt to vvt +func ConvertSubtitle(url string, w http.ResponseWriter) error { + // Client with compression disabled + c := &http.Client{ + Transport: &http.Transport{DisableCompression: true}, + } + + req, err := http.NewRequest("GET", url, nil) + if err != nil { + return err + } + + resp, err := c.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("Invalid subitle response code: %d", resp.StatusCode) + } + + reader, err := srt2vtt.NewReader(resp.Body) + if err != nil { + return err + } + + _, err = reader.WriteTo(w) + if err != nil { + return err + } + + return nil +} diff --git a/src/routes.go b/src/routes.go index 1569f09..ab1fab3 100644 --- a/src/routes.go +++ b/src/routes.go @@ -23,6 +23,7 @@ func setupRoutes(env *web.Env) { env.Handle("/movies/search/{search}", movies.SearchMovie).WithRole(users.UserRole).Methods("GET") env.Handle("/movies/{id:tt[0-9]+}", movies.PolochonDeleteHandler).WithRole(users.UserRole).Methods("DELETE") env.Handle("/movies/{id:tt[0-9]+}/refresh", movies.RefreshMovieHandler).WithRole(users.UserRole).Methods("POST") + env.Handle("/movies/{id:tt[0-9]+}/subtitles/{lang}", movies.DownloadVVTSubtitle).WithRole(users.UserRole).Methods("GET") env.Handle("/movies/{id:tt[0-9]+}/subtitles/refresh", movies.RefreshMovieSubtitlesHandler).WithRole(users.UserRole).Methods("POST") env.Handle("/movies/refresh", extmedias.RefreshMoviesHandler).WithRole(users.AdminRole).Methods("POST") @@ -35,6 +36,7 @@ func setupRoutes(env *web.Env) { env.Handle("/shows/{id:tt[0-9]+}/refresh", shows.RefreshShowHandler).WithRole(users.UserRole).Methods("POST") env.Handle("/shows/{id:tt[0-9]+}/seasons/{season:[0-9]+}/episodes/{episode:[0-9]+}", shows.RefreshEpisodeHandler).WithRole(users.UserRole).Methods("POST") env.Handle("/shows/{id:tt[0-9]+}/seasons/{season:[0-9]+}/episodes/{episode:[0-9]+}/subtitles/refresh", shows.RefreshEpisodeSubtitlesHandler).WithRole(users.UserRole).Methods("POST") + env.Handle("/shows/{id:tt[0-9]+}/seasons/{season:[0-9]+}/episodes/{episode:[0-9]+}/subtitles/{lang}", shows.DownloadVVTSubtitle).WithRole(users.UserRole).Methods("GET") env.Handle("/shows/refresh", extmedias.RefreshShowsHandler).WithRole(users.AdminRole).Methods("POST") // Wishlist routes for shows