# retoor <retoor@molodetz.nl>
import html
import json
import re
from datetime import datetime, timezone
from decimal import Decimal
def strip_html(text: str) -> str:
if not text:
return ""
text = re.sub(r"<[^>]+>", " ", text)
text = html.unescape(text)
return re.sub(r"\s+", " ", text).strip()
_FLOAT_TOKEN = "@dpfloat@"
def plain_float(value: float) -> str:
if value != value or value in (float("inf"), float("-inf")):
return json.dumps(value)
return format(Decimal(repr(value)), "f")
def _mark_floats(node):
if isinstance(node, bool):
return node
if isinstance(node, float):
return f"{_FLOAT_TOKEN}{plain_float(node)}{_FLOAT_TOKEN}"
if isinstance(node, dict):
return {key: _mark_floats(value) for key, value in node.items()}
if isinstance(node, (list, tuple)):
return [_mark_floats(item) for item in node]
return node
def pretty_json(data, indent: int = 2) -> str:
text = json.dumps(
_mark_floats(data), indent=indent, ensure_ascii=False, default=str
)
return text.replace(f'"{_FLOAT_TOKEN}', "").replace(f'{_FLOAT_TOKEN}"', "")
def slugify(text: str) -> str:
text = text.lower().strip()
text = re.sub(r"[^a-z0-9-]", "-", text)
text = re.sub(r"-+", "-", text)
return text.strip("-")
def generate_uid() -> str:
import uuid_utils
return str(uuid_utils.uuid7())
def make_combined_slug(text: str, uid: str) -> str:
short_uid = uid.replace("-", "")[-12:]
slug_part = slugify(text)
if not slug_part:
return short_uid
return f"{short_uid}-{slug_part}"
def time_ago(dt_str: str) -> str:
dt = datetime.fromisoformat(dt_str)
if dt.tzinfo is None:
dt = dt.replace(tzinfo=timezone.utc)
now = datetime.now(timezone.utc)
diff = now - dt
days = diff.days
if days > 30:
return dt.strftime("%d/%m/%Y")
if days > 0:
return f"{days}d ago"
hours = diff.seconds // 3600
if hours > 0:
return f"{hours}h ago"
minutes = diff.seconds // 60
if minutes > 0:
return f"{minutes}m ago"
return "just now"
def extract_mentions(content: str) -> list[str]:
if not content:
return []
return re.findall(r"(?:^|[\s(])@([a-zA-Z0-9_-]+)", content)
def format_date(dt_str: str, include_time: bool = False) -> str:
if not dt_str:
return ""
try:
dt = datetime.fromisoformat(dt_str)
if include_time:
return dt.strftime("%d/%m/%Y %H:%M")
return dt.strftime("%d/%m/%Y")
except (ValueError, TypeError):
return dt_str