Example #1
0
    async def command_facereplace(self, user, in_channel, parsed):
        try:
            img_url = parsed['image'][1:-1]
            image_file = await get_image(img_url)
        except ValueError:
            return MessageCommand(channel=in_channel,
                                  user=user,
                                  text='Image {} not found.'.format(img_url))

        filename = next(tempfile._get_candidate_names()) + '.png'

        with open(image_file, 'rb') as image:
            try:
                faces = await detect_face(image, self.MAX_FACES)
            except errors.HttpError:
                return MessageCommand(
                    channel=in_channel,
                    user=user,
                    text='Failed API call. Image may be too large.')

            # Reset the file pointer, so we can read the file again
            image.seek(0)

            if faces:
                replace_faces(image, faces, filename)
            else:
                return MessageCommand(channel=in_channel,
                                      user=user,
                                      text='No faces found.')

        os.remove(image_file)
        return UploadCommand(channel=in_channel,
                             user=user,
                             file_name=filename,
                             delete=True)
Example #2
0
    async def stock_info(self, user, in_channel, parsed):
        stock_name = parsed['stock'].upper()
        try:
            if stock_name == 'ALL':
                stocks = list(StockDoc.objects())
                stocks.sort(key=attrgetter('name'))
            else:
                stocks = [StockDoc.objects.get(name=stock_name)]
        except DoesNotExist:
            return MessageCommand(
                channel=in_channel,
                user=user,
                text='Stock {} does not exist'.format(stock_name))

        result = []
        for stock in stocks:
            dividend = self.compute_dividend(stock)
            buy_price = self.compute_price(dividend, stock)
            result.append(
                '`{}{} - {:3d} deaths - Dividend: {:4.01f} - Price: {:3d} - Shares {:3d}/{} ({:4.0%})`'
                .format(' ' * (4 - len(stock.name)), stock.name,
                        self.get_deaths(stock.target_user), dividend,
                        buy_price, stock.quantity, stock.total,
                        stock.quantity / stock.total))
        return MessageCommand(user=user,
                              channel=in_channel,
                              text='\n'.join(result))
Example #3
0
    async def command_list(self, user, in_channel, parsed):
        to_user = user
        if 'user' in parsed and to_user in self.admins:
            user = parsed['user']
        elif 'user' in parsed:
            return MessageCommand(user=to_user, text="Not allowed.")
        else:
            user = to_user

        one_channel = 'channel' in parsed
        reacts = defaultdict(list)
        for react in (ReactDoc.objects(user=user, channel=parsed['channel'])
                      if one_channel else ReactDoc.objects(user=user)):
            reacts[react.channel].append((react.regex, react.emoji))

        for l in reacts.values():
            l.sort()

        res = []
        for channel, l in reacts.items():
            res.append("Reactions in {}".format(channel))
            for i, (reg, em) in enumerate(l):
                res.append("\t{}. {} --> :{}:".format(i, reg, em))

        return MessageCommand(channel=in_channel if 'here' in parsed else None,
                              user=to_user,
                              text='\n'.join(res))
Example #4
0
    async def _history_handler(self, user, in_channel, image_url, hist_list):
        if not hist_list:
            return
        try:
            image_file = await get_image(image_url) if image_url else None
        except ValueError:
            return MessageCommand(channel=None,
                                  user=user,
                                  text='Image {} not found.'.format(image_url))

        text = (rec.text for rec in hist_list)
        # Leslie's regex for cleaning mentions, emoji and uploads
        text = (re.sub('<[^>]*>|:[^\s:]*:|uploaded a file:', '', t)
                for t in text)

        try:
            out_file = await WordcloudBot.make_wordcloud(
                ' '.join(text), image_file)
        except NotImplementedError as e:
            return MessageCommand(
                channel=None,
                user=user,
                text="Apparently can't handle that image: {}".format(
                    e.message()))
        return UploadCommand(channel=in_channel,
                             user=user,
                             file_name=out_file,
                             delete=True)
Example #5
0
    async def command_emoji(self, user, in_channel, parsed):
        emotify = False
        if 'channel' in parsed and parsed['channel'] not in self.channels:
            out_text = "Channel {} not recognized or not permitted.".format(
                parsed['channel'])
            out_channel = None
        elif 'channel' in parsed:
            curr_time = time.time()
            diff = int(self.next_use[user] - curr_time)
            if diff > 0:
                out_text = "You can send another message in {} seconds.".format(
                    diff)
                out_channel = None
            else:
                self.next_use[user] = curr_time + self.delay
                emotify = True
                out_channel = parsed['channel']
        else:
            out_channel = in_channel
            emotify = True

        if emotify:
            out_text = self.emotify(parsed)

        if out_channel is None:
            return MessageCommand(text=out_text, user=user)
        else:
            return MessageCommand(text=out_text, channel=out_channel)
