Files

410 lines
13 KiB
Python

#!/usr/bin/env python3
"""Categorize recipes with category and tags based on content."""
import re
from pathlib import Path
import yaml
WORKDIR = Path("/home/jbrechtel/recipes")
# Recipe classifications: (filename_pattern, {category, tags})
CLASSIFICATIONS = [
("Alain-Ducase-Bread.cook", {
"category": "appetizer",
"tags": ["vegetarian", "french", "cheese"]
}),
("Apple Cider Vinegar Dressing.cook", {
"category": "salad",
"tags": ["vegetarian", "vegan", "gluten-free"]
}),
("Arugula Pesto Chicken with Pecans & Roasted Butternut.cook", {
"category": "dinner",
"tags": ["meat", "chicken", "pasta"]
}),
("Arugula Pesto Wheat Berries Recipe.cook", {
"category": "lunch",
"tags": ["vegetarian", "grain-bowl"]
}),
("Asparagus Salad.cook", {
"category": "salad",
"tags": ["vegetarian", "gluten-free", "spring"]
}),
("Authentic Cacio e Pepe Recipe.cook", {
"category": "dinner",
"tags": ["vegetarian", "italian", "pasta"]
}),
("Baked Chile Relleno with Black Beans.cook", {
"category": "dinner",
"tags": ["vegetarian", "mexican", "beans"]
}),
("Bang Bang Tofu.cook", {
"category": "dinner",
"tags": ["vegetarian", "vegan-option", "asian", "tofu"]
}),
("Barbecue Chicken with Crispy Pan-Fried Okra & Cheddar Biscuits.cook", {
"category": "dinner",
"tags": ["meat", "chicken", "southern"]
}),
("Black Bean and Corn Salad.cook", {
"category": "salad",
"tags": ["vegetarian", "vegan", "gluten-free", "mexican"]
}),
("Black Pepper Tofu (Ottolenghi).cook", {
"category": "dinner",
"tags": ["vegetarian", "asian", "tofu", "vegan-option"]
}),
("Black Pepper Tofu with Bok Choy.cook", {
"category": "dinner",
"tags": ["vegetarian", "asian", "tofu", "vegan-option"]
}),
("Blackened Shrimp and Gouda Grits.cook", {
"category": "dinner",
"tags": ["seafood", "shrimp", "southern"]
}),
("Butter Tofu.cook", {
"category": "dinner",
"tags": ["vegetarian", "indian", "tofu"]
}),
("butternut-turkey-chili.cook", {
"category": "dinner",
"tags": ["meat", "turkey", "chili", "soup"]
}),
("Butternut Turkey Chili.cook", {
"category": "dinner",
"tags": ["meat", "turkey", "chili", "soup"]
}),
("BUTTERNUT & TURKEY CHILI with sweet peppers, spiced pepitas & queso fresco.cook", {
"category": "dinner",
"tags": ["meat", "turkey", "chili", "soup"]
}),
("Cabbage_Salad.cook", {
"category": "salad",
"tags": ["vegetarian", "vegan", "gluten-free"]
}),
("Cajun Shrimp and Sausage Vegetable Foil Packets.cook", {
"category": "dinner",
"tags": ["seafood", "shrimp", "cajun", "sausage"]
}),
("Cajun Spice Mix (for pecans, oysters, etc).cook", {
"category": "appetizer",
"tags": ["vegetarian", "vegan", "spice-blend"]
}),
("Caramel Cake.cook", {
"category": "lunch",
"tags": ["vegetarian", "dessert"]
}),
("Caramel Icing.cook", {
"category": "lunch",
"tags": ["vegetarian", "dessert"]
}),
("cauliflower-milanese.cook", {
"category": "dinner",
"tags": ["vegetarian", "italian", "vegetable"]
}),
("Chana Chickpea Salad.cook", {
"category": "salad",
"tags": ["vegetarian", "vegan", "indian", "gluten-free"]
}),
("Chana Salad.cook", {
"category": "salad",
"tags": ["vegetarian", "vegan", "indian", "gluten-free"]
}),
("Chicken and Pumpkin Gnocchi with Ricotta.cook", {
"category": "dinner",
"tags": ["meat", "chicken", "pasta", "fall"]
}),
("Chickpea Butter Curry.cook", {
"category": "dinner",
"tags": ["vegetarian", "indian", "curry", "vegan-option"]
}),
("Chickpea_Butter_Curry.cook", {
"category": "dinner",
"tags": ["vegetarian", "indian", "curry", "vegan-option"]
}),
("Chinese Orange Shrimp.cook", {
"category": "dinner",
"tags": ["seafood", "shrimp", "asian"]
}),
("Chocolate_Mousse_Cake_with_Raspberries.cook", {
"category": "lunch",
"tags": ["vegetarian", "dessert", "chocolate"]
}),
("Cilantro Pesto Shrimp Over Orzo.cook", {
"category": "dinner",
"tags": ["seafood", "shrimp", "pasta"]
}),
("Crispy Roasted Chickpeas (Garbanzo Beans).cook", {
"category": "appetizer",
"tags": ["vegetarian", "vegan", "gluten-free", "snack"]
}),
("Crispy_Roasted_Chickpeas_(Garbanzo_Beans).cook", {
"category": "appetizer",
"tags": ["vegetarian", "vegan", "gluten-free", "snack"]
}),
("Crispy Tofu With Cashews and Blistered Snap Peas.cook", {
"category": "dinner",
"tags": ["vegetarian", "asian", "tofu", "vegan-option"]
}),
("Dried Fava Soup.cook", {
"category": "lunch",
"tags": ["vegetarian", "vegan", "soup", "mexican"]
}),
("Easy Lemon Rosemary White Bean Soup.cook", {
"category": "lunch",
"tags": ["vegetarian", "vegan", "soup", "gluten-free"]
}),
("Easy_Lemon_Rosemary_White_Bean_Soup.cook", {
"category": "lunch",
"tags": ["vegetarian", "vegan", "soup", "gluten-free"]
}),
("Easy Vegetarian Chili.cook", {
"category": "dinner",
"tags": ["vegetarian", "vegan", "chili", "soup"]
}),
("example-fried-rice.cook", {
"category": "dinner",
"tags": ["meat", "asian", "rice"]
}),
("Fettucine with spiced cherry tomato sauce.cook", {
"category": "dinner",
"tags": ["vegetarian", "italian", "pasta"]
}),
("Gaja's Bulgogi Lettuce Wraps.cook", {
"category": "dinner",
"tags": ["meat", "asian", "korean"]
}),
("Gochugaru Honey Salmon.cook", {
"category": "dinner",
"tags": ["seafood", "salmon", "asian", "korean"]
}),
("Green_Beans_with_Lemon_and_Garlic.cook", {
"category": "lunch",
"tags": ["vegetarian", "vegan", "gluten-free", "side"]
}),
("indian-spiced-chicken.cook", {
"category": "dinner",
"tags": ["meat", "chicken", "indian"]
}),
("Indian Spiced Chicken.cook", {
"category": "dinner",
"tags": ["meat", "chicken", "indian"]
}),
("Italian Sausage and Delicata Rigatoni.cook", {
"category": "dinner",
"tags": ["meat", "sausage", "pasta", "italian"]
}),
("Kale and Chestnut Stew.cook", {
"category": "dinner",
"tags": ["vegetarian", "vegan-option", "soup", "fall"]
}),
("Kkanpoong Tofu.cook", {
"category": "dinner",
"tags": ["vegetarian", "asian", "korean", "tofu"]
}),
("Korean Shrimp Tacos.cook", {
"category": "dinner",
"tags": ["seafood", "shrimp", "asian", "korean", "mexican"]
}),
("Kung Pao Shrimp with Sichuan Roasted Green Beans.cook", {
"category": "dinner",
"tags": ["seafood", "shrimp", "asian", "chinese"]
}),
("Lactation cookies.cook", {
"category": "lunch",
"tags": ["vegetarian", "dessert", "snack"]
}),
("Lactation_cookies.cook", {
"category": "lunch",
"tags": ["vegetarian", "dessert", "snack"]
}),
("Lentil Soup with Lemon and Turmeric.cook", {
"category": "lunch",
"tags": ["vegetarian", "vegan", "soup", "gluten-free", "indian"]
}),
("Moroccan_Spiced_Lentil_and_Chickpea_Soup.cook", {
"category": "lunch",
"tags": ["vegetarian", "vegan", "soup", "moroccan"]
}),
("Moroccan Spiced Lentil & Chickpea Soup.cook", {
"category": "lunch",
"tags": ["vegetarian", "vegan", "soup", "moroccan"]
}),
("Orange Rolls.cook", {
"category": "lunch",
"tags": ["vegetarian", "dessert", "bread"]
}),
("Palak Paneer.cook", {
"category": "dinner",
"tags": ["vegetarian", "indian", "paneer"]
}),
("Passion Fruit Curd Recipe.cook", {
"category": "lunch",
"tags": ["vegetarian", "gluten-free", "dessert"]
}),
("Pecan-Brown Butter Trout.cook", {
"category": "dinner",
"tags": ["seafood", "fish"]
}),
("Ribollita.cook", {
"category": "lunch",
"tags": ["vegetarian", "vegan", "soup", "italian"]
}),
("Roasted Pumpkin Sage.cook", {
"category": "lunch",
"tags": ["vegetarian", "vegan", "soup", "fall"]
}),
("Saag Paneer.cook", {
"category": "dinner",
"tags": ["vegetarian", "indian", "paneer"]
}),
("Sauteed Asparagus with Lemon.cook", {
"category": "lunch",
"tags": ["vegetarian", "vegan", "gluten-free", "side"]
}),
("sheet-pan-miso-chicken-with-radishes-and-lime.cook", {
"category": "dinner",
"tags": ["meat", "chicken", "asian", "japanese"]
}),
("sheet-pan-shrimp-oreganata.cook", {
"category": "dinner",
"tags": ["seafood", "shrimp", "italian"]
}),
("shrimp-feta.cook", {
"category": "dinner",
"tags": ["seafood", "shrimp", "mediterranean", "pasta"]
}),
("Slow Cooker Chicken Shawarma.cook", {
"category": "dinner",
"tags": ["meat", "chicken", "mediterranean", "middle-eastern"]
}),
("Southern_Macaroni_and_Cheese.cook", {
"category": "lunch",
"tags": ["vegetarian", "southern", "pasta"]
}),
("Spaghetti Carbonara.cook", {
"category": "dinner",
"tags": ["meat", "italian", "pasta"]
}),
("Spaghetti_Squash_w_Chickpeas_and_Kale.cook", {
"category": "dinner",
"tags": ["vegetarian", "vegan", "gluten-free", "vegetable"]
}),
("Spanakopita.cook", {
"category": "dinner",
"tags": ["vegetarian", "mediterranean", "greek"]
}),
("Spicy Shrimp Paella.cook", {
"category": "dinner",
"tags": ["seafood", "shrimp", "spanish", "rice"]
}),
("Strawberry and Wild Rice Tartlets.cook", {
"category": "appetizer",
"tags": ["vegetarian", "gluten-free-option", "dessert"]
}),
("Thai_Veggie_Pad_See_Ew.cook", {
"category": "dinner",
"tags": ["vegetarian", "vegan-option", "asian", "thai", "noodles"]
}),
("Tiramisu.cook", {
"category": "lunch",
"tags": ["vegetarian", "italian", "dessert"]
}),
("Warm Up With a Quick Lemony Chicken Soup.cook", {
"category": "lunch",
"tags": ["meat", "chicken", "soup", "gluten-free"]
}),
("West African Peanut Chicken.cook", {
"category": "dinner",
"tags": ["meat", "chicken", "african", "stew"]
}),
("Wheat Berry Salad.cook", {
"category": "salad",
"tags": ["vegetarian", "vegan", "grain-bowl"]
}),
]
def update_frontmatter(filepath, classification):
"""Update category and tags in the YAML frontmatter."""
content = filepath.read_text(encoding="utf-8")
# Find the YAML frontmatter
m = re.match(r'^---\n(.*?)\n---', content, re.DOTALL)
if not m:
print(f" No frontmatter in {filepath.name}")
return False
fm_text = m.group(1)
lines = fm_text.split('\n')
new_lines = []
in_tags = False
category_updated = False
tags_updated = False
for line in lines:
stripped = line.strip()
if stripped.startswith('category:'):
new_lines.append(f"category: {classification['category']}")
category_updated = True
in_tags = False
elif stripped.startswith('tags:'):
# Skip old tags, we'll add new ones
in_tags = True
tags_updated = True
new_lines.append("tags:")
for tag in classification['tags']:
new_lines.append(f" - {tag}")
elif in_tags:
# Skip old tag lines (indented with -)
if stripped.startswith('-') or stripped == '':
continue
else:
in_tags = False
new_lines.append(line)
else:
new_lines.append(line)
if not category_updated:
# Add category before tags or at end of frontmatter
print(f" No category field in {filepath.name}")
if not tags_updated:
# Add tags at end of frontmatter
new_lines.append("tags:")
for tag in classification['tags']:
new_lines.append(f" - {tag}")
new_fm = '\n'.join(new_lines)
new_content = f"---\n{new_fm}\n---" + content[m.end():]
filepath.write_text(new_content, encoding="utf-8")
return True
def main():
updated = 0
errors = 0
for filename, classification in CLASSIFICATIONS:
fp = WORKDIR / filename
if not fp.exists():
print(f"NOT FOUND: {filename}")
errors += 1
continue
try:
update_frontmatter(fp, classification)
print(f"UPDATED: {filename}{classification['category']} [{', '.join(classification['tags'])}]")
updated += 1
except Exception as e:
print(f"ERROR: {filename}: {e}")
errors += 1
print(f"\n{'='*50}")
print(f"Total: {len(CLASSIFICATIONS)} | Updated: {updated} | Errors: {errors}")
if __name__ == "__main__":
main()