More commands
This commit is contained in:
133
commands/xkcd.go
Normal file
133
commands/xkcd.go
Normal file
@ -0,0 +1,133 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
|
||||
)
|
||||
|
||||
type XkcdCommand struct{}
|
||||
|
||||
type XkcdComic struct {
|
||||
Num int `json:"num"`
|
||||
Title string `json:"title"`
|
||||
SafeTitle string `json:"safe_title"`
|
||||
Img string `json:"img"`
|
||||
Alt string `json:"alt"`
|
||||
Transcript string `json:"transcript"`
|
||||
Link string `json:"link"`
|
||||
News string `json:"news"`
|
||||
Year string `json:"year"`
|
||||
Month string `json:"month"`
|
||||
Day string `json:"day"`
|
||||
}
|
||||
|
||||
func (x XkcdCommand) Name() string {
|
||||
return "xkcd"
|
||||
}
|
||||
|
||||
func (x XkcdCommand) Help() string {
|
||||
return "Get a random XKCD comic. Usage: /xkcd"
|
||||
}
|
||||
|
||||
func (x XkcdCommand) Execute(update tgbotapi.Update, bot *tgbotapi.BotAPI) {
|
||||
// Send "typing" action
|
||||
typingAction := tgbotapi.NewChatAction(update.Message.Chat.ID, tgbotapi.ChatTyping)
|
||||
bot.Send(typingAction)
|
||||
|
||||
comic, err := getRandomXkcdComic()
|
||||
if err != nil {
|
||||
log.Printf("Error getting XKCD comic: %v", err)
|
||||
msg := tgbotapi.NewMessage(update.Message.Chat.ID, "❌ Error fetching XKCD comic. Please try again later.")
|
||||
bot.Send(msg)
|
||||
return
|
||||
}
|
||||
|
||||
// Create caption
|
||||
caption := createXkcdCaption(comic)
|
||||
|
||||
// Send photo with caption
|
||||
photo := tgbotapi.NewPhoto(update.Message.Chat.ID, tgbotapi.FileURL(comic.Img))
|
||||
photo.Caption = caption
|
||||
bot.Send(photo)
|
||||
}
|
||||
|
||||
func getRandomXkcdComic() (*XkcdComic, error) {
|
||||
// First get the latest comic to know the range
|
||||
resp, err := http.Get("https://xkcd.com/info.0.json")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get latest comic info: %v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
return nil, fmt.Errorf("XKCD API returned status: %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read response: %v", err)
|
||||
}
|
||||
|
||||
var latest XkcdComic
|
||||
if err := json.Unmarshal(body, &latest); err != nil {
|
||||
return nil, fmt.Errorf("failed to parse latest comic: %v", err)
|
||||
}
|
||||
|
||||
// Generate random comic number (avoiding 404 which doesn't exist)
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
var randomNum int
|
||||
for {
|
||||
randomNum = rand.Intn(latest.Num) + 1
|
||||
if randomNum != 404 { // Comic 404 doesn't exist
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Get the random comic
|
||||
url := fmt.Sprintf("https://xkcd.com/%d/info.0.json", randomNum)
|
||||
resp, err = http.Get(url)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get comic %d: %v", randomNum, err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
return nil, fmt.Errorf("comic %d returned status: %d", randomNum, resp.StatusCode)
|
||||
}
|
||||
|
||||
body, err = io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read comic response: %v", err)
|
||||
}
|
||||
|
||||
var comic XkcdComic
|
||||
if err := json.Unmarshal(body, &comic); err != nil {
|
||||
return nil, fmt.Errorf("failed to parse comic: %v", err)
|
||||
}
|
||||
|
||||
return &comic, nil
|
||||
}
|
||||
|
||||
func createXkcdCaption(comic *XkcdComic) string {
|
||||
url := fmt.Sprintf("https://xkcd.com/%d/", comic.Num)
|
||||
|
||||
// Try to include alt text if caption isn't too long
|
||||
fullCaption := fmt.Sprintf("%s\n\n%s\n\n%s", comic.Title, comic.Alt, url)
|
||||
if len(fullCaption) <= 1000 { // Keep it reasonable for Telegram
|
||||
return fullCaption
|
||||
}
|
||||
|
||||
// Fallback to just title and URL if too long
|
||||
return fmt.Sprintf("%s\n\n%s", comic.Title, url)
|
||||
}
|
||||
|
||||
func init() {
|
||||
Register(XkcdCommand{})
|
||||
}
|
Reference in New Issue
Block a user