View difference between Paste ID: 0CYCisB5 and CBZVeXhW
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
# 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-
	while room.connected: room.say(raw_input())
272+
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)