Skip to content
This repository was archived by the owner on Jan 13, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
# - Code -
# ----------------------------------------------------------------------------------------------------------------------
def version_handler() -> str:
version = 0,1,1
version = 0,2,0
version_str = ".".join(str(i) for i in version)

with open("src/AthenaTwitchBot/_info/_v.py", "w") as file:
Expand Down
2 changes: 1 addition & 1 deletion src/AthenaTwitchBot/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# - Package Imports -
# ----------------------------------------------------------------------------------------------------------------------
from AthenaTwitchBot.decorators.command import command_method
from AthenaTwitchBot.decorators.frequentoutput import frequent_output_method
from AthenaTwitchBot.decorators.scheduled_task import scheduled_task_method

from AthenaTwitchBot.models.twitch_bot import TwitchBot
from AthenaTwitchBot.models.twitch_bot_protocol import TwitchBotProtocol
Expand Down
2 changes: 1 addition & 1 deletion src/AthenaTwitchBot/_info/_v.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
def _version():
return '0.1.1'
return '0.2.0'
14 changes: 14 additions & 0 deletions src/AthenaTwitchBot/data/emotes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# ----------------------------------------------------------------------------------------------------------------------
# - Package Imports -
# ----------------------------------------------------------------------------------------------------------------------
# General Packages
from __future__ import annotations

# Custom Library

# Custom Packages

# ----------------------------------------------------------------------------------------------------------------------
# - Code -
# ----------------------------------------------------------------------------------------------------------------------
four_head = "4head"
14 changes: 10 additions & 4 deletions src/AthenaTwitchBot/decorators/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,24 @@
# Custom Library

# Custom Packages
from AthenaTwitchBot.models.wrapper_helpers.command import Command

# ----------------------------------------------------------------------------------------------------------------------
# - Code -
# ----------------------------------------------------------------------------------------------------------------------
def command_method(name:str):
def command_method(name:str, case_sensitive:bool=False):
def decorator(fnc):
def wrapper(*args, **kwargs):
return fnc(*args, **kwargs)
def wrapper(*args_, **kwargs_):
return fnc(*args_, **kwargs_)

# store attributes for later use by the bot
wrapper.is_command = True
wrapper.command_name = name
# store some information
wrapper.cmd = Command(
name=name,
case_sensitive=case_sensitive,
callback=wrapper,
)

return wrapper
return decorator
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,16 @@
# Custom Library

# Custom Packages
from AthenaTwitchBot.models.wrapper_helpers.scheduled_task import ScheduledTask

# ----------------------------------------------------------------------------------------------------------------------
# - Code -
# ----------------------------------------------------------------------------------------------------------------------
def frequent_output_method(delay:int=3600): # default is every hour
def scheduled_task_method(*,delay:int=3600,before:bool=True): # default is every hour
"""
Create a method that runs every couple of seconds.
The delay parameter is defined in seconds
:param before:
:param delay:
:return:
"""
Expand All @@ -25,7 +27,11 @@ def wrapper(*args, **kwargs):

# store attributes for later use by the bot
# to be used by the protocol to assign it top an async call loop
wrapper.is_frequent_output = True # typo caught by NoirPi
wrapper.delay = delay
wrapper.is_task = True # typo caught by NoirPi
wrapper.tsk = ScheduledTask(
delay=delay,
before=before,
callback=wrapper
)
return wrapper
return decorator
68 changes: 44 additions & 24 deletions src/AthenaTwitchBot/functions/launch.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,37 +11,57 @@
# Custom Packages
from AthenaTwitchBot.models.twitch_bot import TwitchBot
from AthenaTwitchBot.models.twitch_bot_protocol import TwitchBotProtocol
from AthenaTwitchBot.models.outputs.output import Output
from AthenaTwitchBot.models.outputs.output_console import OutputConsole

# ----------------------------------------------------------------------------------------------------------------------
# - Code -
# ----------------------------------------------------------------------------------------------------------------------
def launch(
*, # after this, keywords only
bot:TwitchBot=None,
protocol_factory:Callable=None,
*,
output:Output=None,
host:str='irc.chat.twitch.tv',
port:int=6667 #todo make this into the ssl port
port:int=6667, #todo make this into the ssl port

auto_restart:bool=False
):
# a bot always has to be defined
if bot is None or not isinstance(bot, TwitchBot):
raise SyntaxError("a proper bot has not been defined")

loop = asyncio.get_event_loop()

# assemble the protocol if a custom hasn't been defined
if protocol_factory is None:
protocol_factory = lambda: TwitchBotProtocol(
bot=bot,
main_loop=loop,
)

loop.run_until_complete(
loop.create_connection(
protocol_factory=protocol_factory,
host=host,
port=port,
)
)
loop.run_forever()
loop.close()

if output is None:
output=OutputConsole()
output.pre_launch()

