This commit is contained in:
@@ -7,6 +7,7 @@ import io
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
import time
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import streamlit as st
|
import streamlit as st
|
||||||
@@ -56,6 +57,39 @@ def read_csv_preview(csv_bytes: bytes, limit: int = 200) -> list[dict[str, str]]
|
|||||||
return rows
|
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:
|
def render_sitemap_tab() -> None:
|
||||||
st.title("Sitemap Generator")
|
st.title("Sitemap Generator")
|
||||||
st.caption("Crawl a site, export a sitemap CSV, and keep resume data inside the container data volume.")
|
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:
|
else:
|
||||||
safe_name = sanitize_job_name(job_name)
|
safe_name = sanitize_job_name(job_name)
|
||||||
output_path = SITEMAP_OUTPUT_DIR / f"{safe_name}.csv"
|
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:
|
try:
|
||||||
with st.spinner("Running sitemap crawl..."):
|
with st.spinner("Running sitemap crawl..."):
|
||||||
@@ -118,7 +154,9 @@ def render_sitemap_tab() -> None:
|
|||||||
resume=resume_existing,
|
resume=resume_existing,
|
||||||
fresh=start_fresh,
|
fresh=start_fresh,
|
||||||
)
|
)
|
||||||
|
captured_stdout.flush()
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
|
captured_stdout.flush()
|
||||||
st.error(str(exc))
|
st.error(str(exc))
|
||||||
else:
|
else:
|
||||||
st.session_state["sitemap_result"] = {
|
st.session_state["sitemap_result"] = {
|
||||||
@@ -206,7 +244,7 @@ def render_sitemap_tab() -> None:
|
|||||||
|
|
||||||
crawl_output = (result_data.get("stdout") or "").strip()
|
crawl_output = (result_data.get("stdout") or "").strip()
|
||||||
if crawl_output:
|
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():
|
if log_path.exists():
|
||||||
log_text = log_path.read_text(encoding="utf-8", errors="replace")
|
log_text = log_path.read_text(encoding="utf-8", errors="replace")
|
||||||
|
|||||||
Reference in New Issue
Block a user