Example #6
0
 async def frog_monitor(self, user, in_channel, message):
     match = self.reg.search(message)
     if match:
         return MessageCommand(text='what _{}_ {}'.format(
             match.group(1), match.group(2)),
                               channel=in_channel,
                               user=user)
Example #7
0
    async def command_bind(self, user, in_channel, parsed):
        output = parsed['output']
        key = parsed['key']
        out_text = ''
        if len(output) > self.max_len:
            out_text = 'Binds must be less than {} characters long'.format(
                self.max_len)
            out_channel = None
        elif key in self.binds:
            out_text = '{} is already bound to {}.'.format(
                key, self.binds[key].output)
            out_channel = None
        else:
            self.binds[key] = Bind(user, output)

            # Write bind to mongo
            bind = BindDoc(key=key, user=user, output=output)
            bind.save()

            self.current_bind_exprs[key] = (Literal(key))
            self.update_bind_expr()

        if out_text:
            return MessageCommand(channel=out_channel,
                                  user=user,
                                  text=out_text)
Example #8
0
    async def sell_stocks(self, user, in_channel, parsed):
        err_message = None
        stock_name = parsed['stock'].upper()
        try:
            stock = StockDoc.objects.get(name=stock_name)
        except DoesNotExist:
            err_message = 'Stock {} not found'.format(stock_name)

        if not err_message:
            amount = max(int(parsed['amount']), 1) if 'amount' in parsed else 1
            user_holdings = StockHoldingsDoc.objects.get(user=user)
            stock_amounts = user_holdings.stocks
            if stock_amounts[stock_name] < amount:
                err_message = 'You do not have enough stock to fulfill that sale.'
            else:
                dividend = self.compute_dividend(stock)
                money = self.compute_price(dividend,
                                           stock,
                                           amount=amount,
                                           sell=True)
                await economy.give(user, money)

                stock.update(quantity=stock.quantity + amount)
                stock_amounts[stock_name] -= amount
                if stock_amounts[stock_name] == 0:
                    del stock_amounts[stock_name]
                user_holdings.update(stocks=stock_amounts)

        if err_message:
            return MessageCommand(channel=in_channel,
                                  user=user,
                                  text=err_message)
Example #9
0
    async def command_level(self, user, in_channel, parsed):
        required_level = self.level_commands[parsed['command'].lower()]
        user_level = await economy.level(user)

        secondary = required_level == 1
        cost = self.level_costs[required_level]
        user_currency = await economy.user_currency(user, secondary=secondary)

        if user_level < required_level:
            message = 'You need to pull yourself up by your bootstraps.'
        elif user_level > required_level:
            message = 'You\'ve already done that'
        elif user_currency < cost:
            if secondary:
                message = 'You need {} grades'.format(cost)
            else:
                message = 'You need {} {}. Maybe if you worked harder?'.format(cost, self.currency_name)
        else:
            if secondary:
                await economy.set(user, 0, secondary=True)
                message = 'You\'ve graduated!'
            else:
                await economy.give(user, -cost)
                message = 'You\'ve enrolled!'
            await economy.level_up(user)

        return MessageCommand(channel=in_channel, user=user, text=message)
Example #10
0
 async def command_judge(self, user, in_channel, parsed):
     sent = self.predict(parsed['text'][0])
     sent *= 100
     decimals = parsed['decimals'] if 'decimals' in parsed else '0'
     format_str = 'Positive: {:.' + decimals + 'f}% Negative: {:.' + decimals + 'f}%'
     return MessageCommand(text=format_str.format(sent[2], sent[0]),
                           channel=in_channel,
                           user=user)
Example #11
0
 async def command_check(self, user, in_channel, parsed):
     secondary = self.check_commands[parsed['command'].lower()]
     money = await economy.user_currency(user, secondary=secondary)
     currency_name = 'grades' if secondary else self.currency_name
     return MessageCommand(
         text='You have {} {}'.format(int(money), currency_name),
         channel=in_channel,
         user=user)
