add load more command

This commit is contained in:
2026-02-12 17:52:32 +03:00
parent 4e1d1ca35f
commit a058b622e3
7 changed files with 161 additions and 33 deletions
+72 -18
View File
@@ -12,18 +12,20 @@ import (
"git.vakhrushev.me/av/remembos/internal/config"
"git.vakhrushev.me/av/remembos/internal/memory"
"git.vakhrushev.me/av/remembos/internal/memos"
"git.vakhrushev.me/av/remembos/internal/search"
)
// Bot sends a daily memory via Telegram.
type Bot struct {
api *tgbotapi.BotAPI
service *memory.Service
client *memos.Client
chatID int64
sendAt string // "HH:MM"
publicURL string
loc *time.Location
logger *slog.Logger
api *tgbotapi.BotAPI
service *memory.Service
client *memos.Client
chatID int64
sendAt string // "HH:MM"
publicURL string
loc *time.Location
logger *slog.Logger
allowLoadMore bool
}
// NewBot creates a new Telegram bot.
@@ -32,6 +34,7 @@ func NewBot(
service *memory.Service,
client *memos.Client,
memosURL, publicURL string,
allowLoadMore bool,
loc *time.Location,
logger *slog.Logger,
) (*Bot, error) {
@@ -49,19 +52,24 @@ func NewBot(
logger.Info("telegram bot authorized", "username", api.Self.UserName)
return &Bot{
api: api,
service: service,
client: client,
chatID: cfg.ChatID,
sendAt: cfg.SendAt,
publicURL: pub,
loc: loc,
logger: logger,
api: api,
service: service,
client: client,
chatID: cfg.ChatID,
sendAt: cfg.SendAt,
publicURL: pub,
loc: loc,
logger: logger,
allowLoadMore: allowLoadMore,
}, nil
}
// Run starts the scheduling loop. It blocks until ctx is cancelled.
func (b *Bot) Run(ctx context.Context) {
if b.allowLoadMore {
go b.listenForCommands(ctx)
}
for {
next := b.nextSendTime()
delay := time.Until(next)
@@ -105,15 +113,20 @@ func (b *Bot) sendDaily(ctx context.Context) {
b.logger.Error("failed to get today memory", "error", err)
return
}
b.sendMemory(ctx, mem)
}
// sendMemory formats and sends a memory via Telegram.
func (b *Bot) sendMemory(ctx context.Context, mem *search.Memory) {
if mem == nil {
b.logger.Info("no memory for today, skipping telegram send")
b.logger.Info("no memory to send, skipping")
return
}
mainText, captionText := formatMemory(mem, b.publicURL)
images := imageAttachments(mem.Memo)
// Try to download images
var downloaded []imageFile
if len(images) > 0 {
downloaded = b.downloadImages(ctx, images)
@@ -124,6 +137,47 @@ func (b *Bot) sendDaily(ctx context.Context) {
}
}
// listenForCommands polls for Telegram updates and handles /more commands.
func (b *Bot) listenForCommands(ctx context.Context) {
u := tgbotapi.NewUpdate(0)
u.Timeout = 60
updates := b.api.GetUpdatesChan(u)
for {
select {
case <-ctx.Done():
return
case update, ok := <-updates:
if !ok {
return
}
if update.Message == nil || !update.Message.IsCommand() {
continue
}
if update.Message.Chat.ID != b.chatID {
continue
}
if update.Message.Command() == "more" {
b.handleMore(ctx)
}
}
}
}
// handleMore loads a new memory and sends it.
func (b *Bot) handleMore(ctx context.Context) {
b.logger.Info("handling /more command")
mem, err := b.service.LoadNewMemory(ctx)
if err != nil {
b.logger.Error("failed to load new memory", "error", err)
return
}
b.sendMemory(ctx, mem)
}
type imageFile struct {
filename string
data []byte