Improve web interface (+ other small changes)

- Web Interface shows folders recursively
- Add command line options for web interface (--wi-port, --wi-addr)
- Move command line option parsing to main
- Move shared code to utils.py
- Fix some issues with web interface
- Fix other small things
This commit is contained in:
Fabian Würfl 2018-05-19 22:34:56 +02:00
parent fa5495a341
commit 85f90e4e44
4 changed files with 172 additions and 63 deletions

View File

@ -2,12 +2,12 @@
from flask import Flask, render_template, request, redirect from flask import Flask, render_template, request, redirect
import variables as var import variables as var
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
class ReverseProxied(object): class ReverseProxied(object):
'''Wrap the application in this middleware and configure the '''Wrap the application in this middleware and configure the
front-end server to add these headers, to let you quietly bind front-end server to add these headers, to let you quietly bind
@ -58,17 +58,33 @@ def init_proxy():
@web.route("/", methods=['GET', 'POST']) @web.route("/", methods=['GET', 'POST'])
def index(): def index():
folder_path = var.music_folder folder_path = var.music_folder
files = {} files = util.get_recursive_filelist_sorted(var.music_folder)
dirs = [f for f in listdir(folder_path) if os.path.isdir(os.path.join(folder_path, f))] music_library = util.Dir(folder_path)
for director in dirs: for file in files:
files[director] = [f for f in listdir(folder_path + director) if os.path.isfile(os.path.join(folder_path + director, f))] music_library.add_file(file)
if request.method == 'POST': if request.method == 'POST':
if 'add_file' in request.form and ".." not in request.form['add_music']: print(request.form)
var.playlist.append((request.form['type'], request.form['add_music'])) if 'add_file' in request.form and ".." not in request.form['add_file']:
if 'add_folder' in request.form and ".." not in request.form['add_folder']: item = ('file', request.form['add_file'])
dir_files = [("file", request.form['add_folder'] + '/' + i) for i in files[request.form['add_folder']]] var.playlist.append(item)
var.playlist.extend(dir_files) if ('add_folder' in request.form and ".." not in request.form['add_folder']) or ('add_folder_recursively' in request.form and ".." not in request.form['add_folder_recursively']) :
try:
folder = request.form['add_folder']
except:
folder = request.form['add_folder_recursively']
if not folder.endswith('/'):
folder += '/'
print('folder:', folder)
if 'add_folder_recursively' in request.form:
files = music_library.get_files_recursively(folder)
else:
files = music_library.get_files(folder)
files = list(map(lambda file: ('file', folder + '/' + file), files))
print('Adding to playlist: ', files)
var.playlist.extend(files)
elif 'delete_music' in request.form: elif 'delete_music' in request.form:
try: try:
var.playlist.remove("file", request.form['delete_music']) var.playlist.remove("file", request.form['delete_music'])
@ -87,7 +103,8 @@ def index():
current_music=current_music, current_music=current_music,
user=var.user, user=var.user,
playlist=var.playlist, playlist=var.playlist,
all_files=files) all_files=files,
music_library=music_library)
@web.route('/download', methods=["POST"]) @web.route('/download', methods=["POST"])

View File

