fetch-fonts.py (2426B)
1 #!/usr/bin/env python3 2 """Download latin-subset woff2 for the 3 site fonts from Google Fonts. 3 Best-effort: on any failure the CSS fallback stacks take over.""" 4 import os, re, sys, urllib.request 5 6 UA = ("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 " 7 "(KHTML, like Gecko) Chrome/120.0 Safari/537.36") 8 OUT = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "src", "fonts") 9 OUT = os.path.normpath(OUT) 10 os.makedirs(OUT, exist_ok=True) 11 12 JOBS = [ 13 ("Chakra+Petch", 600, "chakra-petch-600.woff2"), 14 ("Chakra+Petch", 700, "chakra-petch-700.woff2"), 15 ("Inter", 400, "inter-400.woff2"), 16 ("Inter", 500, "inter-500.woff2"), 17 ("Inter", 600, "inter-600.woff2"), 18 ("JetBrains+Mono", 400, "jetbrains-mono-400.woff2"), 19 ("JetBrains+Mono", 600, "jetbrains-mono-600.woff2"), 20 ] 21 22 def fetch(url, headers=None): 23 req = urllib.request.Request(url, headers=headers or {"User-Agent": UA}) 24 with urllib.request.urlopen(req, timeout=25) as r: 25 return r.read() 26 27 def latin_url_from_css(css): 28 # Split into @font-face blocks; pick the one whose unicode-range covers basic latin. 29 blocks = re.findall(r"@font-face\s*{[^}]*}", css) 30 best = None 31 for b in blocks: 32 m = re.search(r"url\((https://[^)]+\.woff2)\)", b) 33 if not m: 34 continue 35 ur = re.search(r"unicode-range:\s*([^;]+);", b) 36 rng = ur.group(1) if ur else "" 37 if "U+0000" in rng or "U+0041" in rng or "U+00" in rng and best is None: 38 best = m.group(1) 39 if "U+0000" in rng: 40 return m.group(1) 41 if best: 42 return best 43 # fallback: last woff2 in the whole css (latin is usually last) 44 urls = re.findall(r"url\((https://[^)]+\.woff2)\)", css) 45 return urls[-1] if urls else None 46 47 ok = 0 48 for fam, wght, fname in JOBS: 49 try: 50 css = fetch(f"https://fonts.googleapis.com/css2?family={fam}:wght@{wght}&display=swap").decode("utf-8", "replace") 51 url = latin_url_from_css(css) 52 if not url: 53 print(f" no url for {fam} {wght}", file=sys.stderr); continue 54 data = fetch(url) 55 with open(os.path.join(OUT, fname), "wb") as f: 56 f.write(data) 57 print(f" ok {fname} ({len(data)} bytes)") 58 ok += 1 59 except Exception as e: 60 print(f" FAIL {fam} {wght}: {e}", file=sys.stderr) 61 62 print(f"downloaded {ok}/{len(JOBS)} fonts -> {OUT}") 63 sys.exit(0 if ok else 1)