Modified to be used in homelabs vip

This commit is contained in:
Joan
2024-03-22 10:48:14 +01:00
parent dfbe346cb2
commit b8c7aaf126
9 changed files with 303 additions and 147 deletions

View File

@@ -1,10 +1,10 @@
version: "3" version: "3"
services: services:
wallamanta-bot-multiuser: wallamanta_homelabs:
build: wallamanta build: wallamanta
image: wallamanta:multiuser image: wallamanta:homelabs
container_name: wallamanta-bot-multiuser container_name: wallamanta_homelabs
volumes: volumes:
- ./data:/app/data - ./data:/app/data
restart: unless-stopped restart: unless-stopped
@@ -20,10 +20,12 @@ services:
- DB_PASSWORD=${DB_PASSWORD} - DB_PASSWORD=${DB_PASSWORD}
- NEW_RELIC_INSERT_KEY=${NEW_RELIC_INSERT_KEY} - NEW_RELIC_INSERT_KEY=${NEW_RELIC_INSERT_KEY}
- NR_ENV=${NR_ENV} - NR_ENV=${NR_ENV}
networks:
- wallamanta_homelabs
wallamanta_db: wallamanta_homelabs_db:
image: mysql:8 image: mysql:8
container_name: wallamanta_db container_name: wallamanta_homelabs_db
volumes: volumes:
- ./db:/var/lib/mysql - ./db:/var/lib/mysql
environment: environment:
@@ -32,10 +34,18 @@ services:
- MYSQL_USER=${DB_USER} - MYSQL_USER=${DB_USER}
- MYSQL_PASSWORD=${DB_PASSWORD} - MYSQL_PASSWORD=${DB_PASSWORD}
restart: unless-stopped restart: unless-stopped
networks:
- wallamanta_homelabs
wallamanta_adminer: wallamanta_homelabs_adminer:
image: adminer image: adminer
container_name: wallamanta_adminer container_name: wallamanta_homelabs_adminer
restart: unless-stopped restart: unless-stopped
ports: ports:
- 8555:8080 - 8655:8080
networks:
- wallamanta_homelabs
networks:
wallamanta_homelabs:
name: wallamanta_homelabs

View File

