Notify OP on HN about claimable sats
This commit is contained in:
parent
0e47ca21fd
commit
9f3b488d05
|
@ -1,2 +1,3 @@
|
||||||
SN_AUTH_COOKIE=
|
SN_AUTH_COOKIE=
|
||||||
|
SN_USERNAME=hn
|
||||||
HN_AUTH_COOKIE=
|
HN_AUTH_COOKIE=
|
||||||
|
|
13
hn.go
13
hn.go
|
@ -159,3 +159,16 @@ func HackerNewsUserLink(user string) string {
|
||||||
func HackerNewsItemLink(id int) string {
|
func HackerNewsItemLink(id int) string {
|
||||||
return fmt.Sprintf("%s/item?id=%d", HackerNewsUrl, id)
|
return fmt.Sprintf("%s/item?id=%d", HackerNewsUrl, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func FindHackerNewsItemId(text string) int {
|
||||||
|
re := regexp.MustCompile(fmt.Sprintf(`\[HN\]\(%s/item\?id=([0-9]+)\)`, HackerNewsUrl))
|
||||||
|
match := re.FindStringSubmatch(text)
|
||||||
|
if len(match) == 0 {
|
||||||
|
log.Fatal("No Hacker News item URL found")
|
||||||
|
}
|
||||||
|
id, err := strconv.Atoi(match[1])
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
|
79
main.go
79
main.go
|
@ -1,9 +1,88 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/joho/godotenv"
|
||||||
|
"github.com/namsral/flag"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
SnUserName string
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
err := godotenv.Load()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("Error loading .env file")
|
||||||
|
}
|
||||||
|
flag.StringVar(&SnUserName, "SN_USERNAME", "", "Username of bot on SN")
|
||||||
|
flag.Parse()
|
||||||
|
if SnUserName == "" {
|
||||||
|
log.Fatal("SN_USERNAME not set")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GenerateHnComment(id int, sats int, nComments int) string {
|
||||||
|
lnInvoiceDocs := "https://docs.lightning.engineering/the-lightning-network/payment-lifecycle/understanding-lightning-invoices"
|
||||||
|
return fmt.Sprintf(
|
||||||
|
""+
|
||||||
|
"Your post received %d sats and %d comments on %s [0].\n\n"+
|
||||||
|
"To claim your sats, reply to this comment with a LN address or invoice [1].\n\n"+
|
||||||
|
"You can create a SN account to obtain a LN address.\n"+
|
||||||
|
"\n\n"+
|
||||||
|
"[0] %s/r/%s (referral link)\n\n"+
|
||||||
|
"[1] %s",
|
||||||
|
sats,
|
||||||
|
nComments,
|
||||||
|
StackerNewsUrl,
|
||||||
|
StackerNewsItemLink(id),
|
||||||
|
SnUserName,
|
||||||
|
lnInvoiceDocs,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GenerateSnReply(sats int, nComments int) string {
|
||||||
|
return fmt.Sprintf("Notified OP on HN that their post received %d sats and %d comments.", sats, nComments)
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
stories := FetchHackerNewsTopStories()
|
stories := FetchHackerNewsTopStories()
|
||||||
filtered := CurateContentForStackerNews(&stories)
|
filtered := CurateContentForStackerNews(&stories)
|
||||||
for _, story := range *filtered {
|
for _, story := range *filtered {
|
||||||
PostStoryToStackerNews(&story)
|
PostStoryToStackerNews(&story)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
items := FetchStackerNewsUserItems(SnUserName)
|
||||||
|
now := time.Now()
|
||||||
|
for _, item := range *items {
|
||||||
|
duration := now.Sub(item.CreatedAt)
|
||||||
|
if duration >= 24*time.Hour && item.Sats > 0 {
|
||||||
|
log.Printf("Found SN item (id=%d) older than 24 hours with %d sats and %d comments\n", item.Id, item.Sats, item.NComments)
|
||||||
|
for _, comment := range item.Comments {
|
||||||
|
if comment.User.Name == SnUserName {
|
||||||
|
snReply := GenerateSnReply(item.Sats, item.NComments)
|
||||||
|
// Check if OP on HN was already notified
|
||||||
|
alreadyNotified := false
|
||||||
|
for _, comment2 := range comment.Comments {
|
||||||
|
if comment2.User.Name == SnUserName {
|
||||||
|
alreadyNotified = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if alreadyNotified {
|
||||||
|
log.Println("OP on HN was already notified")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
text := comment.Text
|
||||||
|
hnItemId := FindHackerNewsItemId(text)
|
||||||
|
hnComment := GenerateHnComment(item.Id, item.Sats, item.NComments)
|
||||||
|
CommentHackerNewsStory(hnComment, hnItemId)
|
||||||
|
CommentStackerNewsPost(snReply, comment.Id)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
30
sn.go
30
sn.go
|
@ -34,17 +34,19 @@ type User struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
}
|
}
|
||||||
type Comment struct {
|
type Comment struct {
|
||||||
Id int `json:"id,string"`
|
Id int `json:"id,string"`
|
||||||
Text string `json:"text"`
|
Text string `json:"text"`
|
||||||
User User `json:"user"`
|
User User `json:"user"`
|
||||||
|
Comments []Comment `json:"comments"`
|
||||||
}
|
}
|
||||||
type Item struct {
|
type Item struct {
|
||||||
Id int `json:"id,string"`
|
Id int `json:"id,string"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Url string `json:"url"`
|
Url string `json:"url"`
|
||||||
Sats int `json:"sats"`
|
Sats int `json:"sats"`
|
||||||
CreatedAt string `json:"createdAt"`
|
CreatedAt time.Time `json:"createdAt"`
|
||||||
Comments []Comment `json:"comments"`
|
Comments []Comment `json:"comments"`
|
||||||
|
NComments int `json:"ncomments"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type UpsertLinkResponse struct {
|
type UpsertLinkResponse struct {
|
||||||
|
@ -63,11 +65,13 @@ type ItemsResponse struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
SnApiUrl string
|
StackerNewsUrl string
|
||||||
SnAuthCookie string
|
SnApiUrl string
|
||||||
|
SnAuthCookie string
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
StackerNewsUrl = "https://stacker.news"
|
||||||
SnApiUrl = "https://stacker.news/api/graphql"
|
SnApiUrl = "https://stacker.news/api/graphql"
|
||||||
err := godotenv.Load()
|
err := godotenv.Load()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -207,12 +211,22 @@ func FetchStackerNewsUserItems(user string) *[]Item {
|
||||||
title
|
title
|
||||||
url
|
url
|
||||||
sats
|
sats
|
||||||
|
createdAt
|
||||||
comments {
|
comments {
|
||||||
|
id
|
||||||
text
|
text
|
||||||
user {
|
user {
|
||||||
name
|
name
|
||||||
}
|
}
|
||||||
|
comments {
|
||||||
|
id
|
||||||
|
text
|
||||||
|
user {
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
ncomments
|
||||||
}
|
}
|
||||||
cursor
|
cursor
|
||||||
}
|
}
|
||||||
|
@ -251,3 +265,7 @@ func FetchStackerNewsUserItems(user string) *[]Item {
|
||||||
|
|
||||||
return &items
|
return &items
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func StackerNewsItemLink(id int) string {
|
||||||
|
return fmt.Sprintf("%s/items/%d", StackerNewsUrl, id)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue