async def youtube_stream_task(self):
        """Check every 15 minutes if a YouTube channel is streaming live. If it is, send an announcement to the
         specified Discord channel."""

        # A standard Google API key has 10.000 units per day
        #   This task, with the minutes set to 10, costs approx. 14.832 units per day
        #   This task, with the minutes set to 15, costs approx. 9.888 units per day

        try:
            discord_channel = self.bot.democraciv_guild_object.get_channel(
                config.YOUTUBE_ANNOUNCEMENT_CHANNEL)
        except AttributeError:
            print(
                f'[BOT] ERROR - I could not find the Democraciv Discord Server! Change "DEMOCRACIV_GUILD_ID" '
                f'in the config to a server I am in or disable YouTube Stream announcements.'
            )
            raise exceptions.GuildNotFoundError(config.DEMOCRACIV_GUILD_ID)

        if discord_channel is None:
            print(
                "[BOT] ERROR - The YOUTUBE_ANNOUNCEMENT_CHANNEL id in config.py is not a channel on the"
                " specified Democraciv guild.")
            raise exceptions.ChannelNotFoundError(
                config.YOUTUBE_ANNOUNCEMENT_CHANNEL)

        stream_data = await self.get_live_broadcast()

        if stream_data is None:
            return

        video_data = stream_data["items"][0]

        _title = video_data['snippet']['title']
        _channel_title = video_data['snippet']['channelTitle']
        _description = video_data['snippet']['description']
        _thumbnail = video_data['snippet']['thumbnails']['high']['url']
        _video_url = f'https://youtube.com/watch?v={video_data["id"]}'

        embed = self.bot.embeds.embed_builder(
            title=
            f"{config.YOUTUBE_LOGO_STREAM}  {_channel_title} - Live on YouTube",
            description="",
            has_footer=False)
        embed.add_field(name="Title",
                        value=f"[{_title}]({_video_url})",
                        inline=False)
        embed.add_field(name="Description",
                        value=self.reduce_youtube_description(_description),
                        inline=False)

        if _thumbnail.startswith('https://'):
            embed.set_image(url=_thumbnail)

        if config.YOUTUBE_EVERYONE_PING_ON_STREAM:
            await discord_channel.send(
                f'@everyone {_channel_title} is live on YouTube!', embed=embed)
        else:
            await discord_channel.send(f'{_channel_title} is live on YouTube!',
                                       embed=embed)
