""" Sopel plugin: jeeves admin Owner commands for bot management and follow mode. !join #channel - join a channel !part [#channel] - leave a channel (defaults to current) !chans - list joined channels !follow - follow owner into channels !unfollow - leave all follow-joined channels immediately !pause - pause keyword responses !resume - resume keyword responses """ 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 from sopel import plugin from sopel.tools import events def setup(bot): jv.ensure_setup(bot) bot.memory.setdefault("jv_follow_enabled", False) bot.memory.setdefault("jv_follow_joined", set()) bot.memory.setdefault("jv_whois_got_channels", False) bot.memory.setdefault("jv_paused", False) def _configured_channels(bot): chans = bot.settings.core.channels or [] return {c.split()[0].lower() for c in chans} @plugin.event("PART") def on_owner_part(bot, trigger): if not jv.is_owner(bot, trigger): return channel = str(trigger.sender) if channel.lower() in _configured_channels(bot): return if channel in {str(c) for c in bot.channels}: bot.part(channel) bot.memory.get("jv_follow_joined", set()).discard(channel.lower()) @plugin.event("QUIT") def on_owner_quit(bot, trigger): if not jv.is_owner(bot, trigger): return configured = _configured_channels(bot) for chan in list(bot.channels): if str(chan).lower() not in configured: bot.part(chan) bot.memory["jv_follow_joined"] = set() @plugin.command("join") def cmd_join(bot, trigger): if not jv.is_owner(bot, trigger): return channel = (trigger.group(2) or "").strip() if not channel.startswith("#"): bot.notice("usage: !join #channel", trigger.nick) return bot.join(channel) @plugin.command("part") def cmd_part(bot, trigger): if not jv.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 jv.is_owner(bot, trigger): return chans = sorted(str(c) for c in bot.channels) bot.notice(("in: " + " ".join(chans)) if chans else "not in any channels", trigger.nick) @plugin.command("follow") def cmd_follow(bot, trigger): if not jv.is_owner(bot, trigger): return arg = (trigger.group(2) or "").strip().lower() if arg == "on": bot.memory["jv_follow_enabled"] = True bot.notice("follow on - tracking your channels every 30s", trigger.nick) elif arg == "off": bot.memory["jv_follow_enabled"] = False bot.notice("follow off", trigger.nick) else: state = "on" if bot.memory.get("jv_follow_enabled") else "off" bot.notice(f"follow is {state}. usage: !follow ", trigger.nick) @plugin.command("unfollow") def cmd_unfollow(bot, trigger): if not jv.is_owner(bot, trigger): return joined = set(bot.memory.get("jv_follow_joined", set())) if not joined: bot.notice("not in any follow-joined channels", trigger.nick) return for chan in joined: bot.part(chan) bot.memory["jv_follow_joined"] = set() bot.notice(f"left {len(joined)} channel(s)", trigger.nick) @plugin.command("pause") def cmd_pause(bot, trigger): if not jv.is_owner(bot, trigger): return bot.memory["jv_paused"] = True bot.notice("keyword responses paused", trigger.nick) @plugin.command("resume") def cmd_resume(bot, trigger): if not jv.is_owner(bot, trigger): return bot.memory["jv_paused"] = False bot.notice("keyword responses resumed", trigger.nick) @plugin.interval(30) def _follow_tick(bot): if not bot.memory.get("jv_follow_enabled"): return bot.memory["jv_whois_got_channels"] = False bot.write(("WHOIS", bot.settings.core.owner)) @plugin.rule(r"(.*)") @plugin.event(events.RPL_WHOISCHANNELS) @plugin.priority("high") def _whois_channels(bot, trigger): if not bot.memory.get("jv_follow_enabled"): return owner = bot.settings.core.owner if len(trigger.args) < 2 or trigger.args[1] != owner: return bot.memory["jv_whois_got_channels"] = True raw = (trigger.group(1) or "").strip() owner_chans = set() for part in raw.split(): chan = part.lstrip("@+~&%") if chan.startswith("#"): owner_chans.add(chan.lower()) current_chans = {str(c).lower() for c in bot.channels} follow_joined = bot.memory.get("jv_follow_joined", set()) for chan in owner_chans: if chan not in current_chans: bot.join(chan) follow_joined.add(chan) bot.memory["jv_follow_joined"] = follow_joined @plugin.rule(r"(.*)") @plugin.event(events.RPL_ENDOFWHOIS) @plugin.priority("high") def _whois_end(bot, trigger): if not bot.memory.get("jv_follow_enabled"): return owner = bot.settings.core.owner if len(trigger.args) < 2 or trigger.args[1] != owner: return if bot.memory.get("jv_whois_got_channels"): return follow_joined = set(bot.memory.get("jv_follow_joined", set())) for chan in follow_joined: bot.part(chan) bot.memory["jv_follow_joined"] = set()