From b4a74a32f4f4ba5ac727b342c267362327392f0d Mon Sep 17 00:00:00 2001 From: thePR0M3TH3AN <53631862+PR0M3TH3AN@users.noreply.github.com> Date: Mon, 16 Mar 2026 11:39:26 -0400 Subject: [PATCH] fix(cli): convert newlines to
in static HTML for Tor compatibility User-entered line breaks were rendering as literal \n\n in the content box because the static HTML injection didn't convert newlines to
tags. Since Tor Browser disables JS, the fix must be server-side. Co-Authored-By: Claude Opus 4.6 --- voxvera/cli.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/voxvera/cli.py b/voxvera/cli.py index 0b256b3..39637a1 100644 --- a/voxvera/cli.py +++ b/voxvera/cli.py @@ -530,7 +530,7 @@ def build_assets( for field in landing_fields: # Use data from config if available, otherwise use localized default value = data.get(field, landing_defaults.get(field, "")) - + # If the value from config is just the master default, # and we are NOT in English, use the localized default instead. if data.get("lang", "en") != "en": @@ -539,6 +539,8 @@ def build_assets( # Support Markdown-style redaction ~~text~~ val_str = re.sub(r"~~(.*?)~~", r'\1', str(value)) + # Convert newlines to
so line breaks render in static HTML (no JS on Tor) + val_str = val_str.replace("\\n", "\n").replace("\n", "
") html = html.replace(f"{{{{t_landing_{field}}}}}", val_str) # 2. Statically replace config placeholders {{key}} @@ -546,6 +548,8 @@ def build_assets( val_str = str(value) # Support Markdown-style redaction ~~text~~ for user fields too val_str = re.sub(r"~~(.*?)~~", r'\1', val_str) + # Convert newlines to
so line breaks render in static HTML (no JS on Tor) + val_str = val_str.replace("\\n", "\n").replace("\n", "
") html = html.replace(f"{{{{{key}}}}}", val_str) # Handle optional file attachment logic @@ -1067,7 +1071,7 @@ def build_site(): for field in landing_fields: # Use data from config if available, otherwise use localized default value = data.get(field, landing_defaults.get(field, "")) - + # If the value from config is just the master default, # and we are NOT in English, use the localized default instead. if current_lang != "en": @@ -1076,6 +1080,8 @@ def build_site(): # Support Markdown-style redaction ~~text~~ val_str = re.sub(r"~~(.*?)~~", r'\1', str(value)) + # Convert newlines to
so line breaks render in static HTML (no JS on Tor) + val_str = val_str.replace("\\n", "\n").replace("\n", "
") html = html.replace(f"{{{{t_landing_{field}}}}}", val_str) # 3. Update relative path for download @@ -1083,7 +1089,9 @@ def build_site(): # 4. Inject site-specific config data (handles any remaining {{key}} placeholders) for key, value in data.items(): - html = html.replace(f"{{{{{key}}}}}", str(value)) + val_str = str(value) + val_str = val_str.replace("\\n", "\n").replace("\n", "
") + html = html.replace(f"{{{{{key}}}}}", val_str) os.makedirs(dest_site, exist_ok=True) with open(dest_site / "index.html", "w") as fh: