Telegram bot can't receive multiple pics at one message - python

I want to setup a telegram bot for receiving multiple images in one message. My bot can receive only the first image, all others are ignored. Here is my code:
# -*- coding: utf-8 -*-
import config
import telebot
from telebot.types import InlineKeyboardMarkup, InlineKeyboardButton, InputMediaPhoto
bot = telebot.TeleBot(config.token)
main_menu_keyboard = telebot.types.ReplyKeyboardMarkup(True,True)
main_menu_keyboard.add('test1', 'test2')
welcome_message='''Hello,
dude
'''
dict = {}
class nameDict:
def __init__(self, name):
self.name = name
self.media = None
def process_name_step(message):
try:
chat_id = message.chat.id
name = message.text
upload = nameDict(name)
dict[chat_id] = upload
message = bot.send_message(chat_id, 'Upload your photos: ')
bot.register_next_step_handler(message, process_media_step)
except Exception as e:
bot.reply_to(message, 'Error...')
def process_media_step(message):
try:
chat_id = message.chat.id
media = message.photo[-1].file_id
upload = dict[chat_id]
upload.media = media
bot.send_photo(chat_id, str(upload.media))
except Exception as e:
bot.reply_to(message, 'Error...')
bot.register_next_step_handler(message, process_media_step)
bot.enable_save_next_step_handlers(delay=2)
bot.load_next_step_handlers()
#bot.message_handler(commands=['start'])
def start_message(message):
bot.send_message(message.chat.id, welcome_message, reply_markup=main_menu_keyboard)
#bot.message_handler(content_types=['text'])
def send_text(message):
if message.text.lower() == 'test1':
message = bot.send_message(message.chat.id, 'Enter youe name: ')
bot.register_next_step_handler(message, process_name_step)
elif message.text.lower() == 'test2':
bot.send_message(message.chat.id, 'Empty')
bot.polling()
Could you please me find a solution on how to receive multiple images in a single message to the bot?
Thanks!

I found a workaround just add a photo handler that saves them locally.
#bot.message_handler(content_types=['photo'])
def get_photo(message):
fileID = message.photo[-1].file_id
file_info = bot.get_file(fileID)
downloaded_file = bot.download_file(file_info.file_path)
user_path=str(message.from_user.id)
if not os.path.exists(user_path):
os.makedirs(user_path)
with open(str(message.from_user.id) + '/' + fileID, 'wb') as new_file:
new_file.write(downloaded_file)

Related

Key Error - An error in the python bot code

Good evening, I am developing a bot that will search for a telegram account by phone number. Tell me what I'm doing wrong: KeyError 'result' crashes.
user = response['result']
# Импортируем модули
import telebot
import requests
# Указываем токен
bot = telebot.TeleBot('')
# Обработчик команды Start
#bot.message_handler(commands=['start'])
def start_message(message):
bot.send_message(message.chat.id, 'Введите номер телефона для поиска аккаунта телеграмм')
# Обработчик ввода номера телефона
#bot.message_handler(content_types=['text'])
def send_text(message):
# Запрос для поиска пользователя
url = 'https://api.telegram.org/bot{bot}/getUserByPhone' + 'phone_number=' + message.text
response = requests.get(url).json()
# Проверка существования пользователя
if 'message' in response:
bot.send_message(message.chat.id, 'Аккаунт телеграмм не найден')
else:
user = response['result']
bot.send_message(message.chat.id, 'Указанный аккаунт был найден:\n\n' +
'ID пользователя: ' + str(user['id']) + '\n\n' +
'Имя пользователя: ' + user['first_name'])
# Запуск бота
bot.polling()
I tried to deal with the error myself, but since I'm not strong in python, it didn't work out for me

discord.ext.commands.errors.CommandNotFound: Command "search" is not found

am having troubles gettimg my commands to work, it keeps telling me that they do not exist when they clearly do. I've been stumped on this for hours and can't figure out why its not working.
import discord
from discord.ext import commands
import os, shutil
from google_images_download import google_images_download
import random
#responsible for handling all of the image commands
class image_cog(commands.Cog):
def init(self, bot):
self.bot = bot
self.download_folder = 'downloads'
self.keywords = "Spongebob"
self.response = google_images_download.googleimagesdownload()
self.arguments = {
"keywords": self.keywords,
"limit":20,
"size":"medium",
"no_directory": True
}
self.image_names = []
#get the latest in the folder
self.update_images()
#commands.command(name="get", help="Displays random image from the downloads")
async def get(self, ctx):
img = self.image_names[random.randint(0, len(self.image_names) - 1)]
await ctx.send(file=discord.File(img))
def clear_folder(self):
for filename in os.listdir(self.download_folder):
file_path = os.path.join(self.download_folder, filename)
try:
if os.path.isfile(file_path) or os.path.islink(file_path):
os.unlink(file_path)
elif os.path.isdir(file_path):
shutil.rmtree(file_path)
except Exception as e:
print('Failed to delete %s. Reason: %s' % (file_path, e))
def update_images(self):
self.image_names = []
#store all the names to the files
for filename in os.listdir(self.download_folder):
self.image_names.append(os.path.join(self.download_folder, filename))
#commands.command(name="search", help="searches for a message on google")
async def search(self, ctx, *args):
self.clear_folder()
#fill the folder with new images
self.arguments['keywords'] = " ".join(args)
self.response.download(self.arguments)
self.update_images()

Discord.py does not want to send mistakes to the console

I wrote the code for the output in the error console via utils.setup_logging
Errors were derived correctly when I only used this code:
discord.utils.setup_logging(level = logging.ERROR, root = False)
discord.utils.setup_logging(level = logging.WARN, root = False)
discord.utils.setup_logging(level = logging.WARNING, root = False)
discord.utils.setup_logging(level = logging.INFO, root = False)
All errors displayed such as code synthesis, warning etc.
But today I create a new team and I made a mistake in the code. After checking it, the console would have to derive a mistake, but she did not do it (the team was not fulfilled by itself). I do not know, maybe I really made a mistake in writing the code. But still the console would have to bring out at least some mistake.
# -*- coding: utf-8 -*-
import discord
from discord.ext import commands
from config import settings
import asyncio
import os
import logging
from time import strftime
from time import gmtime
import sqlite3
bot = commands.Bot(settings['prefix'], intents = discord.Intents.all())
bot.remove_command('help')
discord.utils.setup_logging(level = logging.ERROR, root = False)
discord.utils.setup_logging(level = logging.WARN, root = False)
discord.utils.setup_logging(level = logging.WARNING, root = False)
discord.utils.setup_logging(level = logging.INFO, root = False)
#bot.event
async def on_ready():
print(f'{bot.user.name} підключився до Discord.')
async def load_extensions():
"""Load cogs for main file
"""
for filename in os.listdir('./cogs'):
if filename.endswith('.py'):
await bot.load_extension(f'cogs.{filename[:-3]}')
async def main():
await load_extensions()
await bot.start(settings['token'])
if __name__ == '__main__':
asyncio.run(main())
cogs/test.py
class test(commands.Cog, name='Інформативні команди'):
def __init__(self, bot):
self.bot = bot
#commands.command()
async def server(self, ctx):
snsfwlvl = str(ctx.guild.explicit_content_filter)
if snsfwlvl == 'all_members':
snsfwlvl = 'Перевіряти кожного учасника'
elif snsfwlvl == 'no_role':
snsfwlvl = 'Перевіряти учасників без ролей'
elif snsfwlvl == 'disabled':
snsfwlvl = 'Не встановлено'
else:
snsfwlvl = 'Не знайдено'
text_channels = len(ctx.guild.text_channels)
voice_channels = len(ctx.guild.voice_channels)
stage_channels = len(ctx.guild.stage_channels)
total_channels = text_channels + voice_channels + stage_channels
total_members = ctx.guild.members
online = 0
idle = 0
offline = 0
humans = 0
bots = 0
for member in total_members:
if member.status == 'online':
online+=1
if member.status == 'idle':
idle+=1
if member.status == 'oflline':
oflline+=1
if member.bot is True:
bot+=1
if member.bot is False:
humans+=1
embed = discord.Embed(
color = settings['color'],
title = f"Інформація про сервер {ctx.guild.name}"
)
created_at = ctx.guild.created_at
embed.add_field(
name = f"Власник сервера",
value = f"{ctx.guild.owner.mention}",
inline = True
)
embed.add_field(
name = "Id",
value = ctx.guild.id,
inline = True
)
embed.add_field(
name = "Створений: ",
value = strftime("%d.%m.%y %H:%M:%S", created_at),
inline = True
)
embed.add_field(
name = "Перевірка: ",
value = snsfwlvl,
inline = True
)
embed.add_field(
name = "Учасники:",
value = f"<:total_members:1038376493669154836>Всього: **{total_members}**\n<:members:1038376476870979594>Учасників: **{humans}**\n<:bots:1038376472521482263>Ботів: **{bots}**",
inline = True
)
embed.add_field(
name = "Статуси:",
value = f"<:ofline:1038376481774120970>Онлайн: **{online}**\n<:idle:1038376474958381056>Відійшли: **{idle}**\n<:ofline:1038376481774120970>Не в мережі: **{offline}**",
inline = True
)
embed.add_field(
name = "Канали:",
value = f"<:total_channels:1038376491576205375>Всього: **{total_channels}**\n<:text_channels:1038376489399357504>Текстові: **{text_channels}**\n<:voice_channels:1038376495414001724>Голосові: **{voice_channels}**"
)
embed.set_thumbnail(url = ctx.guild.icon)
await ctx.reply(embed=embed)
I've recently updated my code with logging. First of all, after you have imported library, you should give the basic config of your log.
import logging
logging.basicConfig(filename="bot.log", level=logging.INFO, filemode="a")
As you saw there are multiple levels of logs, NOTSET, DEBUG, INFO, WARNING, ERROR and CRITICAL. By stating I want the level=logging.INFO, I actually inform my logging process that I wish to collect only INFO+ levels, so I won't take DEBUG or NOSET.
You can also produce a format for your logs, like :
logging.basicConfig(filename="BotLog.txt", level=logging.INFO, format="%(asctime)s %(message)s", filemode="a")
This will print the time, then the message to log.
What I don't see in your code is the next step, aka calling the log to register an action.
async def register (ctx, name) :
if name == "" :
logging.warning ("| BOT : no name argument !")
else : logging.info ("| BOT : name to register : "+name)
So it is your responsability to setup but also call logging method. Console will produce error message only if your code is wrong at some point, but if your code is fine, there will be no error. Also, you have to call for functions to actually get errors in. If you code for example :
async def returnMessage (ctx) :
ctx.send (ctx.message)
then you'll only get a NoneType error if you call returnMessage message function, because send() is async and needs an await, that interpreter will only consider once in the function.

GitHub cannot authorize with oauth

I'm trying to make a GitHub bot that posts issues when a complementary app throws errors, but I'm having trouble trying to get an access token. This is my code so far:
import asyncio
import random
import webbrowser
import aiohttp.web
randgen = random.SystemRandom()
# The task is relatively simple. Query for the client ID, client secret, and then produces a URL.
# It opens this URL in a web-browser, then sets up a server on port 12345, waiting for an appropriate response.
# Using this code, it finishes the rest of the flow.
class Authorizer:
def __init__(self):
self.client_id = self.client_secret = ""
self.redirect_url = "http://localhost:12345/callback"
self.scopes = ["public_repo"]
self.state = 0
self.done = False
async def handler(self, request: aiohttp.web.Request):
code = request.query["code"]
async with aiohttp.ClientSession() as client:
async with client.post("https://github.com/login/oauth/access_token",
data=dict(client_id=self.client_id, client_secret=self.client_secret, code=code, state=self.state),
headers=dict(Accept="application/json")) as request:
json = await request.json()
assert str(json["state"]) == self.state
resp = "Access Token: " + json["access_token"]
print(resp)
self.done = True
return aiohttp.web.Response(text=resp)
async def start(self):
self.client_id = input("App Client ID: ")
self.client_secret = input("App Client Secret: ")
self.state = randgen.randint(1, 1000)
scope_str = ' '.join(self.scopes)
url = f"https://github.com/login/oauth/authorize?client_id={self.client_secret}&redirect_uri={self.redirect_url}&scope=" \
f"{scope_str}&state={self.state}"
print("Opening URL: " + url)
webbrowser.open(url)
self.server = aiohttp.web.Server(self.handler)
self.runner = aiohttp.web.ServerRunner(self.server)
await self.runner.setup()
self.site = aiohttp.web.TCPSite(self.runner, 'localhost', 12345)
await self.site.start()
while not self.done:
await asyncio.sleep(1)
await self.site.stop()
input("Complete! Make sure you take your access token with you! Now hit enter to exit.")
if __name__ == '__main__':
auth = Authorizer()
loop = asyncio.get_event_loop()
loop.run_until_complete(auth.start())
I get an error, where the constructed URL gives me a 404 error. Getting rid of the state, redirect URL, and scopes don't change the error. I looked at the official docs when making this, so I don't understand why the constructed error is giving me a 404.

yowsup - Integrating sending and receiving

Background:
I would like to integrate yowsup to my home automation project. I have seen a simple sample on how to receive messages and after some minor changes it is working fine.
Issue:
My problem starts when it comes to integrate the send message feature. Those are the two files I am using:
run.py
from layer import EchoLayer
from yowsup.layers.auth import YowAuthenticationProtocolLayer
from yowsup.layers.protocol_messages import YowMessagesProtocolLayer
from yowsup.layers.protocol_receipts import YowReceiptProtocolLayer
from yowsup.layers.protocol_acks import YowAckProtocolLayer
from yowsup.layers.protocol_presence import YowPresenceProtocolLayer
from yowsup.layers.network import YowNetworkLayer
from yowsup.layers.coder import YowCoderLayer
from yowsup.common import YowConstants
from yowsup.layers import YowLayerEvent
from yowsup.stacks import YowStack, YOWSUP_CORE_LAYERS
from yowsup import env
CREDENTIALS = ("phone", "pwd")
if __name__ == "__main__":
layers = (
EchoLayer,
(YowAuthenticationProtocolLayer, YowMessagesProtocolLayer, YowReceiptProtocolLayer, YowAckProtocolLayer, YowPresenceProtocolLayer)
) + YOWSUP_CORE_LAYERS
stack = YowStack(layers)
# Setting credentials
stack.setProp(YowAuthenticationProtocolLayer.PROP_CREDENTIALS, CREDENTIALS)
# WhatsApp server address
stack.setProp(YowNetworkLayer.PROP_ENDPOINT, YowConstants.ENDPOINTS[0])
stack.setProp(YowCoderLayer.PROP_DOMAIN, YowConstants.DOMAIN)
stack.setProp(YowCoderLayer.PROP_RESOURCE, env.CURRENT_ENV.getResource())
# Sending connecting signal
stack.broadcastEvent(YowLayerEvent(YowNetworkLayer.EVENT_STATE_CONNECT))
# Program main loop
stack.loop()
layer.py
from yowsup.layers.interface import YowInterfaceLayer, ProtocolEntityCallback
from yowsup.layers.protocol_messages.protocolentities import TextMessageProtocolEntity
from yowsup.layers.protocol_receipts.protocolentities import OutgoingReceiptProtocolEntity
from yowsup.layers.protocol_acks.protocolentities import OutgoingAckProtocolEntity
from yowsup.layers.protocol_presence.protocolentities import PresenceProtocolEntity
import threading
import logging
logger = logging.getLogger(__name__)
class EchoLayer(YowInterfaceLayer):
#ProtocolEntityCallback("message")
def onMessage(self, messageProtocolEntity):
#send receipt otherwise we keep receiving the same message over and over
print str(messageProtocolEntity.getFrom()) + ' - ' + str(messageProtocolEntity.getBody())
receipt = OutgoingReceiptProtocolEntity(messageProtocolEntity.getId(), messageProtocolEntity.getFrom())
self.toLower(receipt)
#ProtocolEntityCallback("send_message")
def sendMessage(self, destination, message, messageProtocolEntity):
outgoingMessageProtocolEntity = TextMessageProtocolEntity(
message,
to = destination + "#s.whatsapp.net")
self.toLower(outgoingMessageProtocolEntity)
#ProtocolEntityCallback("receipt")
def onReceipt(self, entity):
ack = OutgoingAckProtocolEntity(entity.getId(), "receipt", "delivery")
self.toLower(ack)
# List of (jid, message) tuples
PROP_MESSAGES = "org.openwhatsapp.yowsup.prop.sendclient.queue"
def __init__(self):
super(EchoLayer, self).__init__()
self.ackQueue = []
self.lock = threading.Condition()
#ProtocolEntityCallback("success")
def onSuccess(self, successProtocolEntity):
self.lock.acquire()
for target in self.getProp(self.__class__.PROP_MESSAGES, []):
phone, message = target
if '#' in phone:
messageEntity = TextMessageProtocolEntity(message, to = phone)
elif '-' in phone:
messageEntity = TextMessageProtocolEntity(message, to = "%s#g.us" % phone)
else:
messageEntity = TextMessageProtocolEntity(message, to = "%s#s.whatsapp.net" % phone)
self.ackQueue.append(messageEntity.getId())
self.toLower(messageEntity)
self.lock.release()
#ProtocolEntityCallback("ack")
def onAck(self, entity):
self.lock.acquire()
if entity.getId() in self.ackQueue:
self.ackQueue.pop(self.ackQueue.index(entity.getId()))
if not len(self.ackQueue):
logger.info("Message sent")
#raise KeyboardInterrupt()
self.lock.release()
Questions:
Where am I supposed to call the send_message method, so I can send messages wherever I need it?
Is there a regular event (triggering every second or something) which I could use to send my messages?
#ProtocolEntityCallback("send_message")
def sendMessage(self, destination, message, messageProtocolEntity):
outgoingMessageProtocolEntity = TextMessageProtocolEntity(
message,
to = destination + "#s.whatsapp.net")
self.toLower(outgoingMessageProtocolEntity)
In the avove code sendMessage to be called, protocolEntity.getTag() == "send_message" has to be True. You don't need it to send message.
layer.py
from yowsup.layers.interface import YowInterfaceLayer, ProtocolEntityCallback
from yowsup.layers.protocol_messages.protocolentities import TextMessageProtocolEntity
from yowsup.layers.protocol_receipts.protocolentities import OutgoingReceiptProtocolEntity
from yowsup.layers.protocol_acks.protocolentities import OutgoingAckProtocolEntity
from yowsup.layers.protocol_presence.protocolentities import PresenceProtocolEntity
import threading
import logging
logger = logging.getLogger(__name__)
recv_msg = []
class EchoLayer(YowInterfaceLayer):
def __init__(self):
super(EchoLayer, self).__init__()
self.ackQueue = []
self.lock = threading.Condition()
#ProtocolEntityCallback("message")
def onMessage(self, messageProtocolEntity):
if messageProtocolEntity.getType() == 'text':
recv_msg.append((messageProtocolEntity.getFrom(),messageProtocolEntity.getBody()))
#send receipt otherwise we keep receiving the same message over and over
receipt = OutgoingReceiptProtocolEntity(messageProtocolEntity.getId(), messageProtocolEntity.getFrom())
self.toLower(receipt)
#ProtocolEntityCallback("receipt")
def onReceipt(self, entity):
ack = OutgoingAckProtocolEntity(entity.getId(), "receipt", "delivery")
self.toLower(ack)
# List of (jid, message) tuples
PROP_MESSAGES = "org.openwhatsapp.yowsup.prop.sendclient.queue"
#ProtocolEntityCallback("success")
def onSuccess(self, successProtocolEntity):
self.lock.acquire()
for target in self.getProp(self.__class__.PROP_MESSAGES, []):
phone, message = target
if '#' in phone:
messageEntity = TextMessageProtocolEntity(message, to = phone)
elif '-' in phone:
messageEntity = TextMessageProtocolEntity(message, to = "%s#g.us" % phone)
else:
messageEntity = TextMessageProtocolEntity(message, to = "%s#s.whatsapp.net" % phone)
self.ackQueue.append(messageEntity.getId())
self.toLower(messageEntity)
self.lock.release()
#ProtocolEntityCallback("ack")
def onAck(self, entity):
self.lock.acquire()
if entity.getId() in self.ackQueue:
self.ackQueue.pop(self.ackQueue.index(entity.getId()))
if not len(self.ackQueue):
self.lock.release()
logger.info("Message sent")
raise KeyboardInterrupt()
self.lock.release()
To send message define a function send_message in the stack run.py. You can also import run.py and use it's function from other script.
from layer import EchoLayer, recv_msg
CREDENTIALS = ("phone", "pwd")
def send_message(destination, message):
'''
destination is <phone number> without '+'
and with country code of type string,
message is string
e.g send_message('11133434343','hello')
'''
messages = [(destination, message)]
layers = (EchoLayer,
(YowAuthenticationProtocolLayer,
YowMessagesProtocolLayer,
YowReceiptProtocolLayer,
YowAckProtocolLayer,
YowPresenceProtocolLayer)
) + YOWSUP_CORE_LAYERS
stack = YowStack(layers)
stack.setProp(EchoLayer.PROP_MESSAGES, messages)
stack.setProp(YowAuthenticationProtocolLayer.PROP_PASSIVE, True)
# Setting credentials
stack.setProp(YowAuthenticationProtocolLayer.PROP_CREDENTIALS, CREDENTIALS)
# WhatsApp server address
stack.setProp(YowNetworkLayer.PROP_ENDPOINT, YowConstants.ENDPOINTS[0])
stack.setProp(YowCoderLayer.PROP_DOMAIN, YowConstants.DOMAIN)
stack.setProp(YowCoderLayer.PROP_RESOURCE, env.CURRENT_ENV.getResource())
# Sending connecting signal
stack.broadcastEvent(YowLayerEvent(YowNetworkLayer.EVENT_STATE_CONNECT))
try:
# Program main loop
stack.loop()
except AuthError as e:
print('Authentication error %s' % e.message)
sys.exit(1)
def recv_message():
layers = ( EchoLayer,
(YowAuthenticationProtocolLayer, YowMessagesProtocolLayer,
YowReceiptProtocolLayer, YowAckProtocolLayer,
YowPresenceProtocolLayer)
) + YOWSUP_CORE_LAYERS
stack = YowStack(layers)
# Setting credentials
stack.setProp(YowAuthenticationProtocolLayer.PROP_CREDENTIALS, CREDENTIALS)
# WhatsApp server address
stack.setProp(YowNetworkLayer.PROP_ENDPOINT, YowConstants.ENDPOINTS[0])
stack.setProp(YowCoderLayer.PROP_DOMAIN, YowConstants.DOMAIN)
stack.setProp(YowCoderLayer.PROP_RESOURCE, env.CURRENT_ENV.getResource())
# Sending connecting signal
stack.broadcastEvent(YowLayerEvent(YowNetworkLayer.EVENT_STATE_CONNECT))
try:
# Program main loop
stack.loop()
except AuthError as e:
print('Authentication error %s' % e.message)
sys.exit(1)
if __name__ == '__main__':
if len(sys.argv) == 1:
print('%s send number message\nrecv\n' % sys.argv[0])
sys.exit(1)
if sys.argv[1] == 'send':
try:
send_message(sys.argv[2],sys.argv[3])
except KeyboardInterrupt:
print('closing')
sys.exit(0)
if sys.argv[1] == 'recv':
try:
recv_message()
except KeyboardInterrupt:
print('closing')
sys.exit(0)
for m in recv_msg:
print('From %s:\n%s\n' % m)
Now you can send message by calling send_message('1234567890','Howdy') and recieve message by calling recv_message().

Categories

Resources