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.
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!