diff options
author | Parker <contact@pkrm.dev> | 2024-05-18 20:06:51 -0500 |
---|---|---|
committer | Parker <contact@pkrm.dev> | 2024-05-18 20:06:51 -0500 |
commit | 32ab780b461c1c2b5e3e34c35b5902ed7006b95e (patch) | |
tree | b8717f5d5136b36c3d9bfe9e00346a7747003596 /code/cogs | |
parent | f0ec1c5a896744e4cdaa377a50b6277562a29f7f (diff) |
Create CordArr
Diffstat (limited to 'code/cogs')
-rw-r--r-- | code/cogs/error.py | 27 | ||||
-rw-r--r-- | code/cogs/newaccount.py | 59 | ||||
-rw-r--r-- | code/cogs/request.py | 56 | ||||
-rw-r--r-- | code/cogs/status.py | 111 | ||||
-rw-r--r-- | code/cogs/tree_sync.py | 33 |
5 files changed, 286 insertions, 0 deletions
diff --git a/code/cogs/error.py b/code/cogs/error.py new file mode 100644 index 0000000..2752400 --- /dev/null +++ b/code/cogs/error.py @@ -0,0 +1,27 @@ +import discord +from discord.ext import commands +from discord import app_commands + + +class slash_handlers(commands.Cog): + def __init__(self, bot): + self.bot = bot + bot.tree.on_error = self.on_error + + async def on_error(self, interaction: discord.Interaction, error): + if ( + isinstance(error, app_commands.CheckFailure) + and interaction.command.name == "newaccount" + ): + embed = discord.Embed( + title="Jellyfin Account Creation Disabled", + description=f"The owner of {self.bot.user.mention} has disabled the ability to create temporary Jellyfin accounts. Contact an administrator for more information.", + color=0xD01B86 + ) + await interaction.response.send_message(embed=embed, ephemeral=True) + else: + raise error + + +async def setup(bot: commands.Bot): + await bot.add_cog(slash_handlers(bot)) diff --git a/code/cogs/newaccount.py b/code/cogs/newaccount.py new file mode 100644 index 0000000..db5abd0 --- /dev/null +++ b/code/cogs/newaccount.py @@ -0,0 +1,59 @@ +import discord +from discord import app_commands +from discord.ext import commands +import sqlite3 + +from func.jellyfin import create_jellyfin_account +from global_variables import JELLYFIN_URL, ENABLE_JELLYFIN_TEMP_ACCOUNTS, ACCOUNT_TIME + + +class NewAccount(commands.Cog): + def __init__(self, bot): + self.bot = bot + + @app_commands.command() + @app_commands.check(lambda inter: ENABLE_JELLYFIN_TEMP_ACCOUNTS) + async def newaccount(self, interaction: discord.Interaction): + "Create a new temporary Jellyfin account" + # Make sure the user doesn't already have an account + db = sqlite3.connect("cordarr.db") + cursor = db.cursor() + cursor.execute( + "SELECT * FROM jellyfin_accounts WHERE user_id = ?", (interaction.user.id,) + ) + if cursor.fetchone(): + embed = discord.Embed( + title="Account Already Exists", + description="Look at your previous DMs with me to find your account information. You will be permitted to create a new account after your current one expires.", + color=0xD01B86 + ) + return await interaction.response.send_message(embed=embed, ephemeral=True) + + # Create a new Jellyfin account for the user + response = create_jellyfin_account(interaction.user.id) + if response: + embed = discord.Embed( + title="Account Created", + description="Your account has been successfully created. Check your DMs for your account information.", + color=0xD01B86 + ) + await interaction.response.send_message(embed=embed, ephemeral=True) + + # Send the user their account information + embed = discord.Embed( + title="Jellyfin Account Information", + description=f"Here is your temporary account information. You will need this to access the Jellyfin server.\n\n**Server URL:** `{JELLYFIN_URL}`\n**Username:** `{response[0]}`\n**Password:** `{response[1]}`\n\nYour account will be automatically deleted in {ACCOUNT_TIME} hours.", + color=0xD01B86 + ) + await interaction.user.send(embed=embed) + else: + embed = discord.Embed( + title="Unknown Error Occured", + description="Error creating Jellyfin account. Please try again. If the error persists, contact an administrator.", + color=0xD01B86 + ) + return await interaction.response.send_message(embed=embed, ephemeral=True) + + +async def setup(bot): + await bot.add_cog(NewAccount(bot)) diff --git a/code/cogs/request.py b/code/cogs/request.py new file mode 100644 index 0000000..efd6c9d --- /dev/null +++ b/code/cogs/request.py @@ -0,0 +1,56 @@ +import discord +from discord import app_commands +from discord.ext import commands + +from func.radarr import get_movies, AddMovieView + + +class Request(commands.GroupCog, name="request"): + def __init__(self, bot): + self.bot = bot + + @app_commands.command(name="movie") + @app_commands.describe(name="Name of the movie to add") + async def request_movie(self, interaction: discord.Interaction, name: str): + "Request a movie to be added to the Radarr library" + get_movies_response = get_movies(name) + if get_movies_response == "NO RESULTS": + embed = discord.Embed( + title="No Results", + description="No results were found for the given movie name. If you are unable to find the movie, contact an administrator to have it added manually.", + color=0xD01B86 + ) + return await interaction.response.send_message(embed=embed, ephemeral=True) + + if get_movies_response == "ALREADY ADDED": + embed = discord.Embed( + title="Already Added", + description="The movie you are trying to add has already been added to the Radarr library.\n\nYou can check the download status of your requests movies by running the `/status` command.", + color=0xD01B86 + ) + return await interaction.response.send_message(embed=embed, ephemeral=True) + + movies, tmdb_ids = get_movies_response + + embed = discord.Embed( + title="Results Found", + description="Please select the movie you would like to add from the dropdown below.", + color=0xD01B86 + ) + view = AddMovieView(movies, tmdb_ids) + await interaction.response.send_message(embed=embed, view=view, ephemeral=True) + + @app_commands.command(name="show") + @app_commands.describe(name="Name of the show/series to add") + async def request_show(self, interaction: discord.Interaction, name: str): + "Request a show/series to be added to the Sonarr library" + embed = discord.Embed( + title="Coming Soon", + description="This feature is not yet implemented. Check back later.", + color=0xD01B86 + ) + await interaction.response.send_message(embed=embed, ephemeral=True) + + +async def setup(bot): + await bot.add_cog(Request(bot)) diff --git a/code/cogs/status.py b/code/cogs/status.py new file mode 100644 index 0000000..7b6b463 --- /dev/null +++ b/code/cogs/status.py @@ -0,0 +1,111 @@ +import discord +from discord import app_commands +from discord.ext import commands +import requests +import sqlite3 +import datetime +import humanize + +from global_variables import RADARR_HOST_URL, RADARR_HEADERS + + +class Status(commands.Cog): + def __init__(self, bot): + self.bot = bot + + @app_commands.command() + async def status(self, interaction: discord.Interaction): + "Get the status of the movies you have requested" + # Get all the movie_ids that were requested by the user + db = sqlite3.connect("cordarr.db") + cursor = db.cursor() + cursor.execute( + "SELECT movie_id, movie_title FROM movies WHERE user_id = ?", + (interaction.user.id,), + ) + requested_movies = cursor.fetchall() + + users_movies = {} # Dictionary to store the movies that the user has requested + for movie_id, movie_title in requested_movies: + users_movies[movie_id] = movie_title + # If theres no movies, return a message saying so + if not users_movies: + embed = discord.Embed( + title="No Movies Requested", + description="You have no movies being downloaded at the moment. If you previously added a movie, it is likely that it has finished downloading. If you believe this is an error, please contact an administrator.", + color=0xD01B86 + ) + return await interaction.response.send_message(embed=embed, ephemeral=True) + # Otherwise, create the default embed to display the movies being downloaded + embed = discord.Embed( + title="Movies Requested", + description="Here are the movies you have requested that are currently being downloaded:\n", + color=0xD01B86 + ) + + # Now, we get the download status of all movies from the Radarr queue + response = requests.get( + f"{RADARR_HOST_URL}/api/v3/queue/", headers=RADARR_HEADERS + ).json() + + count = 0 + added_movie_ids = [] + for movie in response["records"]: + movie_id = movie["movieId"] + # If the movie is user requested and is being downloaded + if movie_id in users_movies.keys(): + count += 1 + added_movie_ids.append(movie_id) + if movie["status"] == "downloading": + # Humanize the download time left, or result to 'Unknown + try: + time_left = humanize.precisedelta( + datetime.datetime.strptime(movie["timeleft"], "%H:%M:%S") + - datetime.datetime.strptime("00:00:00", "%H:%M:%S"), + minimum_unit="seconds", + ) + except ValueError: + # Sometimes movies will download extremely show and therefore might + # show 'days' in the time left, so strptime appropriately + time_left = humanize.precisedelta( + datetime.datetime.strptime(movie["timeleft"], "%d.%H:%M:%S") + - datetime.datetime.strptime("00:00:00", "%H:%M:%S"), + minimum_unit="seconds", + ) + except KeyError or ValueError: + time_left = "Unknown" + + # Add all the information + embed.description += f"\n{count}. **{users_movies[movie_id]}** - Time Left: ` {time_left} `" + else: + embed.description += f"\n{count}. **{users_movies[movie_id]}** - Status: `{str(movie['status']).upper()}`" + + # If a movie wasn't found in the Radarr queue, then it has either finished downloading + # or the movie was never found for download + if len(added_movie_ids) != len(users_movies.keys()): + # Grab all of the "missing" movies to see if a movie is missing or finished downloading + response = requests.get( + f"{RADARR_HOST_URL}/api/v3/wanted/missing", headers=RADARR_HEADERS + ).json() + for movie in response["records"]: + movie_id = movie["id"] + if movie_id in users_movies.keys() and movie_id not in added_movie_ids: + count += 1 + added_movie_ids.append(movie_id) + embed.description += f"\n{count}. **{users_movies[movie_id]}** - Status: ` NOT FOUND `" + # If there are still movies that haven't been added to the embed, then they + # have finished downloading and can be removed from the database + for movie_id in users_movies.keys(): + if movie_id not in added_movie_ids: + cursor.execute( + "DELETE FROM movies WHERE user_id = ? AND movie_id = ?", + (interaction.user.id, movie_id), + ) + db.commit() + db.close() + + await interaction.response.send_message(embed=embed, ephemeral=True) + + +async def setup(bot): + await bot.add_cog(Status(bot)) diff --git a/code/cogs/tree_sync.py b/code/cogs/tree_sync.py new file mode 100644 index 0000000..5050730 --- /dev/null +++ b/code/cogs/tree_sync.py @@ -0,0 +1,33 @@ +from discord.ext import commands +from discord import Object + + +class TreeSync(commands.Cog): + def __init__(self, bot): + self.bot = bot + + @commands.command() + @commands.dm_only() + @commands.is_owner() + async def sync(self, ctx: commands.Context, *, guild: Object = None) -> None: + if not guild or guild == None: + await self.bot.tree.sync() + await ctx.author.send("Synced commands globally") + return + + elif guild != None: + self.bot.tree.copy_global_to(guild=guild) + await self.bot.tree.sync(guild=guild) + + await ctx.author.send(f"Synced the tree to 1 test guild.") + + @sync.error + async def error_sync(self, ctx, error): + if isinstance(error, commands.errors.PrivateMessageOnly): + pass + else: + await ctx.author.send("That is not a valid guild ID") + + +async def setup(bot): + await bot.add_cog(TreeSync(bot)) |