Add smart ETA calculator

This commit is contained in:
John F
2015-04-11 18:51:41 -04:00
parent def89fa5b2
commit 3419042748
6 changed files with 218 additions and 54 deletions
+100 -21
View File
@@ -121,14 +121,20 @@ var mapProps = function(props, data) {
return mappedObject;
};
var createMulticallRequest = function(data) {
var createMulticallRequest = function(data, params) {
params = params || [];
var methodCall = [];
if (!util.isArray(data)) {
data = [data];
}
for (i = 0, len = data.length; i < len; i++) {
methodCall.push({
'methodName': data[i],
'params': []
'params': params
});
}
@@ -142,15 +148,78 @@ client.prototype.getTorrentList = function(callback) {
rTorrent.get('d.multicall', defaults.torrentPropertyMethods)
.then(function(data) {
// create torrent array, each item in the array being
// an object with human-readable property values
var torrents = mapProps(defaults.torrentProperties, data, 'torrent-list');
try {
// add percent complete
Object.keys(torrents).map(function(hash) {
// create torrent array, each item in the array being
// an object with human-readable property values
var torrents = mapProps(defaults.torrentProperties, data, 'torrent-list');
torrents[hash]['percentComplete'] = (torrents[hash]['bytesDone'] / torrents[hash]['sizeBytes'] * 100).toFixed(2);
});
// add percent complete
Object.keys(torrents).map(function(hash) {
var torrent = torrents[hash];
var percentComplete = (torrent['bytesDone'] / torrent['sizeBytes'] * 100).toFixed(2);
var eta = function() {
if (torrent['downloadRate'] > 0) {
var seconds = (torrent['sizeBytes'] - torrent['bytesDone']) / torrent['downloadRate'];
var years = Math.floor(seconds / 31536000);
var weeks = Math.floor((seconds % 31536000) / 604800);
var days = Math.floor(((seconds % 31536000) % 604800) / 86400);
var hours = Math.floor((((seconds % 31536000) % 604800) % 86400) / 3600);
var minutes = Math.floor(((((seconds % 31536000) % 604800) % 86400) % 3600) / 60);
var wholeSeconds = Math.floor((((((seconds % 31536000) % 604800) % 86400) % 3600) % 60) / 60);
var timeRemaining = {};
if (years > 0) {
timeRemaining = {
years: years,
weeks: weeks
}
} else if (weeks > 0) {
timeRemaining = {
weeks: weeks,
days: days
}
} else if (days > 0) {
timeRemaining = {
days: days,
hours: hours
}
} else if (hours > 0) {
timeRemaining = {
hours: hours,
minutes: minutes
}
} else if (minutes > 0) {
timeRemaining = {
minutes: minutes,
seconds: wholeSeconds
}
} else {
timeRemaining = {
seconds: wholeSeconds
}
}
return timeRemaining;
} else {
return 'Infinity';
}
}
torrent['percentComplete'] = percentComplete;
torrent['eta'] = eta();
});
} catch (error) {
console.log(error);
}
callback(null, torrents);
}, function(error) {
@@ -165,31 +234,41 @@ client.prototype.getTorrentList = function(callback) {
client.prototype.stopTorrent = function(hash, callback) {
hash = hash.split(',');
if (!util.isArray(hash)) {
hash = [hash];
}
rTorrent.get('d.stop', hash).then(function(data) {
callback(null, data);
}, function(error) {
console.log(error);
callback(error, null);
});
for (i = 0, len = hash.length; i < len; i++) {
rTorrent.get('d.stop', [hash[i]]).then(function(data) {
callback(null, data);
}, function(error) {
callback(error, null);
});
}
};
client.prototype.startTorrent = function(hash, callback) {
hash = hash.split(',');
if (!util.isArray(hash)) {
hash = [hash];
}
rTorrent.get('d.start', hash).then(function(data) {
callback(null, data);
}, function(error) {
console.log(error);
callback(error, null);
});
for (i = 0, len = hash.length; i < len; i++) {
rTorrent.get('d.start', [hash[i]]).then(function(data) {
callback(null, data);
}, function(error) {
callback(error, null);
});
}
};
+2
View File
@@ -56,6 +56,7 @@
}
&--primary {
flex: 1;
.torrent & {
color: $torrent--primary--foreground;
@@ -66,6 +67,7 @@
&--secondary {
display: flex;
flex: 2;
font-size: 0.85em;
&--sub {
+1 -1
View File
@@ -15,12 +15,12 @@ var performAction = function(action, hash, success, error) {
console.error(torrentsData, status, err.toString());
}.bind(this)
});
};
var TorrentActions = {
click: function(hash) {
AppDispatcher.dispatch({
actionType: TorrentConstants.TORRENT_CLICK,
hash: hash
@@ -1,15 +1,30 @@
var React = require('react');
var Action = require('./Action');
var UIStore = require('../../stores/UIStore');
var TorrentActions = require('../../actions/TorrentActions');
var getSelectedTorrents = function() {
return {
selectedTorrents: UIStore.getSelectedTorrents()
}
};
var FilterBar = React.createClass({
getInitialState: function() {
return null;
return {
selectedTorrents: []
};
},
handleClick: function(event) {
console.log('click ' + event.target);
componentDidMount: function() {
UIStore.addChangeListener(this._onUIStoreChange);
},
componentWillUnmount: function() {
TorrentStore.removeChangeListener(this._onUIStoreChange);
},
render: function() {
@@ -17,13 +32,30 @@ var FilterBar = React.createClass({
return (
<nav className="action-bar">
<ul className="actions">
<Action label="Start Torrent" slug="start-torrent" icon="start" clickHandler={this.handleClick} />
<Action label="Stop Torrent" slug="stop-torrent" icon="stop" clickHandler={this.handleClick} />
<Action label="Pause Torrent" slug="pause-torrent" icon="pause" clickHandler={this.handleClick} />
<Action label="Start Torrent" slug="start-torrent" icon="start" clickHandler={this._start} />
<Action label="Stop Torrent" slug="stop-torrent" icon="stop" clickHandler={this._stop} />
<Action label="Pause Torrent" slug="pause-torrent" icon="pause" clickHandler={this._pause} />
</ul>
</nav>
);
},
_pause: function() {
},
_start: function() {
TorrentActions.start(this.state.selectedTorrents);
},
_stop: function() {
TorrentActions.stop(this.state.selectedTorrents);
},
_onUIStoreChange: function() {
this.setState(getSelectedTorrents);
}
});
@@ -24,37 +24,95 @@ var Torrent = React.createClass({
var uploadTotal = format.data(torrent.uploadTotal);
var downloadRate = format.data(torrent.downloadRate, '/s');
var downloadTotal = format.data(torrent.downloadTotal);
var completed = format.data(torrent.bytesDone);
var totalSize = format.data(torrent.sizeBytes);
var eta = (function() {
if (torrent.eta === 'Infinity') {
return '∞';
} else if (torrent.eta.years > 0) {
return (
<span>
{torrent.eta.years}<em className="unit">y</em>
</span>
);
} else if (torrent.eta.weeks > 0) {
return (
<span>
{torrent.eta.weeks}<em className="unit">w</em>
{torrent.eta.days}<em className="unit">d</em>
</span>
);
} else if (torrent.eta.days > 0) {
return (
<span>
{torrent.eta.days}<em className="unit">d</em>
{torrent.eta.hours}<em className="unit">h</em>
</span>
);
} else if (torrent.eta.hours > 0) {
return (
<span>
{torrent.eta.hours}<em className="unit">h</em>
{torrent.eta.minutes}<em className="unit">m</em>
</span>
);
} else if (torrent.eta.minutes > 0) {
return (
<span>
{torrent.eta.minutes}<em className="unit">m</em>
{torrent.eta.seconds}<em className="unit">s</em>
</span>
);
} else {
return (
<span>
{torrent.eta.seconds}<em className="unit">s</em>
</span>
);
}
})();
return (
<li className={classes} onClick={this._onClick}>
<div className="torrent__details">
<span className="torrent__detail--primary">{torrent.name}</span>
<span className="torrent__detail--primary">{torrent.name}: {torrent.state}</span>
<ul className="torrent__detail--list torrent__detail--secondary">
<li className="torrent__detail--secondary--sub">{torrent.state}</li>
<li className="torrent__detail--secondary--sub">
{uploadRate.value}
<em className="unit">{uploadRate.unit}</em>
</li>
<li className="torrent__detail--secondary--sub">
{uploadTotal.value}
<em className="unit">{uploadTotal.unit}</em>
</li>
<li className="torrent__detail--secondary--sub">
{downloadRate.value}
<em className="unit">{downloadRate.unit}</em>
</li>
<li className="torrent__detail--secondary--sub">
{downloadTotal.value}
<em className="unit">{downloadTotal.unit}</em>
{eta}
</li>
<li className="torrent__detail--secondary--sub">
<span>
{torrent.percentComplete}
<em className="unit">%</em>
</span>
<span>
{completed.value}
<em className="unit">{completed.unit}</em>
</span>
</li>
<li className="torrent__detail--secondary--sub">
{totalSize.value}
<em className="unit">{totalSize.unit}</em>
</li>
<li className="torrent__detail--secondary--sub">
{torrent.ratio}
</li>
<li className="torrent__detail--secondary--sub" onClick={this._onStart}>
Start
<li className="torrent__detail--secondary--sub">
Prs
</li>
<li className="torrent__detail--secondary--sub" onClick={this._onStop}>
Stop
<li className="torrent__detail--secondary--sub">
Sds
</li>
</ul>
</div>
@@ -65,15 +123,8 @@ var Torrent = React.createClass({
_onClick: function() {
TorrentActions.click(this.props.data.hash);
},
_onStop: function() {
TorrentActions.stop(this.props.data.hash);
},
_onStart: function() {
TorrentActions.start(this.props.data.hash);
}
});
module.exports = Torrent;
@@ -15,7 +15,7 @@ var getSelectedTorrents = function() {
return {
selectedTorrents: UIStore.getSelectedTorrents()
}
}
};
var TorrentList = React.createClass({
@@ -61,14 +61,14 @@ var TorrentList = React.createClass({
<header className="torrent__header">
<span className="torrent__detail--primary">Name</span>
<div className="torrent__detail--secondary">
<span className="torrent__detail--secondary--sub">State</span>
<span className="torrent__detail--secondary--sub">Up</span>
<span className="torrent__detail--secondary--sub">&nbsp;</span>
<span className="torrent__detail--secondary--sub">Down</span>
<span className="torrent__detail--secondary--sub">&nbsp;</span>
<span className="torrent__detail--secondary--sub">ETA</span>
<span className="torrent__detail--secondary--sub">Completed</span>
<span className="torrent__detail--secondary--sub">Size</span>
<span className="torrent__detail--secondary--sub">Ratio</span>
<span className="torrent__detail--secondary--sub">Start</span>
<span className="torrent__detail--secondary--sub">Stop</span>
<span className="torrent__detail--secondary--sub">Peers</span>
<span className="torrent__detail--secondary--sub">Seeds</span>
</div>
</header>
{torrentList}