diff --git a/bot.go b/bot.go index dd60a37..1297b28 100644 --- a/bot.go +++ b/bot.go @@ -6,6 +6,8 @@ import ( "log" "net/http" "net/url" + "sort" + "strings" "time" tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api" @@ -37,6 +39,7 @@ type TelegramCommands struct { NewAlbum string Info string Share string + Browse string } type TelegramMessages struct { @@ -94,6 +97,10 @@ func (bot *PhotoBot) ProcessUpdate(update tgbotapi.Update) { return } + if update.Message.Chat == nil || update.Message.Chat.Type != "private" { + return + } + text := update.Message.Text username := update.Message.From.UserName @@ -112,6 +119,21 @@ func (bot *PhotoBot) ProcessUpdate(update tgbotapi.Update) { log.Printf("[%s] cannot update chat db: %s", username, err) } + if update.Message.ReplyToMessage != nil { + // Only deal with forced replies (reply to bot's messages) + if update.Message.ReplyToMessage.From == nil || update.Message.ReplyToMessage.From.UserName != bot.Telegram.API.Self.UserName { + return + } + + if update.Message.ReplyToMessage.Text != "" { + if update.Message.ReplyToMessage.Text == bot.Telegram.Messages.MissingAlbumName { + log.Printf("[%s] reply to previous command /%s: %s", username, bot.Telegram.Commands.NewAlbum, text) + bot.handleNewAlbumCommandReply(update.Message) + return + } + } + } + if text != "" { if update.Message.IsCommand() { log.Printf("[%s] command: %s", username, text) @@ -120,6 +142,8 @@ func (bot *PhotoBot) ProcessUpdate(update tgbotapi.Update) { bot.handleHelpCommand(update.Message) case bot.Telegram.Commands.Share: bot.handleShareCommand(update.Message) + case bot.Telegram.Commands.Browse: + bot.handleBrowseCommand(update.Message) case bot.Telegram.Commands.NewAlbum: bot.handleNewAlbumCommand(update.Message) case bot.Telegram.Commands.Info: @@ -276,27 +300,48 @@ func (bot *PhotoBot) handleHelpCommand(message *tgbotapi.Message) { } func (bot *PhotoBot) handleShareCommand(message *tgbotapi.Message) { + albumList, err := bot.MediaStore.ListAlbums() + if err != nil { + log.Printf("[%s] cannot get album list: %s", message.From.UserName, err) + bot.Telegram.replyToCommandWithMessage(message, bot.Telegram.Messages.ServerError) + return + } + + var text strings.Builder + text.WriteString(fmt.Sprintf(bot.Telegram.Messages.SharedAlbum, bot.Telegram.PerAlbumTokenValidity)) + text.WriteString("\n") + sort.Sort(sort.Reverse(albumList)) var tokenData TokenData = TokenData{ Timestamp: time.Now(), Username: message.From.UserName, } - - if len(message.Text) < len(bot.Telegram.Commands.Share)+3 { - // Global share - tokenData.Entitlement = "" - token := bot.Telegram.TokenGenerator.NewToken(tokenData) - url := fmt.Sprintf("%s/s/%s/%s/album/", bot.Telegram.WebPublicURL, url.PathEscape(message.From.UserName), url.PathEscape(token)) - bot.Telegram.replyWithMessage(message, fmt.Sprintf(bot.Telegram.Messages.SharedGlobal, bot.Telegram.GlobalTokenValidity)) - bot.Telegram.replyWithMessage(message, url) - } else { - // Album share - albumName := message.CommandArguments() - tokenData.Entitlement = albumName + for _, album := range albumList { + title := album.Title // TODO escape me + id := album.ID + if id == "" { + id = "latest" + title = title + " 🔥" + } + tokenData.Entitlement = id token := bot.Telegram.TokenGenerator.NewToken(tokenData) - url := fmt.Sprintf("%s/s/%s/%s/album/%s/", bot.Telegram.WebPublicURL, url.PathEscape(message.From.UserName), url.PathEscape(token), url.PathEscape(albumName)) - bot.Telegram.replyWithMessage(message, fmt.Sprintf(bot.Telegram.Messages.SharedAlbum, albumName, bot.Telegram.PerAlbumTokenValidity)) - bot.Telegram.replyWithMessage(message, url) + url := fmt.Sprintf("%s/s/%s/%s/album/%s/", bot.Telegram.WebPublicURL, url.PathEscape(message.From.UserName), url.PathEscape(token), url.PathEscape(id)) + text.WriteString(fmt.Sprintf("- [%s %s](%s)\n", album.Date.Format("2006-01"), title, url)) + } + + bot.Telegram.replyWithMarkdownMessage(message, text.String()) +} + +func (bot *PhotoBot) handleBrowseCommand(message *tgbotapi.Message) { + var tokenData TokenData = TokenData{ + Timestamp: time.Now(), + Username: message.From.UserName, } + + // Global share + token := bot.Telegram.TokenGenerator.NewToken(tokenData) + url := fmt.Sprintf("%s/s/%s/%s/album/", bot.Telegram.WebPublicURL, url.PathEscape(message.From.UserName), url.PathEscape(token)) + bot.Telegram.replyWithMessage(message, fmt.Sprintf(bot.Telegram.Messages.SharedGlobal, bot.Telegram.GlobalTokenValidity)) + bot.Telegram.replyWithMessage(message, url) } func (bot *PhotoBot) handleInfoCommand(message *tgbotapi.Message) { @@ -315,11 +360,11 @@ func (bot *PhotoBot) handleInfoCommand(message *tgbotapi.Message) { } func (bot *PhotoBot) handleNewAlbumCommand(message *tgbotapi.Message) { - if len(message.Text) < len(bot.Telegram.Commands.NewAlbum)+3 { - bot.Telegram.replyToCommandWithMessage(message, bot.Telegram.Messages.MissingAlbumName) - return - } - albumName := message.CommandArguments() + bot.Telegram.replyWithForcedReply(message, bot.Telegram.Messages.MissingAlbumName) +} + +func (bot *PhotoBot) handleNewAlbumCommandReply(message *tgbotapi.Message) { + albumName := message.Text err := bot.MediaStore.NewAlbum(albumName) if err != nil { @@ -343,3 +388,20 @@ func (telegram *TelegramBackend) replyWithMessage(message *tgbotapi.Message, tex _, err := telegram.API.Send(msg) return err } + +func (telegram *TelegramBackend) replyWithMarkdownMessage(message *tgbotapi.Message, text string) error { + msg := tgbotapi.NewMessage(message.Chat.ID, text) + msg.ParseMode = tgbotapi.ModeMarkdown + _, err := telegram.API.Send(msg) + return err +} + +func (telegram *TelegramBackend) replyWithForcedReply(message *tgbotapi.Message, text string) error { + msg := tgbotapi.NewMessage(message.Chat.ID, text) + msg.ReplyMarkup = tgbotapi.ForceReply{ + ForceReply: true, + Selective: true, + } + _, err := telegram.API.Send(msg) + return err +} diff --git a/main.go b/main.go index 25e1f50..26f450e 100644 --- a/main.go +++ b/main.go @@ -26,14 +26,14 @@ func initConfig() { You can send me your photos and videos. - To start an album, use "/newAlbum album name". + To start an album, use "/newAlbum". To get the current album name, use "/info". To share an album, use "/share album". To share all albums, use "/share". If you are lost, you can get this message again with "/help". Have a nice day!`) - viper.SetDefault("Telegram.Messages.MissingAlbumName", "The album name is missing") + viper.SetDefault("Telegram.Messages.MissingAlbumName", "Which title should I give to the new album?") viper.SetDefault("Telegram.Messages.ServerError", "Server Internal Error") viper.SetDefault("Telegram.Messages.AlbumCreated", "Album created") viper.SetDefault("Telegram.Messages.DoNotUnderstand", "Sorry, I did not understand your request.") @@ -41,7 +41,7 @@ func initConfig() { viper.SetDefault("Telegram.Messages.InfoNoAlbum", "There is no album started, yet.") viper.SetDefault("Telegram.Messages.NoUsername", "You need to set your Telegram username first!") viper.SetDefault("Telegram.Messages.ThankYouMedia", "Got it, thanks!") - viper.SetDefault("Telegram.Messages.SharedAlbum", "The album %s can be reached with the following link. Link is valid for %d days.") + viper.SetDefault("Telegram.Messages.SharedAlbum", "Here are the albums and their sharing links. Links are valid for %d days.") viper.SetDefault("Telegram.Messages.SharedGlobal", "All albums can be reached with the following link. Link is valid for %d days.") // Telegram Commands @@ -49,6 +49,7 @@ func initConfig() { viper.SetDefault("Telegram.Commands.Info", "info") viper.SetDefault("Telegram.Commands.NewAlbum", "newAlbum") viper.SetDefault("Telegram.Commands.Share", "share") + viper.SetDefault("Telegram.Commands.Browse", "browse") // Web Interface viper.SetDefault("WebInterface.SiteName", "My photo album") @@ -152,6 +153,7 @@ func getCommandsFromConfig() TelegramCommands { NewAlbum: viper.GetString("Telegram.Commands.NewAlbum"), Info: viper.GetString("Telegram.Commands.Info"), Share: viper.GetString("Telegram.Commands.Share"), + Browse: viper.GetString("Telegram.Commands.Browse"), } }