@@ -12,16 +12,16 @@ logging.basicConfig(
def work(sleep_time): def work(sleep_time):
time.sleep(30) time.sleep(30)
while True: while True:
user_list = walladb.get_user_list() user_list = walladb.get_active_user_list()
for user in user_list: for user in user_list:
if walladb.is_user_valid(user['telegram_user_id']): if walladb.is_user_active(user['telegram_user_id']):
if walladb.is_user_expired(user['telegram_user_id']): if walladb.is_user_expired(user['telegram_user_id']):
message = "¡Hola!\n\nTu cuenta ha caducado. Si quieres seguir usando @wallamanta_bot ponte en contacto con @jocarduck\n\n¡Gracias!" message = "¡Hola!\n\nTu cuenta ha caducado. Si quieres seguir usando @wallamanta_homelabs_bot renueva tu membresía a Homelabs VIP\n\n¡Gracias!"
try: try:
time.sleep(1) time.sleep(1)
helpers.send_message(user['telegram_user_id'], message) helpers.send_message(user['telegram_user_id'], message)
except Exception as e: except Exception as e:
logging.error(f"Couldn't sent message to {user['telegram_user_id']}. Reason: {e}") logging.error(f"Couldn't send message to {user['telegram_user_id']}. Reason: {e}")
walladb.deactivate_user(user['telegram_user_id']) walladb.deactivate_user(user['telegram_user_id'])
time.sleep(sleep_time) time.sleep(sleep_time)

View File

@@ -14,7 +14,11 @@ LATITUDE = os.getenv("LATITUDE")
LONGITUDE = os.getenv("LONGITUDE") LONGITUDE = os.getenv("LONGITUDE")
SLEEP_TIME = int(os.getenv("SLEEP_TIME")) SLEEP_TIME = int(os.getenv("SLEEP_TIME"))
NEW_RELIC_INSERT_KEY = os.getenv("NEW_RELIC_INSERT_KEY") NEW_RELIC_INSERT_KEY = os.getenv("NEW_RELIC_INSERT_KEY")
NEW_RELIC_METRICS_KEY = os.getenv("NEW_RELIC_METRICS_KEY")
NR_ENV = os.getenv("NR_ENV") NR_ENV = os.getenv("NR_ENV")
NR_HOST_INSIGHTS = os.getenv("NR_HOST_INSIGHTS")
NR_HOST_METRICS = os.getenv("NR_HOST_METRICS")
PROXY_SOCKS = os.getenv("PROXY_SOCKS")
MAX_WORKERS = 12 MAX_WORKERS = 12

View File

@@ -6,7 +6,8 @@ import constants
import pytz import pytz
import walladb import walladb
import json import json
from newrelic_telemetry_sdk import Event, EventClient import string
from newrelic_telemetry_sdk import Event, EventClient, GaugeMetric, MetricClient
from PIL import Image, ImageDraw, ImageFont from PIL import Image, ImageDraw, ImageFont
from datetime import datetime, timedelta, timezone, date from datetime import datetime, timedelta, timezone, date
@@ -59,15 +60,14 @@ def is_date_expired(until):
def random_wait(): def random_wait():
time.sleep(random.random()) time.sleep(random.random())
def download_image(article): def download_image(article, product_id):
r = requests.get(article['images'][0]['original']) r = requests.get(article['images'][0]['original'])
if r.status_code == 200: if r.status_code == 200:
image = open(f"/app/data/images/products/{article['id']}.jpg", "wb") with open(f"/app/data/images/products/{article['id']}_{product_id}.jpg", "wb") as image:
image.write(r.content) image.write(r.content)
image.close()
def create_image(article): def create_image(article, product_id):
download_image(article) download_image(article, product_id)
currency = '?' currency = '?'
if article['currency'] == 'EUR': if article['currency'] == 'EUR':
currency = '' currency = ''
@@ -84,64 +84,69 @@ def create_image(article):
font = ImageFont.truetype("/app/data/fonts/Roboto-Bold.ttf", 90) font = ImageFont.truetype("/app/data/fonts/Roboto-Bold.ttf", 90)
wallamanta_text_font = ImageFont.truetype("/app/data/fonts/Roboto-Bold.ttf", 40) wallamanta_text_font = ImageFont.truetype("/app/data/fonts/Roboto-Bold.ttf", 40)
# inicializamos canvas # inicializamos canvas
image = Image.new('RGBA', (width, height), (255, 255, 255)) with Image.new('RGBA', (width, height), (255, 255, 255)) as image:
# logo homelabers, redimensionamos y ponemos en la parte derecha arriba draw = ImageDraw.Draw(image)
#logo_image = Image.open("/app/data/images/logo.png").convert("RGBA") # escribimos @wallamanta_bot
#hlogo = int((float(logo_image.size[1]) * float(lpercent))) wtext, htext = draw.textsize(wallamanta_text, font=wallamanta_text_font)
#lpercent = wlogo / float(logo_image.size[0]) draw.text(((width / 6) * 5 - wtext / 2, int(height - height * 0.2)), wallamanta_text, "#13C1AC", font=wallamanta_text_font)
#logo_image = logo_image.resize((wlogo, hlogo), Image.Resampling.LANCZOS) # escribimos el precio
#image.paste(logo_image, (int((width / 6) * 5 - logo_image.size[0] / 2), int(height * 0.1)), logo_image) wtext, htext = draw.textsize(price, font=font)
# logo wallamanta, redimensionamos y ponemos en la parte derecha abajo draw.text(((width / 6) * 5 - wtext / 2, height / 2 - htext / 2), price, (0, 0, 0), font=font)
#wallamanta_logo = Image.open("/app/data/images/wallamanta_logo.png").convert("RGBA") # dibujamos rectángulo verde externo, con un margen externo y ancho determinado
#lpercent = wlogo / float(wallamanta_logo.size[0]) draw.rectangle([15, 15, width - 15, height - 15], width = 15, outline="#13C1AC")
#hlogo = int((float(wallamanta_logo.size[1]) * float(lpercent))) # ponemos la imagen del producto en la parte izquierda y se redimensiona dependiendo de lo ancho
#wallamanta_logo = wallamanta_logo.resize((wlogo, hlogo), Image.Resampling.LANCZOS) with Image.open(f"/app/data/images/products/{article['id']}_{product_id}.jpg") as product_image:
#image.paste(wallamanta_logo, (int((width / 6) * 5 - wallamanta_logo.size[0] / 2), int(height - height * 0.2)), wallamanta_logo) hpercent = (baseheight / float(product_image.size[1]))
draw = ImageDraw.Draw(image) wsize = int((float(product_image.size[0]) * float(hpercent)))
# escribimos @wallamanta_bot if wsize < wlimit:
wtext, htext = draw.textsize(wallamanta_text, font=wallamanta_text_font) resized_product_image = product_image.resize((wsize, baseheight), Image.Resampling.LANCZOS)
draw.text(((width / 6) * 5 - wtext / 2, int(height - height * 0.2)), wallamanta_text, "#13C1AC", font=wallamanta_text_font) else:
# escribimos el precio wpercent = wlimit / float(product_image.size[0])
wtext, htext = draw.textsize(price, font=font) hsize = int((float(product_image.size[1]) * float(wpercent)))
draw.text(((width / 6) * 5 - wtext / 2, height / 2 - htext / 2), price, (0, 0, 0), font=font) resized_product_image = product_image.resize((wlimit, hsize), Image.Resampling.LANCZOS)
# dibujamos rectángulo verde externo, con un margen externo y ancho determinado image.paste(resized_product_image, (int((width/3)-(resized_product_image.size[0]/2)), int((height/2) - (resized_product_image.size[1]/2))))
draw.rectangle([15, 15, width - 15, height - 15], width = 15, outline="#13C1AC") resized_product_image.close()
# ponemos la imagen del producto en la parte izquierda y se redimensiona dependiendo de lo ancho # guardamos la imagen con otro nombre
product_image = Image.open(f"/app/data/images/products/{article['id']}.jpg") image.save(f"/app/data/images/products/{article['id']}_{product_id}_composed.png", quality=95)
hpercent = (baseheight / float(product_image.size[1]))
wsize = int((float(product_image.size[0]) * float(hpercent)))
if wsize < wlimit:
product_image = product_image.resize((wsize, baseheight), Image.Resampling.LANCZOS)
else:
wpercent = wlimit / float(product_image.size[0])
hsize = int((float(product_image.size[1]) * float(wpercent)))
product_image = product_image.resize((wlimit, hsize), Image.Resampling.LANCZOS)
image.paste(product_image, (int((width/3)-(product_image.size[0]/2)), int((height/2) - (product_image.size[1]/2))))
# guardamos la imagen con otro nombre
image.save(f"/app/data/images/products/{article['id']}_composed.png", quality=95)
image.close()
product_image.close()
def get_publish_date(article): def get_publish_date(article):
article_date = article['creation_date'] article_date = article['creation_date']
return datetime.fromtimestamp(int(int(article_date)/1000)).astimezone(pytz.timezone("Europe/Madrid")).strftime("%d/%m/%Y - %H:%M:%S") formato_fecha = "%Y-%m-%dT%H:%M:%S.%f%z"
return datetime.strptime(article_date, formato_fecha).astimezone(pytz.timezone("Europe/Madrid")).strftime("%d/%m/%Y - %H:%M:%S")
def get_modified_date(article): def get_modified_date(article):
article_date = article['modification_date'] article_date = article['modification_date']
return datetime.fromtimestamp(int(int(article_date)/1000)).astimezone(pytz.timezone("Europe/Madrid")).strftime("%d/%m/%Y - %H:%M:%S") formato_fecha = "%Y-%m-%dT%H:%M:%S.%f%z"
return datetime.strptime(article_date, formato_fecha).astimezone(pytz.timezone("Europe/Madrid")).strftime("%d/%m/%Y - %H:%M:%S")
def get_random_string(length):
result_str = ''.join(random.choice(string.ascii_letters) for i in range(length))
return result_str
def send_message(telegram_user_id, message): def send_message(telegram_user_id, message):
files = { files = {
'chat_id': (None, telegram_user_id), 'chat_id': (None, telegram_user_id),
'text': (None, message), 'text': (None, message),
} }
requests.post(f'https://api.telegram.org/bot{constants.TELEGRAM_TOKEN}/sendMessage', files=files) try:
#application = Application.builder().get_updates_http_version('1.1').http_version('1.1').token(constants.TELEGRAM_TOKEN).build() requests.post(f'https://api.telegram.org/bot{constants.TELEGRAM_TOKEN}/sendMessage', files=files)
#await application.bot.send_message(chat_id=telegram_user_id, text=message) except:
time.sleep(1)
requests.post(f'https://api.telegram.org/bot{constants.TELEGRAM_TOKEN}/sendMessage', files=files)
def send_message_to_all(message):
for user in walladb.get_user_list:
try:
send_message(user['telegram_user_id'], message)
except Exception as e:
logging.info(f"Error sending message to {user['telegram_user_id']}: {e}")
def check_code(code):
walladb.get_code(code)
def send_article(article, product): def send_article(article, product):
#application = Application.builder().get_updates_http_version('1.1').http_version('1.1').token(constants.TELEGRAM_TOKEN).build() #application = Application.builder().get_updates_http_version('1.1').http_version('1.1').token(constants.TELEGRAM_TOKEN).build()
create_image(article) create_image(article, product['id'])
title = f"*{telegram_escape_characters(article['title'])}*" title = f"*{telegram_escape_characters(article['title'])}*"
description = f"*📝 Descripción*: {telegram_escape_characters(article['description'])}" description = f"*📝 Descripción*: {telegram_escape_characters(article['description'])}"
found_by = f"*🔍 Encontrado por la búsqueda de:* {telegram_escape_characters(product['product_name'])}" found_by = f"*🔍 Encontrado por la búsqueda de:* {telegram_escape_characters(product['product_name'])}"
@@ -165,27 +170,31 @@ def send_article(article, product):
#markup = InlineKeyboardMarkup(keyboard) #markup = InlineKeyboardMarkup(keyboard)
keyboard = {'inline_keyboard':[[{'text':'Ir al anuncio','url':f'https://es.wallapop.com/item/{article["web_slug"]}'}]]} keyboard = {'inline_keyboard':[[{'text':'Ir al anuncio','url':f'https://es.wallapop.com/item/{article["web_slug"]}'}]]}
image = open(f"/app/data/images/products/{article['id']}_composed.png", 'rb') with open(f"/app/data/images/products/{article['id']}_{product['id']}_composed.png", 'rb') as image:
files = { files = {
'chat_id': (None, product['telegram_user_id']), 'chat_id': (None, product['telegram_user_id']),
'photo': image, 'photo': image,
'caption': (None, text), 'caption': (None, text),
'parse_mode': (None, ParseMode.MARKDOWN_V2), 'parse_mode': (None, ParseMode.MARKDOWN_V2),
'reply_markup': (None, json.dumps(keyboard)), 'reply_markup': (None, json.dumps(keyboard)),
} }
response = requests.post(f'https://api.telegram.org/bot{constants.TELEGRAM_TOKEN}/sendPhoto', files=files)
while response.status_code != 200:
logging.info(f"Error sending to Telegram, probably flood restricted. {product['product_name']} ({product['id']}) - ({walladb.get_user(product['telegram_user_id'])}")
random_wait()
response = requests.post(f'https://api.telegram.org/bot{constants.TELEGRAM_TOKEN}/sendPhoto', files=files) response = requests.post(f'https://api.telegram.org/bot{constants.TELEGRAM_TOKEN}/sendPhoto', files=files)
image.close() tries = 0
while response.status_code != 200:
logging.info(f"Error sending to Telegram, probably flood restricted. {product['product_name']} ({product['id']}) - ({walladb.get_user(product['telegram_user_id'])}) - {response.status_code}")
random_wait()
response = requests.post(f'https://api.telegram.org/bot{constants.TELEGRAM_TOKEN}/sendPhoto', files=files)
tries = tries + 1
if tries > 5:
logging.info(f"Gave up after 5 retries. Error sending to Telegram, probably flood restricted. {product['product_name']} ({product['id']}) - ({walladb.get_user(product['telegram_user_id'])}) - {response.status_code}")
break
#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) #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(requests.post(url, files=files).content)
send_to_nr(article, product) send_to_nr(article, product)
#logging.info(response.content) #logging.info(response.content)
logging.info(f"'{title}' (https://es.wallapop.com/item/{article['web_slug']}) sent to {walladb.get_user(product['telegram_user_id'])}") logging.info(f"'{title}' (https://es.wallapop.com/item/{article['web_slug']}) found by {product['product_name']} ({product['id']}) - ({walladb.get_user(product['telegram_user_id'])})")
def get_category_name(category): def get_category_name(category):
category = int(category) category = int(category)
@@ -334,18 +343,36 @@ def send_to_nr(article, product):
"environment": constants.NR_ENV "environment": constants.NR_ENV
} }
) )
event_client = EventClient(insert_key=constants.NEW_RELIC_INSERT_KEY, host="insights-collector.eu01.nr-data.net") event_client = EventClient(insert_key=constants.NEW_RELIC_INSERT_KEY, host=constants.NR_HOST_INSIGHTS)
try: try:
response = event_client.send(event) logging.info(f"=== Sending product {article['title']} info to NR ===")
response = event_client.send(event, timeout=30)
response.raise_for_status()
logging.info(f"=== Sent product {article['title']} info to NR ===")
except Exception as e:
logging.error(f"Error sending to NR: {e}")
def send_statistics_to_nr(query_time, products_found, number_of_searches):
metric_client = MetricClient(insert_key=constants.NEW_RELIC_INSERT_KEY, host=constants.NR_HOST_METRICS)
query_time = GaugeMetric("query_time", query_time, {"units": "Seconds"})
products_found = GaugeMetric("products_found", products_found)
number_of_searches = GaugeMetric("active_searches", number_of_searches)
batch = [query_time, products_found, number_of_searches]
try:
logging.info("=== Sending stats to NR ===")
response = metric_client.send_batch(batch, timeout=30)
response.raise_for_status()
logging.info("=== Stats sent to NR ===")
except Exception as e: except Exception as e:
logging.error(f"Error sending to NR: {e}") logging.error(f"Error sending to NR: {e}")
response.raise_for_status()
def is_valid_request(product): def is_valid_request(product):
is_valid = False is_valid = False
if walladb.get_product(product): if walladb.get_product(product):
if not walladb.is_user_expired(product['telegram_user_id']): if not walladb.is_user_expired(product['telegram_user_id']):
if walladb.is_user_valid(product['telegram_user_id']): if walladb.is_user_active(product['telegram_user_id']):
if walladb.is_user_premium(product['telegram_user_id']) or \ if walladb.is_user_premium(product['telegram_user_id']) or \
walladb.is_user_testing(product['telegram_user_id']): walladb.is_user_testing(product['telegram_user_id']):
is_valid = True is_valid = True

