diff options
Diffstat (limited to 'module')
-rw-r--r-- | module/api/CoreApi.py | 6 | ||||
-rw-r--r-- | module/datatypes/PyFile.py | 38 | ||||
-rw-r--r-- | module/remote/wsbackend/AsyncHandler.py | 13 | ||||
-rw-r--r-- | module/threads/ThreadManager.py | 19 | ||||
-rw-r--r-- | module/web/static/js/models/Progress.js | 18 | ||||
-rw-r--r-- | module/web/static/js/views/abstract/modalView.js | 11 | ||||
-rw-r--r-- | module/web/static/js/views/fileView.js | 1 | ||||
-rw-r--r-- | module/web/static/js/views/headerView.js | 40 | ||||
-rw-r--r-- | module/web/static/js/views/linkGrabberModal.js | 98 | ||||
-rw-r--r-- | module/web/static/js/views/progressView.js | 30 | ||||
-rw-r--r-- | module/web/templates/default/base.html | 77 |
11 files changed, 203 insertions, 148 deletions
diff --git a/module/api/CoreApi.py b/module/api/CoreApi.py index a86197813..d75fe6ad6 100644 --- a/module/api/CoreApi.py +++ b/module/api/CoreApi.py @@ -39,8 +39,8 @@ class CoreApi(ApiComponent): self.core.threadManager.pause, self.core.config['reconnect']['activated'] and self.isTimeReconnect()) - # TODO multi user - for pyfile in self.core.threadManager.getActiveDownloads(): + + for pyfile in self.core.threadManager.getActiveDownloads(self.primaryUID): serverStatus.speed += pyfile.getSpeed() #bytes/s return serverStatus @@ -51,7 +51,7 @@ class CoreApi(ApiComponent): :rtype: list of :class:`ProgressInfo` """ - pass + return self.core.threadManager.getProgressList(self.primaryUID) def pauseServer(self): """Pause server: It won't start any new downloads, but nothing gets aborted.""" diff --git a/module/datatypes/PyFile.py b/module/datatypes/PyFile.py index d6270acaa..14baa68ab 100644 --- a/module/datatypes/PyFile.py +++ b/module/datatypes/PyFile.py @@ -40,7 +40,8 @@ statusMap = { "processing": 14, "custom": 15, "unknown": 16, - } +} + class PyFile(object): """ @@ -54,7 +55,7 @@ class PyFile(object): @staticmethod def fromInfoData(m, info): f = PyFile(m, info.fid, info.name, info.size, info.status, info.media, info.added, info.fileorder, - "", "", "", DownloadStatus.NA, "", info.package, info.owner) + "", "", "", DownloadStatus.NA, "", info.package, info.owner) if info.download: f.url = info.download.url f.pluginname = info.download.plugin @@ -179,7 +180,7 @@ class PyFile(object): def toInfoData(self): return FileInfo(self.fid, self.getName(), self.packageid, self.ownerid, self.getSize(), self.filestatus, - self.media, self.added, self.fileorder, DownloadInfo( + self.media, self.added, self.fileorder, DownloadInfo( self.url, self.pluginname, self.hash, self.status, self.getStatusName(), self.error ) ) @@ -218,18 +219,6 @@ class PyFile(object): def checkIfProcessed(self): self.m.checkAllLinksProcessed(self.id) - def formatWait(self): - """ formats and return wait time in humanreadable format """ - return format_time(self.waitUntil - time()) - - def formatSize(self): - """ formats size to readable format """ - return format_size(self.getSize()) - - def formatETA(self): - """ formats eta to readable format """ - return format_time(self.getETA()) - def getSpeed(self): """ calculates speed """ try: @@ -258,16 +247,6 @@ class PyFile(object): except: return 0 - def getPercent(self): - """ get % of download """ - if self.status == DownloadStatus.Downloading: - try: - return self.plugin.req.percent - except: - return 0 - else: - return self.progress - def getSize(self): """ get size of download """ try: @@ -278,10 +257,7 @@ class PyFile(object): except: return self.size - def notifyChange(self): - self.m.core.eventManager.dispatchEvent("linkUpdated", self.id, self.packageid) - def getProgressInfo(self): - return ProgressInfo(self.plugin, self.name, self.statusname, self.getETA(), self.formatETA(), - self.getBytesArrived(), self.getSize(), - DownloadProgress(self.fid, self.packageid, self.getSpeed(), self.status)) + return ProgressInfo(self.pluginname, self.name, self.getStatusName(), self.getETA(), + self.getBytesArrived(), self.getSize(), + DownloadProgress(self.fid, self.packageid, self.getSpeed(), self.status)) diff --git a/module/remote/wsbackend/AsyncHandler.py b/module/remote/wsbackend/AsyncHandler.py index 5c08aa96d..99ffe9894 100644 --- a/module/remote/wsbackend/AsyncHandler.py +++ b/module/remote/wsbackend/AsyncHandler.py @@ -19,6 +19,7 @@ import re from Queue import Queue, Empty from threading import Lock +from time import time from mod_pywebsocket.msgutil import receive_message @@ -58,6 +59,7 @@ class AsyncHandler(AbstractHandler): req.interval = self.PROGRESS_INTERVAL req.events = self.EVENT_PATTERN req.mode = Mode.STANDBY + req.t = time() # time when update should be pushed self.clients.append(req) @lock @@ -120,6 +122,7 @@ class AsyncHandler(AbstractHandler): def mode_running(self, req): """ Listen for events, closes socket when returning True """ try: + # block length of update interval if necessary ev = req.queue.get(True, req.interval) try: self.send(req, ev) @@ -130,9 +133,15 @@ class AsyncHandler(AbstractHandler): self.send(req, ev) except Empty: + pass + + if req.t <= time(): # TODO: server status is not enough # modify core api to include progress? think of other needed information to show + # eta is quite wrong currently # notifications - self.send(req, self.api.getServerStatus()) - self.send(req, self.api.getProgressInfo())
\ No newline at end of file + self.send(req, self.api.getProgressInfo()) + + # update time for next update + req.t = time() + req.interval
\ No newline at end of file diff --git a/module/threads/ThreadManager.py b/module/threads/ThreadManager.py index a0ece3463..f67179d08 100644 --- a/module/threads/ThreadManager.py +++ b/module/threads/ThreadManager.py @@ -118,9 +118,23 @@ class ThreadManager: def setInfoResults(self, rid, result): self.infoResults[rid].update(result) - def getActiveDownloads(self): + def getActiveDownloads(self, user=None): + # TODO: user context return [x.active for x in self.threads if x.active and isinstance(x.active, PyFile)] + def getProgressList(self, user=None): + info = [] + + # TODO: local threads can create multiple progresses + for thread in self.threads + self.localThreads: + # skip if not belong to current user + if user and thread.user != user: continue + + progress = thread.getProgress() + if progress: info.append(progress) + + return info + def getActiveFiles(self): active = self.getActiveDownloads() @@ -133,9 +147,6 @@ class ThreadManager: """get a id list of all pyfiles processed""" return [x.id for x in self.getActiveFiles()] - def allProgressInfo(self): - pass #TODO - def work(self): """run all task which have to be done (this is for repetetive call by core)""" try: diff --git a/module/web/static/js/models/Progress.js b/module/web/static/js/models/Progress.js index ebbe34862..c6a2fc4d1 100644 --- a/module/web/static/js/models/Progress.js +++ b/module/web/static/js/models/Progress.js @@ -2,10 +2,11 @@ define(['jquery', 'backbone', 'underscore'], function($, Backbone, _) { return Backbone.Model.extend({ -// TODO -// idAttribute: 'fid', + // generated, not submitted + idAttribute: 'pid', defaults: { + pid: -1, plugin: null, name: null, statusmsg: -1, @@ -15,7 +16,6 @@ define(['jquery', 'backbone', 'underscore'], function($, Backbone, _) { download: null }, - // Model Constructor initialize: function() { @@ -26,8 +26,18 @@ define(['jquery', 'backbone', 'underscore'], function($, Backbone, _) { }, + toJSON: function(options) { + var obj = Backbone.Model.prototype.toJSON.call(this, options); + if (obj.total > 0) + obj.percent = Math.round(obj.done * 100 / obj.total); + else + obj.percent = 0; + + return obj; + }, + isDownload : function() { - return this.has('download') + return this.has('download'); } }); diff --git a/module/web/static/js/views/abstract/modalView.js b/module/web/static/js/views/abstract/modalView.js index e0542d552..8f5a7ed0c 100644 --- a/module/web/static/js/views/abstract/modalView.js +++ b/module/web/static/js/views/abstract/modalView.js @@ -82,11 +82,20 @@ define(['jquery', 'backbone', 'underscore', 'omniwindow'], function($, Backbone, this.dialog.trigger('show'); - // TODO: set focus on first element + this.onShow(); + }, + + onShow: function() { + }, hide: function() { this.dialog.trigger('hide'); + this.onHide(); + }, + + onHide: function() { + }, confirm: function() { diff --git a/module/web/static/js/views/fileView.js b/module/web/static/js/views/fileView.js index 2459b6cd6..68e8df176 100644 --- a/module/web/static/js/views/fileView.js +++ b/module/web/static/js/views/fileView.js @@ -6,7 +6,6 @@ define(['jquery', 'backbone', 'underscore', 'app', 'utils/apitypes', 'views/abst tagName: 'li', className: 'file-view row-fluid', -// template: _.template($("#template-file").html()), template: _.compile($("#template-file").html()), events: { 'click .checkbox': 'select', diff --git a/module/web/static/js/views/headerView.js b/module/web/static/js/views/headerView.js index 35df06003..dddae4705 100644 --- a/module/web/static/js/views/headerView.js +++ b/module/web/static/js/views/headerView.js @@ -1,5 +1,5 @@ -define(['jquery', 'underscore', 'backbone', 'app', 'models/ServerStatus', 'flot'], - function($, _, Backbone, App, ServerStatus) { +define(['jquery', 'underscore', 'backbone', 'app', 'models/ServerStatus', 'collections/ProgressList', 'views/progressView', 'flot'], + function($, _, Backbone, App, ServerStatus, ProgressList, ProgressView) { // Renders the header with all information return Backbone.View.extend({ @@ -11,23 +11,34 @@ define(['jquery', 'underscore', 'backbone', 'app', 'models/ServerStatus', 'flot' 'click .btn-grabber': 'open_grabber' }, + // todo: maybe combine these templateStatus: _.compile($('#template-header-status').html()), - templateProgress: _.compile($('#template-header-progress').html()), + templateHeader: _.compile($('#template-header').html()), // Will hold the link grabber grabber: null, notifications: null, + header: null, + progress: null, ws: null, // Status model status: null, + progressList: null, initialize: function() { + var self = this; this.notifications = this.$('#notification-area').calculateHeight().height(0); this.status = new ServerStatus(); this.listenTo(this.status, 'change', this.render); + this.progress = this.$('.progress-list'); + this.progressList = new ProgressList(); + this.listenTo(this.progressList, 'add', function(model) { + self.progress.appendWithAnimation(new ProgressView({model: model}).render().el); + }); + // TODO: button to start stop refresh var ws = App.openWebSocket('/async'); ws.onopen = function() { @@ -108,8 +119,19 @@ define(['jquery', 'underscore', 'backbone', 'app', 'models/ServerStatus', 'flot' this.templateStatus(this.status.toJSON()) ); - // TODO: render progress - this.$('.progress-list'); + var data = {tasks: 0, downloads: 0, speed: 0}; + this.progressList.each(function(progress) { + if (progress.isDownload()) { + data.downloads += 1; + data.speed += progress.get('download').speed; + } else + data.tasks++; + }); + + this.$('#progress-info').html( + this.templateHeader(data) + ); + return this; }, toggle_taskList: function() { @@ -147,7 +169,15 @@ define(['jquery', 'underscore', 'backbone', 'app', 'models/ServerStatus', 'flot' }, onProgressUpdate: function(progress) { + _.each(progress, function(prog) { + if (prog.download) + prog.pid = prog.download.fid; + else + prog.pid = prog.plugin + prog.name; + }); + this.progressList.update(progress); + this.render(); }, onEvent: function(event, args) { diff --git a/module/web/static/js/views/linkGrabberModal.js b/module/web/static/js/views/linkGrabberModal.js index 9f7a5882d..71f97f0bf 100644 --- a/module/web/static/js/views/linkGrabberModal.js +++ b/module/web/static/js/views/linkGrabberModal.js @@ -1,49 +1,53 @@ define(['jquery', 'underscore', 'app', 'views/abstract/modalView', 'text!tpl/default/linkgrabber.html'], function($, _, App, modalView, template) { - // Modal dialog for package adding - triggers package:added when package was added - return modalView.extend({ - - events: { - 'click .btn-success': 'addPackage', - 'keypress #inputPackageName': 'addOnEnter' - }, - - template: _.compile(template), - - initialize: function() { - // Inherit parent events - this.events = _.extend({}, modalView.prototype.events,this.events); - }, - - renderContent: function() { - return $('<h1>Content!</h1>'); - }, - - addOnEnter: function(e) { - if (e.keyCode != 13) return; - this.addPackage(e); - }, - - addPackage: function(e) { - var self = this; - var settings = { - type: 'POST', - data: { - name: JSON.stringify($('#inputPackageName').val()), - links: JSON.stringify(['http://download.pyload.org/random.bin', 'http://download.pyload.org/random100.bin', - 'invalid link', 'invalid link 2', 'invalid link 3', 'inavlid link 4', - 'http://download.pyload.org/random.bin', 'http://download.pyload.org/random.bin', 'http://download.pyload.org/random.bin', - 'A really really long invalid url that should exceed length of most of the urls by far and split into two lines']) - }, - success: function() { - App.vent.trigger('package:added'); - self.hide(); - } - }; - - $.ajax('api/addPackage', settings); - $('#inputPackageName').val(''); - } - - }); -});
\ No newline at end of file + // Modal dialog for package adding - triggers package:added when package was added + return modalView.extend({ + + events: { + 'click .btn-success': 'addPackage', + 'keypress #inputPackageName': 'addOnEnter' + }, + + template: _.compile(template), + + initialize: function() { + // Inherit parent events + this.events = _.extend({}, modalView.prototype.events, this.events); + }, + + renderContent: function() { + return $('<h1>Content!</h1>'); + }, + + addOnEnter: function(e) { + if (e.keyCode != 13) return; + this.addPackage(e); + }, + + addPackage: function(e) { + var self = this; + var settings = { + type: 'POST', + data: { + name: JSON.stringify($('#inputPackageName').val()), + links: JSON.stringify(['http://download.pyload.org/random.bin', 'http://download.pyload.org/random100.bin', + 'invalid link', 'invalid link 2', 'invalid link 3', 'inavlid link 4', + 'http://download.pyload.org/random.bin', 'http://download.pyload.org/random.bin', 'http://download.pyload.org/random.bin', + 'A really really long invalid url that should exceed length of most of the urls by far and split into two lines']) + }, + success: function() { + App.vent.trigger('package:added'); + self.hide(); + } + }; + + $.ajax('api/addPackage', settings); + $('#inputPackageName').val(''); + }, + + onShow: function() { + this.$('#inputPackageName').focus(); + } + + }); + });
\ No newline at end of file diff --git a/module/web/static/js/views/progressView.js b/module/web/static/js/views/progressView.js new file mode 100644 index 000000000..40fbf0652 --- /dev/null +++ b/module/web/static/js/views/progressView.js @@ -0,0 +1,30 @@ +define(['jquery', 'backbone', 'underscore', 'app', 'utils/apitypes', 'views/abstract/itemView'], + function($, Backbone, _, App, Api, ItemView) { + + // Renders single file item + return ItemView.extend({ + + idAttribute: 'pid', + tagName: 'li', + template: _.compile($("#template-header-progress").html()), + events: { + }, + + initialize: function() { + this.listenTo(this.model, 'change', this.render); + this.listenTo(this.model, 'remove', this.unrender); + }, + + onDestroy: function() { + }, + + render: function() { + // TODO: icon + // TODO: other states + // TODO: non download progress + this.$el.css('background-image', 'url(icons/sdf)'); + this.$el.html(this.template(this.model.toJSON())); + return this; + } + }); + });
\ No newline at end of file diff --git a/module/web/templates/default/base.html b/module/web/templates/default/base.html index 2046dd36d..f995f79b7 100644 --- a/module/web/templates/default/base.html +++ b/module/web/templates/default/base.html @@ -38,7 +38,18 @@ {% endblock %}
});
</script>
-
+ <script type="text/template" id="template-header">
+ <%= if downloads %>
+ <% downloads %> downloads running (<% formatSize speed %>/s)
+ <% else %>
+ No running tasks
+ <%/if%>
+ <i class="icon-white iconf-list pull-right"></i>
+
+ <div class="progress" id="globalprogress">
+ <div class="bar" style="width: 48%">48%</div>
+ </div>
+ </script>
<script type="text/template" id="template-header-status">
<span class="pull-right eta"><% formatTime eta %></span><br>
<span class="pull-right remeaning"><% formatSize sizequeue %></span><br>
@@ -47,18 +58,18 @@ </script>
<script type="text/template" id="template-header-progress">
- <li> {# background-image for logo #}
- Some Download
- <span class="pull-right">YouTube</span>
+ {# background-image for logo #}
+ <% name %>
+ <span class="pull-right"><% plugin %></span>
- <div class="progress">
- <div class="bar" style="width: 25%"></div>
- </div>
- 20 Kb of 23 MB (500 kb/s)
- <span class="pull-right">
- 50%
- </span>
- </li>
+ <div class="progress">
+ <div class="bar" style="width: <% percent %>%"></div>
+ </div>
+ <% formatSize done %> of <% formatSize total %> (<% formatSize download.speed %>/s)
+ <span class="pull-right">
+ <% percent %>%
+ <% formatTime eta %>
+ </span>
</script>
{% block head %}
@@ -109,17 +120,8 @@ </div>
<div id="progress-area" style="margin-top: 16px">
- No running tasks
- <i class="icon-white iconf-list pull-right"></i>
-
- <div class="progress" id="globalprogress">
- <div class="bar" style="width: 48%">48%</div>
- </div>
-
- {# <div>#}
- {# <span class="pull-left">3,65 MB of 5,30 MB</span>#}
- {# <span class="pull-right">420,7 kB / sec</span>#}
- {# </div>#}
+ <span id="progress-info">
+ </span>
<div class="popover bottom">
<div class="arrow"></div>
<div class="popover-inner">
@@ -128,32 +130,7 @@ <button type="button" class="close" aria-hidden="true">×</button>
</h3>
<div class="popover-content">
- <ul class="progress-list">
- <li style="background-image: url('icons/sdf')">
- Some Download
- <span class="pull-right">YouTube</span>
-
- <div class="progress">
- <div class="bar" style="width: 25%"></div>
- </div>
- 20 Kb of 23 MB (500 kb/s)
- <span class="pull-right">
- 50%
- </span>
- </li>
- <li style="background-image: url('icons/sdf')">
- Some Download
- <span class="pull-right">YouTube</span>
-
- <div class="progress">
- <div class="bar" style="width: 45%"></div>
- </div>
- 20 Kb of 23 MB (500 kb/s)
- <span class="pull-right">
- 50%
- </span>
- </li>
- </ul>
+ <ul class="progress-list"></ul>
</div>
</div>
</div>
@@ -197,7 +174,7 @@ <div class="block">
<h2 class="block-title">Powered by</h2>
Bootstrap <br>
- dsfdsf <br>
+ Backbone <br>
sdf dsg <br>
</div>
|