Add URL compression for mail content viewer

This commit is contained in:
Bendt
2025-12-19 16:15:08 -05:00
parent 36a1ea7c47
commit 8233829621
2 changed files with 102 additions and 3 deletions

View File

@@ -82,6 +82,10 @@ class ContentDisplayConfig(BaseModel):
# View mode: "markdown" for pretty rendering, "html" for raw/plain display
default_view_mode: Literal["markdown", "html"] = "markdown"
# URL compression: shorten long URLs for better readability
compress_urls: bool = True
max_url_length: int = 50 # Maximum length before URL is compressed
class LinkPanelConfig(BaseModel):
"""Configuration for the link panel."""

View File

@@ -6,10 +6,15 @@ from textual.widgets import Static, Markdown, Label
from textual.reactive import reactive
from src.services.himalaya import client as himalaya_client
from src.mail.config import get_config
from src.mail.screens.LinkPanel import extract_links_from_content, LinkItem
from src.mail.screens.LinkPanel import (
extract_links_from_content,
LinkItem,
LinkItem as LinkItemClass,
)
import logging
from datetime import datetime
from typing import Literal, List
from typing import Literal, List, Dict
from urllib.parse import urlparse
import re
import os
import sys
@@ -18,6 +23,88 @@ import sys
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
def compress_urls_in_content(content: str, max_url_len: int = 50) -> str:
"""Compress long URLs in markdown/text content for better readability.
Replaces long URLs with shortened versions using the same algorithm
as LinkPanel._shorten_url. Preserves markdown link syntax.
Args:
content: The markdown/text content to process
max_url_len: Maximum length for displayed URLs (default 50)
Returns:
Content with compressed URLs
"""
# Pattern for markdown links: [text](url)
def replace_md_link(match):
anchor_text = match.group(1)
url = match.group(2)
# Don't compress if URL is already short
if len(url) <= max_url_len:
return match.group(0)
# Use LinkItem's shortening algorithm
short_url = LinkItemClass._shorten_url(
url,
urlparse(url).netloc.replace("www.", ""),
urlparse(url).path,
max_url_len,
)
# Keep original anchor text, but if it's the same as URL, use short version
if anchor_text == url or anchor_text.startswith("http"):
return f"[🔗 {short_url}]({url})"
else:
return match.group(0) # Keep original if anchor text is meaningful
# Pattern for bare URLs (not inside markdown links)
def replace_bare_url(match):
url = match.group(0)
# Don't compress if URL is already short
if len(url) <= max_url_len:
return url
parsed = urlparse(url)
short_url = LinkItemClass._shorten_url(
url, parsed.netloc.replace("www.", ""), parsed.path, max_url_len
)
# Return as markdown link with icon
return f"[🔗 {short_url}]({url})"
# First, process markdown links
md_link_pattern = r"\[([^\]]+)\]\((https?://[^)]+)\)"
content = re.sub(md_link_pattern, replace_md_link, content)
# Then process bare URLs that aren't already in markdown links
# This regex matches URLs not preceded by ]( which would indicate markdown link
bare_url_pattern = r'(?<!\]\()https?://[^\s<>"\'\)]+[^\s<>"\'\.\,\)\]]'
# Use a more careful approach to avoid double-processing
# Split content, process bare URLs, rejoin
result = []
last_end = 0
for match in re.finditer(bare_url_pattern, content):
# Check if this URL is inside a markdown link (preceded by "](")
prefix_start = max(0, match.start() - 2)
prefix = content[prefix_start : match.start()]
if prefix.endswith("]("):
continue # Skip URLs that are already markdown link targets
result.append(content[last_end : match.start()])
result.append(replace_bare_url(match))
last_end = match.end()
result.append(content[last_end:])
return "".join(result)
class EnvelopeHeader(Vertical):
def __init__(self, **kwargs):
super().__init__(**kwargs)
@@ -192,10 +279,18 @@ class ContentContainer(ScrollableContainer):
# Store the raw content for link extraction
self.current_content = content
# Get URL compression settings from config
config = get_config()
compress_urls = config.content_display.compress_urls
max_url_len = config.content_display.max_url_length
try:
if self.current_mode == "markdown":
# For markdown mode, use the Markdown widget
self.content.update(content)
display_content = content
if compress_urls:
display_content = compress_urls_in_content(content, max_url_len)
self.content.update(display_content)
else:
# For HTML mode, use the Static widget with markup
# First, try to extract the body content if it's HTML