async def deadline(ctx, timezone='America/New_York'): await ctx.message.add_reaction('⌚') sbdb = db.SpoilerBotDatabase(loop) await sbdb.connect() deadline = await sbdb.get_current_deadline() if deadline == None: await ctx.send('No deadline current exists.') await ctx.message.add_reaction('👎') await ctx.message.remove_reaction('⌚', ctx.bot.user) now = datetime.utcnow().replace(tzinfo=tz.tzutc()) end = deadline['end'].replace(tzinfo=tz.tzutc()) diff = relativedelta(end, now) await ctx.send(deadline['message'].format( time=end.astimezone( tz.gettz(timezone)).strftime('%b %d %Y at %I:%M:%S %p %Z'), remain= '{days} days, {hours} hours, {minutes} minutes, and {seconds} seconds to go' .format( days=diff.days, hours=diff.hours, minutes=diff.minutes, seconds=diff.seconds, ), )) await ctx.message.add_reaction('👍') await ctx.message.remove_reaction('⌚', ctx.bot.user)
async def generate_verification_key(loop): for a in range(10): key = ''.join(random.choices(string.ascii_uppercase, k=4)) sbdb = db.SpoilerBotDatabase(loop) await sbdb.connect() flattened = [] if await sbdb.get_verification_key(key) == None: await sbdb.record_verification_key(key) await sbdb.close() return key sbdb.close() raise RuntimeError('Verification key generation failed.')
async def resend(ctx, loop, ircbot, channel): if channel == None: await ctx.message.add_reaction('👎') await ctx.send('{author}, you need to specify a channel.'.format( author=ctx.author.mention)) return if re.search('^#srl-[a-z0-9]{5}$', channel): raceid = channel.partition('-')[-1] else: await ctx.message.add_reaction('👎') await ctx.send( '{author}, that doesn\'t look like an SRL race room.'.format( author=ctx.author.mention)) return # figure out if this game has already been generated sbdb = db.SpoilerBotDatabase(loop) await sbdb.connect() racedata = await sbdb.get_bracket_race(raceid) await sbdb.close() if racedata == None: await ctx.message.add_reaction('👎') await ctx.send( '{author}, `$bracketrace` has not yet been ran for this race.'. format(author=ctx.author.mention)) return ircbot.send('JOIN', channel=channel) hash = racedata['hash'] title = racedata['title'] seed = await pyz3r_asyncio.create_seed( randomizer='item', baseurl=config['alttpr_website']['baseurl'], seed_baseurl=config['alttpr_website']['baseurl_seed'], hash=hash) msg = await generate_bracket_dm( seed=seed, players=title, channel=channel, ) dm = ctx.author.dm_channel if dm == None: dm = await ctx.author.create_dm() await dm.send(msg) await ctx.message.add_reaction('👍')
async def spoilerseed(channel, author, ircbot, loop): if channel == '#speedrunslive': return # ignore private messages if channel == config['srl_irc_nickname']: return if re.search('^#srl-[a-z0-9]{5}$', channel): raceid = channel.partition('-')[-1] else: return sbdb = db.SpoilerBotDatabase(loop) await sbdb.connect() racedata = await sbdb.get_bracket_race(raceid) await sbdb.close() if racedata == None: ircbot.send( 'PRIVMSG', target=channel, message= 'This race is not yet registered with SpoilerTourneyBot. Please run $bracketrace command in discord.' ) return hash = racedata['hash'] seed = await pyz3r_asyncio.create_seed( randomizer='item', baseurl=config['alttpr_website']['baseurl'], seed_baseurl=config['alttpr_website']['baseurl_seed'], hash=hash) ircbot.send('PRIVMSG', target=channel, message='Seed: {permalink} - {code}'.format( permalink=await seed.url(), code=' | '.join(await seed.code())))
async def bracketrace(ctx, loop, ircbot, arg1=None, arg2=None, mode='open', nosrl=False, skirmish=False): if nosrl == False: if arg1 == None: await ctx.message.add_reaction('👎') await ctx.send('{author}, you need the SG episode id.'.format( author=ctx.author.mention)) return if arg2 == None: await ctx.message.add_reaction('👎') await ctx.send('{author}, you need the srl room specified.'.format( author=ctx.author.mention)) return if re.search('^#srl-[a-z0-9]{5}$', arg2): raceid = arg2.partition('-')[-1] channel = arg2 else: await ctx.message.add_reaction('👎') await ctx.send( '{author}, that doesn\'t look like an SRL race room.'.format( author=ctx.author.mention)) return if not await srl.is_race_open(raceid): await ctx.message.add_reaction('👎') await ctx.send( '{author}, that race does not exist or is not in an "Entry Open" state.' .format(author=ctx.author.mention)) return # figure out if this game has already been generated sbdb = db.SpoilerBotDatabase(loop) await sbdb.connect() racedata = await sbdb.get_bracket_race(raceid) await sbdb.close() if not racedata == None: await ctx.message.add_reaction('👎') await ctx.send( '{author}, game data was already generated for that SRL room, try using `$resend #srl-12345` where `#srl-12345` is the SRL channel name to resend seed information and have the bot join the room.' .format(author=ctx.author.mention)) return else: if arg1 == None: await ctx.message.add_reaction('👎') await ctx.send( '{author}, you the race id.'.format(author=ctx.author.mention)) return raceid = 'nosrl' + ''.join( random.choices(string.ascii_letters + string.digits, k=6)) channel = '' if skirmish == False: sg_episode_id = arg1 sge = await sg.find_episode(sg_episode_id) participants = await sge.get_participants_discord() players = await sge.get_player_names() participants.append(ctx.author.name + '#' + ctx.author.discriminator) #filter out duplicates participants = list(set(participants)) if participants == False: await ctx.message.add_reaction('👎') await ctx.send( '{author}, that episode doesn\'t appear to exist.'.format( author=ctx.author.mention)) return title = ' vs. '.join(players) else: title = arg1 sg_episode_id = 0 if mode == 'inverted': seed = await pyz3r_asyncio.create_seed( randomizer='item', # optional, defaults to item baseurl=config['alttpr_website']['baseurl'], seed_baseurl=config['alttpr_website']['baseurl_seed'], settings={ "difficulty": "normal", "enemizer": False, "logic": "NoGlitches", "mode": "inverted", "tournament": True, "variation": "none", "weapons": "randomized", "lang": "en" }) elif mode == 'nologic': seed = await pyz3r_asyncio.create_seed( randomizer='item', # optional, defaults to item baseurl=config['alttpr_website']['baseurl'], seed_baseurl=config['alttpr_website']['baseurl_seed'], settings={ "difficulty": "normal", "enemizer": False, "logic": "None", "mode": "open", "tournament": True, "variation": "none", "weapons": "randomized", "lang": "en" }) elif mode == 'nologickeys': seed = await pyz3r_asyncio.create_seed( randomizer='item', # optional, defaults to item baseurl=config['alttpr_website']['baseurl'], seed_baseurl=config['alttpr_website']['baseurl_seed'], settings={ "difficulty": "normal", "enemizer": False, "logic": "None", "mode": "open", "tournament": True, "variation": "key-sanity", "weapons": "randomized", "lang": "en" }) else: seed = await pyz3r_asyncio.create_seed( randomizer='item', # optional, defaults to item baseurl=config['alttpr_website']['baseurl'], seed_baseurl=config['alttpr_website']['baseurl_seed'], settings={ "difficulty": "normal", "enemizer": False, "logic": "NoGlitches", "mode": "open", "tournament": True, "variation": "none", "weapons": "randomized", "lang": "en" }) rdb = db.RandomizerDatabase(loop) await rdb.connect() spoiler_log = await rdb.get_seed_spoiler(seed.hash) await rdb.close() spoiler_log_url = await helpers.write_json_to_disk(spoiler_log['spoiler'], seed) modlogchannel = ctx.guild.get_channel(config['log_channel'][ctx.guild.id]) msg = 'Race {title}:\n\n' \ 'SRL Channel: {srlchannel}\n' \ 'Permalink: {permalink}\n' \ 'Spoiler log: {spoilerlog}'.format( title=title, srlchannel=channel, permalink=await seed.url(), spoilerlog=spoiler_log_url ) await modlogchannel.send(msg) spdb = db.SpoilerBotDatabase(loop) await spdb.connect() await spdb.record_bracket_race( sg_episode_id=sg_episode_id, srl_race_id=raceid, hash=seed.hash, title=title, permalink=await seed.url(), spoiler_url=spoiler_log_url, initiated_by=ctx.author.name + '#' + ctx.author.discriminator, ) await spdb.close() if skirmish == True: msg = await generate_skirmish_msg( seed=seed, title=title, channel=channel, ) await ctx.send(msg) else: msg = await generate_bracket_dm( seed=seed, title=title, channel=channel, ) for user in participants: u = ctx.guild.get_member_named(user) if u == None: await modlogchannel.send( 'Unable to find {user} for DM.'.format(user=user, )) pass else: dm = u.dm_channel if dm == None: dm = await u.create_dm() await dm.send(msg) if nosrl == False: ircbot.send('JOIN', channel=channel) await ctx.message.add_reaction('👍')
async def qualifier_cmd(ctx, arg1, logger, loop): tz = timezone('US/Eastern') logger.info( 'Qualifier Requested - {servername} - {channelname} - {player} - {seednum}' .format( servername=ctx.guild.name, channelname=ctx.channel.name, player=ctx.author, seednum=arg1, )) # if helpers.check_cmd_filter(ctx.guild.id,ctx.channel.name,'qualifier',config): # return try: seednum = int(arg1) except ValueError: await ctx.message.add_reaction('👎') await ctx.send( '{author}, that is not a number.'.format(author=ctx.author.mention) ) return spdb = db.SpoilerBotDatabase(loop) await spdb.connect() qualifier_seed = await spdb.get_qualifier_seed(seednum) await spdb.close() if qualifier_seed == None: await ctx.message.add_reaction('👎') await ctx.send('{author}, that seed does not exist.'.format( author=ctx.author.mention)) return seed = await pyz3r_asyncio.create_seed( randomizer='item', baseurl=config['alttpr_website']['baseurl'], seed_baseurl=config['alttpr_website']['baseurl_seed'], hash=qualifier_seed['hash']) spoilerlog = qualifier_seed['spoilerlog'] verificationkey = await generate_verification_key(loop) permalink = await seed.url() fscode = ' | '.join(await seed.code()) timestamp = str(datetime.now(tz).replace(microsecond=0)) logger.info( 'Qualifier Generated - {servername} - {channelname} - {player} - {seednum} - {verificationkey}' .format(servername=ctx.guild.name, channelname=ctx.channel.name, player=ctx.author, seednum=seednum, verificationkey=verificationkey)) dm = ctx.author.dm_channel if dm == None: dm = await ctx.author.create_dm() await dm.send( 'This is the verification key that is required to be in the first four characters of the filename of your run:\n`{verificationkey}`\n\n' \ 'Seed number: {seednum}\n' \ 'Timestamp: {timestamp}\n' \ 'Permalink: {permalink}\n' \ 'File select code: [{fscode}]\n' \ 'Spoiler log: {spoilerlog}\n\n' \ 'Submit your run here once completed: <{submiturl}>\n\n' \ 'You have 15 minutes from the receipt of this message to start your run!\n' \ '**Please DM an admin immediately if this was requested in error**, otherwise it may be counted as a forfeit (slowest time of all runners of the seed plus 30 minutes).\n\n' \ 'Good luck <:mudora:536293302689857567>'.format( verificationkey=verificationkey, seednum=seednum, timestamp=timestamp, fscode=fscode, permalink=permalink, spoilerlog=spoilerlog, submiturl=config['qualifier_form_prefill'].format( discordtag=urllib.parse.quote_plus(ctx.author.name + '#' + ctx.author.discriminator), verificationkey=verificationkey, seednum=seednum ) ) ) modlogchannel = ctx.guild.get_channel(config['log_channel'][ctx.guild.id]) msg = 'Qualifier request for {player}:\n\n' \ 'Verification Key: {verificationkey}\n' \ 'Seed Number: {seednum}\n' \ 'Timestamp: {timestamp}'.format( player = ctx.author.name + '#' + ctx.author.discriminator, verificationkey=verificationkey, seednum=seednum, timestamp=timestamp, ) await modlogchannel.send(msg) logger.info( 'Qualifier DM Sent - {servername} - {channelname} - {player} - {seednum} - {verificationkey}' .format(servername=ctx.guild.name, channelname=ctx.channel.name, player=ctx.author, seednum=seednum, verificationkey=verificationkey)) agcm = gspread_asyncio.AsyncioGspreadClientManager(helpers.get_creds) agc = await agcm.authorize() wb = await agc.open_by_key(config['gsheet_id']) wks = await wb.get_worksheet(0) await wks.append_row([ timestamp, str(ctx.author), seednum, verificationkey, "=INDEX('Submitted Runs'!E:G,MATCH(INDIRECT(\"R[0]C[-1]\", false),'Submitted Runs'!C:C,0), 1)*3600+INDEX('Submitted Runs'!E:G,MATCH(INDIRECT(\"R[0]C[-1]\", false),'Submitted Runs'!C:C,0), 2)*60+INDEX('Submitted Runs'!E:G,MATCH(INDIRECT(\"R[0]C[-1]\", false),'Submitted Runs'!C:C,0), 3)", "=INDEX('Submitted Runs'!H:H,MATCH(INDIRECT(\"R[0]C[-2]\", false),'Submitted Runs'!C:C,0), 1)", "=INDEX('Submitted Runs'!I:I,MATCH(INDIRECT(\"R[0]C[-3]\", false),'Submitted Runs'!C:C,0), 1)", "=INDEX('Submitted Runs'!J:J,MATCH(INDIRECT(\"R[0]C[-4]\", false),'Submitted Runs'!C:C,0), 1)" ], value_input_option='USER_ENTERED') logger.info( 'Qualifier Recorded in Gsheet - {servername} - {channelname} - {player} - {seednum} - {verificationkey}' .format(servername=ctx.guild.name, channelname=ctx.channel.name, player=ctx.author, seednum=seednum, verificationkey=verificationkey)) await ctx.message.add_reaction('👍')
async def gen_qualifier_seed(ctx, loop, seednum=None): try: seednum = int(seednum) except ValueError: await ctx.message.add_reaction('👎') await ctx.send( '{author}, that is not a number.'.format(author=ctx.author.mention) ) return spdb = db.SpoilerBotDatabase(loop) await spdb.connect() qualifier_seed = await spdb.get_qualifier_seed(seednum) if not qualifier_seed == None: await ctx.message.add_reaction('👎') await ctx.send( '{author}, that seed already exists. It would need to be manually purged from the database first.' .format(author=ctx.author.mention)) await spdb.close() return seed = await pyz3r_asyncio.create_seed( randomizer='item', # optional, defaults to item baseurl=config['alttpr_website']['baseurl'], seed_baseurl=config['alttpr_website']['baseurl_seed'], settings={ "difficulty": "normal", "enemizer": False, "logic": "NoGlitches", "mode": "open", "tournament": True, "variation": "none", "weapons": "randomized", "lang": "en" }) rdb = db.RandomizerDatabase(loop) await rdb.connect() spoiler_log = await rdb.get_seed_spoiler(seed.hash) await rdb.close() spoiler_log_url = await helpers.write_json_to_disk(spoiler_log['spoiler'], seed) await spdb.insert_qualifier_seed( id=seednum, hash=seed.hash, spoilerlog=spoiler_log_url, ) modlogchannel = ctx.guild.get_channel(config['log_channel'][ctx.guild.id]) msg = '-----------------------------------------\n' \ 'Qualifier Seed #{seednum}:\n\n' \ 'Permalink: {permalink}\n' \ 'Code: [{code}]\n' \ 'Spoiler log: {spoilerlog}'.format( seednum=seednum, permalink=await seed.url(), spoilerlog=spoiler_log_url, code=' | '.join(await seed.code()) ) await modlogchannel.send(msg) await ctx.send(msg) await spdb.close() await ctx.message.add_reaction('👍')
async def spoilerstart(channel, author, ircbot, discordbot, loop, immediate=False): # ignore SRL lobby if channel == '#speedrunslive': return # ignore private messages if channel == config['srl_irc_nickname']: return # extract the raceid from the channel name if re.search('^#srl-[a-z0-9]{5}$', channel): raceid = channel.partition('-')[-1] else: return #we should probably raise an exception instead so we're not hiding an error # check to make sure the race is open for entry (not in progress or finished) if not await is_race_open(raceid): ircbot.send('NOTICE', target=channel, author=author, message='This race is not currently open for entry.') return # make sure the bot isn't entered into the race already # If the bot died and was restarted, a tournament admin might need to force the bot out of the channel if not await get_single_player( raceid, player=config['srl_irc_nickname'].lower()) == None: ircbot.send('PRIVMSG', target=channel, message='Bot is already entered into this race.') return # retrieve the seed details based on what we stored in the database when running the $bracketrace or $skirmish commands in discord sbdb = db.SpoilerBotDatabase(loop) await sbdb.connect() racedata = await sbdb.get_bracket_race(raceid) await sbdb.close() if racedata == None: ircbot.send( 'PRIVMSG', target=channel, message= 'This race is not yet registered with SpoilerTourneyBot. Please run $bracketrace command in discord.' ) return # give each part of the racedata a friendly variable name to make things easier to read sg_episode_id = racedata['sg_episode_id'] srl_race_id = racedata['srl_race_id'] hash = racedata['hash'] title = racedata['title'] spoiler_url = racedata['spoiler_url'] initiated_by = racedata['initiated_by'] # retrieve the seed details from the randomizer website seed = await pyz3r_asyncio.create_seed( randomizer='item', baseurl=config['alttpr_website']['baseurl'], seed_baseurl=config['alttpr_website']['baseurl_seed'], hash=hash) await gatekeeper_immediatestart(ircbot=ircbot, discordbot=discordbot, initiated_by_discordtag=initiated_by, sg_episode_id=sg_episode_id, channel=channel, spoilerlogurl=spoiler_url, title=title, seed=seed, raceid=raceid, loop=loop)