Blame
Date:
Thu Dec 2 14:24:51 2021 UTC
Message:
fetch links title and send them back as privmsg

just like the playonbsd bot :)
001
2021-04-27
op
package main
002
2021-04-27
op
003
2021-04-27
op
import (
004
2021-04-27
op
"crypto/tls"
005
2021-04-27
op
"flag"
006
2021-04-27
op
"fmt"
007
2021-04-27
op
"io"
008
2021-04-27
op
"io/ioutil"
009
2021-04-27
op
"log"
010
2021-04-27
op
"net/http"
011
2021-07-30
op
"path"
012
2021-04-27
op
"path/filepath"
013
2021-04-27
op
"regexp"
014
2021-11-07
op
"strings"
015
2021-04-27
op
016
2021-04-27
op
irc "github.com/fluffle/goirc/client"
017
2021-12-02
op
"golang.org/x/net/html"
018
2021-04-27
op
)
019
2021-04-27
op
020
2021-04-27
op
var (
021
2021-11-07
op
baseurl = flag.String("baseurl", "gemini://m2i.omarpolo.com", "base url")
022
2021-04-27
op
matrixOutDir = flag.String("matrix-out", "", "matrix out directory")
023
2021-04-27
op
024
2021-11-07
op
msgRe = regexp.MustCompile(`https://.*/[^\s]+\.(txt|png|jpg|jpeg|gif)`)
025
2021-07-30
op
channel = "#gemini-it"
026
2021-11-07
op
027
2021-11-07
op
tooLongRe = regexp.MustCompile(`full message at (https://libera.ems.host/.*)[)]`)
028
2021-12-02
op
029
2021-12-02
op
httplink = regexp.MustCompile(`https?://[^\s]+`)
030
2021-04-27
op
)
031
2021-04-27
op
032
2021-04-27
op
func matrix2gemini(conn *irc.Conn, line *irc.Line) {
033
2021-07-30
op
matches := msgRe.FindAllString(line.Text(), -1)
034
2021-04-27
op
035
2021-04-27
op
// it's not a good idea to defer inside a loop, but we know
036
2021-04-27
op
// len(matches) is small (usually just 1). Morover, I like
037
2021-04-27
op
// living in danger!
038
2021-04-27
op
039
2021-04-27
op
for _, link := range matches {
040
2021-04-27
op
resp, err := http.Get(link)
041
2021-04-27
op
if err != nil {
042
2021-04-27
op
conn.Privmsg(
043
2021-04-27
op
channel,
044
2021-04-27
op
fmt.Sprintf("failed to download %q: %s", link, err),
045
2021-04-27
op
)
046
2021-04-27
op
continue
047
2021-04-27
op
}
048
2021-04-27
op
defer resp.Body.Close()
049
2021-04-27
op
050
2021-07-30
op
ext := path.Ext(link)
051
2021-11-07
op
tmpfile, err := ioutil.TempFile(*matrixOutDir, "message-*"+ext)
052
2021-04-27
op
if err != nil {
053
2021-04-27
op
conn.Privmsg(channel, fmt.Sprintf("failed to tmpfile: %s", err))
054
2021-04-27
op
return
055
2021-04-27
op
}
056
2021-04-27
op
defer tmpfile.Close()
057
2021-04-27
op
058
2021-04-27
op
io.Copy(tmpfile, resp.Body)
059
2021-04-27
op
060
2021-04-27
op
conn.Privmsg(
061
2021-04-27
op
channel,
062
2021-04-27
op
fmt.Sprintf(
063
2021-04-27
op
"better: %s/%s",
064
2021-04-27
op
*baseurl,
065
2021-04-27
op
filepath.Base(tmpfile.Name()),
066
2021-04-27
op
),
067
2021-04-27
op
)
068
2021-04-27
op
}
069
2021-04-27
op
}
070
2021-04-27
op
071
2021-11-07
op
func messageTooLong(conn *irc.Conn, line *irc.Line) {
072
2021-11-07
op
matches := tooLongRe.FindStringSubmatch(line.Text())
073
2021-11-07
op
if len(matches) != 2 {
074
2021-11-07
op
return
075
2021-11-07
op
}
076
2021-11-07
op
077
2021-11-07
op
url := matches[1]
078
2021-11-07
op
079
2021-11-07
op
resp, err := http.Get(url)
080
2021-11-07
op
if err != nil {
081
2021-11-07
op
conn.Privmsg(
082
2021-11-07
op
channel,
083
2021-11-07
op
fmt.Sprintf("failed to download %q: %s", url, err),
084
2021-11-07
op
)
085
2021-11-07
op
return
086
2021-11-07
op
}
087
2021-11-07
op
defer resp.Body.Close()
088
2021-11-07
op
089
2021-11-07
op
sb := &strings.Builder{}
090
2021-11-07
op
if _, err := io.Copy(sb, resp.Body); err != nil {
091
2021-11-07
op
conn.Privmsg(
092
2021-11-07
op
channel,
093
2021-11-07
op
fmt.Sprintf("failed to read body of %q: %s", url, err),
094
2021-11-07
op
)
095
2021-11-07
op
return
096
2021-11-07
op
}
097
2021-11-07
op
098
2021-11-07
op
conn.Privmsg(channel, fmt.Sprintf("%s ha detto:", line.Nick))
099
2021-11-07
op
for _, line := range strings.Split(sb.String(), "\n") {
100
2021-11-07
op
conn.Privmsg(
101
2021-11-07
op
channel,
102
2021-11-07
op
line,
103
2021-11-07
op
)
104
2021-11-07
op
}
105
2021-11-07
op
}
106
2021-11-07
op
107
2021-12-02
op
func getPageTitle(node *html.Node) string {
108
2021-12-02
op
for child := node.FirstChild; child != nil; child = child.NextSibling {
109
2021-12-02
op
if child.Type == html.ElementNode && child.Data == "title" {
110
2021-12-02
op
text := node.FirstChild.Data
111
2021-12-02
op
return strings.Trim(text, " \t\n")
112
2021-12-02
op
}
113
2021-12-02
op
}
114
2021-12-02
op
return ""
115
2021-12-02
op
}
116
2021-12-02
op
117
2021-12-02
op
func getPageHead(node *html.Node) *html.Node {
118
2021-12-02
op
if node.Type == html.ElementNode && node.Data == "head" {
119
2021-12-02
op
return node
120
2021-12-02
op
}
121
2021-12-02
op
122
2021-12-02
op
for child := node.FirstChild; child != nil; child = child.NextSibling {
123
2021-12-02
op
if n := getPageHead(node); n != nil {
124
2021-12-02
op
return n
125
2021-12-02
op
}
126
2021-12-02
op
}
127
2021-12-02
op
return nil
128
2021-12-02
op
}
129
2021-12-02
op
130
2021-12-02
op
func pagetitle(conn *irc.Conn, line *irc.Line) {
131
2021-12-02
op
matches := httplink.FindAllString(line.Text(), -1)
132
2021-12-02
op
133
2021-12-02
op
for _, link := range matches {
134
2021-12-02
op
resp, err := http.Get(link)
135
2021-12-02
op
if err != nil {
136
2021-12-02
op
continue
137
2021-12-02
op
}
138
2021-12-02
op
defer resp.Body.Close()
139
2021-12-02
op
140
2021-12-02
op
doc, err := html.Parse(resp.Body)
141
2021-12-02
op
if err != nil {
142
2021-12-02
op
continue
143
2021-12-02
op
}
144
2021-12-02
op
145
2021-12-02
op
head := getPageHead(doc)
146
2021-12-02
op
if head == nil {
147
2021-12-02
op
continue
148
2021-12-02
op
}
149
2021-12-02
op
if title := getPageTitle(head); title != "" {
150
2021-12-02
op
conn.Privmsg(channel, title)
151
2021-12-02
op
}
152
2021-12-02
op
}
153
2021-12-02
op
}
154
2021-12-02
op
155
2021-04-27
op
func dostuff(conn *irc.Conn, line *irc.Line) {
156
2021-04-27
op
matrix2gemini(conn, line)
157
2021-11-07
op
messageTooLong(conn, line)
158
2021-12-02
op
pagetitle(conn, line)
159
2021-04-27
op
// ...
160
2021-04-27
op
}
161
2021-04-27
op
162
2021-04-27
op
func main() {
163
2021-04-27
op
flag.Parse()
164
2021-04-27
op
165
2021-04-27
op
cfg := irc.NewConfig("gemitbot")
166
2021-04-27
op
cfg.SSL = true
167
2021-07-30
op
cfg.SSLConfig = &tls.Config{ServerName: "irc.libera.chat"}
168
2021-07-30
op
cfg.Server = "irc.libera.chat:7000"
169
2021-04-27
op
cfg.NewNick = func(n string) string { return n + "^" }
170
2021-04-27
op
171
2021-04-27
op
c := irc.Client(cfg)
172
2021-04-27
op
173
2021-04-27
op
c.HandleFunc(irc.CONNECTED, func(conn *irc.Conn, line *irc.Line) {
174
2021-04-27
op
log.Println("connected, joining", channel)
175
2021-04-27
op
conn.Join(channel)
176
2021-04-27
op
})
177
2021-04-27
op
178
2021-04-27
op
c.HandleFunc(irc.PRIVMSG, dostuff)
179
2021-04-27
op
c.HandleFunc(irc.ACTION, dostuff)
180
2021-04-27
op
181
2021-04-27
op
quit := make(chan bool)
182
2021-04-27
op
183
2021-04-27
op
c.HandleFunc(irc.DISCONNECTED, func(conn *irc.Conn, line *irc.Line) {
184
2021-04-27
op
quit <- true
185
2021-04-27
op
})
186
2021-04-27
op
187
2021-04-27
op
if err := c.Connect(); err != nil {
188
2021-04-27
op
log.Fatalln("connection error:", err)
189
2021-04-27
op
}
190
2021-04-27
op
191
2021-04-27
op
<-quit
192
2021-04-27
op
}
Omar Polo