diff --git a/api_server.py b/api_server.py index 2cf611d..788c44f 100644 --- a/api_server.py +++ b/api_server.py @@ -29,7 +29,36 @@ async def get_post_html(channel: str, post_id: int): ) return f""" - + + Post {post_id} + + + {post['text']} diff --git a/telegram_client.py b/telegram_client.py index 4fb8629..daa0b8f 100644 --- a/telegram_client.py +++ b/telegram_client.py @@ -4,6 +4,7 @@ from pyrogram.types import Message from config import get_settings import base64 import os +import re logger = logging.getLogger(__name__) settings = get_settings() @@ -38,19 +39,74 @@ class TelegramClient: logger.info("Telegram client disconnected") async def _parse_message(self, message: Message) -> dict: + # Debug raw message structure + print(f"Raw message object: \n{message}") + # Extract text from different sources - text = message.text.html if message.text else "" # Get HTML formatted text + raw_text = message.text.html if message.text else "" + + # Handle polls + poll = getattr(message, "poll", None) + if poll: + try: + question = getattr(poll, "question", "No question text") + raw_text += f"\nšŸ“Š Poll: {poll.question}\n" + if hasattr(poll, "options") and poll.options: + for i, option in enumerate(poll.options, 1): + raw_text += f"{i}. {getattr(option, 'text', '')}\n" + raw_text += "\n→ Vote in Telegram šŸ”—\n" + except Exception as e: + logger.error(f"Error parsing poll: {str(e)}") + raw_text += "\n[Error displaying poll]" # Try to get caption for media messages - if not text and hasattr(message, "caption") and message.caption: - text = message.caption.html + if not raw_text and hasattr(message, "caption") and message.caption: + raw_text = message.caption.html # Try to get text from other attributes - if not text and hasattr(message, "action"): - text = str(message.action) - elif not text and hasattr(message, "entities"): + if not raw_text and hasattr(message, "action"): + raw_text = str(message.action) + elif not raw_text and hasattr(message, "entities"): # Extract HTML from entities - text = message.text.html if message.text else "" + raw_text = message.text.html if message.text else "" + + # Process text entities for links + text_parts = [] + last_offset = 0 + entities = getattr(message, "entities", None) + if entities and isinstance(entities, list): + # Sort entities by offset + entities = sorted(entities, key=lambda x: x.offset) + + for entity in entities: + if entity.offset > last_offset: + text_parts.append(raw_text[last_offset:entity.offset]) + + entity_text = raw_text[entity.offset:entity.offset+entity.length] + + if entity.type == "text_link": + text_parts.append(f"{entity_text}") + elif entity.type == "url": + text_parts.append(f"{entity_text}") + else: + text_parts.append(entity_text) + + last_offset = entity.offset + entity.length + + # Add remaining text + if last_offset < len(raw_text): + text_parts.append(raw_text[last_offset:]) + + processed_text = "".join(text_parts) + else: + processed_text = raw_text + + # Replace only URLs not already in tags + processed_text = re.sub( + r'(?)', + r'\1', + processed_text + ) # Parse media and add video markers media = [] @@ -74,9 +130,9 @@ class TelegramClient: media.append(parsed_media) logger.debug(f"Parsed media: {parsed_media}") - video_count = sum(1 for m in media if m.get("type") == "video") - if video_count > 0: - text = f"[{'Video' if video_count == 1 else f'{video_count} Videos'}] {text}" if text else f"[{'Video' if video_count == 1 else f'{video_count} Videos'}]" + #video_count = sum(1 for m in media if m.get("type") == "video") + #if video_count > 0: + # # processed_text = f"[{'Video' if video_count == 1 else f'{video_count} Videos'}] {processed_text}" if processed_text else f"[{'Video' if video_count == 1 else f'{video_count} Videos'}]" # Always add reactions if present reactions_text = "" @@ -85,25 +141,34 @@ class TelegramClient: f"{r.emoji}({r.count})" for r in message.reactions.reactions ) - text += reactions_text + processed_text += reactions_text # Add media previews to text if media: previews = [] for m in media: if m.get('thumbnail'): - previews.append(f"") + media_type = m.get('type', 'media').upper() + overlay = f"
{media_type}
" + previews.append( + f"
" + f"" + f"{overlay}" + f"
" + ) if previews: - text = "
".join(previews) + "

" + text + previews_container = f"
{''.join(previews)}
" + processed_text = previews_container + processed_text # Convert newlines to HTML breaks AFTER adding reactions - text = text.replace('\n', '
') + processed_text = processed_text.replace('\n', '
') return { "id": message.id, "date": message.date.isoformat(), - "text": text, - "views": message.views or 0 + "text": processed_text, + "views": message.views or 0, + "media_group_id": message.media_group_id } async def _parse_media(self, media_obj) -> dict: @@ -233,10 +298,54 @@ class TelegramClient: "details": f"Message {post_id} in {channel} does not exist" } - # Debug raw message structure - print("Raw message object: %s", message) - - return await self._parse_message(message) + # Check for media group + media_group = [] + if message.media_group_id: + logger.debug(f"Processing media group {message.media_group_id} for message {post_id}") + current_id = post_id + # Collect previous messages in group + while True: + prev_msg = await self.client.get_messages( + chat_id=channel, + message_ids=current_id - 1 + ) + if prev_msg and prev_msg.media_group_id == message.media_group_id: + logger.debug(f"Found previous message in group: {prev_msg.id}") + media_group.insert(0, prev_msg) + current_id -= 1 + else: + break + + # Collect next messages in group + current_id = post_id + while True: + next_msg = await self.client.get_messages( + chat_id=channel, + message_ids=current_id + 1 + ) + if next_msg and next_msg.media_group_id == message.media_group_id: + logger.debug(f"Found next message in group: {next_msg.id}") + media_group.append(next_msg) + current_id += 1 + else: + break + + # Process all messages in group + all_messages = media_group + [message] + logger.debug(f"Combined {len(all_messages)} messages in media group") + parsed_messages = [await self._parse_message(msg) for msg in all_messages] + + # Combine results + combined = { + "id": post_id, + "date": message.date.isoformat(), + "text": "".join([m["text"] for m in parsed_messages if m["text"]]), + "views": max(m["views"] for m in parsed_messages), + "media_group_id": message.media_group_id + } + logger.debug(f"Combined result: {combined}") + + return combined except errors.RPCError as e: logger.error(f"Telegram API error: {e.__class__.__name__} - {e}") raise