def go(msg, what): if not len(msg.args): raise IMException("de quel mot veux-tu connaître la liste des synonymes ?") lang = msg.kwargs["lang"] if "lang" in msg.kwargs else "fr" word = ' '.join(msg.args) try: best, synos, anton = lang_binding[lang](word) except: best, synos, anton = (list(), list(), list()) if what == "synonymes": if len(synos) > 0 or len(best) > 0: res = Response(channel=msg.channel, title="Synonymes de %s" % word) if len(best) > 0: res.append_message(best) if len(synos) > 0: res.append_message(synos) return res else: raise IMException("Aucun synonyme de %s n'a été trouvé" % word) elif what == "antonymes": if len(anton) > 0: res = Response(anton, channel=msg.channel, title="Antonymes de %s" % word) return res else: raise IMException("Aucun antonyme de %s n'a été trouvé" % word) else: raise IMException("WHAT?!")
def cmd_watch(msg): # Get current state node = None for n in context.data.getChilds(): if n["server"] == msg.server and n["channel"] == msg.channel: node = n break if len(msg.args): if msg.args[0] == "stop" and node is not None: context.data.delChild(node) context.save() raise IMException( "This channel will not anymore receives world cup events.") elif msg.args[0] == "start" and node is None: start_watch(msg) else: raise IMException("Use only start or stop as first argument") else: if node is None: start_watch(msg) else: context.data.delChild(node) context.save() raise IMException( "This channel will not anymore receives world cup events.")
def ask_ratp(msg): l = len(msg.args) transport = msg.args[0] if l > 0 else None line = msg.args[1] if l > 1 else None station = msg.args[2] if l > 2 else None direction = msg.args[3] if l > 3 else None if station is not None: times = sorted(ratp.getNextStopsAtStation(transport, line, station, direction), key=lambda i: i[0]) if len(times) == 0: raise IMException("la station %s n'existe pas sur le %s ligne %s." % (station, transport, line)) (time, direction, stationname) = times[0] return Response(message=["\x03\x02%s\x03\x02 direction %s" % (time, direction) for time, direction, stationname in times], title="Prochains passages du %s ligne %s à l'arrêt %s" % (transport, line, stationname), channel=msg.channel) elif line is not None: stations = ratp.getAllStations(transport, line) if len(stations) == 0: raise IMException("aucune station trouvée.") return Response(stations, title="Stations", channel=msg.channel) elif transport is not None: lines = ratp.getTransportLines(transport) if len(lines) == 0: raise IMException("aucune ligne trouvée.") return Response(lines, title="Lignes", channel=msg.channel) else: raise IMException("précise au moins un moyen de transport.")
def _nextURLContent(res): size = int(res.getheader("Content-Length", 524288)) cntype = res.getheader("Content-Type") if max_size >= 0 and (size > max_size or (cntype is not None and cntype[:4] != "text" and cntype[:4] != "appl")): raise IMException("Content too large to be retrieved") data = res.read(size) # Decode content charset = "utf-8" if cntype is not None: lcharset = res.getheader("Content-Type").split(";") if len(lcharset) > 1: for c in lcharset: ch = c.split("=") if ch[0].strip().lower() == "charset" and len(ch) > 1: cha = ch[1].split(".") if len(cha) > 1: charset = cha[1] else: charset = cha[0] import http.client if res.status == http.client.OK or res.status == http.client.SEE_OTHER: return data.decode(charset).strip() elif decode_error: return data.decode(charset).strip() else: raise IMException("A HTTP error occurs: %d - %s" % (res.status, http.client.responses[res.status]))
def cmd_alias(msg): if not len(msg.args): raise IMException("!alias takes as argument an alias to extend.") alias = context.subparse(msg, msg.args[0]) if alias is None or not isinstance(alias, Command): raise IMException("%s is not a valid alias" % msg.args[0]) if alias.cmd in context.data.getNode("aliases").index: return Response( "%s corresponds to %s" % (alias.cmd, context.data.getNode("aliases").index[alias.cmd]["origin"]), channel=msg.channel, nick=msg.frm) elif len(msg.args) > 1: create_alias(alias.cmd, " ".join(msg.args[1:]), channel=msg.channel, creator=msg.frm) return Response("New alias %s successfully registered." % alias.cmd, channel=msg.channel) else: wym = [ m for m in guess(alias.cmd, context.data.getNode("aliases").index) ] raise IMException(msg.args[0] + " is not an alias." + (" Would you mean: %s?" % ", ".join(wym) if len(wym) else ""))
def get_tracking_info(msg): if not len(msg.args): raise IMException("Renseignez un identifiant d'envoi.") res = Response(channel=msg.channel, count=" (%d suivis supplémentaires)") if 'tracker' in msg.kwargs: if msg.kwargs['tracker'] in TRACKING_HANDLERS: trackers = { msg.kwargs['tracker']: TRACKING_HANDLERS[msg.kwargs['tracker']] } else: raise IMException("No tracker named \x02{tracker}\x0F, please use" " one of the following: \x02{trackers}\x0F" .format(tracker=msg.kwargs['tracker'], trackers=', ' .join(TRACKING_HANDLERS.keys()))) else: trackers = TRACKING_HANDLERS for tracknum in msg.args: for name, tracker in trackers.items(): ret = tracker(tracknum) if ret: res.append_message(ret) break if not ret: res.append_message("L'identifiant \x02{id}\x0F semble incorrect," " merci de vérifier son exactitude." .format(id=tracknum)) return res
def headers(url): """Retrieve HTTP header for the given URL Argument: url -- the page URL to get header """ o = urllib.parse.urlparse(web.getNormalizedURL(url), "http") if o.netloc == "": raise IMException("invalid URL") if o.scheme == "http": conn = http.client.HTTPConnection(o.hostname, port=o.port, timeout=5) else: conn = http.client.HTTPSConnection(o.hostname, port=o.port, timeout=5) try: conn.request("HEAD", o.path, None, {"User-agent": "Nemubot v%s" % __version__}) except ConnectionError as e: raise IMException(e.strerror) except socket.timeout: raise IMException("request timeout") except socket.gaierror: print("<tools.web> Unable to receive page %s from %s on %d." % (o.path, o.hostname, o.port if o.port is not None else 0)) raise IMException("an unexpected error occurs") try: res = conn.getresponse() except http.client.BadStatusLine: raise IMException("An error occurs") finally: conn.close() return (res.version, res.status, res.reason, res.getheaders())
def cmd_github_user(msg): if not len(msg.args): raise IMException("indicate a user name to search") res = Response(channel=msg.channel, nomore="No more user") user = info_user(" ".join(msg.args)) if "login" in user: if user["repos"]: kf = (" Known for: " + ", ".join([repo["name"] for repo in user["repos"]])) else: kf = "" if "name" in user: name = user["name"] else: name = user["login"] res.append_message("User %s: %d public repositories; %d public gists; %d followers; %d following; view it at %s.%s" % (name, user["public_repos"], user["public_gists"], user["followers"], user["following"], user["html_url"], kf)) else: raise IMException("User not found") return res
def cmd_reduceurl(msg): minify = list() if not len(msg.args): global LAST_URLS if msg.channel in LAST_URLS and len(LAST_URLS[msg.channel]) > 0: minify.append(LAST_URLS[msg.channel].pop()) else: raise IMException("I have no more URL to reduce.") if len(msg.args) > 4: raise IMException("I cannot reduce that many URLs at once.") else: minify += msg.args if 'provider' in msg.kwargs and msg.kwargs['provider'] in PROVIDERS: provider = msg.kwargs['provider'] else: provider = DEFAULT_PROVIDER res = list() for url in minify: o = urlparse(web.getNormalizedURL(url), "http") minief_url = reduce(url, provider) if o.netloc == "": res.append(gen_response(minief_url, msg, o.scheme)) else: res.append(gen_response(minief_url, msg, o.netloc)) return res
def cmd_smscmd(msg): if not len(msg.args): raise IMException("À qui veux-tu envoyer ce SMS ?") cur_epoch = time.mktime(time.localtime()) dests = msg.args[0].split(",") frm = msg.frm if msg.to_response[ 0] == msg.frm else msg.frm + "@" + msg.to[0] cmd = " ".join(msg.args[1:]) content = None for r in context.subtreat(context.subparse(msg, cmd)): if isinstance(r, Response): for m in r.messages: if isinstance(m, list): for n in m: content = n break if content is not None: break elif isinstance(m, str): content = m break elif isinstance(r, Text): content = r.message if content is None: raise IMException( "Aucun SMS envoyé : le résultat de la commande n'a pas retourné de contenu." ) check_sms_dests(dests, cur_epoch) return send_sms_to_list(msg, frm, dests, content, cur_epoch)
def cmd_github_commit(msg): if not len(msg.args): raise IMException("indicate a repository to view its commits") commit = None if re.match("^[a-fA-F0-9]+$", msg.args[0]): commit = msg.args[0] del msg.args[0] elif re.match("^[a-fA-F0-9]+$", msg.args[-1]): commit = msg.args[-1] del msg.args[-1] repo = " ".join(msg.args) count = " (%d more commits)" if commit is None else None res = Response(channel=msg.channel, nomore="No more commit", count=count) commits = info_commit(repo, commit) if commits is None: raise IMException("Repository or commit not found") for commit in commits: res.append_message("Commit %s by %s on %s: %s" % (commit["sha"][:10], commit["commit"]["author"]["name"], commit["commit"]["author"]["date"], commit["commit"]["message"].replace("\n", " "))) return res
def cmd_spell(msg): if not len(msg.args): raise IMException( "indique une orthographe approximative du mot dont tu veux vérifier l'orthographe." ) lang = msg.kwargs["lang"] if "lang" in msg.kwargs else "fr" res = Response(channel=msg.channel) for word in msg.args: try: r = check_spell(word, lang) except AspellError: raise IMException("Je n'ai pas le dictionnaire `%s' :(" % lang) if r == True: add_score(msg.frm, "correct") res.append_message("l'orthographe de `%s' est correcte" % word) elif len(r) > 0: add_score(msg.frm, "bad") res.append_message(r, title="suggestions pour `%s'" % word) else: add_score(msg.frm, "bad") res.append_message("aucune suggestion pour `%s'" % word) return res
def cmd_github_issue(msg): if not len(msg.args): raise IMException("indicate a repository to view its issues") issue = None li = re.match("^#?([0-9]+)$", msg.args[0]) ri = re.match("^#?([0-9]+)$", msg.args[-1]) if li is not None: issue = li.group(1) del msg.args[0] elif ri is not None: issue = ri.group(1) del msg.args[-1] repo = " ".join(msg.args) count = " (%d more issues)" if issue is None else None res = Response(channel=msg.channel, nomore="No more issue", count=count) issues = info_issue(repo, issue) if issues is None: raise IMException("Repository not found") for issue in issues: res.append_message("%s%s issue #%d: \x03\x02%s\x03\x02 opened by %s on %s: %s" % (issue["state"][0].upper(), issue["state"][1:], issue["number"], issue["title"], issue["user"]["login"], issue["created_at"], issue["body"].replace("\n", " "))) return res
def cmd_overview(msg): if "host" not in msg.kwargs: raise IMException("please give a hostname in keywords") if not len(msg.args): raise IMException("which group would you overview?") for g in msg.args: arts = [] for grp in read_group(g, **msg.kwargs): grp["X-FromName"], grp["X-FromEmail"] = parseaddr( grp["from"] if "from" in grp else "") if grp["X-FromName"] == '': grp["X-FromName"] = grp["X-FromEmail"] arts.append( "On {date}, from \x03{0:02d}{X-FromName}\x0F \x02{subject}\x0F: \x0314{message-id}\x0F" .format( adler32(grp["X-FromEmail"].encode()) & 0xf, **{h: decode_header(i) for h, i in grp.items()})) if len(arts): yield Response(arts, channel=msg.channel, title="In \x03{0:02d}{1}\x0F".format( adler32(g[0].encode()) & 0xf, g))
def validator(url): """Run the w3c validator on the given URL Argument: url -- the URL to validate """ o = urllib.parse.urlparse(getNormalizedURL(url), "http") if o.netloc == "": raise IMException("Indicate a valid URL!") try: req = urllib.request.Request( "https://validator.w3.org/check?uri=%s&output=json" % (urllib.parse.quote(o.geturl())), headers={'User-Agent': "Nemubot v%s" % __version__}) raw = urllib.request.urlopen(req, timeout=10) except urllib.error.HTTPError as e: raise IMException("HTTP error occurs: %s %s" % (e.code, e.reason)) headers = dict() for Hname, Hval in raw.getheaders(): headers[Hname] = Hval if "X-W3C-Validator-Status" not in headers or ( headers["X-W3C-Validator-Status"] != "Valid" and headers["X-W3C-Validator-Status"] != "Invalid"): raise IMException("Unexpected error on W3C servers" + (" (" + headers["X-W3C-Validator-Status"] + ")" if "X-W3C-Validator-Status" in headers else "")) return headers, json.loads(raw.read().decode())
def _get_ytdl(links): cmd = 'youtube-dl -j --'.split() cmd.extend(links) res = [] with subprocess.Popen(cmd, stdout=subprocess.PIPE) as p: if p.wait() > 0: raise IMException("Error while retrieving video information.") for line in p.stdout.read().split(b"\n"): localres = '' if not line: continue info = json.loads(line.decode('utf-8')) if info.get('fulltitle'): localres += info['fulltitle'] elif info.get('title'): localres += info['title'] else: continue if info.get('duration'): d = info['duration'] localres += ' [{0}:{1:06.3f}]'.format(int(d/60), d%60) if info.get('age_limit'): localres += ' [-{}]'.format(info['age_limit']) if info.get('uploader'): localres += ' by {}'.format(info['uploader']) if info.get('upload_date'): localres += ' on {}'.format(info['upload_date']) if info.get('description'): localres += ': ' + info['description'] if info.get('webpage_url'): localres += ' | ' + info['webpage_url'] res.append(localres) if not res: raise IMException("No video information to retrieve about this. Sorry!") return res
def cmd_imdb(msg): if not len(msg.args): raise IMException("precise a movie/serie title!") title = ' '.join(msg.args) if re.match("^tt[0-9]{7}$", title) is not None: data = get_movie_by_id(imdbid=title) else: rm = re.match(r"^(.+)\s\(([0-9]{4})\)$", title) if rm is not None: data = find_movies(rm.group(1), year=rm.group(2)) else: data = find_movies(title) if not data: raise IMException("Movie/series not found") data = get_movie_by_id(data[0]["id"]) res = Response( channel=msg.channel, title="%s (%s)" % (data['Title'], data['Year']), nomore="No more information, more at http://www.imdb.com/title/%s" % data['imdbID']) res.append_message( "%s \x02genre:\x0F %s; \x02rating\x0F: %s (%s votes); \x02plot\x0F: %s" % (data['Type'], data['Genre'], data['imdbRating'], data['imdbVotes'], data['Plot'])) res.append_message("%s \x02from\x0F %s; %s" % (data['Type'], data['Country'], data['Credits'])) return res
def define(msg): if not len(msg.args): raise IMException("Indicate a term to define") s = do_search(msg.args) if not s.definition: raise IMException("no definition found for '%s'." % " ".join(msg.args)) return Response(s.definition, channel=msg.channel)
def cmd_title(msg): if not len(msg.args): raise IMException("Indicate the URL to visit.") url = " ".join(msg.args) res = re.search("<title>(.*?)</title>", page.fetch(" ".join(msg.args)), re.DOTALL) if res is None: raise IMException("The page %s has no title" % url) else: return Response("%s: %s" % (url, res.group(1).replace("\n", " ")), channel=msg.channel)
def lstu_reducer(url, data): json_data = json.loads( web.getURLContent( url, "lsturl=" + quote(data), header={"Content-Type": "application/x-www-form-urlencoded"})) if 'short' in json_data: return json_data['short'] elif 'msg' in json_data: raise IMException("Error: %s" % json_data['msg']) else: IMException("An error occured while shortening %s." % data)
def check_sms_dests(dests, cur_epoch): """Raise exception if one of the dest is not known or has already receive a SMS recently """ for u in dests: if u not in context.data.index: raise IMException( "Désolé, je sais pas comment envoyer de SMS à %s." % u) elif cur_epoch - float(context.data.index[u]["lastuse"]) < 42: raise IMException( "Un peu de calme, %s a déjà reçu un SMS il n'y a pas si longtemps." % u) return True
def cmd_coordinates(msg): if len(msg.args) < 1: raise IMException("indique-moi un nom de ville.") j = msg.args[0].lower() if j not in context.data.index: raise IMException("%s n'est pas une ville connue" % msg.args[0]) coords = context.data.index[j] return Response("Les coordonnées de %s sont %s,%s" % (msg.args[0], coords["lat"], coords["long"]), channel=msg.channel)
def cmd_subreddit(msg): global LAST_SUBS if not len(msg.args): if msg.channel in LAST_SUBS and len(LAST_SUBS[msg.channel]) > 0: subs = [LAST_SUBS[msg.channel].pop()] else: raise IMException("Which subreddit? Need inspiration? " "type !horny or !bored") else: subs = msg.args all_res = list() for osub in subs: sub = re.match(r"^/?(?:(\w)/)?(\w+)/?$", osub) if sub is not None: if sub.group(1) is not None and sub.group(1) != "": where = sub.group(1) else: where = "r" sbr = web.getJSON("https://www.reddit.com/%s/%s/about.json" % (where, sub.group(2))) if sbr is None: raise IMException("subreddit not found") if "title" in sbr["data"]: res = Response(channel=msg.channel, nomore="No more information") res.append_message( ("[NSFW] " if sbr["data"]["over18"] else "") + sbr["data"]["url"] + " " + sbr["data"]["title"] + ": " + sbr["data"] ["public_description" if sbr["data"]["public_description"] != "" else "description"].replace("\n", " ") + " %s subscriber(s)" % sbr["data"]["subscribers"]) if sbr["data"]["public_description"] != "": res.append_message(sbr["data"]["description"].replace( "\n", " ")) all_res.append(res) else: all_res.append( Response("/%s/%s doesn't exist" % (where, sub.group(2)), channel=msg.channel)) else: all_res.append( Response("%s is not a valid subreddit" % osub, channel=msg.channel, nick=msg.frm)) return all_res
def ask_stations(msg): if len(msg.args) > 4: raise IMException("demande-moi moins de stations à la fois.") elif not len(msg.args): raise IMException("pour quelle station ?") for station in msg.args: if re.match("^[0-9]{4,5}$", station): return print_station_status(msg, station) elif station in context.data.index: return print_station_status(msg, context.data.index[station]["number"]) else: raise IMException("numéro de station invalide.")
def cmd_github(msg): if not len(msg.args): raise IMException("indicate a repository name to search") repos = info_repos(" ".join(msg.args)) res = Response(channel=msg.channel, nomore="No more repository", count=" (%d more repo)") for repo in repos["items"]: homepage = "" if repo["homepage"] is not None: homepage = repo["homepage"] + " - " res.append_message("Repository %s: %s%s Main language: %s; %d forks; %d stars; %d watchers; %d opened_issues; view it at %s" % (repo["full_name"], homepage, repo["description"], repo["language"], repo["forks"], repo["stargazers_count"], repo["watchers_count"], repo["open_issues_count"], repo["html_url"])) return res
def cmd_conjug(msg): if len(msg.args) < 2: raise IMException("donne moi un temps et un verbe, et je te donnerai " "sa conjugaison!") tens = ' '.join(msg.args[:-1]) verb = msg.args[-1] conjug = get_conjug(verb, tens) if len(conjug) > 0: return Response(conjug, channel=msg.channel, title="Conjugaison de %s" % verb) else: raise IMException("aucune conjugaison de '%s' n'a été trouvé" % verb)
def add_site(url, nick, channel, server, diffType="diff"): """Add a site to watching list Argument: url -- URL to watch """ o = urlparse(getNormalizedURL(url), "http") if o.netloc == "": raise IMException("sorry, I can't watch this URL :(") alert = ModuleState("alert") alert["nick"] = nick alert["server"] = server alert["channel"] = channel alert["message"] = "{url} just changed!" if url not in DATAS.index: watch = ModuleState("watch") watch["type"] = diffType watch["url"] = url watch["time"] = 123 DATAS.addChild(watch) watch.addChild(alert) start_watching(watch) else: DATAS.index[url].addChild(alert) save() return Response(channel=channel, nick=nick, message="this site is now under my supervision.")
def gen_response(res, msg, srv): if res is None: raise IMException("bad URL : %s" % srv) else: return Text("URL for %s: %s" % (srv, res), server=None, to=msg.to_response)
def cmd_w3m(msg): if not len(msg.args): raise IMException("Indicate the URL to visit.") res = Response(channel=msg.channel) for line in page.render(" ".join(msg.args)).split("\n"): res.append_message(line) return res
def available(dom): js = getJSON(URL_AVAIL % urllib.parse.quote(dom)) if "ErrorMessage" in js: raise IMException(js["ErrorMessage"]["msg"]) return js["DomainInfo"]["domainAvailability"] == "AVAILABLE"