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.")
We use cookies to run the site, measure traffic, and (with your permission) show more relevant content and ads.
You can change your preferences at any time.
Choose what you allow. Strictly necessary cookies may still be used even if you decline.
The numbers below reflect only first-party cookies detected in your browser.
Current status—
Cookies detected (first-party)0
This counter only lists first-party cookies visible via document.cookie.
Depending on your browser or ad blocker, it may stay at 0 until cookies are set (usually after consent + reload).
Third-party cookies are not detectable here.
Last updated—
Analytics
0 detected • 0 known
Measures site traffic (page views, visit duration, errors) to help improve the site. Example: Google Analytics or equivalent tags.
View detected cookies
Functional
0 detected • 0 known
Remembers your choices and enhances your experience (preferences, security, sessions). Disabling may degrade some features.
View detected cookies
Advertising
0 detected • 0 known
Used to measure campaigns, limit repetition, and show more relevant ads (subject to your consent).
View detected cookies
Security (always on)
Anti-abuse protection, site security
Enabled
Some strictly necessary storage may be used to protect the site (e.g. fraud prevention / security).
Unknown / Other
0 detected
Info
Cookies that don't match any known category. These may come from browser extensions,
third-party scripts, or services not yet classified. Their origin is shown when possible.
View detected cookies
Third-Party Services
0 detected on page
Scan
Third-party scripts and services loaded on this page. These may set their own cookies
which are not readable via document.cookie due to browser security.