def detect(text): uri = 'http://ajax.googleapis.com/ajax/services/language/detect' q = urllib.quote(text) bytes = web.get(uri + '?q=' + q + '&v=1.0') result = web.json(bytes) try: return result['responseData']['language'] except Exception: return None
def dict(phenny, input): if not input.group(2): return phenny.reply("Nothing to define.") word = input.group(2) word = urllib.quote(word.encode('utf-8')) def trim(thing): if thing.endswith(' '): thing = thing[:-6] return thing.strip(' :.') bytes = web.get(uri % word) results = {} wordkind = None for kind, sense in r_info.findall(bytes): kind, sense = trim(kind), trim(sense) if kind: wordkind = kind elif sense: results.setdefault(wordkind, []).append(sense) result = input.group(2).encode('utf-8') + ' - ' for key in sorted(results.keys()): if results[key]: result += (key or '') + ' 1. ' + results[key][0] if len(results[key]) > 1: result += ', 2. ' + results[key][1] result += '; ' result = result.rstrip('; ') if result.endswith('-') and (len(result) < 30): phenny.reply('Sorry, no definition found.') else: phenny.say(result)
def py(phenny, input): query = input.group(2).encode('utf-8') uri = 'http://tumbolia.appspot.com/py/' answer = web.get(uri + web.urllib.quote(query)) if answer: phenny.say(answer) else: phenny.reply('Sorry, no result.')
def etymology(word): # @@ <nsh> sbp, would it be possible to have a flag for .ety to get 2nd/etc # entries? - http://swhack.com/logs/2006-07-19#T15-05-29 if len(word) > 25: raise ValueError("Word too long: %s[...]" % word[:10]) word = {'axe': 'ax/axe'}.get(word, word) bytes = web.get(etyuri % web.urllib.quote(word)) definitions = r_definition.findall(bytes) if not definitions: return None defn = text(definitions[0]) m = r_sentence.match(defn) if not m: return None sentence = m.group(0) try: sentence = unicode(sentence, 'iso-8859-1') sentence = sentence.encode('utf-8') except: pass maxlength = 275 if len(sentence) > maxlength: sentence = sentence[:maxlength] words = sentence[:-5].split(' ') words.pop() sentence = ' '.join(words) + ' [...]' sentence = '"' + sentence.replace('"', "'") + '"' return sentence + ' - ' + (etyuri % word)
def wiktionary(word): bytes = web.get(uri % web.urllib.quote(word.encode('utf-8'))) bytes = r_ul.sub('', bytes) mode = None etymology = None definitions = {} for line in bytes.splitlines(): if 'id="Etymology"' in line: mode = 'etymology' elif 'id="Noun"' in line: mode = 'noun' elif 'id="Verb"' in line: mode = 'verb' elif 'id="Adjective"' in line: mode = 'adjective' elif 'id="Adverb"' in line: mode = 'adverb' elif 'id="Interjection"' in line: mode = 'interjection' elif 'id="Particle"' in line: mode = 'particle' elif 'id="Preposition"' in line: mode = 'preposition' elif 'id="' in line: mode = None elif (mode == 'etmyology') and ('<p>' in line): etymology = text(line) elif (mode is not None) and ('<li>' in line): definitions.setdefault(mode, []).append(text(line)) if '<hr' in line: break return etymology, definitions
def translate(text, input, output): uri = 'http://ajax.googleapis.com/ajax/services/language/translate' q = urllib.quote(text) pair = input + '%7C' + output bytes = web.get(uri + '?q=' + q + '&v=1.0&langpair=' + pair) result = web.json(bytes) try: return result['responseData']['translatedText'].encode('cp1252') except Exception: return None
def wa(phenny, input): if not input.group(2): return phenny.reply("No search term.") query = input.group(2).encode('utf-8') uri = 'http://tumbolia.appspot.com/wa/' answer = web.get(uri + web.urllib.quote(query)) if answer: phenny.say(answer) else: phenny.reply('Sorry, no result.')
def search(query): """Search using AjaxSearch, and return its JSON.""" uri = 'http://ajax.googleapis.com/ajax/services/search/web' args = '?v=1.0&safe=off&q=' + web.urllib.quote(query.encode('utf-8')) handler = web.urllib._urlopener web.urllib._urlopener = Grab() bytes = web.get(uri + args) web.urllib._urlopener = handler return web.json(bytes)
def mappings(uri): result = {} bytes = web.get(uri) for item in r_item.findall(bytes): item = r_tag.sub('', item).strip(' \t\r\n') if not ' ' in item: continue command, template = item.split(' ', 1) if not command.isalnum(): continue if not template.startswith('http://'): continue result[command] = template.replace('&', '&') return result
def service(phenny, input, command, args): t = o.services[command] template = t.replace('${args}', urllib.quote(args.encode('utf-8'), '')) template = template.replace('${nick}', urllib.quote(input.nick, '')) uri = template.replace('${sender}', urllib.quote(input.sender, '')) info = web.head(uri) if isinstance(info, list): info = info[0] if not 'text/plain' in info.get('content-type', '').lower(): return phenny.reply("Sorry, the service didn't respond in plain text.") bytes = web.get(uri) lines = bytes.splitlines() if not lines: return phenny.reply("Sorry, the service didn't respond any output.") phenny.say(lines[0][:350])
def local(icao, hour, minute): uri = ('http://www.flightstats.com/' + 'go/Airport/airportDetails.do?airportCode=%s') try: bytes = web.get(uri % icao) except AttributeError: raise GrumbleError('A WEBSITE HAS GONE DOWN WTF STUPID WEB') m = r_from.search(bytes) if m: offset = m.group(1) lhour = int(hour) + int(offset) lhour = lhour % 24 return (str(lhour) + ':' + str(minute) + ', ' + str(hour) + str(minute) + 'Z') # return (str(lhour) + ':' + str(minute) + ' (' + str(hour) + # ':' + str(minute) + 'Z)') return str(hour) + ':' + str(minute) + 'Z'
def do_flickr(term): if isinstance(term, unicode): print 'Term is unicode' t = term.encode('utf-8') else: print 'Term is NOT unicode' t = term q = urllib.quote(t) u = 'http://www.flickr.com/search/?q=%s&w=all' % q bytes = web.get(u) print u # A bit nasty to have three regexes for this, I'll have to clean this mess up savos = "" r_links = re.compile(r'(?ims)<a[^>]*href="/photos/[^/]*/[^/]*/"[^>]*>') # Find all photo links on the result page links = r_links.findall(bytes) if not links: return None r_link = re.compile(r'(?ims)<a[^>]*href="(/photos/[^/]*/[^/]*/)"[^>]*>') r_title = re.compile(r'(?ims)<a[^>]*title="([^"]*)"[^>]*>') i = 0 # Count the links j = 0 # Sometimes links are missing title, we need this to count links WITH titles for link in links: i += 1 midi = r_title.findall(link) if midi: j += 1 mmx = r_link.findall(link) if mmx: savos += "http://flickr.com"+mmx[0]+" - "+midi[0]+" " if i > 10 or j > 3 or len(savos) > 250: break if not savos: return None return savos
def c(phenny, input): """Google calculator.""" if not input.group(2): return phenny.reply("Nothing to calculate.") q = input.group(2).encode('utf-8') q = q.replace('\xcf\x95', 'phi') # utf-8 U+03D5 q = q.replace('\xcf\x80', 'pi') # utf-8 U+03C0 uri = 'http://www.google.com/ig/calculator?q=' bytes = web.get(uri + web.urllib.quote(q)) parts = bytes.split('",') answer = [p for p in parts if p.startswith('rhs: "')][0][6:] if answer: answer = answer.decode('unicode-escape') answer = ''.join(chr(ord(c)) for c in answer) answer = answer.decode('utf-8') answer = answer.replace(u'\xc2\xa0', ',') answer = answer.replace('<sup>', '^(') answer = answer.replace('</sup>', ')') answer = web.decode(answer) phenny.say(answer) else: phenny.say('Sorry, no result.')
def bing(phenny, input): """Queries Bing for the specified input.""" query = input.group(2) if query.startswith(':'): lang, query = query.split(' ', 1) lang = lang[1:] else: lang = 'en-GB' if not query: return phenny.reply('.bing what?') query = web.urllib.quote(query.encode('utf-8')) base = 'http://www.bing.com/search?mkt=%s&q=' % lang bytes = web.get(base + query) m = r_bing.search(bytes) if m: uri = m.group(1) phenny.reply(uri) if not hasattr(phenny.bot, 'last_seen_uri'): phenny.bot.last_seen_uri = {} phenny.bot.last_seen_uri[input.sender] = uri else: phenny.reply("No results found for '%s'." % query)
def calc(phenny, input): """Use the Frink online calculator.""" q = input.group(2) if not q: return phenny.say('0?') query = q[:] for a, b in subs: query = re.sub(a, b, query) query = query.rstrip(' \t') precision = 5 if query[-3:] in ('GBP', 'USD', 'EUR', 'NOK'): precision = 2 query = web.urllib.quote(query.encode('utf-8')) uri = 'http://futureboy.us/fsp/frink.fsp?fromVal=' bytes = web.get(uri + query) m = r_result.search(bytes) if m: result = m.group(1) result = r_tag.sub('', result) # strip span.warning tags result = result.replace('>', '>') result = result.replace('(undefined symbol)', '(?) ') if '.' in result: try: result = str(round(float(result), precision)) except ValueError: pass if not result.strip(): result = '?' elif ' in ' in q: result += ' ' + q.split(' in ', 1)[1] phenny.say(q + ' = ' + result[:350]) else: phenny.reply("Sorry, can't calculate that.") phenny.say('Note that .calc is deprecated, consider using .c')
def wikipedia(term, language="en", last=False): global wikiuri if not "%" in term: if isinstance(term, unicode): t = term.encode("utf-8") else: t = term q = urllib.quote(t) u = wikiuri % (language, q) bytes = web.get(u) else: bytes = web.get(wikiuri % (language, term)) bytes = r_tr.sub("", bytes) if not last: r = r_redirect.search(bytes[:4096]) if r: term = urllib.unquote(r.group(1)) return wikipedia(term, language=language, last=True) paragraphs = r_paragraph.findall(bytes) if not paragraphs: if not last: term = search(term) return wikipedia(term, language=language, last=True) return None # Pre-process paragraphs = [ para for para in paragraphs if ( para and "technical limitations" not in para and "window.showTocToggle" not in para and "Deletion_policy" not in para and "Template:AfD_footer" not in para and not (para.startswith("<p><i>") and para.endswith("</i></p>")) and not 'disambiguation)"' in para ) and not "(images and media)" in para and not "This article contains a" in para and not 'id="coordinates"' in para and not 'class="thumb' in para ] # and not 'style="display:none"' in para] for i, para in enumerate(paragraphs): para = para.replace("<sup>", "|") para = para.replace("</sup>", "|") paragraphs[i] = text(para).strip() # Post-process paragraphs = [para for para in paragraphs if (para and not (para.endswith(":") and len(para) < 150))] para = text(paragraphs[0]) m = r_sentence.match(para) if not m: if not last: term = search(term) return wikipedia(term, language=language, last=True) return None sentence = m.group(0) maxlength = 275 if len(sentence) > maxlength: sentence = sentence[:maxlength] words = sentence[:-5].split(" ") words.pop() sentence = " ".join(words) + " [...]" if ( ("using the Article Wizard if you wish" in sentence) or ("or add a request for it" in sentence) or ("in existing articles" in sentence) ): if not last: term = search(term) return wikipedia(term, language=language, last=True) return None sentence = '"' + sentence.replace('"', "'") + '"' sentence = sentence.decode("utf-8").encode("utf-8") wikiuri = wikiuri.decode("utf-8").encode("utf-8") term = term.decode("utf-8").encode("utf-8") return sentence + " - " + (wikiuri % (language, term))
def f_weather(self, origin, match, args): """.weather <ICAO> - Show the weather at airport with the code <ICAO>.""" if origin.sender == '#talis': if args[0].startswith('.weather '): return icao_code = match.group(2) if not icao_code: return self.msg(origin.sender, 'Try .weather London, for example?') icao_code = code(self, icao_code) if not icao_code: self.msg(origin.sender, 'No ICAO code found, sorry') return uri = 'http://weather.noaa.gov/pub/data/observations/metar/stations/%s.TXT' try: bytes = web.get(uri % icao_code) except AttributeError: raise GrumbleError('OH CRAP NOAA HAS GONE DOWN THE WEB IS BROKEN') if 'Not Found' in bytes: self.msg(origin.sender, icao_code+': no such ICAO code, or no NOAA data') return metar = bytes.splitlines().pop() metar = metar.split(' ') if len(metar[0]) == 4: metar = metar[1:] if metar[0].endswith('Z'): time = metar[0] metar = metar[1:] else: time = None if metar[0] == 'AUTO': metar = metar[1:] if metar[0] == 'VCU': self.msg(origin.sender, icao_code + ': no data provided') return if metar[0].endswith('KT'): wind = metar[0] metar = metar[1:] else: wind = None if ('V' in metar[0]) and (metar[0] != 'CAVOK'): vari = metar[0] metar = metar[1:] else: vari = None if ((len(metar[0]) == 4) or metar[0].endswith('SM')): visibility = metar[0] metar = metar[1:] else: visibility = None while metar[0].startswith('R') and (metar[0].endswith('L') or 'L/' in metar[0]): metar = metar[1:] if len(metar[0]) == 6 and (metar[0].endswith('N') or metar[0].endswith('E') or metar[0].endswith('S') or metar[0].endswith('W')): metar = metar[1:] # 7000SE? cond = [] while (((len(metar[0]) < 5) or metar[0].startswith('+') or metar[0].startswith('-')) and (not (metar[0].startswith('VV') or metar[0].startswith('SKC') or metar[0].startswith('CLR') or metar[0].startswith('FEW') or metar[0].startswith('SCT') or metar[0].startswith('BKN') or metar[0].startswith('OVC')))): cond.append(metar[0]) metar = metar[1:] while '/P' in metar[0]: metar = metar[1:] if not metar: self.msg(origin.sender, icao_code + ': no data provided') return cover = [] while (metar[0].startswith('VV') or metar[0].startswith('SKC') or metar[0].startswith('CLR') or metar[0].startswith('FEW') or metar[0].startswith('SCT') or metar[0].startswith('BKN') or metar[0].startswith('OVC')): cover.append(metar[0]) metar = metar[1:] if not metar: self.msg(origin.sender, icao_code + ': no data provided') return if metar[0] == 'CAVOK': cover.append('CLR') metar = metar[1:] if metar[0] == 'PRFG': cover.append('CLR') # @@? metar = metar[1:] if metar[0] == 'NSC': cover.append('CLR') metar = metar[1:] if ('/' in metar[0]) or (len(metar[0]) == 5 and metar[0][2] == '.'): temp = metar[0] metar = metar[1:] else: temp = None if metar[0].startswith('QFE'): metar = metar[1:] if metar[0].startswith('Q') or metar[0].startswith('A'): pressure = metar[0] metar = metar[1:] else: pressure = None if time: hour = time[2:4] minute = time[4:6] time = local(icao_code, hour, minute) else: time = '(time unknown)' if wind: speed = int(wind[3:5]) if speed < 1: description = 'Calm' elif speed < 4: description = 'Light air' elif speed < 7: description = 'Light breeze' elif speed < 11: description = 'Gentle breeze' elif speed < 16: description = 'Moderate breeze' elif speed < 22: description = 'Fresh breeze' elif speed < 28: description = 'Strong breeze' elif speed < 34: description = 'Near gale' elif speed < 41: description = 'Gale' elif speed < 48: description = 'Strong gale' elif speed < 56: description = 'Storm' elif speed < 64: description = 'Violent storm' else: description = 'Hurricane' degrees = wind[0:3] if degrees == 'VRB': degrees = u'\u21BB'.encode('utf-8') elif (degrees <= 22.5) or (degrees > 337.5): degrees = u'\u2191'.encode('utf-8') elif (degrees > 22.5) and (degrees <= 67.5): degrees = u'\u2197'.encode('utf-8') elif (degrees > 67.5) and (degrees <= 112.5): degrees = u'\u2192'.encode('utf-8') elif (degrees > 112.5) and (degrees <= 157.5): degrees = u'\u2198'.encode('utf-8') elif (degrees > 157.5) and (degrees <= 202.5): degrees = u'\u2193'.encode('utf-8') elif (degrees > 202.5) and (degrees <= 247.5): degrees = u'\u2199'.encode('utf-8') elif (degrees > 247.5) and (degrees <= 292.5): degrees = u'\u2190'.encode('utf-8') elif (degrees > 292.5) and (degrees <= 337.5): degrees = u'\u2196'.encode('utf-8') if not icao_code.startswith('EN') and not icao_code.startswith('ED'): wind = '%s %skt (%s)' % (description, speed, degrees) elif icao_code.startswith('ED'): kmh = int(round(speed * 1.852, 0)) wind = '%s %skm/h (%skt) (%s)' % (description, kmh, speed, degrees) elif icao_code.startswith('EN'): ms = int(round(speed * 0.514444444, 0)) wind = '%s %sm/s (%skt) (%s)' % (description, ms, speed, degrees) else: wind = '(wind unknown)' if visibility: visibility = visibility + 'm' else: visibility = '(visibility unknown)' if cover: level = None for c in cover: if c.startswith('OVC') or c.startswith('VV'): if (level is None) or (level < 8): level = 8 elif c.startswith('BKN'): if (level is None) or (level < 5): level = 5 elif c.startswith('SCT'): if (level is None) or (level < 3): level = 3 elif c.startswith('FEW'): if (level is None) or (level < 1): level = 1 elif c.startswith('SKC') or c.startswith('CLR'): if level is None: level = 0 if level == 8: cover = u'Overcast \u2601'.encode('utf-8') elif level == 5: cover = 'Cloudy' elif level == 3: cover = 'Scattered' elif (level == 1) or (level == 0): cover = u'Clear \u263C'.encode('utf-8') else: cover = 'Cover Unknown' else: cover = 'Cover Unknown' if temp: if '/' in temp: temp = temp.split('/')[0] else: temp = temp.split('.')[0] if temp.startswith('M'): temp = '-' + temp[1:] try: temp = int(temp) except ValueError: temp = '?' else: temp = '?' if pressure: if pressure.startswith('Q'): pressure = pressure.lstrip('Q') if pressure != 'NIL': pressure = str(int(pressure)) + 'mb' else: pressure = '?mb' elif pressure.startswith('A'): pressure = pressure.lstrip('A') if pressure != 'NIL': inches = pressure[:2] + '.' + pressure[2:] mb = int(float(inches) * 33.7685) pressure = '%sin (%smb)' % (inches, mb) else: pressure = '?mb' if isinstance(temp, int): f = round((temp * 1.8) + 32, 2) temp = u'%s\u2109 (%s\u2103)'.encode('utf-8') % (f, temp) else: pressure = '?mb' if isinstance(temp, int): temp = u'%s\u2103'.encode('utf-8') % temp if cond: conds = cond cond = '' intensities = { '-': 'Light', '+': 'Heavy' } descriptors = { 'MI': 'Shallow', 'PR': 'Partial', 'BC': 'Patches', 'DR': 'Drifting', 'BL': 'Blowing', 'SH': 'Showers of', 'TS': 'Thundery', 'FZ': 'Freezing', 'VC': 'In the vicinity:' } phenomena = { 'DZ': 'Drizzle', 'RA': 'Rain', 'SN': 'Snow', 'SG': 'Snow Grains', 'IC': 'Ice Crystals', 'PL': 'Ice Pellets', 'GR': 'Hail', 'GS': 'Small Hail', 'UP': 'Unknown Precipitation', 'BR': 'Mist', 'FG': 'Fog', 'FU': 'Smoke', 'VA': 'Volcanic Ash', 'DU': 'Dust', 'SA': 'Sand', 'HZ': 'Haze', 'PY': 'Spray', 'PO': 'Whirls', 'SQ': 'Squalls', 'FC': 'Tornado', 'SS': 'Sandstorm', 'DS': 'Duststorm', # ? Cf. http://swhack.com/logs/2007-10-05#T07-58-56 'TS': 'Thunderstorm', 'SH': 'Showers' } for c in conds: if c.endswith('//'): if cond: cond += ', ' cond += 'Some Precipitation' elif len(c) == 5: intensity = intensities[c[0]] descriptor = descriptors[c[1:3]] phenomenon = phenomena.get(c[3:], c[3:]) if cond: cond += ', ' cond += intensity + ' ' + descriptor + ' ' + phenomenon elif len(c) == 4: descriptor = descriptors.get(c[:2], c[:2]) phenomenon = phenomena.get(c[2:], c[2:]) if cond: cond += ', ' cond += descriptor + ' ' + phenomenon elif len(c) == 3: intensity = intensities.get(c[0], c[0]) phenomenon = phenomena.get(c[1:], c[1:]) if cond: cond += ', ' cond += intensity + ' ' + phenomenon elif len(c) == 2: phenomenon = phenomena.get(c, c) if cond: cond += ', ' cond += phenomenon # if not cond: # format = u'%s at %s: %s, %s, %s, %s' # args = (icao, time, cover, temp, pressure, wind) # else: # format = u'%s at %s: %s, %s, %s, %s, %s' # args = (icao, time, cover, temp, pressure, cond, wind) if not cond: format = u'%s, %s, %s, %s - %s %s' args = (cover, temp, pressure, wind, str(icao_code), time) else: format = u'%s, %s, %s, %s, %s - %s, %s' args = (cover, temp, pressure, cond, wind, str(icao_code), time) self.msg(origin.sender, format.encode('utf-8') % args)