Exemple #1
0
 async def on_guild_join(self, guild: Guild):
     """Send welcome message on guild join"""
     channel = None
     if guild.system_channel is not None:
         channel: TextChannel = guild.system_channel  # Try to use system message channel
     else:
         y = find(
             lambda x: x.name == "general", guild.text_channels
         )  # if that doesn't exist, try to find a 'general' channel
         if y:
             channel: TextChannel = y
     if channel is not None:
         embed = StyledEmbed(
             title="Welcome to chime",
             description=
             ":wave: Thanks for having me!\n\nchime is a versatile, yet intuitive music bot for discord. It aims to have the best performance while being as user-friendly as possible. \n\n"
             "chime sports a **webinterface where you can manage settings for your server and create and manage personal playlists.** [Check it out here](https://chime.realmayus.xyz).  \n"
             "With using chime you agree to our **[Terms of Service](https://chime.realmayus.xyz/terms)** and our **[Privacy Policy](https://chime.realmayus.xyz/privacy)**.\n"
             "**More info and invite link [here](https://chime.realmayus.xyz)**\n\n**See all available commands with** `"
             + prefix + "help`")
         embed.set_image(
             url=
             "https://raw.githubusercontent.com/realmayus/chime/master/assets/chime_banner.png?token=AJC6B5VTHEZ5UHNY7QNDCU263LCCK"
         )
         await channel.send(embed=embed)
Exemple #2
0
    def get(self) -> Embed:
        embed = StyledEmbed(title="Search results (Page " +
                            str(self.current_page + 1) + ")")

        description, count = get_song_selector_embed_desc_for_current_page(
            self.current_page, self.results)
        self.count = count
        embed.description = description
        return embed
Exemple #3
0
        async def success_callback_url(tracks):
            if not player.is_connected:
                await ctx.invoke(self.join)  # Join channel if not connected

            if isinstance(tracks, TrackPlaylist):
                tracks = tracks.tracks
                await ctx.send(embed=StyledEmbed(description=f"**Added** {len(tracks)} **tracks to queue.**"))
            else:
                try:
                    await ctx.send(embed=StyledEmbed(description=f"**Added** {tracks[0]} **to queue.**"))
                except TypeError:
                    raise BadRequestException("Couldn't add this item to the queue!")
            for track in tracks:
                self.get_controller(ctx).queue.append(track)
Exemple #4
0
 async def handle_timeout(self):
     await self.last_msg.clear_reactions()
     expired_embed = StyledEmbed(
         title="Expired",
         description=
         "This song selector has expired because no one selected a song.")
     await self.last_msg.edit(embed=expired_embed, delete_after=15.0)
Exemple #5
0
 async def success_callback(track_, last_msg: Message):
     await last_msg.clear_reactions()
     await last_msg.edit(embed=StyledEmbed(
         description=
         f"**Added** {track_} **to playlist {playlist}.**"),
                         delete_after=10.0)
     tracks_to_add.append(track_)
Exemple #6
0
 async def pause(self, ctx):
     """Pauses the current track"""
     player = self.bot.wavelink.get_player(ctx.guild.id)
     if player.is_playing and not player.is_paused:
         await player.set_pause(True)
         await ctx.send(embed=StyledEmbed(description=f"Stopped song! Use `{prefix}resume` to resume it."),
                        delete_after=20.0)
     else:
         raise BadRequestException("I am currently not playing any track!")
Exemple #7
0
 async def playlists(self, ctx: Context):
     """Shows a list of all your playlists. Alias of `""" + prefix + """playlist list`"""
     playlists = self.database.get_all_playlists(ctx.author.id)
     await ctx.send(embed=StyledEmbed(
         title="Your playlists",
         description=
         f"use the `{prefix}playlist` commands for adding songs to a playlist, creating playlists, viewing the playlist's contents etc. \n\n"
         +
         "\n".join([f"•  **{playlist['name']}**"
                    for playlist in playlists])))
