From f3813777b7860092fd8326db09b88f4055068b96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20W=C3=BCrfl?= Date: Sun, 20 May 2018 16:05:41 +0200 Subject: [PATCH 1/6] Allow uploading files to existing/new folders --- interface.py | 47 ++++++++++++++++++++++++++++++++------------ templates/index.html | 24 ++++++++++++---------- util.py | 16 +++++++++++++++ 3 files changed, 64 insertions(+), 23 deletions(-) diff --git a/interface.py b/interface.py index 85878b2..76b9624 100644 --- a/interface.py +++ b/interface.py @@ -7,6 +7,7 @@ import os.path from os import listdir import random from werkzeug.utils import secure_filename +import errno class ReverseProxied(object): '''Wrap the application in this middleware and configure the @@ -107,23 +108,43 @@ def index(): music_library=music_library) -@web.route('/download', methods=["POST"]) -def download(): - print(request.form) - - file = request.files['music_file'] +@web.route('/upload', methods=["POST"]) +def upload(): + file = request.files['file'] if not file: return redirect("./", code=406) - elif file.filename == '': - return redirect("./", code=406) - elif '..' in request.form['directory']: + + filename = secure_filename(file.filename).strip() + if filename == '': return redirect("./", code=406) - if file.name == "music_file" and "audio" in file.headers.to_list()[1][1]: - web.config['UPLOAD_FOLDER'] = var.music_folder + request.form['directory'] - filename = secure_filename(file.filename) - print(filename) - file.save(os.path.join(web.config['UPLOAD_FOLDER'], filename)) + targetdir = request.form['targetdir'].strip() + if targetdir == '': + targetdir = 'uploads/' + elif '..' in targetdir: + return redirect("./", code=406) + + print('Uploading file:') + print('filename:', filename) + print('targetdir:', targetdir) + print('mimetype:', file.mimetype) + + if "audio" in file.mimetype: + storagepath = os.path.abspath(os.path.join(var.music_folder, targetdir)) + if not storagepath.startswith(var.music_folder): + return redirect("./", code=406) + + try: + os.makedirs(storagepath) + except OSError as ee: + if ee.errno != errno.EEXIST: + return redirect("./", code=500) + + filepath = os.path.join(storagepath, filename) + if os.path.exists(filepath): + return redirect("./", code=406) + + file.save(filepath) return redirect("./", code=302) else: return redirect("./", code=409) diff --git a/templates/index.html b/templates/index.html index 09009b2..72858fd 100644 --- a/templates/index.html +++ b/templates/index.html @@ -34,19 +34,23 @@
Refresh

-{% if False %} -
-
- - + Upload into + + + {% for dir in music_library.get_subdirs_recursively() %} +
-{% endif %} + +
+
Current Playing : {% if current_music %} @@ -54,7 +58,7 @@ {% else %} No music {% endif %} -
+
Playlist :
diff --git a/util.py b/util.py index 85a4331..8ed6f37 100644 --- a/util.py +++ b/util.py @@ -57,6 +57,22 @@ class Dir(object): return subdirs + def get_subdirs_recursively(self, path=None): + subdirs = [] + if path and path != '': + subdir = path.split('/')[0] + if subdir in self.subdirs: + searchpath = '/'.join(path.split('/')[1::]) + subdirs = self.subdirs[subdir].get_subdirs_recursively(searchpath) + else: + subdirs = list(self.subdirs.keys()) + + for key, val in self.subdirs.items(): + subdirs.extend(map(lambda subdir: key + '/' + subdir,val.get_subdirs_recursively())) + + subdirs.sort() + return subdirs + def get_files(self, path=None): files = [] if path and path != '': From de96175c18990b21bd5365200cbbbe5100d1b7b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20W=C3=BCrfl?= Date: Sun, 20 May 2018 17:02:41 +0200 Subject: [PATCH 2/6] Add download button for each file - This commit also introduces some CSS to place the buttons/forms next to each other --- static/index.css | 23 +++++++++++++++++++++++ templates/index.html | 13 +++++++++++-- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/static/index.css b/static/index.css index e69de29..77ab01a 100644 --- a/static/index.css +++ b/static/index.css @@ -0,0 +1,23 @@ +/* necessary to place both forms/buttons next to each other */ +li.file { + clear: both; + list-style-position: outside; +} + +/* necessary to place both forms/buttons next to each other */ +form.file { + /* Float both forms to the left */ + float: left; +} + +form.file.file_add { + margin-left: 5px; + margin-right: 5px; +} + +/* necessary to place both forms/buttons next to each other */ +form.file.file_download { + clear: right; + /* with some space to the left of the second form */ + margin-right: 20px; +} diff --git a/templates/index.html b/templates/index.html index 72858fd..27712ac 100644 --- a/templates/index.html +++ b/templates/index.html @@ -14,8 +14,17 @@ {%- set files = music_library.get_files(subdirpath) %} {%- if files %} {% for file in files %} - -
  •   {{ file }}
  • +
  • +
    + + +
    +
    + + +  {{ file }} +
    +
  • {% endfor %} {%- endif %} From 74ae51f65cd3f12c4c82fa1b771288be0a3b6cfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20W=C3=BCrfl?= Date: Sun, 20 May 2018 20:32:05 +0200 Subject: [PATCH 3/6] Add download buttons to subdirectory entries --- static/index.css | 30 ++++++++++++++++++++++++++++++ templates/index.html | 17 +++++++++++++++-- 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/static/index.css b/static/index.css index 77ab01a..011d00c 100644 --- a/static/index.css +++ b/static/index.css @@ -21,3 +21,33 @@ form.file.file_download { /* with some space to the left of the second form */ margin-right: 20px; } + +/* necessary to place all forms/buttons of the directory entries next to each other */ +li.directory { + clear: both; + list-style-position: outside; + margin-top: 15px; + margin-bottom: 15px; +} + +li.directory span { + float: left; +} + +form.directory { + float: left; +} + +form.directory.form1 { + margin-left: 5px; + margin-right: 5px; +} + +form.directory.form2 { + margin-right: 5px; +} + +form.directory.form3 { + clear: right; + margin-right: 5px; +} diff --git a/templates/index.html b/templates/index.html index 27712ac..149c3e0 100644 --- a/templates/index.html +++ b/templates/index.html @@ -2,8 +2,21 @@
      {% for subdirname in music_library.get_subdirs(path) %} {%- set subdirpath = path + subdirname + '/' %} -
    • {{ subdirname }}/
      -
    • +
    • + {{ subdirname }}/  +
      + + +
      +
      + + +
      +
      + + +
      +
    • {%- set subdirs = music_library.get_subdirs(subdirpath) %} {%- if subdirs %} {%- for subdir in subdirs %} From b0137b2db667b82c81ffcd10b7543b741bbe20bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20W=C3=BCrfl?= Date: Sun, 20 May 2018 22:41:35 +0200 Subject: [PATCH 4/6] Implement download functionality - directories are served as a zip-file --- interface.py | 32 +++++++++++++++++++++++++++++++- templates/index.html | 4 ++-- util.py | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 3 deletions(-) diff --git a/interface.py b/interface.py index 76b9624..f79a083 100644 --- a/interface.py +++ b/interface.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -from flask import Flask, render_template, request, redirect +from flask import Flask, render_template, request, redirect, send_file import variables as var import util import os.path @@ -149,6 +149,36 @@ def upload(): else: return redirect("./", code=409) +@web.route('/download', methods=["GET"]) +def download(): + if 'file' in request.args: + requested_file = request.args['file'] + if '../' not in requested_file: + folder_path = var.music_folder + files = util.get_recursive_filelist_sorted(var.music_folder) + + if requested_file in files: + filepath = os.path.join(folder_path, requested_file) + try: + return send_file(filepath, as_attachment=True) + except Exception as e: + self.log.exception(e) + self.Error(400) + elif 'directory' in request.args: + requested_dir = request.args['directory'] + folder_path = var.music_folder + requested_dir_fullpath = os.path.abspath(os.path.join(folder_path, requested_dir)) + '/' + if requested_dir_fullpath.startswith(folder_path): + prefix = secure_filename(os.path.relpath(requested_dir_fullpath, folder_path)) + zipfile = util.zipdir(requested_dir_fullpath, requested_dir) + try: + return send_file(zipfile, as_attachment=True) + except Exception as e: + self.log.exception(e) + self.Error(400) + + return redirect("./", code=400) + if __name__ == '__main__': web.run(port=8181, host="127.0.0.1") diff --git a/templates/index.html b/templates/index.html index 149c3e0..75b9b0e 100644 --- a/templates/index.html +++ b/templates/index.html @@ -29,11 +29,11 @@ {% for file in files %}
    • - +
      - +  {{ file }}
      diff --git a/util.py b/util.py index 8ed6f37..e2868c6 100644 --- a/util.py +++ b/util.py @@ -1,8 +1,10 @@ #!/usr/bin/python3 import configparser +import hashlib import os import variables as var +import zipfile __CONFIG = configparser.ConfigParser(interpolation=None) __CONFIG.read("configuration.ini", encoding='latin-1') @@ -23,6 +25,36 @@ def get_recursive_filelist_sorted(path): filelist.sort() return filelist +# - zips all files of the given zippath (must be a directory) +# - returns the absolute path of the created zip file +# - zip file will be in the applications tmp folder (according to configuration) +# - format of the filename itself = prefix_hash.zip +# - prefix can be controlled by the caller +# - hash is a sha1 of the string representation of the directories' contents (which are +# zipped) +def zipdir(zippath, zipname_prefix=None): + zipname = __CONFIG.get('bot', 'tmp_folder') + if zipname_prefix and '../' not in zipname_prefix: + zipname += zipname_prefix.strip().replace('/', '_') + '_' + + files = get_recursive_filelist_sorted(zippath) + hash = hashlib.sha1((str(files).encode())).hexdigest() + zipname += hash + '.zip' + + if os.path.exists(zipname): + return zipname + + zipf = zipfile.ZipFile(zipname, 'w', zipfile.ZIP_DEFLATED) + + for file in files: + filepath = os.path.dirname(file) + file_to_add = os.path.join(zippath, file) + add_file_as = os.path.relpath(os.path.join(zippath, file), os.path.join(zippath, '..')) + zipf.write(file_to_add, add_file_as) + + zipf.close() + return zipname + class Dir(object): def __init__(self, name): self.name = name From 1e80ab2c0c2268602dcbdedc21c0198914941b1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20W=C3=BCrfl?= Date: Sun, 20 May 2018 22:52:08 +0200 Subject: [PATCH 5/6] Add button to download entire music library --- interface.py | 7 +++++-- templates/index.html | 5 +++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/interface.py b/interface.py index f79a083..28ae96a 100644 --- a/interface.py +++ b/interface.py @@ -169,8 +169,11 @@ def download(): folder_path = var.music_folder requested_dir_fullpath = os.path.abspath(os.path.join(folder_path, requested_dir)) + '/' if requested_dir_fullpath.startswith(folder_path): - prefix = secure_filename(os.path.relpath(requested_dir_fullpath, folder_path)) - zipfile = util.zipdir(requested_dir_fullpath, requested_dir) + if os.path.samefile(requested_dir_fullpath, folder_path): + prefix = 'all' + else: + prefix = secure_filename(os.path.relpath(requested_dir_fullpath, folder_path)) + zipfile = util.zipdir(requested_dir_fullpath, prefix) try: return send_file(zipfile, as_attachment=True) except Exception as e: diff --git a/templates/index.html b/templates/index.html index 75b9b0e..87e1b3d 100644 --- a/templates/index.html +++ b/templates/index.html @@ -92,6 +92,11 @@ {% endfor %}

    Music library:

    +
    + + +
    +
    {{ dirlisting() }} From 983d3b5a110790ae121eb55358e56773ea138235 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20W=C3=BCrfl?= Date: Sun, 20 May 2018 23:03:08 +0200 Subject: [PATCH 6/6] Small cleanup changes --- interface.py | 10 +++++----- templates/index.html | 3 ++- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/interface.py b/interface.py index 28ae96a..7ce7fc1 100644 --- a/interface.py +++ b/interface.py @@ -121,13 +121,13 @@ def upload(): targetdir = request.form['targetdir'].strip() if targetdir == '': targetdir = 'uploads/' - elif '..' in targetdir: + elif '../' in targetdir: return redirect("./", code=406) - print('Uploading file:') - print('filename:', filename) - print('targetdir:', targetdir) - print('mimetype:', file.mimetype) + #print('Uploading file:') + #print('filename:', filename) + #print('targetdir:', targetdir) + #print('mimetype:', file.mimetype) if "audio" in file.mimetype: storagepath = os.path.abspath(os.path.join(var.music_folder, targetdir)) diff --git a/templates/index.html b/templates/index.html index 87e1b3d..1a68822 100644 --- a/templates/index.html +++ b/templates/index.html @@ -61,8 +61,9 @@
    Upload into - + +