diff --git a/profiles/__init__.py b/profiles/__init__.py index 7327446..d230ba3 100644 --- a/profiles/__init__.py +++ b/profiles/__init__.py @@ -3,3 +3,9 @@ import logging logger = logging.getLogger(__name__) from .discord import setup +from .twitch import setup as twitch_setup + +__all__ = ( + 'setup', + 'twitch_setup', +) diff --git a/profiles/profiles.py b/profiles/profiles.py index b1f43c0..fc77da0 100644 --- a/profiles/profiles.py +++ b/profiles/profiles.py @@ -28,6 +28,7 @@ class ProfilesRegistry: return await UserProfile.fetch(link.profileid) async def get_profile_twitch(self, userid: str) -> Optional[UserProfile]: + userid = str(userid) link = await TwitchProfileLink.fetch(userid) if link: return await UserProfile.fetch(link.profileid) @@ -41,6 +42,7 @@ class ProfilesRegistry: return await Community.fetch(link.communityid) async def get_community_twitch(self, channelid: str) -> Optional[Community]: + channelid = str(channelid) link = await TwitchCommunityLink.fetch(channelid) if link: return await Community.fetch(link.communityid) diff --git a/profiles/twitch/__init__.py b/profiles/twitch/__init__.py index e69de29..bf5add2 100644 --- a/profiles/twitch/__init__.py +++ b/profiles/twitch/__init__.py @@ -0,0 +1,10 @@ +from typing import TYPE_CHECKING +from .. import logger + +if TYPE_CHECKING: + from meta.bot import Bot + + +async def setup(bot: 'Bot'): + from .component import ProfileComponent + await bot.add_component(ProfileComponent(bot)) diff --git a/profiles/twitch/component.py b/profiles/twitch/component.py new file mode 100644 index 0000000..d50bcc2 --- /dev/null +++ b/profiles/twitch/component.py @@ -0,0 +1,81 @@ +from typing import Optional +import asyncio + +import twitchio +from twitchio.ext import commands as cmds + +from meta import Bot +from meta.logger import log_wrap +from utils.lib import utc_now + +from . import logger + +from ..data import ProfilesData, UserProfile, TwitchProfileLink, Community, TwitchCommunityLink +from ..profiles import ProfilesRegistry + + +class ProfilesComponent(cmds.Component): + def __init__(self, bot: Bot): + self.bot = bot + + self.data = bot.dbconn.load_registry(ProfilesData()) + self.profiles = ProfilesRegistry(self.data) + + # ----- API ----- + async def component_load(self): + await self.data.init() + + async def component_teardown(self): + pass + + # ------ Commands ----- + @log_wrap(isolate=True, action="Fetch Profile") + async def fetch_profile( + self, + user: twitchio.PartialUser, + touch: bool = False, + ) -> UserProfile: + """ + Fetch or create the profile for the given user. + """ + userid = str(user.id) + async with self.bot.dbconn.connection() as conn: + self.bot.dbconn.conn = conn + async with conn.transaction(): + profile = await self.profiles.get_profile_twitch(userid) + if profile is None: + args = {} + try: + user = await user.user() + args['nickname'] = user.display_name + args['avatar'] = user.profile_image.url + except twitchio.HTTPException: + pass + profile = await UserProfile.create(**args) + await TwitchProfileLink.create(profileid=profile.profileid, userid=userid) + elif touch: + await profile.update(last_seen=utc_now()) + + return profile + + @log_wrap(isolate=True, action="Fetch Community") + async def fetch_community( + self, + channel: twitchio.PartialUser, + touch: bool = False, + ) -> Community: + """ + Fetch or create the community for this channel. + """ + chanid = channel.id + async with self.bot.dbconn.connection() as conn: + self.bot.dbconn.conn = conn + async with conn.transaction(): + comm = await self.profiles.get_community_twitch(chanid) + if comm is None: + comm = await Community.create() + await TwitchCommunityLink.create(channelid=chanid, communityid=comm.communityid) + elif touch: + await comm.update(last_seen=utc_now()) + return comm +