Example #12
0
    async def command_twitch(self, user, in_channel, parsed):
        # None if not found
        twitch_channel = parsed.get('twitch_channel')
        if twitch_channel and not twitch_channel.startswith('#'):
            twitch_channel = '#' + twitch_channel

        if twitch_channel not in self.markov.probabilities:
            out_text = "Channel {} not recognized. If you would like this channel added, ask a bot admin.".format(
                twitch_channel)
            out_channel = None
        else:
            out_channel = in_channel
            out_text = self.markov.generate_message(twitch_channel)

        if out_channel is None:
            return MessageCommand(text=out_text, user=user)
        else:
            return MessageCommand(text=out_text, channel=out_channel)
Example #13
0
 async def command_hankey(self, user, in_channel, parsed):
     if await economy.user_currency(user) >= self.cost:
         self.target = parsed['target']
         await economy.give(user, -self.cost)
         self.cost += 1
         with open(SAVE_FILE, 'wb') as f:
             pickle.dump(self.cost, f)
     else:
         return MessageCommand(text="no", channel=in_channel, user=user)
Example #14
0
 async def _quoter_callback(self, out_channel, user, hist_list):
     if not hist_list:
         return None
     quote = random.choice(hist_list)
     year = time.strftime('%Y', time.localtime(float(quote.time)))
     return MessageCommand(channel=out_channel,
                           user=user,
                           text='> {}\n-{} {}'.format(
                               quote.text, quote.user, year))
Example #15
0
 async def market_index(self, user, in_channel, parsed):
     total_dividend = 0
     stock_objs = list(StockDoc.objects())
     for stock in stock_objs:
         total_dividend += self.compute_dividend(stock) * stock.total
     return MessageCommand(channel=in_channel,
                           user=user,
                           text='The {} is at {}'.format(
                               self.index_name,
                               int(total_dividend / len(stock_objs))))
Example #16
0
    async def slots(self, user, in_channel, parsed, rigged=None):
        bet = int(parsed['bet'])
        bank = await economy.user_currency(user)
        msg = ''
        if bank >= bet:
            reels = rigged if rigged else list(random.choice(
                self.slots_sym, 3))
            jacks = reels.count(self.slots_jackpot_symbol)
            jackpot = False
            if jacks:
                if jacks == 3:
                    won = (await casino.get_jackpot('slots'))
                    jackpot = True
                elif jacks == 2:
                    won = bet * 4
                else:
                    won = 0
            else:
                won = bet * 10 if reels.count(reels[0]) == 3 else 0

            if won or jackpot:  # you can win the jackpot when it's 0...
                # only one command can execute at a time, so no race
                if jackpot:
                    await casino.update_jackpot('slots', -won)
                    await casino.record_win(user, 'slots', won)
                    msg = 'JACKPOT!!!! '
                msg += '{0} won {1} {2}!'.format(user, int(won),
                                                 self.currency_name)
            else:
                msg = 'Try again.'
                await casino.update_jackpot('slots',
                                            bet * self.slots_contribution)

            await economy.give(user, won - bet)
            await casino.record(user, 'slots', won - bet)
            return MessageCommand(text='{0}\n{1} Jackpot is {2}.'.format(
                ''.join(reels), msg, int(await casino.get_jackpot('slots'))),
                                  channel=in_channel,
                                  user=user)
        else:
            return MessageCommand(text='Too poor! Sad.',
                                  channel=in_channel,
                                  user=user)
Example #17
0
    async def buy_stocks(self, user, in_channel, parsed):
        err_message = None
        stock_name = parsed['stock'].upper()
        try:
            stock = StockDoc.objects.get(name=stock_name)
        except DoesNotExist:
            err_message = 'Stock {} not found'.format(stock_name)

        if not err_message:
            amount = max(int(parsed['amount']), 1) if 'amount' in parsed else 1

            if stock.target_user == user:
                err_message = 'You cannot buy stock in yourself.'
            elif stock.quantity < amount:
                err_message = 'Not enough stocks in stock.'
            else:
                dividend = self.compute_dividend(stock)
                cost = self.compute_price(dividend, stock, amount=amount)
                if await economy.user_currency(user) < cost:
                    err_message = 'You are too poor.'

        if err_message:
            return MessageCommand(user=user,
                                  channel=in_channel,
                                  text=err_message)

        stock.update(quantity=stock.quantity - amount)

        user_stocks = get_or_create_user(user)

        stock_amounts = user_stocks.stocks
        stock_amounts[stock_name] = stock_amounts.get(stock_name, 0) + amount
        user_stocks.update(stocks=stock_amounts)

        await economy.give(user, -cost)
        return MessageCommand(
            channel=in_channel,
            user=user,
            text='{} bought {} share{} of {} for {} {}.'.format(
                user, amount, 's' if amount > 1 else '', stock_name, cost,
                self.currency_name))
Example #18
0
    async def command_print_bind(self, user, in_channel, parsed):
        raw = self.binds[parsed['key'][0]].output
        args = parsed['formats'].strip().split(
            sep=' ') if 'formats' in parsed else []
        out_channel = in_channel

        try:
            output = raw.format(*args)
        except IndexError:
            output = "Not enough format arguments supplied, got {}".format(
                len(args))
            out_channel = None
        return MessageCommand(channel=out_channel, user=user, text=output)
Example #19
0
    async def command_clear(self, user, in_channel, parsed):
        channel = parsed['channel']
        index = int(parsed['index'])
        react_objs = {(r.regex, r.emoji): r
                      for r in ReactDoc.objects(user=user, channel=channel)}
        reacts = sorted(react_objs)
        if not 0 <= index < len(reacts):
            text = 'Invalid reaction number.'
        else:
            r_obj = react_objs[reacts[index]]
            r_obj.delete()
            text = 'Reaction deleted.'

        return MessageCommand(user=user, channel=in_channel, text=text)
Example #20
0
 async def available_stocks(self, user, in_channel, parsed):
     result = []
     stock_dividends = [
         (int(self.compute_price(self.compute_dividend(stock),
                                 stock)), stock)
         for stock in StockDoc.objects()
     ]
     stock_dividends.sort(reverse=True, key=itemgetter(0))
     for price, stock in stock_dividends:
         result.append('*{}* {}'.format(stock.name, price))
     out_message = (' | '.join(result) + '\n' + datetime.fromtimestamp(
         self.next_dividend_time).strftime('Next dividend %c {}').format(
             self.timezone))
     return MessageCommand(user=user, channel=in_channel, text=out_message)
Example #21
0
 async def command_poll(self, user, in_channel, parsed):
     options = parsed['comma_list']
     noptions = len(options)
     if not 2 <= noptions <= 10:
         text = 'Invalid number of options provided. {} received, please provide between 2 and 10.'.format(
             noptions)
         cb = None
     else:
         text = "Please vote:\n"
         text += "\n".join(
             [a + " " + b for a, b in zip(self.emoji, options)])
         cb = partial(self.response_react, self.emoji[:noptions])
     return MessageCommand(text=text,
                           channel=in_channel,
                           user=user,
                           success_callback=cb)
Example #22
0
 async def _extrema_callback(self,
                             field,
                             out_channel,
                             user,
                             hist_list,
                             target_user=None):
     if not hist_list:
         return
     q_time = max(self._complete_cache(hist_list, user=target_user),
                  key=lambda obj: getattr(obj, field)).time
     quote = next(r for r in hist_list if r.time == q_time)
     year = time.strftime('%Y', time.localtime(float(quote.time)))
     return MessageCommand(channel=out_channel,
                           user=user,
                           text='> {}\n-{} {}'.format(
                               quote.text, quote.user, year))
Example #23
0
    async def check_stocks(self, user, in_channel, parsed):
        user_obj = get_or_create_user(user)
        stocks = user_obj.stocks
        total_dividend = 0
        for stock_name, amount in stocks.items():
            stock_obj = StockDoc.objects.get(name=stock_name)
            dividend = self.compute_dividend(stock_obj)
            total_dividend += amount * dividend

        lines = []
        lines.extend('`{}{}`: {}'.format(stock, ' ' * (4 - len(stock)), amount)
                     for stock, amount in sorted(stocks.items()))
        lines.append('Your next dividend payment will be {} {}.'.format(
            int(total_dividend), self.currency_name))

        return MessageCommand(user=user,
                              channel=in_channel,
                              text='\n'.join(lines))
Example #24
0
    async def command_unbind(self, user, in_channel, parsed):
        key = parsed['key']
        out_text = None
        if key not in self.binds:
            out_text = '{} is not bound.'.format(key)
            out_channel = None
        elif user not in self.admins and self.binds[key].user != user:
            out_text = 'You may only unbind your own binds.'
            out_channel = None
        else:
            bind_obj = BindDoc.objects(key=key)
            bind_obj.delete()
            del self.current_bind_exprs[key]
            del self.binds[key]
            self.update_bind_expr()

        if out_text:
            return MessageCommand(channel=out_channel,
                                  user=user,
                                  text=out_text)
