]>
Commit | Line | Data |
---|---|---|
685e346e A |
1 | import random |
2 | import re | |
3 | from datetime import datetime, timedelta | |
4 | from xml.parsers.expat import ExpatError | |
5 | ||
6 | from pseudoclient.cmd_manager import * | |
7 | from utils import * | |
8 | from internets_utils import * | |
9 | from api.feed import FeedError | |
10 | from api.idlerpg import IrpgPlayer | |
11 | from api.quotes import FmlException | |
12 | from api.weather import WeatherException | |
13 | ||
14 | ||
15 | def get_citystate_from_zipcode(self, zipcode): | |
16 | """Return [city,state] for the given U.S. zip code (if database has been imported)""" | |
17 | try: | |
18 | self.dbp.execute("SELECT city, state FROM zipcode_citystate WHERE zipcode=%s", [int(zipcode)]) | |
19 | city, state = self.dbp.fetchone() | |
20 | return city, state | |
21 | except: | |
22 | return None | |
23 | ||
24 | ||
25 | def command_weather(self, manager, opts, arg, channel, sender, userinfo): | |
26 | arg = self.get_location(opts, arg, channel, sender) | |
27 | if not arg: | |
28 | return | |
29 | w_state = '' | |
30 | if arg.isdigit(): | |
31 | location = get_citystate_from_zipcode(self, arg) | |
32 | if location is None: | |
33 | self.errormsg(channel, 'zip code not recognised.') | |
34 | return False | |
35 | city, state = location | |
36 | location = '{city}, {state}, USA'.format(city=city, state=state) | |
37 | w_state = state + u', ' | |
38 | else: | |
39 | location = arg.strip() | |
40 | ||
41 | try: | |
42 | w = self.weather.get_conditions(location) | |
43 | except WeatherException as exc: | |
44 | if exc == 'this key is not valid': | |
45 | self.elog.warning('WARNING: OpenWeatherMap API key is not correctly set (%s)' % exc) | |
46 | self.errormsg(channel, 'weather data is temporarily unavailable. Try again later') | |
47 | else: | |
48 | self.errormsg(channel, exc) | |
49 | return | |
50 | except FeedError, e: | |
51 | self.errormsg(channel, e.msg) | |
52 | return | |
53 | ||
54 | code = get_tempcolor(w['temp_c']) | |
55 | ||
56 | self.msg(channel, format_weather(code, u"""@sep @b{w[city]}{w_state}{w[country]}@b @sep @bConditions@b {w[description]} @sep \ | |
57 | @bTemperature@b {tempcolor}{w[temp_c]}C / {w[temp_f]}F@o @sep \ | |
58 | @bPressure@b {w[pressure]}mb @sep @bHumidity@b {w[humidity]}% @sep \ | |
59 | @bRain@b {w[rain]} @sep \ | |
60 | Powered by OpenWeatherMap http://openweathermap.org/city/{w[id]} @sep""".format(w=w, tempcolor=code, w_state=w_state))) | |
61 | ||
62 | ||
63 | def command_forecast(self, manager, opts, arg, channel, sender, userinfo): | |
64 | arg = self.get_location(opts, arg, channel, sender) | |
65 | if not arg: | |
66 | return | |
67 | w_state = '' | |
68 | if arg.isdigit(): | |
69 | location = get_citystate_from_zipcode(self, arg) | |
70 | if location is None: | |
71 | self.errormsg(channel, 'zip code not recognised.') | |
72 | return False | |
73 | city, state = location | |
74 | location = '{city}, {state}, USA'.format(city=city, state=state) | |
75 | w_state = state + u', ' | |
76 | else: | |
77 | location = arg.strip() | |
78 | ||
79 | try: | |
80 | w = self.weather.get_forecast(location) | |
81 | except WeatherException as exc: | |
82 | if exc == 'this key is not valid': | |
83 | self.elog.warning('WARNING: OpenWeatherMap API key is not correctly set (%s)' % exc) | |
84 | self.errormsg(channel, 'weather data is temporarily unavailable. Try again later') | |
85 | else: | |
86 | self.errormsg(channel, exc) | |
87 | return | |
88 | except FeedError, e: | |
89 | self.errormsg(channel, e.msg) | |
90 | return | |
91 | ||
92 | fc = ' @sep '.join([u"""@b{day[name]}@b {day[description]} @c04{day[max_c]}C / {day[max_f]}F \ | |
93 | @c10{day[min_c]}C / {day[min_f]}F""".format(day=day) for day in w['days']]) | |
94 | ||
95 | self.msg(channel, u'@sep @b{w[city]}{w_state}{w[country]}@b @sep {fc} @sep'.format(w=w, fc=fc, w_state=w_state)) | |
96 | ||
97 | ||
98 | def command_register_location(self, manager, opts, arg, channel, sender, userinfo): | |
99 | arg = arg.strip() | |
100 | try: | |
101 | w_state = '' | |
102 | if arg.isdigit(): | |
103 | location = get_citystate_from_zipcode(self, arg) | |
104 | if location is None: | |
105 | self.errormsg(channel, 'zip code not recognised.') | |
106 | return False | |
107 | city, state = location | |
108 | location = '{city}, {state}, USA'.format(city=city, state=state) | |
109 | w_state = state + u', ' | |
110 | else: | |
111 | location = arg.strip() | |
112 | ||
113 | w = self.weather.get_conditions(location) | |
114 | except WeatherException as exc: | |
115 | if exc == 'this key is not valid': | |
116 | self.elog.warning('WARNING: OpenWeatherMap API key is not correctly set (%s)' % exc) | |
117 | self.errormsg(channel, 'weather data is temporarily unavailable. Try again later') | |
118 | else: | |
119 | self.errormsg(channel, exc) | |
120 | return | |
121 | except FeedError, e: | |
122 | self.errormsg(channel, e.msg) | |
123 | return | |
124 | ||
125 | loc_name = u'{w[city]}{w_state}{w[country]}'.format(w=w, w_state=w_state) | |
126 | ||
127 | self.users.set(sender, 'location', arg) | |
128 | self.msg(channel, u'%s: registered location @b%s@b' % (sender, loc_name)) | |
129 | ||
130 | def command_bing_translate(self, manager, opts, arg, channel, sender, userinfo): | |
131 | sp = arg.split(' ', 2) | |
132 | try: | |
133 | if len(sp) > 2: | |
134 | source, target, text = sp | |
135 | if source.lower() not in self.bing.languages or target.lower() not in self.bing.languages: | |
136 | source = self.bing.detect_language(arg) | |
137 | target = None | |
138 | translation = self.bing.translate(arg) | |
139 | else: | |
140 | source = source.lower() | |
141 | target = target.lower() | |
142 | translation = self.bing.translate(text, source, target) | |
143 | else: | |
144 | source = self.bing.detect_language(arg) | |
145 | target = None | |
146 | translation = self.bing.translate(arg) | |
147 | except FeedError, e: | |
148 | self.elog.warning('WARNING: Bing translate failed: %s' % e) | |
149 | self.errormsg(channel, e.msg) | |
150 | return | |
151 | ||
152 | self.msg(channel, '[t] [from %s] %s' % (source, translation)) | |
153 | ||
154 | def command_google_search(self, manager, opts, arg, channel, sender, userinfo): | |
155 | try: | |
156 | result = self.google.search(arg, userinfo['ip'] if userinfo['ip'] != '0' else '255.255.255.255') | |
157 | except FeedError, e: | |
158 | self.errormsg(channel, e.msg) | |
159 | return | |
160 | ||
161 | if result['responseStatus'] == 403: | |
162 | self.elog.warning('WARNING: Google Search failed: %s' % result['responseDetails'] if 'responseDetails' in result else 'unknown error') | |
163 | self.notice(sender, 'Google Search is temporarily unavailable. Try again later.') | |
164 | return | |
165 | ||
166 | result = result['responseData']['results'] | |
167 | if not result: | |
168 | self.msg(channel, '[Google] No results found') | |
169 | return | |
170 | ||
171 | json = result[0] | |
172 | self.msg(channel, '[Google] @b%(title)s@b <@u%(url)s@u>' % { | |
173 | 'title': unescape(json['titleNoFormatting']), | |
174 | 'url': json['unescapedUrl']}) | |
175 | self.msg(channel, '[Google] @bDescription@b: %s' % unescape(json['content']).replace('<b>', '@b').replace('</b>', '@b')) | |
176 | ||
177 | def command_calc(self, manager, opts, arg, channel, sender, userinfo): | |
178 | try: # local calculation using PyParsing | |
179 | result = self.nsp.eval(arg) | |
180 | self.msg(channel, '[calc] {} = {}'.format(arg, result)) | |
181 | except: # just throw it at W|A, hopefully they can get it | |
182 | try: | |
183 | result = self.wolfram.alpha(arg) | |
184 | except FeedError as e: | |
185 | self.errormsg(channel, e.msg) | |
186 | return | |
187 | ||
188 | if result is None: | |
189 | self.msg(channel, '[W|A] Invalid input.') | |
190 | else: | |
191 | self.msg(channel, u'[W|A] {r[0]} = {r[1]}'.format(r=result)) | |
192 | ||
193 | def command_youtube_search(self, manager, opts, arg, channel, sender, userinfo): | |
194 | try: | |
195 | res = self.google.yt_search(arg) | |
196 | except FeedError, e: | |
197 | self.errormsg(channel, e.msg) | |
198 | return | |
199 | ||
200 | if not res: | |
201 | self.msg(channel, '[YouTube] No results found') | |
202 | return | |
203 | ||
204 | self.msg(channel, """@sep @bYouTube@b %(title)s @sep @bURL@b %(url)s (%(duration)s) @sep @bViews@b %(views)s @sep \ | |
205 | @bRating@b %(rating)s/5 - %(votes)s votes @c3@b[+]@b %(liked)s likes @c4@b[-]@b %(disliked)s dislikes @sep""" % { | |
206 | 'title': res['title'], | |
207 | 'url': 'http://www.youtube.com/watch?v=' + res['id'], | |
208 | 'duration': '%s' % format_hms(res['duration']), | |
209 | 'views': format_thousand(res['view_count']), | |
210 | 'rating': round(res['rating'], 2) if res['rating'] else 0, | |
211 | 'votes': format_thousand(res['rate_count']) if res['rate_count'] else 0, | |
212 | 'liked': format_thousand(res['liked']) if res['liked'] else 0, | |
213 | 'disliked': format_thousand(res['disliked']) if res['disliked'] else 0 | |
214 | }) | |
215 | ||
216 | def command_dictionary(self, manager, opts, arg, channel, sender, userinfo): | |
217 | try: | |
218 | results = self.wordnik.definition(arg) | |
219 | except FeedError, e: | |
220 | self.errormsg(channel, e.msg) | |
221 | return | |
222 | ||
223 | if not results: | |
224 | self.msg(channel, '[dictionary] Nothing found') | |
225 | return | |
226 | ||
227 | if 'all' in opts: | |
228 | for n, res in enumerate(results, 1): | |
229 | self.notice(sender, u'@sep [{num}/{tot}] @bDefinition@b {res.word} @sep {res.text} @sep'.format( | |
230 | res=res, num=n, tot=len(results))) | |
231 | elif 'number' in opts: | |
232 | if opts['number'] - 1 < 0 or opts['number'] - 1 > len(results): | |
233 | self.errormsg(channel, 'option -n out of range: only %d definitions found.' % len(results)) | |
234 | return | |
235 | ||
236 | result = results[opts['number'] - 1] | |
237 | self.msg(channel, u'@sep [{num}/{tot}] @bDefinition@b {res.word} @sep {res.text} @sep'.format( | |
238 | res=result, num=opts['number'], tot=len(results))) | |
239 | else: | |
240 | for n, res in enumerate(results, 1): | |
241 | self.msg(channel, u'@sep [{num}/{tot}] @bDefinition@b {res.word} @sep {res.text} @sep'.format( | |
242 | res=res, num=n, tot=len(results))) | |
243 | if n == 4: | |
244 | self.notice(sender, 'To view all definitions: .dict {res.word} -a. To view the n-th definition: .dict {res.word} -n <number>'.format(res=res)) | |
245 | break | |
246 | ||
247 | def command_urbandictionary(self, manager, opts, arg, channel, sender, userinfo): | |
248 | expr, sep, def_id = arg.partition('/') | |
249 | try: | |
250 | res = self.urbandictionary.get_definitions(expr.strip()) | |
251 | except FeedError, e: | |
252 | self.errormsg(channel, e.msg) | |
253 | self.elog.warning('feed error in .urbandictionary: %s' % e) | |
254 | return | |
255 | ||
256 | if res['result_type'] == 'no_results' or res['result_type'] == 'fulltext': | |
257 | self.errormsg(channel, 'no results found') | |
258 | elif res['result_type'] == 'exact': | |
259 | if def_id: | |
260 | try: | |
261 | def_id = int(def_id) | |
262 | if def_id < 1: | |
263 | self.errormsg(channel, 'invalid definition number') | |
264 | return | |
265 | ||
266 | entry = res['list'][def_id - 1] | |
267 | definition = entry['definition'].replace('\r\n', ' / ').replace('\n', ' / ') | |
268 | example = entry['example'].replace('\r\n', ' / ').replace('\n', ' / ') | |
269 | self.msg(channel, u'@sep [{num}/{total}] {entry[word]} @sep {definition} @sep'.format( | |
270 | num = def_id, | |
271 | total = len(res['list']), | |
272 | res = res, | |
273 | definition = definition if len(definition) < 200 else definition[:200] + '...', | |
274 | entry = entry)) | |
275 | self.msg(channel, u'@sep @bExample@b %s @sep' % (example if len(example) < 280 else example[:280] + '...')) | |
276 | except ValueError: | |
277 | self.errormsg(channel, 'invalid definition number') | |
278 | except IndexError: | |
279 | self.errormsg(channel, 'definition id out of range: only %d definitions available' % len(res['list'])) | |
280 | else: | |
281 | for num, entry in enumerate(res['list'], 1): | |
282 | if num == 4: | |
283 | self.notice(sender, 'To view a single definition with a related example, type: @b.u %s /def_number@b. For more definitions, visit: %s' % (expr, res['list'][0]['permalink'])) | |
284 | break | |
285 | ||
286 | definition = entry['definition'].replace('\r\n', ' / ').replace('\n', ' / ') | |
287 | self.msg(channel, u'@sep [{num}/{total}] {entry[word]} @sep {definition} @sep'.format( | |
288 | num = num, | |
289 | total = len(res['list']), | |
290 | res = res, | |
291 | definition = definition if len(definition) < 200 else definition[:200] + '...', | |
292 | entry = entry)) | |
293 | else: | |
294 | self.msg(channel, 'An exception occurred and has been reported to the developers. If this error persists please do not use the faulty command until it has been fixed.') | |
295 | self.elog.warning('unrecognized result type: %s' % res['result_type']) | |
296 | ||
297 | def command_imdb(self, manager, opts, arg, channel, sender, userinfo): | |
298 | try: | |
299 | reply = self.imdb.get(arg) | |
300 | except FeedError, e: | |
301 | self.errormsg(channel, e.msg) | |
302 | return | |
303 | except ValueError: | |
304 | self.errormsg(channel, 'movie not found') | |
305 | return | |
306 | ||
307 | if reply['Response'] != 'True': | |
308 | self.msg(channel, '[imdb] Nothing found') | |
309 | return | |
310 | ||
311 | self.msg(channel, u"""@sep @b{r[Title]}@b [{r[Year]}] Rated {r[Rated]} @sep @bRating@b {r[imdbRating]}/10, {r[imdbVotes]} votes @sep \ | |
312 | @bGenre@b {r[Genre]} @sep @bDirector@b {r[Director]} @sep @bActors@b {r[Actors]} @sep @bRuntime@b {r[Runtime]} @sep""".format(r=reply)) | |
313 | self.msg(channel, u'@sep @bPlot@b {r[Plot]} @sep @uhttp://www.imdb.com/title/{r[imdbID]}/@u @sep'.format(r=reply)) | |
314 | ||
315 | def command_lastfm(self, manager, opts, arg, channel, sender, userinfo): | |
316 | try: | |
317 | user = self.lastfm.get_user(arg) | |
318 | if 'error' in user: | |
319 | self.errormsg(channel, user['message']) | |
320 | return | |
321 | latest = self.lastfm.get_recent_tracks(arg, 1) | |
322 | except FeedError as e: | |
323 | self.errormsg(channel, e.msg) | |
324 | return | |
325 | ||
326 | user = user['user'] | |
327 | userinfo = [] | |
328 | if user['realname']: | |
329 | userinfo.append(user['realname']) | |
330 | if user['age']: | |
331 | userinfo.append(user['age']) | |
332 | if user['country']: | |
333 | userinfo.append(user['country']) | |
334 | ||
335 | if userinfo: | |
336 | userinfo = ' [%s]' % ', '.join(userinfo) | |
337 | else: | |
338 | userinfo = '' | |
339 | ||
340 | if 'track' in latest['recenttracks']: | |
341 | if isinstance(latest['recenttracks']['track'], list): | |
342 | latest = latest['recenttracks']['track'][0] | |
343 | else: | |
344 | latest = latest['recenttracks']['track'] | |
345 | try: | |
346 | latest['@attr']['nowplaying'] | |
347 | latest_str = u' @bNow playing@b {latest[artist][#text]} - {latest[name]} @sep'.format(latest=latest) | |
348 | except KeyError: | |
349 | latestdate = get_timespan(datetime.fromtimestamp(int(latest['date']['uts']))) | |
350 | latest_str = u' @bLatest track@b {latest[artist][#text]} - {latest[name]} ({latestdate} ago) @sep'.format( | |
351 | latest=latest, latestdate=latestdate) | |
352 | else: | |
353 | latest_str = '' | |
354 | ||
355 | self.msg(channel, u'@sep @b{user[name]}@b{userinfo} @sep @bPlays@b {plays} since {regdate} @sep \ | |
356 | @bLink@b {user[url]} @sep{latest_track}'.format( | |
357 | userinfo = userinfo, | |
358 | plays = format_thousand(int(user['playcount'])), | |
359 | regdate = user['registered']['#text'][:10], | |
360 | user = user, | |
361 | latest_track = latest_str)) | |
362 | ||
363 | def command_url_shorten(self, manager, opts, arg, channel, sender, userinfo): | |
364 | if not arg.startswith('http://') and not arg.startswith('https://'): | |
365 | self.errormsg(channel, 'a valid URL must start with http:// or https://') | |
366 | return | |
367 | ||
368 | try: | |
369 | reply = self.urls.shorten(arg) | |
370 | except FeedError, e: | |
371 | self.errormsg(channel, e.msg) | |
372 | return | |
373 | ||
374 | if reply['status_code'] != 200: | |
375 | self.errormsg(channel, 'an error occurred.') | |
376 | self.elog.warning('[shorten] error: code %d, %s' % (reply['status_code'], reply['status_txt'])) | |
377 | else: | |
378 | self.msg(channel, '@sep @bShort URL@b %s @sep' % reply['data']['url']) | |
379 | ||
380 | def command_url_expand(self, manager, opts, arg, channel, sender, userinfo): | |
381 | if not arg.startswith('http://') and not arg.startswith('https://'): | |
382 | self.errormsg(channel, 'a valid URL must start with http:// or https://') | |
383 | return | |
384 | ||
385 | try: | |
386 | reply = self.urls.expand(arg) | |
387 | except FeedError, e: | |
388 | self.errormsg(channel, e.msg) | |
389 | return | |
390 | ||
391 | if 'error' in reply: | |
392 | self.errormsg(channel, reply['error']) | |
393 | else: | |
394 | self.msg(channel, '@sep @bLong URL@b {reply[long-url]} @sep @bContent-type@b {reply[content-type]} @sep'.format(reply=reply)) | |
395 | ||
396 | def command_idlerpg(self, manager, opts, arg, channel, sender, userinfo): | |
397 | try: | |
398 | player = IrpgPlayer(arg) | |
399 | except FeedError, e: | |
400 | self.errormsg(channel, e.msg) | |
401 | return | |
402 | ||
403 | if not player.name: | |
404 | self.errormsg(channel, 'player not found. @bNote@b: nicks are case sensitive.') | |
405 | return | |
406 | ||
407 | self.msg(channel, """@sep @b{player.name}@b [{status}] @sep @bLevel@b {player.level} {player.classe} @sep @bNext level@b \ | |
408 | {nextlevel} @sep @bIdled@b {idled_for} @sep @bAlignment@b {player.alignment} @sep""".format( | |
409 | player = player, | |
410 | status = '@c3ON@c' if player.is_online else '@c4OFF@c', | |
411 | nextlevel = timedelta(seconds=player.ttl), | |
412 | idled_for = timedelta(seconds=player.idled_for))) | |
413 | ||
414 | def command_ipinfo(self, manager, opts, arg, channel, sender, userinfo): | |
415 | try: | |
416 | reply = self.ipinfo.get_info(arg) | |
417 | except FeedError, e: | |
418 | self.errormsg(channel, e.msg) | |
419 | return | |
420 | ||
421 | self.msg(channel, """@sep @bIP/Host@b {arg} ({reply[ip_addr]}) @sep @bLocation@b {reply[city]}, {reply[region]}, \ | |
422 | {reply[country_name]} [{reply[country_code]}] @sep{map}""".format( | |
423 | reply = reply, | |
424 | arg = arg.lower(), | |
425 | map = ' http://maps.google.com/maps?q=%s,%s @sep' % (reply['latitude'], reply['longitude']) if reply['latitude'] and reply['longitude'] else '')) | |
426 | ||
427 | dice_regex = re.compile('^(?:(\d+)d)?(\d+)(?:([\+\-])(\d+))?$') | |
428 | def command_dice(self, manager, opts, arg, channel, sender, userinfo): | |
429 | r = dice_regex.search(arg) | |
430 | if not r: | |
431 | self.errormsg(channel, 'invalid format') | |
432 | return | |
433 | ||
434 | num, faces, type, modifier = r.groups() | |
435 | if num: | |
436 | num = int(num) | |
437 | else: | |
438 | num = 1 | |
439 | faces = int(faces) | |
440 | if num < 1 or num > 32 or faces < 2 or faces > 65536: | |
441 | self.errormsg(channel, 'parameter out of range') | |
442 | return | |
443 | ||
444 | total = 0 | |
445 | results = [] | |
446 | for n in xrange(int(num)): | |
447 | randnum = random.randint(1, int(faces)) | |
448 | total += randnum | |
449 | results.append(randnum) | |
450 | ||
451 | if type == '-': | |
452 | modifier = int(modifier) | |
453 | total -= modifier | |
454 | max = num * faces - modifier | |
455 | elif type == '+': | |
456 | modifier = int(modifier) | |
457 | total += modifier | |
458 | max = num * faces + modifier | |
459 | else: | |
460 | max = num * faces | |
461 | ||
462 | self.msg(channel, '@sep @bTotal@b {total} / {max} [{percent}%] @sep @bResults@b {results} @sep'.format( | |
463 | total = total, | |
464 | max = max, | |
465 | percent = 100 * total / max if max != 0 else '9001', | |
466 | results = str(results))) | |
467 | ||
468 | def command_qdb(self, manager, opts, arg, channel, sender, userinfo): | |
469 | try: | |
470 | if not arg: | |
471 | quote = self.quotes.get_qdb_random() | |
472 | else: | |
473 | try: | |
474 | quote_id = int(arg) | |
475 | quote = self.quotes.get_qdb_id(quote_id) | |
476 | if not quote: | |
477 | self.errormsg(channel, 'quote @b%d@b not found' % quote_id) | |
478 | return | |
479 | except ValueError: | |
480 | self.errormsg(channel, 'invalid quote ID') | |
481 | return | |
482 | except ExpatError: # qdb returns a malformed xml when the quote doesn't exist | |
483 | self.errormsg(channel, 'quote @b%d@b not found' % quote_id) | |
484 | return | |
485 | except FeedError, e: | |
486 | self.errormsg(channel, e.msg) | |
487 | return | |
488 | ||
489 | id = quote['id'] | |
490 | for line in quote['lines']: | |
491 | self.msg(channel, u'[qdb {id}] {line}'.format(id=id, line=line.replace('\n', ''))) | |
492 | ||
493 | def command_fml(self, manager, opts, arg, channel, sender, userinfo): | |
494 | try: | |
495 | if not arg: | |
496 | quote = self.quotes.get_fml() | |
497 | else: | |
498 | try: | |
499 | quote_id = int(arg) | |
500 | quote = self.quotes.get_fml(quote_id) | |
501 | if not quote: | |
502 | self.errormsg(channel, 'quote @b%d@b not found' % quote_id) | |
503 | return | |
504 | except (ValueError, IndexError): | |
505 | self.errormsg(channel, 'invalid quote ID') | |
506 | return | |
507 | except (FeedError, FmlException) as e: | |
508 | self.errormsg(channel, e.msg) | |
509 | self.elog.warning('WARNING: .fml error: %s' % e.msg) | |
510 | return | |
511 | ||
512 | self.msg(channel, u'[fml #{quote[id]}] {quote[text]}'.format(quote=quote)) | |
513 | ||
514 | def command_internets_info(self, manager, opts, arg, channel, sender, userinfo): | |
515 | self.notice(sender, '@sep @bRizon Internets Bot@b @sep @bDevelopers@b martin <martin@rizon.net> @sep @bHelp/feedback@b %(channel)s @sep' % { | |
516 | 'channel' : '#internets'}) | |
517 | ||
518 | def command_internets_help(self, manager, opts, arg, channel, sender, userinfo): | |
519 | command = arg.lower() | |
520 | ||
521 | if command == '': | |
522 | message = ['internets: .help internets - for internets commands'] | |
523 | elif command == 'internets': | |
524 | message = manager.get_help() | |
525 | else: | |
526 | message = manager.get_help(command) | |
527 | ||
528 | if message == None: | |
529 | message = ['%s is not a valid command.' % arg] | |
530 | ||
531 | for line in message: | |
532 | self.notice(sender, line) | |
533 | ||
534 | class UserCommandManager(CommandManager): | |
535 | def get_prefix(self): | |
536 | return '.' | |
537 | ||
538 | def get_commands(self): | |
539 | return { | |
540 | 'cc': 'calc', | |
541 | 'calc': (command_calc, ARG_YES, 'Calculates an expression', [], 'expression'), | |
542 | ||
543 | 'dict': 'dictionary', | |
544 | 'dictionary': (command_dictionary, ARG_YES, 'Search for a dictionary definition', [ | |
545 | ('number', '-n', 'display the n-th result', {'type': '+integer'}, ARG_YES), | |
546 | ('all', '-a', 'display all results (using /notice)', {'action': 'store_true'}, ARG_YES)], 'word'), | |
547 | ||
548 | 'u': 'urbandictionary', | |
549 | 'urbandictionary': (command_urbandictionary, ARG_YES, 'Search for a definition on Urban Dictionary', [], 'word'), | |
550 | ||
551 | 'g': 'google', | |
552 | 'google': (command_google_search, ARG_YES, 'Search for something on Google', [], 'google_search'), | |
553 | ||
554 | 't': 'translate', | |
555 | 'translate': (command_bing_translate, ARG_YES, 'Translate something from a language to another', [], 'from to text'), | |
556 | ||
557 | 'yt': 'youtube', | |
558 | 'youtube': (command_youtube_search, ARG_YES, 'Search for something on YouTube', [], 'youtube_search'), | |
559 | ||
560 | 'w': 'weather', | |
561 | 'weather': (command_weather, ARG_OPT, 'Displays current weather conditions for a location', [ | |
562 | ('nick', '-n', 'use the weather location linked to a nick', {'action': 'store_true'}, ARG_YES)]), | |
563 | ||
564 | 'f': 'forecast', | |
565 | 'forecast': (command_forecast, ARG_OPT, 'Displays 5-day forecast for a location', [ | |
566 | ('nick', '-n', 'use the weather location linked to a nick', {'action': 'store_true'}, ARG_YES)]), | |
567 | ||
568 | 'regloc': 'register_location', | |
569 | 'register_location': (command_register_location, ARG_YES, 'Links a location to your nick that will be used as default location in .w and .f', [], 'location'), | |
570 | ||
571 | 'imdb': (command_imdb, ARG_YES, 'Search for information on a movie on IMDB', [], 'movie_title'), | |
572 | ||
573 | 'lastfm': (command_lastfm, ARG_YES, 'Returns information on a Last.fm user', [], 'lastfm_user'), | |
574 | ||
575 | 'shorten': (command_url_shorten, ARG_YES, 'Shortens a URL using http://j.mp', [], 'long_url'), | |
576 | ||
577 | 'expand': (command_url_expand, ARG_YES, 'Expands a shortened URL using http://longurl.org', [], 'shortened_url'), | |
578 | ||
579 | 'irpg': 'idlerpg', | |
580 | 'idlerpg': (command_idlerpg, ARG_YES, 'Returns info on a player in Rizon IdleRPG (http://idlerpg.rizon.net/)', [], 'player_name'), | |
581 | ||
582 | 'ipinfo': (command_ipinfo, ARG_YES, 'Returns short info on a IP address/hostname', [], 'ip/host'), | |
583 | ||
584 | 'd': 'dice', | |
585 | 'dice': (command_dice, ARG_YES, 'Rolls X N-sided dice with an optional modifier A (XdN+A format)', [], 'dice_notation'), | |
586 | ||
587 | 'qdb': (command_qdb, ARG_OPT, 'Displays a quote from qdb.us', []), | |
588 | ||
589 | 'fml': (command_fml, ARG_OPT, 'Displays a quote from http://www.fmylife.com', []), | |
590 | ||
591 | 'info': (command_internets_info, ARG_NO|ARG_OFFLINE, 'Displays version and author information', []), | |
592 | 'help': (command_internets_help, ARG_OPT|ARG_OFFLINE, 'Displays available commands and their usage', []), | |
593 | } |