Exemple #1
0
    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)
Exemple #2
0
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()
Exemple #3
0
    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
Exemple #4
0
 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
Exemple #5
0
    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
Exemple #7
0
    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