【发布时间】:2020-10-04 05:38:28
【问题描述】:
我正在开发一个不和谐的机器人,它可以找到 spotify 播放列表并将曲目的 youtube 对应物排队。我有一个正在运行的循环,它使用曲目名称列表来搜索 youtube 上的视频,然后它会抓取顶部结果并发送到播放它的异步函数。但是,当机器人处于此循环中时,它不接受其他命令。我可以让它与其他命令同时运行吗?以下是我的应用程序的所有代码
from bs4 import BeautifulSoup
import urllib.request
import os
import requests
import base64
import json
import time
import discord
import shutil
from discord.utils import get
from discord import FFmpegPCMAudio
import youtube_dl
import asyncio
from asgiref.sync import async_to_sync
from discord.ext import commands
from dotenv import load_dotenv
load_dotenv()
TOKEN = os.getenv('DISCORD_TOKEN')
bot = commands.Bot(command_prefix='s- ')
accessToken = ""
clientIDSECRET = os.getenv('SPOTIFY_ID')+':'+os.getenv('SPOTIFY_SECRET')
base64Auth = base64.b64encode(clientIDSECRET.encode("utf-8")).decode('ascii')
trackStrings = []
def pretty_print_POST(req):
print('{}\n{}\r\n{}\r\n\r\n{}'.format(
'-----------START-----------',
req.method + ' ' + req.url,
'\r\n'.join('{}: {}'.format(k, v) for k, v in req.headers.items()),
req.body,
))
@bot.event
async def on_ready():
payload={'grant_type':'client_credentials'}
headers = {'Authorization':f'Basic {base64Auth}'}
req = requests.Request('POST', "https://accounts.spotify.com/api/token", data = payload, headers = headers)
prep = req.prepare()
pretty_print_POST(prep)
s = requests.Session()
response = s.send(prep)
global accessToken
accessToken = json.loads(response.content)["access_token"]
print(accessToken)
@bot.command(pass_context=True, aliases=['sp'])
async def spotlist(ctx, userName, playlistName = "", shuffle=False, limit=100, offset=0):
print(limit)
if limit > 100 or limit < 0:
await ctx.send(f'Limit out of bounds! It needs to be between 0 and 100.')
return
playlistId = ""
headers = {'Authorization':f'Bearer {accessToken}'}
if playlistName == "id":
playlistId = userName #Username assumed to be a playlist id instead
else:
playlists = json.loads(requests.get(f'https://api.spotify.com/v1/users/{userName}/playlists', headers=headers).content)
for playlist in playlists["items"]:
if playlist["name"] == playlistName:
playlistId = playlist["id"]
nextURL = f'https://api.spotify.com/v1/playlists/{playlistId}/tracks?offset={offset}&limit={limit}'
while nextURL != None:
trackResponse = requests.get(nextURL, headers = headers)
tracks = json.loads(trackResponse.content)
if(tracks["total"] <= offset):
await ctx.send(f'Offset (third argument) is too large! Your playlist is {tracks["total"]} long.')
return
for track in tracks["items"]:
trackStrings.append(track["track"]["name"] + " " + track["track"]["artists"][0]["name"])
nextURL = tracks["next"]
if(limit != 100):
break
for trackString in trackStrings:
try:
await play(ctx, await SearchVid(trackString))
except:
print("couldn't find song")
@bot.command(pass_context=True, aliases=['j', 'joi'])
async def join(ctx):
channel = ctx.message.author.voice.channel
voice = get(bot.voice_clients, guild=ctx.guild)
if voice and voice.is_connected():
await voice.move_to(channel)
else:
voice = await channel.connect()
@bot.command(pass_context=True, aliases=['l', 'lea'])
async def leave(ctx):
voice = get(bot.voice_clients, guild=ctx.guild)
if voice and voice.is_connected():
await voice.disconnect()
else:
await ctx.send("Don't think I am in a voice channel")
async def playSong(ctx):
voice = get(bot.voice_clients, guild=ctx.guild)
DIR = os.path.abspath(os.path.realpath("Queue"))
try:
first_file = os.listdir(DIR)[0]
except:
print("No more queued song(s)\n")
return
song_path = os.path.abspath(os.path.realpath("Queue") + "\\" + first_file)
async def func(x):
os.remove(song_path)
await playSong(ctx)
try:
voice.play(discord.FFmpegPCMAudio(song_path), after=async_to_sync(func))
await ctx.send(f"playing {first_file}")
voice.source = discord.PCMVolumeTransformer(voice.source)
voice.source.volume = 0.07
except:
print("song already playing")
still_q = len(os.listdir(DIR))
print(f"Songs still in queue: {still_q}")
@bot.command(pass_context=True, aliases=['p', 'pla'])
async def play(ctx, url: str = ""):
await join(ctx)
Queue_infile = os.path.isdir("./Queue")
if Queue_infile is True:
DIR = os.path.abspath(os.path.realpath("Queue"))
try:
_ = os.listdir(DIR)[0]
except:
print("No more queued song(s)\n")
await queue(ctx, url)
await playSong(ctx)
else:
await queue(ctx, url)
await playSong(ctx)
else:
return
@bot.command(pass_context=True, aliases=['s'])
async def skip(ctx):
await stop(ctx)
@bot.command(pass_context=True, aliases=['pa', 'pau'])
async def pause(ctx):
voice = get(bot.voice_clients, guild=ctx.guild)
if voice and voice.is_playing():
print("Music paused")
voice.pause()
await ctx.send("Music paused")
else:
print("Music not playing failed pause")
await ctx.send("Music not playing failed pause")
@bot.command(pass_context=True, aliases=['r', 'res'])
async def resume(ctx):
voice = get(bot.voice_clients, guild=ctx.guild)
if voice and voice.is_paused():
print("Resumed music")
voice.resume()
await ctx.send("Resumed music")
else:
print("Music is not paused")
await ctx.send("Music is not paused")
async def stop(ctx):
voice = get(bot.voice_clients, guild=ctx.guild)
if voice and voice.is_playing():
voice.stop()
else:
print("No music playing failed to stop")
async def SearchVid(textToSearch):
print(textToSearch)
query = urllib.parse.quote(textToSearch)
url = "https://www.youtube.com/results?search_query=" + query
response = urllib.request.urlopen(url)
html = response.read()
soup = BeautifulSoup(html, 'html.parser')
for vid in soup.findAll(attrs={'class':'yt-uix-tile-link'}):
if not vid['href'].startswith("https://googleads.g.doubleclick.net/"):
return 'https://www.youtube.com' + vid['href']
async def queue(ctx, url: str):
Queue_infile = os.path.isdir("./Queue")
if Queue_infile is False:
os.mkdir("Queue")
DIR = os.path.abspath(os.path.realpath("Queue"))
q_num = len(os.listdir(DIR))
queue_path = os.path.abspath(os.path.realpath("Queue") + f"\\{q_num} %(title)s.%(ext)s")
print(queue_path)
ydl_opts = {
'format': 'bestaudio/best',
'outtmpl': queue_path,
'postprocessors': [{
'key': 'FFmpegExtractAudio',
'preferredcodec': 'mp3',
'preferredquality': '192',
}],
}
with youtube_dl.YoutubeDL(ydl_opts) as ydl:
print("Downloading audio now\n")
print(url)
ydl.download([url])
name = os.listdir(DIR)[-1]
await ctx.send("Adding song " + str(name) + " to the queue")
print("Song added to queue\n")
bot.run(TOKEN)
【问题讨论】:
标签: python asynchronous urllib discord.py youtube-dl