from asyncio import new_event_loop from datetime import timedelta from os import environ from typing import Optional, Union from disnake import Client, Guild, Member from dotenv import load_dotenv from ics import Calendar, Event # type: ignore from ics.alarm.display import DisplayAlarm # type: ignore from quart import Quart, abort from sentry_sdk import init from sentry_sdk.integrations.quart import QuartIntegration load_dotenv() DISCORD_TOKEN = environ.get("DISCORD_TOKEN") if not DISCORD_TOKEN: raise Exception("Missing DISCORD_TOKEN env") SENTRY_DSN = environ.get("SENTRY_DSN") if SENTRY_DSN: init(SENTRY_DSN, integrations=[QuartIntegration()]) class Discord(Client): async def on_ready(self): print(f"Logged on as {self.user}!") client = Discord() app = Quart(__name__) def get_guild_by_id(guild_id: Union[int, str]) -> Optional[Guild]: for guild in client.guilds: if guild.id == int(guild_id) or guild.vanity_url_code == str(guild_id): return guild return None def get_bot_member(guild: Guild) -> Optional[Member]: for member in guild.members: if member.id == client.user.id: return member return None async def get_guild_tag(member: Member) -> Optional[str]: if member.guild_permissions.manage_guild: if member.guild.vanity_url_code: return member.guild.vanity_url_code else: invites = await member.guild.invites() return invites[0].code return None @app.route("/.ics") async def index(guild_id): guild = get_guild_by_id(guild_id) if guild is None: abort(404) bot = get_bot_member(guild) guild_tag = await get_guild_tag(bot) calendar = Calendar() for scheduled_event in guild.scheduled_events: event = Event() event.name = scheduled_event.name event.begin = scheduled_event.scheduled_start_time event.end = scheduled_event.scheduled_end_time event.uid = str(scheduled_event.id) event.description = scheduled_event.description event.location = ( scheduled_event.entity_metadata.location if scheduled_event.entity_metadata else None ) if guild_tag: event.url = f"https://discord.gg/{guild_tag}?event={scheduled_event.id}" alarm = DisplayAlarm() alarm.trigger = timedelta(hours=1) event.alarms.append(alarm) calendar.events.add(event) return str(calendar) loop = new_event_loop() discord_task = loop.create_task(client.start(DISCORD_TOKEN)) discord_task.add_done_callback(lambda f: loop.stop()) quart_task = loop.create_task(app.run_task()) quart_task.add_done_callback(lambda f: loop.stop()) loop.run_forever()