import hexchat __module_name__ = "FloatLimit" __module_version__ = "1.3" __module_description__ = "Maintains a float limit (+l users+1) for specific channels on AustNet" # Configuration ALLOWED_SERVERS = ["austnet.org"] # Matches any server containing this string ALLOWED_CHANNELS = ["#aussiechat"] # Start empty, use /floatlimit add #channel timers = {} channel_limits = {} def is_allowed_context(context): server = context.get_info("server") channel = context.get_info("channel") if not server or not channel: return False server = server.lower() channel = channel.lower() server_allowed = any(allowed.lower() in server for allowed in ALLOWED_SERVERS) # If ALLOWED_CHANNELS is empty, we don't allow anything (as requested: "not all") channel_allowed = any(allowed.lower() == channel for allowed in ALLOWED_CHANNELS) return server_allowed and channel_allowed def is_op(context): if not is_allowed_context(context): return False my_nick = context.get_info("nick") users = context.get_list("users") if not users: return False for user in users: if user.nick == my_nick: # Check for @ (Op), % (Half-Op), & (Admin), ~ (Owner) return bool(user.prefix and any(p in user.prefix for p in '@~&%')) return False def update_limit(context): if not context or not is_op(context): return users = context.get_list("users") if not users: return channel = context.get_info("channel") server = context.get_info("server") if not channel or not server: return key = f"{server}-{channel}" new_limit = len(users) + 1 if channel_limits.get(key) != new_limit: context.command(f"MODE {channel} +l {new_limit}") channel_limits[key] = new_limit def on_join(word, word_eol, userdata): context = hexchat.get_context() if not is_allowed_context(context): return hexchat.PRI_NORM channel = context.get_info("channel") server = context.get_info("server") key = f"{server}-{channel}" if key in timers: hexchat.unhook(timers[key]) def timer_cb(userdata): update_limit(context) if key in timers: del timers[key] return 0 timers[key] = hexchat.hook_timer(30000, timer_cb) return hexchat.PRI_NORM def on_part_or_kick(word, word_eol, userdata): context = hexchat.get_context() if not is_allowed_context(context): return hexchat.PRI_NORM def delayed_update(userdata): update_limit(context) return 0 hexchat.hook_timer(500, delayed_update) return hexchat.PRI_NORM def on_quit(word, word_eol, userdata): def delayed_update(userdata): for chan in hexchat.get_list("channels"): if chan.type == 2 and is_allowed_context(chan.context): update_limit(chan.context) return 0 hexchat.hook_timer(500, delayed_update) return hexchat.PRI_NORM def floatlimit_cb(word, word_eol, userdata): global ALLOWED_CHANNELS if len(word) < 2: print(f"FloatLimit: Current channels: {', '.join(ALLOWED_CHANNELS) if ALLOWED_CHANNELS else 'None'}") print("Usage: /floatlimit add #channel | /floatlimit del #channel") return hexchat.EAT_ALL cmd = word[1].lower() if cmd == "add" and len(word) > 2: chan = word[2].lower() if chan not in ALLOWED_CHANNELS: ALLOWED_CHANNELS.append(chan) print(f"FloatLimit: Added {chan}") update_limit(hexchat.get_context()) elif cmd == "del" and len(word) > 2: chan = word[2].lower() if chan in ALLOWED_CHANNELS: ALLOWED_CHANNELS.remove(chan) print(f"FloatLimit: Removed {chan}") return hexchat.EAT_ALL hexchat.hook_print("Join", on_join) hexchat.hook_print("Part", on_part_or_kick) hexchat.hook_print("Part with Reason", on_part_or_kick) hexchat.hook_print("Kick", on_part_or_kick) hexchat.hook_print("Quit", on_quit) hexchat.hook_command("floatlimit", floatlimit_cb, help="/floatlimit add|del #channel") print(f"{__module_name__} v{__module_version__} loaded. Use /floatlimit add #channel to enable it.")