Add torrent page
This commit is contained in:
parent
9779027d1b
commit
27ca75c1ab
@ -284,3 +284,10 @@ export function addTorrent(url) {
|
||||
],
|
||||
)
|
||||
}
|
||||
|
||||
export function fetchTorrents() {
|
||||
return request(
|
||||
'TORRENTS_FETCH',
|
||||
configureAxios().get('/torrents')
|
||||
)
|
||||
}
|
||||
|
@ -43,6 +43,7 @@ import ShowDetails from './components/shows/details'
|
||||
import UserLoginForm from './components/users/login'
|
||||
import UserEdit from './components/users/edit'
|
||||
import UserSignUp from './components/users/signup'
|
||||
import TorrentList from './components/torrents/list'
|
||||
|
||||
function Main(props) {
|
||||
return (
|
||||
@ -61,6 +62,7 @@ function mapStateToProps(state) {
|
||||
movieStore: state.movieStore,
|
||||
showStore: state.showStore,
|
||||
userStore: state.userStore,
|
||||
torrentStore: state.torrentStore,
|
||||
alerts: state.alerts,
|
||||
}
|
||||
}
|
||||
@ -70,7 +72,14 @@ function mapDispatchToProps(dispatch) {
|
||||
}
|
||||
|
||||
const App = connect(mapStateToProps, mapDispatchToProps)(Main);
|
||||
export function startPollingTorrents() {
|
||||
return request(
|
||||
'TORRENTS_FETCH',
|
||||
configureAxios().get('/torrents')
|
||||
)
|
||||
}
|
||||
|
||||
var pollingTorrentsId;
|
||||
const loginCheck = function(nextState, replace, next, f) {
|
||||
const state = store.getState();
|
||||
const isLogged = state.userStore.isLogged;
|
||||
@ -91,6 +100,13 @@ const loginCheck = function(nextState, replace, next, f) {
|
||||
replace('/users/login');
|
||||
} else {
|
||||
f();
|
||||
// Poll torrents once logged
|
||||
if (!pollingTorrentsId) {
|
||||
// Fetch the torrents every 10s
|
||||
pollingTorrentsId = setInterval(function() {
|
||||
store.dispatch(actionCreators.fetchTorrents());
|
||||
}, 10000);
|
||||
}
|
||||
}
|
||||
|
||||
next();
|
||||
@ -208,6 +224,15 @@ const routes = {
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/torrents',
|
||||
component: TorrentList,
|
||||
onEnter: function(nextState, replace, next) {
|
||||
loginCheck(nextState, replace, next, function() {
|
||||
store.dispatch(actionCreators.fetchTorrents());
|
||||
});
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,10 @@ export default function NavBar(props) {
|
||||
<MoviesDropdown username={props.userStore.username} />
|
||||
<ShowsDropdown username={props.userStore.username} />
|
||||
<WishlistDropdown username={props.userStore.username} />
|
||||
<Torrents
|
||||
username={props.userStore.username}
|
||||
torrentsCount={props.torrentStore.torrents.length}
|
||||
/>
|
||||
<UserDropdown username={props.userStore.username} />
|
||||
<Search
|
||||
placeholder="Search movies"
|
||||
@ -148,3 +152,24 @@ function WishlistDropdown(props) {
|
||||
</Nav>
|
||||
);
|
||||
}
|
||||
|
||||
function Torrents(props) {
|
||||
if (props.username === "") {
|
||||
return null;
|
||||
}
|
||||
return(
|
||||
<Nav>
|
||||
<LinkContainer to="/torrents">
|
||||
<NavItem>
|
||||
Torrents
|
||||
{props.torrentsCount > 0 &&
|
||||
<span>
|
||||
|
||||
<span className="label label-info">{props.torrentsCount}</span>
|
||||
</span>
|
||||
}
|
||||
</NavItem>
|
||||
</LinkContainer>
|
||||
</Nav>
|
||||
);
|
||||
}
|
||||
|
133
src/public/js/components/torrents/list.js
Normal file
133
src/public/js/components/torrents/list.js
Normal file
@ -0,0 +1,133 @@
|
||||
import React from 'react'
|
||||
|
||||
export default function TorrentList(props){
|
||||
return (
|
||||
<div>
|
||||
<AddTorrent func={props.addTorrent} />
|
||||
<List torrents={props.torrentStore.torrents} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
class AddTorrent extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = { url: '' };
|
||||
this.handleSubmit = this.handleSubmit.bind(this);
|
||||
this.handleChange = this.handleChange.bind(this);
|
||||
}
|
||||
handleChange(event) {
|
||||
this.setState({ url: event.target.value });
|
||||
}
|
||||
handleSubmit() {
|
||||
if (this.state.url === "") {
|
||||
return;
|
||||
}
|
||||
this.setState({ url: '' });
|
||||
this.props.func(this.state.url);
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<div className="row">
|
||||
<div className="col-xs-12 col-md-12">
|
||||
<form className="input-group" onSubmit={this.handleSubmit}>
|
||||
<input
|
||||
className="form-control"
|
||||
placeholder="Add torrent URL"
|
||||
onChange={this.handleChange}
|
||||
value={this.state.url}
|
||||
/>
|
||||
<span className="input-group-btn">
|
||||
<button
|
||||
className="btn btn-primary"
|
||||
type="button"
|
||||
onClick={this.handleSubmit}
|
||||
>
|
||||
Add
|
||||
</button>
|
||||
</span>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function List(props){
|
||||
if (props.torrents.length === 0) {
|
||||
return (
|
||||
<div className="row">
|
||||
<div className="col-xs-12 col-md-12">
|
||||
<h3>Torrents</h3>
|
||||
<div className="panel panel-default">
|
||||
<div className="panel-heading">No torrents</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div className="row">
|
||||
<div className="col-xs-12 col-md-12">
|
||||
<h3>Torrents</h3>
|
||||
{props.torrents.map(function(el, index) {
|
||||
return (
|
||||
<Torrent key={index} data={el} />
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
function Torrent(props){
|
||||
const done = props.data.is_finished;
|
||||
var progressStyle = 'progress-bar progress-bar-warning';
|
||||
if (done) {
|
||||
progressStyle = 'progress-bar progress-bar-success';
|
||||
}
|
||||
var percentDone = props.data.percent_done;
|
||||
const started = (percentDone !== 0);
|
||||
if (started) {
|
||||
percentDone = Number(percentDone).toFixed(1) + '%';
|
||||
}
|
||||
|
||||
var downloadedSize = prettySize(props.data.downloaded_size);
|
||||
var totalSize = prettySize(props.data.total_size);
|
||||
var downloadRate = prettySize(props.data.download_rate) + "/s";
|
||||
return (
|
||||
<div className="panel panel-default">
|
||||
<div className="panel-heading">{props.data.name}</div>
|
||||
<div className="panel-body">
|
||||
{started &&
|
||||
<div className="progress progress-striped">
|
||||
<div
|
||||
className={progressStyle}
|
||||
style={{width: percentDone}}>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
{!started &&
|
||||
<p>Download not yet started</p>
|
||||
}
|
||||
{started &&
|
||||
<div>
|
||||
<p>{downloadedSize} / {totalSize} - {percentDone} - {downloadRate}</p>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function prettySize(fileSizeInBytes) {
|
||||
var i = -1;
|
||||
var byteUnits = [' kB', ' MB', ' GB', ' TB', 'PB', 'EB', 'ZB', 'YB'];
|
||||
do {
|
||||
fileSizeInBytes = fileSizeInBytes / 1024;
|
||||
i++;
|
||||
} while (fileSizeInBytes > 1024);
|
||||
|
||||
return Math.max(fileSizeInBytes, 0.1).toFixed(1) + byteUnits[i];
|
||||
};
|
@ -5,6 +5,7 @@ import movieStore from './movies'
|
||||
import showStore from './shows'
|
||||
import userStore from './users'
|
||||
import alerts from './alerts'
|
||||
import torrentStore from './torrents'
|
||||
|
||||
// Use combine form form react-redux-form, it's a thin wrapper arround the
|
||||
// default combinedReducers provided with React. It allows the forms to be
|
||||
@ -15,6 +16,7 @@ const rootReducer = combineForms({
|
||||
showStore,
|
||||
userStore,
|
||||
alerts,
|
||||
torrentStore,
|
||||
})
|
||||
|
||||
export default rootReducer;
|
||||
|
20
src/public/js/reducers/torrents.js
Normal file
20
src/public/js/reducers/torrents.js
Normal file
@ -0,0 +1,20 @@
|
||||
const defaultState = {
|
||||
fetching: false,
|
||||
torrents: [],
|
||||
};
|
||||
|
||||
export default function showStore(state = defaultState, action) {
|
||||
switch (action.type) {
|
||||
case 'TORRENTS_FETCH_PENDING':
|
||||
return Object.assign({}, state, {
|
||||
fetching: true,
|
||||
})
|
||||
case 'TORRENTS_FETCH_FULFILLED':
|
||||
return Object.assign({}, state, {
|
||||
fetching: false,
|
||||
torrents: action.payload.data,
|
||||
})
|
||||
default:
|
||||
return state
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user