Exemple #8
0
 async def success_callback_url(tracks):
     nonlocal tracks_to_add
     if isinstance(tracks, TrackPlaylist):
         tracks = tracks.tracks
         await ctx.send(embed=StyledEmbed(
             description=
             f"**Added** {len(tracks)} **tracks to playlist {playlist}.**"
         ),
                        delete_after=10.0)
     else:
         try:
             await ctx.send(embed=StyledEmbed(
                 description=
                 f"**Added** {tracks[0]} **to playlist {playlist}.**"
             ),
                            delete_after=10.0)
         except TypeError:
             raise BadRequestException(
                 "Couldn't add this item to the queue!")
     tracks_to_add = tracks
Exemple #9
0
    def get(self) -> Embed:
        embed = StyledEmbed(
            suppress_tips=True,
            title=self.title + " (Page " + str(self.current_page + 1) + "/" +
            str(math.ceil(len(self.contents) / self.show_per_page)) + ")")

        desc = ""
        count = 1
        for track_index in range(len(self.contents)):
            try:
                track = self.contents[self.current_page * self.show_per_page +
                                      track_index]
                if count == self.show_per_page + 1:
                    break
                desc += str(track) + "\n"
                count += 1
            except IndexError:
                pass
        self.count = count
        embed.description = desc
        return embed
Exemple #10
0
 async def on_voice_state_update(self, member: Member, before: VoiceState, after: VoiceState):
     player: Player = self.bot.wavelink.get_player(member.guild.id)
     controller: MusicController = self.get_controller(player)
     if not before.channel:
         return
     if before.channel.id == player.channel_id:
         """It's actually the bot's channel!"""
         if not after.channel or after.channel != before.channel:
             """Member has left or switched the channel"""
             channel: VoiceChannel = before.channel
             if len(channel.members) <= 1:
                 embed = StyledEmbed(suppress_tips=True, description="**I left the channel due to inactivity.**")
                 await controller.channel.send(embed=embed)
                 if controller.now_playing_msg:
                     await controller.now_playing_msg.delete()
                 try:
                     controller.task.cancel()
                     del self.bot.controllers[member.guild.id]
                     del controller
                 except Exception as e:
                     print(e)
                 await player.stop()
                 await player.disconnect()
Exemple #11
0
    async def send_bot_help(self, mapping):
        embed = StyledEmbed(title='chime help')
        embed.set_thumbnail(url="https://raw.githubusercontent.com/realmayus/chime/master/assets/chime_banner.png?token=AJC6B5VTHEZ5UHNY7QNDCU263LCCK")
        embed.description = "chime is a versatile, yet intuitive music bot for discord. It aims to be as user-friendly as possible while still boasting many features. \n\n" \
                            "**More info and invite link [here](https://chime.realmayus.xyz)** \n\n" \
                            "Chime has a **web app** where you can manage and set up personal playlists and manage settings of your servers! https://chime.realmayus.xyz \n\n" \
                            "**Use** `" + self.clean_prefix + "help [command]` **for more info on a command.**"
        for cog, commands in mapping.items():
            if cog is not None:  # We don't want commands without categories! >:c
                name = cog.qualified_name
                filtered = await self.filter_commands(commands, sort=True)
                if filtered:
                    builder = []
                    for command in commands:  # filtering out hidden commands
                        command: Command
                        builder.append(f"`{prefix + command.name}`" if not command.hidden else "")
                    value = '  '.join(builder)
                    if cog and cog.description:
                        value = '{0}\n{1}'.format(cog.description, value)

                    embed.add_field(name=name, value=value)

        await self.get_destination().send(embed=embed)