@ -18,23 +18,17 @@ import variables as var
import hashlib import hashlib
import youtube_dl import youtube_dl
import media import media
import util
class MumbleBot: class MumbleBot:
def __init__(self): def __init__(self, args):
signal.signal(signal.SIGINT, self.ctrl_caught) signal.signal(signal.SIGINT, self.ctrl_caught)
self.config = configparser.ConfigParser(interpolation=None) self.config = configparser.ConfigParser(interpolation=None)
self.config.read("configuration.ini", encoding='latin-1') self.config.read("configuration.ini", encoding='latin-1')
parser = argparse.ArgumentParser(description='Bot for playing radio stream on Mumble')
parser.add_argument("-s", "--server", dest="host", type=str, required=True, help="The server's hostame of a mumble server")
parser.add_argument("-u", "--user", dest="user", type=str, required=True, help="Username you wish, Default=abot")
parser.add_argument("-P", "--password", dest="password", type=str, default="", help="Password if server requires one")
parser.add_argument("-p", "--port", dest="port", type=int, default=64738, help="Port for the mumble server")
parser.add_argument("-c", "--channel", dest="channel", type=str, default="", help="Default chanel for the bot")
args = parser.parse_args()
self.volume = self.config.getfloat('bot', 'volume') self.volume = self.config.getfloat('bot', 'volume')
self.channel = args.channel self.channel = args.channel
@ -64,11 +58,11 @@ class MumbleBot:
self.nb_exit = 0 self.nb_exit = 0
self.thread = None self.thread = None
interface.init_proxy() if args.wi_addr:
interface.init_proxy()
# t = threading.Thread(target=start_web_interface) tt = threading.Thread(target=start_web_interface, args=(args.wi_addr, args.wi_port))
# t.daemon = True tt.daemon = True
# t.start() tt.start()
self.mumble = pymumble.Mumble(args.host, user=args.user, port=args.port, password=args.password, self.mumble = pymumble.Mumble(args.host, user=args.user, port=args.port, password=args.password,
debug=self.config.getboolean('debug', 'mumbleConnection')) debug=self.config.getboolean('debug', 'mumbleConnection'))
@ -114,16 +108,14 @@ class MumbleBot:
path = os.path.abspath(os.path.join(music_folder, parameter)) path = os.path.abspath(os.path.join(music_folder, parameter))
if path.startswith(music_folder): if path.startswith(music_folder):
if os.path.isfile(path): if os.path.isfile(path):
#self.launch_play_file(path)
filename = path.replace(music_folder, '') filename = path.replace(music_folder, '')
var.playlist.append(["file", filename]) var.playlist.append(["file", filename])
else: else:
# try to do a partial match # try to do a partial match
matches = [file for file in self.__get_recursive_filelist_sorted(music_folder) if parameter.lower() in file.lower()] matches = [file for file in util.get_recursive_filelist_sorted(music_folder) if parameter.lower() in file.lower()]
if len(matches) == 0: if len(matches) == 0:
self.mumble.users[text.actor].send_message(self.config.get('strings', 'no_file')) self.mumble.users[text.actor].send_message(self.config.get('strings', 'no_file'))
elif len(matches) == 1: elif len(matches) == 1:
#self.launch_play_file(music_folder + matches[0])
var.playlist.append(["file", matches[0]]) var.playlist.append(["file", matches[0]])
else: else:
msg = self.config.get('strings', 'multiple_matches') + '<br />' msg = self.config.get('strings', 'multiple_matches') + '<br />'
@ -183,7 +175,7 @@ class MumbleBot:
elif command == self.config.get('command', 'list'): elif command == self.config.get('command', 'list'):
folder_path = self.config.get('bot', 'music_folder') folder_path = self.config.get('bot', 'music_folder')
files = self.__get_recursive_filelist_sorted(folder_path) files = util.get_recursive_filelist_sorted(folder_path)
if files : if files :
self.mumble.users[text.actor].send_message('<br>'.join(files)) self.mumble.users[text.actor].send_message('<br>'.join(files))
else : else :
@ -248,8 +240,8 @@ class MumbleBot:
command = ["ffmpeg", '-v', ffmpeg_debug, '-nostdin', '-i', path, '-ac', '1', '-f', 's16le', '-ar', '48000', '-'] command = ["ffmpeg", '-v', ffmpeg_debug, '-nostdin', '-i', path, '-ac', '1', '-f', 's16le', '-ar', '48000', '-']
self.thread = sp.Popen(command, stdout=sp.PIPE, bufsize=480) self.thread = sp.Popen(command, stdout=sp.PIPE, bufsize=480)
var.current_music.append(title) #var.current_music[2] = title
var.current_music.append(path) #var.current_music[3] = path
def download_music(self, url): def download_music(self, url):
url_hash = hashlib.md5(url.encode()).hexdigest() url_hash = hashlib.md5(url.encode()).hexdigest()
@ -316,26 +308,25 @@ class MumbleBot:
channel = self.mumble.channels[self.mumble.users.myself['channel_id']] channel = self.mumble.channels[self.mumble.users.myself['channel_id']]
channel.send_text_message(msg) channel.send_text_message(msg)
def __get_recursive_filelist_sorted(self, path):
filelist = []
for root, dirs, files in os.walk(path):
relroot = root.replace(path, '')
if relroot in self.config.get('bot', 'ignored_folders'):
continue
if len(relroot):
relroot += '/'
for file in files:
if file in self.config.get('bot', 'ignored_files'):
continue
filelist.append(relroot + file)
filelist.sort() def start_web_interface(addr, port):
return filelist print('Starting web interface on {}:{}'.format(addr, port))
interface.web.run(port=port, host=addr)
def start_web_interface():
interface.web.run(port=8181, host="127.0.0.1")
if __name__ == '__main__': if __name__ == '__main__':
botamusique = MumbleBot() parser = argparse.ArgumentParser(description='Bot for playing radio stream on Mumble')
# Mumble arguments
parser.add_argument("-s", "--server", dest="host", type=str, required=True, help="The server's hostame of a mumble server")
parser.add_argument("-u", "--user", dest="user", type=str, required=True, help="Username you wish, Default=abot")
parser.add_argument("-P", "--password", dest="password", type=str, default="", help="Password if server requires one")
parser.add_argument("-p", "--port", dest="port", type=int, default=64738, help="Port for the mumble server")
parser.add_argument("-c", "--channel", dest="channel", type=str, default="", help="Default chanel for the bot")
# web interface arguments
parser.add_argument('--wi-port', dest='wi_port', type=int, default=8181, help='Listening port of the web interface')
parser.add_argument('--wi-addr', dest='wi_addr', type=str, default=None, help='Listening address of the web interface')
args = parser.parse_args()
botamusique = MumbleBot(args)

