🛠 fixed queue bugs, added spotify song support 🔊

This commit is contained in:
2023-11-10 02:09:55 +00:00
parent e06da40435
commit 77e2175ab6
8 changed files with 155 additions and 66 deletions

View File

@@ -5,12 +5,49 @@ import cogs.music.util as util
import cogs.music.queue as queue import cogs.music.queue as queue
import cogs.music.translate as translate import cogs.music.translate as translate
import datetime
import pytz
import asyncio
from cogs.music.help import music_help from cogs.music.help import music_help
import discord
import spotipy
from spotipy.oauth2 import SpotifyClientCredentials
# Fix this pls
import json
#from .. import config
# Read data from JSON file in ./data/config.json
def read_data():
with open("./data/config.json", "r") as file:
return json.load(file)
raise Exception("Could not load config data")
def get_spotify_creds():
data = read_data()
data = data.get("spotify")
SCID = data.get("SCID")
secret = data.get("SECRET")
return SCID, secret
# call play on ffmpeg exit
class AstroPlayer(discord.FFmpegPCMAudio):
def __init__(self, ctx, source, options) -> None:
#self.ctx = ctx
super().__init__(source, **options)
def _kill_process(self):
super()._kill_process()
#asyncio.create_task(play(self.ctx))
class music(commands.Cog): class music(commands.Cog):
def __init__(self, client): def __init__(self, client):
@@ -23,21 +60,16 @@ class music(commands.Cog):
help_command.cog = self help_command.cog = self
self.help_command = help_command self.help_command = help_command
SCID, secret = get_spotify_creds()
# Authentication - without user
client_credentials_manager = SpotifyClientCredentials(client_id=SCID,
client_secret=secret)
self.sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
queue.initialize_tables() queue.initialize_tables()
@commands.command(
help="Displays latency from the bot",
aliases=['delay'])
async def ping(self, ctx: Context):
start_time = datetime.datetime.now(pytz.utc)
end_time = ctx.message.created_at
delay = int((end_time - start_time).total_seconds() * 1000)
await ctx.send(f"Pong! `{delay}MS`")
@commands.command( @commands.command(
help="Connects to your current voice channel", help="Connects to your current voice channel",
aliases=['connect']) aliases=['connect'])
@@ -53,7 +85,6 @@ class music(commands.Cog):
await util.leave_vc(ctx) await util.leave_vc(ctx)
await ctx.message.add_reaction('👍') await ctx.message.add_reaction('👍')
@commands.command( @commands.command(
help="Queues a song into the bot", help="Queues a song into the bot",
aliases=['p']) aliases=['p'])
@@ -65,14 +96,14 @@ class music(commands.Cog):
server = ctx.guild.id server = ctx.guild.id
await ctx.message.add_reaction('👍')
await util.join_vc(ctx) await util.join_vc(ctx)
await ctx.message.add_reaction('👍')
msg = await ctx.send("Fetching song(s)...") msg = await ctx.send("Fetching song(s)...")
async with ctx.typing(): async with ctx.typing():
#TODO potentially save requests before getting stream link #TODO potentially save requests before getting stream link
# Grab video details such as title thumbnail duration # Grab video details such as title thumbnail duration
audio = translate.main(url) audio = translate.main(url, self.sp)
await msg.delete() await msg.delete()
@@ -99,7 +130,6 @@ class music(commands.Cog):
await queue.play(ctx) await queue.play(ctx)
@commands.command( @commands.command(
help="Display the current music queue", help="Display the current music queue",
aliases=['q', 'songs']) aliases=['q', 'songs'])
@@ -116,7 +146,7 @@ class music(commands.Cog):
n, songs = await queue.grab_songs(server.id) n, songs = await queue.grab_songs(server.id)
# Check once more # Check once more
if len(songs) == 0: if len(songs) == 0 and await queue.is_server_playing(ctx.guild.id) == False:
await ctx.send("🚫 This server has no queue currently. Start the party by queuing up a song!") await ctx.send("🚫 This server has no queue currently. Start the party by queuing up a song!")
return return

