Added button to product found. Added product_name to know from which search provides the article found.

This commit is contained in:
Joan
2023-03-13 16:42:26 +01:00
parent 23fa1205b3
commit 8057bfdba3
4 changed files with 82 additions and 29 deletions

View File

@@ -6,7 +6,9 @@ import constants
from PIL import Image, ImageDraw, ImageFont from PIL import Image, ImageDraw, ImageFont
from datetime import datetime, timedelta from datetime import datetime, timedelta
from telegram import InlineKeyboardButton from telegram import InlineKeyboardButton, InlineKeyboardMarkup
from telegram.ext import Application
from telegram.constants import ParseMode
# Enable logging # Enable logging
logging.basicConfig( logging.basicConfig(
@@ -111,12 +113,18 @@ def create_image(article):
# guardamos la imagen con otro nombre # guardamos la imagen con otro nombre
image.save(f"/app/data/images/products/{article['id']}_composed.png", quality=95) image.save(f"/app/data/images/products/{article['id']}_composed.png", quality=95)
def send_article(article, product): async def send_article(article, product):
application = Application.builder().get_updates_http_version('1.1').http_version('1.1').token(constants.TELEGRAM_TOKEN).build()
create_image(article) create_image(article)
text = f"*{telegram_escape_characters(article['title'])}*\n\n*Descripción*: {telegram_escape_characters(article['description'])}\n\n*Precio*: {telegram_escape_characters(str(article['price']))} {telegram_escape_characters(article['currency'])}\n\n[IR AL ANUNCIO](https://es\.wallapop\.com/item/{telegram_escape_characters(article['web_slug'])})" text = f"*{telegram_escape_characters(article['title'])}*\n\n*Descripción*: {telegram_escape_characters(article['description'])}\n\n*Encontrado por la búsqueda de:*{telegram_escape_characters(product['product_name'])}\n\n*Precio*: {telegram_escape_characters(str(article['price']))} {telegram_escape_characters(article['currency'])}"
url = f"https://api.telegram.org/bot{constants.TELEGRAM_TOKEN}/sendPhoto?chat_id={product['telegram_user_id']}&caption={text}&parse_mode=MarkdownV2" #url = f"https://api.telegram.org/bot{constants.TELEGRAM_TOKEN}/sendPhoto?chat_id={product['telegram_user_id']}&caption={text}&parse_mode=MarkdownV2"
files = {'photo':open(f"/app/data/images/products/{article['id']}_composed.png", 'rb')} #files = {'photo':open(f"/app/data/images/products/{article['id']}_composed.png", 'rb')}
logging.info(requests.post(url, files=files).content) keyboard = [[InlineKeyboardButton("Ir al anuncio", url=f"https://es.wallapop.com/item/{article['web_slug']}")]]
#InlineKeyboardButton("Listar productos", callback_data="list")]
markup = InlineKeyboardMarkup(keyboard)
response = await application.bot.send_photo(chat_id=product['telegram_user_id'], photo=open(f"/app/data/images/products/{article['id']}_composed.png", 'rb'), caption=text, parse_mode=ParseMode.MARKDOWN_V2, reply_markup=markup)
#logging.info(requests.post(url, files=files).content)
logging.info(response)
def get_category_id(category): def get_category_id(category):
ret = constants.CATEGORIES.get(category, '') ret = constants.CATEGORIES.get(category, '')

View File

@@ -88,7 +88,7 @@ def add_test_user(telegram_user_id, telegram_name, until):
found = False found = False
con = sqlite3.connect(constants.DB) con = sqlite3.connect(constants.DB)
cur = con.cursor() cur = con.cursor()
params = (telegram_name,) params = (telegram_user_id,)
res = cur.execute(f"SELECT * FROM users WHERE telegram_user_id=?", params) res = cur.execute(f"SELECT * FROM users WHERE telegram_user_id=?", params)
if res.fetchone() is None: if res.fetchone() is None:
params = (telegram_user_id, True, 'testing', until, telegram_name.first_name) params = (telegram_user_id, True, 'testing', until, telegram_name.first_name)
@@ -119,6 +119,19 @@ def get_user_list():
con.close() con.close()
return ret return ret
def get_user(telegram_user_id):
con = sqlite3.connect(constants.DB)
con.row_factory = dict_factory
cur = con.cursor()
params = (telegram_user_id,)
res = cur.execute(f"SELECT telegram_name FROM users WHERE telegram_user_id=?", params)
if res != None:
ret = res.fetchone()['telegram_name']
else:
ret = 'NoName'
con.close()
return ret
def get_user_type(telegram_user_id): def get_user_type(telegram_user_id):
con = sqlite3.connect(constants.DB) con = sqlite3.connect(constants.DB)
cur = con.cursor() cur = con.cursor()

View File

@@ -91,8 +91,13 @@ async def menu_click_handler(update: Update, context: CallbackContext):
async def add_product_name(update: Update, context: CallbackContext): async def add_product_name(update: Update, context: CallbackContext):
if context.user_data.get('product_name', '') == '': if context.user_data.get('product_name', '') == '':
answer = update.message.text product_name = update.message.text
context.user_data['product_name'] = answer if len(product_name) > 200:
await context.bot.send_message(chat_id=update.effective_chat.id,
text='El nombre del producto a buscar es muy largo, pon otro nombre', reply_markup=ForceReply())
return ADD_PRODUCT_NAME
else:
context.user_data['product_name'] = product_name
if not walladb.get_product(context.user_data): if not walladb.get_product(context.user_data):
await context.bot.send_message(chat_id=update.effective_chat.id, await context.bot.send_message(chat_id=update.effective_chat.id,
text='Escribe el precio mínimo', reply_markup=ForceReply()) text='Escribe el precio mínimo', reply_markup=ForceReply())
@@ -111,9 +116,9 @@ async def add_product_min_price(update: Update, context: CallbackContext):
await context.bot.send_message(chat_id=update.effective_chat.id, await context.bot.send_message(chat_id=update.effective_chat.id,
text='Pon un precio mínimo en números', reply_markup=ForceReply()) text='Pon un precio mínimo en números', reply_markup=ForceReply())
return ADD_PRODUCT_MIN_PRICE return ADD_PRODUCT_MIN_PRICE
if min_price < 0: if min_price < 0 or min_price > 999999:
await context.bot.send_message(chat_id=update.effective_chat.id, await context.bot.send_message(chat_id=update.effective_chat.id,
text='Pon un precio mínimo en números que no sean negativos', reply_markup=ForceReply()) text='Pon un precio mínimo entre 0 y 999999', reply_markup=ForceReply())
return ADD_PRODUCT_MIN_PRICE return ADD_PRODUCT_MIN_PRICE
context.user_data['min_price'] = min_price context.user_data['min_price'] = min_price
await context.bot.send_message(chat_id=update.effective_chat.id, await context.bot.send_message(chat_id=update.effective_chat.id,
@@ -129,9 +134,13 @@ async def add_product_max_price(update: Update, context: CallbackContext):
await context.bot.send_message(chat_id=update.effective_chat.id, await context.bot.send_message(chat_id=update.effective_chat.id,
text='Pon un precio máximo en números', reply_markup=ForceReply()) text='Pon un precio máximo en números', reply_markup=ForceReply())
return ADD_PRODUCT_MAX_PRICE return ADD_PRODUCT_MAX_PRICE
if max_price < 0: if max_price < 0 or max_price > 999999:
await context.bot.send_message(chat_id=update.effective_chat.id, await context.bot.send_message(chat_id=update.effective_chat.id,
text='Pon un precio máximo en números que no sean negativos', reply_markup=ForceReply()) text='Pon un precio máximo entre 0 y 999999', reply_markup=ForceReply())
return ADD_PRODUCT_MAX_PRICE
if max_price < context.user_data['min_price']:
await context.bot.send_message(chat_id=update.effective_chat.id,
text='Pon un precio máximo menor al precio mínimo', reply_markup=ForceReply())
return ADD_PRODUCT_MAX_PRICE return ADD_PRODUCT_MAX_PRICE
context.user_data['max_price'] = max_price context.user_data['max_price'] = max_price
keyboard = [ keyboard = [
@@ -340,7 +349,7 @@ async def add_to_db_and_send(update: Update, context: ContextTypes.DEFAULT_TYPE)
walladb.add_product(context.user_data) walladb.add_product(context.user_data)
p = threading.Thread(target=Worker.run, args=(walladb.get_product(context.user_data), )) p = threading.Thread(target=Worker.run, args=(walladb.get_product(context.user_data), ))
p.start() p.start()
await context.bot.send_message(chat_id=update.effective_chat.id, text=f"¡*{context.user_data['product_name']}* añadido correctamente\!", parse_mode=ParseMode.MARKDOWN_V2) await context.bot.send_message(chat_id=update.effective_chat.id, text=f"¡*{helpers.telegram_escape_characters(context.user_data['product_name'])}* añadido correctamente\!", parse_mode=ParseMode.MARKDOWN_V2)
def error(update, context): def error(update, context):
logging.error(f'Update ---{update}--- caused error ---{context.error}---') logging.error(f'Update ---{update}--- caused error ---{context.error}---')
@@ -371,6 +380,8 @@ def main()->None:
application.add_handler(CommandHandler("remove_user", remove_user_command)) application.add_handler(CommandHandler("remove_user", remove_user_command))
application.add_handler(CommandHandler("status", status_command)) application.add_handler(CommandHandler("status", status_command))
application.add_handler(CommandHandler("test", test_command)) application.add_handler(CommandHandler("test", test_command))
#application.add_handler(CallbackQueryHandler("list", send_list()))
#application.add_handler(CallbackQueryHandler(pattern="list", callback=send_list()))
conv_handler = ConversationHandler( conv_handler = ConversationHandler(
conversation_timeout=60, conversation_timeout=60,

View File

@@ -4,6 +4,7 @@ import logging
import helpers import helpers
import walladb import walladb
import constants import constants
import asyncio
# Enable logging # Enable logging
logging.basicConfig( logging.basicConfig(
@@ -56,6 +57,7 @@ class Worker:
return json_data['search_objects'] return json_data['search_objects']
def first_run(self, product): def first_run(self, product):
logging.info(f"First run for {product['product_name']} for {walladb.get_user(product['telegram_user_id'])}")
for i in range(5): for i in range(5):
helpers.random_wait() helpers.random_wait()
list = [] list = []
@@ -66,7 +68,7 @@ class Worker:
list.insert(0, article['id']) list.insert(0, article['id'])
return list return list
def work(self, product, list): async def work(self, product, list):
helpers.random_wait() # Random wait to make requests separated in time in order to prevent API rate limit helpers.random_wait() # Random wait to make requests separated in time in order to prevent API rate limit
exec_times = [] exec_times = []
while True: while True:
@@ -81,18 +83,20 @@ class Worker:
try: try:
if not self.has_excluded_words(article['title'].lower(), article['description'].lower(), product['title_description_exclude']) and not self.is_title_key_word_excluded(article['title'].lower(), product['title_exclude']): if not self.has_excluded_words(article['title'].lower(), article['description'].lower(), product['title_description_exclude']) and not self.is_title_key_word_excluded(article['title'].lower(), product['title_exclude']):
try: try:
helpers.send_article(article, product) await helpers.send_article(article, product)
except: except:
helpers.send_article(article, product) await helpers.send_article(article, product)
time.sleep(1) # Avoid Telegram flood restriction await asyncio.sleep(1)
#time.sleep(1) # Avoid Telegram flood restriction
list.insert(0, article['id']) list.insert(0, article['id'])
except Exception as e: except Exception as e:
logging.info("---------- EXCEPTION -----------") logging.info("---------- EXCEPTION -----------")
logging.info(f"{product['product_name']} worker crashed. {e}") logging.info(f"{product['product_name']} worker crashed. {e}")
logging.info(f"{product['product_name']}: Trying to parse {article['id']}: {article['title']} .\n") logging.info(f"{product['product_name']}: Trying to parse {article['id']}: {article['title']} .\n")
time.sleep(constants.SLEEP_TIME) #time.sleep(constants.SLEEP_TIME)
await asyncio.sleep(constants.SLEEP_TIME)
exec_times.append(time.time() - start_time) exec_times.append(time.time() - start_time)
logging.info(f"\'{product['product_name']}\' node-> last: {exec_times[-1]} max: {self.get_max_time(exec_times)} avg: {self.get_average_time(exec_times)}") logging.info(f"\'{product['product_name']}\' for {walladb.get_user(product['telegram_user_id'])} ({product['telegram_user_id']}) node-> last: {exec_times[-1]:.2f} max: {self.get_max_time(exec_times):.2f} avg: {self.get_average_time(exec_times):.2f}")
def has_excluded_words(self, title, description, excluded_words): def has_excluded_words(self, title, description, excluded_words):
if len(excluded_words) > 0: if len(excluded_words) > 0:
@@ -125,13 +129,30 @@ class Worker:
largest = i largest = i
return largest return largest
async def old_run(product):
worker = Worker()
list = worker.first_run(product)
while True:
try:
logging.info(f"Wallapop monitor worker started. Checking for new items containing: \'{product['product_name']}\' for {walladb.get_user(product['telegram_user_id'])} ({product['telegram_user_id']}) with given parameters periodically")
await worker.work(product, list)
break
except Exception as e:
logging.info(f"Exception: {e}")
logging.info(f"{product['product_name']} worker crashed. Restarting worker...")
await asyncio.sleep(10)
#time.sleep(10)
logging.info(f"Wallapop monitor worker stopped for: \'{product['product_name']}\'")
def run(product): def run(product):
worker = Worker() worker = Worker()
list = worker.first_run(product) list = worker.first_run(product)
while True: while True:
try: try:
logging.info(f"Wallapop monitor worker started. Checking for new items containing: \'{product['product_name']}\' with given parameters periodically") loop = asyncio.new_event_loop()
worker.work(product, list) asyncio.set_event_loop(loop)
loop.run_until_complete(worker.work(product, list))
loop.close()
break break
except Exception as e: except Exception as e:
logging.info(f"Exception: {e}") logging.info(f"Exception: {e}")