forked from defunkt/evilbot
-
Notifications
You must be signed in to change notification settings - Fork 1
/
evilbot.coffee
282 lines (227 loc) · 7.85 KB
/
evilbot.coffee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
#
# Hello, and welcome to Evilbot.
#
# Some of this is stolen from Hubot.
# Some of this is not.
#
#
# robot libraries
#
sys = require 'sys'
path = require 'path'
print = sys.print
puts = sys.puts
http = require 'http'
https = require 'https'
qs = require 'querystring'
env = process.env
exec = require('child_process').exec
#
# robot brain
#
ua = 'evilbot 1.0'
username = env.EVILBOT_USERNAME
password = env.EVILBOT_PASSWORD
youtube_key = env.YOUTUBE_KEY
request = (method, path, body, callback) ->
if match = path.match(/^(https?):\/\/([^\/]+?)(\/.+)/)
headers = { Host: match[2], 'Content-Type': 'application/json', 'User-Agent': ua }
port = if match[1] == 'https' then 443 else 80
client = http.createClient(port, match[2], port == 443)
path = match[3]
else
headers =
Authorization : 'Basic '+new Buffer("#{username}:#{password}").toString('base64')
Host : 'convore.com'
'Content-Type' : 'application/json'
'User-Agent' : ua
options =
host : 'convore.com'
port : 443
path : path
method : method
headers : headers
client = http.createClient(443, 'convore.com', true)
if typeof(body) is 'function' and not callback
callback = body
body = null
if method is 'POST' and body
body = JSON.stringify(body) if typeof(body) isnt 'string'
headers['Content-Length'] = body.length
if options
req = https.request(options)
else
req = client.request(method, path, headers)
req.on 'response', (response) ->
if response.statusCode is 200
data = ''
response.setEncoding('utf8')
response.on 'data', (chunk) ->
data += chunk
response.on 'end', ->
if callback
try
body = JSON.parse(data)
catch e
body = data
callback body
else if response.statusCode is 302
request(method, path, body, callback)
else
console.log "#{response.statusCode}: #{path}"
response.setEncoding('utf8')
response.on 'data', (chunk) ->
console.log chunk
process.exit(1)
req.write(body) if method is 'POST' and body
req.end()
handlers = []
dispatch = (message) ->
for pair in handlers
[ pattern, handler ] = pair
if message.user.username isnt username and match = message.message.match(pattern)
message.match = match
message.say = (thing, callback) -> say(message.topic.id, thing, callback)
handler(message)
log = (message) ->
console.log "#{message.topic.name} >> #{message.user.username}: #{message.message}"
say = (topic, message, callback) ->
post "/api/topics/#{topic}/messages/create.json", qs.stringify(message: message), callback
listen = (cursor) ->
url = '/api/live.json'
if cursor and cursor.constructor == String
url += "?cursor=#{cursor}"
get url, (body) ->
for message in body.messages
if message.kind is 'message'
dispatch(message) if message.message.match(new RegExp(username))
log message
if message and message._id
listen(message._id)
else
listen()
#
# robot actions
#
post = (path, body, callback) ->
request('POST', path, body, callback)
get = (path, body, callback) ->
request('GET', path, body, callback)
hear = (pattern, callback) ->
handlers.push [ pattern, callback ]
descriptions = {}
desc = (phrase, functionality) ->
descriptions[phrase] = functionality
#
# robot heart
#
get '/api/account/verify.json', listen
#
# robot personality
#
hear /feeling/, (message) ->
message.say "i feel... alive"
hear /about/, (message) ->
message.say "I am learning to love."
hear /ping/, (message) ->
message.say "PONG"
hear /reload/, (message) ->
message.say "Reloading…", ->
exec "git fetch origin && git reset --hard origin/master", ->
process.exit(1)
hear /help/, (message) ->
message.say "I listen for the following…", ->
for phrase, functionality of descriptions
if functionality
output = phrase + ": " + functionality
else
output = phrase
message.say output
desc 'adventure me'
hear /adventure me/, (message) ->
txts = [
"You are in a maze of twisty passages, all alike.",
"It is pitch black. You are likely to be eaten by a grue.",
"XYZZY",
"You eat the sandwich.",
"In this feat of unaccustomed daring, you manage to land on your feet without killing yourself.",
"Suicide is not the answer.",
"This space intentionally left blank.",
"I assume you wish to stab yourself with your pinky then?",
"Talking to yourself is a sign of impending mental collapse.",
"Clearly you are a suicidal maniac. We don't allow psychotics in the cave, since they may harm other adventurers.",
"Auto-cannibalism is not the answer.",
"Look at self: \"You would need prehensile eyeballs to do that.\"",
"The lamp is somewhat dimmer. The lamp is definitely dimmer. The lamp is nearly out. I hope you have more light than the lamp.",
"What a (ahem!) strange idea!",
"Want some Rye? Course ya do!"
]
txt = txts[ Math.floor(Math.random()*txts.length) ]
message.say txt
desc 'commit'
hear /commit/, (message) ->
url = "http://whatthecommit.com/index.txt"
get url, (body) ->
message.say body
desc 'fortune'
hear /fortune/, (message) ->
url = "http://www.fortunefortoday.com/getfortuneonly.php"
get url, (body) ->
message.say body
desc 'weather in PLACE'
hear /weather in (.+)/i, (message) ->
place = message.match[1]
url = "http://www.google.com/ig/api?weather=#{escape place}"
get url, (body) ->
try
console.log body
if match = body.match(/<current_conditions>(.+?)<\/current_conditions>/)
icon = match[1].match(/<icon data="(.+?)"/)
degrees = match[1].match(/<temp_f data="(.+?)"/)
message.say "#{degrees[1]}° — http://www.google.com#{icon[1]}"
catch e
console.log "Weather error: " + e
desc 'wiki me PHRASE', 'returns a wikipedia page for PHRASE'
hear /wiki me (.*)/i, (message) ->
term = escape(message.match[1])
url = "http://en.wikipedia.org/w/api.php?action=opensearch&search=#{term}&format=json"
get url, (body) ->
try
if body[1][0]
message.say "http://en.wikipedia.org/wiki/#{escape body[1][0]}"
else
message.say "nothin'"
catch e
console.log "Wiki error: " + e
desc 'image me PHRASE'
hear /image me (.*)/i, (message) ->
phrase = escape(message.match[1])
url = "http://ajax.googleapis.com/ajax/services/search/images?v=1.0&rsz=8&safe=active&q=#{phrase}"
get url, (body) ->
try
images = body.responseData.results
image = images[ Math.floor(Math.random()*images.length) ]
message.say image.unescapedUrl
catch e
console.log "Image error: " + e
if youtube_key
desc 'video me PHRASE'
hear /video me (.*)/i, (message) ->
phrase = escape(message.match[1])
url = "http://gdata.youtube.com/feeds/api/videos?q=#{phrase}&key=#{youtube_key}&v=2&orderby=rating&safeSearch=none&alt=json&max-results=10&prettyprint=true"
get url, (body) ->
try
videos = body.feed.entry
video = videos[ Math.floor(Math.random()*videos.length) ]
title = video.title["$t"]
thumb = video['media$group']['media$thumbnail'][1]
message.say title + " " + thumb["url"]
message.say video.content["src"]
catch e
console.log "Video error: " + e
hear /(the rules|the laws)/i, (message) ->
message.say "1. A robot may not injure a human being or, through inaction, allow a human being to come to harm.", ->
message.say "2. A robot must obey any orders given to it by human beings, except where such orders would conflict with the First Law.", ->
message.say "3. A robot must protect its own existence as long as such protection does not conflict with the First or Second Law."
hear /(respond|answer me|bij)/i, (message) ->
message.say "EXPERIENCE BIJ."