docs: comprehensive documentation overhaul
Rewrite README.md and all setup guides to reflect the current native GraphQL WebSocket architecture (replacing stale headless Chrome/WebSocket interception descriptions). Add new docs/IRC.md with complete IRC command reference, vote syntax, and ticker symbol table. Archive pre-edit docs to docs/archive/setup-backup-2026-05-10/ and move historical development notes from docs/ root into docs/archive/. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
369
README.md
369
README.md
@@ -1,47 +1,55 @@
|
||||
> [!IMPORTANT]
|
||||
> [!IMPORTANT]
|
||||
> This project was developed entirely with AI coding assistance (Claude Opus 4.6 via Cursor IDE) and has not undergone rigorous review. It is provided as-is and may require adjustments for other environments.
|
||||
|
||||
# Kosmi-IRC Relay via Matterbridge
|
||||
|
||||
A Matterbridge plugin that bridges Kosmi chat rooms with IRC channels, enabling bidirectional message relay.
|
||||
A Matterbridge-based bridge that relays messages bidirectionally between Kosmi chat rooms and IRC channels, with optional Jackbox Game Picker integration for live voting and game announcements.
|
||||
|
||||
## Features
|
||||
|
||||
- ✅ Real-time message relay between Kosmi and IRC
|
||||
- ✅ Headless Chrome automation for reliable Kosmi connection
|
||||
- ✅ WebSocket interception using Chrome DevTools Protocol
|
||||
- ✅ Anonymous Kosmi access (no authentication required)
|
||||
- ✅ Message formatting with source indicators
|
||||
- ✅ Automatic reconnection handling
|
||||
- ✅ Support for any Kosmi room via URL configuration
|
||||
- Real-time bidirectional message relay between Kosmi and IRC
|
||||
- Native GraphQL-over-WebSocket connection to Kosmi (no browser required for basic use)
|
||||
- Anonymous or authenticated Kosmi access (email/password login with token caching)
|
||||
- Jackbox Game Picker integration: live vote detection, game announcements, room code images
|
||||
- IRC commands: `!kreconnect`, `!jreconnect`, `!reconnect`, `!votes`
|
||||
- Ticker-symbol voting for specific games (e.g. `QPL3++`, `TMP2--`)
|
||||
- SIGUSR1 mute toggle for Jackbox announcements
|
||||
- Automatic reconnection on connection loss
|
||||
- Docker deployment with persistent token cache
|
||||
|
||||
## Architecture
|
||||
|
||||
This implementation extends Matterbridge with a custom Kosmi bridge that:
|
||||
This project is a trimmed fork of [Matterbridge](https://github.com/42wim/matterbridge) with two registered bridges: **Kosmi** and **IRC**. The Kosmi bridge connects directly to `wss://engine.kosmi.io/gql-ws` using the `graphql-transport-ws` protocol -- no headless browser is needed for the primary connection path.
|
||||
|
||||
1. Launches a headless Chrome instance using `chromedp`
|
||||
2. Navigates to the Kosmi room and injects a WebSocket interceptor **before page load**
|
||||
3. Captures GraphQL WebSocket messages (`wss://engine.kosmi.io/gql-ws`) from the page
|
||||
4. Relays messages bidirectionally with proper formatting:
|
||||
- **Kosmi → IRC**: `[Kosmi] <username> message`
|
||||
- **IRC → Kosmi**: `[IRC] <username> message`
|
||||
### How It Works
|
||||
|
||||
### Why Headless Chrome?
|
||||
1. **Anonymous access** (default): The bridge calls Kosmi's `anonLogin` HTTP mutation to obtain a JWT, then opens a native WebSocket connection.
|
||||
2. **Authenticated access** (optional): If `Email` and `Password` are configured, headless Chrome (chromedp) performs a one-time browser login to extract a JWT. The token is cached locally and reused across restarts.
|
||||
3. **Room subscription**: After connecting, the bridge subscribes to `newMessage` events via GraphQL and joins the configured room.
|
||||
4. **Message relay**: Incoming Kosmi messages are forwarded to IRC (and vice versa) through the Matterbridge gateway, with configurable nick formatting.
|
||||
|
||||
Kosmi's WebSocket API requires browser session cookies and context that are difficult to replicate with a native WebSocket client. Using headless Chrome automation ensures:
|
||||
- ✅ Automatic session management
|
||||
- ✅ Proper cookie handling
|
||||
- ✅ Reliable WebSocket connection
|
||||
- ✅ No authentication complexity
|
||||
### Message Flow
|
||||
|
||||
```
|
||||
IRC User --> IRC Server --> Matterbridge Gateway --> Kosmi GraphQL WS --> Kosmi Room
|
||||
Kosmi User --> Kosmi Room --> GraphQL subscription --> Matterbridge Gateway --> IRC Channel
|
||||
```
|
||||
|
||||
### Jackbox Integration (Optional)
|
||||
|
||||
When enabled, the relay connects to a Jackbox Game Picker API via WebSocket (or webhook fallback) to:
|
||||
|
||||
- Detect `thisgame++`/`thisgame--` votes and ticker-symbol votes in chat
|
||||
- Announce upcoming games with room codes (optionally as uploaded images)
|
||||
- Respond to `!votes` queries with current vote tallies
|
||||
|
||||
## Installation
|
||||
|
||||
### Option 1: Docker (Recommended) 🐳
|
||||
|
||||
The easiest way to run the bridge:
|
||||
### Option 1: Docker (Recommended)
|
||||
|
||||
```bash
|
||||
# 1. Edit configuration
|
||||
# 1. Copy and edit configuration
|
||||
cp matterbridge.toml.example matterbridge.toml
|
||||
nano matterbridge.toml
|
||||
|
||||
# 2. Build and run
|
||||
@@ -51,45 +59,47 @@ docker-compose up -d
|
||||
docker-compose logs -f
|
||||
```
|
||||
|
||||
**See**: `DOCKER_QUICKSTART.md` for 5-minute setup guide
|
||||
See [DOCKER_QUICKSTART.md](docs/setup/DOCKER_QUICKSTART.md) for a 5-minute setup guide.
|
||||
|
||||
### Option 2: Build from Source
|
||||
|
||||
#### Prerequisites
|
||||
|
||||
- Go 1.21 or higher
|
||||
- Chrome or Chromium browser installed
|
||||
- Go 1.23 or higher
|
||||
- Chrome/Chromium (only required if using email/password authentication)
|
||||
- Access to an IRC server
|
||||
- A Kosmi room URL
|
||||
|
||||
#### Building
|
||||
|
||||
```bash
|
||||
# Clone the repository
|
||||
git clone <repository-url>
|
||||
cd irc-kosmi-relay
|
||||
|
||||
# Download dependencies
|
||||
go mod download
|
||||
|
||||
# Build the bridge
|
||||
go build -o matterbridge
|
||||
go build -o matterbridge .
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
Edit `matterbridge.toml` to configure your bridge:
|
||||
Copy `matterbridge.toml.example` to `matterbridge.toml` and edit it. The key sections:
|
||||
|
||||
```toml
|
||||
# Kosmi configuration
|
||||
[kosmi.hyperspaceout]
|
||||
RoomURL="https://app.kosmi.io/room/@hyperspaceout"
|
||||
RoomURL="https://app.kosmi.io/room/@yourroom"
|
||||
# Optional: Email/password for authenticated access
|
||||
# Requires Chrome/Chromium for browser automation
|
||||
Email=""
|
||||
Password=""
|
||||
RemoteNickFormat="[{PROTOCOL}] <{NICK}> "
|
||||
|
||||
# IRC configuration
|
||||
[irc.libera]
|
||||
Server="irc.libera.chat:6667"
|
||||
[irc.zeronode]
|
||||
Server="irc.libera.chat:6697"
|
||||
Nick="kosmi-relay"
|
||||
UseTLS=false
|
||||
UseTLS=true
|
||||
RemoteNickFormat="[{PROTOCOL}] <{NICK}> "
|
||||
|
||||
# Gateway to connect Kosmi and IRC
|
||||
[[gateway]]
|
||||
@@ -101,22 +111,58 @@ account="kosmi.hyperspaceout"
|
||||
channel="main"
|
||||
|
||||
[[gateway.inout]]
|
||||
account="irc.libera"
|
||||
account="irc.zeronode"
|
||||
channel="#your-channel"
|
||||
|
||||
# Jackbox integration (optional)
|
||||
[jackbox]
|
||||
Enabled=false
|
||||
APIURL="https://your-jackbox-api.example.com"
|
||||
AdminPassword=""
|
||||
UseWebSocket=true
|
||||
EnableRoomCodeImage=true
|
||||
RoomCodeImageDelay=28
|
||||
RoomCodePlaintextDelay=22
|
||||
```
|
||||
|
||||
### Configuration Options
|
||||
### Configuration Reference
|
||||
|
||||
#### Kosmi Settings
|
||||
|
||||
- `RoomURL` (required): Full URL to the Kosmi room
|
||||
- Format: `https://app.kosmi.io/room/@roomname` or `https://app.kosmi.io/room/roomid`
|
||||
- `Server` (optional): WebSocket endpoint (default: `wss://engine.kosmi.io/gql-ws`)
|
||||
- `Debug` (optional): Enable debug logging
|
||||
| Key | Required | Description |
|
||||
|-----|----------|-------------|
|
||||
| `RoomURL` | Yes | Full URL to the Kosmi room |
|
||||
| `Email` | No | Email for authenticated access |
|
||||
| `Password` | No | Password for authenticated access |
|
||||
| `RemoteNickFormat` | No | Format for nicks from other bridges |
|
||||
|
||||
#### IRC Settings
|
||||
|
||||
See [Matterbridge IRC documentation](https://github.com/42wim/matterbridge/wiki/Section-IRC-(basic)) for full IRC configuration options.
|
||||
| Key | Required | Description |
|
||||
|-----|----------|-------------|
|
||||
| `Server` | Yes | IRC server address with port |
|
||||
| `Nick` | Yes | Bot's IRC nickname |
|
||||
| `UseTLS` | No | Enable TLS (recommended) |
|
||||
| `SkipTLSVerify` | No | Skip TLS cert verification |
|
||||
| `NickServNick` | No | NickServ service nick |
|
||||
| `NickServPassword` | No | NickServ password |
|
||||
| `UseSASL` | No | Use SASL authentication |
|
||||
| `RemoteNickFormat` | No | Format for nicks from other bridges |
|
||||
| `Channels` | No | Channels to auto-join |
|
||||
|
||||
#### Jackbox Settings
|
||||
|
||||
| Key | Required | Description |
|
||||
|-----|----------|-------------|
|
||||
| `Enabled` | Yes | Enable/disable Jackbox integration |
|
||||
| `APIURL` | Yes | Jackbox Game Picker API URL |
|
||||
| `AdminPassword` | Yes | API admin password for JWT auth |
|
||||
| `UseWebSocket` | No | Use WebSocket transport (default: true) |
|
||||
| `WebhookPort` | No | Webhook listen port (if not using WS) |
|
||||
| `WebhookSecret` | No | HMAC secret for webhook verification |
|
||||
| `EnableRoomCodeImage` | No | Generate room code images |
|
||||
| `RoomCodeImageDelay` | No | Seconds before sending image announcement |
|
||||
| `RoomCodePlaintextDelay` | No | Seconds before sending plaintext room code |
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -126,154 +172,163 @@ See [Matterbridge IRC documentation](https://github.com/42wim/matterbridge/wiki/
|
||||
|
||||
# Run with debug logging
|
||||
./matterbridge -conf matterbridge.toml -debug
|
||||
|
||||
# Start with Jackbox announcements muted
|
||||
./matterbridge -conf matterbridge.toml -muted
|
||||
```
|
||||
|
||||
## How It Works
|
||||
### CLI Flags
|
||||
|
||||
### Kosmi Connection
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `-conf` | Path to config file (default: `matterbridge.toml`) |
|
||||
| `-debug` | Enable debug logging |
|
||||
| `-version` | Show version |
|
||||
| `-muted` | Start with Jackbox announcements muted |
|
||||
| `-gops` | Enable gops diagnostic agent |
|
||||
|
||||
The bridge connects to Kosmi using headless Chrome automation:
|
||||
### IRC Commands
|
||||
|
||||
1. **Launch Chrome**: Starts a headless Chrome instance via `chromedp`
|
||||
2. **Inject Hook**: Uses `Page.addScriptToEvaluateOnNewDocument` to inject a WebSocket interceptor **before any page scripts run**
|
||||
3. **Navigate**: Loads the Kosmi room URL
|
||||
4. **Intercept**: The injected script hooks `window.WebSocket` constructor to capture all WebSocket messages
|
||||
5. **Poll**: Continuously polls the message queue populated by the interceptor
|
||||
6. **Process**: Extracts chat messages from GraphQL subscription data
|
||||
Users can issue commands in IRC chat. See [docs/IRC.md](docs/IRC.md) for full details.
|
||||
|
||||
### Critical Implementation Detail
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `!kreconnect` | Reconnect the Kosmi bridge |
|
||||
| `!jreconnect` | Reconnect the Jackbox WebSocket |
|
||||
| `!reconnect` | Reconnect all non-IRC services |
|
||||
| `!votes` | Show vote tally for the current game |
|
||||
| `thisgame++` / `thisgame--` | Vote on the current game |
|
||||
| `SYMBOL++` / `SYMBOL--` | Vote on a game by ticker symbol |
|
||||
|
||||
The WebSocket hook **must** be injected before page load using `Page.addScriptToEvaluateOnNewDocument`. This ensures the hook is active when Kosmi's JavaScript creates the WebSocket connection. If injected after page load, the WebSocket will already be established and messages won't be captured.
|
||||
### Mute Toggle
|
||||
|
||||
### Message Flow
|
||||
Jackbox announcements can be toggled at runtime without restarting:
|
||||
|
||||
```
|
||||
IRC User → IRC Server → Matterbridge → Headless Chrome → Kosmi Room
|
||||
Kosmi User → Kosmi Room → WebSocket → Chrome Interceptor → Matterbridge → IRC Server → IRC Channel
|
||||
```bash
|
||||
# Local process
|
||||
kill -SIGUSR1 $(pgrep matterbridge)
|
||||
|
||||
# Docker
|
||||
docker kill -s SIGUSR1 kosmi-irc-relay
|
||||
```
|
||||
|
||||
### Message Filtering
|
||||
See [MUTE_CONTROL.md](docs/setup/MUTE_CONTROL.md) for details.
|
||||
|
||||
- The bridge ignores its own messages by checking for the `[IRC]` prefix
|
||||
- This prevents message loops between Kosmi and IRC
|
||||
## Environment Variables
|
||||
|
||||
## Technical Details
|
||||
| Variable | Description |
|
||||
|----------|-------------|
|
||||
| `DEBUG=1` | Enable debug logging |
|
||||
| `MATTERBRIDGE_DATA_DIR` | Directory for persistent data (token cache) |
|
||||
| `TZ` | Timezone for container logs |
|
||||
| `CHROME_BIN` | Path to Chrome binary (for auth only) |
|
||||
|
||||
### GraphQL API
|
||||
|
||||
The Kosmi bridge uses the following GraphQL operations:
|
||||
|
||||
**Subscription** (receiving messages):
|
||||
```graphql
|
||||
subscription {
|
||||
newMessage(roomId: "roomId") {
|
||||
body
|
||||
time
|
||||
user {
|
||||
displayName
|
||||
username
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Mutation** (sending messages):
|
||||
```graphql
|
||||
mutation {
|
||||
sendMessage(roomId: "roomId", body: "message text") {
|
||||
id
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### File Structure
|
||||
## File Structure
|
||||
|
||||
```
|
||||
bridge/kosmi/
|
||||
├── kosmi.go # Main bridge implementation
|
||||
├── chromedp_client.go # Headless Chrome client with WebSocket interception
|
||||
└── graphql.go # GraphQL message structures (deprecated native client)
|
||||
|
||||
gateway/bridgemap/
|
||||
└── bkosmi.go # Bridge registration
|
||||
|
||||
cmd/test-kosmi/
|
||||
└── main.go # Standalone test program
|
||||
|
||||
matterbridge.toml # Configuration file
|
||||
go.mod # Go module dependencies
|
||||
irc-kosmi-relay/
|
||||
├── matterbridge.go # Entry point: flags, logger, router, mute toggle
|
||||
├── matterbridge.toml.example # Example configuration
|
||||
├── Dockerfile # Docker build (Go 1.23 + Chromium for auth)
|
||||
├── docker-compose.yml # Docker Compose deployment
|
||||
│
|
||||
├── bridge/
|
||||
│ ├── config/
|
||||
│ │ └── config.go # Message types, events, protocol config
|
||||
│ ├── kosmi/
|
||||
│ │ ├── kosmi.go # Kosmi bridge: Connect, Send, message handling
|
||||
│ │ ├── graphql_ws_client.go # Native GraphQL-over-WebSocket client
|
||||
│ │ ├── graphql.go # GraphQL message/payload structs
|
||||
│ │ ├── auth.go # Anonymous login (anonLogin HTTP mutation)
|
||||
│ │ ├── browser_auth.go # Chromedp browser login for email/password
|
||||
│ │ ├── token_cache.go # JWT token caching (file-based)
|
||||
│ │ ├── image_upload.go # Image upload to Kosmi CDN
|
||||
│ │ └── errors.go # Error types
|
||||
│ ├── irc/
|
||||
│ │ ├── irc.go # IRC bridge: Connect, Send, NAMES handling
|
||||
│ │ ├── handlers.go # PRIVMSG handler, commands, vote detection
|
||||
│ │ └── formatting.go # IRC formatting helpers
|
||||
│ └── jackbox/
|
||||
│ ├── client.go # Jackbox API client (REST + WebSocket)
|
||||
│ ├── votes.go # Vote detection (thisgame/ticker parsing)
|
||||
│ ├── tickers.go # Ticker symbol -> game title lookup table
|
||||
│ ├── webhook.go # Webhook transport (alternative to WS)
|
||||
│ ├── image_upload.go # Room code image generation + upload
|
||||
│ └── roomcode_image.go # Room code GIF rendering
|
||||
│
|
||||
├── gateway/
|
||||
│ ├── gateway.go # Gateway message routing and transformation
|
||||
│ ├── router.go # Router: message bus, Jackbox manager, broadcast
|
||||
│ ├── handlers.go # Event handlers: reconnect, votes, files
|
||||
│ └── bridgemap/
|
||||
│ ├── bkosmi.go # Registers "kosmi" protocol
|
||||
│ └── birc.go # Registers "irc" protocol
|
||||
│
|
||||
├── docs/
|
||||
│ ├── IRC.md # IRC command reference
|
||||
│ ├── setup/ # Setup and deployment guides
|
||||
│ └── archive/ # Historical development notes
|
||||
│
|
||||
└── cmd/ # Standalone test/debug tools
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Connection Issues
|
||||
### Kosmi Connection Issues
|
||||
|
||||
**Problem**: Bridge fails to connect to Kosmi
|
||||
**Bridge fails to connect to Kosmi**
|
||||
|
||||
**Solutions**:
|
||||
- Verify Chrome/Chromium is installed: `which google-chrome chromium chromium-browser`
|
||||
- Verify the room URL is correct
|
||||
- Check network connectivity to `app.kosmi.io`
|
||||
- Enable debug logging to see detailed connection logs
|
||||
- Look for "✓ WebSocket hook confirmed installed" in logs
|
||||
- Look for "Status: WebSocket connection intercepted" in logs
|
||||
- Verify `RoomURL` is correct and the room exists
|
||||
- Check network connectivity to `app.kosmi.io` and `engine.kosmi.io`
|
||||
- Enable debug logging (`-debug`) to see WebSocket handshake details
|
||||
- Look for `"Successfully connected to Kosmi"` in logs
|
||||
|
||||
### Message Not Relaying
|
||||
**Authentication fails (email/password)**
|
||||
|
||||
**Problem**: Messages aren't being relayed between Kosmi and IRC
|
||||
- Verify Chrome/Chromium is installed and accessible
|
||||
- Check credentials are correct
|
||||
- Delete `data/kosmi_token_cache.json` to force a fresh login
|
||||
- See [BROWSER_AUTH_GUIDE.md](docs/setup/BROWSER_AUTH_GUIDE.md)
|
||||
|
||||
**Solutions**:
|
||||
- Verify both Kosmi and IRC connections are established
|
||||
- Check the gateway configuration in `matterbridge.toml`
|
||||
- Ensure channel names match in the gateway configuration
|
||||
- Check logs for errors
|
||||
### IRC Connection Issues
|
||||
|
||||
### Authentication Errors
|
||||
- Verify server address and port
|
||||
- Check TLS settings match the server's requirements
|
||||
- Confirm the bot's nick is not already in use
|
||||
- Check NickServ/SASL credentials if authentication is configured
|
||||
|
||||
**Problem**: Kosmi connection fails with authentication error
|
||||
### Messages Not Relaying
|
||||
|
||||
**Note**: Kosmi doesn't require authentication. If you see auth errors, verify:
|
||||
- The WebSocket URL is correct
|
||||
- The room ID is valid
|
||||
- Network isn't blocking WebSocket connections
|
||||
- Verify both bridges show as connected in logs
|
||||
- Check gateway configuration: Kosmi channel must be `"main"`, IRC channel must include `#`
|
||||
- Enable debug logging to trace message flow
|
||||
- Look for `"Forwarding to Matterbridge"` and `"Sending message"` in logs
|
||||
|
||||
## Development
|
||||
### Jackbox Integration Issues
|
||||
|
||||
### Adding Features
|
||||
- Verify `APIURL` is accessible and `AdminPassword` is correct
|
||||
- Check that a Jackbox session is active with games being played
|
||||
- Confirm `Enabled=true` in the `[jackbox]` config section
|
||||
- See [JACKBOX_INTEGRATION.md](docs/setup/JACKBOX_INTEGRATION.md)
|
||||
|
||||
The bridge follows Matterbridge's bridge interface:
|
||||
## Documentation
|
||||
|
||||
```go
|
||||
type Bridger interface {
|
||||
Send(msg config.Message) (string, error)
|
||||
Connect() error
|
||||
JoinChannel(channel config.ChannelInfo) error
|
||||
Disconnect() error
|
||||
}
|
||||
```
|
||||
|
||||
### Testing
|
||||
|
||||
To test the bridge:
|
||||
|
||||
1. Start the bridge with debug logging
|
||||
2. Send a message in the Kosmi room
|
||||
3. Verify it appears in IRC with `[Kosmi]` prefix
|
||||
4. Send a message in IRC
|
||||
5. Verify it appears in Kosmi with `[IRC]` prefix
|
||||
|
||||
## Known Limitations
|
||||
|
||||
1. **Anonymous Access**: The bridge connects anonymously to Kosmi, so it will have a randomly assigned username
|
||||
2. **Message Sending**: The GraphQL mutation for sending messages may need adjustment based on Kosmi's actual API
|
||||
3. **Room Discovery**: The bridge connects to a specific room; it doesn't support room discovery or listing
|
||||
| Document | Description |
|
||||
|----------|-------------|
|
||||
| [IRC.md](docs/IRC.md) | IRC commands, voting syntax, ticker symbols |
|
||||
| [DOCKER_QUICKSTART.md](docs/setup/DOCKER_QUICKSTART.md) | 5-minute Docker setup |
|
||||
| [DOCKER_DEPLOYMENT.md](docs/setup/DOCKER_DEPLOYMENT.md) | Full Docker deployment guide |
|
||||
| [QUICKSTART.md](docs/setup/QUICKSTART.md) | Build-from-source quickstart |
|
||||
| [JACKBOX_INTEGRATION.md](docs/setup/JACKBOX_INTEGRATION.md) | Jackbox Game Picker setup |
|
||||
| [BROWSER_AUTH_GUIDE.md](docs/setup/BROWSER_AUTH_GUIDE.md) | Email/password authentication |
|
||||
| [TOKEN_PERSISTENCE.md](docs/setup/TOKEN_PERSISTENCE.md) | Token caching details |
|
||||
| [MUTE_CONTROL.md](docs/setup/MUTE_CONTROL.md) | Mute toggle guide |
|
||||
|
||||
## Credits
|
||||
|
||||
- Based on [Matterbridge](https://github.com/42wim/matterbridge) by 42wim
|
||||
- Kosmi API reverse engineering from chrome extension analysis
|
||||
- Kosmi API integration via reverse-engineered GraphQL protocol
|
||||
|
||||
## License
|
||||
|
||||
Same as Matterbridge (Apache 2.0)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user