#!/usr/bin/env python3 """ Build a single self-contained HTML file from the source files. Usage: python3 build.py [output.html] python3 build.py --check build to a temp file and only verify What gets inlined: - config.js, i18n.js (plain ' % tag if old not in html: raise SystemExit('build.py: expected tag not found: ' + tag) # a literal inside an inline block would end it early return html.replace(old, '' % body.replace(']*\bsrc="([^"]+)"', html) leftovers += [re.search(r'\bhref="([^"]+)"', tag).group(1) for tag in re.findall(r']*>', html) if re.search(r'\bhref="[^"]+\.css"', tag)] if leftovers: raise SystemExit('build.py: not self-contained, still referencing: ' + ', '.join(sorted(set(leftovers)))) def main(): check = '--check' in sys.argv args = [a for a in sys.argv[1:] if not a.startswith('--')] out = args[0] if args else 'background-standalone.html' html = read('background.html') config_src = read('config.js') themes = parse_themes(config_src) # embedded data preamble (must run before the scene scripts) stars = json.loads(read('vendor/stars.json')) theme_css = {name: read(fname) for name, fname in themes.items()} moon_path = os.path.join(ROOT, 'vendor', 'moon.jpg') moon_uri = '' if os.path.exists(moon_path): with open(moon_path, 'rb') as f: moon_uri = 'data:image/jpeg;base64,' + base64.b64encode(f.read()).decode('ascii') embed = ( '\n' % (json.dumps(stars, separators=(',', ':')), moon_uri, json.dumps(theme_css)) ) # must come before config.js so the early theme loader sees the CSS anchor = '' if anchor not in html: raise SystemExit('build.py: anchor script tag not found in background.html') html = html.replace(anchor, embed + anchor, 1) for tag in INLINED_SCRIPTS: html = inline_script(html, tag, read(tag)) # themes are embedded in window.__inlineThemeCss, so the stylesheet link # is dropped completely (the theme loader guards on getElementById) rep_link = re.search(r'\n[ \t]*]*>', html) if not rep_link: raise SystemExit('build.py: theme-css link not found in background.html') html = html[:rep_link.start()] + '\n ' + \ html[rep_link.end():] verify(html) if check: with tempfile.NamedTemporaryFile('w', suffix='.html', delete=False) as f: f.write(html) tmp = f.name print('OK: self-contained (%d bytes, %d themes, %d stars, moon map %d KB)' % (len(html), len(themes), len(stars), len(moon_uri) // 1024)) os.unlink(tmp) return with open(os.path.join(ROOT, out), 'w', encoding='utf-8') as f: f.write(html) print('Wrote %s (%d bytes)' % (out, len(html))) print('Inlined: %s, stars.json (%d entries), moon.jpg (%d KB), themes: %s' % (', '.join(INLINED_SCRIPTS), len(stars), len(moon_uri) // 1024, ', '.join(sorted(themes)))) if __name__ == '__main__': main()