Ejemplo n.º 1
0
    async def announce_time(self, msg, time: int = None):
        try:
            # Make sure we receive a positive number
            if int(time) < 1:
                raise ValueError

            self.delay = int(time)

            updated = session.query(Settings).filter(Settings.key == "announcement_delay").update({"value": self.delay})

            if not updated:
                # Insert if it wasn't updated, because it didn't exist.
                insert = Settings(key="announcement_delay", value=self.delay)
                session.add(insert)

            session.commit()

            self.restart_task()
            await msg.reply(f"{bot.msg_prefix}New announce time is {time} seconds")
        except ValueError:
            await msg.reply(f"{bot.msg_prefix}Invalid time, please use an integer in seconds")
        except TypeError:
            await msg.reply(f"{bot.msg_prefix} Current announce time is {self.delay} seconds.")
        except Exception as e:
            print(type(e), e)
Ejemplo n.º 2
0
    async def ignore_add(self, msg: Message, pattern: str):

        # Check if the regex is valid, return error if not.
        try:
            re.compile(pattern)
        except re.error:
            await msg.reply(f"{bot.msg_prefix}Invalid regex pattern.")
            return

        # Will not support a space in the pattern, but that doesn't matter because usernames can't have spaces
        query = session.query(IgnoreList).filter(
            IgnoreList.pattern == pattern).one_or_none()
        if query is None:
            # Pattern didn't exist, so add it.
            insert = IgnoreList(pattern=pattern)
            session.add(insert)
            session.commit()
            session.refresh(insert)
            await msg.reply(
                f"{bot.msg_prefix}I will now ignore links from {pattern}")
            bot.ignore_list_patterns[insert.id] = pattern

        else:
            await msg.reply(
                f"{bot.msg_prefix}That pattern is already in the database.")
Ejemplo n.º 3
0
    async def wig_add(self, msg: Message, *args):
        """Adds a new wig to the database"""
        wig_name = " ".join(map(str, args))

        new_wig = Wigs(wig_name=wig_name, enabled=1)
        session.add(new_wig)
        session.commit()

        session.refresh(new_wig)
        await msg.reply(f"{bot.msg_prefix}New wig added as id {new_wig.id}.")
Ejemplo n.º 4
0
def save_topic(topic: dict):
    topic_json = json.dumps(topic)

    rows_affected = session.query(Settings).filter(
        Settings.key == "topic").update({"value": topic_json})

    if not rows_affected:
        ins = Settings(key="topic", value=topic_json)
        session.add(ins)

    session.commit()

    return True
Ejemplo n.º 5
0
    async def shoutout_msg(self, msg: Message, *args):

        message = ""
        for word in args:
            message += f"{word} "

        successful = session.query(Settings.value).filter(Settings.key == "shoutout_msg").update({"value": message})
        if not successful:
            insert = Settings(key="shoutout_msg", value=message)
            session.add(insert)

        session.commit()

        await msg.reply(f"{bot.msg_prefix} Message updated.")
Ejemplo n.º 6
0
    def __init__(self):
        query = session.query(Settings.value).filter(Settings.key == "announcement_delay").one_or_none()
        self.delay = int(query[0]) if query is not None else 900
        self.chan = cfg.channels[0]
        self.next_run = datetime.min
        self.timezone = pytz.timezone("America/Chicago")
        self.channel_active = False
        self.announcements_sleeping = True
        self.sleep_override = False
        self.current_category_setting = "announcement_category"

        self.enable = session.query(Settings.value).filter(Settings.key == "announcement_enabled").one_or_none()
        if self.enable is None:
            insert = Settings(key="announcement_enabled", value=True)
            session.add(insert)
Ejemplo n.º 7
0
    async def set_topic(self, msg, *args):

        topic = ""
        for arg in args:
            topic += f"{arg} "

        rows_affected = session.query(Settings).filter(Settings.key == "topic").update({"value": topic})

        if not rows_affected:
            ins = Settings(key="topic", value=topic)
            session.add(ins)

        session.commit()

        await msg.reply(f"{bot.msg_prefix}Topic set.")
