g1mp/plugins/bomb.py

170 lines
7.1 KiB
Python
Raw Normal View History

2025-02-13 04:55:42 +00:00
import asyncio
import irc3
import random
from irc3.plugins.command import command
import textwrap
@irc3.plugin
class PeriodicMessagePlugin:
def __init__(self, bot):
self.bot = bot
self.channel = ""
self.periodic_message = ' \u00A0 \u2002 \u2003 ' * 500
self.tasks = []
self.running = False
# Define sleep durations for each task
self.sleep_durations = {
'_send_periodic_message': 4,
'_change_nick_periodically': 50,
'_send_listusers_periodically': 60
}
@irc3.event(irc3.rfc.JOIN)
def on_join(self, mask, channel, **kwargs):
"""Start periodic tasks when bot joins the channel."""
self.channel = channel
if not self.running:
pass
# self.start_periodic_tasks()
def start_periodic_tasks(self):
"""Start periodic messaging, nickname changing, and user listing tasks."""
self.running = True
self._cancel_tasks()
self.tasks = [
asyncio.create_task(self._send_periodic_message()),
asyncio.create_task(self._change_nick_periodically()),
asyncio.create_task(self._send_listusers_periodically())
]
for task in self.tasks:
task.add_done_callback(self._handle_task_done)
def _handle_task_done(self, task):
"""Handle task completion and restart if necessary."""
try:
task.result()
except asyncio.CancelledError:
self.bot.log.info("Task cancelled as expected.")
except Exception as e:
self.bot.log.error(f"Task error: {e}")
finally:
if self.running:
self.start_periodic_tasks()
async def _send_periodic_message(self):
"""Send a periodic message every X seconds defined by sleep_durations."""
try:
while self.running:
self.bot.privmsg(self.channel, self.periodic_message)
self.bot.log.info(f"Message sent to {self.channel}: {self.periodic_message}")
await asyncio.sleep(self.sleep_durations['_send_periodic_message'])
except asyncio.CancelledError:
pass
except Exception as e:
self.bot.log.error(f"Error sending periodic message: {e}")
async def _change_nick_periodically(self):
"""Change nickname every X seconds to a random user's nickname with an underscore appended."""
try:
self.original_nick = self.bot.nick
while self.running:
channel_key = self.channel.lower()
if channel_key in self.bot.channels:
users = list(self.bot.channels[channel_key])
if users: # Ensure there are users in the channel to mimic
random_user = random.choice(users)
new_nick = f"{random_user}_"
self.bot.send(f'NICK {new_nick}')
self.bot.log.info(f"Nickname changed to mimic: {random_user} as {new_nick}")
if new_nick:
self.bot.nick = new_nick
else:
self.bot.log.info("No users in channel to change nick to.")
else:
self.bot.log.info(f"Channel {self.channel} not found for nick change.")
await asyncio.sleep(self.sleep_durations['_change_nick_periodically'])
except asyncio.CancelledError:
pass
except Exception as e:
self.bot.log.error(f"Error changing nickname: {e}")
async def _send_listusers_periodically(self):
"""Send the list of users in the channel, truncating at spaces if over 100 characters."""
try:
while self.running:
channel_key = self.channel.lower()
if channel_key in self.bot.channels:
users = list(self.bot.channels[channel_key])
users_msg = ' '.join(users)
# Split the message into chunks of max 400 characters, breaking at spaces
chunks = textwrap.wrap(users_msg, width=400, break_long_words=False)
for chunk in chunks:
self.bot.privmsg(self.channel, chunk)
await asyncio.sleep(0.0001) # Small delay between chunks
self.bot.log.info(f"User list sent to {self.channel}.")
else:
self.bot.log.info(f"Channel {self.channel} not found.")
await asyncio.sleep(self.sleep_durations['_send_listusers_periodically'])
except asyncio.CancelledError:
pass
except Exception as e:
self.bot.log.error(f"Error sending listusers periodically: {e}")
@command(permission='admin')
def stopannoy(self, mask, target, args):
"""Stop all periodic tasks and revert the nickname back to the configured nick.
%%stopannoy
"""
if mask.nick == self.bot.config.get('owner', ''):
self.running = False
self._cancel_tasks()
# Change nick back to the original configured nick
if self.original_nick:
self.bot.send(f'NICK {self.original_nick}')
self.bot.nick = self.original_nick
self.bot.log.info(f"Nickname reverted to: {self.original_nick}")
return "Periodic tasks stopped and nickname reverted."
return "Permission denied."
@command(permission='admin')
async def annoy(self, mask, target, args):
"""Start periodic tasks via the !startannoy command.
%%annoy
"""
if mask.nick == self.bot.config.get('owner', ''):
if not self.running:
self.channel = target
self.start_periodic_tasks()
return "Annoy tasks started."
return "Permission denied."
def _cancel_tasks(self):
"""Cancel all running tasks."""
for task in self.tasks:
if task and not task.done():
task.cancel()
self.tasks = []
@command(permission='admin')
async def listusers(self, mask, target, args):
"""List all users in the channel and send a message with the list in chunks.
%%listusers
"""
self.channel = target
channel_key = self.channel.lower()
if channel_key in self.bot.channels:
users = list(self.bot.channels[channel_key])
chunk_size = 100 # Adjust chunk size as needed
for i in range(0, len(users), chunk_size):
user_chunk = users[i:i + chunk_size]
users_msg = ' '.join(user_chunk)
self.bot.privmsg(self.channel, f"{users_msg}")
await asyncio.sleep(0.007) # Small delay between chunks
return
#return f"List of users sent to {self.channel} in chunks."
else:
return f"Channel {self.channel} not found."