Add commands to like and unlike tweets
This commit is contained in:
parent
d85259a014
commit
cc632e0654
@ -348,6 +348,11 @@ tw --session Offline_Twatter search "from:michaelmalice constitution"
|
||||
test $(sqlite3 twitter.db "select count(*) from tweets where user_id = 44067298 and text like '%constitution%'") -gt "30" # Not sure exactly how many
|
||||
|
||||
|
||||
# Test liking and unliking
|
||||
tw --session Offline_Twatter like_tweet https://twitter.com/elonmusk/status/1589023388676554753
|
||||
tw --session Offline_Twatter unlike_tweet https://twitter.com/elonmusk/status/1589023388676554753
|
||||
|
||||
|
||||
# TODO: Maybe this file should be broken up into multiple test scripts
|
||||
|
||||
echo -e "\033[32mAll tests passed. Finished successfully.\033[0m"
|
||||
|
@ -60,7 +60,12 @@ This application downloads tweets from twitter and saves them in a SQLite databa
|
||||
|
||||
search
|
||||
<TARGET> is the search query. Should be wrapped in quotes if it has spaces.
|
||||
(Requires authentication)
|
||||
|
||||
like_tweet
|
||||
unlike_tweet
|
||||
"Like" or un-"like" the tweet indicated by <TARGET>.
|
||||
(Requires authentication)
|
||||
<flags>:
|
||||
-h, --help
|
||||
Print this message, then exit.
|
||||
|
@ -144,6 +144,10 @@ func main() {
|
||||
follow_user(target, false)
|
||||
case "list_followed":
|
||||
list_followed()
|
||||
case "like_tweet":
|
||||
like_tweet(target)
|
||||
case "unlike_tweet":
|
||||
unlike_tweet(target)
|
||||
default:
|
||||
die(fmt.Sprintf("Invalid operation: %s", operation), true, 3)
|
||||
}
|
||||
@ -318,6 +322,30 @@ func follow_user(handle string, is_followed bool) {
|
||||
}
|
||||
}
|
||||
|
||||
func unlike_tweet(tweet_identifier string) {
|
||||
tweet_id, err := extract_id_from(tweet_identifier)
|
||||
if err != nil {
|
||||
die(err.Error(), false, -1)
|
||||
}
|
||||
err = scraper.UnlikeTweet(tweet_id)
|
||||
if err != nil {
|
||||
die(err.Error(), false, -10)
|
||||
}
|
||||
happy_exit("Unliked the tweet.")
|
||||
}
|
||||
|
||||
func like_tweet(tweet_identifier string) {
|
||||
tweet_id, err := extract_id_from(tweet_identifier)
|
||||
if err != nil {
|
||||
die(err.Error(), false, -1)
|
||||
}
|
||||
err = scraper.LikeTweet(tweet_id)
|
||||
if err != nil {
|
||||
die(err.Error(), false, -10)
|
||||
}
|
||||
happy_exit("Liked the tweet.")
|
||||
}
|
||||
|
||||
func list_followed() {
|
||||
for _, handle := range profile.GetAllFollowedUsers() {
|
||||
fmt.Println(handle)
|
||||
|
@ -218,6 +218,12 @@ func (api *API) do_http_POST(url string, body string, result interface{}) error
|
||||
|
||||
api.add_authentication_headers(req)
|
||||
|
||||
log.Debug(fmt.Sprintf("POST: %s\n", req.URL.String()))
|
||||
for header := range req.Header {
|
||||
log.Debug(fmt.Sprintf(" %s: %s\n", header, req.Header.Get(header)))
|
||||
}
|
||||
log.Debug(" " + body)
|
||||
|
||||
resp, err := api.Client.Do(req)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error executing HTTP POST request:\n %w", err)
|
||||
|
89
scraper/api_types_posting.go
Normal file
89
scraper/api_types_posting.go
Normal file
@ -0,0 +1,89 @@
|
||||
package scraper
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var AlreadyLikedThisTweet error = errors.New("already liked this tweet")
|
||||
var HaventLikedThisTweet error = errors.New("Haven't liked this tweet")
|
||||
|
||||
func (api API) LikeTweet(id TweetID) error {
|
||||
type LikeResponse struct {
|
||||
Data struct {
|
||||
FavoriteTweet string `json:"favorite_tweet"`
|
||||
} `json:"data"`
|
||||
Errors []struct {
|
||||
Message string `json:"message"`
|
||||
Code int `json:"code"`
|
||||
Kind string `json:"kind"`
|
||||
Name string `json:"name"`
|
||||
} `json:"errors"`
|
||||
}
|
||||
var result LikeResponse
|
||||
err := api.do_http_POST(
|
||||
"https://twitter.com/i/api/graphql/lI07N6Otwv1PhnEgXILM7A/FavoriteTweet",
|
||||
"{\"variables\":{\"tweet_id\":\""+fmt.Sprint(id)+"\"},\"queryId\":\"lI07N6Otwv1PhnEgXILM7A\"}",
|
||||
&result,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error executing the HTTP POST request:\n %w", err)
|
||||
}
|
||||
if len(result.Errors) > 0 {
|
||||
if strings.Contains(result.Errors[0].Message, "has already favorited tweet") {
|
||||
return AlreadyLikedThisTweet
|
||||
}
|
||||
}
|
||||
if result.Data.FavoriteTweet != "Done" {
|
||||
panic(fmt.Sprintf("Dunno why but it failed with value %q", result.Data.FavoriteTweet))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (api API) UnlikeTweet(id TweetID) error {
|
||||
type UnlikeResponse struct {
|
||||
Data struct {
|
||||
UnfavoriteTweet string `json:"unfavorite_tweet"`
|
||||
} `json:"data"`
|
||||
Errors []struct {
|
||||
Message string `json:"message"`
|
||||
Code int `json:"code"`
|
||||
Kind string `json:"kind"`
|
||||
Name string `json:"name"`
|
||||
} `json:"errors"`
|
||||
}
|
||||
var result UnlikeResponse
|
||||
err := api.do_http_POST(
|
||||
"https://twitter.com/i/api/graphql/ZYKSe-w7KEslx3JhSIk5LA/UnfavoriteTweet",
|
||||
"{\"variables\":{\"tweet_id\":\""+fmt.Sprint(id)+"\"},\"queryId\":\"ZYKSe-w7KEslx3JhSIk5LA\"}",
|
||||
&result,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error executing the HTTP POST request:\n %w", err)
|
||||
}
|
||||
if len(result.Errors) > 0 {
|
||||
if strings.Contains(result.Errors[0].Message, "not found in actor's") {
|
||||
return HaventLikedThisTweet
|
||||
}
|
||||
}
|
||||
if result.Data.UnfavoriteTweet != "Done" {
|
||||
panic(fmt.Sprintf("Dunno why but it failed with value %q", result.Data.UnfavoriteTweet))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func LikeTweet(id TweetID) error {
|
||||
if !the_api.IsAuthenticated {
|
||||
log.Fatalf("Must be authenticated!")
|
||||
}
|
||||
return the_api.LikeTweet(id)
|
||||
}
|
||||
func UnlikeTweet(id TweetID) error {
|
||||
if !the_api.IsAuthenticated {
|
||||
log.Fatalf("Must be authenticated!")
|
||||
}
|
||||
return the_api.UnlikeTweet(id)
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user