async def _parse_arguments(self, ctx: Context) -> None: _earg = self._get_extra_arg(self.callback) ctx.args = [_earg, ctx] if _earg else [ctx] ctx.kwargs = {} args = ctx.args kwargs = ctx.kwargs view = ctx.view iterator = iter(self.params.items()) if _earg: # we have 'self' as the first parameter so just advance # the iterator and resume parsing try: next(iterator) except StopIteration: fmt = 'Callback for {0.name} command is missing "self" parameter.' raise ClientException(fmt.format(self)) # next we have the 'ctx' as the next parameter try: next(iterator) except StopIteration: fmt = 'Callback for {0.name} command is missing "ctx" parameter.' raise ClientException(fmt.format(self)) for name, param in iterator: if param.kind == param.POSITIONAL_OR_KEYWORD: transformed = await self.transform(ctx, param) args.append(transformed) elif param.kind == param.KEYWORD_ONLY: # kwarg only param denotes "consume rest" semantics if self.rest_is_raw: converter = self._get_converter(param) argument = view.read_rest() kwargs[name] = await self.do_conversion( ctx, converter, argument, param) else: kwargs[name] = await self.transform(ctx, param) break elif param.kind == param.VAR_POSITIONAL: while not view.eof: try: transformed = await self.transform(ctx, param) args.append(transformed) except RuntimeError: break if not self.ignore_extra: if not view.eof: raise TooManyArguments('Too many arguments passed to ' + self.qualified_name)
def play(voice_client, source, *, after=None, speed=1): """Plays an :class:`AudioSource`. Uses a custom AudioPlayer class The finalizer, ``after`` is called after the source has been exhausted or an error occurred. If an error happens while the audio player is running, the exception is caught and the audio player is then stopped. Parameters ----------- voice_client: :class:`VoiceClient` The voice_client we are working with source: :class:`AudioSource` The audio source we're reading from. after The finalizer that is called after the stream is exhausted. All exceptions it throws are silently discarded. This function must have a single parameter, ``error``, that denotes an optional exception that was raised during playing. speed The speed at which the audio is playing Raises ------- ClientException Already playing audio or not connected. TypeError source is not a :class:`AudioSource` or after is not a callable. """ if not voice_client._connected: raise ClientException('Not connected to voice.') if voice_client.is_playing(): raise ClientException('Already playing audio.') if not isinstance(source, player.AudioSource): raise TypeError( 'source must an AudioSource not {0.__class__.__name__}'.format( source)) voice_client._player = AudioPlayer(source, voice_client, after=after, speed_mod=speed) voice_client._player.start()
def __init__(self, source, *, executable='ffmpeg', pipe=False, stderr=None, before_options=None, after_input=None, options=None, reconnect=True): stdin = None if not pipe else source args = [executable] if reconnect: args.extend(('-reconnect', '1', '-reconnect_streamed', '1', '-reconnect_delay_max', '5')) if isinstance(before_options, str): args.extend(shlex.split(before_options)) args.append('-i') args.append('-' if pipe else source) if isinstance(after_input, str): args.extend(shlex.split(after_input)) args.extend( ('-f', 's16le', '-ar', '48000', '-ac', '2', '-loglevel', 'error')) if isinstance(options, str): args.extend(shlex.split(options)) args.append('pipe:1') self._process = None try: self._process = subprocess.Popen(args, stdin=stdin, stdout=subprocess.PIPE, stderr=stderr) self._stdout = self._process.stdout except FileNotFoundError: raise ClientException(executable + ' was not found.') from None except subprocess.SubprocessError as e: raise ClientException( 'Popen failed: {0.__class__.__name__}: {0}'.format(e)) from e
def _spawn_process(self, args, **subprocess_kwargs): process = None try: process = subprocess.Popen(args, creationflags=CREATE_NO_WINDOW, **subprocess_kwargs) process.stdin.write(self._source) process.stdin.close() except FileNotFoundError: executable = args.partition(' ')[0] if isinstance(args, str) else args[0] raise ClientException(executable + ' was not found.') from None except subprocess.SubprocessError as exc: raise ClientException( 'Popen failed: {0.__class__.__name__}: {0}'.format( exc)) from exc else: return process
def create_ffmpeg_player(self, filename, *, use_avconv=False, pipe=False, options=None, before_options=None, headers=None, after=None): """ Stolen from Rapptz/Danny, thanks! """ command = 'ffmpeg' if not use_avconv else 'avconv' input_name = '-' if pipe else shlex.quote(filename) before_args = "" if isinstance(headers, dict): for key, value in headers.items(): before_args += "{}: {}\r\n".format(key, value) before_args = ' -headers ' + shlex.quote(before_args) if isinstance(before_options, str): before_args += ' ' + before_options cmd = command + '{} -i {} -f s16le -ar {} -ac {} -loglevel warning' cmd = cmd.format(before_args, input_name, self.encoder.sampling_rate, self.encoder.channels) if isinstance(options, str): cmd = cmd + ' ' + options cmd += ' pipe:1' stdin = None if not pipe else filename args = shlex.split(cmd) try: p = subprocess.Popen(args, stdin=stdin, stdout=subprocess.PIPE) return ProcessPlayer(p, self, after) except FileNotFoundError as e: raise ClientException('ffmpeg/avconv was not found in your PATH' ' environment variable') from e except subprocess.SubprocessError as e: raise ClientException( 'Popen failed: {0.__name__} {1}'.format(type(e), str(e))) \ from e
def __init__(self, source, title='Unknown Shared Stream'): if executable is None: raise FileNotFoundError('ffmpeg and avconv was not found on the system') self.title = title self._packet = '' args = [executable] args.append('-i') args.append(source) args.extend(('-f', 's16le', '-ar', '48000', '-ac', '2', '-loglevel', 'warning')) args.append('pipe:1') try: self._process = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) self._stdout = self._process.stdout asyncio.ensure_future(self.read_packet()) except FileNotFoundError: raise ClientException(f'{executable} was not found.') from None except subprocess.SubprocessError as e: raise ClientException('Popen failed: {0.__class__.__name__}: {0}'.format(e)) from e
async def play(self): """Play given youtube link""" youtube_link = self.content[len("{}play".format(COMMAND_PREFIX)) + 1:] try: # check for song.mp3 and remove song_there = os.path.isfile("song.mp3") try: logger.debug( "Author:{0}\tText Channel:{1}\tAttempting to remove song.mp3 file" .format(self.username, self.text_channel)) if song_there: os.remove("song.mp3") except PermissionError: logger.debug( "Author:{0}\tText Channel:{1}\tMusic is still playing.". format(self.username, self.text_channel)) raise PermissionError( "Wait for the current music to end or use the `{}stop` command." .format(COMMAND_PREFIX)) if not self.voice.is_connected(): logger.debug( "Author:{0}\tText Channel:{1}\tError:Bot is not connected to a voice channel." .format(self.username, self.text_channel)) raise ConnectionError( "I am not present in any of the voice channels. Please use `{0}join <channel_name>` first." .format(COMMAND_PREFIX)) ydl_opts = { 'format': 'bestaudio/best', 'postprocessors': [{ 'key': 'FFmpegExtractAudio', 'preferredcodec': 'mp3', 'preferredquality': '192', }] } # download youtube video logger.debug( "Author:{0}\tText Channel:{1}\tDownloading youtube link: {2}". format(self.username, self.text_channel, youtube_link)) with youtube_dl.YoutubeDL(ydl_opts) as ydl: ydl.download([youtube_link]) # rename file that ends with `.mp3` as song.mp3 logger.debug( "Author:{0}\tText Channel:{1}\tYoutube Link:{2}\tDownload complete. Renaming to song.mp3" .format(self.username, self.text_channel, youtube_link)) for file in os.listdir("./"): if file.endswith(".mp3"): os.rename(file, "song.mp3") # attempt to play song.mp3 logger.debug( "Author:{0}\tText Channel:{1}\tAttempting to play song.mp3". format(self.username, self.text_channel)) self.voice.play(discord.FFmpegPCMAudio("song.mp3")) except discord.errors.ClientException: logger.debug( "Author:{0}\tText Channel:{1}\tError:Already connected to voice channel." .format(self.username, self.text_channel)) raise ClientException("There is a song currently on play. Please use command `{cmd_prefix}stop` and then use command `{cmd_prefix}play <youtube_link>` again."\ .format(cmd_prefix=COMMAND_PREFIX)) return