🚧 convert to markdown+mediawiki
This commit is contained in:
parent
729b1dde32
commit
f81b7f1a6a
46 changed files with 1134 additions and 0 deletions
104
2_to_markdown.py
Normal file
104
2_to_markdown.py
Normal file
|
@ -0,0 +1,104 @@
|
|||
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])
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue