Connected users number in a voice channel doesn't update - discord

So I'm trying to make a script that shows the number of connected users to voice channels in a server through a voice channel (like the date/time or number of members in a server from StatBot) but it doesn't update most of the time without showing a problem?
Here is the code I made:
#bot.event
async def on_voice_state_update(member, before, after):
vc = bot.get_channel(990136836573782056)
if before.channel is None and after.channel is not None:
tab = list(filter(lambda m: m.voice, member.guild.members))
await vc.edit(name=f"Voice: [{len(tab)}]")
if before.channel is not None and after.channel is None:
tab = list(filter(lambda m: m.voice, member.guild.members))
await vc.edit(name=f"Voice: [{len(tab)}]")

Related

get the number of users in a voice channel with my discord bot in python

I'm looking for a way to get the number of users in a voice channel and to get their username to use it in one of my discord bot command, I found that I can use ctx.guild.member to get the members of users in the server, but not in a specific channel, is there a method to do that ?
I tried this
from discord.ext import commands
bot = commands.Bot(intents=discord.Intents.all(),command_prefix = "/")
#bot.command()
async def teamup(ctx):
channel = ctx.author.VoiceChannel
Or this
bot = commands.Bot(intents=discord.Intents.all(),command_prefix = "/")
#bot.command()
async def teamup(ctx):
channel = ctx.message.author.voice.channel
None of them works, the first tells me that member objects has no attribute VoiceChannel
and the second one tells me that ctx.message.author.voice is a NoneType object and has no attribute channel
You're very close.
#bot.command()
async def teamup(ctx):
channel = ctx.message.author.voice.channel
ctx has an author property; this returns the user/member object for the individual that invoked the command. The user/member has a voice property that returns the VoiceState object of the user. This has a channel property which will return the voice channel that the user is in. Importantly, this will be None if the user isn't in a voice channel. So, putting it together:
#bot.command()
async def teamup(ctx):
voice = ctx.author.voice
if not voice.channel:
await ctx.send("You are not currently in a voice channel")
return
channel = voice.channel
# do what you want with the channel here
await ctx.send(f"You're in {channel.name}!")

How to make discord bot only notify me when an user joining voice channel and already leaving voice channel more than 5 minutes before

#client.event
async def on_voice_state_update(member, before, after):
# This function is called when not only member join to the voice channel,
# but also member changed their status to mute.
# So, it is necessary to catch only events that joining channel.
if before.channel != after.channel:
if after.channel is not None and after.channel.id == int(VOICE_CHANNEL_ID1):
_name = member.nick if member.nick else member.name
message = {
"message": "\n" + _name + " Join The Livestream Channel"
}
requests.post(LINE_NOTIFY_API_URL, headers=HEADERS, data=message)
if before.channel != after.channel:
if after.channel is not None and after.channel.id == int(VOICE_CHANNEL_ID2):
_name = member.nick if member.nick else member.name
message = {
"message": "\n" + _name + " Join The Nongskuy Channel"
}
requests.post(LINE_NOTIFY_API_URL, headers=HEADERS, data=message)
client.run(DISCORD_BOT_ACCESS_TOKEN)
so i'm trying to make a bot that can notify my LINE group whenever someone joining voice channel in my discord server. The problem is, my friend often playing with my bot by leaving and joining the voice channel repeatly and my bot will spamming in my LINE group if someone joining the voice channel.So, i need a help to make my bot only notify my LINE group if an user is already leaving voice channel for 5 minutes and joining again to voice channel
It seems that you essentially want to check if 5, or more, minutes have passed between each voice channel leave/join of a user. You can use the datetime module to get the time of when a user joined and left the channel. How to get the current time in Python. Once you get the time, you can get the minutes of the time like this:
>>> now = datetime.now()
>>> print(now)
2021-11-23 14:05:31.787939
>>> print(now.minute)
5
So you can just store now.minute in another variable and use it for comparison later on.

How to prevent bot from spamming embeds? Discord.py

