]> git.0d.be Git - botaradio.git/blob - command.py
feat: beautified current song string, fix ytplay index problem
[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 log = logging.getLogger("bot")
19
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_query'), cmd_yt_query)
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('remove'), cmd_remove)
50     bot.register_command(constants.commands('list_file'), cmd_list_file)
51     bot.register_command(constants.commands('queue'), cmd_queue)
52     bot.register_command(constants.commands('random'), cmd_random)
53     bot.register_command(constants.commands('repeat'), cmd_repeat)
54     bot.register_command(constants.commands('mode'), cmd_mode)
55     bot.register_command(constants.commands('drop_database'), cmd_drop_database)
56
57 def send_multi_lines(bot, lines, text):
58     global log
59
60     msg = ""
61     br = ""
62     for newline in lines:
63         msg += br
64         br = "<br>"
65         if len(msg) + len(newline) > 5000:
66             bot.send_msg(msg, text)
67             msg = ""
68         msg += newline
69
70     bot.send_msg(msg, text)
71
72 # ---------------- Commands ------------------
73
74
75 def cmd_joinme(bot, user, text, command, parameter):
76     global log
77
78     bot.mumble.users.myself.move_in(
79         bot.mumble.users[text.actor]['channel_id'], token=parameter)
80
81
82 def cmd_user_ban(bot, user, text, command, parameter):
83     global log
84
85     if bot.is_admin(user):
86         if parameter:
87             bot.mumble.users[text.actor].send_text_message(util.user_ban(parameter))
88         else:
89             bot.mumble.users[text.actor].send_text_message(util.get_user_ban())
90     else:
91         bot.mumble.users[text.actor].send_text_message(constants.strings('not_admin'))
92     return
93
94
95 def cmd_user_unban(bot, user, text, command, parameter):
96     global log
97
98     if bot.is_admin(user):
99         if parameter:
100             bot.mumble.users[text.actor].send_text_message(util.user_unban(parameter))
101     else:
102         bot.mumble.users[text.actor].send_text_message(constants.strings('not_admin'))
103     return
104
105
106 def cmd_url_ban(bot, user, text, command, parameter):
107     global log
108
109     if bot.is_admin(user):
110         if parameter:
111             bot.mumble.users[text.actor].send_text_message(util.url_ban(util.get_url_from_input(parameter)))
112         else:
113             bot.mumble.users[text.actor].send_text_message(util.get_url_ban())
114     else:
115         bot.mumble.users[text.actor].send_text_message(constants.strings('not_admin'))
116     return
117
118
119 def cmd_url_unban(bot, user, text, command, parameter):
120     global log
121
122     if bot.is_admin(user):
123         if parameter:
124             bot.mumble.users[text.actor].send_text_message(util.url_unban(util.get_url_from_input(parameter)))
125     else:
126         bot.mumble.users[text.actor].send_text_message(constants.strings('not_admin'))
127     return
128
129
130 def cmd_play(bot, user, text, command, parameter):
131     global log
132
133     if var.playlist.length() > 0:
134         if parameter:
135             if parameter.isdigit() and int(parameter) > 0 and int(parameter) <= len(var.playlist):
136                 bot.interrupt_playing()
137                 bot.launch_music(int(parameter) - 1)
138             else:
139                 bot.send_msg(constants.strings('invalid_index', index=parameter), text)
140
141         elif bot.is_pause:
142             bot.resume()
143         else:
144             bot.send_msg(util.format_current_playing(), text)
145     else:
146         bot.is_pause = False
147         bot.send_msg(constants.strings('queue_empty'), text)
148
149
150 def cmd_pause(bot, user, text, command, parameter):
151     global log
152
153     bot.pause()
154     bot.send_msg(constants.strings('paused'))
155
156
157 def cmd_play_file(bot, user, text, command, parameter):
158     global log
159
160     # if parameter is {index}
161     if parameter.isdigit():
162         files = util.get_recursive_file_list_sorted(var.music_folder)
163         if int(parameter) < len(files):
164             filename = files[int(parameter)].replace(var.music_folder, '')
165             music = {'type': 'file',
166                      'path': filename,
167                      'user': user}
168             music = var.playlist.append(music)
169             log.info("cmd: add to playlist: " + util.format_debug_song_string(music))
170             bot.send_msg(constants.strings('file_added', item=util.format_song_string(music)), text)
171
172     # if parameter is {path}
173     else:
174         # sanitize "../" and so on
175         path = os.path.abspath(os.path.join(var.music_folder, parameter))
176         if not path.startswith(os.path.abspath(var.music_folder)):
177             bot.send_msg(constants.strings('no_file'), text)
178             return
179
180         if os.path.isfile(path):
181             music = {'type': 'file',
182                      'path': parameter,
183                      'user': user}
184             music = var.playlist.append(music)
185             log.info("cmd: add to playlist: " + util.format_debug_song_string(music))
186             bot.send_msg(constants.strings('file_added', item=util.format_song_string(music)), text)
187             return
188
189         # if parameter is {folder}
190         elif os.path.isdir(path):
191             if parameter != '.' and parameter != './':
192                 if not parameter.endswith("/"):
193                     parameter += "/"
194             else:
195                 parameter = ""
196
197             files = util.get_recursive_file_list_sorted(var.music_folder)
198             music_library = util.Dir(var.music_folder)
199             for file in files:
200                 music_library.add_file(file)
201
202             files = music_library.get_files(parameter)
203             msgs = [constants.strings('multiple_file_added')]
204             count = 0
205
206             for file in files:
207                 count += 1
208                 music = {'type': 'file',
209                          'path': file,
210                          'user': user}
211                 music = var.playlist.append(music)
212                 log.info("cmd: add to playlist: " + util.format_debug_song_string(music))
213                 msgs.append("{} ({})".format(music['title'], music['path']))
214
215             if count != 0:
216                 send_multi_lines(bot, msgs, text)
217             else:
218                 bot.send_msg(constants.strings('no_file'), text)
219
220         else:
221             # try to do a partial match
222             files = util.get_recursive_file_list_sorted(var.music_folder)
223             matches = [(index, file) for index, file in enumerate(files) if parameter.lower() in file.lower()]
224             if len(matches) == 0:
225                 bot.send_msg(constants.strings('no_file'), text)
226             elif len(matches) == 1:
227                 music = {'type': 'file',
228                          'path': matches[0][1],
229                          'user': user}
230                 music = var.playlist.append(music)
231                 log.info("cmd: add to playlist: " + util.format_debug_song_string(music))
232                 bot.send_msg(constants.strings('file_added', item=util.format_song_string(music)), text)
233             else:
234                 msgs = [ constants.strings('multiple_matches')]
235                 for match in matches:
236                     msgs.append("<b>{:0>3d}</b> - {:s}".format(match[0], match[1]))
237                 send_multi_lines(bot, msgs, text)
238
239
240 def cmd_play_file_match(bot, user, text, command, parameter):
241     global log
242
243     music_folder = var.music_folder
244     if parameter:
245         files = util.get_recursive_file_list_sorted(music_folder)
246         msgs = [ constants.strings('multiple_file_added')]
247         count = 0
248         try:
249             for file in files:
250                 match = re.search(parameter, file)
251                 if match:
252                     count += 1
253                     music = {'type': 'file',
254                              'path': file,
255                              'user': user}
256                     music = var.playlist.append(music)
257                     log.info("cmd: add to playlist: " + util.format_debug_song_string(music))
258
259                     msgs.append("{} ({})".format(music['title'], music['path']))
260
261             if count != 0:
262                 send_multi_lines(bot, msgs, text)
263             else:
264                 bot.send_msg(constants.strings('no_file'), text)
265
266         except re.error as e:
267             msg = constants.strings('wrong_pattern', error=str(e))
268             bot.send_msg(msg, text)
269     else:
270         bot.send_msg(constants.strings('bad_parameter', command))
271
272
273 def cmd_play_url(bot, user, text, command, parameter):
274     global log
275
276     music = {'type': 'url',
277              # grab the real URL
278              'url': util.get_url_from_input(parameter),
279              'user': user,
280              'ready': 'validation'}
281
282     music = bot.validate_music(music)
283     if music:
284         music = var.playlist.append(music)
285         log.info("cmd: add to playlist: " + util.format_debug_song_string(music))
286         bot.send_msg(constants.strings('file_added', item=util.format_song_string(music)), text)
287         if var.playlist.length() == 2:
288             # If I am the second item on the playlist. (I am the next one!)
289             bot.async_download_next()
290     else:
291         bot.send_msg(constants.strings('unable_download'), text)
292
293
294 def cmd_play_playlist(bot, user, text, command, parameter):
295     global log
296
297     offset = 0  # if you want to start the playlist at a specific index
298     try:
299         offset = int(parameter.split(" ")[-1])
300     except ValueError:
301         pass
302
303     url = util.get_url_from_input(parameter)
304     log.debug("cmd: fetching media info from playlist url %s" % url)
305     items = media.playlist.get_playlist_info(url=url, start_index=offset, user=user)
306     if len(items) > 0:
307         var.playlist.extend(items)
308         for music in items:
309             log.info("cmd: add to playlist: " + util.format_debug_song_string(music))
310
311
312 def cmd_play_radio(bot, user, text, command, parameter):
313     global log
314
315     if not parameter:
316         all_radio = var.config.items('radio')
317         msg = constants.strings('preconfigurated_radio')
318         for i in all_radio:
319             comment = ""
320             if len(i[1].split(maxsplit=1)) == 2:
321                 comment = " - " + i[1].split(maxsplit=1)[1]
322             msg += "<br />" + i[0] + comment
323         bot.send_msg(msg, text)
324     else:
325         if var.config.has_option('radio', parameter):
326             parameter = var.config.get('radio', parameter)
327             parameter = parameter.split()[0]
328         url = util.get_url_from_input(parameter)
329         if url:
330             music = {'type': 'radio',
331                      'url': url,
332                      'user': user}
333
334             log.info("bot: fetching radio server description")
335             music["name"] = media.radio.get_radio_server_description(url)
336
337             var.playlist.append(music)
338             log.info("cmd: add to playlist: " + util.format_debug_song_string(music))
339             bot.async_download_next()
340         else:
341             bot.send_msg(constants.strings('bad_url'))
342
343
344 def cmd_rb_query(bot, user, text, command, parameter):
345     global log
346
347     log.info('cmd: Querying radio stations')
348     if not parameter:
349         log.debug('rbquery without parameter')
350         msg = constants.strings('rb_query_empty')
351         bot.send_msg(msg, text)
352     else:
353         log.debug('cmd: Found query parameter: ' + parameter)
354         # bot.send_msg('Searching for stations - this may take some seconds...', text)
355         rb_stations = radiobrowser.getstations_byname(parameter)
356         msg = constants.strings('rb_query_result')
357         msg += '\n<table><tr><th>!rbplay ID</th><th>Station Name</th><th>Genre</th><th>Codec/Bitrate</th><th>Country</th></tr>'
358         if not rb_stations:
359             log.debug('cmd: No matches found for rbquery ' + parameter)
360             bot.send_msg('Radio-Browser found no matches for ' + parameter, text)
361         else:
362             for s in rb_stations:
363                 stationid = s['id']
364                 stationname = s['stationname']
365                 country = s['country']
366                 codec = s['codec']
367                 bitrate = s['bitrate']
368                 genre = s['genre']
369                 # msg += f'<tr><td>{stationid}</td><td>{stationname}</td><td>{genre}</td><td>{codec}/{bitrate}</td><td>{country}</td></tr>'
370                 msg += '<tr><td>%s</td><td>%s</td><td>%s</td><td>%s/%s</td><td>%s</td></tr>' % (
371                     stationid, stationname, genre, codec, bitrate, country)
372             msg += '</table>'
373             # Full message as html table
374             if len(msg) <= 5000:
375                 bot.send_msg(msg, text)
376             # Shorten message if message too long (stage I)
377             else:
378                 log.debug('Result too long stage I')
379                 msg = constants.strings('rb_query_result') + ' (shortened L1)'
380                 msg += '\n<table><tr><th>!rbplay ID</th><th>Station Name</th></tr>'
381                 for s in rb_stations:
382                     stationid = s['id']
383                     stationname = s['stationname']
384                     # msg += f'<tr><td>{stationid}</td><td>{stationname}</td>'
385                     msg += '<tr><td>%s</td><td>%s</td>' % (stationid, stationname)
386                 msg += '</table>'
387                 if len(msg) <= 5000:
388                     bot.send_msg(msg, text)
389                 # Shorten message if message too long (stage II)
390                 else:
391                     log.debug('Result too long stage II')
392                     msg = constants.strings('rb_query_result') + ' (shortened L2)'
393                     msg += '!rbplay ID - Station Name'
394                     for s in rb_stations:
395                         stationid = s['id']
396                         stationname = s['stationname'][:12]
397                         # msg += f'{stationid} - {stationname}'
398                         msg += '%s - %s' % (stationid, stationname)
399                     if len(msg) <= 5000:
400                         bot.send_msg(msg, text)
401                     # Message still too long
402                     else:
403                         bot.send_msg('Query result too long to post (> 5000 characters), please try another query.',
404                                      text)
405
406
407 def cmd_rb_play(bot, user, text, command, parameter):
408     global log
409
410     log.debug('cmd: Play a station by ID')
411     if not parameter:
412         log.debug('rbplay without parameter')
413         msg = constants.strings('rb_play_empty')
414         bot.send_msg(msg, text)
415     else:
416         log.debug('cmd: Retreiving url for station ID ' + parameter)
417         rstation = radiobrowser.getstationname_byid(parameter)
418         stationname = rstation[0]['name']
419         country = rstation[0]['country']
420         codec = rstation[0]['codec']
421         bitrate = rstation[0]['bitrate']
422         genre = rstation[0]['tags']
423         homepage = rstation[0]['homepage']
424         msg = 'Radio station added to playlist:'
425         # msg += '<table><tr><th>ID</th><th>Station Name</th><th>Genre</th><th>Codec/Bitrate</th><th>Country</th><th>Homepage</th></tr>' + \
426         #       f'<tr><td>{parameter}</td><td>{stationname}</td><td>{genre}</td><td>{codec}/{bitrate}</td><td>{country}</td><td>{homepage}</td></tr></table>'
427         msg += '<table><tr><th>ID</th><th>Station Name</th><th>Genre</th><th>Codec/Bitrate</th><th>Country</th><th>Homepage</th></tr>' + \
428                '<tr><td>%s</td><td>%s</td><td>%s</td><td>%s/%s</td><td>%s</td><td>%s</td></tr></table>' \
429                % (parameter, stationname, genre, codec, bitrate, country, homepage)
430         log.debug('cmd: Added station to playlist %s' % stationname)
431         bot.send_msg(msg, text)
432         url = radiobrowser.geturl_byid(parameter)
433         if url != "-1":
434             log.info('cmd: Found url: ' + url)
435             music = {'type': 'radio',
436                      'name': stationname,
437                      'artist': homepage,
438                      'url': url,
439                      'user': user}
440             var.playlist.append(music)
441             log.info("cmd: add to playlist: " + util.format_debug_song_string(music))
442             bot.async_download_next()
443         else:
444             log.info('cmd: No playable url found.')
445             msg += "No playable url found for this station, please try another station."
446             bot.send_msg(msg, text)
447
448 yt_last_result = []
449 yt_last_page = 0 # TODO: if we keep adding global variables, we need to consider sealing all commands up into classes.
450
451 def cmd_yt_query(bot, user, text, command, parameter):
452     global log, yt_last_result, yt_last_page
453     item_per_page = 5
454
455     if parameter:
456         # if next page
457         if parameter.startswith("-n"):
458             yt_last_page += 1
459             if len(yt_last_result) > yt_last_page * item_per_page:
460                 msg = _yt_format_result(yt_last_result, yt_last_page * item_per_page, item_per_page)
461                 bot.send_msg(constants.strings('yt_result', result_table=msg), text)
462             else:
463                 bot.send_msg(constants.strings('yt_no_more'))
464
465         # if query
466         else:
467             results = util.youtube_search(parameter)
468             if results:
469                 yt_last_result = results
470                 yt_last_page = 0
471                 msg = _yt_format_result(results, 0, item_per_page)
472                 bot.send_msg(constants.strings('yt_result', result_table=msg), text)
473             else:
474                 bot.send_msg(constants.strings('yt_query_error'))
475     else:
476         bot.send_msg(constants.strings('bad_parameter', command=command), text)
477
478 def _yt_format_result(results, start, count):
479     msg = '<table><tr><th width="10%">Index</th><th>Title</th><th width="20%">Uploader</th></tr>'
480     for index, item in enumerate(results[start:start+count]):
481         msg += '<tr><td>{index:d}</td><td>{title}</td><td>{uploader}</td></tr>'.format(
482             index=index + 1 + start, title=item[1], uploader=item[2])
483     msg += '</table>'
484
485     return msg
486
487
488 def cmd_yt_play(bot, user, text, command, parameter):
489     global log, yt_last_result
490
491     if parameter and parameter.isdigit() and 0 <= int(parameter) - 1 < len(yt_last_result):
492         url = "https://www.youtube.com/watch?v=" + yt_last_result[int(parameter) - 1][0]
493         cmd_play_url(bot, user, text, command, url)
494     else:
495         bot.send_msg(constants.strings('bad_parameter', command=command), text)
496
497
498 def cmd_help(bot, user, text, command, parameter):
499     global log
500
501     bot.send_msg(constants.strings('help'), text)
502     if bot.is_admin(user):
503         bot.send_msg(constants.strings('admin_help'), text)
504
505
506 def cmd_stop(bot, user, text, command, parameter):
507     global log
508
509     bot.stop()
510     bot.send_msg(constants.strings('stopped'), text)
511
512
513 def cmd_clear(bot, user, text, command, parameter):
514     global log
515
516     bot.clear()
517     bot.send_msg(constants.strings('cleared'), text)
518
519
520 def cmd_kill(bot, user, text, command, parameter):
521     global log
522
523     if bot.is_admin(user):
524         bot.pause()
525         bot.exit = True
526     else:
527         bot.mumble.users[text.actor].send_text_message(
528             constants.strings('not_admin'))
529
530
531 def cmd_update(bot, user, text, command, parameter):
532     global log
533
534     if bot.is_admin(user):
535         bot.mumble.users[text.actor].send_text_message(
536             constants.strings('start_updating'))
537         msg = util.update(bot.version)
538         bot.mumble.users[text.actor].send_text_message(msg)
539     else:
540         bot.mumble.users[text.actor].send_text_message(
541             constants.strings('not_admin'))
542
543
544 def cmd_stop_and_getout(bot, user, text, command, parameter):
545     global log
546
547     bot.stop()
548     if bot.channel:
549         bot.mumble.channels.find_by_name(bot.channel).move_in()
550
551
552 def cmd_volume(bot, user, text, command, parameter):
553     global log
554
555     # The volume is a percentage
556     if parameter and parameter.isdigit() and 0 <= int(parameter) <= 100:
557         bot.volume_set = float(float(parameter) / 100)
558         bot.send_msg(constants.strings('change_volume',
559             volume=int(bot.volume_set * 100), user=bot.mumble.users[text.actor]['name']), text)
560         var.db.set('bot', 'volume', str(bot.volume_set))
561         log.info('cmd: volume set to %d' % (bot.volume_set * 100))
562     else:
563         bot.send_msg(constants.strings('current_volume', volume=int(bot.volume_set * 100)), text)
564
565
566 def cmd_ducking(bot, user, text, command, parameter):
567     global log
568
569     if parameter == "" or parameter == "on":
570         bot.is_ducking = True
571         var.db.set('bot', 'ducking', True)
572         bot.ducking_volume = var.config.getfloat("bot", "ducking_volume", fallback=0.05)
573         bot.ducking_threshold = var.config.getint("bot", "ducking_threshold", fallback=5000)
574         bot.mumble.callbacks.set_callback(pymumble.constants.PYMUMBLE_CLBK_SOUNDRECEIVED,
575                                           bot.ducking_sound_received)
576         bot.mumble.set_receive_sound(True)
577         log.info('cmd: ducking is on')
578         msg = "Ducking on."
579         bot.send_msg(msg, text)
580     elif parameter == "off":
581         bot.is_ducking = False
582         bot.mumble.set_receive_sound(False)
583         var.db.set('bot', 'ducking', False)
584         msg = "Ducking off."
585         log.info('cmd: ducking is off')
586         bot.send_msg(msg, text)
587
588
589 def cmd_ducking_threshold(bot, user, text, command, parameter):
590     global log
591
592     if parameter and parameter.isdigit():
593         bot.ducking_threshold = int(parameter)
594         var.db.set('bot', 'ducking_threshold', str(bot.ducking_threshold))
595         msg = "Ducking threshold set to %d." % bot.ducking_threshold
596         bot.send_msg(msg, text)
597     else:
598         msg = "Current ducking threshold is %d." % bot.ducking_threshold
599         bot.send_msg(msg, text)
600
601
602 def cmd_ducking_volume(bot, user, text, command, parameter):
603     global log
604
605     # The volume is a percentage
606     if parameter and parameter.isdigit() and 0 <= int(parameter) <= 100:
607         bot.ducking_volume = float(float(parameter) / 100)
608         bot.send_msg(constants.strings('change_ducking_volume',
609             volume=int(bot.ducking_volume * 100), user=bot.mumble.users[text.actor]['name']), text)
610         # var.db.set('bot', 'volume', str(bot.volume_set))
611         var.db.set('bot', 'ducking_volume', str(bot.ducking_volume))
612         log.info('cmd: volume on ducking set to %d' % (bot.ducking_volume * 100))
613     else:
614         bot.send_msg(constants.strings('current_ducking_volume', volume=int(bot.ducking_volume * 100)), text)
615
616
617 def cmd_current_music(bot, user, text, command, parameter):
618     global log
619
620     reply = ""
621     if var.playlist.length() > 0:
622         bot.send_msg(util.format_current_playing())
623     else:
624         reply = constants.strings('not_playing')
625     bot.send_msg(reply, text)
626
627
628 def cmd_skip(bot, user, text, command, parameter):
629     global log
630
631     if var.playlist.length() > 0:
632         bot.stop()
633         bot.launch_music()
634         bot.async_download_next()
635     else:
636         bot.send_msg(constants.strings('queue_empty'), text)
637
638
639 def cmd_remove(bot, user, text, command, parameter):
640     global log
641
642     # Allow to remove specific music into the queue with a number
643     if parameter and parameter.isdigit() and int(parameter) > 0 \
644             and int(parameter) <= var.playlist.length():
645
646         index = int(parameter) - 1
647
648         removed = None
649         if index == var.playlist.current_index:
650             removed = var.playlist.remove(index)
651
652             if index < len(var.playlist):
653                 if not bot.is_pause:
654                     bot.interrupt_playing()
655                     var.playlist.current_index -= 1
656                     # then the bot will move to next item
657
658             else: # if item deleted is the last item of the queue
659                 var.playlist.current_index -= 1
660                 if not bot.is_pause:
661                     bot.interrupt_playing()
662         else:
663             removed = var.playlist.remove(index)
664
665         # the Title isn't here if the music wasn't downloaded
666         bot.send_msg(constants.strings('removing_item',
667             item=removed['title'] if 'title' in removed else removed['url']), text)
668
669         log.info("cmd: delete from playlist: " + str(removed['path'] if 'path' in removed else removed['url']))
670     else:
671         bot.send_msg(constants.strings('bad_parameter', command=command))
672
673
674 def cmd_list_file(bot, user, text, command, parameter):
675     global log
676
677     folder_path = var.music_folder
678
679     files = util.get_recursive_file_list_sorted(folder_path)
680     msgs = [ "<br> <b>Files available:</b>" if not parameter else "<br> <b>Matched files:</b>" ]
681     try:
682         count = 0
683         for index, file in enumerate(files):
684             if parameter:
685                 match = re.search(parameter, file)
686                 if not match:
687                     continue
688
689             count += 1
690             msgs.append("<b>{:0>3d}</b> - {:s}".format(index, file))
691
692         if count != 0:
693             send_multi_lines(bot, msgs, text)
694         else:
695             bot.send_msg(constants.strings('no_file'), text)
696
697     except re.error as e:
698         msg = constants.strings('wrong_pattern', error=str(e))
699         bot.send_msg(msg, text)
700
701
702 def cmd_queue(bot, user, text, command, parameter):
703     global log
704
705     if len(var.playlist) == 0:
706         msg = constants.strings('queue_empty')
707         bot.send_msg(msg, text)
708     else:
709         msgs = [ constants.strings('queue_contents')]
710         for i, value in enumerate(var.playlist):
711             newline = ''
712             if i == var.playlist.current_index:
713                 newline = '<b>{} ▶ ({}) {} ◀</b>'.format(i + 1, value['type'],
714                                                            value['title'] if 'title' in value else value['url'])
715             else:
716                 newline = '<b>{}</b> ({}) {}'.format(i + 1, value['type'],
717                                                      value['title'] if 'title' in value else value['url'])
718
719             msgs.append(newline)
720
721         send_multi_lines(bot, msgs, text)
722
723 def cmd_random(bot, user, text, command, parameter):
724     global log
725
726     bot.interrupt_playing()
727     var.playlist.randomize()
728
729 def cmd_repeat(bot, user, text, command, parameter):
730     global log
731
732     repeat = 1
733     if parameter and parameter.isdigit():
734         repeat = int(parameter)
735
736     music = var.playlist.current_item()
737     for _ in range(repeat):
738         var.playlist.insert(
739             var.playlist.current_index + 1,
740             music
741         )
742         log.info("bot: add to playlist: " + util.format_debug_song_string(music))
743
744     bot.send_msg(constants.strings("repeat", song=util.format_song_string(music), n=str(repeat)), text)
745
746 def cmd_mode(bot, user, text, command, parameter):
747     global log
748
749     if not parameter:
750         bot.send_msg(constants.strings("current_mode", mode=var.playlist.mode), text)
751         return
752     if not parameter in ["one-shot", "repeat", "random"]:
753         bot.send_msg(constants.strings('unknown_mode', mode=parameter), text)
754     else:
755         var.db.set('playlist', 'playback_mode', parameter)
756         var.playlist.set_mode(parameter)
757         log.info("command: playback mode changed to %s." % parameter)
758         bot.send_msg(constants.strings("change_mode", mode=var.playlist.mode,
759                                        user=bot.mumble.users[text.actor]['name']), text)
760         if parameter == "random":
761             bot.stop()
762             var.playlist.randomize()
763             bot.launch_music(0)
764
765
766 def cmd_drop_database(bot, user, text, command, parameter):
767     global log
768
769     var.db.drop_table()
770     var.db = Database(var.dbfile)
771     bot.send_msg(constants.strings('database_dropped'), text)