Search code examples
pythondiscord.pytimeout

Discord.py Timeout server members


A few months ago I came up with the idea to make a functional discord bot for my friend's server. My friend asked me if I could make a member timeout command, so I started my research. Since discord.py will not be updated anymore, this question might be useless and time wasting, but I really want to try it anyways. I know Stack Overflow is about modifying code and not a code-writing service, but I genuinely don't know how I should do this.

My ideas were giving a member a 'Muted' or 'Timed Out' role for the specified time and removing it again after the timer stops, but then I am supposed to use a while loop causing the rest of the code to not be accessible anymore, same goes for using the time.sleep function.

I couldn't find anything about this on the internet, so my only hope is Stack Overflow. I don't want you to write entire programs in your answer, just where I might be looking for, so that I can figer the rest out myself.

Thanks in advance!


Solution

  • Discord recently released a timeout feature which is really good and takes away your problems of creating/removing a role with no send message perms. Discord.py may not recieve updates but, that does not stop you to write your own requests to discord API, or you can also use one of the forks which have already implemented this.

    Here is one simple non-bot script I wrote to make it work:

    import pprint
    import requests
    import datetime
    
    BASE = "https://discord.com/api/v9/"
    TOKEN = "BOT TOKEN" 
    
    
    def timeout_user(*, user_id: int, guild_id: int, until: int):
        endpoint = f'guilds/{guild_id}/members/{user_id}'
        headers = {"Authorization": f"Bot {TOKEN}"}
        url = BASE + endpoint
        timeout = (datetime.datetime.utcnow() + datetime.timedelta(minutes=time_in_mins)).isoformat()
        json = {'communication_disabled_until': timeout}
        session = requests.patch(url, json=json, headers=headers)
        if session.status_code in range(200, 299):
            return session.json()
        else: 
            return print("Did not find any\n", session.status_code)
    
    guild_id = 231
    user_id = 123
    time_in_mins = 2
    member = timeout_user(user_id=user_id, guild_id=guild_id,until=time_in_mins)
    pprint.pprint(member)
    
    {'avatar': None,
     'communication_disabled_until': '2021-12-23T09:49:58.965896+00:00',
     'deaf': False,
     'is_pending': False,
     'joined_at': '2021-12-23T09:06:30.927000+00:00',
     'mute': False,
     'nick': None,
     'pending': False,
     'premium_since': None,
     'roles': [],
     'user': {'avatar': 'avatar hash string',
              'discriminator': '1234',
              'id': 'Member ID',
              'public_flags': 128,
              'username': 'Member Name'}}
    

    Since discord.py is asynchronous, you might want an asynchronous code. Here is one quick integration

    import aiohttp
    import discord
    import datetime
    import warnings
    from discord.ext import commands
    
    warnings.filterwarnings("ignore", category=DeprecationWarning)
    intents = discord.Intents.all()
    bot = commands.Bot(command_prefix=['$',], intents=intents)
    bot.session = aiohttp.ClientSession()
    
    @bot.event
    async def on_ready():
        print(f"{bot.user.name} is ready to go!")
    
    async def timeout_user(*, user_id: int, guild_id: int, until):
        headers = {"Authorization": f"Bot {bot.http.token}"}
        url = f"https://discord.com/api/v9/guilds/{guild_id}/members/{user_id}"
        timeout = (datetime.datetime.utcnow() + datetime.timedelta(minutes=until)).isoformat()
        json = {'communication_disabled_until': timeout}
        async with bot.session.patch(url, json=json, headers=headers) as session:
            if session.status in range(200, 299):
               return True
            return False
    
    
    @bot.command()
    async def timeout(ctx: commands.Context, member: discord.Member, until: int):
        handshake = await timeout_user(user_id=member.id, guild_id=ctx.guild.id, until=until)
        if handshake:
             return await ctx.send(f"Successfully timed out user for {until} minutes.")
        await ctx.send("Something went wrong")
    
    bot.run("BOT TOKEN")
    

    You can read more about the endpoint here