async def audio_player_task(self): while True: self.next.clear() if self.loop: # YTDLSource(PCMVolumeTransformer(AudioSource)) can't be # rewinded, the only way is to recreate it with the same # source if self.current.state == 'downloaded': recreated_source = FFmpegPCMAudio( f'{self.bot.command_prefix}.mp3'.replace('..', '.')) else: recreated_source = FFmpegPCMAudio( self.current.source.stream_url, **YTDLSource.FFMPEG_OPTIONS, ) # if FFmpegPCMAudio fails to read source (e.g. file is missing or # failed to connect to server), .read() returns b'' if not recreated_source.read(): self.loop = False self.voice.stop() self.next.set() else: self.current.source = YTDLSource( self._ctx, recreated_source, data=self.current.source.data, volume=self.volume, ) self.voice.play(self.current.source, after=self.play_next_song) else: # Try to get the next song from SongQueue within # given timeout. If no song will be added to the # queue in time, the player will disconnect due # to performance reasons. try: async with timeout(SONG_QUEUE_TIMEOUT): self.current = await self.songs.get() except asyncio.TimeoutError: await self.current.source.channel.send( f'No new songs in queue for {SONG_QUEUE_TIMEOUT} seconds. Bot now disconnects.' ) self.bot.loop.create_task(self.suspend()) self.exists = False return # feedback to Discord (feedback on loop can produce spam) await self.current.source.channel.send( embed=self.current.create_embed().add_field( name='Loop', value=self.loop).add_field( name='Volume', value=int(self.volume * 100))) self.voice.play(self.current.source, after=self.play_next_song) await self.next.wait()
def make_audio_source(song): source = FFmpegPCMAudio(source=song.source_url, **Queue.ffmpeg_options) if not source.read(): # ensure the source url is readable, for example when ffmpeg gets 403 error, it will refresh the source url and read from that again song.refresh_source() source = make_audio_source(song) return source