Check in
This commit is contained in:
commit
c155adcbe0
4 changed files with 299 additions and 0 deletions
5
go.mod
Normal file
5
go.mod
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
module git.fromouter.space/mcg/mlpcardbot
|
||||||
|
|
||||||
|
go 1.12
|
||||||
|
|
||||||
|
require git.fromouter.space/hamcha/tg v0.0.0-20181213132350-d7698a3c50ea
|
2
go.sum
Normal file
2
go.sum
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
git.fromouter.space/hamcha/tg v0.0.0-20181213132350-d7698a3c50ea h1:2VrIQZEHaUGjf9Rqsli+S+/ZReLpodPWTklVUqQPCX0=
|
||||||
|
git.fromouter.space/hamcha/tg v0.0.0-20181213132350-d7698a3c50ea/go.mod h1:j0xF3DL3Y+HWAMzaFQlJxl9bLOKmFNEZNemg19vC+Cc=
|
236
main.go
Normal file
236
main.go
Normal file
|
@ -0,0 +1,236 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"unicode"
|
||||||
|
|
||||||
|
"git.fromouter.space/hamcha/tg"
|
||||||
|
)
|
||||||
|
|
||||||
|
type config struct {
|
||||||
|
Token string
|
||||||
|
Bind string
|
||||||
|
WebhookURL string
|
||||||
|
WebhookPath string
|
||||||
|
MaxRequestsPerMessage int
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkErr(err error, msg string, args ...interface{}) {
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("FATAL ERROR\n"+msg+":\n ", args...)
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var api *tg.Telegram
|
||||||
|
var cfg config
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
cfgpath := flag.String("config", "mlpcard.conf", "Path to config file")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
cfgfile, err := os.Open(*cfgpath)
|
||||||
|
checkErr(err, "Could not open config file")
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
type CardFaceFlipPics struct {
|
||||||
|
Normal string
|
||||||
|
Flipped string
|
||||||
|
Ponyhead string
|
||||||
|
MCM string
|
||||||
|
}
|
||||||
|
|
||||||
|
func webhook(update tg.APIUpdate) {
|
||||||
|
// Handle inline queries (99% of the usage I hope)
|
||||||
|
if update.Inline != nil {
|
||||||
|
query := update.Inline.Query
|
||||||
|
results, err := mlpapiSearch(query)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
// DO SOMETHING
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
photos := make([]tg.APIInlineQueryResultPhoto, len(results.Data))
|
||||||
|
for i, card := range results.Data {
|
||||||
|
face, caption, buttons := getCardEntry(card, 0)
|
||||||
|
photos[i] = tg.APIInlineQueryResultPhoto{
|
||||||
|
Type: "photo",
|
||||||
|
ResultID: strconv.FormatInt(card.GUID, 10),
|
||||||
|
PhotoURL: face,
|
||||||
|
ThumbURL: face,
|
||||||
|
Title: card.FullName,
|
||||||
|
Caption: caption,
|
||||||
|
Width: 672,
|
||||||
|
Height: 936,
|
||||||
|
ReplyMarkup: &tg.APIInlineKeyboardMarkup{
|
||||||
|
InlineKeyboard: [][]tg.APIInlineKeyboardButton{buttons},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = api.AnswerInlineQuery(tg.InlineQueryResponse{
|
||||||
|
QueryID: update.Inline.QueryID,
|
||||||
|
Results: photos,
|
||||||
|
})
|
||||||
|
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 {
|
||||||
|
cards, err := mlpapiSearch(cardname)
|
||||||
|
if err != nil {
|
||||||
|
errlist = append(errlist, cardname)
|
||||||
|
} else {
|
||||||
|
for _, card := range cards.Data {
|
||||||
|
face, _, _ := getCardEntry(card, 0)
|
||||||
|
cardmedia = append(cardmedia, tg.APIInputMediaPhoto{
|
||||||
|
Type: "photo",
|
||||||
|
Media: face,
|
||||||
|
})
|
||||||
|
if card.Type == "Mane" {
|
||||||
|
face, _, _ := getCardEntry(card, 1)
|
||||||
|
cardmedia = append(cardmedia, tg.APIInputMediaPhoto{
|
||||||
|
Type: "photo",
|
||||||
|
Media: face,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle inline callback requests (flipped cards)
|
||||||
|
if update.Callback != nil {
|
||||||
|
if update.Callback.Data != nil && strings.HasPrefix(*update.Callback.Data, "FLIP") {
|
||||||
|
parts := strings.SplitN(*update.Callback.Data, ",", 3)
|
||||||
|
card, err := mlpapiGetCardByID(parts[1])
|
||||||
|
facenum, _ := strconv.Atoi(parts[2])
|
||||||
|
if err == nil {
|
||||||
|
face, caption, buttons := getCardEntry(card, facenum)
|
||||||
|
api.EditMedia(tg.ClientEditMediaData{
|
||||||
|
InlineID: *update.Callback.InlineID,
|
||||||
|
Media: tg.APIInputMediaPhoto{
|
||||||
|
Type: "photo",
|
||||||
|
Media: face,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
api.EditCaption(tg.ClientEditCaptionData{
|
||||||
|
InlineID: *update.Callback.InlineID,
|
||||||
|
Caption: caption,
|
||||||
|
ReplyMarkup: &tg.APIInlineKeyboardMarkup{
|
||||||
|
InlineKeyboard: [][]tg.APIInlineKeyboardButton{buttons},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fmt.Println("Unknown callback: ", *update.Callback.Data)
|
||||||
|
}
|
||||||
|
api.AnswerCallback(tg.ClientCallbackQueryData{
|
||||||
|
QueryID: update.Callback.ID,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
func getCardEntry(card CardData, flipped int) (string, string, []tg.APIInlineKeyboardButton) {
|
||||||
|
cid := toCardID(card.AllIDs[0])
|
||||||
|
buttons := []tg.APIInlineKeyboardButton{
|
||||||
|
{
|
||||||
|
Text: "Ponyhead",
|
||||||
|
URL: "http://ponyhead.com/cards/" + cid,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
captions := []string{}
|
||||||
|
suffix := ""
|
||||||
|
if card.Type == "Mane" {
|
||||||
|
suffix = "a"
|
||||||
|
num := 1
|
||||||
|
if flipped != 0 {
|
||||||
|
suffix = "b"
|
||||||
|
num = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
buttons = append(buttons, tg.APIInlineKeyboardButton{
|
||||||
|
Text: "🔄",
|
||||||
|
CallbackData: fmt.Sprintf("FLIP,%s,%d", card.GUID, num),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
face := fmt.Sprintf("https://mcg.zyg.ovh/images/cards/%s%s.webp", cid, suffix)
|
||||||
|
return face, strings.Join(captions, " - "), buttons
|
||||||
|
}
|
||||||
|
|
||||||
|
func toCardID(id string) string {
|
||||||
|
id = strings.ToLower(id)
|
||||||
|
idx := strings.IndexFunc(id, unicode.IsLetter)
|
||||||
|
num, set := id[:idx], id[idx:]
|
||||||
|
return set + num
|
||||||
|
}
|
56
mlpapi1.go
Normal file
56
mlpapi1.go
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CardSearchResults struct {
|
||||||
|
Data []CardData `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CardSearchResultsSingle struct {
|
||||||
|
Data CardData `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CardData struct {
|
||||||
|
AllIDs []string `json:"allids"`
|
||||||
|
GUID int64 `json:"card_version_guid"`
|
||||||
|
FullName string `json:"fullname"`
|
||||||
|
Set string `json:"set"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var netClient = &http.Client{
|
||||||
|
Timeout: time.Second * 20,
|
||||||
|
}
|
||||||
|
|
||||||
|
func mlpapiSearch(query string) (results CardSearchResults, err error) {
|
||||||
|
query = url.QueryEscape(query)
|
||||||
|
requrl := fmt.Sprintf("https://www.ferrictorus.com/mlpapi1/cards?query=%s", query)
|
||||||
|
response, err := netClient.Get(requrl)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer response.Body.Close()
|
||||||
|
|
||||||
|
err = json.NewDecoder(response.Body).Decode(&results)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func mlpapiGetCardByID(id string) (card CardData, err error) {
|
||||||
|
requrl := fmt.Sprintf("https://www.ferrictorus.com/mlpapi1/cards/%s", id)
|
||||||
|
response, err := netClient.Get(requrl)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer response.Body.Close()
|
||||||
|
|
||||||
|
var res CardSearchResultsSingle
|
||||||
|
err = json.NewDecoder(response.Body).Decode(&res)
|
||||||
|
card = res.Data
|
||||||
|
return
|
||||||
|
}
|
Loading…
Reference in a new issue