Youtube DL prepare filename discord bot - discord.py

I'm creating a discord bot which also has a music part. I have it working but i wanted to give the info to the user of which song it's playing. Right now I've this for the play command:
#commands.command()
async def play(self,ctx,url):
await ctx.channel.purge(limit = 1)
ctx.voice_client.stop()
FFMPEG_OPTIONS = {'before_options': '-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5', 'options': '-vn'}
YDL_OPTIONS = {'format':"bestaudio"}
vc = ctx.voice_client
await ctx.send("Searching for the requested song")
with youtube_dl.YoutubeDL(YDL_OPTIONS) as ydl:
info = ydl.extract_info(url, download=False)
videotitle = ydl.prepare_filename(info)
url2 = info['formats'][0]['url']
source = await discord.FFmpegOpusAudio.from_probe(url2, **FFMPEG_OPTIONS)
vc.play(source)
await ctx.send(f"Playing {videotitle}")
This works but i want the output to be changed. Right now i get this:
MIX TECH HOUSE 2020 #8 (Camelphat, Torren Foot, Cardi B, Pax, Muus, Kevin McKay...)-RN7mbUBzUJw.m4a
I want the part "RN7mbUBzUJw.m4a" not to be there. does any one know what goes wrong in the ydl.prepare_filename?

The function YoutubeDL.prepare_filename generates a string that's a valid file name, mangling the video title if necessary and including the video ID and extension. It seems you want just the video title, so you can just do the same thing that function does manually.
The way they get the video title is:
video_title = info_dict.get('title', info_dict.get('id', 'video'))
where info_dict is the dictionary returned by YoutubeDL.extract_info. So in your case
videotitle = info.get('title', 'Video with ID: '+info.get('id', 'unknown'))
should work.

Related

discord.py music bot: Bot doesn't return to queue after finishing the first song

I did everything but couldn't get the bot to play the second song on the queue. When bot finishes the first song, it stops. I have to add another song to queue in order to get the bot to play the second song. How can i make it auto?
Code:
queue=[]
#commands.command()
async def play(self,ctx,message):
if len(queue) <=5 :
if r"https://www.youtube.com/watch\?v=(\S{11})" is message:
queue.append(message)
await ctx.reply(message+" added to queue. 🕒")
else:
keyword=(message)
print(keyword)
htmlurl="https://www.youtube.com/results?search_query=" + str(keyword)
html=(urllib.request.urlopen(htmlurl))
pattern=(r"watch\?v=(\S{11})")
video_ids=re.findall(pattern, html.read().decode())
print(video_ids, ".")
urlh=("https://www.youtube.com/watch?v="+video_ids[0])
print(urlh)
queue.append(urlh)
await ctx.reply(urlh+" added to queue 🕒")
else:
await ctx.send("Queue is full. Limit: 5 videos.")
return
for oyn in range(len(queue)):
if ctx.voice_client.is_playing():
return
else:
FFMPEG_OPTIONS = {'options':'-vn', 'before_options':'-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5'}
YDL_OPTIONS = {"format":"bestaudio",'cachedir': False}
vc = ctx.voice_client
await ctx.send(queue[0]+" is now playing. ✨")
with youtube_dl.YoutubeDL(YDL_OPTIONS) as ydl:
info = ydl.extract_info(queue[0], download= False)
url2 = info["formats"][0]["url"]
source= await discord.FFmpegOpusAudio.from_probe(url2, **FFMPEG_OPTIONS)
vc.play(source)
del(queue[0])

stream audio using yt-dlp kn python instead of downloading the file

