Merge pull request #9 from imperatrona/likes

add LikeTweet and UnlikeTweet methods
This commit is contained in:
Valentine 2024-07-24 04:10:52 +03:00 committed by GitHub
commit e053917d34
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 127 additions and 0 deletions

View file

@ -5,6 +5,7 @@
24.07.2024
- Added method `GetSpace`
- Added methods `LikeTweet`, `UnlikeTweet`
## v0.0.8

View file

@ -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]

View file

@ -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
}

View file

@ -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)
}
}