Python Discord.py bot+;夸特:尝试连接到语音频道总是会给出一个“提示”;任务已将future附加到另一个循环“中”;

Python Discord.py bot+;夸特:尝试连接到语音频道总是会给出一个“提示”;任务已将future附加到另一个循环“中”;,python,discord.py,python-asyncio,quart,Python,Discord.py,Python Asyncio,Quart,我一直在尝试创建一个discord机器人,它可以通过web界面接收命令。我将discord.py用作discordapi包装器,将Quart用作REST框架,因为我需要处理异步任务,而Flask不支持它们 现在我有两个文件: app.py import discord bot = discord.Client(intents=discord.Intents.all()) ... async def play_audio(audio_name, voiceChannel): vc =

我一直在尝试创建一个discord机器人,它可以通过web界面接收命令。我将discord.py用作discordapi包装器,将Quart用作REST框架,因为我需要处理异步任务,而Flask不支持它们

现在我有两个文件:

app.py

import discord

bot = discord.Client(intents=discord.Intents.all())

...

async def play_audio(audio_name, voiceChannel):
    vc = await voiceChannel.connect()
    print("test")
    vc.play(discord.FFmpegPCMAudio(source="audio\{}".format(audio_name), executable=FFMPEG_PATH))
    while vc.is_playing():
        time.sleep(.1)
    await vc.disconnect()

async def get_online_voice_members():
    guild = bot.get_guild(NMC_GUILD_ID)
    online_voice_users = {}
    for voiceChannel in guild.voice_channels:
        for user in voiceChannel.members:
            online_voice_users[user] = voiceChannel
    return online_voice_users

...
import asyncio
from quart import Quart
import app as discord

QUART_APP = Quart(__name__)

@QUART_APP.before_serving
async def before_serving():
    loop = asyncio.get_event_loop()
    await discord.bot.login("MY BOT TOKEN")
    loop.create_task(discord.bot.connect())

...

@QUART_APP.route("/online_list", methods=["GET"])
async def get_online_members():
    resp = {}
    members = await discord.get_online_voice_members()
    for user in members.keys():
        resp[user.id] = {"nick" : user.nick, "channel" : members[user].id}
    return resp

@QUART_APP.route("/goodnight", methods=["GET"])
async def send_goodnight():
    members = await discord.get_online_voice_members()
    for user in members.keys():
        if user.id == 12345:
            await discord.play_audio("goodnight.mp3", members[user])
            break
    return {"response":"OK"}
class DiscordClient:
    def __init__(self):
        self.bot = discord.Client(intents=discord.Intents.all())
        ...

    async def get_online_voice_members(self):
        guild = self.bot.get_guild(NMC_GUILD_ID)
        ...
@QUART_APP.before_serving
async def before_serving():
    loop = asyncio.get_event_loop()
    QUART_APP.discord_client = DiscordClient()
    await QUART_APP.discord_client.bot.login("MY BOT TOKEN")
    loop.create_task(QUART_APP.discord_client.bot.connect())

@QUART_APP.route("/online_list", methods=["GET"])
async def get_online_members():
    resp = {}
    members = await QUART_APP.discord_client.get_online_voice_members()
    ...
api.py

import discord

bot = discord.Client(intents=discord.Intents.all())

...

async def play_audio(audio_name, voiceChannel):
    vc = await voiceChannel.connect()
    print("test")
    vc.play(discord.FFmpegPCMAudio(source="audio\{}".format(audio_name), executable=FFMPEG_PATH))
    while vc.is_playing():
        time.sleep(.1)
    await vc.disconnect()

async def get_online_voice_members():
    guild = bot.get_guild(NMC_GUILD_ID)
    online_voice_users = {}
    for voiceChannel in guild.voice_channels:
        for user in voiceChannel.members:
            online_voice_users[user] = voiceChannel
    return online_voice_users

...
import asyncio
from quart import Quart
import app as discord

QUART_APP = Quart(__name__)

@QUART_APP.before_serving
async def before_serving():
    loop = asyncio.get_event_loop()
    await discord.bot.login("MY BOT TOKEN")
    loop.create_task(discord.bot.connect())

...

@QUART_APP.route("/online_list", methods=["GET"])
async def get_online_members():
    resp = {}
    members = await discord.get_online_voice_members()
    for user in members.keys():
        resp[user.id] = {"nick" : user.nick, "channel" : members[user].id}
    return resp

@QUART_APP.route("/goodnight", methods=["GET"])
async def send_goodnight():
    members = await discord.get_online_voice_members()
    for user in members.keys():
        if user.id == 12345:
            await discord.play_audio("goodnight.mp3", members[user])
            break
    return {"response":"OK"}
class DiscordClient:
    def __init__(self):
        self.bot = discord.Client(intents=discord.Intents.all())
        ...

    async def get_online_voice_members(self):
        guild = self.bot.get_guild(NMC_GUILD_ID)
        ...
@QUART_APP.before_serving
async def before_serving():
    loop = asyncio.get_event_loop()
    QUART_APP.discord_client = DiscordClient()
    await QUART_APP.discord_client.bot.login("MY BOT TOKEN")
    loop.create_task(QUART_APP.discord_client.bot.connect())

@QUART_APP.route("/online_list", methods=["GET"])
async def get_online_members():
    resp = {}
    members = await QUART_APP.discord_client.get_online_voice_members()
    ...
当我在endpoint/online\u列表上发出GET请求时,一切正常,但当我在/goodnight上发出请求时,代码成功运行,直到到达指令
wait discord。播放音频(“goodnight.mp3,members[user])
,它接收正确的参数,但总是引发以下异常:

Traceback (most recent call last):
  File "G:\Gunther\venv\lib\site-packages\quart\app.py", line 1814, in handle_request
    return await self.full_dispatch_request(request_context)
  File "G:\Gunther\venv\lib\site-packages\quart\app.py", line 1836, in full_dispatch_request
    result = await self.handle_user_exception(error)
  File "G:\Gunther\venv\lib\site-packages\quart\app.py", line 1076, in handle_user_exception
    raise error
  File "G:\Gunther\venv\lib\site-packages\quart\app.py", line 1834, in full_dispatch_request
    result = await self.dispatch_request(request_context)
  File "G:\Gunther\venv\lib\site-packages\quart\app.py", line 1882, in dispatch_request
    return await handler(**request_.view_args)
  File "G:/Dati HDD F/GitHub Projects/Gunther/api.py", line 59, in send_buonanotte
    await discord.play_audio("goodnight.mp3", members[user])
  File "G:\Gunther\app.py", line 55, in play_audio
    vc = await voiceChannel.connect()
  File "G:\Gunther\venv\lib\site-packages\discord\abc.py", line 1122, in connect
    await voice.connect(timeout=timeout, reconnect=reconnect)
  File "G:\Gunther\venv\lib\site-packages\discord\voice_client.py", line 352, in connect
    self.ws = await self.connect_websocket()
  File "G:\Gunther\venv\lib\site-packages\discord\voice_client.py", line 323, in connect_websocket
    await ws.poll_event()
  File "G:\Gunther\venv\lib\site-packages\discord\gateway.py", line 893, in poll_event
    await self.received_message(json.loads(msg.data))
  File "G:\Gunther\venv\lib\site-packages\discord\gateway.py", line 825, in received_message
    await self.initial_connection(data)
  File "G:\Gunther\venv\lib\site-packages\discord\gateway.py", line 849, in initial_connection
    recv = await self.loop.sock_recv(state.socket, 70)
  File "C:\Users\Kyles\AppData\Local\Programs\Python\Python38\lib\asyncio\proactor_events.py", line 693, in sock_recv
    return await self._proactor.recv(sock, n)
RuntimeError: Task <Task pending name='Task-27' coro=<ASGIHTTPConnection.handle_request() running at G:\Gunther\venv\lib\site-packages\quart\asgi.py:70> cb=[_wait.<locals>._on_completion() at C:\Users\Kyles\AppData\Local\Programs\Python\Python38\lib\asyncio\tasks.py:507]> got Future <_OverlappedFuture pending overlapped=<pending, 0x199c31f0ca0>> attached to a different loop
回溯(最近一次呼叫最后一次):
文件“G:\Gunther\venv\lib\site packages\quart\app.py”,第1814行,在handle\u请求中
返回等待自我。完全调度请求(请求上下文)
文件“G:\Gunther\venv\lib\site packages\quart\app.py”,第1836行,完整发送请求
结果=等待自我处理用户异常(错误)
文件“G:\Gunther\venv\lib\site packages\quart\app.py”,第1076行,在handle\u user\u exception中
提出错误
文件“G:\Gunther\venv\lib\site packages\quart\app.py”,第1834行,在完整调度请求中
结果=等待自我分派请求(请求上下文)
文件“G:\Gunther\venv\lib\site packages\quart\app.py”,第1882行,在调度请求中
返回等待处理程序(**请求\视图\参数)
文件“G:/Dati HDD F/GitHub Projects/Gunther/api.py”,第59行,在send_buonanotte中
等待不和谐。播放音频(“goodnight.mp3”,成员[用户])
文件“G:\Gunther\app.py”,第55行,播放音频
vc=等待voiceChannel.connect()的声音
文件“G:\Gunther\venv\lib\site packages\discord\abc.py”,第1122行,在connect中
等待语音连接(超时=超时,重新连接=重新连接)
文件“G:\Gunther\venv\lib\site packages\discord\voice\u client.py”,第352行,在connect中
self.ws=等待self.connect\u websocket()
文件“G:\Gunther\venv\lib\site packages\discord\voice\u client.py”,第323行,位于connect\u websocket中
等待ws.poll_事件()
轮询事件中的文件“G:\Gunther\venv\lib\site packages\discord\gateway.py”,第893行
等待self.received_消息(json.loads(msg.data))
文件“G:\Gunther\venv\lib\site packages\discord\gateway.py”,第825行,在收到的消息中
等待自我初始连接(数据)
文件“G:\Gunther\venv\lib\site packages\discord\gateway.py”,第849行,处于初始连接中
recv=等待self.loop.sock\u recv(state.socket,70)
文件“C:\Users\Kyles\AppData\Local\Programs\Python38\lib\asyncio\proactor\u events.py”,第693行,在sock\u recv中
返回等待自我。\u proactor.recv(sock,n)
RuntimeError:任务已附加到其他循环

我想我没有正确理解asyncio库是如何工作的,因为在我看来,无论我做什么尝试,app.py中的行
vc=wait voiceChannel.connect()
总是在与主循环不同的循环上运行。我缺少什么吗?

这是因为您在导入时启动了discord客户端(app.py的第3行)。这样做意味着它将使用导入时可用的事件循环。但是,Quart(和Hypercorn,除非被告知不要太多)将关闭现有循环并在启动时创建一个新循环。因此,我建议使用该功能进行初始化

为了解决这个问题,我将把你的discord命令包装在一个类中,并在启动函数中初始化它。请注意,我喜欢将实例存储在应用程序本身上(这样就可以通过
当前应用程序
代理访问它们),但这并不是必需的。例如

app.py

import discord

bot = discord.Client(intents=discord.Intents.all())

...

async def play_audio(audio_name, voiceChannel):
    vc = await voiceChannel.connect()
    print("test")
    vc.play(discord.FFmpegPCMAudio(source="audio\{}".format(audio_name), executable=FFMPEG_PATH))
    while vc.is_playing():
        time.sleep(.1)
    await vc.disconnect()

async def get_online_voice_members():
    guild = bot.get_guild(NMC_GUILD_ID)
    online_voice_users = {}
    for voiceChannel in guild.voice_channels:
        for user in voiceChannel.members:
            online_voice_users[user] = voiceChannel
    return online_voice_users

...
import asyncio
from quart import Quart
import app as discord

QUART_APP = Quart(__name__)

@QUART_APP.before_serving
async def before_serving():
    loop = asyncio.get_event_loop()
    await discord.bot.login("MY BOT TOKEN")
    loop.create_task(discord.bot.connect())

...

@QUART_APP.route("/online_list", methods=["GET"])
async def get_online_members():
    resp = {}
    members = await discord.get_online_voice_members()
    for user in members.keys():
        resp[user.id] = {"nick" : user.nick, "channel" : members[user].id}
    return resp

@QUART_APP.route("/goodnight", methods=["GET"])
async def send_goodnight():
    members = await discord.get_online_voice_members()
    for user in members.keys():
        if user.id == 12345:
            await discord.play_audio("goodnight.mp3", members[user])
            break
    return {"response":"OK"}
class DiscordClient:
    def __init__(self):
        self.bot = discord.Client(intents=discord.Intents.all())
        ...

    async def get_online_voice_members(self):
        guild = self.bot.get_guild(NMC_GUILD_ID)
        ...
@QUART_APP.before_serving
async def before_serving():
    loop = asyncio.get_event_loop()
    QUART_APP.discord_client = DiscordClient()
    await QUART_APP.discord_client.bot.login("MY BOT TOKEN")
    loop.create_task(QUART_APP.discord_client.bot.connect())

@QUART_APP.route("/online_list", methods=["GET"])
async def get_online_members():
    resp = {}
    members = await QUART_APP.discord_client.get_online_voice_members()
    ...
api.py

import discord

bot = discord.Client(intents=discord.Intents.all())

...

async def play_audio(audio_name, voiceChannel):
    vc = await voiceChannel.connect()
    print("test")
    vc.play(discord.FFmpegPCMAudio(source="audio\{}".format(audio_name), executable=FFMPEG_PATH))
    while vc.is_playing():
        time.sleep(.1)
    await vc.disconnect()

async def get_online_voice_members():
    guild = bot.get_guild(NMC_GUILD_ID)
    online_voice_users = {}
    for voiceChannel in guild.voice_channels:
        for user in voiceChannel.members:
            online_voice_users[user] = voiceChannel
    return online_voice_users

...
import asyncio
from quart import Quart
import app as discord

QUART_APP = Quart(__name__)

@QUART_APP.before_serving
async def before_serving():
    loop = asyncio.get_event_loop()
    await discord.bot.login("MY BOT TOKEN")
    loop.create_task(discord.bot.connect())

...

@QUART_APP.route("/online_list", methods=["GET"])
async def get_online_members():
    resp = {}
    members = await discord.get_online_voice_members()
    for user in members.keys():
        resp[user.id] = {"nick" : user.nick, "channel" : members[user].id}
    return resp

@QUART_APP.route("/goodnight", methods=["GET"])
async def send_goodnight():
    members = await discord.get_online_voice_members()
    for user in members.keys():
        if user.id == 12345:
            await discord.play_audio("goodnight.mp3", members[user])
            break
    return {"response":"OK"}
class DiscordClient:
    def __init__(self):
        self.bot = discord.Client(intents=discord.Intents.all())
        ...

    async def get_online_voice_members(self):
        guild = self.bot.get_guild(NMC_GUILD_ID)
        ...
@QUART_APP.before_serving
async def before_serving():
    loop = asyncio.get_event_loop()
    QUART_APP.discord_client = DiscordClient()
    await QUART_APP.discord_client.bot.login("MY BOT TOKEN")
    loop.create_task(QUART_APP.discord_client.bot.connect())

@QUART_APP.route("/online_list", methods=["GET"])
async def get_online_members():
    resp = {}
    members = await QUART_APP.discord_client.get_online_voice_members()
    ...

这是因为您在导入时启动了discord客户端(app.py的第3行)。这样做意味着它将使用导入时可用的事件循环。但是,Quart(和Hypercorn,除非被告知不要太多)将关闭现有循环,并在其启动时创建一个新循环。因此,我建议使用该功能进行初始化

为了解决这个问题,我将把你的discord命令包装在一个类中,并在启动函数中初始化它。请注意,我喜欢将实例存储在应用程序本身上(这样就可以通过
当前应用程序
代理访问它们),但这并不是必需的。例如

app.py

import discord

bot = discord.Client(intents=discord.Intents.all())

...

async def play_audio(audio_name, voiceChannel):
    vc = await voiceChannel.connect()
    print("test")
    vc.play(discord.FFmpegPCMAudio(source="audio\{}".format(audio_name), executable=FFMPEG_PATH))
    while vc.is_playing():
        time.sleep(.1)
    await vc.disconnect()

