commit 69be69e3b0dd3a7ca5abfc90ca95b857ab8471f2 Author: prosolis <5590409+prosolis@users.noreply.github.com> Date: Sat Mar 7 22:48:35 2026 -0800 Initial commit: Freebee Matrix community bot Full-featured Matrix bot with E2EE via matrix-js-sdk, 32+ plugins, LLM-powered passive classification, XP/leveling, trivia, game releases, anime/movie tracking, and more. Co-Authored-By: Claude Opus 4.6 diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..eb3d937 --- /dev/null +++ b/.env.example @@ -0,0 +1,57 @@ +# Matrix +MATRIX_HOMESERVER_URL=https://matrix.example.com +MATRIX_ACCESS_TOKEN=syt_your_token_here +MATRIX_BOT_USER_ID=@freebee:example.com +MATRIX_BOT_PASSWORD= + +# Which rooms the bot actively posts scheduled content to (comma-separated) +BOT_ROOMS=!roomid:example.com + +# Admins who can run admin-only commands +BOT_ADMIN_USERS=@yourmxid:example.com + +# Runtime +BOT_PREFIX=! +DATA_DIR=./data +LOG_LEVEL=info + +# External APIs +RAWG_API_KEY= +WORDNIK_API_KEY= +CALENDARIFIC_API_KEY= +ASIAN_HOLIDAY_COUNTRIES=JP,CN,KR,IN,TH,VN,TW,PH +HEBCAL_API_KEY= +OPENWEATHER_API_KEY= +FINNHUB_API_KEY= +BANDSINTOWN_API_KEY= +TMDB_API_KEY= +LIBRETRANSLATE_URL= + +# Scheduler times (24h UTC) +SCHEDULE_HOLIDAYS_HOUR=7 +SCHEDULE_HOLIDAYS_MINUTE=0 +SCHEDULE_RELEASES_HOUR=19 +SCHEDULE_RELEASES_MINUTE=0 + +# Feature flags +FEATURE_SHADE=false +FEATURE_URL_PREVIEW=true + +# Crypto reset (set to true to wipe and re-establish E2EE keys on next startup) +CRYPTO_RESET=false + +# LLM passive classifier (requires Ollama — leave blank to disable) +OLLAMA_HOST= +OLLAMA_MODEL= +LLM_SAMPLE_RATE=0.15 + +# Rate limits (calls per user per day, 0 = unlimited) +RATELIMIT_WEATHER=5 +RATELIMIT_TRANSLATE=20 +RATELIMIT_CONCERTS=10 + +# Bot default city for concert digest and location-based features +BOT_DEFAULT_CITY= + +# Trivia +TRIVIA_TIMEOUT_SECONDS=20 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4f0bb48 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +dist/ +data/ +.env +.env.* +!.env.example +node_modules/ +merge_env.py +Twinbee Build Plan.md diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..32b9a15 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,12 @@ +FROM node:20-alpine + +WORKDIR /app + +COPY package.json package-lock.json* ./ +RUN npm ci --omit=dev + +COPY tsconfig.json ./ +COPY src/ ./src/ +RUN npx tsc + +CMD ["node", "dist/index.js"] diff --git a/README.md b/README.md new file mode 100644 index 0000000..7f3844b --- /dev/null +++ b/README.md @@ -0,0 +1,1000 @@ +# Freebee + +A full-featured Matrix community bot with end-to-end encryption support, a plugin architecture, silent passive tracking, daily scheduled posts, and a suite of community engagement features. + +Built for the TwinBee/Parodius community. Runs on Node.js with TypeScript, SQLite, and `matrix-js-sdk` with automatic Rust E2EE. + +--- + +## Table of Contents + +- [Features](#features) +- [Requirements](#requirements) +- [Installation](#installation) +- [Configuration](#configuration) +- [Running the Bot](#running-the-bot) +- [Commands](#commands) +- [Passive Features](#passive-features) +- [Scheduled Posts](#scheduled-posts) +- [Achievements](#achievements) +- [Personality Archetypes](#personality-archetypes) +- [Supported Timezones](#supported-timezones) +- [External APIs](#external-apis) +- [Architecture](#architecture) +- [Database](#database) +- [Troubleshooting](#troubleshooting) +- [Backup & Recovery](#backup--recovery) + +--- + +## Features + +- **End-to-end encryption** via `matrix-js-sdk` with Rust crypto — automatic key management, session rotation, and key gossiping out of the box +- **Automatic token renewal** — set `MATRIX_BOT_PASSWORD` and the bot refreshes expired access tokens on its own +- **Crypto reset flow** — set `CRYPTO_RESET=true` to wipe and re-establish E2EE keys in one restart, with automatic server-side device cleanup +- **Plugin architecture** — modular design with 32+ independent plugins +- **Silent passive tracking** — XP, streaks, stats, achievements, keyword alerts, Markov corpus, and presence tracked without announcements +- **Scheduled daily posts** — Word of the Day, holidays, game releases, birthdays, anime airings, movie releases, and weekly concert digests +- **Multi-calendar holiday support** — Gregorian, Hebrew, Hijri, and Asian calendars (JP, CN, KR, IN, TH, VN, TW, PH) with non-Western holiday featuring +- **XP & leveling system** with cooldown-based anti-farming +- **Reputation system** with natural language thanks detection (LLM-powered sarcasm-aware mode when Ollama is active) +- **32 unlockable achievements** evaluated silently on every message +- **Trivia system** with OpenTDB integration, time-weighted scoring, and threaded conversations +- **Game backlog manager**, now-playing status, and HowLongToBeat integration +- **Stock quotes** via Finnhub with watchlists +- **Anime tracking** via MyAnimeList/Jikan with watchlists and airing alerts +- **Movie & TV tracking** via TMDB with watchlists and release alerts +- **Concert tracking** via Bandsintown with artist watchlists and weekly digests +- **LLM-powered passive classifier** (optional, via Ollama) — multilingual profanity, insult, sentiment, gratitude, and WOTD correctness detection with emoji reactions and robust JSON repair +- **URL preview enrichment** — automatic og:tag extraction for shared links +- **Markov chain text generation** — per-user trigram models for chaos +- **Lookup tools** — Wikipedia, dictionary, and translation (LibreTranslate) +- **Presence system** — away/afk/back status with auto-clear and `!whois` profile cards +- **Community countdowns** — public and private event countdowns +- **Welcome system** — greets new users with bonus XP and provides `!help` via DM +- **Reminder system** with natural language time parsing +- **Reaction polls**, dice rolling, world clock, weather (with geocoding for ambiguous cities and zip codes), and more +- **Inline calculator** — math expressions, percentages, unit conversions via mathjs +- **QR code generator** — generates and posts QR code images to the room +- **Reaction leaderboard** — silently tracks emoji reactions, revealed with `!emojiboard` +- **Per-command rate limiting** for paid API endpoints + +--- + +## Requirements + +- **Node.js 22+** +- **npm** (comes with Node.js) +- A Matrix account for the bot with an access token or password + +--- + +## Installation + +### From Source + +```bash +git clone https://github.com/your-org/freebee.git +cd freebee +npm install +npm run build +``` + +### With Docker + +```bash +git clone https://github.com/your-org/freebee.git +cd freebee +cp .env.example .env +# Edit .env with your configuration +docker compose up -d +``` + +--- + +## Configuration + +Copy `.env.example` to `.env` and fill in the values: + +```bash +cp .env.example .env +``` + +### Required Variables + +| Variable | Description | +|---|---| +| `MATRIX_HOMESERVER_URL` | Your Matrix homeserver (e.g., `https://matrix.example.com`) | +| `MATRIX_BOT_USER_ID` | Bot's full user ID (e.g., `@freebee:example.com`) | +| `MATRIX_ACCESS_TOKEN` | Bot's access token (or set `MATRIX_BOT_PASSWORD` instead) | + +### Authentication + +You can authenticate the bot in two ways: + +1. **Access token only** — set `MATRIX_ACCESS_TOKEN`. If it expires, the bot exits. +2. **Password (recommended)** — set `MATRIX_BOT_PASSWORD`. The bot validates the token on startup and automatically obtains a new one via password login if it's expired or missing. The new token is persisted to `.env`. + +Both can be set simultaneously for maximum resilience. + +### Recommended Variables + +| Variable | Default | Description | +|---|---|---| +| `MATRIX_BOT_PASSWORD` | *(empty)* | Bot account password for automatic token renewal | +| `BOT_ROOMS` | *(empty)* | Comma-separated room IDs for scheduled posts | +| `BOT_ADMIN_USERS` | *(empty)* | Comma-separated admin user IDs | +| `BOT_PREFIX` | `!` | Command prefix | +| `DATA_DIR` | `./data` | Directory for database, crypto store, and logs | +| `LOG_LEVEL` | `info` | Logging level (`debug`, `info`, `warn`, `error`) | +| `BOT_DEFAULT_CITY` | *(empty)* | Default city for concert digests and location features | + +### API Keys + +| Variable | Required For | How to Get | +|---|---|---| +| `RAWG_API_KEY` | `!releases`, daily game releases post | [rawg.io/apidocs](https://rawg.io/apidocs) (free) | +| `WORDNIK_API_KEY` | Word of the Day post | [developer.wordnik.com](https://developer.wordnik.com/) (free) | +| `CALENDARIFIC_API_KEY` | Holiday data (Western + Asian holidays) | [calendarific.com](https://calendarific.com/api-documentation) (free tier) | +| `OPENWEATHER_API_KEY` | `!weather` command | [openweathermap.org](https://openweathermap.org/api) (free tier) | +| `FINNHUB_API_KEY` | `!stock` command | [finnhub.io](https://finnhub.io/) (free, 60 calls/min) | +| `BANDSINTOWN_API_KEY` | `!concerts` command | [bandsintown.com](https://artists.bandsintown.com/) (free) | +| `TMDB_API_KEY` | `!movie`, `!tv` commands | [themoviedb.org](https://www.themoviedb.org/documentation/api) (free) | + +HebCal (Jewish calendar), Aladhan (Islamic calendar), Jikan/MAL (anime), OpenTDB (trivia), Wikipedia, and Free Dictionary are free and require no API keys. + +### Optional: Self-hosted Services + +| Variable | Default | Description | +|---|---|---| +| `LIBRETRANSLATE_URL` | *(empty)* | URL for self-hosted LibreTranslate instance (e.g., `http://localhost:5000`) | +| `OLLAMA_HOST` | *(empty)* | Ollama endpoint for LLM classifier (e.g., `http://localhost:11434`) | +| `OLLAMA_MODEL` | *(empty)* | Ollama model name (e.g., `qwen2.5:1.5b`) | +| `LLM_SAMPLE_RATE` | `0.15` | Fraction of non-keyword messages randomly sampled for LLM classification (0.0–1.0) | +| `ASIAN_HOLIDAY_COUNTRIES` | `JP,CN,KR,IN,TH,VN,TW,PH` | Comma-separated country codes for Asian holiday data | + +LLM features (profanity/insult/sentiment/gratitude detection, smart WOTD validation) are **only active when both `OLLAMA_HOST` and `OLLAMA_MODEL` are set**. Leave them blank to disable. The classifier uses a 16k context window, a 30-second request timeout, and exponential backoff (5s–5min) when Ollama is unreachable. When active, the LLM replaces keyword-based thanks detection with sarcasm-aware gratitude detection for the reputation system. + +### Rate Limits + +| Variable | Default | Description | +|---|---|---| +| `RATELIMIT_WEATHER` | `5` | Max `!weather` calls per user per day | +| `RATELIMIT_TRANSLATE` | `20` | Max `!translate` calls per user per day | +| `RATELIMIT_CONCERTS` | `10` | Max `!concerts` calls per user per day | + +Admins (`BOT_ADMIN_USERS`) bypass all rate limits. Set to `0` for unlimited. + +### Feature Flags + +| Variable | Default | Description | +|---|---|---| +| `FEATURE_URL_PREVIEW` | `true` | Enable automatic URL og:tag previews | +| `FEATURE_SHADE` | `false` | Enable shade plugin (stub) | +| `CRYPTO_RESET` | `false` | Set to `true` to wipe and re-establish E2EE keys on next startup (auto-deletes old device from server) | + +### Scheduler Times + +All times are in **24-hour UTC format**. + +| Variable | Default | Description | +|---|---|---| +| `SCHEDULE_HOLIDAYS_HOUR` | `7` | Hour for holiday post | +| `SCHEDULE_HOLIDAYS_MINUTE` | `0` | Minute for holiday post | +| `SCHEDULE_RELEASES_HOUR` | `19` | Hour for game releases post | +| `SCHEDULE_RELEASES_MINUTE` | `0` | Minute for game releases post | + +Additional scheduled jobs with DB-configured defaults: + +| Job | Default Time | Description | +|---|---|---| +| `wotd` | 08:00 | Word of the Day | +| `birthday_check` | 07:05 | Birthday announcements | +| `anime_releases` | 19:30 | Anime airing alerts | +| `movie_releases` | 20:00 | Movie/TV release alerts | +| `concert_digest` | 10:00 | Weekly concert digest (Sundays only) | + +All schedule times can be adjusted at runtime with `!schedule `. + +### Getting a Matrix Access Token + +1. Log into your bot's Matrix account via Element or another client +2. Go to **Settings > Help & About > Advanced** and copy the access token +3. Alternatively, use the Matrix client-server API: + ```bash + curl -X POST "https://your-homeserver/_matrix/client/v3/login" \ + -H "Content-Type: application/json" \ + -d '{"type":"m.login.password","user":"freebee","password":"your-password"}' + ``` +4. Copy the `access_token` from the response + +Or just set `MATRIX_BOT_PASSWORD` and let the bot handle token management automatically. + +--- + +## Running the Bot + +### Development + +```bash +npm run dev +``` + +### Production + +```bash +npm run build +npm start +``` + +### Docker + +```bash +docker compose up -d + +# View logs +docker compose logs -f freebee + +# Restart +docker compose restart +``` + +The bot will auto-join rooms when invited. + +--- + +## Commands + +All commands use the configured prefix (default: `!`). Use `!help` to get a full command list sent to your DMs. + +### XP & Leveling + +| Command | Description | +|---|---| +| `!rank [@user]` | Show XP, level, and progress bar | +| `!leaderboard [n]` | Top N users by XP (default 10, max 25) | + +XP is earned passively: **10 XP per message** with a 30-second cooldown to prevent farming. The level curve is linear: level N requires N x 100 total XP. + +### Reputation + +| Command | Description | +|---|---| +| `!rep [@user]` | Show reputation score | +| `!repboard` | Top 10 by reputation | + +Reputation is granted automatically when the bot detects natural "thanks" messages directed at another user (e.g., "thanks @user:server.com", "ty @user:server.com"). There's a 24-hour cooldown per giver/receiver pair. The bot reacts with a checkmark to acknowledge. + +When the LLM classifier is active, keyword-based detection is replaced with sarcasm-aware gratitude detection — sarcastic thanks like "thanks for nothing" won't grant rep. + +Receiving reputation also grants **5 bonus XP**. + +### Statistics + +| Command | Description | +|---|---| +| `!stats [@user]` | Full message metrics (words, links, images, questions, etc.) | +| `!rankings [category]` | Leaderboard by category | +| `!personality [@user]` | Your community archetype | + +Valid ranking categories: `messages`, `words`, `links`, `images`, `questions`, `emojis`, `streak` + +### Streaks + +| Command | Description | +|---|---| +| `!streak [@user]` | Current and record streak (in days) | +| `!firstboard` | Early bird leaderboard (who posts first each day) | + +### Reminders + +| Command | Description | +|---|---| +| `!remindme