-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathremind.go
168 lines (139 loc) · 4.58 KB
/
remind.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
package main
import (
"bytes"
"fmt"
"html/template"
"io/ioutil"
"log"
"math/rand"
"os"
"regexp"
"strings"
"time"
"github.com/sendgrid/sendgrid-go"
"github.com/sendgrid/sendgrid-go/helpers/mail"
)
// Define the struct for the clipping
type Clipping struct {
Title string
Author string
Page string
When string
Highlight string
}
func main() {
// Read the contents of the clippings.txt file
filePath := "clippings.txt"
content, err := ioutil.ReadFile(filePath)
if err != nil {
fmt.Printf("Failed to read the file: %v", err)
return
}
// Parse the clippings
clippingSlice := parseClippings(string(content))
// Select 3 random quotes
selectedClippings := selectRandomClippings(clippingSlice, 3)
// pull in environment variables
sendgridAPIKey := os.Getenv("SENDGRID_API_KEY")
senderEmail := os.Getenv("SENDER_EMAIL")
recipientEmail := os.Getenv("RECIPIENT_EMAIL")
// Use the template to generate the email
var tmplFile = "email.tmpl"
tmpl, err := template.New(tmplFile).ParseFiles(tmplFile)
if err != nil {
panic(err)
}
var emailContent bytes.Buffer
err = tmpl.Execute(&emailContent, selectedClippings)
if err != nil {
log.Fatalf("Failed to execute template: %s", err)
}
err = sendEmail(sendgridAPIKey, senderEmail, recipientEmail, emailContent.String())
if err != nil {
log.Fatalf("Failed to send email: %s", err)
}
log.Println("Email sent successfully!")
}
// Parse the clippings from the Kindle file
func parseClippings(data string) []Clipping {
// Split the data into individual clippings
delimiter := "=========="
clippings := strings.Split(data, delimiter)
// Define the regular expression patterns to extract the required information
titlePattern := `^([^\n(]+)` //string up until the first parenthesis
authorPattern := `\((.*?)\)` //string between the first and second parenthesis
pagePattern := `on page (\d+)` //string after the word "page"
whenPattern := `Added on\s+(.+)` //string after the word "Added"
highlightPattern := `Added on[^\n]+\n?\r?\n?(.*)` //string after the word "Added" and the newline
// Create a slice to store the clippings
clippingSlice := []Clipping{}
// Extract the information for each clipping
for _, clipping := range clippings {
// Trim leading and trailing whitespace from the clipping
clipping = strings.TrimSpace(clipping)
// Skip empty clippings
if clipping == "" {
continue
}
// Extract the information using regex
titleRegex := regexp.MustCompile(titlePattern)
authorRegex := regexp.MustCompile(authorPattern)
pageRegex := regexp.MustCompile(pagePattern)
whenRegex := regexp.MustCompile(whenPattern)
highlightRegex := regexp.MustCompile(highlightPattern)
title := extractSubmatch(clipping, titleRegex, "title")
author := extractSubmatch(clipping, authorRegex, "author")
page := extractSubmatch(clipping, pageRegex, "page")
when := extractSubmatch(clipping, whenRegex, "when")
highlight := extractSubmatch(clipping, highlightRegex, "highlight")
// Create a new Clipping struct and append it to the slice
newClipping := Clipping{
Title: title,
Author: author,
Page: page,
When: when,
Highlight: highlight,
}
clippingSlice = append(clippingSlice, newClipping)
}
return clippingSlice
}
// Selects a given number of random clips from the clippings
func selectRandomClippings(clippings []Clipping, count int) []Clipping {
// Set the random seed
rand.Seed(time.Now().UnixNano())
// Shuffle the clippings
rand.Shuffle(len(clippings), func(i, j int) {
clippings[i], clippings[j] = clippings[j], clippings[i]
})
// Select the desired number of clips
clips := clippings[:count]
return clips
}
// Function to extract submatch and handle errors
func extractSubmatch(clipping string, regex *regexp.Regexp, label string) string {
match := regex.FindStringSubmatch(clipping)
if len(match) < 2 {
log.Fatalf("Failed to extract %s from clipping", label)
}
return match[1]
}
// Send an email with the selected clippings
func sendEmail(apiKey, senderEmail, recipientEmail, emailContent string) error {
message := mail.NewSingleEmail(
mail.NewEmail("Remind App", senderEmail),
"Here is your REMINDer",
mail.NewEmail("You", recipientEmail),
"",
emailContent,
)
client := sendgrid.NewSendClient(apiKey)
response, err := client.Send(message)
if err != nil {
return fmt.Errorf("failed to send email: %s", err)
}
if response.StatusCode >= 200 && response.StatusCode < 300 {
return nil
}
return fmt.Errorf("failed to send email: status code %d", response.StatusCode)
}