Robocronp: Add robocronp and some timed commands
- Added: .timemute - Added: .timeban - Added: .listjobs - Added: .deletejob - Many bugfixes are also included~ You'll need to restart your copy of robocop-ng after pulling this.
This commit is contained in:
parent
e148e04a87
commit
d9776ecba9
9 changed files with 311 additions and 21 deletions
28
README.md
28
README.md
|
@ -1,6 +1,6 @@
|
||||||
# Robocop-ng
|
# Robocop-ng
|
||||||
|
|
||||||
Next-gen rewrite of Kurisu/Robocop bot used on ReSwitched bot with discord.py rewrite, designed to be clean, fast and un-bloated.
|
Next-gen rewrite of Kurisu/Robocop bot used on ReSwitched bot with discord.py rewrite, designed to be relatively clean, consistent and un-bloated.
|
||||||
|
|
||||||
Code is based on https://gitlab.com/ao/dpybotbase and https://github.com/916253/Kurisu-Reswitched.
|
Code is based on https://gitlab.com/ao/dpybotbase and https://github.com/916253/Kurisu-Reswitched.
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ If you're moving from Kurisu/Robocop, and want to preserve your data, you'll wan
|
||||||
|
|
||||||
## TODO
|
## TODO
|
||||||
|
|
||||||
All Kurisu/Robocop features are now supported.
|
All Robocop features are now supported.
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary>List of added Kurisu/Robocop features</summary>
|
<summary>List of added Kurisu/Robocop features</summary>
|
||||||
|
@ -83,9 +83,14 @@ Main goal of this project is to get Robocop functionality done, secondary goal i
|
||||||
- [ ] New feature: Modmail
|
- [ ] New feature: Modmail
|
||||||
- [ ] New feature: Submiterr (relies on modmail)
|
- [ ] New feature: Submiterr (relies on modmail)
|
||||||
- [ ] New feature: Highlights (problematic words automatically get posted to modmail channel, relies on modmail)
|
- [ ] New feature: Highlights (problematic words automatically get posted to modmail channel, relies on modmail)
|
||||||
- [ ] A system for running tasks in background with an interval (will be called robocronp)
|
- [ ] Feature creep: Shortlink completion (gl/ao/etc)
|
||||||
- [ ] New moderation feature: mutetime (mute with time, relies on robocronp)
|
- [ ] Feature creep: Pleroma embedding
|
||||||
|
- [x] A system for running jobs in background with an interval (will be called robocronp)
|
||||||
|
- [x] Commands to list said jobs and remove them
|
||||||
|
- [x] New moderation feature: timemute (mute with time, relies on robocronp)
|
||||||
|
- [x] New moderation feature: timeban (ban with expiry, relies on robocronp)
|
||||||
- [ ] New moderation feature: timelock (channel lockdown with time, relies on robocronp)
|
- [ ] New moderation feature: timelock (channel lockdown with time, relies on robocronp)
|
||||||
|
- [x] Improvements to lockdown to ensure that staff can talk
|
||||||
- [x] New moderation feature: Display of mutes, bans and kicks on listwarns (.userlog now)
|
- [x] New moderation feature: Display of mutes, bans and kicks on listwarns (.userlog now)
|
||||||
- [x] New moderation feature: User notes
|
- [x] New moderation feature: User notes
|
||||||
- [x] New moderation feature: Reaction removing features (thanks misson20000!)
|
- [x] New moderation feature: Reaction removing features (thanks misson20000!)
|
||||||
|
@ -93,12 +98,25 @@ Main goal of this project is to get Robocop functionality done, secondary goal i
|
||||||
- [x] New self-moderation feature: .mywarns
|
- [x] New self-moderation feature: .mywarns
|
||||||
- [x] Remove sh, remove risky stuff from eval
|
- [x] Remove sh, remove risky stuff from eval
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>TODO for robocronp</summary>
|
||||||
|
<p>
|
||||||
|
|
||||||
|
the following require me to rethink some of the lockdown code, which I don't feel like
|
||||||
|
|
||||||
|
[ ] lockdown in helper
|
||||||
|
[ ] timelock command
|
||||||
|
[ ] working cronjob for unlock
|
||||||
|
|
||||||
|
</p>
|
||||||
|
</details>
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Thanks to
|
## Thanks to
|
||||||
|
|
||||||
- ReSwitched community, for being amazing
|
- ReSwitched community, for being amazing
|
||||||
- ihaveamac and f916253 for the original kurisu/robocop
|
- ihaveamac/ihaveahax and f916253 for the original kurisu/robocop
|
||||||
- tomGER for working hard on rewriting the .err/.serr commands, those were a nightmare
|
- tomGER for working hard on rewriting the .err/.serr commands, those were a nightmare
|
||||||
- misson20000 for adding in reaction removal feature and putting up with my many BS requests on PR reviews
|
- misson20000 for adding in reaction removal feature and putting up with my many BS requests on PR reviews
|
||||||
|
|
||||||
|
|
21
Robocop.py
21
Robocop.py
|
@ -1,4 +1,5 @@
|
||||||
import os
|
import os
|
||||||
|
import asyncio
|
||||||
import sys
|
import sys
|
||||||
import logging
|
import logging
|
||||||
import logging.handlers
|
import logging.handlers
|
||||||
|
@ -38,27 +39,31 @@ def get_prefix(bot, message):
|
||||||
|
|
||||||
|
|
||||||
wanted_jsons = ["data/restrictions.json",
|
wanted_jsons = ["data/restrictions.json",
|
||||||
|
"data/robocronptab.json",
|
||||||
"data/userlog.json"]
|
"data/userlog.json"]
|
||||||
|
|
||||||
initial_extensions = ['cogs.common',
|
initial_extensions = ['cogs.common',
|
||||||
'cogs.admin',
|
'cogs.admin',
|
||||||
'cogs.basic',
|
|
||||||
'cogs.err',
|
|
||||||
'cogs.verification',
|
'cogs.verification',
|
||||||
'cogs.logs',
|
|
||||||
'cogs.lockdown',
|
|
||||||
'cogs.legacy',
|
|
||||||
'cogs.links',
|
|
||||||
'cogs.mod',
|
'cogs.mod',
|
||||||
'cogs.mod_note',
|
'cogs.mod_note',
|
||||||
'cogs.mod_reacts',
|
'cogs.mod_reacts',
|
||||||
'cogs.mod_userlog',
|
'cogs.mod_userlog',
|
||||||
|
'cogs.mod_timed',
|
||||||
|
'cogs.basic',
|
||||||
|
'cogs.logs',
|
||||||
|
'cogs.err',
|
||||||
|
'cogs.lockdown',
|
||||||
|
'cogs.legacy',
|
||||||
|
'cogs.links',
|
||||||
|
'cogs.robocronp',
|
||||||
'cogs.meme']
|
'cogs.meme']
|
||||||
|
|
||||||
bot = commands.Bot(command_prefix=get_prefix,
|
bot = commands.Bot(command_prefix=get_prefix,
|
||||||
description=config.bot_description, pm_help=True)
|
description=config.bot_description, pm_help=True)
|
||||||
|
|
||||||
bot.log = log
|
bot.log = log
|
||||||
|
bot.loop = asyncio.get_event_loop()
|
||||||
bot.config = config
|
bot.config = config
|
||||||
bot.script_name = script_name
|
bot.script_name = script_name
|
||||||
bot.wanted_jsons = wanted_jsons
|
bot.wanted_jsons = wanted_jsons
|
||||||
|
@ -68,7 +73,7 @@ if __name__ == '__main__':
|
||||||
try:
|
try:
|
||||||
bot.load_extension(extension)
|
bot.load_extension(extension)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.error(f'Failed to load extension {extension}.', file=sys.stderr)
|
log.error(f'Failed to load extension {extension}.')
|
||||||
log.error(traceback.print_exc())
|
log.error(traceback.print_exc())
|
||||||
|
|
||||||
|
|
||||||
|
@ -181,4 +186,4 @@ for wanted_json in wanted_jsons:
|
||||||
with open(wanted_json, "w") as f:
|
with open(wanted_json, "w") as f:
|
||||||
f.write("{}")
|
f.write("{}")
|
||||||
|
|
||||||
bot.run(config.token, bot=True, reconnect=True)
|
bot.run(config.token, bot=True, reconnect=True, loop=bot.loop)
|
||||||
|
|
|
@ -8,17 +8,28 @@ class Lockdown:
|
||||||
def __init__(self, bot):
|
def __init__(self, bot):
|
||||||
self.bot = bot
|
self.bot = bot
|
||||||
|
|
||||||
|
async def unlock_for_staff(self, channel: discord.TextChannel, issuer):
|
||||||
|
for role in config.staff_role_ids:
|
||||||
|
try:
|
||||||
|
await channel.set_permissions(channel.guild.get_role(role),
|
||||||
|
send_messages=False,
|
||||||
|
reason=str(issuer))
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
@commands.guild_only()
|
@commands.guild_only()
|
||||||
@commands.check(check_if_staff)
|
@commands.check(check_if_staff)
|
||||||
@commands.command()
|
@commands.command()
|
||||||
async def lock(self, ctx, channel: discord.TextChannel = None,
|
async def lock(self, ctx, channel: discord.TextChannel = None,
|
||||||
soft: bool = False):
|
soft: bool = False):
|
||||||
"""Prevents people from speaking in current channel, staff only."""
|
"""Prevents people from speaking in a channel, staff only.
|
||||||
|
|
||||||
|
Defaults to current channel."""
|
||||||
if not channel:
|
if not channel:
|
||||||
channel = ctx.channel
|
channel = ctx.channel
|
||||||
log_channel = self.bot.get_channel(config.log_channel)
|
log_channel = self.bot.get_channel(config.log_channel)
|
||||||
|
|
||||||
if ctx.channel.id in config.community_channels:
|
if channel.id in config.community_channels:
|
||||||
roles = [config.named_roles["community"],
|
roles = [config.named_roles["community"],
|
||||||
config.named_roles["hacker"]]
|
config.named_roles["hacker"]]
|
||||||
else:
|
else:
|
||||||
|
@ -26,9 +37,11 @@ class Lockdown:
|
||||||
ctx.guild.default_role.id]
|
ctx.guild.default_role.id]
|
||||||
|
|
||||||
for role in roles:
|
for role in roles:
|
||||||
await ctx.channel.set_permissions(ctx.guild.get_role(role),
|
await channel.set_permissions(channel.guild.get_role(role),
|
||||||
send_messages=False,
|
send_messages=False,
|
||||||
reason=str(ctx.author))
|
reason=str(ctx.author))
|
||||||
|
|
||||||
|
await self.unlock_for_staff(channel, ctx.author)
|
||||||
|
|
||||||
public_msg = "🔒 Channel locked down. "
|
public_msg = "🔒 Channel locked down. "
|
||||||
if not soft:
|
if not soft:
|
||||||
|
@ -57,6 +70,8 @@ class Lockdown:
|
||||||
roles = [config.named_roles["participant"],
|
roles = [config.named_roles["participant"],
|
||||||
ctx.guild.default_role.id]
|
ctx.guild.default_role.id]
|
||||||
|
|
||||||
|
await self.unlock_for_staff(channel, ctx.author)
|
||||||
|
|
||||||
for role in roles:
|
for role in roles:
|
||||||
await ctx.channel.set_permissions(ctx.guild.get_role(role),
|
await ctx.channel.set_permissions(ctx.guild.get_role(role),
|
||||||
send_messages=True,
|
send_messages=True,
|
||||||
|
|
|
@ -116,7 +116,8 @@ class Mod:
|
||||||
chan_message += f"✏️ __Reason__: \"{reason}\""
|
chan_message += f"✏️ __Reason__: \"{reason}\""
|
||||||
else:
|
else:
|
||||||
chan_message += "Please add an explanation below. In the future"\
|
chan_message += "Please add an explanation below. In the future"\
|
||||||
", it is recommended to use `.ban <user> [reason]`"\
|
", it is recommended to use "\
|
||||||
|
"`.kick <user> [reason]`"\
|
||||||
" as the reason is automatically sent to the user."
|
" as the reason is automatically sent to the user."
|
||||||
|
|
||||||
log_channel = self.bot.get_channel(config.log_channel)
|
log_channel = self.bot.get_channel(config.log_channel)
|
||||||
|
|
|
@ -15,7 +15,7 @@ class ModNote:
|
||||||
"""Adds a note to a user, staff only."""
|
"""Adds a note to a user, staff only."""
|
||||||
userlog(target.id, ctx.author, note,
|
userlog(target.id, ctx.author, note,
|
||||||
"notes", target.name)
|
"notes", target.name)
|
||||||
await ctx.send(f"{target.mention}: noted!")
|
await ctx.send(f"{ctx.author.mention}: noted!")
|
||||||
|
|
||||||
@commands.guild_only()
|
@commands.guild_only()
|
||||||
@commands.check(check_if_staff)
|
@commands.check(check_if_staff)
|
||||||
|
|
122
cogs/mod_timed.py
Normal file
122
cogs/mod_timed.py
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
import discord
|
||||||
|
import config
|
||||||
|
import time
|
||||||
|
from discord.ext import commands
|
||||||
|
from helpers.checks import check_if_staff
|
||||||
|
from helpers.robocronp import add_job
|
||||||
|
from helpers.userlogs import userlog
|
||||||
|
from helpers.restrictions import add_restriction
|
||||||
|
|
||||||
|
|
||||||
|
class ModTimed:
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
|
def check_if_target_is_staff(self, target):
|
||||||
|
return any(r.id in config.staff_role_ids for r in target.roles)
|
||||||
|
|
||||||
|
@commands.guild_only()
|
||||||
|
@commands.bot_has_permissions(ban_members=True)
|
||||||
|
@commands.check(check_if_staff)
|
||||||
|
@commands.command()
|
||||||
|
async def timeban(self, ctx, target: discord.Member,
|
||||||
|
hours: int, *, reason: str = ""):
|
||||||
|
"""Bans a user for a specified amount of hours, staff only."""
|
||||||
|
# Hedge-proofing the code
|
||||||
|
if target == ctx.author:
|
||||||
|
return await ctx.send("You can't do mod actions on yourself.")
|
||||||
|
elif self.check_if_target_is_staff(target):
|
||||||
|
return await ctx.send("I can't ban this user as "
|
||||||
|
"they're a member of staff.")
|
||||||
|
|
||||||
|
userlog(target.id, ctx.author, f"{reason} (Timed, for {hours}h)",
|
||||||
|
"bans", target.name)
|
||||||
|
|
||||||
|
safe_name = self.bot.escape_message(str(target))
|
||||||
|
|
||||||
|
dm_message = f"You were banned from {ctx.guild.name}."
|
||||||
|
if reason:
|
||||||
|
dm_message += f" The given reason is: \"{reason}\"."
|
||||||
|
dm_message += f"\n\nThis ban will expire in {hours} hours."
|
||||||
|
|
||||||
|
try:
|
||||||
|
await target.send(dm_message)
|
||||||
|
except discord.errors.Forbidden:
|
||||||
|
# Prevents ban issues in cases where user blocked bot
|
||||||
|
# or has DMs disabled
|
||||||
|
pass
|
||||||
|
|
||||||
|
await target.ban(reason=f"{ctx.author}, reason: {reason}",
|
||||||
|
delete_message_days=0)
|
||||||
|
chan_message = f"⛔ **Timed Ban**: {ctx.author.mention} banned "\
|
||||||
|
f"{target.mention} for {hours} hours | {safe_name}\n"\
|
||||||
|
f"🏷 __User ID__: {target.id}\n"
|
||||||
|
if reason:
|
||||||
|
chan_message += f"✏️ __Reason__: \"{reason}\""
|
||||||
|
else:
|
||||||
|
chan_message += "Please add an explanation below. In the future"\
|
||||||
|
", it is recommended to use `.ban <user> [reason]`"\
|
||||||
|
" as the reason is automatically sent to the user."
|
||||||
|
|
||||||
|
expiry_timestamp = time.time() + (hours * 3600)
|
||||||
|
add_job("unban", target.id, {"guild": ctx.guild.id}, expiry_timestamp)
|
||||||
|
|
||||||
|
log_channel = self.bot.get_channel(config.log_channel)
|
||||||
|
await log_channel.send(chan_message)
|
||||||
|
await ctx.send(f"{safe_name} is now b& for {hours} hours. 👍")
|
||||||
|
|
||||||
|
@commands.guild_only()
|
||||||
|
@commands.check(check_if_staff)
|
||||||
|
@commands.command()
|
||||||
|
async def timemute(self, ctx, target: discord.Member,
|
||||||
|
hours: int, *, reason: str = ""):
|
||||||
|
"""Mutes a user for a specified amount of hours, staff only."""
|
||||||
|
# Hedge-proofing the code
|
||||||
|
if target == ctx.author:
|
||||||
|
return await ctx.send("You can't do mod actions on yourself.")
|
||||||
|
elif self.check_if_target_is_staff(target):
|
||||||
|
return await ctx.send("I can't mute this user as "
|
||||||
|
"they're a member of staff.")
|
||||||
|
|
||||||
|
userlog(target.id, ctx.author, f"{reason} (Timed, for {hours}h)",
|
||||||
|
"mutes", target.name)
|
||||||
|
|
||||||
|
safe_name = self.bot.escape_message(str(target))
|
||||||
|
|
||||||
|
dm_message = f"You were muted!"
|
||||||
|
if reason:
|
||||||
|
dm_message += f" The given reason is: \"{reason}\"."
|
||||||
|
dm_message += f"\n\nThis mute will expire in {hours} hours."
|
||||||
|
|
||||||
|
try:
|
||||||
|
await target.send(dm_message)
|
||||||
|
except discord.errors.Forbidden:
|
||||||
|
# Prevents kick issues in cases where user blocked bot
|
||||||
|
# or has DMs disabled
|
||||||
|
pass
|
||||||
|
|
||||||
|
mute_role = ctx.guild.get_role(config.mute_role)
|
||||||
|
|
||||||
|
await target.add_roles(mute_role, reason=str(ctx.author))
|
||||||
|
|
||||||
|
chan_message = f"🔇 **Timed Mute**: {ctx.author.mention} muted "\
|
||||||
|
f"{target.mention} for {hours} hours | {safe_name}\n"\
|
||||||
|
f"🏷 __User ID__: {target.id}\n"
|
||||||
|
if reason:
|
||||||
|
chan_message += f"✏️ __Reason__: \"{reason}\""
|
||||||
|
else:
|
||||||
|
chan_message += "Please add an explanation below. In the future, "\
|
||||||
|
"it is recommended to use `.mute <user> [reason]`"\
|
||||||
|
" as the reason is automatically sent to the user."
|
||||||
|
|
||||||
|
expiry_timestamp = time.time() + (hours * 3600)
|
||||||
|
add_job("unmute", target.id, {"guild": ctx.guild.id}, expiry_timestamp)
|
||||||
|
|
||||||
|
log_channel = self.bot.get_channel(config.log_channel)
|
||||||
|
await log_channel.send(chan_message)
|
||||||
|
await ctx.send(f"{target.mention} can no longer speak.")
|
||||||
|
add_restriction(target.id, config.mute_role)
|
||||||
|
|
||||||
|
|
||||||
|
def setup(bot):
|
||||||
|
bot.add_cog(ModTimed(bot))
|
|
@ -69,7 +69,7 @@ class ModUserlog:
|
||||||
if idx < 1:
|
if idx < 1:
|
||||||
return "Index is below 1!"
|
return "Index is below 1!"
|
||||||
event = userlog[uid][event_type][idx - 1]
|
event = userlog[uid][event_type][idx - 1]
|
||||||
event_name = userlog_event_types[event_type].lower()
|
event_name = userlog_event_types[event_type]
|
||||||
embed = discord.Embed(color=discord.Color.dark_red(),
|
embed = discord.Embed(color=discord.Color.dark_red(),
|
||||||
title=f"{event_name} {idx} on "
|
title=f"{event_name} {idx} on "
|
||||||
f"{event['timestamp']}",
|
f"{event['timestamp']}",
|
||||||
|
|
92
cogs/robocronp.py
Normal file
92
cogs/robocronp.py
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
import asyncio
|
||||||
|
import config
|
||||||
|
import time
|
||||||
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
|
from helpers.robocronp import get_crontab, delete_job
|
||||||
|
from helpers.restrictions import remove_restriction
|
||||||
|
from helpers.checks import check_if_staff
|
||||||
|
|
||||||
|
|
||||||
|
class Robocronp:
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
bot.loop.create_task(self.minutely())
|
||||||
|
# bot.loop.create_task(self.hourly())
|
||||||
|
|
||||||
|
@commands.guild_only()
|
||||||
|
@commands.check(check_if_staff)
|
||||||
|
@commands.command()
|
||||||
|
async def listjobs(self, ctx):
|
||||||
|
"""Lists timed robocronp jobs, staff only."""
|
||||||
|
ctab = get_crontab()
|
||||||
|
embed = discord.Embed(title=f"Active robocronp jobs")
|
||||||
|
for jobtype in ctab:
|
||||||
|
for jobtimestamp in ctab[jobtype]:
|
||||||
|
for job_name in ctab[jobtype][jobtimestamp]:
|
||||||
|
job_details = repr(ctab[jobtype][jobtimestamp][job_name])
|
||||||
|
embed.add_field(name=f"{jobtype} for {job_name}",
|
||||||
|
value=f"Timestamp: {jobtimestamp}, "
|
||||||
|
f"Details: {job_details}",
|
||||||
|
inline=False)
|
||||||
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
@commands.guild_only()
|
||||||
|
@commands.check(check_if_staff)
|
||||||
|
@commands.command(aliases=["removejob"])
|
||||||
|
async def deletejob(self, ctx, timestamp: str,
|
||||||
|
job_type: str, job_name: str):
|
||||||
|
"""Removes a timed robocronp job, staff only.
|
||||||
|
|
||||||
|
You'll need to supply:
|
||||||
|
- timestamp (like 1545981602)
|
||||||
|
- job type (like "unban")
|
||||||
|
- job name (userid, like 420332322307571713)
|
||||||
|
|
||||||
|
You can get all 3 from listjobs command."""
|
||||||
|
delete_job(timestamp, job_type, job_name)
|
||||||
|
await ctx.send(f"{ctx.author.mention}: Deleted!")
|
||||||
|
|
||||||
|
async def do_jobs(self, ctab, jobtype, timestamp):
|
||||||
|
for job_name in ctab[jobtype][timestamp]:
|
||||||
|
job_details = ctab[jobtype][timestamp][job_name]
|
||||||
|
if jobtype == "unban":
|
||||||
|
target_user = await self.bot.get_user_info(job_name)
|
||||||
|
target_guild = self.bot.get_guild(job_details["guild"])
|
||||||
|
await target_guild.unban(target_user,
|
||||||
|
reason="Robocronp: Timed ban expired.")
|
||||||
|
delete_job(timestamp, jobtype, job_name)
|
||||||
|
elif jobtype == "unmute":
|
||||||
|
remove_restriction(job_name, config.mute_role)
|
||||||
|
target_guild = self.bot.get_guild(job_details["guild"])
|
||||||
|
target_member = target_guild.get_member(int(job_name))
|
||||||
|
target_role = target_guild.get_role(config.mute_role)
|
||||||
|
await target_member.remove_roles(target_role,
|
||||||
|
reason="Robocronp: Timed "
|
||||||
|
"mute expired.")
|
||||||
|
delete_job(timestamp, jobtype, job_name)
|
||||||
|
|
||||||
|
async def minutely(self):
|
||||||
|
await self.bot.wait_until_ready()
|
||||||
|
while not self.bot.is_closed():
|
||||||
|
try:
|
||||||
|
ctab = get_crontab()
|
||||||
|
timestamp = time.time()
|
||||||
|
for jobtype in ctab:
|
||||||
|
for jobtimestamp in ctab[jobtype]:
|
||||||
|
if timestamp > int(jobtimestamp):
|
||||||
|
await self.do_jobs(ctab, jobtype, jobtimestamp)
|
||||||
|
except:
|
||||||
|
# Don't kill cronjobs if something goes wrong.
|
||||||
|
pass
|
||||||
|
await asyncio.sleep(60)
|
||||||
|
|
||||||
|
# async def hourly(self):
|
||||||
|
# await self.bot.wait_until_ready()
|
||||||
|
# while not self.bot.is_closed():
|
||||||
|
# # Your stuff goes here
|
||||||
|
# await asyncio.sleep(3600)
|
||||||
|
|
||||||
|
|
||||||
|
def setup(bot):
|
||||||
|
bot.add_cog(Robocronp(bot))
|
37
helpers/robocronp.py
Normal file
37
helpers/robocronp.py
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
import json
|
||||||
|
import math
|
||||||
|
|
||||||
|
|
||||||
|
def get_crontab():
|
||||||
|
with open("data/robocronptab.json", "r") as f:
|
||||||
|
return json.load(f)
|
||||||
|
|
||||||
|
|
||||||
|
def set_crontab(contents):
|
||||||
|
with open("data/robocronptab.json", "w") as f:
|
||||||
|
f.write(contents)
|
||||||
|
|
||||||
|
|
||||||
|
def add_job(job_type, job_name, job_details, timestamp):
|
||||||
|
timestamp = str(math.floor(timestamp))
|
||||||
|
job_name = str(job_name)
|
||||||
|
ctab = get_crontab()
|
||||||
|
|
||||||
|
if job_type not in ctab:
|
||||||
|
ctab[job_type] = {}
|
||||||
|
|
||||||
|
if timestamp not in ctab[job_type]:
|
||||||
|
ctab[job_type][timestamp] = {}
|
||||||
|
|
||||||
|
ctab[job_type][timestamp][job_name] = job_details
|
||||||
|
set_crontab(json.dumps(ctab))
|
||||||
|
|
||||||
|
|
||||||
|
def delete_job(timestamp, job_type, job_name):
|
||||||
|
timestamp = str(timestamp)
|
||||||
|
job_name = str(job_name)
|
||||||
|
ctab = get_crontab()
|
||||||
|
|
||||||
|
del ctab[job_type][timestamp][job_name]
|
||||||
|
|
||||||
|
set_crontab(json.dumps(ctab))
|
Loading…
Reference in a new issue