all repos — navani @ 0d5afcf4ad87e61c3c01306a2f7a802a31a8d1a4

forlater's primary mail processing service

Initial code for Twitter API
Anirudh Oppiliappan x@icyphox.sh
Thu, 04 Nov 2021 11:23:54 +0530
commit

0d5afcf4ad87e61c3c01306a2f7a802a31a8d1a4

parent

2928def670071abf79a9dd21ecbaa532149405f4

4 files changed, 117 insertions(+), 13 deletions(-)

jump to
M go.modgo.mod

@@ -5,6 +5,8 @@

require ( blitiri.com.ar/go/spf v1.2.0 git.icyphox.sh/rel2abs v0.0.0-20210930060148-3afa938cbb82 + github.com/dghubble/go-twitter v0.0.0-20211002212826-ad02880e616b + github.com/dghubble/oauth1 v0.7.0 github.com/go-shiori/go-readability v0.0.0-20210627123243-82cc33435520 github.com/gomodule/redigo v1.8.5 github.com/joho/godotenv v1.3.0
M go.sumgo.sum

@@ -15,6 +15,8 @@ github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=

github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/cenkalti/backoff/v4 v4.1.1 h1:G2HAfAmvm/GcKan2oOQpBXOd2tT2G57ZnZGWa1PxPBQ= +github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=

@@ -26,6 +28,12 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=

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/dghubble/go-twitter v0.0.0-20211002212826-ad02880e616b h1:LbWfjdLiEeLNzNX8ylxqbAFLixA1jwBcwdT12XSo3i0= +github.com/dghubble/go-twitter v0.0.0-20211002212826-ad02880e616b/go.mod h1:MR6TM9P/md6XOePwjqvsBYvaNO2066MXnbiFASZiCOo= +github.com/dghubble/oauth1 v0.7.0 h1:AlpZdbRiJM4XGHIlQ8BuJ/wlpGwFEJNnB4Mc+78tA/w= +github.com/dghubble/oauth1 v0.7.0/go.mod h1:8pFdfPkv/jr8mkChVbNVuJ0suiHe278BtWI4Tk1ujxk= +github.com/dghubble/sling v1.4.0 h1:/n8MRosVTthvMbwlNZgLx579OGVjUOy3GNEv5BIqAWY= +github.com/dghubble/sling v1.4.0/go.mod h1:0r40aNsU9EdDUVBNhfCstAtFgutjgJGYbO1oNzkMoM8= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=

@@ -51,6 +59,10 @@ github.com/gomodule/redigo v1.8.5 h1:nRAxCa+SVsyjSBrtZmG/cqb6VbTmuRzpg/PoTFlpumc=

github.com/gomodule/redigo v1.8.5/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= +github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=

@@ -113,9 +125,11 @@ github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=

github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/xhit/go-simple-mail/v2 v2.10.0 h1:nib6RaJ4qVh5HD9UE9QJqnUZyWp3upv+Z6CFxaMj0V8=

@@ -163,6 +177,7 @@ golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=

@@ -179,6 +194,8 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= mvdan.cc/xurls/v2 v2.3.0 h1:59Olnbt67UKpxF1EwVBopJvkSUBmgtb468E4GVWIZ1I= mvdan.cc/xurls/v2 v2.3.0/go.mod h1:AjuTy7gEiUArFMjgBBDU4SMxlfUYsRokpJQgNWOt3e4=
M main.gomain.go

@@ -5,9 +5,13 @@ "encoding/json"

"log" "net/http" "net/url" + "os" + "strings" "git.icyphox.sh/forlater/navani/mail" "git.icyphox.sh/forlater/navani/reader" + "git.icyphox.sh/forlater/navani/reader/twitter" + _ "github.com/joho/godotenv" ) func main() {

@@ -31,25 +35,48 @@ parsedURL, err := url.Parse(u)

if err != nil { log.Printf("url parse: %v\n", err) } - - resp, err := reader.Fetch(parsedURL.String()) - if err != nil { - log.Printf("reader fetch: %v\n", err) - } + host := parsedURL.Host + switch { + case strings.Contains(host, "twitter.com"): + creds := twitter.Creds{ + AccessToken: os.Getenv("TWITTER_ACCESS_TOKEN"), + AccessTokenSecret: os.Getenv("TWITTER_ACCESS_SECRET"), + APIKey: os.Getenv("TWITTER_API_KEY"), + APISecret: os.Getenv("TWITTER_API_SECRET"), + } - article, err := reader.Readable(resp.Body, parsedURL) - if (err == nil) && (resp.MIMEType == "text/html") { - err = mail.SendArticle(&article, m.From, true) + client := twitter.GetClient(&creds) + tweet, err := twitter.GetTweet(client, u) + if err != nil { + log.Printf("error getting tweet: %v\n", err) + } + article := twitter.MakeTweetArticle(tweet, parsedURL) + err = mail.SendArticle(article, m.From, true) if err != nil { log.Printf("error sending mail to: %s: %v\n", m.From, err) } else { log.Printf("sent mail to %s: %s\n", m.From, article.Title) } - } else { - log.Printf("not readable: %s: %s\n", article.URL.String(), resp.MIMEType) - err := mail.SendArticle(&article, m.From, false) + default: + resp, err := reader.Fetch(parsedURL.String()) if err != nil { - log.Printf("error sending mail to: %s: %v\n", m.From, err) + log.Printf("reader fetch: %v\n", err) + } + + article, err := reader.Readable(resp.Body, parsedURL) + if (err == nil) && (resp.MIMEType == "text/html") { + err = mail.SendArticle(&article, m.From, true) + if err != nil { + log.Printf("error sending mail to: %s: %v\n", m.From, err) + } else { + log.Printf("sent mail to %s: %s\n", m.From, article.Title) + } + } else { + log.Printf("not readable: %s: %s\n", article.URL.String(), resp.MIMEType) + err := mail.SendArticle(&article, m.From, false) + if err != nil { + log.Printf("error sending mail to: %s: %v\n", m.From, err) + } } } }
A reader/twitter/twitter.go

@@ -0,0 +1,58 @@

+package twitter + +import ( + "fmt" + "net/url" + "path" + "strconv" + + "git.icyphox.sh/forlater/navani/reader" + "github.com/dghubble/go-twitter/twitter" + "github.com/dghubble/oauth1" +) + +type Creds struct { + AccessToken string + AccessTokenSecret string + APIKey string + APISecret string +} + +func GetClient(creds *Creds) *twitter.Client { + config := oauth1.NewConfig(creds.APIKey, creds.APISecret) + token := oauth1.NewToken(creds.AccessToken, creds.AccessTokenSecret) + + httpClient := config.Client(oauth1.NoContext, token) + client := twitter.NewClient(httpClient) + + return client +} + +func parseSnowflake(url string) (int64, error) { + strid := path.Base(url) + id, err := strconv.ParseInt(strid, 10, 64) + if err != nil { + return 0, fmt.Errorf("snowflake: %w\n", err) + } + + return id, nil +} + +func GetTweet(client *twitter.Client, url string) (*twitter.Tweet, error) { + id, err := parseSnowflake(url) + if err != nil { + return nil, err + } + + tweet, _, err := client.Statuses.Show(id, nil) + return tweet, err +} + +func MakeTweetArticle(tweet *twitter.Tweet, u *url.URL) *reader.Article { + article := reader.Article{} + article.Content = tweet.Text + article.Title = fmt.Sprintf("Tweet: %s @%s", tweet.User.Name, tweet.User.ScreenName) + article.Byline = fmt.Sprintf("@%s tweeted on %s", tweet.User.ScreenName, tweet.CreatedAt) + article.URL = u + return &article +}