# -*- coding: utf-8 -*- """ IRC3 Bot Plugin: Urban Dictionary Search This plugin for an IRC bot allows users to search for terms on Urban Dictionary and post the results to an IRC channel. It uses aiohttp for asynchronous HTTP requests and a queue to manage search requests. Features: - Asynchronously fetches definitions from Urban Dictionary. - Enqueues search requests and processes them one at a time. - Formats and posts the definition, example, and permalink to the IRC channel. Usage: ====== To use this module, load it as a plugin in your IRC bot configuration. Example: @command def urban(self, mask, target, args): %%urban ... Author: Zodiac Date: 2025-02-12 """ import irc3 import aiohttp from irc3.plugins.command import command from irc3.compat import Queue @irc3.plugin class UrbanDictionaryPlugin: """ A plugin to search Urban Dictionary for terms and post results to IRC. This plugin uses a queue to manage asynchronous search requests and ensures proper resource cleanup when unloaded. """ def __init__(self, bot): """ Initialize the plugin with bot reference. Args: bot (irc3.IrcBot): The IRC bot instance. """ self.bot = bot self.queue = Queue() # Queue for managing search requests self.session = None # aiohttp session initialized lazily self.bot.loop.create_task(self._process_queue()) # Start queue processor @command(permission='view', aliases=['ud'], public=True) def urban(self, mask, target, args): """ Search Urban Dictionary for a term. Args: mask (str): The user mask (nickname@host) of the command issuer. target (str): The channel or user where the command was issued. args (dict): Command arguments. Usage: %%urban ... """ term = ' '.join(args['']) if not term: return "Please provide a term to search." # Enqueue the search request self.queue.put_nowait((term, target)) return f"\x02Searching Urban Dictionary\x02 for '\x034{term}\x03'..." async def _process_queue(self): """ Process search requests from the queue asynchronously. This method runs indefinitely, processing one request at a time. """ while True: try: # Get the next search request term, target = await self.queue.get() # Ensure the session is initialized if self.session is None or self.session.closed: self.session = aiohttp.ClientSession(loop=self.bot.loop) # Fetch data from Urban Dictionary API url = f"https://api.urbandictionary.com/v0/define?term={term}" async with self.session.get(url) as response: if response.status != 200: self.bot.privmsg(target, f"\x02Error:\x02 Failed to fetch definition for '\x034{term}\x03'.") continue data = await response.json() if not data.get('list'): self.bot.privmsg(target, f"\x02No definition found\x02 for '\x034{term}\x03'.") continue # Extract the first result result = data['list'][0] definition = result['definition'].replace('\n', ' ').strip() example = result['example'].replace('\n', ' ').strip() permalink = result['permalink'] # Format the response with colors and bold response_message = ( f"\x02[{term}]\x02 \x033{definition}\x03 | " f"Example: \x0312{example}\x03 | " f"More: \x032{permalink}\x03" ) # Send the response to the IRC channel self.bot.privmsg(target, response_message) except Exception as e: self.bot.privmsg(target, f"\x02Error:\x02 An unexpected error occurred: {str(e)}") finally: # Mark the task as done self.queue.task_done() def __unload__(self): """ Cleanup when the plugin is unloaded. Ensures that the aiohttp session is properly closed to avoid resource leaks. """ if self.session and not self.session.closed: self.bot.loop.create_task(self.session.close())