View File

@@ -1,3 +1,4 @@
from http import server
import sqlite3 import sqlite3
import discord import discord
@@ -22,7 +23,8 @@ def initialize_tables():
# Create servers table if it doesn't exist # Create servers table if it doesn't exist
cursor.execute('''CREATE TABLE IF NOT EXISTS servers ( cursor.execute('''CREATE TABLE IF NOT EXISTS servers (
server_id TEXT PRIMARY KEY, server_id TEXT PRIMARY KEY,
is_playing INTEGER DEFAULT 0 is_playing INTEGER DEFAULT 0,
song_name TEXT
);''') );''')
# Set all to not playing # Set all to not playing
@@ -83,6 +85,34 @@ async def add_song(server_id, details, queued_by):
return max_order_num return max_order_num
# Pop song from server
async def pop(server_id):
# Connect to db
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
# JUST INCASE!
await add_server(server_id, cursor, conn)
cursor.execute('''SELECT *
FROM songs
WHERE server_id = ?
ORDER BY position
LIMIT 1;''', (server_id,))
result = cursor.fetchone()
conn.commit()
conn.close()
if result == None:
return None
await set_current_song(server_id, result[4])
await mark_song_as_finished(server_id, result[3])
return result[1]
# Add server to db if first time queuing # Add server to db if first time queuing
async def add_server(server_id, cursor, conn): async def add_server(server_id, cursor, conn):
# Check if the server exists # Check if the server exists
@@ -116,6 +146,42 @@ async def mark_song_as_finished(server_id, order_num):
conn.close() conn.close()
# set the current playing song of the server
async def set_current_song(server_id, title):
# Connect to the database
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
cursor.execute(''' UPDATE servers
SET song_name = ?
WHERE server_id = ?''',
(title, server_id))
# Close connection
conn.commit()
conn.close()
async def get_current_song(server_id):
# Connect to the database
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
cursor.execute(''' SELECT song_name
FROM servers
WHERE server_id = ?
LIMIT 1;''',
(server_id,))
result = cursor.fetchone()
# Close connection
conn.commit()
conn.close()
return result[0]
# Grab max order from server # Grab max order from server
async def get_max(server_id, cursor): async def get_max(server_id, cursor):
cursor.execute(f""" cursor.execute(f"""
@@ -131,35 +197,6 @@ async def get_max(server_id, cursor):
return max_order_num return max_order_num
# Pop song from server
async def pop(server_id):
# Connect to db
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
# JUST INCASE!
await add_server(server_id, cursor, conn)
max_order = await get_max(server_id, cursor)
if max_order == -1:
conn.commit()
conn.close()
return None
cursor.execute('''SELECT song_link
FROM songs
WHERE server_id = ? AND position = ?
''', (server_id, max_order))
result = cursor.fetchone()
conn.commit()
conn.close()
await mark_song_as_finished(server_id, max_order)
return result[0]
# Sets the playing variable in a server to true or false # Sets the playing variable in a server to true or false
async def update_server(server_id, playing: bool): async def update_server(server_id, playing: bool):
# Connect to database # Connect to database
@@ -259,7 +296,7 @@ async def play(ctx):
return return
# else play next song and call play again # else play next song and call play again
ctx.voice_client.play( await ctx.voice_client.play(
AstroPlayer(ctx, url, FFMPEG_OPTS)) AstroPlayer(ctx, url, FFMPEG_OPTS))
# call play on ffmpeg exit # call play on ffmpeg exit
@@ -270,4 +307,4 @@ class AstroPlayer(discord.FFmpegPCMAudio):
def _kill_process(self): def _kill_process(self):
super()._kill_process() super()._kill_process()
asyncio.create_task(play(self.ctx)) asyncio.run(play(self.ctx))

View File

@@ -1,6 +1,7 @@
# Handles translating urls and search terms # Handles translating urls and search terms
import yt_dlp as ytdlp import yt_dlp as ytdlp
import spotipy
ydl_opts = { ydl_opts = {
'format': 'bestaudio/best', 'format': 'bestaudio/best',
@@ -9,7 +10,7 @@ ydl_opts = {
'ignoreerrors': True, 'ignoreerrors': True,
} }
def main(url): def main(url, sp):
#url = url.lower() #url = url.lower()
@@ -20,7 +21,7 @@ def main(url):
#TODO add better regex or something #TODO add better regex or something
if 'spotify' in url: if 'spotify' in url:
if 'track' in url: if 'track' in url:
return spotify_song(url) return spotify_song(url, sp)
elif 'playlist' in url: elif 'playlist' in url:
return spotify_playlist(url) return spotify_playlist(url)
@@ -57,8 +58,21 @@ def search_song(search):
return [data] return [data]
def spotify_song(url): def spotify_song(url, sp):
return [] track = sp.track(url.split("/")[-1].split("?")[0])
search = ""
for i in track["artists"]:
# grabs all the artists name's if there's more than one
search = search + (i['name'] + ", ")
# remove last comma
search = search[:-2]
# set search to name
query = search + " - " + track['name']
return search_song(query)
def spotify_playlist(url): def spotify_playlist(url):
@@ -74,8 +88,6 @@ def song_download(url):
if info is None: if info is None:
return [] return []
print(info.keys())
data = {'url': info['url'], data = {'url': info['url'],
'title': info['title'], 'title': info['title'],
'thumbnail': info['thumbnail'], 'thumbnail': info['thumbnail'],

View File

@@ -2,7 +2,7 @@ import discord
from discord.ext.commands.context import Context from discord.ext.commands.context import Context
from discord.ext.commands.converter import CommandError from discord.ext.commands.converter import CommandError
import config import config
from . import queue
# Joining/moving to the user's vc in a guild # Joining/moving to the user's vc in a guild
async def join_vc(ctx: Context): async def join_vc(ctx: Context):
@@ -69,7 +69,7 @@ async def display_server_queue(ctx: Context, songs, n):
title=f"{server.name}'s Queue!", title=f"{server.name}'s Queue!",
color=config.get_color("main")) color=config.get_color("main"))
display = "" display = f"🔊 Currently playing: ``{await queue.get_current_song(ctx.guild.id)}``\n"
for i, song in enumerate(songs): for i, song in enumerate(songs):
display += f"``{i + 1}.`` {song[0]} - {format_time(song[1])} Queued by {song[2]}\n" display += f"``{i + 1}.`` {song[0]} - {format_time(song[1])} Queued by {song[2]}\n"
msg.add_field(name="Songs:", msg.add_field(name="Songs:",

View File

@@ -13,6 +13,16 @@ def read_data():
raise Exception("Could not load config data") raise Exception("Could not load config data")
def get_spotify_creds():
data = read_data()
data = data.get("spotify")
SCID = data.get("SCID")
secret = data.get("SECRET")
return SCID, secret
# Reading prefix # Reading prefix
def get_prefix(): def get_prefix():
data = read_data() data = read_data()

View File

@@ -6,4 +6,4 @@ import help
client = Astro(command_prefix=config.get_prefix(), intents=discord.Intents.all()) client = Astro(command_prefix=config.get_prefix(), intents=discord.Intents.all())
client.help_command = help.AstroHelp() client.help_command = help.AstroHelp()
client.run(config.get_login("live")) client.run(config.get_login("dev"))

View File

@@ -24,4 +24,4 @@ spotipy==2.23.0
urllib3==2.0.2 urllib3==2.0.2
websockets==11.0.3 websockets==11.0.3
yarl==1.9.2 yarl==1.9.2
yt-dlp==2023.3.4 yt-dlp