fix(liveuamap): preserve safe marker and wrapper semantics

This commit is contained in:
Shadowbroker
2026-08-18 16:08:32 -06:00
parent d3a2b55fed
commit 6990fc1961
4 changed files with 57 additions and 14 deletions
+9 -8
View File
@@ -113,14 +113,9 @@ def _collect(
out.append(marker)
return
# Common wrapper shapes returned by APIs or page-side serialization.
for key in _WRAPPER_KEYS:
if key in value and isinstance(value[key], (dict, list, str)):
_collect(value[key], out, depth=depth + 1, inherited_id=None)
return
# A direct marker is accepted even if coordinates are absent here; the
# provider formatter performs the final coordinate/range validation.
# Coordinate-bearing objects are markers even if they also contain a field
# named `data`/`events`. Check them before generic wrapper traversal so a
# legitimate marker cannot be swallowed by wrapper heuristics.
if _looks_like_marker(value):
marker = dict(value)
if inherited_id and not marker.get("id"):
@@ -128,6 +123,12 @@ def _collect(
out.append(marker)
return
# Common wrapper shapes returned by APIs or page-side serialization.
for key in _WRAPPER_KEYS:
if key in value and isinstance(value[key], (dict, list, str)):
_collect(value[key], out, depth=depth + 1, inherited_id=None)
return
# Some versions expose a dictionary keyed by marker ID. Traverse mapping
# values while preserving the key as a fallback identifier.
traversable = [
+24 -6
View File
@@ -274,9 +274,9 @@ def _fetch_liveuamap_browser() -> list[dict[str, Any]]:
page.wait_for_timeout(5_000)
html = page.content()
# Try the useful payload before classifying the page as
# a challenge. Normal pages may legitimately load a
# Turnstile asset; valid marker data should win.
# Try useful marker state before classifying the page as
# a challenge. Normal pages may load Turnstile assets;
# valid marker data should win over that heuristic.
payload = _read_page_payload(page, html)
if payload is None:
if _looks_like_challenge(html):
@@ -341,6 +341,26 @@ def _fetch_liveuamap_browser() -> list[dict[str, Any]]:
return []
def _normalize_marker_link(raw: Any, base_url: str) -> str:
"""Resolve only HTTP(S) marker links; reject active/non-web URL schemes."""
text = _as_text(raw).strip()
if not text:
return ""
try:
parsed = urlparse(text)
except ValueError:
return ""
if parsed.scheme:
return text if parsed.scheme.lower() in {"http", "https"} else ""
try:
resolved = urljoin(base_url.rstrip("/") + "/", text)
resolved_scheme = urlparse(resolved).scheme.lower()
except ValueError:
return ""
return resolved if resolved_scheme in {"http", "https"} else ""
def _format_markers(
candidates: list[dict[str, Any]],
*,
@@ -374,9 +394,7 @@ def _format_markers(
image = _as_text(marker.get("img") or marker.get("image") or marker.get("photo") or "").strip()
source = _as_text(marker.get("source") or marker.get("src") or "").strip()
event_time = marker.get("time", marker.get("t", marker.get("timestamp", "")))
link = _as_text(marker.get("link") or marker.get("url") or "").strip()
if link and not urlparse(link).scheme:
link = urljoin(base_url.rstrip("/") + "/", link.lstrip("/"))
link = _normalize_marker_link(marker.get("link") or marker.get("url") or "", base_url)
raw_id = marker.get("id", marker.get("event_id"))
marker_id = _as_text(raw_id).strip() if raw_id is not None else ""