async def queue(ctx): reset_leave_timer() if not _player or not _player.get_current(): # Queue empty and nothing playing await ctx.send( t("commands.queue_empty", locale=ctx.guild.preferred_locale, cmd_prefix="!")) return current = _player.get_current() current_length = utils.to_human_readable_position( current.get_length(), ctx.guild.preferred_locale) current_string = t("commands.queue_helper_entry", locale=ctx.guild.preferred_locale, pos=utils.to_keycap_emojis(0), desc=current.get_song_description(), len=current_length) songs = _player.get_queue().list() if len(songs) == 0: # Queue empty but something's playing await ctx.send( t("commands.queue_single", locale=ctx.guild.preferred_locale, len=current_length, current=current_string)) return # Queue not empty and something's playing total_length = utils.to_human_readable_position( utils.get_total_length([current, *songs]), ctx.guild.preferred_locale) next_string = "\n".join([ t("commands.queue_helper_entry", locale=ctx.guild.preferred_locale, pos=utils.to_keycap_emojis(idx + 1), desc=song.get_song_description(), len=utils.to_human_readable_position(song.get_length(), ctx.guild.preferred_locale)) for idx, song in enumerate(songs[:9]) ]) if len(songs) <= 9: await ctx.send( t("commands.queue_multiple", locale=ctx.guild.preferred_locale, num=1 + len(songs), total=total_length, current=current_string, next=next_string)) else: await ctx.send( t("commands.queue_many", locale=ctx.guild.preferred_locale, num=1 + len(songs), total=total_length, current=current_string, next=next_string, remaining=len(songs) - 9))
async def playnext(ctx: commands.Context, *args): reset_leave_timer() if len(args) > 0: # Show in channel that the bot is typing (fetching the video(s) may take up to a few seconds) # Not using "with ctx.typing()" because the typing indicator sometimes lingered too long after the reply was # already sent await ctx.trigger_typing() reply = t("commands.play_no_results", locale=ctx.guild.preferred_locale) # Can't specify a converter directly for a variable number of arguments unfortunately videos = converters.to_youtube_videos(args) if ctx.voice_client is None: await join_channel(ctx) if videos is not None: cancel_leave_timer() endpoints = [YouTubeEndpoint(video) for video in videos] song_queue = _player.get_queue() song_queue.enqueue(endpoints, pos=0) if not _player.get_current(): # No song is playing, so start playback now _player.play() length = utils.to_human_readable_position( endpoints[0].get_length(), ctx.guild.preferred_locale) if len(endpoints) > 1: reply = t("commands.play_multiple", locale=ctx.guild.preferred_locale, desc=endpoints[0].get_song_description(), len=length, more=len(endpoints) - 1) else: reply = t("commands.play_single", locale=ctx.guild.preferred_locale, desc=endpoints[0].get_song_description(), len=length) else: if len(endpoints) > 1: length = utils.to_human_readable_position( utils.get_total_length(endpoints), ctx.guild.preferred_locale) reply = t("commands.enqueued_multiple", locale=ctx.guild.preferred_locale, num=len(endpoints), total=length, pos=1) else: length = utils.to_human_readable_position( endpoints[0].get_length(), ctx.guild.preferred_locale) reply = t("commands.enqueued_single", locale=ctx.guild.preferred_locale, desc=endpoints[0].get_song_description(), len=length, pos=1) # Send the reply (also clearing the typing status from the channel) await ctx.send(reply)
async def radio(ctx: commands.Context): reset_leave_timer() if _player: current_endpoint = _player.get_current() if current_endpoint: if isinstance(current_endpoint, YouTubeEndpoint): try: current_id = current_endpoint.get_youtube_id() mix_url = f"https://www.youtube.com/watch?v={current_id}&list=RD{current_id}" # If the current song itself is part of the radio, filter it out radio_endpoints = [ YouTubeEndpoint(video) for video in converters.to_youtube_videos([mix_url]) if video.videoid != current_id ] _player.get_queue().enqueue(radio_endpoints) length = utils.to_human_readable_position( utils.get_total_length(radio_endpoints), ctx.guild.preferred_locale) await ctx.send( t("commands.radio", locale=ctx.guild.preferred_locale, num=len(radio_endpoints), total=length)) except urllib.error.HTTPError as error: if error.code == 400: await ctx.send( t("commands.radio_not_found", locale=ctx.guild.preferred_locale)) else: raise error else: await ctx.send( t("commands.radio_not_supported", locale=ctx.guild.preferred_locale))
async def current(ctx: commands.Context): reset_leave_timer() if _player: song = _player.get_current() if song: playtime = utils.to_human_readable_position( _player.get_playtime(), ctx.guild.preferred_locale) length = utils.to_human_readable_position( song.get_length(), ctx.guild.preferred_locale) await ctx.send( t("commands.current", locale=ctx.guild.preferred_locale, desc=song.get_song_description(), pos=playtime, len=length)) return await ctx.send( t("commands.current_no_song", locale=ctx.guild.preferred_locale))
async def clear(ctx): reset_leave_timer() if _player: queue = _player.get_queue() num_songs = queue.size() total_length = utils.to_human_readable_position( queue.get_total_length(), ctx.guild.preferred_locale) queue.clear() await ctx.send( t("commands.queue_clear", locale=ctx.guild.preferred_locale, num=num_songs, total=total_length))
async def play(ctx: commands.Context, *args): reset_leave_timer() if len(args) == 0: # Resume paused song if one is currently playing if _player and _player.is_paused(): _player.play() endpoint = _player.get_current() if endpoint: cancel_leave_timer() await ctx.send( t("commands.resume", locale=ctx.guild.preferred_locale)) try: await ctx.channel.edit( topic=t("commands.channel_topic_playing", locale=ctx.guild.preferred_locale, desc=endpoint.get_song_description())) except discord.Forbidden: _logger.warning( "Unable to edit channel description to current song (missing permission)" ) else: # Show in channel that the bot is typing (fetching the video(s) may take up to a few seconds) # Not using "with ctx.typing()" because the typing indicator sometimes lingered too long after the reply was # already sent await ctx.trigger_typing() reply = t("commands.play_no_results", locale=ctx.guild.preferred_locale) # Can't specify a converter directly for a variable number of arguments unfortunately videos = converters.to_youtube_videos(args) if ctx.voice_client is None: await join_channel(ctx) if videos is not None: cancel_leave_timer() endpoints = [YouTubeEndpoint(video) for video in videos] song_queue = _player.get_queue() song_queue.enqueue(endpoints) if not _player.get_current(): # No song is currently playing, so start playback and reply with appropriate message _player.play() length = utils.to_human_readable_position( endpoints[0].get_length(), ctx.guild.preferred_locale) if len(endpoints) > 1: reply = t("commands.playnow_multiple", locale=ctx.guild.preferred_locale, desc=endpoints[0].get_song_description(), len=length, more=len(endpoints) - 1) else: reply = t("commands.play_single", locale=ctx.guild.preferred_locale, desc=endpoints[0].get_song_description(), len=length) else: # A song is already playing, reply with a different message in this case position = song_queue.size() - len(endpoints) + 1 if len(endpoints) > 1: length = utils.to_human_readable_position( utils.get_total_length(endpoints), ctx.guild.preferred_locale) reply = t("commands.enqueued_multiple", locale=ctx.guild.preferred_locale, num=len(endpoints), total=length, pos=position) else: length = utils.to_human_readable_position( endpoints[0].get_length(), ctx.guild.preferred_locale) reply = t("commands.enqueued_single", locale=ctx.guild.preferred_locale, desc=endpoints[0].get_song_description(), len=length, pos=position) # Send the reply (also clearing the typing status from the channel) await ctx.send(reply)