Add space groups, fix HLTB scraper, fix quote wall E2EE, improve tarot prompts

Space groups: automatic room grouping via membership overlap percentage.
Rooms with sufficient shared members are grouped together so leaderboards,
trivia scores, and stats aggregate across the community. Uses strict
clique-based algorithm (every room must meet threshold with every other
room in group). Configurable via SPACE_GROUP_THRESHOLD env var. Persisted
to SQLite, recomputed hourly and on startup.

HLTB scraper: rewrote for new howlongtobeat.com API (two-step token auth
via /api/finder/init + /api/finder endpoint).

Quote wall: fix E2EE decrypt flow for reply-to-save (ParseRaw before
Decrypt, skip ParseRaw after Decrypt returns pre-parsed event). Fix
subcommand matching for delete/search. Remove broken star-reaction handler
and old quote handler from user.go.

Other fixes:
- Strip Matrix reply fallback before command detection (main.go)
- Increase Ollama context window to 8192
- Improve tarot spread prompts (~4x longer, narrative arc)
- Add "cards are props" instruction to tarot LLM prompt
- Fix movies.go CommandDef name mismatch
- Add Community category to !help
- Remove daily horoscope broadcast cron
- Update README with all changes

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
prosolis
2026-03-11 00:45:25 -07:00
parent 1c02732445
commit 0fc15668da
12 changed files with 460 additions and 103 deletions

26
main.go
View File

@@ -147,6 +147,9 @@ func main() {
os.Exit(1)
}
// Initialize space groups (room overlap detection for community-wide leaderboards)
plugin.InitSpaceGroups(client)
// ---- Set up event handlers ----
syncer := client.Syncer.(*mautrix.DefaultSyncer)
@@ -179,6 +182,12 @@ func main() {
}
body := content.Body
// Strip Matrix reply fallback: "> <@user:server> ..." lines followed by blank line
if strings.HasPrefix(body, "> <@") || strings.HasPrefix(body, "> * <@") {
if idx := strings.Index(body, "\n\n"); idx >= 0 {
body = strings.TrimSpace(body[idx+2:])
}
}
msgCtx := plugin.MessageContext{
RoomID: evt.RoomID,
EventID: evt.ID,
@@ -216,7 +225,7 @@ func main() {
// ---- Set up cron scheduler ----
scheduler := cron.New()
setupScheduledJobs(scheduler, client, wotdPlugin, holidaysPlugin, gamingPlugin, birthdayPlugin, animePlugin, moviesPlugin, concertsPlugin, esteemedPlugin, horoscopePlugin)
setupScheduledJobs(scheduler, client, wotdPlugin, holidaysPlugin, gamingPlugin, birthdayPlugin, animePlugin, moviesPlugin, concertsPlugin, esteemedPlugin)
scheduler.Start()
// ---- Start syncing ----
@@ -252,7 +261,6 @@ func setupScheduledJobs(
movies *plugin.MoviesPlugin,
concerts *plugin.ConcertsPlugin,
esteemed *plugin.EsteemPlugin,
horoscope *plugin.HoroscopePlugin,
) {
rooms := getRooms()
@@ -271,14 +279,6 @@ func setupScheduledJobs(
}
})
// Daily horoscopes at 06:30
c.AddFunc("30 6 * * *", func() {
slog.Info("scheduler: posting daily horoscopes")
for _, r := range rooms {
horoscope.PostDailyHoroscopes(r)
}
})
// Holidays at 07:00
c.AddFunc("0 7 * * *", func() {
slog.Info("scheduler: posting holidays")
@@ -338,6 +338,12 @@ func setupScheduledJobs(
esteemed.PostWeekly()
})
// Space groups refresh every hour
c.AddFunc("0 * * * *", func() {
slog.Info("scheduler: refreshing space groups")
plugin.RefreshSpaceGroups()
})
// Database maintenance at 03:00 daily
c.AddFunc("0 3 * * *", func() {
slog.Info("scheduler: running database maintenance")