4 import pymumble.pymumble_py3 as pymumble
10 import variables as var
11 from librb import radiobrowser
12 from database import SettingsDatabase
13 from media.playlist import get_item_wrapper
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 = get_item_wrapper(bot, type='file', path=filename, user=user)
175 var.playlist.append(music_wrapper)
176 log.info("cmd: add to playlist: " + music_wrapper.format_debug_string())
177 bot.send_msg(constants.strings('file_added', item=music_wrapper.format_song_string(user)), text)
179 # if parameter is {path}
181 # sanitize "../" and so on
182 path = os.path.abspath(os.path.join(var.music_folder, parameter))
183 if not path.startswith(os.path.abspath(var.music_folder)):
184 bot.send_msg(constants.strings('no_file'), text)
187 if os.path.isfile(path):
188 music_wrapper = get_item_wrapper(bot, type='file', path=parameter, user=user)
189 var.playlist.append(music_wrapper)
190 log.info("cmd: add to playlist: " + music_wrapper.format_debug_string())
191 bot.send_msg(constants.strings('file_added', item=music_wrapper.format_song_string(user)), text)
194 # if parameter is {folder}
195 elif os.path.isdir(path):
196 if parameter != '.' and parameter != './':
197 if not parameter.endswith("/"):
202 files = util.get_recursive_file_list_sorted(var.music_folder)
203 music_library = util.Dir(var.music_folder)
205 music_library.add_file(file)
207 files = music_library.get_files(parameter)
208 msgs = [constants.strings('multiple_file_added')]
213 music_wrapper = get_item_wrapper(bot, type='file', path=file, user=user)
214 var.playlist.append(music_wrapper)
215 log.info("cmd: add to playlist: " + music_wrapper.format_debug_string())
216 msgs.append("{} ({})".format(music_wrapper.item().title, music_wrapper.item().path))
219 send_multi_lines(bot, msgs, text)
221 bot.send_msg(constants.strings('no_file'), text)
224 # try to do a partial match
225 files = util.get_recursive_file_list_sorted(var.music_folder)
226 matches = [(index, file) for index, file in enumerate(files) if parameter.lower() in file.lower()]
227 if len(matches) == 0:
228 bot.send_msg(constants.strings('no_file'), text)
229 elif len(matches) == 1:
231 music_wrapper = get_item_wrapper(bot, type='file', path=file, user=user)
232 var.playlist.append(music_wrapper)
233 log.info("cmd: add to playlist: " + music_wrapper.format_debug_string())
234 bot.send_msg(constants.strings('file_added', item=music_wrapper.format_song_string(user)), text)
236 msgs = [ constants.strings('multiple_matches')]
237 for match in matches:
238 msgs.append("<b>{:0>3d}</b> - {:s}".format(match[0], match[1]))
239 send_multi_lines(bot, msgs, text)
242 def cmd_play_file_match(bot, user, text, command, parameter):
245 music_folder = var.music_folder
247 files = util.get_recursive_file_list_sorted(music_folder)
248 msgs = [ constants.strings('multiple_file_added')]
253 match = re.search(parameter, file)
256 music_wrapper = get_item_wrapper(bot, type='file', path=file, user=user)
257 music_wrappers.append(music_wrapper)
258 log.info("cmd: add to playlist: " + music_wrapper.format_debug_string())
259 msgs.append("{} ({})".format(music_wrapper.item().title, music_wrapper.item().path))
262 var.playlist.extend(music_wrappers)
263 send_multi_lines(bot, msgs, text)
265 bot.send_msg(constants.strings('no_file'), text)
267 except re.error as e:
268 msg = constants.strings('wrong_pattern', error=str(e))
269 bot.send_msg(msg, text)
271 bot.send_msg(constants.strings('bad_parameter', command=command))
274 def cmd_play_url(bot, user, text, command, parameter):
277 url = util.get_url_from_input(parameter)
278 music_wrapper = get_item_wrapper(bot, type='url', url=url)
279 var.playlist.append(music_wrapper)
281 log.info("cmd: add to playlist: " + music_wrapper.format_debug_string())
282 bot.send_msg(constants.strings('file_added', item=music_wrapper.format_song_string()), text)
283 if len(var.playlist) == 2:
284 # If I am the second item on the playlist. (I am the next one!)
285 bot.async_download_next()
288 def cmd_play_playlist(bot, user, text, command, parameter):
291 offset = 0 # if you want to start the playlist at a specific index
293 offset = int(parameter.split(" ")[-1])
297 url = util.get_url_from_input(parameter)
298 log.debug("cmd: fetching media info from playlist url %s" % url)
299 items = get_playlist_info(bot, url=url, start_index=offset, user=user)
301 var.playlist.extend(list(map(lambda item: PlaylistItemWrapper(item, user), items)))
303 log.info("cmd: add to playlist: " + music.format_debug_string())
305 bot.send_msg(constants.strings("playlist_fetching_failed"), text)
308 def cmd_play_radio(bot, user, text, command, parameter):
312 all_radio = var.config.items('radio')
313 msg = constants.strings('preconfigurated_radio')
316 if len(i[1].split(maxsplit=1)) == 2:
317 comment = " - " + i[1].split(maxsplit=1)[1]
318 msg += "<br />" + i[0] + comment
319 bot.send_msg(msg, text)
321 if var.config.has_option('radio', parameter):
322 parameter = var.config.get('radio', parameter)
323 parameter = parameter.split()[0]
324 url = util.get_url_from_input(parameter)
326 music_wrapper = get_item_wrapper(bot, type='radio', url=url)
328 var.playlist.append(music_wrapper)
329 log.info("cmd: add to playlist: " + music_wrapper.format_debug_string())
331 bot.send_msg(constants.strings('bad_url'))
334 def cmd_rb_query(bot, user, text, command, parameter):
337 log.info('cmd: Querying radio stations')
339 log.debug('rbquery without parameter')
340 msg = constants.strings('rb_query_empty')
341 bot.send_msg(msg, text)
343 log.debug('cmd: Found query parameter: ' + parameter)
344 # bot.send_msg('Searching for stations - this may take some seconds...', text)
345 rb_stations = radiobrowser.getstations_byname(parameter)
346 msg = constants.strings('rb_query_result')
347 msg += '\n<table><tr><th>!rbplay ID</th><th>Station Name</th><th>Genre</th><th>Codec/Bitrate</th><th>Country</th></tr>'
349 log.debug('cmd: No matches found for rbquery ' + parameter)
350 bot.send_msg('Radio-Browser found no matches for ' + parameter, text)
352 for s in rb_stations:
354 stationname = s['stationname']
355 country = s['country']
357 bitrate = s['bitrate']
359 # msg += f'<tr><td>{stationid}</td><td>{stationname}</td><td>{genre}</td><td>{codec}/{bitrate}</td><td>{country}</td></tr>'
360 msg += '<tr><td>%s</td><td>%s</td><td>%s</td><td>%s/%s</td><td>%s</td></tr>' % (
361 stationid, stationname, genre, codec, bitrate, country)
363 # Full message as html table
365 bot.send_msg(msg, text)
366 # Shorten message if message too long (stage I)
368 log.debug('Result too long stage I')
369 msg = constants.strings('rb_query_result') + ' (shortened L1)'
370 msg += '\n<table><tr><th>!rbplay ID</th><th>Station Name</th></tr>'
371 for s in rb_stations:
373 stationname = s['stationname']
374 # msg += f'<tr><td>{stationid}</td><td>{stationname}</td>'
375 msg += '<tr><td>%s</td><td>%s</td>' % (stationid, stationname)
378 bot.send_msg(msg, text)
379 # Shorten message if message too long (stage II)
381 log.debug('Result too long stage II')
382 msg = constants.strings('rb_query_result') + ' (shortened L2)'
383 msg += '!rbplay ID - Station Name'
384 for s in rb_stations:
386 stationname = s['stationname'][:12]
387 # msg += f'{stationid} - {stationname}'
388 msg += '%s - %s' % (stationid, stationname)
390 bot.send_msg(msg, text)
391 # Message still too long
393 bot.send_msg('Query result too long to post (> 5000 characters), please try another query.',
397 def cmd_rb_play(bot, user, text, command, parameter):
400 log.debug('cmd: Play a station by ID')
402 log.debug('rbplay without parameter')
403 msg = constants.strings('rb_play_empty')
404 bot.send_msg(msg, text)
406 log.debug('cmd: Retreiving url for station ID ' + parameter)
407 rstation = radiobrowser.getstationname_byid(parameter)
408 stationname = rstation[0]['name']
409 country = rstation[0]['country']
410 codec = rstation[0]['codec']
411 bitrate = rstation[0]['bitrate']
412 genre = rstation[0]['tags']
413 homepage = rstation[0]['homepage']
414 msg = 'Radio station added to playlist:'
415 # msg += '<table><tr><th>ID</th><th>Station Name</th><th>Genre</th><th>Codec/Bitrate</th><th>Country</th><th>Homepage</th></tr>' + \
416 # f'<tr><td>{parameter}</td><td>{stationname}</td><td>{genre}</td><td>{codec}/{bitrate}</td><td>{country}</td><td>{homepage}</td></tr></table>'
417 msg += '<table><tr><th>ID</th><th>Station Name</th><th>Genre</th><th>Codec/Bitrate</th><th>Country</th><th>Homepage</th></tr>' + \
418 '<tr><td>%s</td><td>%s</td><td>%s</td><td>%s/%s</td><td>%s</td><td>%s</td></tr></table>' \
419 % (parameter, stationname, genre, codec, bitrate, country, homepage)
420 log.debug('cmd: Added station to playlist %s' % stationname)
421 bot.send_msg(msg, text)
422 url = radiobrowser.geturl_byid(parameter)
424 log.info('cmd: Found url: ' + url)
425 music_wrapper = get_item_wrapper(bot, type='radio', url=url, name=stationname)
426 var.playlist.append(music_wrapper)
427 log.info("cmd: add to playlist: " + music_wrapper.format_debug_string())
428 bot.async_download_next()
430 log.info('cmd: No playable url found.')
431 msg += "No playable url found for this station, please try another station."
432 bot.send_msg(msg, text)
435 yt_last_page = 0 # TODO: if we keep adding global variables, we need to consider sealing all commands up into classes.
437 def cmd_yt_search(bot, user, text, command, parameter):
438 global log, yt_last_result, yt_last_page
443 if parameter.startswith("-n"):
445 if len(yt_last_result) > yt_last_page * item_per_page:
446 msg = _yt_format_result(yt_last_result, yt_last_page * item_per_page, item_per_page)
447 bot.send_msg(constants.strings('yt_result', result_table=msg), text)
449 bot.send_msg(constants.strings('yt_no_more'))
453 results = util.youtube_search(parameter)
455 yt_last_result = results
457 msg = _yt_format_result(results, 0, item_per_page)
458 bot.send_msg(constants.strings('yt_result', result_table=msg), text)
460 bot.send_msg(constants.strings('yt_query_error'))
462 bot.send_msg(constants.strings('bad_parameter', command=command), text)
464 def _yt_format_result(results, start, count):
465 msg = '<table><tr><th width="10%">Index</th><th>Title</th><th width="20%">Uploader</th></tr>'
466 for index, item in enumerate(results[start:start+count]):
467 msg += '<tr><td>{index:d}</td><td>{title}</td><td>{uploader}</td></tr>'.format(
468 index=index + 1 + start, title=item[1], uploader=item[2])
474 def cmd_yt_play(bot, user, text, command, parameter):
475 global log, yt_last_result, yt_last_page
478 if parameter.isdigit() and 0 <= int(parameter) - 1 < len(yt_last_result):
479 url = "https://www.youtube.com/watch?v=" + yt_last_result[int(parameter) - 1][0]
480 cmd_play_url(bot, user, text, command, url)
482 results = util.youtube_search(parameter)
484 yt_last_result = results
486 url = "https://www.youtube.com/watch?v=" + yt_last_result[0][0]
487 cmd_play_url(bot, user, text, command, url)
489 bot.send_msg(constants.strings('yt_query_error'))
491 bot.send_msg(constants.strings('bad_parameter', command=command), text)
494 def cmd_help(bot, user, text, command, parameter):
497 bot.send_msg(constants.strings('help'), text)
498 if bot.is_admin(user):
499 bot.send_msg(constants.strings('admin_help'), text)
502 def cmd_stop(bot, user, text, command, parameter):
506 bot.send_msg(constants.strings('stopped'), text)
509 def cmd_clear(bot, user, text, command, parameter):
513 bot.send_msg(constants.strings('cleared'), text)
516 def cmd_kill(bot, user, text, command, parameter):
519 if bot.is_admin(user):
523 bot.mumble.users[text.actor].send_text_message(
524 constants.strings('not_admin'))
527 def cmd_update(bot, user, text, command, parameter):
530 if bot.is_admin(user):
531 bot.mumble.users[text.actor].send_text_message(
532 constants.strings('start_updating'))
533 msg = util.update(bot.version)
534 bot.mumble.users[text.actor].send_text_message(msg)
536 bot.mumble.users[text.actor].send_text_message(
537 constants.strings('not_admin'))
540 def cmd_stop_and_getout(bot, user, text, command, parameter):
545 bot.mumble.channels.find_by_name(bot.channel).move_in()
548 def cmd_volume(bot, user, text, command, parameter):
551 # The volume is a percentage
552 if parameter and parameter.isdigit() and 0 <= int(parameter) <= 100:
553 bot.volume_set = float(float(parameter) / 100)
554 bot.send_msg(constants.strings('change_volume',
555 volume=int(bot.volume_set * 100), user=bot.mumble.users[text.actor]['name']), text)
556 var.db.set('bot', 'volume', str(bot.volume_set))
557 log.info('cmd: volume set to %d' % (bot.volume_set * 100))
559 bot.send_msg(constants.strings('current_volume', volume=int(bot.volume_set * 100)), text)
562 def cmd_ducking(bot, user, text, command, parameter):
565 if parameter == "" or parameter == "on":
566 bot.is_ducking = True
567 var.db.set('bot', 'ducking', True)
568 bot.ducking_volume = var.config.getfloat("bot", "ducking_volume", fallback=0.05)
569 bot.ducking_threshold = var.config.getint("bot", "ducking_threshold", fallback=5000)
570 bot.mumble.callbacks.set_callback(pymumble.constants.PYMUMBLE_CLBK_SOUNDRECEIVED,
571 bot.ducking_sound_received)
572 bot.mumble.set_receive_sound(True)
573 log.info('cmd: ducking is on')
575 bot.send_msg(msg, text)
576 elif parameter == "off":
577 bot.is_ducking = False
578 bot.mumble.set_receive_sound(False)
579 var.db.set('bot', 'ducking', False)
581 log.info('cmd: ducking is off')
582 bot.send_msg(msg, text)
585 def cmd_ducking_threshold(bot, user, text, command, parameter):
588 if parameter and parameter.isdigit():
589 bot.ducking_threshold = int(parameter)
590 var.db.set('bot', 'ducking_threshold', str(bot.ducking_threshold))
591 msg = "Ducking threshold set to %d." % bot.ducking_threshold
592 bot.send_msg(msg, text)
594 msg = "Current ducking threshold is %d." % bot.ducking_threshold
595 bot.send_msg(msg, text)
598 def cmd_ducking_volume(bot, user, text, command, parameter):
601 # The volume is a percentage
602 if parameter and parameter.isdigit() and 0 <= int(parameter) <= 100:
603 bot.ducking_volume = float(float(parameter) / 100)
604 bot.send_msg(constants.strings('change_ducking_volume',
605 volume=int(bot.ducking_volume * 100), user=bot.mumble.users[text.actor]['name']), text)
606 # var.db.set('bot', 'volume', str(bot.volume_set))
607 var.db.set('bot', 'ducking_volume', str(bot.ducking_volume))
608 log.info('cmd: volume on ducking set to %d' % (bot.ducking_volume * 100))
610 bot.send_msg(constants.strings('current_ducking_volume', volume=int(bot.ducking_volume * 100)), text)
613 def cmd_current_music(bot, user, text, command, parameter):
617 if len(var.playlist) > 0:
618 bot.send_msg(var.playlist.current_item().format_current_playing())
620 reply = constants.strings('not_playing')
621 bot.send_msg(reply, text)
624 def cmd_skip(bot, user, text, command, parameter):
629 if len(var.playlist) == 0:
630 bot.send_msg(constants.strings('queue_empty'), text)
633 def cmd_last(bot, user, text, command, parameter):
636 if len(var.playlist) > 0:
638 var.playlist.point_to(len(var.playlist) - 1)
640 bot.send_msg(constants.strings('queue_empty'), text)
643 def cmd_remove(bot, user, text, command, parameter):
646 # Allow to remove specific music into the queue with a number
647 if parameter and parameter.isdigit() and int(parameter) > 0 \
648 and int(parameter) <= len(var.playlist):
650 index = int(parameter) - 1
653 if index == var.playlist.current_index:
654 removed = var.playlist.remove(index)
656 if index < len(var.playlist):
659 var.playlist.current_index -= 1
660 # then the bot will move to next item
662 else: # if item deleted is the last item of the queue
663 var.playlist.current_index -= 1
667 removed = var.playlist.remove(index)
669 bot.send_msg(constants.strings('removing_item',
670 item=removed.format_short_string()), text)
672 log.info("cmd: delete from playlist: " + removed.format_debug_string())
674 bot.send_msg(constants.strings('bad_parameter', command=command))
677 def cmd_list_file(bot, user, text, command, parameter):
680 folder_path = var.music_folder
682 files = util.get_recursive_file_list_sorted(folder_path)
683 msgs = [ "<br> <b>Files available:</b>" if not parameter else "<br> <b>Matched files:</b>" ]
686 for index, file in enumerate(files):
688 match = re.search(parameter, file)
693 msgs.append("<b>{:0>3d}</b> - {:s}".format(index, file))
696 send_multi_lines(bot, msgs, text)
698 bot.send_msg(constants.strings('no_file'), text)
700 except re.error as e:
701 msg = constants.strings('wrong_pattern', error=str(e))
702 bot.send_msg(msg, text)
705 def cmd_queue(bot, user, text, command, parameter):
708 if len(var.playlist) == 0:
709 msg = constants.strings('queue_empty')
710 bot.send_msg(msg, text)
712 msgs = [ constants.strings('queue_contents')]
713 for i, music in enumerate(var.playlist):
715 if i == var.playlist.current_index:
716 newline = '<b>{} ▶ ({}) {} ◀</b>'.format(i + 1, music.display_type(),
717 music.format_short_string())
719 newline = '<b>{}</b> ({}) {}'.format(i + 1, music.display_type(),
720 music.format_short_string())
724 send_multi_lines(bot, msgs, text)
726 def cmd_random(bot, user, text, command, parameter):
730 var.playlist.randomize()
732 def cmd_repeat(bot, user, text, command, parameter):
736 if parameter and parameter.isdigit():
737 repeat = int(parameter)
739 music = var.playlist.current_item()
740 for _ in range(repeat):
742 var.playlist.current_index + 1,
745 log.info("bot: add to playlist: " + music.format_debug_string)
747 bot.send_msg(constants.strings("repeat", song=music.format_song_string, n=str(repeat)), text)
749 def cmd_mode(bot, user, text, command, parameter):
753 bot.send_msg(constants.strings("current_mode", mode=var.playlist.mode), text)
755 if not parameter in ["one-shot", "repeat", "random", "autoplay"]:
756 bot.send_msg(constants.strings('unknown_mode', mode=parameter), text)
758 var.db.set('playlist', 'playback_mode', parameter)
759 var.playlist = media.playlist.get_playlist(parameter, var.playlist)
760 log.info("command: playback mode changed to %s." % parameter)
761 bot.send_msg(constants.strings("change_mode", mode=var.playlist.mode,
762 user=bot.mumble.users[text.actor]['name']), text)
763 if parameter == "random":
767 def cmd_drop_database(bot, user, text, command, parameter):
771 var.db = SettingsDatabase(var.dbfile)
772 bot.send_msg(constants.strings('database_dropped'), text)
775 def cmd_real_time_rms(bot, user, text, command, parameter):
776 bot._display_rms = not bot._display_rms
778 def cmd_loop_state(bot, user, text, command, parameter):
779 print(bot._loop_status)
781 def cmd_item(bot, user, text, command, parameter):
782 print(bot.wait_for_downloading)
783 print(var.playlist.current_item().to_dict())