cogs, shardable, setup, update, say_ralf commands
Signed-off-by: Marc Ahlgrim <marc@onemarcfifty.com>
This commit is contained in:
@@ -2,16 +2,12 @@
|
|||||||
|
|
||||||
R.A.L.F. (short for Responsive Artificial Lifeform ;-) ) is the "housekeeping" bot on the oneMarcFifty Discord Server
|
R.A.L.F. (short for Responsive Artificial Lifeform ;-) ) is the "housekeeping" bot on the oneMarcFifty Discord Server
|
||||||
|
|
||||||
It can do the following things (release version 0.2):
|
It can do the following things (release version 0.4):
|
||||||
|
|
||||||
- reply with "pong" to a "ping" (WHOA!!!)
|
- reply with "pong" to a "ping" (WHOA!!!)
|
||||||
- Send out configurable random messages when the server is idle (like "Did you know...")
|
- Send out configurable random messages when the server is idle (like "Did you know...")
|
||||||
- automatically create Events (we have Sunday video sessions at 9 AM and 6 PM)
|
- automatically create Events (we have Sunday video sessions at 9 AM and 6 PM)
|
||||||
- remind subscribers of upcoming events
|
- remind subscribers of upcoming events
|
||||||
|
|
||||||
Planned (release 0.3)
|
|
||||||
|
|
||||||
- Help the user create a support thread with a modal view
|
|
||||||
- let the user subscribe / unsubscribe to notification messages with a modal view
|
- let the user subscribe / unsubscribe to notification messages with a modal view
|
||||||
|
|
||||||
## How to use
|
## How to use
|
||||||
@@ -22,10 +18,45 @@ You need the discord.py wrapper from Rapptz :
|
|||||||
cd discord.py/
|
cd discord.py/
|
||||||
python3 -m pip install -U .[voice]
|
python3 -m pip install -U .[voice]
|
||||||
|
|
||||||
Next, adapt the `secret.py` file to reflect your token etc.
|
Next, adapt the `config.json` file to reflect your token etc.
|
||||||
Also, customize all settings in `config.py` and the text files in the
|
|
||||||
`bot_messages`directory
|
|
||||||
|
|
||||||
Now you can cd into the bot's directory and launch it with
|
Now you can cd into the bot's directory and launch it with
|
||||||
|
|
||||||
python3 main.py
|
python3 main.py
|
||||||
|
|
||||||
|
## slash commands
|
||||||
|
|
||||||
|
The bot supports the following commands:
|
||||||
|
**/setup** set up basic functionality (channel for idle messages, frequency of the messages, channel that contains the templates)
|
||||||
|
**/subscribe** let a user subscribe to roles that are defined in the scheduled events
|
||||||
|
**/update** update the bot (re-read the template channel)
|
||||||
|
**/say_ralf** let ralf say something. You can specify the channel and the message ;-)
|
||||||
|
|
||||||
|
## How do you configure R.A.L.F. ?
|
||||||
|
|
||||||
|
First you need a minimum `config.json`like shown in `minimum.config.json` that contains your token and client id.
|
||||||
|
|
||||||
|
All other values are taken from a "Template" channel. When you run the **/setup** command, R.A.L.F. will let you chose that one.
|
||||||
|
|
||||||
|
In that template channel, you just create messages that you want R.A.L.F. to send randomly into the configured idle_channel.
|
||||||
|
|
||||||
|
### how to configure Events ?
|
||||||
|
|
||||||
|
A special type of template message contains a definition of scheduled events. The message needs to contain data that can be converted to a dict object, like this:
|
||||||
|
|
||||||
|
{
|
||||||
|
"title": "Sunday Funday session (PM)",
|
||||||
|
"description": "Chat with Marc and the folks here on the server ! Share your screen if you want to walk through a problem. Talk about tech stuff with the other members or just listen in...",
|
||||||
|
"channel": 12345452435,
|
||||||
|
"notify_hint": "get notified when the PM session starts",
|
||||||
|
"subscription_role_num": 12432345423,
|
||||||
|
"notify_minutes": 30,
|
||||||
|
"day_of_week": 6,
|
||||||
|
"start_time": "18:00:00",
|
||||||
|
"end_time": "19:00:00"
|
||||||
|
}
|
||||||
|
|
||||||
|
(when you use the /update command, it will tell you if it could read it or not.)
|
||||||
|
Every Monday, R.A.L.F. will then go through the Events and create them as scheduled events on the guild/server.
|
||||||
|
|
||||||
|
If the user has the `subscription_role_num` role, then he/she will be notified by R.A.L.F. roughly `notify_minutes`before the event starts.
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
Hi, I am R.A.L.F., your assistant bot.
|
|
||||||
|
|
||||||
Did you know that there is a **video/voice session** that is **open to everyone** on this server?
|
|
||||||
***Every Sunday at 9 AM and 6 PM Berlin/Paris time*** you can join in the <#758271650688008202> channel.
|
|
||||||
|
|
||||||
Chat with Marc and the folks here on the server !
|
|
||||||
Share your screen if you want to walk through a problem.
|
|
||||||
Talk about tech stuff with the other members
|
|
||||||
or just listen in...
|
|
||||||
|
|
||||||
****Everyone is invited!****
|
|
||||||
|
|
||||||
Type **/subscribe** if you want to get notified half an hour before the conference starts.
|
|
||||||
you can use the same command to unsubscribe at any time - no questions asked ;-)
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
Hi, I am R.A.L.F., your assistant bot.
|
|
||||||
|
|
||||||
You can interact with me by typing "/" and then a command:
|
|
||||||
|
|
||||||
**/support** helps you open a support thread as described in the <#954732247909552149> channel
|
|
||||||
**/subscribe** subscribe to get notified half an hour before the Sunday Funday session starts
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
Hi, this is R.A.L.F., your assistant bot.
|
|
||||||
|
|
||||||
Please check in every now and then to the <#954732247909552149> channel.
|
|
||||||
This is where folks here on the server ask for help.
|
|
||||||
Maybe **** YOU **** can help someone there ?
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
Hi, I am R.A.L.F., your assistant bot.
|
|
||||||
|
|
||||||
Did you know that you can see ***all of Marc's videos*** in the <#792662116456726538> channel?
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
Hi, I am R.A.L.F., your assistant bot.
|
|
||||||
|
|
||||||
**We are always looking for Sponsors!**
|
|
||||||
|
|
||||||
If you have Nitro or if you want to spend some $$$
|
|
||||||
|
|
||||||
*** maybe you want to boost the server ? ***
|
|
||||||
|
|
||||||
This will give everyone better video and voice quality in the Sunday Funday calls or for tech support calls.
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
Hi, I am R.A.L.F., your assistant bot!
|
|
||||||
|
|
||||||
Did you know that we have a ***support channel*** here ?
|
|
||||||
|
|
||||||
Please see the <#954732247909552149> channel on how to get help on a tech issue.
|
|
||||||
Alternatively, you can type /support and I will help you to create one.
|
|
||||||
|
|
||||||
Please do also check in every now and then to the <#866779182293057566> channel.
|
|
||||||
Maybe ****YOU**** can help someone there ?
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
Hi, I am R.A.L.F., the Responsive Artificial Life Form ;-)
|
|
||||||
|
|
||||||
Did you know that everyone can use the
|
|
||||||
|
|
||||||
*** <#957636889718968380> ***
|
|
||||||
|
|
||||||
channel for video/voice calls at any time ?
|
|
||||||
+269
-143
@@ -1,19 +1,19 @@
|
|||||||
import discord
|
import discord
|
||||||
import random
|
import random
|
||||||
import numpy as np
|
|
||||||
import utils
|
import utils
|
||||||
import datetime
|
import datetime
|
||||||
import config
|
import os
|
||||||
|
import ast
|
||||||
|
|
||||||
from glob import glob
|
|
||||||
from dateutil import tz
|
from dateutil import tz
|
||||||
from sys import exit
|
|
||||||
|
|
||||||
from discord import app_commands
|
|
||||||
from discord.ext import tasks
|
from discord.ext import tasks
|
||||||
|
from discord.ext.commands import Bot,AutoShardedBot
|
||||||
|
|
||||||
from classes.dis_events import DiscordEvents
|
from classes.dis_events import DiscordEvents
|
||||||
from classes.subscribe import Subscribe
|
from classes.subscribe import Subscribe
|
||||||
|
from classes.config import Config
|
||||||
|
from dataclasses import dataclass
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# #######################################
|
# #######################################
|
||||||
@@ -21,80 +21,222 @@ from classes.subscribe import Subscribe
|
|||||||
# #######################################
|
# #######################################
|
||||||
|
|
||||||
|
|
||||||
class OMFClient(discord.Client):
|
class OMFBot(AutoShardedBot):
|
||||||
|
|
||||||
channel_idle_timer: int
|
# each guild has the following elements:
|
||||||
lastNotifyTimeStamp = None
|
# - a list of scheduled Events (EventsList)
|
||||||
theGuild : discord.Guild = None
|
# - a list of Messages that will be sent at idle times
|
||||||
|
# - a timer indicating the number of scheduler runs to
|
||||||
|
# wait before a new idle message is sent
|
||||||
|
|
||||||
lastSentMessage:discord.Message=None
|
@dataclass
|
||||||
|
class GuildData:
|
||||||
|
EventsList = {}
|
||||||
|
idle_messages=[]
|
||||||
|
channel_idle_timer=0
|
||||||
|
|
||||||
guildEventsList = None
|
# the guildDataList contains one GuildData class per item.
|
||||||
guildEventsClass: DiscordEvents = None
|
# the key is the guild ID
|
||||||
|
|
||||||
|
guildDataList={}
|
||||||
|
|
||||||
|
# configData is the generic config object that reads / writes
|
||||||
|
# the config data to disk
|
||||||
|
|
||||||
|
configData:Config
|
||||||
|
|
||||||
|
# EventsClass is the interface to the restful api
|
||||||
|
# that allows us to create scheduled events
|
||||||
|
|
||||||
|
EventsClass : DiscordEvents
|
||||||
|
|
||||||
# #######################################
|
# #######################################
|
||||||
# init constructor
|
# init constructor
|
||||||
# #######################################
|
# #######################################
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
|
|
||||||
print('Init')
|
|
||||||
|
|
||||||
# Try to set all intents
|
# Try to set all intents
|
||||||
|
|
||||||
intents = discord.Intents.all()
|
intents = discord.Intents.all()
|
||||||
super().__init__(intents=intents)
|
super().__init__(command_prefix="!",intents=intents)
|
||||||
|
self.prefix="!"
|
||||||
# We need a `discord.app_commands.CommandTree` instance
|
self.configData=Config('config.json')
|
||||||
# to register application commands (slash commands in this case)
|
|
||||||
|
|
||||||
self.tree = app_commands.CommandTree(self)
|
|
||||||
|
|
||||||
# The subscribe command will add/remove the notification roles
|
# The subscribe command will add/remove the notification roles
|
||||||
# based on the scheduled events
|
# based on the scheduled events
|
||||||
|
|
||||||
@self.tree.command(name="subscribe", description="(un)subscribe to Events)")
|
@self.tree.command(name="subscribe", description="(un)subscribe to Events)")
|
||||||
async def subscribe(interaction: discord.Interaction):
|
async def subscribe(interaction: discord.Interaction):
|
||||||
|
|
||||||
# preload the menu items with the roles that the user has already
|
|
||||||
# we might move this to the init of the modal
|
|
||||||
|
|
||||||
x: Subscribe
|
x: Subscribe
|
||||||
role: discord.Role
|
|
||||||
member: discord.Member
|
member: discord.Member
|
||||||
|
|
||||||
x=Subscribe()
|
guildNode=self.configData.readGuild(interaction.guild.id)
|
||||||
member = interaction.user
|
member = interaction.user
|
||||||
|
x=Subscribe(autoEvents=guildNode["AUTO_EVENTS"],member=member)
|
||||||
for option in x.Menu.options:
|
|
||||||
role = option.value
|
|
||||||
if not (member.get_role(role) is None):
|
|
||||||
option.default=True
|
|
||||||
await interaction.response.send_modal(x)
|
await interaction.response.send_modal(x)
|
||||||
|
|
||||||
|
# The setup command will ask for the guild parameters and
|
||||||
|
# read them in
|
||||||
|
@self.tree.command(name="setup", description="Define parameters for the bot")
|
||||||
|
async def setup(
|
||||||
|
interaction: discord.Interaction,
|
||||||
|
template_channel:discord.TextChannel,
|
||||||
|
idle_channel:discord.TextChannel,
|
||||||
|
idle_sleepcycles:int,
|
||||||
|
avoid_spam:int):
|
||||||
|
|
||||||
self.channel_idle_timer = 0
|
if not interaction.user.guild_permissions.administrator:
|
||||||
self.idle_channel = self.get_channel(config.CONFIG["IDLE_MESSAGE_CHANNEL_ID"])
|
await interaction.response.send_message(f'only an Administrator can do that', ephemeral=True)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
jData={
|
||||||
|
"IDLE_MESSAGE_CHANNEL_ID" : idle_channel.id,
|
||||||
|
"CONFIG_CHANNEL_ID": template_channel.id,
|
||||||
|
"CHANNEL_IDLE_INTERVAL" : idle_sleepcycles,
|
||||||
|
"AVOID_SPAM" : avoid_spam,
|
||||||
|
"AUTO_EVENTS": []
|
||||||
|
}
|
||||||
|
self.configData.writeGuild(interaction.guild.id,jData)
|
||||||
|
await interaction.response.send_message(f'All updated\nThank you for using my services!\nyou might need to run /update', ephemeral=True)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"ERROR in setup command: {e}")
|
||||||
|
await interaction.response.send_message(f'Ooops, there was a glitch!', ephemeral=True)
|
||||||
|
|
||||||
|
# The update command will read the guild configs from the
|
||||||
|
# message templates channel
|
||||||
|
@self.tree.command(name="update", description="read in the message templates and update the cache")
|
||||||
|
async def update(interaction: discord.Interaction):
|
||||||
|
|
||||||
|
if not interaction.user.guild_permissions.administrator:
|
||||||
|
await interaction.response.send_message(f'only an Administrator can do that', ephemeral=True)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
await self.readMessageTemplates(interaction.guild)
|
||||||
|
#self.configData.writeGuild(interaction.guild.id,jData)
|
||||||
|
|
||||||
|
numMessages=len(self.guildDataList[f'{interaction.guild.id}'].idle_messages)
|
||||||
|
guildNode=self.configData.readGuild(interaction.guild.id)
|
||||||
|
eventNodes=guildNode["AUTO_EVENTS"]
|
||||||
|
numEvents=len(eventNodes)
|
||||||
|
|
||||||
|
await interaction.response.send_message(f'{numEvents} Events and {numMessages} Message templates\nThank you for using my services!', ephemeral=True)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"ERROR in update command: {e}")
|
||||||
|
await interaction.response.send_message(f'Ooops, there was a glitch!', ephemeral=True)
|
||||||
|
|
||||||
|
@self.tree.command(name="say_ralf", description="admin function")
|
||||||
|
async def say_ralf(
|
||||||
|
interaction: discord.Interaction,
|
||||||
|
which_channel:discord.TextChannel,
|
||||||
|
message:str):
|
||||||
|
|
||||||
|
if not interaction.user.guild_permissions.administrator:
|
||||||
|
await interaction.response.send_message(f'only an Administrator can do that', ephemeral=True)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
await which_channel.send(message)
|
||||||
|
await interaction.response.send_message('message sent', ephemeral=True)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"ERROR in say_ralf: {e}")
|
||||||
|
await interaction.response.send_message(f'Ooops, there was a glitch!', ephemeral=True)
|
||||||
|
|
||||||
|
|
||||||
|
# ################################
|
||||||
|
# the bot run command just starts
|
||||||
|
# the bot with the token from
|
||||||
|
# the json config file
|
||||||
|
# ################################
|
||||||
|
|
||||||
|
def run(self,*args, **kwargs):
|
||||||
|
super().run(token=self.configData.getToken())
|
||||||
|
|
||||||
# #########################
|
# #########################
|
||||||
# setup_hook waits for the
|
# setup_hook waits for the
|
||||||
# command tree to sync
|
# command tree to sync
|
||||||
|
# and loads the cogs
|
||||||
# #########################
|
# #########################
|
||||||
|
|
||||||
async def setup_hook(self) -> None:
|
async def setup_hook(self) -> None:
|
||||||
# Sync the application command with Discord.
|
# Sync the application command with Discord.
|
||||||
await self.tree.sync()
|
await self.tree.sync()
|
||||||
|
# load all cogs
|
||||||
|
try:
|
||||||
|
for file in os.listdir("cogs"):
|
||||||
|
if file.endswith(".py"):
|
||||||
|
name = file[:-3]
|
||||||
|
await self.load_extension(f"cogs.{name}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"ERROR in setup_hook: {e}")
|
||||||
|
|
||||||
|
|
||||||
# ######################################################
|
# ######################################################
|
||||||
# send_random_message is called when the server is idle
|
# send_random_message is called when the server is idle
|
||||||
# and posts a random message to the server
|
# and posts a random message to the server
|
||||||
# ######################################################
|
# ######################################################
|
||||||
|
|
||||||
async def send_random_message(self):
|
async def send_random_message(self,guildID):
|
||||||
|
guildNode=self.configData.readGuild(guildID)
|
||||||
print("Sending random message")
|
print("Sending random message")
|
||||||
if self.idle_channel == None:
|
idle_channel_id=guildNode["IDLE_MESSAGE_CHANNEL_ID"]
|
||||||
self.idle_channel = self.get_channel(config.CONFIG["IDLE_MESSAGE_CHANNEL_ID"])
|
idle_channel=self.get_channel(idle_channel_id)
|
||||||
print (f'The idle channel is {config.CONFIG["IDLE_MESSAGE_CHANNEL_ID"]} - {self.idle_channel}')
|
gdn:self.GuildData
|
||||||
await self.idle_channel.send(f"{random.choice(self.idle_messages)}")
|
gdn=self.guildDataList[f'{guildID}']
|
||||||
|
idle_messages=gdn.idle_messages
|
||||||
|
|
||||||
|
# if the author of the previously last sent message and
|
||||||
|
# the new message is ourselves, then delete the
|
||||||
|
# previous message
|
||||||
|
try:
|
||||||
|
lastSentMessage = await idle_channel.fetch_message(
|
||||||
|
idle_channel.last_message_id)
|
||||||
|
if (int(f'{guildNode["AVOID_SPAM"]}') == 1) and (lastSentMessage is not None):
|
||||||
|
if (lastSentMessage.author == self.user):
|
||||||
|
await lastSentMessage.delete()
|
||||||
|
except Exception as e:
|
||||||
|
print(f"delete lastmessage error: {e}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
await idle_channel.send(f'{random.choice(idle_messages)}')
|
||||||
|
except Exception as e:
|
||||||
|
print(f"send random message error: {e}")
|
||||||
|
|
||||||
|
# ######################################################
|
||||||
|
# readMessageTemplates reads all messages from
|
||||||
|
# the guildID/"config"/"CONFIG_CHANNEL_ID"] node
|
||||||
|
# of the configdata and stores it in the idleMessages dict
|
||||||
|
# in an array under the guild ID key
|
||||||
|
# ######################################################
|
||||||
|
|
||||||
|
async def readMessageTemplates(self,theGuild:discord.Guild):
|
||||||
|
|
||||||
|
# we init the guild data with a new GuildData object
|
||||||
|
self.guildDataList[f'{theGuild.id}'] = self.GuildData()
|
||||||
|
|
||||||
|
guildNode=self.configData.readGuild(theGuild.id)
|
||||||
|
if guildNode is None:
|
||||||
|
print (f"Guild {theGuild.id} has no setup")
|
||||||
|
return
|
||||||
|
theTemplateChannel:discord.TextChannel
|
||||||
|
theTemplateChannel=theGuild.get_channel(int(guildNode["CONFIG_CHANNEL_ID"]))
|
||||||
|
message:discord.Message
|
||||||
|
messages = theTemplateChannel.history(limit=50)
|
||||||
|
self.guildDataList[f'{theGuild.id}'].idle_messages=[]
|
||||||
|
eventNodes=[]
|
||||||
|
async for message in messages:
|
||||||
|
messageContent:str
|
||||||
|
messageContent=message.content
|
||||||
|
try:
|
||||||
|
someDict=ast.literal_eval(messageContent)
|
||||||
|
if isinstance(someDict, dict):
|
||||||
|
eventNodes.append(someDict)
|
||||||
|
except Exception as e:
|
||||||
|
self.guildDataList[f'{theGuild.id}'].idle_messages.append(message.content)
|
||||||
|
guildNode["AUTO_EVENTS"]=eventNodes
|
||||||
|
self.configData.writeGuild(theGuild.id,guildNode)
|
||||||
|
|
||||||
|
numMessages=len(self.guildDataList[f'{theGuild.id}'].idle_messages)
|
||||||
|
numEvents=len(eventNodes)
|
||||||
|
print(f'{numEvents} Events and {numMessages} Message templates')
|
||||||
|
|
||||||
|
|
||||||
# ######################################################
|
# ######################################################
|
||||||
# on_ready is called once the client is initialized
|
# on_ready is called once the client is initialized
|
||||||
@@ -105,37 +247,18 @@ class OMFClient(discord.Client):
|
|||||||
async def on_ready(self):
|
async def on_ready(self):
|
||||||
print('Logged on as', self.user)
|
print('Logged on as', self.user)
|
||||||
|
|
||||||
|
self.EventsClass = DiscordEvents(
|
||||||
|
discord_token=self.configData.getToken(),
|
||||||
|
client_id=self.configData.getClientID(),
|
||||||
|
bot_permissions=8,
|
||||||
|
api_version=10)
|
||||||
|
|
||||||
# read in the random message files
|
# read in the random message files
|
||||||
# the idle_messages array holds one element per message
|
# the idle_messages array holds one element per message
|
||||||
# every file is read in as a whole into one element of the array
|
# every message is read in as a whole into one element of the array
|
||||||
|
|
||||||
self.idle_messages = []
|
for theGuild in self.guilds:
|
||||||
|
await self.readMessageTemplates(theGuild)
|
||||||
for filename in glob(config.CONFIG["IDLE_MESSAGE_DIR"] + '/*.txt'):
|
|
||||||
print ("read {}",filename)
|
|
||||||
with open(filename) as f:
|
|
||||||
self.idle_messages.append(f.read())
|
|
||||||
|
|
||||||
self.idle_messages = np.array(self.idle_messages)
|
|
||||||
|
|
||||||
# store the guild for further use
|
|
||||||
guild: discord.Guild
|
|
||||||
for guild in self.guilds:
|
|
||||||
if (int(guild.id) == int(config.SECRETS["GUILD_ID"])):
|
|
||||||
print (f"GUILD MATCHES {guild.id}")
|
|
||||||
self.theGuild = guild
|
|
||||||
|
|
||||||
if (self.theGuild is None):
|
|
||||||
print("the guild (Server ID)could not be found - please check all config data")
|
|
||||||
exit()
|
|
||||||
|
|
||||||
self.guildEventsClass = DiscordEvents(
|
|
||||||
discord_token=config.SECRETS["BOT_TOKEN"],
|
|
||||||
client_id=config.SECRETS["CLIENT_ID"],
|
|
||||||
bot_permissions=8,
|
|
||||||
api_version=10,
|
|
||||||
guild_id=config.SECRETS["GUILD_ID"]
|
|
||||||
)
|
|
||||||
|
|
||||||
# start the schedulers
|
# start the schedulers
|
||||||
|
|
||||||
@@ -149,11 +272,14 @@ class OMFClient(discord.Client):
|
|||||||
# for the next sunday
|
# for the next sunday
|
||||||
# ######################################################
|
# ######################################################
|
||||||
|
|
||||||
async def create_events (self):
|
async def create_events (self,theGuild):
|
||||||
|
|
||||||
print("Create Events")
|
print("Create Events")
|
||||||
|
|
||||||
for theEvent in config.AUTO_EVENTS:
|
guildNode=self.configData.readGuild(theGuild.id)
|
||||||
|
eventNodes=guildNode["AUTO_EVENTS"]
|
||||||
|
|
||||||
|
for theEvent in eventNodes:
|
||||||
|
|
||||||
# calculate the date of the future event
|
# calculate the date of the future event
|
||||||
theDate:datetime.datetime = utils.onDay(datetime.date.today(),theEvent['day_of_week'])
|
theDate:datetime.datetime = utils.onDay(datetime.date.today(),theEvent['day_of_week'])
|
||||||
@@ -171,16 +297,18 @@ class OMFClient(discord.Client):
|
|||||||
# after 2 AM
|
# after 2 AM
|
||||||
strStart=theDate.strftime(f"%Y-%m-%dT{utcStartTime}")
|
strStart=theDate.strftime(f"%Y-%m-%dT{utcStartTime}")
|
||||||
strEnd=theDate.strftime(f"%Y-%m-%dT{utcEndTime}")
|
strEnd=theDate.strftime(f"%Y-%m-%dT{utcEndTime}")
|
||||||
await self.guildEventsClass.create_guild_event(
|
|
||||||
|
await self.EventsClass.create_guild_event(
|
||||||
event_name=theEvent['title'],
|
event_name=theEvent['title'],
|
||||||
event_description=theEvent['description'],
|
event_description=theEvent['description'],
|
||||||
event_start_time=f"{strStart}",
|
event_start_time=f"{strStart}",
|
||||||
event_end_time=f"{strEnd}",
|
event_end_time=f"{strEnd}",
|
||||||
event_metadata={},
|
event_metadata={},
|
||||||
event_privacy_level=2,
|
event_privacy_level=2,
|
||||||
channel_id=theEvent['channel'])
|
channel_id=theEvent['channel'],
|
||||||
|
guild_id=theGuild.id)
|
||||||
# once we have created the event, we let everyone know
|
# once we have created the event, we let everyone know
|
||||||
channel = self.get_channel(config.CONFIG["IDLE_MESSAGE_CHANNEL_ID"])
|
channel = theGuild.get_channel(guildNode["IDLE_MESSAGE_CHANNEL_ID"])
|
||||||
await channel.send(f'Hi - I have created the scheduled Event {theEvent["title"]}')
|
await channel.send(f'Hi - I have created the scheduled Event {theEvent["title"]}')
|
||||||
|
|
||||||
|
|
||||||
@@ -188,9 +316,10 @@ class OMFClient(discord.Client):
|
|||||||
# get_event_list gives a list of scheduled events
|
# get_event_list gives a list of scheduled events
|
||||||
# ######################################################
|
# ######################################################
|
||||||
|
|
||||||
async def get_events_list (self):
|
async def get_events_list (self,theGuild: discord.Guild):
|
||||||
eventList = await self.guildEventsClass.list_guild_events()
|
|
||||||
self.guildEventsList = eventList
|
eventList = await self.EventsClass.list_guild_events(theGuild.id)
|
||||||
|
self.GuildData(self.guildDataList[f'{theGuild.id}']).EventsList = eventList
|
||||||
return eventList
|
return eventList
|
||||||
|
|
||||||
# ######################################################
|
# ######################################################
|
||||||
@@ -207,30 +336,16 @@ class OMFClient(discord.Client):
|
|||||||
if message.flags.ephemeral:
|
if message.flags.ephemeral:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
print("{} has just sent {}".format(message.author, message.content))
|
print("{} has just sent {}".format(message.author, message.content))
|
||||||
# if the author of the previously last sent message and
|
|
||||||
# the new message is ourselves, then delete the
|
|
||||||
# previous message
|
|
||||||
|
|
||||||
if (int(f'{config.CONFIG["AVOID_SPAM"]}') == 1) and (self.lastSentMessage is not None):
|
|
||||||
if ((message.author == self.user) and
|
|
||||||
(self.lastSentMessage.author == self. user) and
|
|
||||||
(int(f"{self.lastSentMessage.channel.id}") == (int(config.CONFIG["IDLE_MESSAGE_CHANNEL_ID"])))):
|
|
||||||
try:
|
|
||||||
await self.lastSentMessage.delete()
|
|
||||||
except Exception as e:
|
|
||||||
print(f"delete lastmessage error: {e}")
|
|
||||||
|
|
||||||
|
|
||||||
self.lastSentMessage = message
|
|
||||||
|
|
||||||
# don't respond to ourselves
|
# don't respond to ourselves
|
||||||
if message.author == self.user:
|
if message.author == self.user:
|
||||||
return
|
return
|
||||||
|
|
||||||
# reset the idle timer if a message has been sent or received
|
# reset the idle timer if a message has been sent or received
|
||||||
self.channel_idle_timer = 0
|
self.guildDataList[f'{message.guild.id}'].channel_idle_timer=0
|
||||||
|
|
||||||
|
await self.process_commands(message)
|
||||||
|
|
||||||
|
|
||||||
# ######################################################
|
# ######################################################
|
||||||
@@ -263,10 +378,11 @@ class OMFClient(discord.Client):
|
|||||||
|
|
||||||
if datetime.date.today().weekday() == 0:
|
if datetime.date.today().weekday() == 0:
|
||||||
print("create events")
|
print("create events")
|
||||||
try:
|
for theGuild in self.guilds:
|
||||||
await self.create_events()
|
try:
|
||||||
except Exception as e:
|
await self.create_events(theGuild=theGuild)
|
||||||
print(f"Daily Task create Events failed: {e}")
|
except Exception as e:
|
||||||
|
print(f"Daily Task create Events failed: {e}")
|
||||||
|
|
||||||
|
|
||||||
# ######################################################
|
# ######################################################
|
||||||
@@ -281,50 +397,60 @@ class OMFClient(discord.Client):
|
|||||||
@tasks.loop(minutes=10)
|
@tasks.loop(minutes=10)
|
||||||
async def task_scheduler(self):
|
async def task_scheduler(self):
|
||||||
|
|
||||||
self.channel_idle_timer += 1
|
|
||||||
print("SCHEDULE")
|
print("SCHEDULE")
|
||||||
|
|
||||||
# #####################################
|
for theGuild in self.guilds:
|
||||||
# see if we need to send a random message
|
guildNode=self.configData.readGuild(theGuild.id)
|
||||||
# if the counter is greater than CHANNEL_IDLE_INTERVAL
|
if guildNode is None:
|
||||||
# then send a random message into the idle_channel
|
print (f"Guild {theGuild.id} has no setup")
|
||||||
# #####################################
|
continue
|
||||||
try:
|
gdn:self.GuildData
|
||||||
if self.channel_idle_timer >= config.CONFIG["CHANNEL_IDLE_INTERVAL"]:
|
gdn=self.guildDataList[f'{theGuild.id}']
|
||||||
self.channel_idle_timer = 0
|
gdn.channel_idle_timer += 1
|
||||||
await self.send_random_message()
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Scheduler random_message failed: {e}")
|
|
||||||
|
|
||||||
# see if we need to send out notifications for events
|
# #####################################
|
||||||
# The Event details are stored in config.
|
# see if we need to send a random message
|
||||||
eventList=None
|
# if the counter is greater than CHANNEL_IDLE_INTERVAL
|
||||||
for theEvent in config.AUTO_EVENTS:
|
# then send a random message into the idle_channel
|
||||||
# first let's convert the String dates to datetime:
|
# #####################################
|
||||||
theDate=utils.onDay(datetime.date.today(),theEvent['day_of_week'])
|
|
||||||
startTime=theEvent['start_time']
|
try:
|
||||||
eventScheduledTimeDate=datetime.datetime.fromisoformat (theDate.strftime(f"%Y-%m-%dT{startTime}"))
|
if gdn.channel_idle_timer >= guildNode["CHANNEL_IDLE_INTERVAL"]:
|
||||||
# now let's figure out the time deltas:
|
gdn.channel_idle_timer = 0
|
||||||
timeUntilEvent=eventScheduledTimeDate - datetime.datetime.today()
|
await self.send_random_message(guildID=theGuild.id)
|
||||||
earliestPing=eventScheduledTimeDate - datetime.timedelta(minutes=theEvent["notify_minutes"]) - datetime.timedelta(minutes=10)
|
except Exception as e:
|
||||||
latestPing=eventScheduledTimeDate - datetime.timedelta(minutes=theEvent["notify_minutes"])
|
print(f"Scheduler random_message failed: {e}")
|
||||||
#print("found scheduled event")
|
|
||||||
#print(f"The event is on {theDate} at {startTime} - that is in {timeUntilEvent}")
|
# see if we need to send out notifications for events
|
||||||
#print (f"we ping between {earliestPing} and {latestPing}")
|
# The Event details are stored in config.
|
||||||
# If we are in the interval then let's initiate the reminder
|
eventList=None
|
||||||
if (earliestPing < datetime.datetime.today() <= latestPing):
|
|
||||||
# let's first check if the event is still on
|
for theEvent in guildNode["AUTO_EVENTS"]:
|
||||||
# it may have been deleted or modified on the server
|
# first let's convert the String dates to datetime:
|
||||||
# we don't want to alert for non-existing events
|
theDate=utils.onDay(datetime.date.today(),theEvent['day_of_week'])
|
||||||
# we'll just use the title to compare for the time being.
|
startTime=theEvent['start_time']
|
||||||
print("Let me check if the event is still on")
|
eventScheduledTimeDate=datetime.datetime.fromisoformat (theDate.strftime(f"%Y-%m-%dT{startTime}"))
|
||||||
try:
|
# now let's figure out the time deltas:
|
||||||
if eventList == None:
|
timeUntilEvent=eventScheduledTimeDate - datetime.datetime.today()
|
||||||
eventList = await self.get_events_list()
|
earliestPing=eventScheduledTimeDate - datetime.timedelta(minutes=theEvent["notify_minutes"]) - datetime.timedelta(minutes=10)
|
||||||
for theScheduledEvent in eventList:
|
latestPing=eventScheduledTimeDate - datetime.timedelta(minutes=theEvent["notify_minutes"])
|
||||||
if theScheduledEvent["name"] == theEvent["title"]:
|
#print("found scheduled event")
|
||||||
channel = self.get_channel(config.CONFIG["IDLE_MESSAGE_CHANNEL_ID"])
|
#print(f"The event is on {theDate} at {startTime} - that is in {timeUntilEvent}")
|
||||||
theMessageText=f'Hi <@&{theEvent["subscription_role_num"]}>, the event *** {theEvent["title"]} *** will start in roughly {theEvent["notify_minutes"]} minutes in the <#{theEvent["channel"]}> channel. {theEvent["description"]}'
|
#print (f"we ping between {earliestPing} and {latestPing}")
|
||||||
await channel.send(f"{theMessageText}")
|
# If we are in the interval then let's initiate the reminder
|
||||||
except Exception as e:
|
if (earliestPing < datetime.datetime.today() <= latestPing):
|
||||||
print(f"Scheduler event_reminder failed: {e}")
|
# let's first check if the event is still on
|
||||||
|
# it may have been deleted or modified on the server
|
||||||
|
# we don't want to alert for non-existing events
|
||||||
|
# we'll just use the title to compare for the time being.
|
||||||
|
print("Let me check if the event is still on")
|
||||||
|
try:
|
||||||
|
if eventList == None:
|
||||||
|
eventList = await self.get_events_list(theGuild=theGuild)
|
||||||
|
for theScheduledEvent in eventList:
|
||||||
|
if theScheduledEvent["name"] == theEvent["title"]:
|
||||||
|
channel = self.get_channel(guildNode["IDLE_MESSAGE_CHANNEL_ID"])
|
||||||
|
theMessageText=f'Hi <@&{theEvent["subscription_role_num"]}>, the event *** {theEvent["title"]} *** will start in roughly {theEvent["notify_minutes"]} minutes in the <#{theEvent["channel"]}> channel. {theEvent["description"]}'
|
||||||
|
await channel.send(f"{theMessageText}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Scheduler event_reminder failed: {e}")
|
||||||
|
|||||||
@@ -0,0 +1,87 @@
|
|||||||
|
import json
|
||||||
|
|
||||||
|
# very rudimentary implementation of a
|
||||||
|
# generic config class using a json File
|
||||||
|
# this is OK for few clients.
|
||||||
|
# for many (>100) clients we should consider file locking
|
||||||
|
# for very many (>10000) clients we should use a database
|
||||||
|
|
||||||
|
class Config():
|
||||||
|
|
||||||
|
configFileName:str
|
||||||
|
cfg:json
|
||||||
|
|
||||||
|
def __init__(self,filename:str) -> None:
|
||||||
|
|
||||||
|
self.configFileName = filename
|
||||||
|
self.readConfig()
|
||||||
|
|
||||||
|
def readConfig(self) -> json:
|
||||||
|
try:
|
||||||
|
f = open(self.configFileName)
|
||||||
|
self.cfg = json.load(f)
|
||||||
|
f.close()
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error reading Config Data: {e}")
|
||||||
|
|
||||||
|
def writeConfig(self):
|
||||||
|
try:
|
||||||
|
with open(self.configFileName, 'w', encoding='utf-8') as f:
|
||||||
|
json.dump(self.cfg, f, ensure_ascii=False, indent=5)
|
||||||
|
f.close()
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error writing Config Data: {e}")
|
||||||
|
|
||||||
|
|
||||||
|
def getNode(self,nodeID:str):
|
||||||
|
if nodeID in self.cfg:
|
||||||
|
return self.cfg[nodeID]
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def getToken(self):
|
||||||
|
secretNode=self.getNode("secret")
|
||||||
|
return secretNode.get('BOT_TOKEN')
|
||||||
|
|
||||||
|
def getClientID(self):
|
||||||
|
secretNode=self.getNode("secret")
|
||||||
|
return secretNode.get('CLIENT_ID')
|
||||||
|
|
||||||
|
def readGuild(self,guildID) -> json:
|
||||||
|
guildNode=self.getNode("guilds")
|
||||||
|
return guildNode.get(f"{guildID}")
|
||||||
|
|
||||||
|
def writeGuild(self,guildID,nodeData):
|
||||||
|
guildNode=self.getNode("guilds")
|
||||||
|
guildNode[f"{guildID}"]=nodeData
|
||||||
|
self.writeConfig()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# the config.json contains the following main nodes:
|
||||||
|
|
||||||
|
# #######################
|
||||||
|
# "secret"
|
||||||
|
# #######################
|
||||||
|
|
||||||
|
# the secret key contains the following items:
|
||||||
|
|
||||||
|
# the BOT_TOKEN is the Oauth2 token for your bot
|
||||||
|
# example: "BOT_TOKEN" : "DFHEZRERZQRJTSUPERSECRETTTOKENUTZZH"
|
||||||
|
|
||||||
|
# #######################
|
||||||
|
# "guilds"
|
||||||
|
# #######################
|
||||||
|
|
||||||
|
# the guilds node contains all guild specific items, such as channel IDs
|
||||||
|
# that node will be created if the /setup command is used
|
||||||
|
|
||||||
|
# "CONFIG_CHANNEL_ID" is the ID of the channel where the
|
||||||
|
# idle message templates are located
|
||||||
|
|
||||||
|
# "IDLE_MESSAGE_CHANNEL_ID" is the ID of the channel where the
|
||||||
|
# bot posts a message about the new "ticket"
|
||||||
|
|
||||||
|
# QUESTION_SLEEPING_TIME (number)
|
||||||
|
# # Variable that indicates when the bot answers after a question has been asked
|
||||||
|
# (in scheduler cycles)
|
||||||
+12
-14
@@ -10,24 +10,21 @@ from classes.restfulapi import DiscordAPI
|
|||||||
|
|
||||||
class DiscordEvents(DiscordAPI):
|
class DiscordEvents(DiscordAPI):
|
||||||
|
|
||||||
def __init__(self,
|
# def __init__(self,
|
||||||
discord_token: str,
|
# discord_token: str,
|
||||||
client_id: str,
|
# client_id: str,
|
||||||
bot_permissions: int,
|
# bot_permissions: int,
|
||||||
api_version: int,
|
# api_version: int) -> None:
|
||||||
guild_id:str) -> None:
|
#
|
||||||
|
# super().__init__(discord_token,client_id,bot_permissions,api_version)
|
||||||
super().__init__(discord_token,client_id,bot_permissions,api_version)
|
|
||||||
self.guild_id = guild_id
|
|
||||||
print (f" DiscordEvent Client {client_id} guild {guild_id}")
|
|
||||||
|
|
||||||
|
|
||||||
async def list_guild_events(self) -> list:
|
async def list_guild_events(self,guild_id) -> list:
|
||||||
|
|
||||||
# Returns a list of upcoming events for the supplied guild ID
|
# Returns a list of upcoming events for the supplied guild ID
|
||||||
# Format of return is a list of one dictionary per event containing information.
|
# Format of return is a list of one dictionary per event containing information.
|
||||||
|
|
||||||
event_retrieve_url = f'{self.base_api_url}/guilds/{self.guild_id}/scheduled-events'
|
event_retrieve_url = f'{self.base_api_url}/guilds/{guild_id}/scheduled-events'
|
||||||
response_list = await self.get_api(event_retrieve_url)
|
response_list = await self.get_api(event_retrieve_url)
|
||||||
return response_list
|
return response_list
|
||||||
|
|
||||||
@@ -39,7 +36,8 @@ class DiscordEvents(DiscordAPI):
|
|||||||
event_end_time: str,
|
event_end_time: str,
|
||||||
event_metadata: dict,
|
event_metadata: dict,
|
||||||
event_privacy_level=2,
|
event_privacy_level=2,
|
||||||
channel_id=None
|
channel_id=None,
|
||||||
|
guild_id=0
|
||||||
) -> None:
|
) -> None:
|
||||||
|
|
||||||
# Creates a guild event using the supplied arguments
|
# Creates a guild event using the supplied arguments
|
||||||
@@ -50,7 +48,7 @@ class DiscordEvents(DiscordAPI):
|
|||||||
# Event times can use UTC Offsets! - if you omit, then it will be
|
# Event times can use UTC Offsets! - if you omit, then it will be
|
||||||
# undefined (i.e. UTC / GMT+0)
|
# undefined (i.e. UTC / GMT+0)
|
||||||
|
|
||||||
event_create_url = f'{self.base_api_url}/guilds/{self.guild_id}/scheduled-events'
|
event_create_url = f'{self.base_api_url}/guilds/{guild_id}/scheduled-events'
|
||||||
event_data = json.dumps({
|
event_data = json.dumps({
|
||||||
'name': event_name,
|
'name': event_name,
|
||||||
'privacy_level': event_privacy_level,
|
'privacy_level': event_privacy_level,
|
||||||
|
|||||||
+26
-18
@@ -1,6 +1,8 @@
|
|||||||
import discord
|
import discord
|
||||||
import traceback
|
import traceback
|
||||||
import config
|
|
||||||
|
from numpy import array
|
||||||
|
from classes.config import Config
|
||||||
|
|
||||||
# ############################################
|
# ############################################
|
||||||
# the Subscribe() class is a modal ui dialog
|
# the Subscribe() class is a modal ui dialog
|
||||||
@@ -12,23 +14,31 @@ import config
|
|||||||
|
|
||||||
class Subscribe(discord.ui.Modal, title='(un)subscribe to Event-Notification'):
|
class Subscribe(discord.ui.Modal, title='(un)subscribe to Event-Notification'):
|
||||||
|
|
||||||
# We need to make sure that the config is read at object definition time
|
|
||||||
# because AUTO_EVENTS might be empty otherwise
|
|
||||||
if config.AUTO_EVENTS == []:
|
|
||||||
config.readConfig()
|
|
||||||
|
|
||||||
# define the menu options (label=text, vaue=role_id)
|
def __init__(self, autoEvents : array,member:discord.Member) -> None:
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
menu_options = []
|
# create the menu items from the Event roles:
|
||||||
for menu_option in config.AUTO_EVENTS:
|
menu_options = []
|
||||||
menu_options.append(discord.SelectOption(label= menu_option["notify_hint"],
|
for menu_option in autoEvents:
|
||||||
value=menu_option["subscription_role_num"]))
|
menu_options.append(discord.SelectOption(
|
||||||
# define the UI dropdown menu Element
|
label= menu_option["notify_hint"],
|
||||||
|
value=menu_option["subscription_role_num"]))
|
||||||
|
|
||||||
Menu = discord.ui.Select(
|
# define the UI dropdown menu Element
|
||||||
options = menu_options,
|
self.Menu = discord.ui.Select(
|
||||||
max_values=len(config.AUTO_EVENTS),
|
options = menu_options,
|
||||||
min_values=0)
|
max_values=len(autoEvents),
|
||||||
|
min_values=0)
|
||||||
|
|
||||||
|
# Make sure the existing user roles are preselected
|
||||||
|
for option in self.Menu.options:
|
||||||
|
role = option.value
|
||||||
|
if not (member.get_role(role) is None):
|
||||||
|
option.default=True
|
||||||
|
|
||||||
|
# now add the child element to the form for drawing
|
||||||
|
self.add_item(self.Menu)
|
||||||
|
|
||||||
|
|
||||||
# #####################################
|
# #####################################
|
||||||
@@ -44,9 +54,8 @@ class Subscribe(discord.ui.Modal, title='(un)subscribe to Event-Notification'):
|
|||||||
roles = interaction.user.guild.roles
|
roles = interaction.user.guild.roles
|
||||||
member: discord.Member
|
member: discord.Member
|
||||||
member = interaction.user
|
member = interaction.user
|
||||||
|
|
||||||
# first we remove all roles
|
# first we remove all roles
|
||||||
|
|
||||||
for option in self.Menu.options:
|
for option in self.Menu.options:
|
||||||
role=member.get_role(option.value)
|
role=member.get_role(option.value)
|
||||||
if not (role is None):
|
if not (role is None):
|
||||||
@@ -55,7 +64,6 @@ class Subscribe(discord.ui.Modal, title='(un)subscribe to Event-Notification'):
|
|||||||
# then we assign all selected roles
|
# then we assign all selected roles
|
||||||
# unfortunately we need to loop through all rolles
|
# unfortunately we need to loop through all rolles
|
||||||
# maybe there is a better solution ?
|
# maybe there is a better solution ?
|
||||||
|
|
||||||
for option in self.Menu._selected_values:
|
for option in self.Menu._selected_values:
|
||||||
for role in roles:
|
for role in roles:
|
||||||
if int(option) == int(role.id):
|
if int(option) == int(role.id):
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import time
|
||||||
|
import os
|
||||||
|
|
||||||
|
from discord.ext import commands
|
||||||
|
|
||||||
|
class Information(commands.Cog):
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
|
@commands.command()
|
||||||
|
async def ping(self, ctx):
|
||||||
|
before = time.monotonic()
|
||||||
|
before_ws = int(round(self.bot.latency * 1000, 1))
|
||||||
|
message = await ctx.send("🏓 Pong")
|
||||||
|
ping = (time.monotonic() - before) * 1000
|
||||||
|
await message.edit(content=f"🏓 Pong: {before_ws}ms | REST: {int(ping)}ms")
|
||||||
|
|
||||||
|
async def setup(bot):
|
||||||
|
await bot.add_cog(Information(bot))
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
import json
|
|
||||||
|
|
||||||
# Config data is stored in config.json
|
|
||||||
# see the config.json.example file and below comments
|
|
||||||
# readConfig() reads the file
|
|
||||||
|
|
||||||
cfg = None
|
|
||||||
AUTO_EVENTS = []
|
|
||||||
SECRETS = {}
|
|
||||||
CONFIG = {}
|
|
||||||
|
|
||||||
def readConfig():
|
|
||||||
try:
|
|
||||||
f = open('config.json')
|
|
||||||
global cfg
|
|
||||||
cfg = json.load(f)
|
|
||||||
#configData = json.loads(data)
|
|
||||||
f.close()
|
|
||||||
global AUTO_EVENTS
|
|
||||||
AUTO_EVENTS = cfg["AUTO_EVENTS"]
|
|
||||||
global CONFIG
|
|
||||||
CONFIG = cfg["config"]
|
|
||||||
global SECRETS
|
|
||||||
SECRETS = cfg["secret"]
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Error reading Config Data: {e}")
|
|
||||||
|
|
||||||
# the config.json contains the following main nodes:
|
|
||||||
|
|
||||||
# #######################
|
|
||||||
# "secret"
|
|
||||||
# #######################
|
|
||||||
|
|
||||||
# the secret key contains the following items:
|
|
||||||
|
|
||||||
# the BOT_TOKEN is the Oauth2 token for your bot
|
|
||||||
# example: "BOT_TOKEN" : "DFHEZRERZQRJTSUPERSECRETTTOKENUTZZH"
|
|
||||||
|
|
||||||
# The GUILD_ID is the ID of your Server - in the discord client,
|
|
||||||
# right click on your server and select " copy ID" to get it
|
|
||||||
# example: "GUILD_ID" : "0236540000563456"
|
|
||||||
|
|
||||||
# The client ID can be copied from your App settings page and is needed
|
|
||||||
# to authenticate with the Discord Restful API for Event creation
|
|
||||||
# example "CLIENT_ID" : "9990236500564536"
|
|
||||||
|
|
||||||
# #######################
|
|
||||||
# "config"
|
|
||||||
# #######################
|
|
||||||
|
|
||||||
# the config node contains all generic config items, such as channel IDs
|
|
||||||
# and scheduler variables
|
|
||||||
|
|
||||||
# CHANNEL_IDLE_INTERVAL (number)
|
|
||||||
# the number of scheduler cycles that the channel needs to be idle
|
|
||||||
# before the bot posts a generic "did you know"
|
|
||||||
# message
|
|
||||||
|
|
||||||
# IDLE_MESSAGE_DIR (path without trailing slash)
|
|
||||||
# the name of the directory where the text files are
|
|
||||||
# located which contain the messages
|
|
||||||
# which the bot will randomly send
|
|
||||||
# (1 file = 1 message)
|
|
||||||
|
|
||||||
# IDLE_MESSAGE_CHANNEL_ID
|
|
||||||
# the channel where the bot will post messages to
|
|
||||||
|
|
||||||
# QUESTION_SLEEPING_TIME (number)
|
|
||||||
# # Variable that indicates when the bot answers after a question has been asked
|
|
||||||
# (in scheduler cycles)
|
|
||||||
|
|
||||||
# #######################
|
|
||||||
# "AUTO_EVENTS"
|
|
||||||
# #######################
|
|
||||||
|
|
||||||
# The Auto Events.
|
|
||||||
# this is used in three contexts:
|
|
||||||
# 1. Automatic creation of the event
|
|
||||||
# 2. Automatic reminder of subscribed users
|
|
||||||
# 3. in the /subscribe command
|
|
||||||
# this needs to be an array of dict
|
|
||||||
+40
-40
@@ -1,44 +1,44 @@
|
|||||||
{
|
{
|
||||||
"secret" :
|
"secret": {
|
||||||
{
|
"BOT_TOKEN": "YOURBOTTOKEN",
|
||||||
"BOT_TOKEN" : "YOURBOTTOKEN",
|
"CLIENT_ID": "YOURCLIENTID"
|
||||||
"GUILD_ID" : "YOURGUILDID",
|
|
||||||
"CLIENT_ID" : "YOURCLIENTID",
|
|
||||||
"AVOID_SPAM" : 1
|
|
||||||
},
|
},
|
||||||
"config" :
|
"guilds": {
|
||||||
{
|
"123456456": {
|
||||||
"CHANNEL_IDLE_INTERVAL": 4,
|
"config": {
|
||||||
"IDLE_MESSAGE_DIR" : "bot_messages",
|
"CHANNEL_IDLE_INTERVAL": 4,
|
||||||
"IDLE_MESSAGE_CHANNEL_ID" : 12345678900,
|
"IDLE_MESSAGE_DIR": "bot_messages",
|
||||||
"QUESTION_SLEEPING_TIME" : 2,
|
"IDLE_MESSAGE_CHANNEL_ID": 12345678900,
|
||||||
"SUPPORT_CHANNEL_ID" : 1234567
|
"QUESTION_SLEEPING_TIME": 2,
|
||||||
},
|
"SUPPORT_CHANNEL_ID": 1234567,
|
||||||
"AUTO_EVENTS" :
|
"AVOID_SPAM": 1
|
||||||
[
|
},
|
||||||
{
|
"AUTO_EVENTS": [
|
||||||
"title":"Sunday Funday session (AM)",
|
{
|
||||||
"description":"Chat with Marc and the folks here on the server ! Share your screen if you want to walk through a problem. Talk about tech stuff with the other members or just listen in...",
|
"title": "Sunday Funday session (AM)",
|
||||||
"channel":12345678900,
|
"description": "Chat with Marc and the folks here on the server ! Share your screen if you want to walk through a problem. Talk about tech stuff with the other members or just listen in...",
|
||||||
"notify_hint":"get notified when the AM session starts",
|
"channel": 12345678900,
|
||||||
"subscription_role":"notify_am",
|
"notify_hint": "get notified when the AM session starts",
|
||||||
"subscription_role_num":12345678900,
|
"subscription_role": "notify_am",
|
||||||
"notify_minutes":30,
|
"subscription_role_num": 12345678900,
|
||||||
"day_of_week":6,
|
"notify_minutes": 30,
|
||||||
"start_time":"09:00:00",
|
"day_of_week": 6,
|
||||||
"end_time":"10:00:00"
|
"start_time": "09:00:00",
|
||||||
},
|
"end_time": "10:00:00"
|
||||||
{
|
},
|
||||||
"title":"Sunday Funday session (PM)",
|
{
|
||||||
"description":"Chat with Marc and the folks here on the server ! Share your screen if you want to walk through a problem. Talk about tech stuff with the other members or just listen in...",
|
"title": "Sunday Funday session (PM)",
|
||||||
"channel":12345678900,
|
"description": "Chat with Marc and the folks here on the server ! Share your screen if you want to walk through a problem. Talk about tech stuff with the other members or just listen in...",
|
||||||
"notify_hint":"get notified when the PM session starts",
|
"channel": 12345678900,
|
||||||
"subscription_role":"notify_pm",
|
"notify_hint": "get notified when the PM session starts",
|
||||||
"subscription_role_num":12345678900,
|
"subscription_role": "notify_pm",
|
||||||
"notify_minutes":30,
|
"subscription_role_num": 12345678900,
|
||||||
"day_of_week":6,
|
"notify_minutes": 30,
|
||||||
"start_time":"18:00:00",
|
"day_of_week": 6,
|
||||||
"end_time":"19:00:00"
|
"start_time": "18:00:00",
|
||||||
|
"end_time": "19:00:00"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,4 @@
|
|||||||
import classes.bot as bot
|
import classes.bot as bot
|
||||||
import config
|
|
||||||
|
|
||||||
if config.cfg is None:
|
client = bot.OMFBot()
|
||||||
config.readConfig()
|
client.run()
|
||||||
|
|
||||||
client = bot.OMFClient()
|
|
||||||
client.run(config.SECRETS["BOT_TOKEN"])
|
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"secret": {
|
||||||
|
"BOT_TOKEN": "YOURBOTTOKEN",
|
||||||
|
"CLIENT_ID": "YOURCLIENTID"
|
||||||
|
},
|
||||||
|
"guilds":
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user