我正在尝试学习如何使用 Discord.py 编写机器人代码,并且正在关注 Dasma tech 的 YouTube 教程,了解如何创建音乐机器人。
我已经到了机器人可以加入发送命令的人的语音通道的地步,但是,在分配字典“self.vc[id] =等待channel.connect()”时,它没有被分配。
我已经检查了多次代码,与Dasma Tech的相同,并且运行代码时没有任何错误。
我正在 Raspberry pi 5 上运行代码,如果这有任何帮助的话。
在测试问题时,我在调用函数 join_VC 之前和之后添加了一个打印,第一个打印工作正常,但之后的打印不起作用,我不明白为什么。分配后 join_VC 中的打印和调用 join_VC 后的 ctx.send 也没有输出。
我相信分配 self.vc[id] 的问题是阻止机器人在使用离开命令时离开语音通道,因为它不知道它连接到什么,因为 self.vc[ 的默认值id] 为无。
代码:
导入不和谐 从discord_components导入选择,选择选项,按钮 导入不和谐.ext 从discord.ext导入命令 导入异步 从 asyncio 导入 run_coroutine_threadsafe 从 urllib 导入解析,请求 进口重新 导入 json 导入操作系统 从 youtube_dl 导入 YoutubeDL
类 music_cog(commands.Cog): def init(自我,机器人): self.bot = 机器人
self.is_playing = {}
self.is_paused = {}
self.musicQueue = {}
self.queueIndex = {}
self.YTDL_OPTIONS = {'format': 'bestaudio', 'nonplaylist': 'True'}
self.FFMPEG_OPTIONS = {'before_options': '-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5', 'options': '-vn'}
self.embedBlue = 0x2c76dd
self.embedRed = 0xdf1141
self.embedGreen = 0x0eaa51
self.vc = {}
@commands.Cog.listener()
async def on_ready(self):
for guild in self.bot.guilds:
id = int(guild.id)
self.musicQueue[id] = []
self.queueIndex[id] = 0
self.vc[id] = None
self.is_paused[id] = self.is_playing[id] = False
@commands.Cog.listener()
async def on_voice_state_update(self, member, before, after):
id = int(member.guild.id)
if member.id != self.bot.user.id and before.channel != None and after.channel != before.channel:
remainingChannelMembers = before.channel.members
if len(remainingChannelMembers) == 1 and remainingChannelMembers[0].id == self.bot.user.id and self.vc[id].is_connected():
self.is_playing[id] = self.is_paused[id] = False
self.musicQueue[id] = []
self.queueIndex[id] = 0
await self.vc[id].disconnect()
def now_playing_embed(self, ctx, song):
title = song['title']
link = song['link']
thumbnail = song['thumbnail']
author = ctx.author
avatar = author.avatar_url
embed = discord.Embed(
title = "Now Playing",
description=f'[{title}]({link})',
colour = self.embedGreen
)
embed.set_thumbnail(url=thumbnail)
embed.set_footer(text=f'Song added by: {str(author)}', icon_url=avatar)
return embed
async def join_VC(self, ctx, channel):
id = int(ctx.guild.id)
if self.vc[id] == None or not self.vc[id].is_connected():
self.vc[id] = await channel.connect()
print("It is: ", self.vc[id], " in join_vc")
if self.vc[id] == None:
await ctx.send("Could not connect to the voice channel ")
return None
else:
await self.vc[id].move_to(channel)
print(self.vc[id])
def search_YT(self, search):
queryString = parse.urlencode({'search_query': search})
htmContent = request.urlopen('http://www.youtube.com/results?' + queryString)
searchResults = re.findall('/watch\?v=(.{11})', htmContent.read().decode())
return searchResults[0:10]
def extract_YT(self, url):
with YoutubeDL(self.YTDL_OPTIONS) as ydl:
try:
info = ydl.extract_info(url, download=False)
except:
return False
return {
'link': 'https://www.youtube.com/watch?v=' + url,
'thumbnail': 'https://i.ytimg.com/vi/' + url + '/hqdefault.jpg?sqp=-oaymwEcCOADEI4CSFXyq4qpAw4IARUAAIhCGAFwAcABBg==&rs=AOn4CLD5ul4xKN-IUfez6KIW_j5y70mlig',
'source': info['formats'][0]['url'],
'title': info['title']
}
def play_next(self, ctx):
id = int(ctx.guild.id)
if not self.is_playing[id]:
return
if self.queueIndex[id] + 1 < len(self.musicQueue[id]):
self.i_playing[id] = True
self.queueIndex[id] += 1
song = self.musicQueue[id][self.queueIndex[id]][0]
message = self.now_playing_embed(ctx, song)
coro = ctx.send(embed=message)
fut = run_coroutine_threadsafe(coro, self.bot.loop)
try:
fut.result()
except:
pass
self.vc[id].play(discord.FFmegPCMAudio(
song['source'], ** self.FFMPEG_OPTIONS), after=lambda e: self.play_next(ctx))
else:
self.queueIndex[id] += 1
self.is_playing[id] = False
async def play_music(self, ctx):
id = int(ctx.guild.id)
if self.queueIndex[id] < len(self.musicQueue[id]):
self.is_playing[id] = True
self.is_paused[id] = False
await self.join_VC(ctx, self.musicQueue[id][self.queueIndex[id]][1])
song = self.musicQueue[id][self.queueIndex[id]][0]
message = self.now_playing_embed(ctx, song)
await ctx.send(embed=message)
self.vc[id].play(discord.FFmpegPCMAudio(
song['source'], **self.FFMPEG_OPTIONS), after=lambda e: self.play_next(ctx))
else:
await ctx.send("There are no songs in queue to be played")
self.queueIndex[id] += 1
self.is_playing = False
@ commands.command(
name="join",
aliases=["j","jion"],
help=""
)
async def join(self, ctx):
id = int(ctx.guild.id)
if ctx.author.voice:
userChannel = ctx.message.author.voice.channel
print("Before assignment self.vc[id] = ", self.vc[id])
await self.join_VC(ctx, userChannel)
print("After assignment self.vc[id] = ", self.vc[id])
await ctx.send(f'Rhythmus has joined {userChannel}')
else:
await ctx.send("You need to be in a voice channel")
@ commands.command(
name="leave",
aliases=["l","laeve"],
help=""
)
async def leave(self, ctx):
id = int(ctx.guild.id)
self.is_playing[id] = self.is_paused[id] = False
self.musicQueue[id] = []
self.queueIndex[id] = 0
if self.vc[id] != None:
await ctx.send("Rhythmus has left the voice channel")
await self.vc[id].disconnect()
您分配的方式:
self.vc[id] = await channel.connect()
将
channel.connect()
放入您稍后将使用的词典中。但是, channel.connect()
返回另一个类,该类不返回 VC 的会话 ID(我认为这就是您想要获取的)。相反,它返回 VoiceClient。
来自 docs 的返回类型:
与语音服务器完全连接的语音客户端。
discord.VoiceProtocol
。这意味着它将是一个类,而不是实际的 VC ID 或会话 ID(我假设您想要)。
我意识到以下是错误的,因为它只是格式正确......
这里的范围是错误的。您多次使用
self
,但它不在同一类中。这意味着它将始终返回 None
,因为它无法被引用。