def ddg(bot: DeltaBot, payload: str, message: Message, replies: Replies) -> None: """Search in DuckDuckGo.""" mode = _get_mode(bot, message.get_sender_contact().addr) page = 'lite' if mode == 'htmlzip' else 'html' url = "https://duckduckgo.com/{}?q={}".format(page, quote_plus(payload)) replies.add(**_download_file(bot, url, mode))
def w(bot: DeltaBot, payload: str, message: Message, replies: Replies) -> None: """Search in Wikipedia.""" sender = message.get_sender_contact().addr lang = _get_locale(bot, sender) url = "https://{}.m.wikipedia.org/wiki/?search={}".format( lang, quote_plus(payload)) replies.add(**_download_file(bot, url, _get_mode(bot, sender)))
def lines_top(message: Message, replies: Replies) -> None: """Send Color Lines scoreboard. Example: `/lines_top` """ limit = 15 text = '🏆 Color Lines Scoreboard\n\n' game = db.get_game_by_addr(message.get_sender_contact().addr) if not game: games = db.get_games(limit) else: games = db.get_games() if not games: text += '(Empty list)' for n, g in enumerate(games[:limit], 1): text += '#{} {} {}\n'.format(n, db.get_nick(g['addr']), g['score']) if game: player_pos = games.index(game) if player_pos >= limit: text += '\n' if player_pos > limit: pgame = games[player_pos - 1] text += '#{} {} {}\n'.format(player_pos, db.get_nick(pgame['addr']), pgame['score']) text += '#{} {} {}\n'.format(player_pos + 1, db.get_nick(game['addr']), game['score']) if player_pos < len(games) - 1: ngame = games[player_pos + 1] text += '#{} {} {}\n'.format(player_pos + 2, db.get_nick(ngame['addr']), ngame['score']) replies.add(text=text)
def lyrics(payload: str, replies: Replies) -> None: """Get song lyrics. """ base_url = 'https://www.lyrics.com' url = "{}/lyrics/{}".format(base_url, quote(payload)) with requests.get(url, headers=HEADERS) as r: r.raise_for_status() soup = bs4.BeautifulSoup(r.text, 'html.parser') best_matches = soup.find('div', class_='best-matches') a = best_matches and best_matches.a if not a: soup = soup.find('div', class_='sec-lyric') a = soup and soup.a if a: artist, name = map(unquote_plus, a['href'].split('/')[-2:]) url = base_url + a['href'] with requests.get(url, headers=HEADERS) as r: r.raise_for_status() soup = bs4.BeautifulSoup(r.text, 'html.parser') lyric = soup.find(id='lyric-body-text') if lyric: text = '🎵 {} - {}\n\n{}'.format(name, artist, lyric.get_text()) replies.add(text=text) return replies.add(text='No results for: {}'.format(payload))
def echo(payload: str, replies: Replies) -> None: """Echo back received text. To use it send a message like: /echo hello world """ replies.add(text=payload or "echo")
def filter_messages(bot: DeltaBot, message: Message, replies: Replies) -> None: """Process turns in Exquisite Corpse game groups """ if not message.chat.is_group(): sender = message.get_sender_contact() g = db.get_game_by_turn(sender.addr) if g is None: return if len(message.text.split()) < 10: text = '❌ Text too short. Send a message with at least 10 words' replies.add(text=text) else: paragraph = g['text'] + ' ' + message.text db.set_text(g['gid'], paragraph) p = db.get_player_by_addr(sender.addr) assert p is not None if p['round'] == 3: db.delete_player(p['addr']) else: db.set_player(p['addr'], p['round'] + 1, g['gid']) p = _get_by_round(g['gid']) if p is None: # End Game text = _end_game(g['gid']) replies.add(text=text, chat=bot.get_chat(g['gid'])) else: db.set_turn(g['gid'], p['addr']) _run_turn(bot, p, bot.get_chat(g['gid']), paragraph)
def filter_messages(message: Message, bot: DeltaBot, replies: Replies) -> None: """Natural language processing and learning. """ if replies.has_replies() or not message.text: return self_contact = bot.self_contact name = bot.account.get_config('displayname') quote = message.quote reply_to_dash = _getdefault(bot, 'reply_to_dash', '1') not in ('0', 'no') resp = None if reply_to_dash and message.text.startswith('#') and \ len(message.text) > 1: resp = CBOT.get_response(message.text[1:]) elif not message.chat.is_group() or (quote and quote.get_sender_contact() == self_contact): resp = CBOT.get_response(message.text) elif self_contact.addr in message.text or (name and name in message.text): resp = CBOT.get_response( _rmprefix(_rmprefix(message.text, self_contact.addr), name).strip(':,').strip()) if resp: bot.logger.debug('Confidence: %s | message: %s | reply: %s', resp.confidence, resp.in_response_to, resp.text) if resp.confidence >= float(_getdefault(bot, 'min_confidence', '0')): replies.add(text=resp.text) else: replies.add(text=random.choice(default_replies)) if quote and quote.text and _getdefault(bot, 'learn') == '1': CBOT.learn_response( Statement(text=message.text, in_response_to=quote.text))
def poll_new(bot: DeltaBot, payload: str, message: Message, replies: Replies) -> None: """Create a new public poll. Example: /poll_new Do you like polls? yes no maybe """ lines = [] for ln in payload.split("\n"): ln = ln.strip() if ln: lines.append(ln) if len(lines) < 3: replies.add(text="❌ Invalid poll, at least two options needed") return question = lines.pop(0) poll = Poll(addr=message.get_sender_contact().addr, question=question) for i, opt in enumerate(lines, 1): poll.options.append(Option(id=i, text=opt)) with session_scope() as session: session.add(poll) session.flush() text, html = _format_poll(bot, poll) replies.add(text=text, html=html)
def quote(bot: DeltaBot, payload: str, message: Message, replies: Replies) -> None: """Get Wikiquote quotes. Search in Wikiquote or get the quote of the day if no text is given. Example: `/quote Richard Stallman` """ locale = _get_locale(bot, message.get_sender_contact().addr) if locale in wq.supported_languages(): lang = locale else: lang = None if payload: authors = wq.search(payload, lang=lang) if authors: if payload.lower() == authors[0].lower(): author = authors[0] else: author = choice(authors) text = f'"{choice(wq.quotes(author, max_quotes=200, lang=lang))}"\n\n― {author}' else: text = f"No quote found for: {payload}" else: _quote, author = wq.quote_of_the_day(lang=lang) text = f'"{_quote}"\n\n― {author}' replies.add(text=text)
def _check_feed(bot: DeltaBot, f: sqlite3.Row) -> None: fchats = db.get_fchats(f['url']) if not fchats: db.remove_feed(f['url']) return bot.logger.debug('Checking feed: %s', f['url']) d = feedparser.parse(f['url'], etag=f['etag'], modified=f['modified']) bozo_exception = d.get('bozo_exception', '') if d.get('bozo') == 1 and not isinstance(bozo_exception, CharacterEncodingOverride): bot.logger.exception(bozo_exception) return if d.entries and f['latest']: d.entries = get_new_entries(d.entries, tuple(map(int, f['latest'].split()))) if not d.entries: return html = format_entries(d.entries[:50]) replies = Replies(bot, logger=bot.logger) for gid in fchats: try: replies.add(html=html, chat=bot.get_chat(gid)) except (ValueError, AttributeError): db.remove_fchat(gid) replies.send_reply_messages() latest = get_latest_date(d.entries) or f['latest'] modified = d.get('modified') or d.get('updated') db.update_feed(f['url'], d.get('etag'), modified, latest)
def wf_unbridge(message: Message, replies: Replies) -> None: """Remove bridge with the WriteFreely blog in the chat it is sent. Example: `/wf_unbridge` """ db.del_chat(message.chat.id) replies.add(text='✔️Removed bridge.')
def filter_messages(bot: DeltaBot, message: Message, replies: Replies) -> None: """Detect messages like +1 or -1 to increase/decrease score. """ if not message.quote: return score = _parse(message.text) if not score: return sender = message.get_sender_contact().addr is_admin = bot.is_admin(sender) if score < 0 and not is_admin: return if not is_admin and db.get_score(sender) - score < 0: replies.add(text="❌ You can't give what you don't have...", quote=message) return receiver = message.quote.get_sender_contact().addr if sender == receiver: return sender_score = _add_score(sender, -score) receiver_score = _add_score(receiver, score) if is_admin: text = '{0}: {1}{4}' else: text = '{0}: {1}{4}\n{2}: {3}{4}' text = text.format( bot.get_contact(receiver).name, receiver_score, bot.get_contact(sender).name, sender_score, _getdefault(bot, 'score_badge')) replies.add(text=text, quote=message)
def c4_play(bot: DeltaBot, payload: str, message: Message, replies: Replies) -> None: """Invite a friend to play Connect4. Example: `/c4_play [email protected]` """ if not payload: replies.add(text="Missing address") return if payload == bot.self_contact.addr: replies.add(text="Sorry, I don't want to play") return p1 = message.get_sender_contact().addr p2 = payload if p1 == p2: replies.add(text="You can't play with yourself") return g = db.get_game_by_players(p1, p2) if g is None: # first time playing with p2 chat = bot.create_group( '4️⃣ {} 🆚 {} [c4]'.format(p1, p2), [p1, p2]) b = Board() db.add_game(p1, p2, chat.id, b.export(), p1) text = 'Hello {1},\nYou have been invited by {0} to play Connect4' text += '\n\n{2}: {0}\n{3}: {1}\n\n' text = text.format( p1, p2, b.get_disc(BLACK), b.get_disc(WHITE)) replies.add(text=text + _run_turn(chat.id), chat=chat) else: text = 'You already have a game group with {}'.format(p2) replies.add(text=text, chat=bot.get_chat(g['gid']))
def chatter_learn(payload: str, replies: Replies) -> None: """Learn new response. You must provide two lines, the first line is the question and the second line is the response. """ LIST_TRAINER.train(payload.split('\n', maxsplit=1)) replies.add(text='✔️Learned.')
def web(bot: DeltaBot, payload: str, message: Message, replies: Replies) -> None: """Download a webpage or file.""" mode = _get_mode(bot, message.get_sender_contact().addr) try: replies.add(**_download_file(bot, payload, mode)) except FileTooBig as err: replies.add(text=str(err))
def topic(message: Message, replies: Replies) -> None: """Show IRC channel topic. """ chan = db.get_channel_by_gid(message.chat.id) if not chan: replies.add(text='This is not an IRC channel') else: replies.add(text='Topic:\n{}'.format(irc_bridge.get_topic(chan)))
def img(bot: DeltaBot, payload: str, replies: Replies) -> None: """Search for images, returns image links. """ text = '\n\n'.join(_get_images(bot, payload)) if text: replies.add(text='{}:\n\n{}'.format(payload, text)) else: replies.add(text='No results for: {}'.format(payload))
def cmd_read(bot: DeltaBot, payload: str, message: Message, replies: Replies) -> None: """Download a webpage and try to improve its readability.""" mode = _get_mode(bot, message.get_sender_contact().addr) try: replies.add(**_download_file(bot, payload, mode, True)) except FileTooBig as err: replies.add(text=str(err))
def _roll_dice(count: int, quote: Message, replies: Replies) -> None: dices = [] total = 0 for _ in range(count): rand = random.randrange(0, 6) total += rand + 1 dices.append(DICES[rand]) replies.add(text="{} ({})".format(" ".join(dices), total), quote=quote)
def wttr(bot: DeltaBot, payload: str, message: Message, replies: Replies) -> None: """Search weather info from wttr.in""" lang = _get_locale(bot, message.get_sender_contact().addr) url = 'https://wttr.in/{}_Fnp_lang={}.png'.format(quote(payload), lang) reply = _download_file(bot, url) reply.pop('text') replies.add(**reply)
def img1(bot: DeltaBot, payload: str, replies: Replies) -> None: """Get an image based on the given text. """ imgs = _download_images(bot, payload, 1) if not imgs: replies.add(text='No results for: {}'.format(payload)) else: for reply in imgs: replies.add(**reply)
def friends_leave(message: Message, replies: Replies) -> None: """Remove you from the list. """ addr = message.get_sender_contact().addr if db.get_bio(addr) is None: replies.add(text='You are not in the list yet') else: db.remove_user(addr) replies.add(text='You were removed from the list')
def img5(bot: DeltaBot, payload: str, replies: Replies) -> None: """Search for images, returns 5 results. """ imgs = _download_images(bot, payload, 5) if not imgs: replies.add(text='No results for: {}'.format(payload)) else: for reply in imgs: replies.add(**reply)
def corpse_leave(bot: DeltaBot, message: Message, replies: Replies) -> None: """Leave Exquisite Corpse game in current group. Example: `/corpse_leave` """ p = db.get_player_by_addr(message.get_sender_contact().addr) if p: _remove_from_game(bot, p, db.get_game_by_gid(p['game'])) else: replies.add(text='❌ You are not playing Exquisite Corpse.')
def translate_filter(bot: DeltaBot, message: Message, replies: Replies) -> None: """Send me in private any text message to translate it.""" if not message.chat.is_group() and message.text: lang = _get_language(bot, message.get_sender_contact().addr) if lang in langs.values(): text = _translate("auto", lang, message.text, bot) else: text = (f"❌ Invalid language code: {lang!r}." " Send /tr to see the list of available codes.") replies.add(text=text, quote=message)
def xkcd_get(payload: str, message: Message, replies: Replies) -> None: """Get the comic with the given number or a ramdom comic if no number is provided.""" if not payload: comic = xkcd.getRandomComic() elif payload.isdigit(): comic = xkcd.getComic(int(payload)) else: comic = None if comic is None or comic.number == -1: replies.add(text="❌ Invalid comic number", quote=message) else: replies.add(**_get_reply(comic))
def group_adminchan(bot: DeltaBot, args: list, message: Message, replies: Replies) -> None: """Join the admin group of the given channel. """ ch = db.get_channel_by_id(int(args[0])) if ch: sender = message.get_sender_contact() _add_contact(bot.get_chat(ch['admin']), sender) text = '{}\n\n{}'.format(ch['name'], ch['topic'] or '-') replies.add(text=text, chat=bot.get_chat(sender)) else: replies.add(text='❌ Invalid ID')
def filter_messages(bot: DeltaBot, message: Message, replies: Replies) -> None: """Detect messages like +1 or -1 to increase/decrease score.""" if message.quote: receiver_addr = message.quote.get_sender_contact().addr score = _parse(message.text) else: args = message.text.split(maxsplit=2) if len(args) == 2 and "@" in args[0]: receiver_addr = args[0] score = _parse(args[1]) else: score = 0 if not score: return sender_addr = message.get_sender_contact().addr is_admin = bot.is_admin(sender_addr) if (score < 0 and not is_admin) or sender_addr == receiver_addr: return with session_scope() as session: sender = session.query(User).filter_by(addr=sender_addr).first() if not sender: sender = User(addr=sender_addr) session.add(sender) if not is_admin and sender.score - score < 0: replies.add(text="❌ You can't give what you don't have...", quote=message) return if not is_admin: sender.score -= score sender_score = sender.score receiver = session.query(User).filter_by(addr=receiver_addr).first() if not receiver: receiver = User(addr=receiver_addr) session.add(receiver) receiver.score += score receiver_score = receiver.score if is_admin: text = "{0}: {1}{4}" else: text = "{0}: {1}{4}\n{2}: {3}{4}" text = text.format( bot.get_contact(receiver_addr).name, receiver_score, bot.get_contact(sender_addr).name, sender_score, _getdefault(bot, "score_badge"), ) replies.add(text=text, quote=message)
def poll_list(message: Message, replies: Replies) -> None: """Show your public polls.""" with session_scope() as session: text = "" for poll in (session.query(Poll).filter_by( addr=message.get_sender_contact().addr).all()): if len(poll.question) > 100: q = poll.question[:100] + "..." else: q = poll.question text += "📊 /poll_get_{} {}\n\n".format(poll.id, q) replies.add(text=text or "❌ Empty list", chat=message.get_sender_chat())
def feed_sub(bot: DeltaBot, payload: str, message: Message, replies: Replies) -> None: """Subscribe current chat to the given feed. """ url = db.normalize_url(payload) feed = db.get_feed(url) if feed: d = feedparser.parse(feed['url']) else: max_fc = int(_getdefault(bot, 'max_feed_count')) if 0 <= max_fc <= len(db.get_feeds()): replies.add(text='Sorry, maximum number of feeds reached') return d = feedparser.parse(url) bozo_exception = d.get('bozo_exception', '') if (d.get('bozo') == 1 and not isinstance( bozo_exception, CharacterEncodingOverride)) or not d.entries: replies.add(text='Invalid feed url: {}'.format(url)) bot.logger.warning('Invalid feed %s: %s', url, bozo_exception) return feed = dict( url=url, etag=d.get('etag'), modified=d.get('modified') or d.get('updated'), latest=get_latest_date(d.entries), ) db.add_feed(url, feed['etag'], feed['modified'], feed['latest']) assert feed if message.chat.is_group(): chat = message.chat else: chat = bot.create_group( d.feed.get('title') or url, [message.get_sender_contact()]) if chat.id in db.get_fchats(feed['url']): replies.add(text='Chat alredy subscribed to that feed.', chat=chat) return db.add_fchat(chat.id, feed['url']) title = d.feed.get('title') or '-' desc = d.feed.get('description') or '-' text = 'Title: {}\n\nURL: {}\n\nDescription: {}'.format( title, feed['url'], desc) if d.entries and feed['latest']: latest = tuple(map(int, feed['latest'].split())) html = format_entries(get_old_entries(d.entries, latest)[:5]) replies.add(text=text, html=html, chat=chat) else: replies.add(text=text, chat=chat)