Discord bot isn't playing audio when commanded - python-3.x

I am using python 3.6
I am making a discord bot to play music.
Whenever I give it the 'play' command the discord app shows that the bot is producing audio but I don't hear any audio. I checked the settings and maximized all the audio-related settings.
When I go back to pycharm, I see this error in the 'run' tab:
Traceback (most recent call last):
File "/Volumes/Mahmoud-Disk/MyProfile/Library/Python/3.8/lib/python/site-packages/discord/ext/commands/core.py", line 229, in wrapped
ret = await coro(*args, **kwargs)
File "/Volumes/Mahmoud-Disk/MyProfile/Desktop/Discord Bot/Discord-Bot/main.py", line 72, in play
await ctx.send(embed = discord.Embed(
TypeError: __init__() got an unexpected keyword argument 'author'
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/Volumes/Mahmoud-Disk/MyProfile/Library/Python/3.8/lib/python/site-packages/discord/ext/commands/bot.py", line 1349, in invoke
await ctx.command.invoke(ctx)
File "/Volumes/Mahmoud-Disk/MyProfile/Library/Python/3.8/lib/python/site-packages/discord/ext/commands/core.py", line 1023, in invoke
await injected(*ctx.args, **ctx.kwargs) # type: ignore
File "/Volumes/Mahmoud-Disk/MyProfile/Library/Python/3.8/lib/python/site-packages/discord/ext/commands/core.py", line 238, in wrapped
raise CommandInvokeError(exc) from exc
discord.ext.commands.errors.CommandInvokeError: Command raised an exception: TypeError: __init__() got an unexpected keyword argument 'author'
Here is my code:
import discord
from discord.ext import commands
import wavelink
client = commands.Bot(command_prefix = ".", intents = discord.Intents.all())
class CustomPlayer (wavelink.Player):
def __init__(self):
super().__init__()
self.queue = wavelink.Queue()
#client.event
async def on_ready():
client.loop.create_task(connect_nodes()) #HTTPS and Websocket operations
async def connect_nodes(): #Helper function
await client.wait_until_ready()
await wavelink.NodePool.create_node(
bot = client ,
host = "127.0.0.1" ,
port = 2333 ,
password = "yk I can't "
)
#client.event
async def on_wavelink_node_ready(node = wavelink.Node):
print(f"Node: <{node.identifier}> is ready!")
#client.command()
async def connect(ctx):
vc = ctx.voice_client
try:
channel = ctx.author.voice.channel
except AttributeError:
return await ctx.send("Please join a channel to connect.")
if not vc:
await ctx.author.voice.channel.connect(cls = CustomPlayer())
else:
await ctx.send("The bot is already connected to a voice channel.")
#client.command()
async def disconnect(ctx):
vc = ctx.voice_client
if vc:
await vc.disconnect()
else:
await ctx.send("Bot is not connected to a voice channel.")
#client.command()
async def play(ctx, *, search: wavelink.YouTubeTrack):
vc = ctx.voice_client #represents a discord voice connection
if not vc:
custom_player = CustomPlayer()
vc: CustomPlayer = await ctx.author.voice.channel.connect(cls = custom_player)
if vc.is_playing():
vc.queue.put(item = search)
await ctx.send(embed = discord.Embed(
title = search.title,
url = search.uri,
author = ctx.author,
description = f"Queued {search.title} in {vc.channel}"
))
else:
await vc.play(search)
await ctx.send(embed = discord.Embed(
title = search.title,
url = search.uri,
author = ctx.author,
description = f"Playing {vc.source.title} in {vc.channel}"))
I have no idea what to do to fix this problem.

Simply, I removed the
author = ctx.author,
That are in the "play()" command both times

Related

Discord bot runs differently when called in-file and from outside file

I am trying to integrate a discord bot into an app such that when the user of the app does something, it calls a function that uploads something to discord. This means that the bot only has an on_ready function, and then a client.close() at the end. I wrapped the entire thing inside its own function for easy access from the main app file. Here's the code
def uploader(filePath):
homeDir = str(Path.home())
with open(f'{homeDir}/Library/Application Support/FileBreakerApp/userInfo.json', 'r') as json_file:
userInfo = json.load(json_file)
bot = discord.Client()
#bot.event
async def on_ready():
botChannel = await bot.fetch_channel(userInfo["botChannel"])
await botChannel.send("This confirms that uploader is running")
file = SplitFile(filePath)
for name in file.chunkNames:
fileObj = discord.File(
open(f'{homeDir}/Library/Application Support/FileBreakerApp/filePieces/{name}', 'rb'),
filename=name)
await botChannel.send(file=fileObj)
print("sent file")
await botChannel.send(f'successfully uploaded:{file.fullName}')
await bot.close()
bot.run('CENSORED')
What I want it to do is after it sends "sucessfully uploaded..." it will close the bot, so the code can move on from bot.run() and end the method. This worked perfectly when I called the outermost function within the file it was written in, but when I called it from the main file it threw the following error:
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/tkinter/__init__.py", line 1884, in __call__
return self.func(*args)
File "/Users/nathanwolf/Documents/coding/PycharmProjects/Discord-File-Breaker/Interface.py", line 62, in uploadFile
uploader(filename)
File "/Users/nathanwolf/Documents/coding/PycharmProjects/Discord-File-Breaker/Uploader.py", line 27, in uploader
bot.run('CENSORED')
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/discord/client.py", line 635, in run
loop.add_signal_handler(signal.SIGINT, lambda: loop.stop())
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/asyncio/unix_events.py", line 89, in add_signal_handler
self._check_closed()
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/asyncio/base_events.py", line 510, in _check_closed
raise RuntimeError('Event loop is closed')
RuntimeError: Event loop is closed
I read some sources saying that it had to do with enabling server members intent, so I did that on the developer portal, to no avail. Few others seem to have this problem, and one source said it had to do with bot.close(). Given that, here is my current theory:
I run several others of this kind of function in the app (a bot nested in a function), all with the same token so I could run them through one bot user. By the time this runs, another function like it has been run already, with no issues. This suggests that when it closes the event loop, the next call of bot.run doesn't reopen it.
How can I reopen the bot's event loop at the beginning of this function?(bot.start(TOKEN) doesn't appear to work)
Thanks!
You essentially need to create a new event loop before running this. You can either do this in the function or better (imo) make this an async function and create an event loop in your main file.
def uploader(filePath):
import asyncio
homeDir = str(Path.home())
with open(f'{homeDir}/Library/Application Support/FileBreakerApp/userInfo.json', 'r') as json_file:
userInfo = json.load(json_file)
bot = discord.Client()
#bot.event
async def on_ready():
botChannel = await bot.fetch_channel(userInfo["botChannel"])
await botChannel.send("This confirms that uploader is running")
file = SplitFile(filePath)
for name in file.chunkNames:
fileObj = discord.File(
open(f'{homeDir}/Library/Application Support/FileBreakerApp/filePieces/{name}', 'rb'),
filename=name)
await botChannel.send(file=fileObj)
print("sent file")
await botChannel.send(f'successfully uploaded:{file.fullName}')
await bot.close()
loop = asyncio.new_event_loop()
loop.run_until_complete(bot.start('CENSORED')
loop.close()
OR
# main.py
import asyncio as aio
loop = aio.new_event_loop()
loop.run_until_complete(uploader("./YOUR/PATH/HERE"))
loop.close()
# your func
async def uploader(filePath):
homeDir = str(Path.home())
with open(f'{homeDir}/Library/Application Support/FileBreakerApp/userInfo.json', 'r') as json_file:
userInfo = json.load(json_file)
bot = discord.Client()
#bot.event
async def on_ready():
botChannel = await bot.fetch_channel(userInfo["botChannel"])
await botChannel.send("This confirms that uploader is running")
file = SplitFile(filePath)
for name in file.chunkNames:
fileObj = discord.File(
open(f'{homeDir}/Library/Application Support/FileBreakerApp/filePieces/{name}', 'rb'),
filename=name)
await botChannel.send(file=fileObj)
print("sent file")
await botChannel.send(f'successfully uploaded:{file.fullName}')
await bot.close()
await bot.start('CENSORED')

Message in a specific Discord channel

Hi guys i'm trying to make the bot send a message automatically in a specific channel. I took the channel ID and pass it in the if condition (a_string.find ('data: []')! = -1). However this code gives me this error. See OUTPU ERROR.
P.S. I'm using Replit and Live is the file name (Live.py)
from discord.ext import commands
from Naked.toolshed.shell import execute_js, muterun_js
import sys
class Live(commands.Cog):
def __init__(self,client):
self.client=client
#commands.Cog.listener()
async def on_ready(self):
channel = self.get_channel(828711580434169858)
response = muterun_js('serverJs.js')
original_stdout = sys.stdout # Save a reference to the original standard output
if response.exitcode == 0:
a_string= str(response.stdout)#stampa in console
if (a_string.find('data: []') != -1):
print("Streamer: Offline ")
else:
print("Streamer: Online")
await channel.send('Live Link: https://...link....')
else:
sys.stderr.write(response.stderr)
#commands.command()
async def Live(self,ctx):
await ctx.send('')
def setup(client):
client.add_cog(Live(client))
OUTPUT ERROR:
Ignoring exception in on_ready
Traceback (most recent call last):
File "/opt/virtualenvs/python3/lib/python3.8/site-packages/discord/client.py", line 343, in _run_event
await coro(*args, **kwargs)
File "/home/runner/Solaris-IA/cogs/Live.py", line 12, in on_ready
channel = self.get_channel(828711580434169858)
AttributeError: 'Live' object has no attribute 'get_channel'
It's self.client.get_channel, not self.get_channel, you haven't defined that function
channel = self.client.get_channel(828711580434169858)

Discordpy welcome bot

So, i tried to make a bot that send embed to specific channel everytime user join my server.
The code is look like this
import discord
import asyncio
import datetime
from discord.ext import commands
intents = discord.Intents()
intents.members = True
intents.messages = True
intents.presences = True
bot = commands.Bot(command_prefix="a!", intents=intents)
#bot.event
async def on_ready():
print('Bot is ready.')
#bot.event
async def on_member_join(ctx, member):
embed = discord.Embed(colour=0x1abc9c, description=f"Welcome {member.name} to {member.guild.name}!")
embed.set_thumbnail(url=f"{member.avatar_url}")
embed.set_author(name=member.name, icon_url=member.avatar_url)
embed.timestamp = datetime.datetime.utcnow()
channel = guild.get_channel(816353040482566164)
await channel.send(embed=embed)
and i got an error
Ignoring exception in on_member_join
Traceback (most recent call last):
File "C:\Users\Piero\AppData\Roaming\Python\Python39\site-packages\discord\client.py", line 343, in _run_event
await coro(*args, **kwargs)
File "C:\Users\Piero\Documents\Discord\a-chan\achan_bot\main.py", line 24, in on_member_join
channel = guild.get_channel(816353040482566164)
NameError: name 'guild' is not defined
Anyone know what is wrong in my code?
First of all, looking at the discord.py documention, ctx is not passed to the on_member_join event reference. However, you can use the attributes of member which is passed in order to get the values which you need.
#bot.event
async def on_member_join(member):
embed = discord.Embed(
colour=0x1abc9c,
description=f"Welcome {member.name} to {member.guild.name}!"
)
embed.set_thumbnail(url=f"{member.avatar_url}")
embed.set_author(name=member.name, icon_url=member.avatar_url)
embed.timestamp = datetime.datetime.utcnow()
channel = member.guild.get_channel(816353040482566164)
await channel.send(embed=embed)
Interestingly enough, you did this perfectly for getting the guild name, but it seems you forgot to do the same when retrieving channel.
You did not define guild.
To define your guild you can do the following:
guild = bot.get_guild(GuildID)
It's the same method you used to define your channel, just for your guild now.
For further information you can have a look at the docs: https://discordpy.readthedocs.io/en/latest/api.html#discord.Client.get_guild
Also take into account that we do not have a paramter like ctx in an on_member_join event.
The event just has the parameter member in your case:
#bot.event
async def on_member_join(member): #Removed ctx

Send Discord Message from a looped function

So I've run into a wall trying to get this code to work.
I'm writing a fairly simple Discord bot that does two things.
The main part of the bot is to run an API request when the bot initializes to get a base value of a return. I then have a function that I want to run every X seconds, that checks the value again, and if it changes, send a message to a Discord Channel and then update the variable to the new value, so that the loop can report when it changes again.
The second part, which is not as critical but I still want to include it, is that a user can send a bot command to report the current value of the return.
Problem #1: Arises when I start the loop without the code to send the result via discord message. If i don't include the line to send the discord message in the loop code, the loop runs and prints out the results to the console (for test purposes). However, when the loop is running, I can no longer get the bot to respond to the command.
Problem #2: If I include the code to send the discord message, the whole thing immediately fails and gives me the following error:
File "bot.py", line 67, in <module>
asyncio.run(update_status())
File "/usr/lib/python3.7/asyncio/runners.py", line 43, in run
return loop.run_until_complete(main)
File "/usr/lib/python3.7/asyncio/base_events.py", line 584, in run_until_complete
return future.result()
File "bot.py", line 63, in update_status
await channel.send(f'Server status is still: {updatestatus}.')
File "/usr/local/lib/python3.7/dist-packages/discord/abc.py", line 905, in send
nonce=nonce, allowed_mentions=allowed_mentions)
File "/usr/local/lib/python3.7/dist-packages/discord/http.py", line 185, in request
async with self.__session.request(method, url, **kwargs) as r:
File "/usr/local/lib/python3.7/dist-packages/aiohttp/client.py", line 1012, in __aenter__
self._resp = await self._coro
File "/usr/local/lib/python3.7/dist-packages/aiohttp/client.py", line 357, in _request
raise RuntimeError('Session is closed')
RuntimeError: Session is closed
Problem #3: More of a minor nuisance, but if I set my code up so that it works in Problem #1, the loop does not start automatically, but only after I press Ctrl+C (note: I am writing the code on a Raspi 4 via PuTTY.
Any thoughts?
Full Code:
# bot.py
import os
import requests
import discord
import json
import asyncio
from dotenv import load_dotenv
from discord.ext import commands
from discord.ext import tasks
from discord.utils import get
load_dotenv()
TOKEN = os.getenv('DISCORD_TOKEN')
CLIENTID = os.getenv('CLIENT_ID')
CLIENTSECRET = os.getenv('CLIENT_SECRET')
bot = commands.Bot(command_prefix='+')
#bot.event
async def on_ready():
print(f'{bot.user.name} has connected to Discord!')
channel = bot.get_channel(795162312112865280)
await channel.send('MurkyBot has connected')
def create_access_token(client_id, client_secret, region = 'us'):
data = { 'grant_type': 'client_credentials' }
response = requests.post('https://%s.battle.net/oauth/token' % region, data=data, auth=(client_id, client_secret))
return response.json()
tokenresponse = create_access_token(CLIENTID, CLIENTSECRET)
accesstoken = tokenresponse["access_token"]
print(accesstoken)
initialrequest = requests.get(f'https://us.api.blizzard.com/data/wow/connected-realm/154?namespace=dynamic-us&locale=en_US&access_token={accesstoken}')
initialrequest = initialrequest.json()
initialstatus = initialrequest['status']['type']
print(f'Initial status: {initialstatus}')
#bot.command(name='status', help='Gets the current server status')
async def manual_status(ctx):
manualrequest = requests.get(f'https://us.api.blizzard.com/data/wow/connected-realm/154?namespace=dynamic-us&locale=en_US&access_token={accesstoken}')
manualrequest = manualrequest.json()
manualstatus = manualrequest['status']['type']
channel = bot.get_channel(795162312112865280)
await ctx.send(f'Current world server status is: {manualstatus}')
bot.run(TOKEN)
async def update_status():
while True:
global initialstatus
channel = bot.get_channel(795162312112865280)
updaterequest = requests.get(f'https://us.api.blizzard.com/data/wow/connected-realm/154?namespace=dynamic-us&locale=en_US&access_token={accesstoken}')
updaterequest = updaterequest.json()
updatestatus = updaterequest['status']['type']
if updatestatus != initialstatus:
await channel.send(f'Server status has changed to: {updatestatus}!')
initialstatus = updatestatus
print('Status Change')
await asyncio.sleep(5)
else:
await channel.send(f'Server status is still: {updatestatus}.')
print('No Change')
await asyncio.sleep(5)
asyncio.run(update_status())
.run is a blocking call, meaning that everything stops and waits for it to complete. Therefore, the second part can only run after you ctrl+c, ending the script however.
You may want to check out discord.ext.tasks, it will have the intended functionality.
For what you're trying to do, here would be the updated code using discord.ext.tasks:
from dotenv import load_dotenv
from discord.ext import commands
from discord.ext import tasks
from discord.utils import get
load_dotenv()
TOKEN = os.getenv('DISCORD_TOKEN')
CLIENTID = os.getenv('CLIENT_ID')
CLIENTSECRET = os.getenv('CLIENT_SECRET')
bot = commands.Bot(command_prefix='+')
#tasks.loop(seconds=60.0)
async def update_status():
while True:
global initialstatus
channel = bot.get_channel(795162312112865280)
updaterequest = requests.get(f'https://us.api.blizzard.com/data/wow/connected-realm/154?namespace=dynamic-us&locale=en_US&access_token={accesstoken}')
updaterequest = updaterequest.json()
updatestatus = updaterequest['status']['type']
if updatestatus != initialstatus:
await channel.send(f'Server status has changed to: {updatestatus}!')
initialstatus = updatestatus
print('Status Change')
await asyncio.sleep(5)
else:
await channel.send(f'Server status is still: {updatestatus}.')
print('No Change')
await asyncio.sleep(5)
#bot.event
async def on_ready():
update_status.start()
print(f'{bot.user.name} has connected to Discord!')
channel = bot.get_channel(795162312112865280)
await channel.send('MurkyBot has connected')
def create_access_token(client_id, client_secret, region = 'us'):
data = { 'grant_type': 'client_credentials' }
response = requests.post('https://%s.battle.net/oauth/token' % region, data=data, auth=(client_id, client_secret))
return response.json()
tokenresponse = create_access_token(CLIENTID, CLIENTSECRET)
accesstoken = tokenresponse["access_token"]
print(accesstoken)
initialrequest = requests.get(f'https://us.api.blizzard.com/data/wow/connected-realm/154?namespace=dynamic-us&locale=en_US&access_token={accesstoken}')
initialrequest = initialrequest.json()
initialstatus = initialrequest['status']['type']
print(f'Initial status: {initialstatus}')
#bot.command(name='status', help='Gets the current server status')
async def manual_status(ctx):
manualrequest = requests.get(f'https://us.api.blizzard.com/data/wow/connected-realm/154?namespace=dynamic-us&locale=en_US&access_token={accesstoken}')
manualrequest = manualrequest.json()
manualstatus = manualrequest['status']['type']
channel = bot.get_channel(795162312112865280)
await ctx.send(f'Current world server status is: {manualstatus}')
bot.run(TOKEN)

Discord.py song queuing system

I am trying to code a discord music bot and it worked until i converted the queuing system from a list of URLs to a dictionary with the song name so i can display what's playing next.
When the second song is about to play I get this error message:
C:\Users\sammy\AppData\Local\Programs\Python\Python38\lib\site-packages\discord\player.py:611: RuntimeWarning: coroutine 'Command.__call__' was never awaited
self.after(error)
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
Here is the code, I've trimmed it a bit so that it's not super long:
global ydl_opts
ydl_opts = {
'format': 'bestaudio/best',
'postprocessors': [{
'key': 'FFmpegExtractAudio',
'preferredcodec': 'mp3',
'preferredquality': '192',
}],
}
from discord.utils import get
global voice
global queue_list
queue_list = {}
def queue():
global queue_list
print("hi")
print(len(queue_list))
if len(queue_list) != 0:
keys = list(queue_list.keys())
values = list(queue_list.values())
print("AAAAAAAAAAAAA: " + str(values[0]))
play_url(str(values[0]))
print("AAAAAAAAAAAAA2: " + str(queue_list[keys[0]]))
del queue_list[keys[0]]
print(str(queue_list))
def play_url(url):
try:
os.remove("song.mp3")
except:pass
url = str(url)
with youtube_dl.YoutubeDL(ydl_opts) as ydl:
ydl.download([url])
for file in os.listdir("./"):
if file.endswith(".mp3"):
os.rename(file, "song.mp3")
voice.play(discord.FFmpegPCMAudio("song.mp3"), after=lambda e: queue())
voice.source = discord.PCMVolumeTransformer(voice.source)
voice.source.volume = 0.07
#client.command()
async def play(ctx, curl):
#global voice
try:
global voice
voice = await ctx.message.author.voice.channel.connect()
except:pass
if voice.is_playing() == False:
print("first")
song_there = os.path.isfile("song.mp3")
try:
if song_there:
os.remove("song.mp3")
except PermissionError:
return
#voice = get(client.voice_clients, guild=ctx.guild)
play_url(curl)
elif voice and voice.is_playing():
print("next")
info_dict = YoutubeDL(ydl_opts).extract_info(curl, download=False)#youtube dl attribute settings are needed
#print(info_dict['title'])
if info_dict.get('title', None) in queue_list:
queue_list[str(info_dict['title']) + str(random.randint())] = curl
else:
queue_list[str(info_dict['title'])] = curl
#print(str(queue_list))
pass
#client.command(pass_context=True)
async def pause(ctx):
#voice = get(ctx.client.voice_clients, guild=ctx.guild)
#voice = await ctx.message.author.voice.channel.connect()
if voice and voice.is_playing():
voice.pause()
#client.command(pass_context=True)
async def resume(ctx):
if voice and voice.is_paused():
voice.resume()
#client.command(pass_context=True)
async def stop(ctx):
global queue_list
queue_list = []
if voice and voice.is_playing():
voice.stop()
#client.command(pass_context=True)
async def skip(ctx):
voice.stop()
try:
os.remove("song.mp3")
except:pass
play_url(queue_list[0])
#client.command(pass_context=True)
async def queue(ctx):
values = list(queue_list.values())
keys = list(queue_list.keys())
await ctx.send("*Up Next:*")
for i in range(len(keys)):
info_dict = YoutubeDL(ydl_opts).extract_info(values[i], download=False)
message = "**" + str(i + 1) + ".** " + str(keys[i]) + " (" + str(info_dict['duration']) + ")"
await ctx.send(message)
client.run(TOKEN)
C:\Users\sammy\AppData\Local\Programs\Python\Python38\lib\site-packages\discord\player.py:611: RuntimeWarning: coroutine 'Command.call' was never awaited
self.after(error)
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
As your error code states you forgot to add "await" at the beginning of line 611.
C:\Users\sammy\AppData\Local\Programs\Python\Python38\lib\site-packages\discord\player.py is the file path for your script
:611: is the line within aforementioned file
RuntimeWarning: coroutine 'Command.call' was never awaited self.after(error) is what went wrong within the file.
I hope this breakdown has been helpful for you and aids your ventures.
(Usually) means you forgot to use await before a coroutine (functions starting with async) somewhere, which is mandatory.

Resources