Need to pass variable "update" to method news() - python

I'm trying to create a python telegram bot that send random news every x time, and it works when i give the method news() the chat_id statically directly on the method, I tried passing it directly on the method start(), that execute a run_repeating job like that:
def start():
context.job_queue.run_repeating(news(update=update, context=context), interval=newsTimer, first=1)
but after you run the command for the first time (and works) it trows a lot of errors.
Instead I hardcoded the chat_id inside the news() method.
Anyone has any hint on how could I pass the variable update to the news() method?
Here's my full code:
from dotenv import load_dotenv
import telegram.ext
import requests
import datetime
import random
import json
import os
load_dotenv()
token = os.getenv('TOKEN')
api = os.getenv('API')
languages = "en"
newsTimer = 600
query = "world"
pageSize = "100"
yesterday = str(datetime.datetime.now() - datetime.timedelta(days=1))
today = str(datetime.datetime.now())
api_url = "https://newsapi.org/v2/everything?q=" + query + "&from=" + yesterday + "&to=" + today + "&sortBy=popularity&pageSize=+"+ pageSize +"&apiKey=" + api
def start(update, context):
context.job_queue.run_repeating(news, interval=newsTimer, first=1)
def help(update, context):
update.message.reply_text("""
Available commands:
/start - start bot
/help - help
""")
def news(context):
response = requests.get(api_url)
json_data = json.loads(response.text)
i = random.randint(0, 99)
title = json_data['articles'][i]['title']
image = json_data['articles'][i]['urlToImage']
description = json_data['articles'][i]['description']
author = json_data['articles'][i]['author']
article = json_data['articles'][i]
if title is None:
title = "No title"
if image is None:
image = "https://www.alfasolare.ru/a_solar_restyle/wp-content/themes/consultix/images/no-image-found-360x260.png"
if description is None:
description = "No Content"
if author is None:
author = "No Author"
if article is None:
i = random.randint(0, len(json_data['articles']))
caption = "<a>" + title + "\n" + description + "\n Author: " + author + "</a>"
chat_id = "XXXXXXXXX" #my own chat id
context.bot.send_photo(
chat_id=chat_id,
photo=image,
caption=caption,
parse_mode=telegram.ParseMode.HTML
)
if __name__ == '__main__':
updater = telegram.ext.Updater(token, use_context=True)
dispatcher = updater.dispatcher
dispatcher.add_handler(telegram.ext.CommandHandler('start', start))
dispatcher.add_handler(telegram.ext.CommandHandler('help', help))
if updater.start_polling():
print("Bot started successfully!")
if updater.idle():
print("Bot stopped")

context.job_queue.run_repeating(news(update=update, context=context), interval=newsTimer, first=1)
this can't work since the callback argument of JobQueue.run_* must be a function. However, news(update=update, context=context) is the return value of that function call, which is None as news doesn't return anything.
To pass additional data to the job callback, you can use the context argument of JobQueue.run_*. This is also explained in PTBs wiki page on JobQueue and showcased in the timerbot.py example.
Disclaimer: I'm currently the maintainer of python-telegram-bot

Related

telegram bot breaks down when it is used by more than one person

After more than one person uses the bot, the error 2022-06-03 19:46:12,641 (init.py:648 MainThread) ERROR - TeleBot appears: "A request to the Telegram API was unsuccessful. Error code: 400. Description: Bad Request: message text is empty". I read a lot of things, but nothing helped
import telebot
from telebot import types
import gspread
from registration_sheet import gs, sh
from button import button1, button2, mm
token = 'token'
txt = open("C:/Users/nmash/Desktop/Cloud/terms_of_the_agreement.txt", encoding = "utf-8")
class Telegrambot():
def __init__(self, token):
super(Telegrambot, self).__init__()
self.bot = telebot.TeleBot(token)
self.message_handler()
self.start()
def start(self):
self.bot.polling(none_stop=True)
def message_handler(self):
#self.bot.message_handler(content_types=['text'])
def message_worker(message):
if message.text == '/start':
button1()
self.bot.send_message(message.from_user.id, txt.read(), reply_markup=mm)
#self.bot.send_message(message.from_user.id, "Вы приняли условия соглашения✅", reply_markup=mm)
if message.text == "Принять условия соглашения✅":
self.bot.send_message(message.from_user.id, "Вы приняли условия соглашения✅", reply_markup=types.ReplyKeyboardRemove())
self.registration(message)
def registration(self, message):
def message_han(message):
sent = self.bot.send_message(message.from_user.id, 'Введите своё имя:')
self.bot.register_next_step_handler(sent, reg)
def reg(message):
name = message.text
worksheet = sh.sheet1
values_list = worksheet.row_values(2)
number = 0
while True:
n = number + 1
number = n
values_list = worksheet.row_values(number)
if values_list == []:
userId = number
break
worksheet.append_row([name, userId])
self.bot.send_message(message.from_user.id, "Ваше имя: " + name + "\nВаше ID: " + str(number))
message_han(message)
Telegrambot(token=token)

How to send Telegram Bold message using the Native API?

I want to send a Telegram message using the native Python requests so that the "First Name" is received in using in BOLD. I have tried HTML and Markdown syntax but it's not showing.
import json
import requests
# Telegram bot configurations
TELE_TOKEN='TOKEN'
URL = "https://api.telegram.org/bot{}/".format(TELE_TOKEN)
def send_message(text, chat_id):
url = URL + "sendMessage?text={}&chat_id={}".format(text, chat_id)
requests.get(url)
# AWS Lambda handler
def lambda_handler(event, context):
message = json.loads(event['body'])
chat_id = message['message']['chat']['id']
first_name = message['message']['chat']['first_name']
text = message['message']['text']
# How can the first name be in BOLD?
reply = "Hello " + first_name + "! You have said:" + text
send_message(reply, chat_id)
return {
'statusCode': 200
}
Telegram supports formatting in either HTML or Markdown. For formatting, you have to set the parse_mode parameter to either HTML,Markdown (legacy), orMarkdownV2.
E.g.: To get the output as "bold text", you could use,
text=<b>bold text</b>&parse_mode=HTML or
text=*bold text*&parse_mode=Markdown or
text=*bold text*&parse_mode=MarkdownV2.
You could simply do that change in your code snippet;
def send_message(text, chat_id):
url = URL + "sendMessage?text={}&chat_id={}&parse_mode=MarkdownV2".format(text, chat_id)
requests.get(url)
# AWS Lambda handler
def lambda_handler(event, context):
...
# How can the first name be in BOLD?
reply = "Hello *" + first_name + "*! You have said:" + text
...
Read more about the formatting options here: https://core.telegram.org/bots/api#formatting-options

Retrieving data from 2 python scripts

This is the first script which get's data from a website:
import requests
def get_prices():
name = "SeedifyFund"
crypto_data = requests.get("https://api.pancakeswap.info/api/tokens").json()["data"]
data = None
for i in crypto_data:
current = crypto_data[i]
if current['name'] == name:
data = {
"PriceUSD": current["price"],
"PriceBNB": current["price_BNB"],
}
return data
if __name__ == "__main__":
print(get_prices())
The code above outputs the following: {'PriceUSD': '1.022239219137518991087869433174527', 'PriceBNB': '0.002452203037583603303073246037795846'}
I'm having issue an issue with the second script. I want it to use the data that it has collected above and print it in a telegram bot when the user types /price. The code for the second script:
import telegram
from telegram.ext import Updater
from telegram.ext import CommandHandler
from tracker import get_prices
telegram_bot_token = "API TOKEN"
updater = Updater(token=telegram_bot_token, use_context=True)
dispatcher = updater.dispatcher
def price(update, context):
chat_id = update.effective_chat.id
message = ""
crypto_data = get_prices()
for i in crypto_data:
bnbprice = crypto_data[i]["pricebnb"]
usdprice = crypto_data[i]["priceusd"]
message += f"1 SFUND = \n${usdprice:,.2f} USD\n{bnbprice:.3f} BNB\n\n"
context.bot.send_message(chat_id=chat_id, text=message)
dispatcher.add_handler(CommandHandler("price", price))
updater.start_polling()
When the user types /price in the telegram chat it give this error:
coin = crypto_data[i]["pricebnb"]
TypeError: string indices must be integers
Could someone tell me what I'm doing wrong and help me solve the issue. Many thanks

How to make Dynamic commands in telegram

How do you send an id for items in the data base with out creating a method for each id
My goal is to type the id desired /13 and the bot returns the info I need about that item
The repo of choice is pyTelegramBotAPI
for database access and manipulation I am using flask-sqlalchemy
import telebot
from config import telegram_token
bot = telebot.TeleBot(telegram_token)
#bot.message_handler(commands=['summary'])
def send_welcome(message):
summary = """ return general info about bot performance """
bot.reply_to(message, summary )
#bot.message_handler(commands=['<id>'])
def send_welcome(message):
id_ = """ return info about this id"""
bot.reply_to(message, id_)
Your link to API shows method with regex to recognize command
#bot.message_handler(regexp="SOME_REGEXP")
which you could use with regexp="/\d+" to get any /number.
And later you should use message.text[1:] to get this number as string (without /).
#bot.message_handler(regexp="/\d+")
def get_id(message):
id_ = message.text[1:] # as string without `/`
#id_ = int(message.text[1:]) # as integer
bot.reply_to(message, id_)
EDIT:
To run function only for /number it needs also ^ $
regexp="^/\d+$"
Without ^ $ it will run function also for hello /13 world
Minimal working code
import os
import telebot
TELEGRAM_TOKEN = os.getenv('TELEGRAM_TOKEN')
bot = telebot.TeleBot(TELEGRAM_TOKEN)
#bot.message_handler(regexp="^\d+$")
def get_id(message):
id_ = message.text[1:] # as string without `/`
#id_ = int(message.text[1:]) # as integer
bot.reply_to(message, id_)
bot.polling()
EDIT:
You can also use
#bot.message_handler(func=lambda message: ...)
like
#bot.message_handler(func=lambda msg: msg.text[0] == '/' and msg.text[1:].isdecimal())
def get_id(message):
id_ = message.text[1:] # as string without `/`
#id_ = int(message.text[1:]) # as integer
bot.reply_to(message, id_)
or more readable
def is_number_command(message):
text = message.text
return text[0] == '/' and text[1:].isdecimal()
#bot.message_handler(func=is_number_command)
def get_id(message):
id_ = message.text[1:] # as string without `/`
#id_ = int(message.text[1:]) # as integer
bot.reply_to(message, id_)
You can use text[1:].isdecimal() or text[1:].isdigit() or text[1:].isnumeric() or str.isdecimal(text[1:]) or str.isdigit(text[1:]) or str.isnumeric(text[1:])
With func you can use other functions to make it even more complex.

How to restart telegram bot in Python (with initial state of variables) for new client?

this is my first question here. I try to rewrite telegram bot in Python. And I cant solve one problem. When I test my bot by myself everything fine, but if another user connect with my bot script doesn`t start for him with initial state of variables. For example, in this code script increment x variable when user send "1". But for new user x already not null. Please help me to fix it.
import StringIO
import json
import logging
import random
import urllib
import urllib2
# for sending images
from PIL import Image
import multipart
# standard app engine imports
from google.appengine.api import urlfetch
from google.appengine.ext import ndb
import webapp2
TOKEN = 'TOKEN HERE'
BASE_URL = 'https://api.telegram.org/bot' + TOKEN + '/'
x = 0
# ================================
class EnableStatus(ndb.Model):
# key name: str(chat_id)
enabled = ndb.BooleanProperty(indexed=False, default=False)
# ================================
def setEnabled(chat_id, yes):
es = EnableStatus.get_or_insert(str(chat_id))
es.enabled = yes
es.put()
def getEnabled(chat_id):
es = EnableStatus.get_by_id(str(chat_id))
if es:
return es.enabled
return False
# ================================
class MeHandler(webapp2.RequestHandler):
def get(self):
urlfetch.set_default_fetch_deadline(60)
self.response.write(json.dumps(json.load(urllib2.urlopen(BASE_URL + 'getMe'))))
class GetUpdatesHandler(webapp2.RequestHandler):
def get(self):
urlfetch.set_default_fetch_deadline(60)
self.response.write(json.dumps(json.load(urllib2.urlopen(BASE_URL + 'getUpdates'))))
class SetWebhookHandler(webapp2.RequestHandler):
def get(self):
urlfetch.set_default_fetch_deadline(60)
url = self.request.get('url')
if url:
self.response.write(json.dumps(json.load(urllib2.urlopen(BASE_URL + 'setWebhook', urllib.urlencode({'url': url})))))
class WebhookHandler(webapp2.RequestHandler):
def post(self):
urlfetch.set_default_fetch_deadline(60)
body = json.loads(self.request.body)
logging.info('request body:')
logging.info(body)
self.response.write(json.dumps(body))
update_id = body['update_id']
message = body['message']
message_id = message.get('message_id')
date = message.get('date')
text = message.get('text')
fr = message.get('from')
chat = message['chat']
chat_id = chat['id']
if not text:
logging.info('no text')
return
def reply(msg=None, img=None):
if msg:
resp = urllib2.urlopen(BASE_URL + 'sendMessage', urllib.urlencode({
'chat_id': str(chat_id),
'text': msg.encode('utf-8'),
'disable_web_page_preview': 'true',
#'reply_to_message_id': str(message_id),
})).read()
elif img:
resp = multipart.post_multipart(BASE_URL + 'sendPhoto', [
('chat_id', str(chat_id)),
#('reply_to_message_id', str(message_id)),
], [
('photo', 'image.jpg', img),
])
else:
logging.error('no msg or img specified')
resp = None
logging.info('send response:')
logging.info(resp)
if text.startswith('/'):
if text == '/start':
reply('Bot start')
setEnabled(chat_id, True)
elif text == '/stop':
reply('Bot disabled')
setEnabled(chat_id, False)
else:
reply('What command?')
elif '1' in text:
global x
x = x + 1
reply(str(x))
else:
if getEnabled(chat_id):
reply('?')
else:
logging.info('not enabled for chat_id {}'.format(chat_id))
app = webapp2.WSGIApplication([
('/me', MeHandler),
('/updates', GetUpdatesHandler),
('/set_webhook', SetWebhookHandler),
('/webhook', WebhookHandler),
], debug=True)
Instead of variable x, you may want to use python dictionary like this -
x = {}
and then use it like this -
key = str(chat_id)
if key in x:
x[key] += 1
else:
x[key] = 1

Categories