while True:
try:
# a bot always has to be defined
if bot is None or not isinstance(bot, TwitchBot):
raise SyntaxError("a proper bot has not been defined")

loop = asyncio.get_event_loop()

# assemble the protocol if a custom hasn't been defined
if protocol_factory is None:
protocol_factory = lambda: TwitchBotProtocol(bot=bot,output=output)

loop.run_until_complete(
loop.create_connection(
protocol_factory=protocol_factory,
host=host,
port=port,
)
)
loop.run_forever()
loop.close()
except ConnectionResetError:
print("not connection")
if auto_restart:
loop = asyncio.get_running_loop()
loop.stop()
continue
else:
break

except : # make sure everything else is caught else the loop will continue indefinitely
raise

39 changes: 22 additions & 17 deletions src/AthenaTwitchBot/functions/twitch_message_constructors.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,29 +32,34 @@ def _find_bot_only(content:list[str],message:str, bot_name:str) -> TwitchMessage
return False

TAG_MAPPING:dict[str:Callable] = {
"@badge-info": lambda tm, tag_value: setattr(tm, "badge_info", tag_value),
"badges": lambda tm, tag_value: setattr(tm, "badges", tag_value),
"client-nonce": lambda tm, tag_value: setattr(tm, "client_nonce", tag_value),
"color": lambda tm, tag_value: setattr(tm, "color", HEX(tag_value)),
"display-name": lambda tm, tag_value: setattr(tm, "display_name", tag_value),
"emotes": lambda tm, tag_value: setattr(tm, "emotes", tag_value),
"first-msg": lambda tm, tag_value: setattr(tm, "first_msg", bool(tag_value)),
"flags": lambda tm, tag_value: setattr(tm, "flags", tag_value),
"id": lambda tm, tag_value: setattr(tm, "message_id", tag_value),
"mod": lambda tm, tag_value: setattr(tm, "mod", bool(tag_value)),
"room-id": lambda tm, tag_value: setattr(tm, "room_id", tag_value),
"subscriber": lambda tm, tag_value: setattr(tm, "subscriber", bool(tag_value)),
"tmi-sent-ts": lambda tm, tag_value: setattr(tm, "tmi_sent_ts", int(tag_value)),
"turbo": lambda tm, tag_value: setattr(tm, "turbo", bool(tag_value)),
"user-id": lambda tm, tag_value: setattr(tm, "user_id", int(tag_value)),
"user-type": lambda tm, tag_value: setattr(tm, "user_type", tag_value),
"@badge-info": lambda tm, tag_value: setattr(tm, "badge_info", tag_value),
"badges": lambda tm, tag_value: setattr(tm, "badges", tag_value),
"client-nonce": lambda tm, tag_value: setattr(tm, "client_nonce", tag_value),
"color": lambda tm, tag_value: setattr(tm, "color", HEX(tag_value) if tag_value else HEX()),
"display-name": lambda tm, tag_value: setattr(tm, "display_name", tag_value),
"emotes": lambda tm, tag_value: setattr(tm, "emotes", tag_value),
"first-msg": lambda tm, tag_value: setattr(tm, "first_msg", bool(int(tag_value))),
"flags": lambda tm, tag_value: setattr(tm, "flags", tag_value),
"id": lambda tm, tag_value: setattr(tm, "message_id", tag_value),
"mod": lambda tm, tag_value: setattr(tm, "mod", bool(int(tag_value))),
"room-id": lambda tm, tag_value: setattr(tm, "room_id", tag_value),
"subscriber": lambda tm, tag_value: setattr(tm, "subscriber", bool(int(tag_value))),
"tmi-sent-ts": lambda tm, tag_value: setattr(tm, "tmi_sent_ts", int(tag_value)),
"turbo": lambda tm, tag_value: setattr(tm, "turbo", bool(int(tag_value))),
"user-id": lambda tm, tag_value: setattr(tm, "user_id", int(tag_value)),
"user-type": lambda tm, tag_value: setattr(tm, "user_type", tag_value),
"reply-parent-display-name":lambda tm, tag_value: setattr(tm, "reply_parent_display_name", tag_value),
"reply-parent-msg-body": lambda tm, tag_value: setattr(tm, "reply_parent_msg_body", tag_value),
"reply-parent-msg-id": lambda tm, tag_value: setattr(tm, "reply_parent_msg_id", int(tag_value)),
"reply-parent-user-id": lambda tm, tag_value: setattr(tm, "reply_parent_user_id", int(tag_value)),
"reply-parent-user-login": lambda tm, tag_value: setattr(tm, "reply_parent_user_login", tag_value),
"emote-only": lambda tm, tag_value: setattr(tm, "emote_only", bool(int(tag_value))),
}

# ----------------------------------------------------------------------------------------------------------------------
# - Code -
# ----------------------------------------------------------------------------------------------------------------------
def twitch_message_constructor_tags(message_bytes:bytearray, bot_name:str) -> TwitchMessage:
print(message_bytes)
message = message_bytes.decode("UTF_8")
content = message.split(" ")

