def cobed(line, weights): print("Cobedising. In: %s" % line) line = requests.get("http://cobed.gefjun.rfw.name/", params={"q": ircstrip(line.lower())}, headers={"X-Cobed-Auth": "kobun:nowbunbun"}).text.upper() print(" Out: %s" % line) line = re.sub(r"^\S+:\s*", "", line) weights["cobedise"] += 1 return line
def hl_match(pattern, text): if pattern.startswith("/") and pattern.endswith("/") and len(pattern) > 1: try: return re.match(pattern[1:-1], text, flags=re.IGNORECASE) except: return False else: return pattern.lower() in ircstrip(text.lower())
def passiveCorrector(self, server, line) -> "privmsg": msg = Message(line) nick = msg.address.nick if not self.dictionary.check(nick): self.dictionary.add(nick) nick = server.lower(nick) if msg.text and msg.text[0] in "@!.:`~/": return if msg.text.startswith("\x01ACTION") and msg.text.endswith("\x01"): data = self.spellcheck(msg.text[8:-1]) else: data = self.spellcheck(msg.text) user = self.users.setdefault(nick, [0, 0]) user[0] += len(data) if data else 0 user[1] += len(line.split(" ")) - 3 if user[1] > self.reset_at: user[0] /= self.reset_to user[1] /= self.reset_to if data: with sqlite3.connect(self.db) as typos: for i in data: typos.execute( "INSERT INTO typos VALUES (?, ?, ?, ?, ?)", (time.time(), nick, msg.context, self.name, i)) threshhold_context = self.getSettings(msg.context) threshhold_user = self.getSettings(nick) if threshhold_user == threshhold_context == None: return threshhold = min(threshhold_context, threshhold_user, key=lambda x: float("inf") if x is None else x) if user[1] and 1000 * user[0] / user[1] > threshhold: sentence_substitute = ircstrip(msg.text) if sentence_substitute.startswith( "\x01ACTION") and sentence_substitute.endswith( "\x01"): sentence_substitute = "%s %s" % ( msg.address.nick, sentence_substitute[8:-1]) for word, sub in data.items(): sentence_substitute = sentence_substitute.replace( word, "\x02%s\x02" % sub[0] if sub else strikethrough(word)) server.message( ("%s: " % msg.address.nick) + sentence_substitute, msg.context) if len(data) == 1: self.last = list(data.keys())[0] else: self.last = None
def log(self, data): if self.verbosity != self.QUIET: # TODO: Turn this into an event callback. if self.verbosity & (self.FULL_MESSAGE | self.TYPE_ONLY): if self.verbosity & self.TYPE_ONLY: output = data.split()[0] else: output = ircstrip(data) sys.stdout.write("%s ← %s" % (self.servername, output)) if self.work.qsize() and self.verbosity & self.QUEUE_STATE: sys.stdout.write(" ⬩ %d messages queued." % self.work.qsize()) print()
def spellcheck(self, sentence): sentence = ircstrip(sentence) if self.isLiteral(sentence): return words = set(sentence.split()) sentence = [self.stripContractions(i) for i in words if self.isWord(i)] errors = [i for i in sentence if i and not (self.dictionary.check(i) or self.alternate.check(i))] suggestions = [set(self.alternate.suggest(i)) | set(self.dictionary.suggest(i)) for i in errors] # reduce the suggestions suggestions = [{"".join(z for z in i if z.isalpha() or z in "'").lower() for i in x} for x in suggestions] wrong = [] append = {} for i, word in enumerate(errors): suffixless = {word.rstrip(suffix) for suffix in self.suffixes} - {word} if all(self.spellcheck(i) for i in suffixless): continue elif "".join(i for i in word if i.isalpha()).lower() not in suggestions[i]: token = set(word) & set(self.wordsep) if token: token = token.pop() words = word.split(token) suggested = [self.spellcheck(i) for i in words] suggested = [list(i.values())[0] if i else None for i in suggested] if all(suggested): wrong.append(word) elif any(suggested): if suggested[0]: suggested = suggested[0] suggested = [i + token + words[1] for i in suggested] else: suggested = suggested[1] suggested = [words[0] + token + i for i in suggested] append[word] = suggested else: # Repetition for emphasis is allowed over a threshhold string = re.escape(word) pattern = re.sub(r"(.+?)\1\1+", r"(\1)+", string, flags=re.IGNORECASE) truncated = re.sub(r"(.+?)\1\1+", r"\1\1", word, flags=re.IGNORECASE) truncated2 = re.sub(r"(.+?)\1\1+", r"\1", word, flags=re.IGNORECASE) suggestions[i] |= set(self.alternate.suggest(truncated) + self.dictionary.suggest(truncated) + self.alternate.suggest(truncated2) + self.dictionary.suggest(truncated2)) if not any(re.match(pattern, x) for x in suggestions[i]): wrong.append(word) if wrong or append: wrong = {i: self.alternate.suggest(i) for i in wrong} wrong.update(append) # wrong = {k: [i for i in v if difflib.SequenceMatcher(None, k, i).quick_ratio() > 0.6] for k, v in wrong.items()} return wrong # Give a dictionary of words : [suggestions]
def passiveCorrector(self, server, line) -> "privmsg": msg = Message(line) nick = msg.address.nick if not self.dictionary.check(nick): self.dictionary.add(nick) nick = server.lower(nick) if msg.text and msg.text[0] in "@!.:`~/": return if msg.text.startswith("\x01ACTION") and msg.text.endswith("\x01"): data = self.spellcheck(msg.text[8:-1]) else: data = self.spellcheck(msg.text) user = self.users.setdefault(nick, [0, 0]) user[0] += len(data) if data else 0 user[1] += len(line.split(" ")) - 3 if user[1] > self.reset_at: user[0] /= self.reset_to user[1] /= self.reset_to if data: with sqlite3.connect(self.db) as typos: for i in data: typos.execute("INSERT INTO typos VALUES (?, ?, ?, ?, ?)", (time.time(), nick, msg.context, self.name, i)) threshhold_context = self.getSettings(msg.context) threshhold_user = self.getSettings(nick) if threshhold_user == threshhold_context == None: return threshhold = min(threshhold_context, threshhold_user, key=lambda x: float("inf") if x is None else x) if user[1] and 1000*user[0]/user[1] > threshhold: sentence_substitute = ircstrip(msg.text) if sentence_substitute.startswith("\x01ACTION") and sentence_substitute.endswith("\x01"): sentence_substitute = "%s %s" % (msg.address.nick, sentence_substitute[8:-1]) for word, sub in data.items(): sentence_substitute = sentence_substitute.replace(word, "\x02%s\x02" % sub[0] if sub else strikethrough(word)) server.message(("%s: " % msg.address.nick) + sentence_substitute, msg.context) if len(data) == 1: self.last = list(data.keys())[0] else: self.last = None
def linesize(font, text): return font.getsize(ircstrip(text))
def strip(x): return "".join(i for i in ircstrip(x.strip()) if not unicodedata.category(i).startswith("C"))
def spellcheck(self, sentence): sentence = ircstrip(sentence) if self.isLiteral(sentence): return words = set(sentence.split()) sentence = [ self.stripContractions(i) for i in words if self.isWord(i) ] errors = [ i for i in sentence if i and not (self.dictionary.check(i) or self.alternate.check(i)) ] suggestions = [ set(self.alternate.suggest(i)) | set(self.dictionary.suggest(i)) for i in errors ] # reduce the suggestions suggestions = [{ "".join(z for z in i if z.isalpha() or z in "'").lower() for i in x } for x in suggestions] wrong = [] append = {} for i, word in enumerate(errors): suffixless = {word.rstrip(suffix) for suffix in self.suffixes} - {word} if all(self.spellcheck(i) for i in suffixless): continue elif "".join(i for i in word if i.isalpha()).lower() not in suggestions[i]: token = set(word) & set(self.wordsep) if token: token = token.pop() words = word.split(token) suggested = [self.spellcheck(i) for i in words] suggested = [ list(i.values())[0] if i else None for i in suggested ] if all(suggested): wrong.append(word) elif any(suggested): if suggested[0]: suggested = suggested[0] suggested = [ i + token + words[1] for i in suggested ] else: suggested = suggested[1] suggested = [ words[0] + token + i for i in suggested ] append[word] = suggested else: # Repetition for emphasis is allowed over a threshhold string = re.escape(word) pattern = re.sub(r"(.+?)\1\1+", r"(\1)+", string, flags=re.IGNORECASE) truncated = re.sub(r"(.+?)\1\1+", r"\1\1", word, flags=re.IGNORECASE) truncated2 = re.sub(r"(.+?)\1\1+", r"\1", word, flags=re.IGNORECASE) suggestions[i] |= set( self.alternate.suggest(truncated) + self.dictionary.suggest(truncated) + self.alternate.suggest(truncated2) + self.dictionary.suggest(truncated2)) if not any( re.match(pattern, x) for x in suggestions[i]): wrong.append(word) if wrong or append: wrong = {i: self.alternate.suggest(i) for i in wrong} wrong.update(append) # wrong = {k: [i for i in v if difflib.SequenceMatcher(None, k, i).quick_ratio() > 0.6] for k, v in wrong.items()} return wrong # Give a dictionary of words : [suggestions]
def update_watchers(self, server, msg): ctx = server.lower(msg.context) # update user = server.lower(msg.address.nick) self.active.setdefault(ctx, {})[user] = time.time() highlighted = [] if ctx not in self.config["accounts"]: return acc = self.config["accounts"][ctx] if ctx in self.watchers: watchers = self.watchers[ctx] push = {"type": "note"} if msg.text.startswith("\x01ACTION ") and msg.text.endswith("\x01"): push["body"] = "* %s %s" % (msg.address.nick, ircstrip(msg.text[8:-1])) else: push["body"], push["title"] = ircstrip(msg.text), msg.address.nick for email in watchers: if any(email == target and hl_match(word, msg.text) for word, target, _ in self.usersettings.get(ctx, [])): hlpush = {"type": "note", "email": email, "body": push["body"]} if "title" in push: hlpush["title"] = "🔔 " + push["title"] else: hlpush["title"] = "🔔 Highlight from " + msg.address.nick with self.pushlock: self.skip.add(self.push(hlpush, acc["token"])) highlighted.append(email) else: push["email"] = email with self.pushlock: self.skip.add(self.push(push, acc["token"])) for word, email, when in self.usersettings.get(ctx, []): nick = server.lower(self.config["users"][email]) # Parse when inactive_match = re.match(r"(\S+(?:,\s*\S+)* )?inactive( \d+)?", when) offline_match = re.match(r"(\S+(?:,\s*\S+)* )?offline", when) if inactive_match: who, timeout = inactive_match.groups() if who is None: who = [nick] else: who = re.split(r",\s*", who.strip()) if timeout is None: timeout = "15" timeout = 60 * int(timeout.strip()) when = "inactive" elif offline_match: who, = offline_match.groups() if who is None: who = [nick] else: who = re.split(r",\s*", who) when = "offline" if email not in highlighted and hl_match(word, msg.text): if (when == "always" or (when == "offline" and server.isIn(ctx, server.channels) and not any(server.isIn(i, server.channels[ctx]) for i in who)) or (when =="inactive" and all(not server.isIn(i, self.active[ctx]) or time.time() - self.active[ctx][self.lower(i)] >= timeout for i in who))): push = {"type": "note", "title": "🔔 Highlight from %s" % msg.address.nick, "body": ircstrip(msg.text), "email":email} if msg.text.startswith("\x01ACTION ") and msg.text.endswith("\x01"): push["body"] = "* %s %s" % (msg.address.nick, ircstrip(msg.text[8:-1])) with self.pushlock: self.skip.add(self.push(push, acc["token"])) highlighted.append(email)