Exemplo n.º 1
0
 async def get_track_description(self,
                                 track,
                                 local_folder_current_path,
                                 shorten=False) -> Optional[str]:
     """Get the user facing formatted track name."""
     string = None
     if track and getattr(track, "uri", None):
         query = Query.process_input(track.uri, local_folder_current_path)
         if query.is_local or "localtracks/" in track.uri:
             if (hasattr(track, "title") and track.title != "Unknown title"
                     and hasattr(track, "author")
                     and track.author != "Unknown artist"):
                 if shorten:
                     string = f"{track.author} - {track.title}"
                     if len(string) > 40:
                         string = f"{(string[:40]).rstrip(' ')}..."
                     string = f'**{escape(f"{string}", formatting=True)}**'
                 else:
                     string = (
                         f'**{escape(f"{track.author} - {track.title}", formatting=True)}**'
                         + escape(f"\n{query.to_string_user()} ",
                                  formatting=True))
             elif hasattr(track,
                          "title") and track.title != "Unknown title":
                 if shorten:
                     string = f"{track.title}"
                     if len(string) > 40:
                         string = f"{(string[:40]).rstrip(' ')}..."
                     string = f'**{escape(f"{string}", formatting=True)}**'
                 else:
                     string = f'**{escape(f"{track.title}", formatting=True)}**' + escape(
                         f"\n{query.to_string_user()} ", formatting=True)
             else:
                 string = query.to_string_user()
                 if shorten and len(string) > 40:
                     string = f"{(string[:40]).rstrip(' ')}..."
                 string = f'**{escape(f"{string}", formatting=True)}**'
         else:
             if track.is_stream:
                 icy = await self.icyparser(track.uri)
                 if icy:
                     title = icy
                 else:
                     title = f"{track.title} - {track.author}"
             elif track.author.lower() not in track.title.lower():
                 title = f"{track.title} - {track.author}"
             else:
                 title = track.title
             string = f"{title}"
             if shorten and len(string) > 40:
                 string = f"{(string[:40]).rstrip(' ')}..."
                 string = re.sub(RE_SQUARE, "", string)
             string = f"**[{escape(string, formatting=True)}]({track.uri}) **"
     elif hasattr(track, "to_string_user") and track.is_local:
         string = track.to_string_user() + " "
         if shorten and len(string) > 40:
             string = f"{(string[:40]).rstrip(' ')}..."
         string = f'**{escape(f"{string}", formatting=True)}**'
     return string
Exemplo n.º 2
0
    async def choose(self, ctx, *choices):
        """Choose between multiple options.

        To denote options which include whitespace, you should use
        double quotes.
        """
        choices = [escape(c, mass_mentions=True) for c in choices if c]
        if len(choices) < 2:
            await ctx.send(_("Not enough options to pick from."))
        else:
            await ctx.send(choice(choices))
Exemplo n.º 3
0
 def prepare_command_list(
     ctx: commands.Context, command_list: Iterable[Tuple[str, dict]]
 ) -> List[Tuple[str, str]]:
     results = []
     for command, body in command_list:
         responses = body["response"]
         if isinstance(responses, list):
             result = ", ".join(responses)
         elif isinstance(responses, str):
             result = responses
         else:
             continue
         # Cut preview to 52 characters max
         if len(result) > 52:
             result = result[:49] + "..."
         # Replace newlines with spaces
         result = result.replace("\n", " ")
         # Escape markdown and mass mentions
         result = escape(result, formatting=True, mass_mentions=True)
         results.append((f"{ctx.clean_prefix}{command}", result))
     return results
Exemplo n.º 4
0
    async def check_streams(self):
        for stream in self.streams:
            try:
                try:
                    is_rerun = False
                    is_schedule = False
                    if stream.__class__.__name__ == "TwitchStream":
                        await self.maybe_renew_twitch_bearer_token()
                        embed, is_rerun = await stream.is_online()

                    elif stream.__class__.__name__ == "YoutubeStream":
                        embed, is_schedule = await stream.is_online()

                    else:
                        embed = await stream.is_online()
                except OfflineStream:
                    if not stream._messages_cache:
                        continue
                    for message in stream._messages_cache:
                        if await self.bot.cog_disabled_in_guild(
                                self, message.guild):
                            continue
                        autodelete = await self.config.guild(message.guild
                                                             ).autodelete()
                        if autodelete:
                            with contextlib.suppress(discord.NotFound):
                                await message.delete()
                    stream._messages_cache.clear()
                    await self.save_streams()
                else:
                    if stream._messages_cache:
                        continue
                    for channel_id in stream.channels:
                        channel = self.bot.get_channel(channel_id)
                        if not channel:
                            continue
                        if await self.bot.cog_disabled_in_guild(
                                self, channel.guild):
                            continue
                        ignore_reruns = await self.config.guild(
                            channel.guild).ignore_reruns()
                        if ignore_reruns and is_rerun:
                            continue
                        ignore_schedules = await self.config.guild(
                            channel.guild).ignore_schedule()
                        if ignore_schedules and is_schedule:
                            continue
                        if is_schedule:
                            # skip messages and mentions
                            await self._send_stream_alert(
                                stream, channel, embed)
                            await self.save_streams()
                            continue
                        await set_contextual_locales_from_guild(
                            self.bot, channel.guild)

                        mention_str, edited_roles = await self._get_mention_str(
                            channel.guild, channel)

                        if mention_str:
                            alert_msg = await self.config.guild(
                                channel.guild).live_message_mention()
                            if alert_msg:
                                content = alert_msg  # Stop bad things from happening here...
                                content = content.replace(
                                    "{stream.name}", str(stream.name)
                                )  # Backwards compatibility
                                content = content.replace(
                                    "{stream}", str(stream.name))
                                content = content.replace(
                                    "{mention}", mention_str)
                            else:
                                content = _(
                                    "{mention}, {stream} is live!").format(
                                        mention=mention_str,
                                        stream=escape(str(stream.name),
                                                      mass_mentions=True,
                                                      formatting=True),
                                    )
                        else:
                            alert_msg = await self.config.guild(
                                channel.guild).live_message_nomention()
                            if alert_msg:
                                content = alert_msg  # Stop bad things from happening here...
                                content = content.replace(
                                    "{stream.name}", str(stream.name)
                                )  # Backwards compatibility
                                content = content.replace(
                                    "{stream}", str(stream.name))
                            else:
                                content = _("{stream} is live!").format(
                                    stream=escape(str(stream.name),
                                                  mass_mentions=True,
                                                  formatting=True))
                        await self._send_stream_alert(stream, channel, embed,
                                                      content)
                        if edited_roles:
                            for role in edited_roles:
                                await role.edit(mentionable=False)
                        await self.save_streams()
            except Exception as e:
                log.error(
                    "An error has occured with Streams. Please report it.",
                    exc_info=e)
Exemplo n.º 5
0
 async def lmgtfy(self, ctx, *, search_terms: str):
     """Create a lmgtfy link."""
     search_terms = escape(urllib.parse.quote_plus(search_terms),
                           mass_mentions=True)
     await ctx.send("https://lmgtfy.com/?q={}".format(search_terms))
Exemplo n.º 6
0
    async def _enqueue_tracks(
        self, ctx: commands.Context, query: Union[Query, list], enqueue: bool = True
    ) -> Union[discord.Message, List[lavalink.Track], lavalink.Track]:
        player = lavalink.get_player(ctx.guild.id)
        try:
            if self.play_lock[ctx.message.guild.id]:
                return await self.send_embed_msg(
                    ctx,
                    title=_("Unable To Get Tracks"),
                    description=_("Wait until the playlist has finished loading."),
                )
        except KeyError:
            self.update_player_lock(ctx, True)
        guild_data = await self.config.guild(ctx.guild).all()
        first_track_only = False
        single_track = None
        index = None
        playlist_data = None
        playlist_url = None
        seek = 0
        if type(query) is not list:
            if not await self.is_query_allowed(self.config, ctx, f"{query}", query_obj=query):
                raise QueryUnauthorized(
                    _("{query} is not an allowed query.").format(query=query.to_string_user())
                )
            if query.single_track:
                first_track_only = True
                index = query.track_index
                if query.start_time:
                    seek = query.start_time
            try:
                result, called_api = await self.api_interface.fetch_track(ctx, player, query)
            except TrackEnqueueError:
                self.update_player_lock(ctx, False)
                return await self.send_embed_msg(
                    ctx,
                    title=_("Unable to Get Track"),
                    description=_(
                        "I'm unable to get a track from Lavalink at the moment, "
                        "try again in a few minutes."
                    ),
                )
            except Exception as e:
                self.update_player_lock(ctx, False)
                raise e
            tracks = result.tracks
            playlist_data = result.playlist_info
            if not enqueue:
                return tracks
            if not tracks:
                self.update_player_lock(ctx, False)
                title = _("Nothing found.")
                embed = discord.Embed(title=title)
                if result.exception_message:
                    if "Status Code" in result.exception_message:
                        embed.set_footer(text=result.exception_message[:2000])
                    else:
                        embed.set_footer(text=result.exception_message[:2000].replace("\n", ""))
                if await self.config.use_external_lavalink() and query.is_local:
                    embed.description = _(
                        "Local tracks will not work "
                        "if the `Lavalink.jar` cannot see the track.\n"
                        "This may be due to permissions or because Lavalink.jar is being run "
                        "in a different machine than the local tracks."
                    )
                elif query.is_local and query.suffix in _PARTIALLY_SUPPORTED_MUSIC_EXT:
                    title = _("Track is not playable.")
                    embed = discord.Embed(title=title)
                    embed.description = _(
                        "**{suffix}** is not a fully supported format and some "
                        "tracks may not play."
                    ).format(suffix=query.suffix)
                return await self.send_embed_msg(ctx, embed=embed)
        else:
            tracks = query
        queue_dur = await self.queue_duration(ctx)
        queue_total_duration = self.format_time(queue_dur)
        before_queue_length = len(player.queue)

        if not first_track_only and len(tracks) > 1:
            # a list of Tracks where all should be enqueued
            # this is a Spotify playlist already made into a list of Tracks or a
            # url where Lavalink handles providing all Track objects to use, like a
            # YouTube or Soundcloud playlist
            if len(player.queue) >= 10000:
                return await self.send_embed_msg(ctx, title=_("Queue size limit reached."))
            track_len = 0
            empty_queue = not player.queue
            async for track in AsyncIter(tracks):
                if len(player.queue) >= 10000:
                    continue
                query = Query.process_input(track, self.local_folder_current_path)
                if not await self.is_query_allowed(
                    self.config,
                    ctx,
                    f"{track.title} {track.author} {track.uri} " f"{str(query)}",
                    query_obj=query,
                ):
                    if IS_DEBUG:
                        log.debug(f"Query is not allowed in {ctx.guild} ({ctx.guild.id})")
                    continue
                elif guild_data["maxlength"] > 0:
                    if self.is_track_length_allowed(track, guild_data["maxlength"]):
                        track_len += 1
                        track.extras.update(
                            {
                                "enqueue_time": int(time.time()),
                                "vc": player.channel.id,
                                "requester": ctx.author.id,
                            }
                        )
                        player.add(ctx.author, track)
                        self.bot.dispatch(
                            "red_audio_track_enqueue", player.channel.guild, track, ctx.author
                        )

                else:
                    track_len += 1
                    track.extras.update(
                        {
                            "enqueue_time": int(time.time()),
                            "vc": player.channel.id,
                            "requester": ctx.author.id,
                        }
                    )
                    player.add(ctx.author, track)
                    self.bot.dispatch(
                        "red_audio_track_enqueue", player.channel.guild, track, ctx.author
                    )
            player.maybe_shuffle(0 if empty_queue else 1)

            if len(tracks) > track_len:
                maxlength_msg = _(" {bad_tracks} tracks cannot be queued.").format(
                    bad_tracks=(len(tracks) - track_len)
                )
            else:
                maxlength_msg = ""
            playlist_name = escape(
                playlist_data.name if playlist_data else _("No Title"), formatting=True
            )
            embed = discord.Embed(
                description=bold(f"[{playlist_name}]({playlist_url})")
                if playlist_url
                else playlist_name,
                title=_("Playlist Enqueued"),
            )
            embed.set_footer(
                text=_("Added {num} tracks to the queue.{maxlength_msg}").format(
                    num=track_len, maxlength_msg=maxlength_msg
                )
            )
            if not guild_data["shuffle"] and queue_dur > 0:
                embed.set_footer(
                    text=_(
                        "{time} until start of playlist playback: starts at #{position} in queue"
                    ).format(time=queue_total_duration, position=before_queue_length + 1)
                )
            if not player.current:
                await player.play()
            self.update_player_lock(ctx, False)
            message = await self.send_embed_msg(ctx, embed=embed)
            return tracks or message
        else:
            single_track = None
            # a ytsearch: prefixed item where we only need the first Track returned
            # this is in the case of [p]play <query>, a single Spotify url/code
            # or this is a localtrack item
            try:
                if len(player.queue) >= 10000:
                    return await self.send_embed_msg(ctx, title=_("Queue size limit reached."))

                single_track = (
                    tracks
                    if isinstance(tracks, lavalink.rest_api.Track)
                    else tracks[index]
                    if index
                    else tracks[0]
                )
                if seek and seek > 0:
                    single_track.start_timestamp = seek * 1000
                query = Query.process_input(single_track, self.local_folder_current_path)
                if not await self.is_query_allowed(
                    self.config,
                    ctx,
                    (
                        f"{single_track.title} {single_track.author} {single_track.uri} "
                        f"{str(query)}"
                    ),
                    query_obj=query,
                ):
                    if IS_DEBUG:
                        log.debug(f"Query is not allowed in {ctx.guild} ({ctx.guild.id})")
                    self.update_player_lock(ctx, False)
                    return await self.send_embed_msg(
                        ctx, title=_("This track is not allowed in this server.")
                    )
                elif guild_data["maxlength"] > 0:
                    if self.is_track_length_allowed(single_track, guild_data["maxlength"]):
                        single_track.extras.update(
                            {
                                "enqueue_time": int(time.time()),
                                "vc": player.channel.id,
                                "requester": ctx.author.id,
                            }
                        )
                        player.add(ctx.author, single_track)
                        player.maybe_shuffle()
                        self.bot.dispatch(
                            "red_audio_track_enqueue",
                            player.channel.guild,
                            single_track,
                            ctx.author,
                        )
                    else:
                        self.update_player_lock(ctx, False)
                        return await self.send_embed_msg(
                            ctx, title=_("Track exceeds maximum length.")
                        )

                else:
                    single_track.extras.update(
                        {
                            "enqueue_time": int(time.time()),
                            "vc": player.channel.id,
                            "requester": ctx.author.id,
                        }
                    )
                    player.add(ctx.author, single_track)
                    player.maybe_shuffle()
                    self.bot.dispatch(
                        "red_audio_track_enqueue", player.channel.guild, single_track, ctx.author
                    )
            except IndexError:
                self.update_player_lock(ctx, False)
                title = _("Nothing found")
                desc = EmptyEmbed
                if await self.bot.is_owner(ctx.author):
                    desc = _("Please check your console or logs for details.")
                return await self.send_embed_msg(ctx, title=title, description=desc)
            except Exception as e:
                self.update_player_lock(ctx, False)
                raise e
            description = await self.get_track_description(
                single_track, self.local_folder_current_path
            )
            embed = discord.Embed(title=_("Track Enqueued"), description=description)
            if not guild_data["shuffle"] and queue_dur > 0:
                embed.set_footer(
                    text=_("{time} until track playback: #{position} in queue").format(
                        time=queue_total_duration, position=before_queue_length + 1
                    )
                )

        if not player.current:
            await player.play()
        self.update_player_lock(ctx, False)
        message = await self.send_embed_msg(ctx, embed=embed)
        return single_track or message