Switch blog.json from embedded content to content_url links

Changes blog.json generation to link to hosted markdown files instead of
embedding full content. Each post now includes a content_url field pointing
to {site_url}/{slug}/index.md. This significantly reduces blog.json file
size while maintaining full content access via standard HTTP requests.

Updated README.rst to document the new linking behavior & how blog.json works.
This commit is contained in:
russell@unturf.com 2026-01-20 03:21:19 -05:00
parent 2bda81d294
commit d8cf83e051
2 changed files with 13 additions and 24 deletions

View file

@ -67,7 +67,7 @@ The blog automatically generates multiple formats optimized for AI agents & LLM
**Generated files:** **Generated files:**
- ``/blog.json`` - Entire blog in single JSON file (jsonblog.dev format) - ``/blog.json`` - Blog index with links to markdown files (jsonblog.dev format)
- ``/feeds/all.json`` - JSON Feed v1.1 alternative to Atom/RSS - ``/feeds/all.json`` - JSON Feed v1.1 alternative to Atom/RSS
- ``/llms.txt`` - AI agent onboarding documentation with API info - ``/llms.txt`` - AI agent onboarding documentation with API info
- ``/*/index.md`` - GitHub-flavored Markdown for every post - ``/*/index.md`` - GitHub-flavored Markdown for every post
@ -77,11 +77,15 @@ The blog automatically generates multiple formats optimized for AI agents & LLM
These formats enable AI agents, LLMs, & automated systems to: These formats enable AI agents, LLMs, & automated systems to:
- Ingest entire blog content in one request (blog.json) - Discover all posts & fetch markdown via ``content_url`` links (blog.json)
- Subscribe to updates via JSON instead of XML (feeds/all.json) - Subscribe to updates via JSON instead of XML (feeds/all.json)
- Discover blog structure & available formats (llms.txt) - Discover blog structure & available formats (llms.txt)
- Read posts without HTML parsing (index.txt, index.md) - Read posts without HTML parsing (index.txt, index.md)
**How blog.json works:**
The ``blog.json`` file uses the jsonblog.dev format & links to hosted markdown files instead of embedding content. Each post includes a ``content_url`` field pointing to ``https://russell.ballestrini.net/{slug}/index.md``. This keeps the JSON file lightweight while providing full access to all post content through standard HTTP requests.
All formats are automatically generated during CI/CD builds & kept in sync with the HTML content. All formats are automatically generated during CI/CD builds & kept in sync with the HTML content.
**Requirements:** **Requirements:**

View file

@ -1,7 +1,7 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
""" """
Generate JSON Blog (jsonblog.dev) format - single JSON file with all posts. Generate JSON Blog (jsonblog.dev) format - single JSON file with all posts.
Uses Markdown content from index.md files generated by rst2md.py. Links to Markdown files (index.md) generated by rst2md.py instead of embedding content.
""" """
import json import json
@ -109,20 +109,8 @@ def parse_atom_feed(atom_path):
return feed_info, entries return feed_info, entries
def load_markdown_content(output_dir, slug):
"""Load markdown content from index.md file."""
md_path = output_dir / slug / 'index.md'
if md_path.exists():
try:
return md_path.read_text(encoding='utf-8')
except Exception as e:
print(f"Warning: Could not read {md_path}: {e}")
return None
return None
def generate_jsonblog(atom_path, output_dir, site_url): def generate_jsonblog(atom_path, output_dir, site_url):
"""Generate JSON Blog format with Markdown content.""" """Generate JSON Blog format with links to Markdown content."""
feed_info, entries = parse_atom_feed(atom_path) feed_info, entries = parse_atom_feed(atom_path)
jsonblog = { jsonblog = {
@ -146,15 +134,12 @@ def generate_jsonblog(atom_path, output_dir, site_url):
'createdAt': entry['createdAt'], 'createdAt': entry['createdAt'],
} }
# Try to load markdown content # Check if markdown file exists, then link to it
md_content = load_markdown_content(output_dir, entry['slug']) md_path = output_dir / entry['slug'] / 'index.md'
if md_content: if md_path.exists():
post['content'] = md_content post['content_url'] = f"{site_url}/{entry['slug']}/index.md"
post['content_type'] = 'markdown' post['content_type'] = 'markdown'
markdown_found += 1 markdown_found += 1
else:
# Fallback to plain text from HTML
post['content'] = entry['content']
if entry['updatedAt'] and entry['updatedAt'] != entry['createdAt']: if entry['updatedAt'] and entry['updatedAt'] != entry['createdAt']:
post['updatedAt'] = entry['updatedAt'] post['updatedAt'] = entry['updatedAt']
@ -170,7 +155,7 @@ def generate_jsonblog(atom_path, output_dir, site_url):
jsonblog['posts'].append(post) jsonblog['posts'].append(post)
print(f"Generated {len(jsonblog['posts'])} posts ({markdown_found} with markdown content)") print(f"Generated {len(jsonblog['posts'])} posts ({markdown_found} with markdown links)")
return jsonblog return jsonblog