I have discord bot and it checks whether streamer is live or not. And I have a function that prevents it from spamming when someone is live:
if status is True:
async for message in channel.history(limit=2000):
if message.content == f"`Hey #everyone, {twitch_name} is live! Check it out:" + f"https://www.twitch.tv/{twitch_name}`":
break
else:
async for member in guild.fetch_members(limit=None):
if member.id == int(user_id):
await member.add_roles(role)
await channel.send(f"`Hey #everyone, {twitch_name} is live! Check it out:" + f"https://www.twitch.tv/{twitch_name}`")
print(f"{user} started streaming. Sending a notification.")
break
And I wonder if there is the way to do same with embeds, but idk what to use. I though I can use if embed = twitch_embed: break instead of if message.content.
I want to send both message and embed when someone is live one time per stream each like mee6 does:
And I want to combine message and embed antispam function in the code. Please help! All my code here if you need:
import os
import json
import discord
import requests
from discord.ext import tasks, commands
from server import ping
from twitchAPI.twitch import Twitch
from discord.utils import get
intents = discord.Intents.all()
bot = commands.Bot(command_prefix='$', intents=intents)
# Authentication with Twitch API.
client_id = os.getenv('client_id')
client_secret = os.getenv('Dweller_token')
twitch = Twitch(client_id, client_secret)
twitch.authenticate_app([])
TWITCH_STREAM_API_ENDPOINT_V5 = "https://api.twitch.tv/kraken/streams/{}"
API_HEADERS = {
'Client-ID': client_id,
'Accept': 'application/vnd.twitchtv.v5+json',
}
user_info = twitch.get_users(logins=['turb4ik'])
user_id = user_info['data'][0]['id']
print(user_info)
# Returns true if online, false if not.
def checkuser(user):
try:
userid = twitch.get_users(logins=[user])['data'][0]['id']
url = TWITCH_STREAM_API_ENDPOINT_V5.format(userid)
try:
req = requests.Session().get(url, headers=API_HEADERS)
jsondata = req.json()
if 'stream' in jsondata:
if jsondata['stream'] is not None:
return True
else:
return False
except Exception as e:
print("Error checking user: ", e)
return False
except IndexError:
return False
# Executes when bot is started
#bot.event
async def on_ready():
# Defines a loop that will run every 10 seconds (checks for live users every 10 seconds).
#tasks.loop(seconds=10)
async def live_notifs_loop():
# Opens and reads the json file
with open('streamers.json', 'r') as file:
streamers = json.loads(file.read())
# Makes sure the json isn't empty before continuing.
if streamers is not None:
# Gets the guild, 'twitch streams' channel, and streaming role.
guild = bot.get_guild(690995360411156531)
channel = bot.get_channel(785523710362124298)
role = get(guild.roles, id=835581408272580649)
# Loops through the json and gets the key,value which in this case is the user_id and twitch_name of
# every item in the json.
for user_id, twitch_name in streamers.items():
print("checking" + " " + str(twitch_name))
# Takes the given twitch_name and checks it using the checkuser function to see if they're live.
# Returns either true or false.
status = checkuser(twitch_name)
# Gets the user using the collected user_id in the json
user = bot.get_user(int(user_id))
# Makes sure they're live
if status is True:
# Checks to see if the live message has already been sent.
#limit = 0
#limit += 1
async for message in channel.history(limit=2000):
# If it has, break the loop (do nothing).
if message.content == f"`Hey #everyone, {twitch_name} is live! Check it out:" + f"https://www.twitch.tv/{twitch_name}`":
break
# If it hasn't, assign them the streaming role and send the message.
else:
# Gets all the members in your guild.
async for member in guild.fetch_members(limit=None):
# If one of the id's of the members in your guild matches the one from the json and
# they're live, give them the streaming role.
if member.id == int(user_id):
await member.add_roles(role)
# Sends the live notification to the 'twitch streams' channel then breaks the loop.
'''twitch_embed = discord.Embed(
title=f":red_circle: **LIVE**\n{user.name} is now streaming on Twitch!",
color=0xac1efb
)'''
#twitch_embed.add_field(name='**Game**', value='add value',inline=True)
#twitch_embed.add_field(name='**Viewers**', value='add value',inline=True)
#twitch_embed.set_image(url=f'\nhttps://www.twitch.tv/{twitch_name}')
await channel.send(f"`Hey #everyone, {twitch_name} is live! Check it out:" + f"https://www.twitch.tv/{twitch_name}`")
#await channel.send(embed=twitch_embed)
print(f"{user} started streaming. Sending a notification.")
break
# If they aren't live do this:
else:
# Gets all the members in your guild.
async for member in guild.fetch_members(limit=None):
# If one of the id's of the members in your guild matches the one from the json and they're not
# live, remove the streaming role.
if member.id == int(user_id):
await member.remove_roles(role)
# Checks to see if the live notification was sent.
async for message in channel.history(limit=200):
# If it was, delete it.
if str(user.mention) in message.content and "is now streaming" in message.content:
await message.delete()
# Start your loop.
live_notifs_loop.start()
# Command to add Twitch usernames to the json.
#bot.command(name='addtwitch', help='Adds your Twitch to the live notifs.', pass_context=True)
#commands.has_permissions(administrator = True)
async def addtwitch(ctx, twitch_name):
# Opens and reads the json file.
with open('streamers.json', 'r') as file:
streamers = json.loads(file.read())
# Gets the users id that called the command.
user_id = ctx.author.id
# Assigns their given twitch_name to their discord id and adds it to the streamers.json.
streamers[user_id] = twitch_name
# Adds the changes we made to the json file.
with open('streamers.json', 'w') as file:
file.write(json.dumps(streamers))
# Tells the user it worked.
await ctx.send(f"Added {twitch_name} for {ctx.author} to the notifications list.")
ping()
bot.run(os.getenv('token'))
Edit:
Please say if something is not right or you don't understand the question instead of just closing it.
To send the embed in the same message you can use content an example would be:
await channel.send(content=f"`Hey #everyone, {twitch_name} is live! Check it out:" + f"https://www.twitch.tv/{twitch_name}`", embed=twitch_embed)
There would be no change in your check function as the message.content would be the same text message just with an embed as well.
You should really check if the stream has finished either by web scraping or some API instead of checking message content. If the stream finishes 3 hours ago but you only check for 2 streamers there won't be a change unless you have thought of this already.