Ejemplo n.º 8
0
    async def announce_category_add(self, msg, *args):
        """Add a category"""

        cat_name = " ".join(map(str, args))
        exists = session.query(AnnouncementCategories).filter(AnnouncementCategories.name == cat_name).count()
        if exists:
            await msg.reply(f"{bot.msg_prefix}Duplicate category name")
            return

        # Insert the new category into the database
        new_announcement = AnnouncementCategories(name=cat_name)
        session.add(new_announcement)
        session.commit()

        # Refresh to pull the ID inserted as
        session.refresh(new_announcement)
        await msg.reply(f"{bot.msg_prefix}{new_announcement.name} added as id {new_announcement.id}")
Ejemplo n.º 9
0
    def get_cooldown(self, feed: str):
        """
        Returns the cooldown
        Loads it from the database,
        or returns 0 if one is not set.
        """
        if feed not in self.mqtt_cooldown:
            q = session.query(Settings.value).filter(Settings.key == f"mqtt_cooldown_{feed}").one_or_none()
            if q is None:
                # Value wasn't in the database, lets insert it.
                insert = Settings(key=f"mqtt_cooldown_{feed}", value=0)
                session.add(insert)
                self.mqtt_cooldown[feed] = 0
            else:
                self.mqtt_cooldown[feed] = int(q[0])

        return self.mqtt_cooldown[feed]
Ejemplo n.º 10
0
    def set_cooldown(self, feed: str, cooldown: int) -> None:
        """
        Sets the MQTT cooldown
        Updates or inserts the value into the database
        Exception handling should be done in the calling function
        """
        q = session.query(Settings.id).filter(Settings.key == f"mqtt_cooldown_{feed}").one_or_none()
        if q is None:
            # Value wasn't in the database, lets insert it.
            insert = Settings(key=f"mqtt_cooldown_{feed}", value=cooldown)
            session.add(insert)
            self.mqtt_cooldown[feed] = cooldown
        else:
            session.query(Settings).filter(Settings.key == f"mqtt_cooldown_{feed}").update({"value": cooldown})
            self.mqtt_cooldown[feed] = cooldown

        session.commit()
Ejemplo n.º 11
0
    async def on_pubsub_bits(self, raw: PubSubData, data) -> None:
        """Send MQTT push when a us4er redeems bits"""
        """
        print(raw.message_dict)
        {'data':
            {'user_name': 'tisboyo', 'channel_name': 'baldengineer',
            'user_id': '461713054', 'channel_id': '125957551', 'time': '2020-09-20T02:48:34.819702158Z',
            'chat_message': 'cheer1', 'bits_used': 1, 'total_bits_used': 2,
            'is_anonymous': False, 'context': 'cheer', 'badge_entitlement': None},
        'version': '1.0',
        'message_type': 'bits_event',
        'message_id': '5a2da2f4-a6b5-5d23-b7cc-839a3ea5140c'
        }
        """
        # bits = await load_data("bits")
        # bits[datetime.now().isoformat()] = raw.message_dict
        # await save_data("bits", bits)

        user_id = raw.message_dict["data"]["user_id"]
        server_id = raw.message_dict["data"]["channel_id"]
        bits_used = raw.message_dict["data"]["bits_used"]

        rows_affected = (session.query(Users).filter(
            Users.user_id == user_id, Users.channel == server_id).update({
                "cheers":
                Users.cheers + bits_used,
                "last_message":
                datetime.now()
            }))

        # If the user doesn't exist, insert them
        if not rows_affected:
            user_object = Users(
                user_id=user_id,
                channel=server_id,
                user=raw.message_dict["data"]["user_name"],
                message_count=1,
                cheers=bits_used,
            )
            session.add(user_object)

        session.commit()
Ejemplo n.º 12
0
    async def announce_add(self, msg, *args):

        message = ""

        # Build the message
        for arg in args:
            message += f"{arg} "

        print(f"Adding to announce: {message}", end="")

        announcement_object = Announcements(text=message)

        session.add(announcement_object)
        session.commit()
        session.refresh(announcement_object)
        id = announcement_object.id

        print(f"...done, {id=}")

        await msg.reply(f"{bot.msg_prefix}Added announce {id=}")