def get_democraciv_channel(
        bot,
        channel: DemocracivChannel) -> typing.Optional[discord.TextChannel]:
    to_return = bot.democraciv_guild_object.get_channel(channel.value)

    if to_return is None:
        raise exceptions.ChannelNotFoundError(channel.name)

    return to_return
    async def twitch_task(self):
        """Checks every 30 seconds if a stream is live on Twitch. If it is and has not been announced yet, send
        announcement and mod/executive reminders to specified Discord channel."""

        try:
            channel = self.bot.democraciv_guild_object.get_channel(config.TWITCH_ANNOUNCEMENT_CHANNEL)
        except AttributeError:
            print(f'[BOT] ERROR - I could not find the Democraciv Discord Server! Change "DEMOCRACIV_GUILD_ID" '
                  f'in the config.py to a server I am in or disable Twitch announcements.')
            raise exceptions.GuildNotFoundError(config.DEMOCRACIV_GUILD_ID)

        if channel is None:
            print("[BOT] ERROR - The TWITCH_ANNOUNCEMENT_CHANNEL id in config.py is not a channel on the"
                  " specified Democraciv guild.")
            raise exceptions.ChannelNotFoundError(config.TWITCH_ANNOUNCEMENT_CHANNEL)

        twitch_data = await self.check_twitch_livestream()

        if twitch_data == self.StreamStatus.OFFLINE:
            return

        elif twitch_data == self.StreamStatus.LIVE_AND_ANNOUNCED:
            return

        elif twitch_data[0] == self.StreamStatus.LIVE_AND_NOT_ANNOUNCED:
            embed = self.bot.embeds.embed_builder(title=f"{config.TWITCH_LOGO}  {self.streamer} - "
                                                        f"Live on Twitch",
                                                  description="", has_footer=False, colour=0x984efc)
            embed.add_field(name="Title", value=twitch_data[2], inline=False)
            embed.add_field(name="Link", value=f"https://twitch.tv/{self.streamer}", inline=False)
            embed.set_image(url=twitch_data[3])

            if config.TWITCH_EVERYONE_PING_ON_ANNOUNCEMENT:
                await channel.send(f'@everyone {self.streamer} is live on Twitch!', embed=embed)
            else:
                await channel.send(f'{self.streamer} is live on Twitch!', embed=embed)

            if config.TWITCH_ANNOUNCEMENT_TO_REDDIT:
                data = {
                    "kind": "link",
                    "nsfw": False,
                    "sr": config.REDDIT_SUBREDDIT,
                    "title": f"{self.streamer} is live on Twitch: {twitch_data[2]}",
                    "spoiler": False,
                    "resubmit": True,
                    "url": f"https://twitch.tv/{self.streamer}"
                }

                await self.bot.reddit_api.post_to_reddit(data)

            # Send reminder about streaming rules to executive channel
            await self.streaming_rules_reminder()

            # Send reminder to moderation to export Twitch VOD
            await self.export_twitch_reminder()
    async def streaming_rules_reminder(self):
        executive_channel = mk.get_democraciv_channel(self.bot, mk.DemocracivChannel.EXECUTIVE_CHANNEL)

        try:
            minister_role = mk.get_democraciv_role(self.bot, mk.DemocracivRole.MINISTER_ROLE)
            governor_role = mk.get_democraciv_role(self.bot, mk.DemocracivRole.GOVERNOR_ROLE)
            executive_proxy_role = mk.get_democraciv_role(self.bot, mk.DemocracivRole.EXECUTIVE_PROXY_ROLE)
        except exceptions.RoleNotFoundError:
            minister_role = governor_role = executive_proxy_role = None

        if executive_channel is None:
            raise exceptions.ChannelNotFoundError("executive")

        embed = self.bot.embeds.embed_builder(title="Streaming Guidelines",
                                              description="Looks like you're starting another game session. "
                                                          "Remember these guidelines!")

        embed.add_field(name="Don't show the stream key",
                        value="Never show the stream key or the DMs with the "
                              "moderator that sent you the key on stream!",
                        inline=False)

        embed.add_field(name="Introduce yourself",
                        value="No one knows which voice belongs to whom! "
                              "Introduce yourself with your name and position.",
                        inline=False)

        embed.add_field(name="Keep it short",
                        value="In the past, streams often were too long. Keep the stream "
                              "short and don't waste time by starting the stream when not everyone "
                              "is ready or the game is not even started yet!",
                        inline=False)

        embed.add_field(name="Hand over the save-game",
                        value="Remember to send the save-game to one of "
                              "the moderators after the stream!",
                        inline=False)

        embed.set_thumbnail(url="https://cdn.discordapp.com/attachments/423938725525979146/"
                                "645394491133394966/01-twitch-logo.jpg")

        if minister_role is not None and governor_role is not None and executive_proxy_role is not None:
            await executive_channel.send(f"{minister_role.mention} {governor_role.mention} "
                                         f"{executive_proxy_role.mention}")

        await executive_channel.send(embed=embed)
