From 965a7d56370c76a4d2906d023834c6b633097a58 Mon Sep 17 00:00:00 2001 From: Dan Date: Thu, 20 Jun 2024 23:00:20 -0400 Subject: [PATCH] FEAT: Added Plex Module FIX: Fixed Spotify Module Fix: Fixed Sync Issues DOC: Added .env references for new APIs --- config.py | 3 ++ main.py | 8 +++- modules/plex_module.py | 85 +++++++++++++++++++++++++++++++++++++++ modules/spotify_module.py | 17 +++++--- 4 files changed, 106 insertions(+), 7 deletions(-) create mode 100644 modules/plex_module.py diff --git a/config.py b/config.py index a73528f..8a15c90 100644 --- a/config.py +++ b/config.py @@ -4,6 +4,9 @@ from dotenv import load_dotenv load_dotenv() DISCORD_TOKEN = os.getenv("DISCORD_TOKEN") +DISCORD_GUILD_ID = os.getenv("DISCORD_GUILD_ID") SPOTIPY_CLIENT_ID = os.getenv("SPOTIPY_CLIENT_ID") SPOTIPY_CLIENT_SECRET = os.getenv("SPOTIPY_CLIENT_SECRET") SPOTIPY_REDIRECT_URI = os.getenv("SPOTIPY_REDIRECT_URI") +PLEX_URL = os.getenv("PLEX_URL") +PLEX_TOKEN = os.getenv("PLEX_TOKEN") diff --git a/main.py b/main.py index cef257e..d9487c5 100644 --- a/main.py +++ b/main.py @@ -8,8 +8,12 @@ class Selena(discord.Client): self.tree = discord.app_commands.CommandTree(self) async def setup_hook(self): - await self.load_extension("modules.spotify_module") - await self.tree.sync() + guild = discord.Object(id=config.DISCORD_GUILD_ID) + modules = ["modules.spotify_module", "modules.plex_module"] + for module in modules: + await self.load_extension(module) + # self.tree.copy_global_to(guild=guild) + await self.tree.sync(guild=guild) async def load_extension(self, name): module = __import__(name, fromlist=["setup"]) diff --git a/modules/plex_module.py b/modules/plex_module.py new file mode 100644 index 0000000..e59454e --- /dev/null +++ b/modules/plex_module.py @@ -0,0 +1,85 @@ +import discord +from discord import app_commands +from plexapi.server import PlexServer +import config + + +class PlexModule: + def __init__(self, bot): + self.bot = bot + self.plex = PlexServer(config.PLEX_URL, config.PLEX_TOKEN) + self.add_commands() + + def add_commands(self): + @app_commands.command( + name="list_libraries", description="List all Plex libraries" + ) + async def list_libraries(interaction: discord.Interaction): + await interaction.response.defer() + try: + libraries = self.plex.library.sections() + library_names = [lib.title for lib in libraries] + await interaction.followup.send( + f"Plex Libraries: {', '.join(library_names)}" + ) + except Exception as e: + await interaction.followup.send(f"An error occurred: {e}") + + @app_commands.command( + name="search_library", + description="Search for a movie in a library" + ) + async def search_library( + interaction: discord.Interaction, library: str, query: str + ): + await interaction.response.defer() + try: + lib = self.plex.library.section(library) + results = lib.search(query) + if not results: + await interaction.followup.send( + f"No results found for '{query}' in '{library}'" + ) + return + + result_titles = [result.title for result in results] + await interaction.followup.send( + f"Search results in {library}: {', '.join(result_titles)}" + ) + except Exception as e: + await interaction.followup.send(f"An error occurred: {e}") + + @app_commands.command( + name="play_movie", description="Play a movie on a specified Plex " + "client" + ) + async def play_movie( + interaction: discord.Interaction, client_name: str, movie_name: str + ): + await interaction.response.defer() + try: + client = next( + (c for c in self.plex.clients() if c.title == client_name), + None + ) + if not client: + await interaction.followup.send( + f"No client found with the name '{client_name}'" + ) + return + + movie = self.plex.library.section('Movies').get(movie_name) + client.playMedia(movie) + await interaction.followup.send( + f"Playing '{movie_name}' on '{client_name}'" + ) + except Exception as e: + await interaction.followup.send(f"An error occurred: {e}") + + self.bot.tree.add_command(list_libraries) + self.bot.tree.add_command(search_library) + self.bot.tree.add_command(play_movie) + + +async def setup(bot): + PlexModule(bot) diff --git a/modules/spotify_module.py b/modules/spotify_module.py index 77ea8ab..5485e8e 100644 --- a/modules/spotify_module.py +++ b/modules/spotify_module.py @@ -30,10 +30,12 @@ class SpotifyModule: try: current = self.sp.currently_playing() if current is None or current["item"] is None: - await interaction.followup.send("No song is currently playing") + await interaction.followup.send( + "No song is currently playing" + ) else: track = current["item"] - artist = ", ".join([artist["name"] for artist in track["artists"]]) + artist = ", ".join([a["name"] for a in track["artists"]]) await interaction.followup.send( f"Currently playing: {track['name']} by {artist} " f"({track['album']['name']})" @@ -57,13 +59,16 @@ class SpotifyModule: devices = self.sp.devices() if not devices["devices"]: - await interaction.followup.send("No active devices found. Please open Spotify on a device.") + await interaction.followup.send( + "No active devices found. Please open Spotify on a " + "device." + ) return self.sp.start_playback(uris=[uri]) await interaction.followup.send( f"Now playing: {track['name']} by " - f"{', '.join([artist['name'] for artist in track['artists']])} " + f"{', '.join([a['name'] for a in track['artists']])} " f"({track['album']['name']})" ) except Exception as e: @@ -109,7 +114,9 @@ class SpotifyModule: await interaction.response.defer() try: self.sp.previous_track() - await interaction.followup.send("Returned to the previous track.") + await interaction.followup.send( + "Returned to the previous track." + ) except Exception as e: await interaction.followup.send(f"An error occurred: {e}")