Compare commits
No commits in common. "9488795186720e835c74af08aab4abae43dbb0a9" and "451fea735537aa6ab2f32386874b4283d7e61f25" have entirely different histories.
9488795186
...
451fea7355
@ -141,7 +141,7 @@ func GetShows(env *web.Env, user *models.User, source string, category string, f
|
||||
for _, id := range media.IDs {
|
||||
pShow, _ := pShows.Has(id)
|
||||
wShow, _ := wShows.IsShowInWishlist(id)
|
||||
show := shows.NewWithClient(id, client, pShow, wShow)
|
||||
show := shows.NewWithClient(&polochon.Show{ImdbID: id}, client, pShow, wShow)
|
||||
|
||||
// First check in the DB
|
||||
before := []polochon.Detailer{env.Backend.Detailer}
|
||||
|
6
backend/fresh.conf
Normal file
6
backend/fresh.conf
Normal file
@ -0,0 +1,6 @@
|
||||
root: .
|
||||
valid_ext: .go
|
||||
colors: 1
|
||||
build_name: dev-build
|
||||
build_log: dev-build.log
|
||||
tmp_path: ../build
|
@ -2,12 +2,20 @@ package main
|
||||
|
||||
import (
|
||||
// Modules
|
||||
_ "github.com/odwrtw/polochon/modules/addicted"
|
||||
_ "github.com/odwrtw/polochon/modules/canape"
|
||||
_ "github.com/odwrtw/polochon/modules/eztv"
|
||||
_ "github.com/odwrtw/polochon/modules/fsnotify"
|
||||
_ "github.com/odwrtw/polochon/modules/imdb"
|
||||
_ "github.com/odwrtw/polochon/modules/mock"
|
||||
_ "github.com/odwrtw/polochon/modules/openguessit"
|
||||
_ "github.com/odwrtw/polochon/modules/opensubtitles"
|
||||
_ "github.com/odwrtw/polochon/modules/pushover"
|
||||
_ "github.com/odwrtw/polochon/modules/tmdb"
|
||||
_ "github.com/odwrtw/polochon/modules/tpb"
|
||||
_ "github.com/odwrtw/polochon/modules/trakttv"
|
||||
_ "github.com/odwrtw/polochon/modules/transmission"
|
||||
_ "github.com/odwrtw/polochon/modules/tvdb"
|
||||
_ "github.com/odwrtw/polochon/modules/yifysubtitles"
|
||||
_ "github.com/odwrtw/polochon/modules/yts"
|
||||
)
|
||||
|
@ -283,7 +283,6 @@ func GetWishlistHandler(env *web.Env, w http.ResponseWriter, r *http.Request) er
|
||||
func RefreshMovieSubtitlesHandler(env *web.Env, w http.ResponseWriter, r *http.Request) error {
|
||||
vars := mux.Vars(r)
|
||||
id := vars["id"]
|
||||
lang := polochon.Language(vars["lang"])
|
||||
|
||||
// Get the user
|
||||
user := auth.GetCurrentUser(r, env.Log)
|
||||
@ -295,35 +294,29 @@ func RefreshMovieSubtitlesHandler(env *web.Env, w http.ResponseWriter, r *http.R
|
||||
}
|
||||
|
||||
movie := &papi.Movie{Movie: &polochon.Movie{ImdbID: id}}
|
||||
sub, err := client.UpdateSubtitle(movie, lang)
|
||||
refreshSubs, err := client.UpdateSubtitles(movie)
|
||||
if err != nil {
|
||||
return env.RenderError(w, err)
|
||||
}
|
||||
|
||||
// TODO: handle this with a better error
|
||||
if sub == nil {
|
||||
return env.RenderJSON(w, nil)
|
||||
subs := []subtitles.Subtitle{}
|
||||
for _, lang := range refreshSubs {
|
||||
subtitleURL, _ := client.SubtitleURL(movie, lang)
|
||||
subs = append(subs, subtitles.Subtitle{
|
||||
Language: lang,
|
||||
URL: subtitleURL,
|
||||
VVTFile: fmt.Sprintf("/movies/%s/subtitles/%s", id, lang),
|
||||
})
|
||||
}
|
||||
|
||||
url, err := client.DownloadURLWithToken(sub)
|
||||
if err != nil {
|
||||
return env.RenderError(w, err)
|
||||
}
|
||||
|
||||
s := &subtitles.Subtitle{
|
||||
Subtitle: sub.Subtitle,
|
||||
URL: url,
|
||||
VVTFile: fmt.Sprintf("/movies/%s/subtitles/%s", id, sub.Lang),
|
||||
}
|
||||
|
||||
return env.RenderJSON(w, s)
|
||||
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 := polochon.Language(vars["lang"])
|
||||
lang := vars["lang"]
|
||||
|
||||
// Get the user
|
||||
user := auth.GetCurrentUser(r, env.Log)
|
||||
@ -334,14 +327,7 @@ func DownloadVVTSubtitle(env *web.Env, w http.ResponseWriter, r *http.Request) e
|
||||
return env.RenderError(w, err)
|
||||
}
|
||||
|
||||
s := &papi.Subtitle{
|
||||
Subtitle: &polochon.Subtitle{
|
||||
Video: &papi.Movie{Movie: &polochon.Movie{ImdbID: id}},
|
||||
Lang: lang,
|
||||
},
|
||||
}
|
||||
|
||||
url, err := client.DownloadURLWithToken(s)
|
||||
url, err := client.SubtitleURL(&papi.Movie{Movie: &polochon.Movie{ImdbID: id}}, lang)
|
||||
if err != nil {
|
||||
return env.RenderError(w, err)
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ func (m *Movie) MarshalJSON() ([]byte, error) {
|
||||
|
||||
if m.pMovie != nil {
|
||||
// Get the DownloadURL
|
||||
movieToMarshal.PolochonURL, _ = m.client.DownloadURLWithToken(m.pMovie)
|
||||
movieToMarshal.PolochonURL, _ = m.client.DownloadURL(m.pMovie)
|
||||
|
||||
// Get the metadata
|
||||
movieToMarshal.DateAdded = m.pMovie.DateAdded
|
||||
@ -58,14 +58,13 @@ func (m *Movie) MarshalJSON() ([]byte, error) {
|
||||
movieToMarshal.Container = m.pMovie.Container
|
||||
|
||||
// Append the Subtitles
|
||||
for _, s := range m.pMovie.Subtitles {
|
||||
sub := subtitles.Subtitle{Subtitle: s.Subtitle}
|
||||
if !sub.Embedded {
|
||||
subtitleURL, _ := m.client.DownloadURLWithToken(s)
|
||||
sub.URL = subtitleURL
|
||||
sub.VVTFile = fmt.Sprintf("/movies/%s/subtitles/%s", m.ImdbID, s.Lang)
|
||||
}
|
||||
movieToMarshal.Subtitles = append(movieToMarshal.Subtitles, sub)
|
||||
for _, l := range m.pMovie.Subtitles {
|
||||
subtitleURL, _ := m.client.SubtitleURL(m.pMovie, l)
|
||||
movieToMarshal.Subtitles = append(movieToMarshal.Subtitles, subtitles.Subtitle{
|
||||
Language: l,
|
||||
URL: subtitleURL,
|
||||
VVTFile: fmt.Sprintf("/movies/%s/subtitles/%s", m.ImdbID, l),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -74,18 +73,13 @@ func (m *Movie) MarshalJSON() ([]byte, error) {
|
||||
|
||||
// New returns a new Movie with all the needed infos
|
||||
func New(imdbID string, client *papi.Client, pMovie *papi.Movie, isWishlisted bool) *Movie {
|
||||
var m *polochon.Movie
|
||||
if pMovie != nil && pMovie.Movie != nil {
|
||||
m = pMovie.Movie
|
||||
} else {
|
||||
m = &polochon.Movie{ImdbID: imdbID}
|
||||
}
|
||||
|
||||
return &Movie{
|
||||
client: client,
|
||||
pMovie: pMovie,
|
||||
Wishlisted: isWishlisted,
|
||||
Movie: m,
|
||||
Movie: &polochon.Movie{
|
||||
ImdbID: imdbID,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -43,7 +43,7 @@ func setupRoutes(env *web.Env) {
|
||||
env.Handle("/movies/{id:tt[0-9]+}", movies.PolochonDeleteHandler).WithRole(models.UserRole).Methods("DELETE")
|
||||
env.Handle("/movies/{id:tt[0-9]+}/refresh", movies.RefreshMovieHandler).WithRole(models.UserRole).Methods("POST")
|
||||
env.Handle("/movies/{id:tt[0-9]+}/subtitles/{lang}", movies.DownloadVVTSubtitle).WithRole(models.UserRole).Methods("GET")
|
||||
env.Handle("/movies/{id:tt[0-9]+}/subtitles/{lang}", movies.RefreshMovieSubtitlesHandler).WithRole(models.UserRole).Methods("POST")
|
||||
env.Handle("/movies/{id:tt[0-9]+}/subtitles/refresh", movies.RefreshMovieSubtitlesHandler).WithRole(models.UserRole).Methods("POST")
|
||||
env.Handle("/movies/refresh", extmedias.RefreshMoviesHandler).WithRole(models.AdminRole).Methods("POST")
|
||||
|
||||
// Shows routes
|
||||
@ -54,7 +54,7 @@ func setupRoutes(env *web.Env) {
|
||||
env.Handle("/shows/{id:tt[0-9]+}", shows.GetDetailsHandler).WithRole(models.UserRole).Methods("GET")
|
||||
env.Handle("/shows/{id:tt[0-9]+}/refresh", shows.RefreshShowHandler).WithRole(models.UserRole).Methods("POST")
|
||||
env.Handle("/shows/{id:tt[0-9]+}/seasons/{season:[0-9]+}/episodes/{episode:[0-9]+}", shows.RefreshEpisodeHandler).WithRole(models.UserRole).Methods("POST")
|
||||
env.Handle("/shows/{id:tt[0-9]+}/seasons/{season:[0-9]+}/episodes/{episode:[0-9]+}/subtitles/{lang}", shows.RefreshEpisodeSubtitlesHandler).WithRole(models.UserRole).Methods("POST")
|
||||
env.Handle("/shows/{id:tt[0-9]+}/seasons/{season:[0-9]+}/episodes/{episode:[0-9]+}/subtitles/refresh", shows.RefreshEpisodeSubtitlesHandler).WithRole(models.UserRole).Methods("POST")
|
||||
env.Handle("/shows/{id:tt[0-9]+}/seasons/{season:[0-9]+}/episodes/{episode:[0-9]+}/subtitles/{lang}", shows.DownloadVVTSubtitle).WithRole(models.UserRole).Methods("GET")
|
||||
env.Handle("/shows/refresh", extmedias.RefreshShowsHandler).WithRole(models.AdminRole).Methods("POST")
|
||||
|
||||
|
@ -3,6 +3,7 @@ package shows
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"git.quimbo.fr/odwrtw/canape/backend/models"
|
||||
"git.quimbo.fr/odwrtw/canape/backend/subtitles"
|
||||
@ -25,13 +26,18 @@ func (e *Episode) MarshalJSON() ([]byte, error) {
|
||||
|
||||
var downloadURL string
|
||||
var subs []subtitles.Subtitle
|
||||
var dateAdded time.Time
|
||||
var quality string
|
||||
var audioCodec string
|
||||
var videoCodec string
|
||||
var container string
|
||||
|
||||
// If the episode is present, fill the downloadURL
|
||||
if e.show.pShow != nil {
|
||||
pEpisode := e.show.pShow.GetEpisode(e.Season, e.Episode)
|
||||
if pEpisode != nil {
|
||||
// Get the DownloadURL
|
||||
downloadURL, _ = e.show.client.DownloadURLWithToken(
|
||||
downloadURL, _ = e.show.client.DownloadURL(
|
||||
&papi.Episode{
|
||||
ShowEpisode: &polochon.ShowEpisode{
|
||||
ShowImdbID: e.ShowImdbID,
|
||||
@ -40,21 +46,20 @@ func (e *Episode) MarshalJSON() ([]byte, error) {
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
e.ShowEpisode.VideoMetadata = pEpisode.ShowEpisode.VideoMetadata
|
||||
e.ShowEpisode.File = pEpisode.ShowEpisode.File
|
||||
dateAdded = pEpisode.DateAdded
|
||||
quality = string(pEpisode.Quality)
|
||||
audioCodec = pEpisode.AudioCodec
|
||||
videoCodec = pEpisode.VideoCodec
|
||||
container = pEpisode.Container
|
||||
|
||||
// Append the Subtitles
|
||||
for _, s := range pEpisode.Subtitles {
|
||||
sub := subtitles.Subtitle{Subtitle: s.Subtitle}
|
||||
if !sub.Embedded {
|
||||
subtitleURL, _ := e.show.client.DownloadURLWithToken(s)
|
||||
sub.URL = subtitleURL
|
||||
sub.VVTFile = fmt.Sprintf(
|
||||
"/shows/%s/seasons/%d/episodes/%d/subtitles/%s",
|
||||
e.ShowImdbID, e.Season, e.Episode, s.Lang)
|
||||
}
|
||||
subs = append(subs, sub)
|
||||
for _, l := range pEpisode.Subtitles {
|
||||
subtitleURL, _ := e.show.client.SubtitleURL(pEpisode, l)
|
||||
subs = append(subs, subtitles.Subtitle{
|
||||
Language: l,
|
||||
URL: subtitleURL,
|
||||
VVTFile: fmt.Sprintf("/shows/%s/seasons/%d/episodes/%d/subtitles/%s", e.ShowImdbID, e.Season, e.Episode, l),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -64,11 +69,21 @@ func (e *Episode) MarshalJSON() ([]byte, error) {
|
||||
*alias
|
||||
PolochonURL string `json:"polochon_url"`
|
||||
Subtitles []subtitles.Subtitle `json:"subtitles"`
|
||||
DateAdded time.Time `json:"date_added"`
|
||||
Quality string `json:"quality"`
|
||||
AudioCodec string `json:"audio_codec"`
|
||||
VideoCodec string `json:"video_codec"`
|
||||
Container string `json:"container"`
|
||||
Thumb string `json:"thumb"`
|
||||
}{
|
||||
alias: (*alias)(e),
|
||||
PolochonURL: downloadURL,
|
||||
Subtitles: subs,
|
||||
DateAdded: dateAdded,
|
||||
Quality: quality,
|
||||
AudioCodec: audioCodec,
|
||||
VideoCodec: videoCodec,
|
||||
Container: container,
|
||||
Thumb: e.Thumb,
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"strconv"
|
||||
|
||||
"net/http"
|
||||
@ -34,15 +35,15 @@ func GetDetailsHandler(env *web.Env, w http.ResponseWriter, r *http.Request) err
|
||||
|
||||
pShow, err := client.GetShow(id)
|
||||
if err != nil && err != papi.ErrResourceNotFound {
|
||||
env.Log.Println("Got error getting show ", err)
|
||||
log.Println("Got error getting show ", err)
|
||||
}
|
||||
|
||||
wShow, err := models.IsShowWishlisted(env.Database, user.ID, id)
|
||||
if err != nil && err != papi.ErrResourceNotFound {
|
||||
env.Log.Println("Got error getting wishlisted show ", err)
|
||||
log.Println("Got error getting wishlisted show ", err)
|
||||
}
|
||||
|
||||
s := NewWithClient(id, client, pShow, wShow)
|
||||
s := NewWithClient(&polochon.Show{ImdbID: id}, client, pShow, wShow)
|
||||
// First try from the db
|
||||
first := []polochon.Detailer{env.Backend.Detailer}
|
||||
// Then try from the polochon detailers
|
||||
@ -80,15 +81,15 @@ func RefreshShowHandler(env *web.Env, w http.ResponseWriter, r *http.Request) er
|
||||
|
||||
pShow, err := client.GetShow(id)
|
||||
if err != nil && err != papi.ErrResourceNotFound {
|
||||
env.Log.Println("Got error getting show ", err)
|
||||
log.Println("Got error getting show ", err)
|
||||
}
|
||||
|
||||
wShow, err := models.IsShowWishlisted(env.Database, user.ID, id)
|
||||
if err != nil && err != papi.ErrResourceNotFound {
|
||||
env.Log.Println("Got error getting wishlisted show ", err)
|
||||
log.Println("Got error getting wishlisted show ", err)
|
||||
}
|
||||
|
||||
s := NewWithClient(id, client, pShow, wShow)
|
||||
s := NewWithClient(&polochon.Show{ImdbID: id}, client, pShow, wShow)
|
||||
// Refresh the polochon detailers
|
||||
detailers := env.Config.Show.Detailers
|
||||
err = s.Refresh(env, detailers)
|
||||
@ -162,7 +163,7 @@ func SearchShow(env *web.Env, w http.ResponseWriter, r *http.Request) error {
|
||||
for _, s := range shows {
|
||||
pShow, _ := pShows.Has(s.ImdbID)
|
||||
wShow, _ := wShows.IsShowInWishlist(s.ImdbID)
|
||||
show := NewWithClient(s.ImdbID, client, pShow, wShow)
|
||||
show := NewWithClient(s, client, pShow, wShow)
|
||||
|
||||
// First try from the db
|
||||
first := []polochon.Detailer{env.Backend.Detailer}
|
||||
@ -241,7 +242,8 @@ func GetWishlistHandler(env *web.Env, w http.ResponseWriter, r *http.Request) er
|
||||
showList := []*Show{}
|
||||
for _, wishedShow := range wShows.List() {
|
||||
pShow, _ := pShows.Has(wishedShow.ImdbID)
|
||||
show := NewWithClient(wishedShow.ImdbID, client, pShow, wishedShow)
|
||||
poloShow := &polochon.Show{ImdbID: wishedShow.ImdbID}
|
||||
show := NewWithClient(poloShow, client, pShow, wishedShow)
|
||||
|
||||
// First check in the DB
|
||||
before := []polochon.Detailer{env.Backend.Detailer}
|
||||
@ -307,7 +309,7 @@ func RefreshEpisodeHandler(env *web.Env, w http.ResponseWriter, r *http.Request)
|
||||
}
|
||||
|
||||
s := &Show{
|
||||
Show: pShow.Show,
|
||||
Show: &polochon.Show{ImdbID: id},
|
||||
client: client,
|
||||
pShow: pShow,
|
||||
}
|
||||
@ -341,7 +343,6 @@ func RefreshEpisodeHandler(env *web.Env, w http.ResponseWriter, r *http.Request)
|
||||
func RefreshEpisodeSubtitlesHandler(env *web.Env, w http.ResponseWriter, r *http.Request) error {
|
||||
vars := mux.Vars(r)
|
||||
id := vars["id"]
|
||||
lang := polochon.Language(vars["lang"])
|
||||
|
||||
// No need to check errors here as the router is making sure that season
|
||||
// and episode are numbers
|
||||
@ -365,35 +366,29 @@ func RefreshEpisodeSubtitlesHandler(env *web.Env, w http.ResponseWriter, r *http
|
||||
},
|
||||
}
|
||||
|
||||
sub, err := client.UpdateSubtitle(e, lang)
|
||||
refreshedSubs, err := client.UpdateSubtitles(e)
|
||||
if err != nil {
|
||||
return env.RenderError(w, err)
|
||||
}
|
||||
|
||||
// TODO: handle this with a better error
|
||||
if sub == nil {
|
||||
return env.RenderJSON(w, nil)
|
||||
}
|
||||
|
||||
url, err := client.DownloadURL(sub)
|
||||
if err != nil {
|
||||
return env.RenderError(w, err)
|
||||
}
|
||||
|
||||
s := &subtitles.Subtitle{
|
||||
Subtitle: sub.Subtitle,
|
||||
URL: url,
|
||||
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, s)
|
||||
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 := polochon.Language(vars["lang"])
|
||||
lang := vars["lang"]
|
||||
season, _ := strconv.Atoi(vars["season"])
|
||||
episode, _ := strconv.Atoi(vars["episode"])
|
||||
|
||||
@ -406,20 +401,13 @@ func DownloadVVTSubtitle(env *web.Env, w http.ResponseWriter, r *http.Request) e
|
||||
return env.RenderError(w, err)
|
||||
}
|
||||
|
||||
s := &papi.Subtitle{
|
||||
Subtitle: &polochon.Subtitle{
|
||||
Video: &papi.Episode{
|
||||
url, err := client.SubtitleURL(&papi.Episode{
|
||||
ShowEpisode: &polochon.ShowEpisode{
|
||||
ShowImdbID: id,
|
||||
Season: season,
|
||||
Episode: episode,
|
||||
},
|
||||
},
|
||||
Lang: lang,
|
||||
},
|
||||
}
|
||||
|
||||
url, err := client.DownloadURLWithToken(s)
|
||||
}, lang)
|
||||
if err != nil {
|
||||
return env.RenderError(w, err)
|
||||
}
|
||||
|
@ -62,14 +62,7 @@ func New(imdbID string) *Show {
|
||||
}
|
||||
|
||||
// NewWithClient returns a new Show with a polochon ShowConfig
|
||||
func NewWithClient(imdbID string, client *papi.Client, pShow *papi.Show, wShow *models.WishedShow) *Show {
|
||||
var show *polochon.Show
|
||||
if pShow == nil || pShow.Show == nil {
|
||||
show = &polochon.Show{ImdbID: imdbID}
|
||||
} else {
|
||||
show = pShow.Show
|
||||
}
|
||||
|
||||
func NewWithClient(show *polochon.Show, client *papi.Client, pShow *papi.Show, wShow *models.WishedShow) *Show {
|
||||
s := &Show{
|
||||
Show: show,
|
||||
client: client,
|
||||
@ -259,7 +252,7 @@ func getPolochonShows(env *web.Env, user *models.User) ([]*Show, error) {
|
||||
// Create Shows objects from the shows retrieved
|
||||
for _, pShow := range pshows.List() {
|
||||
wShow, _ := wShows.IsShowInWishlist(pShow.ImdbID)
|
||||
show := NewWithClient(pShow.ImdbID, client, pShow, wShow)
|
||||
show := NewWithClient(&polochon.Show{ImdbID: pShow.ImdbID}, client, pShow, wShow)
|
||||
shows = append(shows, show)
|
||||
}
|
||||
return shows, nil
|
||||
|
@ -1,10 +1,8 @@
|
||||
package subtitles
|
||||
|
||||
import polochon "github.com/odwrtw/polochon/lib"
|
||||
|
||||
// Subtitle represents a Subtitle
|
||||
type Subtitle struct {
|
||||
*polochon.Subtitle
|
||||
Language string `json:"language"`
|
||||
URL string `json:"url"`
|
||||
VVTFile string `json:"vvt_file"`
|
||||
}
|
||||
|
2
dev.sh
2
dev.sh
@ -135,7 +135,7 @@ case $1 in
|
||||
# Apply the migrations
|
||||
_migrate -path "$MIGRATION_SCHEMA" up
|
||||
|
||||
(cd backend && CONFIG_FILE="../config.yml" go run ./*.go)
|
||||
(cd backend && CONFIG_FILE="../config.yml" fresh -c fresh.conf)
|
||||
;;
|
||||
docker-db)
|
||||
_ensure_command docker
|
||||
|
@ -20,14 +20,10 @@ export function updateUser(data) {
|
||||
);
|
||||
}
|
||||
|
||||
export function deleteUser(username, userId) {
|
||||
export function deleteUser(username) {
|
||||
return request(
|
||||
"ADMIN_DELETE_USER",
|
||||
configureAxios().delete("/admins/users/" + username),
|
||||
null,
|
||||
{
|
||||
username,
|
||||
id: userId,
|
||||
}
|
||||
[() => getUsers()]
|
||||
);
|
||||
}
|
||||
|
@ -1,25 +1,24 @@
|
||||
import { configureAxios, request } from "../requests";
|
||||
|
||||
export const searchMovieSubtitle = (imdbId, lang) => {
|
||||
export const searchMovieSubtitles = (imdbId) => {
|
||||
return request(
|
||||
"MOVIE_SUBTITLES_UPDATE",
|
||||
configureAxios().post(`/movies/${imdbId}/subtitles/${lang}`),
|
||||
configureAxios().post(`/movies/${imdbId}/subtitles/refresh`),
|
||||
null,
|
||||
{ imdbId, lang }
|
||||
{ imdbId: imdbId }
|
||||
);
|
||||
};
|
||||
|
||||
export const searchEpisodeSubtitle = (imdbId, season, episode, lang) => {
|
||||
export const searchEpisodeSubtitles = (imdbId, season, episode) => {
|
||||
const url = `/shows/${imdbId}/seasons/${season}/episodes/${episode}`;
|
||||
return request(
|
||||
"EPISODE_SUBTITLES_UPDATE",
|
||||
configureAxios().post(`${url}/subtitles/${lang}`),
|
||||
configureAxios().post(`${url}/subtitles/refresh`),
|
||||
null,
|
||||
{
|
||||
imdbId,
|
||||
season,
|
||||
episode,
|
||||
lang,
|
||||
imdbId: imdbId,
|
||||
season: season,
|
||||
episode: episode,
|
||||
}
|
||||
);
|
||||
};
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React from "react";
|
||||
import React, { useEffect } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { getAdminModules } from "../../actions/admins";
|
||||
|
||||
@ -10,15 +10,9 @@ export const AdminModules = () => {
|
||||
const loading = useSelector((state) => state.admin.fetchingModules);
|
||||
const modules = useSelector((state) => state.admin.modules);
|
||||
|
||||
const fetchModules = () => {
|
||||
useEffect(() => {
|
||||
dispatch(getAdminModules());
|
||||
};
|
||||
}, [dispatch]);
|
||||
|
||||
return (
|
||||
<Modules
|
||||
modules={modules}
|
||||
isLoading={loading}
|
||||
fetchModules={fetchModules}
|
||||
/>
|
||||
);
|
||||
return <Modules modules={modules} isLoading={loading} />;
|
||||
};
|
||||
|
@ -51,7 +51,7 @@ export const UserEdit = ({ id }) => {
|
||||
e.preventDefault();
|
||||
}
|
||||
if (confirmDelete) {
|
||||
dispatch(deleteUser(user.name, id));
|
||||
dispatch(deleteUser(name));
|
||||
setModal(false);
|
||||
} else {
|
||||
setConfirmDelete(true);
|
||||
|
@ -18,7 +18,7 @@ export const DownloadAndStream = ({ url, name, subtitles }) => {
|
||||
DownloadAndStream.propTypes = {
|
||||
url: PropTypes.string,
|
||||
name: PropTypes.string,
|
||||
subtitles: PropTypes.object,
|
||||
subtitles: PropTypes.array,
|
||||
};
|
||||
|
||||
const DownloadButton = ({ url }) => (
|
||||
@ -67,18 +67,19 @@ const StreamButton = ({ name, url, subtitles }) => {
|
||||
StreamButton.propTypes = {
|
||||
name: PropTypes.string.isRequired,
|
||||
url: PropTypes.string.isRequired,
|
||||
subtitles: PropTypes.object,
|
||||
subtitles: PropTypes.array,
|
||||
};
|
||||
|
||||
const Player = ({ url, subtitles }) => {
|
||||
const subs = subtitles || [];
|
||||
|
||||
return (
|
||||
<div className="embed-responsive embed-responsive-16by9">
|
||||
<video className="embed-responsive-item" controls>
|
||||
<source src={url} type="video/mp4" />
|
||||
{subtitles &&
|
||||
[...subtitles.entries()].map(([lang, sub]) => (
|
||||
{subs.map((sub, index) => (
|
||||
<track
|
||||
key={lang}
|
||||
key={index}
|
||||
kind="subtitles"
|
||||
label={sub.language}
|
||||
src={sub.vvt_file}
|
||||
@ -90,6 +91,6 @@ const Player = ({ url, subtitles }) => {
|
||||
);
|
||||
};
|
||||
Player.propTypes = {
|
||||
subtitles: PropTypes.object,
|
||||
subtitles: PropTypes.array,
|
||||
url: PropTypes.string.isRequired,
|
||||
};
|
||||
|
@ -3,22 +3,25 @@ import PropTypes from "prop-types";
|
||||
|
||||
import Dropdown from "react-bootstrap/Dropdown";
|
||||
|
||||
import { prettySize, upperCaseFirst } from "../../utils";
|
||||
|
||||
export const SubtitlesButton = ({
|
||||
subtitles,
|
||||
inLibrary,
|
||||
searching,
|
||||
search,
|
||||
fetchingSubtitles,
|
||||
}) => {
|
||||
if (inLibrary === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/* eslint-disable */
|
||||
const [show, setShow] = useState(false);
|
||||
/* eslint-enable */
|
||||
|
||||
const onSelect = (eventKey) => {
|
||||
if (eventKey === null || eventKey != 1) {
|
||||
setShow(false);
|
||||
}
|
||||
};
|
||||
|
||||
const onToggle = (isOpen, event, metadata) => {
|
||||
// Don't close on select
|
||||
if (metadata && metadata.source !== "select") {
|
||||
@ -26,20 +29,10 @@ export const SubtitlesButton = ({
|
||||
}
|
||||
};
|
||||
|
||||
const searchAll = () => {
|
||||
const langs = ["fr_FR", "en_US"];
|
||||
for (const lang of langs) {
|
||||
search(lang);
|
||||
}
|
||||
};
|
||||
|
||||
const count = subtitles && subtitles.size !== 0 ? subtitles.size : 0;
|
||||
|
||||
const searching = fetchingSubtitles.length > 0;
|
||||
|
||||
const count = subtitles && subtitles.length !== 0 ? subtitles.length : 0;
|
||||
return (
|
||||
<span className="mr-1 mb-1">
|
||||
<Dropdown drop="up" show={show} onToggle={onToggle}>
|
||||
<Dropdown drop="up" show={show} onToggle={onToggle} onSelect={onSelect}>
|
||||
<Dropdown.Toggle variant="secondary" bsPrefix="btn-sm w-md-100">
|
||||
<i className="fa fa-commenting mr-1" />
|
||||
Subtitles
|
||||
@ -47,13 +40,9 @@ export const SubtitlesButton = ({
|
||||
</Dropdown.Toggle>
|
||||
|
||||
<Dropdown.Menu>
|
||||
<Dropdown.Item eventKey={1} onClick={searchAll}>
|
||||
<div className="d-flex justify-content-between align-items-center">
|
||||
<span>Automatic search</span>
|
||||
<div
|
||||
className={`fa ${searching ? "fa-spin" : ""} fa-refresh ml-1`}
|
||||
/>
|
||||
</div>
|
||||
<Dropdown.Item eventKey={1} onClick={search}>
|
||||
<i className={`fa ${searching ? "fa-spin" : ""} fa-refresh mr-1`} />
|
||||
Automatic search
|
||||
</Dropdown.Item>
|
||||
{count > 0 && (
|
||||
<React.Fragment>
|
||||
@ -64,13 +53,10 @@ export const SubtitlesButton = ({
|
||||
</React.Fragment>
|
||||
)}
|
||||
{count > 0 &&
|
||||
[...subtitles.entries()].map(([lang, subtitle]) => (
|
||||
<SubtitleEntry
|
||||
key={lang}
|
||||
subtitle={subtitle}
|
||||
searching={searching}
|
||||
search={search}
|
||||
/>
|
||||
subtitles.map((subtitle, index) => (
|
||||
<Dropdown.Item href={subtitle.url} key={index}>
|
||||
{subtitle.language.split("_")[1]}
|
||||
</Dropdown.Item>
|
||||
))}
|
||||
</Dropdown.Menu>
|
||||
</Dropdown>
|
||||
@ -78,42 +64,8 @@ export const SubtitlesButton = ({
|
||||
);
|
||||
};
|
||||
SubtitlesButton.propTypes = {
|
||||
subtitles: PropTypes.object,
|
||||
subtitles: PropTypes.array,
|
||||
inLibrary: PropTypes.bool.isRequired,
|
||||
fetchingSubtitles: PropTypes.array.isRequired,
|
||||
searching: PropTypes.bool.isRequired,
|
||||
search: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export const SubtitleEntry = ({ subtitle, search }) => {
|
||||
const lang = upperCaseFirst(subtitle.lang.split("_")[0]);
|
||||
const size = subtitle.size ? subtitle.size : 0;
|
||||
const embedded = subtitle.embedded ? subtitle.embedded : false;
|
||||
|
||||
const handleRefresh = () => {
|
||||
search(subtitle.lang);
|
||||
};
|
||||
|
||||
return (
|
||||
<Dropdown.Item as="span" disabled={embedded}>
|
||||
<div className="d-flex justify-content-between align-items-center">
|
||||
<a href={subtitle.url ? subtitle.url : ""} className="link-unstyled">
|
||||
{lang}
|
||||
{embedded && <small className="ml-2">(Inside the video)</small>}
|
||||
{size !== 0 && <span> ({prettySize(size)})</span>}
|
||||
</a>
|
||||
{!embedded && (
|
||||
<div
|
||||
onClick={handleRefresh}
|
||||
className={`clickable fa ${
|
||||
subtitle.searching ? "fa-spin" : ""
|
||||
} fa-refresh`}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</Dropdown.Item>
|
||||
);
|
||||
};
|
||||
SubtitleEntry.propTypes = {
|
||||
search: PropTypes.func.isRequired,
|
||||
subtitle: PropTypes.object,
|
||||
};
|
||||
|
@ -1,23 +1,18 @@
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import { prettySize } from "../../utils";
|
||||
|
||||
export const PolochonMetadata = ({
|
||||
quality,
|
||||
container,
|
||||
videoCodec,
|
||||
audioCodec,
|
||||
releaseGroup,
|
||||
size,
|
||||
}) => {
|
||||
if (!quality || quality === "") {
|
||||
return null;
|
||||
}
|
||||
|
||||
const s = size === 0 ? "" : prettySize(size);
|
||||
|
||||
const metadata = [quality, container, videoCodec, audioCodec, releaseGroup, s]
|
||||
const metadata = [quality, container, videoCodec, audioCodec, releaseGroup]
|
||||
.filter((m) => m && m !== "")
|
||||
.join(", ");
|
||||
|
||||
@ -34,5 +29,4 @@ PolochonMetadata.propTypes = {
|
||||
videoCodec: PropTypes.string,
|
||||
audioCodec: PropTypes.string,
|
||||
releaseGroup: PropTypes.string,
|
||||
size: PropTypes.number,
|
||||
};
|
||||
|
@ -53,7 +53,6 @@ const ListDetails = (props) => {
|
||||
container={props.data.container}
|
||||
audioCodec={props.data.audio_codec}
|
||||
videoCodec={props.data.video_codec}
|
||||
size={props.data.size}
|
||||
/>
|
||||
<Plot plot={props.data.plot} />
|
||||
{props.children}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { useState } from "react";
|
||||
import React from "react";
|
||||
import Loader from "../loader/loader";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
@ -7,29 +7,11 @@ import { upperCaseFirst } from "../../utils";
|
||||
// TODO: udpate this
|
||||
import { OverlayTrigger, Tooltip } from "react-bootstrap";
|
||||
|
||||
const Modules = ({ isLoading, modules, fetchModules }) => {
|
||||
const [show, setShow] = useState(false);
|
||||
const Modules = ({ isLoading, modules }) => {
|
||||
if (isLoading) {
|
||||
return <Loader />;
|
||||
}
|
||||
|
||||
const handleClick = () => {
|
||||
fetchModules();
|
||||
setShow(true);
|
||||
};
|
||||
|
||||
if (!show) {
|
||||
return (
|
||||
<div className="row">
|
||||
<div className="col-12 col-md-8 offset-md-2 mb-3">
|
||||
<div className="btn btn-secondary w-100" onClick={handleClick}>
|
||||
Show modules status
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="row">
|
||||
{Object.keys(modules).map((type) => (
|
||||
@ -41,7 +23,6 @@ const Modules = ({ isLoading, modules, fetchModules }) => {
|
||||
Modules.propTypes = {
|
||||
isLoading: PropTypes.bool.isRequired,
|
||||
modules: PropTypes.object.isRequired,
|
||||
fetchModules: PropTypes.func.isRequired,
|
||||
};
|
||||
export default Modules;
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
|
||||
import { searchMovieSubtitle } from "../../actions/subtitles";
|
||||
import { searchMovieSubtitles } from "../../actions/subtitles";
|
||||
|
||||
import { SubtitlesButton } from "../buttons/subtitles";
|
||||
|
||||
@ -15,16 +15,16 @@ export const MovieSubtitlesButton = () => {
|
||||
const subtitles = useSelector(
|
||||
(state) => state.movies.movies.get(imdbId).subtitles
|
||||
);
|
||||
const fetchingSubtitles = useSelector(
|
||||
const searching = useSelector(
|
||||
(state) => state.movies.movies.get(imdbId).fetchingSubtitles
|
||||
);
|
||||
|
||||
return (
|
||||
<SubtitlesButton
|
||||
inLibrary={inLibrary}
|
||||
fetchingSubtitles={fetchingSubtitles}
|
||||
searching={searching}
|
||||
subtitles={subtitles}
|
||||
search={(lang) => dispatch(searchMovieSubtitle(imdbId, lang))}
|
||||
search={() => dispatch(searchMovieSubtitles(imdbId))}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
@ -74,7 +74,6 @@ export const Episode = ({ season, episode }) => {
|
||||
container={data.container}
|
||||
audioCodec={data.audio_codec}
|
||||
videoCodec={data.video_codec}
|
||||
size={data.size}
|
||||
light
|
||||
/>
|
||||
<ShowMore
|
||||
|
@ -2,7 +2,7 @@ import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
|
||||
import { searchEpisodeSubtitle } from "../../../actions/subtitles";
|
||||
import { searchEpisodeSubtitles } from "../../../actions/subtitles";
|
||||
|
||||
import { SubtitlesButton } from "../../buttons/subtitles";
|
||||
|
||||
@ -10,27 +10,30 @@ export const EpisodeSubtitlesButton = ({ season, episode }) => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const imdbId = useSelector((state) => state.show.show.imdb_id);
|
||||
const fetchingSubtitles = useSelector(
|
||||
(state) =>
|
||||
const searching = useSelector((state) =>
|
||||
state.show.show.seasons.get(season).get(episode).fetchingSubtitles
|
||||
? state.show.show.seasons.get(season).get(episode).fetchingSubtitles
|
||||
: false
|
||||
);
|
||||
const inLibrary = useSelector(
|
||||
(state) =>
|
||||
state.show.show.seasons.get(season).get(episode).polochon_url !== ""
|
||||
);
|
||||
const subtitles = useSelector(
|
||||
(state) => state.show.show.seasons.get(season).get(episode).subtitles
|
||||
const subtitles = useSelector((state) =>
|
||||
state.show.show.seasons.get(season).get(episode).subtitles
|
||||
? state.show.show.seasons.get(season).get(episode).subtitles
|
||||
: []
|
||||
);
|
||||
|
||||
const search = (lang) => {
|
||||
dispatch(searchEpisodeSubtitle(imdbId, season, episode, lang));
|
||||
const search = () => {
|
||||
dispatch(searchEpisodeSubtitles(imdbId, season, episode));
|
||||
};
|
||||
|
||||
return (
|
||||
<SubtitlesButton
|
||||
subtitles={subtitles}
|
||||
inLibrary={inLibrary}
|
||||
fetchingSubtitles={fetchingSubtitles}
|
||||
searching={searching}
|
||||
search={search}
|
||||
/>
|
||||
);
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React from "react";
|
||||
import React, { useEffect } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
|
||||
import { PolochonList } from "../polochons/list";
|
||||
@ -12,19 +12,15 @@ export const UserProfile = () => {
|
||||
const modules = useSelector((state) => state.user.modules);
|
||||
const modulesLoading = useSelector((state) => state.user.modulesLoading);
|
||||
|
||||
const fetchModules = () => {
|
||||
useEffect(() => {
|
||||
dispatch(getUserModules());
|
||||
};
|
||||
}, [dispatch]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<UserEdit />
|
||||
<PolochonList />
|
||||
<Modules
|
||||
modules={modules}
|
||||
isLoading={modulesLoading}
|
||||
fetchModules={fetchModules}
|
||||
/>
|
||||
<Modules modules={modules} isLoading={modulesLoading} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -17,11 +17,6 @@ export default (state = defaultState, action) =>
|
||||
break;
|
||||
}
|
||||
|
||||
case "ADMIN_DELETE_USER_FULFILLED": {
|
||||
draft.users.delete(action.payload.main.id);
|
||||
break;
|
||||
}
|
||||
|
||||
case "ADMIN_GET_STATS_FULFILLED": {
|
||||
draft.stats = action.payload.response.data;
|
||||
break;
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { produce } from "immer";
|
||||
|
||||
import { formatTorrents } from "../utils";
|
||||
import { formatSubtitle, formatSubtitles } from "./utils";
|
||||
|
||||
const defaultState = {
|
||||
loading: false,
|
||||
@ -13,9 +12,8 @@ const defaultState = {
|
||||
|
||||
const formatMovie = (movie) => {
|
||||
movie.fetchingDetails = false;
|
||||
movie.fetchingSubtitles = [];
|
||||
movie.fetchingSubtitles = false;
|
||||
movie.torrents = formatTorrents(movie);
|
||||
movie.subtitles = formatSubtitles(movie.subtitles);
|
||||
return movie;
|
||||
};
|
||||
|
||||
@ -89,28 +87,15 @@ export default (state = defaultState, action) =>
|
||||
draft.lastFetchUrl = action.payload.url;
|
||||
break;
|
||||
|
||||
case "MOVIE_SUBTITLES_UPDATE_PENDING": {
|
||||
let imdbId = action.payload.main.imdbId;
|
||||
let lang = action.payload.main.lang;
|
||||
draft.movies.get(imdbId).fetchingSubtitles.push(lang);
|
||||
if (draft.movies.get(imdbId).subtitles.get(lang)) {
|
||||
draft.movies.get(imdbId).subtitles.get(lang).searching = true;
|
||||
}
|
||||
case "MOVIE_SUBTITLES_UPDATE_PENDING":
|
||||
draft.movies.get(action.payload.main.imdbId).fetchingSubtitles = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case "MOVIE_SUBTITLES_UPDATE_FULFILLED": {
|
||||
let imdbId = action.payload.main.imdbId;
|
||||
let lang = action.payload.main.lang;
|
||||
let data = action.payload.response.data;
|
||||
draft.movies.get(imdbId).fetchingSubtitles = draft.movies
|
||||
.get(imdbId)
|
||||
.fetchingSubtitles.filter((l) => l != lang);
|
||||
if (data) {
|
||||
draft.movies.get(imdbId).subtitles.set(lang, formatSubtitle(data));
|
||||
}
|
||||
case "MOVIE_SUBTITLES_UPDATE_FULFILLED":
|
||||
draft.movies.get(action.payload.main.imdbId).fetchingSubtitles = false;
|
||||
draft.movies.get(action.payload.main.imdbId).subtitles =
|
||||
action.payload.response.data;
|
||||
break;
|
||||
}
|
||||
|
||||
case "SELECT_MOVIE":
|
||||
draft.selectedImdbId = action.payload.imdbId;
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { produce } from "immer";
|
||||
|
||||
import { formatTorrents } from "../utils";
|
||||
import { formatSubtitle, formatSubtitles } from "./utils";
|
||||
|
||||
const defaultState = {
|
||||
loading: false,
|
||||
@ -11,12 +10,10 @@ const defaultState = {
|
||||
const formatEpisode = (episode) => {
|
||||
// Format the episode's torrents
|
||||
episode.torrents = formatTorrents(episode);
|
||||
episode.subtitles = formatSubtitles(episode.subtitles);
|
||||
|
||||
// Set the default fetching data
|
||||
episode.fetching = false;
|
||||
// Holds the languages of the subtitles currently fetching
|
||||
episode.fetchingSubtitles = [];
|
||||
episode.fetchingSubtitles = false;
|
||||
};
|
||||
|
||||
export default (state = defaultState, action) =>
|
||||
@ -101,42 +98,22 @@ export default (state = defaultState, action) =>
|
||||
break;
|
||||
}
|
||||
|
||||
case "EPISODE_SUBTITLES_UPDATE_PENDING": {
|
||||
let season = action.payload.main.season;
|
||||
let episode = action.payload.main.episode;
|
||||
let lang = action.payload.main.lang;
|
||||
case "EPISODE_SUBTITLES_UPDATE_PENDING":
|
||||
draft.show.seasons
|
||||
.get(season)
|
||||
.get(episode)
|
||||
.fetchingSubtitles.push(lang);
|
||||
if (draft.show.seasons.get(season).get(episode).subtitles.get(lang)) {
|
||||
draft.show.seasons
|
||||
.get(season)
|
||||
.get(episode)
|
||||
.subtitles.get(lang).searching = true;
|
||||
}
|
||||
.get(action.payload.main.season)
|
||||
.get(action.payload.main.episode).fetchingSubtitles = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case "EPISODE_SUBTITLES_UPDATE_FULFILLED": {
|
||||
let season = action.payload.main.season;
|
||||
let episode = action.payload.main.episode;
|
||||
let lang = action.payload.main.lang;
|
||||
let data = action.payload.response.data;
|
||||
draft.show.seasons.get(season).get(episode).fetchingSubtitles =
|
||||
draft.show.seasons
|
||||
.get(season)
|
||||
.get(episode)
|
||||
.fetchingSubtitles.filter((l) => l != lang);
|
||||
if (data) {
|
||||
.get(action.payload.main.season)
|
||||
.get(action.payload.main.episode).subtitles =
|
||||
action.payload.response.data;
|
||||
draft.show.seasons
|
||||
.get(season)
|
||||
.get(episode)
|
||||
.subtitles.set(lang, formatSubtitle(data));
|
||||
}
|
||||
.get(action.payload.main.season)
|
||||
.get(action.payload.main.episode).fetchingSubtitles = false;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return draft;
|
||||
}
|
||||
|
@ -1,22 +0,0 @@
|
||||
export const formatSubtitles = (subtitles) => {
|
||||
if (!subtitles || subtitles.length == 0) {
|
||||
return new Map();
|
||||
}
|
||||
|
||||
let map = new Map();
|
||||
subtitles.forEach((subtitle) => {
|
||||
subtitle = formatSubtitle(subtitle);
|
||||
map.set(subtitle.lang, subtitle);
|
||||
});
|
||||
|
||||
return map;
|
||||
};
|
||||
|
||||
export const formatSubtitle = (subtitle) => {
|
||||
if (!subtitle) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
subtitle.searching = false;
|
||||
return subtitle;
|
||||
};
|
@ -146,8 +146,3 @@ div.sweet-alert > h2 {
|
||||
.toast {
|
||||
background-color: $card-bg;
|
||||
}
|
||||
|
||||
.link-unstyled, .link-unstyled:link, .link-unstyled:hover {
|
||||
color: inherit;
|
||||
text-decoration: inherit;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user