class Vicky(irc.bot.SingleServerIRCBot): def __init__(self, channel, nickname, server, port=6667, enabled=[]): self.bot = irc.bot.SingleServerIRCBot.__init__(self, [(server, port)], nickname, nickname) self.channel = Channel(users=[], name=channel) self.cm = CogManager() def run(self): # TODO pull default modules from config enabled_modules = ['kodictrl'] self.cm.load_all(enabled_modules, bot=self) self.start() def sendmsg(self, msg: str, channel=None): # TODO split and send for long messages self.connection.privmsg(self.channel.name, msg) def on_nicknameinuse(self, client, event): client.nick(client.get_nickname() + "_") def on_welcome(self, client, event): client.join(self.channel.name) def on_join(self, c, event): print(event) # self.connection.privmsg(self.channel, "I have joined!") def on_namreply(self, c, event): self.gen_userlist() def on_nick(self, c, event): self.channel.setnick(event.source.nick, event.target) print(self.channel) def on_part(self, c, event): self.channel.remove(event.source.nick) def on_quit(self, c, event): self.channel.remove(event.source.nick) def on_privmsg(self, c, event): print(event) def on_pubmsg(self, c, event): # TODO pull prefixes from config prefix = ";" msg = Message(message=event.arguments[0], user=self.channel.getuser(event.source.nick)) # TEMP stick in a module after events are wired # if "http" in msg.message: # try: # urlexpression = "http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+" # possible = re.findall(urlexpression, msg.message) # req = get(possible[0]) # if req.status == 200: # soup = bs4(req.data, "html.parser") # if soup is not None: # try: # title = soup.title.string # except AttributeError as error: # pass # else: # self.sendmsg(title.strip()) # except: # pass if msg.message.startswith(prefix): command = Command(prefix=prefix, data=msg) # TODO move these if command.name == "reload" or command.name == "load": if m := self.cm.import_module(command.message, self): self.cm.add_cog(m, command.message, self) self.sendmsg(f"{command.name}ed {command.message}") else: self.sendmsg(f"failed to {command.name} {command.message}") elif command.name == "unload": if self.cm.unload(command.message): self.sendmsg(f"unloaded {command.message}") else: self.sendmsg(f"Could not unload {command.message}") elif command.name == "loaded": available = ", ".join(list(self.cm.modules.keys())) loaded = ", ".join(list(self.cm.cogs.keys())) self.sendmsg(f"Loaded: {loaded}") self.sendmsg(f"Available: {available}") else: self.cm.do_command(command) return
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.")
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.")
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 async def wsend(self, data): if type(data) is list: data = "42{}".format(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}" else: print("invalid data type for wsend") await self._ws.send(data) print(f"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): 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: print("Socket started") 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): print(f"RECV {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()) return data = json.loads(message[2:]) await self.cm.do_event(data=data) if data[0] == "self::join": nickmsg = [ "room::handleChange", { "userId": self.api.login_data.user.get("user_id"), "handle": self.botconfig.nickname } ] await self.wsend(nickmsg) 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): # todo logger # todo create an enum for different error codes. if error == 'ERR_ACCOUNT_REQUIRED': # if we do not disconnect, spy mode becomes possible. await self.disconnect() raise Exception("Account must be signed in to join this room.") if error == 'ENOSESSION': # if we do not disconnect, spy mode becomes possible. await self.disconnect() raise Exception("Session was invalidated.") if data[0] == "room::message": prefix = self.botconfig.prefix if data[1].get("message").startswith(prefix): data[1].update({"sender": self.ul.get(handle=data[1].get("handle"))}) c = Command(prefix=prefix, data=Message(**data[1])) if c.name == "reload" or c.name == "load": if m := self.cm.import_module(c.message, self): self.cm.add_cog(m, c.message, self) await self.wsend( Message.makeMsg(message=f"{c.name}ed {c.message}", room=self.room)) else: await self.wsend( Message.makeMsg(message=f"failed to {c.name} {c.message}", room=self.room)) if c.name == "unload": if self.cm.unload(c.message): await self.wsend( Message.makeMsg(message=f"unloaded {c.message}", room=self.room)) else: await self.wsend( Message.makeMsg(message=f"Could not unload {c.message}", room=self.room)) if c.name == "loaded": await self.wsend( Message.makeMsg(message=f"modules: {self.cm.modules}, cogs:{self.cm.cogs}", room=self.room)) await self.cm.do_command(c)