🛠 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.translate as translate
import datetime
import pytz
import asyncio
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):
def __init__(self, client):
@@ -23,21 +60,16 @@ class music(commands.Cog):
help_command.cog = self
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()
@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(
help="Connects to your current voice channel",
aliases=['connect'])
@@ -53,7 +85,6 @@ class music(commands.Cog):
await util.leave_vc(ctx)
await ctx.message.add_reaction('👍')
@commands.command(
help="Queues a song into the bot",
aliases=['p'])
@@ -65,14 +96,14 @@ class music(commands.Cog):
server = ctx.guild.id
await ctx.message.add_reaction('👍')
await util.join_vc(ctx)
await ctx.message.add_reaction('👍')
msg = await ctx.send("Fetching song(s)...")
async with ctx.typing():
#TODO potentially save requests before getting stream link
# Grab video details such as title thumbnail duration
audio = translate.main(url)
audio = translate.main(url, self.sp)
await msg.delete()
@@ -99,7 +130,6 @@ class music(commands.Cog):
await queue.play(ctx)
@commands.command(
help="Display the current music queue",
aliases=['q', 'songs'])
@@ -116,7 +146,7 @@ class music(commands.Cog):
n, songs = await queue.grab_songs(server.id)
# 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!")
return
@@ -148,4 +178,4 @@ class music(commands.Cog):
await queue.pop(server.id)
# Safe to ignore error for now
ctx.voice_client.stop()
ctx.voice_client.stop()

View File

@@ -1,3 +1,4 @@
from http import server
import sqlite3
import discord
@@ -22,7 +23,8 @@ def initialize_tables():
# Create servers table if it doesn't exist
cursor.execute('''CREATE TABLE IF NOT EXISTS servers (
server_id TEXT PRIMARY KEY,
is_playing INTEGER DEFAULT 0
is_playing INTEGER DEFAULT 0,
song_name TEXT
);''')
# Set all to not playing
@@ -83,6 +85,34 @@ async def add_song(server_id, details, queued_by):
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
async def add_server(server_id, cursor, conn):
# Check if the server exists
@@ -116,6 +146,42 @@ async def mark_song_as_finished(server_id, order_num):
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
async def get_max(server_id, cursor):
cursor.execute(f"""
@@ -131,35 +197,6 @@ async def get_max(server_id, cursor):
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
async def update_server(server_id, playing: bool):
# Connect to database
@@ -259,7 +296,7 @@ async def play(ctx):
return
# else play next song and call play again
ctx.voice_client.play(
await ctx.voice_client.play(
AstroPlayer(ctx, url, FFMPEG_OPTS))
# call play on ffmpeg exit
@@ -270,4 +307,4 @@ class AstroPlayer(discord.FFmpegPCMAudio):
def _kill_process(self):
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
import yt_dlp as ytdlp
import spotipy
ydl_opts = {
'format': 'bestaudio/best',
@@ -9,7 +10,7 @@ ydl_opts = {
'ignoreerrors': True,
}
def main(url):
def main(url, sp):
#url = url.lower()
@@ -20,13 +21,13 @@ def main(url):
#TODO add better regex or something
if 'spotify' in url:
if 'track' in url:
return spotify_song(url)
return spotify_song(url, sp)
elif 'playlist' in url:
return spotify_playlist(url)
soundcloud_song = 'soundcloud' in url and 'sets' not in url
# Not implemented yet
#soundcloud_playlist = 'soundcloud' in url and 'sets' in url
# soundcloud_playlist = 'soundcloud' in url and 'sets' in url
youtube_song = 'watch?v=' in url or 'youtu.be/' in url
youtube_playlist = 'playlist?list=' in url
@@ -57,8 +58,21 @@ def search_song(search):
return [data]
def spotify_song(url):
return []
def spotify_song(url, sp):
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):
@@ -74,8 +88,6 @@ def song_download(url):
if info is None:
return []
print(info.keys())
data = {'url': info['url'],
'title': info['title'],
'thumbnail': info['thumbnail'],

View File

@@ -2,7 +2,7 @@ import discord
from discord.ext.commands.context import Context
from discord.ext.commands.converter import CommandError
import config
from . import queue
# Joining/moving to the user's vc in a guild
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!",
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):
display += f"``{i + 1}.`` {song[0]} - {format_time(song[1])} Queued by {song[2]}\n"
msg.add_field(name="Songs:",