Discord Python Rewrite - Broadcast

Is it possible to make the bot sends 1 message on every server that the bot is in without sending the message to every channel? I have a working code but it sends to all channel
#client.command()
async def broadcast(ctx, *, message):
for guild in client.guilds:
for channel in guild.channels:
if guild.name == ctx.author.guild.name:
pass
else:
try:
await channel.send(message)
await ctx.send(
'Sent to {} (ID: {}, Owner: {}#{} With {} Members)'.format(
guild.name,
guild.id,
guild.owner.name,
guild.owner.discriminator,
guild.member_count
))
except:
await ctx.send(
'Could not send at {} (Channel ID: {}). (Owner: {}#{})'.format(
guild.name,
channel.id,
guild.owner.name,
guild.owner.discriminator,
))
return
else:
break
please help
If you use
for guild in client.guilds:
channel = discord.utils.get(guild.text_channels, name="general")
if channel != None:
#do something
you could get the #general channel from each guild. That would be just one channel (Discord allows multiple channels to share names but most people won't do this, and .get() will return the first only, anyway).
This is much better than looping over all channels and slightly better than picking random channels but I still would consider letting guilds set their own broadcast reception channels.
Tested and it works, albeit my bot exists only in one server, I don't know if there are unknown consequences for trying to do this over 100+ servers.

Discord.py (rewrite) How to check if the bot is already in the channel you're asking it to join?

I'm having a little bit of trouble making my bot check if it's already in the channel it's being asked to join.
Just as an example, this is a bit of code:
async def _sound(self, ctx:commands.Context):
voice_channel = None
if ctx.author.voice != None:
voice_channel = ctx.author.voice.channel
if voice_channel != None:
vc = await voice_channel.connect()
vc.play(discord.FFmpegPCMAudio('sound.mp3'))
await asyncio.sleep(5)
await vc.disconnect()
The problem I'm facing is, if I use the command >sound while the bot is still in the voice channel, I get an error saying that the bot is already in the channel. I've attempted comparing the client channel and the user channel and if they're the same to disconnect and then reconnect avoiding the error but I can't get it right. This is what I tried but didn't work:
voice_client = ctx.voice_client
if voice_client.channel.id == voice_channel.id:
await voice_channel.disconnect
vc = await voice_channel.connect()
vc.play(discord.FFmpegPCMAudio('sound.mp3'))
asyncio.sleep(4)
await vc.disconnect()
You can get the VoiceClient of the bot in that guild (if any), through ctx.voice_client. You can then move that client between channels (which will do nothing if it's already there), or create a new client through voice_channel.connect if it doesn't exist:
#commands.command()
async def _sound(self, ctx):
if ctx.author.voice is None or ctx.author.voice.channel is None:
return
voice_channel = ctx.author.voice.channel
if ctx.voice_client is None:
vc = await voice_channel.connect()
else:
await ctx.voice_client.move_to(voice_channel)
vc = ctx.voice_client
vc.play(discord.FFmpegPCMAudio('sound.mp3'))
await asyncio.sleep(5)
await vc.disconnect()

Resources