- rst2md.py now creates both index.md (with metadata) and index-slim.md (clean) - generate_jsonblog.py references index-slim.md for clean content - Fixes "Error: No content found" in blog viewer - strip_pelican_metadata() removes title and metadata fields
133 lines
3.8 KiB
Python
133 lines
3.8 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Convert RST files to Markdown using pandoc.
|
|
Strips Pelican metadata headers from the resulting markdown.
|
|
"""
|
|
|
|
import subprocess
|
|
import sys
|
|
from pathlib import Path
|
|
import re
|
|
|
|
|
|
def strip_pelican_metadata(content):
|
|
"""Remove Pelican metadata header from markdown content.
|
|
|
|
Pandoc converts RST metadata to a format like:
|
|
# Title
|
|
|
|
field_name
|
|
field_value
|
|
|
|
another_field
|
|
another_value
|
|
|
|
Content starts here...
|
|
"""
|
|
lines = content.split('\n')
|
|
i = 0
|
|
|
|
# First line is usually the title (keep it)
|
|
if i < len(lines) and lines[i].strip().startswith('#'):
|
|
i += 1
|
|
|
|
# Skip blank lines after title
|
|
while i < len(lines) and not lines[i].strip():
|
|
i += 1
|
|
|
|
# Skip metadata fields (field name on one line, value on next)
|
|
metadata_fields = ['author', 'slug', 'date', 'tags', 'status', 'category', 'summary']
|
|
|
|
while i < len(lines):
|
|
line = lines[i].strip().lower()
|
|
|
|
# Check if this line is a metadata field name
|
|
if any(line == field for field in metadata_fields):
|
|
# Skip field name line
|
|
i += 1
|
|
# Skip value line(s) - could be multiline
|
|
while i < len(lines) and lines[i].strip():
|
|
# If next line is another field name, stop
|
|
if any(lines[i].strip().lower() == field for field in metadata_fields):
|
|
break
|
|
i += 1
|
|
# Skip blank line after field
|
|
if i < len(lines) and not lines[i].strip():
|
|
i += 1
|
|
elif not line:
|
|
# Skip blank lines between metadata
|
|
i += 1
|
|
else:
|
|
# Hit content - stop stripping
|
|
break
|
|
|
|
# Return content from this point forward
|
|
return '\n'.join(lines[i:]).strip() + '\n'
|
|
|
|
|
|
def convert_file(rst_path, md_path=None, create_slim=True):
|
|
"""Convert a single RST file to Markdown using pandoc.
|
|
|
|
Creates two versions:
|
|
- index.md: Full markdown with metadata
|
|
- index-slim.md: Clean markdown without metadata
|
|
"""
|
|
rst_path = Path(rst_path)
|
|
if md_path is None:
|
|
md_path = rst_path.with_suffix('.md')
|
|
else:
|
|
md_path = Path(md_path)
|
|
|
|
# First convert with pandoc (full version with metadata)
|
|
subprocess.run(
|
|
['pandoc', '-f', 'rst', '-t', 'gfm', '-o', str(md_path), str(rst_path)],
|
|
check=True
|
|
)
|
|
|
|
# Create slim version without metadata
|
|
if create_slim:
|
|
content = md_path.read_text()
|
|
clean_content = strip_pelican_metadata(content)
|
|
|
|
# Create -slim.md version
|
|
slim_path = md_path.parent / md_path.name.replace('.md', '-slim.md')
|
|
slim_path.write_text(clean_content)
|
|
|
|
return md_path
|
|
|
|
|
|
def convert_output_directory(output_dir):
|
|
"""Convert all index.rst files in output directory to index.md and index-slim.md."""
|
|
output_path = Path(output_dir)
|
|
count = 0
|
|
|
|
for rst_file in output_path.rglob('index.rst'):
|
|
md_file = rst_file.with_suffix('.md')
|
|
try:
|
|
convert_file(rst_file, md_file, create_slim=True)
|
|
count += 1
|
|
except subprocess.CalledProcessError as e:
|
|
print(f"Warning: Failed to convert {rst_file}: {e}")
|
|
|
|
print(f"Generated {count} index.md files and {count} index-slim.md files")
|
|
return count
|
|
|
|
|
|
if __name__ == '__main__':
|
|
if len(sys.argv) < 2:
|
|
print("Usage: rst2md.py <output_directory>")
|
|
print(" rst2md.py <file.rst> [output.md]")
|
|
sys.exit(1)
|
|
|
|
path = Path(sys.argv[1])
|
|
|
|
if path.is_dir():
|
|
count = convert_output_directory(path)
|
|
print(f"Converted {count} RST files to Markdown")
|
|
elif path.is_file():
|
|
output = sys.argv[2] if len(sys.argv) > 2 else None
|
|
md_path = convert_file(path, output)
|
|
print(f"Converted {path} -> {md_path}")
|
|
else:
|
|
print(f"Error: {path} not found")
|
|
sys.exit(1)
|