Last active 1723284561

aly's Avatar aly revised this gist 1723284560. Go to revision

2 files changed, 139 insertions

bot.py(file created)

@@ -0,0 +1,130 @@
1 + from interactions import slash_command, SlashContext, Client, slash_option, OptionType, auto_defer, Embed, check, Task, DateTrigger, listen
2 + from requests import get, post
3 + from datetime import datetime, timedelta, date
4 + from re import findall
5 + from os import environ
6 +
7 + bot = Client(token=environ["BOT_TOKEN"])
8 +
9 + is_recurring = True
10 + owner_username = "alyssile"
11 + officer_role_suffix = "Officer"
12 + # add IDs for guilds you want the bot to register commands in
13 + guilds = [353071720342487040, 1038346577267392582]
14 + role_housel = 1149914848428294315
15 + role_weekly = 1149914607822061599
16 + role_tribal = 1149914662197010522
17 + role_grandc = 1149914810486632488
18 + role_jumboc = 1149929534129459290
19 + role_fashio = 1212403886263115786
20 + # role_testing = 873495029883236392 # TODO
21 +
22 + async def check_officer(ctx: SlashContext):
23 + return ctx.author.username == owner_username or any(role.name[-len(officer_role_suffix):] == officer_role_suffix for role in ctx.author.roles)
24 +
25 + #@slash_command(name="xivtimers", description="Show current timers", scopes=guilds)
26 + #@slash_option(name="clear", description="Clears the previous message from the channel", required=False, opt_type=OptionType.BOOLEAN)
27 + #@slash_option(name="recur", description="Sets up the command to refresh the embed automatically each time one of the timers expires", required=False, opt_type=OptionType.BOOLEAN)
28 + #@check(check=check_officer)
29 + #@auto_defer()
30 + #async def xivtimers_cmd(ctx: SlashContext, clear: bool=False, recur: bool=False):
31 + # global is_recurring
32 + # if is_recurring:
33 + # await ctx.send(f"There's already a recurring channel update task running... check with {owner_username}", delete_after=10, ephemeral=True)
34 + # return
35 + # await xivtimers(ctx.channel_id, clear, recur)
36 +
37 + async def xivtimers(channel_id, clear: bool=False, recur: bool=False, mention: str=""):
38 + global is_recurring
39 + channel = bot.get_channel(channel_id)
40 + now = datetime.now()
41 + data = get("https://www.xenoveritas.org/static/ffxiv/timers.json").json()
42 + embed = Embed(title="Timers", color="#eb144c")
43 + timers = {}
44 + maintenance = False
45 + #print('data["timers"]', data["timers"])
46 + for timer in data["timers"]:
47 + if not any(label in timer for label in ["start", "end", "end_label"]):
48 + print(timer)
49 + continue
50 + if timer.get('end',0) and (now-timedelta(hours=6)).timestamp() > int(timer.get('end',0)/1000):
51 + continue
52 + end_label = timer.get("endLabel", f"<t:{int(timer.get('end',0)/1000)}:R>")
53 + ts = datetime.fromtimestamp(int(timer.get('start',0)/1000))
54 + if "<a href=" in timer["name"]:
55 + name = timer["name"].split('">')[1].split("<")[0]
56 + else:
57 + name = timer["name"]
58 + if "all worlds maintenance" in name.lower() and now > ts and now < datetime.fromtimestamp(int(timer.get('end',0)/1000)):
59 + maintenance = True
60 + timers["Maintenance complete"] = datetime.fromtimestamp(int(timer.get('end',0)/1000))
61 + if now < ts:
62 + timers[name] = ts
63 + embed.add_field(name=name, value=f"Start{'s' if now.timestamp() < int(timer.get('start',0)/1000) else 'ed'} <t:{int(timer.get('start',0)/1000)}:R>, {'runs' if 'endLabel' in timer else 'ends'} {end_label}")
64 +
65 + if maintenance:
66 + embed.title = "Timers (Maintenance)"
67 +
68 + def generate_field(name: str, hour: int, role: int=None, day: int=None):
69 + nonlocal timers, now
70 + if (day is not None and now.weekday() == day) and now.hour >= hour:
71 + _now = now + timedelta(1)
72 + elif now.hour >= hour:
73 + _now = now + timedelta(1)
74 + else:
75 + _now = now
76 + reset = datetime.combine(_now, datetime.min.time())+timedelta(hours=hour)
77 + if day is not None:
78 + reset += timedelta((day-_now.weekday())%7)
79 + timers[f"<@&{role}>"] = reset
80 + return {"name": name, "value": f"<t:{int(reset.timestamp())}:R>", "inline": True}
81 +
82 + # embed.add_field(name="Patch 6.5", value=f"<t:{int(datetime(2023,10,3,19,00).timestamp())}:R>")
83 +
84 + if not maintenance:
85 + housing_start_date = datetime(2022,5,27,1,0)
86 + if now.hour >= 1:
87 + _now = now+timedelta(1)
88 + else:
89 + _now = now
90 + mod = (_now - housing_start_date).days % 9
91 + house_reset = datetime.combine(_now, datetime.min.time())+timedelta(abs(mod-5 if mod <= 5 else mod-9))+timedelta(hours=1)
92 + timers[f"<@&{role_housel}>"] = house_reset
93 + embed.add_field(name="Housing " + ("Results ending" if mod > 5 else "Lottery ending"), value=f"<t:{int(house_reset.timestamp())}:R>", inline=True)
94 +
95 + embed.add_field(**generate_field("Weekly Reset", 19, day=1, role=role_weekly))
96 + embed.add_field(**generate_field("Fashion Report Judging", 19, day=4, role=role_fashio))
97 + embed.add_field(**generate_field("Tribal/Duty Reset", 1, role=role_tribal))
98 + embed.add_field(**generate_field("Grand Company Reset", 6, role=role_grandc))
99 + embed.add_field(**generate_field("Jumbo Cactpot", 19, day=5, role=role_jumboc))
100 +
101 + #print("\n".join(f"{t:%Y/%m/%d %H:%M:%S}" for t in timers.values()))
102 +
103 + async for message in channel.history(limit=2 if not is_recurring else 1):
104 + print(message)
105 + if message.author == bot.user.id:
106 + await message.delete()
107 +
108 + # timers[f"<@&{role_testing}>"] = datetime.now()+timedelta(seconds=20) # TODO
109 +
110 + _mention = mention
111 + mention, earliest = min(timers.items(), key=lambda x: x[1])
112 + embed.add_field(name="Refreshing", value=f"<t:{int(earliest.timestamp())}:R>", inline=True)
113 +
114 + await channel.send(content=_mention, embed=embed)
115 +
116 + print(f"Setting up timer at {earliest:%Y/%m/%d %H:%M:%S} in {channel_id}")
117 + @Task.create(DateTrigger(earliest))
118 + async def recurring():
119 + await xivtimers(channel_id, clear, recur, mention=mention)
120 + recurring.start()
121 +
122 + @listen()
123 + async def on_startup():
124 + print("Bot started")
125 + await xivtimers(1063529561486270494, True, True)
126 + await (bot.get_channel("1127730623818256384")).send("xivtimers restarted")
127 + # channel = bot.get_channel("1127730623818256384")
128 + # await channel.send("Bot restarted, please run `/xivtimers clear:True recur:True` in <#1063529561486270494> (<@133057442425602048>)")
129 +
130 + bot.start()

docker-compose.yml(file created)

@@ -0,0 +1,9 @@
1 + services:
2 + bot:
3 + image: ghcr.io/alyssadev/python-discord-bot:latest
4 + environment:
5 + - BOT_TOKEN=
6 + volumes:
7 + - .:/usr/src/app
8 + - /etc/localtime:/etc/localtime:ro
9 + restart: always
Newer Older