315 lines
12 KiB
Python
315 lines
12 KiB
Python
###
|
|
# Copyright (c) 2025, Stormux
|
|
#
|
|
# This plugin is licensed under the same terms as Limnoria itself.
|
|
###
|
|
|
|
import supybot.utils as utils
|
|
from supybot.commands import *
|
|
import supybot.plugins as plugins
|
|
import supybot.ircutils as ircutils
|
|
import supybot.callbacks as callbacks
|
|
import supybot.world as world
|
|
import supybot.schedule as schedule
|
|
import supybot.conf as conf
|
|
import supybot.ircmsgs as ircmsgs
|
|
import time
|
|
import re
|
|
|
|
class Greet(callbacks.Plugin):
|
|
"""
|
|
A plugin to greet users when they join a channel.
|
|
Features flood protection and timeout between greetings.
|
|
Only greets users the first time they join during a session,
|
|
and resets when the greeting message changes.
|
|
"""
|
|
|
|
def __init__(self, irc):
|
|
self.__parent = super(Greet, self)
|
|
self.__parent.__init__(irc)
|
|
|
|
# Dictionary to track which users have been greeted in this session
|
|
self.greetedUsers = {}
|
|
|
|
# Dictionary to store the greeting message used for each user
|
|
self.userGreetingVersion = {}
|
|
|
|
# Debug mode
|
|
self.debugMode = False
|
|
|
|
def doJoin(self, irc, msg):
|
|
"""
|
|
Called when someone joins a channel.
|
|
"""
|
|
channel = msg.args[0]
|
|
nick = msg.nick
|
|
|
|
# Log event for debugging
|
|
if self.debugMode:
|
|
self._logDebug(irc, f"JOIN event detected: {nick} joined {channel}")
|
|
|
|
# Don't greet ourselves
|
|
if nick == irc.nick:
|
|
if self.debugMode:
|
|
self._logDebug(irc, f"Not greeting self (bot)")
|
|
return
|
|
|
|
# Check if greetings are enabled for this channel
|
|
if not self.registryValue('enabled', channel):
|
|
if self.debugMode:
|
|
self._logDebug(irc, f"Greetings disabled for {channel}")
|
|
return
|
|
|
|
# Get the greeting message for this channel
|
|
greeting = self.registryValue('message', channel)
|
|
if not greeting:
|
|
if self.debugMode:
|
|
self._logDebug(irc, f"No greeting message set for {channel}")
|
|
return
|
|
|
|
# Check if we've already greeted this user with this greeting
|
|
userKey = f"{nick.lower()}@{channel}"
|
|
|
|
if userKey in self.greetedUsers and channel in self.greetedUsers[userKey]:
|
|
# If the greeting has changed since we last greeted this user, we should greet them again
|
|
lastGreetingUsed = self.userGreetingVersion.get(userKey, "")
|
|
if greeting == lastGreetingUsed:
|
|
if self.debugMode:
|
|
self._logDebug(irc, f"User {nick} already greeted in this session with current greeting")
|
|
return
|
|
else:
|
|
if self.debugMode:
|
|
self._logDebug(irc, f"Greeting for {channel} has changed, will greet {nick} again")
|
|
|
|
# Get the timeout
|
|
timeout = self.registryValue('timeout', channel) or 3
|
|
|
|
if self.debugMode:
|
|
self._logDebug(irc, f"Will greet in {channel} after {timeout}s: {greeting}")
|
|
|
|
# Mark this user as greeted in this channel
|
|
if userKey not in self.greetedUsers:
|
|
self.greetedUsers[userKey] = set()
|
|
self.greetedUsers[userKey].add(channel)
|
|
|
|
# Store the greeting version we're using for this user
|
|
self.userGreetingVersion[userKey] = greeting
|
|
|
|
# Use a closure to capture the current values
|
|
def sendGreeting(channelToGreet=channel, greetingMsg=greeting):
|
|
if self.debugMode:
|
|
self._logDebug(irc, f"Sending greeting in {channelToGreet}: {greetingMsg}")
|
|
try:
|
|
# Make sure the channel is still valid when we send the message
|
|
if channelToGreet in irc.state.channels:
|
|
irc.queueMsg(ircmsgs.privmsg(channelToGreet, greetingMsg))
|
|
except Exception as e:
|
|
if self.debugMode:
|
|
self._logDebug(irc, f"Error sending greeting: {str(e)}")
|
|
|
|
# Schedule the greeting
|
|
schedule.addEvent(sendGreeting, time.time() + timeout)
|
|
|
|
def _logDebug(self, irc, message):
|
|
"""Send debug messages to the first available channel"""
|
|
try:
|
|
# Send to the owner via private message instead of to a channel
|
|
for owner in self.registryValue('owners') or []:
|
|
irc.queueMsg(ircmsgs.privmsg(owner, f"[GREET-DEBUG] {message}"))
|
|
return
|
|
|
|
# Fallback: send to the first available channel
|
|
for channel in list(irc.state.channels):
|
|
try:
|
|
irc.queueMsg(ircmsgs.privmsg(channel, f"[GREET-DEBUG] {message}"))
|
|
break
|
|
except:
|
|
continue
|
|
except Exception as e:
|
|
# Last resort, log to Supybot's logs
|
|
self.log.error(f"Debug logging error: {str(e)}")
|
|
|
|
@wrap(['channel'])
|
|
def greettest(self, irc, msg, args, channel):
|
|
"""[<channel>]
|
|
|
|
Test the greeting by sending it immediately.
|
|
"""
|
|
greeting = self.registryValue('message', channel)
|
|
if greeting:
|
|
irc.queueMsg(ircmsgs.privmsg(channel, greeting))
|
|
irc.replySuccess("Greeting test sent")
|
|
else:
|
|
irc.error("No greeting message is set for this channel")
|
|
|
|
@wrap(['owner', 'channel'])
|
|
def greettrigger(self, irc, msg, args, channel):
|
|
"""[<channel>]
|
|
|
|
Simulates a join event with timeout (owner only).
|
|
"""
|
|
greeting = self.registryValue('message', channel)
|
|
if not greeting:
|
|
irc.error(f"No greeting message is set for {channel}")
|
|
return
|
|
|
|
# Get the timeout
|
|
timeout = self.registryValue('timeout', channel) or 3
|
|
|
|
irc.replySuccess(f"Simulating join event with {timeout}s delay")
|
|
|
|
# Schedule the greeting
|
|
def sendGreeting():
|
|
irc.queueMsg(ircmsgs.privmsg(channel, greeting))
|
|
|
|
schedule.addEvent(sendGreeting, time.time() + timeout)
|
|
|
|
@wrap(['owner', 'boolean'])
|
|
def greetdebug(self, irc, msg, args, enable):
|
|
"""<on|off>
|
|
|
|
Enables or disables debug mode (owner only).
|
|
"""
|
|
self.debugMode = enable
|
|
if enable:
|
|
irc.replySuccess("Debug mode enabled")
|
|
else:
|
|
irc.replySuccess("Debug mode disabled")
|
|
|
|
@wrap(['channel'])
|
|
def resetgreethistory(self, irc, msg, args, channel):
|
|
"""[<channel>]
|
|
|
|
Resets the greeting history for the channel, causing all users to be
|
|
greeted again
|
|
on their next join (even if they were greeted before).
|
|
"""
|
|
# Clear the greeting history for this channel
|
|
for userKey in list(self.greetedUsers.keys()):
|
|
if channel in self.greetedUsers[userKey]:
|
|
self.greetedUsers[userKey].remove(channel)
|
|
# If this user has no more channels, remove the entry
|
|
# completely
|
|
if not self.greetedUsers[userKey]:
|
|
del self.greetedUsers[userKey]
|
|
if userKey in self.userGreetingVersion:
|
|
del self.userGreetingVersion[userKey]
|
|
|
|
irc.replySuccess(f"Greeting history for {channel} has been reset.")
|
|
|
|
@wrap(['channel'])
|
|
def greeton(self, irc, msg, args, channel):
|
|
"""[<channel>]
|
|
|
|
Enables greetings for a channel.
|
|
"""
|
|
self.setRegistryValue('enabled', True, channel)
|
|
greeting = self.registryValue('message', channel)
|
|
if greeting:
|
|
irc.replySuccess(f"Greetings enabled for {channel}. Current greeting: \"{greeting}\"")
|
|
else:
|
|
irc.error(f"Greetings enabled for {channel}, but no greeting message is set.")
|
|
|
|
@wrap(['channel'])
|
|
def greetoff(self, irc, msg, args, channel):
|
|
"""[<channel>]
|
|
|
|
Disables greetings for a channel.
|
|
"""
|
|
self.setRegistryValue('enabled', False, channel)
|
|
irc.replySuccess(f"Greetings disabled for {channel}.")
|
|
|
|
@wrap(['channel'])
|
|
def greetclear(self, irc, msg, args, channel):
|
|
"""[<channel>]
|
|
|
|
Removes the greeting message for a channel.
|
|
"""
|
|
self.setRegistryValue('message', '', channel)
|
|
self.setRegistryValue('enabled', False, channel)
|
|
irc.replySuccess(f"Greeting message cleared and disabled for {channel}.")
|
|
|
|
@wrap(['channel'])
|
|
def greetstatus(self, irc, msg, args, channel):
|
|
"""[<channel>]
|
|
|
|
Shows the current greeting status and message for a channel.
|
|
"""
|
|
enabled = self.registryValue('enabled', channel)
|
|
message = self.registryValue('message', channel)
|
|
timeout = self.registryValue('timeout', channel) or 3
|
|
|
|
# Count how many users have been greeted in this channel
|
|
greetedCount = sum(1 for userKey in self.greetedUsers if channel in
|
|
self.greetedUsers[userKey])
|
|
|
|
if enabled and message:
|
|
irc.reply(f"Greetings are enabled for {channel}. Timeout: {timeout} seconds. Message: \"{message}\"")
|
|
irc.reply(f"Users greeted in this session: {greetedCount}")
|
|
elif enabled and not message:
|
|
irc.reply(f"Greetings are enabled for {channel}, but no message is set.")
|
|
else:
|
|
irc.reply(f"Greetings are disabled for {channel}. Message: \"{message or 'None'}\"")
|
|
|
|
@wrap(['channel', 'positiveInt'])
|
|
def greettimeout(self, irc, msg, args, channel, seconds):
|
|
"""[<channel>] <seconds>
|
|
|
|
Sets the timeout in seconds between joins before sending a greeting.
|
|
Default is 3 seconds.
|
|
"""
|
|
self.setRegistryValue('timeout', seconds, channel)
|
|
irc.replySuccess(f"Greeting timeout for {channel} set to {seconds} seconds.")
|
|
|
|
@wrap(['channel', 'text'])
|
|
def greet(self, irc, msg, args, channel, text):
|
|
"""[<channel>] <message>
|
|
|
|
Sets the greeting message for a channel.
|
|
The greeting will be sent when users join the channel for the first
|
|
time
|
|
in a session. If the greeting message changes, users will be greeted
|
|
again.
|
|
|
|
To manage greetings, use the other commands:
|
|
greeton - Enables greetings for the channel
|
|
greetoff - Disables greetings for the channel
|
|
greetclear - Removes the greeting message for the channel
|
|
greetdebug on|off - Enables/disables debug mode (owner only)
|
|
greettest - Immediately sends the greeting to test the message
|
|
greettrigger - Simulates a join event with timeout (owner only)
|
|
greetstatus - Shows current status and message
|
|
greettimeout <seconds> - Sets delay before greeting
|
|
resetgreethistory - Resets who has been greeted, greeting everyone
|
|
again
|
|
|
|
Examples:
|
|
greet #channel Welcome to our channel!
|
|
"""
|
|
oldGreeting = self.registryValue('message', channel)
|
|
self.setRegistryValue('message', text, channel)
|
|
self.setRegistryValue('enabled', True, channel)
|
|
|
|
# If greeting message has changed, reset who has been greeted with this
|
|
# message
|
|
if oldGreeting != text:
|
|
# Mark that the greeting has changed by removing this channel from
|
|
# all users' greeted lists
|
|
for userKey in list(self.greetedUsers.keys()):
|
|
if channel in self.greetedUsers[userKey]:
|
|
self.greetedUsers[userKey].remove(channel)
|
|
# If this user has no more channels, remove the entry
|
|
# completely
|
|
if not self.greetedUsers[userKey]:
|
|
del self.greetedUsers[userKey]
|
|
if userKey in self.userGreetingVersion:
|
|
del self.userGreetingVersion[userKey]
|
|
|
|
irc.replySuccess(f"Greeting message for {channel} set to: \"{text}\" (greeting history reset)")
|
|
else:
|
|
irc.replySuccess(f"Greeting message for {channel} set to: \"{text}\"")
|
|
|
|
Class = Greet
|
|
|
|
# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79:
|