From 29d9ee5432f8bee91744cd4a00864b379d3ba396 Mon Sep 17 00:00:00 2001
From: Dan <daniel.sapelli@gmail.com>
Date: Thu, 20 Jun 2024 21:43:01 -0400
Subject: [PATCH] FEAT: Added Spotify Support to Selena

---
 cogs/__init__.py    |  0
 cogs/spotify_cog.py | 60 +++++++++++++++++++++++++++++++++++++++++++++
 config.py           |  9 +++++++
 main.py             | 22 +++++++++++++++++
 4 files changed, 91 insertions(+)
 create mode 100644 cogs/__init__.py
 create mode 100644 cogs/spotify_cog.py
 create mode 100644 config.py
 create mode 100644 main.py

diff --git a/cogs/__init__.py b/cogs/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/cogs/spotify_cog.py b/cogs/spotify_cog.py
new file mode 100644
index 0000000..3b969b0
--- /dev/null
+++ b/cogs/spotify_cog.py
@@ -0,0 +1,60 @@
+import discord
+from discord import app_commands
+import spotipy
+from spotipy.oauth2 import SpotifyOAuth
+import config
+
+
+class SpotifyCog(discord.Cog):
+    def __init__(self, bot):
+        self.bot = bot
+        self.sp = spotipy.Spotify(
+            auth_manager=SpotifyOAuth(
+                client_id=config.SPOTIFY_CLIENT_ID,
+                client_secret=config.SPOTIFY_CLIENT_SECRET,
+                redirect_uri=config.SPOTIFY_REDIRECT_URI,
+                scope=(
+                    "user-library-read user-read-playback-state "
+                    "user-modify-playback-state user-read-currently-playing"
+                )
+            )
+        )
+
+    @app_commands.command(
+        name="current_track", description="Get the currently playing song"
+    )
+    async def current_track(self, interaction: discord.Interaction):
+        current = self.sp.currently_playing()
+        if current is None or current["item"] is None:
+            await interaction.response.send_message(
+                "No song is currently playing"
+            )
+        else:
+            track = current["item"]
+            artist = ", ".join([artist["name"] for artist in track["artists"]])
+            await interaction.response.send_message(
+                f"Currently playing: {track['name']} by {artist} "
+                f"({track['album']['name']})"
+            )
+
+    @app_commands.command(
+        name="play_track", description="Play a track by searching for it"
+    )
+    async def play_track(self, interaction: discord.Interaction, query: str):
+        results = self.sp.search(q=query, limit=1, type="track")
+        if not results["tracks"]["items"]:
+            await interaction.response.send_message("No results found")
+            return
+
+        track = results["tracks"]["items"][0]
+        uri = track["uri"]
+        self.sp.start_playback(uris=[uri])
+        await interaction.response.send_message(
+            f"Now playing: {track['name']} by "
+            f"{', '.join([artist['name'] for artist in track['artists']])} "
+            f"({track['album']['name']})"
+        )
+
+
+async def setup(bot):
+    await bot.add_cog(SpotifyCog(bot))
diff --git a/config.py b/config.py
new file mode 100644
index 0000000..68df0a5
--- /dev/null
+++ b/config.py
@@ -0,0 +1,9 @@
+import os
+from dotenv import load_dotenv
+
+load_dotenv()
+
+DISCORD_TOKEN = os.getenv("DISCORD_TOKEN")
+SPOTIFY_CLIENT_ID = os.getenv("SPOTIFY_CLIENT_ID")
+SPOTIFY_CLIENT_SECRET = os.getenv("SPOTIFY_CLIENT_SECRET")
+SPOTIFY_REDIRECT_URI = os.getenv("SPOTIFY_REDIRECT_URI")
diff --git a/main.py b/main.py
new file mode 100644
index 0000000..a2ad1ec
--- /dev/null
+++ b/main.py
@@ -0,0 +1,22 @@
+import discord
+import config
+
+
+class Selena(discord.Client):
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        self.tree = discord.app_commands.CommandTree(self)
+
+    async def setup_hook(self):
+        for extension in ["cogs.spotify_cog"]:
+            await self.load_extension(extension)
+        await self.tree.sync()
+
+    async def on_ready(self):
+        print("Logged in as {0.user}".format(self))
+
+
+if __name__ == "__main__":
+    intents = discord.Intents.default()
+    client = Selena(intents=intents)
+    client.run(config.DISCORD_TOKEN)