Exemple #12
0
    async def on_command_error(self, ctx, error):
        """A local error handler for all errors arising from commands in this cog."""
        if isinstance(error, commands.NoPrivateMessage):
            try:
                return await ctx.send(embed=StyledEmbed(
                    description=
                    "<:warning:746377344393936997>  This command can't be executed in DMs.'"
                ))
            except discord.HTTPException:
                pass
        elif isinstance(
                error,
                discord.ext.commands.errors.CommandInvokeError) and isinstance(
                    error.original,
                    chime.misc.BadRequestException.BadRequestException):
            return await ctx.send(embed=StyledEmbed(
                description='<:warning:746377344393936997>  ' +
                str(error.original.text)))
        elif isinstance(error,
                        discord.ext.commands.errors.MissingRequiredArgument):
            return await ctx.send(embed=StyledEmbed(
                description='<:warning:746377344393936997>  ' + str(error)))
        elif isinstance(error, discord.ext.commands.errors.BadArgument):
            return await ctx.send(embed=StyledEmbed(
                description='<:warning:746377344393936997>  ' + str(error)))
        elif isinstance(error, discord.ext.commands.errors.CommandOnCooldown):
            return await ctx.send(embed=StyledEmbed(
                description='<:warning:746377344393936997>  ' + str(error)))
        elif isinstance(error, discord.ext.commands.errors.CommandNotFound):
            return
        elif isinstance(
                error,
                discord.ext.commands.errors.CommandInvokeError) and isinstance(
                    error.original, wavelink.errors.ZeroConnectedNodes):
            report_channel_ = await self.bot.fetch_channel(report_channel)
            error_embed = StyledEmbed(
                suppress_tips=True,
                title="<:warning:746377344393936997>  Outage Report")
            error_embed.description = "Chime detected an outage:\n\n" + "```" + '\n'.join(
                [
                    line.strip('\n') for line in traceback.format_exception(
                        type(error), error, error.__traceback__, limit=1)
                ]) + "```"
            error_embed.set_author(name="Automatic Outage Report")
            await report_channel_.send("<@&718113149651255386>",
                                       embed=error_embed)
            return await ctx.send(embed=StyledEmbed(
                description=
                '<:warning:746377344393936997>  A critical outage has been detected and the developers **have been notified**. Sorry! You can get support here: \nhttps://discord.gg/DGd8T53'
            ))

        try:
            await ctx.send(embed=StyledEmbed(
                description=
                "<:warning:746377344393936997> Sorry, an unknown error occurred whilst executing this command. The error has been reported automatically. You can get support here: \nhttps://discord.gg/DGd8T53"
            ))
        except:
            pass

        print('Ignoring exception in command {}:'.format(ctx.command),
              file=sys.stderr)
        traceback.print_exception(type(error),
                                  error,
                                  error.__traceback__,
                                  file=sys.stderr)

        channel = await self.bot.fetch_channel(report_channel)
        error_embed = StyledEmbed(
            suppress_tips=True,
            title=f"<:warning:746377344393936997>  `{type(error)}`")
        error_embed.set_author(name="Unhandled Error")

        # upload to hastebin
        key = json.loads(
            requests.post('https://hasteb.in/documents',
                          data='Ignoring Exception in command ' +
                          str(ctx.command) + ":\n\n" + '\n'.join([
                              line.strip('\n')
                              for line in traceback.format_exception(
                                  type(error), error, error.__traceback__)
                          ])).text)["key"]

        # send to auto-reports channel in chime lounge
        error_embed.description = f"chime witnessed an [unhandled exception](https://hasteb.in/{key}) whilst executing command `{ctx.command}`:\n\n```" + '\n'.join(
            [
                line.strip('\n') for line in traceback.format_exception(
                    type(error), error, error.__traceback__, limit=1)
            ]) + "```"

        await channel.send(embed=error_embed)
Exemple #13
0
    async def send_group_help(self, group: CustomCommand):
        embed = StyledEmbed(title='`' + group.qualified_name + '`')
        desc = ""
        if group.help:
            desc += group.help

        if group.usage:
            embed.add_field(name="**Usage**", value=f"`{prefix + group.usage}`", inline=False)

        if group.aliases and len(group.aliases) > 0:
            embed.add_field(name="**Aliases**", value=' '.join([f"`{prefix + alias}`" for alias in group.aliases]), inline=False)


        if hasattr(group, "available_args") and group.available_args:
            arg_builder = ""
            for typ in group.available_args:
                arg_builder += f"\n**{typ['type']}**"
                for arg in typ['args']:
                    arg_builder += f"\n`{arg['name']}`\n***{arg['desc']}***"
            embed.add_field(name="**Arguments**", value=arg_builder)

        if hasattr(group, "examples") and group.examples:
            example_builder = ""
            for ex in group.examples:
                example_builder += f"\n`{ex['ex']}`\n{ex['desc']}"
            embed.add_field(name="**Examples**", value=example_builder)

        embed.description = desc

        await self.get_destination().send(embed=embed)
