SHOW:
|
|
- or go back to the newest paste.
| 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 | DEBUG = False | |
| 12 | ||
| 13 | def httpRequest(server, resource, body="", headers={}, method="GET"):
| |
| 14 | connection = httplib.HTTPConnection(server) | |
| 15 | connection.request(method, resource, body, headers) | |
| 16 | response = connection.getresponse() | |
| 17 | headers = response.getheaders() | |
| 18 | data = response.read() | |
| 19 | connection.close() | |
| 20 | return (headers, data) | |
| 21 | ||
| 22 | class TinychatMessage(): | |
| 23 | def __init__(self, msg, nick, user=None, recipient=None, color=None, pm=False): | |
| 24 | self.msg = msg | |
| 25 | self.nick = nick | |
| 26 | self.user = user | |
| 27 | self.recipient = recipient | |
| 28 | self.color = color | |
| 29 | self.pm = pm | |
| 30 | ||
| 31 | def printFormatted(self): | |
| 32 | if self.pm: | |
| 33 | pm = "(PM) " | |
| 34 | else: | |
| 35 | pm = "" | |
| 36 | print(pm + self.recipient + ": " + self.nick + ": " + self.msg) | |
| 37 | ||
| 38 | class TinychatUser(): | |
| 39 | def __init__(self, nick, id=None, color=None, lastMsg=None): | |
| 40 | self.nick = nick | |
| 41 | self.id = id | |
| 42 | self.color = color | |
| 43 | self.lastMsg = lastMsg | |
| 44 | ||
| 45 | TINYCHAT_COLORS = ["#7db257", "#a78901", "#9d5bb5", "#5c1a7a", "#c53332", "#821615", "#a08f23", "#487d21", "#c356a3", "#1d82eb", "#919104", "#a990", "#b9807f", "#7bb224", "#1965b6", "#32a5d9"] | |
| 46 | ||
| 47 | class TinychatRoom(): | |
| 48 | # Manages a single room connection | |
| 49 | def __init__(self, room, nick=None, passwd=None): | |
| 50 | self.room = room | |
| 51 | self.tcUrl = self._getTcUrl() | |
| 52 | parts = self.tcUrl.split("/")
| |
| 53 | server = parts[2].split(":")
| |
| 54 | self.server = server[0] | |
| 55 | self.port = int(server[1]) | |
| 56 | self.app = parts[3] | |
| 57 | self.url = "http://tinychat.com/" + room | |
| 58 | self.connected = False | |
| 59 | self.queue = [] | |
| 60 | self.color = TINYCHAT_COLORS[random.randint(0, len(TINYCHAT_COLORS) - 1)] | |
| 61 | self.nick = nick | |
| 62 | self.passwd = passwd | |
| 63 | if self.nick == "": self.nick = None | |
| 64 | if self.passwd == "": self.passwd = None | |
| 65 | self.topic = None | |
| 66 | self.users = {}
| |
| 67 | self.echo = __name__ == "__main__" | |
| 68 | self.stack = False | |
| 69 | ||
| 70 | def connect(self): | |
| 71 | if not self.connected: | |
| 72 | self.connection = rtmp_protocol.RtmpClient(self.server, self.port, self.tcUrl, self.url, '', self.app) | |
| 73 | if self.nick: | |
| 74 | n = self.nick.lower() | |
| 75 | else: | |
| 76 | n = "" | |
| 77 | self.connection.connect([self.room, self._getAutoOp(), u'show', u'tinychat', n]) | |
| 78 | self.connected = True | |
| 79 | self._listen() | |
| 80 | ||
| 81 | def disconnect(self): | |
| 82 | if self.connected: | |
| 83 | self.connected = False | |
| 84 | - | self.connection.socket.shutdown(socket.SHUT_RDWR) |
| 84 | + | |
| 85 | self.connection.socket.shutdown(socket.SHUT_RDWR) | |
| 86 | except: | |
| 87 | pass | |
| 88 | self.onDisconnect() | |
| 89 | ||
| 90 | def poll(self): | |
| 91 | q = self.queue | |
| 92 | self.queue = [] | |
| 93 | return q | |
| 94 | ||
| 95 | # Commands | |
| 96 | def say(self, msg): | |
| 97 | if len(msg) > 152: return | |
| 98 | self._sendCommand("privmsg", [u"" + self._encodeMessage(msg), u"" + self.color + ",en"])
| |
| 99 | ||
| 100 | def pm(self, msg, recipient): | |
| 101 | if len(msg) > 152: return | |
| 102 | self._sendCommand("privmsg", [u"" + self._encodeMessage("/msg " + recipient + " " + msg), u"" + self.color + ",en", u"n" + self._getUser(recipient).id + "-" + recipient])
| |
| 103 | ||
| 104 | def setNick(self, nick=None): | |
| 105 | if not nick: nick = self.nick | |
| 106 | self.nick = nick | |
| 107 | self._sendCommand("nick", [u"" + nick])
| |
| 108 | ||
| 109 | def cycleColor(self): | |
| 110 | try: | |
| 111 | i = TINYCHAT_COLORS.index(self.color) | |
| 112 | except: | |
| 113 | i = TINYCHAT_COLORS[random.randint(0, len(TINYCHAT_COLORS) - 1)] | |
| 114 | i = (i + 1) % len(TINYCHAT_COLORS) | |
| 115 | self.color = TINYCHAT_COLORS[i] | |
| 116 | ||
| 117 | def ban(self, nick): | |
| 118 | self._sendCommand("kick", [u"" + nick, self._getUser(nick).id])
| |
| 119 | ||
| 120 | # Events | |
| 121 | def onMessage(self, user, message): | |
| 122 | if self.echo: message.printFormatted() | |
| 123 | ||
| 124 | def onPM(self, user, message): | |
| 125 | if self.echo: message.printFormatted() | |
| 126 | ||
| 127 | def onQuit(self, user): | |
| 128 | if self.echo: print(self.room + ": " + user.nick + " left the room.") | |
| 129 | ||
| 130 | def onBan(self, user): | |
| 131 | if self.echo: print(self.room + ": " + user.nick + " was banned.") | |
| 132 | ||
| 133 | def onJoin(self, user): | |
| 134 | if self.echo: print(self.room + ": " + user.nick + " entered the room.") | |
| 135 | ||
| 136 | def onRegister(self, user): | |
| 137 | if self.echo: print("You have connected to " + self.room + ".")
| |
| 138 | ||
| 139 | def onNickChange(self, new, old, user): | |
| 140 | if self.echo: print(self.room + ": " + old + " changed nickname to " + new + ".") | |
| 141 | ||
| 142 | def onTopic(self, topic): | |
| 143 | if self.echo: print(self.room + ": Topic set to \"" + topic + "\".") | |
| 144 | ||
| 145 | def onUserList(self, users): | |
| 146 | pass | |
| 147 | ||
| 148 | def onDisconnect(self): | |
| 149 | if self.echo: print("You have disconnected from " + self.room + ".")
| |
| 150 | ||
| 151 | # Helper methods | |
| 152 | def _listen(self): | |
| 153 | while self.connected: | |
| 154 | try: | |
| 155 | msg = self.connection.reader.next() | |
| 156 | if DEBUG: print("SERVER: " + str(msg))
| |
| 157 | if msg['msg'] == rtmp_protocol.DataTypes.COMMAND: | |
| 158 | pars = msg['command'] | |
| 159 | cmd = pars[0].encode("ascii", "ignore").lower()
| |
| 160 | if len(pars) > 3: | |
| 161 | pars = pars[3:] | |
| 162 | else: | |
| 163 | pars = [] | |
| 164 | for i in range(len(pars)): | |
| 165 | if type(pars[i]) == str: pars[i] = pars[i].encode("ascii", "ignore")
| |
| 166 | if cmd == "privmsg": | |
| 167 | recipient = pars[0] | |
| 168 | message = pars[1] | |
| 169 | color = pars[2].lower().split(",")[0]
| |
| 170 | nick = pars[3] | |
| 171 | if recipient[0] == "#": | |
| 172 | recipient = "^".join(recipient.split("^")[1:])
| |
| 173 | else: | |
| 174 | recipient = "-".join(recipient.split("-")[1:])
| |
| 175 | user = self._getUser(nick) | |
| 176 | message = TinychatMessage(self._decodeMessage(message), nick, user, recipient, color) | |
| 177 | user.lastMsg = message | |
| 178 | user.color = color | |
| 179 | if self.stack: self.queue.append(message) | |
| 180 | if recipient.lower() == self.nick.lower(): | |
| 181 | message.pm = True | |
| 182 | if message.msg.startswith("/msg ") and len(message.msg.split(" ")) >= 2: message.msg = " ".join(message.msg.split(" ")[2:])
| |
| 183 | self.onPM(user, message) | |
| 184 | else: | |
| 185 | self.onMessage(user, message) | |
| 186 | elif cmd == "registered": | |
| 187 | if self.nick: self.setNick() | |
| 188 | user = self._getUser(pars[0]) | |
| 189 | user.id = pars[1] | |
| 190 | self.onRegister(user) | |
| 191 | elif cmd == "topic": | |
| 192 | self.topic = pars[0] | |
| 193 | self.onTopic(self.topic) | |
| 194 | elif cmd == "nick": | |
| 195 | user = self._getUser(pars[0]) | |
| 196 | old = user.nick | |
| 197 | user.nick = pars[1] | |
| 198 | if old.lower() in self.users.keys(): | |
| 199 | del self.users[old.lower()] | |
| 200 | self.users[user.nick.lower()] = user | |
| 201 | self.onNickChange(user.nick, old, user) | |
| 202 | elif cmd == "quit": | |
| 203 | user = self.users[pars[0].lower()] | |
| 204 | del self.users[pars[0].lower()] | |
| 205 | self.onQuit(user) | |
| 206 | elif cmd == "kick": | |
| 207 | self.onBan(user = self.users[pars[1].lower()]) | |
| 208 | elif cmd == "join": | |
| 209 | user = self._getUser(pars[1]) | |
| 210 | user.id = pars[0] | |
| 211 | self.onJoin(user) | |
| 212 | elif cmd == "joins": | |
| 213 | for i in range((len(pars) - 1) / 2): | |
| 214 | user = self._getUser(pars[i*2 + 2]) | |
| 215 | user.id = pars[i*2 + 1] | |
| 216 | elif cmd == "joinsdone": | |
| 217 | self.onUserList(self.users) | |
| 218 | except: | |
| 219 | self.disconnect() | |
| 220 | ||
| 221 | def _getUser(self, nick): | |
| 222 | if not nick.lower() in self.users.keys(): self.users[nick.lower()] = TinychatUser(nick) | |
| 223 | return self.users[nick.lower()] | |
| 224 | ||
| 225 | def _decodeMessage(self, msg): | |
| 226 | chars = msg.split(",")
| |
| 227 | msg = "" | |
| 228 | for i in chars: | |
| 229 | msg += chr(int(i)) | |
| 230 | return msg | |
| 231 | ||
| 232 | def _encodeMessage(self, msg): | |
| 233 | msg2 = [] | |
| 234 | for i in msg: | |
| 235 | msg2.append(str(ord(i))) | |
| 236 | return ",".join(msg2) | |
| 237 | ||
| 238 | def _sendCommand(self, cmd, pars=[]): | |
| 239 | msg = {"msg": rtmp_protocol.DataTypes.COMMAND, "command": [u"" + cmd, 0, None] + pars}
| |
| 240 | if DEBUG: print("CLIENT: " + str(msg))
| |
| 241 | self.connection.writer.write(msg) | |
| 242 | self.connection.writer.flush() | |
| 243 | ||
| 244 | def _getTcUrl(self): | |
| 245 | return parseString(httpRequest("tinychat.com", "/api/find.room/" + self.room)[1]).getElementsByTagName("response")[0].getAttribute("rtmp")
| |
| 246 | ||
| 247 | def _getAutoOp(self): | |
| 248 | if self.nick and self.passwd: | |
| 249 | 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]
| |
| 250 | cookies = [] | |
| 251 | for header in headers: | |
| 252 | if header[0].lower() == "set-cookie": | |
| 253 | parts = header[1].split(", ")
| |
| 254 | for i in range(len(parts)): | |
| 255 | part = parts[i] | |
| 256 | part2 = part.split(";")[0]
| |
| 257 | if "=" in part2: | |
| 258 | if "," in part2: | |
| 259 | part2 = part2.split(", ")[1]
| |
| 260 | cookies.append(part2) | |
| 261 | break | |
| 262 | if len(cookies) > 0: | |
| 263 | html = httpRequest("tinychat.com", "/" + self.room, "", {"Content-Type": "application/x-www-form-urlencoded", "Cookie": "; ".join(cookies)})[1]
| |
| 264 | if ", autoop: \"" in html: | |
| 265 | return html.split(", autoop: \"")[1].split("\"")[0]
| |
| 266 | return u"none" | |
| 267 | ||
| 268 | if __name__ == "__main__": | |
| 269 | room = TinychatRoom(raw_input("Enter room name: "), raw_input("Enter username (optional): "), raw_input("Enter password (optional): "))
| |
| 270 | thread.start_new_thread(room.connect, ()) | |
| 271 | while not room.connected: time.sleep(1) | |
| 272 | while room.connected: room.say(raw_input()) |