Advertisement
agunq

ch.py

Sep 6th, 2023 (edited)
1,865
0
Never
3
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 49.09 KB | None | 0 0
  1. ################################################################
  2. # Original By : Lumirayz/Lumz lumirayz@gmail.com
  3. # Edited By : Agunq
  4. # Use python3 because python2 is discontinued :(
  5. # Require websocket-client module
  6. #   pip install websocket-client
  7. ################################################################
  8.  
  9. import websocket
  10. import random
  11. import re
  12. import time
  13. import urllib.request
  14. import urllib.parse
  15. import select
  16. import threading
  17.  
  18. VERSION = "its disastah v1.2"
  19. BigMessage_Multiple = 0
  20. BigMessage_Cut      = 1
  21.  
  22. MessageFlags = {
  23.     "PREMIUM" : 1 << 2 ,
  24.     "BG_ON" : 1 << 3 ,
  25.     "MEDIA_ON" : 1 << 4 ,
  26.     "CENSORED" : 1 << 5 ,
  27.     "SHOW_MOD_ICON" : 1 << 6 ,
  28.     "SHOW_STAFF_ICON" : 1 << 7 ,
  29.     "CHANNEL_RED" : 1 << 8 ,
  30.     "CHANNEL_ORANGE" : 1 << 9 ,
  31.     "CHANNEL_GREEN" : 1 << 10 ,
  32.     "CHANNEL_CYAN" : 1 << 11 ,
  33.     "CHANNEL_BLUE" : 1 << 12 ,
  34.     "CHANNEL_PURPLE" : 1 << 13 ,
  35.     "CHANNEL_PINK" : 1 << 14 ,
  36.     "CHANNEL_MOD" : 1 << 15
  37.     }
  38.  
  39. RoomFlags = {
  40.     "LIST_TAXONOMY" : 1 << 0 ,
  41.     "NO_ANONS" : 1 << 2 ,
  42.     "NO_FLAGGING" : 1 << 3 ,
  43.     "NO_COUNTER" : 1 << 4 ,
  44.     "NO_IMAGES" : 1 << 5 ,
  45.     "NO_LINKS" : 1 << 6 ,
  46.     "NO_VIDEOS" : 1 << 7 ,
  47.     "NO_STYLED_TEXT" : 1 << 8 ,
  48.     "NO_LINKS_CHATANGO" : 1 << 9 ,
  49.     "NO_BROADCAST_MSG_WITH_BW" : 1 << 10 ,
  50.     "RATE_LIMIT_REGIMEON" : 1 << 11 ,
  51.     "CHANNELS_DISABLED" : 1 << 13 ,
  52.     "NLP_SINGLEMSG" : 1 << 14 ,
  53.     "NLP_MSGQUEUE" : 1 << 15 ,
  54.     "BROADCAST_MODE" : 1 << 16 ,
  55.     "CLOSED_IF_NO_MODS" : 1 << 17 ,
  56.     "IS_CLOSED" : 1 << 18 ,
  57.     "SHOW_MOD_ICONS" : 1 << 19 ,
  58.     "MODS_CHOOSE_VISIBILITY" : 1 << 20 ,
  59.     "NLP_NGRAM" : 1 << 21 ,
  60.     "NO_PROXIES" : 1 << 22 ,
  61.     "HAS_XML" : 1 << 28 ,
  62.     "UNSAFE" : 1 << 29
  63.     }
  64.  
  65. ModeratorFlags = {
  66.     "DELETED" : 1 << 0 ,
  67.     "EDIT_MODS" :  1 << 1 ,
  68.     "EDIT_MOD_VISIBILITY" : 1 << 2 ,
  69.     "EDIT_BW" : 1 << 3 ,
  70.     "EDIT_RESTRICTIONS" : 1 << 4 ,
  71.     "EDIT_GROUP" : 1 << 5 ,
  72.     "SEE_COUNTER" : 1 << 6 ,
  73.     "SEE_MOD_CHANNEL" : 1 << 7 ,
  74.     "SEE_MOD_ACTIONS" : 1 << 8 ,
  75.     "EDIT_NLP" : 1 << 9 ,
  76.     "EDIT_GP_ANNC" : 1 << 10 ,
  77.     "EDIT_ADMINS" : 1 << 11 ,
  78.     "EDIT_SUPERMODS" : 1 << 12 ,
  79.     "NO_SENDING_LIMITATIONS" : 1 << 13 ,
  80.     "SEE_IPS" : 1 << 14 ,
  81.     "CLOSE_GROUP" : 1 << 15 ,
  82.     "CAN_BROADCAST" : 1 << 16 ,
  83.     "MOD_ICON_VISIBLE" : 1 << 17 ,
  84.     "IS_STAFF" : 1 << 18 ,
  85.     "STAFF_ICON_VISIBLE" : 1 << 19 ,
  86.     "UNBAN_ALL" : 1 << 20
  87.     }
  88.  
  89. def getFlag(n, FlagSet):
  90.     if n <= 0: return {}
  91.     newflag = FlagSet
  92.     f = FlagSet.values()
  93.     c = 0
  94.     bit = n
  95.     newset = {}
  96.     while bit != 0:
  97.         bit >>= 1
  98.         c += 1
  99.         tv = 1 << c
  100.         if tv not in f:
  101.             newflag[str(tv)] = tv
  102.    
  103.     for flag, number in newflag.items():
  104.         if n & number :
  105.             newset[flag] = number
  106.          
  107.     return newset
  108.  
  109. specials = {'tango-hyoo': 60,
  110.             'monosekai': 76,
  111.             'nico-nico': 29
  112.             }
  113.  
  114. tsweights = [['5', 75], ['6', 75], ['7', 75], ['8', 75], ['16', 75], ['17', 75], ['18', 75], ['9', 95], ['11', 95], ['12', 95], ['13', 95], ['14', 95], ['15', 95], ['19', 110], ['23', 110], ['24', 110], ['25', 110], ['26', 110], ['28', 104], ['29', 104], ['30', 104], ['31', 104], ['32', 104], ['33', 104], ['35', 101], ['36', 101], ['37', 101], ['38', 101], ['39', 101], ['40', 101], ['41', 101], ['42', 101], ['43', 101], ['44', 101], ['45', 101], ['46', 101], ['47', 101], ['48', 101], ['49', 101], ['50', 101], ['52', 110], ['53', 110], ['55', 110], ['57', 110], ['58', 110], ['59', 110], ['60', 110], ['61', 110], ['62', 110], ['63', 110], ['64', 110], ['65', 110], ['66', 110], ['68', 95], ['71', 116], ['72', 116], ['73', 116], ['74', 116], ['75', 116], ['76', 116], ['77', 116], ['78', 116], ['79', 116], ['80', 116], ['81', 116], ['82', 116], ['83', 116], ['84', 116]]
  115.  
  116. def getServer(group):
  117.   try:
  118.     sn = specials[group]
  119.   except KeyError:
  120.     group = group.replace("_", "q")
  121.     group = group.replace("-", "q")
  122.     fnv = float(int(group[0:min(5, len(group))], 36))
  123.     lnv = group[6: (6 + min(3, len(group) - 5))]
  124.     if(lnv):
  125.       lnv = float(int(lnv, 36))
  126.       lnv = max(lnv,1000)
  127.     else:
  128.       lnv = 1000
  129.     num = (fnv % lnv) / lnv
  130.     maxnum = sum(map(lambda x: x[1], tsweights))
  131.     cumfreq = 0
  132.     sn = 0
  133.     for wgt in tsweights:
  134.       cumfreq += float(wgt[1]) / maxnum
  135.       if(num <= cumfreq):
  136.         sn = int(wgt[0])
  137.         break
  138.   return "s" + str(sn) + ".chatango.com"
  139.  
  140. def genUid():
  141.   return str(random.randrange(10 ** 15, 10 ** 16))
  142.  
  143. def clean_message(msg):
  144.   n = re.search("<n(.*?)/>", msg)
  145.   if n: n = n.group(1)
  146.   f = re.search("<f(.*?)>", msg)
  147.   if f: f = f.group(1)
  148.   msg = re.sub("<n.*?/>", "", msg)
  149.   msg = re.sub("<f.*?>", "", msg)
  150.   msg = strip_html(msg)
  151.   msg = msg.replace("&lt;", "<")
  152.   msg = msg.replace("&gt;", ">")
  153.   msg = msg.replace("&quot;", "\"")
  154.   msg = msg.replace("&apos;", "'")
  155.   msg = msg.replace("&amp;", "&")
  156.   return msg, n, f
  157.  
  158. def strip_html(msg):
  159.     msg = re.sub("<\/?[^>]*>", "", msg)
  160.     return msg
  161.  
  162. def parseNameColor(n):
  163.   return n
  164.  
  165. def parseFont(f):
  166.   try:
  167.     sizecolor, fontface = f.split("=", 1)
  168.     sizecolor = sizecolor.strip()
  169.     size = int(sizecolor[1:3])
  170.     col = sizecolor[3:6]
  171.     if col == "": col = None
  172.     face = f.split("\"", 2)[1]
  173.     return col, face, size
  174.   except:
  175.     return None, None, None
  176.  
  177. def getAnonId(n, ssid):
  178.   if n == None: n = "5504"
  179.   try:
  180.     return "".join(list(
  181.       map(lambda x: str(x[0] + x[1])[-1], list(zip(
  182.         list(map(lambda x: int(x), n)),
  183.         list(map(lambda x: int(x), ssid[4:]))
  184.       )))
  185.     ))
  186.   except ValueError:
  187.     return "NNNN"
  188.  
  189. class PM:
  190.   def __init__(self, mgr):
  191.     self._auth_re = re.compile(r"auth\.chatango\.com ?= ?([^;]*)", re.IGNORECASE)
  192.     self._connected = False
  193.     self._reconnecting = False
  194.  
  195.     self._mgr = mgr
  196.     self._auid = None
  197.     self._premium = False
  198.     self._blocklist = set()
  199.     self._contacts = set()
  200.     self._status = dict()
  201.     self._wlock = False
  202.     self._firstCommand = True
  203.     self._wbuf = ""
  204.     self._wlockbuf = ""
  205.     self._pingTask = None
  206.  
  207.     if self._mgr:
  208.       self._connect()
  209.  
  210.   def _getAuth(self, name, password):
  211.     data = urllib.parse.urlencode({
  212.       "user_id": name,
  213.       "password": password,
  214.       "storecookie": "on",
  215.       "checkerrors": "yes"
  216.     }).encode()
  217.     try:
  218.       resp = urllib.request.urlopen("https://chatango.com/login", data)
  219.       headers = resp.headers
  220.     except Exception:
  221.       return None
  222.     for header, value in headers.items():
  223.       if header.lower() == "set-cookie":
  224.         m = self._auth_re.search(value)
  225.         if m:
  226.           auth = m.group(1)
  227.           if auth == "":
  228.             return None
  229.           return auth
  230.     return None
  231.  
  232.   def _auth(self):
  233.     self._auid = self._getAuth(self._mgr.name, self._mgr.password)
  234.     if self._auid == None:
  235.       self._websock.close()
  236.       self._callEvent("onLoginFail")
  237.       return False
  238.     self._sendCommand("tlogin", self._auid, "2")
  239.     self._setWriteLock(True)
  240.     return True
  241.  
  242.   def connect(self):
  243.     self._connect()
  244.  
  245.   def _connect(self):
  246.    
  247.       self._websock = websocket.WebSocket()
  248.       self._websock.connect('ws://%s:%s/' % (self._mgr._PMHost, self._mgr._PMPort), origin='https://st.chatango.com')
  249.       self._auth()
  250.       self._pingTask = self.mgr.setInterval(self.mgr._pingDelay, self.ping)
  251.    
  252.    
  253.   def attemptReconnect(self):
  254.     try:
  255.       print("try reconect PM attempt %s" %  (self._attempt))
  256.       self._reconnect()
  257.     except:
  258.       time.sleep(10)
  259.       self._attempt -= 1
  260.       if self._attempt > 0:
  261.         self.attemptReconnect()
  262.       else:
  263.         print("failed to reconnect PM")
  264.         self.disconnect()
  265.      
  266.   def reconnect(self):
  267.     self._attempt = 3
  268.     self.attemptReconnect()
  269.  
  270.   def _reconnect(self):
  271.     self._reconnecting = True
  272.     if self._connected:
  273.       self._disconnect()
  274.     self._connect()  
  275.     self._reconnecting = False
  276.     self._callEvent("onPMReconnect")
  277.    
  278.   def disconnect(self):
  279.     self._disconnect()
  280.     self._callEvent("onPMDisconnect")
  281.  
  282.   def _disconnect(self):
  283.     self._connected = False
  284.     self._pingTask.cancel()
  285.     self._websock.close()
  286.  
  287.   def _feed(self, data):
  288.     data = data.split(b"\x00")
  289.     for food in data:
  290.       self._process(food.decode(errors="replace").rstrip("\r\n").replace("&#39;", "'"))
  291.  
  292.   def _process(self, data):
  293.     self._callEvent("onRaw", data)
  294.     data = data.split(":")
  295.     cmd, args = data[0], data[1:]
  296.     #print(cmd, args)
  297.     func = "rcmd_" + cmd
  298.     if hasattr(self, func):
  299.       getattr(self, func)(args)
  300.  
  301.   def getManager(self): return self._mgr
  302.   def getContacts(self): return self._contacts
  303.   def getBlocklist(self): return self._blocklist
  304.  
  305.   mgr = property(getManager)
  306.   contacts = property(getContacts)
  307.   blocklist = property(getBlocklist)
  308.  
  309.   def rcmd_OK(self, args):
  310.     self._connected = True
  311.     self._setWriteLock(False)
  312.     self._sendCommand("wl")
  313.     self._sendCommand("getblock")
  314.     self._sendCommand("getpremium", "1")
  315.     self._callEvent("onPMConnect")
  316.  
  317.   def rcmd_wl(self, args):
  318.     self._contacts = set()
  319.     for i in range(len(args) // 4):
  320.       name, last_on, is_on, idle = args[i * 4: i * 4 + 4]
  321.       user = User(name)
  322.       if last_on=="None":pass
  323.       elif is_on == "off": self._status[user] = [int(last_on), "offline", 0]
  324.       elif is_on == "app": self._status[user] = [int(last_on), "app", 0]
  325.       elif idle == '0' and is_on == "on": self._status[user] = [int(last_on), "online", 0]
  326.       else: self._status[user] = [int(last_on), "online", time.time() - int(idle) * 60]
  327.       self._contacts.add(user)
  328.     self._callEvent("onPMContactlistReceive")
  329.  
  330.   def rcmd_wladd(self, args):
  331.     name, is_on, last_on = args
  332.     user = User(name)
  333.     if is_on == "on":
  334.       if last_on == '0':
  335.         idle = 0
  336.       else:
  337.         idle = time.time() - int(last_on) * 60
  338.       last_on = 0
  339.       is_on = "online"
  340.     elif is_on == "app":
  341.       if last_on == '0':
  342.         idle = 0
  343.       else:
  344.         idle = time.time() - int(last_on) * 60
  345.       last_on = 0
  346.       is_on = "app"
  347.     else:
  348.       idle = 0
  349.       if last_on == "None":
  350.         last_on = 0
  351.       else:
  352.         last_on = int(last_on)
  353.       is_on = "offline"
  354.     self._status[user] = [last_on, is_on, idle]
  355.     if user not in self._contacts:
  356.       self._contacts.add(user)
  357.     self._callEvent("onPMContactAdd", user)
  358.  
  359.   def rcmd_wldelete(self, args):
  360.     user = User(args[0])
  361.     if user in self._contacts:
  362.       self._contacts.remove(user)
  363.     self._callEvent("onPMContactRemove", user)
  364.  
  365.   def rcmd_block_list(self, args):
  366.     self._blocklist = set()
  367.     for name in args:
  368.       if name == "": continue
  369.       self._blocklist.add(User(name))
  370.  
  371.   def rcmd_idleupdate(self, args):
  372.     user = User(args[0])
  373.     if user in self._status:
  374.       last_on, is_on, idle = self._status[user]  
  375.     if args[1] == '1':
  376.       self._status[user] = [last_on, is_on, 0]
  377.     else:
  378.       self._status[user] = [last_on, is_on, time.time()]
  379.  
  380.   def rcmd_track(self, args):
  381.     user = User(args[0])
  382.     is_on = args[2]
  383.     if is_on == "online":
  384.       if args[1] == '0':
  385.         idle = 0
  386.       else:
  387.         idle = time.time() - float(args[1]) * 60
  388.       last_on = idle
  389.     else:
  390.       last_on = float(args[1])
  391.       idle = 0
  392.     self._status[user] = [last_on, is_on, idle]
  393.  
  394.   def rcmd_status(self, args):
  395.     user = User(args[0])
  396.     is_on = args[2]
  397.     if is_on == "online":
  398.       if args[1] == '0':
  399.         idle = 0
  400.       else:
  401.         idle = time.time() - float(args[1]) * 60
  402.       last_on = idle
  403.     else:
  404.       last_on = float(args[1])
  405.       idle = 0
  406.     self._status[user] = [last_on, is_on, idle]
  407.  
  408.   def rcmd_connect(self, args):
  409.     user = User(args[0])
  410.     is_on = args[2]
  411.     if is_on == "online":
  412.       if args[1] == '0':
  413.         idle = 0
  414.       else:
  415.         idle = time.time() - float(args[1]) * 60
  416.       last_on = idle
  417.     else:
  418.       last_on = float(args[1])
  419.       idle = 0
  420.     self._status[user] = [last_on, is_on, idle]
  421.  
  422.   def rcmd_DENIED(self, args):
  423.     self._disconnect()
  424.     self._callEvent("onLoginFail")
  425.  
  426.   def rcmd_msg(self, args):
  427.     user = User(args[0])
  428.     body = strip_html(":".join(args[5:]))
  429.     self._callEvent("onPMMessage", user, body)
  430.  
  431.   def rcmd_msgoff(self, args):
  432.     user = User(args[0])
  433.     body = strip_html(":".join(args[5:]))
  434.     self._callEvent("onPMOfflineMessage", user, body)
  435.  
  436.   def rcmd_wlonline(self, args):
  437.     user = User(args[0])
  438.     last_on = float(args[1])
  439.     self._status[user] = [last_on,"online",last_on]
  440.     self._callEvent("onPMContactOnline", user)
  441.  
  442.   def rcmd_wlapp(self, args):
  443.     user = User(args[0])
  444.     last_on = float(args[1])
  445.     self._status[user] = [last_on,"app",last_on]
  446.     self._callEvent("onPMContactApp", user)
  447.  
  448.   def rcmd_wloffline(self, args):
  449.     user = User(args[0])
  450.     last_on = float(args[1])
  451.     self._status[user] = [last_on,"offline",0]
  452.     self._callEvent("onPMContactOffline", user)
  453.  
  454.   def rcmd_premium(self, args):
  455.     if float(args[1]) > time.time():
  456.       self._premium = True
  457.       self.setBgMode(1)
  458.       self.setRecordingMode(1)
  459.     else:
  460.       self._premium = False
  461.  
  462.   def rcmd_kickingoff(self, args):
  463.     self.disconnect()
  464.  
  465.   def rcmd_toofast(self, args):
  466.     self.disconnect()
  467.  
  468.   def rcmd_unblocked(self, user):
  469.     if user in self._blocklist:
  470.       self._blocklist.remove(user)
  471.       self._callEvent("onPMUnblock", user)
  472.  
  473.   def ping(self):
  474.     self._sendCommand("")
  475.     self._callEvent("onPMPing")
  476.  
  477.   def message(self, user, msg):
  478.     if msg!=None:
  479.       msg = "<n%s/><m v=\"1\"><g x%ss%s=\"%s\">%s</g></m>" % (self._mgr.user.nameColor.lower(), self._mgr.user.fontSize, self._mgr.user.fontColor.lower(), self._mgr.user.fontFace, msg)
  480.       self._sendCommand("msg", user.name, msg)
  481.  
  482.   def addContact(self, user):
  483.     if user not in self._contacts:
  484.       self._sendCommand("wladd", user.name)
  485.  
  486.   def removeContact(self, user):
  487.     if user in self._contacts:
  488.       self._sendCommand("wldelete", user.name)
  489.  
  490.   def block(self, user):
  491.     if user not in self._blocklist:
  492.       self._sendCommand("block", user.name, user.name, "S")
  493.       self._blocklist.add(user)
  494.       self._callEvent("onPMBlock", user)
  495.  
  496.   def unblock(self, user):
  497.     if user in self._blocklist:
  498.       self._sendCommand("unblock", user.name)
  499.  
  500.   def setBgMode(self, mode):
  501.     self._sendCommand("msgbg", str(mode))
  502.  
  503.   def setRecordingMode(self, mode):
  504.     self._sendCommand("msgmedia", str(mode))
  505.  
  506.   def setIdle(self):
  507.     self._sendCommand("idle:0")
  508.  
  509.   def setActive(self):
  510.     self._sendCommand("idle:1")
  511.  
  512.   def rawTrack(self, user):
  513.     cmd = ":".join(["track" , user.name]) + "\r\n\x00"
  514.     self._websock.send(cmd)
  515.     op, data = self._websock.recv_data()
  516.     cmd = "\r\n\x00"
  517.     self._websock.send(cmd)
  518.     if(len(data) > 0):
  519.       self._feed(data)
  520.  
  521.   def track(self, user):
  522.     self.rawTrack(user)
  523.     return self._status[user]
  524.  
  525.   def checkOnline(self, user):
  526.     if user in self._status:
  527.       return self._status[user][1]
  528.     else:
  529.       return None
  530.  
  531.   def getIdle(self, user):
  532.     if not user in self._status: return None
  533.     if not self._status[user][1]: return 0
  534.     if not self._status[user][2]: return time.time()
  535.     else: return self._status[user][2]
  536.  
  537.   def _callEvent(self, evt, *args, **kw):
  538.     getattr(self.mgr, evt)(self, *args, **kw)
  539.     self.mgr.onEventCalled(self, evt, *args, **kw)
  540.  
  541.   def _write(self, data):
  542.     if self._wlock:
  543.       self._wlockbuf += data
  544.     else:
  545.       self._wbuf += data
  546.  
  547.   def _setWriteLock(self, lock):
  548.     self._wlock = lock
  549.     if self._wlock == False:
  550.       self._write(self._wlockbuf)
  551.       self._wlockbuf = ""
  552.      
  553.   def _sendCommand(self, *args):
  554.     if self._firstCommand:
  555.       terminator = "\x00"
  556.       self._firstCommand = False
  557.     else:
  558.       terminator = "\r\n\x00"
  559.     cmd = ":".join(args) + terminator
  560.     self._write(cmd)
  561.     return cmd
  562.  
  563. class Room:
  564.   def __init__(self, room, uid = None, server = None, port = None, mgr = None):
  565.     self._name = room
  566.     self._server = server or getServer(room)
  567.     self._port = port or 8081 #1800/8080
  568.     self._mgr = mgr
  569.     self._wlock = False
  570.     self._firstCommand = True
  571.     self._wbuf = ""
  572.     self._wlockbuf = ""
  573.     self._connected = False
  574.     self._reconnecting = False
  575.     self._uid = uid or genUid()
  576.     self._channel = "0"
  577.     self._owner = None
  578.     self._mods = dict()
  579.     self._mqueue = dict()
  580.     self._mbqueue = dict()
  581.     self._history = list()
  582.     self._status = dict()
  583.     self._connectAmmount = 0
  584.     self._premium = False
  585.     self._userCount = 0
  586.     self._pingTask = None
  587.     self._users = dict()
  588.     self._msgs = dict()
  589.     self._silent = False
  590.     self._banlist = dict()
  591.     self._unbanlist = dict()
  592.     self._bannedwords = list()
  593.    
  594.     if self._mgr:
  595.       self._mgr._rooms[self.name] = self
  596.       self._connect()
  597.  
  598.   def getMessage(self, mid):
  599.     return self._msgs.get(mid)
  600.  
  601.   def createMessage(self, msgid, **kw):
  602.     if msgid not in self._msgs:
  603.       msg = Message(msgid = msgid, **kw)
  604.       self._msgs[msgid] = msg
  605.     else:
  606.       msg = self._msgs[msgid]
  607.     return msg
  608.  
  609.   def connect(self):
  610.     self._connect()
  611.  
  612.   def _connect(self):
  613.     self._websock = websocket.WebSocket()
  614.     self._websock.connect('wss://%s:%s/' % (self._server, self._port), origin='https://st.chatango.com', header = { "Pragma" : "no-cache", "Cache-Control" : "no-cache" })
  615.     self._auth()
  616.     self._pingTask = self.mgr.setInterval(self.mgr._pingDelay, self.ping)
  617.  
  618.  
  619.   def attemptReconnect(self):
  620.     try:
  621.       print("try reconect %s attempt %s" %  (self.name, self._attempt))
  622.       self._reconnect()
  623.     except:
  624.       time.sleep(10)
  625.       self._attempt -= 1
  626.       if self._attempt > 0:
  627.         self.attemptReconnect()
  628.       else:
  629.         print("failed to reconnect %s" % self.name)
  630.         self.disconnect()
  631.      
  632.   def reconnect(self):
  633.     self._attempt = 3
  634.     self.attemptReconnect()
  635.  
  636.   def _reconnect(self):
  637.     self._reconnecting = True
  638.     if self._connected:
  639.       self._disconnect()
  640.     self._connect()
  641.     self._reconnecting = False
  642.  
  643.   def disconnect(self):
  644.     self._disconnect()
  645.     self._callEvent("onDisconnect")
  646.  
  647.   def _disconnect(self):
  648.     self._connected = False
  649.     self._pingTask.cancel()
  650.     self._websock.close()
  651.     if not self._reconnecting:
  652.       if self.name in self.mgr._rooms:
  653.         del self.mgr._rooms[self.name]
  654.    
  655.   def _auth(self):
  656.     if self._mgr._name and self._mgr._password:
  657.       self._sendCommand("bauth", self._name, self._uid, self._mgr._name, self._mgr._password)
  658.     else:
  659.       self._sendCommand("bauth", self._name, self._uid)
  660.     self._setWriteLock(True)
  661.      
  662.   def login(self, name, password=None):
  663.     if password != None:
  664.       self._sendCommand("blogin", name, password)
  665.     else:
  666.       self._sendCommand("blogin", name)
  667.  
  668.   def logout(self):
  669.     self._sendCommand("blogout")
  670.  
  671.   def getName(self): return self._name
  672.   def getManager(self): return self._mgr
  673.   def getUserlist(self):
  674.     ul = []
  675.     for data in self._status.values():
  676.       user = data[0]
  677.       if user not in ul:
  678.           ul.append(user)
  679.     return ul
  680.  
  681.   def _getUserlist(self):
  682.     ul = []
  683.     for data in self._status.values():
  684.       user = data[0]
  685.       if user.name[0] not in ["!", "#"]:
  686.         ul.append(user)
  687.     return ul
  688.    
  689.   def getUserNames(self):
  690.     ul = self.getUserlist()
  691.     return list(map(lambda x: x.name, ul))
  692.  
  693.   def getOwner(self): return self._owner
  694.   def getOwnerName(self): return self._owner.name
  695.   def getMods(self):
  696.     newset = set()
  697.     for mod in self._mods.keys():
  698.       newset.add(mod)
  699.     return newset
  700.   def getModNames(self):
  701.     mods = self._mods.keys()
  702.     newset = list()
  703.     for x in mods:
  704.       newset.append(x.name)
  705.     return newset
  706.   def getUserCount(self):
  707.     if self._userCount == 0:
  708.       return len(self.getUserlist())
  709.     else:
  710.       return self._userCount
  711.   def getSilent(self): return self._silent
  712.   def setSilent(self, val): self._silent = val
  713.   def getBanlist(self): return list(self._banlist.keys())
  714.   def getUnBanlist(self): return [(record["target"], record["src"]) for record in self._unbanlist.values()]
  715.   def getBannedWords(self): return self._bannedwords
  716.   def getFlags(self): return self._flags
  717.    
  718.   name = property(getName)
  719.   mgr = property(getManager)
  720.   userlist = property(getUserlist)
  721.   _userlist = property(_getUserlist)
  722.   usernames = property(getUserNames)
  723.   owner = property(getOwner)
  724.   ownername = property(getOwnerName)
  725.   mods = property(getMods)
  726.   modnames = property(getModNames)
  727.   usercount = property(getUserCount)
  728.   silent = property(getSilent, setSilent)
  729.   banlist = property(getBanlist)
  730.   unbanlist = property(getUnBanlist)
  731.   bannedwords = property(getBannedWords)
  732.   flags = property(getFlags)
  733.  
  734.   def _feed(self, data):
  735.     data = data.split(b"\x00")
  736.     for food in data:
  737.       self._process(food.decode(errors="replace").rstrip("\r\n").replace("&#39;", "'"))
  738.      
  739.   def _process(self, data):
  740.     self._callEvent("onRaw", data)
  741.     data = data.split(":")
  742.     cmd, args = data[0], data[1:]
  743.     #print(cmd, args)
  744.     func = "rcmd_" + cmd
  745.     if hasattr(self, func):
  746.       getattr(self, func)(args)
  747.  
  748.   def rcmd_ok(self, args):
  749.     self._connected = True
  750.     self._attempt = 0
  751.     if args[2] == "C" and self._mgr._password == None and self._mgr._name == None:
  752.       n = args[4].rsplit('.', 1)[0]
  753.       n = n[-4:]
  754.       pid = args[1][0:8]
  755.       name = "!anon" + getAnonId(n, pid)
  756.       self._mgr.user._nameColor = n
  757.     elif args[2] == "C" and self._mgr._password == None:
  758.       self.login(self._mgr._name)
  759.     elif args[2] != "M":
  760.       self._callEvent("onLoginFail")
  761.       self.disconnect()
  762.     self._owner = User(args[0])
  763.     self._uid = args[1]
  764.     self._aid = args[1][4:8]
  765.     if len(args[6]) > 0:
  766.       self._mods = dict((x,y) for x, y in list(map(lambda x: (User(x.split(",")[0]), getFlag(int(x.split(",")[1]), ModeratorFlags)), args[6].split(";"))))
  767.     self._flags = getFlag(int(args[7]), RoomFlags)
  768.     self._i_log = list()
  769.  
  770.   def rcmd_groupflagsupdate(self, args):
  771.     old_flags = set(self._flags.items())
  772.     self._flags = getFlag(int(args[0]), RoomFlags)
  773.     new_flags = set(self._flags.items())
  774.     add_flags = new_flags - old_flags
  775.     if len(add_flags) > 0:
  776.       self._callEvent("onGroupFlagsAdded", dict(add_flags))
  777.      
  778.     remove_flags = old_flags - new_flags
  779.     if len(remove_flags) > 0:
  780.       self._callEvent("onGroupFlagsRemoved", dict(remove_flags))
  781.      
  782.     self._callEvent("onGroupFlagsUpdate")
  783.  
  784.   def rcmd_denied(self, args):
  785.     self._disconnect()
  786.     self._callEvent("onConnectFail")
  787.  
  788.   def rcmd_inited(self, args):
  789.     self._sendCommand("g_participants", "start")
  790.     self._sendCommand("getpremium", "1")
  791.     self._sendCommand("getbannedwords")
  792.     self._sendCommand("getratelimit")
  793.     self.requestBanlist()
  794.     self.requestUnBanlist()
  795.     if self._connectAmmount == 0:
  796.       self._callEvent("onConnect")
  797.       for msg in reversed(self._i_log):
  798.         user = msg.user
  799.         self._callEvent("onHistoryMessage", user, msg)
  800.         self._addHistory(msg)
  801.       del self._i_log
  802.     else:
  803.       self._callEvent("onReconnect")
  804.     self._connectAmmount += 1
  805.     self._setWriteLock(False)
  806.  
  807.   def rcmd_getratelimit(self, args):
  808.     pass
  809.  
  810.   def rcmd_bw(self, args):
  811.     for word in args:
  812.       words = urllib.parse.unquote(word).split(",")
  813.       for word in words:
  814.         if word not in self._bannedwords and len(word) > 0:  
  815.             self._bannedwords.append(word)
  816.     bannedwords = self._bannedwords
  817.     self._callEvent("onBannedWordsUpdated", bannedwords)
  818.  
  819.   def rcmd_premium(self, args):
  820.     if float(args[1]) > time.time():
  821.       self._premium = True
  822.       if self._mgr.user._mbg: self.setBgMode(1)
  823.       if self._mgr.user._mrec: self.setRecordingMode(1)
  824.     else:
  825.       self._premium = False
  826.  
  827.   def rcmd_mods(self, args):
  828.     modnames = args
  829.     mods = dict((x, y) for x, y in list(map(lambda x: (User(x.split(",")[0]), getFlag(int(x.split(",")[1]), ModeratorFlags)), modnames)))
  830.     curmods = mods.keys()
  831.     premods = self._mods.keys()
  832.     for user in curmods - premods: #modded
  833.       self._callEvent("onModAdd", user)
  834.     for user in premods - curmods: #demodded
  835.       self._callEvent("onModRemove", user)
  836.     self._callEvent("onModChange")
  837.     self._mods = mods
  838.  
  839.   def rcmd_b(self, args):
  840.     mtime = float(args[0])
  841.     channel = args[7]
  842.     puid = args[3]
  843.     ip = args[6]
  844.     name = args[1]
  845.     rawmsg = ":".join(args[8:])
  846.     msg, n, f = clean_message(rawmsg)
  847.     if name == "":
  848.       nameColor = None
  849.       name = "#" + args[2]
  850.       if name == "#":
  851.         name = "!anon" + getAnonId(n, puid)
  852.     else:
  853.       if n: nameColor = parseNameColor(n)
  854.       else: nameColor = None
  855.     i = args[5]
  856.     unid = args[4]
  857.     user = User(name)
  858.     if puid:
  859.       user.updatePuid(puid)
  860.     if f: fontColor, fontFace, fontSize = parseFont(f)
  861.     else: fontColor, fontFace, fontSize = None, None, None
  862.     msg = Message(
  863.       time = mtime,
  864.       channel = channel,
  865.       user = user,
  866.       body = msg[1:],
  867.       raw = rawmsg[1:],
  868.       uid = puid,
  869.       ip = ip,
  870.       nameColor = nameColor,
  871.       fontColor = fontColor,
  872.       fontFace = fontFace,
  873.       fontSize = fontSize,
  874.       unid = unid,
  875.       room = self
  876.     )
  877.  
  878.     umsgid = self._mbqueue.get(i)
  879.     if umsgid:
  880.         if msg.user != self.mgr.user:
  881.           msg.user._fontColor = msg.fontColor
  882.           msg.user._fontFace = msg.fontFace
  883.           msg.user._fontSize = msg.fontSize
  884.           msg.user._nameColor = msg.nameColor
  885.  
  886.         del self._mbqueue[i]
  887.         self._channel = msg.channel  
  888.         thread = threading.Thread(target=self._callEvent, args = ("onMessage", msg.user, msg, ))
  889.         thread.daemon = True
  890.         thread.start()
  891.         self._addHistory(msg)
  892.     else:
  893.         self._mqueue[i] = msg
  894.  
  895.   def rcmd_u(self, args):
  896.     msg = self._mqueue.get(args[0])
  897.     if msg:
  898.         if msg.user != self.mgr.user:
  899.           msg.user._fontColor = msg.fontColor
  900.           msg.user._fontFace = msg.fontFace
  901.           msg.user._fontSize = msg.fontSize
  902.           msg.user._nameColor = msg.nameColor
  903.          
  904.         del self._mqueue[args[0]]
  905.         msg.attach(self, args[1])
  906.         self._channel = msg.channel  
  907.         thread = threading.Thread(target=self._callEvent, args = ("onMessage", msg.user, msg, ))
  908.         thread.daemon = True
  909.         thread.start()
  910.         self._addHistory(msg)
  911.     else:
  912.         self._mbqueue[args[0]] = args[1]
  913.  
  914.   def rcmd_i(self, args):
  915.     mtime = float(args[0])
  916.     channel = args[7]
  917.     puid = args[3]
  918.     ip = args[6]
  919.     if ip == "": ip = None
  920.     name = args[1]
  921.     rawmsg = ":".join(args[8:])
  922.     msg, n, f = clean_message(rawmsg)
  923.     msgid = args[5]
  924.     if name == "":
  925.       nameColor = None
  926.       name = "#" + args[2]
  927.       if name == "#":
  928.         name = "!anon" + getAnonId(n, puid)
  929.     else:
  930.       if n: nameColor = parseNameColor(n)
  931.       else: nameColor = None
  932.     if f: fontColor, fontFace, fontSize = parseFont(f)
  933.     else: fontColor, fontFace, fontSize = None, None, None
  934.     user = User(name)
  935.     if puid:
  936.       user.updatePuid(puid)
  937.     msg = self.createMessage(
  938.       msgid = msgid,
  939.       time = mtime,
  940.       channel = channel,
  941.       user = user,
  942.       body = msg,
  943.       raw = rawmsg,
  944.       ip = args[6],
  945.       unid = args[4],
  946.       nameColor = nameColor,
  947.       fontColor = fontColor,
  948.       fontFace = fontFace,
  949.       fontSize = fontSize,
  950.       room = self
  951.     )
  952.     self._i_log.append(msg)
  953.  
  954.   def rcmd_g_participants(self, args):
  955.     args = ":".join(args)
  956.     args = args.split(";")
  957.     for data in args:
  958.       data = data.split(":")
  959.       sid = data[0]
  960.       usertime = float(data[1])
  961.       name = data[3]
  962.       puid = data[2]
  963.       if name.lower() == "none":
  964.           n = str(int(usertime))[-4:]
  965.           if data[4].lower() == "none":
  966.             name = "!anon" + getAnonId(n, puid)
  967.           else:
  968.             name = "#" + data[4]
  969.       user = User(name)
  970.       if puid:
  971.         user.updatePuid(puid)
  972.       user.addSessionId(self, sid)
  973.  
  974.       if sid not in self._status:
  975.         self._status[sid] = [user, usertime, data[2], data[3], data[4]]
  976.  
  977.   def rcmd_participant(self, args):
  978.     name = args[3]
  979.     sid = args[1]
  980.     usertime = float(args[6])
  981.     puid = args[2]
  982.     if name.lower() == "none":
  983.       n = str(int(usertime))[-4:]
  984.       if args[4].lower() == "none":
  985.         name = "!anon" + getAnonId(n, puid)
  986.       else:
  987.         name = "#" + args[4]
  988.     user = User(name)
  989.     if puid:
  990.       user.updatePuid(puid)
  991.     if args[0] == "0": #leave
  992.       user.removeSessionId(self, sid)
  993.       if sid in self._status:
  994.         del self._status[sid]
  995.         self._callEvent("onLeave", user, puid)
  996.        
  997.     if args[0] == "1" or args[0] == "2": #join
  998.       user.addSessionId(self, sid)
  999.       self._status[sid] = [user, usertime, args[2], args[3], args[4]]
  1000.       self._callEvent("onJoin", user, puid)
  1001.  
  1002.        
  1003.   def rcmd_show_fw(self, args):
  1004.     self._callEvent("onFloodWarning")
  1005.  
  1006.   def rcmd_show_tb(self, args):
  1007.     self._callEvent("onFloodBan")
  1008.  
  1009.   def rcmd_tb(self, args):
  1010.     self._callEvent("onFloodBanRepeat")
  1011.  
  1012.   def rcmd_delete(self, args):
  1013.     msg = self.getMessage(args[0])
  1014.     if msg:
  1015.       if msg in self._history:
  1016.         self._history.remove(msg)
  1017.         self._callEvent("onMessageDelete", msg.user, msg)
  1018.         msg.detach()
  1019.  
  1020.   def rcmd_deleteall(self, args):
  1021.     for msgid in args:
  1022.       self.rcmd_delete([msgid])
  1023.  
  1024.   def rcmd_n(self, args):
  1025.     self._userCount = int(args[0], 16)
  1026.     self._callEvent("onUserCountChange")
  1027.  
  1028.   def rcmd_blocklist(self, args):
  1029.     self._banlist = dict()
  1030.     sections = ":".join(args).split(";")
  1031.     for section in sections:
  1032.       params = section.split(":")
  1033.       if len(params) != 5: continue
  1034.       if params[2] == "": continue
  1035.       user = User(params[2])
  1036.       self._banlist[user] = {
  1037.         "unid":params[0],
  1038.         "ip":params[1],
  1039.         "target":user,
  1040.         "time":float(params[3]),
  1041.         "src":User(params[4])
  1042.       }
  1043.     self._callEvent("onBanlistUpdate")
  1044.  
  1045.   def rcmd_unblocklist(self, args):
  1046.     self._unbanlist = dict()
  1047.     sections = ":".join(args).split(";")
  1048.     for section in sections:
  1049.       params = section.split(":")
  1050.       if len(params) != 5: continue
  1051.       if params[2] == "": continue
  1052.       user = User(params[2])
  1053.       self._unbanlist[user] = {
  1054.         "unid":params[0],
  1055.         "ip":params[1],
  1056.         "target":user,
  1057.         "time":float(params[3]),
  1058.         "src":User(params[4])
  1059.       }
  1060.     self._callEvent("onUnBanlistUpdate")
  1061.  
  1062.   def rcmd_blocked(self, args):
  1063.     try:
  1064.       msg = self.getLastMessageByIp(args[1])
  1065.       if args[2] == "":
  1066.         target = msg.user
  1067.       else:
  1068.         target = User(args[2])
  1069.       user = User(args[3])
  1070.       self._banlist[target] = {"unid":args[0], "ip":args[1], "target":target, "time":float(args[4]), "src":user}
  1071.       self._callEvent("onBan", user, target)
  1072.       self.requestBanlist()
  1073.     except Exception as e:
  1074.       print(e)
  1075.    
  1076.   def rcmd_unblocked(self, args):
  1077.     if args[2] == "": return
  1078.     target = User(args[2])
  1079.     user = User(args[3])
  1080.     try:
  1081.        del self._banlist[target]
  1082.     except:
  1083.       return
  1084.     self._unbanlist[user] = {"unid":args[0], "ip":args[1], "target":target, "time":float(args[4]), "src":user}
  1085.     self._callEvent("onUnban", user, target)
  1086.     self.requestUnBanlist()
  1087.  
  1088.   def ping(self):
  1089.     self._sendCommand("")
  1090.     self._callEvent("onPing")
  1091.  
  1092.   def rawMessage(self, channel, msg):
  1093.     msg = "<n" + self._mgr.user.nameColor + "/>" + msg
  1094.     msg = "<f x%0.2i%s=\"%s\">" %(self._mgr.user.fontSize, self._mgr.user.fontColor, self._mgr.user.fontFace) + msg
  1095.     if not self._silent:
  1096.       self._sendCommand("bm", "tl2r", channel, msg)
  1097.  
  1098.   def message(self, msg, html = False, channel = None):
  1099.     if msg == None:
  1100.       return
  1101.     if not html:
  1102.       msg = msg.replace("<", "&lt;").replace(">", "&gt;")
  1103.     if len(msg) > self.mgr._maxLength:
  1104.       if self.mgr._tooBigMessage == BigMessage_Cut:
  1105.         self.message(msg[:self.mgr._maxLength], html = html)
  1106.       elif self.mgr._tooBigMessage == BigMessage_Multiple:
  1107.         while len(msg) > 0:
  1108.           sect = msg[:self.mgr._maxLength]
  1109.           msg = msg[self.mgr._maxLength:]
  1110.           self.message(sect, html = html)
  1111.       return
  1112.     if channel == None:
  1113.         channel = str(int(self._channel) + 64)
  1114.     self.rawMessage(channel, msg)
  1115.  
  1116.   def setBgMode(self, mode):
  1117.     self._sendCommand("msgbg", str(mode))
  1118.  
  1119.   def setRecordingMode(self, mode):
  1120.     self._sendCommand("msgmedia", str(mode))
  1121.  
  1122.   def addBadWord(self, word):
  1123.     if self.getLevel(self._mgr.user) == 2:
  1124.       self._bannedwords.append(word)
  1125.       self._sendCommand("setbannedwords", "403", ", ".join(self._bannedwords))
  1126.        
  1127.   def removeBadWord(self, word):
  1128.     if self.getLevel(self._mgr.user) == 2:
  1129.       self._bannedwords.remove(word)
  1130.       self._sendCommand("setbannedwords", "403", ", ".join(self._bannedwords))
  1131.  
  1132.   def addMod(self, user):
  1133.     if self.getLevel(self._mgr.user) == 2:
  1134.       self._sendCommand("addmod", user.name)
  1135.    
  1136.   def removeMod(self, user):
  1137.     if self.getLevel(self._mgr.user) == 2:
  1138.       self._sendCommand("removemod", user.name)
  1139.  
  1140.   def flag(self, message):
  1141.     self._sendCommand("g_flag", message.msgid)
  1142.  
  1143.   def flagUser(self, user):
  1144.     msg = self.getLastMessage(user)
  1145.     if msg:
  1146.       self.flag(msg)
  1147.       return True
  1148.     return False
  1149.  
  1150.   def delete(self, message):
  1151.     if self.getLevel(self._mgr.user) > 0:
  1152.       self._sendCommand("delmsg", message.msgid)
  1153.  
  1154.   def rawClearUser(self, unid, ip, user):
  1155.     self._sendCommand("delallmsg", unid, ip, user)
  1156.  
  1157.   def clearUser(self, user):
  1158.     if self.getLevel(self._mgr.user) > 0:
  1159.       msg = self.getLastMessage(user)
  1160.       if msg:
  1161.         if user.name[0] in ["!","#"]:
  1162.           username = ""
  1163.         else:
  1164.           username = user.name
  1165.         self.rawClearUser(msg.unid, msg.ip, username)
  1166.       return True
  1167.     return False
  1168.  
  1169.   def clearall(self):
  1170.     self._sendCommand("clearall")
  1171.     if self.getLevel(self._mgr.user) == 1:
  1172.       for msg in self._history:
  1173.         self.clearUser(msg.user)
  1174.     self._callEvent("onClearAll")
  1175.    
  1176.  
  1177.   def rawBan(self, name, ip, unid):
  1178.     self._sendCommand("block", unid, ip, name)
  1179.  
  1180.   def ban(self, msg):
  1181.     if self.getLevel(self._mgr.user) > 0:
  1182.       if msg.user.name[0] in ["!","#"]:
  1183.         username = ""
  1184.       else:
  1185.         username = msg.user.name
  1186.       self.rawBan(username, msg.ip, msg.unid)
  1187.  
  1188.   def banUser(self, user):
  1189.     msg = self.getLastMessage(user)
  1190.     if msg:
  1191.       self.ban(msg)
  1192.       return True
  1193.     return False
  1194.  
  1195.   def requestBanlist(self):
  1196.     self._sendCommand("blocklist", "block", "", "next", "500")
  1197.    
  1198.   def requestUnBanlist(self):
  1199.     self._sendCommand("blocklist", "unblock", "", "next", "500")
  1200.  
  1201.   def rawUnban(self, name, ip, unid):
  1202.     self._sendCommand("removeblock", unid, ip, name)
  1203.  
  1204.   def unban(self, user):
  1205.     rec = self._getBanRecord(user)
  1206.     if rec:
  1207.       self.rawUnban(rec["target"].name, rec["ip"], rec["unid"])
  1208.       return True
  1209.     else:
  1210.       return False
  1211.  
  1212.   def _getBanRecord(self, user):
  1213.     if user in self._banlist:
  1214.       return self._banlist[user]
  1215.     return None
  1216.  
  1217.   def _callEvent(self, evt, *args, **kw):
  1218.     #try:
  1219.     getattr(self.mgr, evt)(self, *args, **kw)
  1220.     #except Exception as e:
  1221.       #print("failed to call event", evt, e)
  1222.       #pass
  1223.     self.mgr.onEventCalled(self, evt, *args, **kw)
  1224.  
  1225.   def _write(self, data):
  1226.     if self._wlock:
  1227.       self._wlockbuf += data
  1228.     else:
  1229.       self._wbuf += data
  1230.  
  1231.   def _setWriteLock(self, lock):
  1232.     self._wlock = lock
  1233.     if self._wlock == False:
  1234.       self._write(self._wlockbuf)
  1235.       self._wlockbuf = ""
  1236.      
  1237.   def _sendCommand(self, *args):
  1238.     if self._firstCommand:
  1239.       terminator = "\x00"
  1240.       self._firstCommand = False
  1241.     else:
  1242.       terminator = "\r\n\x00"
  1243.     self._write(":".join(args) + terminator)
  1244.    
  1245.   def getLevel(self, user):
  1246.     if user == self._owner: return 2
  1247.     if user in self._mods: return 1
  1248.     return 0
  1249.  
  1250.   def getBadge(self, msg):
  1251.     channel = int(msg.channel)
  1252.     badge = getFlag(channel, MessageFlags)
  1253.     if "SHOW_MOD_ICON" in badge.keys() or "SHOW_STAFF_ICON" in badge.keys():
  1254.       return 1
  1255.     else:
  1256.       return 0
  1257.  
  1258.   def getLastMessage(self, user = None):
  1259.     if user:
  1260.       try:
  1261.         i = 1
  1262.         while True:
  1263.           msg = self._history[-i]
  1264.           if msg.user == user:
  1265.             return msg
  1266.           i += 1
  1267.       except IndexError:
  1268.         return None
  1269.     else:
  1270.       try:
  1271.         return self._history[-1]
  1272.       except IndexError:
  1273.         return None
  1274.     return None
  1275.  
  1276.   def getLastMessageByIp(self, ip = None):
  1277.     if ip:
  1278.       try:
  1279.         i = 1
  1280.         while True:
  1281.           msg = self._history[-i]
  1282.           if msg.ip == ip:
  1283.             return msg
  1284.           i += 1
  1285.       except IndexError:
  1286.         return None
  1287.     else:
  1288.       try:
  1289.         return self._history[-1]
  1290.       except IndexError:
  1291.         return None
  1292.     return None
  1293.  
  1294.   def findUser(self, name):
  1295.     name = name.lower()
  1296.     ul = self.getUserlist()
  1297.     udi = dict(zip([u.name for u in ul], ul))
  1298.     cname = None
  1299.     for n in udi.keys():
  1300.       if n.find(name) != -1:
  1301.         if cname: return None
  1302.         cname = n
  1303.     if cname: return udi[cname]
  1304.     else: return None
  1305.  
  1306.   def _addHistory(self, msg):
  1307.     self._history.append(msg)
  1308.     if self.getBadge(msg) > 0:
  1309.       if msg.user not in self._mods.keys() and msg.user != self._owner:
  1310.         self._mods[msg.user] = {}
  1311.     if len(self._history) > self.mgr._maxHistoryLength:
  1312.       rest, self._history = self._history[:-self.mgr._maxHistoryLength], self._history[-self.mgr._maxHistoryLength:]
  1313.       for msg in rest:
  1314.         msg.detach()
  1315.  
  1316. class RoomManager:
  1317.   _Room = Room
  1318.   _PM = PM
  1319.   _PMHost = "c1.chatango.com"
  1320.   _PMPort = 8080 #1800/8080
  1321.   _pingDelay = 20
  1322.   _tooBigMessage = BigMessage_Multiple
  1323.   _maxLength = 2800
  1324.   _maxHistoryLength = 150
  1325.  
  1326.   def __init__(self, name = None, password = None, pm = True):
  1327.     self._name = name
  1328.     self._password = password
  1329.     self._tasks = set()
  1330.     self._rooms = dict()
  1331.     self._running = False
  1332.     if pm:
  1333.       conn = self._PM(mgr = self)
  1334.       self._pm = conn
  1335.     else:
  1336.       self._pm = None
  1337.  
  1338.   def joinThread(self, room):
  1339.     self._Room(room, mgr = self)
  1340.    
  1341.   def joinRoom(self, room):
  1342.     room = room.lower()
  1343.     if room not in self._rooms:
  1344.       self.joinThread(room)
  1345.  
  1346.   def leaveRoom(self, room):
  1347.     room = room.lower()
  1348.     if room in self._rooms:
  1349.       con = self._rooms[room]
  1350.       con.disconnect()
  1351.  
  1352.   def getRoom(self, room):
  1353.     room = room.lower()
  1354.     if room in self._rooms:
  1355.       return self._rooms[room]
  1356.     else:
  1357.       return None
  1358.  
  1359.   def getUser(self): return User(self._name)
  1360.   def getName(self): return self._name
  1361.   def getPassword(self): return self._password
  1362.   def getRooms(self): return set(self._rooms.values())
  1363.   def getRoomNames(self): return set(self._rooms.keys())
  1364.   def getPM(self): return self._pm
  1365.  
  1366.   user = property(getUser)
  1367.   name = property(getName)
  1368.   password = property(getPassword)
  1369.   rooms = property(getRooms)
  1370.   roomnames = property(getRoomNames)
  1371.   pm = property(getPM)
  1372.  
  1373.   def onInit(self):
  1374.     pass
  1375.  
  1376.   def onConnect(self, room):
  1377.     pass
  1378.  
  1379.   def onReconnect(self, room):
  1380.     pass
  1381.  
  1382.   def onConnectFail(self, room):
  1383.     pass
  1384.  
  1385.   def onDisconnect(self, room):
  1386.     pass
  1387.  
  1388.   def onLoginFail(self, room):
  1389.     pass
  1390.  
  1391.   def onGroupFlagsUpdate(self, room):
  1392.     pass
  1393.  
  1394.   def onGroupFlagsAdded(self, room, flags):
  1395.     pass
  1396.  
  1397.   def onGroupFlagsRemoved(self, room, flags):
  1398.     pass
  1399.  
  1400.   def onFloodBan(self, room):
  1401.     pass
  1402.  
  1403.   def onFloodBanRepeat(self, room):
  1404.     pass
  1405.  
  1406.   def onFloodWarning(self, room):
  1407.     pass
  1408.  
  1409.   def onMessageDelete(self, room, user, message):
  1410.     pass
  1411.  
  1412.   def onModChange(self, room):
  1413.     pass
  1414.  
  1415.   def onModAdd(self, room, user):
  1416.     pass
  1417.    
  1418.   def onClearAll(self, room):
  1419.     pass
  1420.  
  1421.   def onModRemove(self, room, user):
  1422.     pass
  1423.  
  1424.   def onMessage(self, room, user, message):
  1425.     pass
  1426.  
  1427.   def onBannedWordsUpdated(self, room, words):
  1428.     pass
  1429.  
  1430.   def onHistoryMessage(self, room, user, message):
  1431.     pass
  1432.  
  1433.   def onJoin(self, room, user, puid):
  1434.     pass
  1435.  
  1436.   def onLeave(self, room, user, puid):
  1437.     pass
  1438.  
  1439.   def onRaw(self, room, raw):
  1440.     pass
  1441.  
  1442.   def onPing(self, room):
  1443.     pass
  1444.  
  1445.   def onUserCountChange(self, room):
  1446.     pass
  1447.  
  1448.   def onBan(self, room, user, target):
  1449.     pass
  1450.  
  1451.   def onUnban(self, room, user, target):
  1452.     pass
  1453.  
  1454.   def onBanlistUpdate(self, room):
  1455.     pass
  1456.  
  1457.   def onUnBanlistUpdate(self, room):
  1458.     pass
  1459.  
  1460.   def onPMConnect(self, pm):
  1461.     pass
  1462.  
  1463.   def onPMReconnect(self, pm):
  1464.     pass
  1465.  
  1466.   def onPMDisconnect(self, pm):
  1467.     pass
  1468.  
  1469.   def onPMPing(self, pm):
  1470.     pass
  1471.  
  1472.   def onPMMessage(self, pm, user, body):
  1473.     pass
  1474.  
  1475.   def onPMOfflineMessage(self, pm, user, body):
  1476.     pass
  1477.  
  1478.   def onPMContactlistReceive(self, pm):
  1479.     pass
  1480.  
  1481.   def onPMBlocklistReceive(self, pm):
  1482.     pass
  1483.  
  1484.   def onPMContactAdd(self, pm, user):
  1485.     pass
  1486.  
  1487.   def onPMContactRemove(self, pm, user):
  1488.     pass
  1489.  
  1490.   def onPMBlock(self, pm, user):
  1491.     pass
  1492.  
  1493.   def onPMUnblock(self, pm, user):
  1494.     pass
  1495.  
  1496.   def onPMContactOnline(self, pm, user):
  1497.     pass
  1498.  
  1499.   def onPMContactApp(self, pm, user):
  1500.     pass
  1501.  
  1502.   def onPMContactOffline(self, pm, user):
  1503.     pass
  1504.  
  1505.   def onEventCalled(self, room, evt, *args, **kw):
  1506.     pass
  1507.    
  1508.   class _Task:
  1509.     def cancel(self):
  1510.       self.mgr.removeTask(self)
  1511.  
  1512.   def _tick(self):
  1513.     now = time.time()
  1514.     for task in set(self._tasks):
  1515.       if task.target <= now:
  1516.         task.func(*task.args, **task.kw)
  1517.         if task.isInterval:
  1518.           task.target = now + task.timeout
  1519.         else:
  1520.           self._tasks.remove(task)
  1521.  
  1522.   def setTimeout(self, timeout, func, *args, **kw):
  1523.     task = self._Task()
  1524.     task.mgr = self
  1525.     task.target = time.time() + timeout
  1526.     task.timeout = timeout
  1527.     task.func = func
  1528.     task.isInterval = False
  1529.     task.args = args
  1530.     task.kw = kw
  1531.     self._tasks.add(task)
  1532.     return task
  1533.  
  1534.   def setInterval(self, timeout, func, *args, **kw):
  1535.     task = self._Task()
  1536.     task.mgr = self
  1537.     task.target = time.time() + timeout
  1538.     task.timeout = timeout
  1539.     task.func = func
  1540.     task.isInterval = True
  1541.     task.args = args
  1542.     task.kw = kw
  1543.     self._tasks.add(task)
  1544.     return task
  1545.  
  1546.   def removeTask(self, task):
  1547.     if task in self._tasks:
  1548.       self._tasks.remove(task)
  1549.  
  1550.   @classmethod
  1551.   def easy_start(cl, rooms = None, name = None, password = None, pm = True):
  1552.    
  1553.     if not rooms: rooms = str(input("Room names separated by semicolons: ")).split(";")
  1554.     if len(rooms) == 1 and rooms[0] == "": rooms = []
  1555.     if name == None: name = str(input("User name: "))
  1556.     if name == "" or " " in name: name = None
  1557.     if password == None: password = str(input("User password: "))
  1558.     if password == "": password = None
  1559.     if name == None or password == None: pm = False
  1560.     self = cl(name, password, pm = pm)
  1561.     self.rooms_copy = rooms
  1562.     if len(self.rooms_copy)>0:
  1563.       for room in self.rooms_copy:
  1564.         self.joinRoom(room)
  1565.     if len(rooms) > 0 or (name != None and password != None):
  1566.       self.main()
  1567.    
  1568.      
  1569.   def main(self):
  1570.     self.onInit()
  1571.     self._running = True
  1572.     while self._running:
  1573.       conns = list(self._rooms.values())
  1574.       if self.pm:
  1575.         conns.append(self.pm)
  1576.       socks = [x._websock.sock for x in conns if x._websock.sock != None ]
  1577.       wsocks = [x._websock.sock for x in conns if x._wbuf != "" and x._websock.sock != None]
  1578.       rd, wr, sp = select.select(socks, wsocks, [], 0.1)
  1579.       for sock in rd:
  1580.         con = [c for c in conns if c._websock.sock == sock]
  1581.         if len(con) > 0:
  1582.             con = con[0]
  1583.             try:
  1584.                 op, data = con._websock.recv_data()
  1585.                 if(len(data) > 0):
  1586.                     con._feed(data)
  1587.             except:
  1588.                 con.reconnect()
  1589.        
  1590.       for sock in wr:
  1591.         con = [c for c in conns if c._websock.sock == sock]
  1592.         if len(con) > 0:
  1593.             con = con[0]
  1594.             try:
  1595.                 size = con._websock.send(con._wbuf)
  1596.                 con._wbuf = con._wbuf[size:]
  1597.             except:
  1598.                 con.reconnect()
  1599.    
  1600.       self._tick()
  1601.      
  1602.   def stop(self):
  1603.     self._running = False
  1604.     conns = list(self._rooms.values())
  1605.     if self.pm:
  1606.       conns.append(self.pm)
  1607.     for conn in conns:
  1608.       conn.disconnect()
  1609.  
  1610.   def enableBg(self):
  1611.     self.user._mbg = True
  1612.     for room in self.rooms:
  1613.       room.setBgMode(1)
  1614.  
  1615.   def disableBg(self):
  1616.     self.user._mbg = False
  1617.     for room in self.rooms:
  1618.       room.setBgMode(0)
  1619.  
  1620.   def enableRecording(self):
  1621.     self.user._mrec = True
  1622.     for room in self.rooms:
  1623.       room.setRecordingMode(1)
  1624.  
  1625.   def disableRecording(self):
  1626.     self.user._mrec = False
  1627.     for room in self.rooms:
  1628.       room.setRecordingMode(0)
  1629.  
  1630.   def setNameColor(self, color3x):
  1631.     self.user._nameColor = color3x
  1632.  
  1633.   def setFontColor(self, color3x):
  1634.     self.user._fontColor = color3x
  1635.  
  1636.   def setFontFace(self, face):
  1637.     self.user._fontFace = face
  1638.  
  1639.   def setFontSize(self, size):
  1640.     if size < 9: size = 9
  1641.     if size > 22: size = 22
  1642.     self.user._fontSize = size
  1643.  
  1644.  
  1645. _users = dict()
  1646. def User(name):
  1647.   if name == None: name = ""
  1648.   user = _users.get(name.lower())
  1649.   if not user:
  1650.     user = _User(name)
  1651.     _users[name.lower()] = user
  1652.   return user
  1653.  
  1654. class _User:
  1655.   def __init__(self, name):
  1656.     self._name = name.lower()
  1657.     self._raw = name
  1658.     self._puid = ""
  1659.     self._sids = dict()
  1660.     self._msgs = list()
  1661.     self._nameColor = "000"
  1662.     self._fontSize = 12
  1663.     self._fontFace = "0"
  1664.     self._fontColor = "000"
  1665.     self._mbg = False
  1666.     self._mrec = False
  1667.  
  1668.   def getName(self): return self._name
  1669.   def getRaw(self): return self._raw
  1670.   def getPuid(self): return self._puid
  1671.   def getSessionIds(self, room = None):
  1672.     if room:
  1673.       return self._sids.get(room, set())
  1674.     else:
  1675.       return set.union(*self._sids.values())
  1676.   def getRooms(self): return self._sids.keys()
  1677.   def getRoomNames(self): return [room.name for room in self.getRooms()]
  1678.   def getFontColor(self): return self._fontColor
  1679.   def getFontFace(self): return self._fontFace
  1680.   def getFontSize(self): return self._fontSize
  1681.   def getNameColor(self): return self._nameColor
  1682.  
  1683.   name = property(getName)
  1684.   raw = property(getRaw)
  1685.   puid = property(getPuid)
  1686.   sids = property(getSessionIds)
  1687.   rooms = property(getRooms)
  1688.   roomnames = property(getRoomNames)
  1689.   fontColor = property(getFontColor)
  1690.   fontFace = property(getFontFace)
  1691.   fontSize = property(getFontSize)
  1692.   nameColor = property(getNameColor)
  1693.  
  1694.   def addSessionId(self, room, sid):
  1695.     if room not in self._sids:
  1696.       self._sids[room] = set()
  1697.     self._sids[room].add(sid)
  1698.  
  1699.   def removeSessionId(self, room, sid):
  1700.     try:
  1701.       self._sids[room].remove(sid)
  1702.       if len(self._sids[room]) == 0:
  1703.         del self._sids[room]
  1704.     except KeyError:
  1705.       pass
  1706.  
  1707.   def clearSessionIds(self, room):
  1708.     try:
  1709.       del self._sids[room]
  1710.     except KeyError:
  1711.       pass
  1712.  
  1713.   def hasSessionId(self, room, sid):
  1714.     try:
  1715.       if sid in self._sids[room]:
  1716.         return True
  1717.       else:
  1718.         return False
  1719.     except KeyError:
  1720.       return False
  1721.  
  1722.   def updatePuid(self, puid):
  1723.     self._puid = puid
  1724.  
  1725.   def __repr__(self):
  1726.     return "<User: %s>" %(self.name)
  1727.  
  1728. class Message:
  1729.   def attach(self, room, msgid):
  1730.     if self._msgid == None:
  1731.       self._room = room
  1732.       self._msgid = msgid
  1733.       self._room._msgs[msgid] = self
  1734.  
  1735.   def detach(self):
  1736.     if self._msgid != None and self._msgid in self._room._msgs:
  1737.       del self._room._msgs[self._msgid]
  1738.       self._msgid = None
  1739.  
  1740.   def __init__(self, **kw):
  1741.     self._msgid = None
  1742.     self._time = None
  1743.     self._channel = None
  1744.     self._user = None
  1745.     self._body = None
  1746.     self._room = None
  1747.     self._raw = ""
  1748.     self._ip = None
  1749.     self._unid = ""
  1750.     self._nameColor = "000"
  1751.     self._fontSize = 12
  1752.     self._fontFace = "0"
  1753.     self._fontColor = "000"
  1754.     for attr, val in kw.items():
  1755.       if val == None: continue
  1756.       setattr(self, "_" + attr, val)
  1757.  
  1758.   def getId(self): return self._msgid
  1759.   def getTime(self): return self._time
  1760.   def getChannel(self): return self._channel
  1761.   def getUser(self): return self._user
  1762.   def getBody(self): return self._body
  1763.   def getUid(self): return self._uid
  1764.   def getIP(self): return self._ip
  1765.   def getFontColor(self): return self._fontColor
  1766.   def getFontFace(self): return self._fontFace
  1767.   def getFontSize(self): return self._fontSize
  1768.   def getNameColor(self): return self._nameColor
  1769.   def getRoom(self): return self._room
  1770.   def getRaw(self): return self._raw
  1771.   def getUnid(self): return self._unid
  1772.  
  1773.   msgid = property(getId)
  1774.   time = property(getTime)
  1775.   channel = property(getChannel)
  1776.   user = property(getUser)
  1777.   body = property(getBody)
  1778.   uid = property(getUid)
  1779.   room = property(getRoom)
  1780.   ip = property(getIP)
  1781.   fontColor = property(getFontColor)
  1782.   fontFace = property(getFontFace)
  1783.   fontSize = property(getFontSize)
  1784.   raw = property(getRaw)
  1785.   nameColor = property(getNameColor)
  1786.   unid = property(getUnid)
  1787.  
Advertisement
Comments
  • _Suraj_
    268 days
    # text 0.03 KB | 0 0
    1. this code can't run in pydroid.
    • agunq
      267 days
      # text 0.11 KB | 0 0
      1. i never tried it on pydroid, can you please give me more detail to your current error while you use this code
    • agunq
      267 days
      # text 0.18 KB | 0 0
      1. i have tried it and it works just fine on pydroid 3 version 6.4_arm64, make sure you installed websocket-client on Pip, furthermore i still need more detail if you keep getting error
Add Comment
Please, Sign In to add comment
Advertisement