2016-05-31 16:51:12 +02:00
|
|
|
(function () {
|
|
|
|
'use strict';
|
|
|
|
|
2016-06-04 10:52:24 +02:00
|
|
|
angular.module('ariaNg').factory('aria2TaskService', ['$q', '$translate', 'aria2RpcService', function ($q, $translate, aria2RpcService) {
|
2016-05-31 16:51:12 +02:00
|
|
|
var getFileNameFromPath = function (path) {
|
|
|
|
if (!path) {
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
|
|
|
|
var index = path.lastIndexOf('/');
|
|
|
|
|
|
|
|
if (index <= 0 || index == path.length) {
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
|
|
|
|
return path.substring(index + 1);
|
|
|
|
};
|
|
|
|
|
|
|
|
var calculateDownloadRemainTime = function (remainBytes, downloadSpeed) {
|
|
|
|
if (downloadSpeed == 0) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return remainBytes / downloadSpeed;
|
|
|
|
};
|
|
|
|
|
|
|
|
var getTaskName = function (task) {
|
|
|
|
var taskName = "";
|
|
|
|
|
|
|
|
if (task.bittorrent && task.bittorrent.info) {
|
|
|
|
taskName = task.bittorrent.info.name;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!taskName && task.files && task.files.length >= 1) {
|
|
|
|
taskName = getFileNameFromPath(task.files[0].path);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!taskName && task.files && task.files.length >= 1 && task.files[0].uris && task.files[0].uris.length >= 1) {
|
|
|
|
taskName = getFileNameFromPath(task.files[0].uris[0].uri);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!taskName) {
|
|
|
|
taskName = $translate.instant('Unknown');
|
|
|
|
}
|
|
|
|
|
|
|
|
return taskName;
|
|
|
|
};
|
|
|
|
|
|
|
|
var processDownloadTask = function (task) {
|
|
|
|
if (!task) {
|
|
|
|
return task;
|
|
|
|
}
|
|
|
|
|
|
|
|
task.totalLength = parseInt(task.totalLength);
|
|
|
|
task.completedLength = parseInt(task.completedLength);
|
|
|
|
task.completePercent = (task.totalLength > 0 ? task.completedLength / task.totalLength * 100 : 0);
|
2016-05-31 16:55:25 +02:00
|
|
|
task.remainLength = task.totalLength - task.completedLength;
|
2016-05-31 16:51:12 +02:00
|
|
|
task.remainPercent = 100 - task.completePercent;
|
2016-05-31 16:55:25 +02:00
|
|
|
|
|
|
|
task.uploadSpeed = parseInt(task.uploadSpeed);
|
|
|
|
task.downloadSpeed = parseInt(task.downloadSpeed);
|
|
|
|
|
2016-05-31 16:51:12 +02:00
|
|
|
task.taskName = getTaskName(task);
|
|
|
|
task.idle = task.downloadSpeed == 0;
|
|
|
|
|
2016-05-31 16:55:25 +02:00
|
|
|
task.remainTime = calculateDownloadRemainTime(task.remainLength, task.downloadSpeed);
|
2016-05-31 16:51:12 +02:00
|
|
|
|
|
|
|
if (task.files) {
|
|
|
|
for (var i = 0; i < task.files.length; i++) {
|
|
|
|
var file = task.files[i];
|
|
|
|
file.fileName = getFileNameFromPath(file.path);
|
|
|
|
file.length = parseInt(file.length);
|
|
|
|
file.completedLength = parseInt(file.completedLength);
|
|
|
|
file.completePercent = (file.length > 0 ? file.completedLength / file.length * 100 : 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return task;
|
|
|
|
};
|
|
|
|
|
|
|
|
var estimateCompletedPercentFromBitField = function (bitfield) {
|
|
|
|
var totalLength = bitfield.length * 0xf;
|
|
|
|
var completedLength = 0;
|
|
|
|
|
|
|
|
if (totalLength == 0) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (var i = 0; i < bitfield.length; i++) {
|
|
|
|
var num = parseInt(bitfield[i], 16);
|
|
|
|
completedLength += num;
|
|
|
|
}
|
|
|
|
|
|
|
|
return completedLength / totalLength;
|
|
|
|
};
|
|
|
|
|
|
|
|
return {
|
2016-06-04 09:33:40 +02:00
|
|
|
getTaskList: function (type, full, callback, silent) {
|
2016-05-31 16:51:12 +02:00
|
|
|
var invokeMethod = null;
|
|
|
|
|
|
|
|
if (type == 'downloading') {
|
|
|
|
invokeMethod = aria2RpcService.tellActive;
|
|
|
|
} else if (type == 'waiting') {
|
|
|
|
invokeMethod = aria2RpcService.tellWaiting;
|
|
|
|
} else if (type == 'stopped') {
|
|
|
|
invokeMethod = aria2RpcService.tellStopped;
|
|
|
|
} else {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
return invokeMethod({
|
|
|
|
requestParams: full ? aria2RpcService.getFullTaskParams() : aria2RpcService.getBasicTaskParams(),
|
2016-06-04 09:33:40 +02:00
|
|
|
silent: !!silent,
|
2016-05-31 16:51:12 +02:00
|
|
|
callback: function (result) {
|
|
|
|
if (!callback) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
callback(result);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
},
|
2016-06-04 09:33:40 +02:00
|
|
|
getTaskStatus: function (gid, callback, silent) {
|
2016-05-31 16:51:12 +02:00
|
|
|
return aria2RpcService.tellStatus({
|
|
|
|
gid: gid,
|
2016-06-04 09:33:40 +02:00
|
|
|
silent: !!silent,
|
2016-05-31 16:51:12 +02:00
|
|
|
callback: function (result) {
|
|
|
|
if (!callback) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
var task = processDownloadTask(result);
|
|
|
|
callback(task);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
},
|
2016-06-01 18:02:10 +02:00
|
|
|
getTaskOptions: function (gid, callback) {
|
2016-05-31 16:51:12 +02:00
|
|
|
return aria2RpcService.getOption({
|
|
|
|
gid: gid,
|
|
|
|
callback: callback
|
|
|
|
});
|
|
|
|
},
|
2016-06-01 18:02:10 +02:00
|
|
|
setTaskOption: function (gid, key, value, callback) {
|
|
|
|
var data = {};
|
|
|
|
data[key] = value;
|
2016-06-04 09:33:40 +02:00
|
|
|
|
2016-06-01 18:02:10 +02:00
|
|
|
return aria2RpcService.changeOption({
|
|
|
|
gid: gid,
|
|
|
|
options: data,
|
|
|
|
callback: callback
|
|
|
|
});
|
|
|
|
},
|
2016-06-04 09:33:40 +02:00
|
|
|
getBtTaskPeers: function (gid, callback, silent) {
|
2016-05-31 16:51:12 +02:00
|
|
|
return aria2RpcService.getPeers({
|
|
|
|
gid: gid,
|
2016-06-04 09:33:40 +02:00
|
|
|
silent: !!silent,
|
2016-05-31 16:51:12 +02:00
|
|
|
callback: function (result) {
|
|
|
|
if (!callback) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (result) {
|
|
|
|
for (var i = 0; i < result.length; i++) {
|
|
|
|
var peer = result[i];
|
|
|
|
peer.completePercent = estimateCompletedPercentFromBitField(peer.bitfield) * 100;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
callback(result);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
},
|
|
|
|
startTasks: function (gids, callback) {
|
|
|
|
return aria2RpcService.unpauseMulti({
|
|
|
|
gids: gids,
|
|
|
|
callback: callback
|
|
|
|
});
|
|
|
|
},
|
|
|
|
pauseTasks: function (gids, callback) {
|
|
|
|
return aria2RpcService.forcePauseMulti({
|
|
|
|
gids: gids,
|
|
|
|
callback: callback
|
|
|
|
});
|
|
|
|
},
|
2016-06-04 10:52:24 +02:00
|
|
|
removeTasks: function (tasks, callback) {
|
|
|
|
var runningTaskGids = [];
|
|
|
|
var stoppedTaskGids = [];
|
|
|
|
|
|
|
|
for (var i = 0; i < tasks.length; i++) {
|
|
|
|
if (tasks[i].status == 'complete' || tasks[i].status == 'error' || tasks[i].status == 'removed') {
|
|
|
|
stoppedTaskGids.push(tasks[i].gid);
|
|
|
|
} else {
|
|
|
|
runningTaskGids.push(tasks[i].gid);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var promises = [];
|
|
|
|
var results = {
|
|
|
|
runningResult: null,
|
|
|
|
stoppedResult: null
|
|
|
|
};
|
|
|
|
|
|
|
|
if (runningTaskGids.length > 0) {
|
|
|
|
promises.push(aria2RpcService.forceRemoveMulti({
|
|
|
|
gids: runningTaskGids,
|
|
|
|
callback: function (result) {
|
|
|
|
results.runningResult = result;
|
|
|
|
}
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (stoppedTaskGids.length > 0) {
|
|
|
|
promises.push(aria2RpcService.removeDownloadResultMulti({
|
|
|
|
gids: stoppedTaskGids,
|
|
|
|
callback: function (result) {
|
|
|
|
results.stoppedResult = result;
|
|
|
|
}
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
|
|
|
return $q.all(promises).then(function () {
|
|
|
|
if (callback) {
|
|
|
|
callback(results);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
},
|
2016-05-31 18:09:11 +02:00
|
|
|
changeTaskPosition: function (gid, position, callback) {
|
|
|
|
return aria2RpcService.changePosition({
|
|
|
|
gid: gid,
|
|
|
|
pos: position,
|
|
|
|
how: 'POS_SET',
|
|
|
|
callback: callback
|
|
|
|
})
|
|
|
|
},
|
2016-06-04 10:52:24 +02:00
|
|
|
clearStoppedTasks: function (callback) {
|
|
|
|
return aria2RpcService.purgeDownloadResult({
|
|
|
|
callback: callback
|
|
|
|
});
|
|
|
|
},
|
2016-05-31 16:51:12 +02:00
|
|
|
processDownloadTasks: function (tasks) {
|
|
|
|
if (!angular.isArray(tasks)) {
|
|
|
|
return;
|
|
|
|
}
|
2016-05-31 16:55:25 +02:00
|
|
|
|
2016-05-31 16:51:12 +02:00
|
|
|
for (var i = 0; i < tasks.length; i++) {
|
|
|
|
processDownloadTask(tasks[i]);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
estimateHealthPercentFromPeers: function (task, peers) {
|
|
|
|
if (peers.length < 1) {
|
|
|
|
return task.completePercent;
|
|
|
|
}
|
|
|
|
|
|
|
|
var bitfieldCompletedArr = new Array(task.bitfield.length);
|
|
|
|
var bitfieldPieceArr = new Array(task.bitfield.length);
|
|
|
|
var totalLength = task.bitfield.length * 0xf;
|
|
|
|
var healthBitCount = 0;
|
|
|
|
|
|
|
|
for (var i = 0; i < task.bitfield.length; i++) {
|
|
|
|
var num = parseInt(task.bitfield[i], 16);
|
|
|
|
bitfieldCompletedArr[i] = 0;
|
|
|
|
bitfieldPieceArr[i] = 0;
|
|
|
|
|
|
|
|
if (num == 0xf) {
|
|
|
|
bitfieldCompletedArr[i] = num;
|
|
|
|
} else {
|
|
|
|
bitfieldPieceArr[i] = num;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (var i = 0; i < peers.length; i++) {
|
|
|
|
var peer = peers[i];
|
|
|
|
var bitfield = peer.bitfield;
|
|
|
|
|
|
|
|
for (var j = 0; j < bitfield.length; j++) {
|
|
|
|
var num = parseInt(bitfield[j], 16);
|
|
|
|
|
|
|
|
if (num == 0xf) {
|
|
|
|
bitfieldCompletedArr[j] += num;
|
|
|
|
} else {
|
|
|
|
bitfieldPieceArr[j] = Math.max(bitfieldPieceArr[j], num);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (var i = 0; i < bitfieldCompletedArr.length; i++) {
|
|
|
|
bitfieldCompletedArr[i] += bitfieldPieceArr[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
var completed = true;
|
|
|
|
|
|
|
|
for (var i = 0; i < bitfieldCompletedArr.length; i++) {
|
|
|
|
var bitCount = Math.min(bitfieldCompletedArr[i], 0xf);
|
|
|
|
healthBitCount += bitCount;
|
|
|
|
bitfieldCompletedArr[i] -= bitCount;
|
|
|
|
|
|
|
|
if (bitCount < 0xf) {
|
|
|
|
completed = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!completed) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var healthPercent = healthBitCount / totalLength * 100;
|
|
|
|
|
|
|
|
if (healthPercent < task.completePercent) {
|
|
|
|
healthPercent = task.completePercent;
|
|
|
|
}
|
|
|
|
|
|
|
|
return healthPercent;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}]);
|
|
|
|
})();
|