Ejemplo n.º 13
0
    async def on_user_join(self, user_name: str, channel: Channel, commit: bool = True) -> None:
        """User has joined the channel"""

        # get_user_info is cached by the bot, so only one actual request per user is sent to the api
        user_id = await get_user_id(user_name)
        channel_id = await get_user_id(channel.name)

        # Don't overwrite if the user is already here, happens if they join twice
        if (user_name, user_id) not in self.user_joined.keys():
            in_database = session.query(Users).filter(Users.user_id == user_id, Users.channel == channel_id).one_or_none()

            # If the user isn't in the database insert them so we can find them later
            if not in_database:
                user_object = Users(user_id=user_id, channel=channel_id, user=user_name)
                session.add(user_object)
                if commit:
                    session.commit()

            self.user_joined[(user_name, user_id)] = datetime.now()
            print(f"{datetime.now().isoformat()}: {user_name} has joined #{channel.name}, in database: {bool(in_database)}")
Ejemplo n.º 14
0
    async def user_exit(self, users: Union[str, frozenset], channel: Channel):

        now = datetime.now()

        # If only a single user is passed, convert it to a frozenset as if a list of users was passed
        if isinstance(users, str):
            users = frozenset([users])

        for user_name in users:
            # Build a tuple to compare
            user = (user_name, await get_user_id(user_name))

            # Check to make sure the user is still in the user_joined to prevent errors
            if user in self.user_joined.keys():
                # Calculate the time in the channel for this session
                joined: datetime = self.user_joined[user]
                parted = now
                time_this_session = parted - joined

                _, user_id = user
                channel_id = int(await get_user_id(channel.name))

                # Update the database
                # Adding time objects is not possible with sqlite, so using an integer to track seconds
                rows_affected = (
                    session.query(Users)
                    .filter(Users.user_id == user_id, Users.channel == channel_id)
                    .update({"time_in_channel": Users.time_in_channel + time_this_session.seconds})
                )

                if not rows_affected:
                    user_object = Users(
                        user_id=user_id, channel=channel_id, user=user_name, time_in_channel=time_this_session.seconds
                    )
                    session.add(user_object)

                # Remove the user from the user_joined key, since they have exited the channel
                del self.user_joined[user]

        # Commit the changes
        session.commit()
Ejemplo n.º 15
0
    async def on_raw_message(self, msg: Message) -> None:
        """Increment the user message counter"""

        # Make sure the user actually sent a message,and it's not a whisper.
        if not msg.is_user_message or msg.is_whisper:
            return

        user_id = msg.tags.user_id
        server_id = msg.tags.room_id

        rows_affected = (session.query(Users).filter(
            Users.user_id == user_id, Users.channel == server_id).update({
                "message_count":
                Users.message_count + 1,
                "last_message":
                datetime.now()
            }))

        # If the user doesn't exist, insert them
        if not rows_affected:
            user_object = Users(user_id=user_id,
                                channel=server_id,
                                user=msg.author,
                                message_count=1)
            session.add(user_object)

            # Added for #155
            # If we have had a raid in the last 60 seconds, don't send anything for the new users,
            # even thought they got inserted into the database.
            if (self.last_raid + timedelta(seconds=60)) < datetime.now():
                if not bot.user_ignored(msg.author):
                    await bot.MQTT.send(
                        first_time_chatter_topic,
                        dumps({
                            "author": msg.author,
                            "timestamp": str(datetime.now())
                        }))
                    print(f"New user {msg.author} sent to MQTT.")

        session.commit()
Ejemplo n.º 16
0
    async def on_raw_message(self, msg: Message) -> None:
        """Increment the user message counter"""

        # Make sure the user actually sent a message,and it's not a whisper.
        if not msg.is_user_message or msg.is_whisper:
            return

        user_id = msg.tags.user_id
        server_id = msg.tags.room_id

        rows_affected = (
            session.query(Users)
            .filter(Users.user_id == user_id, Users.channel == server_id)
            .update({"message_count": Users.message_count + 1, "last_message": datetime.now()})
        )

        # If the user doesn't exist, insert them
        if not rows_affected:
            user_object = Users(user_id=user_id, channel=server_id, user=msg.author, message_count=1)
            session.add(user_object)

        session.commit()
