More commands

This commit is contained in:
2025-06-25 15:53:42 +02:00
parent 1eaef9f22f
commit e7a8cbc2a1
6 changed files with 381 additions and 1 deletions

133
commands/xkcd.go Normal file
View 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{})
}