69 lines
1.7 KiB
Python
69 lines
1.7 KiB
Python
from datetime import timedelta
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
from jinja2 import Environment, FileSystemLoader, select_autoescape
|
|
|
|
BASE = Path(__file__).resolve().parent.parent
|
|
|
|
|
|
def humanize(value: float | str | None) -> str:
|
|
if value is None:
|
|
return "—"
|
|
n = float(value)
|
|
for unit in ("B", "KiB", "MiB", "GiB", "TiB"):
|
|
if abs(n) < 1024 or unit == "TiB":
|
|
if unit == "B":
|
|
return f"{int(n)} B"
|
|
return f"{n:.1f} {unit}"
|
|
n /= 1024
|
|
return f"{n:.1f} TiB"
|
|
|
|
|
|
def rate(value: float | str | None) -> str:
|
|
if value is None:
|
|
return "—"
|
|
n = float(value)
|
|
for unit in ("B/s", "KiB/s", "MiB/s", "GiB/s"):
|
|
if abs(n) < 1024 or unit == "GiB/s":
|
|
if unit == "B/s":
|
|
return f"{int(n)} B/s"
|
|
return f"{n:.1f} {unit}"
|
|
n /= 1024
|
|
return f"{n:.1f} GiB/s"
|
|
|
|
|
|
def uptime_str(seconds: float | None) -> str:
|
|
if seconds is None:
|
|
return "—"
|
|
td = timedelta(seconds=int(seconds))
|
|
days, rem = divmod(td.seconds, 86400)
|
|
hours, rem = divmod(rem, 3600)
|
|
minutes = rem // 60
|
|
parts: list[str] = []
|
|
if days:
|
|
parts.append(f"{days}d")
|
|
if days or hours:
|
|
parts.append(f"{hours}h")
|
|
parts.append(f"{minutes}m")
|
|
return " ".join(parts)
|
|
|
|
|
|
def pct(value: float | None) -> str:
|
|
if value is None:
|
|
return "—"
|
|
return f"{value:.0f}%"
|
|
|
|
|
|
env = Environment(
|
|
loader=FileSystemLoader(BASE / "templates"),
|
|
autoescape=select_autoescape(("html", "j2")),
|
|
)
|
|
env.filters["humanize"] = humanize
|
|
env.filters["rate"] = rate
|
|
env.filters["uptime"] = uptime_str
|
|
env.filters["pct"] = pct
|
|
|
|
|
|
def render(name: str, **kwargs: Any) -> str:
|
|
return env.get_template(name).render(**kwargs)
|