Last active
March 1, 2020 16:56
-
-
Save miyoyo/f565d9224b8e6f88a3355fd9c084786a to your computer and use it in GitHub Desktop.
Flutter doc explorer bot (CC-By) (Updated 2019/05/27: Updated domains)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"bytes" | |
"encoding/json" | |
"fmt" | |
"net/http" | |
"os" | |
"os/signal" | |
"regexp" | |
"syscall" | |
"github.com/bwmarrin/discordgo" | |
"github.com/jasonlvhit/gocron" | |
"github.com/sahilm/fuzzy" | |
) | |
type index []struct { | |
Name string `json:"name"` | |
QualifiedName string `json:"qualifiedName"` | |
Href string `json:"href"` | |
Type string `json:"type"` | |
OverriddenDepth int `json:"overriddenDepth"` | |
EnclosedBy struct { | |
Name string `json:"name"` | |
Type string `json:"type"` | |
} `json:"enclosedBy,omitempty"` | |
} | |
type pubSearch struct { | |
Packages []struct { | |
Package string `json:"package"` | |
} `json:"packages"` | |
Next string `json:"next"` | |
} | |
var searchStrings []string | |
var searchIndex index | |
func main() { | |
directPattern := regexp.MustCompile("!\\[(.*?)\\]") | |
searchPattern := regexp.MustCompile("\\?\\[(.*?)\\]") | |
pubPattern := regexp.MustCompile("&\\[(.*?)\\]") | |
bot, err := discordgo.New("Bot TOKEN") | |
if err != nil { | |
panic(err.Error()) | |
} | |
bot.AddHandler(func(s *discordgo.Session, h *discordgo.MessageCreate) { | |
if h.Author.ID == s.State.User.ID { | |
return | |
} | |
if len(h.Content) >= 21 { | |
if h.Content[:21] == "<@462299661995343882>" { //Bot source | |
bot.ChannelMessageSendEmbed(h.ChannelID, &discordgo.MessageEmbed{ | |
Title: "ℹ️ Help", | |
Description: "⚠️ These commands can be within a message, and there can be multiple per messages", | |
Fields: []*discordgo.MessageEmbedField{ | |
&discordgo.MessageEmbedField{ | |
Name: "![query]", | |
Value: "Gives a direct link to the first result matching 'query', with a bias towards constructors", | |
}, | |
&discordgo.MessageEmbedField{ | |
Name: "?[query]", | |
Value: "Shows the 10 first search results about 'query'", | |
}, | |
&discordgo.MessageEmbedField{ | |
Name: "&[query]", | |
Value: "Shows up to 13 search results about 'query' on Pub", | |
}, | |
}, | |
Footer: &discordgo.MessageEmbedFooter{ | |
Text: "Source: https://gist.github.com/miyoyo/f565d9224b8e6f88a3355fd9c084786a", | |
}, | |
}) | |
} | |
} | |
for _, value := range directPattern.FindAllStringSubmatch(h.Content, -1) { | |
matches := fuzzy.Find(value[1], searchStrings) | |
if len(matches) == 0 { | |
s.ChannelMessageSendEmbed(h.ChannelID, &discordgo.MessageEmbed{ | |
Title: "Direct reference - " + value[1], | |
Description: "Not found.", | |
Color: 0xEE0000, | |
}) | |
} else { | |
selected := matches[0] | |
if len(matches) > 1 && searchIndex[matches[0].Index].Type != "class" { | |
if searchIndex[matches[1].Index].Type == "class" { | |
selected = matches[1] | |
} | |
} | |
s.ChannelMessageSend(h.ChannelID, "https://api.flutter.dev/flutter/"+searchIndex[selected.Index].Href) | |
} | |
} | |
for _, value := range searchPattern.FindAllStringSubmatch(h.Content, -1) { | |
matches := fuzzy.Find(value[1], searchStrings) | |
embeds := []*discordgo.MessageEmbedField{} | |
setSize := 5 | |
if len(matches) < setSize { | |
setSize = len(matches) | |
} | |
for _, result := range matches[:setSize] { | |
embeds = append(embeds, &discordgo.MessageEmbedField{ | |
Name: searchIndex[result.Index].Type + " " + searchIndex[result.Index].Name + " - " + searchIndex[result.Index].EnclosedBy.Name, | |
Value: "https://api.flutter.dev/flutter/" + searchIndex[result.Index].Href, | |
}) | |
} | |
if len(embeds) == 0 { | |
s.ChannelMessageSendEmbed(h.ChannelID, &discordgo.MessageEmbed{ | |
Title: "Search results - " + value[1], | |
Description: "Not found.", | |
Color: 0xEE0000, | |
}) | |
} else { | |
s.ChannelMessageSendEmbed(h.ChannelID, &discordgo.MessageEmbed{ | |
Title: "Search results - " + value[1], | |
Fields: embeds, | |
}) | |
} | |
} | |
for _, value := range pubPattern.FindAllStringSubmatch(h.Content, -1) { | |
var pubResult pubSearch | |
embeds := []*discordgo.MessageEmbedField{} | |
out, err := http.Get("https://pub.dev/api/search?q=" + value[1]) | |
if err != nil { | |
bot.ChannelMessageSend("446257816345378827", "Failed to query search api: %s"+err.Error()) //Debug channel | |
s.ChannelMessageSendEmbed(h.ChannelID, &discordgo.MessageEmbed{ | |
Title: "Search results - " + value[1], | |
Description: "Could not contact Pub.", | |
Color: 0xEE0000, | |
}) | |
return | |
} | |
buf := new(bytes.Buffer) | |
buf.ReadFrom(out.Body) | |
json.Unmarshal(buf.Bytes(), &pubResult) | |
for _, result := range pubResult.Packages { | |
embeds = append(embeds, &discordgo.MessageEmbedField{ | |
Name: result.Package, | |
Value: "https://pub.dev/packages/" + result.Package, | |
}) | |
} | |
if len(embeds) == 0 { | |
s.ChannelMessageSendEmbed(h.ChannelID, &discordgo.MessageEmbed{ | |
Title: "Pub search results - " + value[1], | |
Description: "Not found.", | |
Color: 0xEE0000, | |
}) | |
return | |
} | |
s.ChannelMessageSendEmbed(h.ChannelID, &discordgo.MessageEmbed{ | |
Title: "Pub search results - " + value[1], | |
Fields: embeds, | |
}) | |
} | |
}) | |
if bot.Open() != nil { | |
panic("could not open bot: " + err.Error()) | |
} | |
updateIndex(bot) | |
go func(bot *discordgo.Session) { | |
gocron.Every(1).Day().Do(updateIndex, bot) | |
gocron.Every(30).Minutes().Do(func() { bot.UpdateStatus(0, "mention me for help.") }) | |
<-gocron.Start() | |
}(bot) | |
fmt.Println("FlutterDoc is now running. Press CTRL-C to exit.") | |
sc := make(chan os.Signal, 1) | |
signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt, os.Kill) | |
<-sc | |
bot.Close() | |
} | |
func updateIndex(bot *discordgo.Session) { | |
bot.UpdateStatusComplex(discordgo.UpdateStatusData{ | |
Status: "idle", | |
AFK: true, | |
Game: &discordgo.Game{ | |
Name: "updating search...", | |
}, | |
}) | |
out, err := http.Get("https://api.flutter.dev/flutter/index.json") | |
if err != nil { | |
bot.ChannelMessageSend("446257816345378827", "Failed to update index: %s"+err.Error()) //Debug channel | |
return | |
} | |
buf := new(bytes.Buffer) | |
buf.ReadFrom(out.Body) | |
json.Unmarshal(buf.Bytes(), &searchIndex) | |
searchStrings = nil | |
for _, value := range searchIndex { | |
searchStrings = append(searchStrings, value.QualifiedName) | |
} | |
bot.UpdateStatus(0, "mention me for help.") | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment