Example #1
0
class QuantumJumpBot:
    def __init__(self, settings):
        self._ws = None
        self.state = BotState(BotState.INITIALIZED)
        self.start_time = time.time()
        self.api = Http()

        self.cm = CogManager()
        self.settings = settings
        self.botconfig = self.settings.Bot
        self.ul = UserList()
        self.room = self.botconfig.roomname
        if self.settings.Bot.debug:
            self.log = QuantumLogger('QuantumJump', self.room, 10)
        else:
            self.log = QuantumLogger('QuantumJump', self.room, 19)

    async def wsend(self, data):
        if type(data) is list:
            data = f"42{json.dumps(data)}"
        elif type(data) is str:
            type_exemptions = ["2probe", "5", "2"]
            if not data.startswith("42") and data not in type_exemptions:
                data = f"42{data}"
        self.log.ws_send(data)

        await self._ws.send(data)

    async def run(self):
        enabled_modules = self.settings.Modules["enabled"]
        self.cm.load_all(enabled_modules, bot=self)
        await self.connect()

    async def disconnect(self):
        self.state = BotState.DISCONNECT
        await self._ws.close()


    async def connect(self):
        logged_in = await self.api.login(self.botconfig.username,
                                          self.botconfig.password)
        async with websockets.connect(
                uri=await self.api.get_wss(),
                timeout=600,
                origin="https://jumpin.chat"
        ) as self._ws:
            self.log.info("Connected to websocket.")
            self.state = BotState.RUNNING
            await self.wsend("2probe")
            async for message in self._ws:
                await self._recv(message=message)

    async def _recv(self, message: str):
        if not message:
            return
        self.log.ws_event(message)

        if message.isdigit():
            return

        if message == "3probe":
            await self.wsend("5")
            roommsg = [
                "room::join",
                {"room": self.botconfig.roomname}
            ]
            await self.wsend(roommsg)
            asyncio.create_task(self.pacemaker())
            # await self.api.enroll()
            return

        data = json.loads(message[2:])

        if data[0] == "room::updateUserList":
            for user in data[1].get("users", []):
                if user:
                    self.ul.add(User(**user))
            if user := data[1].get("user", None):
                if user:
                    self.ul.add(User(**user))
        if data[0] == "room::updateUser":
            self.ul.update(User(**data[1].get("user", None)))

        if data[0] == "room::updateUsers":
            for user in data[1].get("users", []):
                self.ul.update(User(**user))

        # todo  update userlist when a name changes.
        if data[0] == "room::handleChange":
            # ["room::handleChange",{"userId":"5e22c017be8a4900076d3e21","handle":"Tech"}]
            pass
        if data[0] == "room::disconnect":
            self.ul.remove(User(**data[1].get("user", None)))

        if data[0] == "self::join":
            nickmsg = [
                "room::handleChange", {
                    "userId": self.api.login_data.user.get("userId"),
                    "handle": self.botconfig.nickname
                }
            ]
            await self.wsend(nickmsg)
            await self.wsend('42["room::users", {}]')

            # deprecated
            # user_list_data = await self.api.getroominfo(room=str(self.room))
            # self.ul = UserList(**user_list_data)
        if data[0] == "client::error":
            if error := data[1].get("error", False):
                if error == 'ERR_ACCOUNT_REQUIRED':
                    await self.disconnect()
                    raise Exception("Account must be signed in to join this room.")
                if error == 'ENOSESSION':
                    await self.disconnect()
                    raise Exception("Session was invalidated.")
Example #2
0
class Cog:
    def __init__(self, bot):
        self.bot = bot
        self.name = self.__class__.__name__
        self.__cog__ = True
        self.log = QuantumLogger(self.name, self.bot.room)
        self.log.info(f"initializing cog")
        self.bot_settings = bot.botconfig
        self.settings = bot.settings.Modules.get(self.__class__.__name__, None)

        self.events = [getattr(self, name)  # what gets stored.
                       for name in dir(self)  # loop
                       if "__" not in name  # ignore builtins
                       and callable(getattr(self, name))  # is callable
                       and hasattr(getattr(self, name), "__event__")
                       ]

        self.commands = [getattr(self, name)  # what gets stored.
                         for name in dir(self)  # loop
                         if "__" not in name  # ignore builtins
                         and callable(getattr(self, name))  # is callable
                         and hasattr(getattr(self, name), "__command__")
                         ]

    #####
    # client control
    ######
    async def ws_send(self, data):
        await self.bot.wsend(data=data)

    async def send_message(self, message: str, room: str = None, color=None, style=None):
        if not room:
            room = self.bot_settings.roomname

        if color is None and self.bot_settings.rainbow:
            color = Colors.random()
            await self.change_color(color)
        elif color is not None:
            await self.change_color(color)

        if len(message) > 254:
            # re.DOTALL makes . match everything, including newline
            messages = re.findall("(.{1,254}[.,;:]|.{1,254})", message, re.DOTALL)
            chunk_limit = self.bot_settings.chunk_limit
            if chunk_limit == 0 or chunk_limit == None:
                chunk_limit = len(messages)
            for i in range(0, chunk_limit):
                message = messages[i][:254]
                if style is not None:
                    message = encodetxt(message, style)
                await self.send_message(message, room=room, color=color, style=style)
            return
        else:
            if style is not None:
                # TODO check if valid style
                message = encodetxt(message, style)
            data = [
                "room::message",
                {
                    "message": message,
                    "room": room
                }
            ]
            await self.ws_send(data=data)

    async def send_action(self, message: str, room: str = None, color=None, style=None):
        """/me messages, styling doesn't work"""
        if color is None and self.bot_settings.rainbow:
            color = Colors.random()
            await self.change_color(color)
        elif color is not None:
            await self.change_color(color)
        if style is not None:
            # TODO check if valid style
            message = encodetxt(message, style)
        if not room:
            room = self.bot_settings.roomname
        data = [
            "room::command",
            {
                "message": {
                    "command": "me",
                    "value": message
                },
                "room": room
            }
        ]
        await self.ws_send(data=data)

    #####
    # Jumpin Commands
    #####
    async def remove_yt(self, id):
        data = ["youtube::remove", {"id": id}]
        await self.ws_send(data=data)

    async def checkisplaying(self, notify: bool = True):
        data = [
            "youtube::checkisplaying",
            {
                "notify": notify
            }
        ]
        await self.ws_send(data=data)

    async def play(self, video_id: str, title: str):
        data = [
            "youtube::play",
            {
                "videoId": video_id,
                "title": title
            }
        ]
        await self.ws_send(data=data)

    async def remove(self, id: str):
        data = [
            "youtube::remove",
            {
                "id": id
            }
        ]
        await self.ws_send(data=data)

    async def get_ignore_list(self, room: str):
        data = [
            "room::getIgnoreList",
            {
                "roomName": room
            }
        ]
        await self.ws_send(data=data)

    async def kick(self, user_id: str):
        data = [
            "room::operation::kick",
            {
                "user_list_id": user_id
            }
        ]
        await self.ws_send(data=data)

    async def banlist(self):
        data = [
            "room::operation::banlist",
            {
                "user_list_id": self.bot.api.session.user.user_id
            }
        ]
        await self.ws_send(data=data)

    async def ban(self, user_id: str, duration: int = 24):
        # perm is 4464
        data = [
            "room::operation::ban",
            {
                "user_list_id": user_id,
                "duration": duration
            }
        ]
        await self.ws_send(data=data)

    async def unban(self, ban_id: str, handle: str):
        data = [
            "room::operation::unban",
            {
                "banlistId": ban_id,
                "handle": handle
            }
        ]
        await self.ws_send(data=data)

    async def handle_change(self, nick: str):
        data = [
            "room::handleChange",
            {
                "handle": nick
            }
        ]
        await self.ws_send(data=data)

    async def change_color(self, color: str):
        data = [
            "room::changeColor",
            {
                "color": color
            }
        ]
        await self.ws_send(data=data)

    async def is_still_joined(self, room: str = None):
        if not room:
            room = self.bot_settings.roomname
        data = [
            "room::isStillJoined",
            {
                "room": room
            }
        ]

        await self.ws_send(data=data)

    async def join(self, room: str = None):
        if not room:
            room = self.bot_settings.roomname
        data = ["room::join", {"room": room}]
        await self.ws_send(data=data)

    async def close_broadcast(self, user_id: str):
        data = [
            "room::operation::closeBroadcast",
            {
                "user_list_id": user_id
            }
        ]
        await self.ws_send(data=data)

    async def do_pm(self):
        pass

    def __repr__(self) -> str:
        return self.name

    # these dont actually need to be here anymore.
    # left for reference
    @event(event="room::updateUser")
    async def updateUser(self, user: User):
        pass

    @event(event="room::updateUserList")
    async def updateUserList(self, userlist: UserList):
        pass

    @event(event="room::updateIgnore")
    async def updateIgnore(self, ignore_list: list):
        pass

    @event(event="room::status")
    async def status(self, status: Status):
        pass

    @event(event="room::handleChange")
    async def handleChange(self, handle_change: HandleChange):
        pass

    @event(event="room::message")
    async def message(self, message: Message):
        pass

    @event(event="room::error")
    async def error(self, message):
        pass

    @event(event="room::alert")
    async def alert(self, message):
        pass


    @event(event="youtube::playlistUpdate")
    # 42["youtube::playlistUpdate",[{"startTime":null,"endTime":null,"description":null,"channelId":"UCqukXrA3L_B0EVHiM14EU7g","pausedAt":null,"_id":"5dea8a123533d70008b01aa9","mediaId":"jesc3yvZSws","title":"DANZIG - Mother Lyrics","link":"https://youtu.be/jesc3yvZSws","duration":226,"thumb":"https://i.ytimg.com/vi/jesc3yvZSws/default.jpg","mediaType":"TYPE_YOUTUBE","startedBy":"5c4b7b6746bb1a000712c13c","createdAt":"2019-12-06T17:04:18.334Z"}]]
    async def playlistUpdate(self, playlistUpdate: list):
        pass
