Files
ncmr-songs/wip/274/274-transect-build.py
T
mikkeli 3a8d49641a 274: move the song and its working files into wip/274/
Eleven files were cluttering wip/ alongside an unrelated draft. They now
sit together in their own directory.

Checked against the pipeline in novoyuuparosk-auto-wiki before moving:

- discovery is source_dir.rglob("*.md"), so nested directories are found
- the skip test is `"wip" in rel.parts`, which still excludes wip/274/
  while the song is in progress
- relative links resolve as (path.parent / rel_path), i.e. against the
  file's own directory, so the three docs keep linking to each other
- the lrc field resolves as abs_path.parent / lrc_rel, so 274.lrc must
  and does sit beside 274.md

Both scripts locate their inputs from __file__, so they needed no change;
verified after the move that --check is clean and the page rebuilds all
132 entries.

Non-Markdown files are never read by the pipeline at all.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S6MpcBisZYhX45oDGRRJoz
2026-09-15 17:10:06 +09:00

76 lines
3.0 KiB
Python
Executable File

#!/usr/bin/env python3
"""Rebuild the data payload inside 274-transect.html from 274-lookup.md.
The HTML is self-contained: it carries its data in a <script id="data"> block so
it opens straight from disk. This script re-reads the roster table out of
274-lookup.md, joins the route line and district bands, and writes the payload back
into the HTML in place. The page's markup, CSS and JS are left untouched.
python3 274-transect-build.py
Inputs : 274-lookup.md (roster, source of truth), 274-route.json, 274-districts.json
Output : 274-transect.html (data block replaced)
"""
import io, json, os, re, sys
HERE = os.path.dirname(os.path.abspath(__file__))
p = lambda n: os.path.join(HERE, n)
CHOME = re.compile(r'[一二三四五六七八九十百]+丁目$')
def roster(path):
hdr, rows = None, []
for line in io.open(path, encoding='utf-8'):
if line.startswith('| km | Name |'):
hdr = [c.strip() for c in line.strip().strip('|').split('|')]
continue
if hdr and line.startswith('| ') and line.count('|') >= 13:
c = [x.strip() for x in line.strip().strip('|').split('|')]
if re.match(r'^\d+\.\d+$', c[0]):
rows.append(dict(zip(hdr, c)))
if not rows:
sys.exit('no roster rows found in %s' % path)
return rows
def oaza_of(address, cities):
a = address or ''
for c in cities:
if a.startswith(c):
a = a[len(c):]
break
return CHOME.sub('', a).strip() or '—'
def main():
bands = json.load(io.open(p('274-districts.json'), encoding='utf-8'))
route = json.load(io.open(p('274-route.json'), encoding='utf-8'))
cities = sorted({b['city'] for b in bands if b.get('city')}, key=len, reverse=True)
items = []
for r in roster(p('274-lookup.md')):
items.append(dict(
km=float(r['km']), name=r['Name'], obj=r['Object'],
kana=r.get('Kana', ''), romaji=r.get('Romaji', ''), kind=r['Kind'],
off=float(r['Off (m)'] or 0), lat=float(r['Lat']), lon=float(r['Lon']),
L=r.get('Length', ''), y=r.get('Built', ''), g=r.get('Grade', ''),
addr=r.get('Address', ''), addrk=r.get('Address kana', ''),
oaza=oaza_of(r.get('Address', ''), cities),
city=next((c for c in cities if (r.get('Address') or '').startswith(c)), '')))
items.sort(key=lambda o: (o['km'], o['obj']))
payload = json.dumps(dict(route=route, items=items, bands=bands),
ensure_ascii=False, separators=(',', ':'))
html = io.open(p('274-transect.html'), encoding='utf-8').read()
new, n = re.subn(r'(<script id="data" type="application/json">).*?(</script>)',
lambda m: m.group(1) + payload + m.group(2), html, count=1, flags=re.S)
if not n:
sys.exit('data block not found in 274-transect.html')
io.open(p('274-transect.html'), 'w', encoding='utf-8').write(new)
print('%d entries, %d district bands, %d route points -> 274-transect.html'
% (len(items), len(bands), len(route)))
if __name__ == '__main__':
main()