Merge branch 'browser_streaming' into 'master'
Browser streaming See merge request !70
This commit is contained in:
commit
5cdae9f334
@ -19,7 +19,6 @@
|
|||||||
"react-dom": "^15.3.2",
|
"react-dom": "^15.3.2",
|
||||||
"react-infinite-scroller": "^1.0.4",
|
"react-infinite-scroller": "^1.0.4",
|
||||||
"react-loading": "^0.0.9",
|
"react-loading": "^0.0.9",
|
||||||
"react-player": "^0.14.1",
|
|
||||||
"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",
|
||||||
@ -27,7 +26,8 @@
|
|||||||
"react-router-redux": "^4.0.7",
|
"react-router-redux": "^4.0.7",
|
||||||
"redux": "^3.6.0",
|
"redux": "^3.6.0",
|
||||||
"redux-logger": "^2.7.4",
|
"redux-logger": "^2.7.4",
|
||||||
"redux-thunk": "^2.1.0"
|
"redux-thunk": "^2.1.0",
|
||||||
|
"universal-cookie": "^2.0.7"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"axios": "^0.15.2",
|
"axios": "^0.15.2",
|
||||||
|
@ -80,14 +80,26 @@ func (a *Authorizer) Login(rw http.ResponseWriter, req *http.Request, username,
|
|||||||
|
|
||||||
// CurrentUser returns the logged in username from session and verifies the token
|
// CurrentUser returns the logged in username from session and verifies the token
|
||||||
func (a *Authorizer) CurrentUser(rw http.ResponseWriter, req *http.Request) (User, error) {
|
func (a *Authorizer) CurrentUser(rw http.ResponseWriter, req *http.Request) (User, error) {
|
||||||
|
var tokenStr string
|
||||||
h := req.Header.Get("Authorization")
|
h := req.Header.Get("Authorization")
|
||||||
// No user logged
|
if h != "" {
|
||||||
if h == "" {
|
// Get the token from the header
|
||||||
return nil, nil
|
tokenStr = strings.Replace(h, "Bearer ", "", -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the token from the header
|
// If the token string is still empty, check in the cookies
|
||||||
tokenStr := strings.Replace(h, "Bearer ", "", -1)
|
if tokenStr == "" {
|
||||||
|
tokenCookie, err := req.Cookie("token")
|
||||||
|
if err != nil || tokenCookie == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
tokenStr = tokenCookie.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
// No user logged
|
||||||
|
if tokenStr == "" {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Keyfunc to decode the token
|
// Keyfunc to decode the token
|
||||||
var keyfunc jwt.Keyfunc = func(token *jwt.Token) (interface{}, error) {
|
var keyfunc jwt.Keyfunc = func(token *jwt.Token) (interface{}, error) {
|
||||||
|
@ -14,6 +14,7 @@ import (
|
|||||||
"gitlab.quimbo.fr/odwrtw/canape-sql/src/internal/auth"
|
"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/backend"
|
||||||
"gitlab.quimbo.fr/odwrtw/canape-sql/src/internal/config"
|
"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/users"
|
||||||
"gitlab.quimbo.fr/odwrtw/canape-sql/src/internal/web"
|
"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")
|
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)
|
||||||
|
}
|
||||||
|
@ -34,6 +34,7 @@ func (m *Movie) MarshalJSON() ([]byte, error) {
|
|||||||
type Subtitle struct {
|
type Subtitle struct {
|
||||||
Language string `json:"language"`
|
Language string `json:"language"`
|
||||||
URL string `json:"url"`
|
URL string `json:"url"`
|
||||||
|
VVTFile string `json:"vvt_file"`
|
||||||
}
|
}
|
||||||
var subtitles []Subtitle
|
var subtitles []Subtitle
|
||||||
// If the episode is present, fill the downloadURL
|
// If the episode is present, fill the downloadURL
|
||||||
@ -46,6 +47,7 @@ func (m *Movie) MarshalJSON() ([]byte, error) {
|
|||||||
subtitles = append(subtitles, Subtitle{
|
subtitles = append(subtitles, Subtitle{
|
||||||
Language: l,
|
Language: l,
|
||||||
URL: subtitleURL,
|
URL: subtitleURL,
|
||||||
|
VVTFile: fmt.Sprintf("/movies/%s/subtitles/%s", m.ImdbID, l),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package shows
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
"github.com/odwrtw/papi"
|
"github.com/odwrtw/papi"
|
||||||
@ -26,6 +27,7 @@ func (e *Episode) MarshalJSON() ([]byte, error) {
|
|||||||
type Subtitle struct {
|
type Subtitle struct {
|
||||||
Language string `json:"language"`
|
Language string `json:"language"`
|
||||||
URL string `json:"url"`
|
URL string `json:"url"`
|
||||||
|
VVTFile string `json:"vvt_file"`
|
||||||
}
|
}
|
||||||
var subtitles []Subtitle
|
var subtitles []Subtitle
|
||||||
// If the episode is present, fill the downloadURL
|
// If the episode is present, fill the downloadURL
|
||||||
@ -46,6 +48,7 @@ func (e *Episode) MarshalJSON() ([]byte, error) {
|
|||||||
subtitles = append(subtitles, Subtitle{
|
subtitles = append(subtitles, Subtitle{
|
||||||
Language: l,
|
Language: l,
|
||||||
URL: subtitleURL,
|
URL: subtitleURL,
|
||||||
|
VVTFile: fmt.Sprintf("/shows/%s/seasons/%d/episodes/%d/subtitles/%s", e.ShowImdbID, e.Season, e.Episode, l),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
|
|
||||||
"gitlab.quimbo.fr/odwrtw/canape-sql/src/internal/auth"
|
"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/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/users"
|
||||||
"gitlab.quimbo.fr/odwrtw/canape-sql/src/internal/web"
|
"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")
|
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)
|
||||||
|
}
|
||||||
|
43
src/internal/subtitles/handler.go
Normal file
43
src/internal/subtitles/handler.go
Normal file
@ -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
|
||||||
|
}
|
@ -11,9 +11,11 @@ import 'file-loader?name=[name].png!../img/apple-touch-icon.png'
|
|||||||
import 'file-loader?name=[name].png!../img/favicon-16x16.png'
|
import 'file-loader?name=[name].png!../img/favicon-16x16.png'
|
||||||
import 'file-loader?name=[name].png!../img/favicon-32x32.png'
|
import 'file-loader?name=[name].png!../img/favicon-32x32.png'
|
||||||
import 'file-loader?name=[name].png!../img/favicon.ico'
|
import 'file-loader?name=[name].png!../img/favicon.ico'
|
||||||
import 'file-loader?name=[name].png!../img/manifest.json'
|
|
||||||
import 'file-loader?name=[name].png!../img/safari-pinned-tab.svg'
|
import 'file-loader?name=[name].png!../img/safari-pinned-tab.svg'
|
||||||
|
|
||||||
|
// Import manifest
|
||||||
|
import 'file-loader?name=[name].json!../manifest.json'
|
||||||
|
|
||||||
// Styles
|
// Styles
|
||||||
import '../less/app.less'
|
import '../less/app.less'
|
||||||
|
|
||||||
@ -79,15 +81,15 @@ export function startPollingTorrents() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
var pollingTorrentsId;
|
// This function returns true if the user is logged in, false otherwise
|
||||||
const loginCheck = function(nextState, replace, next, f) {
|
function isLoggedIn() {
|
||||||
const state = store.getState();
|
const state = store.getState();
|
||||||
const isLogged = state.userStore.isLogged;
|
const isLogged = state.userStore.isLogged;
|
||||||
let token = localStorage.getItem('token');
|
let token = localStorage.getItem('token');
|
||||||
|
|
||||||
// Let's check if the user has a token, if he does let's assume he's logged
|
// Let's check if the user has a token, if he does let's assume he's logged
|
||||||
// in. If that's not the case he will be logged out on the fisrt query
|
// in. If that's not the case he will be logged out on the fisrt query
|
||||||
if (token !== "") {
|
if (token && token !== "") {
|
||||||
store.dispatch({
|
store.dispatch({
|
||||||
type: 'USER_SET_TOKEN',
|
type: 'USER_SET_TOKEN',
|
||||||
payload: {
|
payload: {
|
||||||
@ -96,10 +98,23 @@ const loginCheck = function(nextState, replace, next, f) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isLogged && token === "") {
|
if (isLogged || (token && token !== "")) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
var pollingTorrentsId;
|
||||||
|
const loginCheck = function(nextState, replace, next, f = null) {
|
||||||
|
const loggedIn = isLoggedIn();
|
||||||
|
if (!loggedIn) {
|
||||||
replace('/users/login');
|
replace('/users/login');
|
||||||
} else {
|
} else {
|
||||||
|
if (f) {
|
||||||
f();
|
f();
|
||||||
|
}
|
||||||
|
|
||||||
// Poll torrents once logged
|
// Poll torrents once logged
|
||||||
if (!pollingTorrentsId) {
|
if (!pollingTorrentsId) {
|
||||||
// Fetch the torrents every 10s
|
// Fetch the torrents every 10s
|
||||||
@ -112,18 +127,42 @@ const loginCheck = function(nextState, replace, next, f) {
|
|||||||
next();
|
next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const defaultRoute = '/movies/explore/yts/seeds';
|
||||||
const routes = {
|
const routes = {
|
||||||
path: '/',
|
path: '/',
|
||||||
component: App,
|
component: App,
|
||||||
indexRoute: {onEnter: ({params}, replace) => replace('/movies/explore/yts/seeds')},
|
indexRoute: {onEnter: ({params}, replace) => replace(defaultRoute)},
|
||||||
childRoutes: [
|
childRoutes: [
|
||||||
{ path: '/users/login' , component: UserLoginForm },
|
{
|
||||||
{ path: '/users/signup' , component: UserSignUp },
|
path: '/users/signup',
|
||||||
{ path: '/users/edit' , component: UserEdit },
|
component: UserSignUp
|
||||||
{ path: '/users/signup' , component: UserSignUp },
|
},
|
||||||
|
{
|
||||||
|
path: '/users/login',
|
||||||
|
component: UserLoginForm,
|
||||||
|
onEnter: function(nextState, replace, next) {
|
||||||
|
if (isLoggedIn()) {
|
||||||
|
// User is already logged in, redirect him to the default route
|
||||||
|
replace(defaultRoute);
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/users/edit',
|
||||||
|
component: UserEdit,
|
||||||
|
onEnter: function(nextState, replace, next) {
|
||||||
|
loginCheck(nextState, replace, next);
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/users/logout',
|
path: '/users/logout',
|
||||||
onEnter: function(nextState, replace, next) {
|
onEnter: function(nextState, replace, next) {
|
||||||
|
// Stop polling
|
||||||
|
if (pollingTorrentsId !== null) {
|
||||||
|
clearInterval(pollingTorrentsId);
|
||||||
|
pollingTorrentsId = null;
|
||||||
|
}
|
||||||
store.dispatch(actionCreators.userLogout());
|
store.dispatch(actionCreators.userLogout());
|
||||||
replace('/users/login');
|
replace('/users/login');
|
||||||
next();
|
next();
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import ReactPlayer from 'react-player'
|
|
||||||
|
|
||||||
import { Button, Dropdown, MenuItem, Modal } from 'react-bootstrap'
|
import { Button, Dropdown, MenuItem, Modal } from 'react-bootstrap'
|
||||||
|
|
||||||
@ -56,12 +55,46 @@ export default class DownloadButton extends React.Component {
|
|||||||
</Modal.Title>
|
</Modal.Title>
|
||||||
</Modal.Header>
|
</Modal.Header>
|
||||||
<Modal.Body>
|
<Modal.Body>
|
||||||
<div className="embed-responsive embed-responsive-16by9">
|
<Player
|
||||||
<ReactPlayer url={this.props.url} playing controls/>
|
url={this.props.url}
|
||||||
</div>
|
subtitles={this.props.subtitles}
|
||||||
|
/>
|
||||||
</Modal.Body>
|
</Modal.Body>
|
||||||
</Modal>
|
</Modal>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class Player extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
var subtitles = [];
|
||||||
|
if (props.subtitles && props.subtitles.length) {
|
||||||
|
subtitles = props.subtitles;
|
||||||
|
}
|
||||||
|
this.state = {
|
||||||
|
subtitles: subtitles,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div className="embed-responsive embed-responsive-16by9">
|
||||||
|
<video controls>
|
||||||
|
<source src={this.props.url} type="video/mp4"/>
|
||||||
|
{this.props.subtitles.map(function(el, index) {
|
||||||
|
return (
|
||||||
|
<track
|
||||||
|
key={index}
|
||||||
|
kind="subtitles"
|
||||||
|
label={el.language}
|
||||||
|
src={el.vvt_file}
|
||||||
|
srcLang={el.language}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</video>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -32,7 +32,10 @@ function MovieButtons(props) {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
|
|
||||||
<DownloadButton url={props.movie.polochon_url}/>
|
<DownloadButton
|
||||||
|
url={props.movie.polochon_url}
|
||||||
|
subtitles={props.movie.subtitles}
|
||||||
|
/>
|
||||||
|
|
||||||
<a type="button" className="btn btn-warning btn-sm" href={imdb_link}>
|
<a type="button" className="btn btn-warning btn-sm" href={imdb_link}>
|
||||||
<i className="fa fa-external-link"></i> IMDB
|
<i className="fa fa-external-link"></i> IMDB
|
||||||
|
@ -182,6 +182,7 @@ function Episode(props) {
|
|||||||
})}
|
})}
|
||||||
<DownloadButton
|
<DownloadButton
|
||||||
url={props.data.polochon_url}
|
url={props.data.polochon_url}
|
||||||
|
subtitles={props.data.subtitles}
|
||||||
customClassName="episode-button"
|
customClassName="episode-button"
|
||||||
xs
|
xs
|
||||||
/>
|
/>
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import jwtDecode from 'jwt-decode'
|
import jwtDecode from 'jwt-decode'
|
||||||
|
import Cookies from 'universal-cookie'
|
||||||
|
|
||||||
const defaultState = {
|
const defaultState = {
|
||||||
userLoading: false,
|
userLoading: false,
|
||||||
@ -36,12 +37,19 @@ export default function userStore(state = defaultState, action) {
|
|||||||
|
|
||||||
function logoutUser(state) {
|
function logoutUser(state) {
|
||||||
localStorage.removeItem('token');
|
localStorage.removeItem('token');
|
||||||
|
const cookies = new Cookies();
|
||||||
|
cookies.remove('token');
|
||||||
|
|
||||||
return Object.assign({}, state, defaultState)
|
return Object.assign({}, state, defaultState)
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateFromToken(state, token) {
|
function updateFromToken(state, token) {
|
||||||
const decodedToken = jwtDecode(token);
|
const decodedToken = jwtDecode(token);
|
||||||
localStorage.setItem('token', token);
|
localStorage.setItem('token', token);
|
||||||
|
|
||||||
|
const cookies = new Cookies();
|
||||||
|
cookies.set('token', token);
|
||||||
|
|
||||||
return Object.assign({}, state, {
|
return Object.assign({}, state, {
|
||||||
userLoading: false,
|
userLoading: false,
|
||||||
isLogged: true,
|
isLogged: true,
|
||||||
|
@ -23,6 +23,7 @@ func setupRoutes(env *web.Env) {
|
|||||||
env.Handle("/movies/search/{search}", movies.SearchMovie).WithRole(users.UserRole).Methods("GET")
|
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]+}", 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]+}/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/{id:tt[0-9]+}/subtitles/refresh", movies.RefreshMovieSubtitlesHandler).WithRole(users.UserRole).Methods("POST")
|
||||||
env.Handle("/movies/refresh", extmedias.RefreshMoviesHandler).WithRole(users.AdminRole).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]+}/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]+}", 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/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")
|
env.Handle("/shows/refresh", extmedias.RefreshShowsHandler).WithRole(users.AdminRole).Methods("POST")
|
||||||
|
|
||||||
// Wishlist routes for shows
|
// Wishlist routes for shows
|
||||||
|
34
yarn.lock
34
yarn.lock
@ -991,6 +991,10 @@ convert-source-map@^1.1.0:
|
|||||||
version "1.3.0"
|
version "1.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.3.0.tgz#e9f3e9c6e2728efc2676696a70eb382f73106a67"
|
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.3.0.tgz#e9f3e9c6e2728efc2676696a70eb382f73106a67"
|
||||||
|
|
||||||
|
cookie@^0.3.1:
|
||||||
|
version "0.3.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb"
|
||||||
|
|
||||||
core-js@^1.0.0:
|
core-js@^1.0.0:
|
||||||
version "1.2.7"
|
version "1.2.7"
|
||||||
resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636"
|
resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636"
|
||||||
@ -1322,10 +1326,6 @@ fbjs@^0.8.4:
|
|||||||
promise "^7.1.1"
|
promise "^7.1.1"
|
||||||
ua-parser-js "^0.7.9"
|
ua-parser-js "^0.7.9"
|
||||||
|
|
||||||
fetch-jsonp@^1.0.2:
|
|
||||||
version "1.0.5"
|
|
||||||
resolved "https://registry.yarnpkg.com/fetch-jsonp/-/fetch-jsonp-1.0.5.tgz#fd1720a6876f557237013ec70ee969dd140486e4"
|
|
||||||
|
|
||||||
file-loader:
|
file-loader:
|
||||||
version "0.9.0"
|
version "0.9.0"
|
||||||
resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-0.9.0.tgz#1d2daddd424ce6d1b07cfe3f79731bed3617ab42"
|
resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-0.9.0.tgz#1d2daddd424ce6d1b07cfe3f79731bed3617ab42"
|
||||||
@ -1956,6 +1956,10 @@ is-my-json-valid@^2.12.4:
|
|||||||
jsonpointer "^4.0.0"
|
jsonpointer "^4.0.0"
|
||||||
xtend "^4.0.0"
|
xtend "^4.0.0"
|
||||||
|
|
||||||
|
is-node@^1.0.2:
|
||||||
|
version "1.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/is-node/-/is-node-1.0.2.tgz#d7d002745ef7debbb7477e988956ab0a4fccb653"
|
||||||
|
|
||||||
is-number@^2.0.2, is-number@^2.1.0:
|
is-number@^2.0.2, is-number@^2.1.0:
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f"
|
resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f"
|
||||||
@ -2178,10 +2182,6 @@ load-json-file@^1.0.0:
|
|||||||
pinkie-promise "^2.0.0"
|
pinkie-promise "^2.0.0"
|
||||||
strip-bom "^2.0.0"
|
strip-bom "^2.0.0"
|
||||||
|
|
||||||
load-script@^1.0.0:
|
|
||||||
version "1.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/load-script/-/load-script-1.0.0.tgz#0491939e0bee5643ee494a7e3da3d2bac70c6ca4"
|
|
||||||
|
|
||||||
loader-utils@0.2.x, loader-utils@^0.2.11, loader-utils@^0.2.5, loader-utils@^0.2.7, loader-utils@~0.2.2, loader-utils@~0.2.5:
|
loader-utils@0.2.x, loader-utils@^0.2.11, loader-utils@^0.2.5, loader-utils@^0.2.7, loader-utils@~0.2.2, loader-utils@~0.2.5:
|
||||||
version "0.2.16"
|
version "0.2.16"
|
||||||
resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-0.2.16.tgz#f08632066ed8282835dff88dfb52704765adee6d"
|
resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-0.2.16.tgz#f08632066ed8282835dff88dfb52704765adee6d"
|
||||||
@ -3024,7 +3024,7 @@ qs@~6.3.0:
|
|||||||
version "6.3.0"
|
version "6.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.3.0.tgz#f403b264f23bc01228c74131b407f18d5ea5d442"
|
resolved "https://registry.yarnpkg.com/qs/-/qs-6.3.0.tgz#f403b264f23bc01228c74131b407f18d5ea5d442"
|
||||||
|
|
||||||
query-string@^4.1.0, query-string@^4.2.2, query-string@^4.2.3:
|
query-string@^4.1.0, query-string@^4.2.2:
|
||||||
version "4.3.1"
|
version "4.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.3.1.tgz#54baada6713eafc92be75c47a731f2ebd09cd11d"
|
resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.3.1.tgz#54baada6713eafc92be75c47a731f2ebd09cd11d"
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -3096,14 +3096,6 @@ react-overlays@^0.6.10:
|
|||||||
react-prop-types "^0.4.0"
|
react-prop-types "^0.4.0"
|
||||||
warning "^3.0.0"
|
warning "^3.0.0"
|
||||||
|
|
||||||
react-player:
|
|
||||||
version "0.14.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/react-player/-/react-player-0.14.1.tgz#72c45ec13bb8445cda22d0482f26aa1a3af629f0"
|
|
||||||
dependencies:
|
|
||||||
fetch-jsonp "^1.0.2"
|
|
||||||
load-script "^1.0.0"
|
|
||||||
query-string "^4.2.3"
|
|
||||||
|
|
||||||
react-prop-types@^0.4.0:
|
react-prop-types@^0.4.0:
|
||||||
version "0.4.0"
|
version "0.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/react-prop-types/-/react-prop-types-0.4.0.tgz#f99b0bfb4006929c9af2051e7c1414a5c75b93d0"
|
resolved "https://registry.yarnpkg.com/react-prop-types/-/react-prop-types-0.4.0.tgz#f99b0bfb4006929c9af2051e7c1414a5c75b93d0"
|
||||||
@ -3714,6 +3706,14 @@ unique-stream@^1.0.0:
|
|||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/unique-stream/-/unique-stream-1.0.0.tgz#d59a4a75427447d9aa6c91e70263f8d26a4b104b"
|
resolved "https://registry.yarnpkg.com/unique-stream/-/unique-stream-1.0.0.tgz#d59a4a75427447d9aa6c91e70263f8d26a4b104b"
|
||||||
|
|
||||||
|
universal-cookie@^2.0.7:
|
||||||
|
version "2.0.7"
|
||||||
|
resolved "https://registry.yarnpkg.com/universal-cookie/-/universal-cookie-2.0.7.tgz#3f42c25574196aba1ca5bbf754b2b6ba28329828"
|
||||||
|
dependencies:
|
||||||
|
cookie "^0.3.1"
|
||||||
|
is-node "^1.0.2"
|
||||||
|
object-assign "^4.1.0"
|
||||||
|
|
||||||
url-loader:
|
url-loader:
|
||||||
version "0.5.7"
|
version "0.5.7"
|
||||||
resolved "https://registry.yarnpkg.com/url-loader/-/url-loader-0.5.7.tgz#67e8779759f8000da74994906680c943a9b0925d"
|
resolved "https://registry.yarnpkg.com/url-loader/-/url-loader-0.5.7.tgz#67e8779759f8000da74994906680c943a9b0925d"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user