View File

@@ -1,6 +1,7 @@
python-telegram-bot==20.4 python-telegram-bot==20.4
python-telegram-bot[job-queue]==20.4 python-telegram-bot[job-queue]==20.4
requests==2.31.0 requests==2.31.0
requests[socks]==2.31.0
prettytable==3.6.0 prettytable==3.6.0
Pillow==9.4.0 Pillow==9.4.0
mysql-connector-python==8.0.32 mysql-connector-python==8.0.32

View File

@@ -2,6 +2,7 @@ import time
import concurrent.futures import concurrent.futures
import logging import logging
import helpers
import worker import worker
import walladb import walladb
import constants import constants
@@ -17,6 +18,8 @@ def work():
searches = {} searches = {}
while True: while True:
start_time = time.time()
logging.info(f"=== Beginning Searches ===")
products = walladb.get_all_valid_products() products = walladb.get_all_valid_products()
first_run_products = [] first_run_products = []
@@ -24,7 +27,7 @@ def work():
try: try:
searches[product['id']] searches[product['id']]
except: except:
logging.info(f"New product added: {product['product_name']} ({product['id']}) - ({walladb.get_user(product['telegram_user_id'])}") logging.info(f"New product added: {product['product_name']} ({product['id']}) - ({walladb.get_user(product['telegram_user_id'])})")
first_run_products.append(product) first_run_products.append(product)
if len(first_run_products) > 0: if len(first_run_products) > 0:
@@ -39,14 +42,23 @@ def work():
else: else:
logging.info(f"First run for {product['product_name']} ({product['id']}) - ({walladb.get_user(product['telegram_user_id'])}) got: {len(searches[product['id']])}") logging.info(f"First run for {product['product_name']} ({product['id']}) - ({walladb.get_user(product['telegram_user_id'])}) got: {len(searches[product['id']])}")
products_found = 0
with concurrent.futures.ThreadPoolExecutor(max_workers=constants.MAX_WORKERS) as executor: with concurrent.futures.ThreadPoolExecutor(max_workers=constants.MAX_WORKERS) as executor:
future_to_search = {executor.submit(worker.work, product, searches[product['id']]): product for product in products} future_to_search = {executor.submit(worker.work, product, searches[product['id']]): product for product in products}
for future in concurrent.futures.as_completed(future_to_search): for future in concurrent.futures.as_completed(future_to_search):
product = future_to_search[future] product = future_to_search[future]
try: try:
searches[product['id']] = future.result() new_searches = future.result()
search_products_found = len(set(new_searches) - set(searches[product['id']]))
searches[product['id']] = new_searches
except Exception as e: except Exception as e:
logging.info(f"Error occurred in search for {product['product_name']} ({product['id']}) - ({walladb.get_user(product['telegram_user_id'])}): {e}") logging.info(f"Error occurred in search for {product['product_name']} ({product['id']}) - ({walladb.get_user(product['telegram_user_id'])}): {e}")
else: else:
logging.info(f"Search for {product['product_name']} ({product['id']}) - ({walladb.get_user(product['telegram_user_id'])})") products_found = products_found + search_products_found
time.sleep(constants.SLEEP_TIME) logging.info(f"Search for {product['product_name']} ({product['id']}) - ({walladb.get_user(product['telegram_user_id'])}) completed ({len(searches[product['id']])}) (+{search_products_found})")
#gc.collect()
completed_time = round(time.time() - start_time, 2)
helpers.send_statistics_to_nr(completed_time, products_found, len(products))
wait_time = max(constants.SLEEP_TIME - completed_time, 1)
logging.info(f"=== Searches finished in {completed_time} seconds. Found a total of {products_found} products from {len(products)} searches. Sleeping for {wait_time} seconds ===")
time.sleep(wait_time)

View File

@@ -74,7 +74,7 @@ def setup_db():
else: else:
logging.info("OK") logging.info("OK")
def is_user_valid(telegram_user_id): def is_user_active(telegram_user_id):
if telegram_user_id < 0: if telegram_user_id < 0:
ret = False ret = False
else: else:
@@ -114,6 +114,17 @@ def is_user_premium(telegram_user_id):
ret = False ret = False
return ret return ret
def is_user_homelabs(telegram_user_id):
with connect_db() as con:
with con.cursor(prepared=True) as cur:
params = (telegram_user_id,)
cur.execute(f"SELECT * FROM users WHERE telegram_user_id=%s AND active=True AND type='homelabs'", params)
try:
ret = cur.fetchone() != None
except:
ret = False
return ret
def is_user_testing(telegram_user_id): def is_user_testing(telegram_user_id):
with connect_db() as con: with connect_db() as con:
with con.cursor(prepared=True) as cur: with con.cursor(prepared=True) as cur:
@@ -125,12 +136,31 @@ def is_user_testing(telegram_user_id):
ret = False ret = False
return ret return ret
def enable_user(telegram_user_id, telegram_name):
found = False
with connect_db() as con:
with con.cursor(prepared=True) as cur:
params = (telegram_user_id,)
res = cur.execute(f"SELECT * FROM users WHERE telegram_user_id=%s", params)
try:
if res == None:
params = (telegram_user_id, False, None, None, telegram_name.first_name)
cur.execute("INSERT INTO users VALUES (%s, %s, %s, %s, %s)", params)
con.commit()
logging.info(f"Enabled user {telegram_user_id} - {telegram_name.first_name}")
else:
found = True
logging.info(f"User {telegram_user_id} - {telegram_name.first_name} was already enabled")
except Exception as e:
logging.error(f"Couldn't find username with id {telegram_user_id}: {e}")
return found
def add_premium_user(telegram_user_id, until): def add_premium_user(telegram_user_id, until):
found = False found = False
with connect_db() as con: with connect_db() as con:
with con.cursor(prepared=True) as cur: with con.cursor(prepared=True) as cur:
res = cur.execute(f"SELECT * FROM users WHERE telegram_user_id=%s", params) res = cur.execute(f"SELECT * FROM users WHERE telegram_user_id={telegram_user_id}")
if res.fetchone() != None: if res != None:
params = (until, telegram_user_id) params = (until, telegram_user_id)
cur.execute(f"UPDATE users SET active = True, type = 'premium', until = %s WHERE telegram_user_id=%s", params) cur.execute(f"UPDATE users SET active = True, type = 'premium', until = %s WHERE telegram_user_id=%s", params)
con.commit() con.commit()
@@ -138,33 +168,46 @@ def add_premium_user(telegram_user_id, until):
logging.info(f"Added premium user {telegram_user_id} until {until}") logging.info(f"Added premium user {telegram_user_id} until {until}")
return found return found
def add_test_user(telegram_user_id, telegram_name, until): def add_test_user(telegram_user_id, until):
found = False found = False
with connect_db() as con: with connect_db() as con:
with con.cursor(prepared=True) as cur: with con.cursor(prepared=True) as cur:
params = (telegram_user_id,) res = cur.execute(f"SELECT * FROM users WHERE telegram_user_id={telegram_user_id}")
cur.execute(f"SELECT * FROM users WHERE telegram_user_id=%s", params) if res != None:
try: params = (until, telegram_user_id)
cur.fetchone() cur.execute(f"UPDATE users SET active = True, type = 'testing', until = %s WHERE telegram_user_id=%s", params)
params = (telegram_user_id, True, 'testing', until, telegram_name.first_name)
cur.execute("INSERT INTO users VALUES (%s, %s, %s, %s, %s)", params)
con.commit() con.commit()
found = True found = True
except Exception as e: logging.info(f"Added testing user {telegram_user_id} until {until}")
logging.error(f"Couldn't find username with id {telegram_user_id}: {e}") return found
logging.info(f"Added test user {telegram_user_id} until {until}")
return not found
def remove_valid_user(telegram_user_id): def remove_valid_user(telegram_user_id):
with connect_db() as con: with connect_db() as con:
with con.cursor(prepared=True) as cur: with con.cursor(prepared=True) as cur:
params = (telegram_user_id,) params = (telegram_user_id,)
res = cur.execute(f"SELECT * FROM users WHERE telegram_user_id=%s", params) res = cur.execute(f"SELECT * FROM users WHERE telegram_user_id={telegram_user_id}")
if res.fetchone() != None: if res != None:
cur.execute(f"UPDATE users SET active = False WHERE telegram_user_id=%s", params) cur.execute(f"UPDATE users SET active = False WHERE telegram_user_id=%s", params)
con.commit() con.commit()
logging.info(f"De-activated user {telegram_user_id}") logging.info(f"De-activated user {telegram_user_id}")
def get_code(code):
with connect_db() as con:
with con.cursor(dictionary=True, prepared=True) as cur:
params = (code,)
res = cur.execute(f"SELECT * FROM codes WHERE code_id=%s", params)
ret = cur.fetchone()
return ret
def use_code(code):
with connect_db() as con:
with con.cursor(prepared=True) as cur:
params = (code,)
res = cur.execute(f"SELECT * FROM codes WHERE code_id=%s", params)
if res.fetchone() != None:
cur.execute(f"UPDATE codes SET used = True WHERE code_id=%s", params)
con.commit()
def get_user_list(): def get_user_list():
with connect_db() as con: with connect_db() as con:
with con.cursor(dictionary=True, prepared=True) as cur: with con.cursor(dictionary=True, prepared=True) as cur:
@@ -172,6 +215,13 @@ def get_user_list():
ret = cur.fetchall() ret = cur.fetchall()
return ret return ret
def get_active_user_list():
with connect_db() as con:
with con.cursor(dictionary=True, prepared=True) as cur:
res = cur.execute(f"SELECT * FROM users WHERE active=True")
ret = cur.fetchall()
return ret
def get_user(telegram_user_id): def get_user(telegram_user_id):
with connect_db() as con: with connect_db() as con:
with con.cursor(dictionary=True, prepared=True) as cur: with con.cursor(dictionary=True, prepared=True) as cur:

View File

@@ -26,6 +26,10 @@ ACTION, ADD_PRODUCT_NAME, ADD_PRODUCT_MIN_PRICE, ADD_PRODUCT_MAX_PRICE, \
ADD_PRODUCT_CATEGORY, ADD_PRODUCT_TITLE_EXCLUDE, ADD_PRODUCT_DESCRIPTION_EXCLUDE, \ ADD_PRODUCT_CATEGORY, ADD_PRODUCT_TITLE_EXCLUDE, ADD_PRODUCT_DESCRIPTION_EXCLUDE, \
ADD_PRODUCT_COORDS, ADD_PRODUCT_DISTANCE, REMOVE_PRODUCT, LIST, FINISH, CONTINUE_OR_FINISH = range(13) ADD_PRODUCT_COORDS, ADD_PRODUCT_DISTANCE, REMOVE_PRODUCT, LIST, FINISH, CONTINUE_OR_FINISH = range(13)
MAX_PRODUCTS_TESTING = 5
MAX_PRODUCTS_PREMIUM = 30
MAX_PRODUCTS_HOMELABS = 5
# Enable logging # Enable logging
logging.basicConfig( logging.basicConfig(
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO
@@ -37,10 +41,10 @@ httpx_logger = logging.getLogger('httpx')
httpx_logger.setLevel(logging.WARNING) httpx_logger.setLevel(logging.WARNING)
async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
if walladb.is_user_valid(helpers.get_telegram_user_id(update)): if walladb.is_user_active(helpers.get_telegram_user_id(update)):
message = "Utiliza el menú de la conversación para añadir un producto y sigue los pasos indicados. Si tienes cualquier duda contacta con @jocarduck para más información." message = "Utiliza el menú de la conversación para añadir un producto y sigue los pasos indicados. Si tienes cualquier duda contacta con @jocarduck para más información."
else: else:
message = "Activa tu periodo de prueba de 7 días con `/test` o contacta con @jocarduck para más información." message = "No tienes permitido usar este bot."
await update.message.reply_markdown_v2(helpers.telegram_escape_characters(message)) await update.message.reply_markdown_v2(helpers.telegram_escape_characters(message))
async def main_menu(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: async def main_menu(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
@@ -58,21 +62,27 @@ async def main_menu(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
async def menu_click_handler(update: Update, context: CallbackContext): async def menu_click_handler(update: Update, context: CallbackContext):
await update.callback_query.edit_message_reply_markup(None) await update.callback_query.edit_message_reply_markup(None)
telegram_user_id = helpers.get_telegram_user_id(update) telegram_user_id = helpers.get_telegram_user_id(update)
if walladb.is_user_valid(telegram_user_id): if walladb.is_user_active(telegram_user_id):
context.user_data['telegram_user_id'] = telegram_user_id context.user_data['telegram_user_id'] = telegram_user_id
query = update.callback_query query = update.callback_query
number_of_products = walladb.count_user_products(telegram_user_id)
if query.data == 'add': if query.data == 'add':
valid = False valid = False
number_of_products = walladb.count_user_products(telegram_user_id) number_of_products = walladb.count_user_products(telegram_user_id)
if walladb.is_user_testing(telegram_user_id): if walladb.is_user_testing(telegram_user_id):
valid = True valid = True
if number_of_products >= 5: if number_of_products >= MAX_PRODUCTS_TESTING:
message = "Ya tienes 5 productos en seguimiento. Con premium puedes tener hasta 20." message = f"Ya tienes {MAX_PRODUCTS_TESTING} productos en seguimiento. Borra algunos para añadir más."
valid = False valid = False
elif walladb.is_user_premium(telegram_user_id): elif walladb.is_user_premium(telegram_user_id):
valid = True valid = True
if number_of_products >= 20: if number_of_products >= MAX_PRODUCTS_PREMIUM:
message = "Ya tienes 20 productos en seguimiento. Borra algunos para añadir más." message = f"Ya tienes {MAX_PRODUCTS_PREMIUM} productos en seguimiento. Borra algunos para añadir más."
valid = False
elif walladb.is_user_homelabs(telegram_user_id):
valid = True
if number_of_products >= MAX_PRODUCTS_HOMELABS:
message = f"Ya tienes {MAX_PRODUCTS_HOMELABS} productos en seguimiento. Borra algunos para añadir más."
valid = False valid = False
if valid: if valid:
await context.bot.send_message(chat_id=update.effective_chat.id, await context.bot.send_message(chat_id=update.effective_chat.id,
@@ -82,14 +92,22 @@ async def menu_click_handler(update: Update, context: CallbackContext):
await context.bot.send_message(chat_id=update.effective_chat.id, text=f'{message}') await context.bot.send_message(chat_id=update.effective_chat.id, text=f'{message}')
return ConversationHandler.END return ConversationHandler.END
if query.data == 'remove': if query.data == 'remove':
await send_list(update, context) if number_of_products != 0:
return REMOVE_PRODUCT await send_list(update, context)
return REMOVE_PRODUCT
message = "No tienes ninguna búsqueda activa"
await context.bot.send_message(chat_id=update.effective_chat.id, text=f'{message}')
return ConversationHandler.END
if query.data == 'list': if query.data == 'list':
await send_list(update, context) if number_of_products != 0:
return LIST await send_list(update, context)
return LIST
message = "No tienes ninguna búsqueda activa"
await context.bot.send_message(chat_id=update.effective_chat.id, text=f'{message}')
return ConversationHandler.END
else: else:
await context.bot.send_message(chat_id=update.effective_chat.id, await context.bot.send_message(chat_id=update.effective_chat.id,
text=helpers.telegram_escape_characters('Activa tu periodo de prueba de 7 días con `/test` o contacta con @jocarduck para más información.'), parse_mode=ParseMode.MARKDOWN_V2) text=helpers.telegram_escape_characters('No tienes permiso para usar este bot.'), parse_mode=ParseMode.MARKDOWN_V2)
return ConversationHandler.END return ConversationHandler.END
async def add_product_name(update: Update, context: CallbackContext): async def add_product_name(update: Update, context: CallbackContext):
@@ -340,7 +358,7 @@ async def product_details(update: Update, context: ContextTypes.DEFAULT_TYPE) ->
async def send_list(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: async def send_list(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
telegram_user_id = helpers.get_telegram_user_id(update) telegram_user_id = helpers.get_telegram_user_id(update)
if walladb.is_user_valid(telegram_user_id): if walladb.is_user_active(telegram_user_id):
if walladb.is_user_testing(telegram_user_id) or walladb.is_user_premium(telegram_user_id): if walladb.is_user_testing(telegram_user_id) or walladb.is_user_premium(telegram_user_id):
query = update.callback_query query = update.callback_query
if query.data == 'remove': if query.data == 'remove':
@@ -373,28 +391,21 @@ async def remove_user_command(update: Update, context: ContextTypes.DEFAULT_TYPE
async def status_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: async def status_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
telegram_user_id = helpers.get_telegram_user_id(update) telegram_user_id = helpers.get_telegram_user_id(update)
if walladb.is_user_valid(telegram_user_id): if walladb.is_user_active(telegram_user_id):
type = walladb.get_user_type(telegram_user_id) type = walladb.get_user_type(telegram_user_id)
until = walladb.get_user_until(telegram_user_id) until = walladb.get_user_until(telegram_user_id)
message = f"Tu cuenta es tipo: {type} y caduca el {helpers.get_spanish_date(until)}." message = f"Tu cuenta es tipo: {type} y caduca el {helpers.get_spanish_date(until)}."
await update.message.reply_markdown_v2(helpers.telegram_escape_characters(message)) await update.message.reply_markdown_v2(helpers.telegram_escape_characters(message))
async def test_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: async def start_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
telegram_user_id = helpers.get_telegram_user_id(update) telegram_user_id = helpers.get_telegram_user_id(update)
telegram_user_name = helpers.get_telegram_user_name(update) telegram_user_name = helpers.get_telegram_user_name(update)
#if not walladb.is_user_valid(telegram_user_id): #if not walladb.is_user_valid(telegram_user_id):
if telegram_user_id < 0: if telegram_user_id < 0:
message = "Este bot no se puede usar en grupos." message = "Este bot no se puede usar en grupos."
elif walladb.get_user(telegram_user_id) == "NoName": elif walladb.get_user(telegram_user_id) == "NoName":
until = helpers.get_date_ahead(7) walladb.enable_user(telegram_user_id, telegram_user_name)
walladb.add_test_user(telegram_user_id, telegram_user_name, until) message = f"Bienvenido a @wallamanta, usa el comando /help para más información."
message = f"Periodo de prueba activado hasta el {helpers.get_spanish_date(until)}."
else:
message = "Ya has utilizado el periodo de prueba."
if walladb.is_user_testing(telegram_user_id):
message = "Ya estás en el periodo de prueba."
elif walladb.is_user_premium(telegram_user_id):
message = "Ya eres premium. No puedes volver al periodo de prueba."
await update.message.reply_markdown_v2(helpers.telegram_escape_characters(message)) await update.message.reply_markdown_v2(helpers.telegram_escape_characters(message))
async def add_to_db_and_send(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: async def add_to_db_and_send(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
@@ -428,6 +439,36 @@ async def list_threads(update: Update, context: ContextTypes.DEFAULT_TYPE) -> No
else: else:
await update.message.reply_markdown_v2(helpers.telegram_escape_characters(f"{threads_string}")) await update.message.reply_markdown_v2(helpers.telegram_escape_characters(f"{threads_string}"))
async def message_to_all(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
if helpers.is_user_admin(update.message.chat_id):
message = update.message.text.split('/message_to_all ')[1]
helpers.send_message_to_all(message)
await update.message.reply_markdown_v2(helpers.telegram_escape_characters(f"Messages sent to all users"))
async def code(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
code = update.message.text.split('/code ')[1]
telegram_user_id = update.message.chat_id
if len(code) != 12:
await update.message.reply_markdown_v2(helpers.telegram_escape_characters(f"El código no tiene el formato correcto"))
else:
code = walladb.get_code(code)
if code:
until = helpers.get_date_ahead(code['days'])
try:
if code['type'] == 'premium':
walladb.add_premium_user(telegram_user_id, until)
await update.message.reply_markdown_v2(helpers.telegram_escape_characters(f"Activado periodo premium hasta el {until}"))
elif code['type'] == 'testing':
walladb.add_test_user(telegram_user_id, until)
await update.message.reply_markdown_v2(helpers.telegram_escape_characters(f"Activado periodo testing hasta el {until}"))
walladb.use_code(code)
except Exception as e:
error_code = helpers.get_random_string(8)
logging.info(f"Error trying to checkout code {code}: {e}. {error_code}")
await update.message.reply_markdown_v2(helpers.telegram_escape_characters(f"Ha habido un error, contacta con @jocarduck y dale el siguiente código de error: `{error_code}`"))
else:
await update.message.reply_markdown_v2(helpers.telegram_escape_characters(f"El código no es válido o ya ha sido usado"))
def count_threads(): def count_threads():
time.sleep(10) time.sleep(10)
while True: while True:
@@ -447,17 +488,19 @@ def main()->None:
p = threading.Thread(target=account_checker.work, args=(3600, )) p = threading.Thread(target=account_checker.work, args=(3600, ))
p.start() p.start()
p = threading.Thread(target=count_threads) #p = threading.Thread(target=count_threads)
p.start() #p.start()
# on different commands - answer in Telegram # on different commands - answer in Telegram
application.add_handler(CommandHandler("start", start_command))
application.add_handler(CommandHandler("help", help_command)) application.add_handler(CommandHandler("help", help_command))
application.add_handler(CommandHandler("admin", admin_command)) application.add_handler(CommandHandler("admin", admin_command))
application.add_handler(CommandHandler("add_premium_user", add_premium_user_command)) application.add_handler(CommandHandler("add_premium_user", add_premium_user_command))
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("list_threads", list_threads)) application.add_handler(CommandHandler("list_threads", list_threads))
application.add_handler(CommandHandler("message_to_all", message_to_all))
application.add_handler(CommandHandler("code", code))
#application.add_handler(CallbackQueryHandler("list", send_list())) #application.add_handler(CallbackQueryHandler("list", send_list()))
#application.add_handler(CallbackQueryHandler(pattern="list", callback=send_list())) #application.add_handler(CallbackQueryHandler(pattern="list", callback=send_list()))

View File

@@ -1,5 +1,5 @@
import time
import requests import requests
from random import randint
import logging import logging
import helpers import helpers
import walladb import walladb
@@ -13,6 +13,7 @@ logging.basicConfig(
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def request(product_name, steps=15, latitude=constants.LATITUDE, longitude=constants.LONGITUDE, distance='0', condition='all', min_price=0, max_price=10000000, category="", subcategories=[]): def request(product_name, steps=15, latitude=constants.LATITUDE, longitude=constants.LONGITUDE, distance='0', condition='all', min_price=0, max_price=10000000, category="", subcategories=[]):
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36'}
distance = str(int(distance) * 1000) distance = str(int(distance) * 1000)
url = (f"https://api.wallapop.com/api/v3/general/search?keywords={product_name}" url = (f"https://api.wallapop.com/api/v3/general/search?keywords={product_name}"
f"&order_by=newest&latitude={latitude}" f"&order_by=newest&latitude={latitude}"
@@ -22,8 +23,8 @@ def request(product_name, steps=15, latitude=constants.LATITUDE, longitude=const
f"&max_sale_price={max_price}" f"&max_sale_price={max_price}"
f"&filters_source=quick_filters&language=es_ES") f"&filters_source=quick_filters&language=es_ES")
if condition != "all": #if condition != "all":
url = url + f"&condition={condition}" # new, as_good_as_new, good, fair, has_given_it_all # url = url + f"&condition={condition}" # new, as_good_as_new, good, fair, has_given_it_all
if category != "": if category != "":
url = url + f"&category_ids={category}" url = url + f"&category_ids={category}"
@@ -37,39 +38,45 @@ def request(product_name, steps=15, latitude=constants.LATITUDE, longitude=const
search_objects = list() search_objects = list()
for step in range(steps): for step in range(steps):
#helpers.random_wait()
tries = 5 tries = 5
for _ in range(tries): for _ in range(tries):
response = requests.get(url+f"&step={step}")
try: try:
if randint(0, 1) == 0:
response = requests.get(url+f"&step={step}", timeout=1, headers=headers)
else:
response = requests.get(url+f"&step={step}", timeout=1, headers=headers, proxies=dict(https=f'socks5://{constants.PROXY_SOCKS}'))
if response.status_code == 200: if response.status_code == 200:
search_objects = search_objects + response.json()['search_objects'] search_objects = search_objects + response.json()['search_objects']
break break
else: else:
logging.info(f"\'{product_name}\' -> Wallapop returned status {response.status_code}. Illegal parameters or Wallapop service is down. Retrying...") logging.info(f"\'{product_name}\' -> Wallapop returned status {response.status_code}. Illegal parameters or Wallapop service is down. Retrying...")
except Exception as e: except Exception as e:
logging.info("Error while querying Wallapop, try #{_}: " + e) logging.info(f"Error while querying Wallapop, try #{_}: {e}")
time.sleep(3) for __ in range(_):
helpers.random_wait()
return search_objects return search_objects
def first_run(product): def first_run(product):
logging.info(f"First run for {product['product_name']} for {walladb.get_user(product['telegram_user_id'])} ({walladb.get_user(product['telegram_user_id'])})") steps = 1
#logging.info(f"First run for {product['product_name']} for {walladb.get_user(product['telegram_user_id'])} ({walladb.get_user(product['telegram_user_id'])})")
list = [] list = []
if not helpers.is_valid_request(product): if not helpers.is_valid_request(product):
return list return list
if product['category'] == '': if product['category'] == '':
articles = request(product['product_name'], 15, product['latitude'], product['longitude'], product['distance'], product['condition'], product['min_price'], product['max_price'], product['category']) articles = request(product['product_name'], steps, product['latitude'], product['longitude'], product['distance'], product['condition'], product['min_price'], product['max_price'], product['category'])
for article in articles: for article in articles:
list.insert(0, article['id']) list.insert(0, article['id'])
else: else:
if '0' in product['category'].split(','): if '0' in product['category'].split(','):
articles = request(product['product_name'], 15, product['latitude'], product['longitude'], product['distance'], product['condition'], product['min_price'], product['max_price']) articles = request(product['product_name'], steps, product['latitude'], product['longitude'], product['distance'], product['condition'], product['min_price'], product['max_price'])
for article in articles: for article in articles:
list.insert(0, article['id']) list.insert(0, article['id'])
else: else:
for category in product['category'].split(','): for category in product['category'].split(','):
if product['subcategory'] == '' or not helpers.has_subcategory(category): if product['subcategory'] == '' or not helpers.has_subcategory(category):
articles = request(product['product_name'], 15, product['latitude'], product['longitude'], product['distance'], product['condition'], product['min_price'], product['max_price'], category) articles = request(product['product_name'], steps, product['latitude'], product['longitude'], product['distance'], product['condition'], product['min_price'], product['max_price'], category)
for article in articles: for article in articles:
list.insert(0, article['id']) list.insert(0, article['id'])
else: else:
@@ -77,33 +84,35 @@ def first_run(product):
for subcategory in product['subcategory'].split(','): for subcategory in product['subcategory'].split(','):
if helpers.is_subcategory(category, subcategory): if helpers.is_subcategory(category, subcategory):
subcategories.append(subcategory) subcategories.append(subcategory)
articles = request(product['product_name'], 15, product['latitude'], product['longitude'], product['distance'], product['condition'], product['min_price'], product['max_price'], category, subcategories) articles = request(product['product_name'], steps, product['latitude'], product['longitude'], product['distance'], product['condition'], product['min_price'], product['max_price'], category, subcategories)
for article in articles: for article in articles:
list.insert(0, article['id']) list.insert(0, article['id'])
return list return list
def work(product, list): def work(product, searches_list):
logging.info(f"Searching {product['product_name']}") list = searches_list.copy()
steps = 1
logging.info(f"Searching {product['product_name']} ({product['id']}) - ({walladb.get_user(product['telegram_user_id'])})")
articles_list = [] articles_list = []
if product['category'] == '': if product['category'] == '':
articles_list.append(request(product['product_name'], 1, product['latitude'], product['longitude'], product['distance'], product['condition'], product['min_price'], product['max_price'])) articles_list.append(request(product['product_name'], steps, product['latitude'], product['longitude'], product['distance'], product['condition'], product['min_price'], product['max_price']))
else: else:
if '0' in product['category'].split(','): if '0' in product['category'].split(','):
articles_list.append(request(product['product_name'], 1, product['latitude'], product['longitude'], product['distance'], product['condition'], product['min_price'], product['max_price'])) articles_list.append(request(product['product_name'], steps, product['latitude'], product['longitude'], product['distance'], product['condition'], product['min_price'], product['max_price']))
else: else:
for category in product['category'].split(','): for category in product['category'].split(','):
if product['subcategory'] == '' or not helpers.has_subcategory(category): if product['subcategory'] == '' or not helpers.has_subcategory(category):
articles_list.append(request(product['product_name'], 1, product['latitude'], product['longitude'], product['distance'], product['condition'], product['min_price'], product['max_price'], category)) articles_list.append(request(product['product_name'], steps, product['latitude'], product['longitude'], product['distance'], product['condition'], product['min_price'], product['max_price'], category))
else: else:
subcategories = [] subcategories = []
for subcategory in product['subcategory'].split(','): for subcategory in product['subcategory'].split(','):
if helpers.is_subcategory(category, subcategory): if helpers.is_subcategory(category, subcategory):
subcategories.append(subcategory) subcategories.append(subcategory)
articles_list.append(request(product['product_name'], 1, product['latitude'], product['longitude'], product['distance'], product['condition'], product['min_price'], product['max_price'], category, subcategories)) articles_list.append(request(product['product_name'], steps, product['latitude'], product['longitude'], product['distance'], product['condition'], product['min_price'], product['max_price'], category, subcategories))
for articles in articles_list: for articles in articles_list:
for article in articles: for article in articles:
if not article['id'] in list: if not article['id'] in list:
logging.info(f"Found article {article['title']} for {walladb.get_user(product['telegram_user_id'])} ({product['telegram_user_id']})") logging.info(f"Found article {article['title']} for {product['product_name']} ({product['id']}) - ({walladb.get_user(product['telegram_user_id'])})")
try: try:
if not has_excluded_words(article['title'].lower(), article['description'].lower(), product['title_description_exclude']) and not is_title_key_word_excluded(article['title'].lower(), product['title_exclude']): if not has_excluded_words(article['title'].lower(), article['description'].lower(), product['title_description_exclude']) and not is_title_key_word_excluded(article['title'].lower(), product['title_exclude']):
helpers.send_article(article, product) helpers.send_article(article, product)
@@ -112,7 +121,7 @@ def work(product, list):
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")
return list[:600] return list[:100]
def has_excluded_words(title, description, excluded_words): def has_excluded_words(title, description, excluded_words):
if len(excluded_words) > 0: if len(excluded_words) > 0:
@@ -129,4 +138,4 @@ def is_title_key_word_excluded(title, excluded_words):
logging.info("Checking '" + word + "' for title: '" + title) logging.info("Checking '" + word + "' for title: '" + title)
if word.lower().lstrip().rstrip() in title.lower(): if word.lower().lstrip().rstrip() in title.lower():
return True return True
return False return False