Example #3
0
class QuantumJumpBot:
    def __init__(self, settings):
        self._ws = None
        self.state = BotState(BotState.INITIALIZED)
        self.start_time = time.time()
        self.api = Http()
        self.cm = CogManager()
        self.settings = settings
        self.botconfig = self.settings.Bot
        self.ul = UserList()
        self.room = self.botconfig.roomname
        if self.settings.Bot.debug:
            self.log = QuantumLogger('QuantumJump', 10)
        else:
            self.log = QuantumLogger('QuantumJump', 19)

    async def wsend(self, data):
        if type(data) is list:
            data = f"42{json.dumps(data)}"
        elif type(data) is str:
            type_exemptions = ["2probe", "5", "2"]
            if not data.startswith("42") and data not in type_exemptions:
                data = f"42{data}"
        await self._ws.send(data)
        self.log.ws_send(data)

    async def run(self):
        enabled_modules = self.settings.Modules["enabled"]
        self.cm.load_all(enabled_modules, bot=self)
        await self.connect()

    async def disconnect(self):
        self.state = BotState.DISCONNECT
        await self._ws.close()

    async def connect(self):
        logged_in = await self.api.login(self.botconfig.username,
                                         self.botconfig.password)
        self.log.info(f"Logged in: {logged_in}")

        async with websockets.connect(
                uri=await self.api.get_wss(),
                timeout=600,
                origin="https://jumpin.chat") as self._ws:
            self.log.info("Connected to websocket.")
            self.state = BotState.RUNNING
            await self.wsend("2probe")
            async for message in self._ws:
                await self._recv(message=message)

    async def _recv(self, message: str):

        if message.isdigit():
            return
        self.log.ws_event(message)

        if message == "3probe":
            await self.wsend("5")
            roommsg = ["room::join", {"room": self.botconfig.roomname}]
            await self.wsend(roommsg)
            asyncio.create_task(self.pacemaker())
            return

        data = json.loads(message[2:])

        if data[0] == "room::status":
            msg = data[1].get("message")
            if "added a video to the playlist" in msg:

                ytid = re.search("(?:v=|\.be\/)(.{11})", msg)[1]
                myid = msg.split(' ')[0]
                title = msg.split('added a video to the playlist: ')[1]
                title = title.split('(https://')[0]

                #data = await self.endpoint(f"https://www.googleapis.com/youtube/v3/videos/?part=snippet%2CcontentDetails%2Cstatistics&id={ytid}",ytid)

                mydb = mysql.connector.connect(
                    host=
                    "gk90usy5ik2otcvi.cbetxkdyhwsb.us-east-1.rds.amazonaws.com",
                    user="******",
                    passwd="n9rgtn2meyhthi9t",
                    database="ppyh9hbf089e36w6")
                cursor = mydb.cursor()

                ids = ((ytid))
                myv = f"SELECT COUNT(*) as count FROM videos WHERE ytid LIKE '{ytid}'"
                add = f"""INSERT INTO videos (ytid, title) VALUES ('{ytid}', '{title}')"""
                our = "SELECT COUNT(*) as count FROM videos"

                cursor.execute(myv)
                myvideos = cursor.fetchone()[0]

                if myvideos == 0:
                    try:
                        cursor.execute(add, ids)
                        mydb.commit()
                        print(f"Added {title} to video.coder.ml/watch/{ytid}.")
                    except:
                        mydb.rollback()

                cursor.execute(our)
                allvids = cursor.fetchone()[0]
                print(f"{allvids} videos in cache.")

                mydb.close()

        if data[0] == "room::updateUserList":
            for user in data[1].get("users", []):
                if user:
                    self.ul.add(User(**user))
            if user := data[1].get("user", None):
                if user:
                    self.ul.add(User(**user))
        if data[0] == "room::updateUser":
            self.ul.update(User(**data[1].get("user", None)))

        if data[0] == "room::updateUsers":
            for user in data[1].get("users", []):
                self.ul.update(User(**user))

        #todo  update userlist when a name changes.
        if data[0] == "room::handleChange":
            # ["room::handleChange",{"userId":"5e22c017be8a4900076d3e21","handle":"Tech"}]
            pass
        if data[0] == "room::disconnect":
            self.ul.remove(User(**data[1].get("user", None)))

        if data[0] == "self::join":
            nickmsg = [
                "room::handleChange", {
                    "userId": self.api.login_data.user.get("userId"),
                    "handle": self.botconfig.nickname
                }
            ]
            await self.wsend(nickmsg)
            await self.wsend('42["room::users", {}]')

            # deprecated
            # user_list_data = await self.api.getroominfo(room=str(self.room))
            # self.ul = UserList(**user_list_data)
        if data[0] == "client::error":
            if error := data[1].get("error", False):
                if error == 'ERR_ACCOUNT_REQUIRED':
                    await self.disconnect()
                    raise Exception(
                        "Account must be signed in to join this room.")
                if error == 'ENOSESSION':
                    await self.disconnect()
                    raise Exception("Session was invalidated.")