This commit is contained in:
Lartza
2020-03-10 22:22:20 +02:00
parent 44c7adae1f
commit b2ced96ba4
15 changed files with 166 additions and 121 deletions
+24 -5
View File
@@ -19,6 +19,7 @@ from media.radio import RadioItem
log = logging.getLogger("bot")
def register_all_commands(bot):
bot.register_command(constants.commands('joinme'), cmd_joinme, no_partial_match=False, access_outside_channel=True)
bot.register_command(constants.commands('user_ban'), cmd_user_ban, no_partial_match=True)
@@ -71,6 +72,7 @@ def register_all_commands(bot):
bot.register_command('loop', cmd_loop_state, True)
bot.register_command('item', cmd_item, True)
def send_multi_lines(bot, lines, text, linebreak="<br />"):
global log
@@ -86,12 +88,13 @@ def send_multi_lines(bot, lines, text, linebreak="<br />"):
bot.send_msg(msg, text)
# ---------------- Variables -----------------
song_shortlist = []
# ---------------- Commands ------------------
# ---------------- Commands ------------------
def cmd_joinme(bot, user, text, command, parameter):
global log
@@ -146,6 +149,7 @@ def cmd_url_ban(bot, user, text, command, parameter):
bot.mumble.users[text.actor].send_text_message(constants.strings('not_admin'))
return
def cmd_url_ban_list(bot, user, text, command, parameter):
if bot.is_admin(user):
bot.mumble.users[text.actor].send_text_message(util.get_url_ban())
@@ -153,6 +157,7 @@ def cmd_url_ban_list(bot, user, text, command, parameter):
bot.mumble.users[text.actor].send_text_message(constants.strings('not_admin'))
return
def cmd_url_unban(bot, user, text, command, parameter):
global log
@@ -170,9 +175,11 @@ def cmd_play(bot, user, text, command, parameter):
if len(var.playlist) > 0:
if parameter:
if parameter.isdigit() and 1 <= int(parameter) <= len(var.playlist):
var.playlist.point_to(int(parameter) - 1 - 1) # First "-1" transfer 12345 to 01234, second "-1"
# First "-1" transfer 12345 to 01234, second "-1"
# point to the previous item. the loop will next to
# the one you want
var.playlist.point_to(int(parameter) - 1 - 1)
bot.interrupt()
else:
bot.send_msg(constants.strings('invalid_index', index=parameter), text)
@@ -331,7 +338,6 @@ def cmd_play_url(bot, user, text, command, parameter):
bot.send_msg(constants.strings('bad_parameter', command=command))
def cmd_play_playlist(bot, user, text, command, parameter):
global log
@@ -480,9 +486,11 @@ def cmd_rb_play(bot, user, text, command, parameter):
msg += "No playable url found for this station, please try another station."
bot.send_msg(msg, text)
yt_last_result = []
yt_last_page = 0 # TODO: if we keep adding global variables, we need to consider sealing all commands up into classes.
def cmd_yt_search(bot, user, text, command, parameter):
global log, yt_last_result, yt_last_page, song_shortlist
item_per_page = 5
@@ -516,6 +524,7 @@ def cmd_yt_search(bot, user, text, command, parameter):
else:
bot.send_msg(constants.strings('bad_parameter', command=command), text)
def _yt_format_result(results, start, count):
msg = '<table><tr><th width="10%">Index</th><th>Title</th><th width="20%">Uploader</th></tr>'
for index, item in enumerate(results[start:start+count]):
@@ -772,12 +781,14 @@ def cmd_queue(bot, user, text, command, parameter):
send_multi_lines(bot, msgs, text)
def cmd_random(bot, user, text, command, parameter):
global log
bot.interrupt()
var.playlist.randomize()
def cmd_repeat(bot, user, text, command, parameter):
global log
@@ -795,13 +806,14 @@ def cmd_repeat(bot, user, text, command, parameter):
bot.send_msg(constants.strings("repeat", song=music.format_song_string(), n=str(repeat)), text)
def cmd_mode(bot, user, text, command, parameter):
global log
if not parameter:
bot.send_msg(constants.strings("current_mode", mode=var.playlist.mode), text)
return
if not parameter in ["one-shot", "repeat", "random", "autoplay"]:
if parameter not in ["one-shot", "repeat", "random", "autoplay"]:
bot.send_msg(constants.strings('unknown_mode', mode=parameter), text)
else:
var.db.set('playlist', 'playback_mode', parameter)
@@ -813,6 +825,7 @@ def cmd_mode(bot, user, text, command, parameter):
bot.interrupt()
bot.launch_music()
def cmd_play_tags(bot, user, text, command, parameter):
if not parameter:
bot.send_msg(constants.strings('bad_parameter', command=command), text)
@@ -829,7 +842,6 @@ def cmd_play_tags(bot, user, text, command, parameter):
log.info("cmd: add to playlist: " + music_wrapper.format_debug_string())
msgs.append("<li><b>{}</b> (<i>{}</i>)</li>".format(music_wrapper.item().title, ", ".join(music_wrapper.item().tags)))
if count != 0:
msgs.append("</ul>")
var.playlist.extend(music_wrappers)
@@ -926,6 +938,7 @@ def cmd_remove_tag(bot, user, text, command, parameter):
bot.send_msg(constants.strings('bad_parameter', command=command), text)
def cmd_find_tagged(bot, user, text, command, parameter):
global song_shortlist
@@ -954,6 +967,7 @@ def cmd_find_tagged(bot, user, text, command, parameter):
else:
bot.send_msg(constants.strings("no_file"), text)
def cmd_search_library(bot, user, text, command, parameter):
global song_shortlist
if not parameter:
@@ -1078,6 +1092,7 @@ def cmd_delete_from_library(bot, user, text, command, parameter):
bot.send_msg(constants.strings('bad_parameter', command=command), text)
def cmd_drop_database(bot, user, text, command, parameter):
global log
@@ -1091,6 +1106,7 @@ def cmd_drop_database(bot, user, text, command, parameter):
else:
bot.mumble.users[text.actor].send_text_message(constants.strings('not_admin'))
def cmd_refresh_cache(bot, user, text, command, parameter):
global log
if bot.is_admin(user):
@@ -1100,13 +1116,16 @@ def cmd_refresh_cache(bot, user, text, command, parameter):
else:
bot.mumble.users[text.actor].send_text_message(constants.strings('not_admin'))
# Just for debug use
def cmd_real_time_rms(bot, user, text, command, parameter):
bot._display_rms = not bot._display_rms
def cmd_loop_state(bot, user, text, command, parameter):
print(bot._loop_status)
def cmd_item(bot, user, text, command, parameter):
print(bot.wait_for_downloading)
print(var.playlist.current_item().to_dict())
+2
View File
@@ -1,5 +1,6 @@
import variables as var
def strings(option, *argv, **kwargs):
string = ""
try:
@@ -22,6 +23,7 @@ def strings(option, *argv, **kwargs):
else:
return string
def commands(command):
string = ""
try:
+3 -4
View File
@@ -2,11 +2,14 @@ import sqlite3
import json
import datetime
class DatabaseError(Exception):
pass
class SettingsDatabase:
version = 1
def __init__(self, db_path):
self.db_path = db_path
@@ -227,7 +230,6 @@ class MusicDatabase:
condition.append('LOWER(title) LIKE ?')
filler.append("%{:s}%".format(keyword.lower()))
condition_str = " AND ".join(condition)
conn = sqlite3.connect(self.db_path)
@@ -246,7 +248,6 @@ class MusicDatabase:
condition.append('LOWER(tags) LIKE ?')
filler.append("%{:s},%".format(tag.lower()))
condition_str = " AND ".join(condition)
conn = sqlite3.connect(self.db_path)
@@ -284,7 +285,6 @@ class MusicDatabase:
return self._result_to_dict(results)
def _result_to_dict(self, results):
if len(results) > 0:
music_dicts = []
@@ -324,7 +324,6 @@ class MusicDatabase:
conn.commit()
conn.close()
def drop_table(self):
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
+14 -7
View File
@@ -57,6 +57,7 @@ web = Flask(__name__)
log = logging.getLogger("bot")
user = 'Remote Control'
def init_proxy():
global web
if var.is_proxified:
@@ -64,20 +65,22 @@ def init_proxy():
# https://stackoverflow.com/questions/29725217/password-protect-one-webpage-in-flask-app
def check_auth(username, password):
"""This function is called to check if a username /
password combination is valid.
"""
return username == var.config.get("webinterface", "user") and password == var.config.get("webinterface", "password")
def authenticate():
"""Sends a 401 response that enables basic auth"""
global log
return Response(
'Could not verify your access level for that URL.\n'
return Response('Could not verify your access level for that URL.\n'
'You have to login with proper credentials', 401,
{'WWW-Authenticate': 'Basic realm="Login Required"'})
def requires_auth(f):
@wraps(f)
def decorated(*args, **kwargs):
@@ -90,6 +93,7 @@ def requires_auth(f):
return f(*args, **kwargs)
return decorated
def tag_color(tag):
num = hash(tag) % 8
if num == 0:
@@ -109,14 +113,15 @@ def tag_color(tag):
elif num == 7:
return "dark"
def build_tags_color_lookup():
color_lookup = {}
for tag in var.music_db.query_all_tags():
color_lookup[tag] = tag_color(tag)
return color_lookup
def build_path_tags_lookup():
path_tags_lookup = {}
ids = list(var.cache.file_id_lookup.values())
@@ -128,11 +133,13 @@ def build_path_tags_lookup():
return path_tags_lookup
def recur_dir(dirobj):
for name, dir in dirobj.get_subdirs().items():
print(dirobj.fullpath + "/" + name)
recur_dir(dir)
@web.route("/", methods=['GET'])
@requires_auth
def index():
@@ -153,6 +160,7 @@ def index():
paused=var.bot.is_pause,
)
@web.route("/playlist", methods=['GET'])
@requires_auth
def playlist():
@@ -177,6 +185,7 @@ def playlist():
return jsonify({'items': items})
def status():
if len(var.playlist) > 0:
return jsonify({'ver': var.playlist.version,
@@ -231,15 +240,13 @@ def post():
music_wrappers = list(map(
lambda file:
get_cached_wrapper_by_id(var.bot, var.cache.file_id_lookup[folder + file], user),
files))
get_cached_wrapper_by_id(var.bot, var.cache.file_id_lookup[folder + file], user), files))
var.playlist.extend(music_wrappers)
for music_wrapper in music_wrappers:
log.info('web: add to playlist: ' + music_wrapper.format_debug_string())
elif 'add_url' in request.form:
music_wrapper = get_cached_wrapper_from_scrap(var.bot, type='url', url=request.form['add_url'], user=user)
var.playlist.append(music_wrapper)
@@ -279,7 +286,6 @@ def post():
else:
var.playlist.remove(index)
elif 'play_music' in request.form:
music_wrapper = var.playlist[int(request.form['play_music'])]
log.info("web: jump to: " + music_wrapper.format_debug_string())
@@ -358,6 +364,7 @@ def post():
return status()
@web.route('/upload', methods=["POST"])
def upload():
global log
+5 -1
View File
@@ -2,6 +2,7 @@ from librb.rbRadios import RadioBrowser
rb = RadioBrowser()
def getstations_byname(query):
results = rb.stations_byname(query)
stations = []
@@ -13,16 +14,19 @@ def getstations_byname(query):
pass
return stations
def geturl_byid(id):
url = rb.playable_station(id)['url']
if url != None:
if url is not None:
return url
else:
return "-1"
def getstationname_byid(id):
return rb.stations_byid(id)
if __name__ == "__main__":
r = getstations_byname('r.sh')
stationinfo = getstationname_byid(96748)
-1
View File
@@ -180,4 +180,3 @@ class RadioBrowser:
kwargs["params"] = params
endpoint = self.builder.produce_endpoint(endpoint="station_search")
return request(endpoint, **kwargs)
-1
View File
@@ -35,7 +35,6 @@ class MusicCache(dict):
# print(id)
# raise KeyError("Unable to fetch item from the database! Please try to refresh the cache by !recache.")
def get_item(self, bot, **kwargs):
# kwargs should provide type and id, and parameters to build the item if not existed in the library.
# if cached
+4
View File
@@ -24,15 +24,19 @@ type : file
user
'''
def file_item_builder(bot, **kwargs):
return FileItem(bot, kwargs['path'])
def file_item_loader(bot, _dict):
return FileItem(bot, "", _dict)
def file_item_id_generator(**kwargs):
return hashlib.md5(kwargs['path'].encode()).hexdigest()
item_builders['file'] = file_item_builder
item_loaders['file'] = file_item_loader
item_id_generators['file'] = file_item_id_generator
+6
View File
@@ -15,19 +15,24 @@ item_builders = {}
item_loaders = {}
item_id_generators = {}
def example_builder(bot, **kwargs):
return BaseItem(bot)
def example_loader(bot, _dict):
return BaseItem(bot, from_dict=_dict)
def example_id_generator(**kwargs):
return ""
item_builders['base'] = example_builder
item_loaders['base'] = example_loader
item_id_generators['base'] = example_id_generator
def dicts_to_items(bot, music_dicts):
items = []
for music_dict in music_dicts:
@@ -35,6 +40,7 @@ def dicts_to_items(bot, music_dicts):
items.append(item_loaders[type](bot, music_dict))
return items
def dict_to_item(bot, music_dict):
type = music_dict['type']
return item_loaders[type](bot, music_dict)
+4
View File
@@ -11,6 +11,7 @@ import constants
log = logging.getLogger("bot")
def get_radio_server_description(url):
global log
@@ -92,12 +93,15 @@ def radio_item_builder(bot, **kwargs):
else:
return RadioItem(bot, kwargs['url'], '')
def radio_item_loader(bot, _dict):
return RadioItem(bot, "", "", _dict)
def radio_item_id_generator(**kwargs):
return hashlib.md5(kwargs['url'].encode()).hexdigest()
item_builders['radio'] = radio_item_builder
item_loaders['radio'] = radio_item_loader
item_id_generators['radio'] = radio_item_id_generator
+4 -1
View File
@@ -17,15 +17,19 @@ import media.system
log = logging.getLogger("bot")
def url_item_builder(bot, **kwargs):
return URLItem(bot, kwargs['url'])
def url_item_loader(bot, _dict):
return URLItem(bot, "", _dict)
def url_item_id_generator(**kwargs):
return hashlib.md5(kwargs['url'].encode()).hexdigest()
item_builders['url'] = url_item_builder
item_loaders['url'] = url_item_loader
item_id_generators['url'] = url_item_id_generator
@@ -214,7 +218,6 @@ class URLItem(BaseItem):
return dict
def format_debug_string(self):
return "[url] {title} ({url})".format(
title=self.title,
+2
View File
@@ -6,6 +6,7 @@ import hashlib
from media.item import item_builders, item_loaders, item_id_generators
from media.url import URLItem, url_item_id_generator
def get_playlist_info(url, start_index=0, user=""):
items = []
ydl_opts = {
@@ -63,6 +64,7 @@ def playlist_url_item_builder(bot, **kwargs):
def playlist_url_item_loader(bot, _dict):
return PlaylistURLItem(bot, "", "", "", "", _dict)
item_builders['url_from_playlist'] = playlist_url_item_builder
item_loaders['url_from_playlist'] = playlist_url_item_loader
item_id_generators['url_from_playlist'] = url_item_id_generator
+3 -8
View File
@@ -151,7 +151,7 @@ class MumbleBot:
self.ducking_volume = var.db.getfloat("bot", "ducking_volume", fallback=self.ducking_volume)
self.ducking_threshold = var.config.getfloat("bot", "ducking_threshold", fallback=5000)
self.ducking_threshold = var.db.getfloat("bot", "ducking_threshold", fallback=self.ducking_threshold)
self.mumble.callbacks.set_callback(pymumble.constants.PYMUMBLE_CLBK_SOUNDRECEIVED, \
self.mumble.callbacks.set_callback(pymumble.constants.PYMUMBLE_CLBK_SOUNDRECEIVED,
self.ducking_sound_received)
self.mumble.set_receive_sound(True)
@@ -247,7 +247,6 @@ class MumbleBot:
constants.strings('url_ban'))
return
command_exc = ""
try:
if command in self.cmd_handle:
@@ -319,7 +318,7 @@ class MumbleBot:
def launch_music(self):
if var.playlist.is_empty():
return
assert self.wait_for_downloading == False
assert self.wait_for_downloading is False
music_wrapper = var.playlist.current_item()
uri = music_wrapper.uri()
@@ -367,7 +366,6 @@ class MumbleBot:
var.playlist.remove_by_id(next.id)
var.cache.free_and_delete(next.id)
# =======================
# Loop
# =======================
@@ -490,7 +488,7 @@ class MumbleBot:
if rms < self.ducking_threshold:
print('%6d/%6d ' % (rms, self._max_rms) + '-'*int(rms/200), end='\r')
else:
print('%6d/%6d ' % (rms, self._max_rms) + '-'*int(self.ducking_threshold/200) \
print('%6d/%6d ' % (rms, self._max_rms) + '-'*int(self.ducking_threshold/200)
+ '+'*int((rms - self.ducking_threshold)/200), end='\r')
if rms > self.ducking_threshold:
@@ -558,7 +556,6 @@ class MumbleBot:
command = ("ffmpeg", '-v', ffmpeg_debug, '-nostdin', '-ss', "%f" % self.playhead, '-i',
uri, '-ac', '1', '-f', 's16le', '-ar', '48000', '-')
if var.config.getboolean('bot', 'announce_current_music'):
self.send_msg(var.playlist.current_item().format_current_playing())
@@ -572,7 +569,6 @@ class MumbleBot:
self.last_volume_cycle_time = time.time()
self.pause_at_id = ""
# TODO: this is a temporary workaround for issue #44 of pymumble.
def _clear_pymumble_soundqueue(self):
for id, user in self.mumble.users.items():
@@ -582,7 +578,6 @@ class MumbleBot:
self.log.debug("bot: pymumble soundqueue cleared.")
def start_web_interface(addr, port):
global formatter
import interface
+3 -1
View File
@@ -19,7 +19,7 @@ from PIL import Image
from io import BytesIO
from sys import platform
import traceback
import urllib.parse, urllib.request, urllib.error
import urllib.request
import base64
import media
import media.radio
@@ -65,6 +65,7 @@ def get_recursive_file_list_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)
@@ -309,6 +310,7 @@ def get_url_from_input(string):
else:
return False
def youtube_search(query):
global log