diff --git a/purge_discord.py b/purge_discord.py index 9635dce..4e954f7 100755 --- a/purge_discord.py +++ b/purge_discord.py @@ -1,49 +1,40 @@ #!/bin/python3 import asyncio, aiohttp, os, sys, json from dotenv import load_dotenv - - -# method to print out the usage instructions if the program was called incorrectly -def usage(): - sys.exit("Usage: ./purge_discord.py [OPTION]... [ARGUMENT]...\n" - "Delete all the user's messages in the given Discord channel.\n" - "The channel may be specified using one of the following options:\n" - # "\t-i, --channel-id delete messages in the channel corresponding to the supplied ID\n" - "\t-u, --channel-url delete messages in the channel corresponding to the supplied URL") - +import argparse async def main(): - # parsing command-line arguments - if len(sys.argv) == 3: - # if sys.argv[1] == "-i" or sys.argv[1] == "--channel-id": - # channel = sys.argv[2] - # elif sys.argv[1] == "-u" or sys.argv[1] == "--channel-url": - if sys.argv[1] == "-u" or sys.argv[1] == "--channel-url": - guild = sys.argv[2].split("/")[-2] # parsing the server (guild) ID from the URL by splitting it on `/` and taking the second last segment - channel = sys.argv[2].split("/")[-1] # parsing the channel ID from the URL by splitting it on `/` and taking the last segment - - # setting host URL based on whether the channel is in @me or in a guild/server - if (guild == "@me"): - guild_url = "https://discord.com/api/v9/channels/" + channel - channel_url = guild_url - else: - guild_url = "https://discord.com/api/v9/guilds/" + guild - channel_url = "https://discord.com/api/v9/channels/" + channel - - else: - usage() - else: - usage() - + parser = argparse.ArgumentParser(description="Script to delete all a user's messages in a given Discord server") + parser.add_argument("-u", "--channel-url", type=str, help="URL of a channel in the server", required=True) + args=parser.parse_args() # reading Discord token from the .env file. should be in the format `DISCORD_TOKEN=` load_dotenv() token = os.getenv("DISCORD_TOKEN") if not token: - sys.exit("DISCORD_TOKEN environment variable is not set") + raise Exception("DISCORD_TOKEN environment variable is not set") + + guild = args.channel_url.split("/")[-2] # "guild" is discord's internal name for servers + channel = args.channel_url.split("/")[-1] + + # setting host URL based on whether the channel is in @me or in a guild/server + if (guild == "@me"): + guild_url = "https://discord.com/api/v9/channels/" + channel + channel_url = guild_url + else: + guild_url = "https://discord.com/api/v9/guilds/" + guild + channel_url = "https://discord.com/api/v9/channels/" + channel + + headers = { + "accept": "*/*", + "accept-language": "en-GB,en;q=0.8", + "authorization": token, + "origin": "https://discord.com", + "priority": "u=1, i", + "referer": "https://discord.com/channels/" + guild + "/" + channel, + } - headers = {"authorization": token} offset = 0 # messages are received from the API in batches of 25, so need to keep track of the offset when requesting to make sure no old messages are received to_delete = [] # list of messages to be deleted @@ -51,11 +42,10 @@ async def main(): async with aiohttp.ClientSession() as session: # getting the user ID pertaining to the Discord token that the script is using async with session.request("GET", "https://discord.com/api/v9/users/@me", headers=headers) as response: - try: + try: user = (await response.json())["id"] except KeyError: - print("User ID not found in JSON response. Actual JSON response: " + json.dumps(await response.json(), indent=4)) - sys.exit(1) + raise Exception("User ID not found in JSON response. Actual JSON response: " + json.dumps(await response.json(), indent=4)) # looping to fill up list of messages by requesting batches of messages from the API and adding them to the list while True: @@ -74,11 +64,9 @@ async def main(): try: print(json.dumps(await response.json(), indent=4)) print("Channel is not yet indexed. Waiting for " + str((await response.json())["retry_after"]) + "s as requested by the Discord API") - sys.exit(1) await asyncio.sleep((await response.json())["retry_after"]) except KeyError: - print("Unexpected JSON response received from Discord after trying to search for messages. Actual JSON response: " + json.dumps(await response.json(), indent=4)) - sys.exit(1) + raise Exception("Unexpected JSON response received from Discord after trying to search for messages. Actual JSON response: " + json.dumps(await response.json(), indent=4)) # if the batch is not empty, adding the messages in batch to the list of messages to be deleted if batch: @@ -98,7 +86,7 @@ async def main(): # looping infinitely until message is successfully deleted while True: - async with session.request("DELETE", channel_url + "/messages/" + message[0]["id"], headers=headers) as response: + async with session.request("DELETE", "https://discord.com/api/v9/channels/" + message[0]["channel_id"] + "/messages/" + message[0]["id"], headers=headers) as response: # if successful status returned, printing success message and breaking out of loop if 200 <= response.status <= 299: deleted_messages += 1 @@ -119,8 +107,7 @@ async def main(): # otherwise, printing out json response and aborting else: print(response.status) - print("Unexpected HTTP status code received. Actual response: " + json.dumps(await response.json(), indent=4)) - sys.exit(1) + raise Exception("Unexpected HTTP status code received. Actual response: " + json.dumps(await response.json(), indent=4)) if __name__ == "__main__":