This repository has been archived on 2022-01-02. You can view files and clone it, but cannot push or open issues/pull-requests.
AriaNg/src/scripts/services/aria2TaskService.js

432 lines
16 KiB
JavaScript

(function () {
'use strict';
angular.module('ariaNg').factory('aria2TaskService', ['$q', '$translate', 'aria2RpcService', 'ariaNgCommonService', function ($q, $translate, aria2RpcService, ariaNgCommonService) {
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 = "";
var success = true;
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');
success = false;
}
return {
name: taskName,
success: success
};
};
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);
task.remainLength = task.totalLength - task.completedLength;
task.remainPercent = 100 - task.completePercent;
task.uploadLength = (task.uploadLength ? parseInt(task.uploadLength) : 0);
task.shareRatio = (task.uploadLength / task.completedLength);
task.uploadSpeed = parseInt(task.uploadSpeed);
task.downloadSpeed = parseInt(task.downloadSpeed);
task.idle = task.downloadSpeed == 0;
task.remainTime = calculateDownloadRemainTime(task.remainLength, task.downloadSpeed);
var taskNameResult = getTaskName(task);
task.taskName = taskNameResult.name;
task.hasTaskName = taskNameResult.success;
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.selected = (file.selected == 'true');
file.completedLength = parseInt(file.completedLength);
file.completePercent = (file.length > 0 ? file.completedLength / file.length * 100 : 0);
}
}
return task;
};
var getPieceStatus = function (bitField, pieceCount) {
var pieces = [];
if (!bitField) {
return pieces;
}
var pieceIndex = 0;
for (var i = 0; i < bitField.length; i++) {
var bitSet = parseInt(bitField[i], 16);
for (var j = 1; j <= 4; j++) {
var bit = (1 << (4 - j));
var isCompleted = (bitSet & bit) == bit;
pieces.push(isCompleted);
pieceIndex++;
if (pieceIndex >= pieceCount) {
return pieces;
}
}
}
return pieces;
};
var getCombinedPieces = function (bitField, pieceCount) {
var pieces = getPieceStatus(bitField, pieceCount);
var combinedPieces = [];
for (var i = 0; i < pieces.length; i++) {
var isCompleted = pieces[i];
if (combinedPieces.length > 0 && combinedPieces[combinedPieces.length - 1].isCompleted == isCompleted) {
combinedPieces[combinedPieces.length - 1].count++;
} else {
combinedPieces.push({
isCompleted: isCompleted,
count: 1
});
}
}
return combinedPieces;
};
var createLocalPeerFromTask = function (task) {
return {
local: true,
bitfield: task.bitfield,
completePercent: task.completePercent,
downloadSpeed: task.downloadSpeed,
name: '(local)',
seeder: task.seeder,
uploadSpeed: task.uploadSpeed
};
};
return {
getTaskList: function (type, full, callback, silent) {
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({
requestWholeInfo: full,
requestParams: full ? aria2RpcService.getFullTaskParams() : aria2RpcService.getBasicTaskParams(),
silent: !!silent,
callback: function (response) {
if (!callback) {
return;
}
callback(response);
}
});
},
getTaskStatus: function (gid, callback, silent) {
return aria2RpcService.tellStatus({
gid: gid,
silent: !!silent,
callback: function (response) {
if (!callback) {
return;
}
if (response.success) {
processDownloadTask(response.data);
}
callback(response);
}
});
},
getTaskOptions: function (gid, callback, silent) {
return aria2RpcService.getOption({
gid: gid,
silent: !!silent,
callback: callback
});
},
setTaskOption: function (gid, key, value, callback, silent) {
var data = {};
data[key] = value;
return aria2RpcService.changeOption({
gid: gid,
options: data,
silent: !!silent,
callback: callback
});
},
selectTaskFile: function (gid, selectedFileIndexArr, callback, silent) {
var selectedFileIndex = '';
for (var i = 0; i < selectedFileIndexArr.length; i++) {
if (selectedFileIndex.length > 0) {
selectedFileIndex += ',';
}
selectedFileIndex += selectedFileIndexArr[i];
}
return this.setTaskOption(gid, 'select-file', selectedFileIndex, callback, silent);
},
getBtTaskPeers: function (task, callback, silent, includeLocal) {
return aria2RpcService.getPeers({
gid: task.gid,
silent: !!silent,
callback: function (response) {
if (!callback) {
return;
}
if (response.success) {
var peers = response.data;
for (var i = 0; i < peers.length; i++) {
var peer = peers[i];
var upstreamToSpeed = peer.uploadSpeed;
var downstreamFromSpeed = peer.downloadSpeed;
var completedPieces = getPieceStatus(peer.bitfield, task.numPieces);
peer.name = peer.ip + ':' + peer.port;
peer.completePercent = ariaNgCommonService.countArray(completedPieces, true) / task.numPieces * 100;
peer.downloadSpeed = upstreamToSpeed;
peer.uploadSpeed = downstreamFromSpeed;
}
if (includeLocal) {
peers.push(createLocalPeerFromTask(task));
}
}
callback(response);
}
});
},
newUriTasks: function (tasks, pauseOnAdded, callback, silent) {
return aria2RpcService.addUriMulti({
tasks: tasks,
pauseOnAdded: !!pauseOnAdded,
silent: !!silent,
callback: callback
});
},
startTasks: function (gids, callback, silent) {
return aria2RpcService.unpauseMulti({
gids: gids,
silent: !!silent,
callback: callback
});
},
pauseTasks: function (gids, callback, silent) {
return aria2RpcService.forcePauseMulti({
gids: gids,
silent: !!silent,
callback: callback
});
},
removeTasks: function (tasks, callback, silent) {
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 hasSuccess = false;
var hasError = false;
var results = [];
if (runningTaskGids.length > 0) {
promises.push(aria2RpcService.forceRemoveMulti({
gids: runningTaskGids,
silent: !!silent,
callback: function (response) {
ariaNgCommonService.pushArrayTo(results, response.results);
hasSuccess = hasSuccess | response.hasSuccess;
hasError = hasError | response.hasError;
}
}));
}
if (stoppedTaskGids.length > 0) {
promises.push(aria2RpcService.removeDownloadResultMulti({
gids: stoppedTaskGids,
silent: !!silent,
callback: function (response) {
ariaNgCommonService.pushArrayTo(results, response.results);
hasSuccess = hasSuccess | response.hasSuccess;
hasError = hasError | response.hasError;
}
}));
}
return $q.all(promises).then(function () {
if (callback) {
callback({
hasSuccess: !!hasSuccess,
hasError: !!hasError,
results: results
});
}
});
},
changeTaskPosition: function (gid, position, callback, silent) {
return aria2RpcService.changePosition({
gid: gid,
pos: position,
how: 'POS_SET',
silent: !!silent,
callback: callback
})
},
clearStoppedTasks: function (callback, silent) {
return aria2RpcService.purgeDownloadResult({
silent: !!silent,
callback: callback
});
},
processDownloadTasks: function (tasks) {
if (!angular.isArray(tasks)) {
return;
}
for (var i = 0; i < tasks.length; i++) {
processDownloadTask(tasks[i]);
}
},
getPieceStatus: function (bitField, pieceCount) {
return getPieceStatus(bitField, pieceCount);
},
getCombinedPieces: function (bitField, pieceCount) {
return getCombinedPieces(bitField, pieceCount);
},
estimateHealthPercentFromPeers: function (task, peers) {
if (peers.length < 1) {
return task.completePercent;
}
var totalPieces = [];
var currentPieces = getPieceStatus(task.bitfield, task.numPieces);
var maxCompletedPieceCount = 0;
var maxCompletedPercent = task.completePercent;
for (var i = 0; i < currentPieces.length; i++) {
var count = currentPieces[i] ? 1 : 0;
totalPieces.push(count);
maxCompletedPieceCount += count;
}
for (var i = 0; i < peers.length; i++) {
var peer = peers[i];
var peerPieces = getPieceStatus(peer.bitfield, task.numPieces);
var completedPieceCount = 0;
for (var j = 0; j < peerPieces.length; j++) {
var count = (peerPieces[j] ? 1 : 0);
totalPieces[j] += count;
completedPieceCount += count;
}
if (completedPieceCount > maxCompletedPieceCount) {
maxCompletedPieceCount = completedPieceCount;
maxCompletedPercent = peer.completePercent;
} else if (completedPieceCount == maxCompletedPieceCount && peer.completePercent > maxCompletedPercent) {
maxCompletedPercent = peer.completePercent;
}
}
var totalCompletedPieceCount = 0;
while (true) {
var completed = true;
for (var i = 0; i < totalPieces.length; i++) {
if (totalPieces[i] > 0) {
totalCompletedPieceCount++;
totalPieces[i]--;
} else {
completed = false;
}
}
if (!completed) {
break;
}
}
if (totalCompletedPieceCount <= maxCompletedPieceCount) {
return maxCompletedPercent;
}
var healthPercent = totalCompletedPieceCount / task.numPieces * 100;
if (healthPercent <= maxCompletedPercent) {
return maxCompletedPercent;
}
return healthPercent;
}
};
}]);
})();