コード例 #1
0
ファイル: yo.py プロジェクト: svkampen/Karkat
    def __init__(self, server):
        self.server = server
        self.yodaemon = YoCollector(server, self.yo_receive)
        self.yodaemon.start()
        self.routesf = server.get_config_dir("yo_routes.json")
        self.routes = Config(self.routesf, default={})

        self.usersf = server.get_config_dir("yo_users.json")
        self.users = Config(self.usersf, default={})

        self.keysf = server.get_config_dir("yo_keys.json")
        self.keys = Config(self.keysf, default={})
        super().__init__(server)
コード例 #2
0
ファイル: pushbullet.py プロジェクト: svkampen/Karkat
 def __init__(self, server):
     self.server = server
     self.configf = server.get_config_dir("pushbullet.json")
     self.config = Config(self.configf, default={"accounts":{}, "users":{}})
     self.usersettingsf = server.get_config_dir("pushbullet_settings.json")
     self.usersettings = Config(self.usersettingsf, default={})
     self.bouncefmt = "\x0303· \x02%(nick)s\x0f\x0f: %(body)s"
     self.listeners = []
     self.skip = set()
     self.sent = set()
     self.pushlock = threading.Lock()
     self.watchers = {}
     self.channels = {}
     self.active = {}
     self.rejoin_ignore = {}
     self.lower = server.lower
     self.listen()
     for channel, account in self.config["accounts"].items():
         try:
             self.channels[channel] = requests.get("https://api.pushbullet.com/v2/users/me", headers={"Authorization": "Bearer " + account["token"]}).json()
         except:
             pass
     super().__init__(server)
コード例 #3
0
ファイル: cah.py プロジェクト: svkampen/Karkat
    def __init__(self, server):
        self.instances.append(self)
        self.games = {}
        self.lock = threading.Lock()

        self.config = Config(server.get_config_dir(CONFIG_FILE))

        self.expansiondir = server.get_config_dir("CardsAgainstHumanity")
        if not os.path.exists(self.expansiondir):
            os.makedirs(self.expansiondir, exist_ok=True)
        if not os.path.exists(self.expansiondir + "/statistics.db"):
            # Initialise the db
            with sqlite3.connect(self.expansiondir + "/statistics.db") as db:
                db.execute(
                    "CREATE TABLE white (timestamp int, nick text, channel text, round int, czar text, prompt text, cards text, bet int, rank int);"
                )

        CardsAgainstHumanity.loadcards(self.expansiondir)

        server.register("privmsg", self.trigger)
        server.register("privmsg", self.custom_cards)
        server.register("privmsg", self.remove_player)
