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 # View mode: "markdown" for pretty rendering, "html" for raw/plain display
default_view_mode: Literal["markdown", "html"] = "markdown" 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): class LinkPanelConfig(BaseModel):
"""Configuration for the link panel.""" """Configuration for the link panel."""

View File

@@ -6,10 +6,15 @@ from textual.widgets import Static, Markdown, Label
from textual.reactive import reactive from textual.reactive import reactive
from src.services.himalaya import client as himalaya_client from src.services.himalaya import client as himalaya_client
from src.mail.config import get_config 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 import logging
from datetime import datetime from datetime import datetime
from typing import Literal, List from typing import Literal, List, Dict
from urllib.parse import urlparse
import re import re
import os import os
import sys import sys
@@ -18,6 +23,88 @@ import sys
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) 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): class EnvelopeHeader(Vertical):
def __init__(self, **kwargs): def __init__(self, **kwargs):
super().__init__(**kwargs) super().__init__(**kwargs)
@@ -192,10 +279,18 @@ class ContentContainer(ScrollableContainer):
# Store the raw content for link extraction # Store the raw content for link extraction
self.current_content = content 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: try:
if self.current_mode == "markdown": if self.current_mode == "markdown":
# For markdown mode, use the Markdown widget # 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: else:
# For HTML mode, use the Static widget with markup # For HTML mode, use the Static widget with markup
# First, try to extract the body content if it's HTML # First, try to extract the body content if it's HTML