Search code examples
pythondiscord.pyyoutube-dl

Porting code from youtube-dl to yt-dlp library for Python Discord Bot


This is my first question here therefore I hope this format is fine. I've searched for the issue on internet and checked the documentation of yt-dlp however could not find something useful or maybe I just dont understand what to do.

In a normal case, I was using youtube-dl to download musics from youtube and play it in my discord bot but its download rate restrictions became problematic (60-80 KiB/s). For this reason I started the use yt-dlp. It works fine if I use url directly. However, when I use a searchword instead of url, seems like code does not extract the info to get url. (Below code was working fine with youtube-dl too) Here is the code:

@bot.command()
async def play(ctx, *, searchword):
    ydl_opts = {}
    voice = ctx.voice_client

    #get the title and url from video

Below code works fine with direct url but when I write something such as (! is my command prefix by the way) !play By the Sword download does not start but console says:

Downloading playlist: By the Sword
    if searchword[0:4] == "http" or searchword[0:3] == "www":
        with yt_dlp.YoutubeDL(ydl_opts) as ydl:
            info = ydl.extract_info(searchword, download = False)
            title = info["title"]
            url = searchword
 
    if searchword[0:4] != "http" and searchword[0:3] != "www":
        with yt_dlp.YoutubeDL(ydl_opts) as ydl:
            info = ydl.extract_info(f"ytsearch:{searchword}", download = False)["entries"][0]
            title = info["title"]
            url = info["webpage_url"]
 
    ydl_opts = {
        'format' : 'bestaudio/best',
        "outtmpl" : f"{title}.mp3",
        "postprocessors": 
        [{"key" : "FFmpegExtractAudio", "preferredcodec" : "mp3", "preferredquality" : "192"}],   
    }



    def download(url):
        with yt_dlp.YoutubeDL(ydl_opts) as ydl:
            ydl.download([url])
    loop = asyncio.get_event_loop()
    await loop.run_in_executor(None, download, url)

    #playing and queueing audio
    if voice.is_playing():
        queuelist.append(title)
        await ctx.send(f"Added to queue: {title}")
    else:
        voice.play(discord.FFmpegPCMAudio(f"{title}.mp3"), after = lambda e : check_queue())
        await ctx.send(f"Playing {title} !!!")
        filestodelete.append(title)

    def check_queue():
        try:
            if queuelist[0] != None:
                voice.play(discord.FFmpegPCMAudio(f"{queuelist[0]}.mp3"), after = lambda e : check_queue())
                filestodelete.append(queuelist[0])
                queuelist.pop(0)
        except IndexError:
            for file in filestodelete:
                os.remove(f"{file}.mp3")
            filestodelete.clear() 

I am not sure if the problem is about

info = ydl.extract_info(f"ytsearch:{searchword}", download = False)["entries"][0]

or downloading itself. Documentation of yt-dlp says that,

Tip: If you are porting your code from youtube-dl to yt-dlp, one important point to look out for is that we do not guarantee the return value of YoutubeDL.extract_info to be json serializable, or even be a dictionary. It will be dictionary-like, but if you want to ensure it is a serializable dictionary, pass it through YoutubeDL.sanitize_info as shown in the example above

Here is the link: https://github.com/yt-dlp/yt-dlp#embedding-yt-dlp Thanks.


Solution

  • Apparently, I solved the issue by myself by using a different way. As I mentioned above youtube_dl works fine however yt_dlp .extract_info() is problematic. A simple solution to fix this is extracting info by using youtube_dl module, then download file by using yt_dlp.

    Use this for downlaoding:

    with yt_dlp.YoutubeDL(ydl_opts) as ydl:
                ydl.download([url])
    

    But this for extracting url and title from a given string which is not URL

    if searchword[0:4] != "http" and searchword[0:3] != "www":
            with youtube_dl.YoutubeDL(ydl_opts) as ydl:
                info = ydl.extract_info(f"ytsearch:{searchword}", download = False)["entries"][0]
                title = info["title"]
                url = info["webpage_url"]
    

    Do not forget to include both modules!