Ejemplo n.º 17
0
    async def lost(self, msg: Message, *args):
        # Check if user is on ignore list
        if bot.user_ignored(str(msg.author)):
            return

        # Increase both counts
        self.lost_count["session"] += 1
        self.lost_count["total"] += 1

        rows_affected = (session.query(Settings).filter(
            Settings.key == "lost_count").update(
                {"value": json.dumps(self.lost_count)}))

        if not rows_affected:
            ins = Settings(key="lost_count", value=json.dumps(self.lost_count))
            session.add(ins)

        session.commit()

        await msg.reply(
            f"@baldengineer has lost {self.lost_count['session']} things so far today, {self.lost_count['total']} total."
        )
Ejemplo n.º 18
0
    async def trivia_q(self, msg: Message, question_num: int, answer_num: int):
        question_num, answer_num = int(question_num), int(
            answer_num)  # Framework only passes strings, convert it.
        channel_id = await get_user_id(msg.channel.name)

        print(
            f"Trivia question #{question_num}, Answer: {ascii_lowercase[answer_num-1].upper()}"
        )

        # Don't send a question while another is active, queuing the next one.
        while self.question_active or self.almost_active:
            await sleep(0.5)

        self.almost_active = True  # Resets in reset_question

        # Don't set the question as active until it's sent to chat.
        self.current_question = question_num
        self.current_answer = answer_num

        result = session.query(TriviaQuestions).filter_by(
            id=self.current_question).one_or_none()

        self.answer_text = ascii_lowercase[answer_num - 1]
        if result is not None:
            # Send a welcome message and instructions if this is the first question of the session
            if not self.trivia_active:
                await msg.reply(f"{bot.msg_prefix}Trivia incoming...")
                await msg.reply(
                    f"{self.msg_prefix}To play trivia, answer with a single letter message of your answer(case insensitive)."
                )
                self.trivia_active = True

            async def sleep_if_active(time: int) -> bool:
                """Sleeps if trivia is active, returns True if trivia is still active at the end of the sleep"""
                # If trivia is not active, we will speed past sending the messages to chat and finalize answers
                for _ in range(time * 2):
                    if self.trivia_active:
                        await sleep(0.5)
                    else:
                        return False

                return True

            # Mark question as active
            self.question_active = True  # Resets in reset_question

            # Sleep early to let the watchers catch up to the stream
            if await sleep_if_active(7 + self.manual_delay):
                # Send the question to chat
                await msg.reply(f"{self.msg_prefix}{result.text}")

            if await sleep_if_active(40):
                await msg.reply(f"{self.msg_prefix}15 seconds remaining")

            if await sleep_if_active(10):
                await msg.reply(f"{self.msg_prefix}Final answers...")

            # One last sleep to let people get final answers in.
            await sleep_if_active(5)

            # Insert/Update the participants that got a correct answer
            correctly_answered = list()
            for participant in self.session:
                if (self.session[participant]["q"].get(
                        self.current_question, False) and participant in self.
                        current_question_participant  # See note in reset_session
                    ):
                    correctly_answered.append(participant)
                    # Get the user id, but sometimes this fails and returns a -1, if it's -1 try again up to 3 times.
                    # If it still fails, send a message to the console and do not insert into the database.
                    user_id = -1
                    get_user_id_count = 0
                    while user_id == -1:
                        user_id = await get_user_id(participant)
                        get_user_id_count += 1
                        if get_user_id_count >= 3:
                            print(
                                f"Unable to fetch user id for {participant} after 3 attempts."
                            )
                            break

                    query = (session.query(TriviaResults).filter(
                        TriviaResults.user_id == user_id,
                        TriviaResults.channel == channel_id).one_or_none()
                             )  # Grab the current row
                    if query:  # Update it
                        query.trivia_points += 1  # type: ignore
                        query.questions_answered_correctly[
                            self.current_question] = True

                    else:
                        # Insert if the row didn't exist.
                        query = TriviaResults(
                            user_id=user_id,
                            channel=channel_id,
                            questions_answered_correctly={
                                self.current_question: True
                            },
                            trivia_points=1,
                        )
                    # Update the query
                    session.add(query)
                    session.commit()

            if len(correctly_answered) > 0:
                correctly_answered = ", ".join(correctly_answered)
                # Check the total length, if over 500 characters shorten it.
                message = f"{self.msg_prefix} Congrats to {correctly_answered} for the correct answer."
                if len(message) > 500:
                    count = len(correctly_answered.split(", "))
                    message = f"{self.msg_prefix} Wow! {count} of you got it right! Congrats"

                await msg.reply(message)

            self.reset_question()
