Merge pull request #1 from BafDyce/upload-download

[Web Interface] Fix & enhance upload/download functionality
This commit is contained in:
Fabian Würfl 2018-05-20 23:07:30 +02:00 committed by GitHub
commit 310b27c6b8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 215 additions and 28 deletions

View File

@ -1,12 +1,13 @@
#!/usr/bin/python3 #!/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 variables as var
import util import util
import os.path import os.path
from os import listdir from os import listdir
import random import random
from werkzeug.utils import secure_filename from werkzeug.utils import secure_filename
import errno
class ReverseProxied(object): class ReverseProxied(object):
'''Wrap the application in this middleware and configure the '''Wrap the application in this middleware and configure the
@ -107,27 +108,80 @@ def index():
music_library=music_library) music_library=music_library)
@web.route('/download', methods=["POST"]) @web.route('/upload', methods=["POST"])
def download(): def upload():
print(request.form) file = request.files['file']
file = request.files['music_file']
if not file: if not file:
return redirect("./", code=406) return redirect("./", code=406)
elif file.filename == '':
return redirect("./", code=406) filename = secure_filename(file.filename).strip()
elif '..' in request.form['directory']: if filename == '':
return redirect("./", code=406) return redirect("./", code=406)
if file.name == "music_file" and "audio" in file.headers.to_list()[1][1]: targetdir = request.form['targetdir'].strip()
web.config['UPLOAD_FOLDER'] = var.music_folder + request.form['directory'] if targetdir == '':
filename = secure_filename(file.filename) targetdir = 'uploads/'
print(filename) elif '../' in targetdir:
file.save(os.path.join(web.config['UPLOAD_FOLDER'], filename)) 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) return redirect("./", code=302)
else: else:
return redirect("./", code=409) 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):
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:
self.log.exception(e)
self.Error(400)
return redirect("./", code=400)
if __name__ == '__main__': if __name__ == '__main__':
web.run(port=8181, host="127.0.0.1") web.run(port=8181, host="127.0.0.1")

View File

@ -0,0 +1,53 @@
/* 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;
}
/* 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;
}

View File

@ -2,8 +2,21 @@
<ul> <ul>
{% for subdirname in music_library.get_subdirs(path) %} {% for subdirname in music_library.get_subdirs(path) %}
{%- set subdirpath = path + subdirname + '/' %} {%- set subdirpath = path + subdirname + '/' %}
<li>{{ subdirname }}/ <form method="post"><input type="text" value="{{ subdirpath }}" name="add_folder" hidden><input type="submit" value="Add all tracks from this folder"></form> <li class="directory">
<form method="post"><input type="text" value="{{ subdirpath }}" name="add_folder_recursively" hidden><input type="submit" value="Add all tracks from this folder (recursively)"></form></li> <span>{{ subdirname }}/&nbsp;</span>
<form method="post" class="directory form1">
<input type="text" value="{{ subdirpath }}" name="add_folder" hidden>
<input type="submit" value="Add all tracks from this folder">
</form>
<form method="post" class="directory form2">
<input type="text" value="{{ subdirpath }}" name="add_folder_recursively" hidden>
<input type="submit" value="Add all tracks from this folder (recursively)">
</form>
<form action="./download" method="get" class="directory form3">
<input type="text" value="{{ subdirpath }}" name="directory" hidden>
<input type="submit" value="Download entire directory">
</form>
</li>
{%- set subdirs = music_library.get_subdirs(subdirpath) %} {%- set subdirs = music_library.get_subdirs(subdirpath) %}
{%- if subdirs %} {%- if subdirs %}
{%- for subdir in subdirs %} {%- for subdir in subdirs %}
@ -14,8 +27,17 @@
{%- set files = music_library.get_files(subdirpath) %} {%- set files = music_library.get_files(subdirpath) %}
{%- if files %} {%- if files %}
{% for file in files %} {% for file in files %}
<!--<li>{{ file }}</li>--> <li class="file">
<li><form method="post"><input type="text" value="{{ subdirpath }}/{{ file }}" name="add_file" hidden><input type="submit" value="Add">&nbsp;&nbsp;{{ file }}</form></li> <form method="post" class="file file_add">
<input type="text" value="{{ subdirpath }}{{ file }}" name="add_file" hidden>
<input type="submit" value="Add">
</form>
<form action="./download" method="get" class="file file_download">
<input type="text" value="{{ subdirpath }}{{ file }}" name="file" hidden>
<input type="submit" value="Download">
&nbsp;{{ file }}
</form>
</li>
{% endfor %} {% endfor %}
{%- endif %} {%- endif %}
</ul> </ul>
@ -34,19 +56,24 @@
<body> <body>
<a href="."><h5>Refresh</h5></a> <a href="."><h5>Refresh</h5></a>
<br> <br>
{% if False %}
<div id="download"> <div id="upload">
<form action="./download" method="post" enctype="multipart/form-data"> <form action="./upload" method="post" enctype="multipart/form-data">
<input type="file" name="music_file" value="Browse Music file"/> <input type="file" name="file" value="Browse Music file"/>
<select name="directory"> Upload into
{% for dir in all_files %} <input list="targetdirs" id="targetdir" name="targetdir" placeholder="uploads" />
<option value={{ dir }}>{{ dir }}</option> <datalist id="targetdirs">
<option value="uploads">
{% for dir in music_library.get_subdirs_recursively() %}
<option value="{{ dir }}">
{% endfor %} {% endfor %}
</select> </datalist>
<input type="submit" value="Upload"/> <input type="submit" value="Upload"/>
</form> </form>
</div> </div>
{% endif %}
<br />
<div id="playlist"> <div id="playlist">
Current Playing : Current Playing :
{% if current_music %} {% if current_music %}
@ -54,7 +81,7 @@
{% else %} {% else %}
No music No music
{% endif %} {% endif %}
<br> <br />
Playlist : Playlist :
<form method="post"><input type="text" value="randomize" name="action" hidden><input type="submit" value="Randomize playlist"></form> <form method="post"><input type="text" value="randomize" name="action" hidden><input type="submit" value="Randomize playlist"></form>
@ -66,6 +93,11 @@
{% endfor %} {% endfor %}
</ul> </ul>
<h2>Music library:</h2> <h2>Music library:</h2>
<form action="./download" method="get" class="directory">
<input type="text" value="./" name="directory" hidden>
<input type="submit" value="Download entire music library">
</form>
<br />
{{ dirlisting() }} {{ dirlisting() }}

48
util.py
View File

@ -1,8 +1,10 @@
#!/usr/bin/python3 #!/usr/bin/python3
import configparser import configparser
import hashlib
import os import os
import variables as var import variables as var
import zipfile
__CONFIG = configparser.ConfigParser(interpolation=None) __CONFIG = configparser.ConfigParser(interpolation=None)
__CONFIG.read("configuration.ini", encoding='latin-1') __CONFIG.read("configuration.ini", encoding='latin-1')
@ -23,6 +25,36 @@ def get_recursive_filelist_sorted(path):
filelist.sort() filelist.sort()
return filelist 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): class Dir(object):
def __init__(self, name): def __init__(self, name):
self.name = name self.name = name
@ -57,6 +89,22 @@ class Dir(object):
return subdirs 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): def get_files(self, path=None):
files = [] files = []
if path and path != '': if path and path != '':