diff --git a/main.go b/main.go index 011c56f..aff04b9 100644 --- a/main.go +++ b/main.go @@ -6,15 +6,17 @@ import ( "fmt" "os" "strconv" + "strings" "github.com/hamcha/tg" ) type Config struct { - Token string - Bind string - WebhookURL string - WebhookPath string + Token string + Bind string + WebhookURL string + WebhookPath string + MaxRequestsPerMessage int } func checkErr(err error, msg string, args ...interface{}) { @@ -26,6 +28,7 @@ func checkErr(err error, msg string, args ...interface{}) { } var api *tg.Telegram +var cfg Config func main() { cfgpath := flag.String("config", "stappa.conf", "Path to config file") @@ -34,73 +37,133 @@ func main() { cfgfile, err := os.Open(*cfgpath) checkErr(err, "Could not open config file") - var cfg Config err = json.NewDecoder(cfgfile).Decode(&cfg) checkErr(err, "Could not decode JSON from config file contents") cfgfile.Close() + // Set default maxreq + if cfg.MaxRequestsPerMessage < 1 { + cfg.MaxRequestsPerMessage = 5 + } + api = tg.MakeAPIClient(cfg.Token) api.SetWebhook(cfg.WebhookURL) api.HandleWebhook(cfg.Bind, cfg.WebhookPath, webhook) } func webhook(update tg.APIUpdate) { - // Ignore everything that isn't an inline query (for now) - if update.Inline == nil { - return - } + // Handle inline queries (99% of the usage I hope) + if update.Inline != nil { + query := update.Inline.Query + offset, _ := strconv.Atoi(update.Inline.Offset) + results, err := scryfallSearch(query, offset) + if err != nil { + fmt.Println(err) + // DO SOMETHING + return + } - query := update.Inline.Query - offset, _ := strconv.Atoi(update.Inline.Offset) - results, err := scryfallSearch(query, offset) - if err != nil { - fmt.Println(err) - // DO SOMETHING - return - } + nextcard := "" + if results.HasMore { + nextcard = strconv.Itoa(offset + len(results.Data)) + } + photos := make([]tg.APIInlineQueryResultPhoto, len(results.Data)) + for i, card := range results.Data { + caption := fmt.Sprintf("EDHREC rank: #%d - cardmarket: € %s", card.EdhrecRank, card.Eur) + photos[i] = tg.APIInlineQueryResultPhoto{ + Type: "photo", + ResultID: card.ID, + PhotoURL: card.ImageUris.Large, + ThumbURL: card.ImageUris.Normal, + Title: card.Name, + Caption: caption, + Width: 672, + Height: 936, + ReplyMarkup: &tg.APIInlineKeyboardMarkup{ + InlineKeyboard: [][]tg.APIInlineKeyboardButton{{ + { + Text: "Scryfall", + URL: card.ScryfallURI, + }, { + Text: "EDHREC", + URL: card.RelatedUris.Edhrec, + }, { + Text: "MCM", + URL: card.PurchaseUris.Magiccardmarket, + }, + }}, + }, + } + } - nextcard := "" - if results.HasMore { - nextcard = strconv.Itoa(offset + len(results.Data)) - } - photos := make([]tg.APIInlineQueryResultPhoto, len(results.Data)) - for i, card := range results.Data { - caption := fmt.Sprintf("EDHREC rank: #%d - cardmarket: € %s", card.EdhrecRank, card.Eur) - photos[i] = tg.APIInlineQueryResultPhoto{ - Type: "photo", - ResultID: card.ID, - PhotoURL: card.ImageUris.Large, - ThumbURL: card.ImageUris.Normal, - Title: card.Name, - Caption: caption, - Width: 672, - Height: 936, - ReplyMarkup: &tg.APIInlineKeyboardMarkup{ - InlineKeyboard: [][]tg.APIInlineKeyboardButton{{ - { - Text: "Scryfall", - URL: card.ScryfallURI, - }, { - Text: "EDHREC", - URL: card.RelatedUris.Edhrec, - }, { - Text: "MCM", - URL: card.PurchaseUris.Magiccardmarket, - }, - }}, - }, + err = api.AnswerInlineQuery(tg.InlineQueryResponse{ + QueryID: update.Inline.QueryID, + Results: photos, + NextOffset: nextcard, + }) + if err != nil { + fmt.Println(err) + // DO SOMETHING + return } } - err = api.AnswerInlineQuery(tg.InlineQueryResponse{ - QueryID: update.Inline.QueryID, - Results: photos, - NextOffset: nextcard, - }) - if err != nil { - fmt.Println(err) - // DO SOMETHING - return + // Check for card requests + if update.Message != nil && update.Message.Text != nil { + requests := getCardRequests(*update.Message.Text) + if len(requests) > cfg.MaxRequestsPerMessage { + api.SendTextMessage(tg.ClientTextMessageData{ + ChatID: update.Message.Chat.ChatID, + Text: fmt.Sprintf("You asked for way too many cards (%d!), please only ask me for at most %d cards in a single message.", len(requests), cfg.MaxRequestsPerMessage), + ReplyID: &update.Message.MessageID, + }) + return + } + cardmedia := []tg.APIInputMediaPhoto{} + errlist := []string{} + for _, cardname := range requests { + card, err := scryfallGetCard(cardname) + if err != nil { + errlist = append(errlist, cardname) + } else { + cardmedia = append(cardmedia, tg.APIInputMediaPhoto{ + Type: "photo", + Media: card.ImageUris.Large, + }) + } + } + if len(cardmedia) > 0 { + api.SendAlbum(tg.ClientAlbumData{ + ChatID: update.Message.Chat.ChatID, + Media: cardmedia, + Silent: true, + ReplyID: &update.Message.MessageID, + }) + } + if len(errlist) > 0 { + api.SendTextMessage(tg.ClientTextMessageData{ + ChatID: update.Message.Chat.ChatID, + Text: "I couldn't find these cards you mentioned: " + strings.Join(errlist, ", "), + ReplyID: &update.Message.MessageID, + }) + } } } + +func getCardRequests(str string) (out []string) { + remaining := str + for len(remaining) > 1 { + nextToken := strings.Index(remaining, "[[") + if nextToken < 0 { + break + } + endToken := strings.Index(remaining[nextToken:], "]]") + if endToken < 0 { + break + } + out = append(out, remaining[nextToken+2:nextToken+endToken]) + remaining = remaining[nextToken+2+endToken:] + } + return +} diff --git a/scryfall.go b/scryfall.go index 91d1a9f..9f16c83 100644 --- a/scryfall.go +++ b/scryfall.go @@ -73,3 +73,16 @@ func scryfallSearch(query string, offset int) (results CardSearchResults, err er results.Data = results.Data[cardoffset:maxoffset] return } + +func scryfallGetCard(cardname string) (card CardData, err error) { + cardname = url.QueryEscape(cardname) + requrl := fmt.Sprintf("https://api.scryfall.com/cards/named?fuzzy=%s") + response, err := netClient.Get(requrl) + if err != nil { + return + } + defer response.Body.Close() + + err = json.NewDecoder(response.Body).Decode(&card) + return +}