No history yet at {path} - the checker workflows populate this after their first run.
"""
# pylint: enable=line-too-long
def build_cards(overall_counts):
"""Return the row of big per-state count cards at the top of the page."""
return "".join(
f'
Channel Signal — {alive_pct_overall:.0f}% on air
{total_channels} channels · {len(by_list)} lists{recovered_subline} · last swept {escape(last_checked)} · page built {escape(generated_at)}
{cards}
Alive share, over time
{svg_trend(trend)}
By list
{legend_html()}
| List | Channels | Alive | Signal |
{"".join(list_rows)}
Flagged Invalid, answering again
Channels sitting on an [x] row that answered like a live stream when a workflow last ran check_channels.py with --invalid or --include-invalid. Not proof the source is back for good - a single good answer can be a flaky CDN having a moment, not a restored channel - so this is a shortlist to look at by hand, not something to auto-restore.
| List | Channel | State | URL | Last checked |
{"".join(recovered_rows) or '| none right now |
'}
"""
# pylint: enable=line-too-long
def main():
"""Generate the dashboard from the command-line-given (or default) history path."""
parser = argparse.ArgumentParser(
description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter,
)
parser.add_argument("--history", default=DEFAULT_HISTORY, help="path to history.jsonl")
parser.add_argument("--out", default=DEFAULT_OUT, help="path to write the dashboard HTML")
args = parser.parse_args()
generated_at = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
html = render(args.history, generated_at)
os.makedirs(os.path.dirname(args.out), exist_ok=True)
with open(args.out, "w", encoding="utf-8") as handle:
handle.write(html)
print(f"Wrote {args.out}")
if __name__ == "__main__":
main()