#!/usr/bin/env python3 import pymongo import discord import asyncio import threading import logging import parsedatetime import datetime TOKEN = "MjM5NzI3NzQ2Nzk0NzgyNzIw.Cu5BbA.z7bkO3Ncd_L80htVzREHYDsEGNk" VERSION = "v0.1.0" client = pymongo.MongoClient() db = client.vainbot cli = discord.Client() @cli.event async def on_ready(): log.warning("Logged in as " + cli.user.name + " (" + str(cli.user.id) + ")") def cleanup(): log.warning("purging old data from database") now = datetime.datetime.utcnow() db.usercache.remove({ "date": {"$lt": now - datetime.timedelta(minutes=30)} }) db.playwithme.remove({ "end": {"$lt": now} }) async def get_user(id): now = datetime.datetime.utcnow() user = db.usercache.find_one({ "id": id, "date": {"$gt": now - datetime.timedelta(minutes=30)} }) if user: return user user = await cli.get_user_info(id) db.usercache.insert_one({ "id": id, "mention": user.mention, "date": now }) return await get_user(id) async def search_teammates(who, query): cal = parsedatetime.Calendar() if " for " in query or " until " in query: delimit = query.rfind("for") if delimit == -1: delimit = query.rfind("until") startstr = query[:delimit] endstr = query[delimit:] else: startstr = query endstr = "for 30 minutes" start = cal.parseDT(startstr)[0] end = cal.parseDT(endstr, sourceTime=start)[0] db.playwithme.insert_one({ "player": who.id, "start": start, "end": end }) log.info(who.name + " requested a game " + ", ".join([str(d) for d in (start, end)])) players = [] query = { "$or": [ { "start": { "$gt": start, "$lt": end } }, { "end": { "$gt": start, "$lt": end } }, { "start": {"$lt": start}, "end": {"$gt": end} } ] } for teammate in db.playwithme.find(query): mention = (await get_user(teammate["player"]))["mention"] if not mention in players: players += [mention] if len(players) > 1: return ", ".join(players) + " can play together at." else: return "Nobody can play at that time. I will notify you if anyone wants to play between %s and %s. It is now %s." % (start.strftime("%H:%M"), end.strftime("%H:%M"), datetime.datetime.now().strftime("%H:%M")) @cli.event async def on_message(message): msg = message.content.lower() if msg.startswith("?ping"): await cli.send_message(message.channel, "Pong!") if msg.startswith("?about"): await cli.send_message(message.channel, "Vainglory Discord bot " + VERSION + " written & hosted by shutterfly") if msg.startswith("?help"): await cli.send_message(message.channel, "Commands: ?help, ?ping, ?about") await cli.send_message(message.channel, " to find teammates.") await cli.send_message(message.channel, " to cancel.") if msg.startswith("play with me") or msg.startswith("?play"): if msg.startswith("play with me"): when = message.content[len("play with me"):] else: when = message.content[len("?play"):] response = await search_teammates(message.author, when) await cli.send_message(message.channel, response) if msg.startswith("don't play with me") or msg.startswith("dont play with me"): db.playwithme.remove({"player": message.author.id}) await cli.send_message(message.channel, "Canceled all notifications.") # # "play" role Discoid backwards compatibility # if msg.startswith("\\getrole play") or msg.startswith("\\play"): # toggles the "play" role log.info("toggled " + message.author.name + "'s play role") for role in message.author.roles: if role.name == "play": await cli.remove_roles(message.author, role) await cli.send_message(message.channel, "Removed the 'play' role.") return for role in message.server.roles: if role.name == "play": await cli.add_roles(message.author, role) await cli.send_message(message.channel, "Added the 'play' role.") if __name__ == '__main__': logging.basicConfig() log = logging.getLogger() log.setLevel(logging.INFO) threading.Timer(10 * 60, cleanup).start() cli.run(TOKEN)