aboutsummaryrefslogtreecommitdiffstats
path: root/jeeves/quotes.py
diff options
context:
space:
mode:
authorAhmed <git@gumx.cc>2026-06-14 01:46:29 +0300
committerAhmed <git@gumx.cc>2026-06-14 01:46:29 +0300
commit5a8d568931d9b23ce0df1265d05259a7012081c9 (patch)
tree4ea19b8bb1763a38246f342f172c285f6579e09b /jeeves/quotes.py
init: mostly vibed
Diffstat (limited to 'jeeves/quotes.py')
-rw-r--r--jeeves/quotes.py150
1 files changed, 150 insertions, 0 deletions
diff --git a/jeeves/quotes.py b/jeeves/quotes.py
new file mode 100644
index 0000000..c840a6d
--- /dev/null
+++ b/jeeves/quotes.py
@@ -0,0 +1,150 @@
+"""
+Sopel plugin: jeeves quotes
+
+Maintains a shared quote bank with automatic periodic posting.
+
+ !quote - post a random quote
+ !quote add <text> - add a quote (op/owner)
+ !quote del <N> - delete quote by index (op/owner)
+ !quote list - show total count
+ !quotes - show auto-post state for this channel
+ !quotes on|off - enable/disable auto-posting (op/owner)
+
+Auto-post interval is configured via:
+ !set quotes_interval <min> - minutes between auto-posts (default 60)
+"""
+
+import os as _os, sys as _sys
+_d = _os.path.dirname(_os.path.abspath(__file__))
+if _d not in _sys.path:
+ _sys.path.insert(0, _d)
+import jv_core as jv
+
+import random
+import time
+
+from sopel import plugin
+
+
+def setup(bot):
+ jv.ensure_setup(bot)
+
+
+@plugin.command("quote")
+def cmd_quote(bot, trigger):
+ args = (trigger.group(2) or "").strip().split(None, 1)
+ sub = args[0].lower() if args else ""
+
+ if sub == "add":
+ if not jv.is_authorized(bot, trigger):
+ return
+ text = args[1].strip() if len(args) > 1 else ""
+ if not text:
+ bot.notice("usage: !quote add <text>", trigger.nick)
+ return
+ with bot.memory["jv_lock"]:
+ bot.memory["jv_db"].setdefault("quotes", []).append(text)
+ n = len(bot.memory["jv_db"]["quotes"])
+ jv.save(bot)
+ bot.notice(f"quote #{n} added", trigger.nick)
+ return
+
+ if sub == "del":
+ if not jv.is_authorized(bot, trigger):
+ return
+ if len(args) < 2:
+ bot.notice("usage: !quote del <N>", trigger.nick)
+ return
+ try:
+ idx = int(args[1]) - 1
+ except ValueError:
+ bot.notice("usage: !quote del <N>", trigger.nick)
+ return
+ with bot.memory["jv_lock"]:
+ quotes = bot.memory["jv_db"].get("quotes", [])
+ if idx < 0 or idx >= len(quotes):
+ bot.notice(f"no quote #{idx + 1}", trigger.nick)
+ return
+ quotes.pop(idx)
+ jv.save(bot)
+ bot.notice(f"quote #{idx + 1} deleted", trigger.nick)
+ return
+
+ if sub == "list":
+ quotes = bot.memory.get("jv_db", {}).get("quotes", [])
+ count = len(quotes)
+ dest = trigger.sender if str(trigger.sender).startswith("#") else trigger.nick
+ bot.say(f"{count} quote(s) in the bank", dest)
+ return
+
+ quotes = bot.memory.get("jv_db", {}).get("quotes", [])
+ if not quotes:
+ dest = trigger.sender if str(trigger.sender).startswith("#") else trigger.nick
+ bot.say("no quotes in the bank yet", dest)
+ return
+ dest = trigger.sender if str(trigger.sender).startswith("#") else trigger.nick
+ bot.say(random.choice(quotes), dest)
+
+
+@plugin.command("quotes")
+def cmd_quotes(bot, trigger):
+ args = (trigger.group(2) or "").strip().split()
+ arg = args[0].lower() if args else ""
+ in_chan = str(trigger.sender).startswith("#")
+ channel = str(trigger.sender) if in_chan else None
+
+ if arg in ("on", "off"):
+ if not jv.is_authorized(bot, trigger):
+ return
+ if not in_chan:
+ bot.notice("use !quotes on|off in a channel", trigger.nick)
+ return
+ with bot.memory["jv_lock"]:
+ jv.chan_db(bot, channel)["quotes"]["enabled"] = (arg == "on")
+ jv.save(bot)
+ bot.say(f"quote auto-post turned {arg} for {channel}", channel)
+ return
+
+ if in_chan:
+ ch = jv.chan_db(bot, channel)
+ enabled = ch["quotes"]["enabled"]
+ last = ch["quotes"]["last_broadcast"]
+ interval = jv.cfg_val(bot, "quotes_interval", channel)
+ if last:
+ ago = int(time.time() - last)
+ last_str = f"{ago // 60}m ago" if ago >= 60 else f"{ago}s ago"
+ else:
+ last_str = "never"
+ state = "on" if enabled else "off"
+ count = len(bot.memory.get("jv_db", {}).get("quotes", []))
+ bot.say(
+ f"quote auto-post: {state} | every {interval} min | {count} quote(s) | last: {last_str}",
+ channel,
+ )
+ else:
+ bot.notice("usage: !quotes [on|off] (use in a channel)", trigger.nick)
+
+
+@plugin.interval(60)
+def _quotes_tick(bot):
+ if "jv_db" not in bot.memory:
+ return
+ now = time.time()
+ quotes = bot.memory["jv_db"].get("quotes", [])
+ if not quotes:
+ return
+
+ for chan_name in list(bot.channels):
+ channel = str(chan_name)
+ ch = jv.chan_db(bot, channel)
+ if not ch["quotes"]["enabled"]:
+ continue
+ interval_sec = jv.cfg_val(bot, "quotes_interval", channel) * 60
+ if now - ch["quotes"]["last_broadcast"] < interval_sec:
+ continue
+
+ quote = random.choice(quotes)
+ with bot.memory["jv_lock"]:
+ jv.chan_db(bot, channel)["quotes"]["last_broadcast"] = now
+ jv.save(bot)
+ bot.say(quote, channel)