feat: add RandomLine command support for website generation

Introduced a new command structure for RandomLine entries in the website generation process, allowing for dynamic rendering of random lines based on configuration. Updated the configuration file to include a new category option for commands and enhanced documentation to reflect these changes. This addition improves the command reference organization and user experience on the website.
This commit is contained in:
agessaman
2026-04-15 09:40:39 -07:00
parent 90fdd0c77a
commit a4d5f5478b
4 changed files with 144 additions and 0 deletions

View File

@@ -393,6 +393,7 @@ pong = "Ping!"
# file.<key> = path to text file
# prefix.<key> = string prepended to the chosen line (often an emoji)
# channel.<key> or channels.<key> = comma-separated channel names; if set, trigger only works in those channels (e.g. channel.momjoke = #jokes)
# category.<key> = command reference category for website generation (default: fun/Fun Commands)
# default prefix (blank = no prefix)
prefix.default =
@@ -402,16 +403,19 @@ triggers.momjoke = momjoke,momjokes,mom joke,mom jokes,mom-joke,mom-jokes
file.momjoke = data/randomlines/momjokes.txt
prefix.momjoke = 🥸
# channel.momjoke = #jokes
# category.momjoke = fun
# Fun Facts
triggers.funfact = funfact,funfacts,fun fact,fun facts,fun-fact,fun-facts
file.funfact = data/randomlines/funfacts.txt
prefix.funfact = 💡
category.funfact = fun
# Example: fortunes via RandomLine
#triggers.fortune = fortune,fortunes
#file.fortune = data/randomlines/fortunes.txt
#prefix.fortune = 🥠
#category.fortune = fun
[Scheduled_Messages]
# Scheduled message format: HHMM = channel:message

View File

@@ -108,6 +108,7 @@ Examples of sections that configure specific commands or features:
- **`[Alert_Command]`** Emergency alerts (agency IDs, etc.).
- **`[Sports_Command]`** Sports scores (teams, leagues).
- **`[Joke_Command]`**, **`[DadJoke_Command]`** Joke sources and options.
- **`[RandomLine]`** Trigger-based random-line responses via `triggers.<key>`, `file.<key>`, optional `prefix.<key>`, optional channel restriction (`channel.<key>`/`channels.<key>`), and optional website category override (`category.<key>`). Website command reference groups RandomLine entries under **Fun Commands** by default unless `category.<key>` is set.
Common per-command options (when supported by that command):

View File

@@ -965,6 +965,85 @@ def get_website_title(config: configparser.ConfigParser) -> str:
return f"{bot_name} - Command Reference"
class WebsiteRandomLineCommand:
"""Command-like object used to render RandomLine entries on the website."""
def __init__(
self,
key: str,
triggers: list[str],
category: str,
usage: str,
description: str,
allowed_channels: Optional[list[str]] = None
):
self.name = key
self.keywords = triggers
self.category = category
self.description = description
self.allowed_channels = allowed_channels
self._usage = usage
def get_usage_info(self) -> dict[str, Any]:
return {
'usage': self._usage,
'short_description': self.description,
'description': self.description,
'examples': [],
'parameters': [],
'subcommands': [],
}
def normalize_category_name(category_name: str) -> str:
"""Normalize category names to lowercase underscore style."""
return category_name.strip().lower().replace('-', '_').replace(' ', '_')
def get_randomline_commands(config: configparser.ConfigParser) -> dict[str, Any]:
"""Build website command entries from [RandomLine] triggers."""
randomline_commands: dict[str, Any] = {}
if not config.has_section('RandomLine'):
return randomline_commands
command_prefix = config.get('Bot', 'command_prefix', fallback='').strip()
for option, value in config.items('RandomLine'):
if not option.startswith('triggers.'):
continue
key = option.split('.', 1)[1].strip()
if not key:
continue
triggers = [trigger.strip() for trigger in value.split(',') if trigger.strip()]
if not triggers:
continue
category_override = config.get('RandomLine', f'category.{key}', fallback='').strip()
category = normalize_category_name(category_override) if category_override else 'fun'
display_trigger = triggers[0]
usage = f"{command_prefix}{display_trigger}" if command_prefix else display_trigger
channel_opt = config.get('RandomLine', f'channel.{key}', fallback='').strip()
if not channel_opt:
channel_opt = config.get('RandomLine', f'channels.{key}', fallback='').strip()
allowed_channels = [ch.strip() for ch in channel_opt.split(',') if ch.strip()] if channel_opt else None
description = "Returns a random line from a configured text list."
randomline_commands[f"randomline.{key}"] = WebsiteRandomLineCommand(
key=key,
triggers=triggers,
category=category,
usage=usage,
description=description,
allowed_channels=allowed_channels,
)
return randomline_commands
def load_channels_from_config(config: configparser.ConfigParser) -> dict[str, dict[str, str]]:
"""Load channels from Channels_List section, grouped by category
@@ -2479,6 +2558,7 @@ def generate_samples(config_file):
name: cmd for name, cmd in commands.items()
if name not in admin_commands and not getattr(cmd, 'hidden', False)
}
public_commands.update(get_randomline_commands(config))
# Sort commands
sorted_commands = sorted(public_commands.items(), key=lambda x: x[0])
@@ -2714,6 +2794,7 @@ def main():
# Filter out admin and hidden commands
filtered_commands = filter_commands(commands, admin_commands)
filtered_commands.update(get_randomline_commands(config))
logger.info(f"Filtered to {len(filtered_commands)} public commands")
# Log which commands are included

View File

@@ -0,0 +1,58 @@
import configparser
from generate_website import generate_html, get_randomline_commands
def _build_config() -> configparser.ConfigParser:
config = configparser.ConfigParser()
config.add_section("Bot")
config.set("Bot", "command_prefix", "!")
config.add_section("RandomLine")
config.set("RandomLine", "prefix.default", "")
return config
def test_get_randomline_commands_defaults_to_fun_category():
config = _build_config()
config.set("RandomLine", "triggers.momjoke", "momjoke,mom joke")
config.set("RandomLine", "file.momjoke", "data/randomlines/momjokes.txt")
randomline_commands = get_randomline_commands(config)
command = randomline_commands["randomline.momjoke"]
assert command.name == "momjoke"
assert command.category == "fun"
assert command.keywords == ["momjoke", "mom joke"]
assert command.get_usage_info()["usage"] == "!momjoke"
def test_get_randomline_commands_applies_category_override():
config = _build_config()
config.set("RandomLine", "triggers.funfact", "funfact,fun fact")
config.set("RandomLine", "file.funfact", "data/randomlines/funfacts.txt")
config.set("RandomLine", "category.funfact", "Games And Entertainment")
randomline_commands = get_randomline_commands(config)
command = randomline_commands["randomline.funfact"]
assert command.category == "games_and_entertainment"
def test_generate_html_includes_randomline_commands_in_fun_section():
config = _build_config()
config.set("RandomLine", "triggers.momjoke", "momjoke,mom joke")
config.set("RandomLine", "file.momjoke", "data/randomlines/momjokes.txt")
randomline_commands = get_randomline_commands(config)
html_content = generate_html(
bot_name="TestBot",
title="TestBot - Command Reference",
introduction="Intro",
commands=list(randomline_commands.items()),
monitor_channels=[],
channels_data={},
style="default",
)
assert "Fun Commands" in html_content
assert "momjoke" in html_content