Exemple #14
0
    async def playlist(self,
                       ctx: Context,
                       action: str,
                       playlist: str = None,
                       *,
                       additional_args=None):
        """Manage all your personal playlists. You can also manage them on [chime's web app](https://chime.realmayus.xyz)"""
        if action == "create":
            if not additional_args:  # if the playlist name contained spaces, the individual parts would be in additional_args
                self.database.create_playlist(ctx.author.id, playlist)
                await ctx.message.add_reaction("<:ok:746377326245445653>")
            else:
                raise BadRequestException(
                    "If you want spaces in your playlist's name, you have to wrap it in quotation marks!"
                )

        elif action == "show" or action == "view":
            if playlist is not None:
                contents = self.database.get_playlist_contents(
                    ctx.author.id, playlist)
                if len(contents) == 0:
                    raise BadRequestException("Playlist is empty!")

                embed = PagedListEmbed(f"Contents of `{playlist}`", [
                    f"{i + 1}.  {song['title']}"
                    for i, song in enumerate(contents)
                ], ctx, self.bot)
                await embed.send(embed.get())
            else:
                raise BadRequestException("Please enter a playlist name!")

        elif action == "play":
            if playlist is not None:
                contents = self.database.get_playlist_contents(
                    ctx.author.id, playlist)
                await self.join_channel(ctx)
                if len(contents) == 0:
                    raise BadRequestException("Playlist is empty!")

                index = 0
                failed = 0
                for index, song_data_raw in enumerate(contents):
                    try:
                        track = await self.bot.wavelink.build_track(
                            song_data_raw["data"])
                        controller = self.get_controller(ctx)
                        controller.queue.append(track)
                    except BuildTrackError:
                        failed += 1
                        print("Failed to reconstruct track with data " +
                              song_data_raw["data"])
                await ctx.send(embed=StyledEmbed(
                    description=f"**Added** {index + 1} **tracks to queue**."))
                if failed > 0:
                    raise BadRequestException(
                        f"**Failed to add** {failed} **track(s)**!")
            else:
                raise BadRequestException("Please enter a playlist name!")

        elif action == "list":
            await ctx.invoke(self.playlists)

        elif action == "add":
            tracks_to_add = []
            if playlist is None:
                raise BadRequestException("Please enter a playlist name!")

            async def success_callback(track_, last_msg: Message):
                await last_msg.clear_reactions()
                await last_msg.edit(embed=StyledEmbed(
                    description=
                    f"**Added** {track_} **to playlist {playlist}.**"),
                                    delete_after=10.0)
                tracks_to_add.append(track_)

            async def success_callback_url(tracks):
                nonlocal tracks_to_add
                if isinstance(tracks, TrackPlaylist):
                    tracks = tracks.tracks
                    await ctx.send(embed=StyledEmbed(
                        description=
                        f"**Added** {len(tracks)} **tracks to playlist {playlist}.**"
                    ),
                                   delete_after=10.0)
                else:
                    try:
                        await ctx.send(embed=StyledEmbed(
                            description=
                            f"**Added** {tracks[0]} **to playlist {playlist}.**"
                        ),
                                       delete_after=10.0)
                    except TypeError:
                        raise BadRequestException(
                            "Couldn't add this item to the queue!")
                tracks_to_add = tracks

            if not additional_args:
                raise BadRequestException(
                    "You have to provide either a search term or a URL!")

            await search_song(additional_args, ctx, self.bot, success_callback,
                              success_callback_url)

            if len(tracks_to_add) > 0:
                self.database.add_to_playlist(ctx.author.id, playlist,
                                              tracks_to_add)
                await ctx.message.add_reaction("<:ok:746377326245445653>")
            else:
                raise BadRequestException("No track selected!")
        elif action == "share":
            if playlist is None:
                raise BadRequestException("Please enter a playlist name!")
            playlist_id = self.database.raise_if_not_exists(
                ctx.author.id, playlist)
            message = f"{ctx.author.id}:{playlist_id}:{playlist}:{ctx.author.name}"
            message_bytes = message.encode("utf8")
            base64_bytes = base64.b64encode(message_bytes)
            base64_message = base64_bytes.decode("ascii")
            await ctx.send(embed=StyledEmbed(
                title="Share this link",
                description=f"https://chime.realmayus.xyz/view/{base64_message}"
            ))
        elif action == "delete":
            raise BadRequestException(
                "This feature has not been implemented yet.")
        else:
            raise BadRequestException(
                "This action does not exist. Valid actions are: `create`, `list`, `add`, `show`, `play`, `delete` and `share`."
            )
