diff --git a/api_server.py b/api_server.py
index 5d8193d..97fae56 100644
--- a/api_server.py
+++ b/api_server.py
@@ -520,7 +520,13 @@ async def get_media(channel: str, post_id: int, file_unique_id: str, digest: str
@app.get("/rss/{channel}", response_class=Response)
@app.get("/rss/{channel}/{token}", response_class=Response)
-async def get_rss_feed(channel: str, token: str | None = None, limit: int = 50, output_type: str = 'rss', exclude_flags: str | None = None):
+async def get_rss_feed(channel: str,
+ token: str | None = None,
+ limit: int = 50,
+ output_type: str = 'rss',
+ exclude_flags: str | None = None,
+ merge_seconds: int = 5
+ ):
if Config["token"]:
if token != Config["token"]:
logger.error(f"Invalid token for RSS feed: {token}, expected: {Config['token']}")
@@ -530,10 +536,18 @@ async def get_rss_feed(channel: str, token: str | None = None, limit: int = 50,
while True:
try:
if output_type == 'rss':
- rss_content = await generate_channel_rss(channel, client=client.client, limit=limit, exclude_flags=exclude_flags)
+ rss_content = await generate_channel_rss(channel,
+ client=client.client,
+ limit=limit,
+ exclude_flags=exclude_flags,
+ merge_seconds=merge_seconds)
return Response(content=rss_content, media_type="application/xml")
elif output_type == 'html':
- rss_content = await generate_channel_html(channel, client=client.client, limit=limit, exclude_flags=exclude_flags)
+ rss_content = await generate_channel_html(channel,
+ client=client.client,
+ limit=limit,
+ exclude_flags=exclude_flags,
+ merge_seconds=merge_seconds)
return Response(content=rss_content, media_type="text/html")
except ValueError as e:
error_message = f"Invalid parameters for RSS feed generation: {str(e)}"
diff --git a/config.py b/config.py
index 2b14ee5..b6168c0 100644
--- a/config.py
+++ b/config.py
@@ -11,5 +11,6 @@ def get_settings():
"pyrogram_bridge_url": os.getenv("PYROGRAM_BRIDGE_URL", ""),
"log_level": os.getenv("LOG_LEVEL", "INFO"),
"debug": os.getenv("DEBUG", "False") == "True",
- "token": os.getenv("TOKEN", "")
+ "token": os.getenv("TOKEN", ""),
+ "time_based_merge": os.getenv("TIME_BASED_MERGE", "False") == "True",
}
diff --git a/post_parser.py b/post_parser.py
index b2fccc7..66a2378 100644
--- a/post_parser.py
+++ b/post_parser.py
@@ -404,9 +404,9 @@ class PostParser:
def _generate_html_footer(self, message: Message) -> str:
content_footer = []
- if reactions_views_html := self._reactions_views_links(message): # Add reactions, views and links
+ if reactions_views_html := self._reactions_views_links(message): # Add reactions, views, date and links
content_footer.append(reactions_views_html)
- if flags_html := self._format_flags(message): # Add flags
+ if flags_html := self._format_flags(message): # Add flags
content_footer.append(flags_html)
html_footer = '\n'.join(content_footer)
html_footer = self._sanitize_html(html_footer)
@@ -475,14 +475,19 @@ class PostParser:
if views := getattr(message, "views", None):
views_html = f'{views} views'
- # If both reactions and views exist, insert a line break between them.
- if reactions_html and views_html:
- parts.append(reactions_html + "
" + views_html)
- elif reactions_html:
- parts.append(reactions_html)
- elif views_html:
- parts.append(views_html)
+ # Combine reactions and views on the same line
+ if reactions_html or views_html:
+ parts.append(f'{reactions_html} {views_html}')
+ # Add date and links on the same line
+ second_line_parts = []
+
+ # Format date as DD/MM/YY, HH:MM:SS
+ if message.date:
+ formatted_date = message.date.strftime("%d/%m/%y, %H:%M:%S")
+ second_line_parts.append(formatted_date)
+
+ # Add links
channel_identifier = self.get_channel_username(message)
if channel_identifier:
links = []
@@ -490,12 +495,15 @@ class PostParser:
channel_id = channel_identifier[4:] # Remove '-100' prefix for web links
links.append(f'Open in Telegram')
links.append(f'Open in Web')
- else: # For channels with username
+ else: # For channels with username
links.append(f'Open in Telegram')
links.append(f'Open in Web')
- parts.append(' '.join(links))
+ second_line_parts.extend(links)
- html = ' '.join(parts) if parts else None
+ if second_line_parts:
+ parts.append(' '.join(second_line_parts))
+
+ html = '
'.join(parts) if parts else None
return f"
{html}" if html else None
except Exception as e:
diff --git a/rss_generator.py b/rss_generator.py
index 9b319bb..be5b533 100644
--- a/rss_generator.py
+++ b/rss_generator.py
@@ -16,6 +16,49 @@ if not logger.handlers:
logger.addHandler(handler)
+async def create_time_based_media_groups(messages, merge_seconds: int = 5):
+ messages_sorted = sorted(messages, key=lambda x: x.date)
+ cluster = []
+ last_msg_date = None
+ current_media_group_id = None
+
+ for msg in messages_sorted:
+
+ if not cluster:
+ cluster.append(msg)
+ last_msg_date = msg.date
+ current_media_group_id = getattr(msg, "media_group_id", None)
+ continue
+
+ time_diff = (msg.date - last_msg_date).total_seconds()
+
+ msg_media_group_id = getattr(msg, "media_group_id", None)
+
+ if time_diff <= merge_seconds:
+ if current_media_group_id:
+ msg.media_group_id = current_media_group_id
+ elif msg_media_group_id:
+ current_media_group_id = msg_media_group_id
+ for m in cluster:
+ m.media_group_id = current_media_group_id
+ cluster.append(msg)
+ last_msg_date = msg.date
+ else:
+ if len(cluster) >= 2 and not current_media_group_id:
+ new_group_id = f"time_{min(m.date for m in cluster)}"
+ for m in cluster:
+ m.media_group_id = new_group_id
+ cluster = [msg]
+ last_msg_date = msg.date
+ current_media_group_id = msg_media_group_id
+
+ if len(cluster) >= 2 and not current_media_group_id:
+ new_group_id = f"time_{min(m.date for m in cluster)}"
+ for m in cluster:
+ m.media_group_id = new_group_id
+
+ return messages
+
async def create_messages_groups(messages):
"""
Process messages into formatted posts, handling media groups
@@ -96,31 +139,38 @@ async def render_messages_groups(messages_groups, post_parser, exclude_flags: st
'author': message_data['author'],
'flags': message_data['flags']
})
- else: # Multiple messages in group - need to merge
+ else: # Multiple messages in group - merge media, text and html body
processed_messages = [post_parser.process_message(msg) for msg in group]
- main_message = next( # Find main message (one with text)
+ main_message = next( # Determine main message for header/footer/title
(msg for msg in processed_messages if msg['text']),
- processed_messages[0] # fallback to first if none has text
+ processed_messages[0] # fallback if no message contains text
)
- # Collect all media sections
+ # Collect all media sections from all messages in the group
all_media = [msg['html']['media'] for msg in processed_messages if msg['html']['media']]
combined_media = '\n'.join(all_media)
-
- # Combine parts
+
+ # Merge text fields from all messages
+ all_texts = [msg['text'] for msg in processed_messages if msg['text']]
+ combined_text = '\n'.join(all_texts)
+
+ # Merge html body sections from all messages
+ all_html_bodies = [msg['html']['body'] for msg in processed_messages if msg['html']['body']]
+ combined_html_body = '\n'.join(all_html_bodies)
+
html_parts = [
f'