6148dfd211
The tiles draw what Home Assistant reports (a new /api/states answers for the tiles on the page); the ··· menu gets Identify (the screen's own show_alert with flash), Copy layout from another screen, Export and Import as JSON; the Alerts page opens with Try it (/api/alerts/test, one screen or all); the library filters by room and hides what is placed, with lit icons for what is on; ⌘K searches screens, entities and actions; the Update badge lists what's new from the changelog (copied into the image) and a running update shows a progress bar with the ESPHome stage and the last log line. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
42 lines
1.4 KiB
Python
42 lines
1.4 KiB
Python
"""What's new for the Update badge (app 0.2.74): the CHANGELOG sections since a screen's firmware.
|
|
|
|
The Dockerfile copies CHANGELOG.md next to this file; a development checkout has it one folder up.
|
|
Each `## <app> (firmware <fw>)` section gives its bullet lines as plain text, newest first.
|
|
"""
|
|
import re
|
|
from pathlib import Path
|
|
|
|
HEADER = re.compile(r'^## (\d+\.\d+\.\d+) \(firmware (\d+\.\d+\.\d+)\)')
|
|
BOLD = re.compile(r'\*\*(.+?)\*\*')
|
|
CODE = re.compile(r'`([^`]*)`')
|
|
LINK = re.compile(r'\[([^\]]+)\]\([^)]+\)')
|
|
|
|
|
|
def load(path=None, limit=20):
|
|
"""[{app, firmware, lines}] for the latest sections; [] without a changelog."""
|
|
candidates = [Path(path)] if path else [Path(__file__).with_name('CHANGELOG.md'), Path(__file__).parent.parent / 'CHANGELOG.md']
|
|
for candidate in candidates:
|
|
if candidate.exists():
|
|
return parse(candidate.read_text(), limit)
|
|
return []
|
|
|
|
|
|
def parse(text, limit=20):
|
|
sections = []
|
|
for line in text.splitlines():
|
|
match = HEADER.match(line)
|
|
if match:
|
|
if len(sections) >= limit:
|
|
break
|
|
sections.append({'app': match.group(1), 'firmware': match.group(2), 'lines': []})
|
|
elif sections and line.startswith('- '):
|
|
sections[-1]['lines'].append(plain(line[2:]))
|
|
return sections
|
|
|
|
|
|
def plain(markdown):
|
|
text = BOLD.sub(r'\1', markdown)
|
|
text = CODE.sub(r'\1', text)
|
|
text = LINK.sub(r'\1', text)
|
|
return text.strip()
|