Merge upstream master and format HTML
This commit is contained in:
commit
d2e32a3af5
111
command.py
111
command.py
@ -11,7 +11,7 @@ import interface
|
||||
import media.system
|
||||
import util
|
||||
import variables as var
|
||||
from librb import radiobrowser
|
||||
from pyradios import RadioBrowser
|
||||
from database import SettingsDatabase, MusicDatabase, Condition
|
||||
from media.item import item_id_generators, dict_to_item, dicts_to_items
|
||||
from media.cache import get_cached_wrapper_from_scrap, get_cached_wrapper_by_id, get_cached_wrappers_by_tags, \
|
||||
@ -74,8 +74,8 @@ def register_all_commands(bot):
|
||||
bot.register_command(constants.commands('change_user_password'), cmd_user_password, no_partial_match=True)
|
||||
# Just for debug use
|
||||
bot.register_command('rtrms', cmd_real_time_rms, True)
|
||||
#bot.register_command('loop', cmd_loop_state, True)
|
||||
#bot.register_command('item', cmd_item, True)
|
||||
# bot.register_command('loop', cmd_loop_state, True)
|
||||
# bot.register_command('item', cmd_item, True)
|
||||
|
||||
|
||||
def send_multi_lines(bot, lines, text, linebreak="<br />"):
|
||||
@ -86,7 +86,7 @@ def send_multi_lines(bot, lines, text, linebreak="<br />"):
|
||||
for newline in lines:
|
||||
msg += br
|
||||
br = linebreak
|
||||
if bot.mumble.get_max_message_length()\
|
||||
if bot.mumble.get_max_message_length() \
|
||||
and (len(msg) + len(newline)) > (bot.mumble.get_max_message_length() - 4): # 4 == len("<br>")
|
||||
bot.send_msg(msg, text)
|
||||
msg = ""
|
||||
@ -338,11 +338,10 @@ def cmd_play_playlist(bot, user, text, command, parameter):
|
||||
pass
|
||||
|
||||
url = util.get_url_from_input(parameter)
|
||||
log.debug("cmd: fetching media info from playlist url %s" % url)
|
||||
log.debug(f"cmd: fetching media info from playlist url {url}")
|
||||
items = get_playlist_info(url=url, start_index=offset, user=user)
|
||||
if len(items) > 0:
|
||||
items = var.playlist.extend(list(map(
|
||||
lambda item: get_cached_wrapper_from_scrap(**item), items)))
|
||||
items = var.playlist.extend(list(map(lambda item: get_cached_wrapper_from_scrap(**item), items)))
|
||||
for music in items:
|
||||
log.info("cmd: add to playlist: " + music.format_debug_string())
|
||||
else:
|
||||
@ -386,24 +385,22 @@ def cmd_rb_query(bot, user, text, command, parameter):
|
||||
bot.send_msg(msg, text)
|
||||
else:
|
||||
log.debug('cmd: Found query parameter: ' + parameter)
|
||||
# bot.send_msg('Searching for stations - this may take some seconds...', text)
|
||||
rb_stations = radiobrowser.getstations_byname(parameter)
|
||||
rb = RadioBrowser()
|
||||
rb_stations = rb.search(name=parameter, name_exact=False)
|
||||
msg = constants.strings('rb_query_result')
|
||||
msg += '\n<table><tr><th>!rbplay ID</th><th>Station Name</th><th>Genre</th><th>Codec/Bitrate</th><th>Country</th></tr>'
|
||||
if not rb_stations:
|
||||
log.debug('cmd: No matches found for rbquery ' + parameter)
|
||||
bot.send_msg('Radio-Browser found no matches for ' + parameter, text)
|
||||
log.debug(f"cmd: No matches found for rbquery {parameter}")
|
||||
bot.send_msg(f"Radio-Browser found no matches for {parameter}", text)
|
||||
else:
|
||||
for s in rb_stations:
|
||||
stationid = s['id']
|
||||
stationname = s['stationname']
|
||||
country = s['country']
|
||||
station_id = s['stationuuid']
|
||||
station_name = s['name']
|
||||
country = s['countrycode']
|
||||
codec = s['codec']
|
||||
bitrate = s['bitrate']
|
||||
genre = s['genre']
|
||||
# msg += f'<tr><td>{stationid}</td><td>{stationname}</td><td>{genre}</td><td>{codec}/{bitrate}</td><td>{country}</td></tr>'
|
||||
msg += '<tr><td>%s</td><td>%s</td><td>%s</td><td>%s/%s</td><td>%s</td></tr>' % (
|
||||
stationid, stationname, genre, codec, bitrate, country)
|
||||
genre = s['tags']
|
||||
msg += f"<tr><td>{station_id}</td><td>{station_name}</td><td>{genre}</td><td>{codec}/{bitrate}</td><td>{country}</td></tr>"
|
||||
msg += '</table>'
|
||||
# Full message as html table
|
||||
if len(msg) <= 5000:
|
||||
@ -414,10 +411,9 @@ def cmd_rb_query(bot, user, text, command, parameter):
|
||||
msg = constants.strings('rb_query_result') + ' (shortened L1)'
|
||||
msg += '\n<table><tr><th>!rbplay ID</th><th>Station Name</th></tr>'
|
||||
for s in rb_stations:
|
||||
stationid = s['id']
|
||||
stationname = s['stationname']
|
||||
# msg += f'<tr><td>{stationid}</td><td>{stationname}</td>'
|
||||
msg += '<tr><td>%s</td><td>%s</td>' % (stationid, stationname)
|
||||
station_id = s['stationuuid']
|
||||
station_name = s['name']
|
||||
msg += f'<tr><td>{station_id}</td><td>{station_name}</td>'
|
||||
msg += '</table>'
|
||||
if len(msg) <= 5000:
|
||||
bot.send_msg(msg, text)
|
||||
@ -427,16 +423,14 @@ def cmd_rb_query(bot, user, text, command, parameter):
|
||||
msg = constants.strings('rb_query_result') + ' (shortened L2)'
|
||||
msg += '!rbplay ID - Station Name'
|
||||
for s in rb_stations:
|
||||
stationid = s['id']
|
||||
stationname = s['stationname'][:12]
|
||||
# msg += f'{stationid} - {stationname}'
|
||||
msg += '%s - %s' % (stationid, stationname)
|
||||
station_id = s['stationuuid']
|
||||
station_name = s['name'][:12]
|
||||
msg += f'{station_id} - {station_name}'
|
||||
if len(msg) <= 5000:
|
||||
bot.send_msg(msg, text)
|
||||
# Message still too long
|
||||
else:
|
||||
bot.send_msg('Query result too long to post (> 5000 characters), please try another query.',
|
||||
text)
|
||||
bot.send_msg('Query result too long to post (> 5000 characters), please try another query.', text)
|
||||
|
||||
|
||||
def cmd_rb_play(bot, user, text, command, parameter):
|
||||
@ -449,22 +443,21 @@ def cmd_rb_play(bot, user, text, command, parameter):
|
||||
bot.send_msg(msg, text)
|
||||
else:
|
||||
log.debug('cmd: Retreiving url for station ID ' + parameter)
|
||||
rstation = radiobrowser.getstationname_byid(parameter)
|
||||
rb = RadioBrowser()
|
||||
rstation = rb.station_by_uuid(parameter)
|
||||
stationname = rstation[0]['name']
|
||||
country = rstation[0]['country']
|
||||
country = rstation[0]['countrycode']
|
||||
codec = rstation[0]['codec']
|
||||
bitrate = rstation[0]['bitrate']
|
||||
genre = rstation[0]['tags']
|
||||
homepage = rstation[0]['homepage']
|
||||
url = rstation[0]['url']
|
||||
msg = 'Radio station added to playlist:'
|
||||
# msg += '<table><tr><th>ID</th><th>Station Name</th><th>Genre</th><th>Codec/Bitrate</th><th>Country</th><th>Homepage</th></tr>' + \
|
||||
# f'<tr><td>{parameter}</td><td>{stationname}</td><td>{genre}</td><td>{codec}/{bitrate}</td><td>{country}</td><td>{homepage}</td></tr></table>'
|
||||
|
||||
msg += '<table><tr><th>ID</th><th>Station Name</th><th>Genre</th><th>Codec/Bitrate</th><th>Country</th><th>Homepage</th></tr>' + \
|
||||
'<tr><td>%s</td><td>%s</td><td>%s</td><td>%s/%s</td><td>%s</td><td>%s</td></tr></table>' \
|
||||
% (parameter, stationname, genre, codec, bitrate, country, homepage)
|
||||
log.debug('cmd: Added station to playlist %s' % stationname)
|
||||
f"<tr><td>{parameter}</td><td>{stationname}</td><td>{genre}</td><td>{codec}/{bitrate}</td><td>{country}</td><td>{homepage}</td></tr></table>"
|
||||
log.debug(f'cmd: Added station to playlist {stationname}')
|
||||
bot.send_msg(msg, text)
|
||||
url = radiobrowser.geturl_byid(parameter)
|
||||
if url != "-1":
|
||||
log.info('cmd: Found url: ' + url)
|
||||
music_wrapper = get_cached_wrapper_from_scrap(type='radio', url=url, name=stationname, user=user)
|
||||
@ -517,7 +510,7 @@ def cmd_yt_search(bot, user, text, command, parameter):
|
||||
|
||||
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]):
|
||||
for index, item in enumerate(results[start:start + count]):
|
||||
msg += '<tr><td>{index:d}</td><td>{title}</td><td>{uploader}</td></tr>'.format(
|
||||
index=index + 1, title=item[1], uploader=item[2])
|
||||
msg += '</table>'
|
||||
@ -602,10 +595,9 @@ def cmd_volume(bot, user, text, command, parameter):
|
||||
# The volume is a percentage
|
||||
if parameter and parameter.isdigit() and 0 <= int(parameter) <= 100:
|
||||
bot.volume_set = float(float(parameter) / 100)
|
||||
bot.send_msg(constants.strings('change_volume',
|
||||
volume=int(bot.volume_set * 100), user=bot.mumble.users[text.actor]['name']), text)
|
||||
bot.send_msg(constants.strings('change_volume', volume=int(bot.volume_set * 100), user=bot.mumble.users[text.actor]['name']), text)
|
||||
var.db.set('bot', 'volume', str(bot.volume_set))
|
||||
log.info('cmd: volume set to %d' % (bot.volume_set * 100))
|
||||
log.info(f'cmd: volume set to {bot.volume_set * 100}')
|
||||
else:
|
||||
bot.send_msg(constants.strings('current_volume', volume=int(bot.volume_set * 100)), text)
|
||||
|
||||
@ -618,8 +610,7 @@ def cmd_ducking(bot, user, text, command, parameter):
|
||||
var.db.set('bot', 'ducking', True)
|
||||
bot.ducking_volume = var.config.getfloat("bot", "ducking_volume", fallback=0.05)
|
||||
bot.ducking_threshold = var.config.getint("bot", "ducking_threshold", fallback=5000)
|
||||
bot.mumble.callbacks.set_callback(pymumble.constants.PYMUMBLE_CLBK_SOUNDRECEIVED,
|
||||
bot.ducking_sound_received)
|
||||
bot.mumble.callbacks.set_callback(pymumble.constants.PYMUMBLE_CLBK_SOUNDRECEIVED, bot.ducking_sound_received)
|
||||
bot.mumble.set_receive_sound(True)
|
||||
log.info('cmd: ducking is on')
|
||||
msg = "Ducking on."
|
||||
@ -639,10 +630,10 @@ def cmd_ducking_threshold(bot, user, text, command, parameter):
|
||||
if parameter and parameter.isdigit():
|
||||
bot.ducking_threshold = int(parameter)
|
||||
var.db.set('bot', 'ducking_threshold', str(bot.ducking_threshold))
|
||||
msg = "Ducking threshold set to %d." % bot.ducking_threshold
|
||||
msg = f"Ducking threshold set to {bot.ducking_threshold}."
|
||||
bot.send_msg(msg, text)
|
||||
else:
|
||||
msg = "Current ducking threshold is %d." % bot.ducking_threshold
|
||||
msg = f"Current ducking threshold is {bot.ducking_threshold}."
|
||||
bot.send_msg(msg, text)
|
||||
|
||||
|
||||
@ -652,11 +643,9 @@ def cmd_ducking_volume(bot, user, text, command, parameter):
|
||||
# The volume is a percentage
|
||||
if parameter and parameter.isdigit() and 0 <= int(parameter) <= 100:
|
||||
bot.ducking_volume = float(float(parameter) / 100)
|
||||
bot.send_msg(constants.strings('change_ducking_volume',
|
||||
volume=int(bot.ducking_volume * 100), user=bot.mumble.users[text.actor]['name']), text)
|
||||
# var.db.set('bot', 'volume', str(bot.volume_set))
|
||||
bot.send_msg(constants.strings('change_ducking_volume', volume=int(bot.ducking_volume * 100), user=bot.mumble.users[text.actor]['name']), text)
|
||||
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(f'cmd: volume on ducking set to {bot.ducking_volume * 100}')
|
||||
else:
|
||||
bot.send_msg(constants.strings('current_ducking_volume', volume=int(bot.ducking_volume * 100)), text)
|
||||
|
||||
@ -826,7 +815,7 @@ def cmd_mode(bot, user, text, command, parameter):
|
||||
else:
|
||||
var.db.set('playlist', 'playback_mode', parameter)
|
||||
var.playlist = media.playlist.get_playlist(parameter, var.playlist)
|
||||
log.info("command: playback mode changed to %s." % parameter)
|
||||
log.info(f"command: playback mode changed to {parameter}.")
|
||||
bot.send_msg(constants.strings("change_mode", mode=var.playlist.mode,
|
||||
user=bot.mumble.users[text.actor]['name']), text)
|
||||
if parameter == "random":
|
||||
@ -878,8 +867,7 @@ def cmd_add_tag(bot, user, text, command, parameter):
|
||||
if tags[0]:
|
||||
if index.isdigit() and 1 <= int(index) <= len(var.playlist):
|
||||
var.playlist[int(index) - 1].add_tags(tags)
|
||||
log.info("cmd: add tags %s to song %s" % (", ".join(tags),
|
||||
var.playlist[int(index) - 1].format_debug_string()))
|
||||
log.info(f"cmd: add tags {', '.join(tags)} to song {var.playlist[int(index) - 1].format_debug_string()}")
|
||||
bot.send_msg(constants.strings("added_tags",
|
||||
tags=", ".join(tags),
|
||||
song=var.playlist[int(index) - 1].format_title()), text)
|
||||
@ -888,8 +876,7 @@ def cmd_add_tag(bot, user, text, command, parameter):
|
||||
elif index == "*":
|
||||
for item in var.playlist:
|
||||
item.add_tags(tags)
|
||||
log.info("cmd: add tags %s to song %s" % (", ".join(tags),
|
||||
item.format_debug_string()))
|
||||
log.info(f"cmd: add tags {', '.join(tags)} to song {item.format_debug_string()}")
|
||||
bot.send_msg(constants.strings("added_tags_to_all", tags=", ".join(tags)), text)
|
||||
return
|
||||
|
||||
@ -917,15 +904,14 @@ def cmd_remove_tag(bot, user, text, command, parameter):
|
||||
if index.isdigit() and 1 <= int(index) <= len(var.playlist):
|
||||
if tags[0] != "*":
|
||||
var.playlist[int(index) - 1].remove_tags(tags)
|
||||
log.info("cmd: remove tags %s from song %s" % (", ".join(tags),
|
||||
var.playlist[int(index) - 1].format_debug_string()))
|
||||
log.info(f"cmd: remove tags {', '.join(tags)} from song {var.playlist[int(index) - 1].format_debug_string()}")
|
||||
bot.send_msg(constants.strings("removed_tags",
|
||||
tags=", ".join(tags),
|
||||
song=var.playlist[int(index) - 1].format_title()), text)
|
||||
return
|
||||
else:
|
||||
var.playlist[int(index) - 1].clear_tags()
|
||||
log.info("cmd: clear tags from song %s" % (var.playlist[int(index) - 1].format_debug_string()))
|
||||
log.info(f"cmd: clear tags from song {var.playlist[int(index) - 1].format_debug_string()}")
|
||||
bot.send_msg(constants.strings("cleared_tags",
|
||||
song=var.playlist[int(index) - 1].format_title()), text)
|
||||
return
|
||||
@ -934,14 +920,13 @@ def cmd_remove_tag(bot, user, text, command, parameter):
|
||||
if tags[0] != "*":
|
||||
for item in var.playlist:
|
||||
item.remove_tags(tags)
|
||||
log.info("cmd: remove tags %s from song %s" % (", ".join(tags),
|
||||
item.format_debug_string()))
|
||||
log.info(f"cmd: remove tags {', '.join(tags)} from song {item.format_debug_string()}")
|
||||
bot.send_msg(constants.strings("removed_tags_from_all", tags=", ".join(tags)), text)
|
||||
return
|
||||
else:
|
||||
for item in var.playlist:
|
||||
item.clear_tags()
|
||||
log.info("cmd: clear tags from song %s" % (item.format_debug_string()))
|
||||
log.info(f"cmd: clear tags from song {item.format_debug_string()}")
|
||||
bot.send_msg(constants.strings("cleared_tags_from_all"), text)
|
||||
return
|
||||
|
||||
@ -969,7 +954,7 @@ def cmd_find_tagged(bot, user, text, command, parameter):
|
||||
count += 1
|
||||
if count > ITEMS_PER_PAGE:
|
||||
break
|
||||
msgs.append("<li><b>{:d}</b> - <b>{}</b> (<i>{}</i>)</li>".format(i+1, item.title, ", ".join(item.tags)))
|
||||
msgs.append("<li><b>{:d}</b> - <b>{}</b> (<i>{}</i>)</li>".format(i + 1, item.title, ", ".join(item.tags)))
|
||||
|
||||
if count != 0:
|
||||
msgs.append("</ul>")
|
||||
@ -1210,7 +1195,7 @@ def cmd_web_user_add(bot, user, text, command, parameter):
|
||||
if parameter not in web_users:
|
||||
web_users.append(parameter)
|
||||
var.db.set("privilege", "web_access", json.dumps(web_users))
|
||||
bot.send_msg(constants.strings('web_user_list', users=", ". join(web_users)), text)
|
||||
bot.send_msg(constants.strings('web_user_list', users=", ".join(web_users)), text)
|
||||
else:
|
||||
bot.send_msg(constants.strings('command_disabled', command=command), text)
|
||||
|
||||
@ -1227,7 +1212,7 @@ def cmd_web_user_remove(bot, user, text, command, parameter):
|
||||
if parameter in web_users:
|
||||
web_users.remove(parameter)
|
||||
var.db.set("privilege", "web_access", json.dumps(web_users))
|
||||
bot.send_msg(constants.strings('web_user_list', users=", ". join(web_users)), text)
|
||||
bot.send_msg(constants.strings('web_user_list', users=", ".join(web_users)), text)
|
||||
else:
|
||||
bot.send_msg(constants.strings('command_disabled', command=command), text)
|
||||
|
||||
@ -1237,7 +1222,7 @@ def cmd_web_user_list(bot, user, text, command, parameter):
|
||||
|
||||
if auth_method == 'password':
|
||||
web_users = json.loads(var.db.get("privilege", "web_access", fallback='[]'))
|
||||
bot.send_msg(constants.strings('web_user_list', users=", ". join(web_users)), text)
|
||||
bot.send_msg(constants.strings('web_user_list', users=", ".join(web_users)), text)
|
||||
else:
|
||||
bot.send_msg(constants.strings('command_disabled', command=command), text)
|
||||
|
||||
|
@ -1,33 +0,0 @@
|
||||
from librb.rbRadios import RadioBrowser
|
||||
|
||||
rb = RadioBrowser()
|
||||
|
||||
|
||||
def getstations_byname(query):
|
||||
results = rb.stations_byname(query)
|
||||
stations = []
|
||||
for st in results:
|
||||
try:
|
||||
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)
|
||||
except:
|
||||
pass
|
||||
return stations
|
||||
|
||||
|
||||
def geturl_byid(id):
|
||||
url = rb.playable_station(id)['url']
|
||||
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)
|
||||
pass
|
@ -1,16 +0,0 @@
|
||||
BASE_URL = "http://www.radio-browser.info/webservice/"
|
||||
|
||||
endpoints = {
|
||||
"countries": {1: "{fmt}/countries", 2: "{fmt}/countries/{filter}"},
|
||||
"codecs": {1: "{fmt}/codecs", 2: "{fmt}/codecs/{filter}"},
|
||||
"states": {
|
||||
1: "{fmt}/states",
|
||||
2: "{fmt}/states/{filter}",
|
||||
3: "{fmt}/states/{country}/{filter}",
|
||||
},
|
||||
"languages": {1: "{fmt}/languages", 2: "{fmt}/languages/{filter}"},
|
||||
"tags": {1: "{fmt}/tags", 2: "{fmt}/tags/{filter}"},
|
||||
"stations": {1: "{fmt}/stations", 3: "{fmt}/stations/{by}/{search_term}"},
|
||||
"playable_station": {3: "{ver}/{fmt}/url/{station_id}"},
|
||||
"station_search": {1: "{fmt}/stations/search"},
|
||||
}
|
@ -1,179 +0,0 @@
|
||||
import requests
|
||||
|
||||
from librb.rbConstants import endpoints, BASE_URL
|
||||
|
||||
|
||||
def request(endpoint, **kwargs):
|
||||
|
||||
fmt = kwargs.get("format", "json")
|
||||
|
||||
if fmt == "xml":
|
||||
content_type = "application/%s" % fmt
|
||||
else:
|
||||
content_type = "application/%s" % fmt
|
||||
|
||||
headers = {"content-type": content_type, "User-Agent": "pyradios/dev"}
|
||||
|
||||
params = kwargs.get("params", {})
|
||||
|
||||
url = BASE_URL + endpoint
|
||||
|
||||
resp = requests.get(url, headers=headers, params=params)
|
||||
|
||||
if resp.status_code == 200:
|
||||
if fmt == "xml":
|
||||
return resp.text
|
||||
return resp.json()
|
||||
|
||||
return resp.raise_for_status()
|
||||
|
||||
|
||||
class EndPointBuilder:
|
||||
def __init__(self, fmt="json"):
|
||||
self.fmt = fmt
|
||||
self._option = None
|
||||
self._endpoint = None
|
||||
|
||||
@property
|
||||
def endpoint(self):
|
||||
return endpoints[self._endpoint][self._option]
|
||||
|
||||
def produce_endpoint(self, **parts):
|
||||
self._option = len(parts)
|
||||
self._endpoint = parts["endpoint"]
|
||||
parts.update({"fmt": self.fmt})
|
||||
return self.endpoint.format(**parts)
|
||||
|
||||
|
||||
class RadioBrowser:
|
||||
def __init__(self, fmt="json"):
|
||||
self.fmt = fmt
|
||||
self.builder = EndPointBuilder(fmt=self.fmt)
|
||||
|
||||
def countries(self, filter=""):
|
||||
endpoint = self.builder.produce_endpoint(endpoint="countries")
|
||||
return request(endpoint)
|
||||
|
||||
def codecs(self, filter=""):
|
||||
endpoint = self.builder.produce_endpoint(endpoint="codecs")
|
||||
return request(endpoint)
|
||||
|
||||
def states(self, country="", filter=""):
|
||||
endpoint = self.builder.produce_endpoint(
|
||||
endpoint="states", country=country, filter=filter
|
||||
)
|
||||
return request(endpoint)
|
||||
|
||||
def languages(self, filter=""):
|
||||
endpoint = self.builder.produce_endpoint(endpoint="languages", filter=filter)
|
||||
return request(endpoint)
|
||||
|
||||
def tags(self, filter=""):
|
||||
endpoint = self.builder.produce_endpoint(endpoint="tags", filter=filter)
|
||||
return request(endpoint)
|
||||
|
||||
def stations(self, **params):
|
||||
endpoint = self.builder.produce_endpoint(endpoint="stations")
|
||||
kwargs = {}
|
||||
if params:
|
||||
kwargs.update({"params": params})
|
||||
return request(endpoint, **kwargs)
|
||||
|
||||
def stations_byid(self, id):
|
||||
endpoint = self.builder.produce_endpoint(
|
||||
endpoint="stations", by="byid", search_term=id
|
||||
)
|
||||
return request(endpoint)
|
||||
|
||||
def stations_byuuid(self, uuid):
|
||||
endpoint = self.builder.produce_endpoint(
|
||||
endpoint="stations", by="byuuid", search_term=uuid
|
||||
)
|
||||
return request(endpoint)
|
||||
|
||||
def stations_byname(self, name):
|
||||
endpoint = self.builder.produce_endpoint(
|
||||
endpoint="stations", by="byname", search_term=name
|
||||
)
|
||||
return request(endpoint)
|
||||
|
||||
def stations_bynameexact(self, nameexact):
|
||||
endpoint = self.builder.produce_endpoint(
|
||||
endpoint="stations", by="bynameexact", search_term=nameexact
|
||||
)
|
||||
return request(endpoint)
|
||||
|
||||
def stations_bycodec(self, codec):
|
||||
endpoint = self.builder.produce_endpoint(
|
||||
endpoint="stations", by="bycodec", search_term=codec
|
||||
)
|
||||
return request(endpoint)
|
||||
|
||||
def stations_bycodecexact(self, codecexact):
|
||||
endpoint = self.builder.produce_endpoint(
|
||||
endpoint="stations", by="bycodecexact", search_term=codecexact
|
||||
)
|
||||
return request(endpoint)
|
||||
|
||||
def stations_bycountry(self, country):
|
||||
endpoint = self.builder.produce_endpoint(
|
||||
endpoint="stations", by="bycountry", search_term=country
|
||||
)
|
||||
return request(endpoint)
|
||||
|
||||
def stations_bycountryexact(self, countryexact):
|
||||
endpoint = self.builder.produce_endpoint(
|
||||
endpoint="stations", by="bycountryexact", search_term=countryexact
|
||||
)
|
||||
return request(endpoint)
|
||||
|
||||
def stations_bystate(self, state):
|
||||
endpoint = self.builder.produce_endpoint(
|
||||
endpoint="stations", by="bystate", search_term=state
|
||||
)
|
||||
return request(endpoint)
|
||||
|
||||
def stations_bystateexact(self, stateexact):
|
||||
endpoint = self.builder.produce_endpoint(
|
||||
endpoint="stations", by="bystateexact", search_term=stateexact
|
||||
)
|
||||
return request(endpoint)
|
||||
|
||||
#
|
||||
def stations_bylanguage(self, language):
|
||||
endpoint = self.builder.produce_endpoint(
|
||||
endpoint="stations", by="bylanguage", search_term=language
|
||||
)
|
||||
return request(endpoint)
|
||||
|
||||
def stations_bylanguageexact(self, languageexact):
|
||||
endpoint = self.builder.produce_endpoint(
|
||||
endpoint="stations", by="bylanguageexact", search_term=languageexact
|
||||
)
|
||||
return request(endpoint)
|
||||
|
||||
def stations_bytag(self, tag):
|
||||
endpoint = self.builder.produce_endpoint(
|
||||
endpoint="stations", by="bytag", search_term=tag
|
||||
)
|
||||
return request(endpoint)
|
||||
|
||||
def stations_bytagexact(self, tagexact):
|
||||
endpoint = self.builder.produce_endpoint(
|
||||
endpoint="stations", by="bytagexact", search_term=tagexact
|
||||
)
|
||||
return request(endpoint)
|
||||
|
||||
def playable_station(self, station_id):
|
||||
endpoint = self.builder.produce_endpoint(
|
||||
endpoint="playable_station", station_id=station_id, ver="v2"
|
||||
)
|
||||
|
||||
return request(endpoint)
|
||||
|
||||
def station_search(self, params, **kwargs):
|
||||
# http://www.radio-browser.info/webservice#Advanced_station_search
|
||||
assert isinstance(params, dict), "params is not a dict"
|
||||
kwargs["params"] = params
|
||||
endpoint = self.builder.produce_endpoint(endpoint="station_search")
|
||||
return request(endpoint, **kwargs)
|
@ -108,6 +108,16 @@ class MusicCache(dict):
|
||||
self.dir_lock.acquire()
|
||||
self.log.info("library: rebuild directory cache")
|
||||
files = util.get_recursive_file_list_sorted(var.music_folder)
|
||||
|
||||
# remove deleted files
|
||||
results = self.db.query_music(Condition().or_equal('type', 'file'))
|
||||
for result in results:
|
||||
if result['path'] not in files:
|
||||
self.log.debug("library: music file missed: %s, delete from library." % result['path'])
|
||||
self.db.delete_music(Condition().and_equal('id', result['id']))
|
||||
else:
|
||||
files.remove(result['path'])
|
||||
|
||||
for file in files:
|
||||
results = self.db.query_music(Condition().and_equal('path', file))
|
||||
if not results:
|
||||
@ -129,7 +139,10 @@ class CachedItemWrapper:
|
||||
self.version = 0
|
||||
|
||||
def item(self):
|
||||
if self.id in self.lib:
|
||||
return self.lib[self.id]
|
||||
else:
|
||||
raise ValueError(f"Uncached item of id {self.id}.")
|
||||
|
||||
def to_dict(self):
|
||||
dict = self.item().to_dict()
|
||||
|
20
mumbleBot.py
20
mumbleBot.py
@ -35,7 +35,7 @@ class MumbleBot:
|
||||
|
||||
def __init__(self, args):
|
||||
self.log = logging.getLogger("bot")
|
||||
self.log.info("bot: botamusique version %s, starting..." % self.version)
|
||||
self.log.info(f"bot: botamusique version {self.version}, starting...")
|
||||
signal.signal(signal.SIGINT, self.ctrl_caught)
|
||||
self.cmd_handle = {}
|
||||
self.volume_set = var.config.getfloat('bot', 'volume')
|
||||
@ -50,8 +50,6 @@ class MumbleBot:
|
||||
self.channel = var.config.get("server", "channel", fallback=None)
|
||||
|
||||
var.user = args.user
|
||||
var.music_folder = util.solve_filepath(var.config.get('bot', 'music_folder'))
|
||||
var.tmp_folder = util.solve_filepath(var.config.get('bot', 'tmp_folder'))
|
||||
var.is_proxified = var.config.getboolean(
|
||||
"webinterface", "is_web_proxified")
|
||||
self.exit = False
|
||||
@ -186,8 +184,8 @@ class MumbleBot:
|
||||
new_version = util.new_release_version()
|
||||
if version.parse(new_version) > version.parse(self.version):
|
||||
changelog = util.fetch_changelog()
|
||||
self.log.info("update: new version %s found, current installed version %s." % (new_version, self.version))
|
||||
self.log.info("update: changelog: " + changelog)
|
||||
self.log.info(f"update: new version {new_version} found, current installed version {self.version}.")
|
||||
self.log.info(f"update: changelog: {changelog}")
|
||||
changelog = changelog.replace("\n", "<br>")
|
||||
self.send_channel_msg(constants.strings('new_version_found', new_version=new_version, changelog=changelog))
|
||||
else:
|
||||
@ -305,7 +303,7 @@ class MumbleBot:
|
||||
except:
|
||||
error_traceback = traceback.format_exc()
|
||||
error = error_traceback.rstrip().split("\n")[-1]
|
||||
self.log.error("bot: command %s failed with error: %s\n" % (command_exc, error_traceback))
|
||||
self.log.error(f"bot: command {command_exc} failed with error: {error_traceback}\n")
|
||||
self.send_msg(constants.strings('error_executing_command', command=command_exc, error=error), text)
|
||||
|
||||
def send_msg(self, msg, text):
|
||||
@ -408,7 +406,7 @@ class MumbleBot:
|
||||
def async_download(self, item):
|
||||
th = threading.Thread(
|
||||
target=self._download, name="Prepare-" + item.id[:7], args=(item,))
|
||||
self.log.info("bot: start preparing item in thread: %s" % item.format_debug_string())
|
||||
self.log.info(f"bot: start preparing item in thread: {item.format_debug_string()}")
|
||||
th.daemon = True
|
||||
th.start()
|
||||
return th
|
||||
@ -443,7 +441,7 @@ class MumbleBot:
|
||||
|
||||
while self.thread and self.mumble.sound_output.get_buffer_size() > 0.5 and not self.exit:
|
||||
# If the buffer isn't empty, I cannot send new music part, so I wait
|
||||
self._loop_status = 'Wait for buffer %.3f' % self.mumble.sound_output.get_buffer_size()
|
||||
self._loop_status = f'Wait for buffer {self.mumble.sound_output.get_buffer_size():.3f}'
|
||||
time.sleep(0.01)
|
||||
|
||||
if self.thread:
|
||||
@ -629,7 +627,7 @@ class MumbleBot:
|
||||
self.song_start_at = -1
|
||||
if len(var.playlist) > 0:
|
||||
self.pause_at_id = var.playlist.current_item().id
|
||||
self.log.info("bot: music paused at %.2f seconds." % self.playhead)
|
||||
self.log.info(f"bot: music paused at {self.playhead:.2f} seconds.")
|
||||
|
||||
def resume(self):
|
||||
self.is_pause = False
|
||||
@ -768,6 +766,8 @@ if __name__ == '__main__':
|
||||
|
||||
DatabaseMigration(var.db, var.music_db).migrate()
|
||||
|
||||
var.music_folder = util.solve_filepath(var.config.get('bot', 'music_folder'))
|
||||
var.tmp_folder = util.solve_filepath(var.config.get('bot', 'tmp_folder'))
|
||||
var.cache = MusicCache(var.music_db)
|
||||
|
||||
if var.config.get("bot", "refresh_cache_on_startup", fallback=True):
|
||||
@ -785,7 +785,7 @@ if __name__ == '__main__':
|
||||
if playback_mode in ["one-shot", "repeat", "random", "autoplay"]:
|
||||
var.playlist = media.playlist.get_playlist(playback_mode)
|
||||
else:
|
||||
raise KeyError("Unknown playback mode '%s'" % playback_mode)
|
||||
raise KeyError(f"Unknown playback mode '{playback_mode}'")
|
||||
|
||||
# ======================
|
||||
# Create bot instance
|
||||
|
@ -8,3 +8,4 @@ mutagen
|
||||
requests
|
||||
packaging
|
||||
pymumble
|
||||
pyradios
|
File diff suppressed because one or more lines are too long
@ -28,14 +28,12 @@
|
||||
<button type="button" id="play-pause-btn" class="btn btn-info mb-2 btn-space" onclick="togglePlayPause()">
|
||||
<i class="fas fa-play"></i>
|
||||
</button>
|
||||
<button type="button" id="fast-forward-btn" class="btn btn-info mb-2"
|
||||
onclick="request('post', {action : 'next'})">
|
||||
<button type="button" id="fast-forward-btn" class="btn btn-info mb-2" onclick="request('post', {action : 'next'})">
|
||||
<i class="fas fa-fast-forward"></i>
|
||||
</button>
|
||||
<div class="ml-auto">
|
||||
<div class="dropdown mr-2">
|
||||
<button class="btn btn-secondary dropdown-toggle" type="button" id="play-mode"
|
||||
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<button class="btn btn-secondary dropdown-toggle" type="button" id="play-mode" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<i class="fas fa-tasks mr-2" aria-hidden="true" id="modeIndicator"></i>
|
||||
</button>
|
||||
<div class="dropdown-menu" aria-labelledby="play-mode">
|
||||
@ -53,8 +51,7 @@
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" id="volume-popover-btn" class="btn btn-warning ml-1"
|
||||
onclick="toggleVolumePopover()">
|
||||
<button type="button" id="volume-popover-btn" class="btn btn-warning ml-1" onclick="toggleVolumePopover()">
|
||||
<i class="fa fa-volume-up" aria-hidden="true"></i>
|
||||
</button>
|
||||
|
||||
@ -63,8 +60,7 @@
|
||||
<i class="fa fa-volume-down" aria-hidden="true"></i>
|
||||
</a>
|
||||
|
||||
<input type="range" class="custom-range ml-1" id="volume-slider" min="0" max="1" step="0.01"
|
||||
value="0.5" onchange="setVolumeDelayed(this.value)" />
|
||||
<input type="range" class="custom-range ml-1" id="volume-slider" min="0" max="1" step="0.01" value="0.5" onchange="setVolumeDelayed(this.value)" />
|
||||
|
||||
<a onclick="request('post', {action : 'volume_up'})">
|
||||
<i class="fa fa-volume-up" aria-hidden="true"></i>
|
||||
@ -98,8 +94,7 @@
|
||||
</tr>
|
||||
<tr class="playlist-expand table-dark d-none">
|
||||
<td colspan="4" class="text-center">
|
||||
<a class="text-muted" href="javascript:">See item <span
|
||||
class="playlist-expand-item-range"></span> on the playlist.
|
||||
<a class="text-muted" href="javascript:">See item <span class="playlist-expand-item-range"></span> on the playlist.
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
@ -161,16 +156,13 @@
|
||||
<label>Type</label>
|
||||
<div id="filter-type" class="input-group mb-2">
|
||||
<div class="btn-group btn-group-sm btn-group-toggle">
|
||||
<label id="filter-type-file" class="btn btn-secondary"
|
||||
onclick="setFilterType(event, 'file')">
|
||||
<label id="filter-type-file" class="btn btn-secondary" onclick="setFilterType(event, 'file')">
|
||||
<input type="checkbox" name="options"> File
|
||||
</label>
|
||||
<label id="filter-type-url" class="btn btn-secondary"
|
||||
onclick="setFilterType(event, 'url')">
|
||||
<label id="filter-type-url" class="btn btn-secondary" onclick="setFilterType(event, 'url')">
|
||||
<input type="checkbox" name="options"> URL
|
||||
</label>
|
||||
<label id="filter-type-radio" class="btn btn-secondary"
|
||||
onclick="setFilterType(event, 'radio')">
|
||||
<label id="filter-type-radio" class="btn btn-secondary" onclick="setFilterType(event, 'radio')">
|
||||
<input type="checkbox" name="options"> Radio
|
||||
</label>
|
||||
</div>
|
||||
@ -188,8 +180,7 @@
|
||||
|
||||
<label for="filter-keywords">Keywords</label>
|
||||
<div id="filter-path" class="input-group mb-2">
|
||||
<input class="form-control form-control-sm" id="filter-keywords" name="keywords"
|
||||
placeholder="Keywords..." style="margin-top:5px;" />
|
||||
<input class="form-control form-control-sm" id="filter-keywords" name="keywords" placeholder="Keywords..." style="margin-top:5px;" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -197,8 +188,7 @@
|
||||
<label for="filter-tag">Tags</label>
|
||||
<div id="filter-type mb-2">
|
||||
{% for tag in tags_color_lookup.keys() %}
|
||||
<span id="filter-tag"
|
||||
class="filter-tag tag-unclicked tag-click badge badge-{{ tags_color_lookup[tag] }}">{{ tag }}</span>
|
||||
<span id="filter-tag" class="filter-tag tag-unclicked tag-click badge badge-{{ tags_color_lookup[tag] }}">{{ tag }}</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
@ -226,66 +216,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<label for="filter-keywords">Keywords</label>
|
||||
<div id="filter-path" class="input-group mb-2">
|
||||
<input class="form-control form-control-sm" id="filter-keywords" name="keywords"
|
||||
placeholder="Keywords..." style="margin-top:5px;" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="library-info-col col-4 d-none d-md-flex" style="padding: 3px;">
|
||||
<span class="library-item-path text-muted path">Path/to/the/file</span>
|
||||
<div class="library-item-tags">
|
||||
<a class="tag-space tag-click library-item-edit"><i class="fas fa-edit"
|
||||
style="color: #AAAAAA"></i></a>
|
||||
<span class="library-item-notag badge badge-light text-muted font-italic">No
|
||||
tag</span>
|
||||
<span class="library-item-tag tag-space badge">Tag</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="library-group" class="list-group library-group" style="overflow: auto;">
|
||||
<div id="library-item-loading" class="list-group-item library-item">
|
||||
<img style="margin: auto; width: 35px;" src="static/img/loading.svg" />
|
||||
</div>
|
||||
<div id="library-item-empty" style="display: none" class="list-group-item library-item">
|
||||
<img style="margin: auto; width: 35px;" src="static/img/empty_box.svg" />
|
||||
</div>
|
||||
<div id="library-item" style="display: none;" class="list-group-item library-item">
|
||||
<input hidden type="text" class="library-item-id" value="" />
|
||||
|
||||
<div class="btn-group library-action">
|
||||
<button class="library-item-add-next btn btn-info btn-sm btn-space" type="button" title="Next to play">
|
||||
<svg class="library-btn-svg" style="width: 1rem; fill: currentColor;" viewBox="5 5 17 17">
|
||||
<path d="m5.700245,3.92964l0,14.150376l11.451127,-7.075188l-11.451127,-7.075188z"></path>
|
||||
<path
|
||||
d="m20.942859,18.221072l-3.323292,0l0,3.323292l-1.107764,0l0,-3.323292l-3.323292,0l0,-1.107764l3.323292,0l0,-3.323292l1.107764,0l0,3.323292l3.323292,0l0,1.107764z">
|
||||
</path>
|
||||
</svg>
|
||||
|
||||
</button>
|
||||
<button class="library-item-add-bottom library-btn btn btn-info btn-sm btn-space" type="button"
|
||||
title="Add to bottom">
|
||||
<svg class="library-btn-svg" style="width: 1rem; fill: currentColor;" viewBox="2 2 20 20">
|
||||
<path d="M2,16H10V14H2M18,14V10H16V14H12V16H16V20H18V16H22V14M14,6H2V8H14M14,10H2V12H14V10Z">
|
||||
</path>
|
||||
</svg>
|
||||
|
||||
</button>
|
||||
<button class="library-item-download btn btn-primary btn-sm btn-space" type="button">
|
||||
<i class="fas fa-download" aria-hidden="true"></i>
|
||||
</button>
|
||||
<button class="library-item-trash btn btn-danger btn-sm btn-space" type="button">
|
||||
<i class="fas fa-trash-alt"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="library-info-col library-info-title col-5" style="padding: 12px 0;">
|
||||
<div>
|
||||
<span class="library-item-type lead text-muted btn-space">[File]</span>
|
||||
@ -298,31 +228,60 @@
|
||||
<span class="library-item-path text-muted path">Path/to/the/file</span>
|
||||
<div class="library-item-tags">
|
||||
<a class="tag-space tag-click library-item-edit"><i class="fas fa-edit" style="color: #AAAAAA"></i></a>
|
||||
<span class="library-item-notag badge badge-light text-muted font-italic">No
|
||||
tag</span>
|
||||
<span class="library-item-notag badge badge-light text-muted font-italic">No tag</span>
|
||||
<span class="library-item-tag tag-space badge">Tag</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="btn-group" role="group" class="mb-2">
|
||||
<button type="submit" class="btn btn-secondary mr-1" onclick="addAllResults()"><i class="fas fa-plus"
|
||||
aria-hidden="true"></i> Add All
|
||||
<div class="btn-group library-action">
|
||||
<button class="library-item-add-next btn btn-info btn-sm btn-space" type="button" title="Next to play">
|
||||
<svg class="library-btn-svg" style="width: 1rem; fill: currentColor;" viewBox="5 5 17 17">
|
||||
<path d="m5.700245,3.92964l0,14.150376l11.451127,-7.075188l-11.451127,-7.075188z"></path>
|
||||
<path d="m20.942859,18.221072l-3.323292,0l0,3.323292l-1.107764,0l0,-3.323292l-3.323292,0l0,-1.107764l3.323292,0l0,-3.323292l1.107764,0l0,3.323292l3.323292,0l0,1.107764z"></path>
|
||||
</svg>
|
||||
|
||||
</button>
|
||||
<button type="submit" class="btn btn-secondary mr-1"
|
||||
onclick="request('post', {action : 'rescan'}); updateResults()">
|
||||
<button class="library-item-add-bottom library-btn btn btn-info btn-sm btn-space" type="button" title="Add to bottom">
|
||||
<svg class="library-btn-svg" style="width: 1rem; fill: currentColor;" viewBox="2 2 20 20">
|
||||
<path d="M2,16H10V14H2M18,14V10H16V14H12V16H16V20H18V16H22V14M14,6H2V8H14M14,10H2V12H14V10Z"></path>
|
||||
</svg>
|
||||
|
||||
</button>
|
||||
<button class="library-item-download btn btn-primary btn-sm btn-space" type="button">
|
||||
<i class="fas fa-download" aria-hidden="true"></i>
|
||||
</button>
|
||||
<button class="library-item-trash btn btn-danger btn-sm btn-space" type="button">
|
||||
<i class="fas fa-trash-alt"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="list-group">
|
||||
<div id="library-pagination" style="margin-left: auto; margin-top: 10px;">
|
||||
<ul id="library-page-ul" class="pagination pagination">
|
||||
<li class="library-page-li page-item active">
|
||||
<a class="library-page-no page-link">1</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="btn-group mb-2" role="group">
|
||||
<button type="submit" class="btn btn-secondary mr-1" onclick="addAllResults()"><i class="fas fa-plus" aria-hidden="true"></i> Add All
|
||||
</button>
|
||||
<button type="submit" class="btn btn-secondary mr-1" onclick="request('post', {action : 'rescan'}); updateResults()">
|
||||
<i class="fas fa-sync-alt" aria-hidden="true"></i> Rescan Files
|
||||
</button>
|
||||
<button type="submit" class="btn btn-secondary mr-1" onclick="downloadAllResults()"><i class="fas fa-download"
|
||||
aria-hidden="true"></i> Download All
|
||||
<button type="submit" class="btn btn-secondary mr-1" onclick="downloadAllResults()"><i class="fas fa-download" aria-hidden="true"></i> Download All
|
||||
</button>
|
||||
<button type="button" class="btn btn-danger mr-1" data-toggle="modal" data-target="#deleteWarningModal"><i
|
||||
class="fas fa-trash-alt" aria-hidden="true"></i>
|
||||
<button type="button" class="btn btn-danger mr-1" data-toggle="modal" data-target="#deleteWarningModal"><i class="fas fa-trash-alt" aria-hidden="true"></i>
|
||||
Delete All
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="deleteWarningModal" tabindex="-1" role="dialog" aria-labelledby="Warning-Delete-File"
|
||||
aria-hidden="true">
|
||||
<div class="modal fade" id="deleteWarningModal" tabindex="-1" role="dialog" aria-labelledby="Warning-Delete-File" aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
@ -338,13 +297,16 @@
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
||||
<button type="button" class="btn btn-danger" data-dismiss="modal"
|
||||
onclick="deleteAllResults()">Delete All Listed Files</button>
|
||||
<button type="button" class="btn btn-danger" data-dismiss="modal" onclick="deleteAllResults()">Delete All Listed Files</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- beautify ignore:start -->
|
||||
{% if upload_enabled %}
|
||||
<div id="upload" class="container mb-3">
|
||||
{% else %}
|
||||
@ -362,9 +324,7 @@
|
||||
<div class="input-group mb-3">
|
||||
<div id="uploadField" style="display: flex; width: 100%">
|
||||
<div class="custom-file">
|
||||
<input type="file" name="file[]" class="custom-file-input"
|
||||
id="uploadSelectFile" aria-describedby="uploadSubmit"
|
||||
value="Browse Music file" multiple />
|
||||
<input type="file" name="file[]" class="custom-file-input" id="uploadSelectFile" aria-describedby="uploadSubmit" value="Browse Music file" multiple />
|
||||
<label class="custom-file-label" for="uploadSelectFile">Choose file</label>
|
||||
</div>
|
||||
</div>
|
||||
@ -377,8 +337,7 @@
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">Upload To</span>
|
||||
</div>
|
||||
<input class="form-control" list="targetdirs" id="uploadTargetDir"
|
||||
name="targetdir" placeholder="uploads" />
|
||||
<input class="form-control" list="targetdirs" id="uploadTargetDir" name="targetdir" placeholder="uploads" />
|
||||
<datalist id="targetdirs">
|
||||
{% for dir in dirs %}
|
||||
<option value="{{ dir }}">
|
||||
@ -387,8 +346,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<button class="btn btn-primary" type="button" id="uploadSubmit"><i
|
||||
class="fas fa-upload mr-1"></i>Upload!</button>
|
||||
<button class="btn btn-primary" type="button" id="uploadSubmit"><i class="fas fa-upload mr-1"></i>Upload!</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -397,6 +355,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- beautify ignore:end -->
|
||||
|
||||
<div class="container mb-5">
|
||||
<div class="card-deck">
|
||||
@ -409,8 +368,7 @@
|
||||
<div class="input-group mb-2">
|
||||
<input class="form-control" type="text" id="add_url_input" placeholder="URL...">
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary"
|
||||
onclick="var $i = $('#add_url_input')[0]; request('post', {add_url : $i.value }); $i.value = ''; ">Add
|
||||
<button type="submit" class="btn btn-primary" onclick="var $i = $('#add_url_input')[0]; request('post', {add_url : $i.value }); $i.value = ''; ">Add
|
||||
URL
|
||||
</button>
|
||||
</div>
|
||||
@ -424,8 +382,7 @@
|
||||
<div class="input-group mb-2">
|
||||
<input class="form-control" type="text" id="add_radio_input" placeholder="Radio Address...">
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary"
|
||||
onclick="var $i = $('#add_radio_input')[0]; request('post', {add_radio : $i.value }); $i.value = '';">Add
|
||||
<button type="submit" class="btn btn-primary" onclick="var $i = $('#add_radio_input')[0]; request('post', {add_radio : $i.value }); $i.value = '';">Add
|
||||
Radio
|
||||
</button>
|
||||
</div>
|
||||
@ -433,12 +390,11 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="floating-button" style="bottom: 120px;" onclick="togglePlayer()">
|
||||
<i class="fas fa-play" aria-hidden="true"></i>
|
||||
</div>
|
||||
|
||||
<div id="theme-switch-btn" class="floating-button" style="bottom: 50px;">
|
||||
<div class="floating-button" style="bottom: 50px;" onclick="switchTheme()">
|
||||
<i class="fas fa-lightbulb" aria-hidden="true"></i>
|
||||
</div>
|
||||
|
||||
@ -455,16 +411,13 @@
|
||||
<img id="playerArtwork" src="static/img/unknown-album.png" style="display: none;" />
|
||||
<div id="playerInfo">
|
||||
<div id="playerActionBox">
|
||||
<button id="playerPlayBtn" class="btn btn-primary btn-sm btn-space" style="display: none"
|
||||
onclick="request('post', {action: 'resume'})">
|
||||
<button id="playerPlayBtn" class="btn btn-primary btn-sm btn-space" style="display: none" onclick="request('post', {action: 'resume'})">
|
||||
<i class="fas fa-play"></i>
|
||||
</button>
|
||||
<button id="playerPauseBtn" class="btn btn-primary btn-sm btn-space" style="display: none"
|
||||
onclick="request('post', {action: 'pause'})">
|
||||
<button id="playerPauseBtn" class="btn btn-primary btn-sm btn-space" style="display: none" onclick="request('post', {action: 'pause'})">
|
||||
<i class="fas fa-pause"></i>
|
||||
</button>
|
||||
<button id="playerSkipBtn" class="btn btn-primary btn-sm"
|
||||
onclick="request('post', {action : 'next'})">
|
||||
<button id="playerSkipBtn" class="btn btn-primary btn-sm" onclick="request('post', {action : 'next'})">
|
||||
<i class="fas fa-fast-forward"></i>
|
||||
</button>
|
||||
</div>
|
||||
@ -474,8 +427,7 @@
|
||||
</div>
|
||||
<span id="playerArtist">Artist</span>
|
||||
<div id="playerBarBox" class="progress">
|
||||
<div id="playerBar" class="progress-bar" role="progressbar" aria-valuenow="50" aria-valuemin="0"
|
||||
aria-valuemax="100"></div>
|
||||
<div id="playerBar" class="progress-bar" role="progressbar" aria-valuenow="50" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -505,26 +457,21 @@
|
||||
<input hidden type="text" id="addTagModalItemId" name="id" value="">
|
||||
<div class="modal-tag" style="display: none; width: 100%;">
|
||||
<span class="modal-tag-text tag-space badge badge-pill badge-dark">Tag</span>
|
||||
<a class="modal-tag-remove tag-click small"><i
|
||||
class="fas fa-times-circle btn-outline-danger"></i></a>
|
||||
<a class="modal-tag-remove tag-click small"><i class="fas fa-times-circle btn-outline-danger"></i></a>
|
||||
</div>
|
||||
<div id="addTagModalTags" style="margin-left: 5px; margin-bottom: 10px;">
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<input class="form-control form-control-sm btn-space" type="text" id="addTagModalInput"
|
||||
placeholder="tag1,tag2,...">
|
||||
<button id="addTagModalAddBtn" type="button" class="btn btn-primary btn-sm"
|
||||
onclick="addTagModalAdd()">
|
||||
<input class="form-control form-control-sm btn-space" type="text" id="addTagModalInput" placeholder="tag1,tag2,...">
|
||||
<button id="addTagModalAddBtn" type="button" class="btn btn-primary btn-sm" onclick="addTagModalAdd()">
|
||||
<i class="fas fa-plus" aria-hidden="true"></i>
|
||||
Add
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
||||
<button id="addTagModalSubmit" type="button" class="btn btn-success" data-dismiss="modal"
|
||||
onclick="addTagModalSubmit()">Edit!</button>
|
||||
<button id="addTagModalSubmit" type="button" class="btn btn-success" data-dismiss="modal" onclick="addTagModalSubmit()">Edit!</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -535,8 +482,7 @@
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="uploadTitle"><i class="fas fa-upload mr-1"></i>Uploading files...
|
||||
</h5>
|
||||
<h5 class="modal-title" id="uploadTitle"><i class="fas fa-upload mr-1"></i>Uploading files...</h5>
|
||||
</div>
|
||||
<div id="uploadModalBody" class="modal-body">
|
||||
<div id="uploadSuccessAlert" class="alert alert-success" role="alert" style="display: none">
|
||||
@ -549,8 +495,7 @@
|
||||
<span class="uploadItemTitle mr-3"></span>
|
||||
<span class="uploadItemError text-danger"></span>
|
||||
<div class="progress" style="margin-top: 5px; height: 10px;">
|
||||
<div class="uploadProgress progress-bar" role="progressbar" aria-valuenow="0"
|
||||
aria-valuemin="0" aria-valuemax="100"></div>
|
||||
<div class="uploadProgress progress-bar" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -558,9 +503,7 @@
|
||||
<div class="modal-footer">
|
||||
<button type="button" id="uploadClose" class="btn btn-success" data-dismiss="modal">
|
||||
<i class="fas fa-times mr-1"></i> Close</button>
|
||||
<button type="button" id="uploadCancel" class="btn btn-danger" data-toggle="tooltip"
|
||||
data-html="true"
|
||||
title="<strong>Are you really sure?</strong> <br /> Click again to abort uploading.">
|
||||
<button type="button" id="uploadCancel" class="btn btn-danger" data-toggle="tooltip" data-html="true" title="<strong>Are you really sure?</strong> <br /> Click again to abort uploading.">
|
||||
<i class="fas fa-trash-alt mr-1" aria-hidden="true"></i> Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -27,8 +27,7 @@
|
||||
<div class="form-group mt-3">
|
||||
<label for="token_input">Token</label>
|
||||
<div class="input-group">
|
||||
<input type="password" class="form-control btn-space" id="token_input" name="token"
|
||||
placeholder="xxxxxxx">
|
||||
<input type="password" class="form-control btn-space" id="token_input" name="token" placeholder="xxxxxxx">
|
||||
<button type="submit" class="btn btn-primary">Submit</button>
|
||||
</div>
|
||||
</div>
|
||||
|
Loading…
x
Reference in New Issue
Block a user