async def get_online_voice_members():
    guild = bot.get_guild(NMC_GUILD_ID)
    online_voice_users = {}
    for voiceChannel in guild.voice_channels:
        for user in voiceChannel.members:
            online_voice_users[user] = voiceChannel
    return online_voice_users

...
import asyncio
from quart import Quart
import app as discord

QUART_APP = Quart(__name__)

@QUART_APP.before_serving
async def before_serving():
    loop = asyncio.get_event_loop()
    await discord.bot.login("MY BOT TOKEN")
    loop.create_task(discord.bot.connect())

...

@QUART_APP.route("/online_list", methods=["GET"])
async def get_online_members():
    resp = {}
    members = await discord.get_online_voice_members()
    for user in members.keys():
        resp[user.id] = {"nick" : user.nick, "channel" : members[user].id}
    return resp

@QUART_APP.route("/goodnight", methods=["GET"])
async def send_goodnight():
    members = await discord.get_online_voice_members()
    for user in members.keys():
        if user.id == 12345:
            await discord.play_audio("goodnight.mp3", members[user])
            break
    return {"response":"OK"}
class DiscordClient:
    def __init__(self):
        self.bot = discord.Client(intents=discord.Intents.all())
        ...

    async def get_online_voice_members(self):
        guild = self.bot.get_guild(NMC_GUILD_ID)
        ...
@QUART_APP.before_serving
async def before_serving():
    loop = asyncio.get_event_loop()
    QUART_APP.discord_client = DiscordClient()
    await QUART_APP.discord_client.bot.login("MY BOT TOKEN")
    loop.create_task(QUART_APP.discord_client.bot.connect())

@QUART_APP.route("/online_list", methods=["GET"])
async def get_online_members():
    resp = {}
    members = await QUART_APP.discord_client.get_online_voice_members()
    ...
api.py

import discord

bot = discord.Client(intents=discord.Intents.all())

...

async def play_audio(audio_name, voiceChannel):
    vc = await voiceChannel.connect()
    print("test")
    vc.play(discord.FFmpegPCMAudio(source="audio\{}".format(audio_name), executable=FFMPEG_PATH))
    while vc.is_playing():
        time.sleep(.1)
    await vc.disconnect()

async def get_online_voice_members():
    guild = bot.get_guild(NMC_GUILD_ID)
    online_voice_users = {}
    for voiceChannel in guild.voice_channels:
        for user in voiceChannel.members:
            online_voice_users[user] = voiceChannel
    return online_voice_users

...
import asyncio
from quart import Quart
import app as discord

QUART_APP = Quart(__name__)

@QUART_APP.before_serving
async def before_serving():
    loop = asyncio.get_event_loop()
    await discord.bot.login("MY BOT TOKEN")
    loop.create_task(discord.bot.connect())

...

@QUART_APP.route("/online_list", methods=["GET"])
async def get_online_members():
    resp = {}
    members = await discord.get_online_voice_members()
    for user in members.keys():
        resp[user.id] = {"nick" : user.nick, "channel" : members[user].id}
    return resp

@QUART_APP.route("/goodnight", methods=["GET"])
async def send_goodnight():
    members = await discord.get_online_voice_members()
    for user in members.keys():
        if user.id == 12345:
            await discord.play_audio("goodnight.mp3", members[user])
            break
    return {"response":"OK"}
class DiscordClient:
    def __init__(self):
        self.bot = discord.Client(intents=discord.Intents.all())
        ...

    async def get_online_voice_members(self):
        guild = self.bot.get_guild(NMC_GUILD_ID)
        ...
@QUART_APP.before_serving
async def before_serving():
    loop = asyncio.get_event_loop()
    QUART_APP.discord_client = DiscordClient()
    await QUART_APP.discord_client.bot.login("MY BOT TOKEN")
    loop.create_task(QUART_APP.discord_client.bot.connect())

@QUART_APP.route("/online_list", methods=["GET"])
async def get_online_members():
    resp = {}
    members = await QUART_APP.discord_client.get_online_voice_members()
    ...