Ejemplo n.º 5
0
    async def welcome(self, ctx):
        """Add a welcome message that every new member will see once they join this server"""

        is_welcome_enabled = await self.bot.checks.is_welcome_message_enabled(
            ctx.guild.id)
        current_welcome_channel = await utils.get_welcome_channel(
            self.bot, ctx.guild)
        current_welcome_message = await self.bot.db.fetchval(
            "SELECT welcome_message FROM guilds WHERE id = $1", ctx.guild.id)

        if current_welcome_channel is None:
            current_welcome_channel = "-"
        else:
            current_welcome_channel = current_welcome_channel.mention

        if not current_welcome_message:
            current_welcome_message = "-"
        elif len(current_welcome_message) > 1024:
            current_welcome_message = "*The welcome message is too long to fit in here.*"

        embed = self.bot.embeds.embed_builder(
            title=f":wave:  Welcome Messages on {ctx.guild.name}",
            description=
            f"React with the {config.GUILD_SETTINGS_GEAR} emoji to change"
            f" these settings.",
            has_footer=False)
        embed.add_field(name="Enabled",
                        value=self.emojiy_settings(is_welcome_enabled))
        embed.add_field(name="Welcome Channel", value=current_welcome_channel)
        embed.add_field(name="Welcome Message",
                        value=current_welcome_message,
                        inline=False)

        info_embed = await ctx.send(embed=embed)

        flow = Flow(self.bot, ctx)

        if await flow.gear_reaction_confirm(info_embed, 300):
            status_question = await ctx.send(
                "React with :white_check_mark: to enable welcome messages,"
                " or with :x: to disable welcome messages.")

            reaction = await flow.get_yes_no_reaction_confirm(
                status_question, 240)

            if reaction is None:
                return

            if reaction:
                await self.bot.db.execute(
                    "UPDATE guilds SET welcome = true WHERE id = $1",
                    ctx.guild.id)
                await ctx.send(":white_check_mark: Enabled welcome messages.")

                # Get new welcome channel
                await ctx.send(
                    ":information_source: Reply with the name of the welcome channel."
                )

                channel_object = await flow.get_new_channel(240)

                if isinstance(channel_object, str):
                    raise exceptions.ChannelNotFoundError(channel_object)

                status = await self.bot.db.execute(
                    "UPDATE guilds SET welcome_channel = $2 WHERE id = $1",
                    ctx.guild.id, channel_object.id)

                if status == "UPDATE 1":
                    await ctx.send(
                        f":white_check_mark: Set the welcome channel to {channel_object.mention}."
                    )

                # Get new welcome message
                await ctx.send(
                    f":information_source: Reply with the message that should be sent to {channel_object.mention} "
                    f"every time a new member joins.\n\nWrite `{{member}}` "
                    f"to make the Bot mention the user.")

                welcome_message = await flow.get_text_input(300)

                if welcome_message:
                    status = await self.bot.db.execute(
                        "UPDATE guilds SET welcome_message = $2 WHERE id = $1",
                        ctx.guild.id, welcome_message)

                    if status == "UPDATE 1":
                        await ctx.send(
                            f":white_check_mark: Welcome message was set.")

            elif not reaction:
                await self.bot.db.execute(
                    "UPDATE guilds SET welcome = false WHERE id = $1",
                    ctx.guild.id)
                await ctx.send(
                    ":white_check_mark: Welcome messages were disabled.")

            await self.bot.cache.update_guild_config_cache()
Ejemplo n.º 6
0
    async def exclude(self, ctx, channel: str = None):
        """Exclude message edits & deletions in a channel from showing up in your server's log channel


            **Usage:**
                `-server exclude` to see all excluded channels
                `-server exclude <channel>` to add/remove a channel to/from the excluded channels list
        """
        current_logging_channel = await utils.get_logging_channel(
            self.bot, ctx.guild)

        if current_logging_channel is None:
            return await ctx.send(
                ":x: This server currently has no logging channel."
                " Please set one with `-server logs`.")

        help_description = "Add or remove a channel to the excluded channels with:\n`-server exclude [channel_name]`\n"

        excluded_channels = await self.bot.db.fetchval(
            "SELECT logging_excluded FROM guilds WHERE id = $1", ctx.guild.id)
        if not channel:
            current_excluded_channels_by_name = []

            if excluded_channels is None:
                return await ctx.send(
                    "There are no from logging excluded channels on this server."
                )

            for channel in excluded_channels:
                channel = self.bot.get_channel(channel)
                if channel is not None:
                    current_excluded_channels_by_name.append(channel.mention)

            if not current_excluded_channels_by_name:
                current_excluded_channels_by_name = "There are no from logging excluded channels on this server."
            else:
                current_excluded_channels_by_name = '\n'.join(
                    current_excluded_channels_by_name)

            embed = self.bot.embeds.embed_builder(
                title=f"Logging-Excluded Channels on {ctx.guild.name}",
                description=help_description,
                has_footer=False)
            embed.add_field(name="Excluded Channels",
                            value=current_excluded_channels_by_name)
            return await ctx.send(embed=embed)

        else:
            try:
                channel_object = await commands.TextChannelConverter().convert(
                    ctx, channel)
            except commands.BadArgument:
                raise exceptions.ChannelNotFoundError(channel)

            if not channel_object:
                raise exceptions.ChannelNotFoundError(channel)

            # Remove channel
            if channel_object.id in excluded_channels:
                remove_status = await self.bot.db.execute(
                    "UPDATE guilds SET logging_excluded = array_remove(logging_excluded, $2 ) WHERE id = $1",
                    ctx.guild.id, channel_object.id)

                if remove_status == "UPDATE 1":
                    await self.bot.cache.update_guild_config_cache()
                    return await ctx.send(
                        f":white_check_mark: {channel_object.mention} is no longer excluded from"
                        f" showing up in {current_logging_channel.mention}.")

            # Add channel
            add_status = await self.bot.db.execute(
                "UPDATE guilds SET logging_excluded = array_append(logging_excluded,"
                " $2) WHERE id = $1", ctx.guild.id, channel_object.id)

            if add_status == "UPDATE 1":
                await ctx.send(
                    f":white_check_mark: Excluded channel {channel_object.mention} from showing up in "
                    f"{current_logging_channel.mention}.")
                await self.bot.cache.update_guild_config_cache()
