]> git.0d.be Git - botaradio.git/blob - command.py
feat: three playback mode "one-shot", "loop", "random"
[botaradio.git] / command.py
1 # coding=utf-8
2 import logging
3 import os.path
4 import pymumble.pymumble_py3 as pymumble
5 import re
6
7 import constants
8 import media.file
9 import media.playlist
10 import media.radio
11 import media.system
12 import media.url
13 import util
14 import variables as var
15 from librb import radiobrowser
16 from database import Database
17
18
19 def register_all_commands(bot):
20     bot.register_command(constants.commands('joinme'), cmd_joinme)
21     bot.register_command(constants.commands('user_ban'), cmd_user_ban)
22     bot.register_command(constants.commands('user_unban'), cmd_user_unban)
23     bot.register_command(constants.commands('url_ban'), cmd_url_ban)
24     bot.register_command(constants.commands('url_unban'), cmd_url_unban)
25     bot.register_command(constants.commands('play'), cmd_play)
26     bot.register_command(constants.commands('pause'), cmd_pause)
27     bot.register_command(constants.commands('play_file'), cmd_play_file)
28     bot.register_command(constants.commands('play_file_match'), cmd_play_file_match)
29     bot.register_command(constants.commands('play_url'), cmd_play_url)
30     bot.register_command(constants.commands('play_playlist'), cmd_play_playlist)
31     bot.register_command(constants.commands('play_radio'), cmd_play_radio)
32     bot.register_command(constants.commands('rb_query'), cmd_rb_query)
33     bot.register_command(constants.commands('rb_play'), cmd_rb_play)
34     bot.register_command(constants.commands('help'), cmd_help)
35     bot.register_command(constants.commands('stop'), cmd_stop)
36     bot.register_command(constants.commands('clear'), cmd_clear)
37     bot.register_command(constants.commands('kill'), cmd_kill)
38     bot.register_command(constants.commands('update'), cmd_update)
39     bot.register_command(constants.commands('stop_and_getout'), cmd_stop_and_getout)
40     bot.register_command(constants.commands('volume'), cmd_volume)
41     bot.register_command(constants.commands('ducking'), cmd_ducking)
42     bot.register_command(constants.commands('ducking_threshold'), cmd_ducking_threshold)
43     bot.register_command(constants.commands('ducking_volume'), cmd_ducking_volume)
44     bot.register_command(constants.commands('current_music'), cmd_current_music)
45     bot.register_command(constants.commands('skip'), cmd_skip)
46     bot.register_command(constants.commands('remove'), cmd_remove)
47     bot.register_command(constants.commands('list_file'), cmd_list_file)
48     bot.register_command(constants.commands('queue'), cmd_queue)
49     bot.register_command(constants.commands('random'), cmd_random)
50     bot.register_command(constants.commands('mode'), cmd_mode)
51     bot.register_command(constants.commands('drop_database'), cmd_drop_database)
52
53 def send_multi_lines(bot, lines, text):
54     msg = ""
55     br = ""
56     for newline in lines:
57         msg += br
58         br = "<br>"
59         if len(msg) + len(newline) > 5000:
60             bot.send_msg(msg, text)
61             msg = ""
62         msg += newline
63
64     bot.send_msg(msg, text)
65
66 # ---------------- Commands ------------------
67
68
69 def cmd_joinme(bot, user, text, command, parameter):
70     bot.mumble.users.myself.move_in(
71         bot.mumble.users[text.actor]['channel_id'], token=parameter)
72
73
74 def cmd_user_ban(bot, user, text, command, parameter):
75     if bot.is_admin(user):
76         if parameter:
77             bot.mumble.users[text.actor].send_text_message(util.user_ban(parameter))
78         else:
79             bot.mumble.users[text.actor].send_text_message(util.get_user_ban())
80     else:
81         bot.mumble.users[text.actor].send_text_message(constants.strings('not_admin'))
82     return
83
84
85 def cmd_user_unban(bot, user, text, command, parameter):
86     if bot.is_admin(user):
87         if parameter:
88             bot.mumble.users[text.actor].send_text_message(util.user_unban(parameter))
89     else:
90         bot.mumble.users[text.actor].send_text_message(constants.strings('not_admin'))
91     return
92
93
94 def cmd_url_ban(bot, user, text, command, parameter):
95     if bot.is_admin(user):
96         if parameter:
97             bot.mumble.users[text.actor].send_text_message(util.url_ban(util.get_url_from_input(parameter)))
98         else:
99             bot.mumble.users[text.actor].send_text_message(util.get_url_ban())
100     else:
101         bot.mumble.users[text.actor].send_text_message(constants.strings('not_admin'))
102     return
103
104
105 def cmd_url_unban(bot, user, text, command, parameter):
106     if bot.is_admin(user):
107         if parameter:
108             bot.mumble.users[text.actor].send_text_message(util.url_unban(util.get_url_from_input(parameter)))
109     else:
110         bot.mumble.users[text.actor].send_text_message(constants.strings('not_admin'))
111     return
112
113
114 def cmd_play(bot, user, text, command, parameter):
115     if var.playlist.length() > 0:
116         if parameter is not None and parameter.isdigit() and int(parameter) > 0 \
117                 and int(parameter) <= len(var.playlist):
118             bot.stop()
119             bot.launch_music(int(parameter) - 1)
120         elif bot.is_pause:
121             bot.resume()
122         else:
123             bot.send_msg(util.format_current_playing(), text)
124     else:
125         bot.is_pause = False
126         bot.send_msg(constants.strings('queue_empty'), text)
127
128
129 def cmd_pause(bot, user, text, command, parameter):
130     bot.pause()
131     bot.send_msg(constants.strings('paused'))
132
133
134 def cmd_play_file(bot, user, text, command, parameter):
135     music_folder = var.config.get('bot', 'music_folder')
136     # if parameter is {index}
137     if parameter.isdigit():
138         files = util.get_recursive_filelist_sorted(music_folder)
139         if int(parameter) < len(files):
140             filename = files[int(parameter)].replace(music_folder, '')
141             music = {'type': 'file',
142                      'path': filename,
143                      'user': user}
144             logging.info("cmd: add to playlist: " + filename)
145             music = var.playlist.append(music)
146             bot.send_msg(constants.strings('file_added', item=util.format_song_string(music)), text)
147
148     # if parameter is {path}
149     else:
150         # sanitize "../" and so on
151         path = os.path.abspath(os.path.join(music_folder, parameter))
152         if not path.startswith(os.path.abspath(music_folder)):
153             bot.send_msg(constants.strings('no_file'), text)
154             return
155
156         if os.path.isfile(path):
157             music = {'type': 'file',
158                      'path': parameter,
159                      'user': user}
160             logging.info("cmd: add to playlist: " + parameter)
161             music = var.playlist.append(music)
162             bot.send_msg(constants.strings('file_added', item=util.format_song_string(music)), text)
163             return
164
165         # if parameter is {folder}
166         elif os.path.isdir(path):
167             if parameter != '.' and parameter != './':
168                 if not parameter.endswith("/"):
169                     parameter += "/"
170             else:
171                 parameter = ""
172
173             files = util.get_recursive_filelist_sorted(music_folder)
174             music_library = util.Dir(music_folder)
175             for file in files:
176                 music_library.add_file(file)
177
178             files = music_library.get_files(parameter)
179             msgs = [constants.strings('multiple_file_added')]
180             count = 0
181
182             for file in files:
183                 count += 1
184                 music = {'type': 'file',
185                          'path': file,
186                          'user': user}
187                 logging.info("cmd: add to playlist: " + file)
188                 music = var.playlist.append(music)
189
190                 msgs.append("{} ({})".format(music['title'], music['path']))
191
192             if count != 0:
193                 send_multi_lines(bot, msgs, text)
194             else:
195                 bot.send_msg(constants.strings('no_file'), text)
196
197         else:
198             # try to do a partial match
199             files = util.get_recursive_filelist_sorted(music_folder)
200             matches = [(index, file) for index, file in enumerate(files) if parameter.lower() in file.lower()]
201             if len(matches) == 0:
202                 bot.send_msg(constants.strings('no_file'), text)
203             elif len(matches) == 1:
204                 music = {'type': 'file',
205                          'path': matches[0][1],
206                          'user': user}
207                 logging.info("cmd: add to playlist: " + matches[0][1])
208                 music = var.playlist.append(music)
209                 bot.send_msg(constants.strings('file_added', item=util.format_song_string(music)), text)
210             else:
211                 msgs = [ constants.strings('multiple_matches')]
212                 for match in matches:
213                     msgs.append("<b>{:0>3d}</b> - {:s}".format(match[0], match[1]))
214                 send_multi_lines(bot, msgs, text)
215
216
217 def cmd_play_file_match(bot, user, text, command, parameter):
218     music_folder = var.config.get('bot', 'music_folder')
219     if parameter is not None:
220         files = util.get_recursive_filelist_sorted(music_folder)
221         msgs = [ constants.strings('file_added')]
222         count = 0
223         try:
224             for file in files:
225                 match = re.search(parameter, file)
226                 if match:
227                     count += 1
228                     music = {'type': 'file',
229                              'path': file,
230                              'user': user}
231                     logging.info("cmd: add to playlist: " + file)
232                     music = var.playlist.append(music)
233
234                     msgs.append("{} ({})".format(music['title'], music['path']))
235
236             if count != 0:
237                 send_multi_lines(bot, msgs, text)
238             else:
239                 bot.send_msg(constants.strings('no_file'), text)
240
241         except re.error as e:
242             msg = constants.strings('wrong_pattern', error=str(e))
243             bot.send_msg(msg, text)
244     else:
245         bot.send_msg(constants.strings('bad_parameter', command))
246
247
248 def cmd_play_url(bot, user, text, command, parameter):
249     music = {'type': 'url',
250              # grab the real URL
251              'url': util.get_url_from_input(parameter),
252              'user': user,
253              'ready': 'validation'}
254
255     music = bot.validate_music(music)
256     if music:
257         var.playlist.append(music)
258         logging.info("cmd: add to playlist: " + music['url'])
259         bot.send_msg(constants.strings('file_added', item=util.format_song_string(music)), text)
260         if var.playlist.length() == 2:
261             # If I am the second item on the playlist. (I am the next one!)
262             bot.async_download_next()
263     else:
264         bot.send_msg(constants.strings('unable_download'), text)
265
266
267 def cmd_play_playlist(bot, user, text, command, parameter):
268     offset = 0  # if you want to start the playlist at a specific index
269     try:
270         offset = int(parameter.split(" ")[-1])
271     except ValueError:
272         pass
273
274     url = util.get_url_from_input(parameter)
275     logging.debug("cmd: fetching media info from playlist url %s" % url)
276     items = media.playlist.get_playlist_info(url=url, start_index=offset, user=user)
277     if len(items) > 0:
278         var.playlist.extend(items)
279         for music in items:
280             logging.info("cmd: add to playlist: " + util.format_debug_song_string(music))
281
282
283 def cmd_play_radio(bot, user, text, command, parameter):
284     if not parameter:
285         all_radio = var.config.items('radio')
286         msg = constants.strings('preconfigurated_radio')
287         for i in all_radio:
288             comment = ""
289             if len(i[1].split(maxsplit=1)) == 2:
290                 comment = " - " + i[1].split(maxsplit=1)[1]
291             msg += "<br />" + i[0] + comment
292         bot.send_msg(msg, text)
293     else:
294         if var.config.has_option('radio', parameter):
295             parameter = var.config.get('radio', parameter)
296             parameter = parameter.split()[0]
297         url = util.get_url_from_input(parameter)
298         if url:
299             music = {'type': 'radio',
300                      'url': url,
301                      'user': user}
302             var.playlist.append(music)
303             logging.info("cmd: add to playlist: " + music['url'])
304             bot.async_download_next()
305         else:
306             bot.send_msg(constants.strings('bad_url'))
307
308
309 def cmd_rb_query(bot, user, text, command, parameter):
310     logging.info('cmd: Querying radio stations')
311     if not parameter:
312         logging.debug('rbquery without parameter')
313         msg = constants.strings('rb_query_empty')
314         bot.send_msg(msg, text)
315     else:
316         logging.debug('cmd: Found query parameter: ' + parameter)
317         # bot.send_msg('Searching for stations - this may take some seconds...', text)
318         rb_stations = radiobrowser.getstations_byname(parameter)
319         msg = constants.strings('rb_query_result')
320         msg += '\n<table><tr><th>!rbplay ID</th><th>Station Name</th><th>Genre</th><th>Codec/Bitrate</th><th>Country</th></tr>'
321         if not rb_stations:
322             logging.debug('cmd: No matches found for rbquery ' + parameter)
323             bot.send_msg('Radio-Browser found no matches for ' + parameter, text)
324         else:
325             for s in rb_stations:
326                 stationid = s['id']
327                 stationname = s['stationname']
328                 country = s['country']
329                 codec = s['codec']
330                 bitrate = s['bitrate']
331                 genre = s['genre']
332                 # msg += f'<tr><td>{stationid}</td><td>{stationname}</td><td>{genre}</td><td>{codec}/{bitrate}</td><td>{country}</td></tr>'
333                 msg += '<tr><td>%s</td><td>%s</td><td>%s</td><td>%s/%s</td><td>%s</td></tr>' % (
334                     stationid, stationname, genre, codec, bitrate, country)
335             msg += '</table>'
336             # Full message as html table
337             if len(msg) <= 5000:
338                 bot.send_msg(msg, text)
339             # Shorten message if message too long (stage I)
340             else:
341                 logging.debug('Result too long stage I')
342                 msg = constants.strings('rb_query_result') + ' (shortened L1)'
343                 msg += '\n<table><tr><th>!rbplay ID</th><th>Station Name</th></tr>'
344                 for s in rb_stations:
345                     stationid = s['id']
346                     stationname = s['stationname']
347                     # msg += f'<tr><td>{stationid}</td><td>{stationname}</td>'
348                     msg += '<tr><td>%s</td><td>%s</td>' % (stationid, stationname)
349                 msg += '</table>'
350                 if len(msg) <= 5000:
351                     bot.send_msg(msg, text)
352                 # Shorten message if message too long (stage II)
353                 else:
354                     logging.debug('Result too long stage II')
355                     msg = constants.strings('rb_query_result') + ' (shortened L2)'
356                     msg += '!rbplay ID - Station Name'
357                     for s in rb_stations:
358                         stationid = s['id']
359                         stationname = s['stationname'][:12]
360                         # msg += f'{stationid} - {stationname}'
361                         msg += '%s - %s' % (stationid, stationname)
362                     if len(msg) <= 5000:
363                         bot.send_msg(msg, text)
364                     # Message still too long
365                     else:
366                         bot.send_msg('Query result too long to post (> 5000 characters), please try another query.',
367                                      text)
368
369
370 def cmd_rb_play(bot, user, text, command, parameter):
371     logging.debug('cmd: Play a station by ID')
372     if not parameter:
373         logging.debug('rbplay without parameter')
374         msg = constants.strings('rb_play_empty')
375         bot.send_msg(msg, text)
376     else:
377         logging.debug('cmd: Retreiving url for station ID ' + parameter)
378         rstation = radiobrowser.getstationname_byid(parameter)
379         stationname = rstation[0]['name']
380         country = rstation[0]['country']
381         codec = rstation[0]['codec']
382         bitrate = rstation[0]['bitrate']
383         genre = rstation[0]['tags']
384         homepage = rstation[0]['homepage']
385         msg = 'Radio station added to playlist:'
386         # msg += '<table><tr><th>ID</th><th>Station Name</th><th>Genre</th><th>Codec/Bitrate</th><th>Country</th><th>Homepage</th></tr>' + \
387         #       f'<tr><td>{parameter}</td><td>{stationname}</td><td>{genre}</td><td>{codec}/{bitrate}</td><td>{country}</td><td>{homepage}</td></tr></table>'
388         msg += '<table><tr><th>ID</th><th>Station Name</th><th>Genre</th><th>Codec/Bitrate</th><th>Country</th><th>Homepage</th></tr>' + \
389                '<tr><td>%s</td><td>%s</td><td>%s</td><td>%s/%s</td><td>%s</td><td>%s</td></tr></table>' \
390                % (parameter, stationname, genre, codec, bitrate, country, homepage)
391         logging.debug('cmd: Added station to playlist %s' % stationname)
392         bot.send_msg(msg, text)
393         url = radiobrowser.geturl_byid(parameter)
394         if url != "-1":
395             logging.info('cmd: Found url: ' + url)
396             music = {'type': 'radio',
397                      'title': stationname,
398                      'artist': homepage,
399                      'url': url,
400                      'user': user}
401             var.playlist.append(music)
402             logging.info("cmd: add to playlist: " + music['url'])
403             bot.async_download_next()
404         else:
405             logging.info('cmd: No playable url found.')
406             msg += "No playable url found for this station, please try another station."
407             bot.send_msg(msg, text)
408
409
410 def cmd_help(bot, user, text, command, parameter):
411     bot.send_msg(constants.strings('help'), text)
412     if bot.is_admin(user):
413         bot.send_msg(constants.strings('admin_help'), text)
414
415
416 def cmd_stop(bot, user, text, command, parameter):
417     bot.stop()
418     bot.send_msg(constants.strings('stopped'), text)
419
420
421 def cmd_clear(bot, user, text, command, parameter):
422     bot.clear()
423     bot.send_msg(constants.strings('cleared'), text)
424
425
426 def cmd_kill(bot, user, text, command, parameter):
427     if bot.is_admin(user):
428         bot.pause()
429         bot.exit = True
430     else:
431         bot.mumble.users[text.actor].send_text_message(
432             constants.strings('not_admin'))
433
434
435 def cmd_update(bot, user, text, command, parameter):
436     if bot.is_admin(user):
437         bot.mumble.users[text.actor].send_text_message(
438             constants.strings('start_updating'))
439         msg = util.update(bot.version)
440         bot.mumble.users[text.actor].send_text_message(msg)
441     else:
442         bot.mumble.users[text.actor].send_text_message(
443             constants.strings('not_admin'))
444
445
446 def cmd_stop_and_getout(bot, user, text, command, parameter):
447     bot.stop()
448     if bot.channel:
449         bot.mumble.channels.find_by_name(bot.channel).move_in()
450
451
452 def cmd_volume(bot, user, text, command, parameter):
453     # The volume is a percentage
454     if parameter is not None and parameter.isdigit() and 0 <= int(parameter) <= 100:
455         bot.volume_set = float(float(parameter) / 100)
456         bot.send_msg(constants.strings('change_volume',
457             volume=int(bot.volume_set * 100), user=bot.mumble.users[text.actor]['name']), text)
458         var.db.set('bot', 'volume', str(bot.volume_set))
459         logging.info('cmd: volume set to %d' % (bot.volume_set * 100))
460     else:
461         bot.send_msg(constants.strings('current_volume', volume=int(bot.volume_set * 100)), text)
462
463
464 def cmd_ducking(bot, user, text, command, parameter):
465     if parameter == "" or parameter == "on":
466         bot.is_ducking = True
467         var.db.set('bot', 'ducking', True)
468         bot.ducking_volume = var.config.getfloat("bot", "ducking_volume", fallback=0.05)
469         bot.ducking_threshold = var.config.getint("bot", "ducking_threshold", fallback=5000)
470         bot.mumble.callbacks.set_callback(pymumble.constants.PYMUMBLE_CLBK_SOUNDRECEIVED,
471                                           bot.ducking_sound_received)
472         bot.mumble.set_receive_sound(True)
473         logging.info('cmd: ducking is on')
474         msg = "Ducking on."
475         bot.send_msg(msg, text)
476     elif parameter == "off":
477         bot.is_ducking = False
478         bot.mumble.set_receive_sound(False)
479         var.db.set('bot', 'ducking', False)
480         msg = "Ducking off."
481         logging.info('cmd: ducking is off')
482         bot.send_msg(msg, text)
483
484
485 def cmd_ducking_threshold(bot, user, text, command, parameter):
486     if parameter is not None and parameter.isdigit():
487         bot.ducking_threshold = int(parameter)
488         var.db.set('bot', 'ducking_threshold', str(bot.ducking_threshold))
489         msg = "Ducking threshold set to %d." % bot.ducking_threshold
490         bot.send_msg(msg, text)
491     else:
492         msg = "Current ducking threshold is %d." % bot.ducking_threshold
493         bot.send_msg(msg, text)
494
495
496 def cmd_ducking_volume(bot, user, text, command, parameter):
497     # The volume is a percentage
498     if parameter is not None and parameter.isdigit() and 0 <= int(parameter) <= 100:
499         bot.ducking_volume = float(float(parameter) / 100)
500         bot.send_msg(constants.strings('change_ducking_volume',
501             volume=int(bot.ducking_volume * 100), user=bot.mumble.users[text.actor]['name']), text)
502         # var.db.set('bot', 'volume', str(bot.volume_set))
503         var.db.set('bot', 'ducking_volume', str(bot.ducking_volume))
504         logging.info('cmd: volume on ducking set to %d' % (bot.ducking_volume * 100))
505     else:
506         bot.send_msg(constants.strings('current_ducking_volume', volume=int(bot.ducking_volume * 100)), text)
507
508
509 def cmd_current_music(bot, user, text, command, parameter):
510     reply = ""
511     if var.playlist.length() > 0:
512         bot.send_msg(util.format_current_playing())
513     else:
514         reply = constants.strings('not_playing')
515     bot.send_msg(reply, text)
516
517
518 def cmd_skip(bot, user, text, command, parameter):
519     if var.playlist.length() > 0:
520         bot.stop()
521         bot.launch_music()
522         bot.async_download_next()
523     else:
524         bot.send_msg(constants.strings('queue_empty'), text)
525
526
527 def cmd_remove(bot, user, text, command, parameter):
528     # Allow to remove specific music into the queue with a number
529     if parameter is not None and parameter.isdigit() and int(parameter) > 0 \
530             and int(parameter) <= var.playlist.length():
531
532         index = int(parameter) - 1
533
534         removed = None
535         if index == var.playlist.current_index:
536             removed = var.playlist.remove(index)
537
538             if index < len(var.playlist):
539                 if not bot.is_pause:
540                     bot.kill_ffmpeg()
541                     var.playlist.current_index -= 1
542                     # then the bot will move to next item
543
544             else: # if item deleted is the last item of the queue
545                 var.playlist.current_index -= 1
546                 if not bot.is_pause:
547                     bot.kill_ffmpeg()
548         else:
549             removed = var.playlist.remove(index)
550
551         # the Title isn't here if the music wasn't downloaded
552         bot.send_msg(constants.strings('removing_item',
553             item=removed['title'] if 'title' in removed else removed['url']), text)
554
555         logging.info("cmd: delete from playlist: " + str(removed['path'] if 'path' in removed else removed['url']))
556     else:
557         bot.send_msg(constants.strings('bad_parameter', command=command))
558
559
560 def cmd_list_file(bot, user, text, command, parameter):
561     folder_path = var.config.get('bot', 'music_folder')
562
563     files = util.get_recursive_filelist_sorted(folder_path)
564     msgs = [ "<br> <b>Files available:</b>" if not parameter else "<br> <b>Matched files:</b>" ]
565     try:
566         count = 0
567         for index, file in enumerate(files):
568             if parameter:
569                 match = re.search(parameter, file)
570                 if not match:
571                     continue
572
573             count += 1
574             msgs.append("<b>{:0>3d}</b> - {:s}".format(index, file))
575
576         if count != 0:
577             send_multi_lines(bot, msgs, text)
578         else:
579             bot.send_msg(constants.strings('no_file'), text)
580
581     except re.error as e:
582         msg = constants.strings('wrong_pattern', error=str(e))
583         bot.send_msg(msg, text)
584
585
586 def cmd_queue(bot, user, text, command, parameter):
587     if len(var.playlist) == 0:
588         msg = constants.strings('queue_empty')
589         bot.send_msg(msg, text)
590     else:
591         msgs = [ constants.strings('queue_contents')]
592         for i, value in enumerate(var.playlist):
593             newline = ''
594             if i == var.playlist.current_index:
595                 newline = '<b>{} ▶ ({}) {} ◀</b>'.format(i + 1, value['type'],
596                                                            value['title'] if 'title' in value else value['url'])
597             else:
598                 newline = '<b>{}</b> ({}) {}'.format(i + 1, value['type'],
599                                                      value['title'] if 'title' in value else value['url'])
600
601             msgs.append(newline)
602
603         send_multi_lines(bot, msgs, text)
604
605 def cmd_random(bot, user, text, command, parameter):
606     bot.stop()
607     var.playlist.randomize()
608     bot.launch_music(0)
609
610 def cmd_mode(bot, user, text, command, parameter):
611     if not parameter:
612         bot.send_msg(constants.strings("current_mode", mode=var.playlist.mode), text)
613         return
614     if not parameter in ["one-shot", "loop", "random"]:
615         bot.send_msg(constants.strings('unknown_mode', mode=parameter), text)
616     else:
617         var.playlist.set_mode(parameter)
618         if parameter == "random":
619             bot.stop()
620             var.playlist.randomize()
621             bot.launch_music(0)
622
623
624 def cmd_drop_database(bot, user, text, command, parameter):
625     var.db.drop_table()
626     var.db = Database(var.dbfile)
627     bot.send_msg(constants.strings('database_dropped'), text)