Merge branch '2-post-curated-content' into 'develop'
Use discord to enable manual posting of HN links Closes #2 See merge request ekzyis/hnbot!4
This commit is contained in:
commit
75597bab8e
|
@ -1,2 +1,3 @@
|
|||
SN_AUTH_COOKIE=
|
||||
DISCORD_WEBHOOK=
|
||||
DISCORD_TOKEN=
|
||||
|
|
38
discord.go
38
discord.go
|
@ -6,12 +6,15 @@ import (
|
|||
"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/bwmarrin/discordgo"
|
||||
"github.com/joho/godotenv"
|
||||
"github.com/namsral/flag"
|
||||
)
|
||||
|
||||
var (
|
||||
DiscordWebhook string
|
||||
DiscordToken string
|
||||
DiscordClient *discordgo.Session
|
||||
)
|
||||
|
||||
type DiscordEmbedFooter struct {
|
||||
|
@ -37,10 +40,45 @@ func init() {
|
|||
log.Fatal("Error loading .env file")
|
||||
}
|
||||
flag.StringVar(&DiscordWebhook, "DISCORD_WEBHOOK", "", "Webhook to send logs to discord")
|
||||
flag.StringVar(&DiscordToken, "DISCORD_TOKEN", "", "Discord bot token")
|
||||
flag.Parse()
|
||||
if DiscordWebhook == "" {
|
||||
log.Fatal("DISCORD_WEBHOOK not set")
|
||||
}
|
||||
if DiscordToken == "" {
|
||||
log.Fatal("DISCORD_TOKEN not set")
|
||||
}
|
||||
initBot()
|
||||
}
|
||||
|
||||
func initBot() {
|
||||
var err error
|
||||
DiscordClient, err = discordgo.New(DiscordToken)
|
||||
if err != nil {
|
||||
log.Fatal("error creating discord session:", err)
|
||||
}
|
||||
DiscordClient.AddHandler(func(s *discordgo.Session, event *discordgo.Ready) {
|
||||
log.Println("Logged in as", event.User.Username)
|
||||
})
|
||||
DiscordClient.AddHandler(onMessage)
|
||||
DiscordClient.Identify.Intents = discordgo.IntentsGuildMessages | discordgo.IntentsMessageContent
|
||||
err = DiscordClient.Open()
|
||||
if err != nil {
|
||||
log.Fatal("error opening connection to discord: ", err, " -- Is your token correct?")
|
||||
}
|
||||
}
|
||||
|
||||
func onMessage(s *discordgo.Session, m *discordgo.MessageCreate) {
|
||||
// Ignore all messages created by the bot itself
|
||||
if m.Author.ID == s.State.User.ID {
|
||||
return
|
||||
}
|
||||
id, err := ParseHackerNewsLink(m.Content)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
story := FetchStoryById(id)
|
||||
PostStoryToStackerNews(&story)
|
||||
}
|
||||
|
||||
func SendEmbedToDiscord(embed DiscordEmbed) {
|
||||
|
|
15
go.mod
15
go.mod
|
@ -3,11 +3,18 @@ module gitlab.com/ekzyis/hnbot
|
|||
go 1.20
|
||||
|
||||
require (
|
||||
github.com/dustin/go-humanize v1.0.1
|
||||
github.com/joho/godotenv v1.5.1
|
||||
github.com/namsral/flag v1.7.4-pre
|
||||
github.com/stretchr/testify v1.8.2
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/bwmarrin/discordgo v0.27.1 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/joho/godotenv v1.5.1 // indirect
|
||||
github.com/namsral/flag v1.7.4-pre // indirect
|
||||
github.com/gorilla/websocket v1.4.2 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/stretchr/testify v1.8.2 // indirect
|
||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b // indirect
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
|
13
go.sum
13
go.sum
|
@ -1,8 +1,12 @@
|
|||
github.com/bwmarrin/discordgo v0.27.1 h1:ib9AIc/dom1E/fSIulrBwnez0CToJE113ZGt4HoliGY=
|
||||
github.com/bwmarrin/discordgo v0.27.1/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0kIVMCHkZtRY=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||
github.com/namsral/flag v1.7.4-pre h1:b2ScHhoCUkbsq0d2C15Mv+VU8bl8hAXV8arnWiOHNZs=
|
||||
|
@ -16,6 +20,15 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
|||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
|
||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b h1:7mWr3k41Qtv8XlltBkDkl8LoP3mpSgBW8BUoxtEdbXg=
|
||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
|
|
18
hn.go
18
hn.go
|
@ -2,9 +2,12 @@ package main
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type ItemID = int
|
||||
|
@ -23,11 +26,13 @@ type Story struct {
|
|||
var (
|
||||
HackerNewsUrl string
|
||||
HackerNewsFirebaseUrl string
|
||||
HackerNewsLinkRegexp *regexp.Regexp
|
||||
)
|
||||
|
||||
func init() {
|
||||
HackerNewsUrl = "https://news.ycombinator.com"
|
||||
HackerNewsFirebaseUrl = "https://hacker-news.firebaseio.com/v0"
|
||||
HackerNewsLinkRegexp = regexp.MustCompile(`(?:https?:\/\/)?news\.ycombinator\.com\/item\?id=([0-9]+)`)
|
||||
}
|
||||
|
||||
func FetchHackerNewsTopStories() []Story {
|
||||
|
@ -79,6 +84,19 @@ func FetchStoryById(id ItemID) Story {
|
|||
return story
|
||||
}
|
||||
|
||||
func ParseHackerNewsLink(link string) (ItemID, error) {
|
||||
match := HackerNewsLinkRegexp.FindStringSubmatch(link)
|
||||
if len(match) == 0 {
|
||||
return -1, errors.New("input is not a hacker news link")
|
||||
}
|
||||
id, err := strconv.Atoi(match[1])
|
||||
if err != nil {
|
||||
// this should never happen
|
||||
panic(err)
|
||||
}
|
||||
return id, nil
|
||||
}
|
||||
|
||||
func HackerNewsUserLink(user string) string {
|
||||
return fmt.Sprintf("%s/user?id=%s", HackerNewsUrl, user)
|
||||
}
|
||||
|
|
13
main.go
13
main.go
|
@ -1,9 +1,14 @@
|
|||
package main
|
||||
|
||||
import "time"
|
||||
|
||||
func main() {
|
||||
stories := FetchHackerNewsTopStories()
|
||||
filtered := CurateContentForStackerNews(&stories)
|
||||
for _, story := range *filtered {
|
||||
PostStoryToStackerNews(&story)
|
||||
for {
|
||||
stories := FetchHackerNewsTopStories()
|
||||
filtered := CurateContentForStackerNews(&stories)
|
||||
for _, story := range *filtered {
|
||||
PostStoryToStackerNews(&story)
|
||||
}
|
||||
time.Sleep(time.Hour)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue