Discord.py: 如何在播放命令上实现ytsearch?

Discord.py: How to implement ytsearch on the play command?

大家好,我创建了这个音乐机器人,我想像机器人“Rythm”一样在播放按钮上实现 ytsearch。目前它只能用 url 播放音乐,但我希望我的机器人能够使用相同的命令从 url 和关键字(比如 !play never gonna give you up)播放,但是我不知道该怎么做。你们能帮帮我吗?

musics= {}
ytdl = youtube_dl.YoutubeDL()

class Video:
    def __init__(self, link):
        video = ytdl.extract_info(link, download = False)
        video_format = video["formats"][0]
        self.url =video["webpage_url"]
        self.stream_url =video_format["url"]

def play_song(client, queue, song):
    source= discord.PCMVolumeTransformer(discord.FFmpegPCMAudio(song.stream_url
    , before_options = "-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5"))
    
    def next(_):
        if len(queue)>0:
            new_song= queue[0]
            del queue[0]
            play_song(client, queue, new_song)
        else:
            asyncio.run_coroutine_threadsafe(client.disconnect(), bot.loop)
    
    
    client.play(source, after=next)


@bot.command()
async def play (ctx, url):
    client = ctx.guild.voice_client
    if client and client.channel:
        video = Video(url)
        musics[ctx.guild].append(video)
    else:
        channel = ctx.author.voice.channel
        video = Video(url)
        musics[ctx.guild] = []
        client = await channel.connect()
        await ctx.send(f"Playing : {video.url}")
        play_song(client, musics[ctx.guild], video)

编辑: 所以在尝试添加 ytdl_options 之后,它给了我这个错误,即使没有 --noplaylist,它仍然给我同样的错误(我正在尝试播放的音乐是炫目的音乐)。

ytdl_options = {
    'noplaylist': True,
    'default_search': 'auto'
}


ytdl = youtube_dl.YoutubeDL(ytdl_options)
[download] Downloading playlist: blinding
[youtube:search] query "blinding": Downloading page 1
[youtube:search] playlist blinding: Downloading 1 videos
[download] Downloading video 1 of 1
[youtube] 4NRXx6U8ABQ: Downloading webpage
[youtube] Downloading just video 4NRXx6U8ABQ because of --no-playlist
[download] Finished downloading playlist: blinding
Ignoring exception in command play:
Traceback (most recent call last):
  File "C:\Users\pietr\AppData\Local\Programs\Python\Python39\lib\site-packages\discord\ext\commands\core.py", line 85, in wrapped
    ret = await coro(*args, **kwargs)
  File "c:\Users\pietr\Desktop\Discord bot\Discord bot", line 152, in play
    video = Video(url)
  File "c:\Users\pietr\Desktop\Discord bot\Discord bot", line 93, in __init__
    video_format = video["formats"][0]
KeyError: 'formats'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "C:\Users\pietr\AppData\Local\Programs\Python\Python39\lib\site-packages\discord\ext\commands\bot.py", line 902, in invoke
    await ctx.command.invoke(ctx)
  File "C:\Users\pietr\AppData\Local\Programs\Python\Python39\lib\site-packages\discord\ext\commands\core.py", line 864, in invoke
    await injected(*ctx.args, **ctx.kwargs)
  File "C:\Users\pietr\AppData\Local\Programs\Python\Python39\lib\site-packages\discord\ext\commands\core.py", line 94, in wrapped
    raise CommandInvokeError(exc) from exc
discord.ext.commands.errors.CommandInvokeError: Command raised an exception: KeyError: 'formats'

大概想看一下Youtube API。将 resource 更改为 search,然后单击 list (by keyword)。您将获得示例代码。

您首先需要 Obtain authorization credentials 才能使其正常工作。

创建 YoutubeDL 对象时,可以通过设置 default_search 选项指定其默认搜索行为。

引自here(强调我的):

Use this prefix for unqualified URLs. For example "gvsearch2:" downloads two videos from google videos for youtube-dl "large apple". Use the value "auto" to let youtube-dl guess ("auto_warning" to emit a warning when guessing). "error" just throws an error. The default value "fixup_error" repairs broken URLs, but emits an error if this is not possible instead of searching.

ytdl_options = {'default_search': 'auto'}
ytdl = youtube_dl.YoutubeDL(ytdl_options)

您需要处理完成搜索的情况,因为返回的格式与提供有效 URL 时的格式不同。

import youtube_dl

ytdl_options = {
    'noplaylist': True,
    'default_search': 'auto'
}

ytdl = youtube_dl.YoutubeDL(ytdl_options)

link = 'test search'

video = ytdl.extract_info(link, download = False)

if 'entries' in video:
    video_format = video['entries'][0]["formats"][0]
elif 'formats' in video:
    video_format = video["formats"][0]

url = video["webpage_url"]
stream_url = video_format["url"]