1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
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 <name> - 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 <dish name>", 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 <name> - 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)
|