4 import pymumble.pymumble_py3 as pymumble
14 import variables as var
15 from librb import radiobrowser
16 from database import Database
18 log = logging.getLogger("bot")
20 def register_all_commands(bot):
21 bot.register_command(constants.commands('joinme'), cmd_joinme)
22 bot.register_command(constants.commands('user_ban'), cmd_user_ban)
23 bot.register_command(constants.commands('user_unban'), cmd_user_unban)
24 bot.register_command(constants.commands('url_ban'), cmd_url_ban)
25 bot.register_command(constants.commands('url_unban'), cmd_url_unban)
26 bot.register_command(constants.commands('play'), cmd_play)
27 bot.register_command(constants.commands('pause'), cmd_pause)
28 bot.register_command(constants.commands('play_file'), cmd_play_file)
29 bot.register_command(constants.commands('play_file_match'), cmd_play_file_match)
30 bot.register_command(constants.commands('play_url'), cmd_play_url)
31 bot.register_command(constants.commands('play_playlist'), cmd_play_playlist)
32 bot.register_command(constants.commands('play_radio'), cmd_play_radio)
33 bot.register_command(constants.commands('rb_query'), cmd_rb_query)
34 bot.register_command(constants.commands('rb_play'), cmd_rb_play)
35 bot.register_command(constants.commands('yt_search'), cmd_yt_search)
36 bot.register_command(constants.commands('yt_play'), cmd_yt_play)
37 bot.register_command(constants.commands('help'), cmd_help)
38 bot.register_command(constants.commands('stop'), cmd_stop)
39 bot.register_command(constants.commands('clear'), cmd_clear)
40 bot.register_command(constants.commands('kill'), cmd_kill)
41 bot.register_command(constants.commands('update'), cmd_update)
42 bot.register_command(constants.commands('stop_and_getout'), cmd_stop_and_getout)
43 bot.register_command(constants.commands('volume'), cmd_volume)
44 bot.register_command(constants.commands('ducking'), cmd_ducking)
45 bot.register_command(constants.commands('ducking_threshold'), cmd_ducking_threshold)
46 bot.register_command(constants.commands('ducking_volume'), cmd_ducking_volume)
47 bot.register_command(constants.commands('current_music'), cmd_current_music)
48 bot.register_command(constants.commands('skip'), cmd_skip)
49 bot.register_command(constants.commands('last'), cmd_last)
50 bot.register_command(constants.commands('remove'), cmd_remove)
51 bot.register_command(constants.commands('list_file'), cmd_list_file)
52 bot.register_command(constants.commands('queue'), cmd_queue)
53 bot.register_command(constants.commands('random'), cmd_random)
54 bot.register_command(constants.commands('repeat'), cmd_repeat)
55 bot.register_command(constants.commands('mode'), cmd_mode)
56 bot.register_command(constants.commands('drop_database'), cmd_drop_database)
59 bot.register_command('rtrms', cmd_real_time_rms)
60 # bot.register_command('loop', cmd_loop_state)
61 # bot.register_command('item', cmd_item)
63 def send_multi_lines(bot, lines, text):
71 if (len(msg) + len(newline)) > (bot.mumble.get_max_message_length() - 4) != 0: # 4 == len("<br>")
72 bot.send_msg(msg, text)
76 bot.send_msg(msg, text)
78 # ---------------- Commands ------------------
81 def cmd_joinme(bot, user, text, command, parameter):
84 bot.mumble.users.myself.move_in(
85 bot.mumble.users[text.actor]['channel_id'], token=parameter)
88 def cmd_user_ban(bot, user, text, command, parameter):
91 if bot.is_admin(user):
93 bot.mumble.users[text.actor].send_text_message(util.user_ban(parameter))
95 bot.mumble.users[text.actor].send_text_message(util.get_user_ban())
97 bot.mumble.users[text.actor].send_text_message(constants.strings('not_admin'))
101 def cmd_user_unban(bot, user, text, command, parameter):
104 if bot.is_admin(user):
106 bot.mumble.users[text.actor].send_text_message(util.user_unban(parameter))
108 bot.mumble.users[text.actor].send_text_message(constants.strings('not_admin'))
112 def cmd_url_ban(bot, user, text, command, parameter):
115 if bot.is_admin(user):
117 bot.mumble.users[text.actor].send_text_message(util.url_ban(util.get_url_from_input(parameter)))
119 bot.mumble.users[text.actor].send_text_message(util.get_url_ban())
121 bot.mumble.users[text.actor].send_text_message(constants.strings('not_admin'))
125 def cmd_url_unban(bot, user, text, command, parameter):
128 if bot.is_admin(user):
130 bot.mumble.users[text.actor].send_text_message(util.url_unban(util.get_url_from_input(parameter)))
132 bot.mumble.users[text.actor].send_text_message(constants.strings('not_admin'))
136 def cmd_play(bot, user, text, command, parameter):
139 if var.playlist.length() > 0:
141 if parameter.isdigit() and int(parameter) > 0 and int(parameter) <= len(var.playlist):
142 bot.interrupt_playing()
143 bot.launch_music(int(parameter) - 1)
145 bot.send_msg(constants.strings('invalid_index', index=parameter), text)
150 bot.send_msg(util.format_current_playing(), text)
153 bot.send_msg(constants.strings('queue_empty'), text)
156 def cmd_pause(bot, user, text, command, parameter):
160 bot.send_msg(constants.strings('paused'))
163 def cmd_play_file(bot, user, text, command, parameter):
166 # if parameter is {index}
167 if parameter.isdigit():
168 files = util.get_recursive_file_list_sorted(var.music_folder)
169 if int(parameter) < len(files):
170 filename = files[int(parameter)].replace(var.music_folder, '')
171 music = {'type': 'file',
174 music = var.playlist.append(music)
175 log.info("cmd: add to playlist: " + util.format_debug_song_string(music))
176 bot.send_msg(constants.strings('file_added', item=util.format_song_string(music)), text)
178 # if parameter is {path}
180 # sanitize "../" and so on
181 path = os.path.abspath(os.path.join(var.music_folder, parameter))
182 if not path.startswith(os.path.abspath(var.music_folder)):
183 bot.send_msg(constants.strings('no_file'), text)
186 if os.path.isfile(path):
187 music = {'type': 'file',
190 music = var.playlist.append(music)
191 log.info("cmd: add to playlist: " + util.format_debug_song_string(music))
192 bot.send_msg(constants.strings('file_added', item=util.format_song_string(music)), text)
195 # if parameter is {folder}
196 elif os.path.isdir(path):
197 if parameter != '.' and parameter != './':
198 if not parameter.endswith("/"):
203 files = util.get_recursive_file_list_sorted(var.music_folder)
204 music_library = util.Dir(var.music_folder)
206 music_library.add_file(file)
208 files = music_library.get_files(parameter)
209 msgs = [constants.strings('multiple_file_added')]
214 music = {'type': 'file',
217 music = var.playlist.append(music)
218 log.info("cmd: add to playlist: " + util.format_debug_song_string(music))
219 msgs.append("{} ({})".format(music['title'], music['path']))
222 send_multi_lines(bot, msgs, text)
224 bot.send_msg(constants.strings('no_file'), text)
227 # try to do a partial match
228 files = util.get_recursive_file_list_sorted(var.music_folder)
229 matches = [(index, file) for index, file in enumerate(files) if parameter.lower() in file.lower()]
230 if len(matches) == 0:
231 bot.send_msg(constants.strings('no_file'), text)
232 elif len(matches) == 1:
233 music = {'type': 'file',
234 'path': matches[0][1],
236 music = var.playlist.append(music)
237 log.info("cmd: add to playlist: " + util.format_debug_song_string(music))
238 bot.send_msg(constants.strings('file_added', item=util.format_song_string(music)), text)
240 msgs = [ constants.strings('multiple_matches')]
241 for match in matches:
242 msgs.append("<b>{:0>3d}</b> - {:s}".format(match[0], match[1]))
243 send_multi_lines(bot, msgs, text)
246 def cmd_play_file_match(bot, user, text, command, parameter):
249 music_folder = var.music_folder
251 files = util.get_recursive_file_list_sorted(music_folder)
252 msgs = [ constants.strings('multiple_file_added')]
256 match = re.search(parameter, file)
259 music = {'type': 'file',
262 music = var.playlist.append(music)
263 log.info("cmd: add to playlist: " + util.format_debug_song_string(music))
265 msgs.append("{} ({})".format(music['title'], music['path']))
268 send_multi_lines(bot, msgs, text)
270 bot.send_msg(constants.strings('no_file'), text)
272 except re.error as e:
273 msg = constants.strings('wrong_pattern', error=str(e))
274 bot.send_msg(msg, text)
276 bot.send_msg(constants.strings('bad_parameter', command))
279 def cmd_play_url(bot, user, text, command, parameter):
282 music = {'type': 'url',
284 'url': util.get_url_from_input(parameter),
286 'ready': 'validation'}
288 music = bot.validate_music(music)
290 music = var.playlist.append(music)
291 log.info("cmd: add to playlist: " + util.format_debug_song_string(music))
292 bot.send_msg(constants.strings('file_added', item=util.format_song_string(music)), text)
293 if var.playlist.length() == 2:
294 # If I am the second item on the playlist. (I am the next one!)
295 bot.async_download_next()
297 bot.send_msg(constants.strings('unable_download'), text)
300 def cmd_play_playlist(bot, user, text, command, parameter):
303 offset = 0 # if you want to start the playlist at a specific index
305 offset = int(parameter.split(" ")[-1])
309 url = util.get_url_from_input(parameter)
310 log.debug("cmd: fetching media info from playlist url %s" % url)
311 items = media.playlist.get_playlist_info(url=url, start_index=offset, user=user)
313 var.playlist.extend(items)
315 log.info("cmd: add to playlist: " + util.format_debug_song_string(music))
317 bot.send_msg(constants.strings("playlist_fetching_failed"), text)
320 def cmd_play_radio(bot, user, text, command, parameter):
324 all_radio = var.config.items('radio')
325 msg = constants.strings('preconfigurated_radio')
328 if len(i[1].split(maxsplit=1)) == 2:
329 comment = " - " + i[1].split(maxsplit=1)[1]
330 msg += "<br />" + i[0] + comment
331 bot.send_msg(msg, text)
333 if var.config.has_option('radio', parameter):
334 parameter = var.config.get('radio', parameter)
335 parameter = parameter.split()[0]
336 url = util.get_url_from_input(parameter)
338 music = {'type': 'radio',
342 log.info("bot: fetching radio server description")
343 music["name"] = media.radio.get_radio_server_description(url)
345 var.playlist.append(music)
346 log.info("cmd: add to playlist: " + util.format_debug_song_string(music))
347 bot.async_download_next()
349 bot.send_msg(constants.strings('bad_url'))
352 def cmd_rb_query(bot, user, text, command, parameter):
355 log.info('cmd: Querying radio stations')
357 log.debug('rbquery without parameter')
358 msg = constants.strings('rb_query_empty')
359 bot.send_msg(msg, text)
361 log.debug('cmd: Found query parameter: ' + parameter)
362 # bot.send_msg('Searching for stations - this may take some seconds...', text)
363 rb_stations = radiobrowser.getstations_byname(parameter)
364 msg = constants.strings('rb_query_result')
365 msg += '\n<table><tr><th>!rbplay ID</th><th>Station Name</th><th>Genre</th><th>Codec/Bitrate</th><th>Country</th></tr>'
367 log.debug('cmd: No matches found for rbquery ' + parameter)
368 bot.send_msg('Radio-Browser found no matches for ' + parameter, text)
370 for s in rb_stations:
372 stationname = s['stationname']
373 country = s['country']
375 bitrate = s['bitrate']
377 # msg += f'<tr><td>{stationid}</td><td>{stationname}</td><td>{genre}</td><td>{codec}/{bitrate}</td><td>{country}</td></tr>'
378 msg += '<tr><td>%s</td><td>%s</td><td>%s</td><td>%s/%s</td><td>%s</td></tr>' % (
379 stationid, stationname, genre, codec, bitrate, country)
381 # Full message as html table
383 bot.send_msg(msg, text)
384 # Shorten message if message too long (stage I)
386 log.debug('Result too long stage I')
387 msg = constants.strings('rb_query_result') + ' (shortened L1)'
388 msg += '\n<table><tr><th>!rbplay ID</th><th>Station Name</th></tr>'
389 for s in rb_stations:
391 stationname = s['stationname']
392 # msg += f'<tr><td>{stationid}</td><td>{stationname}</td>'
393 msg += '<tr><td>%s</td><td>%s</td>' % (stationid, stationname)
396 bot.send_msg(msg, text)
397 # Shorten message if message too long (stage II)
399 log.debug('Result too long stage II')
400 msg = constants.strings('rb_query_result') + ' (shortened L2)'
401 msg += '!rbplay ID - Station Name'
402 for s in rb_stations:
404 stationname = s['stationname'][:12]
405 # msg += f'{stationid} - {stationname}'
406 msg += '%s - %s' % (stationid, stationname)
408 bot.send_msg(msg, text)
409 # Message still too long
411 bot.send_msg('Query result too long to post (> 5000 characters), please try another query.',
415 def cmd_rb_play(bot, user, text, command, parameter):
418 log.debug('cmd: Play a station by ID')
420 log.debug('rbplay without parameter')
421 msg = constants.strings('rb_play_empty')
422 bot.send_msg(msg, text)
424 log.debug('cmd: Retreiving url for station ID ' + parameter)
425 rstation = radiobrowser.getstationname_byid(parameter)
426 stationname = rstation[0]['name']
427 country = rstation[0]['country']
428 codec = rstation[0]['codec']
429 bitrate = rstation[0]['bitrate']
430 genre = rstation[0]['tags']
431 homepage = rstation[0]['homepage']
432 msg = 'Radio station added to playlist:'
433 # msg += '<table><tr><th>ID</th><th>Station Name</th><th>Genre</th><th>Codec/Bitrate</th><th>Country</th><th>Homepage</th></tr>' + \
434 # f'<tr><td>{parameter}</td><td>{stationname}</td><td>{genre}</td><td>{codec}/{bitrate}</td><td>{country}</td><td>{homepage}</td></tr></table>'
435 msg += '<table><tr><th>ID</th><th>Station Name</th><th>Genre</th><th>Codec/Bitrate</th><th>Country</th><th>Homepage</th></tr>' + \
436 '<tr><td>%s</td><td>%s</td><td>%s</td><td>%s/%s</td><td>%s</td><td>%s</td></tr></table>' \
437 % (parameter, stationname, genre, codec, bitrate, country, homepage)
438 log.debug('cmd: Added station to playlist %s' % stationname)
439 bot.send_msg(msg, text)
440 url = radiobrowser.geturl_byid(parameter)
442 log.info('cmd: Found url: ' + url)
443 music = {'type': 'radio',
448 var.playlist.append(music)
449 log.info("cmd: add to playlist: " + util.format_debug_song_string(music))
450 bot.async_download_next()
452 log.info('cmd: No playable url found.')
453 msg += "No playable url found for this station, please try another station."
454 bot.send_msg(msg, text)
457 yt_last_page = 0 # TODO: if we keep adding global variables, we need to consider sealing all commands up into classes.
459 def cmd_yt_search(bot, user, text, command, parameter):
460 global log, yt_last_result, yt_last_page
465 if parameter.startswith("-n"):
467 if len(yt_last_result) > yt_last_page * item_per_page:
468 msg = _yt_format_result(yt_last_result, yt_last_page * item_per_page, item_per_page)
469 bot.send_msg(constants.strings('yt_result', result_table=msg), text)
471 bot.send_msg(constants.strings('yt_no_more'))
475 results = util.youtube_search(parameter)
477 yt_last_result = results
479 msg = _yt_format_result(results, 0, item_per_page)
480 bot.send_msg(constants.strings('yt_result', result_table=msg), text)
482 bot.send_msg(constants.strings('yt_query_error'))
484 bot.send_msg(constants.strings('bad_parameter', command=command), text)
486 def _yt_format_result(results, start, count):
487 msg = '<table><tr><th width="10%">Index</th><th>Title</th><th width="20%">Uploader</th></tr>'
488 for index, item in enumerate(results[start:start+count]):
489 msg += '<tr><td>{index:d}</td><td>{title}</td><td>{uploader}</td></tr>'.format(
490 index=index + 1 + start, title=item[1], uploader=item[2])
496 def cmd_yt_play(bot, user, text, command, parameter):
497 global log, yt_last_result, yt_last_page
500 if parameter.isdigit() and 0 <= int(parameter) - 1 < len(yt_last_result):
501 url = "https://www.youtube.com/watch?v=" + yt_last_result[int(parameter) - 1][0]
502 cmd_play_url(bot, user, text, command, url)
504 results = util.youtube_search(parameter)
506 yt_last_result = results
508 url = "https://www.youtube.com/watch?v=" + yt_last_result[0][0]
509 cmd_play_url(bot, user, text, command, url)
511 bot.send_msg(constants.strings('yt_query_error'))
513 bot.send_msg(constants.strings('bad_parameter', command=command), text)
516 def cmd_help(bot, user, text, command, parameter):
519 bot.send_msg(constants.strings('help'), text)
520 if bot.is_admin(user):
521 bot.send_msg(constants.strings('admin_help'), text)
524 def cmd_stop(bot, user, text, command, parameter):
528 bot.send_msg(constants.strings('stopped'), text)
531 def cmd_clear(bot, user, text, command, parameter):
535 bot.send_msg(constants.strings('cleared'), text)
538 def cmd_kill(bot, user, text, command, parameter):
541 if bot.is_admin(user):
545 bot.mumble.users[text.actor].send_text_message(
546 constants.strings('not_admin'))
549 def cmd_update(bot, user, text, command, parameter):
552 if bot.is_admin(user):
553 bot.mumble.users[text.actor].send_text_message(
554 constants.strings('start_updating'))
555 msg = util.update(bot.version)
556 bot.mumble.users[text.actor].send_text_message(msg)
558 bot.mumble.users[text.actor].send_text_message(
559 constants.strings('not_admin'))
562 def cmd_stop_and_getout(bot, user, text, command, parameter):
567 bot.mumble.channels.find_by_name(bot.channel).move_in()
570 def cmd_volume(bot, user, text, command, parameter):
573 # The volume is a percentage
574 if parameter and parameter.isdigit() and 0 <= int(parameter) <= 100:
575 bot.volume_set = float(float(parameter) / 100)
576 bot.send_msg(constants.strings('change_volume',
577 volume=int(bot.volume_set * 100), user=bot.mumble.users[text.actor]['name']), text)
578 var.db.set('bot', 'volume', str(bot.volume_set))
579 log.info('cmd: volume set to %d' % (bot.volume_set * 100))
581 bot.send_msg(constants.strings('current_volume', volume=int(bot.volume_set * 100)), text)
584 def cmd_ducking(bot, user, text, command, parameter):
587 if parameter == "" or parameter == "on":
588 bot.is_ducking = True
589 var.db.set('bot', 'ducking', True)
590 bot.ducking_volume = var.config.getfloat("bot", "ducking_volume", fallback=0.05)
591 bot.ducking_threshold = var.config.getint("bot", "ducking_threshold", fallback=5000)
592 bot.mumble.callbacks.set_callback(pymumble.constants.PYMUMBLE_CLBK_SOUNDRECEIVED,
593 bot.ducking_sound_received)
594 bot.mumble.set_receive_sound(True)
595 log.info('cmd: ducking is on')
597 bot.send_msg(msg, text)
598 elif parameter == "off":
599 bot.is_ducking = False
600 bot.mumble.set_receive_sound(False)
601 var.db.set('bot', 'ducking', False)
603 log.info('cmd: ducking is off')
604 bot.send_msg(msg, text)
607 def cmd_ducking_threshold(bot, user, text, command, parameter):
610 if parameter and parameter.isdigit():
611 bot.ducking_threshold = int(parameter)
612 var.db.set('bot', 'ducking_threshold', str(bot.ducking_threshold))
613 msg = "Ducking threshold set to %d." % bot.ducking_threshold
614 bot.send_msg(msg, text)
616 msg = "Current ducking threshold is %d." % bot.ducking_threshold
617 bot.send_msg(msg, text)
620 def cmd_ducking_volume(bot, user, text, command, parameter):
623 # The volume is a percentage
624 if parameter and parameter.isdigit() and 0 <= int(parameter) <= 100:
625 bot.ducking_volume = float(float(parameter) / 100)
626 bot.send_msg(constants.strings('change_ducking_volume',
627 volume=int(bot.ducking_volume * 100), user=bot.mumble.users[text.actor]['name']), text)
628 # var.db.set('bot', 'volume', str(bot.volume_set))
629 var.db.set('bot', 'ducking_volume', str(bot.ducking_volume))
630 log.info('cmd: volume on ducking set to %d' % (bot.ducking_volume * 100))
632 bot.send_msg(constants.strings('current_ducking_volume', volume=int(bot.ducking_volume * 100)), text)
635 def cmd_current_music(bot, user, text, command, parameter):
639 if var.playlist.length() > 0:
640 bot.send_msg(util.format_current_playing())
642 reply = constants.strings('not_playing')
643 bot.send_msg(reply, text)
646 def cmd_skip(bot, user, text, command, parameter):
649 if var.playlist.length() > 0:
652 bot.async_download_next()
654 bot.send_msg(constants.strings('queue_empty'), text)
657 def cmd_last(bot, user, text, command, parameter):
660 if len(var.playlist) > 0:
661 bot.interrupt_playing()
662 bot.launch_music(len(var.playlist) - 1)
663 bot.async_download_next()
665 bot.send_msg(constants.strings('queue_empty'), text)
668 def cmd_remove(bot, user, text, command, parameter):
671 if bot.download_in_progress:
672 bot.send_msg(constants.strings("cannot_change_when_download"))
675 # Allow to remove specific music into the queue with a number
676 if parameter and parameter.isdigit() and int(parameter) > 0 \
677 and int(parameter) <= var.playlist.length():
679 index = int(parameter) - 1
682 if index == var.playlist.current_index:
683 removed = var.playlist.remove(index)
685 if index < len(var.playlist):
687 bot.interrupt_playing()
688 var.playlist.current_index -= 1
689 # then the bot will move to next item
691 else: # if item deleted is the last item of the queue
692 var.playlist.current_index -= 1
694 bot.interrupt_playing()
696 removed = var.playlist.remove(index)
698 # the Title isn't here if the music wasn't downloaded
699 bot.send_msg(constants.strings('removing_item',
700 item=removed['title'] if 'title' in removed else removed['url']), text)
702 log.info("cmd: delete from playlist: " + str(removed['path'] if 'path' in removed else removed['url']))
704 bot.send_msg(constants.strings('bad_parameter', command=command))
707 def cmd_list_file(bot, user, text, command, parameter):
710 folder_path = var.music_folder
712 files = util.get_recursive_file_list_sorted(folder_path)
713 msgs = [ "<br> <b>Files available:</b>" if not parameter else "<br> <b>Matched files:</b>" ]
716 for index, file in enumerate(files):
718 match = re.search(parameter, file)
723 msgs.append("<b>{:0>3d}</b> - {:s}".format(index, file))
726 send_multi_lines(bot, msgs, text)
728 bot.send_msg(constants.strings('no_file'), text)
730 except re.error as e:
731 msg = constants.strings('wrong_pattern', error=str(e))
732 bot.send_msg(msg, text)
735 def cmd_queue(bot, user, text, command, parameter):
738 if len(var.playlist) == 0:
739 msg = constants.strings('queue_empty')
740 bot.send_msg(msg, text)
742 msgs = [ constants.strings('queue_contents')]
743 for i, value in enumerate(var.playlist):
745 if i == var.playlist.current_index:
746 newline = '<b>{} ▶ ({}) {} ◀</b>'.format(i + 1, value['type'],
747 value['title'] if 'title' in value else value['url'])
749 newline = '<b>{}</b> ({}) {}'.format(i + 1, value['type'],
750 value['title'] if 'title' in value else value['url'])
754 send_multi_lines(bot, msgs, text)
756 def cmd_random(bot, user, text, command, parameter):
759 bot.interrupt_playing()
760 var.playlist.randomize()
762 def cmd_repeat(bot, user, text, command, parameter):
766 if parameter and parameter.isdigit():
767 repeat = int(parameter)
769 music = var.playlist.current_item()
770 for _ in range(repeat):
772 var.playlist.current_index + 1,
775 log.info("bot: add to playlist: " + util.format_debug_song_string(music))
777 bot.send_msg(constants.strings("repeat", song=util.format_song_string(music), n=str(repeat)), text)
779 def cmd_mode(bot, user, text, command, parameter):
783 bot.send_msg(constants.strings("current_mode", mode=var.playlist.mode), text)
785 if not parameter in ["one-shot", "repeat", "random"]:
786 bot.send_msg(constants.strings('unknown_mode', mode=parameter), text)
788 var.db.set('playlist', 'playback_mode', parameter)
789 var.playlist.set_mode(parameter)
790 log.info("command: playback mode changed to %s." % parameter)
791 bot.send_msg(constants.strings("change_mode", mode=var.playlist.mode,
792 user=bot.mumble.users[text.actor]['name']), text)
793 if parameter == "random":
795 var.playlist.randomize()
798 def cmd_drop_database(bot, user, text, command, parameter):
802 var.db = Database(var.dbfile)
803 bot.send_msg(constants.strings('database_dropped'), text)
806 def cmd_real_time_rms(bot, user, text, command, parameter):
807 bot._display_rms = not bot._display_rms
809 def cmd_loop_state(bot, user, text, command, parameter):
810 print(bot._loop_status)
812 def cmd_item(bot, user, text, command, parameter):
813 print(bot.wait_for_downloading)
814 print(var.playlist.current_item())