From 2fd8f5d20b6ebfc657c52e14bcea4adc50237076 Mon Sep 17 00:00:00 2001 From: Manuel Date: Tue, 17 Oct 2023 00:00:00 +0200 Subject: [PATCH 1/4] chore: Add dockerignore, Update editorconfig, Update dependencies * Add dockerignore and update editorconfig for Dockerfile * Abort docker build if arch is not supported --- .dockerignore | 5 +++++ .editorconfig | 6 +++++- Dockerfile.multiarch | 6 ++++-- config.example.toml | 2 +- docker-bake.hcl | 1 - go.mod | 4 ++-- go.sum | 31 ++++++++----------------------- 7 files changed, 25 insertions(+), 30 deletions(-) create mode 100644 .dockerignore diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..38c978b --- /dev/null +++ b/.dockerignore @@ -0,0 +1,5 @@ +* +!*.example.* +!**/go.mod +!**/go.sum +!**/*.go diff --git a/.editorconfig b/.editorconfig index 84dd35a..75f84cb 100644 --- a/.editorconfig +++ b/.editorconfig @@ -10,7 +10,11 @@ trim_trailing_whitespace = true indent_style = tab indent_size = 4 -[*.{yml,yaml,hcl,toml}] +[{Dockerfile,Dockerfile.*}] +indent_style = space +indent_size = 4 + +[*.{yml,yaml,hcl,toml,json}] indent_style = space indent_size = 2 diff --git a/Dockerfile.multiarch b/Dockerfile.multiarch index a34e326..1dfb97d 100644 --- a/Dockerfile.multiarch +++ b/Dockerfile.multiarch @@ -10,7 +10,8 @@ RUN apt-get update && \ "arm64") apt-get install -y gcc-aarch64-linux-gnu ;; \ "armv7") apt-get install -y gcc-arm-linux-gnueabihf ;; \ "riscv64") apt-get install -y gcc-riscv64-linux-gnu ;; \ - *) apt-get install -y gcc ;; \ + "amd64") apt-get install -y gcc ;; \ + *) echo "Arch not supported" && exit 1 ;; \ esac WORKDIR /tmp/app @@ -20,7 +21,8 @@ RUN go mod download && \ "arm64") export CC="aarch64-linux-gnu-gcc" PIE=true ;; \ "armv7") export CC="arm-linux-gnueabihf-gcc" GOARM="7" ;; \ "riscv64") export CC="riscv64-linux-gnu-gcc" ;; \ - *) export CC="gcc" PIE=true ;; \ + "amd64") export CC="gcc" PIE=true ;; \ + *) echo "Arch not supported" && exit 1 ;; \ esac && \ export CGO_ENABLED=1 && \ if [ $PIE = true ]; then \ diff --git a/config.example.toml b/config.example.toml index bf3549b..c23a723 100644 --- a/config.example.toml +++ b/config.example.toml @@ -1,4 +1,4 @@ -username = "Someuser" +username = "" password = "asd123" #proxyaddr = "socks5://localhost:5555" channels = [ diff --git a/docker-bake.hcl b/docker-bake.hcl index 49fef6f..2c6c7cc 100644 --- a/docker-bake.hcl +++ b/docker-bake.hcl @@ -26,7 +26,6 @@ target "prod" { #dockerfile = "Dockerfile" dockerfile = "Dockerfile.multiarch" output = ["type=registry"] - } target "dev" { inherits = ["default"] diff --git a/go.mod b/go.mod index ef4193e..3c91360 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/BurntSushi/toml v1.3.2 github.com/jmoiron/sqlx v1.3.5 github.com/mattn/go-sqlite3 v1.14.17 - github.com/n0madic/twitter-scraper v0.0.0-20230711213008-94503a2bc36c + github.com/n0madic/twitter-scraper v0.0.0-20231012104931-652b5b5115a4 ) -require golang.org/x/net v0.14.0 // indirect +require golang.org/x/net v0.17.0 // indirect diff --git a/go.sum b/go.sum index 0110c05..8fd4225 100644 --- a/go.sum +++ b/go.sum @@ -1,13 +1,7 @@ -cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g= @@ -17,24 +11,21 @@ github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM= github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= -github.com/n0madic/twitter-scraper v0.0.0-20230711213008-94503a2bc36c h1:pcEcP5jkXQuze3pkUDc7qtDZca1TP208LgkgXzVn/lc= -github.com/n0madic/twitter-scraper v0.0.0-20230711213008-94503a2bc36c/go.mod h1:VS1i48kYWIoiS0vz6k7GU6iuwcr6deD3CovldOR2rQE= +github.com/n0madic/twitter-scraper v0.0.0-20231012104931-652b5b5115a4 h1:U+UOzbyHe3Y5I/rSCUPsBKfVDq5YaMHWyLpljFU+B3I= +github.com/n0madic/twitter-scraper v0.0.0-20231012104931-652b5b5115a4/go.mod h1:qoLNLwgpaGspT8E82iwzof9xGsQTg35j36PlXrD3R4o= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= -golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= -golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= -golang.org/x/oauth2 v0.9.0/go.mod h1:qYgFZaFiu6Wg24azG8bdV52QJXJGbZzIIsRCdVKzbLw= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -45,26 +36,20 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= -golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo= +golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= From 711f2d2e7b4888e7c087bde7519439fe031e74c5 Mon Sep 17 00:00:00 2001 From: Manuel Date: Tue, 17 Oct 2023 00:05:00 +0200 Subject: [PATCH 2/4] fix: Open account login flow rework --- cmd/tweeter.go | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/cmd/tweeter.go b/cmd/tweeter.go index 1bbd295..e9d03b5 100644 --- a/cmd/tweeter.go +++ b/cmd/tweeter.go @@ -100,26 +100,33 @@ func Run() { log.Println("We're already logged in, skipping login...") } else { scraper.ClearCookies() - err = scraper.Login(config.Username, config.Password) - if err != nil { - log.Printf("An error occurred during scraper login: %s\n", err.Error()) + if len(config.Username) > 0 { + err = scraper.Login(config.Username, config.Password) + if err != nil { + log.Fatalf("An error occurred during scraper login: %s\n", err.Error()) + } else { + log.Printf("New Login - Saving cookies to %s\n", cookiePath) + js, jsonErr := json.Marshal(scraper.GetCookies()) + if jsonErr != nil { + log.Fatalf("An error occurred during cookie serialization: %s\n", jsonErr.Error()) + } + f, fErr := os.Create(cookiePath) + if fErr != nil { + log.Fatalf("Failed to create cookie file at %s with the following error: %s\n", cookiePath, fErr.Error()) + } + f.Write(js) + writeErr := f.Close() + if writeErr != nil { + log.Fatalf("An error occurred on closing cookie file: %s\n", writeErr.Error()) + } + } + } else { log.Println("Trying open account login... ") err = scraper.LoginOpenAccount() if err != nil { log.Fatalf("An error occurred during scraper login: %s\n", err.Error()) } defer scraper.Logout() - } else { - log.Printf("New Login - Saving cookies to %s\n", cookiePath) - js, jsonErr := json.Marshal(scraper.GetCookies()) - if jsonErr != nil { - log.Fatalf("An error occurred during cookie serialization: %s\n", jsonErr.Error()) - } - f, fErr := os.Create(cookiePath) - if fErr != nil { - log.Fatalf("Failed to create cookie file at %s with the following error: %s\n", cookiePath, fErr.Error()) - } - f.Write(js) } } From 712d83c0f0ebe9ba53b596227f2f092b6fb2bc1c Mon Sep 17 00:00:00 2001 From: Manuel Date: Tue, 17 Oct 2023 00:07:00 +0200 Subject: [PATCH 3/4] fix: Fix database query Fix ordering in database query if more than one tweet with same timestamp --- cmd/database.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cmd/database.go b/cmd/database.go index d90188d..44fff72 100644 --- a/cmd/database.go +++ b/cmd/database.go @@ -57,7 +57,7 @@ func NewDatabase(driver string, connectString string) (*Database, error) { func (db *Database) GetNewestTweet(channel string) (*Tweet, error) { tweet := Tweet{} - err := db.Get(&tweet, "SELECT * FROM tweet WHERE channel=$1 ORDER BY timestamp DESC LIMIT 1", channel) + err := db.Get(&tweet, "SELECT * FROM tweet WHERE channel=$1 ORDER BY timestamp DESC, snowflake DESC LIMIT 1", channel) if err != nil { return nil, err } @@ -66,7 +66,7 @@ func (db *Database) GetNewestTweet(channel string) (*Tweet, error) { func (db *Database) GetTweets(channel string) ([]*Tweet, error) { tweet := []*Tweet{} - err := db.Select(&tweet, "SELECT * FROM tweet WHERE channel=$1 ORDER BY timestamp DESC", channel) + err := db.Select(&tweet, "SELECT * FROM tweet WHERE channel=$1 ORDER BY timestamp DESC, snowflake DESC", channel) if err != nil { return nil, err } @@ -80,7 +80,7 @@ func (db *Database) ContainsTweet(channel string, tweet *ts.Tweet) (bool, error) } t := Tweet{} - rows, err := db.Queryx("SELECT * FROM tweet WHERE channel=$1 ORDER BY timestamp DESC", channel) + rows, err := db.Queryx("SELECT * FROM tweet WHERE channel=$1 ORDER BY timestamp DESC, snowflake DESC", channel) if err != nil { return false, err } @@ -124,7 +124,7 @@ func (db *Database) PruneOldestTweets(channel string) error { tx.Rollback() return err } - rows, err := tx.Queryx("SELECT tweet_id from tweet WHERE channel=$1 ORDER by timestamp ASC LIMIT $2", channel, count-KeepTweets) + rows, err := tx.Queryx("SELECT tweet_id from tweet WHERE channel=$1 ORDER by timestamp ASC, snowflake ASC LIMIT $2", channel, count-KeepTweets) if err != nil { tx.Rollback() return err From e6bf12fa35eeec4c94dc975a35a0a594eaeca778 Mon Sep 17 00:00:00 2001 From: Manuel Date: Tue, 17 Oct 2023 00:10:00 +0200 Subject: [PATCH 4/4] feat: Add embeds, rework embed struct --- cmd/embed.go | 106 +++++++++++++++++++++++++++++-------------------- cmd/webhook.go | 77 ++++++++++++++++++++++++++++++----- 2 files changed, 129 insertions(+), 54 deletions(-) diff --git a/cmd/embed.go b/cmd/embed.go index b06d0d2..7740004 100644 --- a/cmd/embed.go +++ b/cmd/embed.go @@ -4,18 +4,21 @@ import ( "errors" "strconv" "strings" + "time" ) type Embed struct { - Author Author `json:"author"` - Title string `json:"title"` - URL string `json:"url"` - Description string `json:"description"` - Color int64 `json:"color"` - Fields []Field `json:"fields"` + Author Author `json:"author,omitempty"` + Title string `json:"title,omitempty"` + URL string `json:"url,omitempty"` + Description string `json:"description,omitempty"` + Timestamp string `json:"timestamp,omitempty"` + Color int64 `json:"color,omitempty"` + Fields []Field `json:"fields,omitempty"` Thumbnail Image `json:"thumbnail,omitempty"` Image Image `json:"image,omitempty"` - Footer Footer `json:"footer"` + Video Video `json:"video,omitempty"` + Footer Footer `json:"footer,omitempty"` } type Author struct { @@ -39,60 +42,75 @@ type Image struct { URL string `json:"url"` } -func (w *Webhook) NewEmbed(Title, Description, URL string) { - emb := Embed{Title: Title, Description: Description, URL: URL} +type Video struct { + URL string `json:"url"` +} + +func (w *Webhook) NewEmbedWithURL(URL string) *Embed { + emb := Embed{URL: URL} w.Embeds = append(w.Embeds, &emb) + return &emb } -func (w *Webhook) SetAuthor(Name, URL, IconURL string) { - if len(w.Embeds) == 0 { - emb := Embed{Author: Author{Name, URL, IconURL}} - w.Embeds = append(w.Embeds, &emb) - } else { - w.Embeds[0].Author = Author{Name, URL, IconURL} - } +func (w *Webhook) NewEmbed() *Embed { + emb := Embed{} + w.Embeds = append(w.Embeds, &emb) + return &emb } -func (w *Webhook) SetColor(color string) error { +func (e *Embed) SetTitle(Title string) *Embed { + e.Title = Title + return e +} + +func (e *Embed) SetText(Description string) *Embed { + e.Description = Description + return e +} + +func (e *Embed) SetAuthor(Name, URL, IconURL string) *Embed { + e.Author = Author{Name, URL, IconURL} + return e +} + +func (e *Embed) SetColor(color string) (*Embed, error) { color = strings.Replace(color, "0x", "", -1) color = strings.Replace(color, "0X", "", -1) color = strings.Replace(color, "#", "", -1) colorInt, err := strconv.ParseInt(color, 16, 64) if err != nil { - return errors.New("Invalid hex code passed") + return nil, errors.New("Invalid hex code passed") } - w.Embeds[0].Color = colorInt - return nil + e.Color = colorInt + return e, nil } -func (w *Webhook) SetThumbnail(URL string) error { - if len(w.Embeds) < 1 { - return errors.New("Invalid Embed passed in, Webhook.Embeds must have at least one Embed element") - } - w.Embeds[0].Thumbnail = Image{URL} - return nil +func (e *Embed) SetThumbnail(URL string) *Embed { + e.Thumbnail = Image{URL} + return e } -func (w *Webhook) SetImage(URL string) error { - if len(w.Embeds) < 1 { - return errors.New("Invalid Embed passed in, Webhook.Embeds must have at least one Embed element") - } - w.Embeds[0].Image = Image{URL} - return nil +func (e *Embed) SetImage(URL string) *Embed { + e.Image = Image{URL} + return e } -func (w *Webhook) SetFooter(Text, IconURL string) error { - if len(w.Embeds) < 1 { - return errors.New("Invalid Embed passed in, Webhook.Embeds must have at least one Embed element") - } - w.Embeds[0].Footer = Footer{Text, IconURL} - return nil +func (e *Embed) SetVideo(URL string) *Embed { + e.Video = Video{URL} + return e } -func (w *Webhook) AddField(Name, Value string, Inline bool) error { - if len(w.Embeds) < 1 { - return errors.New("Invalid Embed passed in, Webhook.Embeds must have at least one Embed element") - } - w.Embeds[0].Fields = append(w.Embeds[0].Fields, Field{Name, Value, Inline}) - return nil +func (e *Embed) SetFooter(Text, IconURL string) *Embed { + e.Footer = Footer{Text, IconURL} + return e +} + +func (e *Embed) SetTimestamp(timestamp time.Time) *Embed { + e.Timestamp = timestamp.Format(time.RFC3339) + return e +} + +func (e *Embed) AddField(Name, Value string, Inline bool) *Embed { + e.Fields = append(e.Fields, Field{Name, Value, Inline}) + return e } diff --git a/cmd/webhook.go b/cmd/webhook.go index 9969eab..deb9176 100644 --- a/cmd/webhook.go +++ b/cmd/webhook.go @@ -6,6 +6,13 @@ import ( ts "github.com/n0madic/twitter-scraper" "log" "net/http" + "strings" + //"strconv" +) + +const ( + BaseURL = "https://twitter.com/" + BaseIcon = "https://abs.twimg.com/icons/apple-touch-icon-192x192.png" ) type Webhook struct { @@ -25,24 +32,74 @@ type Mention struct { func sendToWebhook(webhookURL string, tweets []*ts.Tweet) { for _, tweet := range tweets { - // Temporarily hardcoded data := Webhook{ - Content: tweet.PermanentURL, + Content: "<" + tweet.PermanentURL + ">", Mention: &Mention{Parse: []string{"roles"}}, - Embeds: []*Embed{}, } - jsonData, err := json.Marshal(data) + urlsToAppend := []string{} + userUrl := BaseURL + tweet.Username + + mainEmbed := data.NewEmbedWithURL(tweet.PermanentURL) + mainEmbed.SetAuthor(tweet.Name+" (@"+tweet.Username+")", userUrl, "https://unavatar.io/twitter/"+tweet.Username) + mainEmbed.SetText(tweet.Text) + mainEmbed.SetColor("#26a7de") + mainEmbed.SetFooter("Twitter", BaseIcon) + mainEmbed.SetTimestamp(tweet.TimeParsed) + //mainEmbed.SetFooter("Twitter • ", BaseIcon) + + for i, photo := range tweet.Photos { + embed := mainEmbed + if i > 0 { + embed = data.NewEmbedWithURL(tweet.PermanentURL) + } + embed.SetImage(photo.URL) + } + for i, gif := range tweet.GIFs { + embed := mainEmbed + if i > 0 { + embed = data.NewEmbedWithURL(tweet.PermanentURL) + } + embed.SetImage(gif.Preview) + } + for i, video := range tweet.Videos { + embed := mainEmbed + if i > 0 { + embed = data.NewEmbedWithURL(tweet.PermanentURL) + } + // Video embeds are not supported right now + embed.SetImage(video.Preview) + embed.SetVideo(video.URL) // This has sadly no effect + urlsToAppend = append(urlsToAppend, strings.Replace(tweet.PermanentURL, "twitter", "fxtwitter", 1)) + } + + err := sendRequest(webhookURL, &data) if err != nil { - log.Printf("Error while generating JSON for tweet %s: %s", tweet.ID, err.Error()) + log.Println("Error while sending webhook for tweet %s: %s", tweet.ID, err.Error()) continue } - resp, err := http.Post(webhookURL, "application/json", bytes.NewBuffer(jsonData)) - if err != nil { - log.Printf("Error while sending webhook for tweet %s: %s", tweet.ID, err.Error()) - continue + for _, url := range urlsToAppend { + err := sendRequest(webhookURL, &Webhook{Content: url}) + if err != nil { + log.Println("Error while sending webhook for tweet %s: %s", tweet.ID, err.Error()) + continue + } } - defer resp.Body.Close() } } + +func sendRequest(url string, data *Webhook) error { + jsonData, err := json.Marshal(data) + if err != nil { + return err + } + + resp, err := http.Post(url, "application/json", bytes.NewBuffer(jsonData)) + defer resp.Body.Close() + if err != nil { + return err + } + + return nil +}