Performance improvements
* Pre-compute name, formatted sizes and speeds. * Handle name edge-cases such as no-path and no-uris better. * Unroll getCtx. * Improve performance of mergeMap. * Delay the search filter. As indicated by Chrome/Gecko profilers.
This commit is contained in:
parent
4ab27fb503
commit
38a413e95b
32
index.html
32
index.html
|
@ -264,7 +264,7 @@
|
|||
<fieldset>
|
||||
<div class="span4">
|
||||
<label for="downloadFilter">Search</label>
|
||||
<input id="downloadFilter" type="text" ng-model="downloadFilter" class="input-large"/>
|
||||
<input id="downloadFilter" type="text" ng-model="downloadFilter" ng-change="onDownloadFilter()" class="input-large"/>
|
||||
<br>
|
||||
<b>Found: {{totalDownloads}} / {{totalAria2Downloads()}} </b>
|
||||
</div>
|
||||
|
@ -277,7 +277,7 @@
|
|||
<tbody>
|
||||
<tr>
|
||||
<td class="download-name download-item" ng-click="download.collapsed = !download.collapsed">
|
||||
{{getName(download)}}
|
||||
{{download.name}}
|
||||
</td>
|
||||
<td class="download-controls download-item" rowspan="2">
|
||||
<!-- {{{ download control buttons -->
|
||||
|
@ -368,11 +368,11 @@
|
|||
</li>
|
||||
|
||||
<li class="label label-active hidden-phone">
|
||||
<span title="Download Size"><i class="icon-cloud-download"> </i> {{download.totalLength | blength}}</span>
|
||||
<span title="Download Size"><i class="icon-cloud-download"> </i> {{download.fmtTotalLength}}</span>
|
||||
</li>
|
||||
|
||||
<li class="label label-active hidden-phone">
|
||||
<span title="Downloaded"><i class="icon-download-alt"> </i> {{download.completedLength | blength}}</span>
|
||||
<span title="Downloaded"><i class="icon-download-alt"> </i> {{download.fmtCompletedLength}}</span>
|
||||
</li>
|
||||
|
||||
<li class="label label-active hidden-phone hidden-tablet">
|
||||
|
@ -389,11 +389,11 @@
|
|||
</li>
|
||||
|
||||
<li class="label label-info">
|
||||
<span title="Download Size"><i class="icon-cloud-download"> </i> {{download.totalLength | blength}}</span>
|
||||
<span title="Download Size"><i class="icon-cloud-download"> </i> {{download.fmtTotalLength}}</span>
|
||||
</li>
|
||||
|
||||
<li class="label label-info hidden-phone">
|
||||
<span title="Downloaded"><i class="icon-download-alt"> </i> {{download.completedLength | blength}}</span>
|
||||
<span title="Downloaded"><i class="icon-download-alt"> </i> {{download.fmtCompletedLength}}</span>
|
||||
</li>
|
||||
|
||||
<li class="label label-info hidden-phone">
|
||||
|
@ -436,7 +436,7 @@
|
|||
</li>
|
||||
|
||||
<li class="label label-success">
|
||||
<span title="Download Size"><i class="icon-cloud-download"> </i> {{download.totalLength | blength}}</span>
|
||||
<span title="Download Size"><i class="icon-cloud-download"> </i> {{download.fmtTotalLength}}</span>
|
||||
</li>
|
||||
|
||||
<!-- }}} -->
|
||||
|
@ -455,7 +455,7 @@
|
|||
|
||||
<li ng-show="hasStatus(download, 'removed')"
|
||||
class="label label-warning">
|
||||
<span title="Download Size"><i class="icon-cloud-download"> </i> {{download.totalLength | blength}}</span>
|
||||
<span title="Download Size"><i class="icon-cloud-download"> </i> {{download.fmtTotalLength}}</span>
|
||||
</li>
|
||||
<!-- }}} -->
|
||||
</ul>
|
||||
|
@ -471,7 +471,7 @@
|
|||
</li>
|
||||
|
||||
<li class="label label-important">
|
||||
<span title="Download Size"><i class="icon-cloud-download"> </i> {{download.totalLength | blength}}</span>
|
||||
<span title="Download Size"><i class="icon-cloud-download"> </i> {{download.fmtTotalLength}}</span>
|
||||
</li>
|
||||
<!-- }}} -->
|
||||
</ul>
|
||||
|
@ -495,21 +495,21 @@
|
|||
<ul class="stats download-item">
|
||||
<li class="label" title="Download Path"><i class="icon-folder-open"> </i> <span class="download-dir">{{download.dir}}</span></li>
|
||||
<li class="label" title="Estimated Time"><i class="icon-time"> </i> <span class="download-eta">{{getEta(download) | time}}</span></li>
|
||||
<li class="label" title="Download Size"><i class="icon-cloud-download"> </i> <span class="download-totalLength">{{download.totalLength | blength}}</span></li>
|
||||
<li class="label" title="Downloaded"><i class="icon-download-alt"> </i> <span class="download-completedLength">{{download.completedLength | blength}}</span></li>
|
||||
<li class="label" title="Download Speed"><i class="icon-download"> </i> <span class="download-downloadSpeed">{{download.downloadSpeed | bspeed}}</span></li>
|
||||
<li class="label" title="Download Size"><i class="icon-cloud-download"> </i> <span class="download-totalLength">{{download.fmtTotalLength}}</span></li>
|
||||
<li class="label" title="Downloaded"><i class="icon-download-alt"> </i> <span class="download-completedLength">{{download.fmtCompletedLength}}</span></li>
|
||||
<li class="label" title="Download Speed"><i class="icon-download"> </i> <span class="download-downloadSpeed">{{download.fmtDownloadSpeed}}</span></li>
|
||||
|
||||
<li class="label" title="Upload Speed" ng-show="download.bittorrent"><i class="icon-upload"> </i> <span class="download-uploadSpeed">{{download.uploadSpeed | bspeed}}</span></li>
|
||||
<li class="label" title="Uploaded" ng-show="download.bittorrent"><i class="icon-upload-alt"> </i> <span class="download-uploadLength">{{download.uploadLength | blength}}</span></li>
|
||||
<li class="label" title="Upload Speed" ng-show="download.bittorrent"><i class="icon-upload"> </i> <span class="download-uploadSpeed">{{download.fmtUploadSpeed}}</span></li>
|
||||
<li class="label" title="Uploaded" ng-show="download.bittorrent"><i class="icon-upload-alt"> </i> <span class="download-uploadLength">{{download.fmtUploadLength}}</span></li>
|
||||
|
||||
<li class="label" title="Connections"><i class="icon-link"> </i> <span class="download-connections">{{download.connections}}</span></li>
|
||||
|
||||
<li class="label" title="Download GID"><i class="icon-reorder"> </i> <span class="download-gid">{{download.gid}}</span></li>
|
||||
<li class="label" title="Number of Pieces"># of <i class="icon-puzzle-piece"> </i> <span class="download-numPieces">{{download.numPieces}}</span></li>
|
||||
<li class="label" title="Piece Length"><i class="icon-puzzle-piece"></i> Length <span class="download-pieceLength">{{download.pieceLength | blength}}</span></li>
|
||||
<li class="label" title="Piece Length"><i class="icon-puzzle-piece"></i> Length <span class="download-pieceLength">{{download.fmtPieceLength}}</span></li>
|
||||
</ul>
|
||||
<ul class="download-files hidden-phone download-item">
|
||||
<li class="label" ng-repeat="file in download.files">{{file.relpath}} ({{file.length | blength}})</li>
|
||||
<li class="label" ng-repeat="file in download.files">{{file.relpath}} ({{file.fmtLength}})</li>
|
||||
</ul>
|
||||
<div ng-show="hasStatus(download, 'active')" class="download-item">
|
||||
<div class="download-graph" dspeed="download.downloadSpeed" uspeed="download.uploadSpeed" dgraph draw="!download.collapsed"></div>
|
||||
|
|
|
@ -106,10 +106,26 @@ function(
|
|||
|
||||
// download search filter
|
||||
scope.downloadFilter = "";
|
||||
scope.downloadFilterCommitted = "";
|
||||
|
||||
scope.onDownloadFilter = function() {
|
||||
if (scope.downloadFilterTimer) {
|
||||
clearTimeout(scope.downloadFilterTimer);
|
||||
}
|
||||
scope.downloadFilterTimer = setTimeout(function() {
|
||||
delete scope.downloadFilterTimer;
|
||||
if (scope.downloadFilterCommitted !== scope.downloadFilter) {
|
||||
scope.downloadFilterCommitted = scope.downloadFilter;
|
||||
scope.$digest();
|
||||
}
|
||||
}, 500);
|
||||
};
|
||||
|
||||
scope.filterDownloads = function(downloads) {
|
||||
var filter = scope.downloadFilter;
|
||||
if (!filter.length) return downloads;
|
||||
if (!scope.downloadFilterCommitted) {
|
||||
return downloads;
|
||||
}
|
||||
var filter = scope.downloadFilterCommitted;
|
||||
return _.filter(downloads, function(d) {
|
||||
if (!d.files.length) return true;
|
||||
|
||||
|
@ -187,27 +203,79 @@ function(
|
|||
// convert the donwload form aria2 to once used by the view,
|
||||
// minor additions of some fields and checks
|
||||
scope.getCtx = function(d, ctx) {
|
||||
ctx = ctx || {};
|
||||
if (!ctx) {
|
||||
ctx = {
|
||||
dir: d.dir,
|
||||
status: d.status,
|
||||
gid: d.gid,
|
||||
numPieces: d.numPieces,
|
||||
connections: d.connections,
|
||||
bitfield: d.bitfield,
|
||||
totalLength: d.totalLength,
|
||||
fmtTotalLength: utils.fmtsize(d.totalLength),
|
||||
completedLength: d.completedLength,
|
||||
fmtCompletedLength: utils.fmtsize(d.completedLength),
|
||||
uploadLength: d.uploadLength,
|
||||
fmtUploadLength: utils.fmtsize(d.uploadLength),
|
||||
pieceLength: d.pieceLength,
|
||||
fmtPieceLength: utils.fmtsize(d.pieceLength),
|
||||
downloadSpeed: d.downloadSpeed,
|
||||
fmtDownloadSpeed: utils.fmtspeed(d.downloadSpeed),
|
||||
uploadSpeed: d.uploadSpeed,
|
||||
fmtUploadSpeed: utils.fmtspeed(d.uploadSpeed),
|
||||
files: []
|
||||
};
|
||||
}
|
||||
else {
|
||||
ctx.dir = d.dir;
|
||||
ctx.status = d.status;
|
||||
ctx.gid = d.gid;
|
||||
ctx.numPieces = d.numPieces;
|
||||
ctx.connections = d.connections;
|
||||
ctx.bitfield = d.bitfield;
|
||||
if (ctx.totalLength !== d.totalLength) {
|
||||
ctx.totalLength = d.totalLength;
|
||||
ctx.fmtTotalLength = utils.fmtsize(d.totalLength);
|
||||
}
|
||||
if (ctx.completedLength !== d.completedLength) {
|
||||
ctx.completedLength = d.completedLength;
|
||||
ctx.fmtCompletedLength = utils.fmtsize(d.completedLength);
|
||||
}
|
||||
if (ctx.uploadLength !== d.uploadength) {
|
||||
ctx.uploadLength = d.uploadlength;
|
||||
ctx.fmtUploadLength = utils.fmtsize(d.uploadLength);
|
||||
}
|
||||
if (ctx.pieceLength !== d.pieceLength) {
|
||||
ctx.pieceLength = d.pieceLength;
|
||||
ctx.fmtPieceLength = utils.fmtsize(d.pieceLength);
|
||||
}
|
||||
if (ctx.downloadSpeed !== d.downloadSpeed) {
|
||||
ctx.downloadSpeed = d.downloadSpeed;
|
||||
ctx.fmtDownloadSpeed = utils.fmtspeed(d.downloadSpeed);
|
||||
}
|
||||
if (ctx.uploadSpeed !== d.uploadSpeed) {
|
||||
ctx.uploadSpeed = d.uploadSpeed;
|
||||
ctx.fmtUploadSpeed = utils.fmtspeed(d.uploadSpeed);
|
||||
}
|
||||
}
|
||||
|
||||
_.each([
|
||||
'totalLength', 'completedLength', 'uploadLength', 'dir',
|
||||
'pieceLength', 'downloadSpeed', 'uploadSpeed', 'status',
|
||||
'gid', 'numPieces', 'connections', 'bitfield'
|
||||
], function(e) {
|
||||
ctx[e] = d[e];
|
||||
});
|
||||
|
||||
var files = d["files"];
|
||||
var dlName;
|
||||
var files = d.files;
|
||||
if (files) {
|
||||
var cfiles = ctx["files"] || (ctx["files"] = []);
|
||||
dlName = files[0].path || d.files[0].uris[0].uri;
|
||||
var cfiles = ctx.files;
|
||||
for (var i = 0; i < files.length; ++i) {
|
||||
var cfile = cfiles[i] || (cfiles[i] = {});
|
||||
var file = files[i];
|
||||
if (file.path !== cfile.path) {
|
||||
cfile.path = file.path;
|
||||
cfile.length = file.length;
|
||||
cfile.fmtLength = utils.fmtsize(file.length);
|
||||
cfile.relpath = file.path.replace(re_slashes, slash);
|
||||
if (!cfile.relpath.startsWith("[")) { // METADATA
|
||||
if (!cfile.relpath) {
|
||||
cfile.relpath = (file.uris && file.uris[0] && file.uris[0].uri) || "Unknown";
|
||||
}
|
||||
else if (!cfile.relpath.startsWith("[")) { // METADATA
|
||||
cfile.relpath = cfile.relpath.substr(ctx.dir.length + 1);
|
||||
}
|
||||
}
|
||||
|
@ -215,20 +283,24 @@ function(
|
|||
cfiles.length = files.length;
|
||||
}
|
||||
else {
|
||||
delete ctx["files"];
|
||||
delete ctx.files;
|
||||
}
|
||||
|
||||
var btName;
|
||||
if (d.bittorrent) {
|
||||
ctx.bittorrentName = d.bittorrent.info && d.bittorrent.info.name;
|
||||
btName = d.bittorrent.info && d.bittorrent.info.name;
|
||||
ctx.bittorrent = true;
|
||||
}
|
||||
else {
|
||||
delete ctx.bittorrentName;
|
||||
delete ctx.bittorrent;
|
||||
}
|
||||
|
||||
ctx.name = btName || utils.getFileName(dlName) || dlName || "Unknown";
|
||||
|
||||
// collapse the download details initially
|
||||
if (ctx.collapsed === undefined)
|
||||
if (ctx.collapsed === undefined) {
|
||||
ctx.collapsed = true;
|
||||
}
|
||||
|
||||
return ctx;
|
||||
};
|
||||
|
@ -284,17 +356,6 @@ function(
|
|||
return percentage;
|
||||
};
|
||||
|
||||
// gets a pretty name for the download
|
||||
scope.getName = function(d) {
|
||||
if (d.bittorrentName) {
|
||||
return d.bittorrentName;
|
||||
}
|
||||
|
||||
return utils.getFileName(
|
||||
d.files[0].path || d.files[0].uris[0].uri
|
||||
);
|
||||
}
|
||||
|
||||
// gets the type for the download as classified by the aria2 rpc calls
|
||||
scope.getType = function(d) {
|
||||
var type = d.status;
|
||||
|
@ -320,7 +381,7 @@ function(
|
|||
settings[i].val = vals[i] || settings[i].val;
|
||||
}
|
||||
|
||||
modals.invoke('settings', settings, scope.getName(d) + ' settings', function(settings) {
|
||||
modals.invoke('settings', settings, scope.name + ' settings', function(settings) {
|
||||
var sets = {};
|
||||
for (var i in settings) { sets[i] = settings[i].val };
|
||||
|
||||
|
|
|
@ -1,31 +1,11 @@
|
|||
(function() {
|
||||
function fmtlen(len) {
|
||||
len = +len; // coerce to number
|
||||
if (len <= 1024) {
|
||||
return len.toFixed(0) + " B";
|
||||
}
|
||||
len /= 1024;
|
||||
if (len <= 1024) {
|
||||
return len.toFixed(1) + " KB"
|
||||
}
|
||||
len /= 1024;
|
||||
if (len <= 1024) {
|
||||
return len.toFixed(2) + " MB";
|
||||
}
|
||||
len /= 1024;
|
||||
return len.toFixed(3) + " GB";
|
||||
}
|
||||
|
||||
angular .module('webui.filters.bytes', [])
|
||||
.filter('blength', ['$filter', function(filter) {
|
||||
return fmtlen;
|
||||
}])
|
||||
.filter('bspeed', ['$filter', function(filter) {
|
||||
return function(speed) {
|
||||
return fmtlen(speed) + "/s";
|
||||
};
|
||||
}])
|
||||
.filter('time', function() {
|
||||
angular.module('webui.filters.bytes', ["webui.services.utils"])
|
||||
.filter('blength', ['$filter', "$utils", function(filter, utils) {
|
||||
return utils.fmtsize;
|
||||
}])
|
||||
.filter('bspeed', ['$filter', "$utils", function(filter, utils) {
|
||||
return utils.fmtspeed;
|
||||
}])
|
||||
.filter('time', function() {
|
||||
function pad(f) {
|
||||
return ("0" + f).substr(-2);
|
||||
}
|
||||
|
@ -42,6 +22,4 @@
|
|||
var days = Math.floor(time / 86400);
|
||||
return days + "::" + pad(hrs) + ":" + pad(mins) + ":" + pad(secs);
|
||||
};
|
||||
});
|
||||
})();
|
||||
|
||||
});
|
||||
|
|
|
@ -26,7 +26,28 @@ angular.module('webui.services.utils', [])
|
|||
};
|
||||
})();
|
||||
|
||||
return {
|
||||
var utils = {
|
||||
|
||||
fmtsize: function(len) {
|
||||
len = +len; // coerce to number
|
||||
if (len <= 1024) {
|
||||
return len.toFixed(0) + " B";
|
||||
}
|
||||
len /= 1024;
|
||||
if (len <= 1024) {
|
||||
return len.toFixed(1) + " KB"
|
||||
}
|
||||
len /= 1024;
|
||||
if (len <= 1024) {
|
||||
return len.toFixed(2) + " MB";
|
||||
}
|
||||
len /= 1024;
|
||||
return len.toFixed(3) + " GB";
|
||||
},
|
||||
|
||||
fmtspeed: function(speed) {
|
||||
return utils.fmtsize(speed) + "/s";
|
||||
},
|
||||
// saves the key value pair in cookies
|
||||
setCookie: function(key, value) {
|
||||
var exdate = new Date();
|
||||
|
@ -70,31 +91,29 @@ angular.module('webui.services.utils', [])
|
|||
};
|
||||
})(),
|
||||
randStr: function() {
|
||||
return this.uuid();
|
||||
return utils.uuid();
|
||||
},
|
||||
|
||||
// maps the array in place to the destination
|
||||
// arr, dest (optional): array
|
||||
// func: a merge mapping func, see ctrls/download.js
|
||||
mergeMap: function(arr, dest, func) {
|
||||
if (!dest) dest = [];
|
||||
|
||||
for (var i = 0; i < dest.length; i++) {
|
||||
if (i >= arr.length) {
|
||||
// remove the deleted downloads
|
||||
dest.splice(i, dest.length - arr.length);
|
||||
break;
|
||||
if (!dest) {
|
||||
dest = [];
|
||||
}
|
||||
if (!dest[i]) dest[i] = {};
|
||||
|
||||
for (var i = 0, e = Math.min(arr.length, dest.length); i < e; ++i) {
|
||||
func(arr[i], dest[i]);
|
||||
}
|
||||
|
||||
// insert newly created downloads
|
||||
// Insert newly created downloads
|
||||
while (i < arr.length) {
|
||||
dest.push(func(arr[i++]));
|
||||
}
|
||||
|
||||
// Truncate if necessary.
|
||||
dest.length = arr.length;
|
||||
|
||||
return dest;
|
||||
},
|
||||
// get info title from global statistics
|
||||
|
@ -144,4 +163,5 @@ angular.module('webui.services.utils', [])
|
|||
return chunks;
|
||||
}
|
||||
};
|
||||
return utils;
|
||||
}]);
|
||||
|
|
Loading…
Reference in New Issue
Block a user