Skip to content

Instantly share code, notes, and snippets.

@ilkka
Created June 13, 2026 16:29
Show Gist options
  • Select an option

  • Save ilkka/0d89c1ca7da0833186a52e6b8289db16 to your computer and use it in GitHub Desktop.

Select an option

Save ilkka/0d89c1ca7da0833186a52e6b8289db16 to your computer and use it in GitHub Desktop.
Python Nerd Font installer
#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.14"
# dependencies = ["httpx>=0.28.1"]
# ///
from pathlib import Path
from dataclasses import dataclass
import inspect
import logging
import httpx
import subprocess
# Add fonts here
FONTS = ["IBMPlexMono.tar.xz"]
FONTS_DIR = Path.home() / ".local" / "share" / "fonts" / "nfdl"
BASEURL = "https://api.github.com/repos/ryanoasis/nerd-fonts"
COMMON_HEADERS = {
"Accept": "application/vnd.github+json",
"X-GitHub-API-Version": "2026-03-10",
}
logging.basicConfig(level=logging.INFO)
log = logging.getLogger("nfdl")
@dataclass
class Asset:
name: str
browser_download_url: str
def name_without_suffixes(self) -> str:
return self.name.replace("".join(Path(self.name).suffixes), "")
@classmethod
def from_dict(cls, env):
"""Make an instance from a bag of things ignoring anything not actually in the dataclass def."""
return cls(
**{k: v for k, v in env.items() if k in inspect.signature(cls).parameters}
)
def get_font_download_urls(client: httpx.Client, fonts: list[str]) -> list[Asset]:
r = client.get(f"{BASEURL}/releases/latest", follow_redirects=True)
picked = []
assets = r.json()["assets"]
for font in fonts:
for asset in assets:
if asset["name"].startswith(font):
picked.append(Asset.from_dict(asset))
return picked
def download_font(font: Asset, target_dir: Path, client: httpx.Client) -> None:
fontname = font.name_without_suffixes()
fontdir = target_dir / fontname
if fontdir.exists():
log.info(f"{fontdir} exists, remove to re-download")
return
log.info(f"Installing {fontname} in {fontdir}")
fontdir.mkdir(parents=True, exist_ok=True)
with subprocess.Popen(
["tar", "-xJf", "-"], stdin=subprocess.PIPE, cwd=fontdir
) as tar:
with client.stream(
"GET", font.browser_download_url, follow_redirects=True
) as stream:
for data in stream.iter_bytes():
tar.stdin.write(data)
def rebuild_font_cache() -> None:
subprocess.run(["fc-cache"])
def main() -> None:
FONTS_DIR.mkdir(parents=True, exist_ok=True)
with httpx.Client(headers=COMMON_HEADERS) as client:
urls = get_font_download_urls(client, FONTS)
for font_url in urls:
download_font(font_url, FONTS_DIR, client)
rebuild_font_cache()
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment