scripts: renderer now handles ANSI colours and masks serials/IPs
This commit is contained in:
@@ -9,6 +9,37 @@ import asyncio, html, io, re
|
||||
from PIL import Image
|
||||
from playwright.async_api import async_playwright
|
||||
|
||||
|
||||
ANSI_COL={30:'#6e7681',31:'#ff5c6c',32:'#3ddc84',33:'#ffb454',34:'#58a6ff',35:'#d2a8ff',36:'#7fdbff',37:'#e6edf3',
|
||||
90:'#8b949e',91:'#ff7b86',92:'#56f09f',93:'#ffd479',94:'#79c0ff',95:'#e2c5ff',96:'#a5f3ff',97:'#ffffff'}
|
||||
def ansi_to_html(line):
|
||||
"""Convert ANSI SGR colour/bold sequences to <span> tags (everything else is stripped)."""
|
||||
out=[]; open_spans=0; pos=0
|
||||
for m in re.finditer(r'\x1b\[([0-9;]*)m|\x1b\[[0-9;?]*[A-Za-z]',line):
|
||||
out.append(html.escape(line[pos:m.start()])); pos=m.end()
|
||||
if m.group(1) is None: continue
|
||||
codes=[int(c) if c else 0 for c in m.group(1).split(';')]
|
||||
for c in codes:
|
||||
if c==0: out.append('</span>'*open_spans); open_spans=0
|
||||
elif c==1: out.append('<span style="font-weight:700">'); open_spans+=1
|
||||
elif c in ANSI_COL: out.append(f'<span style="color:{ANSI_COL[c]}">'); open_spans+=1
|
||||
out.append(html.escape(line[pos:])); out.append('</span>'*open_spans)
|
||||
return ''.join(out)
|
||||
|
||||
def mask(lines, serial_cols=True, ips=True):
|
||||
"""Sanitize output before publishing: hide drive serials and private IPs."""
|
||||
res=[]
|
||||
for l in lines:
|
||||
if ips: l=re.sub(r'\b(10|192\.168|172\.(1[6-9]|2\d|3[01]))\.(\d+)\.(\d+)\.(\d+)\b','x.x.x.x',l) if not l.startswith('x') else l
|
||||
if serial_cols and re.match(r'^(\d+|m2-\d)\s+/dev/',l):
|
||||
parts=re.split(r'(\s{2,})',l)
|
||||
# fields alternate with whitespace; serial is the 8th field (index 14 in the split list)
|
||||
if len(parts)>14:
|
||||
v=parts[14]; parts[14]=v[:2]+'\u2022'*max(0,len(v)-2)
|
||||
l=''.join(parts)
|
||||
res.append(l)
|
||||
return res
|
||||
|
||||
DEFAULT_RULES=[(r'✓|\bOK\b|\bNORMAL\b|\bPASS(ED)?\b|HEALTH_OK','#3ddc84'),(r'⚠️?|\bWARN(ING)?\b|HEALTH_WARN|\[WARN\]','#ffb454'),(r'\bERROR\b|\bFAIL(ED)?\b|\bCRITICAL\b|✗|HEALTH_ERR','#ff5c6c'),(r'^=+.*=+$|^┏.*|^┃.*|^┣.*|^┗.*','#7fdbff')]
|
||||
|
||||
PAGE='''<!doctype html><meta charset=utf-8>
|
||||
@@ -25,6 +56,7 @@ PAGE='''<!doctype html><meta charset=utf-8>
|
||||
<div id=win><div id=bar><span class=dot style=background:#ff5f56></span><span class=dot style=background:#ffbd2e></span><span class=dot style=background:#27c93f></span><span id=ttl>%(t)s</span></div><pre id=t></pre></div>'''
|
||||
|
||||
def colorize(line, rules):
|
||||
if '\x1b[' in line: return ansi_to_html(line)
|
||||
s=html.escape(line)
|
||||
for pat,col in rules:
|
||||
if pat.startswith('^'):
|
||||
|
||||
Reference in New Issue
Block a user