From 5a8d568931d9b23ce0df1265d05259a7012081c9 Mon Sep 17 00:00:00 2001 From: Ahmed Date: Sun, 14 Jun 2026 01:46:29 +0300 Subject: init: mostly vibed --- contessa/commands.py | 191 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 191 insertions(+) create mode 100644 contessa/commands.py (limited to 'contessa/commands.py') diff --git a/contessa/commands.py b/contessa/commands.py new file mode 100644 index 0000000..ac5be72 --- /dev/null +++ b/contessa/commands.py @@ -0,0 +1,191 @@ +""" +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) -- cgit v1.2.3