clone

every nostr nip as a chapter of an illustrated, early-2000s printed game manual

main
nip.guide / tools / build_nip_index.py
build_nip_index.py 2.2K
1"""Build site/assets/nip-index.json — the structured index consumed by webmcp.js.23Sources: manifest.json (status/tags/dates) + the built HTML pages (category,4meta description, section anchors, kinds from the cartridge spec card).5Re-run after adding or editing any page: python3 tools/build_nip_index.py6"""7import html8import json9import os10import re1112ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))13SITE = os.path.join(ROOT, 'site')141516def text_of(fragment):17 return html.unescape(re.sub(r'<[^>]+>', '', fragment)).strip()181920def extract(page_path):21 t = open(page_path, encoding='utf-8').read()22 out = {}23 m = re.search(r'<meta name="description" content="([^"]*)"', t)24 out['summary'] = html.unescape(m.group(1)) if m else None25 m = re.search(r'class="booklet-note">Chapter [0-9A-F]{2} - ([^<]+)<', t)26 out['category'] = m.group(1).strip() if m else None27 out['sections'] = [28 {'anchor': sid, 'title': text_of(body)}29 for sid, body in re.findall(r'<h2 class="bar" id="([^"]+)"[^>]*>(.*?)</h2>', t, re.S)30 ]31 # Kind numbers from the cartridge "Kind(s)" row, if present.32 m = re.search(r'<dt>Kinds?[^<]*</dt>\s*<dd>(.*?)</dd>', t, re.S | re.I)33 out['kinds'] = sorted({int(k) for k in re.findall(r'\b(\d{1,5})\b', text_of(m.group(1)))}) if m else []34 return out353637def main():38 manifest = json.load(open(os.path.join(ROOT, 'manifest.json')))39 entries = []40 for i, e in enumerate(manifest):41 low = e['num'].lower()42 page = os.path.join(SITE, 'nips', f'{low}.html')43 rec = {44 'nip': e['num'],45 'title': e['title'],46 'status': e['status'],47 'status_note': e['note'],48 'tags': e['tags'],49 'created': e['created'],50 'updated': e['updated'],51 'url': f'nips/{low}.html',52 'prev': manifest[i - 1]['num'] if i > 0 else None,53 'next': manifest[i + 1]['num'] if i < len(manifest) - 1 else None,54 }55 rec.update(extract(page))56 entries.append(rec)57 out = os.path.join(SITE, 'assets', 'nip-index.json')58 json.dump(entries, open(out, 'w'), separators=(',', ':'))59 print(f'{out}: {len(entries)} entries, {os.path.getsize(out)} bytes')606162if __name__ == '__main__':63 main()