Or:
```
python
#!/usr/bin/env python3
import os
import yaml
import json
import subprocess
import re
from datetime import datetime
import argparse
from pathlib import Path
def extract_front_matter(content):
"""Extract YAML front matter from Jekyll post."""
front_matter_match = re.match(r'^---\s+(.*?)\s+---\s+(.*)', content, re.DOTALL)
if front_matter_match:
front_matter = yaml.safe_load(front_matter_match.group(1))
content = front_matter_match.group(2).strip()
return front_matter, content
return {}, content
def convert_time_format(jekyll_date):
"""Convert Jekyll date format to Unix timestamp."""
if not jekyll_date:
return int(datetime.now().timestamp())
try:
dt = datetime.fromisoformat(str(jekyll_date).replace('Z', '+00:00'))
return int(dt.timestamp())
except ValueError:
try:
dt = datetime.strptime(str(jekyll_date), "%Y-%m-%d %H:%M:%S %z")
return int(dt.timestamp())
except ValueError:
try:
dt = datetime.strptime(str(jekyll_date), "%Y-%m-%d")
return int(dt.timestamp())
except ValueError:
return int(datetime.now().timestamp())
def publish_to_nostr(title, content, published_at, tags=None, key_path=None):
"""Publish content to Nostr using nak."""
if tags is None:
tags = []
# Prepare the command
cmd = ["nak", "publish"]
# Add key if provided
if key_path:
cmd.extend(["--key", key_path])
# Add tags
for tag in tags:
cmd.extend(["--tag", f"t:{tag}"])
# Add title as a tag
if title:
cmd.extend(["--tag", f"title:{title}"])
# Add published timestamp
cmd.extend(["--created-at", str(published_at)])
# Add content
cmd.append(content)
# Execute command
try:
result = subprocess.run(cmd, capture_output=True, text=True, check=True)
note_id = result.stdout.strip()
return True, note_id
except subprocess.CalledProcessError as e:
return False, f"Error: {e.stderr}"
def process_jekyll_post(post_path, key_path=None, dry_run=False):
"""Process a single Jekyll post and convert it to Nostr."""
with open(post_path, 'r', encoding='utf-8') as file:
content = file.read()
front_matter, post_content = extract_front_matter(content)
title = front_matter.get('title', '')
date = front_matter.get('date')
categories = front_matter.get('categories', [])
tags = front_matter.get('tags', [])
# Combine categories and tags
all_tags = []
if isinstance(categories, list):
all_tags.extend(categories)
elif categories:
all_tags.append(str(categories))
if isinstance(tags, list):
all_tags.extend(tags)
elif tags:
all_tags.append(str(tags))
# Convert time
published_at = convert_time_format(date)
# Format final content
final_content = f"{title}\n\n{post_content}"
if dry_run:
print(f"Would publish: {title}")
print(f"Tags: {all_tags}")
print(f"Date: {published_at}")
print(f"Content length: {len(final_content)} characters")
else:
success, result = publish_to_nostr(title, final_content, published_at, all_tags, key_path)
if success:
print(f"Published: {title} -> Note ID: {result}")
else:
print(f"Failed to publish {title}: {result}")
return True
def main():
parser = argparse.ArgumentParser(description="Convert Jekyll blog posts to Nostr notes using NAK")
parser.add_argument("--posts-dir", required=True, help="Directory containing Jekyll posts")
parser.add_argument("--key", help="Path to Nostr private key file")
parser.add_argument("--dry-run", action="store_true", help="Preview without publishing")
args = parser.parse_args()
posts_dir = Path(args.posts_dir)
if not posts_dir.exists() or not posts_dir.is_dir():
print(f"Error: {posts_dir} is not a valid directory")
return
post_files = list(posts_dir.glob("*.md")) + list(posts_dir.glob("*.markdown"))
if not post_files:
print(f"No markdown files found in {posts_dir}")
return
print(f"Found {len(post_files)} Jekyll posts")
for post_file in post_files:
print(f"Processing {post_file.name}...")
process_jekyll_post(post_file, args.key, args.dry_run)
print("Conversion complete!")
if __name__ == "__main__":
main()
```