Exemple #15
0
def get_currently_playing_embed(current_track: Track, current_time=None):
    currently_playing_embed = StyledEmbed(
        title="<:music_note:718120922367787099>  " + current_track.title)
    currently_playing_embed.set_author(name="Now playing",
                                       url=current_track.uri)

    if current_time:
        currently_playing_embed.description = get_song_progress_bar(
            current_time, current_track.duration)

    currently_playing_embed.add_field(name="Duration",
                                      value=get_friendly_time_delta(
                                          current_track.duration))
    currently_playing_embed.add_field(name="Artist",
                                      value=current_track.author)
    if current_track.thumb is not None:
        currently_playing_embed.set_thumbnail(url=current_track.thumb)
    return currently_playing_embed
Exemple #16
0
    async def stats(self, ctx):
        """Shows useful information about the current node your chime player is connected to. Useful for troubleshooting."""
        player = self.bot.wavelink.get_player(ctx.guild.id)
        node = player.node

        embed = StyledEmbed(title="chime stats")
        embed.description = f'Connected to {len(self.bot.wavelink.nodes)} node(s).\n' \
                            f'Best available node: **{self.bot.wavelink.get_best_node().__repr__()}**\n'
        embed.add_field(name="Stream count",
                        value=f"{str(node.stats.playing_players)}")
        embed.add_field(name="Server Count", value=f"{len(self.bot.guilds)}")
        embed.add_field(
            name="Lavalink uptime",
            value=
            f"{str(datetime.timedelta(seconds=round(node.stats.uptime / 1000)))}"
        )

        current_time = time.time()
        difference = int(round(current_time - self.bot.start_time))
        timestamp = str(datetime.timedelta(seconds=difference))
        embed.add_field(name="Bot uptime", value=f"{timestamp}")
        await ctx.send(embed=embed)
Exemple #17
0
 async def success_callback(track_, last_msg: Message):
     await last_msg.clear_reactions()
     await last_msg.edit(embed=StyledEmbed(description=f"**Added** {track_} **to queue.**"), delete_after=10.0)
     if not player.is_connected:
         await ctx.invoke(self.join)  # Join channel if not connected
     self.get_controller(ctx).queue.append(track_)