コード例 #4
0
ファイル: pushbullet.py プロジェクト: svkampen/Karkat
class PushBullet(Callback):
    HLCMD = r"\.highlight(?: (always|(?:\S+(?:,\s*\S+)* )?inactive(?: \d+)?|(?:\S+(?:,\s*\S+)* )?offline|remove))?(?: (.+))?"

    def __init__(self, server):
        self.server = server
        self.configf = server.get_config_dir("pushbullet.json")
        self.config = Config(self.configf, default={"accounts":{}, "users":{}})
        self.usersettingsf = server.get_config_dir("pushbullet_settings.json")
        self.usersettings = Config(self.usersettingsf, default={})
        self.bouncefmt = "\x0303· \x02%(nick)s\x0f\x0f: %(body)s"
        self.listeners = []
        self.skip = set()
        self.sent = set()
        self.pushlock = threading.Lock()
        self.watchers = {}
        self.channels = {}
        self.active = {}
        self.rejoin_ignore = {}
        self.lower = server.lower
        self.listen()
        for channel, account in self.config["accounts"].items():
            try:
                self.channels[channel] = requests.get("https://api.pushbullet.com/v2/users/me", headers={"Authorization": "Bearer " + account["token"]}).json()
            except:
                pass
        super().__init__(server)

    def listen(self):
        for channel, account in self.config["accounts"].items():
            self.listeners.append(PushListener(account["token"], partial(self.update, channel)))
        for listener in self.listeners:
            listener.start()

    def update(self, account):
        acc = self.config["accounts"][account]
        params = {"modified_after": acc["last"]}
        headers = {"Authorization": "Bearer " + acc["token"]}
        watchers = self.watchers.setdefault(self.lower(account), set())
        req = requests.get("https://api.pushbullet.com/v2/pushes", params=params, headers=headers)
        pushes = req.json()["pushes"]
        if not pushes:
            return
        pushes.reverse()
        for push in pushes:
            sender_email = push["sender_email"].lower()
            hlmatch = re.match(self.HLCMD, push.get("body", ""))
            with self.pushlock:
                if push["iden"] in self.skip:
                    self.skip.remove(push["iden"])
                elif hlmatch:
                    when, word = hlmatch.groups()
                    if sender_email in self.config["users"]:
                        nick = self.config["users"][sender_email]
                        settings = self.usersettings.get(self.lower(account), [])
                        if word is None: word = nick
                        if when is None: when = "offline"
                        pattern = [word, sender_email, when]
                        matches = [i for i, x in enumerate(settings) if x[0:2] == pattern[0:2]]
                        if when == "remove":
                            settings = [i for i in settings if i[0:2] != pattern[0:2]]
                            hlconfirm = {"type": "note", "email": sender_email, "title": "* %r removed from alerts." % word}                            
                        elif matches and pattern in settings:
                            settings.remove(pattern)
                            hlconfirm = {"type": "note", "email": sender_email, "title": "* %r removed from alerts." % word}
                        elif matches:
                            for i in matches:
                                settings[i] = pattern
                            hlconfirm = {"type": "note", "email": sender_email, "title": "* Alert for %r changed to %r." % (word, when)}
                        else:
                            settings.append(pattern)
                            hlconfirm = {"type": "note", "email": sender_email, "title": "* %r added to alerts." % word}
                        self.skip.add(self.push(hlconfirm, acc["token"]))
                        self.usersettings[self.lower(account)] = settings
                # Handle user joins
                elif push.get("body", "") == ".join":
                    if sender_email in self.config["users"]:
                        nick = self.config["users"][sender_email]
                        self.server.message("03│ ⁍ │ %s has joined the conversation via pushbullet." % nick, account)
                        watchers.add(sender_email)
                        push_join = {"type": "note", "title": "* %s has joined via PushBullet" % nick}
                        actives = {"type": "note", "email": push["sender_email"], "title": "* Now listening to %s" % account}
                        ausers = [k for k, v in self.active.setdefault(self.lower(account), {}).items() if time.time() - v < ACTIVITY_TIMEOUT]
                        if ausers:
                            actives["body"] = "Active users:\n%s" % (", ".join(ausers))
                        for email in watchers:
                            if email.lower() != sender_email:
                                push_join["email"] = email
                                self.skip.add(self.push(push_join, acc["token"]))
                        self.skip.add(self.push(actives, acc["token"]))
                elif push.get("body", "") == ".part":
                    if sender_email in watchers:
                        nick = self.config["users"][sender_email]
                        self.server.message("03│ ⁍ │ %s has stopped listening to the conversation." % nick, account)
                        watchers.remove(sender_email)
                        push_part = {"type": "note", "title": "* %s is no longer receiving updates via PushBullet" % nick}
                        partconfirm = {"type": "note", "email": push["sender_email"], "title": "* No longer listening to %s" % account}
                        for email in watchers:
                            if email.lower() != sender_email:
                                push_part["email"] = email
                                self.skip.add(self.push(push_part, acc["token"]))
                        self.skip.add(self.push(partconfirm, acc["token"]))
                else:
                    display_sender = self.config["users"].get(sender_email, push["sender_email"])
                    for email in watchers:
                        if email.lower() != sender_email:
                            self.skip.add(self.push(push_bounce(push, display_sender, email), acc["token"]))
                    if push["iden"] not in self.sent:
                        @command("reply", r"(?:(https?://\S+|:.+?:))?\s*(.*)")
                        def pushreply(server, message, link, text, push=push):
                            user = push["sender_email"]
                            return self.send_push.funct(self, server, message, user, link, text)
                        self.server.reply_hook = pushreply
                    if sender_email in watchers:
                        self.server.message(self.bouncefmt % {"nick": display_sender, "body": push_text(push)}, account)
                    else:
                        self.server.message(push_format(push, self.sent, self.config["users"]), account)

            acc["last"] = max(push["modified"], acc["last"])
        self.save(account, acc)


    def save(self, channel, account):
        with self.config as conf:
            conf["accounts"][channel] = account

    def queue(self, push):
        pass

    @command("setpush", "(.+@.+)")
    def set_push(self, server, msg, email):
        with self.config as conf:
            conf["users"][email.lower()] = msg.address.nick
        return "03│ ⁍ │ Associated %s with pushbullet account %s." % (msg.address.nick, email)

    @command("pushassoc", r"(#\S+)\s+(\S+)", admin=True)
    def add_channel(self, server, msg, channel, token):
        account = {"token": token, "last": time.time()}
        with self.config as conf:
            conf["accounts"][server.lower(channel)] = account
        listener = PushListener(account["token"], partial(self.update, channel))
        self.listeners.append(listener)
        listener.start()
        self.channels[channel] = requests.get("https://api.pushbullet.com/v2/users/me", headers={"Authorization": "Bearer " + token}).json()
        return "03│ ⁍ │ Done."

    @command("help", r"(?:(\S+)\s+)?pushbullet")
    def pushbullet_info(self, server, msg, user):
        try:
            acc = self.config["accounts"][self.lower(msg.context)]
            email = self.channels[self.lower(msg.context)]["email"]
        except KeyError:
            return "04│ ⁍ │ This channel has no associated pushbullet."

        steps = ["Go to https://www.pushbullet.com/add-friend", 
                 "Add %s (%s) as a friend" % (msg.context, email), 
                 "Visit https://www.pushbullet.com/?email=%s and send your first push to the channel!" % email]
        if user:
            user_email = self.get_user(user)
            if user not in self.config["users"]:
                steps = ["If you don't have an account: Set up an account at http://www.pushbullet.com/ and install pushbullet on your devices", "Type /msg %s .setpush EMAIL_ADDRESS" % server.nick] + steps
        else:
            return "03│ ⁍ │ Type .setpush \x02email\x02, then go to 12https://www.pushbullet.com/add-friend\x0f and add \x0303%s\x03 as a friend." % email            
        if user_email is None:
            return "03│ ⁍ │ %s: type .setpush \x02email\x02, then go to 12https://www.pushbullet.com/add-friend\x0f and add \x0303%s\x03 as a friend." % (user, email)
        else:
            with self.pushlock:
                self.sent.add(self.push({"type" : "link", 
                           "title": "Add %s on PushBullet" % msg.context,
                           "body" : "\r\n".join("%d) %s" % (i+1, s) for i, s in enumerate(steps)),
                           "link" : "https://www.pushbullet.com/add-friend",
                           "email": user_email}, 
                          acc["token"]))
            return "03│ ⁍ │ I've sent instructions to %s's pushbullet address." % user
        
        
    @command("send", r"(\S+(?:,\s*\S+)*)(?:\s+(https?://\S+|:.+?:))?(?:\s+(.+))?")
    def send_push(self, server, msg, user, link, text):
        try:
            acc = self.config["accounts"][server.lower(msg.context)]
        except KeyError:
            return

        push = {}

        user = self.get_user(user)
        if user is None:
            return "03│ ⁍ │ %s has not associated their pushbullet." % user

        push["title"] = msg.address.nick + ":"

        if link:
            if link.startswith(":"):
                link = image_search(link[1:-1])[0]["url"] 
            push["url"] = link
            push["type"] = "link"
        else:
            push["type"] = "note"
        if text:
            push["body"] = text
        push["email"] = user
        with self.pushlock:
            self.sent.add(self.push(push, acc["token"]))

    @msghandler
    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)

    ## Channel state tracking

    def update_active_quit(self, server, line) -> "quit":
        words = line.split(" ", 2)
        nick = Address(words[0]).nick
        lnick = server.lower(nick)
        requires_updates = []
        for channel in self.active:
            if lnick in self.active[channel]:
                if time.time() - self.active[channel][lnick] < ACTIVITY_TIMEOUT:
                    requires_updates.append(channel)
                else:
                    self.rejoin_ignore.setdefault(channel, {})[lnick] = time.time()
                del self.active[channel][lnick]
        # Update watchers
        push = {"type": "note", "title": "* %s has disconnected" % nick, "body": cstrip(words[-1])}
        for channel in requires_updates:
            ctx = server.lower(channel)
            if ctx in self.watchers and ctx in self.config["accounts"]:
                acc = self.config["accounts"][ctx]
                watchers = self.watchers[ctx]
                for email in watchers:
                    push["email"] = email
                    with self.pushlock:
                        self.skip.add(self.push(push, acc["token"]))


    def update_active_part(self, server, line) -> "part":
        words = line.split(" ", 3)
        nick = Address(words[0]).nick
        lnick = server.lower(nick)
        channel = server.lower(words[2])
        push = {"type": "note", "title": "* %s has left the channel" % nick, "body": cstrip(words[-1])}
        if lnick in self.active[channel]:
            if (time.time() - self.active[channel][lnick] < ACTIVITY_TIMEOUT
                and channel in self.watchers 
                and channel in self.config["accounts"]):
                # Update watchers
                acc = self.config["accounts"][channel]
                watchers = self.watchers[channel]
                for email in watchers:
                    push["email"] = email
                    with self.pushlock:
                        self.skip.add(self.push(push, acc["token"]))
            del self.active[channel][lnick]

    def update_active_nick(self, server, line) -> "nick":
        words = line.split(" ", 2)
        nick = Address(words[0]).nick
        lnick = server.lower(nick)
        newnick = words[2]
        requires_updates = []
        for channel in self.active:
            if lnick in self.active[channel]:
                if time.time() - self.active[channel][lnick] < ACTIVITY_TIMEOUT:
                    requires_updates.append(channel)
                del self.active[channel][lnick]
                self.active[channel][server.lower(newnick)] = time.time()
        # Update watchers
        push = {"type": "note", "title": "* %s is now known as %s" % (nick, newnick)}
        for channel in requires_updates:
            ctx = server.lower(channel)
            if ctx in self.watchers and ctx in self.config["accounts"]:
                acc = self.config["accounts"][ctx]
                watchers = self.watchers[ctx]
                for email in watchers:
                    push["email"] = email
                    with self.pushlock:
                        self.skip.add(self.push(push, acc["token"]))

    def update_active_join(self, server, line) -> "join":
        words = line.split(" ", 3)
        nick = Address(words[0]).nick
        lnick = server.lower(nick)
        channel = server.lower(cstrip(words[2]))
        push = {"type": "note", "title": "* %s has joined the channel" % nick}
        if ((lnick not in self.rejoin_ignore.setdefault(channel, {})
            or (time.time() - self.rejoin_ignore[channel][lnick]) > ACTIVITY_TIMEOUT)
            and channel in self.watchers 
            and channel in self.config["accounts"]):
            # Update watchers
            acc = self.config["accounts"][channel]
            watchers = self.watchers[channel]
            for email in watchers:
                push["email"] = email
                with self.pushlock:
                    self.skip.add(self.push(push, acc["token"]))
        if lnick in self.rejoin_ignore[channel]:
            del self.rejoin_ignore[channel][lnick]
        self.active.setdefault(channel, {})[lnick] = time.time()

    def update_active_kick(self, server, line) -> "kick":
        words = line.split(" ", 4)
        kicker = Address(words[0]).nick
        nick = words[3]
        lnick = server.lower(nick)
        channel = server.lower(words[2])
        push = {"type": "note", "title": "* %s has kicked %s from %s" % (kicker, nick, words[2]), "body": cstrip(words[-1])}
        if (channel in self.watchers 
            and channel in self.config["accounts"]):
            # Update watchers
            acc = self.config["accounts"][channel]
            watchers = self.watchers[channel]
            for email in watchers:
                push["email"] = email
                with self.pushlock:
                    self.skip.add(self.push(push, acc["token"]))
        if lnick in self.active[channel]:
            del self.active[channel][lnick]


    def push(self, push, token):
        headers = {"Authorization": "Bearer " + token}
        response = requests.post("https://api.pushbullet.com/v2/pushes", headers=headers, data=push).json()
        return response["iden"]

    def get_user(self, user):
        if "@" not in user:
            users = self.config["users"]
            users = [i for i in users if self.lower(user) == self.lower(users[i])]
            if not users:
                return
            else:
                user = users[0]
        return user

    def __destroy__(self, server):
        for listener in self.listeners:
            listener.listening = False

    @command("pbflush", admin=True)
    def pbflush(self, server, msg):
        for channel, account in self.config["accounts"].items():
            self.update(channel)
        return "03│ ⁍ │ Manually tickled all pushbullet connections."        

    @command("pbrestart", admin=True)
    def pbrestart(self, server, msg):
        for listener in self.listeners:
            listener.listening = False  
        self.listeners = []   
        self.listen()
        return "03│ ⁍ │ Restarted all tickle threads."