commit
bc223da3d0
@ -16,6 +16,7 @@
|
|||||||
"react": "^15.3.2",
|
"react": "^15.3.2",
|
||||||
"react-bootstrap": "^0.30.6",
|
"react-bootstrap": "^0.30.6",
|
||||||
"react-dom": "^15.3.2",
|
"react-dom": "^15.3.2",
|
||||||
|
"react-loading": "^0.0.9",
|
||||||
"react-redux": "^4.4.6",
|
"react-redux": "^4.4.6",
|
||||||
"react-redux-form": "^1.2.4",
|
"react-redux-form": "^1.2.4",
|
||||||
"react-router": "^3.0.0",
|
"react-router": "^3.0.0",
|
||||||
|
@ -2,11 +2,14 @@ package extmedias
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"gitlab.quimbo.fr/odwrtw/canape-sql/src/internal/auth"
|
||||||
"gitlab.quimbo.fr/odwrtw/canape-sql/src/internal/movies"
|
"gitlab.quimbo.fr/odwrtw/canape-sql/src/internal/movies"
|
||||||
"gitlab.quimbo.fr/odwrtw/canape-sql/src/internal/shows"
|
"gitlab.quimbo.fr/odwrtw/canape-sql/src/internal/shows"
|
||||||
|
"gitlab.quimbo.fr/odwrtw/canape-sql/src/internal/users"
|
||||||
|
|
||||||
"gitlab.quimbo.fr/odwrtw/canape-sql/src/internal/web"
|
"gitlab.quimbo.fr/odwrtw/canape-sql/src/internal/web"
|
||||||
|
|
||||||
@ -89,12 +92,19 @@ func GetMediaIDs(env *web.Env, mediaType string, source string, category string,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetMovies get some movies
|
// GetMovies get some movies
|
||||||
func GetMovies(env *web.Env, source string, category string, force bool) ([]*movies.Movie, error) {
|
func GetMovies(env *web.Env, user *users.User, source string, category string, force bool) ([]*movies.Movie, error) {
|
||||||
movieIds, err := GetMediaIDs(env, "movie", source, category, force)
|
movieIds, err := GetMediaIDs(env, "movie", source, category, force)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the URLs from polochon, we don't really care if it fails for now
|
||||||
|
var urls map[string]string
|
||||||
|
urls, err = movies.GetPolochonMoviesURLs(user)
|
||||||
|
if err != nil {
|
||||||
|
env.Log.Errorf("error while getting polochon movies url: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
movieList := []*movies.Movie{}
|
movieList := []*movies.Movie{}
|
||||||
for _, id := range movieIds {
|
for _, id := range movieIds {
|
||||||
movie := movies.New(id)
|
movie := movies.New(id)
|
||||||
@ -108,6 +118,13 @@ func GetMovies(env *web.Env, source string, category string, force bool) ([]*mov
|
|||||||
env.Log.Errorf("error while getting movie torrents : %s", err)
|
env.Log.Errorf("error while getting movie torrents : %s", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if urls != nil {
|
||||||
|
if url, ok := urls[id]; ok {
|
||||||
|
movie.PolochonURL = url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
movieList = append(movieList, movie)
|
movieList = append(movieList, movie)
|
||||||
}
|
}
|
||||||
return movieList, nil
|
return movieList, nil
|
||||||
@ -157,10 +174,16 @@ func Explore(env *web.Env, w http.ResponseWriter, r *http.Request) error {
|
|||||||
category = "popular"
|
category = "popular"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
v := auth.GetCurrentUser(r, env.Log)
|
||||||
|
user, ok := v.(*users.User)
|
||||||
|
if !ok {
|
||||||
|
return env.RenderError(w, errors.New("invalid user"))
|
||||||
|
}
|
||||||
|
|
||||||
// Get the medias without trying to refresh them
|
// Get the medias without trying to refresh them
|
||||||
movies, err := GetMovies(env, source, category, false)
|
movies, err := GetMovies(env, user, source, category, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return env.RenderError(w, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return env.RenderJSON(w, movies)
|
return env.RenderJSON(w, movies)
|
||||||
@ -188,7 +211,7 @@ func ExploreShows(env *web.Env, w http.ResponseWriter, r *http.Request) error {
|
|||||||
// Get the medias without trying to refresh them
|
// Get the medias without trying to refresh them
|
||||||
shows, err := GetShows(env, source, category, false)
|
shows, err := GetShows(env, source, category, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return env.RenderError(w, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return env.RenderJSON(w, shows)
|
return env.RenderJSON(w, shows)
|
||||||
@ -218,13 +241,19 @@ func Refresh(env *web.Env, w http.ResponseWriter, r *http.Request) error {
|
|||||||
category = "popular"
|
category = "popular"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
v := auth.GetCurrentUser(r, env.Log)
|
||||||
|
user, ok := v.(*users.User)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("invalid user type")
|
||||||
|
}
|
||||||
|
|
||||||
// We'll refresh the medias for each sources
|
// We'll refresh the medias for each sources
|
||||||
for _, source := range MediaSources {
|
for _, source := range MediaSources {
|
||||||
env.Log.Debugf("refreshing %s", source)
|
env.Log.Debugf("refreshing %s", source)
|
||||||
// GetMedias and refresh them
|
// GetMedias and refresh them
|
||||||
_, err := GetMovies(env, source, category, true)
|
_, err := GetMovies(env, user, source, category, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return env.RenderError(w, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -250,7 +279,7 @@ func RefreshShows(env *web.Env, w http.ResponseWriter, r *http.Request) error {
|
|||||||
// GetMedias and refresh them
|
// GetMedias and refresh them
|
||||||
_, err := GetShows(env, source, category, true)
|
_, err := GetShows(env, source, category, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return env.RenderError(w, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package movies
|
package movies
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
@ -63,6 +64,21 @@ func getPolochonMovies(user *users.User) ([]*Movie, error) {
|
|||||||
return movies, nil
|
return movies, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetPolochonMoviesURLs returns the polochon urls associated with an imdb id
|
||||||
|
func GetPolochonMoviesURLs(user *users.User) (map[string]string, error) {
|
||||||
|
movies, err := getPolochonMovies(user)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
urls := make(map[string]string, len(movies))
|
||||||
|
for _, movie := range movies {
|
||||||
|
urls[movie.ImdbID] = movie.PolochonURL
|
||||||
|
}
|
||||||
|
|
||||||
|
return urls, nil
|
||||||
|
}
|
||||||
|
|
||||||
// FromPolochon will returns movies from Polochon
|
// FromPolochon will returns movies from Polochon
|
||||||
func FromPolochon(env *web.Env, w http.ResponseWriter, r *http.Request) error {
|
func FromPolochon(env *web.Env, w http.ResponseWriter, r *http.Request) error {
|
||||||
v := auth.GetCurrentUser(r, env.Log)
|
v := auth.GetCurrentUser(r, env.Log)
|
||||||
@ -113,15 +129,28 @@ func GetDetailsHandler(env *web.Env, w http.ResponseWriter, r *http.Request) err
|
|||||||
|
|
||||||
// SearchMovie will search movie
|
// SearchMovie will search movie
|
||||||
func SearchMovie(env *web.Env, w http.ResponseWriter, r *http.Request) error {
|
func SearchMovie(env *web.Env, w http.ResponseWriter, r *http.Request) error {
|
||||||
key := r.FormValue("key")
|
var data struct {
|
||||||
if key == "" {
|
Key string `json:"key"`
|
||||||
|
}
|
||||||
|
err := json.NewDecoder(r.Body).Decode(&data)
|
||||||
|
if err != nil {
|
||||||
|
return env.RenderError(w, errors.New("failed to get the search key"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if data.Key == "" {
|
||||||
return env.RenderError(w, errors.New("no given key"))
|
return env.RenderError(w, errors.New("no given key"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
v := auth.GetCurrentUser(r, env.Log)
|
||||||
|
user, ok := v.(*users.User)
|
||||||
|
if !ok {
|
||||||
|
return env.RenderError(w, errors.New("invalid user"))
|
||||||
|
}
|
||||||
|
|
||||||
var movies []*polochon.Movie
|
var movies []*polochon.Movie
|
||||||
searchers := env.Config.MovieSearchers
|
searchers := env.Config.MovieSearchers
|
||||||
for _, searcher := range searchers {
|
for _, searcher := range searchers {
|
||||||
result, err := searcher.SearchMovie(key, env.Log)
|
result, err := searcher.SearchMovie(data.Key, env.Log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
env.Log.Errorf("error while searching movie : %s", err)
|
env.Log.Errorf("error while searching movie : %s", err)
|
||||||
continue
|
continue
|
||||||
@ -129,7 +158,14 @@ func SearchMovie(env *web.Env, w http.ResponseWriter, r *http.Request) error {
|
|||||||
movies = append(movies, result...)
|
movies = append(movies, result...)
|
||||||
}
|
}
|
||||||
|
|
||||||
env.Log.Debugf("got %d movies doing search %q", len(movies), key)
|
// Get the URLs from polochon, we don't really care if it fails for now
|
||||||
|
var urls map[string]string
|
||||||
|
urls, err = GetPolochonMoviesURLs(user)
|
||||||
|
if err != nil {
|
||||||
|
env.Log.Errorf("error while getting polochon movies url: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
env.Log.Debugf("got %d movies doing search %q", len(movies), data.Key)
|
||||||
movieList := []*Movie{}
|
movieList := []*Movie{}
|
||||||
for _, m := range movies {
|
for _, m := range movies {
|
||||||
movie := New(m.ImdbID)
|
movie := New(m.ImdbID)
|
||||||
@ -143,6 +179,13 @@ func SearchMovie(env *web.Env, w http.ResponseWriter, r *http.Request) error {
|
|||||||
env.Log.Errorf("error while getting movie torrents : %s", err)
|
env.Log.Errorf("error while getting movie torrents : %s", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if urls != nil {
|
||||||
|
if url, ok := urls[m.ImdbID]; ok {
|
||||||
|
movie.PolochonURL = url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
movieList = append(movieList, movie)
|
movieList = append(movieList, movie)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package shows
|
package shows
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
@ -27,15 +28,21 @@ func GetDetailsHandler(env *web.Env, w http.ResponseWriter, r *http.Request) err
|
|||||||
|
|
||||||
// SearchShow will search a show
|
// SearchShow will search a show
|
||||||
func SearchShow(env *web.Env, w http.ResponseWriter, r *http.Request) error {
|
func SearchShow(env *web.Env, w http.ResponseWriter, r *http.Request) error {
|
||||||
key := r.FormValue("key")
|
var data struct {
|
||||||
if key == "" {
|
Key string `json:"key"`
|
||||||
|
}
|
||||||
|
if err := json.NewDecoder(r.Body).Decode(&data); err != nil {
|
||||||
|
return env.RenderError(w, errors.New("failed to get the search key"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if data.Key == "" {
|
||||||
return env.RenderError(w, errors.New("no given key"))
|
return env.RenderError(w, errors.New("no given key"))
|
||||||
}
|
}
|
||||||
|
|
||||||
var shows []*polochon.Show
|
var shows []*polochon.Show
|
||||||
searchers := env.Config.ShowSearchers
|
searchers := env.Config.ShowSearchers
|
||||||
for _, searcher := range searchers {
|
for _, searcher := range searchers {
|
||||||
result, err := searcher.SearchShow(key, env.Log)
|
result, err := searcher.SearchShow(data.Key, env.Log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
env.Log.Errorf("error while searching show : %s", err)
|
env.Log.Errorf("error while searching show : %s", err)
|
||||||
continue
|
continue
|
||||||
@ -43,7 +50,7 @@ func SearchShow(env *web.Env, w http.ResponseWriter, r *http.Request) error {
|
|||||||
shows = append(shows, result...)
|
shows = append(shows, result...)
|
||||||
}
|
}
|
||||||
|
|
||||||
env.Log.Debugf("got %d shows doing search %q", len(shows), key)
|
env.Log.Debugf("got %d shows doing search %q", len(shows), data.Key)
|
||||||
showList := []*Show{}
|
showList := []*Show{}
|
||||||
for _, s := range shows {
|
for _, s := range shows {
|
||||||
show := New(s.ImdbID)
|
show := New(s.ImdbID)
|
||||||
|
24
src/main.go
24
src/main.go
@ -71,22 +71,24 @@ func main() {
|
|||||||
|
|
||||||
authMiddleware := auth.NewMiddleware(env.Auth, log)
|
authMiddleware := auth.NewMiddleware(env.Auth, log)
|
||||||
|
|
||||||
|
// TODO: refresh sould be handled by admins only
|
||||||
|
|
||||||
env.Handle("/users/login", users.LoginPOSTHandler).Methods("POST")
|
env.Handle("/users/login", users.LoginPOSTHandler).Methods("POST")
|
||||||
env.Handle("/users/signup", users.SignupPOSTHandler).Methods("POST")
|
env.Handle("/users/signup", users.SignupPOSTHandler).Methods("POST")
|
||||||
env.Handle("/users/details", users.DetailsHandler).WithRole(users.UserRole)
|
env.Handle("/users/details", users.DetailsHandler).WithRole(users.UserRole).Methods("GET")
|
||||||
env.Handle("/users/edit", users.EditHandler).WithRole(users.UserRole)
|
env.Handle("/users/edit", users.EditHandler).WithRole(users.UserRole).Methods("POST")
|
||||||
|
|
||||||
env.Handle("/movies/polochon", movies.FromPolochon).WithRole(users.UserRole)
|
env.Handle("/movies/polochon", movies.FromPolochon).WithRole(users.UserRole).Methods("GET")
|
||||||
env.Handle("/movies/{id:tt[0-9]+}/get_details", movies.GetDetailsHandler).WithRole(users.UserRole)
|
env.Handle("/movies/{id:tt[0-9]+}/get_details", movies.GetDetailsHandler).WithRole(users.UserRole).Methods("GET")
|
||||||
env.Handle("/movies/explore", extmedias.Explore)
|
env.Handle("/movies/explore", extmedias.Explore).WithRole(users.UserRole).Methods("GET")
|
||||||
env.Handle("/movies/refresh", extmedias.Refresh)
|
env.Handle("/movies/refresh", extmedias.Refresh).WithRole(users.UserRole).Methods("POST")
|
||||||
env.Handle("/movies/search", movies.SearchMovie)
|
env.Handle("/movies/search", movies.SearchMovie).WithRole(users.UserRole).Methods("POST")
|
||||||
|
|
||||||
// env.Handle("/shows/polochon", shows.FromPolochon).WithRole(users.UserRole)
|
// env.Handle("/shows/polochon", shows.FromPolochon).WithRole(users.UserRole)
|
||||||
env.Handle("/shows/{id:tt[0-9]+}", shows.GetDetailsHandler)
|
env.Handle("/shows/{id:tt[0-9]+}", shows.GetDetailsHandler).WithRole(users.UserRole).Methods("GET")
|
||||||
env.Handle("/shows/refresh", extmedias.RefreshShows)
|
env.Handle("/shows/refresh", extmedias.RefreshShows).WithRole(users.UserRole).Methods("POST")
|
||||||
env.Handle("/shows/explore", extmedias.ExploreShows)
|
env.Handle("/shows/explore", extmedias.ExploreShows).WithRole(users.UserRole).Methods("GET")
|
||||||
env.Handle("/shows/search", shows.SearchShow)
|
env.Handle("/shows/search", shows.SearchShow).WithRole(users.UserRole).Methods("POST")
|
||||||
|
|
||||||
n := negroni.Classic()
|
n := negroni.Classic()
|
||||||
n.Use(authMiddleware)
|
n.Use(authMiddleware)
|
||||||
|
@ -80,6 +80,13 @@ export function selectMovie(imdbId) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function searchMovies(search) {
|
||||||
|
return request(
|
||||||
|
'SEARCH_MOVIES',
|
||||||
|
configureAxios().post('/movies/search', search)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export function getMovieDetails(imdbId) {
|
export function getMovieDetails(imdbId) {
|
||||||
return request(
|
return request(
|
||||||
'MOVIE_GET_DETAILS',
|
'MOVIE_GET_DETAILS',
|
||||||
@ -105,6 +112,13 @@ export function fetchShows(url) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function searchShows(search) {
|
||||||
|
return request(
|
||||||
|
'SEARCH_SHOWS',
|
||||||
|
configureAxios().post('/shows/search', search)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export function fetchShowDetails(imdbId) {
|
export function fetchShowDetails(imdbId) {
|
||||||
return request(
|
return request(
|
||||||
'SHOW_FETCH_DETAILS',
|
'SHOW_FETCH_DETAILS',
|
||||||
|
@ -83,14 +83,19 @@ const MovieListPopular = (props) => (
|
|||||||
const MovieListPolochon = (props) => (
|
const MovieListPolochon = (props) => (
|
||||||
<MovieList {...props} moviesUrl='/movies/polochon'/>
|
<MovieList {...props} moviesUrl='/movies/polochon'/>
|
||||||
)
|
)
|
||||||
|
const MovieListSearch = (props) => (
|
||||||
|
<MovieList {...props} />
|
||||||
|
)
|
||||||
|
|
||||||
const ShowListPopular = (props) => (
|
const ShowListPopular = (props) => (
|
||||||
<ShowList {...props} showsUrl='/shows/explore'/>
|
<ShowList {...props} showsUrl='/shows/explore'/>
|
||||||
)
|
)
|
||||||
|
|
||||||
const ShowDetailsView = (props) => (
|
const ShowDetailsView = (props) => (
|
||||||
<ShowDetails {...props} />
|
<ShowDetails {...props} />
|
||||||
)
|
)
|
||||||
|
const ShowListSearch = (props) => (
|
||||||
|
<ShowList {...props} />
|
||||||
|
)
|
||||||
|
|
||||||
ReactDOM.render((
|
ReactDOM.render((
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
@ -100,8 +105,10 @@ ReactDOM.render((
|
|||||||
<Route path="/users/login" component={UserLoginForm} />
|
<Route path="/users/login" component={UserLoginForm} />
|
||||||
<Route path="/users/signup" component={UserSignUp} />
|
<Route path="/users/signup" component={UserSignUp} />
|
||||||
<Route path="/users/edit" component={UserIsAuthenticated(UserEdit)} />
|
<Route path="/users/edit" component={UserIsAuthenticated(UserEdit)} />
|
||||||
|
<Route path="/movies/search/:search" component={UserIsAuthenticated(MovieListSearch)} />
|
||||||
<Route path="/movies/popular" component={UserIsAuthenticated(MovieListPopular)} />
|
<Route path="/movies/popular" component={UserIsAuthenticated(MovieListPopular)} />
|
||||||
<Route path="/movies/polochon(/:page)" component={UserIsAuthenticated(MovieListPolochon)} />
|
<Route path="/movies/polochon(/:page)" component={UserIsAuthenticated(MovieListPolochon)} />
|
||||||
|
<Route path="/shows/search/:search" component={UserIsAuthenticated(ShowListSearch)} />
|
||||||
<Route path="/shows/popular" component={UserIsAuthenticated(ShowListPopular)} />
|
<Route path="/shows/popular" component={UserIsAuthenticated(ShowListPopular)} />
|
||||||
<Route path="/shows/details/:imdbId" component={UserIsAuthenticated(ShowDetailsView)} />
|
<Route path="/shows/details/:imdbId" component={UserIsAuthenticated(ShowDetailsView)} />
|
||||||
</Route>
|
</Route>
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
|
||||||
export default function ListDetails(props) {
|
export default function ListDetails(props) {
|
||||||
|
let genres;
|
||||||
|
if (props.data.genres) {
|
||||||
|
genres = props.data.genres.join(', ');
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<div className="col-xs-7 col-md-4">
|
<div className="col-xs-7 col-md-4">
|
||||||
<div className="show-detail affix">
|
<div className="show-detail affix">
|
||||||
@ -12,6 +16,12 @@ export default function ListDetails(props) {
|
|||||||
{props.data.runtime} min
|
{props.data.runtime} min
|
||||||
</p>
|
</p>
|
||||||
}
|
}
|
||||||
|
{props.data.genres &&
|
||||||
|
<p>
|
||||||
|
<i className="fa fa-tags"></i>
|
||||||
|
{genres}
|
||||||
|
</p>
|
||||||
|
}
|
||||||
<p>
|
<p>
|
||||||
<i className="fa fa-star-o"></i>
|
<i className="fa fa-star-o"></i>
|
||||||
{props.data.rating} <small>({props.data.votes} counts)</small>
|
{props.data.rating} <small>({props.data.votes} counts)</small>
|
||||||
|
17
src/public/js/components/loader/loader.js
Normal file
17
src/public/js/components/loader/loader.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import Loading from 'react-loading'
|
||||||
|
|
||||||
|
export default function Loader() {
|
||||||
|
return (
|
||||||
|
<div className="row" id="container">
|
||||||
|
<div className="col-md-6 col-md-offset-3">
|
||||||
|
<Loading
|
||||||
|
type="bars"
|
||||||
|
height="100%"
|
||||||
|
width="100%"
|
||||||
|
color="#EBEBEB"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
@ -2,6 +2,7 @@ import React from 'react'
|
|||||||
|
|
||||||
import ListPosters from '../list/posters'
|
import ListPosters from '../list/posters'
|
||||||
import ListDetails from '../list/details'
|
import ListDetails from '../list/details'
|
||||||
|
import Loader from '../loader/loader'
|
||||||
|
|
||||||
class MovieButtons extends React.Component {
|
class MovieButtons extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
@ -53,7 +54,24 @@ class MovieButtons extends React.Component {
|
|||||||
|
|
||||||
export default class MovieList extends React.Component {
|
export default class MovieList extends React.Component {
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
this.props.fetchMovies(this.props.moviesUrl);
|
if (this.props.moviesUrl) {
|
||||||
|
this.props.fetchMovies(this.props.moviesUrl);
|
||||||
|
} else if (this.props.params && this.props.params.search != "") {
|
||||||
|
this.props.searchMovies({
|
||||||
|
key: this.props.params.search
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
componentWillUpdate(nextProps, nextState) {
|
||||||
|
if (!nextProps.params || nextProps.params.search === "") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (this.props.params.search === nextProps.params.search) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.props.searchMovies({
|
||||||
|
key: nextProps.params.search
|
||||||
|
});
|
||||||
}
|
}
|
||||||
render() {
|
render() {
|
||||||
const movies = this.props.movieStore.movies;
|
const movies = this.props.movieStore.movies;
|
||||||
@ -63,6 +81,12 @@ export default class MovieList extends React.Component {
|
|||||||
index = 0;
|
index = 0;
|
||||||
}
|
}
|
||||||
const selectedMovie = movies[index];
|
const selectedMovie = movies[index];
|
||||||
|
|
||||||
|
// Loading
|
||||||
|
if (this.props.movieStore.loading) {
|
||||||
|
return (<Loader />);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="row" id="container">
|
<div className="row" id="container">
|
||||||
<ListPosters
|
<ListPosters
|
||||||
|
@ -1,15 +1,37 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { Link } from 'react-router'
|
|
||||||
import { store } from '../store'
|
import { store } from '../store'
|
||||||
import { isUserLoggedIn } from '../actions/actionCreators'
|
import { isUserLoggedIn } from '../actions/actionCreators'
|
||||||
|
|
||||||
import { Nav, Navbar, NavItem, NavDropdown, MenuItem } from 'react-bootstrap'
|
import { Nav, Navbar, NavItem, NavDropdown, MenuItem } from 'react-bootstrap'
|
||||||
import { LinkContainer } from 'react-router-bootstrap'
|
import { LinkContainer } from 'react-router-bootstrap'
|
||||||
|
import { Control, Form } from 'react-redux-form';
|
||||||
|
|
||||||
export default class NavBar extends React.Component {
|
export default class NavBar extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.handleMovieSearch = this.handleMovieSearch.bind(this);
|
||||||
|
this.handleShowSearch = this.handleShowSearch.bind(this);
|
||||||
|
}
|
||||||
|
handleMovieSearch() {
|
||||||
|
this.props.router.push(`/movies/search/${encodeURI(this.props.movieStore.search)}`)
|
||||||
|
}
|
||||||
|
handleShowSearch() {
|
||||||
|
this.props.router.push(`/shows/search/${encodeURI(this.props.showStore.search)}`)
|
||||||
|
}
|
||||||
render() {
|
render() {
|
||||||
const username = this.props.userStore.username;
|
const username = this.props.userStore.username;
|
||||||
const isLoggedIn = username !== "" ? true : false;
|
const isLoggedIn = username !== "" ? true : false;
|
||||||
|
const location = this.props.router.getCurrentLocation().pathname;
|
||||||
|
let displayMovieSearch = false;
|
||||||
|
let displayShowSearch = false;
|
||||||
|
if (isLoggedIn && location.indexOf("movies") > -1)
|
||||||
|
{
|
||||||
|
displayMovieSearch = true;
|
||||||
|
}
|
||||||
|
if (isLoggedIn && location.indexOf("shows") > -1)
|
||||||
|
{
|
||||||
|
displayShowSearch = true;
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Navbar fluid fixedTop collapseOnSelect>
|
<Navbar fluid fixedTop collapseOnSelect>
|
||||||
@ -53,6 +75,30 @@ export default class NavBar extends React.Component {
|
|||||||
</NavDropdown>
|
</NavDropdown>
|
||||||
}
|
}
|
||||||
</Nav>
|
</Nav>
|
||||||
|
{displayMovieSearch &&
|
||||||
|
<Navbar.Form pullRight>
|
||||||
|
<Form model="movieStore" className="input-group" onSubmit={() => this.handleMovieSearch()}>
|
||||||
|
<Control.text
|
||||||
|
model="movieStore.search"
|
||||||
|
className="form-control"
|
||||||
|
placeholder="Search movies"
|
||||||
|
updateOn="change"
|
||||||
|
/>
|
||||||
|
</Form>
|
||||||
|
</Navbar.Form>
|
||||||
|
}
|
||||||
|
{displayShowSearch &&
|
||||||
|
<Navbar.Form pullRight>
|
||||||
|
<Form model="showStore" className="input-group" onSubmit={() => this.handleShowSearch()}>
|
||||||
|
<Control.text
|
||||||
|
model="showStore.search"
|
||||||
|
className="form-control"
|
||||||
|
placeholder="Search shows"
|
||||||
|
updateOn="change"
|
||||||
|
/>
|
||||||
|
</Form>
|
||||||
|
</Navbar.Form>
|
||||||
|
}
|
||||||
</Navbar.Collapse>
|
</Navbar.Collapse>
|
||||||
</Navbar>
|
</Navbar>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,10 +1,15 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
import Loader from '../loader/loader'
|
||||||
|
|
||||||
export default class ShowDetails extends React.Component {
|
export default class ShowDetails extends React.Component {
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
this.props.fetchShowDetails(this.props.params.imdbId);
|
this.props.fetchShowDetails(this.props.params.imdbId);
|
||||||
}
|
}
|
||||||
render() {
|
render() {
|
||||||
|
// Loading
|
||||||
|
if (this.props.showStore.loading) {
|
||||||
|
return (<Loader />);
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<div className="row" id="container">
|
<div className="row" id="container">
|
||||||
<Header data={this.props.showStore.show} />
|
<Header data={this.props.showStore.show} />
|
||||||
|
@ -3,6 +3,7 @@ import { Link } from 'react-router'
|
|||||||
|
|
||||||
import ListDetails from '../list/details'
|
import ListDetails from '../list/details'
|
||||||
import ListPosters from '../list/posters'
|
import ListPosters from '../list/posters'
|
||||||
|
import Loader from '../loader/loader'
|
||||||
|
|
||||||
function ShowButtons(props) {
|
function ShowButtons(props) {
|
||||||
const imdbLink = `http://www.imdb.com/title/${props.show.imdb_id}`;
|
const imdbLink = `http://www.imdb.com/title/${props.show.imdb_id}`;
|
||||||
@ -20,7 +21,24 @@ function ShowButtons(props) {
|
|||||||
|
|
||||||
export default class ShowList extends React.Component {
|
export default class ShowList extends React.Component {
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
this.props.fetchShows(this.props.showsUrl);
|
if (this.props.showsUrl) {
|
||||||
|
this.props.fetchShows(this.props.showsUrl);
|
||||||
|
} else if (this.props.params && this.props.params.search != "") {
|
||||||
|
this.props.searchShows({
|
||||||
|
key: this.props.params.search
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
componentWillUpdate(nextProps, nextState) {
|
||||||
|
if (!nextProps.params || nextProps.params.search === "") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (this.props.params.search === nextProps.params.search) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.props.searchShows({
|
||||||
|
key: nextProps.params.search
|
||||||
|
});
|
||||||
}
|
}
|
||||||
render() {
|
render() {
|
||||||
const shows = this.props.showStore.shows;
|
const shows = this.props.showStore.shows;
|
||||||
@ -30,6 +48,12 @@ export default class ShowList extends React.Component {
|
|||||||
index = 0;
|
index = 0;
|
||||||
}
|
}
|
||||||
const selectedShow = shows[index];
|
const selectedShow = shows[index];
|
||||||
|
|
||||||
|
// Loading
|
||||||
|
if (this.props.showStore.loading) {
|
||||||
|
return (<Loader />);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="row" id="container">
|
<div className="row" id="container">
|
||||||
<ListPosters
|
<ListPosters
|
||||||
|
@ -1,13 +1,19 @@
|
|||||||
const defaultState = {
|
const defaultState = {
|
||||||
|
loading: false,
|
||||||
movies: [],
|
movies: [],
|
||||||
filter: "",
|
filter: "",
|
||||||
perPage: 30,
|
perPage: 30,
|
||||||
selectedImdbId: "",
|
selectedImdbId: "",
|
||||||
fetchingDetails: false,
|
fetchingDetails: false,
|
||||||
|
search: "",
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function movieStore(state = defaultState, action) {
|
export default function movieStore(state = defaultState, action) {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
|
case 'MOVIE_LIST_FETCH_PENDING':
|
||||||
|
return Object.assign({}, state, {
|
||||||
|
loading: true,
|
||||||
|
})
|
||||||
case 'MOVIE_LIST_FETCH_FULFILLED':
|
case 'MOVIE_LIST_FETCH_FULFILLED':
|
||||||
let selectedImdbId = "";
|
let selectedImdbId = "";
|
||||||
// Select the first movie
|
// Select the first movie
|
||||||
@ -17,6 +23,16 @@ export default function movieStore(state = defaultState, action) {
|
|||||||
return Object.assign({}, state, {
|
return Object.assign({}, state, {
|
||||||
movies: action.payload.data,
|
movies: action.payload.data,
|
||||||
selectedImdbId: selectedImdbId,
|
selectedImdbId: selectedImdbId,
|
||||||
|
loading: false,
|
||||||
|
})
|
||||||
|
case 'SEARCH_MOVIES_PENDING':
|
||||||
|
return Object.assign({}, state, {
|
||||||
|
loading: true,
|
||||||
|
})
|
||||||
|
case 'SEARCH_MOVIES_FULFILLED':
|
||||||
|
return Object.assign({}, state, {
|
||||||
|
movies: action.payload.data,
|
||||||
|
loading: false,
|
||||||
})
|
})
|
||||||
case 'MOVIE_GET_DETAILS_PENDING':
|
case 'MOVIE_GET_DETAILS_PENDING':
|
||||||
return Object.assign({}, state, {
|
return Object.assign({}, state, {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
const defaultState = {
|
const defaultState = {
|
||||||
|
loading: false,
|
||||||
shows: [],
|
shows: [],
|
||||||
filter: "",
|
filter: "",
|
||||||
perPage: 30,
|
perPage: 30,
|
||||||
@ -6,10 +7,15 @@ const defaultState = {
|
|||||||
show: {
|
show: {
|
||||||
seasons: [],
|
seasons: [],
|
||||||
},
|
},
|
||||||
|
search: "",
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function showStore(state = defaultState, action) {
|
export default function showStore(state = defaultState, action) {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
|
case 'SHOW_LIST_FETCH_PENDING':
|
||||||
|
return Object.assign({}, state, {
|
||||||
|
loading: true,
|
||||||
|
})
|
||||||
case 'SHOW_LIST_FETCH_FULFILLED':
|
case 'SHOW_LIST_FETCH_FULFILLED':
|
||||||
let selectedImdbId = "";
|
let selectedImdbId = "";
|
||||||
// Select the first show
|
// Select the first show
|
||||||
@ -19,12 +25,26 @@ export default function showStore(state = defaultState, action) {
|
|||||||
return Object.assign({}, state, {
|
return Object.assign({}, state, {
|
||||||
shows: action.payload.data,
|
shows: action.payload.data,
|
||||||
selectedImdbId: selectedImdbId,
|
selectedImdbId: selectedImdbId,
|
||||||
|
loading: false,
|
||||||
|
})
|
||||||
|
case 'SHOW_FETCH_DETAILS_PENDING':
|
||||||
|
return Object.assign({}, state, {
|
||||||
|
loading: true,
|
||||||
})
|
})
|
||||||
case 'SHOW_FETCH_DETAILS_FULFILLED':
|
case 'SHOW_FETCH_DETAILS_FULFILLED':
|
||||||
return Object.assign({}, state, {
|
return Object.assign({}, state, {
|
||||||
show: sortEpisodes(action.payload.data),
|
show: sortEpisodes(action.payload.data),
|
||||||
|
loading: false,
|
||||||
|
})
|
||||||
|
case 'SEARCH_SHOWS_PENDING':
|
||||||
|
return Object.assign({}, state, {
|
||||||
|
loading: true,
|
||||||
|
})
|
||||||
|
case 'SEARCH_SHOWS_FULFILLED':
|
||||||
|
return Object.assign({}, state, {
|
||||||
|
shows: action.payload.data,
|
||||||
|
loading: false,
|
||||||
})
|
})
|
||||||
return state;
|
|
||||||
case 'SELECT_SHOW':
|
case 'SELECT_SHOW':
|
||||||
// Don't select the show if we're fetching another show's details
|
// Don't select the show if we're fetching another show's details
|
||||||
if (state.fetchingDetails) {
|
if (state.fetchingDetails) {
|
||||||
|
@ -3081,6 +3081,10 @@ react-dom@^15.3.2:
|
|||||||
version "15.3.2"
|
version "15.3.2"
|
||||||
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-15.3.2.tgz#c46b0aa5380d7b838e7a59c4a7beff2ed315531f"
|
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-15.3.2.tgz#c46b0aa5380d7b838e7a59c4a7beff2ed315531f"
|
||||||
|
|
||||||
|
react-loading:
|
||||||
|
version "0.0.9"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-loading/-/react-loading-0.0.9.tgz#e9fba6948915ba7742a508193828b6c73eb04956"
|
||||||
|
|
||||||
react-overlays@^0.6.10:
|
react-overlays@^0.6.10:
|
||||||
version "0.6.10"
|
version "0.6.10"
|
||||||
resolved "https://registry.yarnpkg.com/react-overlays/-/react-overlays-0.6.10.tgz#e7e52dad47f00a0fc784eb044428c3a9e874bfa3"
|
resolved "https://registry.yarnpkg.com/react-overlays/-/react-overlays-0.6.10.tgz#e7e52dad47f00a0fc784eb044428c3a9e874bfa3"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user