Add Subathon
authorGeorgios Atheridis <georgios@atheridis.org>
Fri, 30 Jun 2023 20:11:42 +0000 (21:11 +0100)
committerGeorgios Atheridis <georgios@atheridis.org>
Fri, 30 Jun 2023 20:11:42 +0000 (21:11 +0100)
ihaspeks/main.py
ihaspeks/scripts/subathon.py [new file with mode: 0644]

index 277be70b9623ee7bcfe9484873ef6bb160dcffc1..9c870fe19630e0b359f7e3147fa3c2a8c6a49905 100644 (file)
@@ -1,28 +1,30 @@
-from aptbot import Bot, Message, Commands
-import os
 import importlib
 import importlib.util
+import logging
+import os
+import time
 import traceback
-import tools.raid
-import tools.smart_privmsg
-import tools.permissions
-import tools.smart_start_stream_time
+from importlib import reload
+from threading import Event, Thread
+
+import analyze_auto_message
 import analyze_command
-import scripts.unit_converter
+import database_manager
 import scripts.alwase
-import scripts.chatting
 import scripts.chat
-import scripts.crylaugh
+import scripts.chatting
 import scripts.clean_queue
+import scripts.command_generator
+import scripts.crylaugh
 import scripts.discord_start_stream
+import scripts.subathon
+import scripts.unit_converter
 import scripts.will_be_missed
-import scripts.command_generator
-import database_manager
-import analyze_auto_message
-import time
-import logging
-from threading import Event
-from importlib import reload
+import tools.permissions
+import tools.raid
+import tools.smart_privmsg
+import tools.smart_start_stream_time
+from aptbot import Bot, Commands, Message
 
 reload(tools.raid)
 reload(tools.smart_privmsg)
@@ -37,6 +39,7 @@ reload(scripts.crylaugh)
 reload(scripts.clean_queue)
 reload(scripts.discord_start_stream)
 reload(scripts.will_be_missed)
+reload(scripts.subathon)
 reload(scripts.command_generator)
 reload(database_manager)
 reload(analyze_auto_message)
