-
Notifications
You must be signed in to change notification settings - Fork 2
/
xkcdbot.go
171 lines (129 loc) · 3.88 KB
/
xkcdbot.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
package main
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"log"
"net/http"
)
const url string = "https://xkcd.com"
const counterApiUrl string = "https://kvdb.io"
type XKCDComic struct {
Month string `json:"month"`
Num int `json:"num"`
Link string `json:"link"`
Year string `json:"year"`
News string `json:"news"`
SafeTitle string `json:"safe_title"`
Transcript string `json:"transcript"`
Alt string `json:"alt"`
Img string `json:"img"`
Title string `json:"title"`
Day string `json:"day"`
}
func getXKCD(webHookUrl string) {
counterApiBucket := getEnvVar("KVDB_BUCKET")
if webHookUrl == "" {
log.Fatal("No such environment variable WEBHOOK_URL")
}
endpoint := counterApiUrl + "/" + counterApiBucket + "/xkcd"
// Get metadata for the latest posted XKCD comic strip. -1 means "get latest"
latestComicMetadata := getComicMetadata(-1)
lastComicIndex := getLastComicIndex(endpoint)
// Sort of a while loop - if there are newer comic(s) since last update, we should get'em all
for latestComicMetadata.Num > lastComicIndex {
nextComic := getComicMetadata(lastComicIndex + 1)
var err error
sendSlackNotification(webHookUrl, "Siste XKCD "+nextComic.Img)
fileName := fmt.Sprintf("xkcd-%d.png", nextComic.Num)
err = downloadFileFromUrl(nextComic.Img, fileName)
if err == nil {
lastComicIndex++
incrementComicIndex(endpoint)
} else {
break
}
// Break out of the loop once we have downloaded the latest comic
if latestComicMetadata.Num == lastComicIndex {
break
}
}
}
func incrementComicIndex(url string) {
client := &http.Client{}
payload := []byte("+1")
req, _ := http.NewRequest(http.MethodPatch, url, bytes.NewBuffer(payload))
req.Header.Set("Content-Type", "application/json")
resp, err := client.Do(req)
if err != nil {
log.Fatal("An error occurred incrementing comic index!")
}
defer resp.Body.Close()
}
func setComicIndex(value int, url string) {
client := &http.Client{}
payload := []byte(fmt.Sprint(value))
req, _ := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(payload))
req.Header.Set("Content-Type", "application/json")
resp, err := client.Do(req)
if err != nil {
log.Fatal("An error occurred setting comic index!")
}
defer resp.Body.Close()
}
func getLastComicIndex(url string) int {
// GET kvdb.io/bucket/key
response, apiError := http.Get(url)
if apiError != nil {
log.Fatal(apiError)
}
defer response.Body.Close()
body, err := ioutil.ReadAll(response.Body)
var latestComic int
err = json.Unmarshal(body, &latestComic)
if err != nil {
println("There was an error getting the index, does the key actually exist?")
panic(err.Error())
}
return latestComic
}
func getComicMetadata(comicNumber int) XKCDComic {
// Arbitrary comic: https://xkcd.com/{comicIndex}/info.0.json where comicIndex is 1..N
// Latest published comic: https://xkcd.com/info.0.json
// If comicNumber is set to a positive integer, it means we want one particular comic. If not, get the latest one.
var comicUrl string
if comicNumber > 0 {
comicUrl = fmt.Sprintf("https://xkcd.com/%d/info.0.json", comicNumber)
} else {
comicUrl = "https://xkcd.com/info.0.json"
}
response, apiError := http.Get(comicUrl)
if apiError != nil {
log.Fatal(apiError)
}
defer response.Body.Close()
body, err := ioutil.ReadAll(response.Body)
var comicMetadata XKCDComic
err = json.Unmarshal(body, &comicMetadata)
if err != nil {
panic(err.Error())
}
return comicMetadata
}
func XKCDCreate(w http.ResponseWriter, r *http.Request) {
var x XKCDComic
err := decodeJSONBody(w, r, &x)
if err != nil {
var mr *malformedRequest
if errors.As(err, &mr) {
http.Error(w, mr.msg, mr.status)
} else {
log.Print(err.Error())
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
}
return
}
fmt.Fprintf(w, "Comic: %+v", x)
}