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 $(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
|
# TODO: Maybe this file should be broken up into multiple test scripts
|
||||||
|
|
||||||
echo -e "\033[32mAll tests passed. Finished successfully.\033[0m"
|
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
|
search
|
||||||
<TARGET> is the search query. Should be wrapped in quotes if it has spaces.
|
<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>:
|
<flags>:
|
||||||
-h, --help
|
-h, --help
|
||||||
Print this message, then exit.
|
Print this message, then exit.
|
||||||
|
@ -144,6 +144,10 @@ func main() {
|
|||||||
follow_user(target, false)
|
follow_user(target, false)
|
||||||
case "list_followed":
|
case "list_followed":
|
||||||
list_followed()
|
list_followed()
|
||||||
|
case "like_tweet":
|
||||||
|
like_tweet(target)
|
||||||
|
case "unlike_tweet":
|
||||||
|
unlike_tweet(target)
|
||||||
default:
|
default:
|
||||||
die(fmt.Sprintf("Invalid operation: %s", operation), true, 3)
|
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() {
|
func list_followed() {
|
||||||
for _, handle := range profile.GetAllFollowedUsers() {
|
for _, handle := range profile.GetAllFollowedUsers() {
|
||||||
fmt.Println(handle)
|
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)
|
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)
|
resp, err := api.Client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Error executing HTTP POST request:\n %w", err)
|
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