Added final updates in preparation for v1.0.0 release.
- Added uv as the installation and run method, replacing pip. - Added default_cooldown configuration option for custom commands. - Added ctx.commands.prefix and ctx.commands.module_commands properties. - Added ctx.events dynamic registration methods table. - Added ctx.storage.transaction() context manager documentation. - Added OwncastClient.base_url property. - Added note that service wrapper types are importable from owlbot.api. - Added full international timezone list with Wikipedia reference. - Updated module_name description to cover package modules. - Fixed cron library reference from croniter to cronsim.
@@ -95,4 +95,5 @@ modules:
|
||||
|
||||
| Key | Default | Description |
|
||||
|-----|---------|-------------|
|
||||
| `default_cooldown` | `5` | Default cooldown in seconds for newly created custom commands. |
|
||||
| `max_nesting_depth` | `4` | Maximum nesting depth for placeholders. `$(` tokens encountered at or beyond this depth are treated as literal text. |
|
||||
|
||||
+1
-1
@@ -100,7 +100,7 @@ For example: `Dec 25 2025 12:00:00 AM EST`
|
||||
|
||||
If the target date is in the past for `$(countdown)`, it returns "0 seconds". The same applies to `$(countup)` when the date is in the future.
|
||||
|
||||
**Supported timezones:** UTC, GMT, EST, EDT, CST, CDT, MST, MDT, PST, PDT, AKST, AKDT, HST.
|
||||
**Supported timezones ([full list](https://en.wikipedia.org/wiki/List_of_time_zone_abbreviations)):** ACDT, ACST, ACT, ACWST, ADT, AEDT, AEST, AFT, AKDT, AKST, ALMT, AMST, AMT, ANAT, AQTT, ART, AST, AWST, AZOST, AZOT, AZT, BIT, BIOT, BNT, BOT, BRST, BRT, BST, BTT, CAT, CCT, CDT, CEST, CET, CHADT, CHAST, CHOT, CHOST, CHST, CHUT, CIST, CKT, CLST, CLT, COST, COT, CST, CVT, CWST, CXT, DAVT, DDUT, DFT, EASST, EAST, EAT, ECT, EDT, EEST, EET, EGST, EGT, EST, FET, FJT, FKST, FKT, FNT, GALT, GAMT, GET, GFT, GILT, GIT, GMT, GST, GYT, HAEC, HDT, HKT, HMT, HOVST, HOVT, HST, ICT, IDLW, IDT, IOT, IRDT, IRKT, IRST, IST, JST, KALT, KGT, KOST, KRAT, KST, LHST, LINT, MAGT, MART, MAWT, MDT, MEST, MET, MHT, MIST, MIT, MMT, MSK, MST, MUT, MVT, MYT, NCT, NDT, NFT, NOVT, NPT, NST, NT, NUT, NZDT, NZDST, NZST, OMST, ORAT, PDT, PET, PETT, PGT, PHOT, PHST, PHT, PKT, PMDT, PMST, PONT, PST, PWT, PYST, PYT, RET, ROTT, SAKT, SAMT, SAST, SBT, SCT, SDT, SGT, SLST, SRET, SRT, SST, SYOT, TAHT, TFT, THA, TJT, TKT, TLT, TMT, TOT, TRT, TST, TVT, ULAST, ULAT, UTC, UYST, UYT, UZT, VET, VLAT, VOLT, VOST, VUT, WAKT, WAST, WAT, WEST, WET, WGST, WGT, WIB, WIT, WITA, WST, YAKT, YEKT.
|
||||
|
||||
## Cooldowns
|
||||
|
||||
|
||||
+9
-7
@@ -21,18 +21,20 @@ Owlbot's core is a framework for building and running modules. If the included m
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- **Python 3.10+**
|
||||
- **[uv](https://docs.astral.sh/uv/getting-started/installation/)** — handles Python and dependency management automatically
|
||||
- A running **Owncast 0.2.4** instance
|
||||
|
||||
### 1. Installation
|
||||
|
||||
Install Owlbot and its dependencies using pip. This procedure assumes Owlbot is being installed on the same system as Owncast, but this is not a requirement.
|
||||
Clone the repository and install dependencies. This procedure assumes Owlbot is being installed on the same system as Owncast, but this is not a requirement.
|
||||
|
||||
```bash
|
||||
pip install git+https://git.logal.dev/LogalDeveloper/Owlbot.git@v1.0.0
|
||||
git clone --branch v1.0.0 https://git.logal.dev/LogalDeveloper/Owlbot.git
|
||||
cd Owlbot
|
||||
uv sync
|
||||
```
|
||||
|
||||
This also installs a set of default modules.
|
||||
`uv sync` installs the correct Python version, creates a virtual environment, and installs all dependencies. This also installs a set of default modules.
|
||||
|
||||
### 2. Access Token
|
||||
|
||||
@@ -65,7 +67,7 @@ These instructions assume Owlbot is running on the same system as Owncast.
|
||||
1. Run the below command to generate the webhook URL. This is used by Owncast to send events to Owlbot.
|
||||
|
||||
```
|
||||
$ owlbot --webhook-path
|
||||
$ uv run owlbot --webhook-path
|
||||
http://127.0.0.1:8081/webhook/TyeKM7ciVtaM0Zsb49akoRdJYKpdbxCD98neteUtU-c
|
||||
```
|
||||
|
||||
@@ -100,10 +102,10 @@ stream.logal.dev {
|
||||
|
||||
### 6. Running
|
||||
|
||||
Start Owlbot from the directory containing your `config.yaml`:
|
||||
Start Owlbot from the directory containing your `config.yaml`. `uv run` executes the command inside the project's virtual environment.
|
||||
|
||||
```bash
|
||||
owlbot
|
||||
uv run owlbot
|
||||
```
|
||||
|
||||
### 7. Verify
|
||||
|
||||
+5
-5
@@ -7,8 +7,8 @@ Owlbot logs startup information, errors, and runtime activity to help with troub
|
||||
`INFO` logs high-level events: startup, configuration, module loading, and errors. `DEBUG` adds internal details like event dispatch, storage operations, and handler execution, which is useful for troubleshooting.
|
||||
|
||||
```bash
|
||||
owlbot # INFO level
|
||||
owlbot -v # DEBUG level
|
||||
uv run owlbot # INFO level
|
||||
uv run owlbot -v # DEBUG level
|
||||
```
|
||||
|
||||
## File Logging
|
||||
@@ -18,8 +18,8 @@ Setting `log_dir` causes Owlbot to write an `owlbot.log` file to that directory
|
||||
The directory can be configured via the config file, environment variable, or CLI flag:
|
||||
|
||||
```bash
|
||||
owlbot -l logs/ # CLI flag
|
||||
OWLBOT_LOG_DIR=logs/ owlbot # environment variable
|
||||
uv run owlbot -l logs/ # CLI flag
|
||||
OWLBOT_LOG_DIR=logs/ uv run owlbot # environment variable
|
||||
```
|
||||
|
||||
```yaml
|
||||
@@ -35,5 +35,5 @@ If the directory does not exist, it is created automatically. If the path is not
|
||||
Owlbot uses a hierarchical naming scheme rooted at `owlbot`. Module loggers are named `owlbot.modules.<module_name>`, so log output from a module called `ping` appears as `owlbot.modules.ping`. This makes it straightforward to filter output with standard tools:
|
||||
|
||||
```bash
|
||||
owlbot -v | grep "owlbot.modules.ping"
|
||||
uv run owlbot -v | grep "owlbot.modules.ping"
|
||||
```
|
||||
|
||||
@@ -108,6 +108,8 @@ async def setup(ctx: ModuleContext) -> None:
|
||||
| `ctx.commands.unregister(name)` | Remove a command by name. Only works for commands owned by the calling module. |
|
||||
| `ctx.commands.get(name)` | Get a `CommandInfo` for a command by name or alias. Only returns commands owned by the calling module. |
|
||||
| `ctx.commands.exists(name)` | Check if a command name or alias is registered by any module. |
|
||||
| `ctx.commands.prefix` | Property: the command prefix character (e.g., `"!"`). |
|
||||
| `ctx.commands.module_commands` | Property: dict of commands registered by this module only (maps name to `CommandInfo`). |
|
||||
|
||||
`CommandInfo` has these fields:
|
||||
|
||||
|
||||
+3
-1
@@ -18,7 +18,7 @@ async def setup(ctx: ModuleContext) -> None:
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `module_name` | `str` | The module's name (filename without `.py`). |
|
||||
| `module_name` | `str` | The module's name (filename without `.py` for single-file modules, or directory name for packages). |
|
||||
| `config` | `ModuleConfig` | Module-scoped configuration ([details](Modules-Config)). |
|
||||
| `owncast_client` | `OwncastClient` | Owncast Integration API client ([details](Modules-Owncast-API)). |
|
||||
| `storage` | `ModuleStorage` | Per-module SQLite storage ([details](Modules-Storage)). |
|
||||
@@ -31,6 +31,8 @@ async def setup(ctx: ModuleContext) -> None:
|
||||
|
||||
`ModuleContext` is a dataclass. All fields except `logger` are set during construction. `logger` is derived from `module_name` in `__post_init__`.
|
||||
|
||||
The service wrapper types (`ModuleCommands`, `ModuleEvents`, `ModuleRoutes`) are importable from `owlbot.api` for use in type annotations on helper functions:
|
||||
|
||||
## EventContext\[E\]
|
||||
|
||||
Event handlers receive an `EventContext` parameterized by the event type. It wraps the event data and provides access to all services from `ModuleContext`:
|
||||
|
||||
+8
-1
@@ -92,7 +92,14 @@ async def setup(ctx: ModuleContext) -> None:
|
||||
)
|
||||
```
|
||||
|
||||
`ctx.events.register()` takes a handler function, a tuple of event types, and an optional priority. `ctx.events.unregister()` is available for removing handlers mid-runtime.
|
||||
### Available Methods
|
||||
|
||||
| Method | Description |
|
||||
|--------|-------------|
|
||||
| `ctx.events.register(handler, event_types, priority=...)` | Register a handler for one or more event types. The module name is automatically supplied. |
|
||||
| `ctx.events.unregister(handler)` | Remove a handler from all event types. Only works for handlers owned by the calling module. |
|
||||
| `ctx.events.get(event_type)` | Get handlers registered by this module for a specific event type. |
|
||||
| `ctx.events.module_events` | Property: all handlers registered by this module, grouped by event type. |
|
||||
|
||||
## Event Types
|
||||
|
||||
|
||||
@@ -62,6 +62,7 @@ clients = await ctx.owncast_client.get_connected_clients()
|
||||
|
||||
| Method | Description |
|
||||
|--------|-------------|
|
||||
| `base_url` | Property: the Owncast server base URL. |
|
||||
| `send_message(body)` | Send a chat message visible to all. |
|
||||
| `send_system_message(body)` | Send a system message visible to all. |
|
||||
| `send_action(body)` | Send an action message (like IRC `/me`). |
|
||||
|
||||
@@ -125,6 +125,15 @@ Never use f-strings or string formatting for SQL parameters. This prevents SQL i
|
||||
|
||||
Each handler invocation runs inside a single transaction. All storage operations within the handler share that transaction. If the handler completes normally, everything is committed together. If it raises an exception, everything is rolled back. No manual commit or rollback is needed.
|
||||
|
||||
For finer-grained control within a handler, use the `transaction()` context manager to group operations that should succeed or fail together independently of the rest of the handler:
|
||||
|
||||
```python
|
||||
async with ctx.storage.transaction():
|
||||
await ctx.storage.execute("UPDATE balances SET amount = amount - ?", (cost,))
|
||||
await ctx.storage.execute("INSERT INTO purchases (item) VALUES (?)", (item,))
|
||||
# Both committed together on success, or both rolled back if either fails
|
||||
```
|
||||
|
||||
## Connection Pooling
|
||||
|
||||
Storage uses a connection pool with lazy creation. Connections are created on-demand up to `pool_size` (default 4, configurable in `config.yaml` under `owlbot.pool_size`). WAL (Write-Ahead Logging) mode is enabled on all connections so concurrent readers and a single writer don't block each other.
|
||||
|
||||
+1
-1
@@ -56,7 +56,7 @@ A single token combining hours, minutes, and/or seconds. Minimum interval is 30
|
||||
|
||||
### Cron Expressions
|
||||
|
||||
Standard 5-field cron expressions for precise scheduling. Minimum gap between firings is 1 minute. Uses the [croniter](https://github.com/kiorky/croniter) library for parsing.
|
||||
Standard 5-field cron expressions for precise scheduling. Minimum gap between firings is 1 minute. Uses the [cronsim](https://github.com/cuu508/cronsim) library for parsing.
|
||||
|
||||
| Example | Schedule |
|
||||
|---------|----------|
|
||||
|
||||
Reference in New Issue
Block a user