Expand Down
13 changes: 13 additions & 0 deletions src/AthenaTwitchBot/models/outputs/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# ----------------------------------------------------------------------------------------------------------------------
# - Package Imports -
# ----------------------------------------------------------------------------------------------------------------------
# General Packages
from __future__ import annotations

# Custom Library

# Custom Packages

# ----------------------------------------------------------------------------------------------------------------------
# - Code -
# ----------------------------------------------------------------------------------------------------------------------
27 changes: 27 additions & 0 deletions src/AthenaTwitchBot/models/outputs/output.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# ----------------------------------------------------------------------------------------------------------------------
# - Package Imports -
# ----------------------------------------------------------------------------------------------------------------------
# General Packages
from __future__ import annotations
from abc import ABC, abstractmethod

# Custom Library

# Custom Packages
from AthenaTwitchBot.models.twitch_message import TwitchMessage

# ----------------------------------------------------------------------------------------------------------------------
# - Code -
# ----------------------------------------------------------------------------------------------------------------------
class Output(ABC):

@abstractmethod
def pre_launch(self):
"""Output the state of the application before anything is run"""
@abstractmethod
def message(self, message:TwitchMessage):
"""Output of a received message"""

@abstractmethod
def undefined(self,message=None):
"""Output anything that is supposed to be undefined (this should eventually not be present anymore)"""
43 changes: 43 additions & 0 deletions src/AthenaTwitchBot/models/outputs/output_console.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# ----------------------------------------------------------------------------------------------------------------------
# - Package Imports -
# ----------------------------------------------------------------------------------------------------------------------
# General Packages
from __future__ import annotations

# Custom Library
from AthenaColor import StyleNest, ForeNest, BackNest

# Custom Packages
from AthenaTwitchBot.models.outputs.output import Output
from AthenaTwitchBot.models.twitch_message import TwitchMessage, TwitchMessagePing, TwitchMessageOnlyForBot
# noinspection PyProtectedMember
from AthenaTwitchBot._info._v import _version

# ----------------------------------------------------------------------------------------------------------------------
# - Code -
# ----------------------------------------------------------------------------------------------------------------------
class OutputConsole(Output):

def pre_launch(self):
print(
ForeNest.SlateGray(
f"- AthenaTwitchBot {ForeNest.HotPink('v', _version(), sep='')} -",
f" made by Andreas Sas",
"",
sep="\n"
),
)

def message(self, message:TwitchMessage):
match message:
case TwitchMessagePing():
print(ForeNest.SlateGray(message.text), ForeNest.ForestGreen("PING RECEIVED"))
case TwitchMessageOnlyForBot():
print(ForeNest.SlateGray(message.text))
case TwitchMessage(first_msg=True):
print(ForeNest.BlueViolet(message.username), ForeNest.SlateGray(":"),ForeNest.White(message.text))
case TwitchMessage():
print(ForeNest.SlateGray(message.username, ":"),ForeNest.White(message.text))

def undefined(self,message=None):
print(ForeNest.SlateGray(message))
14 changes: 8 additions & 6 deletions src/AthenaTwitchBot/models/twitch_bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
# Custom Library

# Custom Packages
from AthenaTwitchBot.models.wrapper_helpers.command import Command
from AthenaTwitchBot.models.wrapper_helpers.scheduled_task import ScheduledTask

# ----------------------------------------------------------------------------------------------------------------------
# - Code -
Expand All @@ -29,8 +31,8 @@ class TwitchBot:
predefined_commands:InitVar[dict[str: Callable]]=None # made part of init if someone wants to feel the pain of adding commands manually

# noinspection PyDataclass
commands:dict[str: Callable]=field(init=False)
frequent_outputs:list[tuple[Callable, int]]=field(init=False)
commands:dict[str: Command]=field(init=False)
scheduled_tasks:list[ScheduledTask]=field(init=False)

# non init slots

Expand All @@ -40,7 +42,7 @@ class TwitchBot:
def __new__(cls, *args, **kwargs):
# Loop over own functions to see if any is decorated with the command setup
cls.commands = {}
cls.frequent_outputs = []
cls.scheduled_tasks = []

# create the actual instance
# Which is to be used in the commands tuple
Expand All @@ -50,9 +52,9 @@ def __new__(cls, *args, **kwargs):
for k,v in cls.__dict__.items():
if inspect.isfunction(v):
if "is_command" in (attributes := [attribute for attribute in dir(v) if not attribute.startswith("__")]):
cls.commands[v.command_name] = v
elif "is_frequent_output" in attributes:
cls.frequent_outputs.append((v,v.delay))
cls.commands[v.cmd.name.lower()] = v.cmd
elif "is_task" in attributes:
cls.scheduled_tasks.append(v.tsk)

return obj

Expand Down
Loading