Ejemplo n.º 19
0
    async def on_pubsub_subscription(self, raw: PubSubData, data):
        """Twitch subscription event"""
        """
        print(raw.message_dict)
        {'benefit_end_month': 0, 'user_name': 'tisboyo', 'display_name': 'tisboyo', 'channel_name': 'baldengineer',
        'user_id': '461713054', 'channel_id': '125957551', 'time': '2020-09-27T20:01:35.385520498Z',
        'sub_message': {'message': '', 'emotes': None}, 'sub_plan': 'Prime', 'sub_plan_name': '104 Capacitor Level Sub',
        'months': 0, 'cumulative_months': 4, 'streak_months': 4, 'context': 'resub', 'is_gift': False,
        'multi_month_duration': 0}

        print(raw.raw_data)
        {'type': 'MESSAGE', 'data': {'topic': 'channel-subscribe-events-v1.125957551',
        'message': '{"benefit_end_month":0,"user_name":"tisboyo","display_name":"tisboyo","channel_name":"baldengineer",
        "user_id":"461713054","channel_id":"125957551","time":"2020-09-27T20:01:35.385520498Z",
        "sub_message":{"message":"","emotes":null},"sub_plan":"Prime","sub_plan_name":"104 Capacitor Level Sub",
        "months":0,"cumulative_months":4,"streak_months":4,"context":"resub","is_gift":false,"multi_month_duration":0}'}}
        """

        if raw.message_dict["is_gift"]:  # A gift subscription
            user_id = raw.message_dict["recipient_id"]
            # Add count to the user for gifting a sub
            gifter_id = int(raw.message_dict["user_id"])
            channel_id = int(raw.message_dict["channel_id"])
            session.query(Users).filter(Users.user_id == gifter_id,
                                        Users.channel == channel_id).update({
                                            Users.subs_gifted:
                                            Users.subs_gifted + 1
                                        })

        else:  # A regular subscription
            user_id = raw.message_dict["user_id"]

        cumulative_months = raw.message_dict[
            "cumulative_months"] if "cumulative_months" in raw.message_dict else 0
        streak_months = raw.message_dict[
            "streak_months"] if "streak_months" in raw.message_dict else 0

        # In both gift and regular sub
        server_id = raw.message_dict["channel_id"]
        sub_level = raw.message_dict["sub_plan"]

        rows_affected = (session.query(Subscriptions).filter(
            Subscriptions.user_id == user_id,
            Subscriptions.channel == server_id).update({
                "subscription_level":
                sub_level,
                "cumulative_months":
                cumulative_months,
                "streak_months":
                streak_months
            }))

        # Add row if one wasn't updated.
        if not rows_affected:
            user_object = Subscriptions(
                user_id=user_id,
                channel=server_id,
                subscription_level=sub_level,
                cumulative_months=cumulative_months,
                streak_months=streak_months,
            )
            session.add(user_object)

        session.commit()
Ejemplo n.º 20
0
 async def ignore_user(self, msg: Message, user: str):
     insert = LinksToDiscordIgnoreList(username=user.lower())
     session.add(insert)
     session.commit()
     await msg.reply(f"{bot.msg_prefix}I will now ignore links from {user}")
Ejemplo n.º 21
0
        # Verify the category is a valid one
        if (category := self.get_announcements_category(category_id)) is None:
            await msg.reply(f"{bot.msg_prefix}Invalid category id.")
            return

        # TODO Change to just an update, and do a alembic revision to insert a default after #79 is complete.
        updated = (
            session.query(Settings)
            .filter(Settings.key == self.current_category_setting)
            .update({Settings.value: category_id})
        )

        if not updated:  # Insert the key
            insert = Settings(key=self.current_category_setting, value=category_id)
            session.add(insert)

        session.commit()

        await msg.reply(f"{bot.msg_prefix}Active announcement category is now {category.name}")

    def get_announcements_category(self, category_id: int) -> AnnouncementCategories or None:
        """
        Returns an AnnouncementCategories object or None
        Use: if (category := self.get_announcements_category(category_id)) is None:
        """
        category_id = int(category_id)
        category = session.query(AnnouncementCategories).filter(AnnouncementCategories.id == category_id).first()
        # Have to check if a valid category was returned
        # to prevent a NoneType error if an invalid one is found
        if category is None: