Refactor caching and Telegram integration

- Updated configuration to enforce Redis caching for notified articles, removing memory cache options.
- Enhanced wallamonitor.py to load Redis cache settings and handle errors more effectively.
- Implemented new API endpoints for clearing Redis cache and retrieving Telegram forum topics.
- Improved frontend components to support fetching and displaying available Telegram threads.
- Added functionality for clearing cache from the UI, ensuring better management of notified articles.
This commit is contained in:
Omar Sánchez Pizarro
2026-01-19 21:24:46 +01:00
parent 96db30ff00
commit 5cc96a2371
7 changed files with 382 additions and 88 deletions

View File

@@ -87,6 +87,46 @@ class TelegramManager:
def escape_html(self, text):
return html.escape(str(text))
async def get_forum_topics_async(self):
"""Obtiene los topics/hilos del canal/grupo"""
try:
# Intentar obtener forum topics usando la API
try:
# Usar get_forum_topics si está disponible (python-telegram-bot 20+)
result = await self._bot.get_forum_topics(chat_id=self._channel, limit=100)
topics = []
if hasattr(result, 'topics') and result.topics:
for topic in result.topics:
topics.append({
'id': topic.message_thread_id,
'name': getattr(topic, 'name', f'Thread {topic.message_thread_id}'),
'icon_color': getattr(topic, 'icon_color', None),
'icon_custom_emoji_id': getattr(topic, 'icon_custom_emoji_id', None),
})
return topics
except AttributeError:
# Si get_forum_topics no existe, usar método alternativo
return await self._get_topics_from_messages()
except Exception as e:
self.logger.error(f"Error obteniendo forum topics: {e}")
return await self._get_topics_from_messages()
async def _get_topics_from_messages(self):
"""Obtiene topics desde mensajes recientes (workaround)"""
try:
topics_dict = {}
# Intentar obtener algunos mensajes recientes
# Nota: Esto solo funciona si hay mensajes recientes con thread_id
self.logger.info("Obteniendo topics desde mensajes recientes...")
return []
except Exception as e:
self.logger.error(f"Error obteniendo topics desde mensajes: {e}")
return []
def get_forum_topics(self):
"""Versión síncrona para obtener forum topics"""
return self._loop.run_until_complete(self.get_forum_topics_async())
def send_telegram_article(self, search_name, article, thread_id=None):
self._loop.run_until_complete(self.send_telegram_article_async(search_name, article, thread_id))
@@ -117,8 +157,8 @@ class TelegramManager:
# Crear botones inline para el primer mensaje del grupo
if is_favorite:
keyboard = [
[
keyboard = [
[
InlineKeyboardButton("✅ En favoritos", callback_data=f"already_fav_{article.get_platform()}_{article.get_id()}"),
InlineKeyboardButton("🗑️ Quitar", callback_data=f"unfav_{article.get_platform()}_{article.get_id()}")
],
@@ -130,9 +170,9 @@ class TelegramManager:
keyboard = [
[
InlineKeyboardButton("⭐ Añadir a favoritos", callback_data=f"fav_{article.get_platform()}_{article.get_id()}_{search_name}"),
InlineKeyboardButton("Ir al anuncio", url=f"{article.get_url()}")
InlineKeyboardButton("Ir al anuncio", url=f"{article.get_url()}")
]
]
]
reply_markup = InlineKeyboardMarkup(keyboard)
# Enviar un mensaje adicional con los botones (reply al primer mensaje del grupo)
@@ -149,6 +189,7 @@ class TelegramManager:
def _add_handlers(self):
"""Añade los handlers para comandos y callbacks"""
self._application.add_handler(CommandHandler("favs", self.handle_favs_command))
self._application.add_handler(CommandHandler("threads", self.handle_threads_command))
self._application.add_handler(CallbackQueryHandler(self.handle_favorite_callback, pattern="^fav_"))
self._application.add_handler(CallbackQueryHandler(self.handle_unfavorite_callback, pattern="^unfav_"))
self.logger.info("Handlers de comandos y callbacks añadidos")
@@ -231,7 +272,7 @@ class TelegramManager:
]
]
else:
new_keyboard = [
new_keyboard = [
[
InlineKeyboardButton("✅ En favoritos", callback_data=f"already_fav_{platform}_{article_id}"),
InlineKeyboardButton("🗑️ Quitar", callback_data=f"unfav_{platform}_{article_id}")
@@ -243,6 +284,39 @@ class TelegramManager:
self.logger.info(f"Artículo {article_id} ({platform}) marcado como favorito")
async def handle_threads_command(self, update: telegram.Update, context: telegram.ext.ContextTypes.DEFAULT_TYPE):
"""Maneja el comando /threads para mostrar los threads disponibles"""
try:
topics = await self.get_forum_topics_async()
if not topics:
await update.message.reply_text(
"📋 No se pudieron obtener los threads automáticamente.\n\n"
"💡 <b>Cómo obtener el Thread ID:</b>\n"
"1. Haz clic derecho en el tema/hilo\n"
"2. Selecciona 'Copiar enlace del tema'\n"
"3. El número al final de la URL es el Thread ID\n\n"
"Ejemplo: <code>t.me/c/1234567890/8</code> → Thread ID = <b>8</b>",
parse_mode="HTML"
)
return
message = f"📋 <b>Threads Disponibles ({len(topics)})</b>\n\n"
for topic in topics:
name = topic.get('name', f'Thread {topic["id"]}')
thread_id = topic['id']
message += f"• <b>{self.escape_html(name)}</b> → Thread ID: <code>{thread_id}</code>\n"
await update.message.reply_text(message, parse_mode="HTML")
except Exception as e:
self.logger.error(f"Error en comando /threads: {e}")
await update.message.reply_text(
"❌ Error obteniendo threads. Usa el método manual:\n\n"
"1. Haz clic derecho en el tema\n"
"2. Copia el enlace del tema\n"
"3. El número al final es el Thread ID"
)
async def handle_favs_command(self, update: telegram.Update, context: telegram.ext.ContextTypes.DEFAULT_TYPE):
"""Maneja el comando /favs para mostrar los favoritos"""
if not self._article_cache:
@@ -326,7 +400,7 @@ class TelegramManager:
]
]
else:
keyboard = [
keyboard = [
[
InlineKeyboardButton("⭐ Añadir a favoritos", callback_data=f"fav_{platform}_{article_id}_Unknown")
]