i want to stream audio for a discord bot instead of downloading the file and extracting the audio file from it. i have tried code from Is there a way to directly stream audio from a youtube video using youtube-dl or pafy library in python 3.7?
Yes Simple
Install yt_dlp
Import it
Use This Code :
ffmpeg_options = {'options': '-vn'}
ydl_opts = {'format': 'bestaudio'}
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
song_info = ydl.extract_info(url, download=False)
ctx.voice_client.play(discord.FFmpegPCMAudio(song_info["url"], **ffmpeg_options))
Example:
async def streamx(ctx, url):
voiceChannel = ctx.message.author.voice.channel //get Message Sender Channel. When you want it to join without a seperat function.
await voiceChannel.connect() //same applies to this
ffmpeg_options = {'options': '-vn'}
ydl_opts = {'format': 'bestaudio'}
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
song_info = ydl.extract_info(url, download=False)
ctx.voice_client.play(discord.FFmpegPCMAudio(song_info["url"], **ffmpeg_options))
You can adapt the ydl_opts with the documentation from yt_dlp.
Greetings!

Play mp3 music from a local Folder? discord.py

I want my bot to play multiple songs after each other. All I have is my bot playing one song and then stopping to do it. My Code so far:
#bot.command()
async def startq(ctx):
channel = bot.get_channel(705831663497904211)
vc = await channel.connect()
vc.play(discord.FFmpegPCMAudio("E:\Programmieren\Programmieren\Disc-Bot\music2.mp3"))
You should add the songs you want in the songs list, after that it should play all the songs.
You can also scan all the files in the folder and add them to the list using glob.
Note: I have not tried it, but it should work theoretically.
import glob
#bot.command()
async def startq(ctx):
channel = bot.get_channel(705831663497904211)
vc = await channel.connect()
songs = ["music2.mp3","music1.mp3"]
# or check all files in folder
songs = glob.glob("E:\Programmieren\Programmieren\Disc-Bot\*.mp3")
for song in songs:
vc.play(discord.FFmpegPCMAudio(f"E:\Programmieren\Programmieren\Disc-Bot\{song}"))
while vc.is_playing():
await asyncio.sleep(1)

FFmpeg doesn't play any audio through Discord.py BOT

Here is my code for my Discord bot's play function:
#bot.command()
async def play(ctx, url:str = None): # DOESN'T WORK, DOWNLOADS BUT DOESN'T PLAY
...
ytdl_options = {
'format': 'bestaudio/best',
'postprocessors': [{
'key': 'FFmpegExtractAudio',
'preferredcodec': 'mp3',
'preferredquality': '192',
}],
}
ytdl = youtube_dl.YoutubeDL(ytdl_options)
loop = asyncio.get_event_loop()
data = await loop.run_in_executor(None, lambda: ytdl.extract_info(url))
if 'entries' in data:
data = data['entries'][0] # taking top item from a YT playlist
source = ytdl.prepare_filename(data)
vc.play(discord.FFmpegPCMAudio(source)) #play audio
print(vc.is_playing())
await ctx.send("Now playing: " + data.get('title')) #now playing
asyncio.sleep(3)
print(vc.is_playing())
When I call the function, it runs fine and downloads the video from youtube-dl, then sends the message "Now playing: X", but doesn't play any audio.
I added the two print(vc.is_playing()) lines and what is returned in the shell is:
True
False
So clearly it tries to play the song but immediately fails.
There are no exceptions thrown, so I can't understand why FFmpeg doesn't want to play the audio.

Python Youtube ffmpeg Session Has Been Invalidated

I get the following error while I'm playing YouTube audio with my bot
[tls # 0000024ef8c4d480] Error in the pull function.
[matroska,webm # 0000024ef8c4a400] Read error
[tls # 0000024ef8c4d480] The specified session has been invalidated for some reason.
Last message repeated 1 times
It seems like YouTube links expire? I don't really know but I need to fix this issue. This is my code:
class YTDLSource(discord.PCMVolumeTransformer):
def __init__(self, source, *, data, requester):
super().__init__(source)
self.requester = requester
self.title = data['title']
self.description = data['description']
self.uploader = data['uploader']
self.duration = data['duration']
self.web_url = data['webpage_url']
self.thumbnail = data['thumbnail']
def __getitem__(self, item: str):
return self.__getattribute__(item)
#classmethod
async def create_source(cls, ctx, player, search: str, *, loop, download=True):
async with ctx.typing():
loop = loop or asyncio.get_event_loop()
to_run = partial(ytdl.extract_info, url=search, download=download)
raw_data = await loop.run_in_executor(None, to_run)
if 'entries' in raw_data:
# take first item from a playlist
if len(raw_data['entries']) == 1:
data = raw_data['entries'][0]
else:
data = raw_data['entries']
#loops entries to grab each video_url
total_duration = 0
try:
for i in data:
webpage = i['webpage_url']
title = i['title']
description = i['description']
uploader = i['uploader']
duration = i['duration']
thumbnail = i['thumbnail']
total_duration += duration
if download:
source = ytdl.prepare_filename(i)
source = cls(discord.FFmpegPCMAudio(source), data=i, requester=ctx.author)
else:
source = {'webpage_url': webpage, 'requester': ctx.author, 'title': title, 'uploader': uploader, 'description': description, 'duration': duration, 'thumbnail': thumbnail}
player.queue.append(source)
except Exception as e:
print(e)
return
embed=discord.Embed(title="Playlist", description="Queued", color=0x30a4fb, timestamp=datetime.now(timezone.utc))
embed.set_author(name=ctx.author.display_name, icon_url=ctx.author.avatar_url)
embed.set_thumbnail(url=data[0]['thumbnail'])
embed.add_field(name=raw_data['title'], value=f"{len(data)} videos queued.", inline=True)
embed.set_footer(text=raw_data["uploader"] + ' - ' + '{0[0]}m {0[1]}s'.format(divmod(total_duration, 60)))
await ctx.send(embed=embed)
return
embed=discord.Embed(title="Playlist", description="Queued", color=0x30a4fb, timestamp=datetime.now(timezone.utc))
embed.set_author(name=ctx.author.display_name, icon_url=ctx.author.avatar_url)
embed.set_thumbnail(url=data['thumbnail'])
embed.add_field(name=data['title'], value=(data["description"][:72] + (data["description"][72:] and '...')), inline=True)
embed.set_footer(text=data["uploader"] + ' - ' + '{0[0]}m {0[1]}s'.format(divmod(data["duration"], 60)))
await ctx.send(embed=embed)
if download:
source = ytdl.prepare_filename(data)
else:
source = {'webpage_url': data['webpage_url'], 'requester': ctx.author, 'title': data['title'], 'uploader': data['uploader'], 'description': data['description'], 'duration': data['duration'], 'thumbnail': data['thumbnail']}
player.queue.append(source)
return
source = cls(discord.FFmpegPCMAudio(source), data=data, requester=ctx.author)
player.queue.append(source)
#classmethod
async def regather_stream(cls, data, *, loop):
loop = loop or asyncio.get_event_loop()
requester = data['requester']
to_run = partial(ytdl.extract_info, url=data['webpage_url'], download=True)
data = await loop.run_in_executor(None, to_run)
return(cls(discord.FFmpegPCMAudio(data['url']), data=data, requester=requester))
I'm using the rewrite branch of discord.py for the bot.
I'm not sure if I need to provide more details? Please let me know, I really need to get this fixed...
In fact it isn't really a problem with your code (and many people complain of this error).
This is just a possible issue when streaming a video. If you absolutely want to stream it, you have to accept this as a potential issue. Note how (almost) every music bots set limitations for the video/music you want to listen to.
If you need to ensure you do not get this issue, you have to fully download the music. (Which will also make the bot loading longer before playing).
Would you be able to post all your code? i may have a solution for you if i was able to see the whole code.
the solution i would recomend is to download the soong and then delete it after.
You could set your download to true and then add this in your player_loop
try:
# We are no longer playing this song...so, lets delete it!
with YoutubeDL(ytdlopts) as ydl:
info = ydl.extract_info(source.web_url, download=False)
filename = ydl.prepare_filename(info)
try:
if os.path.exists(filename):
os.remove(filename)
else:
pass
except Exception as E:
print(E)
await self.np.delete()
except discord.HTTPException:
pass
bit botched but could be cleaned up, this was the best solution i have found for me.

Resources