Python Youtube ffmpeg Session Has Been Invalidated - ffmpeg

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.

Related

Youtube DL prepare filename discord bot

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.

Discord sniping edited messages not working

I've scrolled through other people's posts about this, ive tried reworking their code to mine, but it doesnt seem to work
snipe_message_author = {}
#client.event
async def on_message_edit(message_before, message_after):
snipe_message_author = message_before.author
guild = message_before.guild.name
#client.command()
async def snipeedit(ctx):
channel = ctx.channel
try:
snipeEmbed = discord.Embed(colour = discord.Colour.orange(),title=f"{snipe_message_author[channel.id]}", description = f"""Original message : {message_before.content}
Updated message : {message_after.content}""")
await ctx.send(embed = snipeEmbed)
except:
await ctx.send(f"There are no edited messages in #{channel.name}")
Every time i try the code, it returns "There are no edited messages in #*channel*"
I think its because of the snipe_message_author
thanks to anyone who helps.
As Łukasz Kwieciński's comment says:
You never add anything to snipe_message_author = {}, it can't work at all. Based on other posts, you can easily come up with a solution.
Take a look at the following code:
edited_messages = {}
#client.event
async def on_message_edit(message_before, message_after):
edited_messages[message_before.guild.id] = (message_before.content, message_after.content, message_before.author)
#client.command()
async def snipeedit(ctx):
try:
content_before, content_after, message_author = edited_messages[ctx.guild.id]
snipeEmbed = discord.Embed(color=discord.Colour.orange(), title=f"{message_author}",
description=f"Original message : {content_before}
Updated message : {content_after}")
await ctx.send(embed=snipeEmbed)
except:
await ctx.send(f"There are no edited messages in #{ctx.channel.name}")
In our on_message_edit event, we first define what should be "saved" for our guild or what exactly applies.
After we define these things, they are saved in the order specified. So now we have 3 "data" stored. We query or redefine these in our try statement and then read them from edited_messages for the corresponding ctx.guild.

Giphy API not responding in discord.py

I made a discord bot that shows you gifs when you type a certain command but the problem is that it works fine in the first half but takes a long time to show the gifs when not used.
Basically it doesn't show the gifs instantly when not used.
Here's the code that I've written:
#client.command()
async def gif(ctx, *, q = 'dance'):
api_key = 'Some Key here'
api_instanc = giphy_client.DefaultApi()
try:
api_responce = api_instanc.gifs_search_get(api_key, q, limit = 7,rating = 'r')
lst = list(api_responce.data)
giff = random.choice(lst)
emb = discord.Embed(title = f"Requested by {ctx.author} " + q )
emb.set_image(url= f'https://media.giphy.com/media/{giff.id}/giphy.gif')
await ctx.channel.send(embed = emb)
except ApiException as e:
await ctx.channel.send("API EXCEPTION")
It doesn't show any errors but doesn't work after the long time.
Any re-write of the code with aiohttp will be appreciated because I am learning that.
I think the module you are using is not asynchronous which leads to blocking read more.
Default in the command is search = None you can use that with an if statement to check.
After that is the request for the api to get the image.
Here is the code edited to use aiohttp
# import aiohttp
# import random
#bot.command()
async def giphy(ctx, search: str = None):
api_key = ""
embed = discord.Embed(title=f"Requested by {ctx.author}")
async with aiohttp.ClientSession() as session:
# search
if search:
embed.description = search
async with session.get(f'http://api.giphy.com/v1/gifs/search?q={search}&api_key={api_key}&limit=10') as response:
data = await response.json()
gif_choice = random.randint(0, 9)
embed.set_image(url=data['data'][gif_choice]['images']['original']['url'])
# radnom
else:
async with session.get(f'http://api.giphy.com/v1/gifs/random?api_key={api_key}&limit=10') as response:
data = await response.json()
embed.set_image(url=data['data']['images']['original']['url'])
await ctx.send(embed=embed)

News command discord.py

I've made a news command in discord.py using newsapi, I'm having a problem where it sends the top 10 headlines one by one, I wanna make it so that it sends the headline in one embed.
Here's the code :
#commands.command()
async def news(self, ctx):
open_bbc_page = requests.get(main_url).json()
article = open_bbc_page["articles"]
results = []
for ar in article:
results.append(ar["title"])
for i in range(len(results)):
ree = (i + 1, results[i])
em = discord.Embed(title="Here's the trending news", description = f"{ree}",color = 0xa3a3ff)
await ctx.send(embed=em)[enter image description here][1]
[1]: https://i.stack.imgur.com/Fel1n.jpg
You could put them all into the description of the embed like this:
for ar in article:
results.append(ar["title"])
embeddescription = '/n'.join(results)
em = discord.Embed(title="Here's the trending news", description = embeddescription,color = 0xa3a3ff)
await ctx.send(embed=em)
Just need to make sure they arent longer than 2048 characters combined, this is the limit for embed descriptions.
def set_news(ctx, content)
with open('news.json', 'r') as f:
msg = json.load(f)
msg[str("news")] = content
with open('news.json', 'r') as f:
json.dump(msg, f)
def check_news()
with open('news.json', 'r') as f:
msg = json.load(f)
return msg
#bot.command()
async def news_set(ctx, content):
set_news(ctx, content)
await ctx.send("I set news to {content}!")
#bot.command()
async def news(ctx):
news = check_news()
await ctx.send(f"News: {news}")

Problem with (AttributeError) client.logs_from

i was creating bot for discord channel. But I don't understand where i have wronged or errored in my code
I was do from tutorial but in video this wrong not present. Then I search this problem in another tutorial, but i don't have result pls help
#client.command(pass_context=True, name='clear', aliases=['purgemessages'], no_pm=True)
async def clear(ctx, number):
number = int(number)
if number > 99 or number < 1:
await ctx.send("Sorry comrade>-< \n But i can deleted message within a range of 1 - 99")
else:
author = ctx.message.author
authorID = author.id
mgs = []
number = int(number)
channel = ctx.message.channel
async for x in client.logs_from((channel), limit = int(number)):
mgs.append
await ctx.message.channel.delete_messages(ctx, member, mgs)
await ctx.send("This was deleted ^^")
I want a bot to delete messages
You should use client.purge() to do it.
It seems that you're looking for a way to delete the command caller's messages (a.k.a author).
Here's a quick example using purge() method :
author = ctx.message.author
# check function
def is_caller(message):
if(message.author.id == author.id):
return(True)
else:
return(False)
# delete the author's messages
# the purge method returns a list of deleted messages
deleted_message = await client.purge(
limit = number,
check = is_caller
)
await ctx.send(f"{len(deleted_message)} messages deleted.")
The limit is represented by the number parameter of your command.
Hope it helped !

Resources