Example #25
0
 async def _stats_callback(self,
                           out_channel,
                           user,
                           hist_list,
                           target_user=None):
     if not hist_list:
         return
     softmaxes = [
         (obj.neg_sent, obj.neut_sent, obj.pos_sent)
         for obj in self._complete_cache(hist_list, user=target_user)
     ]
     counts = [0, 0]
     for s in softmaxes:
         # Exclude neutral val
         counts[np.argmax((s[0], s[2]))] += 1
     negative, positive = [100 * c / len(softmaxes) for c in counts]
     return MessageCommand(
         text='Positive: {:.0f}% Negative: {:.0f}%'.format(
             positive, negative),
         user=user,
         channel=out_channel)
Example #26
0
    async def command_generate(self, user, in_channel, parsed):
        target_user = parsed['user']
        if 'reddit' in parsed:
            user_exists = await self._update_reddit_user(target_user)

            if user_exists:
                out_channel = in_channel
                out_message = await self._generate_message(target_user,
                                                           reddit=True)
            else:
                out_channel = None
                out_message = 'User {} either does not exist or has no self posts or comments'.format(
                    target_user)
        else:
            if target_user in self.user_transitions:
                out_channel = in_channel
                out_message = await self._generate_message(target_user)
            else:
                out_channel = None
                out_message = 'User {} not found'.format(target_user)
        return MessageCommand(user=user, channel=out_channel, text=out_message)
Example #27
0
    async def command_stats(self, user, in_channel, parsed):
        won, lost, played, jc, jt, jw = await casino.get_stats(user, 'slots')
        msg = '{game} Stats for {user}:\n\tNet *{net}* {currency} (+{won}/{lost}). Played {played} times.\n\tHit {jack} jackpot(s).'
        if jt:
            msg += ' Last jackpot hit was {amount} {currency} at {date:%H:%M:%S %m/%d/%Y} UTC.'
        else:
            jt = datetime.utcnow()
            jw = 0

        formatted = msg.format(user=user,
                               game='Slots',
                               net=int(won + lost),
                               currency=self.currency_name,
                               won=int(won),
                               lost=int(lost),
                               played=played,
                               jack=jc,
                               amount=int(jw),
                               date=jt)

        return MessageCommand(text=formatted, channel=in_channel, user=user)
Example #28
0
    async def sentiment_monitor(self, user, in_channel, message, timestamp):
        if not in_channel:
            return
        neg, neut, pos = self.predict(message)
        SentimentDoc(time=timestamp,
                     user=user,
                     channel=in_channel,
                     pos_sent=pos,
                     neut_sent=neut,
                     neg_sent=neg).save()
        channel_sentiment = self.sentiments[in_channel]
        channel_sentiment.append(pos + 0.2 > neg)
        if len(channel_sentiment) > 10:
            channel_sentiment.pop(0)

        self.cooldowns[in_channel] -= 1
        if self.cooldowns[in_channel] <= 0 and channel_sentiment.count(
                False) >= 7:
            self.cooldowns[in_channel] = COOLDOWN
            return MessageCommand(
                text='You guys should cheer up. http://placekitten.com/{}/{}'.
                format(random.randint(300, 500), random.randint(300, 500)),
                channel=in_channel)
Example #29
0
    async def command_gain(self, user, in_channel, parsed):
        level = self.work_commands[parsed['command'].lower()]
        required_channel = self.channel_order[level]

        user_level = await economy.level(user)

        err_message = None
        if user_level < level:
            err_message = 'You can\'t do that yet.'
        elif user_level > level:
            err_message = 'You\'re better than that now.'
        elif required_channel != in_channel:
            err_message = 'None of that in here, go to #{}.'.format(required_channel)
        else:
            if level == 0:
                await economy.give(user, 1)
            elif level == 1:
                await economy.give(user, 1, secondary=True)
            elif level == 2:
                await economy.give(user, 5)

        if err_message:
            return MessageCommand(channel=in_channel, user=user, text=err_message)
Example #30
0
    async def command_create(self, user, in_channel, parsed):
        target_channel = parsed['channel']
        reg_text = parsed['target_pattern']
        emoji = parsed['emoji'][1:-1]

        if target_channel not in self.out_channels:
            text = "Reactions in channel {} not permitted.".format(
                target_channel)
        elif len(self.reacts[target_channel][user]) >= self.max_per_user:
            text = "Maximum number of emojis per channel reached."
        else:
            try:
                reg = re.compile(reg_text, re.IGNORECASE)
                react_obj = ReactDoc(user=user,
                                     channel=target_channel,
                                     regex=reg_text,
                                     emoji=emoji)
                react_obj.save()
                self.reacts[target_channel][user].add((reg, emoji))
                text = 'Reaction saved'
            except re.error:
                text = 'Invalid pattern.'

        return MessageCommand(user=user, channel=in_channel, text=text)