diff --git a/config.ini.example b/config.ini.example index 6779fa6..8116716 100644 --- a/config.ini.example +++ b/config.ini.example @@ -393,6 +393,7 @@ pong = "Ping!" # file. = path to text file # prefix. = string prepended to the chosen line (often an emoji) # channel. or channels. = comma-separated channel names; if set, trigger only works in those channels (e.g. channel.momjoke = #jokes) +# category. = 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 diff --git a/docs/configuration.md b/docs/configuration.md index c0dd954..5aa969e 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -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.`, `file.`, optional `prefix.`, optional channel restriction (`channel.`/`channels.`), and optional website category override (`category.`). Website command reference groups RandomLine entries under **Fun Commands** by default unless `category.` is set. Common per-command options (when supported by that command): diff --git a/generate_website.py b/generate_website.py index c9fabd1..4b8a201 100755 --- a/generate_website.py +++ b/generate_website.py @@ -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 diff --git a/tests/test_generate_website_randomline.py b/tests/test_generate_website_randomline.py new file mode 100644 index 0000000..033cdfa --- /dev/null +++ b/tests/test_generate_website_randomline.py @@ -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