View File

@ -1,3 +1,28 @@
{% macro dirlisting(path='') -%}
<ul>
{% for subdirname in music_library.get_subdirs(path) %}
{%- 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>
<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>
{%- set subdirs = music_library.get_subdirs(subdirpath) %}
{%- if subdirs %}
{%- for subdir in subdirs %}
{{- dirlisting(subdirpath) -}}
{%- endfor %}
{%- endif %}
<ul>
{%- set files = music_library.get_files(subdirpath) %}
{%- if files %}
{% for file in files %}
<!--<li>{{ file }}</li>-->
<li><form method="post"><input type=text value="{{ subdirpath }}/{{ file }}" name="add_file" hidden><input type="submit" value="{{ file }}"></form></li>
{% endfor %}
{%- endif %}
</ul>
{% endfor %}
</ul>
{%- endmacro %}
<!DOCTYPE html> <!DOCTYPE html>
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
@ -38,19 +63,8 @@
</li> </li>
{% endfor %} {% endfor %}
</ul> </ul>
<br> <h2>Music library:</h2>
{% for dir in all_files %} {{ dirlisting() }}
{{ dir }}
<form method="post"><input type=text value={{ dir }} name="add_folder" hidden><input type="submit" value="add all folder"></form>
<br>
<ul>
{% for m in all_files[dir] %}
<li>
<form method="post"><input type=text value="{{ dir }}/{{ m }}" name="add_music" hidden><input type="submit" value="{{ m }}"></form>
</li>
{% endfor %}
</ul>
{% endfor %}
</div> </div>
@ -61,4 +75,4 @@
</div> </div>
</body> </body>
</html> </html>

87
util.py Normal file
View File

@ -0,0 +1,87 @@
#!/usr/bin/python3
import configparser
import os
import variables as var
__CONFIG = configparser.ConfigParser(interpolation=None)
__CONFIG.read("configuration.ini", encoding='latin-1')
def get_recursive_filelist_sorted(path):
filelist = []
for root, dirs, files in os.walk(path):
relroot = root.replace(path, '')
if relroot != '' and relroot in __CONFIG.get('bot', 'ignored_folders'):
continue
if len(relroot):
relroot += '/'
for file in files:
if file in __CONFIG.get('bot', 'ignored_files'):
continue
filelist.append(relroot + file)
filelist.sort()
return filelist
class Dir(object):
def __init__(self, name):
self.name = name
self.subdirs = {}
self.files = []
def add_file(self, file):
if file.startswith(self.name + '/'):
file = file.replace(self.name + '/', '')
if '/' in file:
# This file is in a subdir
subdir = file.split('/')[0]
if subdir in self.subdirs:
self.subdirs[subdir].add_file(file)
else:
self.subdirs[subdir] = Dir(subdir)
self.subdirs[subdir].add_file(file)
else:
self.files.append(file)
return True
def get_subdirs(self, path=None):
if path and path != '':
subdir = path.split('/')[0]
if subdir in self.subdirs:
searchpath = '/'.join(path.split('/')[1::])
return self.subdirs[subdir].get_subdirs(searchpath)
else:
return self.subdirs
def get_files(self, path=None):
if path and path != '':
subdir = path.split('/')[0]
if subdir in self.subdirs:
searchpath = '/'.join(path.split('/')[1::])
return self.subdirs[subdir].get_files(searchpath)
else:
return self.files
def get_files_recursively(self, path=None):
print('in get_files_recursively', path)
if path and path != '':
subdir = path.split('/')[0]
if subdir in self.subdirs:
searchpath = '/'.join(path.split('/')[1::])
return self.subdirs[subdir].get_files_recursively(searchpath)
else:
files = self.files
for key, val in self.subdirs.items():
files.extend(map(lambda file: key + '/' + file,val.get_files_recursively()))
return files
def render_text(self, ident=0):
print('{}{}/'.format(' ' * (ident * 4), self.name))
for key, val in self.subdirs.items():
val.render_text(ident+1)
for file in self.files:
print('{}{}'.format(' ' * ((ident + 1)) * 4, file))