Advertisement
MegaLoler

Python Tinychat Library revision 5

Jul 10th, 2012
1,101
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. import rtmp_protocol
  2. import httplib
  3. from xml.dom.minidom import parseString
  4. import thread
  5. import time
  6. import random
  7. import socket
  8.  
  9. # Tinychat Library by MegaLoler
  10.  
  11. # Changes:
  12. # Added youtube and soundcloud control commands
  13. # Incorporated some console commands for when running the script directly
  14.  
  15. # Brief Todo:
  16. # Unban command
  17. # Fix bug where all messages received in rooms the same name as your username appear to be PMs
  18. # Ability to tell whether users are moderators or not
  19. # Figure out more things to add :P
  20.  
  21. DEBUG = False
  22.  
  23. def httpRequest(server, resource, body="", headers={}, method="GET"):
  24.     connection = httplib.HTTPConnection(server)
  25.     connection.request(method, resource, body, headers)
  26.     response = connection.getresponse()
  27.     headers = response.getheaders()
  28.     data = response.read()
  29.     connection.close()
  30.     return (headers, data)
  31.    
  32. class TinychatMessage():
  33.     def __init__(self, msg, nick, user=None, recipient=None, color=None, pm=False):
  34.         self.msg = msg
  35.         self.nick = nick
  36.         self.user = user
  37.         self.recipient = recipient
  38.         self.color = color
  39.         self.pm = pm
  40.    
  41.     def printFormatted(self):
  42.         if self.pm:
  43.             pm = "(PM) "
  44.         else:
  45.             pm = ""
  46.         print(pm + self.recipient + ": " + self.nick + ": " + self.msg)
  47.  
  48. class TinychatUser():
  49.     def __init__(self, nick, id=None, color=None, lastMsg=None):
  50.         self.nick = nick
  51.         self.id = id
  52.         self.color = color
  53.         self.lastMsg = lastMsg
  54.  
  55. TINYCHAT_COLORS = ["#7db257", "#a78901", "#9d5bb5", "#5c1a7a", "#c53332", "#821615", "#a08f23", "#487d21", "#c356a3", "#1d82eb", "#919104", "#a990", "#b9807f", "#7bb224", "#1965b6", "#32a5d9"]
  56.  
  57. class TinychatRoom():
  58.     # Manages a single room connection 
  59.     def __init__(self, room, nick=None, passwd=None):
  60.         self.room = room
  61.         self.tcUrl = self._getTcUrl()
  62.         parts = self.tcUrl.split("/")
  63.         server = parts[2].split(":")
  64.         self.server = server[0]
  65.         self.port = int(server[1])
  66.         self.app = parts[3]
  67.         self.url = "http://tinychat.com/" + room
  68.         self.connected = False
  69.         self.queue = []
  70.         self.color = TINYCHAT_COLORS[random.randint(0, len(TINYCHAT_COLORS) - 1)]
  71.         self.nick = nick
  72.         self.passwd = passwd
  73.         if self.nick == "": self.nick = None
  74.         if self.passwd == "": self.passwd = None
  75.         self.topic = None
  76.         self.users = {}
  77.         self.echo = __name__ == "__main__"
  78.         self.stack = False
  79.  
  80.     def connect(self):
  81.         if not self.connected:
  82.             self.connection = rtmp_protocol.RtmpClient(self.server, self.port, self.tcUrl, self.url, '', self.app)
  83.             if self.nick:
  84.                 n = self.nick.lower()
  85.             else:
  86.                 n = ""
  87.             self.connection.connect([self.room, self._getAutoOp(), u'show', u'tinychat', n])
  88.             self.connected = True
  89.             self._listen()
  90.    
  91.     def disconnect(self):
  92.         if self.connected:
  93.             self.connected = False
  94.             try:
  95.                 self.connection.socket.shutdown(socket.SHUT_RDWR)
  96.             except:
  97.                 pass
  98.             self.onDisconnect()
  99.    
  100.     def poll(self):
  101.         q = self.queue
  102.         self.queue = []
  103.         return q
  104.        
  105.     # Commands
  106.     def say(self, msg):
  107.         if len(msg) > 152: return
  108.         self._sendCommand("privmsg", [u"" + self._encodeMessage(msg), u"" + self.color + ",en"])
  109.        
  110.     def pm(self, msg, recipient):
  111.         if len(msg) > 152: return
  112.         self._sendCommand("privmsg", [u"" + self._encodeMessage("/msg " + recipient + " " + msg), u"" + self.color + ",en", u"n" + self._getUser(recipient).id + "-" + recipient])
  113.        
  114.     def setNick(self, nick=None):
  115.         if not nick: nick = self.nick
  116.         self.nick = nick
  117.         self._sendCommand("nick", [u"" + nick])
  118.    
  119.     def cycleColor(self):
  120.         try:
  121.             i = TINYCHAT_COLORS.index(self.color)
  122.         except:
  123.             i = TINYCHAT_COLORS[random.randint(0, len(TINYCHAT_COLORS) - 1)]
  124.         i = (i + 1) % len(TINYCHAT_COLORS)
  125.         self.color = TINYCHAT_COLORS[i]
  126.    
  127.     def ban(self, nick):
  128.         self._sendCommand("kick", [u"" + nick, self._getUser(nick).id])
  129.    
  130.     def playYoutube(self, video):
  131.         self.say("/mbs youTube " + str(video) + " 0")
  132.    
  133.     def stopYoutube(self):
  134.         self.say("/mbc youTube")
  135.    
  136.     def playSoundcloud(self, track):
  137.         self.say("/mbs soundCloud " + str(track) + " 0")
  138.    
  139.     def stopSoundcloud(self):
  140.         self.say("/mbc soundCloud")
  141.    
  142.     # Events
  143.     def onMessage(self, user, message):
  144.         if self.echo: message.printFormatted()
  145.        
  146.     def onPM(self, user, message):
  147.         if self.echo: message.printFormatted()
  148.    
  149.     def onQuit(self, user):
  150.         if self.echo: print(self.room + ": " + user.nick + " left the room.")
  151.    
  152.     def onBan(self, user):
  153.         if self.echo: print(self.room + ": " + user.nick + " was banned.")
  154.    
  155.     def onJoin(self, user):
  156.         if self.echo: print(self.room + ": " + user.nick + " entered the room.")
  157.    
  158.     def onRegister(self, user):
  159.         if self.echo: print("You have connected to " + self.room + ".")
  160.    
  161.     def onNickChange(self, new, old, user):
  162.         if self.echo: print(self.room + ": " + old + " changed nickname to " + new + ".")
  163.    
  164.     def onTopic(self, topic):
  165.         if self.echo: print(self.room + ": Topic set to \"" + topic + "\".")
  166.    
  167.     def onUserList(self, users):
  168.         pass
  169.    
  170.     def onDisconnect(self):
  171.         if self.echo: print("You have disconnected from " + self.room + ".")
  172.    
  173.     # Helper methods
  174.     def _listen(self):
  175.         while self.connected:
  176.             try:
  177.                 msg = self.connection.reader.next()
  178.                 if DEBUG: print("SERVER: " + str(msg))
  179.                 if msg['msg'] == rtmp_protocol.DataTypes.COMMAND:
  180.                     pars = msg['command']
  181.                     cmd = pars[0].encode("ascii", "ignore").lower()
  182.                     if len(pars) > 3:
  183.                         pars = pars[3:]
  184.                     else:
  185.                         pars = []
  186.                     for i in range(len(pars)):
  187.                         if type(pars[i]) == str: pars[i] = pars[i].encode("ascii", "ignore")
  188.                     if cmd == "privmsg":
  189.                         recipient = pars[0]
  190.                         message = pars[1]
  191.                         color = pars[2].lower().split(",")[0]
  192.                         nick = pars[3]
  193.                         if recipient[0] == "#":
  194.                             recipient = "^".join(recipient.split("^")[1:])
  195.                         else:
  196.                             recipient = "-".join(recipient.split("-")[1:])
  197.                         user = self._getUser(nick)
  198.                         message = TinychatMessage(self._decodeMessage(message), nick, user, recipient, color)
  199.                         user.lastMsg = message
  200.                         user.color = color
  201.                         if self.stack: self.queue.append(message)
  202.                         if recipient.lower() == self.nick.lower():
  203.                             message.pm = True
  204.                             if message.msg.startswith("/msg ") and len(message.msg.split(" ")) >= 2: message.msg = " ".join(message.msg.split(" ")[2:])
  205.                             self.onPM(user, message)
  206.                         else:
  207.                             self.onMessage(user, message)
  208.                     elif cmd == "registered":
  209.                         if self.nick: self.setNick()
  210.                         user = self._getUser(pars[0])
  211.                         user.id = pars[1]
  212.                         self.onRegister(user)
  213.                     elif cmd == "topic":
  214.                         self.topic = pars[0]
  215.                         self.onTopic(self.topic)
  216.                     elif cmd == "nick":
  217.                         user = self._getUser(pars[0])
  218.                         old = user.nick
  219.                         user.nick = pars[1]
  220.                         if old.lower() in self.users.keys():
  221.                             del self.users[old.lower()]
  222.                             self.users[user.nick.lower()] = user
  223.                         self.onNickChange(user.nick, old, user)
  224.                     elif cmd == "quit":
  225.                         user = self.users[pars[0].lower()]
  226.                         del self.users[pars[0].lower()]
  227.                         self.onQuit(user)
  228.                     elif cmd == "kick":
  229.                         self.onBan(user = self.users[pars[1].lower()])
  230.                     elif cmd == "join":
  231.                         user = self._getUser(pars[1])
  232.                         user.id = pars[0]
  233.                         self.onJoin(user)
  234.                     elif cmd == "joins":
  235.                         for i in range((len(pars) - 1) / 2):
  236.                             user = self._getUser(pars[i*2 + 2])
  237.                             user.id = pars[i*2 + 1]
  238.                     elif cmd == "joinsdone":
  239.                         self.onUserList(self.users)
  240.             except:
  241.                 self.disconnect()
  242.                    
  243.     def _getUser(self, nick):
  244.         if not nick.lower() in self.users.keys(): self.users[nick.lower()] = TinychatUser(nick)
  245.         return self.users[nick.lower()]
  246.    
  247.     def _decodeMessage(self, msg):
  248.         chars = msg.split(",")
  249.         msg = ""
  250.         for i in chars:
  251.             msg += chr(int(i))
  252.         return msg
  253.        
  254.     def _encodeMessage(self, msg):
  255.         msg2 = []
  256.         for i in msg:
  257.             msg2.append(str(ord(i)))
  258.         return ",".join(msg2)
  259.    
  260.     def _sendCommand(self, cmd, pars=[]):
  261.         msg = {"msg": rtmp_protocol.DataTypes.COMMAND, "command": [u"" + cmd, 0, None] + pars}
  262.         if DEBUG: print("CLIENT: " + str(msg))
  263.         self.connection.writer.write(msg)
  264.         self.connection.writer.flush()
  265.    
  266.     def _getTcUrl(self):   
  267.         return parseString(httpRequest("tinychat.com", "/api/find.room/" + self.room)[1]).getElementsByTagName("response")[0].getAttribute("rtmp")
  268.        
  269.     def _getAutoOp(self):
  270.         if self.nick and self.passwd:
  271.             headers = httpRequest("tinychat.com", "/login", "form_sent=1&referer=&next=&username=" + self.nick + "&password=" + self.passwd + "&passwordfake=Password&remember=1", {"Content-Type": "application/x-www-form-urlencoded"}, "POST")[0]
  272.             cookies = []
  273.             for header in headers:
  274.                 if header[0].lower() == "set-cookie":
  275.                     parts = header[1].split(", ")
  276.                     for i in range(len(parts)):
  277.                         part = parts[i]
  278.                         part2 = part.split(";")[0]
  279.                         if "=" in part2:
  280.                             if "," in part2:
  281.                                 part2 = part2.split(", ")[1]
  282.                             cookies.append(part2)
  283.                     break
  284.             if len(cookies) > 0:
  285.                 html = httpRequest("tinychat.com", "/" + self.room, "", {"Content-Type": "application/x-www-form-urlencoded", "Cookie": "; ".join(cookies)})[1]
  286.                 if ", autoop: \"" in html:
  287.                     return html.split(", autoop: \"")[1].split("\"")[0]
  288.         return u"none"
  289.  
  290. if __name__ == "__main__":
  291.     room = TinychatRoom(raw_input("Enter room name: "), raw_input("Enter username (optional): "), raw_input("Enter password (optional): "))
  292.     thread.start_new_thread(room.connect, ())
  293.     while not room.connected: time.sleep(1)
  294.     while room.connected:
  295.         msg = raw_input()
  296.         if len(msg) > 0:
  297.                 if msg[0] == "/":
  298.                         msg = msg[1:]
  299.                         if len(msg) > 0:
  300.                                 parts = msg.split(" ")
  301.                                 if len(parts) == 1:
  302.                                         cmd = parts[0]
  303.                                         pars = []
  304.                                         par = ""
  305.                                 else:
  306.                                         cmd = parts[0]
  307.                                         pars = parts[1:]
  308.                                         par = " ".join(parts[1:])
  309.                                 if cmd.lower() == "say":
  310.                                         room.say(par)
  311.                                 elif cmd.lower() == "pm":
  312.                                         if len(pars) > 1:
  313.                                                 room.pm(" ".join(pars[1:]), pars[0])
  314.                                         else:
  315.                                                 print("Please supply the recipient's nick as well as the message to send")
  316.                                 elif cmd.lower() == "nick":
  317.                                         room.setNick(par)
  318.                                 elif cmd.lower() == "color":
  319.                                         room.cycleColor()
  320.                                 elif cmd.lower() == "ban":
  321.                                         room.ban(par)
  322.                                 elif cmd.lower() == "quit":
  323.                                         room.disconnect()
  324.                     elif cmd.lower() == "playyoutube":
  325.                                         room.playYoutube(par)
  326.                     elif cmd.lower() == "stopyoutube":
  327.                                         room.stopYoutube()
  328.                     elif cmd.lower() == "playsoundcloud":
  329.                                         room.playSoundcloud(par)
  330.                     elif cmd.lower() == "stopsoundcloud":
  331.                                         room.stopSoundcloud()
  332.                 else:
  333.                         room.say(msg)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement