[Added] Spielverabredungen für Tabletop Sachsen
This commit is contained in:
parent
85207037ba
commit
b9703ce354
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,4 +1,5 @@
|
||||
.env
|
||||
.venv
|
||||
**/fregbot-birthday.log
|
||||
**/*.log
|
||||
.idea/**
|
||||
uv.lock
|
||||
@ -9,6 +9,10 @@ dependencies = [
|
||||
"discord.py",
|
||||
"pydantic",
|
||||
]
|
||||
[project.optional-dependencies]
|
||||
spielverabredungen = [
|
||||
"click",
|
||||
]
|
||||
|
||||
[tool.setuptools_scm]
|
||||
|
||||
|
||||
123
src/spielverabredungen.py
Normal file
123
src/spielverabredungen.py
Normal file
@ -0,0 +1,123 @@
|
||||
import asyncio
|
||||
import datetime
|
||||
import locale
|
||||
import logging
|
||||
from datetime import timedelta
|
||||
from typing import Iterable
|
||||
|
||||
import click
|
||||
import discord
|
||||
from discord import Client, ForumChannel
|
||||
from pydantic import BaseModel, PositiveInt
|
||||
|
||||
|
||||
class SpielverabredungenConfig(BaseModel):
|
||||
guild_id: int
|
||||
channel_id: int
|
||||
start: datetime.datetime
|
||||
end: datetime.datetime
|
||||
go_back_threads_days: PositiveInt
|
||||
|
||||
@property
|
||||
def dates(self) -> Iterable[datetime.date]:
|
||||
start, end = self.start.date(), self.end.date()
|
||||
assert start <= end, f'Start date {self.start} must be smaller than end date {self.end}'
|
||||
curr_date = start
|
||||
while curr_date <= end:
|
||||
yield curr_date
|
||||
curr_date += timedelta(days=1)
|
||||
|
||||
|
||||
class SpielverabredungenClient(Client):
|
||||
config_object: SpielverabredungenConfig = None
|
||||
|
||||
def __get_channel(self) -> ForumChannel:
|
||||
guild = self.get_guild(self.config_object.guild_id)
|
||||
assert guild, f'Guild with ID {self.config_object.guild_id} not found'
|
||||
channel = discord.utils.get(guild.channels, id=self.config_object.channel_id)
|
||||
assert channel, f'Channel with ID {self.config_object.channel_id} not found in guild {self.config_object.guild_id}'
|
||||
assert isinstance(channel,
|
||||
ForumChannel), f'Channel with ID {self.config_object.channel_id} is not a forum channel'
|
||||
return channel
|
||||
|
||||
def __check_duplicate_channels(self, channel: ForumChannel, dates: Iterable[datetime.date],
|
||||
thread_lookback_days: int) -> Iterable[datetime.date]:
|
||||
skipped_dates = 0
|
||||
potential_threadnames = {self.__get_thread_name(date): date for date in dates}
|
||||
max_lookback_date = datetime.date.today() - datetime.timedelta(days=thread_lookback_days)
|
||||
for thread in channel.threads:
|
||||
if thread.locked:
|
||||
continue
|
||||
if thread.created_at.date() < max_lookback_date:
|
||||
break
|
||||
if thread.name in potential_threadnames:
|
||||
del potential_threadnames[thread.name]
|
||||
skipped_dates += 1
|
||||
logging.info('Skipping %d days from posting, as the threads were already found', skipped_dates)
|
||||
yield from potential_threadnames.values()
|
||||
|
||||
@staticmethod
|
||||
def __get_thread_name(date: datetime.date) -> str:
|
||||
return date.strftime('%Y-%m-%d %A')
|
||||
|
||||
async def __create_thread(self, channel: ForumChannel, date: datetime.date) -> bool:
|
||||
name = self.__get_thread_name(date)
|
||||
thread = await channel.create_thread(name=name,
|
||||
content="Tragt hier eure Spielverabredungen ein für oben genanntes Datum.",
|
||||
reason='Spielverabredungen - Erstellt von Bot')
|
||||
return thread is not None
|
||||
|
||||
async def on_ready(self):
|
||||
logging.info(f'Logging in as {self.user}')
|
||||
try:
|
||||
channel = self.__get_channel()
|
||||
logging.info('Channel obtained')
|
||||
dates = self.__check_duplicate_channels(channel, self.config_object.dates,
|
||||
self.config_object.go_back_threads_days)
|
||||
for index, date in enumerate(dates, start=1):
|
||||
if index % 10 == 0:
|
||||
logging.info('Attempting Thread creation number %d for %s', index, date)
|
||||
if not await self.__create_thread(channel, date):
|
||||
logging.error('Could not create thread for %s', date)
|
||||
await asyncio.sleep(1)
|
||||
except Exception as e:
|
||||
logging.error(f'Error: {e}')
|
||||
finally:
|
||||
await self.close()
|
||||
|
||||
|
||||
@click.command()
|
||||
@click.option('--guild', '-g', type=int, help='ID of the guild (server) to post in', default=812043029967536188,
|
||||
show_default=True)
|
||||
@click.option('--channel', '-c', type=int, help='ID of the channel to post threads in', default=1389312271397818509,
|
||||
show_default=True)
|
||||
@click.option('--start', '-s', type=click.DateTime(), help='Date to start the threads for. Defaults to today',
|
||||
default=datetime.datetime.today(), show_default=True)
|
||||
@click.option('--end', '-e', type=click.DateTime(), help='Date to end the threads for. Defaults to today + 90 days',
|
||||
default=datetime.datetime.today() + datetime.timedelta(days=90))
|
||||
@click.option('--thread-lookback', type=int, default=180, help='How many days to look back for duplicate threads',
|
||||
show_default=True)
|
||||
@click.option('--token', envvar='SPIELVERABREDUNGEN_TOKEN', help='Token to authenticate the bot', required=True)
|
||||
@click.option('--debug', is_flag=True, help='Write debug messages to log')
|
||||
def main(guild: int, channel: int, start: datetime.datetime, end: datetime.datetime, token: str,
|
||||
thread_lookback: int, debug: bool) -> None:
|
||||
intents = discord.Intents.default()
|
||||
intents.messages = True
|
||||
|
||||
log_handler = logging.FileHandler(filename='spielabredungen.log', encoding='utf-8', mode='w')
|
||||
if debug:
|
||||
log_handler.setLevel(logging.DEBUG)
|
||||
else:
|
||||
log_handler.setLevel(logging.INFO)
|
||||
|
||||
locale.setlocale(locale.LC_ALL, 'de_DE.UTF-8')
|
||||
logging.debug('Setting locale to "de_DE.UTF-8"')
|
||||
|
||||
client = SpielverabredungenClient(intents=intents)
|
||||
client.config_object = SpielverabredungenConfig(guild_id=guild, channel_id=channel, start=start, end=end,
|
||||
go_back_threads_days=thread_lookback)
|
||||
client.run(token, log_handler=log_handler, root_logger=True)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Loading…
Reference in New Issue
Block a user