Exemple #18
0
    async def feedback(self, ctx):
        """Gives you options to send feedback or to report bugs."""
        msg: Message = await ctx.send(embed=StyledEmbed(
            title="Feedback",
            description=
            "Thanks for helping to improve chime! What's the problem? \n \n "
            u"1\N{variation selector-16}\N{combining enclosing keycap}" +
            "  I'd like to send feedback\n"
            u"2\N{variation selector-16}\N{combining enclosing keycap}" +
            "  I'd like to report an outage\n"
            u"3\N{variation selector-16}\N{combining enclosing keycap}" +
            "  I'd like to report a bug\n"))
        [
            await msg.add_reaction(
                u"%s\N{variation selector-16}\N{combining enclosing keycap}" %
                str(x + 1)) for x in range(3)
        ]

        def check_reaction(reaction: RawReactionActionEvent):
            return reaction.member == ctx.author and isinstance(
                reaction.emoji.name,
                str) and ((reaction.emoji.name[0].isdigit()
                           and int(str(reaction.emoji.name)[0]) in range(4))
                          and reaction.message_id == msg.id)

        try:
            reaction: RawReactionActionEvent = await self.bot.wait_for(
                'raw_reaction_add', timeout=20.0, check=check_reaction)
        except asyncio.TimeoutError:
            """Handle Timeout"""
        else:
            if str(reaction.emoji.name[0]).isdigit() and int(
                    str(reaction.emoji.name)[0]) in range(4):
                selected_number = int(str(reaction.emoji.name[0]))
                what_to_do = None
                if selected_number == 1:
                    what_to_do = "Send Feedback"
                elif selected_number == 2:
                    what_to_do = "Report Outage"
                elif selected_number == 3:
                    what_to_do = "Report Bug"

                if selected_number == 2 or selected_number == 3:
                    await msg.edit(embed=StyledEmbed(
                        title=what_to_do,
                        description=
                        "Got it. Please describe the issue as precise as possible in your next message. Bonus points for steps to reproduce. Send `stop` to abort"
                    ))
                    await msg.clear_reactions()

                else:
                    await msg.edit(embed=StyledEmbed(
                        title=what_to_do,
                        description=
                        "Got it. Please describe your feedback in the next message you send. Send `stop` to abort"
                    ))
                    await msg.clear_reactions()

                try:
                    description: Message = await self.bot.wait_for(
                        'message',
                        timeout=60.0,
                        check=lambda m: m.channel == ctx.channel and m.author
                        == ctx.author)
                except asyncio.TimeoutError:
                    await ctx.channel.send(
                        "Aborting feedback wizard because no answer was sent.")
                else:

                    if description.content == "stop":
                        await ctx.send("Ok.")
                        return

                    if selected_number == 2 or selected_number == 3:
                        if selected_number == 2:
                            """Urgent issue"""
                            captcha_solved = False
                            while not captcha_solved:
                                solution, file = self.get_captcha_file()
                                embed: StyledEmbed = StyledEmbed(
                                    title="Please solve the captcha.",
                                    description=
                                    "Not case sensitive. To quit, enter `stop`, for a new captcha enter `new`"
                                )
                                await ctx.send(file=file, embed=embed)
                                try:
                                    captcha_sol: Message = await self.bot.wait_for(
                                        'message',
                                        timeout=30.0,
                                        check=lambda ms: ms.channel == ctx.
                                        channel and ms.author == ctx.author)
                                    captcha_sol: str = captcha_sol.content
                                except asyncio.TimeoutError:
                                    await ctx.channel.send(
                                        "Aborting feedback wizard because no captcha answer was sent."
                                    )
                                else:
                                    if captcha_sol.lower() == "stop":
                                        await ctx.send("Ok.")
                                        return

                                    if captcha_sol.lower().replace(
                                            "o",
                                            "0").replace("7", "1").replace(
                                                "8", "b") == solution.lower(
                                                ).replace("o", "0").replace(
                                                    "7",
                                                    "1").replace("8", "b"):
                                        captcha_solved = True

                            report_channel_ = await self.bot.fetch_channel(
                                report_channel)
                            error_embed = StyledEmbed(
                                suppress_tips=True,
                                title=f"👥  Outage Report")
                            error_embed.description = "A user has submitted an outage report:\n\n" + description.content
                            error_embed.set_author(name="User Report")
                            await report_channel_.send(
                                "<@&718113149651255386>", embed=error_embed)
                            await ctx.channel.send(
                                "Thanks for the report and for making chime better! A developer will look into the issue as soon as possible."
                            )
                        elif selected_number == 3:
                            report_channel_ = await self.bot.fetch_channel(
                                report_channel)
                            error_embed = StyledEmbed(
                                suppress_tips=True, title=f"👥  Bug Report")
                            error_embed.description = "A user has submitted a bug report:\n\n" + description.content
                            error_embed.set_author(name="User Report")
                            await report_channel_.send(embed=error_embed)
                            await ctx.channel.send(
                                "Thanks for the report and for making chime better! A developer will look into the issue"
                                + ("." if selected_number ==
                                   3 else " as soon as possible."))

                    elif selected_number == 1:
                        report_channel_ = await self.bot.fetch_channel(
                            report_channel)
                        error_embed = StyledEmbed(suppress_tips=True,
                                                  title=f"👥  Feedback")
                        error_embed.description = "A user has submitted feedback:\n\n" + description.content
                        error_embed.set_author(name="User Feedback")
                        await report_channel_.send(embed=error_embed)
                        await ctx.channel.send(
                            "Thanks for the report and for making chime better! The feedback was sent to the developers."
                        )