diff --git a/MANIFEST.in b/MANIFEST.in index 62af6e7f..b56caaea 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -7,6 +7,7 @@ include onionshare/404.html include onionshare/strings.json include onionshare_gui/templates/index.html include onionshare_gui/static/jquery-1.11.1.min.js +include onionshare_gui/static/helpers.js include onionshare_gui/static/onionshare.js include onionshare_gui/static/style.css include onionshare_gui/static/loader.gif diff --git a/onionshare/onionshare.py b/onionshare/onionshare.py index c84e24b9..1b0895cb 100644 --- a/onionshare/onionshare.py +++ b/onionshare/onionshare.py @@ -27,30 +27,62 @@ def set_file_info(new_filename, new_filehash, new_filesize): REQUEST_LOAD = 0 REQUEST_DOWNLOAD = 1 -REQUEST_OTHER = 2 +REQUEST_PROGRESS = 2 +REQUEST_OTHER = 3 request_q = Queue.Queue() -def add_request(type): +download_count = 0 + +def add_request(type, path, data=None): global request_q request_q.put({ 'type': type, - 'path': request.path + 'path': path, + 'data': data }) @app.route("/{0}".format(slug)) def index(): global filename, filesize, filehash, slug, strings, REQUEST_LOAD - add_request(REQUEST_LOAD) + add_request(REQUEST_LOAD, request.path) return render_template_string(open('{0}/index.html'.format(os.path.dirname(__file__))).read(), slug=slug, filename=os.path.basename(filename), filehash=filehash, filesize=filesize, strings=strings) @app.route("/{0}/download".format(slug)) def download(): - global filename, request_q, REQUEST_DOWNLOAD - add_request(REQUEST_DOWNLOAD) + global filename, filesize, request_q, download_count + global REQUEST_DOWNLOAD, REQUEST_PROGRESS + + # each download has a unique id + download_id = download_count + download_count += 1 + + # tell GUI the download started + path = request.path + add_request(REQUEST_DOWNLOAD, path, { 'id':download_id }) + dirname = os.path.dirname(filename) basename = os.path.basename(filename) - return send_from_directory(dirname, basename, as_attachment=True) + + def generate(): + chunk_size = 102400 # 100kb + + fp = open(filename, 'rb') + done = False + while not done: + chunk = fp.read(102400) + if chunk == '': + done = True + yield chunk + + # tell GUI the progress + add_request(REQUEST_PROGRESS, path, { 'id':download_id, 'bytes':fp.tell() }) + fp.close() + + r = Response(generate()) + r.headers.add('Content-Length', filesize) + r.headers.add('Content-Disposition', 'attachment', filename=basename) + return r @app.errorhandler(404) def page_not_found(e): diff --git a/onionshare_gui/static/helpers.js b/onionshare_gui/static/helpers.js new file mode 100644 index 00000000..951320ba --- /dev/null +++ b/onionshare_gui/static/helpers.js @@ -0,0 +1,11 @@ +function human_readable_filesize(bytes, si) { + var thresh = si ? 1000 : 1024; + if(bytes < thresh) return bytes + ' B'; + var units = si ? ['kB','MB','GB','TB','PB','EB','ZB','YB'] : ['KiB','MiB','GiB','TiB','PiB','EiB','ZiB','YiB']; + var u = -1; + do { + bytes /= thresh; + ++u; + } while(bytes >= thresh); + return bytes.toFixed(1)+' '+units[u]; +}; diff --git a/onionshare_gui/static/onionshare.js b/onionshare_gui/static/onionshare.js index c8cf3125..42c9120f 100644 --- a/onionshare_gui/static/onionshare.js +++ b/onionshare_gui/static/onionshare.js @@ -21,7 +21,8 @@ $(function(){ var REQUEST_LOAD = 0; var REQUEST_DOWNLOAD = 1; - var REQUEST_OTHER = 2; + var REQUEST_PROGRESS = 2; + var REQUEST_OTHER = 3; function check_for_requests() { $.ajax({ url: '/check_for_requests', @@ -31,7 +32,14 @@ $(function(){ if(r.type == REQUEST_LOAD) { update($('').addClass('weblog').html(onionshare.strings['download_page_loaded'])); } else if(r.type == REQUEST_DOWNLOAD) { - update($('').addClass('weblog').html(onionshare.strings['download_started'])); + var $download = $('') + .attr('id', 'download-'+r.data.id) + .addClass('weblog').html(onionshare.strings['download_started']) + .append($('').addClass('progress')); + update($download); + } else if(r.type == REQUEST_PROGRESS) { + var percent = Math.floor((r.data.bytes / onionshare.filesize) * 100); + $('#download-'+r.data.id+' .progress').html(' '+human_readable_filesize(r.data.bytes)+', '+percent+'%'); } else { if(r.path != '/favicon.ico') update($('').addClass('weblog-error').html(onionshare.strings['other_page_loaded']+': '+r.path)); @@ -65,7 +73,7 @@ $(function(){ $('#loading').remove(); - $('#filesize .value').html(onionshare.filesize+' bytes'); + $('#filesize .value').html(human_readable_filesize(onionshare.filesize)); $('#filehash .value').html(onionshare.filehash); $('#filesize').show(500); $('#filehash').show(500); diff --git a/onionshare_gui/templates/index.html b/onionshare_gui/templates/index.html index a3bb0a0a..d0fe467c 100644 --- a/onionshare_gui/templates/index.html +++ b/onionshare_gui/templates/index.html @@ -29,6 +29,7 @@ +