From e235a6a79ff4da6824ca7d50497d4231247b29fa Mon Sep 17 00:00:00 2001 From: Valentine Date: Wed, 24 Jul 2024 03:54:57 +0300 Subject: [PATCH] add LikeTweet and UnlikeTweet methods --- CHANGELOG.md | 1 + README.md | 24 ++++++++++++++ tweet.go | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++ tweet_test.go | 14 ++++++++ 4 files changed, 127 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 88cb146..b7de3ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ 24.07.2024 - Added method `GetSpace` +- Added methods `LikeTweet`, `UnlikeTweet` ## v0.0.8 diff --git a/README.md b/README.md index ec6aedd..0766bec 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,8 @@ You can use this library to get tweets, profiles, and trends trivially. - [Get following](#get-following) - [Get followers](#get-followers) - [Get space](#get-space) + - [Like tweet](#like-tweet) + - [Unlike tweet](#unlike-tweet) - [Create tweet](#create-tweet) - [Delete tweet](#delete-tweet) - [Create retweet](#create-retweet) @@ -457,6 +459,28 @@ if strings.HasPrefix(spaceUrl, "https://twitter.com/i/spaces/") { space, err := scraper.GetSpace(spaceId) ``` +### Like tweet + +> [!IMPORTANT] +> Requires authentication! + +500 requests / 15 minutes (combined with `UnlikeTweet` method) + +```golang +err := scraper.LikeTweet("tweet_id") +``` + +### Unlike tweet + +> [!IMPORTANT] +> Requires authentication! + +500 requests / 15 minutes (combined with `LikeTweet` method) + +```golang +err := scraper.UnlikeTweet("tweet_id") +``` + ### Create tweet > [!IMPORTANT] diff --git a/tweet.go b/tweet.go index 889466f..0f31705 100644 --- a/tweet.go +++ b/tweet.go @@ -249,3 +249,91 @@ func (s *Scraper) DeleteRetweet(tweetId string) error { return nil } + +func (s *Scraper) LikeTweet(tweetId string) error { + req, err := s.newRequest("POST", "https://twitter.com/i/api/graphql/lI07N6Otwv1PhnEgXILM7A/FavoriteTweet") + if err != nil { + return err + } + + req.Header.Set("content-type", "application/json") + variables := map[string]interface{}{ + "tweet_id": tweetId, + } + body := map[string]interface{}{ + "variables": variables, + "queryId": "lI07N6Otwv1PhnEgXILM7A", + } + + b, _ := json.Marshal(body) + req.Body = io.NopCloser(bytes.NewReader(b)) + + var response struct { + Data struct { + FavoriteTweet string `json:"favorite_tweet"` + } `json:"data"` + Errors []struct { + Message string `json:"message"` + Code int `json:"code"` + } `json:"errors"` + } + + err = s.RequestAPI(req, &response) + if err != nil { + return err + } + + if len(response.Errors) > 0 && response.Errors[0].Code == 139 { + return errors.New("tweet already liked") + } + + if response.Data.FavoriteTweet != "Done" { + return errors.New("unknown error") + } + + return nil +} + +func (s *Scraper) UnlikeTweet(tweetId string) error { + req, err := s.newRequest("POST", "https://twitter.com/i/api/graphql/ZYKSe-w7KEslx3JhSIk5LA/UnfavoriteTweet") + if err != nil { + return err + } + + req.Header.Set("content-type", "application/json") + variables := map[string]interface{}{ + "tweet_id": tweetId, + } + body := map[string]interface{}{ + "variables": variables, + "queryId": "ZYKSe-w7KEslx3JhSIk5LA", + } + + b, _ := json.Marshal(body) + req.Body = io.NopCloser(bytes.NewReader(b)) + + var response struct { + Data struct { + UnfavoriteTweet string `json:"unfavorite_tweet"` + } `json:"data"` + Errors []struct { + Message string `json:"message"` + Code int `json:"code"` + } `json:"errors"` + } + + err = s.RequestAPI(req, &response) + if err != nil { + return err + } + + if len(response.Errors) > 0 && response.Errors[0].Code == 144 { + return errors.New("tweet already not liked") + } + + if response.Data.UnfavoriteTweet != "Done" { + return errors.New("unknown error") + } + + return nil +} diff --git a/tweet_test.go b/tweet_test.go index 6095488..981aa21 100644 --- a/tweet_test.go +++ b/tweet_test.go @@ -94,3 +94,17 @@ func TestDeleteRetweet(t *testing.T) { t.Error(err) } } + +func TestLikeAndUnlikeTweet(t *testing.T) { + if skipAuthTest { + t.Skip("Skipping test due to environment variable") + } + + tweetId := "1792634158977568997" + if err := testScraper.LikeTweet(tweetId); err != nil { + t.Error(err) + } + if err := testScraper.UnlikeTweet(tweetId); err != nil { + t.Error(err) + } +}