> [!IMPORTANT] > This project was developed entirely with AI coding assistance (Claude Opus 4.6 via Cursor IDE) and has not undergone rigorous human review. It is provided as-is and may require adjustments for other environments. # owncast-irc-bridge Bidirectional chat bridge between [Owncast](https://owncast.online/) and IRC. Messages sent in your Owncast chat appear in an IRC channel and vice versa. ## Quick Start (Docker Compose) **1. Create your config file** ```bash cp config.example.toml config.toml ``` Edit `config.toml` with your IRC server/channel and Owncast URL. **2. Get an Owncast access token** In your Owncast admin panel, go to **Integrations > Access Tokens** and create a token with "send messages" permission. **3. Set the token** ```bash export OWNCAST_ACCESS_TOKEN="your-token-here" ``` Or create a `.env` file (git-ignored): ``` OWNCAST_ACCESS_TOKEN=your-token-here WEBHOOK_SECRET=some-random-secret ``` **4. Configure the Owncast webhook** In your Owncast admin, go to **Integrations > Webhooks** and add a webhook pointing to: ``` http://:9078/webhook?secret=some-random-secret ``` If `WEBHOOK_SECRET` is set, the bridge rejects any request that doesn't include a matching `?secret=` query parameter. If unset, all requests are accepted (a warning is logged at startup). Select the events: **Chat Message**, **Stream Started**, **Stream Stopped**. **5. Run it** ```bash docker compose up -d ``` Check logs: ```bash docker compose logs -f ``` ## Running Without Docker Requires Rust 1.75+. ```bash cargo build --release export OWNCAST_ACCESS_TOKEN="your-token-here" ./target/release/owncast-irc-bridge --config config.toml ``` ## Configuration See [`config.example.toml`](config.example.toml) for all options. The only required sections are `[irc]` (with `server` and `channel`) and `[owncast]` (with `url`). Everything else has defaults. | Section | Key | Default | Description | |---------|-----|---------|-------------| | `irc` | `server` | *(required)* | IRC server hostname | | `irc` | `port` | `6667` | IRC server port | | `irc` | `tls` | `false` | Use TLS for IRC | | `irc` | `nick` | `owncast-bridge` | IRC nickname | | `irc` | `channel` | *(required)* | IRC channel to join | | `owncast` | `url` | *(required)* | Owncast instance URL | | `owncast` | `webhook_port` | `9078` | Port the webhook server listens on | | `owncast` | `websocket_enabled` | `false` | Also connect via WebSocket (redundant with webhook, useful as fallback) | | `owncast` | `health_poll_interval_secs` | `30` | How often to poll Owncast status | | `bridge` | `irc_prefix` | `[IRC]` | Prefix for IRC messages in Owncast | | `bridge` | `owncast_prefix` | `[OC]` | Prefix for Owncast messages in IRC | | `control` | `socket_path` | `/tmp/owncast-irc-bridge.sock` | Unix socket for `bridge-ctl` | Secrets are always read from environment variables (not the config file): | Variable | Required | Description | |----------|----------|-------------| | `OWNCAST_ACCESS_TOKEN` | Yes | Owncast integration API token | | `IRC_PASSWORD` | No | IRC server password (PASS command) | | `WEBHOOK_SECRET` | No | Shared secret for webhook authentication | ## Runtime Control Use `bridge-ctl` to interact with a running bridge: ```bash bridge-ctl status # Show bridge status as JSON bridge-ctl irc reconnect # Reconnect to IRC bridge-ctl owncast reconnect # Reconnect to Owncast bridge-ctl quit # Shut down the bridge ``` Inside Docker: ```bash docker compose exec bridge bridge-ctl status ``` ## How It Works - **Owncast → IRC:** Owncast sends webhook events to the bridge. The bridge formats the message and sends it to IRC via PRIVMSG. - **IRC → Owncast:** The bridge listens for PRIVMSG in the configured channel and posts to Owncast via the integration API. - **Deduplication:** If both webhook and WebSocket are enabled, duplicate messages are detected by ID and dropped. - **Echo suppression:** Messages the bridge itself sent are recognized and not re-bridged. - **Stream events:** Stream start/stop events are announced in IRC. - **Health polling:** The bridge polls Owncast's `/api/status` endpoint and announces state changes in IRC.