diff --git a/README.md b/README.md
index 5ffd023..0bb7fc2 100644
--- a/README.md
+++ b/README.md
@@ -17,6 +17,7 @@ Cog Function
| sayurl | **Alpha** | Convert any URL into text and post to discord
No error checking and pretty spammy |
| secrethitler | **Incomplete** | Play the Secret Hitler game
Concept, no work done yet |
| stealemoji | **Alpha** | Steals any custom emoji it sees in a reaction
Some planned upgrades for server generation |
+| timerole | **Alpha** | Add roles to members after specified time on the server
Upgraded from V2, please report any bugs |
| werewolf | **Alpha** | Play the classic party game Werewolf within discord
Another massive project currently being developed, will be fully customizable |
diff --git a/timerole/__init__.py b/timerole/__init__.py
new file mode 100644
index 0000000..9e7f94b
--- /dev/null
+++ b/timerole/__init__.py
@@ -0,0 +1,5 @@
+from .timerole import Timerole
+
+
+def setup(bot):
+ bot.add_cog(Timerole(bot))
diff --git a/timerole/info.json b/timerole/info.json
new file mode 100644
index 0000000..3ea5a0e
--- /dev/null
+++ b/timerole/info.json
@@ -0,0 +1,22 @@
+{
+ "author": [
+ "Bobloy"
+ ],
+ "bot_version": [
+ 3,
+ 0,
+ 0
+ ],
+ "description": "Apply roles based on the # of days on server",
+ "hidden": false,
+ "install_msg": "Thank you for installing timerole. Configure with [p]timerole",
+ "requirements": [],
+ "short": "Apply roles after # of days",
+ "tags": [
+ "bobloy",
+ "utilities",
+ "tools",
+ "tool",
+ "roles"
+ ]
+}
\ No newline at end of file
diff --git a/timerole/timerole.py b/timerole/timerole.py
new file mode 100644
index 0000000..fb2fff2
--- /dev/null
+++ b/timerole/timerole.py
@@ -0,0 +1,143 @@
+import asyncio
+from datetime import timedelta, datetime
+
+import discord
+from redbot.core import Config, checks, commands
+from redbot.core.bot import Red
+from redbot.core.utils.chat_formatting import pagify
+
+
+class Timerole:
+ """Add roles to users based on time on server"""
+
+ def __init__(self, bot: Red):
+ self.bot = bot
+ self.config = Config.get_conf(self, identifier=9811198108111121, force_registration=True)
+ default_global = {}
+ default_guild = {
+ 'announce': None,
+ 'roles': {}
+ }
+
+ self.config.register_global(**default_global)
+ self.config.register_guild(**default_guild)
+
+ @commands.command()
+ @checks.guildowner()
+ @commands.guild_only()
+ async def runtimerole(self, ctx: commands.Context):
+ """Trigger the daily timerole"""
+
+ await self.timerole_update()
+ await ctx.send("Success")
+
+ @commands.group()
+ @checks.mod_or_permissions(administrator=True)
+ @commands.guild_only()
+ async def timerole(self, ctx):
+ """Adjust timerole settings"""
+ if ctx.invoked_subcommand is None:
+ await ctx.send_help()
+
+ @timerole.command()
+ async def addrole(self, ctx: commands.Context, role: discord.Role, days: int, *requiredroles: discord.Role):
+ """Add a role to be added after specified time on server"""
+ guild = ctx.guild
+
+ to_set = {'days': days}
+ if requiredroles:
+ to_set['required'] = [r.id for r in requiredroles]
+
+ await self.config.guild(guild).roles.set_raw(role.id, value=to_set)
+ await ctx.send("Time Role for {0} set to {1} days".format(role.name, days))
+
+ @timerole.command()
+ async def channel(self, ctx: commands.Context, channel: discord.TextChannel):
+ """Sets the announce channel for role adds"""
+ guild = ctx.guild
+
+ await self.config.guild(guild).announce.set(channel.id)
+ await ctx.send("Announce channel set to {0}".format(channel.mention))
+
+ @timerole.command()
+ async def removerole(self, ctx: commands.Context, role: discord.Role):
+ """Removes a role from being added after specified time"""
+ guild = ctx.guild
+
+ await self.config.guild(guild).roles.set_raw(role.id, value=None)
+ await ctx.send("{0} will no longer be applied".format(role.name))
+
+ @timerole.command()
+ async def list(self, ctx: commands.Context):
+ """Lists all currently setup timeroles"""
+ guild = ctx.guild
+
+ role_dict = await self.config.guild(guild).roles()
+ out = ""
+ for r_id, r_data in role_dict.items():
+ if r_data is not None:
+ role = discord.utils.get(guild.roles, id=int(r_id))
+ r_roles = []
+ if role is None:
+ role = r_id
+ if 'required' in r_data:
+ r_roles = [str(discord.utils.get(guild.roles, id=int(new_id))) for new_id in r_data['required']]
+ out += "{} || {} days || requires: {}\n".format(str(role), r_data['days'], r_roles)
+ await ctx.maybe_send_embed(out)
+
+ async def timerole_update(self):
+ for guild in self.bot.guilds:
+ addlist = []
+
+ role_dict = await self.config.guild(guild).roles()
+ if not any(role_data for role_data in role_dict.values()): # No roles
+ continue
+
+ for member in guild.members:
+ has_roles = [r.id for r in member.roles]
+
+ get_roles = [int(rID) for rID, r_data in role_dict.items() if r_data is not None]
+
+ check_roles = set(get_roles) - set(has_roles)
+
+ for role_id in check_roles:
+ # Check for required role
+ if 'required' in role_dict[str(role_id)]:
+ if not set(role_dict[str(role_id)]['required']) & set(has_roles):
+ # Doesn't have required role
+ continue
+
+ if member.joined_at + timedelta(
+ days=role_dict[str(role_id)]['days']) <= datetime.today():
+ # Qualifies
+ addlist.append((member, role_id))
+
+ channel = await self.config.guild(guild).announce()
+ if channel is not None:
+ channel = guild.get_channel(channel)
+
+ title = "**These members have received the following roles**\n"
+ results = ""
+ for member, role_id in addlist:
+ role = discord.utils.get(guild.roles, id=role_id)
+ await member.add_roles(role, reason="Timerole")
+ results += "{} : {}\n".format(member.display_name, role.name)
+
+ if channel is not None and results:
+ await channel.send(title)
+ for page in pagify(
+ results, shorten_by=50):
+ await channel.send(page)
+
+ async def check_day(self):
+ while self is self.bot.get_cog("Timerole"):
+ tomorrow = datetime.now() + timedelta(days=1)
+ midnight = datetime(year=tomorrow.year, month=tomorrow.month,
+ day=tomorrow.day, hour=0, minute=0, second=0)
+
+ await asyncio.sleep((midnight - datetime.now()).seconds)
+
+ await self.timerole_update()
+
+ await asyncio.sleep(3)
+ # then start loop over again