Files
velox-bot/internal/commands/fun/public/joke.go
T

154 lines
3.2 KiB
Go

package public
import (
"context"
"encoding/json"
"errors"
"fmt"
"net/http"
"time"
"velox-bot/internal/commands/fun/shared"
"github.com/bwmarrin/discordgo"
)
var Joke = &discordgo.ApplicationCommand{
Name: "joke",
Description: "Get a random joke",
Contexts: &[]discordgo.InteractionContextType{
discordgo.InteractionContextGuild,
discordgo.InteractionContextBotDM,
discordgo.InteractionContextPrivateChannel,
},
Options: []*discordgo.ApplicationCommandOption{
{
Type: discordgo.ApplicationCommandOptionString,
Name: "type",
Description: "The type of joke to get",
Required: false,
Choices: []*discordgo.ApplicationCommandOptionChoice{
{
Name: "Programming",
Value: "Programming",
},
{
Name: "Misc",
Value: "Miscellaneous",
},
{
Name: "Dark",
Value: "Dark",
},
{
Name: "Pun",
Value: "Pun",
},
{
Name: "Spooky",
Value: "Spooky",
},
{
Name: "Christmas",
Value: "Christmas",
},
},
},
},
}
func JokeHandler(s *discordgo.Session, i *discordgo.InteractionCreate) {
jokeType := "Any"
if opts := i.ApplicationCommandData().Options; len(opts) > 0 {
if v := opts[0].StringValue(); v != "" {
jokeType = v
}
}
if !isValidJokeType(jokeType) {
jokeType = "Any"
}
ctx, cancel := context.WithTimeout(context.Background(), 6*time.Second)
defer cancel()
content, err := fetchJoke(ctx, jokeType)
if err != nil {
if i.GuildID != "" {
shared.RespondEphemeral(s, i, "Failed to get joke.")
} else {
shared.Respond(s, i, "Failed to get joke.")
}
return
}
shared.Respond(s, i, content)
}
func isValidJokeType(t string) bool {
switch t {
case "Any", "Programming", "Misc", "Dark", "Pun", "Spooky", "Christmas":
return true
default:
return false
}
}
type jokeAPIResponse struct {
Error bool `json:"error"`
Message string `json:"message"`
Type string `json:"type"`
Joke string `json:"joke"`
Setup string `json:"setup"`
Delivery string `json:"delivery"`
}
func fetchJoke(ctx context.Context, jokeType string) (string, error) {
const baseURL = "https://v2.jokeapi.dev/joke"
req, err := http.NewRequestWithContext(ctx, http.MethodGet, fmt.Sprintf("%s/%s", baseURL, jokeType), nil)
if err != nil {
return "", err
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
return "", err
}
defer resp.Body.Close()
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
return "", fmt.Errorf("joke api status: %s", resp.Status)
}
var data jokeAPIResponse
if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
return "", err
}
if data.Error {
if data.Message != "" {
return "", errors.New(data.Message)
}
return "", errors.New("joke api returned error")
}
switch data.Type {
case "single":
if data.Joke == "" {
return "", errors.New("empty joke")
}
return data.Joke, nil
case "twopart":
if data.Setup == "" && data.Delivery == "" {
return "", errors.New("empty joke")
}
if data.Setup == "" {
return data.Delivery, nil
}
if data.Delivery == "" {
return data.Setup, nil
}
return data.Setup + "\n" + data.Delivery, nil
default:
return "", fmt.Errorf("unknown joke type: %q", data.Type)
}
}