gpn23-recipes/2_to_markdown.py

104 lines
3.5 KiB
Python

import json
import sys
from pathlib import Path
from datetime import timedelta
import re
from pathvalidate import validate_filename
import os
def parse_duration(duration):
if not duration:
return ""
match = re.match(r"PT(?:(\d+)H)?(?:(\d+)M)?", duration)
if not match:
return duration
hours, minutes = match.groups()
hours = f"{int(hours)}h " if hours else ""
minutes = f"{int(minutes)}m" if minutes else ""
return f"{hours}{minutes}".strip()
def format_recipe_to_markdown(recipe):
md = []
# Title
md.append(f"# {recipe.get('name', 'Untitled Recipe')}")
# Description
if 'description' in recipe:
md.append(f"\n_{recipe['description']}_\n")
# Metadata
time_parts = []
if 'prepTime' in recipe:
time_parts.append(f"Prep time: {parse_duration(recipe['prepTime'])}")
if 'cookTime' in recipe:
time_parts.append(f"Cook time: {parse_duration(recipe['cookTime'])}")
if 'totalTime' in recipe:
time_parts.append(f"Total time: {parse_duration(recipe['totalTime'])}")
if 'recipeYield' in recipe:
time_parts.append(f"Yield: {recipe['recipeYield']}")
if time_parts:
md.append('\n**Details:** ' + ' | '.join(time_parts) + '\n')
# Ingredients
if 'recipeIngredient' in recipe:
md.append("\n## Ingredients")
for ingredient in recipe['recipeIngredient']:
md.append(f"- {ingredient}")
# Instructions
if 'recipeInstructions' in recipe:
md.append("\n## Instructions")
instructions = recipe['recipeInstructions']
if isinstance(instructions, list):
for i, step in enumerate(instructions, 1):
if isinstance(step, dict):
text = step.get('text', '').strip()
else:
text = str(step).strip()
md.append(f"{i}. {text.replace(chr(10), ' ')}")
else:
for i, line in enumerate(instructions.strip().split('\n'), 1):
if line.strip():
md.append(f"{i}. {line.strip()}")
# Nutrition
if 'nutrition' in recipe:
md.append("\n## Nutrition")
for key, value in recipe['nutrition'].items():
if key != "@type":
md.append(f"- **{key.replace('_', ' ').capitalize()}**: {value}")
return '\n'.join(md)
def main(json_file):
with open(json_file, 'r', encoding='utf-8') as f:
data = json.load(f)
# If the JSON-LD is embedded in @graph or a list
# if isinstance(data, list):
# recipe = next((item for item in data if item.get('@type') == 'Recipe'), data[0])
# elif '@graph' in data:
# recipe = next((item for item in data['@graph'] if item.get('@type') == 'Recipe'), data['@graph'][0])
if isinstance(data, list) and data[0].get('@type') == 'Recipe':
recipes = data
elif data.get('@type') == 'Recipe':
recipes = [data]
else:
print("No Recipe object found in JSON.")
return
for recipe in recipes:
markdown_fn = f"{recipe.get('name', 'Untitled Recipe')}.md"
validate_filename(markdown_fn) # XXX does this check directory traversal?
markdown = format_recipe_to_markdown(recipe)
print(markdown)
with open(os.path.join("recipes-md", markdown_fn), "w") as f:
f.write(markdown)
if __name__ == "__main__":
if len(sys.argv) != 2:
print("Usage: python recipe_to_md.py <path_to_recipe_json>")
else:
main(sys.argv[1])