import copy import bs4 from bs4.element import NavigableString class PreparedMessage: allowed_tags = ( "b", "strong", "i", "em", "s", "strike", "del", "code", "pre", "a", "br", "p", ) def __init__(self, html: str) -> None: self._soup = bs4.BeautifulSoup(html, "html.parser") self._clean() def _clean(self) -> None: # Remove disallowed tags for tag in self._soup.find_all(True): if isinstance(tag, bs4.Tag) and tag.name not in self.allowed_tags: tag.unwrap() # Replace
with line breaks for br in self._soup.find_all("br"): br.replace_with(NavigableString("\n")) # Replace

with its content + line break for p in self._soup.find_all("p"): content = p.get_text() p.replace_with(NavigableString(f"{content}\n")) def to_whatsapp(self) -> str: soup = copy.deepcopy(self._soup) formatting = { ("b", "strong"): "*", ("i", "em"): "_", ("s", "strike", "del"): "~", ("code",): "`", ("pre",): "```", } for tags, symbol in formatting.items(): for tag in soup.find_all(tags): content = tag.get_text() if symbol == "```": replacement = f"{symbol}\n{content}\n{symbol}" else: replacement = f"{symbol}{content}{symbol}" tag.replace_with(NavigableString(replacement)) # Convert to "text (url)" only in WhatsApp for a in soup.find_all("a"): if not isinstance(a, bs4.Tag): continue text = a.get_text() href = a.get("href", "") if href and isinstance(href, str) and not href.startswith("javascript:"): replacement = href.strip() else: replacement = text a.replace_with(NavigableString(replacement)) text = soup.get_text() lines = [line.strip() for line in text.splitlines()] return "\n".join(line for line in lines if line) def to_sms(self) -> str: soup = copy.deepcopy(self._soup) # Remove all tags for tag in soup.find_all(True): tag.replace_with(NavigableString(tag.get_text())) text = soup.get_text() lines = [line.strip() for line in text.splitlines() if line.strip()] return "\n".join(lines)