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)