OpenBibleDiscord/main.go
2022-07-14 13:38:31 +02:00

274 lines
6.3 KiB
Go

package main
import (
"flag"
"log"
"os"
"os/signal"
"strings"
"time"
"github.com/bwmarrin/discordgo"
"github.com/gocolly/colly"
)
type BibleStructure struct {
bibleref string
verse string
}
func TopicScraper(keyword string) []BibleStructure {
c := colly.NewCollector()
c.SetRequestTimeout(120 * time.Second)
verses := make([]BibleStructure, 0)
c.OnHTML("div.verse", func(h *colly.HTMLElement) {
v := BibleStructure{}
v.bibleref = h.ChildText("a")
v.verse = h.ChildText("p")
verses = append(verses, v)
})
c.Visit("https://www.openbible.info/topics/" + keyword)
return verses
}
func VerseBuilder(search string, n int) string {
// If user enters negative number
if n < 1 {
return "Invalid"
}
// Set max ammount of verses to 5
if n > 5 {
n = 5
}
topic := TopicScraper(search)
topicLen := len(topic)
// If site can't find any topics
if topicLen == 0 {
return "No results"
}
var returnString strings.Builder
// String to be returned
returnString.WriteString("Topic: " + search + "\n")
// Populate return string
for i := 0; i < n; i++ {
if i < topicLen {
returnString.WriteString(topic[i].bibleref + "\n" + "> " + topic[i].verse + "\n\n")
} else {
return returnString.String()
}
}
return returnString.String()
}
// Bot parameters
var (
GuildID = flag.String("guild", "", "Test guild ID. If not passed - bot registers commands globally")
BotToken = flag.String("token", "[YOUR-DISCORD-TOKEN]", "Bot access token")
RemoveCommands = flag.Bool("rmcmd", true, "Remove all commands after shutdowning or not")
)
var s *discordgo.Session
func init() { flag.Parse() }
func init() {
var err error
s, err = discordgo.New("Bot " + *BotToken)
if err != nil {
log.Fatalf("Invalid bot parameters: %v", err)
}
}
var (
commands = []*discordgo.ApplicationCommand{
{
Name: "bible-topic",
Description: "What does the bible say about a topic?",
Type: discordgo.ChatApplicationCommand,
Options: []*discordgo.ApplicationCommandOption{
{
Name: "topic",
Description: "A topic in the bible",
Type: discordgo.ApplicationCommandOptionString,
Required: true,
Autocomplete: true,
},
{
Name: "amount",
Description: "Amount of verses to see (max 5)",
Type: discordgo.ApplicationCommandOptionInteger,
Required: false,
Autocomplete: false,
},
},
},
}
commandHandlers = map[string]func(s *discordgo.Session, i *discordgo.InteractionCreate){
"bible-topic": func(s *discordgo.Session, i *discordgo.InteractionCreate) {
switch i.Type {
case discordgo.InteractionApplicationCommand:
data := i.ApplicationCommandData()
amountOfVerses := 1
if len(data.Options) > 1 {
amountOfVerses = int(data.Options[1].IntValue())
}
err := s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: VerseBuilder(data.Options[0].StringValue(), amountOfVerses),
},
})
if err != nil {
panic(err)
}
// Autocomplete options introduce a new interaction type (8) for returning custom autocomplete results.
case discordgo.InteractionApplicationCommandAutocomplete:
data := i.ApplicationCommandData()
choices := []*discordgo.ApplicationCommandOptionChoice{
{
Name: "10 commandments",
Value: "10 commandments",
},
{
Name: "homosexaulity",
Value: "homosexaulity",
},
{
Name: "forgiveness",
Value: "forgiveness",
},
{
Name: "sodom",
Value: "sodom",
},
{
Name: "signs of the end times",
Value: "signs of the end times",
},
{
Name: "bitter woman",
Value: "bitter woman",
},
{
Name: "the purpose of the woman",
Value: "the purpose of the woman",
},
{
Name: "woman",
Value: "woman",
},
{
Name: "abortion",
Value: "abortion",
},
{
Name: "harming your body",
Value: "harming your body",
},
{
Name: "healthy eating",
Value: "healthy eating",
},
{
Name: "confrontation",
Value: "confrontation",
},
{
Name: "confusion",
Value: "confusion",
},
{
Name: "non believers",
Value: "non believers",
},
{
Name: "not giving up",
Value: "not giving up",
},
{
Name: "truth",
Value: "truth",
},
{
Name: "transvestites",
Value: "transvestites",
},
{
Name: "telling the truth",
Value: "telling the truth",
},
{
Name: "not telling the truth",
Value: "not telling the truth",
},
// And so on, up to 25 choices
}
if data.Options[0].StringValue() != "" {
choices = append(choices, &discordgo.ApplicationCommandOptionChoice{
Name: data.Options[0].StringValue(), // To get user input you just get value of the autocomplete option.
Value: data.Options[0].StringValue(),
})
}
err := s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionApplicationCommandAutocompleteResult,
Data: &discordgo.InteractionResponseData{
Choices: choices, // This is basically the whole purpose of autocomplete interaction - return custom options to the user.
},
})
if err != nil {
panic(err)
}
}
},
}
)
func main() {
s.AddHandler(func(s *discordgo.Session, r *discordgo.Ready) { log.Println("Bot is up!") })
s.AddHandler(func(s *discordgo.Session, i *discordgo.InteractionCreate) {
if h, ok := commandHandlers[i.ApplicationCommandData().Name]; ok {
h(s, i)
}
})
err := s.Open()
if err != nil {
log.Fatalf("Cannot open the session: %v", err)
}
defer s.Close()
createdCommands, err := s.ApplicationCommandBulkOverwrite(s.State.User.ID, *GuildID, commands)
if err != nil {
log.Fatalf("Cannot register commands: %v", err)
}
stop := make(chan os.Signal, 1)
signal.Notify(stop, os.Interrupt)
<-stop
log.Println("Gracefully shutting down")
if *RemoveCommands {
for _, cmd := range createdCommands {
err := s.ApplicationCommandDelete(s.State.User.ID, *GuildID, cmd.ID)
if err != nil {
log.Fatalf("Cannot delete %q command: %v", cmd.Name, err)
}
}
}
}