async def add(ctx: MrvnCommandContext, status: Option(str, choices=[ OptionChoice("Online", "online"), OptionChoice("Invisible", "invisible"), OptionChoice("Idle", "idle"), OptionChoice("Do Not Disturb", "dnd") ]), activity: Option(str, choices=[ OptionChoice("Playing", "playing"), OptionChoice("Streaming", "streaming"), OptionChoice("Listening", "listening"), OptionChoice("Watching", "watching"), OptionChoice("Competing", "competing") ]), text: ParseUntilEndsOption(str)): if len(await BotStatusEntry.filter()) == ENTRIES_LIMIT: await ctx.respond_embed(Style.ERROR, ctx.translate("bot_status_command_add_limit_reached")) return elif len(text) > 50: await ctx.respond_embed(Style.ERROR, ctx.translate("bot_status_command_add_text_too_long")) return await BotStatusEntry.create(status=status, activity=activity.lower(), text=text) status_update.start_task() await ctx.respond_embed(Style.OK, ctx.translate("bot_status_command_add_status_added"))
async def generate(self, ctx, server: Option(str, 'Guild ID'), user: Option(str, 'User ID')): try: guild = await self.bot.fetch_guild(server) except: await ctx.respond("Guild not found.", ephemeral=True) return messages = [] earliest = datetime.now(timezone.utc) foundOne = True await ctx.defer() while foundOne: foundOne = False for channel in await guild.fetch_channels(): if channel.type == ChannelType.text: try: async for message in channel.history(before=earliest): if str(message.author.id) == user: foundOne = True messages.append(message) if message.created_at < earliest: earliest = message.created_at except Exception as e: print(e) msg = f'Found {len(messages)} messages. Delete all (deletion may find more)?' confirm_view = Confirm(delete_history(messages)) await ctx.respond(msg, ephemeral=True, view=confirm_view)
async def ban(self, ctx, member: Option(Member, 'Ban a member of the server.', required=False), userid: Option(str, 'Ban any user by id.', required=False)): if not ctx.user.guild_permissions.ban_members: await ctx.respond(conf.get_string(ctx.user, 'insufficientUserPermissions'), ephemeral=True) return if not member and not userid: await ctx.respond('Must enter at least one of member or userid.', ephemeral=True) if member: user = member else: user = Object(userid) try: await ctx.guild.ban(user) except NotFound: await ctx.respond(f'User {user.id} could not be found', ephemeral=True) return except Forbidden: log.exception( f'Could not ban {user.id} from server {ctx.guild.id}. Check permissions.' ) await ctx.respond( 'Ban failed due to permissions issue. Do I have the "ban" permission?', ephemeral=True) return await ctx.respond(f'Banned user {user.id}.')
async def make_sprint(self, ctx, delay: Option(int, 'Minutes until the sprint starts.', required=False) = DEFAULT_DELAY, duration: Option(int, 'Sprint duration in minutes', required=False) = DEFAULT_DURATION): start_time = datetime.datetime.now() + datetime.timedelta( minutes=delay) end_time = start_time + datetime.timedelta(minutes=duration) activeSprints[ctx.channel.id] = { 'start': start_time, 'end': end_time, 'members': {} } await delay_function(start_time, send_message, (ctx.channel, 'Starting a ' + str(duration) + '-minute sprint with {mentions}!')) await delay_function(end_time, send_message, ( ctx.channel, 'Sprint has ended, {mentions}, you have 1 minute to submit your final word counts!' )) await delay_function(end_time + datetime.timedelta(minutes=1), end_sprint, [ctx.channel]) view = NewSprintView(delay * 60 + duration * 60, ctx.channel) view.interaction = await ctx.respond( '{0}-minute sprint starting in {1} minutes.'.format( duration, delay), view=view)
async def message_reminder( self, ctx, content: Option(str, 'What should I remind you about?'), time: Option(str, 'A time and/or date in UTC, or a duration from now.')): when_time = parse_time(time) if not when_time: await ctx.respond(f'Unable to parse time string: ' + time, ephemeral=True) return msg = f'Reminder: {content}' reminder_id = save_one_reminder(ctx.user, when_time, msg) await set_reminder(reminder_id, when_time, ctx.user, msg) await ctx.respond( f'I\'ll DM you "{msg}" {friendly_until_string(when_time, True)}.', ephemeral=True)
async def roll_dice(self, ctx, rolls: str, label: Option(str, 'Would you like to label this roll?', required=False)): embed = Embed() command_name, results = roll_command(str(ctx.user.id), rolls) for key, value in results.items(): embed.add_field(name=key, value=value) follow_up = False if label: embed.title = label if not command_name and not any(char.isdigit() for char in label): follow_up = True else: label = rolls if command_name: embed.title = command_name label = command_name msg = ctx.user.mention + ' rolled ' + label + '!' await ctx.respond(msg, embed=embed) if follow_up: suppress_until = userconfig.get_key(ctx.user.id, SUPPRESS_SAVE_CONFIG_KEY) sanitize_suppress_save_config(ctx.user.id, suppress_until) if not suppress_until or suppress_until < datetime.now(): confirmer = Confirm(saver(label, rolls), middle_callback=suppress_autosave, middle_label="Don't show for 24H", cancel_callback=never_show_autosave, cancel_label="Never show this") await ctx.respond(f'Would you like to save {rolls} as {label}?', view=confirmer, ephemeral=True)
async def pick( self, ctx, number: Option(int, 'How many to pick of the given choices.', required=False) = 1, options: Option(str, 'What to pick from. Separated by spaces or commas.', required=False) = None, role: Option( Role, 'Pick a random member that has a given role on this server.', required=False) = None): embed = Embed() if options: if ',' in options: optionset = options.split(',') else: optionset = options.split() embed.set_footer(text='Options were:\n> ' + '\n> '.join(optionset)) elif role: optionset = [member.mention for member in role.members] embed.set_footer( text= f'Randomly selected from all members with the {role.name} role.' ) if role.is_default(): embed.set_footer( text='Randomly selected from all members of this server.') else: await ctx.respond( 'Sorry, you have to give me something to pick from, either options or a role.', ephemeral=True) return if number < 1: await ctx.respond( 'I have chosen nothing. I award you no points, and may the gods have mercy on your soul.', ephemeral=True) return if number > len(optionset): number = len(optionset) embed.insert_field_at(0, name='Chosen:', value='**' + '**\n**'.join(sample(optionset, number)) + '**', inline=False) await ctx.respond('I have chosen!', embed=embed)
async def permathread(self, ctx: ApplicationContext, name: Option(str, "Thread name")): if not isinstance(ctx.channel, TextChannel): await ctx.respond('Must be inside a text channel') return thread: Thread = await ctx.channel.create_thread(name=name, type=ChannelType.public_thread) await self.permathreads.insert_one({'_id': thread.id}) await ctx.respond('Created permathread')
async def choices(ctx, choice_str: Option(str, choices=[ OptionChoice("Choice 1", "Anus"), OptionChoice("Choice 2", "Amogus"), OptionChoice("Choice 3", "Test") ])): await ctx.respond_embed(Style.INFO, f"{choice_str}")
async def submit_words(self, ctx, words: Option(int, 'Your final wordcount.')): if ctx.channel.id in activeSprints: activeSprints[ctx.channel.id]['members'][ ctx.user.mention]['endCount'] = words await ctx.respond('Word count for {0} updated to {1}'.format( ctx.user.mention, words)) else: await ctx.respond('No active sprints.', ephemeral=True)
async def add_notice(self, ctx, title: Option(str, 'Title to find the notice by.'), text: Option(str, 'Content of the notice.')): if ctx.user.guild_permissions.administrator: curr_notices = load_notices(ctx.guild.id) new_notice = { 'text': text, 'created': datetime.utcnow().isoformat() } reply = f'Create notice "{title}"?\n' if title in curr_notices: reply = f'Update notice "{title}"?\n' reply += f'Old content:\n```\n{curr_notices[title]["text"]}\n```\n' new_notice['created'] = curr_notices[title]['created'] reply += f'New content:\n>>> {text}' confirm_view = Confirm(update_notice(title, new_notice)) await ctx.respond(reply, view=confirm_view, ephemeral=True) else: await ctx.respond("Only a server admin can add notices.", ephemeral=True)
async def generate(self, ctx, name: Option(str, 'Which generator?', autocomplete=gen_autocomplete), count: Option(int, 'How many? Default 1.', required=False) = 1, public: Option( bool, 'Should others see output? Default false.', required=False) = False): if name in conf.get_object(ctx.guild, 'generators'): await ctx.respond('\n'.join([ generator.extract_text(generator.generate(name)) for _ in range(count) ]), ephemeral=not public) else: await ctx.respond(f"{name} is not a recognized generator.")
async def read_notice(self, ctx, title: Option(str, 'Read which notice?', autocomplete=notice_autocomplete, required=False)): curr_notices = load_notices(ctx.guild.id) if not title: msg = '>>> ' + get_latest(curr_notices) elif title in curr_notices: msg = '>>> ' + curr_notices[title]['text'] else: msg = f'Notice "{title}" not found. Try using the autocomplete.' await ctx.respond(msg)
async def purge(ctx: MrvnCommandContext, number: Option(int, min_value=1, max_value=200), member: Member = None): try: deleted = await ctx.channel.purge( limit=number, check=lambda msg: member is None or msg.author == member, bulk=True) except Forbidden: await ctx.respond_embed( Style.ERROR, ctx.translate("moderation_bot_insufficient_perms")) else: await ctx.respond_embed( Style.OK, ctx.format("moderation_command_purge_messages_removed", ctx.author.mention, deleted))
async def delete_notice(self, ctx, title: Option(str, 'Delete which notice?', autocomplete=notice_autocomplete)): if ctx.user.guild_permissions.administrator: curr_notices = load_notices(ctx.guild.id) if title in curr_notices: reply = f'Delete notice {title}?\nFormer content was:\n```\n{curr_notices[title]["text"]}\n```' confirm_view = Confirm(remove_notice(title)) await ctx.respond(reply, view=confirm_view, ephemeral=True) else: await ctx.respond(f'Notice "{title}" not found.', ephemeral=True) else: await ctx.respond("Only a server admin can delete notices.", ephemeral=True)
async def search(self, ctx, site_name: Option(str, 'What wiki to search', autocomplete=wikis_autocomplete), query: str): mw_options = conf.get_object(ctx.guild, 'mwSites') if site_name not in mw_options: return await ctx.respond( f'"{site_name}" is not a valid search source on this server.') site = Site(mw_options[site_name]['url'], path=mw_options[site_name]['path'], clients_useragent=USER_AGENT) results = site.search(query) title = results.next().get('title').replace(' ', '_') await ctx.respond(f'First result for "{query}":\n' + str( f'https://{mw_options[site_name]["url"]}{mw_options[site_name]["pagePath"]}{title}' ))
async def join_sprint( self, ctx, words: Option( int, 'Your starting wordcount. Will be subtracted from your total.', required=False) = 0): if ctx.channel.id in activeSprints: activeSprints[ctx.channel.id]['members'][ctx.user.mention] = { 'startCount': words, 'endCount': words } await ctx.respond( 'Added {0} to {1:.0f}-minute sprint starting in {2:.1f} minutes.' .format(ctx.user.mention, *describe_sprint(ctx.channel))) else: await ctx.respond('No active sprints.', ephemeral=True)
async def vision(ctx: MrvnCommandContext, image: Option(Attachment)): if not image.content_type.startswith("image"): await ctx.respond_embed( Style.ERROR, ctx.translate("vision_command_vision_invalid_content_type")) return await ctx.defer() session = aiohttp.ClientSession(timeout=ClientTimeout(20)) try: response = await session.post( SERVICE_URL, data="userlink=%s" % parse.quote(image.url, safe=''), headers={ "Cookie": "textonly=true; imageonly=true; qronly=false", "Content-Type": "application/x-www-form-urlencoded" }) except (aiohttp.ClientConnectionError, asyncio.TimeoutError): await ctx.respond_embed( Style.ERROR, ctx.translate("vision_command_vision_connection_error")) return finally: await session.close() text = await response.text() response.close() soup = BeautifulSoup(text, "html.parser") results = soup.find_all("div", {"class": "success description"}) if not len(results): await ctx.respond_embed(Style.ERROR, ctx.translate("vision_command_vision_fail")) return embed = ctx.get_embed(Style.INFO, results[0].text, ctx.translate("vision_command_vision_title")) embed.set_image(url=image.url) await ctx.respond(embed=embed)
async def mute(ctx: MrvnCommandContext, member: Member, time: int, unit: Option(str, choices=[ OptionChoice("Seconds", "s"), OptionChoice("Minutes", "m"), OptionChoice("Hours", "h"), OptionChoice("Days", "d"), OptionChoice("Weeks", "w"), OptionChoice("Months", "mo"), OptionChoice("Years", "y") ])): if member == runtime.bot.user: await ctx.respond_embed( Style.ERROR, ctx.translate("moderation_cant_do_this_to_bot")) return elif member == ctx.author: await ctx.respond_embed( Style.ERROR, ctx.translate("moderation_cant_do_this_to_self")) return elif member.guild_permissions.administrator: await ctx.respond_embed( Style.ERROR, ctx.translate("moderation_command_mute_cant_mute_administrator")) return elif ctx.author.top_role.position < member.top_role.position or ctx.author.guild_permissions < member.guild_permissions: await ctx.respond_embed( Style.ERROR, ctx.translate("moderation_cant_do_this_to_this_user")) return timestamp = datetime.datetime.utcnow() + datetime.timedelta( 0, time * TIME_DICT[unit]) try: await member.edit(communication_disabled_until=timestamp) except Forbidden: await ctx.respond_embed( Style.ERROR, ctx.translate("moderation_bot_insufficient_perms")) else: await ctx.respond_embed( Style.OK, ctx.format("moderation_command_mute_successful", member.mention))
async def complete(self, ctx, prompt: Option(str, "Text to autocomplete")): base = f'**{discord.utils.escape_markdown(prompt)}**' await ctx.defer() json = { 'prompt': prompt, 'max_tokens': 80, 'temperature': 0.9, } async with self.session.post(URL, headers=HEADERS, json=json) as r: result = await r.json() error = result.get('error') if error: await ctx.send(f"<:pepeLaugh:665663440014147616> {error['message']}") else: final = base + result['choices'][0]['text'] await ctx.send(truncate_string(final))
async def view(self, ctx, target: Option(Member, 'Whose pet?', required=False)): owner = ctx.user if target is not None: owner = target try: my_pet = load_pet(str(owner.id)) except KeyError: if owner == ctx.user: await ctx.respond( "Failed to load your pet. Maybe you don't have one? Try `/summon` to get one now!", ephemeral=True) else: await ctx.respond( f"Failed to load {owner.display_name}'s pet. Maybe they don't have one? They should try /summon!", ephemeral=True) return embed = my_pet.render() view = PetView(my_pet, str(owner.id)) view.interaction = await ctx.respond(f'{owner.mention}\'s pet!', view=view, embed=embed)
async def color(self, ctx: ApplicationContext, hex_code: Option(str, "Hex code")): if not is_hex_color_code(hex_code): await ctx.respond("Invalid hex code. Color format example: 44ff00`" ) # Make sure we have guild space if not (len(ctx.guild.roles) < 250): await ctx.respond('No custom role slots left!') return prefix = self.bot.cfg['color-role-prefix'] color = discord.Colour(int(hex_code, 16)) new_role = await ctx.guild.create_role(name=f'{prefix} #{hex_code}', color=color) user: Member = ctx.author # Unequip old colors for role in ctx.user.roles: if role.name.startswith(prefix): await user.remove_roles(role) # Delete if we're the last owner if len(role.members) < 2: await role.delete() # Give new color try: await user.add_roles(new_role) except Exception as e: await ctx.respond(f'Failed to assign new color: {e}') else: await ctx.respond("✅")
async def show_swatch(self, ctx, color_code: Option( str, 'Hex color string, such as #131071')): swatch = get_swatch(color_code) await ctx.respond('', file=File(swatch, filename=color_code + '.png'))
async def edit(ctx: MrvnCommandContext, key: Option( str, autocomplete=basic_autocomplete(setting_autocomplete)), value: str): await edit_(ctx, key, value, True)
async def lowadm( self, ctx, adm: Option(float, description="Optional ADM Level to flag under.", required=False)): """ Systems with low ADMs. """ if not adm: adm = app_settings.get_low_adm() # @commands.command(pass_context=True) # @message_in_channels(settings.SOV_DISCORD_BOT_CHANNELS) if ctx.channel.id not in settings.SOV_DISCORD_BOT_CHANNELS: return await ctx.respond( f"You do not have permission to use this command here.", ephemeral=True) await ctx.defer() own_ids = settings.DISCORD_BOT_SOV_STRUCTURE_OWNER_IDS include_regions = settings.DISCORD_BOT_ADM_REGIONS include_systems = settings.DISCORD_BOT_ADM_SYSTEMS include_constel = settings.DISCORD_BOT_ADM_CONSTELLATIONS sov_structures = providers.esi.client.Sovereignty.get_sovereignty_structures( ).result() names = {} for s in sov_structures: if s.get('alliance_id') in own_ids: if s.get('vulnerability_occupancy_level'): if s.get('vulnerability_occupancy_level') < adm: names[s.get('solar_system_id')] = { "system_name": s.get('solar_system_id'), "adm": s.get('vulnerability_occupancy_level') } if len(names) == 0: await ctx.respond(f"All above {adm} :ok_hand:") return True systems = [k for k, v in names.items()] constelations = {} for n in systems: system = providers.esi.client.Universe.get_universe_systems_system_id( system_id=n).result() names[n]["system_name"] = system.get("name") names[n]["system_id"] = system.get("system_id") names[n]["constellation_id"] = system.get("constellation_id") if system.get("constellation_id") not in constelations: constelations[system.get("constellation_id")] = {} for c, v in constelations.items(): const = providers.esi.client.Universe.get_universe_constellations_constellation_id( constellation_id=c).result() region = providers.esi.client.Universe.get_universe_regions_region_id( region_id=const.get("region_id")).result() v["region_id"] = const.get("region_id") v["region_name"] = region.get("name") v["constellation_name"] = const.get("name") out_array = {} for k, v in names.items(): out_array[k] = {**v, **constelations[v["constellation_id"]]} output = {} base_str = "**{}** ADM:{}" urls = {} for k, h in sorted(out_array.items(), key=lambda e: e[1]['adm']): show = False if h['region_id'] in include_regions: show = True elif h['constellation_id'] in include_constel: show = True elif h['system_id'] in include_systems: show = True if show: if h['region_name'] not in output: output[h['region_name']] = [] output[h['region_name']].append( base_str.format(h['system_name'], h['adm'])) if h['region_name'].replace(" ", "_") not in urls: urls[h['region_name'].replace(" ", "_")] = [] urls[h['region_name'].replace(" ", "_")].append( h['system_name'].replace(" ", "_")) url = "https://evemaps.dotlan.net/map/{}/{}#adm" if len(output) > 0: embed = Embed(title="Low ADMs!") embed.set_thumbnail( url= "https://avatars3.githubusercontent.com/u/39349660?s=200&v=4") embed.colour = Color.red() embed.description = f"Showing systems with ADMs below {adm}. Due to an ESI bug this data might only update once a day at around 2200-2300 Eve Time. **YMMY**\n[For more info please see this issue](https://github.com/esi/esi-issues/issues/1092)" await ctx.respond(embed=embed) for k, v in output.items(): n = 25 chunks = [ list(v[i * n:(i + 1) * n]) for i in range((len(v) + n - 1) // n) ] for chunk in chunks: await ctx.send("__{}__\n{}".format(k, "\n".join(chunk))) _urls = [] for r, s in urls.items(): _urls.append(url.format(r, ",".join(s))) await ctx.send("\n\n".join(_urls)) else: await ctx.respond(f"No Systems with ADM below {adm}!") return True
async def sov(self, ctx, name_search: Option( str, description="String to search against the sov database.")): """ Sov Details for region/constelation/system/alliance """ if ctx.channel.id not in settings.SOV_DISCORD_BOT_CHANNELS: return await ctx.respond( f"You do not have permission to use this command here.", ephemeral=True) await ctx.defer() name_ids = providers.esi.client.Search.get_search( categories=['constellation', 'solar_system', 'region', 'alliance'], search=name_search).result() hit_ids = { "a": name_ids.get("alliance") or [], "c": name_ids.get("constellation") or [], "s": name_ids.get("solar_system") or [], "r": name_ids.get("region") or [], } for r in hit_ids['r']: constellations = providers.esi.client.Universe.get_universe_regions_region_id( region_id=r).result()["constellations"] for c in constellations: if c not in hit_ids["c"]: hit_ids["c"].append(c) for c in hit_ids['c']: systems = providers.esi.client.Universe.get_universe_constellations_constellation_id( constellation_id=c).result()["systems"] for s in systems: if s not in hit_ids["s"]: hit_ids["s"].append(s) sov_structures = providers.esi.client.Sovereignty.get_sovereignty_structures( ).result() hits = [] names = [] alliances = [] for s in sov_structures: start = s.get('vulnerable_start_time', False) if start: if s.get('solar_system_id') in hit_ids["s"] or s.get( 'alliance_id') in hit_ids["a"]: alliances.append(s.get('alliance_id')) names.append(s.get('solar_system_id')) names.append(s.get('structure_type_id')) hits.append(s) if len(names) == 0: await ctx.respond( ":sad: Nothing found for '{}'".format(name_search)) return True names_alli = {} for a in set(alliances): res = providers.esi.client.Alliance.get_alliances_alliance_id( alliance_id=a).result() names_alli[a] = res.get("ticker") names = providers.esi.client.Universe.post_universe_names( ids=list(set(names))).result() nms = {} for n in names: nms[n.get("id")] = n.get("name") for hit in hits: hit['system_name'] = nms[hit.get('solar_system_id')] if hit.get("structure_type_id") == 32226: hit['structure'] = "TCU" elif hit.get("structure_type_id") == 32458: hit['structure'] = "IHUB" else: hit['structure'] = "¯\\_(ツ)_/¯" hit['alliance_name'] = names_alli[hit.get('alliance_id')] output = [] base_str = "**{}** {} (ADM {})[**{}**] Vulnerable{}" dt_now = pendulum.now(tz="UTC") for h in sorted(hits, key=lambda k: k['vulnerable_start_time']): time = "" time = " for **{}**".format( pendulum.now(tz="UTC").diff_for_humans( h['vulnerable_end_time'], absolute=True)) if h['vulnerable_start_time']: if h['vulnerable_start_time'] > dt_now: time = " in **{}**".format( pendulum.now(tz="UTC").diff_for_humans( h['vulnerable_start_time'], absolute=True)) output.append( base_str.format(h['system_name'], h['structure'], h['vulnerability_occupancy_level'], h['alliance_name'], time)) n = 15 chunks = [ list(output[i * n:(i + 1) * n]) for i in range((len(output) + n - 1) // n) ] overflow = "" if len(output) > 50: overflow = "Only showing first 50..." await ctx.respond("Found {} Sov structures for `{}`\n{}\n".format( len(output), name_search, overflow)) for c in chunks[:5]: await ctx.send("\n".join(c))
# noinspection PyMethodOverriding @staticmethod async def convert(converter, ctx: MrvnCommandContext, argument: str) -> Union[SlashCommand, SlashCommandGroup]: try: command = next(filter(lambda it: it.name == argument, runtime.bot.application_commands)) except StopIteration: raise ArgumentParseException(ctx.translate("std_command_override_command_not_found")) return command async def command_searcher(ctx: AutocompleteContext): return command_names command_option = Option(str, autocomplete=basic_autocomplete(command_searcher)) command_option.converter = CommandConverter() @event_handler() async def startup(): global command_names command_names = set( [cmd.name for cmd in runtime.bot.application_commands if isinstance(cmd, (SlashCommand, SlashCommandGroup))]) @override_group.command(description=Translatable("std_command_override_info_desc")) async def info(ctx: MrvnCommandContext, command: command_option): override = await CommandOverride.get_or_none(guild_id=ctx.guild_id, command_name=command.name)
async def save_macro(self, ctx, name: Option(str, 'Name of the macro. Letters and spaces only.'), rolls: Option(str, 'The dice to roll. Separate with a comma. Modifiers allowed.') ): await ctx.respond(save_command(name, rolls, ctx.user), ephemeral=True)
async def giveaway(ctx, prize: Option(str), winners: Option(int, required=True), duration: Option(str, required=True), url: Option(str) = "", image: Option(str) = ""): if discord.utils.get(bot.get_guild(server).roles, name="Admin") in ctx.author.roles: winners = int(winners) if winners > 1: description = ''' Click the :tada: to be entered into a giveaway! There are %d winners! ''' % winners elif winners == 1: description = ''' Click the :tada: to be entered into a giveaway! There is %d winner! ''' % winners else: await ctx.send(content="ERROR! Must have at least 1 winner!") return days, hours, minutes = [ int(x) if x else 0 for x in re.match( '(?:(\d+)d)?(?:(\d+)h)?(?:(\d+)m)?', duration).groups() ] epoch_time = calendar.timegm(time.gmtime()) duration_in_seconds = (int(days) * 24 * 60 * 60) + ( int(hours) * 60 * 60) + (int(minutes) * 60) if duration_in_seconds < 60: await ctx.send(content="ERROR! Must be at least a minute long!") return giveaway_ends_in_seconds = epoch_time + duration_in_seconds giveaway_ends_in_date = time.strftime( "%b %dth", time.localtime(giveaway_ends_in_seconds)) giveaway_ends_in_time = time.strftime( "%I:%M%p", time.localtime(giveaway_ends_in_seconds)) footer = ''' Giveaway ends on %s at %s. ''' % (giveaway_ends_in_date, giveaway_ends_in_time) url = url if url else "" image = image if image else "" embed = create_embed(title=":partying_face: GIVEAWAY :partying_face:", description=description, color=discord.Color.red(), footer=footer, image=image, author=prize, author_url=url) msg = await ctx.respond(embed=embed) await msg.add_reaction("🎉") giveaway_messages.append(msg) giveaways[prize] = [] await countdown_giveaway(time_in_seconds=duration_in_seconds, giveaway_message=msg, prize=prize, winners_amount=winners) else: await ctx.send( content="You do not have permission to create a giveaway!")
async def weather(self, ctx, location: Option( str, "Location (country, city, address, etc)", required=False)): if not location: result = await self.locations.find_one({'_id': ctx.author.id}) if not result: await ctx.respond('No location specified and no location saved' ) return latitude = result['lat'] longitude = result['long'] address = result['addr'] else: geoloc = self.geolocator.geocode(location) if not geoloc: await ctx.respond('Unknown location') return latitude = geoloc.latitude longitude = geoloc.longitude address = geoloc.address url = "https://data.climacell.co/v4/timelines" querystring = {"apikey": self.api_key} headers = {"Content-Type": "application/json"} payload = { "fields": [ "temperature", "humidity", "windSpeed", "weatherCode", "sunsetTime", "sunriseTime" ], "timesteps": ["1h", "1d"], "location": f"{latitude}, {longitude}" } async with self.session.post(url, json=payload, headers=headers, params=querystring) as r: data = await r.json() sunset = data['data']['timelines'][1]['intervals'][0]['values'][ 'sunsetTime'] sunrise = data['data']['timelines'][1]['intervals'][0]['values'][ 'sunriseTime'] # print(f'sun rises at {arrow.get(sunrise).humanize()}') # TODO: wtf these are wrong? # print(f'sun sets at {arrow.get(sunset).humanize()}') now_field = '' forecast_field = '' num_rows = 4 hour_gap = 2 for i in range(0, num_rows * hour_gap, hour_gap): temp = data['data']['timelines'][0]['intervals'][i]['values'][ 'temperature'] temp_f = self.celsius_to_fahrenheit(temp) weather_code = data['data']['timelines'][0]['intervals'][i][ 'values']['weatherCode'] time = data['data']['timelines'][0]['intervals'][i][ 'startTime'] is_night = sunset < time < sunrise weather_icon = self.get_emote_str_from_weather_code( weather_code, night=is_night) if i == 0: # Now humidity = data['data']['timelines'][0]['intervals'][i][ 'values']['humidity'] wind = data['data']['timelines'][0]['intervals'][i][ 'values']['windSpeed'] * 3.6 now_field = f""" {weather_icon} **{round(temp)}**°C / **{round(temp_f)}**°F 💧 **{humidity}**% 🍃 **{round(wind)}** km/h""" else: hours_from_now = arrow.get(time).humanize() forecast_field += f'{weather_icon} **{round(temp)}**°C / **{round(temp_f)}**°F - {hours_from_now}\n' embed = discord.Embed(color=0x7fffd4) embed.add_field(inline=True, name='Now', value=now_field) embed.add_field(inline=True, name='Forecast', value=forecast_field) embed.set_footer(text=address) await ctx.respond(embed=embed)