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
+50 -31
View File
@@ -19,6 +19,7 @@ from media.radio import RadioItem
log = logging.getLogger("bot") log = logging.getLogger("bot")
def register_all_commands(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('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) 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('loop', cmd_loop_state, True)
bot.register_command('item', cmd_item, True) bot.register_command('item', cmd_item, True)
def send_multi_lines(bot, lines, text, linebreak="<br />"): def send_multi_lines(bot, lines, text, linebreak="<br />"):
global log global log
@@ -79,19 +81,20 @@ def send_multi_lines(bot, lines, text, linebreak="<br />"):
for newline in lines: for newline in lines:
msg += br msg += br
br = linebreak br = linebreak
if (len(msg) + len(newline)) > (bot.mumble.get_max_message_length() - 4) != 0: # 4 == len("<br>") if (len(msg) + len(newline)) > (bot.mumble.get_max_message_length() - 4) != 0: # 4 == len("<br>")
bot.send_msg(msg, text) bot.send_msg(msg, text)
msg = "" msg = ""
msg += newline msg += newline
bot.send_msg(msg, text) bot.send_msg(msg, text)
# ---------------- Variables ----------------- # ---------------- Variables -----------------
song_shortlist = [] song_shortlist = []
# ---------------- Commands ------------------
# ---------------- Commands ------------------
def cmd_joinme(bot, user, text, command, parameter): def cmd_joinme(bot, user, text, command, parameter):
global log 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')) bot.mumble.users[text.actor].send_text_message(constants.strings('not_admin'))
return return
def cmd_url_ban_list(bot, user, text, command, parameter): def cmd_url_ban_list(bot, user, text, command, parameter):
if bot.is_admin(user): if bot.is_admin(user):
bot.mumble.users[text.actor].send_text_message(util.get_url_ban()) 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')) bot.mumble.users[text.actor].send_text_message(constants.strings('not_admin'))
return return
def cmd_url_unban(bot, user, text, command, parameter): def cmd_url_unban(bot, user, text, command, parameter):
global log global log
@@ -170,9 +175,11 @@ def cmd_play(bot, user, text, command, parameter):
if len(var.playlist) > 0: if len(var.playlist) > 0:
if parameter: if parameter:
if parameter.isdigit() and 1 <= int(parameter) <= len(var.playlist): 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 # point to the previous item. the loop will next to
# the one you want # the one you want
var.playlist.point_to(int(parameter) - 1 - 1)
bot.interrupt() bot.interrupt()
else: else:
bot.send_msg(constants.strings('invalid_index', index=parameter), text) bot.send_msg(constants.strings('invalid_index', index=parameter), text)
@@ -241,7 +248,7 @@ def cmd_play_file(bot, user, text, command, parameter, do_not_refresh_cache=Fals
else: else:
# try to do a partial match # try to do a partial match
files = var.cache.files files = var.cache.files
matches = [ file for file in files if parameter.lower() in file.lower()] matches = [file for file in files if parameter.lower() in file.lower()]
if len(matches) == 1: if len(matches) == 1:
file = matches[0] file = matches[0]
music_wrapper = get_cached_wrapper_by_id(bot, var.cache.file_id_lookup[file], user) music_wrapper = get_cached_wrapper_by_id(bot, var.cache.file_id_lookup[file], user)
@@ -250,7 +257,7 @@ def cmd_play_file(bot, user, text, command, parameter, do_not_refresh_cache=Fals
bot.send_msg(constants.strings('file_added', item=music_wrapper.format_song_string())) bot.send_msg(constants.strings('file_added', item=music_wrapper.format_song_string()))
return return
elif len(matches) > 1: elif len(matches) > 1:
msgs = [ constants.strings('multiple_matches') ] msgs = [constants.strings('multiple_matches')]
song_shortlist = [] song_shortlist = []
for index, match in enumerate(matches): for index, match in enumerate(matches):
id = var.cache.file_id_lookup[match] id = var.cache.file_id_lookup[match]
@@ -277,7 +284,7 @@ def cmd_play_file_match(bot, user, text, command, parameter, do_not_refresh_cach
music_folder = var.music_folder music_folder = var.music_folder
if parameter: if parameter:
files = var.cache.files files = var.cache.files
msgs = [ constants.strings('multiple_file_added') + "<ul>"] msgs = [constants.strings('multiple_file_added') + "<ul>"]
count = 0 count = 0
try: try:
music_wrappers = [] music_wrappers = []
@@ -289,12 +296,12 @@ def cmd_play_file_match(bot, user, text, command, parameter, do_not_refresh_cach
music_wrappers.append(music_wrapper) music_wrappers.append(music_wrapper)
log.info("cmd: add to playlist: " + music_wrapper.format_debug_string()) log.info("cmd: add to playlist: " + music_wrapper.format_debug_string())
msgs.append("<li><b>{}</b> ({})</li>".format(music_wrapper.item().title, msgs.append("<li><b>{}</b> ({})</li>".format(music_wrapper.item().title,
file[:match.span()[0]] file[:match.span()[0]]
+ "<b style='color:pink'>" + "<b style='color:pink'>"
+ file[match.span()[0]: match.span()[1]] + file[match.span()[0]: match.span()[1]]
+ "</b>" + "</b>"
+ file[match.span()[1]:] + file[match.span()[1]:]
)) ))
if count != 0: if count != 0:
msgs.append("</ul>") msgs.append("</ul>")
@@ -331,7 +338,6 @@ def cmd_play_url(bot, user, text, command, parameter):
bot.send_msg(constants.strings('bad_parameter', command=command)) bot.send_msg(constants.strings('bad_parameter', command=command))
def cmd_play_playlist(bot, user, text, command, parameter): def cmd_play_playlist(bot, user, text, command, parameter):
global log global log
@@ -480,8 +486,10 @@ def cmd_rb_play(bot, user, text, command, parameter):
msg += "No playable url found for this station, please try another station." msg += "No playable url found for this station, please try another station."
bot.send_msg(msg, text) bot.send_msg(msg, text)
yt_last_result = [] yt_last_result = []
yt_last_page = 0 # TODO: if we keep adding global variables, we need to consider sealing all commands up into classes. 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): def cmd_yt_search(bot, user, text, command, parameter):
global log, yt_last_result, yt_last_page, song_shortlist global log, yt_last_result, yt_last_page, song_shortlist
@@ -516,6 +524,7 @@ def cmd_yt_search(bot, user, text, command, parameter):
else: else:
bot.send_msg(constants.strings('bad_parameter', command=command), text) bot.send_msg(constants.strings('bad_parameter', command=command), text)
def _yt_format_result(results, start, count): def _yt_format_result(results, start, count):
msg = '<table><tr><th width="10%">Index</th><th>Title</th><th width="20%">Uploader</th></tr>' 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]): for index, item in enumerate(results[start:start+count]):
@@ -602,7 +611,7 @@ def cmd_volume(bot, user, text, command, parameter):
if parameter and parameter.isdigit() and 0 <= int(parameter) <= 100: if parameter and parameter.isdigit() and 0 <= int(parameter) <= 100:
bot.volume_set = float(float(parameter) / 100) bot.volume_set = float(float(parameter) / 100)
bot.send_msg(constants.strings('change_volume', bot.send_msg(constants.strings('change_volume',
volume=int(bot.volume_set * 100), user=bot.mumble.users[text.actor]['name'])) volume=int(bot.volume_set * 100), user=bot.mumble.users[text.actor]['name']))
var.db.set('bot', 'volume', str(bot.volume_set)) var.db.set('bot', 'volume', str(bot.volume_set))
log.info('cmd: volume set to %d' % (bot.volume_set * 100)) log.info('cmd: volume set to %d' % (bot.volume_set * 100))
else: else:
@@ -652,7 +661,7 @@ def cmd_ducking_volume(bot, user, text, command, parameter):
if parameter and parameter.isdigit() and 0 <= int(parameter) <= 100: if parameter and parameter.isdigit() and 0 <= int(parameter) <= 100:
bot.ducking_volume = float(float(parameter) / 100) bot.ducking_volume = float(float(parameter) / 100)
bot.send_msg(constants.strings('change_ducking_volume', bot.send_msg(constants.strings('change_ducking_volume',
volume=int(bot.ducking_volume * 100), user=bot.mumble.users[text.actor]['name']), text) volume=int(bot.ducking_volume * 100), user=bot.mumble.users[text.actor]['name']), text)
# var.db.set('bot', 'volume', str(bot.volume_set)) # var.db.set('bot', 'volume', str(bot.volume_set))
var.db.set('bot', 'ducking_volume', str(bot.ducking_volume)) var.db.set('bot', 'ducking_volume', str(bot.ducking_volume))
log.info('cmd: volume on ducking set to %d' % (bot.ducking_volume * 100)) log.info('cmd: volume on ducking set to %d' % (bot.ducking_volume * 100))
@@ -707,7 +716,7 @@ def cmd_remove(bot, user, text, command, parameter):
var.playlist.current_index -= 1 var.playlist.current_index -= 1
# then the bot will move to next item # then the bot will move to next item
else: # if item deleted is the last item of the queue else: # if item deleted is the last item of the queue
var.playlist.current_index -= 1 var.playlist.current_index -= 1
if not bot.is_pause: if not bot.is_pause:
bot.interrupt() bot.interrupt()
@@ -715,7 +724,7 @@ def cmd_remove(bot, user, text, command, parameter):
removed = var.playlist.remove(index) removed = var.playlist.remove(index)
bot.send_msg(constants.strings('removing_item', bot.send_msg(constants.strings('removing_item',
item=removed.format_short_string()), text) item=removed.format_short_string()), text)
log.info("cmd: delete from playlist: " + removed.format_debug_string()) log.info("cmd: delete from playlist: " + removed.format_debug_string())
else: else:
@@ -726,7 +735,7 @@ def cmd_list_file(bot, user, text, command, parameter):
global log global log
files = var.cache.files files = var.cache.files
msgs = [ constants.strings("multiple_file_found") ] msgs = [constants.strings("multiple_file_found")]
try: try:
count = 0 count = 0
for index, file in enumerate(files): for index, file in enumerate(files):
@@ -755,7 +764,7 @@ def cmd_queue(bot, user, text, command, parameter):
msg = constants.strings('queue_empty') msg = constants.strings('queue_empty')
bot.send_msg(msg, text) bot.send_msg(msg, text)
else: else:
msgs = [ constants.strings('queue_contents')] msgs = [constants.strings('queue_contents')]
for i, music in enumerate(var.playlist): for i, music in enumerate(var.playlist):
newline = '' newline = ''
tags = '' tags = ''
@@ -763,21 +772,23 @@ def cmd_queue(bot, user, text, command, parameter):
tags = "<sup>{}</sup>".format(", ".join(music.item().tags)) tags = "<sup>{}</sup>".format(", ".join(music.item().tags))
if i == var.playlist.current_index: if i == var.playlist.current_index:
newline = "<b style='color:orange'>{} ({}) {} </b> {}".format(i + 1, music.display_type(), newline = "<b style='color:orange'>{} ({}) {} </b> {}".format(i + 1, music.display_type(),
music.format_short_string(), tags) music.format_short_string(), tags)
else: else:
newline = '<b>{}</b> ({}) {} {}'.format(i + 1, music.display_type(), newline = '<b>{}</b> ({}) {} {}'.format(i + 1, music.display_type(),
music.format_short_string(), tags) music.format_short_string(), tags)
msgs.append(newline) msgs.append(newline)
send_multi_lines(bot, msgs, text) send_multi_lines(bot, msgs, text)
def cmd_random(bot, user, text, command, parameter): def cmd_random(bot, user, text, command, parameter):
global log global log
bot.interrupt() bot.interrupt()
var.playlist.randomize() var.playlist.randomize()
def cmd_repeat(bot, user, text, command, parameter): def cmd_repeat(bot, user, text, command, parameter):
global log 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) bot.send_msg(constants.strings("repeat", song=music.format_song_string(), n=str(repeat)), text)
def cmd_mode(bot, user, text, command, parameter): def cmd_mode(bot, user, text, command, parameter):
global log global log
if not parameter: if not parameter:
bot.send_msg(constants.strings("current_mode", mode=var.playlist.mode), text) bot.send_msg(constants.strings("current_mode", mode=var.playlist.mode), text)
return 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) bot.send_msg(constants.strings('unknown_mode', mode=parameter), text)
else: else:
var.db.set('playlist', 'playback_mode', parameter) var.db.set('playlist', 'playback_mode', parameter)
@@ -813,6 +825,7 @@ def cmd_mode(bot, user, text, command, parameter):
bot.interrupt() bot.interrupt()
bot.launch_music() bot.launch_music()
def cmd_play_tags(bot, user, text, command, parameter): def cmd_play_tags(bot, user, text, command, parameter):
if not parameter: if not parameter:
bot.send_msg(constants.strings('bad_parameter', command=command), text) 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()) 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))) msgs.append("<li><b>{}</b> (<i>{}</i>)</li>".format(music_wrapper.item().title, ", ".join(music_wrapper.item().tags)))
if count != 0: if count != 0:
msgs.append("</ul>") msgs.append("</ul>")
var.playlist.extend(music_wrappers) var.playlist.extend(music_wrappers)
@@ -897,7 +909,7 @@ def cmd_remove_tag(bot, user, text, command, parameter):
if tags[0] != "*": if tags[0] != "*":
var.playlist[int(index) - 1].remove_tags(tags) var.playlist[int(index) - 1].remove_tags(tags)
log.info("cmd: remove tags %s from song %s" % (", ".join(tags), log.info("cmd: remove tags %s from song %s" % (", ".join(tags),
var.playlist[int(index) - 1].format_debug_string())) var.playlist[int(index) - 1].format_debug_string()))
bot.send_msg(constants.strings("removed_tags", bot.send_msg(constants.strings("removed_tags",
tags=", ".join(tags), tags=", ".join(tags),
song=var.playlist[int(index) - 1].format_short_string()), text) song=var.playlist[int(index) - 1].format_short_string()), text)
@@ -914,7 +926,7 @@ def cmd_remove_tag(bot, user, text, command, parameter):
for item in var.playlist: for item in var.playlist:
item.remove_tags(tags) item.remove_tags(tags)
log.info("cmd: remove tags %s from song %s" % (", ".join(tags), log.info("cmd: remove tags %s from song %s" % (", ".join(tags),
item.format_debug_string())) item.format_debug_string()))
bot.send_msg(constants.strings("removed_tags_from_all", tags=", ".join(tags)), text) bot.send_msg(constants.strings("removed_tags_from_all", tags=", ".join(tags)), text)
return return
else: else:
@@ -926,6 +938,7 @@ def cmd_remove_tag(bot, user, text, command, parameter):
bot.send_msg(constants.strings('bad_parameter', command=command), text) bot.send_msg(constants.strings('bad_parameter', command=command), text)
def cmd_find_tagged(bot, user, text, command, parameter): def cmd_find_tagged(bot, user, text, command, parameter):
global song_shortlist global song_shortlist
@@ -954,6 +967,7 @@ def cmd_find_tagged(bot, user, text, command, parameter):
else: else:
bot.send_msg(constants.strings("no_file"), text) bot.send_msg(constants.strings("no_file"), text)
def cmd_search_library(bot, user, text, command, parameter): def cmd_search_library(bot, user, text, command, parameter):
global song_shortlist global song_shortlist
if not parameter: if not parameter:
@@ -995,7 +1009,7 @@ def cmd_shortlist(bot, user, text, command, parameter):
global song_shortlist, log global song_shortlist, log
indexes = [] indexes = []
try: try:
indexes = [ int(i) for i in parameter.split(" ") ] indexes = [int(i) for i in parameter.split(" ")]
except ValueError: except ValueError:
bot.send_msg(constants.strings('bad_parameter', command=command), text) bot.send_msg(constants.strings('bad_parameter', command=command), text)
return return
@@ -1035,7 +1049,7 @@ def cmd_delete_from_library(bot, user, text, command, parameter):
global song_shortlist, log global song_shortlist, log
indexes = [] indexes = []
try: try:
indexes = [ int(i) for i in parameter.split(" ") ] indexes = [int(i) for i in parameter.split(" ")]
except ValueError: except ValueError:
bot.send_msg(constants.strings('bad_parameter', command=command), text) bot.send_msg(constants.strings('bad_parameter', command=command), text)
return return
@@ -1049,7 +1063,7 @@ def cmd_delete_from_library(bot, user, text, command, parameter):
if 'id' in music_dict: if 'id' in music_dict:
music_wrapper = get_cached_wrapper_by_id(bot, music_dict['id'], user) music_wrapper = get_cached_wrapper_by_id(bot, music_dict['id'], user)
log.info("cmd: remove from library: " + music_wrapper.format_debug_string()) log.info("cmd: remove from library: " + music_wrapper.format_debug_string())
msgs.append("<li>[{}] <b>{}</b></li>".format(music_wrapper.item().type ,music_wrapper.item().title)) msgs.append("<li>[{}] <b>{}</b></li>".format(music_wrapper.item().type, music_wrapper.item().title))
var.playlist.remove_by_id(music_dict['id']) var.playlist.remove_by_id(music_dict['id'])
var.cache.free_and_delete(music_dict['id']) var.cache.free_and_delete(music_dict['id'])
count += 1 count += 1
@@ -1078,6 +1092,7 @@ def cmd_delete_from_library(bot, user, text, command, parameter):
bot.send_msg(constants.strings('bad_parameter', command=command), text) bot.send_msg(constants.strings('bad_parameter', command=command), text)
def cmd_drop_database(bot, user, text, command, parameter): def cmd_drop_database(bot, user, text, command, parameter):
global log global log
@@ -1091,6 +1106,7 @@ def cmd_drop_database(bot, user, text, command, parameter):
else: else:
bot.mumble.users[text.actor].send_text_message(constants.strings('not_admin')) bot.mumble.users[text.actor].send_text_message(constants.strings('not_admin'))
def cmd_refresh_cache(bot, user, text, command, parameter): def cmd_refresh_cache(bot, user, text, command, parameter):
global log global log
if bot.is_admin(user): if bot.is_admin(user):
@@ -1100,13 +1116,16 @@ def cmd_refresh_cache(bot, user, text, command, parameter):
else: else:
bot.mumble.users[text.actor].send_text_message(constants.strings('not_admin')) bot.mumble.users[text.actor].send_text_message(constants.strings('not_admin'))
# Just for debug use # Just for debug use
def cmd_real_time_rms(bot, user, text, command, parameter): def cmd_real_time_rms(bot, user, text, command, parameter):
bot._display_rms = not bot._display_rms bot._display_rms = not bot._display_rms
def cmd_loop_state(bot, user, text, command, parameter): def cmd_loop_state(bot, user, text, command, parameter):
print(bot._loop_status) print(bot._loop_status)
def cmd_item(bot, user, text, command, parameter): def cmd_item(bot, user, text, command, parameter):
print(bot.wait_for_downloading) print(bot.wait_for_downloading)
print(var.playlist.current_item().to_dict()) print(var.playlist.current_item().to_dict())
+2
View File
@@ -1,5 +1,6 @@
import variables as var import variables as var
def strings(option, *argv, **kwargs): def strings(option, *argv, **kwargs):
string = "" string = ""
try: try:
@@ -22,6 +23,7 @@ def strings(option, *argv, **kwargs):
else: else:
return string return string
def commands(command): def commands(command):
string = "" string = ""
try: try:
+8 -9
View File
@@ -2,11 +2,14 @@ import sqlite3
import json import json
import datetime import datetime
class DatabaseError(Exception): class DatabaseError(Exception):
pass pass
class SettingsDatabase: class SettingsDatabase:
version = 1 version = 1
def __init__(self, db_path): def __init__(self, db_path):
self.db_path = db_path self.db_path = db_path
@@ -57,9 +60,9 @@ class SettingsDatabase:
"value TEXT, " "value TEXT, "
"UNIQUE(section, option))") "UNIQUE(section, option))")
cursor.execute("INSERT INTO botamusique (section, option, value) " cursor.execute("INSERT INTO botamusique (section, option, value) "
"VALUES (?, ?, ?)" , ("bot", "db_version", "1")) "VALUES (?, ?, ?)", ("bot", "db_version", "1"))
cursor.execute("INSERT INTO botamusique (section, option, value) " cursor.execute("INSERT INTO botamusique (section, option, value) "
"VALUES (?, ?, ?)" , ("bot", "music_db_version", "0")) "VALUES (?, ?, ?)", ("bot", "music_db_version", "0"))
conn.commit() conn.commit()
conn.close() conn.close()
@@ -90,7 +93,7 @@ class SettingsDatabase:
conn = sqlite3.connect(self.db_path) conn = sqlite3.connect(self.db_path)
cursor = conn.cursor() cursor = conn.cursor()
cursor.execute("INSERT OR REPLACE INTO botamusique (section, option, value) " cursor.execute("INSERT OR REPLACE INTO botamusique (section, option, value) "
"VALUES (?, ?, ?)" , (section, option, value)) "VALUES (?, ?, ?)", (section, option, value))
conn.commit() conn.commit()
conn.close() conn.close()
@@ -214,7 +217,7 @@ class MusicDatabase:
conn = sqlite3.connect(self.db_path) conn = sqlite3.connect(self.db_path)
cursor = conn.cursor() cursor = conn.cursor()
results = cursor.execute("SELECT id, type, title, metadata, tags FROM music " results = cursor.execute("SELECT id, type, title, metadata, tags FROM music "
"WHERE %s" % condition_str, filler).fetchall() "WHERE %s" % condition_str, filler).fetchall()
conn.close() conn.close()
return self._result_to_dict(results) return self._result_to_dict(results)
@@ -227,7 +230,6 @@ class MusicDatabase:
condition.append('LOWER(title) LIKE ?') condition.append('LOWER(title) LIKE ?')
filler.append("%{:s}%".format(keyword.lower())) filler.append("%{:s}%".format(keyword.lower()))
condition_str = " AND ".join(condition) condition_str = " AND ".join(condition)
conn = sqlite3.connect(self.db_path) conn = sqlite3.connect(self.db_path)
@@ -246,7 +248,6 @@ class MusicDatabase:
condition.append('LOWER(tags) LIKE ?') condition.append('LOWER(tags) LIKE ?')
filler.append("%{:s},%".format(tag.lower())) filler.append("%{:s},%".format(tag.lower()))
condition_str = " AND ".join(condition) condition_str = " AND ".join(condition)
conn = sqlite3.connect(self.db_path) conn = sqlite3.connect(self.db_path)
@@ -284,7 +285,6 @@ class MusicDatabase:
return self._result_to_dict(results) return self._result_to_dict(results)
def _result_to_dict(self, results): def _result_to_dict(self, results):
if len(results) > 0: if len(results) > 0:
music_dicts = [] music_dicts = []
@@ -320,11 +320,10 @@ class MusicDatabase:
conn = sqlite3.connect(self.db_path) conn = sqlite3.connect(self.db_path)
cursor = conn.cursor() cursor = conn.cursor()
cursor.execute("DELETE FROM music " cursor.execute("DELETE FROM music "
"WHERE %s" % condition_str, filler) "WHERE %s" % condition_str, filler)
conn.commit() conn.commit()
conn.close() conn.close()
def drop_table(self): def drop_table(self):
conn = sqlite3.connect(self.db_path) conn = sqlite3.connect(self.db_path)
cursor = conn.cursor() cursor = conn.cursor()
+24 -17
View File
@@ -57,6 +57,7 @@ web = Flask(__name__)
log = logging.getLogger("bot") log = logging.getLogger("bot")
user = 'Remote Control' user = 'Remote Control'
def init_proxy(): def init_proxy():
global web global web
if var.is_proxified: if var.is_proxified:
@@ -64,19 +65,21 @@ def init_proxy():
# https://stackoverflow.com/questions/29725217/password-protect-one-webpage-in-flask-app # https://stackoverflow.com/questions/29725217/password-protect-one-webpage-in-flask-app
def check_auth(username, password): def check_auth(username, password):
"""This function is called to check if a username / """This function is called to check if a username /
password combination is valid. password combination is valid.
""" """
return username == var.config.get("webinterface", "user") and password == var.config.get("webinterface", "password") return username == var.config.get("webinterface", "user") and password == var.config.get("webinterface", "password")
def authenticate(): def authenticate():
"""Sends a 401 response that enables basic auth""" """Sends a 401 response that enables basic auth"""
global log global log
return Response( return Response('Could not verify your access level for that URL.\n'
'Could not verify your access level for that URL.\n' 'You have to login with proper credentials', 401,
'You have to login with proper credentials', 401, {'WWW-Authenticate': 'Basic realm="Login Required"'})
{'WWW-Authenticate': 'Basic realm="Login Required"'})
def requires_auth(f): def requires_auth(f):
@wraps(f) @wraps(f)
@@ -90,6 +93,7 @@ def requires_auth(f):
return f(*args, **kwargs) return f(*args, **kwargs)
return decorated return decorated
def tag_color(tag): def tag_color(tag):
num = hash(tag) % 8 num = hash(tag) % 8
if num == 0: if num == 0:
@@ -109,14 +113,15 @@ def tag_color(tag):
elif num == 7: elif num == 7:
return "dark" return "dark"
def build_tags_color_lookup(): def build_tags_color_lookup():
color_lookup = {} color_lookup = {}
for tag in var.music_db.query_all_tags(): for tag in var.music_db.query_all_tags():
color_lookup[tag] = tag_color(tag) color_lookup[tag] = tag_color(tag)
return color_lookup return color_lookup
def build_path_tags_lookup(): def build_path_tags_lookup():
path_tags_lookup = {} path_tags_lookup = {}
ids = list(var.cache.file_id_lookup.values()) ids = list(var.cache.file_id_lookup.values())
@@ -128,11 +133,13 @@ def build_path_tags_lookup():
return path_tags_lookup return path_tags_lookup
def recur_dir(dirobj): def recur_dir(dirobj):
for name, dir in dirobj.get_subdirs().items(): for name, dir in dirobj.get_subdirs().items():
print(dirobj.fullpath + "/" + name) print(dirobj.fullpath + "/" + name)
recur_dir(dir) recur_dir(dir)
@web.route("/", methods=['GET']) @web.route("/", methods=['GET'])
@requires_auth @requires_auth
def index(): def index():
@@ -153,21 +160,22 @@ def index():
paused=var.bot.is_pause, paused=var.bot.is_pause,
) )
@web.route("/playlist", methods=['GET']) @web.route("/playlist", methods=['GET'])
@requires_auth @requires_auth
def playlist(): def playlist():
if len(var.playlist) == 0: if len(var.playlist) == 0:
return jsonify({'items': [render_template('playlist.html', return jsonify({'items': [render_template('playlist.html',
m=False, m=False,
index=-1 index=-1
)] )]
}) })
tags_color_lookup = build_tags_color_lookup() tags_color_lookup = build_tags_color_lookup()
items = [] items = []
for index, item_wrapper in enumerate(var.playlist): for index, item_wrapper in enumerate(var.playlist):
items.append(render_template('playlist.html', items.append(render_template('playlist.html',
index=index, index=index,
tags_color_lookup=tags_color_lookup, tags_color_lookup=tags_color_lookup,
m=item_wrapper.item(), m=item_wrapper.item(),
@@ -175,7 +183,8 @@ def playlist():
) )
) )
return jsonify({ 'items': items }) return jsonify({'items': items})
def status(): def status():
if len(var.playlist) > 0: if len(var.playlist) > 0:
@@ -197,7 +206,7 @@ def post():
if request.method == 'POST': if request.method == 'POST':
if request.form: if request.form:
log.debug("web: Post request from %s: %s" % ( request.remote_addr, str(request.form))) log.debug("web: Post request from %s: %s" % (request.remote_addr, str(request.form)))
if 'add_file_bottom' in request.form and ".." not in request.form['add_file_bottom']: if 'add_file_bottom' in request.form and ".." not in request.form['add_file_bottom']:
path = var.music_folder + request.form['add_file_bottom'] path = var.music_folder + request.form['add_file_bottom']
if os.path.isfile(path): if os.path.isfile(path):
@@ -231,15 +240,13 @@ def post():
music_wrappers = list(map( music_wrappers = list(map(
lambda file: lambda file:
get_cached_wrapper_by_id(var.bot, var.cache.file_id_lookup[folder + file], user), get_cached_wrapper_by_id(var.bot, var.cache.file_id_lookup[folder + file], user), files))
files))
var.playlist.extend(music_wrappers) var.playlist.extend(music_wrappers)
for music_wrapper in music_wrappers: for music_wrapper in music_wrappers:
log.info('web: add to playlist: ' + music_wrapper.format_debug_string()) log.info('web: add to playlist: ' + music_wrapper.format_debug_string())
elif 'add_url' in request.form: elif 'add_url' in request.form:
music_wrapper = get_cached_wrapper_from_scrap(var.bot, type='url', url=request.form['add_url'], user=user) music_wrapper = get_cached_wrapper_from_scrap(var.bot, type='url', url=request.form['add_url'], user=user)
var.playlist.append(music_wrapper) var.playlist.append(music_wrapper)
@@ -279,7 +286,6 @@ def post():
else: else:
var.playlist.remove(index) var.playlist.remove(index)
elif 'play_music' in request.form: elif 'play_music' in request.form:
music_wrapper = var.playlist[int(request.form['play_music'])] music_wrapper = var.playlist[int(request.form['play_music'])]
log.info("web: jump to: " + music_wrapper.format_debug_string()) log.info("web: jump to: " + music_wrapper.format_debug_string())
@@ -358,6 +364,7 @@ def post():
return status() return status()
@web.route('/upload', methods=["POST"]) @web.route('/upload', methods=["POST"])
def upload(): def upload():
global log global log
@@ -366,7 +373,7 @@ def upload():
if not files: if not files:
return redirect("./", code=406) return redirect("./", code=406)
#filename = secure_filename(file.filename).strip() # filename = secure_filename(file.filename).strip()
for file in files: for file in files:
filename = file.filename filename = file.filename
if filename == '': if filename == '':
@@ -385,7 +392,7 @@ def upload():
if "audio" in file.mimetype: if "audio" in file.mimetype:
storagepath = os.path.abspath(os.path.join(var.music_folder, targetdir)) storagepath = os.path.abspath(os.path.join(var.music_folder, targetdir))
print('storagepath:',storagepath) print('storagepath:', storagepath)
if not storagepath.startswith(os.path.abspath(var.music_folder)): if not storagepath.startswith(os.path.abspath(var.music_folder)):
return redirect("./", code=406) return redirect("./", code=406)
+6 -2
View File
@@ -2,27 +2,31 @@ from librb.rbRadios import RadioBrowser
rb = RadioBrowser() rb = RadioBrowser()
def getstations_byname(query): def getstations_byname(query):
results = rb.stations_byname(query) results = rb.stations_byname(query)
stations = [] stations = []
for st in results: for st in results:
try: try:
station = {'stationname': st['name'], 'id':st['id'], 'codec':st['codec'], 'bitrate':st['bitrate'], 'country':st['country'], 'homepage':st['homepage'], 'genre':st['tags']} station = {'stationname': st['name'], 'id': st['id'], 'codec': st['codec'], 'bitrate': st['bitrate'], 'country': st['country'], 'homepage': st['homepage'], 'genre': st['tags']}
stations.append(station) stations.append(station)
except: except:
pass pass
return stations return stations
def geturl_byid(id): def geturl_byid(id):
url = rb.playable_station(id)['url'] url = rb.playable_station(id)['url']
if url != None: if url is not None:
return url return url
else: else:
return "-1" return "-1"
def getstationname_byid(id): def getstationname_byid(id):
return rb.stations_byid(id) return rb.stations_byid(id)
if __name__ == "__main__": if __name__ == "__main__":
r = getstations_byname('r.sh') r = getstations_byname('r.sh')
stationinfo = getstationname_byid(96748) stationinfo = getstationname_byid(96748)
-1
View File
@@ -180,4 +180,3 @@ class RadioBrowser:
kwargs["params"] = params kwargs["params"] = params
endpoint = self.builder.produce_endpoint(endpoint="station_search") endpoint = self.builder.produce_endpoint(endpoint="station_search")
return request(endpoint, **kwargs) return request(endpoint, **kwargs)
+4 -5
View File
@@ -20,7 +20,7 @@ class MusicCache(dict):
self.files = [] self.files = []
self.dir_lock = threading.Lock() self.dir_lock = threading.Lock()
def get_item_by_id(self, bot, id): # Why all these functions need a bot? Because it need the bot to send message! def get_item_by_id(self, bot, id): # Why all these functions need a bot? Because it need the bot to send message!
if id in self: if id in self:
return self[id] return self[id]
@@ -32,9 +32,8 @@ class MusicCache(dict):
return item return item
else: else:
return None return None
#print(id) # print(id)
#raise KeyError("Unable to fetch item from the database! Please try to refresh the cache by !recache.") # raise KeyError("Unable to fetch item from the database! Please try to refresh the cache by !recache.")
def get_item(self, bot, **kwargs): def get_item(self, bot, **kwargs):
# kwargs should provide type and id, and parameters to build the item if not existed in the library. # kwargs should provide type and id, and parameters to build the item if not existed in the library.
@@ -55,7 +54,7 @@ class MusicCache(dict):
return item return item
# if not in the database, build one # if not in the database, build one
self[id] = item_builders[kwargs['type']](bot, **kwargs) # newly built item will not be saved immediately self[id] = item_builders[kwargs['type']](bot, **kwargs) # newly built item will not be saved immediately
return self[id] return self[id]
def get_items_by_tags(self, bot, tags): def get_items_by_tags(self, bot, tags):
+10 -6
View File
@@ -24,15 +24,19 @@ type : file
user user
''' '''
def file_item_builder(bot, **kwargs): def file_item_builder(bot, **kwargs):
return FileItem(bot, kwargs['path']) return FileItem(bot, kwargs['path'])
def file_item_loader(bot, _dict): def file_item_loader(bot, _dict):
return FileItem(bot, "", _dict) return FileItem(bot, "", _dict)
def file_item_id_generator(**kwargs): def file_item_id_generator(**kwargs):
return hashlib.md5(kwargs['path'].encode()).hexdigest() return hashlib.md5(kwargs['path'].encode()).hexdigest()
item_builders['file'] = file_item_builder item_builders['file'] = file_item_builder
item_loaders['file'] = file_item_loader item_loaders['file'] = file_item_loader
item_id_generators['file'] = file_item_id_generator item_id_generators['file'] = file_item_id_generator
@@ -74,7 +78,7 @@ class FileItem(BaseItem):
self.send_client_message(constants.strings('file_missed', file=self.path)) self.send_client_message(constants.strings('file_missed', file=self.path))
return False return False
#self.version += 1 # 0 -> 1, notify the wrapper to save me when validate() is visited the first time # self.version += 1 # 0 -> 1, notify the wrapper to save me when validate() is visited the first time
self.ready = "yes" self.ready = "yes"
return True return True
@@ -153,17 +157,17 @@ class FileItem(BaseItem):
def format_song_string(self, user): def format_song_string(self, user):
return constants.strings("file_item", return constants.strings("file_item",
title=self.title, title=self.title,
artist=self.artist if self.artist else '??', artist=self.artist if self.artist else '??',
user=user user=user
) )
def format_current_playing(self, user): def format_current_playing(self, user):
display = constants.strings("now_playing", item=self.format_song_string(user)) display = constants.strings("now_playing", item=self.format_song_string(user))
if self.thumbnail: if self.thumbnail:
thumbnail_html = '<img width="80" src="data:image/jpge;base64,' + \ thumbnail_html = '<img width="80" src="data:image/jpge;base64,' + \
self.thumbnail + '"/>' self.thumbnail + '"/>'
display += "<br />" + thumbnail_html display += "<br />" + thumbnail_html
return display return display
+9 -3
View File
@@ -15,19 +15,24 @@ item_builders = {}
item_loaders = {} item_loaders = {}
item_id_generators = {} item_id_generators = {}
def example_builder(bot, **kwargs): def example_builder(bot, **kwargs):
return BaseItem(bot) return BaseItem(bot)
def example_loader(bot, _dict): def example_loader(bot, _dict):
return BaseItem(bot, from_dict=_dict) return BaseItem(bot, from_dict=_dict)
def example_id_generator(**kwargs): def example_id_generator(**kwargs):
return "" return ""
item_builders['base'] = example_builder item_builders['base'] = example_builder
item_loaders['base'] = example_loader item_loaders['base'] = example_loader
item_id_generators['base'] = example_id_generator item_id_generators['base'] = example_id_generator
def dicts_to_items(bot, music_dicts): def dicts_to_items(bot, music_dicts):
items = [] items = []
for music_dict in music_dicts: 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)) items.append(item_loaders[type](bot, music_dict))
return items return items
def dict_to_item(bot, music_dict): def dict_to_item(bot, music_dict):
type = music_dict['type'] type = music_dict['type']
return item_loaders[type](bot, music_dict) return item_loaders[type](bot, music_dict)
@@ -48,11 +54,11 @@ class BaseItem:
self.title = "" self.title = ""
self.path = "" self.path = ""
self.tags = [] self.tags = []
self.version = 0 # if version increase, wrapper will re-save this item self.version = 0 # if version increase, wrapper will re-save this item
if from_dict is None: if from_dict is None:
self.id = "" self.id = ""
self.ready = "pending" # pending - is_valid() -> validated - prepare() -> yes, failed self.ready = "pending" # pending - is_valid() -> validated - prepare() -> yes, failed
else: else:
self.id = from_dict['id'] self.id = from_dict['id']
self.ready = from_dict['ready'] self.ready = from_dict['ready']
@@ -110,6 +116,6 @@ class BaseItem:
self.bot.send_msg(msg) self.bot.send_msg(msg)
def to_dict(self): def to_dict(self):
return {"type" : self.type, "id": self.id, "ready": self.ready, "path": self.path, "tags": self.tags} return {"type": self.type, "id": self.id, "ready": self.ready, "path": self.path, "tags": self.tags}
+5 -5
View File
@@ -162,12 +162,12 @@ class BasePlaylist(list):
def randomize(self): def randomize(self):
# current_index will lose track after shuffling, thus we take current music out before shuffling # current_index will lose track after shuffling, thus we take current music out before shuffling
#current = self.current_item() # current = self.current_item()
#del self[self.current_index] # del self[self.current_index]
random.shuffle(self) random.shuffle(self)
#self.insert(0, current) # self.insert(0, current)
self.current_index = -1 self.current_index = -1
self.version += 1 self.version += 1
@@ -183,7 +183,7 @@ class BasePlaylist(list):
var.db.set("playlist", "current_index", self.current_index) var.db.set("playlist", "current_index", self.current_index)
for index, music in enumerate(self): for index, music in enumerate(self):
var.db.set("playlist_item", str(index), json.dumps({'id': music.id, 'user': music.user })) var.db.set("playlist_item", str(index), json.dumps({'id': music.id, 'user': music.user}))
def load(self): def load(self):
current_index = var.db.getint("playlist", "current_index", fallback=-1) current_index = var.db.getint("playlist", "current_index", fallback=-1)
@@ -212,7 +212,7 @@ class BasePlaylist(list):
def start_async_validating(self): def start_async_validating(self):
if not self.validating_thread_lock.locked(): if not self.validating_thread_lock.locked():
time.sleep(0.1) # Just avoid validation finishes too fast and delete songs while something is reading it. time.sleep(0.1) # Just avoid validation finishes too fast and delete songs while something is reading it.
th = threading.Thread(target=self._check_valid, name="Validating") th = threading.Thread(target=self._check_valid, name="Validating")
th.daemon = True th.daemon = True
th.start() th.start()
+8 -4
View File
@@ -11,6 +11,7 @@ import constants
log = logging.getLogger("bot") log = logging.getLogger("bot")
def get_radio_server_description(url): def get_radio_server_description(url):
global log global log
@@ -92,12 +93,15 @@ def radio_item_builder(bot, **kwargs):
else: else:
return RadioItem(bot, kwargs['url'], '') return RadioItem(bot, kwargs['url'], '')
def radio_item_loader(bot, _dict): def radio_item_loader(bot, _dict):
return RadioItem(bot, "", "", _dict) return RadioItem(bot, "", "", _dict)
def radio_item_id_generator(**kwargs): def radio_item_id_generator(**kwargs):
return hashlib.md5(kwargs['url'].encode()).hexdigest() return hashlib.md5(kwargs['url'].encode()).hexdigest()
item_builders['radio'] = radio_item_builder item_builders['radio'] = radio_item_builder
item_loaders['radio'] = radio_item_loader item_loaders['radio'] = radio_item_loader
item_id_generators['radio'] = radio_item_id_generator item_id_generators['radio'] = radio_item_id_generator
@@ -109,7 +113,7 @@ class RadioItem(BaseItem):
super().__init__(bot) super().__init__(bot)
self.url = url self.url = url
if not name: if not name:
self.title = get_radio_server_description(self.url) # The title of the radio station self.title = get_radio_server_description(self.url) # The title of the radio station
else: else:
self.title = name self.title = name
self.id = hashlib.md5(url.encode()).hexdigest() self.id = hashlib.md5(url.encode()).hexdigest()
@@ -121,7 +125,7 @@ class RadioItem(BaseItem):
self.type = "radio" self.type = "radio"
def validate(self): def validate(self):
self.version += 1 # 0 -> 1, notify the wrapper to save me when validate() is visited the first time self.version += 1 # 0 -> 1, notify the wrapper to save me when validate() is visited the first time
return True return True
def is_ready(self): def is_ready(self):
@@ -146,8 +150,8 @@ class RadioItem(BaseItem):
def format_song_string(self, user): def format_song_string(self, user):
return constants.strings("radio_item", return constants.strings("radio_item",
url=self.url, url=self.url,
title=get_radio_title(self.url), # the title of current song title=get_radio_title(self.url), # the title of current song
name=self.title, # the title of radio station name=self.title, # the title of radio station
user=user user=user
) )
+10 -7
View File
@@ -17,15 +17,19 @@ import media.system
log = logging.getLogger("bot") log = logging.getLogger("bot")
def url_item_builder(bot, **kwargs): def url_item_builder(bot, **kwargs):
return URLItem(bot, kwargs['url']) return URLItem(bot, kwargs['url'])
def url_item_loader(bot, _dict): def url_item_loader(bot, _dict):
return URLItem(bot, "", _dict) return URLItem(bot, "", _dict)
def url_item_id_generator(**kwargs): def url_item_id_generator(**kwargs):
return hashlib.md5(kwargs['url'].encode()).hexdigest() return hashlib.md5(kwargs['url'].encode()).hexdigest()
item_builders['url'] = url_item_builder item_builders['url'] = url_item_builder
item_loaders['url'] = url_item_loader item_loaders['url'] = url_item_loader
item_id_generators['url'] = url_item_id_generator item_id_generators['url'] = url_item_id_generator
@@ -97,7 +101,7 @@ class URLItem(BaseItem):
return False return False
else: else:
self.ready = "validated" self.ready = "validated"
self.version += 1 # notify wrapper to save me self.version += 1 # notify wrapper to save me
return True return True
# Run in a other thread # Run in a other thread
@@ -181,7 +185,7 @@ class URLItem(BaseItem):
"bot: finished downloading url (%s) %s, saved to %s." % (self.title, self.url, self.path)) "bot: finished downloading url (%s) %s, saved to %s." % (self.title, self.url, self.path))
self.downloading = False self.downloading = False
self._read_thumbnail_from_file(base_path + ".jpg") self._read_thumbnail_from_file(base_path + ".jpg")
self.version += 1 # notify wrapper to save me self.version += 1 # notify wrapper to save me
return True return True
else: else:
for f in glob.glob(base_path + "*"): for f in glob.glob(base_path + "*"):
@@ -214,7 +218,6 @@ class URLItem(BaseItem):
return dict return dict
def format_debug_string(self): def format_debug_string(self):
return "[url] {title} ({url})".format( return "[url] {title} ({url})".format(
title=self.title, title=self.title,
@@ -224,9 +227,9 @@ class URLItem(BaseItem):
def format_song_string(self, user): def format_song_string(self, user):
if self.ready in ['validated', 'yes']: if self.ready in ['validated', 'yes']:
return constants.strings("url_item", return constants.strings("url_item",
title=self.title if self.title else "??", title=self.title if self.title else "??",
url=self.url, url=self.url,
user=user) user=user)
return self.url return self.url
def format_current_playing(self, user): def format_current_playing(self, user):
@@ -235,7 +238,7 @@ class URLItem(BaseItem):
if self.thumbnail: if self.thumbnail:
thumbnail_html = '<img width="80" src="data:image/jpge;base64,' + \ thumbnail_html = '<img width="80" src="data:image/jpge;base64,' + \
self.thumbnail + '"/>' self.thumbnail + '"/>'
display += "<br />" + thumbnail_html display += "<br />" + thumbnail_html
return display return display
+8 -6
View File
@@ -6,6 +6,7 @@ import hashlib
from media.item import item_builders, item_loaders, item_id_generators from media.item import item_builders, item_loaders, item_id_generators
from media.url import URLItem, url_item_id_generator from media.url import URLItem, url_item_id_generator
def get_playlist_info(url, start_index=0, user=""): def get_playlist_info(url, start_index=0, user=""):
items = [] items = []
ydl_opts = { ydl_opts = {
@@ -63,6 +64,7 @@ def playlist_url_item_builder(bot, **kwargs):
def playlist_url_item_loader(bot, _dict): def playlist_url_item_loader(bot, _dict):
return PlaylistURLItem(bot, "", "", "", "", _dict) return PlaylistURLItem(bot, "", "", "", "", _dict)
item_builders['url_from_playlist'] = playlist_url_item_builder item_builders['url_from_playlist'] = playlist_url_item_builder
item_loaders['url_from_playlist'] = playlist_url_item_loader item_loaders['url_from_playlist'] = playlist_url_item_loader
item_id_generators['url_from_playlist'] = url_item_id_generator item_id_generators['url_from_playlist'] = url_item_id_generator
@@ -98,11 +100,11 @@ class PlaylistURLItem(URLItem):
def format_song_string(self, user): def format_song_string(self, user):
return constants.strings("url_from_playlist_item", return constants.strings("url_from_playlist_item",
title=self.title, title=self.title,
url=self.url, url=self.url,
playlist_url=self.playlist_url, playlist_url=self.playlist_url,
playlist=self.playlist_title, playlist=self.playlist_title,
user=user) user=user)
def format_current_playing(self, user): def format_current_playing(self, user):
display = constants.strings("now_playing", item=self.format_song_string(user)) display = constants.strings("now_playing", item=self.format_song_string(user))
@@ -110,7 +112,7 @@ class PlaylistURLItem(URLItem):
if self.thumbnail: if self.thumbnail:
thumbnail_html = '<img width="80" src="data:image/jpge;base64,' + \ thumbnail_html = '<img width="80" src="data:image/jpge;base64,' + \
self.thumbnail + '"/>' self.thumbnail + '"/>'
display += "<br />" + thumbnail_html display += "<br />" + thumbnail_html
return display return display
+15 -20
View File
@@ -74,8 +74,8 @@ class MumbleBot:
self.song_start_at = -1 self.song_start_at = -1
self.last_ffmpeg_err = "" self.last_ffmpeg_err = ""
self.read_pcm_size = 0 self.read_pcm_size = 0
#self.download_threads = [] # self.download_threads = []
self.wait_for_downloading = False # flag for the loop are waiting for download to complete in the other thread self.wait_for_downloading = False # flag for the loop are waiting for download to complete in the other thread
if var.config.getboolean("webinterface", "enabled"): if var.config.getboolean("webinterface", "enabled"):
wi_addr = var.config.get("webinterface", "listening_addr") wi_addr = var.config.get("webinterface", "listening_addr")
@@ -151,7 +151,7 @@ class MumbleBot:
self.ducking_volume = var.db.getfloat("bot", "ducking_volume", fallback=self.ducking_volume) 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.config.getfloat("bot", "ducking_threshold", fallback=5000)
self.ducking_threshold = var.db.getfloat("bot", "ducking_threshold", fallback=self.ducking_threshold) 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.ducking_sound_received)
self.mumble.set_receive_sound(True) self.mumble.set_receive_sound(True)
@@ -173,7 +173,7 @@ class MumbleBot:
self.nb_exit += 1 self.nb_exit += 1
if var.config.getboolean('bot', 'save_playlist', fallback=True) \ if var.config.getboolean('bot', 'save_playlist', fallback=True) \
and var.config.get("bot", "save_music_library", fallback=True): and var.config.get("bot", "save_music_library", fallback=True):
self.log.info("bot: save playlist into database") self.log.info("bot: save playlist into database")
var.playlist.save() var.playlist.save()
@@ -191,9 +191,9 @@ class MumbleBot:
for command in cmds: for command in cmds:
command = command.strip() command = command.strip()
if command: if command:
self.cmd_handle[command] = { 'handle': handle, self.cmd_handle[command] = {'handle': handle,
'partial_match': not no_partial_match, 'partial_match': not no_partial_match,
'access_outside_channel': access_outside_channel} 'access_outside_channel': access_outside_channel}
self.log.debug("bot: command added: " + command) self.log.debug("bot: command added: " + command)
def set_comment(self): def set_comment(self):
@@ -247,7 +247,6 @@ class MumbleBot:
constants.strings('url_ban')) constants.strings('url_ban'))
return return
command_exc = "" command_exc = ""
try: try:
if command in self.cmd_handle: if command in self.cmd_handle:
@@ -278,7 +277,7 @@ class MumbleBot:
and not self.is_admin(user) \ and not self.is_admin(user) \
and not var.config.getboolean('bot', 'allow_other_channel_message') \ and not var.config.getboolean('bot', 'allow_other_channel_message') \
and self.mumble.users[text.actor]['channel_id'] != self.mumble.users.myself[ and self.mumble.users[text.actor]['channel_id'] != self.mumble.users.myself[
'channel_id']: 'channel_id']:
self.mumble.users[text.actor].send_text_message( self.mumble.users[text.actor].send_text_message(
constants.strings('not_in_my_channel')) constants.strings('not_in_my_channel'))
return return
@@ -319,7 +318,7 @@ class MumbleBot:
def launch_music(self): def launch_music(self):
if var.playlist.is_empty(): if var.playlist.is_empty():
return return
assert self.wait_for_downloading == False assert self.wait_for_downloading is False
music_wrapper = var.playlist.current_item() music_wrapper = var.playlist.current_item()
uri = music_wrapper.uri() uri = music_wrapper.uri()
@@ -341,7 +340,7 @@ class MumbleBot:
# The ffmpeg process is a thread # The ffmpeg process is a thread
# prepare pipe for catching stderr of ffmpeg # prepare pipe for catching stderr of ffmpeg
pipe_rd, pipe_wd = os.pipe() pipe_rd, pipe_wd = os.pipe()
util.pipe_no_wait(pipe_rd) # Let the pipe work in non-blocking mode util.pipe_no_wait(pipe_rd) # Let the pipe work in non-blocking mode
self.thread_stderr = os.fdopen(pipe_rd) self.thread_stderr = os.fdopen(pipe_rd)
self.thread = sp.Popen(command, stdout=sp.PIPE, stderr=pipe_wd, bufsize=480) self.thread = sp.Popen(command, stdout=sp.PIPE, stderr=pipe_wd, bufsize=480)
self.is_pause = False self.is_pause = False
@@ -367,7 +366,6 @@ class MumbleBot:
var.playlist.remove_by_id(next.id) var.playlist.remove_by_id(next.id)
var.cache.free_and_delete(next.id) var.cache.free_and_delete(next.id)
# ======================= # =======================
# Loop # Loop
# ======================= # =======================
@@ -490,14 +488,14 @@ class MumbleBot:
if rms < self.ducking_threshold: if rms < self.ducking_threshold:
print('%6d/%6d ' % (rms, self._max_rms) + '-'*int(rms/200), end='\r') print('%6d/%6d ' % (rms, self._max_rms) + '-'*int(rms/200), end='\r')
else: 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') + '+'*int((rms - self.ducking_threshold)/200), end='\r')
if rms > self.ducking_threshold: if rms > self.ducking_threshold:
if self.on_ducking is False: if self.on_ducking is False:
self.log.debug("bot: ducking triggered") self.log.debug("bot: ducking triggered")
self.on_ducking = True self.on_ducking = True
self.ducking_release = time.time() + 1 # ducking release after 1s self.ducking_release = time.time() + 1 # ducking release after 1s
# ======================= # =======================
# Play Control # Play Control
@@ -558,7 +556,6 @@ class MumbleBot:
command = ("ffmpeg", '-v', ffmpeg_debug, '-nostdin', '-ss', "%f" % self.playhead, '-i', command = ("ffmpeg", '-v', ffmpeg_debug, '-nostdin', '-ss', "%f" % self.playhead, '-i',
uri, '-ac', '1', '-f', 's16le', '-ar', '48000', '-') uri, '-ac', '1', '-f', 's16le', '-ar', '48000', '-')
if var.config.getboolean('bot', 'announce_current_music'): if var.config.getboolean('bot', 'announce_current_music'):
self.send_msg(var.playlist.current_item().format_current_playing()) self.send_msg(var.playlist.current_item().format_current_playing())
@@ -566,13 +563,12 @@ class MumbleBot:
# The ffmpeg process is a thread # The ffmpeg process is a thread
# prepare pipe for catching stderr of ffmpeg # prepare pipe for catching stderr of ffmpeg
pipe_rd, pipe_wd = os.pipe() pipe_rd, pipe_wd = os.pipe()
util.pipe_no_wait(pipe_rd) # Let the pipe work in non-blocking mode util.pipe_no_wait(pipe_rd) # Let the pipe work in non-blocking mode
self.thread_stderr = os.fdopen(pipe_rd) self.thread_stderr = os.fdopen(pipe_rd)
self.thread = sp.Popen(command, stdout=sp.PIPE, stderr=pipe_wd, bufsize=480) self.thread = sp.Popen(command, stdout=sp.PIPE, stderr=pipe_wd, bufsize=480)
self.last_volume_cycle_time = time.time() self.last_volume_cycle_time = time.time()
self.pause_at_id = "" self.pause_at_id = ""
# TODO: this is a temporary workaround for issue #44 of pymumble. # TODO: this is a temporary workaround for issue #44 of pymumble.
def _clear_pymumble_soundqueue(self): def _clear_pymumble_soundqueue(self):
for id, user in self.mumble.users.items(): for id, user in self.mumble.users.items():
@@ -582,7 +578,6 @@ class MumbleBot:
self.log.debug("bot: pymumble soundqueue cleared.") self.log.debug("bot: pymumble soundqueue cleared.")
def start_web_interface(addr, port): def start_web_interface(addr, port):
global formatter global formatter
import interface import interface
@@ -592,7 +587,7 @@ def start_web_interface(addr, port):
logfile = util.solve_filepath(var.config.get('webinterface', 'web_logfile')) logfile = util.solve_filepath(var.config.get('webinterface', 'web_logfile'))
handler = None handler = None
if logfile: if logfile:
handler = logging.handlers.RotatingFileHandler(logfile, mode='a', maxBytes=10240) # Rotate after 10KB handler = logging.handlers.RotatingFileHandler(logfile, mode='a', maxBytes=10240) # Rotate after 10KB
else: else:
handler = logging.StreamHandler() handler = logging.StreamHandler()
@@ -657,7 +652,7 @@ if __name__ == '__main__':
logfile = util.solve_filepath(var.config.get('bot', 'logfile')) logfile = util.solve_filepath(var.config.get('bot', 'logfile'))
handler = None handler = None
if logfile: if logfile:
handler = logging.handlers.RotatingFileHandler(logfile, mode='a', maxBytes=10240) # Rotate after 10KB handler = logging.handlers.RotatingFileHandler(logfile, mode='a', maxBytes=10240) # Rotate after 10KB
else: else:
handler = logging.StreamHandler() handler = logging.StreamHandler()
+4 -2
View File
@@ -19,7 +19,7 @@ from PIL import Image
from io import BytesIO from io import BytesIO
from sys import platform from sys import platform
import traceback import traceback
import urllib.parse, urllib.request, urllib.error import urllib.request
import base64 import base64
import media import media
import media.radio import media.radio
@@ -65,6 +65,7 @@ def get_recursive_file_list_sorted(path):
filelist.sort() filelist.sort()
return filelist return filelist
# - zips all files of the given zippath (must be a directory) # - zips all files of the given zippath (must be a directory)
# - returns the absolute path of the created zip file # - returns the absolute path of the created zip file
# - zip file will be in the applications tmp folder (according to configuration) # - zip file will be in the applications tmp folder (according to configuration)
@@ -309,13 +310,14 @@ def get_url_from_input(string):
else: else:
return False return False
def youtube_search(query): def youtube_search(query):
global log global log
try: try:
r = requests.get("https://www.youtube.com/results", params={'search_query': query}, timeout=5) r = requests.get("https://www.youtube.com/results", params={'search_query': query}, timeout=5)
results = re.findall("watch\?v=(.*?)\".*?title=\"(.*?)\".*?" results = re.findall("watch\?v=(.*?)\".*?title=\"(.*?)\".*?"
"(?:user|channel).*?>(.*?)<", r.text) # (id, title, uploader) "(?:user|channel).*?>(.*?)<", r.text) # (id, title, uploader)
if len(results) > 0: if len(results) > 0:
return results return results