UNPKG

electorrent

Version:

An Electron/Node/AngularJS remote client app for uTorrent server

471 lines (403 loc) 13.9 kB
"use strict"; angular.module("torrentApp").controller("torrentsController", ["$rootScope", "$scope", "$timeout", "$filter", "$q", "$bittorrent", "notificationService", "configService", "AbstractTorrent", function ($rootScope, $scope, $timeout, $filter, $q, $bittorrent, $notify, config, AbstractTorrent) { const TIMEOUT = 2000; const LIMIT = 25; var selected = []; var lastSelected = null; var timeout; var reconnect; var settings = config.getAllSettings(); $scope.connectionLost = false; $scope.torrents = {}; $scope.arrayTorrents = []; $scope.contextMenu = null; $scope.showDragAndDrop = false; $scope.labelsDrowdown = null; $scope.torrentLimit = LIMIT; $scope.labels = []; $scope.trackers = [] $scope.resizeMode = settings.ui.resizeMode; $scope.filters = { status: 'all' }; $rootScope.$on('show:draganddrop', function(event, show) { $scope.showDragAndDrop = show; $scope.$apply(); }) $scope.$on('new:settings', function(event, data) { $scope.resizeMode = data.ui.resizeMode; resetAll(); }); $scope.showMore = function() { $scope.torrentLimit += LIMIT; }; $scope.debug = function(){ for (var i = 0; i < selected.length; i++){ console.info(selected[i]); } return $q.when(); }; $scope.activeOn = function(filter) { if ($scope.filters.status === filter){ return 'active'; } else { return ''; } } $scope.setLabel = function(label){ $rootScope.$btclient.setLabel(getSelectedHashes(), label) .then(function() { $scope.update(); }) .catch(function() { $notify.alert("Could not set label", "The label could not be changed. Please go to settings and configure your connection"); }) } $scope.$on('start:torrents', function(event, fullupdate){ $scope.update(!!fullupdate); startTimer(); }); $scope.$on('clear:torrents', function(){ clearAll() $scope.filters = { status: 'all' }; }) $scope.$on('stop:torrents', function(){ stopTimer(); }) $scope.$on('show:settings', function(){ stopTimer(); }); function startTimer(fullupdate){ if (timeout) { $timeout.cancel(timeout) } timeout = $timeout(function(){ //console.info("Update!"); $scope.update(fullupdate) .then(function(){ startTimer(); $scope.connectionLost = false; }).catch(function() { $scope.connectionLost = true; startReconnect(); }); }, TIMEOUT); } function startReconnect() { $notify.disableAll(); var data = config.getServer(); reconnect = $timeout(function() { $rootScope.$btclient.connect(data.ip, data.port, data.user, data.password) .then(function() { $notify.enableAll(); startTimer(true); }).catch(function() { startReconnect() }) }, TIMEOUT) } function clearAll() { $scope.torrents = {}; $scope.arrayTorrents = []; $scope.labels = []; $scope.trackers = []; } function resetAll() { clearAll() $scope.update(true); console.log("Reset!") } function stopTimer(){ console.info("Torrents stopped"); $timeout.cancel(timeout); } $scope.filterByStatus = function(status){ deselectAll(); lastSelected = null; $scope.filters.status = status; $scope.torrentLimit = LIMIT; refreshTorrents(); } $scope.filterByLabel = function(label){ deselectAll(); lastSelected = null; $scope.filters.label = label; $scope.torrentLimit = LIMIT; refreshTorrents(); } $scope.activeLabel = function(label) { return $scope.filters.label === label; } $scope.filterByTracker = function(tracker) { deselectAll(); lastSelected = null; $scope.filters.tracker = tracker; $scope.torrentLimit = LIMIT; refreshTorrents(); } $scope.activeTracker = function(tracker) { return $scope.filters.tracker === tracker; } $scope.showContextMenu = function(event, torrent /*, index*/) { if (!torrent.selected){ singleSelect(torrent); } $scope.contextMenu.show(event); }; $scope.numInFilter = function(status) { var num = 0; var filter = torrentFilter(status); angular.forEach($scope.torrents, function(torrent /*, hash*/) { if (filter(torrent)) { num++; } }); return num; } $scope.noneSelected = function(){ return selected.length === 0; } function toggleSelect(torrent){ if (!torrent.selected){ selected.push(torrent); } else { selected = selected.filter(function(item){ return item.hash !== torrent.hash; }); } torrent.selected = !torrent.selected; lastSelected = torrent; } function deselectAll(){ for (var i = 0; i < selected.length; i++){ selected[i].selected = false; } selected = []; } function singleSelect(torrent){ deselectAll(); torrent.selected = true; selected.push(torrent); lastSelected = torrent; } function multiSelect(index){ var lastIndex = $scope.arrayTorrents.indexOf(lastSelected); if (lastIndex < 0){ return; } var i, j; if (lastIndex < index){ i = lastIndex; j = index; } else { i = index; j = lastIndex; } deselectAll(); while (i<=j){ $scope.arrayTorrents[i].selected = true; selected.push($scope.arrayTorrents[i]); i++; } } $scope.setSelected = function(event, torrent, index) { if (event.ctrlKey || event.metaKey){ toggleSelect(torrent); } else if (event.shiftKey){ multiSelect(index); } else { singleSelect(torrent); } } function getSelectedHashes(){ var hashes = []; angular.forEach(selected, function(torrent){ hashes.push(torrent.hash) }) return hashes; } $scope.doAction = function(action, name, data) { action(selected, data) .then(function(){ $scope.update(); }) .catch(function(err) { console.error('Action error', err) $notify.alert("Invalid action", "The action could not be performed because the server responded with a faulty reply"); }); }; $scope.doContextAction = function(action, name) { action(selected) .then(function(){ $scope.update(); }) .catch(function(err) { console.error('Context action error', err) $notify.alert("Invalid action", "The action could not be performed because the server responded with a faulty reply"); }) } function fetchTorrents(){ var results = []; angular.forEach($scope.torrents, function(torrent /*, hash*/) { results.push(torrent); }); return results; } $scope.changeSorting = function(sortName, descending) { $scope.torrentLimit = LIMIT; $scope.filters.sort = sortName; $scope.filters.order = descending; refreshTorrents(); } function torrentSorter(){ var sort = $scope.filters.sort || 'dateAdded'; var desc = $scope.filters.order; var sorter = AbstractTorrent.sort(sort); var descSort = function(a, b) { return sorter(a[sort], b[sort]); } var ascSort = function(a, b) { return sorter(a[sort], b[sort]) * (-1); } if (desc) return descSort else return ascSort } function statusFilter(torrent, status) { switch (status) { case 'all': return true; case 'finished': return torrent.isStatusCompleted(); case 'downloading': return torrent.isStatusDownloading() || torrent.isStatusPaused(); case 'paused': return torrent.isStatusPaused(); case 'queued': return torrent.isStatusQueued(); case 'seeding': return torrent.isStatusSeeding(); case 'error': return torrent.isStatusError(); case 'stopped': return torrent.isStatusStopped(); } } function torrentFilter(status, label, tracker){ var filterStatus = status || $scope.filters.status; var filterLabel = label || $scope.filters.label; var filterTracker = tracker || $scope.filters.tracker; return function(torrent){ var keep = []; if (filterStatus) { keep.push(statusFilter(torrent, filterStatus)); } if (filterLabel) { keep.push(torrent.label === filterLabel) } if (filterTracker) { keep.push(torrent.trackers && torrent.trackers.some((tracker) => { return tracker && tracker.includes(filterTracker) })) } return keep.every(function(shouldkeep) { return shouldkeep; }); } } function refreshTorrents(){ var torrents = fetchTorrents(); torrents = torrents.filter(torrentFilter()); torrents = torrents.sort(torrentSorter()); $scope.arrayTorrents = torrents; } function reassignSelected() { var newSelected = [] selected.forEach(function(torrent){ var delegate = $scope.torrents[torrent.hash]; if (delegate){ delegate.selected = true newSelected.push(delegate) } }) selected = newSelected reassignLastSelected() } function reassignLastSelected() { if(!lastSelected) return var lastDelegate = $scope.torrents[lastSelected.hash]; if(lastDelegate) { lastDelegate.selected = true lastSelected = lastDelegate } else { lastSelected = null } } $scope.update = function(fullupdate) { var q = $rootScope.$btclient.torrents(fullupdate) q.then(function(torrents) { newTorrents(torrents); deleteTorrents(torrents); changeTorrents(torrents); updateLabels(torrents); updateTrackers(torrents); }) return q; }; function checkNotification(old, updated) { if (!old || !updated) return if (updated.percent === 1000 && old.percent < 1000) { if (settings.ui.notifications === true){ $notify.torrentComplete(old); } } } function newTorrents(torrents){ if ((torrents.all && torrents.all.length > 0) || torrents.dirty === true) { var torrentMap = {}; for (var i = 0; i < torrents.all.length; i++){ var torrent = torrents.all[i]; torrentMap[torrent.hash] = torrent; var old = $scope.torrents[torrent.hash]; checkNotification(old, torrent); } $scope.torrents = torrentMap; reassignSelected() refreshTorrents() } } function deleteTorrents(torrents){ if (torrents.deleted && torrents.deleted.length > 0) { for (var i = 0; i < torrents.deleted.length; i++) { delete $scope.torrents[torrents.deleted[i]]; } refreshTorrents(); } } function changeTorrents(torrents){ if (torrents.changed && torrents.changed.length > 0) { for (var i = 0; i < torrents.changed.length; i++) { var torrent = torrents.changed[i]; var existing = $scope.torrents[torrent.hash]; checkNotification(existing, torrent); if (existing) { existing.update(torrent); } else { $scope.torrents[torrent.hash] = torrent; } } refreshTorrents() } } function updateLabels(torrents){ if (torrents.labels && torrents.labels.length > 0) { torrents.labels.forEach(function(label /*, index*/){ if (!$scope.labels.includes(label)) { $scope.labels.push(label) } }) } } function updateTrackers(torrents) { if (torrents.trackers && torrents.trackers.length > 0) { torrents.trackers.forEach(function(tracker) { if (!$scope.trackers.includes(tracker)) { $scope.trackers.push(tracker) } }) } } }])