diff options
| author | Christian Cleberg <[email protected]> | 2026-01-07 20:18:27 -0600 |
|---|---|---|
| committer | Christian Cleberg <[email protected]> | 2026-01-07 20:18:27 -0600 |
| commit | 01bd81cf3f943b4aff4e79f93910ab764a873548 (patch) | |
| tree | 1890dfbf76a205a4e3cb47f29aa0528468883b5d /hn.py | |
| parent | 2fd901458c8da24fd0e28d4b07a99d3f4876316f (diff) | |
| download | hn-01bd81cf3f943b4aff4e79f93910ab764a873548.tar.gz hn-01bd81cf3f943b4aff4e79f93910ab764a873548.tar.bz2 hn-01bd81cf3f943b4aff4e79f93910ab764a873548.zip | |
MASSIVE UPDATE TO PYTHON STATIC SERVICE
Diffstat (limited to 'hn.py')
| -rw-r--r-- | hn.py | 109 |
1 files changed, 109 insertions, 0 deletions
@@ -0,0 +1,109 @@ +#!/usr/bin/env python3 +""" +Static Hacker News page generator. + +* Top stories → output/index.html (site root) +* Best, New, Ask, Show, Job → output/<section>/index.html +""" + +import json +import urllib.request +from pathlib import Path +from datetime import datetime +from typing import List, Dict + +BASE_URL = "https://hacker-news.firebaseio.com/v0" +OUTPUT_DIR = Path(__file__).parent / "output" +TEMPLATE_PATH = Path(__file__).parent / "templates" / "base.html" + + +# ---------------------------------------------------------------------- +# Helper functions +# ---------------------------------------------------------------------- +def fetch_json(url: str) -> dict: + """GET a JSON endpoint and return the parsed object.""" + with urllib.request.urlopen(url) as resp: + return json.load(resp) + + +def get_story_ids(endpoint: str, limit: int = 10) -> List[int]: + """Return the first ``limit`` IDs for a given endpoint.""" + url = f"{BASE_URL}/{endpoint}.json" + all_ids = fetch_json(url) + return all_ids[:limit] + + +def get_item(item_id: int) -> Dict: + """Fetch a single Hacker News item.""" + url = f"{BASE_URL}/item/{item_id}.json" + return fetch_json(url) + + +def render_page(title: str, items_html: str, build_time: str) -> str: + """ + Insert title, items, and the build timestamp into the base template. + """ + template = TEMPLATE_PATH.read_text(encoding="utf-8") + rendered = ( + template + .replace("{{title}}", title) + .replace("{{items}}", items_html) + .replace("{{build}}", build_time) + ) + return rendered + + +def build_list_item(story: Dict) -> str: + """Turn a story dict into a single <li> element.""" + url = story.get("url") or f"https://news.ycombinator.com/item?id={story['id']}" + title = story.get("title", "(no title)") + score = story.get("score", 0) + by = story.get("by", "unknown") + return f'<li><a href="{url}">{title}</a> ({score} points) by {by}</li>' + + +# ---------------------------------------------------------------------- +# Main generation logic +# ---------------------------------------------------------------------- +def generate_static_pages(): + # Make sure the top‑level output folder exists + OUTPUT_DIR.mkdir(parents=True, exist_ok=True) + + # One timestamp for the whole run + build_timestamp = datetime.utcnow().strftime("%Y-%m-%d %H:%M UTC") + + # Mapping: endpoint → (human‑readable title, sub‑folder name or None for root) + sections = { + "topstories": ("Top Stories", None), # None → write to root index.html + "beststories": ("Best Stories", "best"), + "newstories": ("New Stories", "new"), + "askstories": ("Ask HN", "ask"), + "showstories": ("Show HN", "show"), + "jobstories": ("Jobs", "job"), + } + + for endpoint, (title, subdir) in sections.items(): + print(f"Fetching {title}…") + ids = get_story_ids(endpoint, limit=10) + stories = [get_item(i) for i in ids] + + items_html = "\n".join(build_list_item(s) for s in stories) + + page_html = render_page(title, items_html, build_timestamp) + + # Determine where to write the file + if subdir is None: + target_path = OUTPUT_DIR / "index.html" + else: + target_dir = OUTPUT_DIR / subdir + target_dir.mkdir(parents=True, exist_ok=True) + target_path = target_dir / "index.html" + + target_path.write_text(page_html, encoding="utf-8") + print(f" → wrote {target_path}") + + print("All pages generated (built at", build_timestamp, ")") + + +if __name__ == "__main__": + generate_static_pages()
\ No newline at end of file |
