diff --git a/modules/adminchannel.py b/modules/adminchannel.py index c7c3980..537d636 100755 --- a/modules/adminchannel.py +++ b/modules/adminchannel.py @@ -129,9 +129,9 @@ def kickban(bot, trigger): @require_chanmsg @require_privilege(OP, 'You are not a channel operator.') -@commands('topic') -@example(".topic We're discussing penises, would you like to join?") -def topic(bot, trigger): +@commands('oldtopic') +@example(".oldtopic We're discussing penises, would you like to join?") +def oldtopic(bot, trigger): """ This gives ops the ability to change the topic. The bot must be a Channel Operator for this command to work. diff --git a/modules/resistor.py b/modules/resistor.py index 7a9fd72..07a9273 100755 --- a/modules/resistor.py +++ b/modules/resistor.py @@ -1,46 +1,166 @@ -#! /usr/bin/env python3 -# coding=utf-8 +#!/usr/bin/env python3 """ Resistor color band codes. """ +import re +import argparse + import module -@module.commands('resist') -@module.example('.resist 10k', 'brown black orange gold') +suffix = {"k": 1000, "m": 10000000} + +sigfig = {"black": 0, + "brown": 1, + "red": 2, + "orange": 3, + "yellow": 4, + "green": 5, + "blue": 6, + "violet": 7, + "grey": 8, + "white": 9} +sigfig_inverse = {val: key for key, val in sigfig.items()} + +multiplier = {"black": 1, + "brown": 10, + "red": 100, + "orange": 1000, + "yellow": 10000, + "green": 100000, + "blue": 1000000, + "violet": 10000000, + "grey": 100000000, + "white": 1000000000, + "gold": 0.1, + "silver": 0.01} +multiplier_inverse = {val: key for key, val in multiplier.items()} + +tolerance = {"brown": "±1%", + "red": "±2%", + "green": "±0.5%", + "blue": "±0.25%", + "violet": "±0.1%", + "grey": "±0.05%", + "gold": "±5%", + "silver": "±10%", + "none": "±20%"} + +temp_coeff = {"black": "250 ppm", + "brown": "100 ppm", + "red": "50 ppm", + "orange": "15 ppm", + "yellow": "25 ppm", + "blue": "10 ppm", + "violet": "5 ppm"} + + +@module.commands("resist") +@module.example(".resist 10k", "brown black orange gold") def resist(bot, trigger): - """Displays the color band code of a resistor for the given resistance.""" - suffix = {'k': 1000, 'm': 10000000} - digit = {'0': 'black', '1': 'brown', '2': 'red', '3': 'orange', '4': 'yellow', - '5': 'green', '6': 'blue', '7': 'violet', '8': 'grey', '9': 'white', - '-1': 'gold', '-2': 'silver'} + """ + Displays the color band code of a resistor for the given resistance. + """ + if not trigger.group(2): + return bot.say("Please specify a value") + parser = argparse.ArgumentParser() + parser.add_argument("value", nargs="+") + parser.add_argument("-r", "--reverse", action="store_true") + parser.add_argument("-n", "--num_bands", type=int, choices=[3,4,5,6], default=4) + args = parser.parse_args(trigger.group(2).split()) - if not trigger.group(2)[-1].isdigit(): - value = trigger.group(2)[:-1] + if args.reverse: # bands-to-value + bot.say(bands_to_value(" ".join(args.value))) + else: # value-to-band + if len(args.value) > 1: + return bot.say("Too many values.") + + value = args.value[0].lower() + mul = 1 + if value[-1] in ["k", "m"]: + mul = suffix[value[-1]] + value = value[:-1] + try: + value = float(value) * mul + except ValueError: + return bot.say("Invalid input.") + return bot.say(value_to_band(value, args.num_bands)) + + +def value_to_band(value, num_bands=4): + """ + Converts a given resistance value to a color band code. + """ + if value < 1: + return "Value too small. Maybe this will be fixed in the future." else: - value = trigger.group(2) + if num_bands > 4: + value = float(format(value, ".3g")) + else: + value = float(format(value, ".2g")) + value = re.sub("\.0$", "", str(value)) + bands = [] + mul = "" - try: - value = float(value) - except ValueError: - return 'Invalid input' + if "." in value: + if value[-2] == ".": + mul = 0.1 + elif value[-3] == ".": + mul = 0.01 + else: + return "Error with sigfigs." + value = value.replace(".", "") - if not trigger.group(2)[-1].isdigit(): - value = value * suffix[trigger.group(2)[-1]] - valueStr = str(value) + val1 = int(value[0]) + val2 = int(value[1]) + bands.append(sigfig_inverse[val1]) + bands.append(sigfig_inverse[val2]) - if value >= 10: - colorCode = digit[valueStr[0]] + " " + digit[valueStr[1]] + " " + if num_bands > 4: + value = value.ljust(4,"0") + val3 = int(value[2]) + bands.append(sigfig_inverse[val3]) + + if not mul: + mul = 10**(len(value) - len(value.rstrip("0"))) + bands.append(multiplier_inverse[mul]) + + # TODO: better tolerance + bands.append("gold") + + if num_bands == 3: + return " ".join(bands) + + # TODO: better temp coeff + if num_bands == 6: + bands.append("red") + + return " ".join(bands) + + +def bands_to_value(bands): + """ + Converts the given color band code into a resistance value. + """ + bands = bands.lower().split() + ret = [] + + if len(bands) > 4: + value = bands[:3] + bands = bands[3:] else: - colorCode = digit[valueStr[2]] + " " + digit['0'] + " " + value = bands[:2] + bands = bands[2:] + value = [sigfig[v] for v in value] - if value < 0.1: - return "Value to small. Just like your dick." - elif value < 1: - colorCode = colorCode + digit['-2'] - elif value < 10: - colorCode = colorCode + digit['-1'] - else: - colorCode = colorCode + digit[str(len(valueStr)-4)] + prod = "" + for x in value: + prod += str(x) + prod = float(prod) * multiplier[bands[0]] + + if len(bands) == 1: + return " ".join([str(prod), tolerance["none"]]) + if len(bands) == 2: + return " ".join([str(prod), tolerance[bands[1]]]) + if len(bands) == 3: + return " ".join([str(prod), tolerance[bands[1]], temp_coeff[bands[2]]]) - colorCode = colorCode + " gold" - bot.say(colorCode) \ No newline at end of file diff --git a/modules/topic.py b/modules/topic.py new file mode 100755 index 0000000..5e873f2 --- /dev/null +++ b/modules/topic.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python3 +""" +This module allows you to add topics to a list in the database and cycle +through them. +""" +import os +import threading +import random + +from module import commands, example + +def setup(bot): + """ + Attempts to create the table in the database if it's not found. + """ + bot.memory['topic_lock'] = threading.Lock() + con = bot.db.connect() + cur = con.cursor() + try: + cur.execute("SELECT * FROM topic").fetchone() + except: + cur.execute("CREATE TABLE topic(" + "topic STRING PRIMARY KEY," + "added_by STRING," + "added_date INT DEFAULT (STRFTIME('%s', 'now')))") + con.commit() + con.close() + + +@commands('topic') +def topic(bot, trigger): + """ + Picks a random topic from the database and applies it. + """ + channel = trigger.sender + con = bot.db.connect() + cur = con.cursor() + cur.execute("SELECT topic FROM topic ORDER BY RANDOM() LIMIT 1;") + topic = cur.fetchone()[0] + con.close() + + bot.write(('TOPIC', channel + ' :' + topic)) + + +@commands('addtopic') +@example('.addtopic Daily reminder to kill all cia niggers on site.') +def addTopic(bot, trigger): + """ + Adds the specified topic to the topic database. + """ + bot.memory['topic_lock'].acquire() + topic = trigger.group(2) + con = bot.db.connect() + cur = con.cursor() + insert = (topic, trigger.nick) + try: + cur.execute("INSERT INTO topic (topic, added_by) VALUES(?,?)", + insert) + confirm = "Added topic: " + topic + except sqlite3.IntegrityError: + confirm = "Error: " + topic + " is already in the database." + con.commit() + con.close() + bot.memory['topic_lock'].release() + bot.say(confirm) diff --git a/modules/watcher.py b/modules/watcher.py index 315c2ca..864b1c3 100755 --- a/modules/watcher.py +++ b/modules/watcher.py @@ -131,15 +131,21 @@ def unwatch(bot, trigger): bot.memory["watcher"].pop(url) except KeyError: return bot.say("Error: I'm not watching that thread.") + removeThread(bot, get_api_url(url),) + bot.say("[\x0304Watcher\x03] No longer watching: \x0307" + url) + + +def removeThread(bot, url): + """ + Removes the provided thread from the database. This should be the API url. + """ con = bot.db.connect() cur = con.cursor() - cur.execute("DELETE FROM watcher WHERE api_url = ?", (get_api_url(url),)) + cur.execute("DELETE FROM watcher WHERE api_url = ?", (url,)) con.commit() con.close() - bot.say("[\x0304Watcher\x03] No longer watching: \x0307" + url) - class WatcherThread(threading.Thread): def __init__(self, bot, api_url, name, last_post, time_since, channel): @@ -171,6 +177,7 @@ class WatcherThread(threading.Thread): msg = "[\x0304Watcher\x03] Thread deleted: " \ + f"\x0307{get_thread_url(self.api_url)}" self.bot.say(msg, self.channel) + removeThread(self.bot, api_url) self.stop.set() continue @@ -182,6 +189,7 @@ class WatcherThread(threading.Thread): msg = "[\x0304Watcher\x03] Thread closed: " \ + f"\x0307{get_thread_url(self.api_url)}" self.bot.say(msg, self.channel) + removeThread(self.bot, api_url) self.stop.set() continue @@ -189,6 +197,7 @@ class WatcherThread(threading.Thread): if new_last_post > self.last_post: self.last_post = new_last_post msg = "[\x0304Watcher\x03] New post from \x0308" \ - + f"{self.name}\x03 in \x0307{get_thread_url(self.api_url)}" + + f"{self.name}\x03: \x0307{get_thread_url(self.api_url)}" + + f"#{self.last_post}" self.bot.say(msg, self.channel)