This commit is contained in:
@@ -7,6 +7,7 @@ import io
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
import streamlit as st
|
||||
@@ -56,6 +57,39 @@ def read_csv_preview(csv_bytes: bytes, limit: int = 200) -> list[dict[str, str]]
|
||||
return rows
|
||||
|
||||
|
||||
class StreamlitOutputBuffer(io.TextIOBase):
|
||||
def __init__(self, placeholder, *, height: int = 220, throttle_seconds: float = 0.2) -> None:
|
||||
self.placeholder = placeholder
|
||||
self.height = height
|
||||
self.throttle_seconds = throttle_seconds
|
||||
self.parts: list[str] = []
|
||||
self.last_render = 0.0
|
||||
|
||||
def write(self, text: str) -> int:
|
||||
if not text:
|
||||
return 0
|
||||
self.parts.append(text)
|
||||
now = time.monotonic()
|
||||
if "\n" in text or (now - self.last_render) >= self.throttle_seconds:
|
||||
self.render()
|
||||
return len(text)
|
||||
|
||||
def flush(self) -> None:
|
||||
self.render()
|
||||
|
||||
def render(self) -> None:
|
||||
self.last_render = time.monotonic()
|
||||
self.placeholder.text_area(
|
||||
"Scan Details",
|
||||
value="".join(self.parts),
|
||||
height=self.height,
|
||||
disabled=True,
|
||||
)
|
||||
|
||||
def getvalue(self) -> str:
|
||||
return "".join(self.parts)
|
||||
|
||||
|
||||
def render_sitemap_tab() -> None:
|
||||
st.title("Sitemap Generator")
|
||||
st.caption("Crawl a site, export a sitemap CSV, and keep resume data inside the container data volume.")
|
||||
@@ -100,7 +134,9 @@ def render_sitemap_tab() -> None:
|
||||
else:
|
||||
safe_name = sanitize_job_name(job_name)
|
||||
output_path = SITEMAP_OUTPUT_DIR / f"{safe_name}.csv"
|
||||
captured_stdout = io.StringIO()
|
||||
output_placeholder = st.empty()
|
||||
captured_stdout = StreamlitOutputBuffer(output_placeholder)
|
||||
captured_stdout.render()
|
||||
|
||||
try:
|
||||
with st.spinner("Running sitemap crawl..."):
|
||||
@@ -118,7 +154,9 @@ def render_sitemap_tab() -> None:
|
||||
resume=resume_existing,
|
||||
fresh=start_fresh,
|
||||
)
|
||||
captured_stdout.flush()
|
||||
except Exception as exc:
|
||||
captured_stdout.flush()
|
||||
st.error(str(exc))
|
||||
else:
|
||||
st.session_state["sitemap_result"] = {
|
||||
@@ -206,7 +244,7 @@ def render_sitemap_tab() -> None:
|
||||
|
||||
crawl_output = (result_data.get("stdout") or "").strip()
|
||||
if crawl_output:
|
||||
st.text_area("Crawler Output", value=crawl_output, height=220, disabled=True)
|
||||
st.text_area("Scan Details", value=crawl_output, height=220, disabled=True)
|
||||
|
||||
if log_path.exists():
|
||||
log_text = log_path.read_text(encoding="utf-8", errors="replace")
|
||||
|
||||
Reference in New Issue
Block a user