@@ -120,18 +123,19 @@ database_manager.update_auto_messages_in_database(auto_message_modules, auto_mes
 def start(bot: Bot, message: Message, stop_event: Event):
     i = 0
     wait = 5
+    scripts.subathon.donations(bot, message)
     while not stop_event.is_set():
         i += wait
         started = tools.smart_start_stream_time.update_start_stream_timestamp()
         if started == "START":
             scripts.clean_queue.clean_queue()
             scripts.discord_start_stream.announce()
-            bot.send_privmsg(
+            bot.send_message(
                 message.channel, "Stream has started, you can now use ?join"
             )
         elif started == "END":
             scripts.clean_queue.clean_queue()
-            bot.send_privmsg(message.channel, "Stream has ended")
+            bot.send_message(message.channel, "Stream has ended")
         if i >= 30:
             analyze_auto_message.do_auto_message(bot, message, auto_message_modules)
             i = 0
@@ -152,6 +156,7 @@ def main(bot: Bot, message: Message):
         scripts.chat.chat(bot, message)
         scripts.crylaugh.crylaugh(bot, message)
     scripts.will_be_missed.will_be_missed(bot, message)
+    scripts.subathon.subathon(bot, message)
 
     # if message.command == Commands.PART:
     #     if message.nick in {'jelemar', 'flauenn', 'ihaspeks', 'blobin_wobin', 'officiallysp'}:
diff --git a/ihaspeks/scripts/subathon.py b/ihaspeks/scripts/subathon.py
new file mode 100644 (file)
index 0000000..a71e1c0
--- /dev/null
@@ -0,0 +1,208 @@
+import json
+import logging
+import os
+import socket
+import sqlite3
+
+import socketio
+import tools.smart_privmsg
+from aptbot.bot import Bot, Commands, Message
+from numpy import array, ceil, exp, sum
+from numpy.random import normal
+
+logger = logging.getLogger(__name__)
+
+SCRIPTS_PATH = os.path.dirname(os.path.realpath(__file__))
+PATH = os.path.join(SCRIPTS_PATH, "..")
+
+socket_file = os.getenv("SUBATHON_SOCKET", "~/.cache/subathon.sock")
+
+conn = sqlite3.connect(os.path.join(PATH, "subathon.db"))
+c = conn.cursor()
+
+c.execute(
+    """
+    CREATE TABLE IF NOT EXISTS subs (
+        user_id TEXT NOT NULL,
+        display_name TEXT NOT NULL,
+        sub_count INTEGER NOT NULL,
+        PRIMARY KEY (user_id)
+    );
+    """
+)
+c.execute(
+    """
+    CREATE TABLE IF NOT EXISTS raids (
+        user_id TEXT NOT NULL,
+        display_name TEXT NOT NULL,
+        raid_count INTEGER NOT NULL,
+        PRIMARY KEY (user_id)
+    );
+    """
+)
+conn.commit()
+c.close()
+
+
+def subathon(bot: Bot, message: Message):
+    if message.command == Commands.USERNOTICE:
+        if message.tags["msg-id"] in {"sub", "resub", "subgift"}:
+            user_id = message.tags["user-id"]
+            sub_type = message.tags["msg-param-sub-plan"]
+            multiplier = 1
+            if sub_type.lower() == "2000":
+                multiplier = 2
+            elif sub_type.lower() == "3000":
+                multiplier = 6
+            display_name = message.tags["display-name"]
+
+            conn = sqlite3.connect(os.path.join(PATH, "subathon.db"))
+            c = conn.cursor()
+
+            c.execute(
+                """SELECT sub_count FROM subs WHERE user_id = ?;""",
+                (user_id,),
+            )
+            if sub_count := c.fetchone():
+                c.execute(
+                    """UPDATE subs
+                    SET
+                        sub_count = sub_count + 1
+                    WHERE
+                        user_id = ?;
+                    """,
+                    (user_id,),
+                )
+            else:
+                c.execute(
+                    "INSERT OR IGNORE INTO subs VALUES (?, ?, ?)",
+                    (
+                        user_id,
+                        display_name,
+                        1,
+                    ),
+                )
+            conn.commit()
+            conn.close()
+
+            # if None, then subcount is 0, else it's subcount
+            sub_count = sub_count or 0
+            timer_add = calculate_increase(sub_count)
+        elif message.tags["msg-id"] == "raid":
+            raid_count = message.tags["msg-param-viewerCount"]
+            if int(raid_count) < 5:
+                return
+            raider_id = message.tags["user-id"]
+            display_name = message.tags["msg-param-displayName"]
+
+            conn = sqlite3.connect(os.path.join(PATH, "subathon.db"))
+            c = conn.cursor()
+
+            c.execute(
+                """SELECT raid_count FROM raids WHERE user_id = ?;""",
+                (raider_id,),
+            )
+
+            if c.fetchone():
+                return
+            c.execute(
+                "INSERT OR IGNORE INTO raids VALUES (?, ?, ?)",
+                (
+                    raider_id,
+                    display_name,
+                    raid_count,
+                ),
+            )
+            timer_add = int(raid_count)
+            multiplier = 10 * 60
+        else:
+            return
+    elif message.command == Commands.PRIVMSG:
+        if bits := message.tags.get("bits"):
+            # Every 400 bits is the same as a sub,
+            # assuming you already subbed 10 times
+            div_count = (int(bits) // 400) * calculate_increase(10)
+
+            # Add 3 seconds for every 1 bit under 400 bits
+            rest_count = (int(bits) % 400) * 3
+
+            timer_add = div_count + rest_count
+            multiplier = 1
+            display_name = message.tags.get("display-name") or message.nick
+        else:
+            return
+    else:
+        return
+
+    total_timer = timer_add * multiplier
+    with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as client:
+        client.connect(socket_file)
+        data = {
+            "time": total_timer,
+            "name": display_name,
+        }
+        client.send(json.dumps(data).encode())
+        client.close()
+
+    verb = "INCREASED ihaspeHappy" if total_timer > 0 else "DECREASED ihaspeAngi"
+    msg = (
+        f"{display_name} has {verb} the timer by {abs(total_timer) // 60} minutes "
+        + f"and {abs(total_timer) % 60} seconds."
+    )
+    tools.smart_privmsg.send_safe(bot, message.channel, msg)
+
+
+# tools.smart_privmsg.send(bot, message, msg_reply)
+
+
+def donations(bot: Bot, message: Message):
+    io = socketio.Client()
+    socket_access_token = os.getenv("STREAMLABS_SOCKET")
+
+    io.connect(
+        f"https://sockets.streamlabs.com?token={socket_access_token}",
+        transports="websocket",
+    )
+
+    @io.on("event")
+    def event(data):
+        match data["type"]:
+            case "donation":
+                amount_cents = int(float(data["message"][0]["amount"]) * 100)
+                div_count = (amount_cents // 400) * calculate_increase(10)
+
+                # Add 3 seconds for every 1 cent under 400 cents
+                rest_count = (amount_cents % 400) * 3
+
+                timer_add = div_count + rest_count
+                display_name = data["message"][0]["from"]
+
+                total_timer = timer_add
+                with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as client:
+                    client.connect(socket_file)
+                    data = {
+                        "time": total_timer,
+                        "name": display_name,
+                    }
+                    client.send(json.dumps(data).encode())
+                    client.close()
+                logger.info("%s donated %s", display_name, amount_cents)
+
+                verb = (
+                    "INCREASED ihaspeHappy"
+                    if total_timer > 0
+                    else "DECREASED ihaspeAngi"
+                )
+                msg = (
+                    f"{display_name} has {verb} the timer "
+                    + f"by {abs(total_timer) // 60} minutes "
+                    + f"and {abs(total_timer) % 60} seconds."
+                )
+                tools.smart_privmsg.send_safe(bot, message.channel, msg)
+
+
+def calculate_increase(sub_count: int) -> int:
+    scale = 0.006
+    avg_time = ceil(30.0 * exp(-scale * sub_count) + 5.0)
+    var_time = 35.0 / (1 + exp(-0.15 * (sub_count - 10))) - 5.0
+    return ceil(normal(avg_time, var_time) * 60.0)