aboutsummaryrefslogtreecommitdiff
path: root/code/cogs
diff options
context:
space:
mode:
authorParker <contact@pkrm.dev>2024-05-18 20:06:51 -0500
committerParker <contact@pkrm.dev>2024-05-18 20:06:51 -0500
commit32ab780b461c1c2b5e3e34c35b5902ed7006b95e (patch)
treeb8717f5d5136b36c3d9bfe9e00346a7747003596 /code/cogs
parentf0ec1c5a896744e4cdaa377a50b6277562a29f7f (diff)
Create CordArr
Diffstat (limited to 'code/cogs')
-rw-r--r--code/cogs/error.py27
-rw-r--r--code/cogs/newaccount.py59
-rw-r--r--code/cogs/request.py56
-rw-r--r--code/cogs/status.py111
-rw-r--r--code/cogs/tree_sync.py33
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))