4 import pymumble.pymumble_py3 as pymumble
10 import variables as var
11 from librb import radiobrowser
12 from database import Database
13 from media.playlist import PlaylistItemWrapper
14 from media.file import FileItem
15 from media.url_from_playlist import PlaylistURLItem, get_playlist_info
16 from media.url import URLItem
17 from media.radio import RadioItem
19 log = logging.getLogger("bot")
21 def register_all_commands(bot):
22 bot.register_command(constants.commands('joinme'), cmd_joinme)
23 bot.register_command(constants.commands('user_ban'), cmd_user_ban)
24 bot.register_command(constants.commands('user_unban'), cmd_user_unban)
25 bot.register_command(constants.commands('url_ban'), cmd_url_ban)
26 bot.register_command(constants.commands('url_unban'), cmd_url_unban)
27 bot.register_command(constants.commands('play'), cmd_play)
28 bot.register_command(constants.commands('pause'), cmd_pause)
29 bot.register_command(constants.commands('play_file'), cmd_play_file)
30 bot.register_command(constants.commands('play_file_match'), cmd_play_file_match)
31 bot.register_command(constants.commands('play_url'), cmd_play_url)
32 bot.register_command(constants.commands('play_playlist'), cmd_play_playlist)
33 bot.register_command(constants.commands('play_radio'), cmd_play_radio)
34 bot.register_command(constants.commands('rb_query'), cmd_rb_query)
35 bot.register_command(constants.commands('rb_play'), cmd_rb_play)
36 bot.register_command(constants.commands('yt_search'), cmd_yt_search)
37 bot.register_command(constants.commands('yt_play'), cmd_yt_play)
38 bot.register_command(constants.commands('help'), cmd_help)
39 bot.register_command(constants.commands('stop'), cmd_stop)
40 bot.register_command(constants.commands('clear'), cmd_clear)
41 bot.register_command(constants.commands('kill'), cmd_kill)
42 bot.register_command(constants.commands('update'), cmd_update)
43 bot.register_command(constants.commands('stop_and_getout'), cmd_stop_and_getout)
44 bot.register_command(constants.commands('volume'), cmd_volume)
45 bot.register_command(constants.commands('ducking'), cmd_ducking)
46 bot.register_command(constants.commands('ducking_threshold'), cmd_ducking_threshold)
47 bot.register_command(constants.commands('ducking_volume'), cmd_ducking_volume)
48 bot.register_command(constants.commands('current_music'), cmd_current_music)
49 bot.register_command(constants.commands('skip'), cmd_skip)
50 bot.register_command(constants.commands('last'), cmd_last)
51 bot.register_command(constants.commands('remove'), cmd_remove)
52 bot.register_command(constants.commands('list_file'), cmd_list_file)
53 bot.register_command(constants.commands('queue'), cmd_queue)
54 bot.register_command(constants.commands('random'), cmd_random)
55 bot.register_command(constants.commands('repeat'), cmd_repeat)
56 bot.register_command(constants.commands('mode'), cmd_mode)
57 bot.register_command(constants.commands('drop_database'), cmd_drop_database)
60 bot.register_command('rtrms', cmd_real_time_rms)
61 bot.register_command('loop', cmd_loop_state)
62 bot.register_command('item', cmd_item)
64 def send_multi_lines(bot, lines, text):
72 if (len(msg) + len(newline)) > (bot.mumble.get_max_message_length() - 4) != 0: # 4 == len("<br>")
73 bot.send_msg(msg, text)
77 bot.send_msg(msg, text)
79 # ---------------- Commands ------------------
82 def cmd_joinme(bot, user, text, command, parameter):
85 bot.mumble.users.myself.move_in(
86 bot.mumble.users[text.actor]['channel_id'], token=parameter)
89 def cmd_user_ban(bot, user, text, command, parameter):
92 if bot.is_admin(user):
94 bot.mumble.users[text.actor].send_text_message(util.user_ban(parameter))
96 bot.mumble.users[text.actor].send_text_message(util.get_user_ban())
98 bot.mumble.users[text.actor].send_text_message(constants.strings('not_admin'))
102 def cmd_user_unban(bot, user, text, command, parameter):
105 if bot.is_admin(user):
107 bot.mumble.users[text.actor].send_text_message(util.user_unban(parameter))
109 bot.mumble.users[text.actor].send_text_message(constants.strings('not_admin'))
113 def cmd_url_ban(bot, user, text, command, parameter):
116 if bot.is_admin(user):
118 bot.mumble.users[text.actor].send_text_message(util.url_ban(util.get_url_from_input(parameter)))
120 bot.mumble.users[text.actor].send_text_message(util.get_url_ban())
122 bot.mumble.users[text.actor].send_text_message(constants.strings('not_admin'))
126 def cmd_url_unban(bot, user, text, command, parameter):
129 if bot.is_admin(user):
131 bot.mumble.users[text.actor].send_text_message(util.url_unban(util.get_url_from_input(parameter)))
133 bot.mumble.users[text.actor].send_text_message(constants.strings('not_admin'))
137 def cmd_play(bot, user, text, command, parameter):
140 if len(var.playlist) > 0:
142 if parameter.isdigit() and 1 <= int(parameter) <= len(var.playlist):
143 var.playlist.point_to(int(parameter) - 1 - 1) # First "-1" transfer 12345 to 01234, second "-1"
144 # point to the previous item. the loop will next to
148 bot.send_msg(constants.strings('invalid_index', index=parameter), text)
153 bot.send_msg(var.playlist.current_item().format_current_playing(), text)
156 bot.send_msg(constants.strings('queue_empty'), text)
159 def cmd_pause(bot, user, text, command, parameter):
163 bot.send_msg(constants.strings('paused'))
166 def cmd_play_file(bot, user, text, command, parameter):
169 # if parameter is {index}
170 if parameter.isdigit():
171 files = util.get_recursive_file_list_sorted(var.music_folder)
172 if int(parameter) < len(files):
173 filename = files[int(parameter)].replace(var.music_folder, '')
174 music_wrapper = PlaylistItemWrapper(FileItem(bot, filename), user)
175 var.playlist.append(music_wrapper)
176 music = music_wrapper.item
177 log.info("cmd: add to playlist: " + music.format_debug_string())
178 bot.send_msg(constants.strings('file_added', item=music.format_song_string(user)), text)
180 # if parameter is {path}
182 # sanitize "../" and so on
183 path = os.path.abspath(os.path.join(var.music_folder, parameter))
184 if not path.startswith(os.path.abspath(var.music_folder)):
185 bot.send_msg(constants.strings('no_file'), text)
188 if os.path.isfile(path):
189 music_wrapper = PlaylistItemWrapper(FileItem(bot, parameter), user)
190 var.playlist.append(music_wrapper)
191 music = music_wrapper.item
192 log.info("cmd: add to playlist: " + music.format_debug_string())
193 bot.send_msg(constants.strings('file_added', item=music.format_song_string(user)), text)
196 # if parameter is {folder}
197 elif os.path.isdir(path):
198 if parameter != '.' and parameter != './':
199 if not parameter.endswith("/"):
204 files = util.get_recursive_file_list_sorted(var.music_folder)
205 music_library = util.Dir(var.music_folder)
207 music_library.add_file(file)
209 files = music_library.get_files(parameter)
210 msgs = [constants.strings('multiple_file_added')]
215 music_wrapper = PlaylistItemWrapper(FileItem(bot, file), user)
216 var.playlist.append(music_wrapper)
217 music = music_wrapper.item
218 log.info("cmd: add to playlist: " + music.format_debug_string())
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:
234 music_wrapper = PlaylistItemWrapper(FileItem(bot, file), user)
235 var.playlist.append(music_wrapper)
236 music = music_wrapper.item
237 log.info("cmd: add to playlist: " + music.format_debug_string())
238 bot.send_msg(constants.strings('file_added', item=music.format_song_string(user)), 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_wrapper = PlaylistItemWrapper(FileItem(bot, file), user)
260 var.playlist.append(music_wrapper)
261 music = music_wrapper.item
262 log.info("cmd: add to playlist: " + music.format_debug_string())
263 msgs.append("{} ({})".format(music.title, music.path))
266 send_multi_lines(bot, msgs, text)
268 bot.send_msg(constants.strings('no_file'), text)
270 except re.error as e:
271 msg = constants.strings('wrong_pattern', error=str(e))
272 bot.send_msg(msg, text)
274 bot.send_msg(constants.strings('bad_parameter', command))
277 def cmd_play_url(bot, user, text, command, parameter):
280 url = util.get_url_from_input(parameter)
281 music_wrapper = PlaylistItemWrapper(URLItem(bot, url), user)
282 var.playlist.append(music_wrapper)
284 log.info("cmd: add to playlist: " + music_wrapper.format_debug_string())
285 bot.send_msg(constants.strings('file_added', item=music_wrapper.format_song_string()), text)
286 if len(var.playlist) == 2:
287 # If I am the second item on the playlist. (I am the next one!)
288 bot.async_download_next()
291 def cmd_play_playlist(bot, user, text, command, parameter):
294 offset = 0 # if you want to start the playlist at a specific index
296 offset = int(parameter.split(" ")[-1])
300 url = util.get_url_from_input(parameter)
301 log.debug("cmd: fetching media info from playlist url %s" % url)
302 items = get_playlist_info(bot, url=url, start_index=offset, user=user)
304 var.playlist.extend(list(map(lambda item: PlaylistItemWrapper(item, user), items)))
306 log.info("cmd: add to playlist: " + music.format_debug_string())
308 bot.send_msg(constants.strings("playlist_fetching_failed"), text)
311 def cmd_play_radio(bot, user, text, command, parameter):
315 all_radio = var.config.items('radio')
316 msg = constants.strings('preconfigurated_radio')
319 if len(i[1].split(maxsplit=1)) == 2:
320 comment = " - " + i[1].split(maxsplit=1)[1]
321 msg += "<br />" + i[0] + comment
322 bot.send_msg(msg, text)
324 if var.config.has_option('radio', parameter):
325 parameter = var.config.get('radio', parameter)
326 parameter = parameter.split()[0]
327 url = util.get_url_from_input(parameter)
329 music_wrapper = PlaylistItemWrapper(RadioItem(bot, url), user)
331 var.playlist.append(music_wrapper)
332 log.info("cmd: add to playlist: " + music_wrapper.format_debug_string())
334 bot.send_msg(constants.strings('bad_url'))
337 def cmd_rb_query(bot, user, text, command, parameter):
340 log.info('cmd: Querying radio stations')
342 log.debug('rbquery without parameter')
343 msg = constants.strings('rb_query_empty')
344 bot.send_msg(msg, text)
346 log.debug('cmd: Found query parameter: ' + parameter)
347 # bot.send_msg('Searching for stations - this may take some seconds...', text)
348 rb_stations = radiobrowser.getstations_byname(parameter)
349 msg = constants.strings('rb_query_result')
350 msg += '\n<table><tr><th>!rbplay ID</th><th>Station Name</th><th>Genre</th><th>Codec/Bitrate</th><th>Country</th></tr>'
352 log.debug('cmd: No matches found for rbquery ' + parameter)
353 bot.send_msg('Radio-Browser found no matches for ' + parameter, text)
355 for s in rb_stations:
357 stationname = s['stationname']
358 country = s['country']
360 bitrate = s['bitrate']
362 # msg += f'<tr><td>{stationid}</td><td>{stationname}</td><td>{genre}</td><td>{codec}/{bitrate}</td><td>{country}</td></tr>'
363 msg += '<tr><td>%s</td><td>%s</td><td>%s</td><td>%s/%s</td><td>%s</td></tr>' % (
364 stationid, stationname, genre, codec, bitrate, country)
366 # Full message as html table
368 bot.send_msg(msg, text)
369 # Shorten message if message too long (stage I)
371 log.debug('Result too long stage I')
372 msg = constants.strings('rb_query_result') + ' (shortened L1)'
373 msg += '\n<table><tr><th>!rbplay ID</th><th>Station Name</th></tr>'
374 for s in rb_stations:
376 stationname = s['stationname']
377 # msg += f'<tr><td>{stationid}</td><td>{stationname}</td>'
378 msg += '<tr><td>%s</td><td>%s</td>' % (stationid, stationname)
381 bot.send_msg(msg, text)
382 # Shorten message if message too long (stage II)
384 log.debug('Result too long stage II')
385 msg = constants.strings('rb_query_result') + ' (shortened L2)'
386 msg += '!rbplay ID - Station Name'
387 for s in rb_stations:
389 stationname = s['stationname'][:12]
390 # msg += f'{stationid} - {stationname}'
391 msg += '%s - %s' % (stationid, stationname)
393 bot.send_msg(msg, text)
394 # Message still too long
396 bot.send_msg('Query result too long to post (> 5000 characters), please try another query.',
400 def cmd_rb_play(bot, user, text, command, parameter):
403 log.debug('cmd: Play a station by ID')
405 log.debug('rbplay without parameter')
406 msg = constants.strings('rb_play_empty')
407 bot.send_msg(msg, text)
409 log.debug('cmd: Retreiving url for station ID ' + parameter)
410 rstation = radiobrowser.getstationname_byid(parameter)
411 stationname = rstation[0]['name']
412 country = rstation[0]['country']
413 codec = rstation[0]['codec']
414 bitrate = rstation[0]['bitrate']
415 genre = rstation[0]['tags']
416 homepage = rstation[0]['homepage']
417 msg = 'Radio station added to playlist:'
418 # msg += '<table><tr><th>ID</th><th>Station Name</th><th>Genre</th><th>Codec/Bitrate</th><th>Country</th><th>Homepage</th></tr>' + \
419 # f'<tr><td>{parameter}</td><td>{stationname}</td><td>{genre}</td><td>{codec}/{bitrate}</td><td>{country}</td><td>{homepage}</td></tr></table>'
420 msg += '<table><tr><th>ID</th><th>Station Name</th><th>Genre</th><th>Codec/Bitrate</th><th>Country</th><th>Homepage</th></tr>' + \
421 '<tr><td>%s</td><td>%s</td><td>%s</td><td>%s/%s</td><td>%s</td><td>%s</td></tr></table>' \
422 % (parameter, stationname, genre, codec, bitrate, country, homepage)
423 log.debug('cmd: Added station to playlist %s' % stationname)
424 bot.send_msg(msg, text)
425 url = radiobrowser.geturl_byid(parameter)
427 log.info('cmd: Found url: ' + url)
428 music_wrapper = PlaylistItemWrapper(RadioItem(bot, url, stationname), user)
429 var.playlist.append(music_wrapper)
430 log.info("cmd: add to playlist: " + music_wrapper.format_debug_string())
431 bot.async_download_next()
433 log.info('cmd: No playable url found.')
434 msg += "No playable url found for this station, please try another station."
435 bot.send_msg(msg, text)
438 yt_last_page = 0 # TODO: if we keep adding global variables, we need to consider sealing all commands up into classes.
440 def cmd_yt_search(bot, user, text, command, parameter):
441 global log, yt_last_result, yt_last_page
446 if parameter.startswith("-n"):
448 if len(yt_last_result) > yt_last_page * item_per_page:
449 msg = _yt_format_result(yt_last_result, yt_last_page * item_per_page, item_per_page)
450 bot.send_msg(constants.strings('yt_result', result_table=msg), text)
452 bot.send_msg(constants.strings('yt_no_more'))
456 results = util.youtube_search(parameter)
458 yt_last_result = results
460 msg = _yt_format_result(results, 0, item_per_page)
461 bot.send_msg(constants.strings('yt_result', result_table=msg), text)
463 bot.send_msg(constants.strings('yt_query_error'))
465 bot.send_msg(constants.strings('bad_parameter', command=command), text)
467 def _yt_format_result(results, start, count):
468 msg = '<table><tr><th width="10%">Index</th><th>Title</th><th width="20%">Uploader</th></tr>'
469 for index, item in enumerate(results[start:start+count]):
470 msg += '<tr><td>{index:d}</td><td>{title}</td><td>{uploader}</td></tr>'.format(
471 index=index + 1 + start, title=item[1], uploader=item[2])
477 def cmd_yt_play(bot, user, text, command, parameter):
478 global log, yt_last_result, yt_last_page
481 if parameter.isdigit() and 0 <= int(parameter) - 1 < len(yt_last_result):
482 url = "https://www.youtube.com/watch?v=" + yt_last_result[int(parameter) - 1][0]
483 cmd_play_url(bot, user, text, command, url)
485 results = util.youtube_search(parameter)
487 yt_last_result = results
489 url = "https://www.youtube.com/watch?v=" + yt_last_result[0][0]
490 cmd_play_url(bot, user, text, command, url)
492 bot.send_msg(constants.strings('yt_query_error'))
494 bot.send_msg(constants.strings('bad_parameter', command=command), text)
497 def cmd_help(bot, user, text, command, parameter):
500 bot.send_msg(constants.strings('help'), text)
501 if bot.is_admin(user):
502 bot.send_msg(constants.strings('admin_help'), text)
505 def cmd_stop(bot, user, text, command, parameter):
509 bot.send_msg(constants.strings('stopped'), text)
512 def cmd_clear(bot, user, text, command, parameter):
516 bot.send_msg(constants.strings('cleared'), text)
519 def cmd_kill(bot, user, text, command, parameter):
522 if bot.is_admin(user):
526 bot.mumble.users[text.actor].send_text_message(
527 constants.strings('not_admin'))
530 def cmd_update(bot, user, text, command, parameter):
533 if bot.is_admin(user):
534 bot.mumble.users[text.actor].send_text_message(
535 constants.strings('start_updating'))
536 msg = util.update(bot.version)
537 bot.mumble.users[text.actor].send_text_message(msg)
539 bot.mumble.users[text.actor].send_text_message(
540 constants.strings('not_admin'))
543 def cmd_stop_and_getout(bot, user, text, command, parameter):
548 bot.mumble.channels.find_by_name(bot.channel).move_in()
551 def cmd_volume(bot, user, text, command, parameter):
554 # The volume is a percentage
555 if parameter and parameter.isdigit() and 0 <= int(parameter) <= 100:
556 bot.volume_set = float(float(parameter) / 100)
557 bot.send_msg(constants.strings('change_volume',
558 volume=int(bot.volume_set * 100), user=bot.mumble.users[text.actor]['name']), text)
559 var.db.set('bot', 'volume', str(bot.volume_set))
560 log.info('cmd: volume set to %d' % (bot.volume_set * 100))
562 bot.send_msg(constants.strings('current_volume', volume=int(bot.volume_set * 100)), text)
565 def cmd_ducking(bot, user, text, command, parameter):
568 if parameter == "" or parameter == "on":
569 bot.is_ducking = True
570 var.db.set('bot', 'ducking', True)
571 bot.ducking_volume = var.config.getfloat("bot", "ducking_volume", fallback=0.05)
572 bot.ducking_threshold = var.config.getint("bot", "ducking_threshold", fallback=5000)
573 bot.mumble.callbacks.set_callback(pymumble.constants.PYMUMBLE_CLBK_SOUNDRECEIVED,
574 bot.ducking_sound_received)
575 bot.mumble.set_receive_sound(True)
576 log.info('cmd: ducking is on')
578 bot.send_msg(msg, text)
579 elif parameter == "off":
580 bot.is_ducking = False
581 bot.mumble.set_receive_sound(False)
582 var.db.set('bot', 'ducking', False)
584 log.info('cmd: ducking is off')
585 bot.send_msg(msg, text)
588 def cmd_ducking_threshold(bot, user, text, command, parameter):
591 if parameter and parameter.isdigit():
592 bot.ducking_threshold = int(parameter)
593 var.db.set('bot', 'ducking_threshold', str(bot.ducking_threshold))
594 msg = "Ducking threshold set to %d." % bot.ducking_threshold
595 bot.send_msg(msg, text)
597 msg = "Current ducking threshold is %d." % bot.ducking_threshold
598 bot.send_msg(msg, text)
601 def cmd_ducking_volume(bot, user, text, command, parameter):
604 # The volume is a percentage
605 if parameter and parameter.isdigit() and 0 <= int(parameter) <= 100:
606 bot.ducking_volume = float(float(parameter) / 100)
607 bot.send_msg(constants.strings('change_ducking_volume',
608 volume=int(bot.ducking_volume * 100), user=bot.mumble.users[text.actor]['name']), text)
609 # var.db.set('bot', 'volume', str(bot.volume_set))
610 var.db.set('bot', 'ducking_volume', str(bot.ducking_volume))
611 log.info('cmd: volume on ducking set to %d' % (bot.ducking_volume * 100))
613 bot.send_msg(constants.strings('current_ducking_volume', volume=int(bot.ducking_volume * 100)), text)
616 def cmd_current_music(bot, user, text, command, parameter):
620 if len(var.playlist) > 0:
621 bot.send_msg(var.playlist.current_item().format_current_playing())
623 reply = constants.strings('not_playing')
624 bot.send_msg(reply, text)
627 def cmd_skip(bot, user, text, command, parameter):
632 if len(var.playlist) == 0:
633 bot.send_msg(constants.strings('queue_empty'), text)
636 def cmd_last(bot, user, text, command, parameter):
639 if len(var.playlist) > 0:
641 var.playlist.point_to(len(var.playlist) - 1)
643 bot.send_msg(constants.strings('queue_empty'), text)
646 def cmd_remove(bot, user, text, command, parameter):
649 # Allow to remove specific music into the queue with a number
650 if parameter and parameter.isdigit() and int(parameter) > 0 \
651 and int(parameter) <= len(var.playlist):
653 index = int(parameter) - 1
656 if index == var.playlist.current_index:
657 removed = var.playlist.remove(index)
659 if index < len(var.playlist):
662 var.playlist.current_index -= 1
663 # then the bot will move to next item
665 else: # if item deleted is the last item of the queue
666 var.playlist.current_index -= 1
670 removed = var.playlist.remove(index)
672 bot.send_msg(constants.strings('removing_item',
673 item=removed.format_short_string()), text)
675 log.info("cmd: delete from playlist: " + removed.format_debug_string())
677 bot.send_msg(constants.strings('bad_parameter', command=command))
680 def cmd_list_file(bot, user, text, command, parameter):
683 folder_path = var.music_folder
685 files = util.get_recursive_file_list_sorted(folder_path)
686 msgs = [ "<br> <b>Files available:</b>" if not parameter else "<br> <b>Matched files:</b>" ]
689 for index, file in enumerate(files):
691 match = re.search(parameter, file)
696 msgs.append("<b>{:0>3d}</b> - {:s}".format(index, file))
699 send_multi_lines(bot, msgs, text)
701 bot.send_msg(constants.strings('no_file'), text)
703 except re.error as e:
704 msg = constants.strings('wrong_pattern', error=str(e))
705 bot.send_msg(msg, text)
708 def cmd_queue(bot, user, text, command, parameter):
711 if len(var.playlist) == 0:
712 msg = constants.strings('queue_empty')
713 bot.send_msg(msg, text)
715 msgs = [ constants.strings('queue_contents')]
716 for i, value in enumerate(var.playlist):
719 if i == var.playlist.current_index:
720 newline = '<b>{} ▶ ({}) {} ◀</b>'.format(i + 1, music.display_type(),
721 music.format_short_string())
723 newline = '<b>{}</b> ({}) {}'.format(i + 1, music.display_type(),
724 music.format_short_string())
728 send_multi_lines(bot, msgs, text)
730 def cmd_random(bot, user, text, command, parameter):
734 var.playlist.randomize()
736 def cmd_repeat(bot, user, text, command, parameter):
740 if parameter and parameter.isdigit():
741 repeat = int(parameter)
743 music = var.playlist.current_item()
744 for _ in range(repeat):
746 var.playlist.current_index + 1,
749 log.info("bot: add to playlist: " + music.format_debug_string)
751 bot.send_msg(constants.strings("repeat", song=music.format_song_string, n=str(repeat)), text)
753 def cmd_mode(bot, user, text, command, parameter):
757 bot.send_msg(constants.strings("current_mode", mode=var.playlist.mode), text)
759 if not parameter in ["one-shot", "repeat", "random"]:
760 bot.send_msg(constants.strings('unknown_mode', mode=parameter), text)
762 var.db.set('playlist', 'playback_mode', parameter)
763 var.playlist = media.playlist.get_playlist(parameter, var.playlist)
764 log.info("command: playback mode changed to %s." % parameter)
765 bot.send_msg(constants.strings("change_mode", mode=var.playlist.mode,
766 user=bot.mumble.users[text.actor]['name']), text)
767 if parameter == "random":
771 def cmd_drop_database(bot, user, text, command, parameter):
775 var.db = Database(var.dbfile)
776 bot.send_msg(constants.strings('database_dropped'), text)
779 def cmd_real_time_rms(bot, user, text, command, parameter):
780 bot._display_rms = not bot._display_rms
782 def cmd_loop_state(bot, user, text, command, parameter):
783 print(bot._loop_status)
785 def cmd_item(bot, user, text, command, parameter):
786 print(bot.wait_for_downloading)
787 print(var.playlist.current_item().item.to_dict())