-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)
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)
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
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'}:
--- /dev/null
+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)