Ejemplo n.º 7
0
    async def logs(self, ctx):
        """Log important events like message edits & deletions and more to a specific channel"""

        is_logging_enabled = await self.bot.checks.is_logging_enabled(
            ctx.guild.id)
        current_logging_channel = await utils.get_logging_channel(
            self.bot, ctx.guild)

        if current_logging_channel is None:
            current_logging_channel = "-"
        else:
            current_logging_channel = current_logging_channel.mention

        embed = self.bot.embeds.embed_builder(
            title=f":spy:  Event Logging on {ctx.guild.name}",
            description=f"React with the {config.GUILD_SETTINGS_GEAR} emoji "
            f"to change these settings.",
            has_footer=False)

        embed.add_field(name="Enabled",
                        value=self.emojiy_settings(is_logging_enabled))
        embed.add_field(name="Log Channel", value=current_logging_channel)

        info_embed = await ctx.send(embed=embed)

        flow = Flow(self.bot, ctx)

        if await flow.gear_reaction_confirm(info_embed, 300):

            status_question = await ctx.send(
                "React with :white_check_mark: to enable logging, "
                "or with :x: to disable logging.")

            reaction = await flow.get_yes_no_reaction_confirm(
                status_question, 240)

            if reaction is None:
                return

            if reaction:
                await self.bot.db.execute(
                    "UPDATE guilds SET logging = true WHERE id = $1",
                    ctx.guild.id)
                await ctx.send(":white_check_mark: Event logging was enabled.")
                await ctx.send(
                    ":information_source: Reply with the name of the channel"
                    " that I should use to log all events to.")

                channel_object = await flow.get_new_channel(240)

                if isinstance(channel_object, str):
                    raise exceptions.ChannelNotFoundError(channel_object)

                status = await self.bot.db.execute(
                    "UPDATE guilds SET logging_channel = $2 WHERE id = $1",
                    ctx.guild.id, channel_object.id)

                if status == "UPDATE 1":
                    await ctx.send(
                        f":white_check_mark: Set the logging channel to {channel_object.mention}."
                    )

            elif not reaction:
                await self.bot.db.execute(
                    "UPDATE guilds SET logging = false WHERE id = $1",
                    ctx.guild.id)
                await ctx.send(":white_check_mark: Event logging was disabled."
                               )

            await self.bot.cache.update_guild_config_cache()
    async def youtube_upload_tasks(self):
        """Check every 10 minutes if the 3 last uploads of a YouTube channel are new. If at least one is,
         send an announcement to the specified Discord channel."""

        # A standard Google API key has 10.000 units per day
        #   This task, with the minutes set to 10, costs approx. 2160 units per day

        try:
            discord_channel = self.bot.democraciv_guild_object.get_channel(
                config.YOUTUBE_ANNOUNCEMENT_CHANNEL)
        except AttributeError:
            print(
                f'[BOT] ERROR - I could not find the Democraciv Discord Server! Change "DEMOCRACIV_GUILD_ID" '
                f'in the config to a server I am in or disable YouTube Upload announcements.'
            )
            raise exceptions.GuildNotFoundError(config.DEMOCRACIV_GUILD_ID)

        if discord_channel is None:
            print(
                "[BOT] ERROR - The YOUTUBE_ANNOUNCEMENT_CHANNEL id in config.py is not a channel on the"
                " specified Democraciv guild.")
            raise exceptions.ChannelNotFoundError(
                config.YOUTUBE_ANNOUNCEMENT_CHANNEL)

        youtube_data = await self.get_newest_upload()

        if youtube_data is None:
            return

        # Each check last 3 uploads in case we missed some in between
        for i in range(3):
            youtube_video = youtube_data["items"][i]

            _id = youtube_video["snippet"]["resourceId"]["videoId"]

            # Try to add post id to database
            status = await self.bot.db.execute(
                "INSERT INTO youtube_uploads (id) VALUES ($1) ON CONFLICT DO NOTHING",
                _id)

            # ID already in database -> post already seen
            if status == "INSERT 0 0":
                continue

            title = youtube_video['snippet']['title']
            channel = youtube_video['snippet']['channelTitle']
            description = youtube_video['snippet']['description']
            thumbnail_url = youtube_video['snippet']['thumbnails']['high'][
                'url']
            video_link = f"https://youtube.com/watch?v={_id}"

            if config.YOUTUBE_VIDEO_UPLOADS_TO_REDDIT:
                data = {
                    "kind": "link",
                    "nsfw": False,
                    "sr": config.REDDIT_SUBREDDIT,
                    "title": title,
                    "spoiler": False,
                    "url": video_link
                }

                await self.bot.reddit_api.post_to_reddit(data)

            embed = self.bot.embeds.embed_builder(
                title=
                f"{config.YOUTUBE_LOGO_UPLOAD}  {channel} - New YouTube video uploaded",
                description="",
                has_footer=False,
                colour=0xff001b)
            embed.add_field(name="Title",
                            value=f"[{title}]({video_link})",
                            inline=False)
            embed.add_field(name="Description",
                            value=self.reduce_youtube_description(description),
                            inline=False)
            embed.set_image(url=thumbnail_url)

            await discord_channel.send(embed=embed)
    async def reddit_task(self):
        """Checks every 60 seconds if the 5 newest reddit posts of a subreddit are new. If at least one is, send
        announcement to the specified Discord channel."""

        try:
            channel = self.bot.democraciv_guild_object.get_channel(
                config.REDDIT_ANNOUNCEMENT_CHANNEL)
        except AttributeError:
            print(
                f'[BOT] ERROR - I could not find the Democraciv Discord Server! Change "DEMOCRACIV_GUILD_ID" '
                f'in config.py to a server I am in or disable Reddit announcements.'
            )
            raise exceptions.GuildNotFoundError(config.DEMOCRACIV_GUILD_ID)

        if channel is None:
            print(
                "[BOT] ERROR - The REDDIT_ANNOUNCEMENT_CHANNEL id in config.py is not a channel on the"
                " specified Democraciv guild.")
            raise exceptions.ChannelNotFoundError(
                config.REDDIT_ANNOUNCEMENT_CHANNEL)

        reddit_post_json = await self.get_newest_reddit_post()

        if reddit_post_json is None:
            return

        # Each check last 5 reddit posts in case we missed some in between
        for i in range(5):
            reddit_post = reddit_post_json["data"]["children"][i]["data"]

            _id = reddit_post['id']

            # Try to add post id to database
            status = await self.bot.db.execute(
                "INSERT INTO reddit_posts (id) VALUES ($1) ON CONFLICT DO NOTHING",
                _id)

            # ID already in database -> post already seen
            if status == "INSERT 0 0":
                continue

            _title = reddit_post['title']
            _author = f"u/{reddit_post['author']}"
            _comments_link = f"https://reddit.com{reddit_post['permalink']}"

            try:
                _thumbnail_url = reddit_post['preview']['images'][0]['source'][
                    'url']
            except KeyError:
                _thumbnail_url = reddit_post['thumbnail']

            embed = self.bot.embeds.embed_builder(
                title=f"{config.REDDIT_LOGO}  New post on r/{self.subreddit}",
                description="",
                has_footer=False,
                colour=0xff2d1c)
            embed.add_field(name="Thread",
                            value=f"[{_title}]({_comments_link})",
                            inline=False)
            embed.add_field(name="Author", value=f"{_author}", inline=False)

            if _thumbnail_url.startswith("https://"):
                _thumbnail_url = html.unescape(_thumbnail_url)
                embed.set_thumbnail(url=_thumbnail_url)

            await channel.send(embed=embed)