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 | # Credits for code base to MegaLOLer | |
10 | # Edits by Nola | |
11 | ||
12 | # Add Cauth token - API - http://tinychat.com/api/captcha/check.php?room=tinychat^[roomname]&guest_id=[user_id] | |
13 | # Fix Bug - If Using Admin account - all messages come in as PMs | |
14 | # Fix Youtube/Sound Cloud API Calls | |
15 | # Unban command - API - http://tinychat.com/ajax/user/clearbans | |
16 | # Ability to tell whether users are moderators or not - Prase JOINS | |
17 | # Add Auto Bans Based on Usernames | |
18 | # Add Trivia/Poker Bot based on IRC Bots | |
19 | # Other things | |
20 | ||
21 | DEBUG = True | |
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 = ["#a78901"] | |
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 | self.userID = None | |
80 | ||
81 | def connect(self): | |
82 | if not self.connected: | |
83 | self.connection = rtmp_protocol.RtmpClient(self.server, self.port, self.tcUrl, self.url, '', self.app) | |
84 | if self.nick: | |
85 | n = self.nick.lower() | |
86 | else: | |
87 | n = "" | |
88 | self.connection.connect([self.room, self._getAutoOp(), u'show', u'tinychat', n]) | |
89 | self.connected = True | |
90 | self._listen() | |
91 | ||
92 | def disconnect(self): | |
93 | if self.connected: | |
94 | self.connected = False | |
95 | try: | |
96 | self.connection.socket.shutdown(socket.SHUT_RDWR) | |
97 | except: | |
98 | pass | |
99 | self.onDisconnect() | |
100 | ||
101 | def poll(self): | |
102 | q = self.queue | |
103 | self.queue = [] | |
104 | return q | |
105 | ||
106 | # Commands | |
107 | def cauth(self): | |
108 | self._sendCauth(self._getTcCauth()) | |
109 | ||
110 | def say(self, msg): | |
111 | if len(msg) > 152: return | |
112 | self._sendCommand("privmsg", [u"" + self._encodeMessage(msg), u"" + self.color + ",en"]) | |
113 | ||
114 | def pm(self, msg, recipient): | |
115 | if len(msg) > 152: return | |
116 | self._sendCommand("privmsg", [u"" + self._encodeMessage("/msg " + recipient + " " + msg), u"" + self.color + ",en", u"n" + self._getUser(recipient).id + "-" + recipient]) | |
117 | ||
118 | def setNick(self, nick=None): | |
119 | if not nick: nick = self.nick | |
120 | self.nick = nick | |
121 | self._sendCommand("nick", [u"" + nick]) | |
122 | ||
123 | def cycleColor(self): | |
124 | try: | |
125 | i = TINYCHAT_COLORS.index(self.color) | |
126 | except: | |
127 | i = TINYCHAT_COLORS[random.randint(0, len(TINYCHAT_COLORS) - 1)] | |
128 | i = (i + 1) % len(TINYCHAT_COLORS) | |
129 | self.color = TINYCHAT_COLORS[i] | |
130 | ||
131 | def ban(self, nick): | |
132 | self._sendCommand("kick", [u"" + nick, self._getUser(nick).id]) | |
133 | ||
134 | def playYoutube(self, video): | |
135 | self.say("/mbs youTube " + str(video) + " 0") | |
136 | ||
137 | def stopYoutube(self): | |
138 | self.say("/mbc youTube") | |
139 | ||
140 | def playSoundcloud(self, track): | |
141 | self.say("/mbs soundCloud " + str(track) + " 0") | |
142 | ||
143 | def stopSoundcloud(self): | |
144 | self.say("/mbc soundCloud") | |
145 | ||
146 | # Events | |
147 | def onMessage(self, user, message): | |
148 | if self.echo: message.printFormatted() | |
149 | ||
150 | def onPM(self, user, message): | |
151 | if self.echo: message.printFormatted() | |
152 | ||
153 | def onQuit(self, user): | |
154 | if self.echo: print(self.room + ": " + user.nick + " left the room.") | |
155 | ||
156 | def onBan(self, user): | |
157 | if self.echo: print(self.room + ": " + user.nick + " was banned.") | |
158 | ||
159 | def onJoin(self, user): | |
160 | if self.echo: print(self.room + ": " + user.nick + " entered the room.") | |
161 | ||
162 | def onRegister(self, user): | |
163 | if self.echo: print("You have connected to " + self.room + ".") | |
164 | ||
165 | def onNickChange(self, new, old, user): | |
166 | if self.echo: print(self.room + ": " + old + " changed nickname to " + new + ".") | |
167 | ||
168 | def onTopic(self, topic): | |
169 | if self.echo: print(self.room + ": Topic set to \"" + topic + "\".") | |
170 | ||
171 | def onUserList(self, users): | |
172 | pass | |
173 | ||
174 | def onDisconnect(self): | |
175 | if self.echo: print("You have disconnected from " + self.room + ".") | |
176 | ||
177 | # Helper methods | |
178 | def _listen(self): | |
179 | while self.connected: | |
180 | try: | |
181 | msg = self.connection.reader.next() | |
182 | if DEBUG: print("SERVER: " + str(msg)) | |
183 | if msg['msg'] == rtmp_protocol.DataTypes.COMMAND: | |
184 | pars = msg['command'] | |
185 | cmd = pars[0].encode("ascii", "ignore").lower() | |
186 | if len(pars) > 3: | |
187 | pars = pars[3:] | |
188 | else: | |
189 | pars = [] | |
190 | for i in range(len(pars)): | |
191 | if type(pars[i]) == str: pars[i] = pars[i].encode("ascii", "ignore") | |
192 | if cmd == "privmsg": | |
193 | recipient = pars[0] | |
194 | message = pars[1] | |
195 | color = pars[2].lower().split(",")[0] | |
196 | nick = pars[3] | |
197 | if recipient[0] == "#": | |
198 | recipient = "^".join(recipient.split("^")[1:]) | |
199 | else: | |
200 | recipient = "-".join(recipient.split("-")[1:]) | |
201 | user = self._getUser(nick) | |
202 | message = TinychatMessage(self._decodeMessage(message), nick, user, recipient, color) | |
203 | user.lastMsg = message | |
204 | user.color = color | |
205 | if self.stack: self.queue.append(message) | |
206 | if recipient.lower() == self.nick.lower(): | |
207 | message.pm = True | |
208 | if message.msg.startswith("/msg ") and len(message.msg.split(" ")) >= 2: message.msg = " ".join(message.msg.split(" ")[2:]) | |
209 | self.onPM(user, message) | |
210 | else: | |
211 | self.onMessage(user, message) | |
212 | elif cmd == "registered": | |
213 | if self.nick: self.setNick() | |
214 | user = self._getUser(pars[0]) | |
215 | user.id = pars[1] | |
216 | self.onRegister(user) | |
217 | elif cmd == "topic": | |
218 | self.topic = pars[0] | |
219 | self.onTopic(self.topic) | |
220 | elif cmd == "nick": | |
221 | user = self._getUser(pars[0]) | |
222 | old = user.nick | |
223 | user.nick = pars[1] | |
224 | if old.lower() in self.users.keys(): | |
225 | del self.users[old.lower()] | |
226 | self.users[user.nick.lower()] = user | |
227 | if user.nick == self.nick: | |
228 | self.userID = user.id | |
229 | self.cauth(); | |
230 | self.onNickChange(user.nick, old, user) | |
231 | elif cmd == "quit": | |
232 | user = self.users[pars[0].lower()] | |
233 | del self.users[pars[0].lower()] | |
234 | self.onQuit(user) | |
235 | elif cmd == "kick": | |
236 | self.onBan(user = self.users[pars[1].lower()]) | |
237 | elif cmd == "join": | |
238 | user = self._getUser(pars[1]) | |
239 | user.id = pars[0] | |
240 | self.onJoin(user) | |
241 | elif cmd == "joins": | |
242 | for i in range((len(pars) - 1) / 2): | |
243 | user = self._getUser(pars[i*2 + 2]) | |
244 | user.id = pars[i*2 + 1] | |
245 | #self.cauth(); | |
246 | elif cmd == "joinsdone": | |
247 | self.onUserList(self.users) | |
248 | except: | |
249 | self.disconnect() | |
250 | ||
251 | def _getUser(self, nick): | |
252 | if not nick.lower() in self.users.keys(): self.users[nick.lower()] = TinychatUser(nick) | |
253 | return self.users[nick.lower()] | |
254 | ||
255 | def _decodeMessage(self, msg): | |
256 | chars = msg.split(",") | |
257 | msg = "" | |
258 | for i in chars: | |
259 | msg += chr(int(i)) | |
260 | return msg | |
261 | ||
262 | def _encodeMessage(self, msg): | |
263 | msg2 = [] | |
264 | for i in msg: | |
265 | msg2.append(str(ord(i))) | |
266 | return ",".join(msg2) | |
267 | ||
268 | def _sendCommand(self, cmd, pars=[]): | |
269 | msg = {"msg": rtmp_protocol.DataTypes.COMMAND, "command": [u"" + cmd, 0, None,] + pars} | |
270 | if DEBUG: print("CLIENT: " + str(msg)) | |
271 | self.connection.writer.write(msg) | |
272 | self.connection.writer.flush() | |
273 | ||
274 | def _sendCauth(self, cauth): | |
275 | self._sendCommand("cauth", [cauth]) | |
276 | ||
277 | def _getTcUrl(self): | |
278 | return parseString(httpRequest("apl.tinychat.com", "/api/find.room/" + self.room + "?site=tinychat&url=tinychat.com")[1]).getElementsByTagName("response")[0].getAttribute("rtmp") | |
279 | ||
280 | def _getTcCauth(self): | |
281 | return self._uglyStripCauthKey(httpRequest("tinychat.com", "/api/captcha/check.php?room=tinychat^" + self.room + "&guest_id=" + self.userID)[1]) | |
282 | ||
283 | def _uglyStripCauthKey(self, json): | |
284 | cauth = json.split('"key":"')[1].split('"')[0] | |
285 | print("CAUTH KEY: " + cauth) | |
286 | return cauth | |
287 | ||
288 | def _getAutoOp(self): | |
289 | if self.nick and self.passwd: | |
290 | 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] | |
291 | cookies = [] | |
292 | for header in headers: | |
293 | if header[0].lower() == "set-cookie": | |
294 | parts = header[1].split(", ") | |
295 | for i in range(len(parts)): | |
296 | part = parts[i] | |
297 | part2 = part.split(";")[0] | |
298 | if "=" in part2: | |
299 | if "," in part2: | |
300 | part2 = part2.split(", ")[1] | |
301 | cookies.append(part2) | |
302 | break | |
303 | if len(cookies) > 0: | |
304 | html = httpRequest("tinychat.com", "/" + self.room, "", {"Content-Type": "application/x-www-form-urlencoded", "Cookie": "; ".join(cookies)})[1] | |
305 | if ", autoop: \"" in html: | |
306 | return html.split(", autoop: \"")[1].split("\"")[0] | |
307 | return u"none" | |
308 | ||
309 | if __name__ == "__main__": | |
310 | room = TinychatRoom(raw_input("Enter room name: "), raw_input("Enter username (optional): "), raw_input("Enter password (optional): ")) | |
311 | thread.start_new_thread(room.connect, ()) | |
312 | while not room.connected: time.sleep(1) | |
313 | while room.connected: | |
314 | msg = raw_input() | |
315 | if len(msg) > 0: | |
316 | if msg[0] == "/": | |
317 | msg = msg[1:] | |
318 | if len(msg) > 0: | |
319 | parts = msg.split(" ") | |
320 | if len(parts) == 1: | |
321 | cmd = parts[0] | |
322 | pars = [] | |
323 | par = "" | |
324 | else: | |
325 | cmd = parts[0] | |
326 | pars = parts[1:] | |
327 | par = " ".join(parts[1:]) | |
328 | if cmd.lower() == "say": | |
329 | room.say(par) | |
330 | elif cmd.lower() == "pm": | |
331 | if len(pars) > 1: | |
332 | room.pm(" ".join(pars[1:]), pars[0]) | |
333 | else: | |
334 | print("Please supply the recipient's nick as well as the message to send") | |
335 | elif cmd.lower() == "nick": | |
336 | room.setNick(par) | |
337 | elif cmd.lower() == "color": | |
338 | room.cycleColor() | |
339 | elif cmd.lower() == "ban": | |
340 | room.ban(par) | |
341 | elif cmd.lower() == "quit": | |
342 | room.disconnect() | |
343 | elif cmd.lower() == "playyoutube": | |
344 | room.playYoutube(par) | |
345 | elif cmd.lower() == "stopyoutube": | |
346 | room.stopYoutube() | |
347 | elif cmd.lower() == "playsoundcloud": | |
348 | room.playSoundcloud(par) | |
349 | elif cmd.lower() == "stopsoundcloud": | |
350 | room.stopSoundcloud() | |
351 | elif cmd.lower() == "cauth": | |
352 | room.cauth() | |
353 | else: | |
354 | room.say(msg) |