""" Sopel plugin: contessa - recipe bot Egyptian, Middle Eastern and Western recipes. !breakfast [list] - random breakfast dish or list all !lunch [list] - random lunch dish or list all !dinner [list] - random dinner dish or list all !snack [list] - random snack or list all !recipe - full recipe (up to 3 lines) !join / !part / !chans / !help - owner commands """ import json import os import random from sopel import plugin from sopel.config.types import FilenameAttribute, StaticSection class ContessaSection(StaticSection): recipes_path = FilenameAttribute("recipes_path", relative=False, default="/var/contessa/recipes.json") def setup(bot): bot.config.define_section("contessa", ContessaSection, validate=False) try: path = bot.config.contessa.recipes_path except Exception: path = "/var/contessa/recipes.json" try: with open(path) as f: bot.memory["ct_recipes"] = json.load(f) except Exception: bot.memory["ct_recipes"] = {"breakfast": [], "lunch": [], "dinner": [], "snack": []} def _is_owner(bot, trigger): return trigger.nick == bot.settings.core.owner def _fmt_random(category, dish): return ( f"{category.capitalize()} suggestion: " f"{dish['name']} | {dish['description']}. " f"Type !recipe {dish['name'].lower()} for the full recipe." ) def _fmt_list(category, dishes): names = ", ".join(d["name"] for d in dishes) return f"{category.capitalize()} dishes ({len(dishes)}): {names}" def _fmt_recipe(dish): line1 = f"{dish['name']} | {dish['description']}" line2 = "Ingredients: " + ", ".join(dish["ingredients"]) steps = " ".join( f"{i+1}. {s.rstrip('.')}." for i, s in enumerate(dish["steps"]) ) line3 = steps return line1, line2, line3 def _all_dishes(bot): recipes = bot.memory.get("ct_recipes", {}) for category, dishes in recipes.items(): for dish in dishes: yield category, dish def _find_dish(bot, query): q = query.strip().lower() for _, dish in _all_dishes(bot): if dish["name"].lower() == q: return dish for _, dish in _all_dishes(bot): if q in dish["name"].lower(): return dish return None def _meal_cmd(bot, trigger, category): arg = (trigger.group(2) or "").strip().lower() recipes = bot.memory.get("ct_recipes", {}) dishes = recipes.get(category, []) if not dishes: bot.say(f"no {category} recipes loaded", trigger.sender) return if arg == "list": bot.say(_fmt_list(category, dishes), trigger.sender) return dish = random.choice(dishes) bot.say(_fmt_random(category, dish), trigger.sender) @plugin.command("breakfast") @plugin.require_chanmsg def cmd_breakfast(bot, trigger): _meal_cmd(bot, trigger, "breakfast") @plugin.command("lunch") @plugin.require_chanmsg def cmd_lunch(bot, trigger): _meal_cmd(bot, trigger, "lunch") @plugin.command("dinner") @plugin.require_chanmsg def cmd_dinner(bot, trigger): _meal_cmd(bot, trigger, "dinner") @plugin.command("snack") @plugin.require_chanmsg def cmd_snack(bot, trigger): _meal_cmd(bot, trigger, "snack") @plugin.command("recipe") @plugin.require_chanmsg def cmd_recipe(bot, trigger): query = (trigger.group(2) or "").strip() if not query: bot.say("usage: !recipe ", trigger.sender) return dish = _find_dish(bot, query) if not dish: bot.say(f"no recipe found for '{query}'", trigger.sender) return line1, line2, line3 = _fmt_recipe(dish) bot.say(line1, trigger.sender) bot.say(line2, trigger.sender) bot.say(line3, trigger.sender) @plugin.command("join") def cmd_join(bot, trigger): if not _is_owner(bot, trigger): return channel = (trigger.group(2) or "").strip() if not channel.startswith("#"): bot.say("usage: !join #channel", trigger.nick) return bot.join(channel) @plugin.command("part") def cmd_part(bot, trigger): if not _is_owner(bot, trigger): return channel = (trigger.group(2) or "").strip() or str(trigger.sender) bot.part(channel) @plugin.command("chans") def cmd_chans(bot, trigger): if not _is_owner(bot, trigger): return chans = sorted(str(c) for c in bot.channels) bot.say(("in: " + " ".join(chans)) if chans else "not in any channels", trigger.nick) @plugin.command("help") def cmd_help(bot, trigger): lines = [ "!breakfast [list] - random breakfast dish or list all", "!lunch [list] - random lunch dish or list all", "!dinner [list] - random dinner dish or list all", "!snack [list] - random snack or list all", "!recipe - full recipe (3 lines)", ] if _is_owner(bot, trigger): lines += [ "!join #channel - join a channel", "!part [#channel] - leave a channel", "!chans - list channels", ] lines.append("!help - this message") for line in lines: bot.say(line, trigger.nick)