FSMstate error, cant connect mongo db to aiogram - python

I'm writing a telegram bot on aiogram and I've decided to use MongoDB as database for the project.
Unfortunately I'm stuck on the user balance feature.
I need to give user a balance and I need to have a possibility to change it.
from aiogram import types
from db import collection
from loader import dp
from states.balance_state import balance
from aiogram.dispatcher.filters.state import State, StatesGroup
from aiogram.dispatcher import FSMContext
import motor.motor_asyncio
from aiogram.contrib.fsm_storage.memory import MemoryStorage
import asyncio
storage=MemoryStorage()
#dp.message_handler(text='/balance', state = None)
async def change_balance(message: types.Message):
await message.answer('Amount')
await balance.amount.set()
async def check_balance(user_id: int, amount, now_balance):
try:
amount = int(amount)
if now_balance + amount >= 0:
await change_balance(user_id, amount)
return True
elif now_balance + amount < 0:
return 'no money'
except Exception:
return False
#dp.message_handler(state=balance.amount)
async def change_balance(message: types.Message, state: FSMContext):
user_id = message.chat.id
answer = message.text
await state.update_data(amount=answer)
check_balance = await check_balance(user_id=user_id, amount=answer)
now_balance = collection.find_one({"_id" : user_id})["money"]
new_balance = now_balance + answer
collection.update_one({"_id" : user_id}, {"$set" : {"money" : new_balance}})
if check_balance == 'no money':
await message.answer('error ')
await state.finish
elif check_balance:
await message.answer('Success')
await state.finish
else:
await message.answer('error')
await state.finish
Ive tried different options but none of them seems to work for some reason
Here is code for database
collection = cluster.Mafia_users.user
async def add_user(user_id, username):
date = datetime.now().date()
collection.insert_one({
"_id" : user_id,
"name" : username,
"date" : str(date),
"money" : int(1),
})
(cluster is connected but i havent add it here for safety purposes)
This is the error that appears in terminal when user writes /balance
FSMStorageWarning: You haven’t set any storage yet so no states and no data will be saved.
You can connect MemoryStorage for debug purposes or non-essential data.
await state.set_state(self.state)

Related

Warning discord.getaway "discord.gateway: Shard ID None heartbeat blocked for more than 10 seconds."

I tried to write a Discord bot that forwards messages from one server to another. But I get a warning that disconnects my connection to the discord gateway. I read that it is possible because of tyme.slep(), but without it, the connection is always interrupted. As I understand it, DDOS protection is activated due to a large number of requests.
import asyncio
import websocket
import json
from threading import Thread
import discord
import requests
from io import BytesIO
import time
from discord.ext import tasks
# Bot
bot_token = "anything"
user_token = "anything"
client = discord.Client(intents=discord.Intents.default())
# Channels list
f = open('channels.txt', 'r')
channels_file = f.read()
channels_array = channels_file.strip().split('\n')
# Connect func
def send_json_request(ws, request):
ws.send(json.dumps(request))
def receive_json_response(ws):
response = ws.recv()
if response:
return json.loads(response)
#WebSoket
def on_closed(ws):
ws.connect("wss://gateway.discord.gg/?v=6&encording=json")
ws = websocket.WebSocket(on_close=on_closed)
ws.connect("wss://gateway.discord.gg/?v=6&encording=json")
def receive_json_response(ws):
response = ws.recv()
if response:
return json.loads(response)
def get_attachment_media(media):
media_array = []
for i in media:
response = requests.get(i['url'])
im = BytesIO(response.content)
print(im)
media_array.append(discord.File(im))
return media_array
def get_channel(id):
for i in channels_array:
if i == id:
return True
return False
#Heartbeat
def heartbeat(interval):
print("Heartbeat begin")
while True:
time.sleep(interval)
heartbeatJSON = {
"op": 1,
"d": "null"
}
send_json_request(ws, heartbeatJSON)
print("Heartbeat sent")
#tasks.loop(seconds=0.5)
async def main():
channel = client.get_channel(anything)
event = receive_json_response(ws)
try:
if event['d']['author']['id'] == 'anything':
return
id_channel = event['d']['channel_id']
id_guild = event['d']['guild_id']
if get_channel(id_channel):
content = event['d']['content']
attachment_media = get_attachment_media(event['d']['attachments'])
await channel.send(content, files=attachment_media)
op_code = event('op')
if op_code == 11:
print('Heartbeat recieved')
except:
pass
#client.event
async def on_ready():
event = receive_json_response(ws)
heartbeat_interval = event['d']['heartbeat_interval'] / 1000
send_json_request(ws, {
"op": 2,
"d": {
"token": user_token,
"properties": {
"$os": 'linux',
"$browser": 'chrome',
"$device": 'pc'
}
}
})
main.start()
asyncio.run(heartbeat(heartbeat_interval))
client.run(bot_token)
I recommend you to check this answer and adjust it to your code.
However, if you are just trying to make your bot copy the contenet of the messages sent in one server and sending to another one, you can do it in a easier way using the on_message() event. This is the entire code, which should also prevent any warning (unless the bot tries to send too many messages in a short period of time):
import discord
intents = discord.Intents.default()
intents.message_content = True # You are missing the message_content intent! (needed to read the content of the guild's messages)
client = discord.Client(intents=intents)
TOKEN = "Your Token"
guild_id = 123456789 # The guild you want your bot to send the messages to
channel_id = 987654321 # The channel of the guild you want your bot to send the messages to
guild = None
channel = None
#client.event
async def on_ready():
global guild, channel, guild_id, channel_id
await client.wait_until_ready()
guild = client.get_guild(guild_id)
channel = guild.get_channel(channel_id)
print("Logged")
#client.event
async def on_message(message : discord.Message):
if message.author == client.user: # You don't want to send the own bot messages
return
if message.guild.id == guild_id: # You don't want to send the messages from the own guild your bot is sending the messages to
return
await channel.send(f"{message.author}: {message.content}") # Add attachments if you want
client.run(TOKEN)

Discord - How to get datetime when a member joined group?

For my problem I ended up using the discom pip library, but if there is any other way to do what I want, I would be happy for the suggestions.
I want to find out what are the datetimes when a user joined a specific discord group.
I managed to get all the IDs of the users from a group, but the documentation is so poor for this library, that I'm having trouble getting the username and datetime joined. I see, that it should be possible, but I can't figure it quite out.
The code I have for the IDs is:
import discum
bot = discum.Client(token="token")
def close_after_fetching(resp, guild_id):
if bot.gateway.finishedMemberFetching(guild_id):
lenmembersfetched = len(bot.gateway.session.guild(guild_id).members)
print(str(lenmembersfetched)+' members fetched')
bot.gateway.removeCommand({'function': close_after_fetching, 'params' :{'guild_id': guild_id}})
bot.gateway.close()
def get_members(guild_id, channel_id):
bot.gateway.fetchMembers(guild_id, channel_id, wait=1)
bot.gateway.command({'function': close_after_fetching, 'params': {'guild_id': guild_id}})
bot.gateway.run()
bot.gateway.resetSession()
return bot.gateway.session.guild(guild_id).members
members = get_members('guild_id', 'channel_id')
membersList = []
for memberID in members:
membersList.append(memberID)
print(memberID)
I end up with a list of all the member IDs, but I need more.
Also, I have a suspicion, that the member list is not complete. Could that be true?
I understand, that this library is not widely used, but any help (especially other solutions) would be much appreciated.
SOLUTION
I ended up using a discord bot to get the list. It is much easier and much more documented.I still used python, but with discord library. 'access_token' is my discord bot token and the answer is put into a .txt file, because it could be to large for discord message.
import discord
import os
from io import BytesIO
import datetime
access_token= os.environ["ACCESS_TOKEN"]
intents = discord.Intents.default()
intents.members = True
client = discord.Client(intents=intents)
#client.event
async def on_ready():
print('We have logged in as {0.user}'.format(client))
#client.event
async def on_message(message):
if message.author == client.user:
return
if message.content.startswith('!members'):
userrole = message.author.top_role.name
if userrole == "Admin" or userrole == "Moderators":
memberList = ""
username = ''
dateJoined = ''
guilds = client.guilds
for guild in guilds:
members = guild.members
for member in members:
if member.bot == False:
username = member.name
dateJoined = member.joined_at.strftime("%d-%m-%Y %H:%M:%S")
memberList = memberList + username + "," + dateJoined + "\n"
as_bytes = map(str.encode, memberList)
content = b"".join(as_bytes)
await message.reply("Member List", file=discord.File(BytesIO(content), "members.txt"))
client.run(access_token)

Can't for the life of me get button + role assignment to work - discord.py

I have been looking for help with this for a solid week now and tried a lot of things, but a lot of answers are outdated with the new Components update for discord.py
I referenced this video for this particular code: https://www.youtube.com/watch?v=1Ntw43Sg35k
This is in a cog if that matters. It worked ONCE but I didn't realize it and messed up the code so I lost it...
It pulls up the embed and even the buttons, but it does not assign the role and the component comes up with "This interaction failed".
enter image description here
Any help would be super appreciated!!
import os, json, asyncio, discord, discord.utils
from discord import Embed, Color
from discord.ext import commands
from discord_components import Button, ButtonStyle, Select, SelectOption, ComponentsBot, component
from discord_components.client import DiscordComponents
from discord_components.interaction import Interaction
from discord.utils import get
#----- Import -----#
client = discord.Client()
def get_prefix(client, message):
with open('prefixes.json','r') as f:
prefixes = json.load(f)
return prefixes[str(message.guild.id)]
client = commands.Bot(command_prefix = get_prefix,intents=discord.Intents.all(),case_sensitive=True,buttons = DiscordComponents(client))
#----- Class Code for f1r4 -----#
class f1r4(commands.Cog):
def __init__(self,client):
self.client = client
#client.command()
async def f1r4(self,ctx):
embed=discord.Embed(
title='Floor 1, Room 4',
url = '',
description = 'You decide that it\'s time to move on. Maybe, somewhere safer too...',
color=Color.green())
embed.set_thumbnail(url='')
embed.add_field(
name = 'North',
value = 'Insert an informative text dump here.',
inline = True)
embed.add_field(
name = 'South',
value = 'take two boogaloo',
inline = True)
embed.add_field(
name = 'East',
value = 'Boy howdy don\'t look at the actual descriptions lol',
inline = True)
msg = await ctx.send(embed=embed,
components=[[
Button(label = 'North'),
Button(label = 'South'),
Button(label = 'East')]])
def check(res):
return ctx.author == res.user and res.channel == ctx.channel
try:
res = await client.wait_for('buttonclick', check=check, timeout=30)
except asyncio.exceptions.TimeoutError:
tembed = discord.Embed(
title = 'Need More Time?',
descprtion = 'Try again once you\'ve had a chance to make your decision!',
color=Color.red())
await msg.edit(
embed=tembed,
components=[
Button(style=ButtonStyle.red,
label='Command Closed',
disabled=True)])
await asyncio.sleep(5)
await msg.delete()
return
if res.component.label == 'North':
member = ctx.author
mrole = discord.utils.find(lambda r:r.name == 'F1R1',ctx.message.guild.roles)
role = get(member.guild.roles, name='F1R1')
if mrole in member.roles:
await res.respond(content='You have a character in Room 1!')
await asyncio.sleep(3)
await msg.delete()
return
else:
await member.add_roles(role)
await asyncio.sleep(5)
await msg.delete()
return
else:
return
def setup(client):
client.add_cog(f1r4(client))
res = await client.wait_for('button_click', check=check, timeout=30) should be res = await self.client.wait_for('button_click', check=check, timeout=30).
There is also an typo on description for tembed.
Suggestions:
Don't import from discord_components.client. discord_components is supposed to export all required objects; using this breaks things if library decides to rename files.
buttons = DiscordComponents(client) should be DiscordComponents(client) in separate line.

How to prevent bot from spamming? | Twitch.py | Discord.py

I'm new to python and i'm making discord bot. So here i have twitch notification function, but when someone is live bot just starts spamming, i think because idk how to get content out of an embed. please help me. the code:
import os
import json
import discord
import requests
from discord.ext import tasks, commands
from discord.utils import get
intents = discord.Intents.all()
bot = commands.Bot(command_prefix='$', intents=intents)
TOKEN = os.getenv('token')
# Authentication with Twitch API.
client_id = os.getenv('client_id')
client_secret = os.getenv('Dweller_token')
body = {
'client_id': client_id,
'client_secret': client_secret,
"grant_type": 'client_credentials'
}
r = requests.post('https://id.twitch.tv/oauth2/token', body)
keys = r.json()
headers = {
'Client-ID': client_id,
'Authorization': 'Bearer ' + keys['access_token']
}
'''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(streamer_name):
stream = requests.get('https://api.twitch.tv/helix/streams?user_login=' + streamer_name, headers=headers)
stream_data = stream.json()
if len(stream_data['data']) == 1:
return True, stream_data
else:
return False, stream_data
# 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():
# username = stream_data['data'][0]['user_name']
# stream_title = stream_data['data'][0]['title']
# game_being_played = stream_data['data'][0]['game_name']
# 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(798127930295058442)
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, stream_data = 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.
async for message in channel.history(limit=200):
print("yes")
twitch_embed = discord.Embed(
title=f":red_circle: **LIVE**\n{user.name} is now streaming on Twitch! \n \n {stream_data['data'][0]['title']}",
color=0xac1efb,
url=f'\nhttps://www.twitch.tv/{twitch_name}'
)
twitch_embed.add_field(
name = '**Game**',
value = stream_data['data'][0]['game_name'],
inline = True
)
twitch_embed.add_field(
name = '**Viewers**',
value = stream_data['data'][0]['viewer_count'],
inline = True
)
twitch_embed.set_author(
name = str(twitch_name),
icon_url = stream_data['data'][0]['thumbnail_url']
)
twitch_embed.set_image(url = f'https://www.twitch.tv/{twitch_name}')
print("yes2")
try:
embed_title = twitch_embed.title
embed_description = twitch_embed.description
except Exception as e:
break
print("yes3")
# If it has, break the loop (do nothing).
if embed_title == True:
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.
await channel.send(
content = f"Hey #everyone! {user.name} is now streaming on Twitch! Go check it out: https://www.twitch.tv/{twitch_name}", 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):
try:
embed_title = message.embeds[0].title
embed_description = message.embeds[0].description
except Exception as e:
break
# If it was, delete it.
if user.mention in embed_title and "is now playing" in embed_title:
print(f"{user} stopped streaming. Removing the notification.")
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)
async def add_twitch(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.")
print('Server Running')
bot.run(TOKEN)
Just for others context, he had shown me the error on discord, so I am answering him through this question!
So mate, I found the error.
The line 106 in your code is:
await message.channel.send(msg)
Now this msg variable send all the details but we just want the content of it and not anything else.
So change that to:
await message.channel.send(msg.content)
Thank You! :D

how to change a json response

i want to know if i can do response["rap"] == "null" then response["rap"] == "account is private"
im new to python / json reason for bad sytax an example of the api with response null is
https://i.stack.imgur.com/IWXys.png
i included full code so you can test it out and play about with the code to see if you can get it to work
thanks for reading this
async def on_me
global rap
global response1234
response1234 = requests.get(f'http://api.chloe.to/rbx?method=username&user={id}').json()
rap = response["rap"]
await asyncio.sleep(60)
if rap == response["null"]:
rap = "Private Account"
#bot.command()
async def account(ctx, id):
response2 = response1234["id"]
id2r = discord.Embed()
id2r.set_author(name='Status : Online', icon_url='https://cdn2.iconfinder.com/data/icons/greenline/512/check-512.png')
id2r.set_thumbnail (url=response1234["avatar"])
id2r.add_field(name='***Username ***', value=response1234["username"],inline = False)
id2r.add_field(name='***RAP ***', value=f"{rap}",inline = False)
id2r.add_field(name='***Rolimons Link***', value=f"https://www.rolimons.com/player/{response2}",inline = False)
id2r.timestamp = datetime.now()
await ctx.send(embed=id2r)
#account.error
async def kick_error(ctx, error):
if isinstance(error, commands.UserInputError):
support = discord.Embed()
support.set_author(name='Status : Online', icon_url='https://cdn2.iconfinder.com/data/icons/greenline/512/check-512.png')
support.set_thumbnail (url='https://i.gifer.com/VG4s.gif')
support.add_field(
name='***Error***', value='Did Not Provide Roblox Username', inline=False)
support.timestamp = datetime.now()
await ctx.send(embed=support)```

Categories