diff --git a/python/README.md b/python/README.md index 0f21f15..b3b4b0b 100644 --- a/python/README.md +++ b/python/README.md @@ -19,45 +19,25 @@ export CONSUMER_SECRET='your_consumer_secret' ## Examples ### Posts -- posts/counts_full_archive.py -- posts/counts_recent.py - posts/create_post.py -- posts/create_tweet.py - posts/delete_post.py -- posts/delete_tweet.py -- posts/full_archive_tweet_counts.py -- posts/full-archive-search.py -- posts/get_tweets_with_bearer_token.py -- posts/get_tweets_with_user_context.py -- posts/like_a_tweet.py -- posts/like.py -- posts/liked_posts.py -- posts/liked_tweets.py -- posts/liking_users.py -- posts/lookup.py -- posts/quote_posts.py -- posts/quote_tweets.py -- posts/recent_search.py -- posts/recent_tweet_counts.py -- posts/repost.py -- posts/reposted_by.py -- posts/retweet_a_tweet.py +- posts/get_liked_posts.py +- posts/get_liking_users.py +- posts/get_post_counts_all.py +- posts/get_post_counts_recent.py +- posts/get_posts_by_ids.py +- posts/get_quoted_posts.py +- posts/like_post.py +- posts/repost_post.py - posts/retweeted_by.py -- posts/search_full_archive.py +- posts/search_all.py - posts/search_recent.py - posts/undo_a_retweet.py -- posts/undo_repost.py - posts/unlike_a_tweet.py -- posts/unlike.py ### Users -- users/block_a_user.py -- users/block.py -- users/blocked.py -- users/followers_lookup.py -- users/followers.py - users/following_lookup.py -- users/following.py +- users/get_followers.py - users/get_users_me_user_context.py - users/get_users_with_bearer_token.py - users/get_users_with_user_context.py @@ -66,37 +46,29 @@ export CONSUMER_SECRET='your_consumer_secret' - users/lookup.py - users/me.py - users/mute_a_user.py -- users/mute.py - users/muted.py - users/unblock_a_user.py -- users/unblock.py - users/unmute_a_user.py -- users/unmute.py ### Timelines -- timelines/home_timeline.py +- timelines/get_mentions.py +- timelines/get_posts.py +- timelines/get_timeline.py - timelines/reverse-chron-home-timeline.py -- timelines/user_mentions.py -- timelines/user_posts.py -- timelines/user_tweets.py ### Streams - streams/filtered_stream.py - streams/sampled_stream.py -- streams/sampled-stream.py ### Lists -- lists/add_member.py -- lists/create_a_list.py -- lists/create.py -- lists/delete_a_list.py -- lists/delete.py +- lists/add_list_member.py +- lists/create_list.py +- lists/delete_list.py - lists/follow_list.py -- lists/list-followers-lookup.py -- lists/list-lookup-by-id.py -- lists/list-member-lookup.py -- lists/List-Tweets.py -- lists/lookup.py +- lists/get_list_by_id.py +- lists/get_list_followers.py +- lists/get_list_members.py +- lists/get_list_posts.py - lists/pin_list.py - lists/Pinned-List.py - lists/remove_member.py @@ -110,26 +82,19 @@ export CONSUMER_SECRET='your_consumer_secret' ### Bookmarks - bookmarks/bookmarks_lookup.py - bookmarks/create_bookmark.py -- bookmarks/create.py - bookmarks/delete_bookmark.py -- bookmarks/delete.py -- bookmarks/lookup.py ### Spaces -- spaces/lookup.py - spaces/search_spaces.py -- spaces/search.py - spaces/spaces_lookup.py ### Direct Messages - direct_messages/get_events_by_conversation.py - direct_messages/get_one_to_one_conversation_events.py - direct_messages/get_user_conversation_events.py -- direct_messages/lookup.py - direct_messages/post_dm_to_conversation.py - direct_messages/post_group_conversation_dm.py - direct_messages/post_one_to_one_dm.py -- direct_messages/send.py ### Media - media/media_upload_v2.py @@ -137,7 +102,6 @@ export CONSUMER_SECRET='your_consumer_secret' ### Compliance - compliance/create_compliance_job.py -- compliance/create_job.py - compliance/download_compliance_results.py - compliance/get_compliance_job_information_by_id.py - compliance/get_jobs.py @@ -145,6 +109,5 @@ export CONSUMER_SECRET='your_consumer_secret' - compliance/upload_ids.py ### Usage -- usage/get_usage_tweets.py - usage/get_usage.py diff --git a/python/bookmarks/bookmarks_lookup.py b/python/bookmarks/bookmarks_lookup.py index e864e22..192198d 100644 --- a/python/bookmarks/bookmarks_lookup.py +++ b/python/bookmarks/bookmarks_lookup.py @@ -1,103 +1,71 @@ -import base64 -import hashlib +""" +Bookmarks Lookup - X API v2 +=========================== +Endpoint: GET https://api.x.com/2/users/:id/bookmarks +Docs: https://developer.x.com/en/docs/twitter-api/bookmarks/api-reference/get-users-id-bookmarks + +Authentication: OAuth 2.0 (User Context) +Required env vars: CLIENT_ID, CLIENT_SECRET +""" + import os -import re import json -import requests -from requests.auth import AuthBase, HTTPBasicAuth -from requests_oauthlib import OAuth2Session +from xdk import Client +from xdk.oauth2_auth import OAuth2PKCEAuth -# First, you will need to enable OAuth 2.0 in your App’s auth settings in the Developer Portal to get your client ID. -# Inside your terminal you will need to set an enviornment variable -# export CLIENT_ID='your-client-id' +# The code below sets the client ID and client secret from your environment variables +# To set environment variables on macOS or Linux, run the export commands below from the terminal: +# export CLIENT_ID='YOUR-CLIENT-ID' +# export CLIENT_SECRET='YOUR-CLIENT-SECRET' client_id = os.environ.get("CLIENT_ID") - -# If you have selected a type of App that is a confidential client you will need to set a client secret. -# Confidential Clients securely authenticate with the authorization server. - -# Inside your terminal you will need to set an enviornment variable -# export CLIENT_SECRET='your-client-secret' - -# Remove the comment on the following line if you are using a confidential client -# client_secret = os.environ.get("CLIENT_SECRET") +client_secret = os.environ.get("CLIENT_SECRET") # Replace the following URL with your callback URL, which can be obtained from your App's auth settings. -redirect_uri = "https://www.example.com" +redirect_uri = "https://example.com" # Set the scopes scopes = ["bookmark.read", "tweet.read", "users.read", "offline.access"] -# Create a code verifier -code_verifier = base64.urlsafe_b64encode(os.urandom(30)).decode("utf-8") -code_verifier = re.sub("[^a-zA-Z0-9]+", "", code_verifier) - -# Create a code challenge -code_challenge = hashlib.sha256(code_verifier.encode("utf-8")).digest() -code_challenge = base64.urlsafe_b64encode(code_challenge).decode("utf-8") -code_challenge = code_challenge.replace("=", "") - -# Start an OAuth 2.0 session -oauth = OAuth2Session(client_id, redirect_uri=redirect_uri, scope=scopes) - -# Create an authorize URL -auth_url = "https://twitter.com/i/oauth2/authorize" -authorization_url, state = oauth.authorization_url( - auth_url, code_challenge=code_challenge, code_challenge_method="S256" -) - -# Visit the URL to authorize your App to make requests on behalf of a user -print( - "Visit the following URL to authorize your App on behalf of your Twitter handle in a browser:" -) -print(authorization_url) - -# Paste in your authorize URL to complete the request -authorization_response = input( - "Paste in the full URL after you've authorized your App:\n" -) - -# Fetch your access token -token_url = "https://api.x.com/2/oauth2/token" - -# The following line of code will only work if you are using a type of App that is a public client -auth = False - -# If you are using a confidential client you will need to pass in basic encoding of your client ID and client secret. - -# Please remove the comment on the following line if you are using a type of App that is a confidential client -# auth = HTTPBasicAuth(client_id, client_secret) - -token = oauth.fetch_token( - token_url=token_url, - authorization_response=authorization_response, - auth=auth, - client_id=client_id, - include_client_id=True, - code_verifier=code_verifier, -) - -# Your access token -access = token["access_token"] - -# Make a request to the users/me endpoint to get your user ID -user_me = requests.request( - "GET", - "https://api.x.com/2/users/me", - headers={"Authorization": "Bearer {}".format(access)}, -).json() -user_id = user_me["data"]["id"] - -# Make a request to the bookmarks url -url = "https://api.x.com/2/users/{}/bookmarks".format(user_id) -headers = { - "Authorization": "Bearer {}".format(access), - "User-Agent": "BookmarksSampleCode", -} -response = requests.request("GET", url, headers=headers) -if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format(response.status_code, response.text) +def main(): + # Step 1: Create PKCE instance + auth = OAuth2PKCEAuth( + client_id=client_id, + client_secret=client_secret, + redirect_uri=redirect_uri, + scope=scopes ) -print("Response code: {}".format(response.status_code)) -json_response = response.json() -print(json.dumps(json_response, indent=4, sort_keys=True)) + + # Step 2: Get authorization URL + auth_url = auth.get_authorization_url() + print("Visit the following URL to authorize your App on behalf of your X handle in a browser:") + print(auth_url) + + # Step 3: Handle callback + callback_url = input("Paste the full callback URL here: ") + + # Step 4: Exchange code for tokens + tokens = auth.fetch_token(authorization_response=callback_url) + access_token = tokens["access_token"] + + # Step 5: Create client + client = Client(access_token=access_token) + + # Step 6: Get authenticated user ID + user_me = client.users.get_me() + user_id = user_me.data["id"] + + # Step 7: Get bookmarks with automatic pagination + all_bookmarks = [] + for page in client.users.get_bookmarks( + user_id, + max_results=100, + tweetfields=["created_at"] + ): + all_bookmarks.extend(page.data) + print(f"Fetched {len(page.data)} bookmarks (total: {len(all_bookmarks)})") + + print(f"\nTotal Bookmarks: {len(all_bookmarks)}") + print(json.dumps({"data": all_bookmarks[:5]}, indent=4, sort_keys=True)) # Print first 5 as example + +if __name__ == "__main__": + main() diff --git a/python/bookmarks/create.py b/python/bookmarks/create.py deleted file mode 100644 index 0499013..0000000 --- a/python/bookmarks/create.py +++ /dev/null @@ -1,54 +0,0 @@ -""" -Create Bookmark - X API v2 -========================== -Endpoint: POST https://api.x.com/2/users/:id/bookmarks -Docs: https://developer.x.com/en/docs/twitter-api/tweets/bookmarks/api-reference/post-users-id-bookmarks - -Authentication: OAuth 2.0 with PKCE (User Context) -Required env vars: BEARER_TOKEN (OAuth 2.0 user access token) -""" - -import requests -import os -import json - -# Note: This endpoint requires OAuth 2.0 User Context -# The bearer_token here should be the user's access token from OAuth 2.0 PKCE flow -bearer_token = os.environ.get("BEARER_TOKEN") - - -def create_url(user_id): - return "https://api.x.com/2/users/{}/bookmarks".format(user_id) - - -def bearer_oauth(r): - """ - Method required by bearer token authentication. - """ - r.headers["Authorization"] = f"Bearer {bearer_token}" - r.headers["User-Agent"] = "v2CreateBookmarkPython" - return r - - -def connect_to_endpoint(url, payload): - response = requests.post(url, auth=bearer_oauth, json=payload) - print(response.status_code) - if response.status_code != 200: - raise Exception(response.status_code, response.text) - return response.json() - - -def main(): - # Replace with the authenticated user's ID - user_id = "your-user-id" - - # Replace with the post ID you want to bookmark - payload = {"tweet_id": "post-id-to-bookmark"} - - url = create_url(user_id) - json_response = connect_to_endpoint(url, payload) - print(json.dumps(json_response, indent=4, sort_keys=True)) - - -if __name__ == "__main__": - main() diff --git a/python/bookmarks/create_bookmark.py b/python/bookmarks/create_bookmark.py index 56346d9..6f7c722 100644 --- a/python/bookmarks/create_bookmark.py +++ b/python/bookmarks/create_bookmark.py @@ -1,107 +1,68 @@ -import base64 -import hashlib +""" +Create Bookmark - X API v2 +========================== +Endpoint: POST https://api.x.com/2/users/:id/bookmarks +Docs: https://developer.x.com/en/docs/twitter-api/tweets/bookmarks/api-reference/post-users-id-bookmarks + +Authentication: OAuth 2.0 (User Context) +Required env vars: CLIENT_ID, CLIENT_SECRET +""" + import os -import re import json -import requests -from requests.auth import AuthBase, HTTPBasicAuth -from requests_oauthlib import OAuth2Session - -# Replace with a Tweet ID you want to Bookmark -tweet_to_bookmark = {"tweet_id": "1460323737035677698"} +from xdk import Client +from xdk.oauth2_auth import OAuth2PKCEAuth -# You will need to enable OAuth 2.0 in your App’s auth settings in the Developer Portal to get your client ID. -# Inside your terminal you will need to set an enviornment variable -# export CLIENT_ID='your-client-id' +# The code below sets the client ID and client secret from your environment variables +# To set environment variables on macOS or Linux, run the export commands below from the terminal: +# export CLIENT_ID='YOUR-CLIENT-ID' +# export CLIENT_SECRET='YOUR-CLIENT-SECRET' client_id = os.environ.get("CLIENT_ID") - -# If you have selected a type of App that is a confidential client you will need to set a client secret. -# Confidential Clients securely authenticate with the authorization server. - -# Inside your terminal you will need to set an enviornment variable -# export CLIENT_SECRET='your-client-secret' - -# Remove the comment on the following line if you are using a confidential client -# client_secret = os.environ.get("CLIENT_SECRET") +client_secret = os.environ.get("CLIENT_SECRET") # Replace the following URL with your callback URL, which can be obtained from your App's auth settings. -redirect_uri = "https://www.example.com" +redirect_uri = "https://example.com" # Set the scopes -scopes = ["bookmark.write", "tweet.read", "users.read", "offline.access"] - -# Create a code verifier -code_verifier = base64.urlsafe_b64encode(os.urandom(30)).decode("utf-8") -code_verifier = re.sub("[^a-zA-Z0-9]+", "", code_verifier) - -# Create a code challenge -code_challenge = hashlib.sha256(code_verifier.encode("utf-8")).digest() -code_challenge = base64.urlsafe_b64encode(code_challenge).decode("utf-8") -code_challenge = code_challenge.replace("=", "") - -# Start and OAuth 2.0 session -oauth = OAuth2Session(client_id, redirect_uri=redirect_uri, scope=scopes) - -# Create an authorize URL -auth_url = "https://twitter.com/i/oauth2/authorize" -authorization_url, state = oauth.authorization_url( - auth_url, code_challenge=code_challenge, code_challenge_method="S256" -) - -# Visit the URL to authorize your App to make requests on behalf of a user -print( - "Visit the following URL to authorize your App on behalf of your Twitter handle in a browser:" -) -print(authorization_url) - -# Paste in your authorize URL to complete the request -authorization_response = input( - "Paste in the full URL after you've authorized your App:\n" -) - -# Fetch your access token -token_url = "https://api.x.com/2/oauth2/token" - -# The following line of code will only work if you are using a type of App that is a public client -auth = False - -# If you are using a confidential client you will need to pass in basic encoding of your client ID and client secret. - -# Please remove the comment on the following line if you are using a type of App that is a confidential client -# auth = HTTPBasicAuth(client_id, client_secret) - -token = oauth.fetch_token( - token_url=token_url, - authorization_response=authorization_response, - auth=auth, - client_id=client_id, - include_client_id=True, - code_verifier=code_verifier, -) - -# Your access token -access = token["access_token"] - -# Make a request to the users/me endpoint to get your user ID -user_me = requests.request( - "GET", - "https://api.x.com/2/users/me", - headers={"Authorization": "Bearer {}".format(access)}, -).json() -user_id = user_me["data"]["id"] - -# Make a request to the bookmarks url -url = "https://api.x.com/2/users/{}/bookmarks".format(user_id) -headers = { - "Authorization": "Bearer {}".format(access), - "Content-Type": "application/json", - "User-Agent": "BookmarksSampleCode", -} -response = requests.request("POST", url, headers=headers, json=tweet_to_bookmark) -if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format(response.status_code, response.text) +scopes = ["tweet.read", "users.read", "bookmark.write", "offline.access"] + +# Replace with a Post ID you want to Bookmark +post_id = "post-id-to-bookmark" + +def main(): + # Step 1: Create PKCE instance + auth = OAuth2PKCEAuth( + client_id=client_id, + client_secret=client_secret, + redirect_uri=redirect_uri, + scope=scopes ) -print("Response code: {}".format(response.status_code)) -json_response = response.json() -print(json.dumps(json_response, indent=4, sort_keys=True)) + + # Step 2: Get authorization URL + auth_url = auth.get_authorization_url() + print("Visit the following URL to authorize your App on behalf of your X handle in a browser:") + print(auth_url) + + # Step 3: Handle callback + callback_url = input("Paste the full callback URL here: ") + + # Step 4: Exchange code for tokens + tokens = auth.fetch_token(authorization_response=callback_url) + access_token = tokens["access_token"] + + # Step 5: Create client + client = Client(access_token=access_token) + + # Step 6: Get authenticated user ID + me_response = client.users.get_me() + user_id = me_response.data["id"] + + # Step 7: Create bookmark + payload = {"tweet_id": post_id} + response = client.users.create_bookmark(user_id, body=payload) + + print("Response code: 200") + print(json.dumps(response.data, indent=4, sort_keys=True)) + +if __name__ == "__main__": + main() diff --git a/python/bookmarks/delete.py b/python/bookmarks/delete.py deleted file mode 100644 index d962f16..0000000 --- a/python/bookmarks/delete.py +++ /dev/null @@ -1,54 +0,0 @@ -""" -Delete Bookmark - X API v2 -========================== -Endpoint: DELETE https://api.x.com/2/users/:id/bookmarks/:tweet_id -Docs: https://developer.x.com/en/docs/twitter-api/tweets/bookmarks/api-reference/delete-users-id-bookmarks-tweet_id - -Authentication: OAuth 2.0 with PKCE (User Context) -Required env vars: BEARER_TOKEN (OAuth 2.0 user access token) -""" - -import requests -import os -import json - -# Note: This endpoint requires OAuth 2.0 User Context -# The bearer_token here should be the user's access token from OAuth 2.0 PKCE flow -bearer_token = os.environ.get("BEARER_TOKEN") - - -def create_url(user_id, post_id): - return "https://api.x.com/2/users/{}/bookmarks/{}".format(user_id, post_id) - - -def bearer_oauth(r): - """ - Method required by bearer token authentication. - """ - r.headers["Authorization"] = f"Bearer {bearer_token}" - r.headers["User-Agent"] = "v2DeleteBookmarkPython" - return r - - -def connect_to_endpoint(url): - response = requests.delete(url, auth=bearer_oauth) - print(response.status_code) - if response.status_code != 200: - raise Exception(response.status_code, response.text) - return response.json() - - -def main(): - # Replace with the authenticated user's ID - user_id = "your-user-id" - - # Replace with the post ID you want to remove from bookmarks - post_id = "post-id-to-unbookmark" - - url = create_url(user_id, post_id) - json_response = connect_to_endpoint(url) - print(json.dumps(json_response, indent=4, sort_keys=True)) - - -if __name__ == "__main__": - main() diff --git a/python/bookmarks/delete_bookmark.py b/python/bookmarks/delete_bookmark.py index fae427b..4241303 100644 --- a/python/bookmarks/delete_bookmark.py +++ b/python/bookmarks/delete_bookmark.py @@ -1,109 +1,67 @@ -import base64 -import hashlib +""" +Delete Bookmark - X API v2 +========================== +Endpoint: DELETE https://api.x.com/2/users/:id/bookmarks/:tweet_id +Docs: https://developer.x.com/en/docs/twitter-api/tweets/bookmarks/api-reference/delete-users-id-bookmarks-tweet_id + +Authentication: OAuth 2.0 (User Context) +Required env vars: CLIENT_ID, CLIENT_SECRET +""" + import os -import re import json -import requests -from requests.auth import AuthBase, HTTPBasicAuth -from requests_oauthlib import OAuth2Session - -# Replace with a Tweet ID you want to remove Bookmark of -bookmarked_tweet_id = "1460323737035677698" +from xdk import Client +from xdk.oauth2_auth import OAuth2PKCEAuth -# You will need to enable OAuth 2.0 in your App’s auth settings in the Developer Portal to get your client ID. -# Inside your terminal you will need to set an enviornment variable -# export CLIENT_ID='your-client-id' +# The code below sets the client ID and client secret from your environment variables +# To set environment variables on macOS or Linux, run the export commands below from the terminal: +# export CLIENT_ID='YOUR-CLIENT-ID' +# export CLIENT_SECRET='YOUR-CLIENT-SECRET' client_id = os.environ.get("CLIENT_ID") - -# If you have selected a type of App that is a confidential client you will need to set a client secret. -# Confidential Clients securely authenticate with the authorization server. - -# Inside your terminal you will need to set an enviornment variable -# export CLIENT_SECRET='your-client-secret' - -# Remove the comment on the following line if you are using a confidential client -# client_secret = os.environ.get("CLIENT_SECRET") - +client_secret = os.environ.get("CLIENT_SECRET") # Replace the following URL with your callback URL, which can be obtained from your App's auth settings. -redirect_uri = "https://www.example.com" +redirect_uri = "https://example.com" # Set the scopes -scopes = ["bookmark.write", "tweet.read", "users.read", "offline.access"] - -# Create a code verifier -code_verifier = base64.urlsafe_b64encode(os.urandom(30)).decode("utf-8") -code_verifier = re.sub("[^a-zA-Z0-9]+", "", code_verifier) - -# Create a code challenge -code_challenge = hashlib.sha256(code_verifier.encode("utf-8")).digest() -code_challenge = base64.urlsafe_b64encode(code_challenge).decode("utf-8") -code_challenge = code_challenge.replace("=", "") - -# Start and OAuth 2.0 session -oauth = OAuth2Session(client_id, redirect_uri=redirect_uri, scope=scopes) - -# Create an authorize URL -auth_url = "https://twitter.com/i/oauth2/authorize" -authorization_url, state = oauth.authorization_url( - auth_url, code_challenge=code_challenge, code_challenge_method="S256" -) - -# Visit the URL to authorize your App to make requests on behalf of a user -print( - "Visit the following URL to authorize your App on behalf of your Twitter handle in a browser:" -) -print(authorization_url) - -# Paste in your authorize URL to complete the request -authorization_response = input( - "Paste in the full URL after you've authorized your App:\n" -) - -# Fetch your access token -token_url = "https://api.x.com/2/oauth2/token" - -# The following line of code will only work if you are using a type of App that is a public client -auth = False - -# If you are using a confidential client you will need to pass in basic encoding of your client ID and client secret. - -# Please remove the comment on the following line if you are using a type of App that is a confidential client -# auth = HTTPBasicAuth(client_id, client_secret) - -token = oauth.fetch_token( - token_url=token_url, - authorization_response=authorization_response, - auth=auth, - client_id=client_id, - include_client_id=True, - code_verifier=code_verifier, -) - -# Your access token -access = token["access_token"] - -# Make a request to the users/me endpoint to get the user ID of the authenticated user -user_me = requests.request( - "GET", - "https://api.x.com/2/users/me", - headers={"Authorization": "Bearer {}".format(access)}, -).json() -user_id = user_me["data"]["id"] - -# Make a request to the bookmarks url -url = "https://api.x.com/2/users/{}/bookmarks/{}".format( - user_id, bookmarked_tweet_id -) -headers = { - "Authorization": "Bearer {}".format(access), - "User-Agent": "BookmarksSampleCode", -} -response = requests.request("DELETE", url, headers=headers) -if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format(response.status_code, response.text) +scopes = ["tweet.read", "users.read", "bookmark.write", "offline.access"] + +# Replace with a Post ID you want to remove Bookmark of +post_id = "post-id-to-unbookmark" + +def main(): + # Step 1: Create PKCE instance + auth = OAuth2PKCEAuth( + client_id=client_id, + client_secret=client_secret, + redirect_uri=redirect_uri, + scope=scopes ) -print("Response code: {}".format(response.status_code)) -json_response = response.json() -print(json.dumps(json_response, indent=4, sort_keys=True)) + + # Step 2: Get authorization URL + auth_url = auth.get_authorization_url() + print("Visit the following URL to authorize your App on behalf of your X handle in a browser:") + print(auth_url) + + # Step 3: Handle callback + callback_url = input("Paste the full callback URL here: ") + + # Step 4: Exchange code for tokens + tokens = auth.fetch_token(authorization_response=callback_url) + access_token = tokens["access_token"] + + # Step 5: Create client + client = Client(access_token=access_token) + + # Step 6: Get authenticated user ID + me_response = client.users.get_me() + user_id = me_response.data["id"] + + # Step 7: Delete bookmark + response = client.users.delete_bookmark(user_id, post_id) + + print("Response code: 200") + print(json.dumps(response.data, indent=4, sort_keys=True)) + +if __name__ == "__main__": + main() diff --git a/python/bookmarks/lookup.py b/python/bookmarks/lookup.py deleted file mode 100644 index 6af4463..0000000 --- a/python/bookmarks/lookup.py +++ /dev/null @@ -1,55 +0,0 @@ -""" -Bookmarks Lookup - X API v2 -=========================== -Endpoint: GET https://api.x.com/2/users/:id/bookmarks -Docs: https://developer.x.com/en/docs/twitter-api/tweets/bookmarks/api-reference/get-users-id-bookmarks - -Authentication: OAuth 2.0 with PKCE (User Context) -Required env vars: BEARER_TOKEN (OAuth 2.0 user access token) -""" - -import requests -import os -import json - -# Note: This endpoint requires OAuth 2.0 User Context -# The bearer_token here should be the user's access token from OAuth 2.0 PKCE flow -bearer_token = os.environ.get("BEARER_TOKEN") - - -def create_url(user_id): - return "https://api.x.com/2/users/{}/bookmarks".format(user_id) - - -def get_params(): - return {"tweet.fields": "created_at"} - - -def bearer_oauth(r): - """ - Method required by bearer token authentication. - """ - r.headers["Authorization"] = f"Bearer {bearer_token}" - r.headers["User-Agent"] = "v2BookmarksLookupPython" - return r - - -def connect_to_endpoint(url, params): - response = requests.request("GET", url, auth=bearer_oauth, params=params) - print(response.status_code) - if response.status_code != 200: - raise Exception(response.status_code, response.text) - return response.json() - - -def main(): - # Replace with the authenticated user's ID - user_id = "your-user-id" - url = create_url(user_id) - params = get_params() - json_response = connect_to_endpoint(url, params) - print(json.dumps(json_response, indent=4, sort_keys=True)) - - -if __name__ == "__main__": - main() diff --git a/python/compliance/create_compliance_job.py b/python/compliance/create_compliance_job.py index f0ceca4..f91daaa 100644 --- a/python/compliance/create_compliance_job.py +++ b/python/compliance/create_compliance_job.py @@ -1,40 +1,28 @@ -import requests +""" +Create Compliance Job - X API v2 +================================ +Endpoint: POST https://api.x.com/2/compliance/jobs +Docs: https://developer.x.com/en/docs/twitter-api/compliance/batch-compliance/api-reference/post-compliance-jobs + +Authentication: Bearer Token (App-only) +Required env vars: BEARER_TOKEN +""" + import os import json +from xdk import Client -# To set your environment variables in your terminal run the following line: -# export 'BEARER_TOKEN'='' bearer_token = os.environ.get("BEARER_TOKEN") - -compliance_job_url = "https://api.x.com/2/compliance/jobs" +client = Client(bearer_token=bearer_token) # For User Compliance Job, replace the type value with users instead of tweets # Also replace the name value with your desired job name -body = {"type": "tweets", "name": "my_batch_compliance_job"} - - -def bearer_oauth(r): - """ - Method required by bearer token authentication. - """ - - r.headers["Authorization"] = f"Bearer {bearer_token}" - r.headers["User-Agent"] = "v2BatchCompliancePython" - return r - - -def connect_to_endpoint(url, params): - response = requests.request("POST", url, auth=bearer_oauth, json=params) - print(response.status_code) - if response.status_code != 200: - raise Exception(response.status_code, response.text) - return response.json() - +payload = {"type": "tweets", "name": "my_batch_compliance_job"} def main(): - json_response = connect_to_endpoint(compliance_job_url, body) - print(json.dumps(json_response, indent=4, sort_keys=True)) - + response = client.compliance.create_job(body=payload) + + print(json.dumps(response.data, indent=4, sort_keys=True)) if __name__ == "__main__": main() diff --git a/python/compliance/create_job.py b/python/compliance/create_job.py deleted file mode 100644 index ba7ce03..0000000 --- a/python/compliance/create_job.py +++ /dev/null @@ -1,56 +0,0 @@ -""" -Create Compliance Job - X API v2 -================================ -Endpoint: POST https://api.x.com/2/compliance/jobs -Docs: https://developer.x.com/en/docs/twitter-api/compliance/batch-compliance/api-reference/post-compliance-jobs - -Authentication: Bearer Token (App-only) -Required env vars: BEARER_TOKEN -""" - -import requests -import os -import json - -bearer_token = os.environ.get("BEARER_TOKEN") - - -def create_url(): - return "https://api.x.com/2/compliance/jobs" - - -def bearer_oauth(r): - """ - Method required by bearer token authentication. - """ - r.headers["Authorization"] = f"Bearer {bearer_token}" - r.headers["User-Agent"] = "v2ComplianceJobPython" - return r - - -def connect_to_endpoint(url, payload): - response = requests.post(url, auth=bearer_oauth, json=payload) - print(response.status_code) - if response.status_code != 200: - raise Exception(response.status_code, response.text) - return response.json() - - -def main(): - url = create_url() - - # Type can be "tweets" or "users" - payload = { - "type": "tweets", - "name": "my_compliance_job" - } - - json_response = connect_to_endpoint(url, payload) - print(json.dumps(json_response, indent=4, sort_keys=True)) - - # Note the job id and upload_url from the response - # You'll need these to upload your dataset and download results - - -if __name__ == "__main__": - main() diff --git a/python/compliance/download_compliance_results.py b/python/compliance/download_compliance_results.py index 7c46399..edb0e3d 100644 --- a/python/compliance/download_compliance_results.py +++ b/python/compliance/download_compliance_results.py @@ -1,23 +1,28 @@ +""" +Download Compliance Results - X API v2 +====================================== +Endpoint: GET (provided in compliance job response) +Docs: https://developer.x.com/en/docs/twitter-api/compliance/batch-compliance/api-reference/get-compliance-jobs-id + +Note: This endpoint uses a pre-signed URL from the compliance job response. +The download_url is provided when you check the status of a compliance job. +""" + import requests -# Replace with your job download_url +# Replace with your job download_url (from the compliance job response) download_url = '' - -def connect_to_endpoint(url): - response = requests.request("GET", url) - print(response.status_code) +def main(): + response = requests.get(download_url) + + print(f"Response code: {response.status_code}") if response.status_code != 200: raise Exception(response.status_code, response.text) - return response.text - - -def main(): - response = connect_to_endpoint(download_url) - entries = response.splitlines() + + entries = response.text.splitlines() for entry in entries: print(entry) - if __name__ == "__main__": main() diff --git a/python/compliance/get_compliance_job_information_by_id.py b/python/compliance/get_compliance_job_information_by_id.py index 5d46e72..5a139d6 100644 --- a/python/compliance/get_compliance_job_information_by_id.py +++ b/python/compliance/get_compliance_job_information_by_id.py @@ -1,39 +1,27 @@ -import requests +""" +Get Compliance Job by ID - X API v2 +=================================== +Endpoint: GET https://api.x.com/2/compliance/jobs/:id +Docs: https://developer.x.com/en/docs/twitter-api/compliance/batch-compliance/api-reference/get-compliance-jobs-id + +Authentication: Bearer Token (App-only) +Required env vars: BEARER_TOKEN +""" + import os import json +from xdk import Client -# To set your environment variables in your terminal run the following line: -# export 'BEARER_TOKEN'='' bearer_token = os.environ.get("BEARER_TOKEN") +client = Client(bearer_token=bearer_token) # Replace with your job ID below job_id = '' -compliance_job_url = f"https://api.x.com/2/compliance/jobs/{job_id}".format(job_id) - - -def bearer_oauth(r): - """ - Method required by bearer token authentication. - """ - - r.headers["Authorization"] = f"Bearer {bearer_token}" - r.headers["User-Agent"] = "v2BatchCompliancePython" - return r - - -def connect_to_endpoint(url): - response = requests.request("GET", url, auth=bearer_oauth) - print(response.status_code) - if response.status_code != 200: - raise Exception(response.status_code, response.text) - return response.json() - - def main(): - json_response = connect_to_endpoint(compliance_job_url) - print(json.dumps(json_response, indent=4, sort_keys=True)) - + response = client.compliance.get_job(job_id) + + print(json.dumps(response.data, indent=4, sort_keys=True)) if __name__ == "__main__": main() diff --git a/python/compliance/get_jobs.py b/python/compliance/get_jobs.py index de65383..15035d6 100644 --- a/python/compliance/get_jobs.py +++ b/python/compliance/get_jobs.py @@ -8,45 +8,20 @@ Required env vars: BEARER_TOKEN """ -import requests import os import json +from xdk import Client bearer_token = os.environ.get("BEARER_TOKEN") +client = Client(bearer_token=bearer_token) - -def create_url(): - return "https://api.x.com/2/compliance/jobs" - - -def get_params(): - # Type can be "tweets" or "users" - return {"type": "tweets"} - - -def bearer_oauth(r): - """ - Method required by bearer token authentication. - """ - r.headers["Authorization"] = f"Bearer {bearer_token}" - r.headers["User-Agent"] = "v2ComplianceJobsPython" - return r - - -def connect_to_endpoint(url, params): - response = requests.get(url, auth=bearer_oauth, params=params) - print(response.status_code) - if response.status_code != 200: - raise Exception(response.status_code, response.text) - return response.json() - +# Type can be "tweets" or "users" +job_type = "tweets" def main(): - url = create_url() - params = get_params() - json_response = connect_to_endpoint(url, params) - print(json.dumps(json_response, indent=4, sort_keys=True)) - + response = client.compliance.get_jobs(type=job_type) + + print(json.dumps(response.data, indent=4, sort_keys=True)) if __name__ == "__main__": main() diff --git a/python/compliance/get_list_of_compliance_jobs.py b/python/compliance/get_list_of_compliance_jobs.py index 54a9c01..84ddf59 100644 --- a/python/compliance/get_list_of_compliance_jobs.py +++ b/python/compliance/get_list_of_compliance_jobs.py @@ -1,39 +1,27 @@ -import requests +""" +Get Compliance Jobs - X API v2 +============================== +Endpoint: GET https://api.x.com/2/compliance/jobs +Docs: https://developer.x.com/en/docs/twitter-api/compliance/batch-compliance/api-reference/get-compliance-jobs + +Authentication: Bearer Token (App-only) +Required env vars: BEARER_TOKEN +""" + import os import json +from xdk import Client -# To set your environment variables in your terminal run the following line: -# export 'BEARER_TOKEN'='' bearer_token = os.environ.get("BEARER_TOKEN") - -compliance_job_url = "https://api.x.com/2/compliance/jobs" +client = Client(bearer_token=bearer_token) # For User Compliance job, replace the value for type with users -query_params = {"type": "tweets"} - - -def bearer_oauth(r): - """ - Method required by bearer token authentication. - """ - - r.headers["Authorization"] = f"Bearer {bearer_token}" - r.headers["User-Agent"] = "v2BatchCompliancePython" - return r - - -def connect_to_endpoint(url, params): - response = requests.request("GET", url, auth=bearer_oauth, params=params) - print(response.status_code) - if response.status_code != 200: - raise Exception(response.status_code, response.text) - return response.json() - +job_type = "tweets" def main(): - json_response = connect_to_endpoint(compliance_job_url, query_params) - print(json.dumps(json_response, indent=4, sort_keys=True)) - + response = client.compliance.get_jobs(type=job_type) + + print(json.dumps(response.data, indent=4, sort_keys=True)) if __name__ == "__main__": main() diff --git a/python/compliance/upload_ids.py b/python/compliance/upload_ids.py index 4c41aba..3083c8d 100644 --- a/python/compliance/upload_ids.py +++ b/python/compliance/upload_ids.py @@ -1,26 +1,33 @@ +""" +Upload IDs for Compliance Job - X API v2 +======================================== +Endpoint: PUT (provided in compliance job response) +Docs: https://developer.x.com/en/docs/twitter-api/compliance/batch-compliance/api-reference/post-compliance-jobs + +Note: This endpoint uses a pre-signed URL from the compliance job response. +The upload_url is provided when you create a compliance job. +""" + +import os import requests -# Replace with your job download_url +# Replace with your job upload_url (from the compliance job response) upload_url = '' # Replace with your file path that contains the list of Tweet IDs or User IDs, one ID per line file_path = '' -headers = {'Content-Type': "text/plain"} - - -def connect_to_endpoint(url): - response = requests.put(url, data=open(file_path, 'rb'), headers=headers) - print(response.status_code) +def main(): + headers = {'Content-Type': "text/plain"} + + with open(file_path, 'rb') as f: + response = requests.put(upload_url, data=f, headers=headers) + + print(f"Response code: {response.status_code}") if response.status_code != 200: raise Exception(response.status_code, response.text) - return response.text - - -def main(): - response = connect_to_endpoint(upload_url) - print(response) - + + print(response.text) if __name__ == "__main__": main() diff --git a/python/direct_messages/get_events_by_conversation.py b/python/direct_messages/get_events_by_conversation.py index 93515f7..0f3e4b4 100644 --- a/python/direct_messages/get_events_by_conversation.py +++ b/python/direct_messages/get_events_by_conversation.py @@ -1,107 +1,75 @@ -import base64 -import hashlib -import os -import re -import json -import requests -from requests_oauthlib import OAuth2Session - -# This example is set up to retrieve Direct Message events by conversation ID. This supports both -# one-to-one and group conversations. -GET_DMS_EVENTS_URL = "https://api.x.com/2/dm_conversations/:dm_conversation_id/dm_events" - -#----------------------------------------------------------------------------------------------------------------------- -# These variables need to be updated to the setting that match how your Twitter App is set-up at -# https://developer.twitter.com/en/portal/dashboard. These will not change from run-by-run. -client_id = '' -#This must match *exactly* the redirect URL specified in the Developer Portal. -redirect_uri = "https://www.example.com" -#----------------------------------------------------------------------------------------------------------------------- -# This variable specifies the conversation to retrieve. A more ready-to-be used example would -# have this passed in from some calling code. -# What is the ID of the conversatikon to retrieve? -dm_conversation_id = "1512210732774948865" -#----------------------------------------------------------------------------------------------------------------------- - -def handle_oauth(): - - # Set the scopes needed to be granted by the authenticating user. - scopes = ["dm.read", "tweet.read", "users.read", "offline.access"] +""" +Get Events by Conversation ID - X API v2 +========================================= +Endpoint: GET https://api.x.com/2/dm_conversations/:dm_conversation_id/dm_events +Docs: https://developer.x.com/en/docs/twitter-api/direct-messages/lookup/api-reference/get-dm-conversations-dm_conversation_id-dm_events - # Create a code verifier - code_verifier = base64.urlsafe_b64encode(os.urandom(30)).decode("utf-8") - code_verifier = re.sub("[^a-zA-Z0-9]+", "", code_verifier) +Authentication: OAuth 2.0 (User Context) +Required env vars: CLIENT_ID, CLIENT_SECRET - # Create a code challenge - code_challenge = hashlib.sha256(code_verifier.encode("utf-8")).digest() - code_challenge = base64.urlsafe_b64encode(code_challenge).decode("utf-8") - code_challenge = code_challenge.replace("=", "") +This example retrieves Direct Message events by conversation ID. +This supports both one-to-one and group conversations. +""" - # Start and OAuth 2.0 session - oauth = OAuth2Session(client_id, redirect_uri=redirect_uri, scope=scopes) - - # Create an authorize URL - auth_url = "https://twitter.com/i/oauth2/authorize" - authorization_url, state = oauth.authorization_url( - auth_url, code_challenge=code_challenge, code_challenge_method="S256" - ) +import os +import json +from xdk import Client +from xdk.oauth2_auth import OAuth2PKCEAuth - # Visit the URL to authorize your App to make requests on behalf of a user - print( - "Visit the following URL to authorize your App on behalf of your Twitter handle in a browser:" - ) - print(authorization_url) +# The code below sets the client ID and client secret from your environment variables +# To set environment variables on macOS or Linux, run the export commands below from the terminal: +# export CLIENT_ID='YOUR-CLIENT-ID' +# export CLIENT_SECRET='YOUR-CLIENT-SECRET' +client_id = os.environ.get("CLIENT_ID") +client_secret = os.environ.get("CLIENT_SECRET") - # Paste in your authorize URL to complete the request - authorization_response = input( - "Paste in the full URL after you've authorized your App:\n" - ) +# Replace the following URL with your callback URL, which can be obtained from your App's auth settings. +redirect_uri = "https://example.com" - # Fetch your access token - token_url = "https://api.x.com/2/oauth2/token" +# Set the scopes +scopes = ["dm.read", "tweet.read", "users.read", "offline.access"] - # The following line of code will only work if you are using a type of App that is a public client - auth = False +# What is the ID of the conversation to retrieve? +dm_conversation_id = "1512210732774948865" - token = oauth.fetch_token( - token_url=token_url, - authorization_response=authorization_response, - auth=auth, +def main(): + # Step 1: Create PKCE instance + auth = OAuth2PKCEAuth( client_id=client_id, - include_client_id=True, - code_verifier=code_verifier, + client_secret=client_secret, + redirect_uri=redirect_uri, + scope=scopes ) - - # Your access token - access = token["access_token"] - - return access - -def get_events_by_conservation_id(dm_conversation_id): - - access = handle_oauth() - - headers = { - "Authorization": "Bearer {}".format(access), - "Content-Type": "application/json", - "User-Agent": "TwitterDevSampleCode", - "X-TFE-Experiment-environment": "staging1", - "Dtab-Local": "/s/gizmoduck/test-users-temporary => /s/gizmoduck/gizmoduck" - } - - request_url = GET_DMS_EVENTS_URL.replace(':dm_conversation_id', str(dm_conversation_id)) - - response = requests.request("GET", request_url, headers=headers) - - if response.status_code != 200: - print("Request returned an error: {} {}".format(response.status_code, response.text)) - else: - print(f"Response code: {response.status_code}") - return response - -def main(): - response = get_events_by_conservation_id(dm_conversation_id) - print(json.dumps(json.loads(response.text), indent=4, sort_keys=True)) + + # Step 2: Get authorization URL + auth_url = auth.get_authorization_url() + print("Visit the following URL to authorize your App on behalf of your X handle in a browser:") + print(auth_url) + + # Step 3: Handle callback + callback_url = input("Paste the full callback URL here: ") + + # Step 4: Exchange code for tokens + tokens = auth.fetch_token(authorization_response=callback_url) + access_token = tokens["access_token"] + + # Step 5: Create client + client = Client(access_token=access_token) + + # Step 6: Get events by conversation ID with automatic pagination + all_events = [] + for page in client.direct_messages.get_events_by_conversation_id( + dm_conversation_id, + max_results=100 + ): + # Access data attribute (model uses extra='allow' so data should be available) + # Use getattr with fallback in case data field is missing from response + page_data = getattr(page, 'data', []) or [] + all_events.extend(page_data) + print(f"Fetched {len(page_data)} events (total: {len(all_events)})") + + print(f"\nTotal Conversation Events: {len(all_events)}") + print(json.dumps({"data": all_events[:5]}, indent=4, sort_keys=True)) # Print first 5 as example if __name__ == "__main__": main() diff --git a/python/direct_messages/get_one_to_one_conversation_events.py b/python/direct_messages/get_one_to_one_conversation_events.py index b03f552..1c2b7aa 100644 --- a/python/direct_messages/get_one_to_one_conversation_events.py +++ b/python/direct_messages/get_one_to_one_conversation_events.py @@ -1,108 +1,75 @@ -import base64 -import hashlib -import os -import re -import json -import requests -from requests_oauthlib import OAuth2Session - -# This example is set up to retrieve Direct Message conversation events associated with a one-to-one message. -# Currently, the v2 DM endpoints support three conversation event types: MessageCreate, ParticipantsJoin, and -# ParticipantsLeave. -GET_DM_EVENTS_URL = "https://api.x.com/2/dm_conversations/with/:participant_id/dm_events" - -#----------------------------------------------------------------------------------------------------------------------- -# These variables need to be updated to the setting that match how your Twitter App is set-up at -# https://developer.twitter.com/en/portal/dashboard. These will not change from run-by-run. -client_id = '' -#This must match *exactly* the redirect URL specified in the Developer Portal. -redirect_uri = "https://www.example.com" -#----------------------------------------------------------------------------------------------------------------------- -# This variable indicates the participant of the one-to-one conversation. A more ready-to-be used example would -# have this passed in from some calling code. -# Who is this one-to-one conversation with? -participant_id = "906948460078698496" -#----------------------------------------------------------------------------------------------------------------------- - -def handle_oauth(): - - # Set the scopes needed to be granted by the authenticating user. - scopes = ["dm.read", "tweet.read", "users.read", "offline.access"] +""" +Get One-to-One Conversation Events - X API v2 +============================================= +Endpoint: GET https://api.x.com/2/dm_conversations/with/:participant_id/dm_events +Docs: https://developer.x.com/en/docs/twitter-api/direct-messages/lookup/api-reference/get-dm-conversations-with-participant_id-dm_events - # Create a code verifier - code_verifier = base64.urlsafe_b64encode(os.urandom(30)).decode("utf-8") - code_verifier = re.sub("[^a-zA-Z0-9]+", "", code_verifier) +Authentication: OAuth 2.0 (User Context) +Required env vars: CLIENT_ID, CLIENT_SECRET - # Create a code challenge - code_challenge = hashlib.sha256(code_verifier.encode("utf-8")).digest() - code_challenge = base64.urlsafe_b64encode(code_challenge).decode("utf-8") - code_challenge = code_challenge.replace("=", "") +This example retrieves Direct Message conversation events associated with a one-to-one message. +Currently, the v2 DM endpoints support three conversation event types: MessageCreate, ParticipantsJoin, and ParticipantsLeave. +""" - # Start and OAuth 2.0 session - oauth = OAuth2Session(client_id, redirect_uri=redirect_uri, scope=scopes) - - # Create an authorize URL - auth_url = "https://twitter.com/i/oauth2/authorize" - authorization_url, state = oauth.authorization_url( - auth_url, code_challenge=code_challenge, code_challenge_method="S256" - ) +import os +import json +from xdk import Client +from xdk.oauth2_auth import OAuth2PKCEAuth - # Visit the URL to authorize your App to make requests on behalf of a user - print( - "Visit the following URL to authorize your App on behalf of your Twitter handle in a browser:" - ) - print(authorization_url) +# The code below sets the client ID and client secret from your environment variables +# To set environment variables on macOS or Linux, run the export commands below from the terminal: +# export CLIENT_ID='YOUR-CLIENT-ID' +# export CLIENT_SECRET='YOUR-CLIENT-SECRET' +client_id = os.environ.get("CLIENT_ID") +client_secret = os.environ.get("CLIENT_SECRET") - # Paste in your authorize URL to complete the request - authorization_response = input( - "Paste in the full URL after you've authorized your App:\n" - ) +# Replace the following URL with your callback URL, which can be obtained from your App's auth settings. +redirect_uri = "https://example.com" - # Fetch your access token - token_url = "https://api.x.com/2/oauth2/token" +# Set the scopes +scopes = ["dm.read", "tweet.read", "users.read", "offline.access"] - # The following line of code will only work if you are using a type of App that is a public client - auth = False +# Who is this one-to-one conversation with? +participant_id = "1716450569358098432" - token = oauth.fetch_token( - token_url=token_url, - authorization_response=authorization_response, - auth=auth, +def main(): + # Step 1: Create PKCE instance + auth = OAuth2PKCEAuth( client_id=client_id, - include_client_id=True, - code_verifier=code_verifier, + client_secret=client_secret, + redirect_uri=redirect_uri, + scope=scopes ) - - # Your access token - access = token["access_token"] - - return access - -def get_one_to_one_conversation_events(participant_id): - - access = handle_oauth() - - headers = { - "Authorization": "Bearer {}".format(access), - "Content-Type": "application/json", - "User-Agent": "TwitterDevSampleCode", - "X-TFE-Experiment-environment": "staging1", - "Dtab-Local": "/s/gizmoduck/test-users-temporary => /s/gizmoduck/gizmoduck" - } - - request_url = GET_DM_EVENTS_URL.replace(':participant_id', str(participant_id)) - - response = requests.request("GET", request_url, headers=headers) - - if response.status_code != 200: - print("Request returned an error: {} {}".format(response.status_code, response.text)) - else: - print(f"Response code: {response.status_code}") - return response - -def main(): - response = get_one_to_one_conversation_events(participant_id) - print(json.dumps(json.loads(response.text), indent=4, sort_keys=True)) + + # Step 2: Get authorization URL + auth_url = auth.get_authorization_url() + print("Visit the following URL to authorize your App on behalf of your X handle in a browser:") + print(auth_url) + + # Step 3: Handle callback + callback_url = input("Paste the full callback URL here: ") + + # Step 4: Exchange code for tokens + tokens = auth.fetch_token(authorization_response=callback_url) + access_token = tokens["access_token"] + + # Step 5: Create client + client = Client(access_token=access_token) + + # Step 6: Get one-to-one conversation events with automatic pagination + all_events = [] + for page in client.direct_messages.get_events_by_participant_id( + participant_id, + max_results=100 + ): + # Access data attribute (model uses extra='allow' so data should be available) + # Use getattr with fallback in case data field is missing from response + page_data = getattr(page, 'data', []) or [] + all_events.extend(page_data) + print(f"Fetched {len(page_data)} events (total: {len(all_events)})") + + print(f"\nTotal Conversation Events: {len(all_events)}") + print(json.dumps({"data": all_events[:5]}, indent=4, sort_keys=True)) # Print first 5 as example if __name__ == "__main__": main() diff --git a/python/direct_messages/get_user_conversation_events.py b/python/direct_messages/get_user_conversation_events.py index b5bc8c5..da3c132 100644 --- a/python/direct_messages/get_user_conversation_events.py +++ b/python/direct_messages/get_user_conversation_events.py @@ -1,102 +1,75 @@ -import base64 -import hashlib -import os -import re -import json -import requests -from requests_oauthlib import OAuth2Session - -# This example is set up to retrieve Direct Message events of the authenticating user. This supports both -# one-to-one and group conversations. -GET_DM_EVENTS_URL = "https://api.x.com/2/dm_events" - -#----------------------------------------------------------------------------------------------------------------------- -# These variables need to be updated to the setting that match how your Twitter App is set-up at -# https://developer.twitter.com/en/portal/dashboard. These will not change from run-by-run. -client_id = "" -#This must match *exactly* the redirect URL specified in the Developer Portal. -redirect_uri = "https://www.example.com" -#----------------------------------------------------------------------------------------------------------------------- - -def handle_oauth(): - - # Set the scopes needed to be granted by the authenticating user. - scopes = ["dm.read", "tweet.read", "users.read", "offline.access"] +""" +Get User Conversation Events - X API v2 +======================================= +Endpoint: GET https://api.x.com/2/dm_events +Docs: https://developer.x.com/en/docs/twitter-api/direct-messages/lookup/api-reference/get-dm-events - # Create a code verifier. - code_verifier = base64.urlsafe_b64encode(os.urandom(30)).decode("utf-8") - code_verifier = re.sub("[^a-zA-Z0-9]+", "", code_verifier) +Authentication: OAuth 2.0 (User Context) +Required env vars: CLIENT_ID, CLIENT_SECRET - # Create a code challenge. - code_challenge = hashlib.sha256(code_verifier.encode("utf-8")).digest() - code_challenge = base64.urlsafe_b64encode(code_challenge).decode("utf-8") - code_challenge = code_challenge.replace("=", "") +This example retrieves Direct Message events of the authenticating user. +This supports both one-to-one and group conversations. +""" - # Start an OAuth 2.0 session. - oauth = OAuth2Session(client_id, redirect_uri=redirect_uri, scope=scopes) - - # Create an authorize URL. - auth_url = "https://twitter.com/i/oauth2/authorize" - authorization_url, state = oauth.authorization_url( - auth_url, code_challenge=code_challenge, code_challenge_method="S256" - ) - - # Visit the URL to authorize your App to make requests on behalf of a user. - print( - "Visit the following URL to authorize your App on behalf of your Twitter handle in a browser:" - ) - print(authorization_url) +import os +import json +from xdk import Client +from xdk.oauth2_auth import OAuth2PKCEAuth - # Paste in your authorize URL to complete the request. - authorization_response = input( - "Paste in the full URL after you've authorized your App:\n" - ) +# The code below sets the client ID and client secret from your environment variables +# To set environment variables on macOS or Linux, run the export commands below from the terminal: +# export CLIENT_ID='YOUR-CLIENT-ID' +# export CLIENT_SECRET='YOUR-CLIENT-SECRET' +client_id = os.environ.get("CLIENT_ID") +client_secret = os.environ.get("CLIENT_SECRET") - # Fetch your access token. - token_url = "https://api.x.com/2/oauth2/token" +# Replace the following URL with your callback URL, which can be obtained from your App's auth settings. +redirect_uri = "https://example.com" - # The following line of code will only work if you are using a type of App that is a public client. - auth = False +# Set the scopes +scopes = ["dm.read", "tweet.read", "users.read", "offline.access"] - token = oauth.fetch_token( - token_url=token_url, - authorization_response=authorization_response, - auth=auth, +def main(): + # Step 1: Create PKCE instance + auth = OAuth2PKCEAuth( client_id=client_id, - include_client_id=True, - code_verifier=code_verifier, + client_secret=client_secret, + redirect_uri=redirect_uri, + scope=scopes ) - - # The access token. - access = token["access_token"] - - return access - -def get_user_conversation_events(): - - access = handle_oauth() - - headers = { - "Authorization": "Bearer {}".format(access), - "Content-Type": "application/json", - "User-Agent": "TwitterDevSampleCode", - "X-TFE-Experiment-environment": "staging1", - "Dtab-Local": "/s/gizmoduck/test-users-temporary => /s/gizmoduck/gizmoduck" - } - - request_url = GET_DM_EVENTS_URL - - response = requests.request("GET", request_url, headers=headers) - - if response.status_code != 200: - print("Request returned an error: {} {}".format(response.status_code, response.text)) - else: - print(f"Response code: {response.status_code}") - return response - -def main(): - response = get_user_conversation_events() - print(json.dumps(json.loads(response.text), indent=4, sort_keys=True)) + + # Step 2: Get authorization URL + auth_url = auth.get_authorization_url() + print("Visit the following URL to authorize your App on behalf of your X handle in a browser:") + print(auth_url) + + # Step 3: Handle callback + callback_url = input("Paste the full callback URL here: ") + + # Step 4: Exchange code for tokens + tokens = auth.fetch_token(authorization_response=callback_url) + access_token = tokens["access_token"] + + # Step 5: Create client + client = Client(access_token=access_token) + + # Step 6: Get user conversation events with automatic pagination + # DM event fields are adjustable. Options include: + # id, text, event_type, created_at, dm_conversation_id, + # sender_id, participant_ids, referenced_tweets, attachments + all_events = [] + for page in client.direct_messages.get_events( + max_results=100, + dm_event_fields=["id", "text", "event_type", "created_at", "sender_id"] + ): + # Access data attribute (model uses extra='allow' so data should be available) + # Use getattr with fallback in case data field is missing from response + page_data = getattr(page, 'data', []) or [] + all_events.extend(page_data) + print(f"Fetched {len(page_data)} events (total: {len(all_events)})") + + print(f"\nTotal DM Events: {len(all_events)}") + print(json.dumps({"data": all_events[:5]}, indent=4, sort_keys=True)) # Print first 5 as example if __name__ == "__main__": main() diff --git a/python/direct_messages/lookup.py b/python/direct_messages/lookup.py deleted file mode 100644 index 3ba8f24..0000000 --- a/python/direct_messages/lookup.py +++ /dev/null @@ -1,78 +0,0 @@ -""" -Direct Messages Lookup - X API v2 -================================= -Endpoint: GET https://api.x.com/2/dm_events -Docs: https://developer.x.com/en/docs/twitter-api/direct-messages/lookup/api-reference/get-dm-events - -Authentication: OAuth 1.0a or OAuth 2.0 (User Context) -Required env vars: CONSUMER_KEY, CONSUMER_SECRET -""" - -from requests_oauthlib import OAuth1Session -import os -import json - -consumer_key = os.environ.get("CONSUMER_KEY") -consumer_secret = os.environ.get("CONSUMER_SECRET") - -# DM event fields are adjustable. Options include: -# id, text, event_type, created_at, dm_conversation_id, -# sender_id, participant_ids, referenced_tweets, attachments -params = {"dm_event.fields": "id,text,event_type,created_at,sender_id"} - -# Get request token -request_token_url = "https://api.x.com/oauth/request_token" -oauth = OAuth1Session(consumer_key, client_secret=consumer_secret) - -try: - fetch_response = oauth.fetch_request_token(request_token_url) -except ValueError: - print( - "There may have been an issue with the consumer_key or consumer_secret you entered." - ) - -resource_owner_key = fetch_response.get("oauth_token") -resource_owner_secret = fetch_response.get("oauth_token_secret") -print("Got OAuth token: %s" % resource_owner_key) - -# Get authorization -base_authorization_url = "https://api.x.com/oauth/authorize" -authorization_url = oauth.authorization_url(base_authorization_url) -print("Please go here and authorize: %s" % authorization_url) -verifier = input("Paste the PIN here: ") - -# Get the access token -access_token_url = "https://api.x.com/oauth/access_token" -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=resource_owner_key, - resource_owner_secret=resource_owner_secret, - verifier=verifier, -) -oauth_tokens = oauth.fetch_access_token(access_token_url) - -access_token = oauth_tokens["oauth_token"] -access_token_secret = oauth_tokens["oauth_token_secret"] - -# Make the request -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=access_token, - resource_owner_secret=access_token_secret, -) - -# Making the request -response = oauth.get("https://api.x.com/2/dm_events", params=params) - -if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format(response.status_code, response.text) - ) - -print("Response code: {}".format(response.status_code)) - -# Saving the response as JSON -json_response = response.json() -print(json.dumps(json_response, indent=4, sort_keys=True)) diff --git a/python/direct_messages/post_dm_to_conversation.py b/python/direct_messages/post_dm_to_conversation.py index 18d6af3..e82afe6 100644 --- a/python/direct_messages/post_dm_to_conversation.py +++ b/python/direct_messages/post_dm_to_conversation.py @@ -1,113 +1,67 @@ -import base64 -import hashlib -import os -import re -import json -import requests -from requests_oauthlib import OAuth2Session - -#This example is set up to add a DM to a specified conversation by referencing its ID. -POST_DM_URL = "https://api.x.com/2/dm_conversations/:dm_conversation_id/messages" - -#----------------------------------------------------------------------------------------------------------------------- -# These variables need to be updated to the setting that match how your Twitter App is set-up at -# https://developer.twitter.com/en/portal/dashboard. These will not change from run-by-run. -client_id = '' -#This must match *exactly* the redirect URL specified in the Developer Portal. -redirect_uri = "https://www.example.com" -#----------------------------------------------------------------------------------------------------------------------- -# These variables indicate the conversation that the message should be added to. A more ready-to-be used example would -# have these passed in from some calling code. -# Provide the ID of the conversation this message should be added to. -dm_conversation_id = "1512210732774948865" -#Set the text of the message to be sent. -text_message = "Hi, I am adding a message to an existing conversation by referencing its ID." -#----------------------------------------------------------------------------------------------------------------------- - -def handle_oauth(): +""" +Post DM to Conversation - X API v2 +=================================== +Endpoint: POST https://api.x.com/2/dm_conversations/:dm_conversation_id/messages +Docs: https://developer.x.com/en/docs/twitter-api/direct-messages/manage/api-reference/post-dm-conversations-dm_conversation_id-messages - # Set the scopes needed to be granted by the authenticating user. - scopes = ["dm.read", "dm.write", "tweet.read", "users.read", "offline.access"] +Authentication: OAuth 2.0 (User Context) +Required env vars: CLIENT_ID, CLIENT_SECRET +""" - # Create a code verifier. - code_verifier = base64.urlsafe_b64encode(os.urandom(30)).decode("utf-8") - code_verifier = re.sub("[^a-zA-Z0-9]+", "", code_verifier) - - # Create a code challenge. - code_challenge = hashlib.sha256(code_verifier.encode("utf-8")).digest() - code_challenge = base64.urlsafe_b64encode(code_challenge).decode("utf-8") - code_challenge = code_challenge.replace("=", "") +import os +import json +from xdk import Client +from xdk.oauth2_auth import OAuth2PKCEAuth - # Start an OAuth 2.0 session. - oauth = OAuth2Session(client_id, redirect_uri=redirect_uri, scope=scopes) +# The code below sets the client ID and client secret from your environment variables +# To set environment variables on macOS or Linux, run the export commands below from the terminal: +# export CLIENT_ID='YOUR-CLIENT-ID' +# export CLIENT_SECRET='YOUR-CLIENT-SECRET' +client_id = os.environ.get("CLIENT_ID") +client_secret = os.environ.get("CLIENT_SECRET") - # Create an authorize URL. - auth_url = "https://twitter.com/i/oauth2/authorize" - authorization_url, state = oauth.authorization_url( - auth_url, code_challenge=code_challenge, code_challenge_method="S256" - ) +# Replace the following URL with your callback URL, which can be obtained from your App's auth settings. +redirect_uri = "https://example.com" - # Visit the URL to authorize your App to make requests on behalf of a user. - print( - "Visit the following URL to authorize your App on behalf of your Twitter handle in a browser:" - ) - print(authorization_url) - - # Paste in your authorize URL to complete the request. - authorization_response = input( - "Paste in the full URL after you've authorized your App:\n" - ) +# Set the scopes +scopes = ["dm.read", "dm.write", "tweet.read", "users.read", "offline.access"] - # Fetch your access token. - token_url = "https://api.x.com/2/oauth2/token" +# Provide the ID of the conversation this message should be added to. +dm_conversation_id = "1856843062712176900" - # The following line of code will only work if you are using a type of App that is a public client - auth = False +# Set the text of the message to be sent. +text_message = "Hi, I am adding a message to an existing conversation by referencing its ID." - token = oauth.fetch_token( - token_url=token_url, - authorization_response=authorization_response, - auth=auth, +def main(): + # Step 1: Create PKCE instance + auth = OAuth2PKCEAuth( client_id=client_id, - include_client_id=True, - code_verifier=code_verifier, + client_secret=client_secret, + redirect_uri=redirect_uri, + scope=scopes ) - - # The access token. - access = token["access_token"] - - return access - -def add_dm_to_conversation(dm_text, dm_conversation_id): - request_body = {} - - access = handle_oauth() - - headers = { - "Authorization": "Bearer {}".format(access), - "Content-Type": "application/json", - "User-Agent": "TwitterDevSampleCode", - "X-TFE-Experiment-environment": "staging1", - "Dtab-Local": "/s/gizmoduck/test-users-temporary => /s/gizmoduck/gizmoduck" - } - - request_url = POST_DM_URL.replace(':dm_conversation_id', str(dm_conversation_id)) - request_body['text'] = dm_text - json_body = json.dumps(request_body) - - #Send DM - response = requests.request("POST", request_url, headers=headers, json=json.loads(json_body)) - - if response.status_code != 201: - print("Request returned an error: {} {}".format(response.status_code, response.text)) - else: - print(f"Response code: {response.status_code}") - - return response - -def main(): - response = add_dm_to_conversation(text_message, dm_conversation_id) - print(json.dumps(json.loads(response.text), indent=4, sort_keys=True)) + + # Step 2: Get authorization URL + auth_url = auth.get_authorization_url() + print("Visit the following URL to authorize your App on behalf of your X handle in a browser:") + print(auth_url) + + # Step 3: Handle callback + callback_url = input("Paste the full callback URL here: ") + + # Step 4: Exchange code for tokens + tokens = auth.fetch_token(authorization_response=callback_url) + access_token = tokens["access_token"] + + # Step 5: Create client + client = Client(access_token=access_token) + + # Step 6: Add DM to conversation + payload = {"text": text_message} + response = client.direct_messages.create_by_conversation_id(dm_conversation_id, body=payload) + + print("Response code: 201") + print(json.dumps(response.data, indent=4, sort_keys=True)) if __name__ == "__main__": main() diff --git a/python/direct_messages/post_group_conversation_dm.py b/python/direct_messages/post_group_conversation_dm.py index 135a9e5..bcc58b0 100644 --- a/python/direct_messages/post_group_conversation_dm.py +++ b/python/direct_messages/post_group_conversation_dm.py @@ -1,116 +1,71 @@ -import base64 -import hashlib -import os -import re -import json -import requests -from requests_oauthlib import OAuth2Session - -#This example is set up to create a new group conversation and add a new DM to it. -POST_DM_URL = "https://api.x.com/2/dm_conversations" - -#----------------------------------------------------------------------------------------------------------------------- -# These variables need to be updated to the setting that match how your Twitter App is set-up at -# https://developer.twitter.com/en/portal/dashboard. These will not change from run-by-run. -client_id = '' -#This must match *exactly* the redirect URL specified in the Developer Portal. -redirect_uri = "https://www.example.com" -#----------------------------------------------------------------------------------------------------------------------- -# These variables indicate the participants of the new group conversation and the message to add. A more ready-to-be -# used example would have these passed in from some calling code. -#Who is in this group conversation? Reference their User IDs. -participant_ids = ["944480690","906948460078698496"] -#Set the text of the message to be sent. -text_message = "Hi, I am creating a new *group* conversation, and starting it with the this message." -#----------------------------------------------------------------------------------------------------------------------- - -def handle_oauth(): - - # Set the scopes needed to be granted by the authenticating user. - scopes = ["dm.read", "dm.write", "tweet.read", "users.read", "offline.access"] +""" +Post Group Conversation Direct Message - X API v2 +================================================= +Endpoint: POST https://api.x.com/2/dm_conversations +Docs: https://developer.x.com/en/docs/twitter-api/direct-messages/manage/api-reference/post-dm-conversations - # Create a code verifier. - code_verifier = base64.urlsafe_b64encode(os.urandom(30)).decode("utf-8") - code_verifier = re.sub("[^a-zA-Z0-9]+", "", code_verifier) +Authentication: OAuth 2.0 (User Context) +Required env vars: CLIENT_ID, CLIENT_SECRET +""" - # Create a code challenge. - code_challenge = hashlib.sha256(code_verifier.encode("utf-8")).digest() - code_challenge = base64.urlsafe_b64encode(code_challenge).decode("utf-8") - code_challenge = code_challenge.replace("=", "") - - # Start an OAuth 2.0 session. - oauth = OAuth2Session(client_id, redirect_uri=redirect_uri, scope=scopes) +import os +import json +from xdk import Client +from xdk.oauth2_auth import OAuth2PKCEAuth - # Create an authorize URL. - auth_url = "https://twitter.com/i/oauth2/authorize" - authorization_url, state = oauth.authorization_url( - auth_url, code_challenge=code_challenge, code_challenge_method="S256" - ) +# The code below sets the client ID and client secret from your environment variables +# To set environment variables on macOS or Linux, run the export commands below from the terminal: +# export CLIENT_ID='YOUR-CLIENT-ID' +# export CLIENT_SECRET='YOUR-CLIENT-SECRET' +client_id = os.environ.get("CLIENT_ID") +client_secret = os.environ.get("CLIENT_SECRET") - # Visit the URL to authorize your App to make requests on behalf of a user. - print( - "Visit the following URL to authorize your App on behalf of your Twitter handle in a browser:" - ) - print(authorization_url) +# Replace the following URL with your callback URL, which can be obtained from your App's auth settings. +redirect_uri = "https://example.com" - # Paste in your authorize URL to complete the request. - authorization_response = input( - "Paste in the full URL after you've authorized your App:\n" - ) +# Set the scopes +scopes = ["dm.read", "dm.write", "tweet.read", "users.read", "offline.access"] - # Fetch your access token. - token_url = "https://api.x.com/2/oauth2/token" +# Who is in this group conversation? Reference their User IDs. +participant_ids = ["2244994945", "1716450569358098432"] - # The following line of code will only work if you are using a type of App that is a public client. - auth = False +# Set the text of the message to be sent. +text_message = "Hi, I am creating a new *group* conversation, and starting it with the this message." - token = oauth.fetch_token( - token_url=token_url, - authorization_response=authorization_response, - auth=auth, +def main(): + # Step 1: Create PKCE instance + auth = OAuth2PKCEAuth( client_id=client_id, - include_client_id=True, - code_verifier=code_verifier, + client_secret=client_secret, + redirect_uri=redirect_uri, + scope=scopes ) - - # The access token - access = token["access_token"] - - return access - -def create_new_group_conversation_with_dm(dm_text, participant_ids): - request_body = {} - - access = handle_oauth() - - headers = { - "Authorization": "Bearer {}".format(access), - "Content-Type": "application/json", - "User-Agent": "TwitterDevSampleCode", - "X-TFE-Experiment-environment": "staging1", - "Dtab-Local": "/s/gizmoduck/test-users-temporary => /s/gizmoduck/gizmoduck" + + # Step 2: Get authorization URL + auth_url = auth.get_authorization_url() + print("Visit the following URL to authorize your App on behalf of your X handle in a browser:") + print(auth_url) + + # Step 3: Handle callback + callback_url = input("Paste the full callback URL here: ") + + # Step 4: Exchange code for tokens + tokens = auth.fetch_token(authorization_response=callback_url) + access_token = tokens["access_token"] + + # Step 5: Create client + client = Client(access_token=access_token) + + # Step 6: Create group conversation with DM + payload = { + "message": {"text": text_message}, + "participant_ids": participant_ids, + "conversation_type": "Group" } - - request_url = POST_DM_URL - request_body['message'] = {} - request_body['message']['text'] = dm_text - request_body['participant_ids'] = participant_ids - request_body['conversation_type'] = "Group" - json_body = json.dumps(request_body) - - #Send DM - response = requests.request("POST", request_url, headers=headers, json=json.loads(json_body)) - - if response.status_code != 201: - print("Request returned an error: {} {}".format(response.status_code, response.text)) - else: - print(f"Response code: {response.status_code}") - - return response - -def main(): - response = create_new_group_conversation_with_dm(text_message, participant_ids) - print(json.dumps(json.loads(response.text), indent=4, sort_keys=True)) + response = client.direct_messages.create_conversation(body=payload) + + print("Response code: 201") + print(json.dumps(response.data, indent=4, sort_keys=True)) if __name__ == "__main__": main() diff --git a/python/direct_messages/post_one_to_one_dm.py b/python/direct_messages/post_one_to_one_dm.py index da59ba4..7512281 100644 --- a/python/direct_messages/post_one_to_one_dm.py +++ b/python/direct_messages/post_one_to_one_dm.py @@ -1,114 +1,67 @@ -import base64 -import hashlib -import os -import re -import json -import requests -from requests_oauthlib import OAuth2Session - -#This example is set up to add a new DM to a one-to-one conversation. -POST_DM_URL = "https://api.x.com/2/dm_conversations/with/:participant_id/messages" - -#----------------------------------------------------------------------------------------------------------------------- -# These variables need to be updated to the setting that match how your Twitter App is set-up at -# https://developer.twitter.com/en/portal/dashboard. These will not change from run-by-run. -client_id = '' -#This must match *exactly* the redirect URL specified in the Developer Portal. -redirect_uri = "https://www.example.com" -#----------------------------------------------------------------------------------------------------------------------- -# These variables indicate the participant of the one-to-one conversation and the message to add. A more ready-to-be -# used example would have these passed in from some calling code. -#Who is this DM being sent to? Reference their User ID. -participant_id = "944480690" -#Set the text of the message to be sent. -text_message = "Hi, I am DMing you using the v2 DM one-to-one endpoint." -#----------------------------------------------------------------------------------------------------------------------- - -def handle_oauth(): - - # Set the scopes needed to be granted by the authenticating user. - scopes = ["dm.read", "dm.write", "tweet.read", "users.read", "offline.access"] +""" +Post One-to-One Direct Message - X API v2 +========================================== +Endpoint: POST https://api.x.com/2/dm_conversations/with/:participant_id/messages +Docs: https://developer.x.com/en/docs/twitter-api/direct-messages/manage/api-reference/post-dm-conversations-with-participant_id-messages - # Create a code verifier - code_verifier = base64.urlsafe_b64encode(os.urandom(30)).decode("utf-8") - code_verifier = re.sub("[^a-zA-Z0-9]+", "", code_verifier) +Authentication: OAuth 2.0 (User Context) +Required env vars: CLIENT_ID, CLIENT_SECRET +""" - # Create a code challenge - code_challenge = hashlib.sha256(code_verifier.encode("utf-8")).digest() - code_challenge = base64.urlsafe_b64encode(code_challenge).decode("utf-8") - code_challenge = code_challenge.replace("=", "") +import os +import json +from xdk import Client +from xdk.oauth2_auth import OAuth2PKCEAuth - # Start an OAuth 2.0 session - oauth = OAuth2Session(client_id, redirect_uri=redirect_uri, scope=scopes) +# The code below sets the client ID and client secret from your environment variables +# To set environment variables on macOS or Linux, run the export commands below from the terminal: +# export CLIENT_ID='YOUR-CLIENT-ID' +# export CLIENT_SECRET='YOUR-CLIENT-SECRET' +client_id = os.environ.get("CLIENT_ID") +client_secret = os.environ.get("CLIENT_SECRET") - # Create an authorize URL - auth_url = "https://twitter.com/i/oauth2/authorize" - authorization_url, state = oauth.authorization_url( - auth_url, code_challenge=code_challenge, code_challenge_method="S256" - ) +# Replace the following URL with your callback URL, which can be obtained from your App's auth settings. +redirect_uri = "https://example.com" - # Visit the URL to authorize your App to make requests on behalf of a user - print( - "Visit the following URL to authorize your App on behalf of your Twitter handle in a browser:" - ) - print(authorization_url) +# Set the scopes +scopes = ["dm.read", "dm.write", "tweet.read", "users.read", "offline.access"] - # Paste in your authorize URL to complete the request - authorization_response = input( - "Paste in the full URL after you've authorized your App:\n" - ) - - # Fetch your access token - token_url = "https://api.x.com/2/oauth2/token" +# Who is this DM being sent to? Reference their User ID. +participant_id = "1716450569358098432" - # The following line of code will only work if you are using a type of App that is a public client - auth = False +# Set the text of the message to be sent. +text_message = "Hi, I am DMing you using the v2 DM one-to-one endpoint." - token = oauth.fetch_token( - token_url=token_url, - authorization_response=authorization_response, - auth=auth, +def main(): + # Step 1: Create PKCE instance + auth = OAuth2PKCEAuth( client_id=client_id, - include_client_id=True, - code_verifier=code_verifier, + client_secret=client_secret, + redirect_uri=redirect_uri, + scope=scopes ) - - # Your access token - access = token["access_token"] - - return access - -def post_dm_to_one_to_one_conversation(participant_id): - - request_body = {} - - access = handle_oauth() - - headers = { - "Authorization": "Bearer {}".format(access), - "Content-Type": "application/json", - "User-Agent": "TwitterDevSampleCode", - "X-TFE-Experiment-environment": "staging1", - "Dtab-Local": "/s/gizmoduck/test-users-temporary => /s/gizmoduck/gizmoduck" - } - - request_url = POST_DM_URL.replace(':participant_id', str(participant_id)) - request_body['text'] = text_message - json_body = json.dumps(request_body) - - #Send DM - response = requests.request("POST", request_url, headers=headers, json=json.loads(json_body)) - - if response.status_code != 201: - print("Request returned an error: {} {}".format(response.status_code, response.text)) - else: - print(f"Response code: {response.status_code}") - - return response - -def main(): - response = post_dm_to_one_to_one_conversation(participant_id) - print(json.dumps(json.loads(response.text), indent=4, sort_keys=True)) + + # Step 2: Get authorization URL + auth_url = auth.get_authorization_url() + print("Visit the following URL to authorize your App on behalf of your X handle in a browser:") + print(auth_url) + + # Step 3: Handle callback + callback_url = input("Paste the full callback URL here: ") + + # Step 4: Exchange code for tokens + tokens = auth.fetch_token(authorization_response=callback_url) + access_token = tokens["access_token"] + + # Step 5: Create client + client = Client(access_token=access_token) + + # Step 6: Send one-to-one DM + payload = {"text": text_message} + response = client.direct_messages.create_by_participant_id(participant_id, body=payload) + + print("Response code: 201") + print(json.dumps(response.data, indent=4, sort_keys=True)) if __name__ == "__main__": main() diff --git a/python/direct_messages/send.py b/python/direct_messages/send.py deleted file mode 100644 index 9299385..0000000 --- a/python/direct_messages/send.py +++ /dev/null @@ -1,82 +0,0 @@ -""" -Send Direct Message - X API v2 -============================== -Endpoint: POST https://api.x.com/2/dm_conversations/with/:participant_id/messages -Docs: https://developer.x.com/en/docs/twitter-api/direct-messages/manage/api-reference/post-dm-conversations-with-participant_id-messages - -Authentication: OAuth 1.0a or OAuth 2.0 (User Context) -Required env vars: CONSUMER_KEY, CONSUMER_SECRET -""" - -from requests_oauthlib import OAuth1Session -import os -import json - -consumer_key = os.environ.get("CONSUMER_KEY") -consumer_secret = os.environ.get("CONSUMER_SECRET") - -# Replace with the user ID you want to send a DM to -participant_id = "recipient-user-id" - -# Message content -payload = {"text": "Hello! This is a test message."} - -# Get request token -request_token_url = "https://api.x.com/oauth/request_token" -oauth = OAuth1Session(consumer_key, client_secret=consumer_secret) - -try: - fetch_response = oauth.fetch_request_token(request_token_url) -except ValueError: - print( - "There may have been an issue with the consumer_key or consumer_secret you entered." - ) - -resource_owner_key = fetch_response.get("oauth_token") -resource_owner_secret = fetch_response.get("oauth_token_secret") -print("Got OAuth token: %s" % resource_owner_key) - -# Get authorization -base_authorization_url = "https://api.x.com/oauth/authorize" -authorization_url = oauth.authorization_url(base_authorization_url) -print("Please go here and authorize: %s" % authorization_url) -verifier = input("Paste the PIN here: ") - -# Get the access token -access_token_url = "https://api.x.com/oauth/access_token" -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=resource_owner_key, - resource_owner_secret=resource_owner_secret, - verifier=verifier, -) -oauth_tokens = oauth.fetch_access_token(access_token_url) - -access_token = oauth_tokens["oauth_token"] -access_token_secret = oauth_tokens["oauth_token_secret"] - -# Make the request -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=access_token, - resource_owner_secret=access_token_secret, -) - -# Making the request -response = oauth.post( - "https://api.x.com/2/dm_conversations/with/{}/messages".format(participant_id), - json=payload -) - -if response.status_code != 201: - raise Exception( - "Request returned an error: {} {}".format(response.status_code, response.text) - ) - -print("Response code: {}".format(response.status_code)) - -# Saving the response as JSON -json_response = response.json() -print(json.dumps(json_response, indent=4, sort_keys=True)) diff --git a/python/lists/List-Tweets.py b/python/lists/List-Tweets.py deleted file mode 100644 index dca8430..0000000 --- a/python/lists/List-Tweets.py +++ /dev/null @@ -1,55 +0,0 @@ -import requests -import os -import json - -# To set your enviornment variables in your terminal run the following line: -# export 'BEARER_TOKEN'='' -bearer_token = os.environ.get("BEARER_TOKEN") - - -def create_url(): - # Tweet fields are adjustable. - # Options include: - # attachments, author_id, context_annotations, - # conversation_id, created_at, entities, geo, id, - # in_reply_to_user_id, lang, non_public_metrics, organic_metrics, - # possibly_sensitive, promoted_metrics, public_metrics, referenced_tweets, - # source, text, and withheld - tweet_fields = "tweet.fields=lang,author_id" - # Be sure to replace list-id with any List ID - id = "list-id" - url = "https://api.x.com/2/lists/{}/tweets".format(id) - return url, tweet_fields - - -def bearer_oauth(r): - """ - Method required by bearer token authentication. - """ - - r.headers["Authorization"] = f"Bearer {bearer_token}" - r.headers["User-Agent"] = "v2ListTweetsLookupPython" - return r - - -def connect_to_endpoint(url, tweet_fields): - response = requests.request( - "GET", url, auth=bearer_oauth, params=tweet_fields) - print(response.status_code) - if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format( - response.status_code, response.text - ) - ) - return response.json() - - -def main(): - url, tweet_fields = create_url() - json_response = connect_to_endpoint(url, tweet_fields) - print(json.dumps(json_response, indent=4, sort_keys=True)) - - -if __name__ == "__main__": - main() diff --git a/python/lists/Pinned-List.py b/python/lists/Pinned-List.py deleted file mode 100644 index 898d63f..0000000 --- a/python/lists/Pinned-List.py +++ /dev/null @@ -1,78 +0,0 @@ -from requests_oauthlib import OAuth1Session -import os -import json - -# In your terminal please set your environment variables by running the following lines of code. -# export 'CONSUMER_KEY'='' -# export 'CONSUMER_SECRET'='' - -consumer_key = os.environ.get("CONSUMER_KEY") -consumer_secret = os.environ.get("CONSUMER_SECRET") - - -# Be sure to replace your-user-id with your own user ID or one of an authenticating user -# You can find a user ID by using the user lookup endpoint -id = "your-user-id" - -# List fields are adjustable, options include: -# created_at, description, owner_id, -# private, follower_count, member_count, -list_fields = "list.fields=created_at,description,private" - -# Get request token -request_token_url = "https://api.x.com/oauth/request_token" -oauth = OAuth1Session(consumer_key, client_secret=consumer_secret) - -try: - fetch_response = oauth.fetch_request_token(request_token_url) -except ValueError: - print( - "There may have been an issue with the consumer_key or consumer_secret you entered." - ) - -resource_owner_key = fetch_response.get("oauth_token") -resource_owner_secret = fetch_response.get("oauth_token_secret") -print("Got OAuth token: %s" % resource_owner_key) - -# Get authorization -base_authorization_url = "https://api.x.com/oauth/authorize" -authorization_url = oauth.authorization_url(base_authorization_url) -print("Please go here and authorize: %s" % authorization_url) -verifier = input("Paste the PIN here: ") - -# Get the access token -access_token_url = "https://api.x.com/oauth/access_token" -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=resource_owner_key, - resource_owner_secret=resource_owner_secret, - verifier=verifier, -) -oauth_tokens = oauth.fetch_access_token(access_token_url) - -access_token = oauth_tokens["oauth_token"] -access_token_secret = oauth_tokens["oauth_token_secret"] - -# Make the request -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=access_token, - resource_owner_secret=access_token_secret, -) - -# Making the request -response = oauth.get( - "https://api.x.com/2/users/{}/pinned_lists".format(id), params=list_fields) - -if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format(response.status_code, response.text) - ) - -print("Response code: {}".format(response.status_code)) - -# Saving the response as JSON -json_response = response.json() -print(json.dumps(json_response, indent=4, sort_keys=True)) diff --git a/python/lists/add_list_member.py b/python/lists/add_list_member.py new file mode 100644 index 0000000..caf5359 --- /dev/null +++ b/python/lists/add_list_member.py @@ -0,0 +1,67 @@ +""" +Add List Member - X API v2 +========================== +Endpoint: POST https://api.x.com/2/lists/:id/members +Docs: https://developer.x.com/en/docs/twitter-api/lists/list-members/api-reference/post-lists-id-members + +Authentication: OAuth 2.0 (User Context) +Required env vars: CLIENT_ID, CLIENT_SECRET +""" + +import os +import json +from xdk import Client +from xdk.oauth2_auth import OAuth2PKCEAuth + +# The code below sets the client ID and client secret from your environment variables +# To set environment variables on macOS or Linux, run the export commands below from the terminal: +# export CLIENT_ID='YOUR-CLIENT-ID' +# export CLIENT_SECRET='YOUR-CLIENT-SECRET' +client_id = os.environ.get("CLIENT_ID") +client_secret = os.environ.get("CLIENT_SECRET") + +# Replace the following URL with your callback URL, which can be obtained from your App's auth settings. +redirect_uri = "https://example.com" + +# Set the scopes +scopes = ["tweet.read", "users.read", "list.read", "list.write", "offline.access"] + +# Be sure to replace your-list-id with your own list ID or one of an authenticated user +list_id = "your-list-id" + +# Be sure to replace user-id-to-add with the user id you wish to add. +user_id = "user-id-to-add" + +def main(): + # Step 1: Create PKCE instance + auth = OAuth2PKCEAuth( + client_id=client_id, + client_secret=client_secret, + redirect_uri=redirect_uri, + scope=scopes + ) + + # Step 2: Get authorization URL + auth_url = auth.get_authorization_url() + print("Visit the following URL to authorize your App on behalf of your X handle in a browser:") + print(auth_url) + + # Step 3: Handle callback + callback_url = input("Paste the full callback URL here: ") + + # Step 4: Exchange code for tokens + tokens = auth.fetch_token(authorization_response=callback_url) + access_token = tokens["access_token"] + + # Step 5: Create client + client = Client(access_token=access_token) + + # Step 6: Add member to list + payload = {"user_id": user_id} + response = client.lists.add_member(list_id, body=payload) + + print("Response code: 200") + print(json.dumps(response.data, indent=4, sort_keys=True)) + +if __name__ == "__main__": + main() diff --git a/python/lists/add_member.py b/python/lists/add_member.py deleted file mode 100644 index fe985f1..0000000 --- a/python/lists/add_member.py +++ /dev/null @@ -1,77 +0,0 @@ -from requests_oauthlib import OAuth1Session -import os -import json - -# In your terminal please set your environment variables by running the following lines of code. -# export 'CONSUMER_KEY'='' -# export 'CONSUMER_SECRET'='' - -consumer_key = os.environ.get("CONSUMER_KEY") -consumer_secret = os.environ.get("CONSUMER_SECRET") - - -# Be sure to replace your-list-id with your own list ID or one of an authenticating user - -id = "your-list-id" - -# Be sure to replace user-id-to-add with the user id you wish to add. -payload = {"user_id": "user-id-to-add"} - -# Get request token -request_token_url = "https://api.x.com/oauth/request_token" -oauth = OAuth1Session(consumer_key, client_secret=consumer_secret) - -try: - fetch_response = oauth.fetch_request_token(request_token_url) -except ValueError: - print( - "There may have been an issue with the consumer_key or consumer_secret you entered." - ) - -resource_owner_key = fetch_response.get("oauth_token") -resource_owner_secret = fetch_response.get("oauth_token_secret") -print("Got OAuth token: %s" % resource_owner_key) - -# Get authorization -base_authorization_url = "https://api.x.com/oauth/authorize" -authorization_url = oauth.authorization_url(base_authorization_url) -print("Please go here and authorize: %s" % authorization_url) -verifier = input("Paste the PIN here: ") - -# Get the access token -access_token_url = "https://api.x.com/oauth/access_token" -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=resource_owner_key, - resource_owner_secret=resource_owner_secret, - verifier=verifier, -) -oauth_tokens = oauth.fetch_access_token(access_token_url) - -access_token = oauth_tokens["oauth_token"] -access_token_secret = oauth_tokens["oauth_token_secret"] - -# Make the request -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=access_token, - resource_owner_secret=access_token_secret, -) - -# Making the request -response = oauth.post( - "https://api.x.com/2/lists/{}/members".format(id), json=payload -) - -if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format(response.status_code, response.text) - ) - -print("Response code: {}".format(response.status_code)) - -# Saving the response as JSON -json_response = response.json() -print(json.dumps(json_response, indent=4, sort_keys=True)) diff --git a/python/lists/create.py b/python/lists/create.py deleted file mode 100644 index cd51ff4..0000000 --- a/python/lists/create.py +++ /dev/null @@ -1,80 +0,0 @@ -""" -Create List - X API v2 -====================== -Endpoint: POST https://api.x.com/2/lists -Docs: https://developer.x.com/en/docs/twitter-api/lists/manage-lists/api-reference/post-lists - -Authentication: OAuth 1.0a (User Context) -Required env vars: CONSUMER_KEY, CONSUMER_SECRET -""" - -from requests_oauthlib import OAuth1Session -import os -import json - -consumer_key = os.environ.get("CONSUMER_KEY") -consumer_secret = os.environ.get("CONSUMER_SECRET") - -# List parameters -payload = { - "name": "My new list", - "description": "A description for my list", - "private": False -} - -# Get request token -request_token_url = "https://api.x.com/oauth/request_token" -oauth = OAuth1Session(consumer_key, client_secret=consumer_secret) - -try: - fetch_response = oauth.fetch_request_token(request_token_url) -except ValueError: - print( - "There may have been an issue with the consumer_key or consumer_secret you entered." - ) - -resource_owner_key = fetch_response.get("oauth_token") -resource_owner_secret = fetch_response.get("oauth_token_secret") -print("Got OAuth token: %s" % resource_owner_key) - -# Get authorization -base_authorization_url = "https://api.x.com/oauth/authorize" -authorization_url = oauth.authorization_url(base_authorization_url) -print("Please go here and authorize: %s" % authorization_url) -verifier = input("Paste the PIN here: ") - -# Get the access token -access_token_url = "https://api.x.com/oauth/access_token" -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=resource_owner_key, - resource_owner_secret=resource_owner_secret, - verifier=verifier, -) -oauth_tokens = oauth.fetch_access_token(access_token_url) - -access_token = oauth_tokens["oauth_token"] -access_token_secret = oauth_tokens["oauth_token_secret"] - -# Make the request -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=access_token, - resource_owner_secret=access_token_secret, -) - -# Making the request -response = oauth.post("https://api.x.com/2/lists", json=payload) - -if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format(response.status_code, response.text) - ) - -print("Response code: {}".format(response.status_code)) - -# Saving the response as JSON -json_response = response.json() -print(json.dumps(json_response, indent=4, sort_keys=True)) diff --git a/python/lists/create_a_list.py b/python/lists/create_a_list.py deleted file mode 100644 index cb4d5b0..0000000 --- a/python/lists/create_a_list.py +++ /dev/null @@ -1,76 +0,0 @@ -from requests_oauthlib import OAuth1Session -import os -import json - -# In your terminal please set your environment variables by running the following lines of code. -# export 'CONSUMER_KEY'='' -# export 'CONSUMER_SECRET'='' - -consumer_key = os.environ.get("CONSUMER_KEY") -consumer_secret = os.environ.get("CONSUMER_SECRET") - - -# Be sure to add replace name-of-list with the name you wish to call the list. -# description and private keys are optional -payload = { "name": "name-of-list", - "description": "description-of-list", - "private": False} - -# Get request token -request_token_url = "https://api.x.com/oauth/request_token" -oauth = OAuth1Session(consumer_key, client_secret=consumer_secret) - -try: - fetch_response = oauth.fetch_request_token(request_token_url) -except ValueError: - print( - "There may have been an issue with the consumer_key or consumer_secret you entered." - ) - -resource_owner_key = fetch_response.get("oauth_token") -resource_owner_secret = fetch_response.get("oauth_token_secret") -print("Got OAuth token: %s" % resource_owner_key) - -# Get authorization -base_authorization_url = "https://api.x.com/oauth/authorize" -authorization_url = oauth.authorization_url(base_authorization_url) -print("Please go here and authorize: %s" % authorization_url) -verifier = input("Paste the PIN here: ") - -# Get the access token -access_token_url = "https://api.x.com/oauth/access_token" -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=resource_owner_key, - resource_owner_secret=resource_owner_secret, - verifier=verifier, -) -oauth_tokens = oauth.fetch_access_token(access_token_url) - -access_token = oauth_tokens["oauth_token"] -access_token_secret = oauth_tokens["oauth_token_secret"] - -# Make the request -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=access_token, - resource_owner_secret=access_token_secret, -) - -# Making the request -response = oauth.post( - "https://api.x.com/2/lists", json=payload -) - -if response.status_code != 201: - raise Exception( - "Request returned an error: {} {}".format(response.status_code, response.text) - ) - -print("Response code: {}".format(response.status_code)) - -# Saving the response as JSON -json_response = response.json() -print(json.dumps(json_response, indent=4, sort_keys=True)) diff --git a/python/lists/create_list.py b/python/lists/create_list.py new file mode 100644 index 0000000..0cdb4e3 --- /dev/null +++ b/python/lists/create_list.py @@ -0,0 +1,68 @@ +""" +Create List - X API v2 +====================== +Endpoint: POST https://api.x.com/2/lists +Docs: https://developer.x.com/en/docs/twitter-api/lists/manage-lists/api-reference/post-lists + +Authentication: OAuth 2.0 (User Context) +Required env vars: CLIENT_ID, CLIENT_SECRET +""" + +import os +import json +from xdk import Client +from xdk.oauth2_auth import OAuth2PKCEAuth + +# The code below sets the client ID and client secret from your environment variables +# To set environment variables on macOS or Linux, run the export commands below from the terminal: +# export CLIENT_ID='YOUR-CLIENT-ID' +# export CLIENT_SECRET='YOUR-CLIENT-SECRET' +client_id = os.environ.get("CLIENT_ID") +client_secret = os.environ.get("CLIENT_SECRET") + +# Replace the following URL with your callback URL, which can be obtained from your App's auth settings. +redirect_uri = "https://example.com" + +# Set the scopes +scopes = ["tweet.read", "users.read", "list.read", "list.write", "offline.access"] + +# Be sure to replace name-of-list with the name you wish to call the list. +# description and private keys are optional +payload = { + "name": "name-of-list", + "description": "description-of-list", + "private": False +} + +def main(): + # Step 1: Create PKCE instance + auth = OAuth2PKCEAuth( + client_id=client_id, + client_secret=client_secret, + redirect_uri=redirect_uri, + scope=scopes + ) + + # Step 2: Get authorization URL + auth_url = auth.get_authorization_url() + print("Visit the following URL to authorize your App on behalf of your X handle in a browser:") + print(auth_url) + + # Step 3: Handle callback + callback_url = input("Paste the full callback URL here: ") + + # Step 4: Exchange code for tokens + tokens = auth.fetch_token(authorization_response=callback_url) + access_token = tokens["access_token"] + + # Step 5: Create client + client = Client(access_token=access_token) + + # Step 6: Create the list + response = client.lists.create(body=payload) + + print("Response code: 201") + print(json.dumps(response.data, indent=4, sort_keys=True)) + +if __name__ == "__main__": + main() diff --git a/python/lists/delete.py b/python/lists/delete.py deleted file mode 100644 index 6d0b4ec..0000000 --- a/python/lists/delete.py +++ /dev/null @@ -1,76 +0,0 @@ -""" -Delete List - X API v2 -====================== -Endpoint: DELETE https://api.x.com/2/lists/:id -Docs: https://developer.x.com/en/docs/twitter-api/lists/manage-lists/api-reference/delete-lists-id - -Authentication: OAuth 1.0a (User Context) -Required env vars: CONSUMER_KEY, CONSUMER_SECRET -""" - -from requests_oauthlib import OAuth1Session -import os -import json - -consumer_key = os.environ.get("CONSUMER_KEY") -consumer_secret = os.environ.get("CONSUMER_SECRET") - -# Replace with the list ID you want to delete -list_id = "list-id-to-delete" - -# Get request token -request_token_url = "https://api.x.com/oauth/request_token" -oauth = OAuth1Session(consumer_key, client_secret=consumer_secret) - -try: - fetch_response = oauth.fetch_request_token(request_token_url) -except ValueError: - print( - "There may have been an issue with the consumer_key or consumer_secret you entered." - ) - -resource_owner_key = fetch_response.get("oauth_token") -resource_owner_secret = fetch_response.get("oauth_token_secret") -print("Got OAuth token: %s" % resource_owner_key) - -# Get authorization -base_authorization_url = "https://api.x.com/oauth/authorize" -authorization_url = oauth.authorization_url(base_authorization_url) -print("Please go here and authorize: %s" % authorization_url) -verifier = input("Paste the PIN here: ") - -# Get the access token -access_token_url = "https://api.x.com/oauth/access_token" -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=resource_owner_key, - resource_owner_secret=resource_owner_secret, - verifier=verifier, -) -oauth_tokens = oauth.fetch_access_token(access_token_url) - -access_token = oauth_tokens["oauth_token"] -access_token_secret = oauth_tokens["oauth_token_secret"] - -# Make the request -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=access_token, - resource_owner_secret=access_token_secret, -) - -# Making the request -response = oauth.delete("https://api.x.com/2/lists/{}".format(list_id)) - -if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format(response.status_code, response.text) - ) - -print("Response code: {}".format(response.status_code)) - -# Saving the response as JSON -json_response = response.json() -print(json.dumps(json_response, indent=4, sort_keys=True)) diff --git a/python/lists/delete_a_list.py b/python/lists/delete_a_list.py deleted file mode 100644 index c00bded..0000000 --- a/python/lists/delete_a_list.py +++ /dev/null @@ -1,75 +0,0 @@ -from requests_oauthlib import OAuth1Session -import os -import json - -# In your terminal please set your environment variables by running the following lines of code. -# export 'CONSUMER_KEY'='' -# export 'CONSUMER_SECRET'='' - -consumer_key = os.environ.get("CONSUMER_KEY") -consumer_secret = os.environ.get("CONSUMER_SECRET") - - -# Be sure to replace your-list-id with the id of the list you wish to delete. The authenticated user must own the list in order to delete - -id = "your-list-id" - - -# Get request token -request_token_url = "https://api.x.com/oauth/request_token" -oauth = OAuth1Session(consumer_key, client_secret=consumer_secret) - -try: - fetch_response = oauth.fetch_request_token(request_token_url) -except ValueError: - print( - "There may have been an issue with the consumer_key or consumer_secret you entered." - ) - -resource_owner_key = fetch_response.get("oauth_token") -resource_owner_secret = fetch_response.get("oauth_token_secret") -print("Got OAuth token: %s" % resource_owner_key) - -# Get authorization -base_authorization_url = "https://api.x.com/oauth/authorize" -authorization_url = oauth.authorization_url(base_authorization_url) -print("Please go here and authorize: %s" % authorization_url) -verifier = input("Paste the PIN here: ") - -# Get the access token -access_token_url = "https://api.x.com/oauth/access_token" -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=resource_owner_key, - resource_owner_secret=resource_owner_secret, - verifier=verifier, -) -oauth_tokens = oauth.fetch_access_token(access_token_url) - -access_token = oauth_tokens["oauth_token"] -access_token_secret = oauth_tokens["oauth_token_secret"] - -# Make the request -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=access_token, - resource_owner_secret=access_token_secret, -) - -# Making the request -response = oauth.delete( - "https://api.x.com/2/lists/{}".format(id) -) - -if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format(response.status_code, response.text) - ) - -print("Response code: {}".format(response.status_code)) - -# Saving the response as JSON -json_response = response.json() -print(json.dumps(json_response, indent=4, sort_keys=True)) diff --git a/python/lists/delete_list.py b/python/lists/delete_list.py new file mode 100644 index 0000000..927b67c --- /dev/null +++ b/python/lists/delete_list.py @@ -0,0 +1,64 @@ +""" +Delete List - X API v2 +====================== +Endpoint: DELETE https://api.x.com/2/lists/:id +Docs: https://developer.x.com/en/docs/twitter-api/lists/manage-lists/api-reference/delete-lists-id + +Authentication: OAuth 2.0 (User Context) +Required env vars: CLIENT_ID, CLIENT_SECRET +""" + +import os +import json +from xdk import Client +from xdk.oauth2_auth import OAuth2PKCEAuth + +# The code below sets the client ID and client secret from your environment variables +# To set environment variables on macOS or Linux, run the export commands below from the terminal: +# export CLIENT_ID='YOUR-CLIENT-ID' +# export CLIENT_SECRET='YOUR-CLIENT-SECRET' +client_id = os.environ.get("CLIENT_ID") +client_secret = os.environ.get("CLIENT_SECRET") + +# Replace the following URL with your callback URL, which can be obtained from your App's auth settings. +redirect_uri = "https://example.com" + +# Set the scopes +scopes = ["tweet.read", "users.read", "list.read", "list.write", "offline.access"] + +# Be sure to replace your-list-id with the id of the list you wish to delete. +# The authenticated user must own the list in order to delete it. +list_id = "your-list-id" + +def main(): + # Step 1: Create PKCE instance + auth = OAuth2PKCEAuth( + client_id=client_id, + client_secret=client_secret, + redirect_uri=redirect_uri, + scope=scopes + ) + + # Step 2: Get authorization URL + auth_url = auth.get_authorization_url() + print("Visit the following URL to authorize your App on behalf of your X handle in a browser:") + print(auth_url) + + # Step 3: Handle callback + callback_url = input("Paste the full callback URL here: ") + + # Step 4: Exchange code for tokens + tokens = auth.fetch_token(authorization_response=callback_url) + access_token = tokens["access_token"] + + # Step 5: Create client + client = Client(access_token=access_token) + + # Step 6: Delete the list + response = client.lists.delete_list(list_id) + + print("Response code: 200") + print(json.dumps(response.data, indent=4, sort_keys=True)) + +if __name__ == "__main__": + main() diff --git a/python/lists/follow_list.py b/python/lists/follow_list.py index d52adc0..bafb9e3 100644 --- a/python/lists/follow_list.py +++ b/python/lists/follow_list.py @@ -1,77 +1,68 @@ -from requests_oauthlib import OAuth1Session +""" +Follow List - X API v2 +===================== +Endpoint: POST https://api.x.com/2/users/:id/followed_lists +Docs: https://developer.x.com/en/docs/twitter-api/lists/list-follows/api-reference/post-users-id-followed_lists + +Authentication: OAuth 2.0 (User Context) +Required env vars: CLIENT_ID, CLIENT_SECRET +""" + import os import json +from xdk import Client +from xdk.oauth2_auth import OAuth2PKCEAuth -# In your terminal please set your environment variables by running the following lines of code. -# export 'CONSUMER_KEY'='' -# export 'CONSUMER_SECRET'='' +# The code below sets the client ID and client secret from your environment variables +# To set environment variables on macOS or Linux, run the export commands below from the terminal: +# export CLIENT_ID='YOUR-CLIENT-ID' +# export CLIENT_SECRET='YOUR-CLIENT-SECRET' +client_id = os.environ.get("CLIENT_ID") +client_secret = os.environ.get("CLIENT_SECRET") -consumer_key = os.environ.get("CONSUMER_KEY") -consumer_secret = os.environ.get("CONSUMER_SECRET") +# Replace the following URL with your callback URL, which can be obtained from your App's auth settings. +redirect_uri = "https://example.com" +# Set the scopes +scopes = ["tweet.read", "users.read", "list.read", "list.write", "offline.access"] -# Be sure to replace your-user-id with your own user ID or one of an authenticating user +# Be sure to replace your-user-id with your own user ID or one of an authenticated user # You can find a user ID by using the user lookup endpoint -id = "your-user-id" - -# Be sure to add replace list-id-to-follow with the list id you wish to follow. -payload = {"list_id": "list-id-to-follow"} - -# Get request token -request_token_url = "https://api.x.com/oauth/request_token" -oauth = OAuth1Session(consumer_key, client_secret=consumer_secret) - -try: - fetch_response = oauth.fetch_request_token(request_token_url) -except ValueError: - print( - "There may have been an issue with the consumer_key or consumer_secret you entered." +user_id = "your-user-id" + +# Be sure to replace list-id-to-follow with the list id you wish to follow. +list_id = "list-id-to-follow" + +def main(): + # Step 1: Create PKCE instance + auth = OAuth2PKCEAuth( + client_id=client_id, + client_secret=client_secret, + redirect_uri=redirect_uri, + scope=scopes ) - -resource_owner_key = fetch_response.get("oauth_token") -resource_owner_secret = fetch_response.get("oauth_token_secret") -print("Got OAuth token: %s" % resource_owner_key) - -# Get authorization -base_authorization_url = "https://api.x.com/oauth/authorize" -authorization_url = oauth.authorization_url(base_authorization_url) -print("Please go here and authorize: %s" % authorization_url) -verifier = input("Paste the PIN here: ") - -# Get the access token -access_token_url = "https://api.x.com/oauth/access_token" -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=resource_owner_key, - resource_owner_secret=resource_owner_secret, - verifier=verifier, -) -oauth_tokens = oauth.fetch_access_token(access_token_url) - -access_token = oauth_tokens["oauth_token"] -access_token_secret = oauth_tokens["oauth_token_secret"] - -# Make the request -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=access_token, - resource_owner_secret=access_token_secret, -) - -# Making the request -response = oauth.post( - "https://api.x.com/2/users/{}/followed_lists".format(id), json=payload -) - -if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format(response.status_code, response.text) - ) - -print("Response code: {}".format(response.status_code)) - -# Saving the response as JSON -json_response = response.json() -print(json.dumps(json_response, indent=4, sort_keys=True)) + + # Step 2: Get authorization URL + auth_url = auth.get_authorization_url() + print("Visit the following URL to authorize your App on behalf of your X handle in a browser:") + print(auth_url) + + # Step 3: Handle callback + callback_url = input("Paste the full callback URL here: ") + + # Step 4: Exchange code for tokens + tokens = auth.fetch_token(authorization_response=callback_url) + access_token = tokens["access_token"] + + # Step 5: Create client + client = Client(access_token=access_token) + + # Step 6: Follow the list + payload = {"list_id": list_id} + response = client.users.follow_list(user_id, body=payload) + + print("Response code: 200") + print(json.dumps(response.data, indent=4, sort_keys=True)) + +if __name__ == "__main__": + main() diff --git a/python/lists/get_followed_lists.py b/python/lists/get_followed_lists.py new file mode 100644 index 0000000..f046587 --- /dev/null +++ b/python/lists/get_followed_lists.py @@ -0,0 +1,42 @@ +""" +User Followed Lists Lookup - X API v2 +====================================== +Endpoint: GET https://api.x.com/2/users/:id/followed_lists +Docs: https://developer.x.com/en/docs/twitter-api/lists/list-follows/api-reference/get-users-id-followed_lists + +Authentication: Bearer Token (App-only) or OAuth (User Context) +Required env vars: BEARER_TOKEN +""" + +import os +import json +from xdk import Client + +bearer_token = os.environ.get("BEARER_TOKEN") +client = Client(bearer_token=bearer_token) + +# You can replace the user-id with any valid User ID you wish to find what Lists they are following. +user_id = "user-id" + +def main(): + # Get user followed lists with automatic pagination + # List fields are adjustable, options include: + # created_at, description, owner_id, + # private, follower_count, member_count, + all_lists = [] + for page in client.users.get_followed_lists( + user_id, + max_results=100, + list_fields=["created_at", "follower_count"] + ): + # Access data attribute (model uses extra='allow' so data should be available) + # Use getattr with fallback in case data field is missing from response + page_data = getattr(page, 'data', []) or [] + all_lists.extend(page_data) + print(f"Fetched {len(page_data)} lists (total: {len(all_lists)})") + + print(f"\nTotal Followed Lists: {len(all_lists)}") + print(json.dumps({"data": all_lists[:5]}, indent=4, sort_keys=True)) # Print first 5 as example + +if __name__ == "__main__": + main() diff --git a/python/lists/get_list_by_id.py b/python/lists/get_list_by_id.py new file mode 100644 index 0000000..d52df4d --- /dev/null +++ b/python/lists/get_list_by_id.py @@ -0,0 +1,35 @@ +""" +List Lookup by ID - X API v2 +============================= +Endpoint: GET https://api.x.com/2/lists/:id +Docs: https://developer.x.com/en/docs/twitter-api/lists/list-lookup/api-reference/get-lists-id + +Authentication: Bearer Token (App-only) or OAuth (User Context) +Required env vars: BEARER_TOKEN +""" + +import os +import json +from xdk import Client + +bearer_token = os.environ.get("BEARER_TOKEN") +if not bearer_token: + raise ValueError("BEARER_TOKEN environment variable is not set") + +client = Client(bearer_token=bearer_token) + +# You can replace the ID given with the List ID you wish to lookup. +list_id = "list-id" + +def main(): + # List fields are adjustable. Options include: + # created_at, follower_count, member_count, private, description, owner_id + response = client.lists.get_by_id( + list_id, + list_fields=["created_at", "follower_count", "member_count", "owner_id", "description"] + ) + + print(json.dumps(response.data, indent=4, sort_keys=True)) + +if __name__ == "__main__": + main() diff --git a/python/lists/get_list_followers.py b/python/lists/get_list_followers.py new file mode 100644 index 0000000..a2892ce --- /dev/null +++ b/python/lists/get_list_followers.py @@ -0,0 +1,47 @@ +""" +List Followers Lookup - X API v2 +================================= +Endpoint: GET https://api.x.com/2/lists/:id/followers +Docs: https://developer.x.com/en/docs/twitter-api/lists/list-follows/api-reference/get-lists-id-followers + +Authentication: Bearer Token (App-only) or OAuth (User Context) +Required env vars: BEARER_TOKEN +""" + +import os +import json +from xdk import Client + +bearer_token = os.environ.get("BEARER_TOKEN") +if not bearer_token: + raise ValueError("BEARER_TOKEN environment variable is not set") + +client = Client(bearer_token=bearer_token) + +# You can replace list-id with the List ID you wish to find followers of. +# Note: Private lists require OAuth 2.0 user context authentication. +list_id = "list-id" + +def main(): + # Get list followers with automatic pagination + # User fields are adjustable, options include: + # created_at, description, entities, id, location, name, + # pinned_tweet_id, profile_image_url, protected, + # public_metrics, url, username, verified, and withheld + all_users = [] + for page in client.lists.get_followers( + list_id, + max_results=100, + user_fields=["created_at", "description", "verified"] + ): + # Access data attribute (model uses extra='allow' so data should be available) + # Use getattr with fallback in case data field is missing from response + page_data = getattr(page, 'data', []) or [] + all_users.extend(page_data) + print(f"Fetched {len(page_data)} users (total: {len(all_users)})") + + print(f"\nTotal Followers: {len(all_users)}") + print(json.dumps({"data": all_users[:5]}, indent=4, sort_keys=True)) # Print first 5 as example + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/python/lists/get_list_members.py b/python/lists/get_list_members.py new file mode 100644 index 0000000..1654040 --- /dev/null +++ b/python/lists/get_list_members.py @@ -0,0 +1,43 @@ +""" +List Members Lookup - X API v2 +============================== +Endpoint: GET https://api.x.com/2/lists/:id/members +Docs: https://developer.x.com/en/docs/twitter-api/lists/list-members/api-reference/get-lists-id-members + +Authentication: Bearer Token (App-only) or OAuth (User Context) +Required env vars: BEARER_TOKEN +""" + +import os +import json +from xdk import Client + +bearer_token = os.environ.get("BEARER_TOKEN") +client = Client(bearer_token=bearer_token) + +# You can replace list-id with the List ID you wish to find members of. +list_id = "list-id" + +def main(): + # Get list members with automatic pagination + # User fields are adjustable, options include: + # created_at, description, entities, id, location, name, + # pinned_tweet_id, profile_image_url, protected, + # public_metrics, url, username, verified, and withheld + all_users = [] + for page in client.lists.get_members( + list_id, + max_results=100, + user_fields=["created_at", "description", "verified"] + ): + # Access data attribute (model uses extra='allow' so data should be available) + # Use getattr with fallback in case data field is missing from response + page_data = getattr(page, 'data', []) or [] + all_users.extend(page_data) + print(f"Fetched {len(page_data)} users (total: {len(all_users)})") + + print(f"\nTotal Members: {len(all_users)}") + print(json.dumps({"data": all_users[:5]}, indent=4, sort_keys=True)) # Print first 5 as example + +if __name__ == "__main__": + main() diff --git a/python/lists/get_list_memberships.py b/python/lists/get_list_memberships.py new file mode 100644 index 0000000..f37b604 --- /dev/null +++ b/python/lists/get_list_memberships.py @@ -0,0 +1,42 @@ +""" +User List Memberships Lookup - X API v2 +======================================= +Endpoint: GET https://api.x.com/2/users/:id/list_memberships +Docs: https://developer.x.com/en/docs/twitter-api/lists/list-members/api-reference/get-users-id-list_memberships + +Authentication: Bearer Token (App-only) or OAuth (User Context) +Required env vars: BEARER_TOKEN +""" + +import os +import json +from xdk import Client + +bearer_token = os.environ.get("BEARER_TOKEN") +client = Client(bearer_token=bearer_token) + +# You can replace the user-id with any valid User ID you wish to find what Lists they are members of. +user_id = "user-id" + +def main(): + # Get user list memberships with automatic pagination + # List fields are adjustable, options include: + # created_at, description, owner_id, + # private, follower_count, member_count, + all_lists = [] + for page in client.users.get_list_memberships( + user_id, + max_results=100, + list_fields=["created_at", "follower_count"] + ): + # Access data attribute (model uses extra='allow' so data should be available) + # Use getattr with fallback in case data field is missing from response + page_data = getattr(page, 'data', []) or [] + all_lists.extend(page_data) + print(f"Fetched {len(page_data)} lists (total: {len(all_lists)})") + + print(f"\nTotal List Memberships: {len(all_lists)}") + print(json.dumps({"data": all_lists[:5]}, indent=4, sort_keys=True)) # Print first 5 as example + +if __name__ == "__main__": + main() diff --git a/python/lists/get_list_posts.py b/python/lists/get_list_posts.py new file mode 100644 index 0000000..283ef42 --- /dev/null +++ b/python/lists/get_list_posts.py @@ -0,0 +1,46 @@ +""" +List Tweets - X API v2 +====================== +Endpoint: GET https://api.x.com/2/lists/:id/tweets +Docs: https://developer.x.com/en/docs/twitter-api/lists/list-tweets/api-reference/get-lists-id-tweets + +Authentication: Bearer Token (App-only) or OAuth (User Context) +Required env vars: BEARER_TOKEN +""" + +import os +import json +from xdk import Client + +bearer_token = os.environ.get("BEARER_TOKEN") +client = Client(bearer_token=bearer_token) + +# Be sure to replace list-id with any List ID +list_id = "list-id" + +def main(): + # Get list tweets with automatic pagination + # Tweet fields are adjustable. + # Options include: + # attachments, author_id, context_annotations, + # conversation_id, created_at, entities, geo, id, + # in_reply_to_user_id, lang, non_public_metrics, organic_metrics, + # possibly_sensitive, promoted_metrics, public_metrics, referenced_tweets, + # source, text, and withheld + all_posts = [] + for page in client.lists.get_posts( + list_id, + max_results=100, + tweet_fields=["lang", "author_id"] + ): + # Access data attribute (model uses extra='allow' so data should be available) + # Use getattr with fallback in case data field is missing from response + page_data = getattr(page, 'data', []) or [] + all_posts.extend(page_data) + print(f"Fetched {len(page_data)} posts (total: {len(all_posts)})") + + print(f"\nTotal Posts: {len(all_posts)}") + print(json.dumps({"data": all_posts[:5]}, indent=4, sort_keys=True)) # Print first 5 as example + +if __name__ == "__main__": + main() diff --git a/python/lists/get_owned_lists.py b/python/lists/get_owned_lists.py new file mode 100644 index 0000000..88333dc --- /dev/null +++ b/python/lists/get_owned_lists.py @@ -0,0 +1,42 @@ +""" +User Owned Lists Lookup - X API v2 +=================================== +Endpoint: GET https://api.x.com/2/users/:id/owned_lists +Docs: https://developer.x.com/en/docs/twitter-api/lists/list-lookup/api-reference/get-users-id-owned_lists + +Authentication: Bearer Token (App-only) or OAuth (User Context) +Required env vars: BEARER_TOKEN +""" + +import os +import json +from xdk import Client + +bearer_token = os.environ.get("BEARER_TOKEN") +client = Client(bearer_token=bearer_token) + +# You can replace user-id with any valid User ID to see if they own any Lists. +user_id = "user-id" + +def main(): + # Get user owned lists with automatic pagination + # List fields are adjustable, options include: + # created_at, description, owner_id, + # private, follower_count, member_count, + all_lists = [] + for page in client.users.get_owned_lists( + user_id, + max_results=100, + list_fields=["created_at", "follower_count"] + ): + # Access data attribute (model uses extra='allow' so data should be available) + # Use getattr with fallback in case data field is missing from response + page_data = getattr(page, 'data', []) or [] + all_lists.extend(page_data) + print(f"Fetched {len(page_data)} lists (total: {len(all_lists)})") + + print(f"\nTotal Owned Lists: {len(all_lists)}") + print(json.dumps({"data": all_lists[:5]}, indent=4, sort_keys=True)) # Print first 5 as example + +if __name__ == "__main__": + main() diff --git a/python/lists/get_pinned_lists.py b/python/lists/get_pinned_lists.py new file mode 100644 index 0000000..6a0af67 --- /dev/null +++ b/python/lists/get_pinned_lists.py @@ -0,0 +1,77 @@ +""" +Pinned Lists Lookup - X API v2 +============================== +Endpoint: GET https://api.x.com/2/users/:id/pinned_lists +Docs: https://developer.x.com/en/docs/twitter-api/lists/pinned-lists/api-reference/get-users-id-pinned_lists + +Authentication: OAuth 2.0 (User Context) +Required env vars: CLIENT_ID, CLIENT_SECRET +""" + +import os +import json +from xdk import Client +from xdk.oauth2_auth import OAuth2PKCEAuth + +# The code below sets the client ID and client secret from your environment variables +# To set environment variables on macOS or Linux, run the export commands below from the terminal: +# export CLIENT_ID='YOUR-CLIENT-ID' +# export CLIENT_SECRET='YOUR-CLIENT-SECRET' +client_id = os.environ.get("CLIENT_ID") +client_secret = os.environ.get("CLIENT_SECRET") + +# Replace the following URL with your callback URL, which can be obtained from your App's auth settings. +redirect_uri = "https://example.com" + +# Set the scopes +scopes = ["tweet.read", "users.read", "list.read", "offline.access"] + +# Be sure to replace your-user-id with your own user ID or one of an authenticated user +# You can find a user ID by using the user lookup endpoint +user_id = "your-user-id" + +def main(): + # Step 1: Create PKCE instance + auth = OAuth2PKCEAuth( + client_id=client_id, + client_secret=client_secret, + redirect_uri=redirect_uri, + scope=scopes + ) + + # Step 2: Get authorization URL + auth_url = auth.get_authorization_url() + print("Visit the following URL to authorize your App on behalf of your X handle in a browser:") + print(auth_url) + + # Step 3: Handle callback + callback_url = input("Paste the full callback URL here: ") + + # Step 4: Exchange code for tokens + tokens = auth.fetch_token(authorization_response=callback_url) + access_token = tokens["access_token"] + + # Step 5: Create client + client = Client(access_token=access_token) + + # Step 6: Get pinned lists + # List fields are adjustable, options include: + # created_at, description, owner_id, + # private, follower_count, member_count, + response = client.users.get_pinned_lists( + user_id, + list_fields=["created_at", "description", "private"] + ) + + # Access data attribute (model uses extra='allow' so data should be available) + response_data = getattr(response, 'data', None) + if response_data is None: + # Try accessing via model_dump if data attribute doesn't exist + response_dict = response.model_dump() if hasattr(response, 'model_dump') else {} + response_data = response_dict.get('data', response_dict) + + print(f"Total Pinned Lists: {len(response_data) if isinstance(response_data, list) else 1}") + print(json.dumps(response_data, indent=4, sort_keys=True)) + +if __name__ == "__main__": + main() diff --git a/python/lists/list-followers-lookup.py b/python/lists/list-followers-lookup.py deleted file mode 100644 index 85566d0..0000000 --- a/python/lists/list-followers-lookup.py +++ /dev/null @@ -1,51 +0,0 @@ -import requests -import os -import json - -# To set your enviornment variables in your terminal run the following line: -# export 'BEARER_TOKEN'='' -bearer_token = os.environ.get("BEARER_TOKEN") - - -def create_url(): - # User fields are adjustable, options include: - # created_at, description, entities, id, location, name, - # pinned_tweet_id, profile_image_url, protected, - # public_metrics, url, username, verified, and withheld - user_fields = "user.fields=created_at,description,verified" - # You can replace list-id with the List ID you wish to find followers of. - id = "list-id" - url = "https://api.x.com/2/lists/{}/followers".format(id) - return url, user_fields - - -def bearer_oauth(r): - """ - Method required by bearer token authentication. - """ - - r.headers["Authorization"] = f"Bearer {bearer_token}" - r.headers["User-Agent"] = "v2ListFollowersLookupPython" - return r - - -def connect_to_endpoint(url, user_fields): - response = requests.request("GET", url, auth=bearer_oauth, params=user_fields) - print(response.status_code) - if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format( - response.status_code, response.text - ) - ) - return response.json() - - -def main(): - url, user_fields = create_url() - json_response = connect_to_endpoint(url, user_fields) - print(json.dumps(json_response, indent=4, sort_keys=True)) - - -if __name__ == "__main__": - main() diff --git a/python/lists/list-lookup-by-id.py b/python/lists/list-lookup-by-id.py deleted file mode 100644 index 6f47eff..0000000 --- a/python/lists/list-lookup-by-id.py +++ /dev/null @@ -1,50 +0,0 @@ -import requests -import os -import json - -# To set your enviornment variables in your terminal run the following line: -# export 'BEARER_TOKEN'='' -bearer_token = os.environ.get("BEARER_TOKEN") - - -def create_url(): - # List fields are adjustable, options include: - # created_at, description, owner_id, - # private, follower_count, member_count, - list_fields = "list.fields=created_at,follower_count" - # You can replace the ID given with the List ID you wish to lookup. - id = "list-id" - url = "https://api.x.com/2/lists/{}".format(id) - return url, list_fields - - -def bearer_oauth(r): - """ - Method required by bearer token authentication. - """ - - r.headers["Authorization"] = f"Bearer {bearer_token}" - r.headers["User-Agent"] = "v2ListLookupPython" - return r - - -def connect_to_endpoint(url, list_fields): - response = requests.request("GET", url, auth=bearer_oauth, params=list_fields) - print(response.status_code) - if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format( - response.status_code, response.text - ) - ) - return response.json() - - -def main(): - url, list_fields = create_url() - json_response = connect_to_endpoint(url, list_fields) - print(json.dumps(json_response, indent=4, sort_keys=True)) - - -if __name__ == "__main__": - main() diff --git a/python/lists/list-member-lookup.py b/python/lists/list-member-lookup.py deleted file mode 100644 index 0f10dd3..0000000 --- a/python/lists/list-member-lookup.py +++ /dev/null @@ -1,50 +0,0 @@ -import requests -import os -import json - -# To set your enviornment variables in your terminal run the following line: -# export 'BEARER_TOKEN'='' -bearer_token = os.environ.get("BEARER_TOKEN") - - -def create_url(): - # User fields are adjustable, options include: - # created_at, description, entities, id, location, name, - # pinned_tweet_id, profile_image_url, protected, - # public_metrics, url, username, verified, and withheld - user_fields = "user.fields=created_at,description,verified" - # You can replace list-id with the List ID you wish to find members of. - id = "list-id" - url = "https://api.x.com/2/lists/{}/members".format(id) - return url, user_fields - -def bearer_oauth(r): - """ - Method required by bearer token authentication. - """ - - r.headers["Authorization"] = f"Bearer {bearer_token}" - r.headers["User-Agent"] = "v2ListMembersLookupPython" - return r - - -def connect_to_endpoint(url, user_fields): - response = requests.request("GET", url, auth=bearer_oauth, params=user_fields) - print(response.status_code) - if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format( - response.status_code, response.text - ) - ) - return response.json() - - -def main(): - url, user_fields = create_url() - json_response = connect_to_endpoint(url, user_fields) - print(json.dumps(json_response, indent=4, sort_keys=True)) - - -if __name__ == "__main__": - main() diff --git a/python/lists/lookup.py b/python/lists/lookup.py deleted file mode 100644 index b736289..0000000 --- a/python/lists/lookup.py +++ /dev/null @@ -1,55 +0,0 @@ -""" -List Lookup - X API v2 -====================== -Endpoint: GET https://api.x.com/2/lists/:id -Docs: https://developer.x.com/en/docs/twitter-api/lists/list-lookup/api-reference/get-lists-id - -Authentication: Bearer Token (App-only) or OAuth (User Context) -Required env vars: BEARER_TOKEN -""" - -import requests -import os -import json - -bearer_token = os.environ.get("BEARER_TOKEN") - - -def create_url(): - # Replace with the list ID you want to look up - list_id = "84839422" - return "https://api.x.com/2/lists/{}".format(list_id) - - -def get_params(): - # List fields are adjustable. Options include: - # created_at, follower_count, member_count, private, description, owner_id - return {"list.fields": "created_at,follower_count,member_count,owner_id,description"} - - -def bearer_oauth(r): - """ - Method required by bearer token authentication. - """ - r.headers["Authorization"] = f"Bearer {bearer_token}" - r.headers["User-Agent"] = "v2ListLookupPython" - return r - - -def connect_to_endpoint(url, params): - response = requests.request("GET", url, auth=bearer_oauth, params=params) - print(response.status_code) - if response.status_code != 200: - raise Exception(response.status_code, response.text) - return response.json() - - -def main(): - url = create_url() - params = get_params() - json_response = connect_to_endpoint(url, params) - print(json.dumps(json_response, indent=4, sort_keys=True)) - - -if __name__ == "__main__": - main() diff --git a/python/lists/pin_list.py b/python/lists/pin_list.py index 20a03b4..f53952a 100644 --- a/python/lists/pin_list.py +++ b/python/lists/pin_list.py @@ -1,77 +1,68 @@ -from requests_oauthlib import OAuth1Session +""" +Pin List - X API v2 +================== +Endpoint: POST https://api.x.com/2/users/:id/pinned_lists +Docs: https://developer.x.com/en/docs/twitter-api/lists/pinned-lists/api-reference/post-users-id-pinned_lists + +Authentication: OAuth 2.0 (User Context) +Required env vars: CLIENT_ID, CLIENT_SECRET +""" + import os import json +from xdk import Client +from xdk.oauth2_auth import OAuth2PKCEAuth -# In your terminal please set your environment variables by running the following lines of code. -# export 'CONSUMER_KEY'='' -# export 'CONSUMER_SECRET'='' +# The code below sets the client ID and client secret from your environment variables +# To set environment variables on macOS or Linux, run the export commands below from the terminal: +# export CLIENT_ID='YOUR-CLIENT-ID' +# export CLIENT_SECRET='YOUR-CLIENT-SECRET' +client_id = os.environ.get("CLIENT_ID") +client_secret = os.environ.get("CLIENT_SECRET") -consumer_key = os.environ.get("CONSUMER_KEY") -consumer_secret = os.environ.get("CONSUMER_SECRET") +# Replace the following URL with your callback URL, which can be obtained from your App's auth settings. +redirect_uri = "https://example.com" +# Set the scopes +scopes = ["tweet.read", "users.read", "list.read", "list.write", "offline.access"] -# Be sure to replace your-user-id with your own user ID or one of an authenticating user +# Be sure to replace your-user-id with your own user ID or one of an authenticated user # You can find a user ID by using the user lookup endpoint -id = "your-user-id" - -# Be sure to add replace list-id-to-pin with the list id you wish to pin. -payload = {"list_id": "list-id-to-pin"} - -# Get request token -request_token_url = "https://api.x.com/oauth/request_token" -oauth = OAuth1Session(consumer_key, client_secret=consumer_secret) - -try: - fetch_response = oauth.fetch_request_token(request_token_url) -except ValueError: - print( - "There may have been an issue with the consumer_key or consumer_secret you entered." +user_id = "your-user-id" + +# Be sure to replace list-id-to-pin with the list id you wish to pin. +list_id = "list-id-to-pin" + +def main(): + # Step 1: Create PKCE instance + auth = OAuth2PKCEAuth( + client_id=client_id, + client_secret=client_secret, + redirect_uri=redirect_uri, + scope=scopes ) - -resource_owner_key = fetch_response.get("oauth_token") -resource_owner_secret = fetch_response.get("oauth_token_secret") -print("Got OAuth token: %s" % resource_owner_key) - -# Get authorization -base_authorization_url = "https://api.x.com/oauth/authorize" -authorization_url = oauth.authorization_url(base_authorization_url) -print("Please go here and authorize: %s" % authorization_url) -verifier = input("Paste the PIN here: ") - -# Get the access token -access_token_url = "https://api.x.com/oauth/access_token" -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=resource_owner_key, - resource_owner_secret=resource_owner_secret, - verifier=verifier, -) -oauth_tokens = oauth.fetch_access_token(access_token_url) - -access_token = oauth_tokens["oauth_token"] -access_token_secret = oauth_tokens["oauth_token_secret"] - -# Make the request -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=access_token, - resource_owner_secret=access_token_secret, -) - -# Making the request -response = oauth.post( - "https://api.x.com/2/users/{}/pinned_lists".format(id), json=payload -) - -if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format(response.status_code, response.text) - ) - -print("Response code: {}".format(response.status_code)) - -# Saving the response as JSON -json_response = response.json() -print(json.dumps(json_response, indent=4, sort_keys=True)) + + # Step 2: Get authorization URL + auth_url = auth.get_authorization_url() + print("Visit the following URL to authorize your App on behalf of your X handle in a browser:") + print(auth_url) + + # Step 3: Handle callback + callback_url = input("Paste the full callback URL here: ") + + # Step 4: Exchange code for tokens + tokens = auth.fetch_token(authorization_response=callback_url) + access_token = tokens["access_token"] + + # Step 5: Create client + client = Client(access_token=access_token) + + # Step 6: Pin the list + payload = {"list_id": list_id} + response = client.users.pin_list(user_id, body=payload) + + print("Response code: 200") + print(json.dumps(response.data, indent=4, sort_keys=True)) + +if __name__ == "__main__": + main() diff --git a/python/lists/remove_list_member.py b/python/lists/remove_list_member.py new file mode 100644 index 0000000..5e80701 --- /dev/null +++ b/python/lists/remove_list_member.py @@ -0,0 +1,67 @@ +""" +Remove List Member - X API v2 +============================== +Endpoint: DELETE https://api.x.com/2/lists/:id/members/:user_id +Docs: https://developer.x.com/en/docs/twitter-api/lists/list-members/api-reference/delete-lists-id-members-user_id + +Authentication: OAuth 2.0 (User Context) +Required env vars: CLIENT_ID, CLIENT_SECRET +""" + +import os +import json +from xdk import Client +from xdk.oauth2_auth import OAuth2PKCEAuth + +# The code below sets the client ID and client secret from your environment variables +# To set environment variables on macOS or Linux, run the export commands below from the terminal: +# export CLIENT_ID='YOUR-CLIENT-ID' +# export CLIENT_SECRET='YOUR-CLIENT-SECRET' +client_id = os.environ.get("CLIENT_ID") +client_secret = os.environ.get("CLIENT_SECRET") + +# Replace the following URL with your callback URL, which can be obtained from your App's auth settings. +redirect_uri = "https://example.com" + +# Set the scopes +scopes = ["tweet.read", "users.read", "list.read", "list.write", "offline.access"] + +# Be sure to replace your-list-id with your own list ID or one of an authenticated user +list_id = "your-list-id" + +# Be sure to replace user-id-to-remove with the id of the user you wish to remove. +# You can find a user ID by using the user lookup endpoint +user_id = "user-id-to-remove" + +def main(): + # Step 1: Create PKCE instance + auth = OAuth2PKCEAuth( + client_id=client_id, + client_secret=client_secret, + redirect_uri=redirect_uri, + scope=scopes + ) + + # Step 2: Get authorization URL + auth_url = auth.get_authorization_url() + print("Visit the following URL to authorize your App on behalf of your X handle in a browser:") + print(auth_url) + + # Step 3: Handle callback + callback_url = input("Paste the full callback URL here: ") + + # Step 4: Exchange code for tokens + tokens = auth.fetch_token(authorization_response=callback_url) + access_token = tokens["access_token"] + + # Step 5: Create client + client = Client(access_token=access_token) + + # Step 6: Remove member from list + response = client.lists.remove_member(list_id, user_id) + + print("Response code: 200") + print(json.dumps(response.data, indent=4, sort_keys=True)) + +if __name__ == "__main__": + main() diff --git a/python/lists/remove_member.py b/python/lists/remove_member.py deleted file mode 100644 index cf51b34..0000000 --- a/python/lists/remove_member.py +++ /dev/null @@ -1,78 +0,0 @@ -from requests_oauthlib import OAuth1Session -import os -import json - -# In your terminal please set your environment variables by running the following lines of code. -# export 'CONSUMER_KEY'='' -# export 'CONSUMER_SECRET'='' - -consumer_key = os.environ.get("CONSUMER_KEY") -consumer_secret = os.environ.get("CONSUMER_SECRET") - - -# Be sure to replace your-list-id with your own list ID or one of an authenticated user -id = "your-list-id" - -# Be sure to add replace user-id-to-remove with the id of the user you wish to remove. -# You can find a user ID by using the user lookup endpoint -user_id = "user-id-to-remove" - - -# Get request token -request_token_url = "https://api.x.com/oauth/request_token" -oauth = OAuth1Session(consumer_key, client_secret=consumer_secret) - -try: - fetch_response = oauth.fetch_request_token(request_token_url) -except ValueError: - print( - "There may have been an issue with the consumer_key or consumer_secret you entered." - ) - -resource_owner_key = fetch_response.get("oauth_token") -resource_owner_secret = fetch_response.get("oauth_token_secret") -print("Got OAuth token: %s" % resource_owner_key) - -# Get authorization -base_authorization_url = "https://api.x.com/oauth/authorize" -authorization_url = oauth.authorization_url(base_authorization_url) -print("Please go here and authorize: %s" % authorization_url) -verifier = input("Paste the PIN here: ") - -# Get the access token -access_token_url = "https://api.x.com/oauth/access_token" -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=resource_owner_key, - resource_owner_secret=resource_owner_secret, - verifier=verifier, -) -oauth_tokens = oauth.fetch_access_token(access_token_url) - -access_token = oauth_tokens["oauth_token"] -access_token_secret = oauth_tokens["oauth_token_secret"] - -# Make the request -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=access_token, - resource_owner_secret=access_token_secret, -) - -# Making the request -response = oauth.delete( - "https://api.x.com/2/lists/{}/members/{}".format(id, user_id) -) - -if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format(response.status_code, response.text) - ) - -print("Response code: {}".format(response.status_code)) - -# Saving the response as JSON -json_response = response.json() -print(json.dumps(json_response, indent=4, sort_keys=True)) diff --git a/python/lists/unfollow_list.py b/python/lists/unfollow_list.py index d28b62a..9a47163 100644 --- a/python/lists/unfollow_list.py +++ b/python/lists/unfollow_list.py @@ -1,78 +1,67 @@ -from requests_oauthlib import OAuth1Session +""" +Unfollow List - X API v2 +======================== +Endpoint: DELETE https://api.x.com/2/users/:id/followed_lists/:list_id +Docs: https://developer.x.com/en/docs/twitter-api/lists/list-follows/api-reference/delete-users-id-followed_lists-list_id + +Authentication: OAuth 2.0 (User Context) +Required env vars: CLIENT_ID, CLIENT_SECRET +""" + import os import json +from xdk import Client +from xdk.oauth2_auth import OAuth2PKCEAuth -# In your terminal please set your environment variables by running the following lines of code. -# export 'CONSUMER_KEY'='' -# export 'CONSUMER_SECRET'='' +# The code below sets the client ID and client secret from your environment variables +# To set environment variables on macOS or Linux, run the export commands below from the terminal: +# export CLIENT_ID='YOUR-CLIENT-ID' +# export CLIENT_SECRET='YOUR-CLIENT-SECRET' +client_id = os.environ.get("CLIENT_ID") +client_secret = os.environ.get("CLIENT_SECRET") -consumer_key = os.environ.get("CONSUMER_KEY") -consumer_secret = os.environ.get("CONSUMER_SECRET") +# Replace the following URL with your callback URL, which can be obtained from your App's auth settings. +redirect_uri = "https://example.com" +# Set the scopes +scopes = ["tweet.read", "users.read", "list.read", "list.write", "offline.access"] # Be sure to replace your-user-id with your own user ID or one of an authenticated user # You can find a user ID by using the user lookup endpoint -id = "your-user-id" +user_id = "your-user-id" -# Be sure to add replace list-id-to-unfollow with the id of the user you wish to unfollow. +# Be sure to replace list-id-to-unfollow with the id of the list you wish to unfollow. list_id = "list-id-to-unfollow" - -# Get request token -request_token_url = "https://api.x.com/oauth/request_token" -oauth = OAuth1Session(consumer_key, client_secret=consumer_secret) - -try: - fetch_response = oauth.fetch_request_token(request_token_url) -except ValueError: - print( - "There may have been an issue with the consumer_key or consumer_secret you entered." - ) - -resource_owner_key = fetch_response.get("oauth_token") -resource_owner_secret = fetch_response.get("oauth_token_secret") -print("Got OAuth token: %s" % resource_owner_key) - -# Get authorization -base_authorization_url = "https://api.x.com/oauth/authorize" -authorization_url = oauth.authorization_url(base_authorization_url) -print("Please go here and authorize: %s" % authorization_url) -verifier = input("Paste the PIN here: ") - -# Get the access token -access_token_url = "https://api.x.com/oauth/access_token" -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=resource_owner_key, - resource_owner_secret=resource_owner_secret, - verifier=verifier, -) -oauth_tokens = oauth.fetch_access_token(access_token_url) - -access_token = oauth_tokens["oauth_token"] -access_token_secret = oauth_tokens["oauth_token_secret"] - -# Make the request -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=access_token, - resource_owner_secret=access_token_secret, -) - -# Making the request -response = oauth.delete( - "https://api.x.com/2/users/{}/followed_lists/{}".format(id, list_id) -) - -if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format(response.status_code, response.text) +def main(): + # Step 1: Create PKCE instance + auth = OAuth2PKCEAuth( + client_id=client_id, + client_secret=client_secret, + redirect_uri=redirect_uri, + scope=scopes ) - -print("Response code: {}".format(response.status_code)) - -# Saving the response as JSON -json_response = response.json() -print(json.dumps(json_response, indent=4, sort_keys=True)) + + # Step 2: Get authorization URL + auth_url = auth.get_authorization_url() + print("Visit the following URL to authorize your App on behalf of your X handle in a browser:") + print(auth_url) + + # Step 3: Handle callback + callback_url = input("Paste the full callback URL here: ") + + # Step 4: Exchange code for tokens + tokens = auth.fetch_token(authorization_response=callback_url) + access_token = tokens["access_token"] + + # Step 5: Create client + client = Client(access_token=access_token) + + # Step 6: Unfollow the list + response = client.users.unfollow_list(user_id, list_id) + + print("Response code: 200") + print(json.dumps(response.data, indent=4, sort_keys=True)) + +if __name__ == "__main__": + main() diff --git a/python/lists/unpin_list.py b/python/lists/unpin_list.py index 03e76d7..d5049eb 100644 --- a/python/lists/unpin_list.py +++ b/python/lists/unpin_list.py @@ -1,78 +1,67 @@ -from requests_oauthlib import OAuth1Session +""" +Unpin List - X API v2 +===================== +Endpoint: DELETE https://api.x.com/2/users/:id/pinned_lists/:list_id +Docs: https://developer.x.com/en/docs/twitter-api/lists/pinned-lists/api-reference/delete-users-id-pinned_lists-list_id + +Authentication: OAuth 2.0 (User Context) +Required env vars: CLIENT_ID, CLIENT_SECRET +""" + import os import json +from xdk import Client +from xdk.oauth2_auth import OAuth2PKCEAuth -# In your terminal please set your environment variables by running the following lines of code. -# export 'CONSUMER_KEY'='' -# export 'CONSUMER_SECRET'='' +# The code below sets the client ID and client secret from your environment variables +# To set environment variables on macOS or Linux, run the export commands below from the terminal: +# export CLIENT_ID='YOUR-CLIENT-ID' +# export CLIENT_SECRET='YOUR-CLIENT-SECRET' +client_id = os.environ.get("CLIENT_ID") +client_secret = os.environ.get("CLIENT_SECRET") -consumer_key = os.environ.get("CONSUMER_KEY") -consumer_secret = os.environ.get("CONSUMER_SECRET") +# Replace the following URL with your callback URL, which can be obtained from your App's auth settings. +redirect_uri = "https://example.com" +# Set the scopes +scopes = ["tweet.read", "users.read", "list.read", "list.write", "offline.access"] # Be sure to replace your-user-id with your own user ID or one of an authenticated user # You can find a user ID by using the user lookup endpoint -id = "your-user-id" +user_id = "your-user-id" -# Be sure to add replace list-id-to-unpin with the id of the user you wish to unpin. +# Be sure to replace list-id-to-unpin with the id of the list you wish to unpin. list_id = "list-id-to-unpin" - -# Get request token -request_token_url = "https://api.x.com/oauth/request_token" -oauth = OAuth1Session(consumer_key, client_secret=consumer_secret) - -try: - fetch_response = oauth.fetch_request_token(request_token_url) -except ValueError: - print( - "There may have been an issue with the consumer_key or consumer_secret you entered." - ) - -resource_owner_key = fetch_response.get("oauth_token") -resource_owner_secret = fetch_response.get("oauth_token_secret") -print("Got OAuth token: %s" % resource_owner_key) - -# Get authorization -base_authorization_url = "https://api.x.com/oauth/authorize" -authorization_url = oauth.authorization_url(base_authorization_url) -print("Please go here and authorize: %s" % authorization_url) -verifier = input("Paste the PIN here: ") - -# Get the access token -access_token_url = "https://api.x.com/oauth/access_token" -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=resource_owner_key, - resource_owner_secret=resource_owner_secret, - verifier=verifier, -) -oauth_tokens = oauth.fetch_access_token(access_token_url) - -access_token = oauth_tokens["oauth_token"] -access_token_secret = oauth_tokens["oauth_token_secret"] - -# Make the request -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=access_token, - resource_owner_secret=access_token_secret, -) - -# Making the request -response = oauth.delete( - "https://api.x.com/2/users/{}/pinned_lists/{}".format(id, list_id) -) - -if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format(response.status_code, response.text) +def main(): + # Step 1: Create PKCE instance + auth = OAuth2PKCEAuth( + client_id=client_id, + client_secret=client_secret, + redirect_uri=redirect_uri, + scope=scopes ) - -print("Response code: {}".format(response.status_code)) - -# Saving the response as JSON -json_response = response.json() -print(json.dumps(json_response, indent=4, sort_keys=True)) + + # Step 2: Get authorization URL + auth_url = auth.get_authorization_url() + print("Visit the following URL to authorize your App on behalf of your X handle in a browser:") + print(auth_url) + + # Step 3: Handle callback + callback_url = input("Paste the full callback URL here: ") + + # Step 4: Exchange code for tokens + tokens = auth.fetch_token(authorization_response=callback_url) + access_token = tokens["access_token"] + + # Step 5: Create client + client = Client(access_token=access_token) + + # Step 6: Unpin the list + response = client.users.unpin_list(user_id, list_id) + + print("Response code: 200") + print(json.dumps(response.data, indent=4, sort_keys=True)) + +if __name__ == "__main__": + main() diff --git a/python/lists/update_a_list.py b/python/lists/update_a_list.py deleted file mode 100644 index 8abf2ba..0000000 --- a/python/lists/update_a_list.py +++ /dev/null @@ -1,81 +0,0 @@ -from requests_oauthlib import OAuth1Session -import os -import json - -# In your terminal please set your environment variables by running the following lines of code. -# export 'CONSUMER_KEY'='' -# export 'CONSUMER_SECRET'='' - -consumer_key = os.environ.get("CONSUMER_KEY") -consumer_secret = os.environ.get("CONSUMER_SECRET") - -# Be sure to add replace update-name-of-list with the name you wish to call the list. -# name, description and private are all optional -payload = { "name": "update-name-of-list", - "description": "update-description-of-list", - "private": False} - - -# Be sure to replace your-list-id with the id of the list you wish to update. The authenticated user must own the list in order to update - -id = "your-list-id" - - -# Get request token -request_token_url = "https://api.x.com/oauth/request_token" -oauth = OAuth1Session(consumer_key, client_secret=consumer_secret) - -try: - fetch_response = oauth.fetch_request_token(request_token_url) -except ValueError: - print( - "There may have been an issue with the consumer_key or consumer_secret you entered." - ) - -resource_owner_key = fetch_response.get("oauth_token") -resource_owner_secret = fetch_response.get("oauth_token_secret") -print("Got OAuth token: %s" % resource_owner_key) - -# Get authorization -base_authorization_url = "https://api.x.com/oauth/authorize" -authorization_url = oauth.authorization_url(base_authorization_url) -print("Please go here and authorize: %s" % authorization_url) -verifier = input("Paste the PIN here: ") - -# Get the access token -access_token_url = "https://api.x.com/oauth/access_token" -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=resource_owner_key, - resource_owner_secret=resource_owner_secret, - verifier=verifier, -) -oauth_tokens = oauth.fetch_access_token(access_token_url) - -access_token = oauth_tokens["oauth_token"] -access_token_secret = oauth_tokens["oauth_token_secret"] - -# Make the request -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=access_token, - resource_owner_secret=access_token_secret, -) - -# Making the request -response = oauth.put( - "https://api.x.com/2/lists/{}".format(id), json=payload -) - -if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format(response.status_code, response.text) - ) - -print("Response code: {}".format(response.status_code)) - -# Saving the response as JSON -json_response = response.json() -print(json.dumps(json_response, indent=4, sort_keys=True)) diff --git a/python/lists/update_list.py b/python/lists/update_list.py new file mode 100644 index 0000000..5df2d4e --- /dev/null +++ b/python/lists/update_list.py @@ -0,0 +1,72 @@ +""" +Update List - X API v2 +====================== +Endpoint: PUT https://api.x.com/2/lists/:id +Docs: https://developer.x.com/en/docs/twitter-api/lists/manage-lists/api-reference/put-lists-id + +Authentication: OAuth 2.0 (User Context) +Required env vars: CLIENT_ID, CLIENT_SECRET +""" + +import os +import json +from xdk import Client +from xdk.oauth2_auth import OAuth2PKCEAuth + +# The code below sets the client ID and client secret from your environment variables +# To set environment variables on macOS or Linux, run the export commands below from the terminal: +# export CLIENT_ID='YOUR-CLIENT-ID' +# export CLIENT_SECRET='YOUR-CLIENT-SECRET' +client_id = os.environ.get("CLIENT_ID") +client_secret = os.environ.get("CLIENT_SECRET") + +# Replace the following URL with your callback URL, which can be obtained from your App's auth settings. +redirect_uri = "https://example.com" + +# Set the scopes +scopes = ["tweet.read", "users.read", "list.read", "list.write", "offline.access"] + +# Be sure to replace update-name-of-list with the name you wish to call the list. +# name, description and private are all optional +payload = { + "name": "update-name-of-list", + "description": "update-description-of-list", + "private": False +} + +# Be sure to replace your-list-id with the id of the list you wish to update. +# The authenticated user must own the list in order to update it. +list_id = "list-id" + +def main(): + # Step 1: Create PKCE instance + auth = OAuth2PKCEAuth( + client_id=client_id, + client_secret=client_secret, + redirect_uri=redirect_uri, + scope=scopes + ) + + # Step 2: Get authorization URL + auth_url = auth.get_authorization_url() + print("Visit the following URL to authorize your App on behalf of your X handle in a browser:") + print(auth_url) + + # Step 3: Handle callback + callback_url = input("Paste the full callback URL here: ") + + # Step 4: Exchange code for tokens + tokens = auth.fetch_token(authorization_response=callback_url) + access_token = tokens["access_token"] + + # Step 5: Create client + client = Client(access_token=access_token) + + # Step 6: Update the list + response = client.lists.update(list_id, body=payload) + + print("Response code: 200") + print(json.dumps(response.data, indent=4, sort_keys=True)) + +if __name__ == "__main__": + main() diff --git a/python/lists/user-list-followed.py b/python/lists/user-list-followed.py deleted file mode 100644 index f28b3be..0000000 --- a/python/lists/user-list-followed.py +++ /dev/null @@ -1,50 +0,0 @@ -import requests -import os -import json - -# To set your enviornment variables in your terminal run the following line: -# export 'BEARER_TOKEN'='' -bearer_token = os.environ.get("BEARER_TOKEN") - - -def create_url(): - # List fields are adjustable, options include: - # created_at, description, owner_id, - # private, follower_count, member_count, - list_fields = "list.fields=created_at,follower_count" - # You can replace the user-id with any valid User ID you wish to find what Lists they are following. - id = "user-id" - url = "https://api.x.com/2/users/{}/followed_lists".format(id) - return url, list_fields - - -def bearer_oauth(r): - """ - Method required by bearer token authentication. - """ - - r.headers["Authorization"] = f"Bearer {bearer_token}" - r.headers["User-Agent"] = "v2userListMembershipsPython" - return r - - -def connect_to_endpoint(url, list_fields): - response = requests.request("GET", url, auth=bearer_oauth, params=list_fields) - print(response.status_code) - if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format( - response.status_code, response.text - ) - ) - return response.json() - - -def main(): - url, list_fields = create_url() - json_response = connect_to_endpoint(url, list_fields) - print(json.dumps(json_response, indent=4, sort_keys=True)) - - -if __name__ == "__main__": - main() diff --git a/python/lists/user-list-memberships.py b/python/lists/user-list-memberships.py deleted file mode 100644 index 3455aaa..0000000 --- a/python/lists/user-list-memberships.py +++ /dev/null @@ -1,50 +0,0 @@ -import requests -import os -import json - -# To set your enviornment variables in your terminal run the following line: -# export 'BEARER_TOKEN'='' -bearer_token = os.environ.get("BEARER_TOKEN") - - -def create_url(): - # List fields are adjustable, options include: - # created_at, description, owner_id, - # private, follower_count, member_count, - list_fields = "list.fields=created_at,follower_count" - # You can replace the user-id with any valid User ID you wish to find what Lists they are members of. - id = "user-id" - url = "https://api.x.com/2/users/{}/list_memberships".format(id) - return url, list_fields - - -def bearer_oauth(r): - """ - Method required by bearer token authentication. - """ - - r.headers["Authorization"] = f"Bearer {bearer_token}" - r.headers["User-Agent"] = "v2userListMembershipsPython" - return r - - -def connect_to_endpoint(url, list_fields): - response = requests.request("GET", url, auth=bearer_oauth, params=list_fields) - print(response.status_code) - if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format( - response.status_code, response.text - ) - ) - return response.json() - - -def main(): - url, list_fields = create_url() - json_response = connect_to_endpoint(url, list_fields) - print(json.dumps(json_response, indent=4, sort_keys=True)) - - -if __name__ == "__main__": - main() diff --git a/python/lists/user-owned-list-lookup.py b/python/lists/user-owned-list-lookup.py deleted file mode 100644 index 3bbcd99..0000000 --- a/python/lists/user-owned-list-lookup.py +++ /dev/null @@ -1,50 +0,0 @@ -import requests -import os -import json - -# To set your enviornment variables in your terminal run the following line: -# export 'BEARER_TOKEN'='' -bearer_token = os.environ.get("BEARER_TOKEN") - - -def create_url(): - # List fields are adjustable, options include: - # created_at, description, owner_id, - # private, follower_count, member_count, - list_fields = "list.fields=created_at,follower_count" - # You can replace user-id with any valid User ID to see if they own any Lists. - id = "user-id" - url = "https://api.x.com/2/users/{}/owned_lists".format(id) - return url, list_fields - - -def bearer_oauth(r): - """ - Method required by bearer token authentication. - """ - - r.headers["Authorization"] = f"Bearer {bearer_token}" - r.headers["User-Agent"] = "v2ListLookupPython" - return r - - -def connect_to_endpoint(url, list_fields): - response = requests.request("GET", url, auth=bearer_oauth, params=list_fields) - print(response.status_code) - if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format( - response.status_code, response.text - ) - ) - return response.json() - - -def main(): - url, list_fields = create_url() - json_response = connect_to_endpoint(url, list_fields) - print(json.dumps(json_response, indent=4, sort_keys=True)) - - -if __name__ == "__main__": - main() diff --git a/python/media/media_upload_v2.py b/python/media/media_upload_v2.py index 0b28df2..5ac66d1 100644 --- a/python/media/media_upload_v2.py +++ b/python/media/media_upload_v2.py @@ -1,11 +1,20 @@ +""" +Media Upload v2 (Video) - X API v2 +=================================== +Endpoint: POST https://api.x.com/2/media/upload +Docs: https://developer.x.com/en/docs/twitter-api/media/upload-media/api-reference + +Authentication: OAuth 2.0 (User Context) +Required env vars: CLIENT_ID, CLIENT_SECRET + +This example demonstrates uploading a video file using chunked uploads. +""" + import os import sys -import base64 -import hashlib -import re import time import requests -from requests_oauthlib import OAuth2Session +from xdk.oauth2_auth import OAuth2PKCEAuth MEDIA_ENDPOINT_URL = 'https://api.x.com/2/media/upload' POST_TO_X_URL = 'https://api.x.com/2/tweets' @@ -13,77 +22,38 @@ # Replace with path to file VIDEO_FILENAME = 'REPLACE_ME' -# You will need to enable OAuth 2.0 in your App’s auth settings in the Developer Portal to get your client ID. -# Inside your terminal you will need to set an enviornment variable -# export CLIENT_ID='your-client-id' +# The code below sets the client ID and client secret from your environment variables +# To set environment variables on macOS or Linux, run the export commands below from the terminal: +# export CLIENT_ID='YOUR-CLIENT-ID' +# export CLIENT_SECRET='YOUR-CLIENT-SECRET' client_id = os.environ.get("CLIENT_ID") - -# If you have selected a type of App that is a confidential client you will need to set a client secret. -# Confidential Clients securely authenticate with the authorization server. - -# Inside your terminal you will need to set an enviornment variable -# export CLIENT_SECRET='your-client-secret' - -# Remove the comment on the following line if you are using a confidential client -# client_secret = os.environ.get("CLIENT_SECRET") +client_secret = os.environ.get("CLIENT_SECRET") # Replace the following URL with your callback URL, which can be obtained from your App's auth settings. -redirect_uri = "https://www.example.com" +redirect_uri = "https://example.com" # Set the scopes scopes = ["media.write", "users.read", "tweet.read", "tweet.write", "offline.access"] -# Create a code verifier -code_verifier = base64.urlsafe_b64encode(os.urandom(30)).decode("utf-8") -code_verifier = re.sub("[^a-zA-Z0-9]+", "", code_verifier) - -# Create a code challenge -code_challenge = hashlib.sha256(code_verifier.encode("utf-8")).digest() -code_challenge = base64.urlsafe_b64encode(code_challenge).decode("utf-8") -code_challenge = code_challenge.replace("=", "") - -# Start and OAuth 2.0 session -oauth = OAuth2Session(client_id, redirect_uri=redirect_uri, scope=scopes) - -# Create an authorize URL -auth_url = "https://x.com/i/oauth2/authorize" -authorization_url, state = oauth.authorization_url( - auth_url, code_challenge=code_challenge, code_challenge_method="S256" -) - -# Visit the URL to authorize your App to make requests on behalf of a user -print( - "Visit the following URL to authorize your App on behalf of your X handle in a browser:" -) -print(authorization_url) - -# Paste in your authorize URL to complete the request -authorization_response = input( - "Paste in the full URL after you've authorized your App:\n" +# Step 1: Create PKCE instance +auth = OAuth2PKCEAuth( + client_id=client_id, + client_secret=client_secret, + redirect_uri=redirect_uri, + scope=scopes ) -# Fetch your access token -token_url = "https://api.x.com/2/oauth2/token" - -# The following line of code will only work if you are using a type of App that is a public client -auth = False +# Step 2: Get authorization URL +auth_url = auth.get_authorization_url() +print("Visit the following URL to authorize your App on behalf of your X handle in a browser:") +print(auth_url) -# If you are using a confidential client you will need to pass in basic encoding of your client ID and client secret. - -# Please remove the comment on the following line if you are using a type of App that is a confidential client -# auth = HTTPBasicAuth(client_id, client_secret) - -token = oauth.fetch_token( - token_url=token_url, - authorization_response=authorization_response, - auth=auth, - client_id=client_id, - include_client_id=True, - code_verifier=code_verifier, -) +# Step 3: Handle callback +callback_url = input("Paste the full callback URL here: ") -# Your access token -access = token["access_token"] +# Step 4: Exchange code for tokens +tokens = auth.fetch_token(authorization_response=callback_url) +access = tokens["access_token"] headers = { "Authorization": "Bearer {}".format(access), diff --git a/python/media/upload.py b/python/media/upload.py index 130fa5b..f3139bd 100644 --- a/python/media/upload.py +++ b/python/media/upload.py @@ -1,91 +1,77 @@ """ Media Upload - X API v2 ======================= -Endpoint: POST https://api.x.com/2/media/upload +Endpoint: POST https://upload.x.com/1.1/media/upload.json Docs: https://developer.x.com/en/docs/twitter-api/media/upload-media/api-reference -Authentication: OAuth 1.0a (User Context) -Required env vars: CONSUMER_KEY, CONSUMER_SECRET +Authentication: OAuth 2.0 (User Context) +Required env vars: CLIENT_ID, CLIENT_SECRET This example demonstrates uploading an image to attach to a post. """ -from requests_oauthlib import OAuth1Session import os import json import base64 +from xdk import Client +from xdk.oauth2_auth import OAuth2PKCEAuth -consumer_key = os.environ.get("CONSUMER_KEY") -consumer_secret = os.environ.get("CONSUMER_SECRET") +# The code below sets the client ID and client secret from your environment variables +# To set environment variables on macOS or Linux, run the export commands below from the terminal: +# export CLIENT_ID='YOUR-CLIENT-ID' +# export CLIENT_SECRET='YOUR-CLIENT-SECRET' +client_id = os.environ.get("CLIENT_ID") +client_secret = os.environ.get("CLIENT_SECRET") -# Path to the media file you want to upload -media_path = "path/to/your/image.jpg" - -# Get request token -request_token_url = "https://api.x.com/oauth/request_token" -oauth = OAuth1Session(consumer_key, client_secret=consumer_secret) - -try: - fetch_response = oauth.fetch_request_token(request_token_url) -except ValueError: - print( - "There may have been an issue with the consumer_key or consumer_secret you entered." - ) - -resource_owner_key = fetch_response.get("oauth_token") -resource_owner_secret = fetch_response.get("oauth_token_secret") -print("Got OAuth token: %s" % resource_owner_key) - -# Get authorization -base_authorization_url = "https://api.x.com/oauth/authorize" -authorization_url = oauth.authorization_url(base_authorization_url) -print("Please go here and authorize: %s" % authorization_url) -verifier = input("Paste the PIN here: ") - -# Get the access token -access_token_url = "https://api.x.com/oauth/access_token" -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=resource_owner_key, - resource_owner_secret=resource_owner_secret, - verifier=verifier, -) -oauth_tokens = oauth.fetch_access_token(access_token_url) +# Replace the following URL with your callback URL, which can be obtained from your App's auth settings. +redirect_uri = "https://example.com" -access_token = oauth_tokens["oauth_token"] -access_token_secret = oauth_tokens["oauth_token_secret"] +# Set the scopes +scopes = ["tweet.read", "tweet.write", "users.read", "offline.access"] -# Make the request -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=access_token, - resource_owner_secret=access_token_secret, -) - -# Read and encode the media file -with open(media_path, "rb") as media_file: - media_data = base64.b64encode(media_file.read()).decode("utf-8") - -# Upload the media (using v1.1 endpoint as v2 media upload is similar) -upload_url = "https://upload.twitter.com/1.1/media/upload.json" -payload = {"media_data": media_data} - -response = oauth.post(upload_url, data=payload) +# Path to the media file you want to upload +media_path = "path/to/your/image.jpg" -if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format(response.status_code, response.text) +def main(): + # Step 1: Create PKCE instance + auth = OAuth2PKCEAuth( + client_id=client_id, + client_secret=client_secret, + redirect_uri=redirect_uri, + scope=scopes ) - -print("Response code: {}".format(response.status_code)) - -# Get the media_id to use when creating a post -json_response = response.json() -media_id = json_response["media_id_string"] -print("Media ID: {}".format(media_id)) -print(json.dumps(json_response, indent=4, sort_keys=True)) - -# You can now use this media_id when creating a post: -# payload = {"text": "My post with media!", "media": {"media_ids": [media_id]}} + + # Step 2: Get authorization URL + auth_url = auth.get_authorization_url() + print("Visit the following URL to authorize your App on behalf of your X handle in a browser:") + print(auth_url) + + # Step 3: Handle callback + callback_url = input("Paste the full callback URL here: ") + + # Step 4: Exchange code for tokens + tokens = auth.fetch_token(authorization_response=callback_url) + access_token = tokens["access_token"] + + # Step 5: Create client + client = Client(access_token=access_token) + + # Step 6: Read and upload the media file + with open(media_path, "rb") as media_file: + media_data = base64.b64encode(media_file.read()).decode("utf-8") + + payload = {"media_data": media_data} + response = client.media.upload_media(body=payload) + + print("Response code: 200") + + # Get the media_id to use when creating a post + media_id = response.data["media_id_string"] + print("Media ID: {}".format(media_id)) + print(json.dumps(response.data, indent=4, sort_keys=True)) + + # You can now use this media_id when creating a post: + # payload = {"text": "My post with media!", "media": {"media_ids": [media_id]}} + +if __name__ == "__main__": + main() diff --git a/python/posts/counts_full_archive.py b/python/posts/counts_full_archive.py deleted file mode 100644 index 963c026..0000000 --- a/python/posts/counts_full_archive.py +++ /dev/null @@ -1,52 +0,0 @@ -""" -Full-Archive Post Counts - X API v2 -=================================== -Endpoint: GET https://api.x.com/2/tweets/counts/all -Docs: https://developer.x.com/en/docs/twitter-api/tweets/counts/api-reference/get-tweets-counts-all - -Authentication: Bearer Token (App-only) -Required env vars: BEARER_TOKEN - -Note: Requires Academic Research access. Returns counts from the entire archive. -""" - -import requests -import os -import json - -bearer_token = os.environ.get("BEARER_TOKEN") - - -def bearer_oauth(r): - """ - Method required by bearer token authentication. - """ - r.headers["Authorization"] = f"Bearer {bearer_token}" - r.headers["User-Agent"] = "v2FullArchivePostCountsPython" - return r - - -def get_params(): - return { - "query": "from:XDevelopers", - "granularity": "day" - } - - -def connect_to_endpoint(url, params): - response = requests.request("GET", url, auth=bearer_oauth, params=params) - print(response.status_code) - if response.status_code != 200: - raise Exception(response.status_code, response.text) - return response.json() - - -def main(): - url = "https://api.x.com/2/tweets/counts/all" - params = get_params() - json_response = connect_to_endpoint(url, params) - print(json.dumps(json_response, indent=4, sort_keys=True)) - - -if __name__ == "__main__": - main() diff --git a/python/posts/counts_recent.py b/python/posts/counts_recent.py deleted file mode 100644 index 8f51666..0000000 --- a/python/posts/counts_recent.py +++ /dev/null @@ -1,52 +0,0 @@ -""" -Recent Post Counts - X API v2 -============================= -Endpoint: GET https://api.x.com/2/tweets/counts/recent -Docs: https://developer.x.com/en/docs/twitter-api/tweets/counts/api-reference/get-tweets-counts-recent - -Authentication: Bearer Token (App-only) -Required env vars: BEARER_TOKEN - -Note: Returns count of posts from the last 7 days matching your query. -""" - -import requests -import os -import json - -bearer_token = os.environ.get("BEARER_TOKEN") - - -def bearer_oauth(r): - """ - Method required by bearer token authentication. - """ - r.headers["Authorization"] = f"Bearer {bearer_token}" - r.headers["User-Agent"] = "v2PostCountsPython" - return r - - -def get_params(): - return { - "query": "from:XDevelopers", - "granularity": "day" - } - - -def connect_to_endpoint(url, params): - response = requests.request("GET", url, auth=bearer_oauth, params=params) - print(response.status_code) - if response.status_code != 200: - raise Exception(response.status_code, response.text) - return response.json() - - -def main(): - url = "https://api.x.com/2/tweets/counts/recent" - params = get_params() - json_response = connect_to_endpoint(url, params) - print(json.dumps(json_response, indent=4, sort_keys=True)) - - -if __name__ == "__main__": - main() diff --git a/python/posts/create_post.py b/python/posts/create_post.py index 63cf6fd..ae7cda5 100644 --- a/python/posts/create_post.py +++ b/python/posts/create_post.py @@ -1,80 +1,64 @@ """ -Create Post - X API v2 -====================== +Create Tweet - X API v2 +======================= Endpoint: POST https://api.x.com/2/tweets Docs: https://developer.x.com/en/docs/twitter-api/tweets/manage-tweets/api-reference/post-tweets -Authentication: OAuth 1.0a (User Context) -Required env vars: CONSUMER_KEY, CONSUMER_SECRET +Authentication: OAuth 2.0 (User Context) +Required env vars: CLIENT_ID, CLIENT_SECRET """ -from requests_oauthlib import OAuth1Session import os import json +from xdk import Client +from xdk.oauth2_auth import OAuth2PKCEAuth -consumer_key = os.environ.get("CONSUMER_KEY") -consumer_secret = os.environ.get("CONSUMER_SECRET") +# The code below sets the client ID and client secret from your environment variables +# To set environment variables on macOS or Linux, run the export commands below from the terminal: +# export CLIENT_ID='YOUR-CLIENT-ID' +# export CLIENT_SECRET='YOUR-CLIENT-SECRET' +client_id = os.environ.get("CLIENT_ID") +client_secret = os.environ.get("CLIENT_SECRET") -# The text content of the post. You can also add parameters for polls, -# quote posts, reply settings, and more. -payload = {"text": "Hello world!"} - -# Get request token -request_token_url = "https://api.x.com/oauth/request_token?oauth_callback=oob&x_auth_access_type=write" -oauth = OAuth1Session(consumer_key, client_secret=consumer_secret) - -try: - fetch_response = oauth.fetch_request_token(request_token_url) -except ValueError: - print( - "There may have been an issue with the consumer_key or consumer_secret you entered." - ) - -resource_owner_key = fetch_response.get("oauth_token") -resource_owner_secret = fetch_response.get("oauth_token_secret") -print("Got OAuth token: %s" % resource_owner_key) +# Replace the following URL with your callback URL, which can be obtained from your App's auth settings. +redirect_uri = "https://example.com" -# Get authorization -base_authorization_url = "https://api.x.com/oauth/authorize" -authorization_url = oauth.authorization_url(base_authorization_url) -print("Please go here and authorize: %s" % authorization_url) -verifier = input("Paste the PIN here: ") +# Set the scopes +scopes = ["tweet.read", "tweet.write", "users.read", "offline.access"] -# Get the access token -access_token_url = "https://api.x.com/oauth/access_token" -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=resource_owner_key, - resource_owner_secret=resource_owner_secret, - verifier=verifier, -) -oauth_tokens = oauth.fetch_access_token(access_token_url) - -access_token = oauth_tokens["oauth_token"] -access_token_secret = oauth_tokens["oauth_token_secret"] - -# Make the request -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=access_token, - resource_owner_secret=access_token_secret, -) - -# Making the request -response = oauth.post( - "https://api.x.com/2/tweets", - json=payload, -) +# Be sure to replace the text with the text you wish to Tweet. +# You can also add parameters to post polls, quote Tweets, Tweet with reply settings, and Tweet to Super Followers in addition to other features. +payload = {"text": "Hello world!"} -if response.status_code != 201: - raise Exception( - "Request returned an error: {} {}".format(response.status_code, response.text) +def main(): + # Step 1: Create PKCE instance + auth = OAuth2PKCEAuth( + client_id=client_id, + client_secret=client_secret, + redirect_uri=redirect_uri, + scope=scopes ) + + # Step 2: Get authorization URL + auth_url = auth.get_authorization_url() + print("Visit the following URL to authorize your App on behalf of your X handle in a browser:") + print(auth_url) + + # Step 3: Handle callback + callback_url = input("Paste the full callback URL here: ") + + # Step 4: Exchange code for tokens + tokens = auth.fetch_token(authorization_response=callback_url) + access_token = tokens["access_token"] + + # Step 5: Create client + client = Client(access_token=access_token) + + # Step 6: Create the tweet + response = client.posts.create(body=payload) + + print("Response code: 201") + print(json.dumps(response.data, indent=4, sort_keys=True)) -print("Response code: {}".format(response.status_code)) - -# Saving the response as JSON -json_response = response.json() -print(json.dumps(json_response, indent=4, sort_keys=True)) +if __name__ == "__main__": + main() diff --git a/python/posts/create_tweet.py b/python/posts/create_tweet.py deleted file mode 100644 index 92c570b..0000000 --- a/python/posts/create_tweet.py +++ /dev/null @@ -1,73 +0,0 @@ -from requests_oauthlib import OAuth1Session -import os -import json - -# In your terminal please set your environment variables by running the following lines of code. -# export 'CONSUMER_KEY'='' -# export 'CONSUMER_SECRET'='' - -consumer_key = os.environ.get("CONSUMER_KEY") -consumer_secret = os.environ.get("CONSUMER_SECRET") - -# Be sure to add replace the text of the with the text you wish to Tweet. You can also add parameters to post polls, quote Tweets, Tweet with reply settings, and Tweet to Super Followers in addition to other features. -payload = {"text": "Hello world!"} - -# Get request token -request_token_url = "https://api.x.com/oauth/request_token?oauth_callback=oob&x_auth_access_type=write" -oauth = OAuth1Session(consumer_key, client_secret=consumer_secret) - -try: - fetch_response = oauth.fetch_request_token(request_token_url) -except ValueError: - print( - "There may have been an issue with the consumer_key or consumer_secret you entered." - ) - -resource_owner_key = fetch_response.get("oauth_token") -resource_owner_secret = fetch_response.get("oauth_token_secret") -print("Got OAuth token: %s" % resource_owner_key) - -# Get authorization -base_authorization_url = "https://api.x.com/oauth/authorize" -authorization_url = oauth.authorization_url(base_authorization_url) -print("Please go here and authorize: %s" % authorization_url) -verifier = input("Paste the PIN here: ") - -# Get the access token -access_token_url = "https://api.x.com/oauth/access_token" -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=resource_owner_key, - resource_owner_secret=resource_owner_secret, - verifier=verifier, -) -oauth_tokens = oauth.fetch_access_token(access_token_url) - -access_token = oauth_tokens["oauth_token"] -access_token_secret = oauth_tokens["oauth_token_secret"] - -# Make the request -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=access_token, - resource_owner_secret=access_token_secret, -) - -# Making the request -response = oauth.post( - "https://api.x.com/2/tweets", - json=payload, -) - -if response.status_code != 201: - raise Exception( - "Request returned an error: {} {}".format(response.status_code, response.text) - ) - -print("Response code: {}".format(response.status_code)) - -# Saving the response as JSON -json_response = response.json() -print(json.dumps(json_response, indent=4, sort_keys=True)) diff --git a/python/posts/delete_post.py b/python/posts/delete_post.py index 0199ab0..dbf7615 100644 --- a/python/posts/delete_post.py +++ b/python/posts/delete_post.py @@ -1,77 +1,65 @@ """ -Delete Post - X API v2 -====================== +Delete Tweet - X API v2 +======================= Endpoint: DELETE https://api.x.com/2/tweets/:id Docs: https://developer.x.com/en/docs/twitter-api/tweets/manage-tweets/api-reference/delete-tweets-id -Authentication: OAuth 1.0a (User Context) -Required env vars: CONSUMER_KEY, CONSUMER_SECRET +Authentication: OAuth 2.0 (User Context) +Required env vars: CLIENT_ID, CLIENT_SECRET """ -from requests_oauthlib import OAuth1Session import os import json +from xdk import Client +from xdk.oauth2_auth import OAuth2PKCEAuth -consumer_key = os.environ.get("CONSUMER_KEY") -consumer_secret = os.environ.get("CONSUMER_SECRET") +# The code below sets the client ID and client secret from your environment variables +# To set environment variables on macOS or Linux, run the export commands below from the terminal: +# export CLIENT_ID='YOUR-CLIENT-ID' +# export CLIENT_SECRET='YOUR-CLIENT-SECRET' +client_id = os.environ.get("CLIENT_ID") +client_secret = os.environ.get("CLIENT_SECRET") -# Replace with the ID of the post you wish to delete. -# The authenticated user must own the post. -post_id = "post-id-to-delete" +# Replace the following URL with your callback URL, which can be obtained from your App's auth settings. +redirect_uri = "https://example.com" -# Get request token -request_token_url = "https://api.x.com/oauth/request_token" -oauth = OAuth1Session(consumer_key, client_secret=consumer_secret) +# Set the scopes +scopes = ["tweet.read", "tweet.write", "users.read", "offline.access"] -try: - fetch_response = oauth.fetch_request_token(request_token_url) -except ValueError: - print( - "There may have been an issue with the consumer_key or consumer_secret you entered." - ) - -resource_owner_key = fetch_response.get("oauth_token") -resource_owner_secret = fetch_response.get("oauth_token_secret") -print("Got OAuth token: %s" % resource_owner_key) - -# Get authorization -base_authorization_url = "https://api.x.com/oauth/authorize" -authorization_url = oauth.authorization_url(base_authorization_url) -print("Please go here and authorize: %s" % authorization_url) -verifier = input("Paste the PIN here: ") - -# Get the access token -access_token_url = "https://api.x.com/oauth/access_token" -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=resource_owner_key, - resource_owner_secret=resource_owner_secret, - verifier=verifier, -) -oauth_tokens = oauth.fetch_access_token(access_token_url) - -access_token = oauth_tokens["oauth_token"] -access_token_secret = oauth_tokens["oauth_token_secret"] - -# Make the request -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=access_token, - resource_owner_secret=access_token_secret, -) - -# Making the request -response = oauth.delete("https://api.x.com/2/tweets/{}".format(post_id)) +# Be sure to replace tweet-id-to-delete with the id of the Tweet you wish to delete. +# The authenticated user must own the Tweet in order to delete it. +post_id = "1997118644242014409" -if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format(response.status_code, response.text) +def main(): + # Step 1: Create PKCE instance + auth = OAuth2PKCEAuth( + client_id=client_id, + client_secret=client_secret, + redirect_uri=redirect_uri, + scope=scopes ) + + # Step 2: Get authorization URL + auth_url = auth.get_authorization_url() + print("Visit the following URL to authorize your App on behalf of your X handle in a browser:") + print(auth_url) + + # Step 3: Handle callback + callback_url = input("Paste the full callback URL here: ") + + # Step 4: Exchange code for tokens + tokens = auth.fetch_token(authorization_response=callback_url) + access_token = tokens["access_token"] + + # Step 5: Create client + client = Client(access_token=access_token) + + # Step 6: Delete the tweet + response = client.posts.delete(post_id) + + print("Response code: 200") + print(json.dumps(response.data, indent=4, sort_keys=True)) -print("Response code: {}".format(response.status_code)) +if __name__ == "__main__": -# Saving the response as JSON -json_response = response.json() -print(json_response) + main() diff --git a/python/posts/delete_tweet.py b/python/posts/delete_tweet.py deleted file mode 100644 index 2184284..0000000 --- a/python/posts/delete_tweet.py +++ /dev/null @@ -1,73 +0,0 @@ -from requests_oauthlib import OAuth1Session -import os -import json - -# In your terminal please set your environment variables by running the following lines of code. -# export 'CONSUMER_KEY'='' -# export 'CONSUMER_SECRET'='' - -consumer_key = os.environ.get("CONSUMER_KEY") -consumer_secret = os.environ.get("CONSUMER_SECRET") - - -# Be sure to replace tweet-id-to-delete with the id of the Tweet you wish to delete. The authenticated user must own the list in order to delete - -id = "tweet-id-to-delete" - - -# Get request token -request_token_url = "https://api.x.com/oauth/request_token" -oauth = OAuth1Session(consumer_key, client_secret=consumer_secret) - -try: - fetch_response = oauth.fetch_request_token(request_token_url) -except ValueError: - print( - "There may have been an issue with the consumer_key or consumer_secret you entered." - ) - -resource_owner_key = fetch_response.get("oauth_token") -resource_owner_secret = fetch_response.get("oauth_token_secret") -print("Got OAuth token: %s" % resource_owner_key) - -# Get authorization -base_authorization_url = "https://api.x.com/oauth/authorize" -authorization_url = oauth.authorization_url(base_authorization_url) -print("Please go here and authorize: %s" % authorization_url) -verifier = input("Paste the PIN here: ") - -# Get the access token -access_token_url = "https://api.x.com/oauth/access_token" -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=resource_owner_key, - resource_owner_secret=resource_owner_secret, - verifier=verifier, -) -oauth_tokens = oauth.fetch_access_token(access_token_url) - -access_token = oauth_tokens["oauth_token"] -access_token_secret = oauth_tokens["oauth_token_secret"] - -# Make the request -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=access_token, - resource_owner_secret=access_token_secret, -) - -# Making the request -response = oauth.delete("https://api.x.com/2/tweets/{}".format(id)) - -if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format(response.status_code, response.text) - ) - -print("Response code: {}".format(response.status_code)) - -# Saving the response as JSON -json_response = response.json() -print(json_response) diff --git a/python/posts/full-archive-search.py b/python/posts/full-archive-search.py deleted file mode 100644 index 785c487..0000000 --- a/python/posts/full-archive-search.py +++ /dev/null @@ -1,40 +0,0 @@ -import requests -import os -import json - -# To set your environment variables in your terminal run the following line: -# export 'BEARER_TOKEN'='' -bearer_token = os.environ.get("BEARER_TOKEN") - -search_url = "https://api.x.com/2/tweets/search/all" - -# Optional params: start_time,end_time,since_id,until_id,max_results,next_token, -# expansions,tweet.fields,media.fields,poll.fields,place.fields,user.fields -query_params = {'query': '(from:twitterdev -is:retweet) OR #twitterdev','tweet.fields': 'author_id'} - - -def bearer_oauth(r): - """ - Method required by bearer token authentication. - """ - - r.headers["Authorization"] = f"Bearer {bearer_token}" - r.headers["User-Agent"] = "v2FullArchiveSearchPython" - return r - - -def connect_to_endpoint(url, params): - response = requests.request("GET", search_url, auth=bearer_oauth, params=params) - print(response.status_code) - if response.status_code != 200: - raise Exception(response.status_code, response.text) - return response.json() - - -def main(): - json_response = connect_to_endpoint(search_url, query_params) - print(json.dumps(json_response, indent=4, sort_keys=True)) - - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/python/posts/full_archive_tweet_counts.py b/python/posts/full_archive_tweet_counts.py deleted file mode 100644 index 697a0be..0000000 --- a/python/posts/full_archive_tweet_counts.py +++ /dev/null @@ -1,39 +0,0 @@ -import requests -import os -import json - -# To set your environment variables in your terminal run the following line: -# export 'BEARER_TOKEN'='' -bearer_token = os.environ.get("BEARER_TOKEN") - -search_url = "https://api.x.com/2/tweets/counts/all" - -# Optional params: start_time,end_time,since_id,until_id,next_token,granularity -query_params = {'query': 'from:twitterdev','granularity': 'day', 'start_time': '2021-01-01T00:00:00Z'} - - -def bearer_oauth(r): - """ - Method required by bearer token authentication. - """ - - r.headers["Authorization"] = f"Bearer {bearer_token}" - r.headers["User-Agent"] = "v2FullArchiveTweetCountsPython" - return r - - -def connect_to_endpoint(url, params): - response = requests.request("GET", search_url, auth=bearer_oauth, params=params) - print(response.status_code) - if response.status_code != 200: - raise Exception(response.status_code, response.text) - return response.json() - - -def main(): - json_response = connect_to_endpoint(search_url, query_params) - print(json.dumps(json_response, indent=4, sort_keys=True)) - - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/python/posts/get_liked_posts.py b/python/posts/get_liked_posts.py new file mode 100644 index 0000000..0c58ab4 --- /dev/null +++ b/python/posts/get_liked_posts.py @@ -0,0 +1,81 @@ +""" +Liked Tweets - X API v2 +====================== +Endpoint: GET https://api.x.com/2/users/:id/liked_tweets +Docs: https://developer.x.com/en/docs/twitter-api/tweets/likes/api-reference/get-users-id-liked_tweets + +Authentication: OAuth 2.0 (User Context) +Required env vars: CLIENT_ID, CLIENT_SECRET +""" + +import os +import json +from xdk import Client +from xdk.oauth2_auth import OAuth2PKCEAuth + +# The code below sets the client ID and client secret from your environment variables +# To set environment variables on macOS or Linux, run the export commands below from the terminal: +# export CLIENT_ID='YOUR-CLIENT-ID' +# export CLIENT_SECRET='YOUR-CLIENT-SECRET' +client_id = os.environ.get("CLIENT_ID") +client_secret = os.environ.get("CLIENT_SECRET") + +# Replace the following URL with your callback URL, which can be obtained from your App's auth settings. +redirect_uri = "https://example.com" + +# Set the scopes +scopes = ["tweet.read", "users.read", "like.read", "offline.access"] + +def main(): + # Step 1: Create PKCE instance + auth = OAuth2PKCEAuth( + client_id=client_id, + client_secret=client_secret, + redirect_uri=redirect_uri, + scope=scopes + ) + + # Step 2: Get authorization URL + auth_url = auth.get_authorization_url() + print("Visit the following URL to authorize your App on behalf of your X handle in a browser:") + print(auth_url) + + # Step 3: Handle callback + callback_url = input("Paste the full callback URL here: ") + + # Step 4: Exchange code for tokens + tokens = auth.fetch_token(authorization_response=callback_url) + access_token = tokens["access_token"] + + # Step 5: Create client + client = Client(access_token=access_token) + + # Step 6: Get the authenticated user's ID + user_me = client.users.get_me() + user_id = user_me.data["id"] + + # Step 7: Get liked tweets with automatic pagination + # Tweet fields are adjustable. + # Options include: + # attachments, author_id, context_annotations, + # conversation_id, created_at, entities, geo, id, + # in_reply_to_user_id, lang, non_public_metrics, organic_metrics, + # possibly_sensitive, promoted_metrics, public_metrics, referenced_tweets, + # source, text, and withheld + all_posts = [] + for page in client.users.get_liked_posts( + user_id, + max_results=100, + tweet_fields=["lang", "author_id"] + ): + # Access data attribute (model uses extra='allow' so data should be available) + # Use getattr with fallback in case data field is missing from response + page_data = getattr(page, 'data', []) or [] + all_posts.extend(page_data) + print(f"Fetched {len(page_data)} posts (total: {len(all_posts)})") + + print(f"\nTotal Liked Tweets: {len(all_posts)}") + print(json.dumps({"data": all_posts[:5]}, indent=4, sort_keys=True)) # Print first 5 as example + +if __name__ == "__main__": + main() diff --git a/python/posts/get_liking_users.py b/python/posts/get_liking_users.py new file mode 100644 index 0000000..4918bd2 --- /dev/null +++ b/python/posts/get_liking_users.py @@ -0,0 +1,79 @@ +""" +Liking Users - X API v2 +====================== +Endpoint: GET https://api.x.com/2/tweets/:id/liking_users +Docs: https://developer.x.com/en/docs/twitter-api/tweets/likes/api-reference/get-tweets-id-liking_users + +Authentication: OAuth 2.0 (User Context) +Required env vars: CLIENT_ID, CLIENT_SECRET +""" + +import os +import json +from xdk import Client +from xdk.oauth2_auth import OAuth2PKCEAuth +from requests.exceptions import HTTPError + +# The code below sets the client ID and client secret from your environment variables +# To set environment variables on macOS or Linux, run the export commands below from the terminal: +# export CLIENT_ID='YOUR-CLIENT-ID' +# export CLIENT_SECRET='YOUR-CLIENT-SECRET' +client_id = os.environ.get("CLIENT_ID") +client_secret = os.environ.get("CLIENT_SECRET") + +# Replace the following URL with your callback URL, which can be obtained from your App's auth settings. +redirect_uri = "https://example.com" + +# Set the scopes +scopes = ["tweet.read", "users.read", "like.read", "offline.access"] + +# You can replace the ID given with the Post ID you wish to get liking users for. +# You can find an ID by using the Post lookup endpoint +post_id = "post-id" + +def main(): + # Step 1: Create PKCE instance + auth = OAuth2PKCEAuth( + client_id=client_id, + client_secret=client_secret, + redirect_uri=redirect_uri, + scope=scopes + ) + + # Step 2: Get authorization URL + auth_url = auth.get_authorization_url() + print("Visit the following URL to authorize your App on behalf of your X handle in a browser:") + print(auth_url) + + # Step 3: Handle callback + callback_url = input("Paste the full callback URL here: ") + + # Step 4: Exchange code for tokens + tokens = auth.fetch_token(authorization_response=callback_url) + access_token = tokens["access_token"] + + # Step 5: Create client + client = Client(access_token=access_token) + + # Step 6: Get liking users with automatic pagination + # User fields are adjustable, options include: + # created_at, description, entities, id, location, name, + # pinned_tweet_id, profile_image_url, protected, + # public_metrics, url, username, verified, and withheld + all_users = [] + for page in client.posts.get_liking_users( + post_id, + max_results=100, + user_fields=["created_at", "description"] + ): + # Access data attribute (model uses extra='allow' so data should be available) + # Use getattr with fallback in case data field is missing from response + page_data = getattr(page, 'data', []) or [] + all_users.extend(page_data) + print(f"Fetched {len(page_data)} users (total: {len(all_users)})") + + print(f"\nTotal Users: {len(all_users)}") + print(json.dumps({"data": all_users[:5]}, indent=4, sort_keys=True)) # Print first 5 as example + +if __name__ == "__main__": + main() diff --git a/python/posts/get_post_counts_all.py b/python/posts/get_post_counts_all.py new file mode 100644 index 0000000..5b64b9c --- /dev/null +++ b/python/posts/get_post_counts_all.py @@ -0,0 +1,43 @@ +""" +Full-Archive Post Counts - X API v2 +=================================== +Endpoint: GET https://api.x.com/2/tweets/counts/all +Docs: https://developer.x.com/en/docs/twitter-api/tweets/counts/api-reference/get-tweets-counts-all + +Authentication: Bearer Token (App-only) +Required env vars: BEARER_TOKEN + +Note: Requires Academic Research access. Returns counts from the entire archive. +""" + +import os +import json +from xdk import Client + +bearer_token = os.environ.get("BEARER_TOKEN") +client = Client(bearer_token=bearer_token) + +query = "from:XDevelopers" + +def main(): + # Get counts with automatic pagination + # Optional: You can add start_time parameter to limit the date range + # Example: start_time="2021-01-01T00:00:00Z" + all_counts = [] + for page in client.posts.get_counts_all( + query=query, + granularity="day" + # start_time="2021-01-01T00:00:00Z" # Optional: uncomment to add date range + ): + # Access data attribute (model uses extra='allow' so data should be available) + # Use getattr with fallback in case data field is missing from response + page_data = getattr(page, 'data', []) or [] + all_counts.extend(page_data) + print(f"Fetched {len(page_data)} count buckets (total: {len(all_counts)})") + + print(f"\nTotal Count Buckets: {len(all_counts)}") + print(json.dumps({"data": all_counts}, indent=4, sort_keys=True)) + + +if __name__ == "__main__": + main() diff --git a/python/posts/get_post_counts_recent.py b/python/posts/get_post_counts_recent.py new file mode 100644 index 0000000..cf959ff --- /dev/null +++ b/python/posts/get_post_counts_recent.py @@ -0,0 +1,40 @@ +""" +Recent Post Counts - X API v2 +============================= +Endpoint: GET https://api.x.com/2/tweets/counts/recent +Docs: https://developer.x.com/en/docs/twitter-api/tweets/counts/api-reference/get-tweets-counts-recent + +Authentication: Bearer Token (App-only) +Required env vars: BEARER_TOKEN + +Note: Returns count of posts from the last 7 days matching your query. +""" + +import os +import json +from xdk import Client + +bearer_token = os.environ.get("BEARER_TOKEN") +client = Client(bearer_token=bearer_token) + +query = "from:XDevelopers" + +def main(): + # Get counts with automatic pagination + all_counts = [] + for page in client.posts.get_counts_recent( + query=query, + granularity="day" + ): + # Access data attribute (model uses extra='allow' so data should be available) + # Use getattr with fallback in case data field is missing from response + page_data = getattr(page, 'data', []) or [] + all_counts.extend(page_data) + print(f"Fetched {len(page_data)} count buckets (total: {len(all_counts)})") + + print(f"\nTotal Count Buckets: {len(all_counts)}") + print(json.dumps({"data": all_counts}, indent=4, sort_keys=True)) + + +if __name__ == "__main__": + main() diff --git a/python/posts/get_posts_by_ids.py b/python/posts/get_posts_by_ids.py new file mode 100644 index 0000000..f8c489e --- /dev/null +++ b/python/posts/get_posts_by_ids.py @@ -0,0 +1,38 @@ +""" +Post Lookup - X API v2 +====================== +Endpoint: GET https://api.x.com/2/tweets +Docs: https://developer.x.com/en/docs/twitter-api/tweets/lookup/api-reference/get-tweets + +Authentication: Bearer Token (App-only) or OAuth (User Context) +Required env vars: BEARER_TOKEN +""" + +import os +import json +from xdk import Client + +bearer_token = os.environ.get("BEARER_TOKEN") +client = Client(bearer_token=bearer_token) + +# Post IDs to look up (comma-separated list, up to 100) +# You can adjust ids to include a single Post or add up to 100 comma-separated IDs +post_ids = ["post-id-1", "post-id-2"] + +def main(): + # Post fields are adjustable. Options include: + # attachments, author_id, context_annotations, conversation_id, + # created_at, entities, geo, id, in_reply_to_user_id, lang, + # non_public_metrics, organic_metrics, possibly_sensitive, + # promoted_metrics, public_metrics, referenced_tweets, + # source, text, and withheld + response = client.posts.get_by_ids( + ids=post_ids, + tweet_fields=["created_at", "author_id", "lang", "source", "public_metrics", "context_annotations", "entities"] + ) + + print(json.dumps(response.data, indent=4, sort_keys=True)) + + +if __name__ == "__main__": + main() diff --git a/python/posts/get_quoted_posts.py b/python/posts/get_quoted_posts.py new file mode 100644 index 0000000..2c02a1a --- /dev/null +++ b/python/posts/get_quoted_posts.py @@ -0,0 +1,44 @@ +""" +Quote Tweets Lookup - X API v2 +============================== +Endpoint: GET https://api.x.com/2/tweets/:id/quote_tweets +Docs: https://developer.x.com/en/docs/twitter-api/tweets/quote-tweets/api-reference/get-tweets-id-quote_tweets + +Authentication: Bearer Token (App-only) or OAuth (User Context) +Required env vars: BEARER_TOKEN +""" + +import os +import json +from xdk import Client + +bearer_token = os.environ.get("BEARER_TOKEN") +client = Client(bearer_token=bearer_token) + +# Replace with the post ID you want to get quotes for +post_id = "1409931481552543749" + +def main(): + # Get quote tweets with automatic pagination + # Tweet fields are adjustable. + # Options include: + # attachments, author_id, context_annotations, + # conversation_id, created_at, entities, geo, id, + # in_reply_to_user_id, lang, non_public_metrics, organic_metrics, + # possibly_sensitive, promoted_metrics, public_metrics, referenced_tweets, + # source, text, and withheld + all_posts = [] + for page in client.posts.get_quoted( + post_id, + max_results=100, + tweet_fields=["created_at"] + ): + all_posts.extend(page.data) + print(f"Fetched {len(page.data)} posts (total: {len(all_posts)})") + + print(f"\nTotal Quote Tweets: {len(all_posts)}") + print(json.dumps({"data": all_posts[:5]}, indent=4, sort_keys=True)) # Print first 5 as example + +if __name__ == "__main__": + main() + \ No newline at end of file diff --git a/python/posts/get_resposted_by.py b/python/posts/get_resposted_by.py new file mode 100644 index 0000000..861b479 --- /dev/null +++ b/python/posts/get_resposted_by.py @@ -0,0 +1,44 @@ +""" +Retweeted By (Users who reposted) - X API v2 +============================================ +Endpoint: GET https://api.x.com/2/tweets/:id/retweeted_by +Docs: https://developer.x.com/en/docs/twitter-api/tweets/retweets/api-reference/get-tweets-id-retweeted_by + +Authentication: Bearer Token (App-only) or OAuth (User Context) +Required env vars: BEARER_TOKEN +""" + +import os +import json +from xdk import Client + +bearer_token = os.environ.get("BEARER_TOKEN") +client = Client(bearer_token=bearer_token) + +# You can replace the ID given with the Post ID you wish to lookup reposting users for +# You can find an ID by using the Post lookup endpoint +post_id = "post-id" + +def main(): + # Get reposted by users with automatic pagination + # User fields are adjustable, options include: + # created_at, description, entities, id, location, name, + # pinned_tweet_id, profile_image_url, protected, + # public_metrics, url, username, verified, and withheld + all_users = [] + for page in client.posts.get_reposted_by( + post_id, + max_results=100, + user_fields=["created_at", "description"] + ): + # Access data attribute (model uses extra='allow' so data should be available) + # Use getattr with fallback in case data field is missing from response + page_data = getattr(page, 'data', []) or [] + all_users.extend(page_data) + print(f"Fetched {len(page_data)} users (total: {len(all_users)})") + + print(f"\nTotal Users: {len(all_users)}") + print(json.dumps({"data": all_users[:5]}, indent=4, sort_keys=True)) # Print first 5 as example + +if __name__ == "__main__": + main() diff --git a/python/posts/get_tweets_with_bearer_token.py b/python/posts/get_tweets_with_bearer_token.py deleted file mode 100644 index e646f70..0000000 --- a/python/posts/get_tweets_with_bearer_token.py +++ /dev/null @@ -1,55 +0,0 @@ -import requests -import os -import json - -# To set your enviornment variables in your terminal run the following line: -# export 'BEARER_TOKEN'='' -bearer_token = os.environ.get("BEARER_TOKEN") - - -def create_url(): - tweet_fields = "tweet.fields=lang,author_id" - # Tweet fields are adjustable. - # Options include: - # attachments, author_id, context_annotations, - # conversation_id, created_at, entities, geo, id, - # in_reply_to_user_id, lang, non_public_metrics, organic_metrics, - # possibly_sensitive, promoted_metrics, public_metrics, referenced_tweets, - # source, text, and withheld - ids = "ids=1278747501642657792,1255542774432063488" - # You can adjust ids to include a single Tweets. - # Or you can add to up to 100 comma-separated IDs - url = "https://api.x.com/2/tweets?{}&{}".format(ids, tweet_fields) - return url - - -def bearer_oauth(r): - """ - Method required by bearer token authentication. - """ - - r.headers["Authorization"] = f"Bearer {bearer_token}" - r.headers["User-Agent"] = "v2TweetLookupPython" - return r - - -def connect_to_endpoint(url): - response = requests.request("GET", url, auth=bearer_oauth) - print(response.status_code) - if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format( - response.status_code, response.text - ) - ) - return response.json() - - -def main(): - url = create_url() - json_response = connect_to_endpoint(url) - print(json.dumps(json_response, indent=4, sort_keys=True)) - - -if __name__ == "__main__": - main() diff --git a/python/posts/get_tweets_with_user_context.py b/python/posts/get_tweets_with_user_context.py deleted file mode 100644 index 8ab866e..0000000 --- a/python/posts/get_tweets_with_user_context.py +++ /dev/null @@ -1,77 +0,0 @@ -from requests_oauthlib import OAuth1Session -import os -import json - -# To set your enviornment variables in your terminal run the following line: -# export 'CONSUMER_KEY'='' -# export 'CONSUMER_SECRET'='' - -consumer_key = os.environ.get("CONSUMER_KEY") -consumer_secret = os.environ.get("CONSUMER_SECRET") - -# You can adjust ids to include a single Tweets -# Or you can add to up to 100 comma-separated IDs -params = {"ids": "1278747501642657792", "tweet.fields": "created_at"} -# Tweet fields are adjustable. -# Options include: -# attachments, author_id, context_annotations, -# conversation_id, created_at, entities, geo, id, -# in_reply_to_user_id, lang, non_public_metrics, organic_metrics, -# possibly_sensitive, promoted_metrics, public_metrics, referenced_tweets, -# source, text, and withheld - -request_token_url = "https://api.x.com/oauth/request_token" -oauth = OAuth1Session(consumer_key, client_secret=consumer_secret) - -try: - fetch_response = oauth.fetch_request_token(request_token_url) -except ValueError: - print( - "There may have been an issue with the consumer_key or consumer_secret you entered." - ) - -resource_owner_key = fetch_response.get("oauth_token") -resource_owner_secret = fetch_response.get("oauth_token_secret") -print("Got OAuth token: %s" % resource_owner_key) - -# Get authorization -base_authorization_url = "https://api.x.com/oauth/authorize" -authorization_url = oauth.authorization_url(base_authorization_url) -print("Please go here and authorize: %s" % authorization_url) -verifier = input("Paste the PIN here: ") - -# Get the access token -access_token_url = "https://api.x.com/oauth/access_token" -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=resource_owner_key, - resource_owner_secret=resource_owner_secret, - verifier=verifier, -) -oauth_tokens = oauth.fetch_access_token(access_token_url) - - -access_token = oauth_tokens["oauth_token"] -access_token_secret = oauth_tokens["oauth_token_secret"] - -# Make the request -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=access_token, - resource_owner_secret=access_token_secret, -) - -response = oauth.get( - "https://api.x.com/2/tweets", params=params -) - -if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format(response.status_code, response.text) - ) - -print("Response code: {}".format(response.status_code)) -json_response = response.json() -print(json.dumps(json_response, indent=4, sort_keys=True)) diff --git a/python/posts/like.py b/python/posts/like.py deleted file mode 100644 index 5bcb4d6..0000000 --- a/python/posts/like.py +++ /dev/null @@ -1,81 +0,0 @@ -""" -Like a Post - X API v2 -====================== -Endpoint: POST https://api.x.com/2/users/:id/likes -Docs: https://developer.x.com/en/docs/twitter-api/tweets/likes/api-reference/post-users-id-likes - -Authentication: OAuth 1.0a (User Context) -Required env vars: CONSUMER_KEY, CONSUMER_SECRET -""" - -from requests_oauthlib import OAuth1Session -import os -import json - -consumer_key = os.environ.get("CONSUMER_KEY") -consumer_secret = os.environ.get("CONSUMER_SECRET") - -# Replace with your own user ID -user_id = "your-user-id" - -# Replace with the post ID you want to like -payload = {"tweet_id": "1354143047324299264"} - -# Get request token -request_token_url = "https://api.x.com/oauth/request_token" -oauth = OAuth1Session(consumer_key, client_secret=consumer_secret) - -try: - fetch_response = oauth.fetch_request_token(request_token_url) -except ValueError: - print( - "There may have been an issue with the consumer_key or consumer_secret you entered." - ) - -resource_owner_key = fetch_response.get("oauth_token") -resource_owner_secret = fetch_response.get("oauth_token_secret") -print("Got OAuth token: %s" % resource_owner_key) - -# Get authorization -base_authorization_url = "https://api.x.com/oauth/authorize" -authorization_url = oauth.authorization_url(base_authorization_url) -print("Please go here and authorize: %s" % authorization_url) -verifier = input("Paste the PIN here: ") - -# Get the access token -access_token_url = "https://api.x.com/oauth/access_token" -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=resource_owner_key, - resource_owner_secret=resource_owner_secret, - verifier=verifier, -) -oauth_tokens = oauth.fetch_access_token(access_token_url) - -access_token = oauth_tokens["oauth_token"] -access_token_secret = oauth_tokens["oauth_token_secret"] - -# Make the request -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=access_token, - resource_owner_secret=access_token_secret, -) - -# Making the request -response = oauth.post( - "https://api.x.com/2/users/{}/likes".format(user_id), json=payload -) - -if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format(response.status_code, response.text) - ) - -print("Response code: {}".format(response.status_code)) - -# Saving the response as JSON -json_response = response.json() -print(json.dumps(json_response, indent=4, sort_keys=True)) diff --git a/python/posts/like_a_tweet.py b/python/posts/like_a_tweet.py deleted file mode 100644 index 00a24ce..0000000 --- a/python/posts/like_a_tweet.py +++ /dev/null @@ -1,77 +0,0 @@ -from requests_oauthlib import OAuth1Session -import os -import json - -# In your terminal please set your environment variables by running the following lines of code. -# export 'CONSUMER_KEY'='' -# export 'CONSUMER_SECRET'='' - -consumer_key = os.environ.get("CONSUMER_KEY") -consumer_secret = os.environ.get("CONSUMER_SECRET") - -# Be sure to replace your-user-id with your own user ID or one of an authenticating user -# You can find a user ID by using the user lookup endpoint -id = "your-user-id" - -# You can replace Tweet ID given with the Tweet ID you wish to like. -# You can find a Tweet ID by using the Tweet lookup endpoint -payload = {"tweet_id": "1354143047324299264"} - -# Get request token -request_token_url = "https://api.x.com/oauth/request_token" -oauth = OAuth1Session(consumer_key, client_secret=consumer_secret) - -try: - fetch_response = oauth.fetch_request_token(request_token_url) -except ValueError: - print( - "There may have been an issue with the consumer_key or consumer_secret you entered." - ) - -resource_owner_key = fetch_response.get("oauth_token") -resource_owner_secret = fetch_response.get("oauth_token_secret") -print("Got OAuth token: %s" % resource_owner_key) - -# Get authorization -base_authorization_url = "https://api.x.com/oauth/authorize" -authorization_url = oauth.authorization_url(base_authorization_url) -print("Please go here and authorize: %s" % authorization_url) -verifier = input("Paste the PIN here: ") - -# Get the access token -access_token_url = "https://api.x.com/oauth/access_token" -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=resource_owner_key, - resource_owner_secret=resource_owner_secret, - verifier=verifier, -) -oauth_tokens = oauth.fetch_access_token(access_token_url) - -access_token = oauth_tokens["oauth_token"] -access_token_secret = oauth_tokens["oauth_token_secret"] - -# Make the request -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=access_token, - resource_owner_secret=access_token_secret, -) - -# Making the request -response = oauth.post( - "https://api.x.com/2/users/{}/likes".format(id), json=payload -) - -if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format(response.status_code, response.text) - ) - -print("Response code: {}".format(response.status_code)) - -# Saving the response as JSON -json_response = response.json() -print(json.dumps(json_response, indent=4, sort_keys=True)) diff --git a/python/posts/like_post.py b/python/posts/like_post.py new file mode 100644 index 0000000..fbed43f --- /dev/null +++ b/python/posts/like_post.py @@ -0,0 +1,69 @@ +""" +Like a Tweet - X API v2 +====================== +Endpoint: POST https://api.x.com/2/users/:id/likes +Docs: https://developer.x.com/en/docs/twitter-api/tweets/likes/api-reference/post-users-id-likes + +Authentication: OAuth 2.0 (User Context) +Required env vars: CLIENT_ID, CLIENT_SECRET +""" + +import os +import json +from xdk import Client +from xdk.oauth2_auth import OAuth2PKCEAuth + +# The code below sets the client ID and client secret from your environment variables +# To set environment variables on macOS or Linux, run the export commands below from the terminal: +# export CLIENT_ID='YOUR-CLIENT-ID' +# export CLIENT_SECRET='YOUR-CLIENT-SECRET' +client_id = os.environ.get("CLIENT_ID") +client_secret = os.environ.get("CLIENT_SECRET") + +# Replace the following URL with your callback URL, which can be obtained from your App's auth settings. +redirect_uri = "https://example.com" + +# Set the scopes +scopes = ["tweet.read", "tweet.write", "users.read", "offline.access", "like.write"] + +# You can replace Tweet ID given with the Tweet ID you wish to like. +# You can find a Tweet ID by using the Tweet lookup endpoint +post_id = "post-id" + +def main(): + # Step 1: Create PKCE instance + auth = OAuth2PKCEAuth( + client_id=client_id, + client_secret=client_secret, + redirect_uri=redirect_uri, + scope=scopes + ) + + # Step 2: Get authorization URL + auth_url = auth.get_authorization_url() + print("Visit the following URL to authorize your App on behalf of your X handle in a browser:") + print(auth_url) + + # Step 3: Handle callback + callback_url = input("Paste the full callback URL here: ") + + # Step 4: Exchange code for tokens + tokens = auth.fetch_token(authorization_response=callback_url) + access_token = tokens["access_token"] + + # Step 5: Create client + client = Client(access_token=access_token) + + # Step 6: Get the authenticated user's ID + user_me = client.users.get_me() + user_id = user_me.data["id"] + + # Step 7: Like the tweet + payload = {"tweet_id": post_id} + response = client.users.like_post(user_id, body=payload) + + print("Response code: 200") + print(json.dumps(response.data, indent=4, sort_keys=True)) + +if __name__ == "__main__": + main() diff --git a/python/posts/liked_posts.py b/python/posts/liked_posts.py deleted file mode 100644 index cfafbf5..0000000 --- a/python/posts/liked_posts.py +++ /dev/null @@ -1,53 +0,0 @@ -""" -Posts Liked by User - X API v2 -============================== -Endpoint: GET https://api.x.com/2/users/:id/liked_tweets -Docs: https://developer.x.com/en/docs/twitter-api/tweets/likes/api-reference/get-users-id-liked_tweets - -Authentication: Bearer Token (App-only) or OAuth (User Context) -Required env vars: BEARER_TOKEN -""" - -import requests -import os -import json - -bearer_token = os.environ.get("BEARER_TOKEN") - - -def create_url(): - # Replace with the user ID you want to get liked posts for - user_id = "2244994945" - return "https://api.x.com/2/users/{}/liked_tweets".format(user_id) - - -def get_params(): - return {"tweet.fields": "created_at"} - - -def bearer_oauth(r): - """ - Method required by bearer token authentication. - """ - r.headers["Authorization"] = f"Bearer {bearer_token}" - r.headers["User-Agent"] = "v2LikedPostsPython" - return r - - -def connect_to_endpoint(url, params): - response = requests.request("GET", url, auth=bearer_oauth, params=params) - print(response.status_code) - if response.status_code != 200: - raise Exception(response.status_code, response.text) - return response.json() - - -def main(): - url = create_url() - params = get_params() - json_response = connect_to_endpoint(url, params) - print(json.dumps(json_response, indent=4, sort_keys=True)) - - -if __name__ == "__main__": - main() diff --git a/python/posts/liked_tweets.py b/python/posts/liked_tweets.py deleted file mode 100644 index b668621..0000000 --- a/python/posts/liked_tweets.py +++ /dev/null @@ -1,58 +0,0 @@ -import requests -import os -import json - -# To set your enviornment variables in your terminal run the following line: -# export 'BEARER_TOKEN'='' -bearer_token = os.environ.get("BEARER_TOKEN") - - -def create_url(): - # Tweet fields are adjustable. - # Options include: - # attachments, author_id, context_annotations, - # conversation_id, created_at, entities, geo, id, - # in_reply_to_user_id, lang, non_public_metrics, organic_metrics, - # possibly_sensitive, promoted_metrics, public_metrics, referenced_tweets, - # source, text, and withheld - tweet_fields = "tweet.fields=lang,author_id" - # Be sure to replace your-user-id with your own user ID or one of an authenticating user - # You can find a user ID by using the user lookup endpoint - id = "your-user-id" - # You can adjust ids to include a single Tweets. - # Or you can add to up to 100 comma-separated IDs - url = "https://api.x.com/2/users/{}/liked_tweets".format(id) - return url, tweet_fields - - -def bearer_oauth(r): - """ - Method required by bearer token authentication. - """ - - r.headers["Authorization"] = f"Bearer {bearer_token}" - r.headers["User-Agent"] = "v2LikedTweetsPython" - return r - - -def connect_to_endpoint(url, tweet_fields): - response = requests.request( - "GET", url, auth=bearer_oauth, params=tweet_fields) - print(response.status_code) - if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format( - response.status_code, response.text - ) - ) - return response.json() - - -def main(): - url, tweet_fields = create_url() - json_response = connect_to_endpoint(url, tweet_fields) - print(json.dumps(json_response, indent=4, sort_keys=True)) - - -if __name__ == "__main__": - main() diff --git a/python/posts/liking_users.py b/python/posts/liking_users.py deleted file mode 100644 index 1b08116..0000000 --- a/python/posts/liking_users.py +++ /dev/null @@ -1,54 +0,0 @@ -import requests -import os -import json - -# To set your enviornment variables in your terminal run the following line: -# export 'BEARER_TOKEN'='' -bearer_token = os.environ.get("BEARER_TOKEN") - - -def create_url(): - # User fields are adjustable, options include: - # created_at, description, entities, id, location, name, - # pinned_tweet_id, profile_image_url, protected, - # public_metrics, url, username, verified, and withheld - user_fields = "user.fields=created_at,description" - # You can replace the ID given with the Tweet ID you wish to like. - # You can find an ID by using the Tweet lookup endpoint - id = "1354143047324299264" - # You can adjust ids to include a single Tweets. - # Or you can add to up to 100 comma-separated IDs - url = "https://api.x.com/2/tweets/{}/liking_users".format(id) - return url, user_fields - - -def bearer_oauth(r): - """ - Method required by bearer token authentication. - """ - - r.headers["Authorization"] = f"Bearer {bearer_token}" - r.headers["User-Agent"] = "v2LikingUsersPython" - return r - - -def connect_to_endpoint(url, user_fields): - response = requests.request("GET", url, auth=bearer_oauth, params=user_fields) - print(response.status_code) - if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format( - response.status_code, response.text - ) - ) - return response.json() - - -def main(): - url, tweet_fields = create_url() - json_response = connect_to_endpoint(url, tweet_fields) - print(json.dumps(json_response, indent=4, sort_keys=True)) - - -if __name__ == "__main__": - main() diff --git a/python/posts/lookup.py b/python/posts/lookup.py deleted file mode 100644 index 802a466..0000000 --- a/python/posts/lookup.py +++ /dev/null @@ -1,61 +0,0 @@ -""" -Post Lookup - X API v2 -====================== -Endpoint: GET https://api.x.com/2/tweets -Docs: https://developer.x.com/en/docs/twitter-api/tweets/lookup/api-reference/get-tweets - -Authentication: Bearer Token (App-only) or OAuth (User Context) -Required env vars: BEARER_TOKEN -""" - -import requests -import os -import json - -bearer_token = os.environ.get("BEARER_TOKEN") - - -def create_url(): - # Post IDs to look up (comma-separated, up to 100) - post_ids = "ids=1278747501642657792,1255542774432063488" - - # Post fields are adjustable. Options include: - # attachments, author_id, context_annotations, conversation_id, - # created_at, entities, geo, id, in_reply_to_user_id, lang, - # non_public_metrics, organic_metrics, possibly_sensitive, - # promoted_metrics, public_metrics, referenced_tweets, - # source, text, and withheld - post_fields = "tweet.fields=created_at,author_id,lang,source,public_metrics,context_annotations,entities" - url = "https://api.x.com/2/tweets?{}&{}".format(post_ids, post_fields) - return url - - -def bearer_oauth(r): - """ - Method required by bearer token authentication. - """ - r.headers["Authorization"] = f"Bearer {bearer_token}" - r.headers["User-Agent"] = "v2PostLookupPython" - return r - - -def connect_to_endpoint(url): - response = requests.request("GET", url, auth=bearer_oauth) - print(response.status_code) - if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format( - response.status_code, response.text - ) - ) - return response.json() - - -def main(): - url = create_url() - json_response = connect_to_endpoint(url) - print(json.dumps(json_response, indent=4, sort_keys=True)) - - -if __name__ == "__main__": - main() diff --git a/python/posts/quote_posts.py b/python/posts/quote_posts.py deleted file mode 100644 index 038ebea..0000000 --- a/python/posts/quote_posts.py +++ /dev/null @@ -1,54 +0,0 @@ -""" -Quote Posts Lookup - X API v2 -============================= -Endpoint: GET https://api.x.com/2/tweets/:id/quote_tweets -Docs: https://developer.x.com/en/docs/twitter-api/tweets/quote-tweets/api-reference/get-tweets-id-quote_tweets - -Authentication: Bearer Token (App-only) or OAuth (User Context) -Required env vars: BEARER_TOKEN -""" - -import requests -import os -import json - -bearer_token = os.environ.get("BEARER_TOKEN") - -# Replace with the post ID you want to get quotes for -post_id = "1409931481552543749" - - -def get_params(): - return {"tweet.fields": "created_at"} - - -def create_url(): - return "https://api.x.com/2/tweets/{}/quote_tweets".format(post_id) - - -def bearer_oauth(r): - """ - Method required by bearer token authentication. - """ - r.headers["Authorization"] = f"Bearer {bearer_token}" - r.headers["User-Agent"] = "v2QuotePostsPython" - return r - - -def connect_to_endpoint(url, params): - response = requests.request("GET", url, auth=bearer_oauth, params=params) - print(response.status_code) - if response.status_code != 200: - raise Exception(response.status_code, response.text) - return response.json() - - -def main(): - url = create_url() - params = get_params() - json_response = connect_to_endpoint(url, params) - print(json.dumps(json_response, indent=4, sort_keys=True)) - - -if __name__ == "__main__": - main() diff --git a/python/posts/quote_tweets.py b/python/posts/quote_tweets.py deleted file mode 100644 index a56204c..0000000 --- a/python/posts/quote_tweets.py +++ /dev/null @@ -1,58 +0,0 @@ -import requests -import os -import json - -# To set your environment variables in your terminal run the following line: -# export 'BEARER_TOKEN'='' - - -def auth(): - return os.environ.get("BEARER_TOKEN") - - -def create_url(): - # Replace with Tweet ID below - tweet_id = 20 - return "https://api.x.com/2/tweets/{}/quote_tweets".format(tweet_id) - - -def get_params(): - # Tweet fields are adjustable. - # Options include: - # attachments, author_id, context_annotations, - # conversation_id, created_at, entities, geo, id, - # in_reply_to_user_id, lang, non_public_metrics, organic_metrics, - # possibly_sensitive, promoted_metrics, public_metrics, referenced_tweets, - # source, text, and withheld - return {"tweet.fields": "created_at"} - - -def create_headers(bearer_token): - headers = {"Authorization": "Bearer {}".format(bearer_token)} - return headers - - -def connect_to_endpoint(url, headers, params): - response = requests.request("GET", url, headers=headers, params=params) - print(response.status_code) - if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format( - response.status_code, response.text - ) - ) - return response.json() - - -def main(): - bearer_token = auth() - url = create_url() - headers = create_headers(bearer_token) - params = get_params() - json_response = connect_to_endpoint(url, headers, params) - print(json.dumps(json_response, indent=4, sort_keys=True)) - - -if __name__ == "__main__": - main() - \ No newline at end of file diff --git a/python/posts/recent_search.py b/python/posts/recent_search.py deleted file mode 100644 index 58b19a9..0000000 --- a/python/posts/recent_search.py +++ /dev/null @@ -1,39 +0,0 @@ -import requests -import os -import json - -# To set your environment variables in your terminal run the following line: -# export 'BEARER_TOKEN'='' -bearer_token = os.environ.get("BEARER_TOKEN") - -search_url = "https://api.x.com/2/tweets/search/recent" - -# Optional params: start_time,end_time,since_id,until_id,max_results,next_token, -# expansions,tweet.fields,media.fields,poll.fields,place.fields,user.fields -query_params = {'query': '(from:twitterdev -is:retweet) OR #twitterdev','tweet.fields': 'author_id'} - - -def bearer_oauth(r): - """ - Method required by bearer token authentication. - """ - - r.headers["Authorization"] = f"Bearer {bearer_token}" - r.headers["User-Agent"] = "v2RecentSearchPython" - return r - -def connect_to_endpoint(url, params): - response = requests.get(url, auth=bearer_oauth, params=params) - print(response.status_code) - if response.status_code != 200: - raise Exception(response.status_code, response.text) - return response.json() - - -def main(): - json_response = connect_to_endpoint(search_url, query_params) - print(json.dumps(json_response, indent=4, sort_keys=True)) - - -if __name__ == "__main__": - main() diff --git a/python/posts/recent_tweet_counts.py b/python/posts/recent_tweet_counts.py deleted file mode 100644 index 2b94f03..0000000 --- a/python/posts/recent_tweet_counts.py +++ /dev/null @@ -1,39 +0,0 @@ -import requests -import os -import json - -# To set your environment variables in your terminal run the following line: -# export 'BEARER_TOKEN'='' -bearer_token = os.environ.get("BEARER_TOKEN") - -search_url = "https://api.x.com/2/tweets/counts/recent" - -# Optional params: start_time,end_time,since_id,until_id,next_token,granularity -query_params = {'query': 'from:twitterdev','granularity': 'day'} - - -def bearer_oauth(r): - """ - Method required by bearer token authentication. - """ - - r.headers["Authorization"] = f"Bearer {bearer_token}" - r.headers["User-Agent"] = "v2RecentTweetCountsPython" - return r - - -def connect_to_endpoint(url, params): - response = requests.request("GET", url, auth=bearer_oauth, params=params) - print(response.status_code) - if response.status_code != 200: - raise Exception(response.status_code, response.text) - return response.json() - - -def main(): - json_response = connect_to_endpoint(search_url, query_params) - print(json.dumps(json_response, indent=4, sort_keys=True)) - - -if __name__ == "__main__": - main() diff --git a/python/posts/repost.py b/python/posts/repost.py deleted file mode 100644 index e5cd46e..0000000 --- a/python/posts/repost.py +++ /dev/null @@ -1,81 +0,0 @@ -""" -Repost (Retweet) - X API v2 -=========================== -Endpoint: POST https://api.x.com/2/users/:id/retweets -Docs: https://developer.x.com/en/docs/twitter-api/tweets/retweets/api-reference/post-users-id-retweets - -Authentication: OAuth 1.0a (User Context) -Required env vars: CONSUMER_KEY, CONSUMER_SECRET -""" - -from requests_oauthlib import OAuth1Session -import os -import json - -consumer_key = os.environ.get("CONSUMER_KEY") -consumer_secret = os.environ.get("CONSUMER_SECRET") - -# Replace with your own user ID (find using user lookup endpoint) -user_id = "your-user-id" - -# Replace with the post ID you want to repost -payload = {"tweet_id": "1412865600439738368"} - -# Get request token -request_token_url = "https://api.x.com/oauth/request_token" -oauth = OAuth1Session(consumer_key, client_secret=consumer_secret) - -try: - fetch_response = oauth.fetch_request_token(request_token_url) -except ValueError: - print( - "There may have been an issue with the consumer_key or consumer_secret you entered." - ) - -resource_owner_key = fetch_response.get("oauth_token") -resource_owner_secret = fetch_response.get("oauth_token_secret") -print("Got OAuth token: %s" % resource_owner_key) - -# Get authorization -base_authorization_url = "https://api.x.com/oauth/authorize" -authorization_url = oauth.authorization_url(base_authorization_url) -print("Please go here and authorize: %s" % authorization_url) -verifier = input("Paste the PIN here: ") - -# Get the access token -access_token_url = "https://api.x.com/oauth/access_token" -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=resource_owner_key, - resource_owner_secret=resource_owner_secret, - verifier=verifier, -) -oauth_tokens = oauth.fetch_access_token(access_token_url) - -access_token = oauth_tokens["oauth_token"] -access_token_secret = oauth_tokens["oauth_token_secret"] - -# Make the request -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=access_token, - resource_owner_secret=access_token_secret, -) - -# Making the request -response = oauth.post( - "https://api.x.com/2/users/{}/retweets".format(user_id), json=payload -) - -if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format(response.status_code, response.text) - ) - -print("Response code: {}".format(response.status_code)) - -# Saving the response as JSON -json_response = response.json() -print(json.dumps(json_response, indent=4, sort_keys=True)) diff --git a/python/posts/repost_post.py b/python/posts/repost_post.py new file mode 100644 index 0000000..646a8cd --- /dev/null +++ b/python/posts/repost_post.py @@ -0,0 +1,69 @@ +""" +Retweet (Repost) - X API v2 +=========================== +Endpoint: POST https://api.x.com/2/users/:id/retweets +Docs: https://developer.x.com/en/docs/twitter-api/tweets/retweets/api-reference/post-users-id-retweets + +Authentication: OAuth 2.0 (User Context) +Required env vars: CLIENT_ID, CLIENT_SECRET +""" + +import os +import json +from xdk import Client +from xdk.oauth2_auth import OAuth2PKCEAuth + +# The code below sets the client ID and client secret from your environment variables +# To set environment variables on macOS or Linux, run the export commands below from the terminal: +# export CLIENT_ID='YOUR-CLIENT-ID' +# export CLIENT_SECRET='YOUR-CLIENT-SECRET' +client_id = os.environ.get("CLIENT_ID") +client_secret = os.environ.get("CLIENT_SECRET") + +# Replace the following URL with your callback URL, which can be obtained from your App's auth settings. +redirect_uri = "https://example.com" + +# Set the scopes +scopes = ["tweet.read", "tweet.write", "users.read", "offline.access"] + +# You can replace the given Tweet ID with the Tweet ID you want to Retweet +# You can find a Tweet ID by using the Tweet lookup endpoint +post_id = "post-id" + +def main(): + # Step 1: Create PKCE instance + auth = OAuth2PKCEAuth( + client_id=client_id, + client_secret=client_secret, + redirect_uri=redirect_uri, + scope=scopes + ) + + # Step 2: Get authorization URL + auth_url = auth.get_authorization_url() + print("Visit the following URL to authorize your App on behalf of your X handle in a browser:") + print(auth_url) + + # Step 3: Handle callback + callback_url = input("Paste the full callback URL here: ") + + # Step 4: Exchange code for tokens + tokens = auth.fetch_token(authorization_response=callback_url) + access_token = tokens["access_token"] + + # Step 5: Create client + client = Client(access_token=access_token) + + # Step 6: Get the authenticated user's ID + user_me = client.users.get_me() + user_id = user_me.data["id"] + + # Step 7: Retweet the tweet + payload = {"tweet_id": post_id} + response = client.users.repost_post(user_id, body=payload) + + print("Response code: 200") + print(json.dumps(response.data, indent=4, sort_keys=True)) + +if __name__ == "__main__": + main() diff --git a/python/posts/reposted_by.py b/python/posts/reposted_by.py deleted file mode 100644 index c2ff4fc..0000000 --- a/python/posts/reposted_by.py +++ /dev/null @@ -1,53 +0,0 @@ -""" -Reposted By (Users who retweeted) - X API v2 -============================================ -Endpoint: GET https://api.x.com/2/tweets/:id/retweeted_by -Docs: https://developer.x.com/en/docs/twitter-api/tweets/retweets/api-reference/get-tweets-id-retweeted_by - -Authentication: Bearer Token (App-only) or OAuth (User Context) -Required env vars: BEARER_TOKEN -""" - -import requests -import os -import json - -bearer_token = os.environ.get("BEARER_TOKEN") - - -def create_url(): - # Replace with the post ID you want to get reposters for - post_id = "1354143047324299264" - return "https://api.x.com/2/tweets/{}/retweeted_by".format(post_id) - - -def get_params(): - return {"user.fields": "created_at"} - - -def bearer_oauth(r): - """ - Method required by bearer token authentication. - """ - r.headers["Authorization"] = f"Bearer {bearer_token}" - r.headers["User-Agent"] = "v2RepostedByPython" - return r - - -def connect_to_endpoint(url, params): - response = requests.request("GET", url, auth=bearer_oauth, params=params) - print(response.status_code) - if response.status_code != 200: - raise Exception(response.status_code, response.text) - return response.json() - - -def main(): - url = create_url() - params = get_params() - json_response = connect_to_endpoint(url, params) - print(json.dumps(json_response, indent=4, sort_keys=True)) - - -if __name__ == "__main__": - main() diff --git a/python/posts/retweet_a_tweet.py b/python/posts/retweet_a_tweet.py deleted file mode 100644 index 40c218b..0000000 --- a/python/posts/retweet_a_tweet.py +++ /dev/null @@ -1,78 +0,0 @@ -from requests_oauthlib import OAuth1Session -import os -import json - -# In your terminal please set your environment variables by running the following lines of code. -# export 'CONSUMER_KEY'='' -# export 'CONSUMER_SECRET'='' - -consumer_key = os.environ.get("CONSUMER_KEY") -consumer_secret = os.environ.get("CONSUMER_SECRET") - - -# Be sure to replace your-user-id with your own user ID or one of an authenticating user -# You can find a user ID by using the user lookup endpoint -id = "your-user-id" - -# You can replace the given Tweet ID with your the Tweet ID you want to Retweet -# You can find a Tweet ID by using the Tweet lookup endpoint -payload = {"tweet_id": "1412865600439738368"} - -# Get request token -request_token_url = "https://api.x.com/oauth/request_token" -oauth = OAuth1Session(consumer_key, client_secret=consumer_secret) - -try: - fetch_response = oauth.fetch_request_token(request_token_url) -except ValueError: - print( - "There may have been an issue with the consumer_key or consumer_secret you entered." - ) - -resource_owner_key = fetch_response.get("oauth_token") -resource_owner_secret = fetch_response.get("oauth_token_secret") -print("Got OAuth token: %s" % resource_owner_key) - -# Get authorization -base_authorization_url = "https://api.x.com/oauth/authorize" -authorization_url = oauth.authorization_url(base_authorization_url) -print("Please go here and authorize: %s" % authorization_url) -verifier = input("Paste the PIN here: ") - -# Get the access token -access_token_url = "https://api.x.com/oauth/access_token" -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=resource_owner_key, - resource_owner_secret=resource_owner_secret, - verifier=verifier, -) -oauth_tokens = oauth.fetch_access_token(access_token_url) - -access_token = oauth_tokens["oauth_token"] -access_token_secret = oauth_tokens["oauth_token_secret"] - -# Make the request -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=access_token, - resource_owner_secret=access_token_secret, -) - -# Making the request -response = oauth.post( - "https://api.x.com/2/users/{}/retweets".format(id), json=payload -) - -if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format(response.status_code, response.text) - ) - -print("Response code: {}".format(response.status_code)) - -# Saving the response as JSON -json_response = response.json() -print(json.dumps(json_response, indent=4, sort_keys=True)) diff --git a/python/posts/retweeted_by.py b/python/posts/retweeted_by.py deleted file mode 100644 index 9876a36..0000000 --- a/python/posts/retweeted_by.py +++ /dev/null @@ -1,56 +0,0 @@ -import requests -import os -import json - -# To set your enviornment variables in your terminal run the following line: -# export 'BEARER_TOKEN'='' - - -bearer_token = os.environ.get("BEARER_TOKEN") - - -def create_url(): - # User fields are adjustable, options include: - # created_at, description, entities, id, location, name, - # pinned_tweet_id, profile_image_url, protected, - # public_metrics, url, username, verified, and withheld - user_fields = "user.fields=created_at,description" - # You can replace the ID given with the Tweet ID you wish to lookup Retweeting users for - # You can find an ID by using the Tweet lookup endpoint - id = "1354143047324299264" - # You can adjust ids to include a single Tweets. - # Or you can add to up to 100 comma-separated IDs - url = "https://api.x.com/2/tweets/{}/retweeted_by".format(id) - return url, user_fields - - -def bearer_oauth(r): - """ - Method required by bearer token authentication. - """ - - r.headers["Authorization"] = f"Bearer {bearer_token}" - r.headers["User-Agent"] = "v2RetweetedByPython" - return r - - -def connect_to_endpoint(url, user_fields): - response = requests.request("GET", url, auth=bearer_oauth, params=user_fields) - print(response.status_code) - if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format( - response.status_code, response.text - ) - ) - return response.json() - - -def main(): - url, user_fields = create_url() - json_response = connect_to_endpoint(url, user_fields) - print(json.dumps(json_response, indent=4, sort_keys=True)) - - -if __name__ == "__main__": - main() diff --git a/python/posts/search_all.py b/python/posts/search_all.py new file mode 100644 index 0000000..2f47372 --- /dev/null +++ b/python/posts/search_all.py @@ -0,0 +1,43 @@ +""" +Full-Archive Search - X API v2 +============================== +Endpoint: GET https://api.x.com/2/tweets/search/all +Docs: https://developer.x.com/en/docs/twitter-api/tweets/search/api-reference/get-tweets-search-all + +Authentication: Bearer Token (App-only) +Required env vars: BEARER_TOKEN + +Note: Requires Academic Research access. Returns posts from the entire archive. +This example demonstrates automatic pagination using the iterate() method +to fetch all pages of results. +""" + +import os +import json +from xdk import Client + +bearer_token = os.environ.get("BEARER_TOKEN") +client = Client(bearer_token=bearer_token) + +query = '(from:xdevelopers -is:retweet) OR #xdevelopers' + +def main(): + # Search with automatic pagination + all_posts = [] + for page in client.posts.search_all( + query=query, + max_results=100, # Per page + tweet_fields=["author_id", "created_at"] + ): + # Access data attribute (model uses extra='allow' so data should be available) + # Use getattr with fallback in case data field is missing from response + page_data = getattr(page, 'data', []) or [] + all_posts.extend(page_data) + print(f"Fetched {len(page_data)} Posts (total: {len(all_posts)})") + + print(f"\nTotal Posts: {len(all_posts)}") + print(json.dumps({"data": all_posts[:5]}, indent=4, sort_keys=True)) # Print first 5 as example + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/python/posts/search_full_archive.py b/python/posts/search_full_archive.py deleted file mode 100644 index e9c9bc8..0000000 --- a/python/posts/search_full_archive.py +++ /dev/null @@ -1,53 +0,0 @@ -""" -Full-Archive Search - X API v2 -============================== -Endpoint: GET https://api.x.com/2/tweets/search/all -Docs: https://developer.x.com/en/docs/twitter-api/tweets/search/api-reference/get-tweets-search-all - -Authentication: Bearer Token (App-only) -Required env vars: BEARER_TOKEN - -Note: Requires Academic Research access. Returns posts from the entire archive. -""" - -import requests -import os -import json - -bearer_token = os.environ.get("BEARER_TOKEN") - -search_url = "https://api.x.com/2/tweets/search/all" - -# Optional params: start_time, end_time, since_id, until_id, max_results, -# next_token, expansions, tweet.fields, media.fields, poll.fields, -# place.fields, user.fields -query_params = { - 'query': '(from:XDevelopers -is:retweet) OR #xapi', - 'tweet.fields': 'author_id' -} - - -def bearer_oauth(r): - """ - Method required by bearer token authentication. - """ - r.headers["Authorization"] = f"Bearer {bearer_token}" - r.headers["User-Agent"] = "v2FullArchiveSearchPython" - return r - - -def connect_to_endpoint(url, params): - response = requests.get(url, auth=bearer_oauth, params=params) - print(response.status_code) - if response.status_code != 200: - raise Exception(response.status_code, response.text) - return response.json() - - -def main(): - json_response = connect_to_endpoint(search_url, query_params) - print(json.dumps(json_response, indent=4, sort_keys=True)) - - -if __name__ == "__main__": - main() diff --git a/python/posts/search_recent.py b/python/posts/search_recent.py index 9538a83..8eb36f8 100644 --- a/python/posts/search_recent.py +++ b/python/posts/search_recent.py @@ -4,48 +4,39 @@ Endpoint: GET https://api.x.com/2/tweets/search/recent Docs: https://developer.x.com/en/docs/twitter-api/tweets/search/api-reference/get-tweets-search-recent -Authentication: Bearer Token (App-only) or OAuth (User Context) +Authentication: Bearer Token (App-only) Required env vars: BEARER_TOKEN Note: Returns posts from the last 7 days. +This example demonstrates automatic pagination using the iterate() method +to fetch all pages of results. """ -import requests import os import json +from xdk import Client bearer_token = os.environ.get("BEARER_TOKEN") +client = Client(bearer_token=bearer_token) -search_url = "https://api.x.com/2/tweets/search/recent" - -# Optional params: start_time, end_time, since_id, until_id, max_results, next_token, -# expansions, tweet.fields, media.fields, poll.fields, place.fields, user.fields -query_params = { - 'query': '(from:XDevelopers -is:retweet) OR #xapi', - 'tweet.fields': 'author_id' -} - - -def bearer_oauth(r): - """ - Method required by bearer token authentication. - """ - r.headers["Authorization"] = f"Bearer {bearer_token}" - r.headers["User-Agent"] = "v2RecentSearchPython" - return r - - -def connect_to_endpoint(url, params): - response = requests.get(url, auth=bearer_oauth, params=params) - print(response.status_code) - if response.status_code != 200: - raise Exception(response.status_code, response.text) - return response.json() - +query = '(from:XDevelopers -is:retweet) OR #XDevelopers' def main(): - json_response = connect_to_endpoint(search_url, query_params) - print(json.dumps(json_response, indent=4, sort_keys=True)) + # Search with automatic pagination + all_posts = [] + for page in client.posts.search_recent( + query=query, + max_results=100, # Per page + tweet_fields=["author_id", "created_at"] + ): + # Access data attribute (model uses extra='allow' so data should be available) + # Use getattr with fallback in case data field is missing from response + page_data = getattr(page, 'data', []) or [] + all_posts.extend(page_data) + print(f"Fetched {len(page_data)} Posts (total: {len(all_posts)})") + + print(f"\nTotal Posts: {len(all_posts)}") + print(json.dumps({"data": all_posts[:5]}, indent=4, sort_keys=True)) # Print first 5 as example if __name__ == "__main__": diff --git a/python/posts/undo_a_retweet.py b/python/posts/undo_a_retweet.py deleted file mode 100644 index 51fe32d..0000000 --- a/python/posts/undo_a_retweet.py +++ /dev/null @@ -1,79 +0,0 @@ -from requests_oauthlib import OAuth1Session -import os -import json - -# In your terminal please set your environment variables by running the following lines of code. -# export 'CONSUMER_KEY'='' -# export 'CONSUMER_SECRET'='' - -consumer_key = os.environ.get("CONSUMER_KEY") -consumer_secret = os.environ.get("CONSUMER_SECRET") - - -# Be sure to replace your-user-id with your own user ID or one of an authenticated user -# You can find a user ID by using the user lookup endpoint -id = "your-user-id" - -# You can replace the given Tweet ID with your the Tweet ID you want to Retweet -# You can find a Tweet ID by using the Tweet lookup endpoint -source_tweet_id = "1412865600439738368" - - -# Get request token -request_token_url = "https://api.x.com/oauth/request_token" -oauth = OAuth1Session(consumer_key, client_secret=consumer_secret) - -try: - fetch_response = oauth.fetch_request_token(request_token_url) -except ValueError: - print( - "There may have been an issue with the consumer_key or consumer_secret you entered." - ) - -resource_owner_key = fetch_response.get("oauth_token") -resource_owner_secret = fetch_response.get("oauth_token_secret") -print("Got OAuth token: %s" % resource_owner_key) - -# Get authorization -base_authorization_url = "https://api.x.com/oauth/authorize" -authorization_url = oauth.authorization_url(base_authorization_url) -print("Please go here and authorize: %s" % authorization_url) -verifier = input("Paste the PIN here: ") - -# Get the access token -access_token_url = "https://api.x.com/oauth/access_token" -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=resource_owner_key, - resource_owner_secret=resource_owner_secret, - verifier=verifier, -) -oauth_tokens = oauth.fetch_access_token(access_token_url) - -access_token = oauth_tokens["oauth_token"] -access_token_secret = oauth_tokens["oauth_token_secret"] - -# Make the request -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=access_token, - resource_owner_secret=access_token_secret, -) - -# Making the request -response = oauth.delete( - "https://api.x.com/2/users/{}/retweets/{}".format(id, source_tweet_id) -) - -if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format(response.status_code, response.text) - ) - -print("Response code: {}".format(response.status_code)) - -# Saving the response as JSON -json_response = response.json() -print(json.dumps(json_response, indent=4, sort_keys=True)) diff --git a/python/posts/undo_repost.py b/python/posts/undo_repost.py deleted file mode 100644 index fb87599..0000000 --- a/python/posts/undo_repost.py +++ /dev/null @@ -1,81 +0,0 @@ -""" -Undo Repost (Unretweet) - X API v2 -================================== -Endpoint: DELETE https://api.x.com/2/users/:id/retweets/:source_tweet_id -Docs: https://developer.x.com/en/docs/twitter-api/tweets/retweets/api-reference/delete-users-id-retweets-tweet_id - -Authentication: OAuth 1.0a (User Context) -Required env vars: CONSUMER_KEY, CONSUMER_SECRET -""" - -from requests_oauthlib import OAuth1Session -import os -import json - -consumer_key = os.environ.get("CONSUMER_KEY") -consumer_secret = os.environ.get("CONSUMER_SECRET") - -# Replace with your own user ID -user_id = "your-user-id" - -# Replace with the post ID you want to undo repost for -source_post_id = "post-id-to-unrepost" - -# Get request token -request_token_url = "https://api.x.com/oauth/request_token" -oauth = OAuth1Session(consumer_key, client_secret=consumer_secret) - -try: - fetch_response = oauth.fetch_request_token(request_token_url) -except ValueError: - print( - "There may have been an issue with the consumer_key or consumer_secret you entered." - ) - -resource_owner_key = fetch_response.get("oauth_token") -resource_owner_secret = fetch_response.get("oauth_token_secret") -print("Got OAuth token: %s" % resource_owner_key) - -# Get authorization -base_authorization_url = "https://api.x.com/oauth/authorize" -authorization_url = oauth.authorization_url(base_authorization_url) -print("Please go here and authorize: %s" % authorization_url) -verifier = input("Paste the PIN here: ") - -# Get the access token -access_token_url = "https://api.x.com/oauth/access_token" -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=resource_owner_key, - resource_owner_secret=resource_owner_secret, - verifier=verifier, -) -oauth_tokens = oauth.fetch_access_token(access_token_url) - -access_token = oauth_tokens["oauth_token"] -access_token_secret = oauth_tokens["oauth_token_secret"] - -# Make the request -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=access_token, - resource_owner_secret=access_token_secret, -) - -# Making the request -response = oauth.delete( - "https://api.x.com/2/users/{}/retweets/{}".format(user_id, source_post_id) -) - -if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format(response.status_code, response.text) - ) - -print("Response code: {}".format(response.status_code)) - -# Saving the response as JSON -json_response = response.json() -print(json.dumps(json_response, indent=4, sort_keys=True)) diff --git a/python/posts/unlike.py b/python/posts/unlike.py deleted file mode 100644 index 4691558..0000000 --- a/python/posts/unlike.py +++ /dev/null @@ -1,81 +0,0 @@ -""" -Unlike a Post - X API v2 -======================== -Endpoint: DELETE https://api.x.com/2/users/:id/likes/:tweet_id -Docs: https://developer.x.com/en/docs/twitter-api/tweets/likes/api-reference/delete-users-id-likes-tweet_id - -Authentication: OAuth 1.0a (User Context) -Required env vars: CONSUMER_KEY, CONSUMER_SECRET -""" - -from requests_oauthlib import OAuth1Session -import os -import json - -consumer_key = os.environ.get("CONSUMER_KEY") -consumer_secret = os.environ.get("CONSUMER_SECRET") - -# Replace with your own user ID -user_id = "your-user-id" - -# Replace with the post ID you want to unlike -post_id = "post-id-to-unlike" - -# Get request token -request_token_url = "https://api.x.com/oauth/request_token" -oauth = OAuth1Session(consumer_key, client_secret=consumer_secret) - -try: - fetch_response = oauth.fetch_request_token(request_token_url) -except ValueError: - print( - "There may have been an issue with the consumer_key or consumer_secret you entered." - ) - -resource_owner_key = fetch_response.get("oauth_token") -resource_owner_secret = fetch_response.get("oauth_token_secret") -print("Got OAuth token: %s" % resource_owner_key) - -# Get authorization -base_authorization_url = "https://api.x.com/oauth/authorize" -authorization_url = oauth.authorization_url(base_authorization_url) -print("Please go here and authorize: %s" % authorization_url) -verifier = input("Paste the PIN here: ") - -# Get the access token -access_token_url = "https://api.x.com/oauth/access_token" -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=resource_owner_key, - resource_owner_secret=resource_owner_secret, - verifier=verifier, -) -oauth_tokens = oauth.fetch_access_token(access_token_url) - -access_token = oauth_tokens["oauth_token"] -access_token_secret = oauth_tokens["oauth_token_secret"] - -# Make the request -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=access_token, - resource_owner_secret=access_token_secret, -) - -# Making the request -response = oauth.delete( - "https://api.x.com/2/users/{}/likes/{}".format(user_id, post_id) -) - -if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format(response.status_code, response.text) - ) - -print("Response code: {}".format(response.status_code)) - -# Saving the response as JSON -json_response = response.json() -print(json.dumps(json_response, indent=4, sort_keys=True)) diff --git a/python/posts/unlike_a_tweet.py b/python/posts/unlike_a_tweet.py deleted file mode 100644 index 91ff611..0000000 --- a/python/posts/unlike_a_tweet.py +++ /dev/null @@ -1,77 +0,0 @@ -from requests_oauthlib import OAuth1Session -import os -import json - -# In your terminal please set your environment variables by running the following lines of code. -# export 'CONSUMER_KEY'='' -# export 'CONSUMER_SECRET'='' -consumer_key = os.environ.get("CONSUMER_KEY") -consumer_secret = os.environ.get("CONSUMER_SECRET") - -# Be sure to replace your-user-id with your own user ID or one of an authenticated user -# You can find a user ID by using the user lookup endpoint -id = "your-user-id" - -# You can replace Tweet ID given with the Tweet ID you wish to like. -# You can find a Tweet ID by using the Tweet lookup endpoint -tweet_id = "1354143047324299264" - -# Get request token -request_token_url = "https://api.x.com/oauth/request_token" -oauth = OAuth1Session(consumer_key, client_secret=consumer_secret) - -try: - fetch_response = oauth.fetch_request_token(request_token_url) -except ValueError: - print( - "There may have been an issue with the consumer_key or consumer_secret you entered." - ) - -resource_owner_key = fetch_response.get("oauth_token") -resource_owner_secret = fetch_response.get("oauth_token_secret") -print("Got OAuth token: %s" % resource_owner_key) - -# Get authorization -base_authorization_url = "https://api.x.com/oauth/authorize" -authorization_url = oauth.authorization_url(base_authorization_url) -print("Please go here and authorize: %s" % authorization_url) -verifier = input("Paste the PIN here: ") - -# Get the access token -access_token_url = "https://api.x.com/oauth/access_token" -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=resource_owner_key, - resource_owner_secret=resource_owner_secret, - verifier=verifier, -) -oauth_tokens = oauth.fetch_access_token(access_token_url) - -access_token = oauth_tokens["oauth_token"] -access_token_secret = oauth_tokens["oauth_token_secret"] - -# Make the request -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=access_token, - resource_owner_secret=access_token_secret, -) - -# Making the request -response = oauth.delete( - "https://api.x.com/2/users/{}/likes/{}".format(id, tweet_id) -) - -if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format( - response.status_code, response.text) - ) - -print("Response code: {}".format(response.status_code)) - -# Saving the response as JSON -json_response = response.json() -print(json.dumps(json_response, indent=4, sort_keys=True)) diff --git a/python/posts/unlike_post.py b/python/posts/unlike_post.py new file mode 100644 index 0000000..7de7542 --- /dev/null +++ b/python/posts/unlike_post.py @@ -0,0 +1,68 @@ +""" +Unlike a Tweet - X API v2 +======================== +Endpoint: DELETE https://api.x.com/2/users/:id/likes/:tweet_id +Docs: https://developer.x.com/en/docs/twitter-api/tweets/likes/api-reference/delete-users-id-likes-tweet_id + +Authentication: OAuth 2.0 (User Context) +Required env vars: CLIENT_ID, CLIENT_SECRET +""" + +import os +import json +from xdk import Client +from xdk.oauth2_auth import OAuth2PKCEAuth + +# The code below sets the client ID and client secret from your environment variables +# To set environment variables on macOS or Linux, run the export commands below from the terminal: +# export CLIENT_ID='YOUR-CLIENT-ID' +# export CLIENT_SECRET='YOUR-CLIENT-SECRET' +client_id = os.environ.get("CLIENT_ID") +client_secret = os.environ.get("CLIENT_SECRET") + +# Replace the following URL with your callback URL, which can be obtained from your App's auth settings. +redirect_uri = "https://example.com" + +# Set the scopes +scopes = ["tweet.read", "tweet.write", "users.read", "offline.access", "like.write"] + +# You can replace Tweet ID given with the Tweet ID you wish to unlike. +# You can find a Tweet ID by using the Tweet lookup endpoint +post_id = "post-id" + +def main(): + # Step 1: Create PKCE instance + auth = OAuth2PKCEAuth( + client_id=client_id, + client_secret=client_secret, + redirect_uri=redirect_uri, + scope=scopes + ) + + # Step 2: Get authorization URL + auth_url = auth.get_authorization_url() + print("Visit the following URL to authorize your App on behalf of your X handle in a browser:") + print(auth_url) + + # Step 3: Handle callback + callback_url = input("Paste the full callback URL here: ") + + # Step 4: Exchange code for tokens + tokens = auth.fetch_token(authorization_response=callback_url) + access_token = tokens["access_token"] + + # Step 5: Create client + client = Client(access_token=access_token) + + # Step 6: Get the authenticated user's ID + user_me = client.users.get_me() + user_id = user_me.data["id"] + + # Step 7: Unlike the tweet + response = client.users.unlike_post(user_id, tweet_id=post_id) + + print("Response code: 200") + print(json.dumps(response.data, indent=4, sort_keys=True)) + +if __name__ == "__main__": + main() diff --git a/python/posts/unrepost_post.py b/python/posts/unrepost_post.py new file mode 100644 index 0000000..f513ce5 --- /dev/null +++ b/python/posts/unrepost_post.py @@ -0,0 +1,68 @@ +""" +Undo Retweet (Unrepost) - X API v2 +================================== +Endpoint: DELETE https://api.x.com/2/users/:id/retweets/:source_tweet_id +Docs: https://developer.x.com/en/docs/twitter-api/tweets/retweets/api-reference/delete-users-id-retweets-tweet_id + +Authentication: OAuth 2.0 (User Context) +Required env vars: CLIENT_ID, CLIENT_SECRET +""" + +import os +import json +from xdk import Client +from xdk.oauth2_auth import OAuth2PKCEAuth + +# The code below sets the client ID and client secret from your environment variables +# To set environment variables on macOS or Linux, run the export commands below from the terminal: +# export CLIENT_ID='YOUR-CLIENT-ID' +# export CLIENT_SECRET='YOUR-CLIENT-SECRET' +client_id = os.environ.get("CLIENT_ID") +client_secret = os.environ.get("CLIENT_SECRET") + +# Replace the following URL with your callback URL, which can be obtained from your App's auth settings. +redirect_uri = "https://example.com" + +# Set the scopes +scopes = ["tweet.read", "tweet.write", "users.read", "offline.access"] + +# You can replace the given Tweet ID with the Tweet ID you want to undo retweet for +# You can find a Tweet ID by using the Tweet lookup endpoint +source_post_id = "post-id" + +def main(): + # Step 1: Create PKCE instance + auth = OAuth2PKCEAuth( + client_id=client_id, + client_secret=client_secret, + redirect_uri=redirect_uri, + scope=scopes + ) + + # Step 2: Get authorization URL + auth_url = auth.get_authorization_url() + print("Visit the following URL to authorize your App on behalf of your X handle in a browser:") + print(auth_url) + + # Step 3: Handle callback + callback_url = input("Paste the full callback URL here: ") + + # Step 4: Exchange code for tokens + tokens = auth.fetch_token(authorization_response=callback_url) + access_token = tokens["access_token"] + + # Step 5: Create client + client = Client(access_token=access_token) + + # Step 6: Get the authenticated user's ID + user_me = client.users.get_me() + user_id = user_me.data["id"] + + # Step 7: Undo retweet + response = client.users.unrepost_post(user_id, source_tweet_id=source_post_id) + + print("Response code: 200") + print(json.dumps(response.data, indent=4, sort_keys=True)) + +if __name__ == "__main__": + main() diff --git a/python/requirements.txt b/python/requirements.txt index a85ab73..ebc8553 100644 --- a/python/requirements.txt +++ b/python/requirements.txt @@ -1,2 +1 @@ -requests>=2.28.0 -requests-oauthlib>=1.3.0 +xdk>=0.4.5 diff --git a/python/spaces/get_by_ids.py b/python/spaces/get_by_ids.py new file mode 100644 index 0000000..3563d08 --- /dev/null +++ b/python/spaces/get_by_ids.py @@ -0,0 +1,34 @@ +""" +Spaces Lookup - X API v2 +======================== +Endpoint: GET https://api.x.com/2/spaces +Docs: https://developer.x.com/en/docs/twitter-api/spaces/lookup/api-reference/get-spaces + +Authentication: Bearer Token (App-only) or OAuth (User Context) +Required env vars: BEARER_TOKEN +""" + +import os +import json +from xdk import Client + +bearer_token = os.environ.get("BEARER_TOKEN") +client = Client(bearer_token=bearer_token) + +# Space IDs to look up (list) +# You can replace the IDs with actual Space IDs you want to look up +space_ids = ["space-id-1", "space-id-2"] + +def main(): + # Optional params: host_ids, conversation_controls, created_at, creator_id, id, invited_user_ids, + # is_ticketed, lang, media_key, participants, scheduled_start, speaker_ids, started_at, state, title, updated_at + response = client.spaces.get_by_ids( + ids=space_ids, + space_fields=["title", "created_at"], + expansions=["creator_id"] + ) + + print(json.dumps(response.data, indent=4, sort_keys=True)) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/python/spaces/lookup.py b/python/spaces/lookup.py deleted file mode 100644 index 5a0f185..0000000 --- a/python/spaces/lookup.py +++ /dev/null @@ -1,55 +0,0 @@ -""" -Spaces Lookup - X API v2 -======================== -Endpoint: GET https://api.x.com/2/spaces -Docs: https://developer.x.com/en/docs/twitter-api/spaces/lookup/api-reference/get-spaces - -Authentication: Bearer Token (App-only) or OAuth (User Context) -Required env vars: BEARER_TOKEN -""" - -import requests -import os -import json - -bearer_token = os.environ.get("BEARER_TOKEN") - - -def create_url(): - # Space IDs to look up (comma-separated) - space_ids = "ids=1DXxyRYNejbKM" - - # Space fields are adjustable. Options include: - # host_ids, created_at, creator_id, id, lang, invited_user_ids, - # participant_count, speaker_ids, started_at, ended_at, subscriber_count, - # topic_ids, state, title, updated_at, scheduled_start, is_ticketed - space_fields = "space.fields=host_ids,created_at,creator_id,participant_count,title,state" - url = "https://api.x.com/2/spaces?{}&{}".format(space_ids, space_fields) - return url - - -def bearer_oauth(r): - """ - Method required by bearer token authentication. - """ - r.headers["Authorization"] = f"Bearer {bearer_token}" - r.headers["User-Agent"] = "v2SpacesLookupPython" - return r - - -def connect_to_endpoint(url): - response = requests.request("GET", url, auth=bearer_oauth) - print(response.status_code) - if response.status_code != 200: - raise Exception(response.status_code, response.text) - return response.json() - - -def main(): - url = create_url() - json_response = connect_to_endpoint(url) - print(json.dumps(json_response, indent=4, sort_keys=True)) - - -if __name__ == "__main__": - main() diff --git a/python/spaces/search.py b/python/spaces/search.py deleted file mode 100644 index 7678e2e..0000000 --- a/python/spaces/search.py +++ /dev/null @@ -1,55 +0,0 @@ -""" -Spaces Search - X API v2 -======================== -Endpoint: GET https://api.x.com/2/spaces/search -Docs: https://developer.x.com/en/docs/twitter-api/spaces/search/api-reference/get-spaces-search - -Authentication: Bearer Token (App-only) or OAuth (User Context) -Required env vars: BEARER_TOKEN -""" - -import requests -import os -import json - -bearer_token = os.environ.get("BEARER_TOKEN") - - -def create_url(): - query = "query=crypto" - state = "state=live" - - # Space fields are adjustable. Options include: - # host_ids, created_at, creator_id, id, lang, invited_user_ids, - # participant_count, speaker_ids, started_at, ended_at, subscriber_count, - # topic_ids, state, title, updated_at, scheduled_start, is_ticketed - space_fields = "space.fields=host_ids,created_at,participant_count,title" - url = "https://api.x.com/2/spaces/search?{}&{}&{}".format(query, state, space_fields) - return url - - -def bearer_oauth(r): - """ - Method required by bearer token authentication. - """ - r.headers["Authorization"] = f"Bearer {bearer_token}" - r.headers["User-Agent"] = "v2SpacesSearchPython" - return r - - -def connect_to_endpoint(url): - response = requests.request("GET", url, auth=bearer_oauth) - print(response.status_code) - if response.status_code != 200: - raise Exception(response.status_code, response.text) - return response.json() - - -def main(): - url = create_url() - json_response = connect_to_endpoint(url) - print(json.dumps(json_response, indent=4, sort_keys=True)) - - -if __name__ == "__main__": - main() diff --git a/python/spaces/search_spaces.py b/python/spaces/search_spaces.py index d0c6340..9004708 100644 --- a/python/spaces/search_spaces.py +++ b/python/spaces/search_spaces.py @@ -1,40 +1,33 @@ -import requests +""" +Search Spaces - X API v2 +======================== +Endpoint: GET https://api.x.com/2/spaces/search +Docs: https://developer.x.com/en/docs/twitter-api/spaces/search/api-reference/get-spaces-search + +Authentication: Bearer Token (App-only) or OAuth (User Context) +Required env vars: BEARER_TOKEN +""" + import os import json +from xdk import Client -# To set your environment variables in your terminal run the following line: -# export 'BEARER_TOKEN'='' bearer_token = os.environ.get("BEARER_TOKEN") +client = Client(bearer_token=bearer_token) -search_url = "https://api.x.com/2/spaces/search" - -search_term = 'NBA' # Replace this value with your search term - -# Optional params: host_ids,conversation_controls,created_at,creator_id,id,invited_user_ids,is_ticketed,lang,media_key,participants,scheduled_start,speaker_ids,started_at,state,title,updated_at -query_params = {'query': search_term, 'space.fields': 'title,created_at', 'expansions': 'creator_id'} - - -def create_headers(bearer_token): - headers = { - "Authorization": "Bearer {}".format(bearer_token), - "User-Agent": "v2SpacesSearchPython" - } - return headers - - -def connect_to_endpoint(url, headers, params): - response = requests.request("GET", search_url, headers=headers, params=params) - print(response.status_code) - if response.status_code != 200: - raise Exception(response.status_code, response.text) - return response.json() - +# Replace this value with your search term +search_term = 'NBA' def main(): - headers = create_headers(bearer_token) - json_response = connect_to_endpoint(search_url, headers, query_params) - print(json.dumps(json_response, indent=4, sort_keys=True)) - + # Optional params: host_ids, conversation_controls, created_at, creator_id, id, invited_user_ids, + # is_ticketed, lang, media_key, participants, scheduled_start, speaker_ids, started_at, state, title, updated_at + response = client.spaces.search( + query=search_term, + space_fields=["title", "created_at"], + expansions=["creator_id"] + ) + + print(json.dumps(response.data, indent=4, sort_keys=True)) if __name__ == "__main__": main() \ No newline at end of file diff --git a/python/spaces/spaces_lookup.py b/python/spaces/spaces_lookup.py deleted file mode 100644 index 7c576d7..0000000 --- a/python/spaces/spaces_lookup.py +++ /dev/null @@ -1,38 +0,0 @@ -import requests -import os -import json - -# To set your environment variables in your terminal run the following line: -# export 'BEARER_TOKEN'='' -bearer_token = os.environ.get("BEARER_TOKEN") - -search_url = "https://api.x.com/2/spaces" - -# Optional params: host_ids,conversation_controls,created_at,creator_id,id,invited_user_ids,is_ticketed,lang,media_key,participants,scheduled_start,speaker_ids,started_at,state,title,updated_at -query_params = {'ids': 'SPACE_ID', 'space.fields': 'title,created_at', 'expansions': 'creator_id'} - - -def create_headers(bearer_token): - headers = { - "Authorization": "Bearer {}".format(bearer_token), - "User-Agent": "v2SpacesLookupPython" - } - return headers - - -def connect_to_endpoint(url, headers, params): - response = requests.request("GET", search_url, headers=headers, params=params) - print(response.status_code) - if response.status_code != 200: - raise Exception(response.status_code, response.text) - return response.json() - - -def main(): - headers = create_headers(bearer_token) - json_response = connect_to_endpoint(search_url, headers, query_params) - print(json.dumps(json_response, indent=4, sort_keys=True)) - - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/python/streams/filtered_stream.py b/python/streams/filtered_stream.py deleted file mode 100644 index 88d578b..0000000 --- a/python/streams/filtered_stream.py +++ /dev/null @@ -1,96 +0,0 @@ -import requests -import os -import json - -# To set your enviornment variables in your terminal run the following line: -# export 'BEARER_TOKEN'='' -bearer_token = os.environ.get("BEARER_TOKEN") - - -def bearer_oauth(r): - """ - Method required by bearer token authentication. - """ - - r.headers["Authorization"] = f"Bearer {bearer_token}" - r.headers["User-Agent"] = "v2FilteredStreamPython" - return r - - -def get_rules(): - response = requests.get( - "https://api.x.com/2/tweets/search/stream/rules", auth=bearer_oauth - ) - if response.status_code != 200: - raise Exception( - "Cannot get rules (HTTP {}): {}".format(response.status_code, response.text) - ) - print(json.dumps(response.json())) - return response.json() - - -def delete_all_rules(rules): - if rules is None or "data" not in rules: - return None - - ids = list(map(lambda rule: rule["id"], rules["data"])) - payload = {"delete": {"ids": ids}} - response = requests.post( - "https://api.x.com/2/tweets/search/stream/rules", - auth=bearer_oauth, - json=payload - ) - if response.status_code != 200: - raise Exception( - "Cannot delete rules (HTTP {}): {}".format( - response.status_code, response.text - ) - ) - print(json.dumps(response.json())) - - -def set_rules(delete): - # You can adjust the rules if needed - sample_rules = [ - {"value": "dog has:images", "tag": "dog pictures"}, - {"value": "cat has:images -grumpy", "tag": "cat pictures"}, - ] - payload = {"add": sample_rules} - response = requests.post( - "https://api.x.com/2/tweets/search/stream/rules", - auth=bearer_oauth, - json=payload, - ) - if response.status_code != 201: - raise Exception( - "Cannot add rules (HTTP {}): {}".format(response.status_code, response.text) - ) - print(json.dumps(response.json())) - - -def get_stream(set): - response = requests.get( - "https://api.x.com/2/tweets/search/stream", auth=bearer_oauth, stream=True, - ) - print(response.status_code) - if response.status_code != 200: - raise Exception( - "Cannot get stream (HTTP {}): {}".format( - response.status_code, response.text - ) - ) - for response_line in response.iter_lines(): - if response_line: - json_response = json.loads(response_line) - print(json.dumps(json_response, indent=4, sort_keys=True)) - - -def main(): - rules = get_rules() - delete = delete_all_rules(rules) - set = set_rules(delete) - get_stream(set) - - -if __name__ == "__main__": - main() diff --git a/python/streams/sampled-stream.py b/python/streams/sampled-stream.py deleted file mode 100644 index ef0eb9d..0000000 --- a/python/streams/sampled-stream.py +++ /dev/null @@ -1,48 +0,0 @@ -import requests -import os -import json - -# To set your environment variables in your terminal run the following line: -# export 'BEARER_TOKEN'='' -bearer_token = os.environ.get("BEARER_TOKEN") - - -def create_url(): - return "https://api.x.com/2/tweets/sample/stream" - - -def bearer_oauth(r): - """ - Method required by bearer token authentication. - """ - - r.headers["Authorization"] = f"Bearer {bearer_token}" - r.headers["User-Agent"] = "v2SampledStreamPython" - return r - - -def connect_to_endpoint(url): - response = requests.request("GET", url, auth=bearer_oauth, stream=True) - print(response.status_code) - for response_line in response.iter_lines(): - if response_line: - json_response = json.loads(response_line) - print(json.dumps(json_response, indent=4, sort_keys=True)) - if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format( - response.status_code, response.text - ) - ) - - -def main(): - url = create_url() - timeout = 0 - while True: - connect_to_endpoint(url) - timeout += 1 - - -if __name__ == "__main__": - main() diff --git a/python/streams/sampled_stream.py b/python/streams/sampled_stream.py deleted file mode 100644 index 456b31b..0000000 --- a/python/streams/sampled_stream.py +++ /dev/null @@ -1,51 +0,0 @@ -""" -Sampled Stream (1% Volume) - X API v2 -===================================== -Endpoint: GET https://api.x.com/2/tweets/sample/stream -Docs: https://developer.x.com/en/docs/twitter-api/tweets/volume-streams/api-reference/get-tweets-sample-stream - -Authentication: Bearer Token (App-only) -Required env vars: BEARER_TOKEN - -Note: Returns approximately 1% of all public posts in real-time. -""" - -import requests -import os -import json - -bearer_token = os.environ.get("BEARER_TOKEN") - - -def bearer_oauth(r): - """ - Method required by bearer token authentication. - """ - r.headers["Authorization"] = f"Bearer {bearer_token}" - r.headers["User-Agent"] = "v2SampledStreamPython" - return r - - -def get_stream(): - response = requests.get( - "https://api.x.com/2/tweets/sample/stream", auth=bearer_oauth, stream=True, - ) - print(response.status_code) - if response.status_code != 200: - raise Exception( - "Cannot get stream (HTTP {}): {}".format( - response.status_code, response.text - ) - ) - for response_line in response.iter_lines(): - if response_line: - json_response = json.loads(response_line) - print(json.dumps(json_response, indent=4, sort_keys=True)) - - -def main(): - get_stream() - - -if __name__ == "__main__": - main() diff --git a/python/streams/stream_posts_filtered.py b/python/streams/stream_posts_filtered.py new file mode 100644 index 0000000..f4a203c --- /dev/null +++ b/python/streams/stream_posts_filtered.py @@ -0,0 +1,80 @@ +""" +Filtered Stream - X API v2 +========================== +Endpoint: GET https://api.x.com/2/tweets/search/stream +Docs: https://developer.x.com/en/docs/twitter-api/tweets/filtered-stream/api-reference/get-tweets-search-stream + +Authentication: Bearer Token (App-only) +Required env vars: BEARER_TOKEN + +Note: Streams posts matching your filter rules in real-time. +""" + +import os +import json +from xdk import Client + +bearer_token = os.environ.get("BEARER_TOKEN") +client = Client(bearer_token=bearer_token) + +def get_rules(): + response = client.stream.get_rules() + # Access data attribute safely + rules_data = getattr(response, 'data', None) + if rules_data: + print(json.dumps(rules_data, indent=4, sort_keys=True)) + return rules_data + + +def delete_all_rules(rules): + if rules is None or not rules: + return None + + ids = [rule["id"] for rule in rules] + payload = {"delete": {"ids": ids}} + response = client.stream.update_rules(body=payload) + # Access data attribute safely + response_data = getattr(response, 'data', None) + if response_data: + print(json.dumps(response_data, indent=4, sort_keys=True)) + + +def set_rules(): + # You can adjust the rules if needed + sample_rules = [ + {"value": "dog has:images", "tag": "dog pictures"}, + {"value": "cat has:images -grumpy", "tag": "cat pictures"}, + ] + payload = {"add": sample_rules} + response = client.stream.update_rules(body=payload) + # Access data attribute safely + response_data = getattr(response, 'data', None) + if response_data: + print(json.dumps(response_data, indent=4, sort_keys=True)) + + +def get_stream(): + # Stream posts matching the filter rules in real-time + # The posts() method is the filtered stream + try: + for post in client.stream.posts(): + # Access data attribute safely + post_data = getattr(post, 'data', None) + if post_data: + print(json.dumps(post_data, indent=4, sort_keys=True)) + except Exception as e: + print(f"Error streaming posts: {e}") + print("Note: This could be a temporary API issue (503 Service Unavailable)") + print("or the stream endpoint may be experiencing issues.") + raise + + +def main(): + rules = get_rules() + delete_all_rules(rules) + set_rules() + get_stream() + + +if __name__ == "__main__": + main() diff --git a/python/streams/stream_posts_sample.py b/python/streams/stream_posts_sample.py new file mode 100644 index 0000000..445486d --- /dev/null +++ b/python/streams/stream_posts_sample.py @@ -0,0 +1,26 @@ +""" +Sampled Stream (1% Volume) - X API v2 +===================================== +Endpoint: GET https://api.x.com/2/tweets/sample/stream +Docs: https://developer.x.com/en/docs/twitter-api/tweets/volume-streams/api-reference/get-tweets-sample-stream + +Authentication: Bearer Token (App-only) +Required env vars: BEARER_TOKEN + +Note: Returns approximately 1% of all public posts in real-time. +""" + +import os +import json +from xdk import Client + +bearer_token = os.environ.get("BEARER_TOKEN") +client = Client(bearer_token=bearer_token) + +def main(): + # Stream posts in real-time + for post in client.stream.posts_sample(): + print(json.dumps(post.data, indent=4, sort_keys=True)) + +if __name__ == "__main__": + main() diff --git a/python/timelines/get_mentions.py b/python/timelines/get_mentions.py new file mode 100644 index 0000000..7b99109 --- /dev/null +++ b/python/timelines/get_mentions.py @@ -0,0 +1,47 @@ +""" +User Mentions Timeline - X API v2 +================================== +Endpoint: GET https://api.x.com/2/users/:id/mentions +Docs: https://developer.x.com/en/docs/twitter-api/tweets/timelines/api-reference/get-users-id-mentions + +Authentication: Bearer Token (App-only) or OAuth (User Context) +Required env vars: BEARER_TOKEN +""" + +import os +import json +from xdk import Client + +bearer_token = os.environ.get("BEARER_TOKEN") +client = Client(bearer_token=bearer_token) + +# Replace with user ID below +user_id = "2244994945" + +def main(): + # Get user mentions with automatic pagination + # Tweet fields are adjustable. + # Options include: + # attachments, author_id, context_annotations, + # conversation_id, created_at, entities, geo, id, + # in_reply_to_user_id, lang, non_public_metrics, organic_metrics, + # possibly_sensitive, promoted_metrics, public_metrics, referenced_tweets, + # source, text, and withheld + all_posts = [] + for page in client.users.get_mentions( + user_id, + max_results=100, + tweet_fields=["created_at"] + ): + # Access data attribute (model uses extra='allow' so data should be available) + # Use getattr with fallback in case data field is missing from response + page_data = getattr(page, 'data', []) or [] + all_posts.extend(page_data) + print(f"Fetched {len(page_data)} posts (total: {len(all_posts)})") + + print(f"\nTotal Mentions: {len(all_posts)}") + print(json.dumps({"data": all_posts[:5]}, indent=4, sort_keys=True)) # Print first 5 as example + +if __name__ == "__main__": + main() + \ No newline at end of file diff --git a/python/timelines/get_posts.py b/python/timelines/get_posts.py new file mode 100644 index 0000000..35ec12e --- /dev/null +++ b/python/timelines/get_posts.py @@ -0,0 +1,44 @@ +""" +User Posts Timeline - X API v2 +============================== +Endpoint: GET https://api.x.com/2/users/:id/tweets +Docs: https://developer.x.com/en/docs/twitter-api/tweets/timelines/api-reference/get-users-id-tweets + +Authentication: Bearer Token (App-only) or OAuth (User Context) +Required env vars: BEARER_TOKEN +""" + +import os +import json +from xdk import Client + +bearer_token = os.environ.get("BEARER_TOKEN") +client = Client(bearer_token=bearer_token) + +# Replace with the user ID you want to get posts for +user_id = "2244994945" + +def main(): + # Get user posts with automatic pagination + # Post fields are adjustable. Options include: + # attachments, author_id, context_annotations, conversation_id, + # created_at, entities, geo, id, in_reply_to_user_id, lang, + # non_public_metrics, organic_metrics, possibly_sensitive, + # promoted_metrics, public_metrics, referenced_tweets, source, text, and withheld + all_posts = [] + for page in client.users.get_posts( + user_id, + max_results=100, + tweet_fields=["created_at"] + ): + # Access data attribute (model uses extra='allow' so data should be available) + # Use getattr with fallback in case data field is missing from response + page_data = getattr(page, 'data', []) or [] + all_posts.extend(page_data) + print(f"Fetched {len(page_data)} posts (total: {len(all_posts)})") + + print(f"\nTotal Posts: {len(all_posts)}") + print(json.dumps({"data": all_posts[:5]}, indent=4, sort_keys=True)) # Print first 5 as example + +if __name__ == "__main__": + main() diff --git a/python/timelines/get_timeline.py b/python/timelines/get_timeline.py new file mode 100644 index 0000000..0f4d5cb --- /dev/null +++ b/python/timelines/get_timeline.py @@ -0,0 +1,78 @@ +""" +Reverse Chronological Home Timeline - X API v2 +============================================== +Endpoint: GET https://api.x.com/2/users/:id/timelines/reverse_chronological +Docs: https://developer.x.com/en/docs/twitter-api/tweets/timelines/api-reference/get-users-id-reverse-chronological-timeline + +Authentication: OAuth 2.0 (User Context) +Required env vars: CLIENT_ID, CLIENT_SECRET +""" + +import os +import json +from xdk import Client +from xdk.oauth2_auth import OAuth2PKCEAuth + +# The code below sets the client ID and client secret from your environment variables +# To set environment variables on macOS or Linux, run the export commands below from the terminal: +# export CLIENT_ID='YOUR-CLIENT-ID' +# export CLIENT_SECRET='YOUR-CLIENT-SECRET' +client_id = os.environ.get("CLIENT_ID") +client_secret = os.environ.get("CLIENT_SECRET") + +# Replace the following URL with your callback URL, which can be obtained from your App's auth settings. +redirect_uri = "https://example.com" + +# Set the scopes +scopes = ["tweet.read", "users.read", "offline.access"] + +def main(): + # Step 1: Create PKCE instance + auth = OAuth2PKCEAuth( + client_id=client_id, + client_secret=client_secret, + redirect_uri=redirect_uri, + scope=scopes + ) + + # Step 2: Get authorization URL + auth_url = auth.get_authorization_url() + print("Visit the following URL to authorize your App on behalf of your X handle in a browser:") + print(auth_url) + + # Step 3: Handle callback + callback_url = input("Paste the full callback URL here: ") + + # Step 4: Exchange code for tokens + tokens = auth.fetch_token(authorization_response=callback_url) + access_token = tokens["access_token"] + + # Step 5: Create client + client = Client(access_token=access_token) + + # Step 6: Get authenticated user ID + me_response = client.users.get_me() + user_id = me_response.data["id"] + + # Step 7: Get reverse chronological timeline with automatic pagination + # Post fields are adjustable. Options include: + # attachments, author_id, context_annotations, conversation_id, + # created_at, entities, geo, id, in_reply_to_user_id, lang, + # possibly_sensitive, public_metrics, referenced_tweets, source, text + all_posts = [] + for page in client.users.get_timeline( + user_id, + max_results=100, + tweet_fields=["created_at"] + ): + # Access data attribute (model uses extra='allow' so data should be available) + # Use getattr with fallback in case data field is missing from response + page_data = getattr(page, 'data', []) or [] + all_posts.extend(page_data) + print(f"Fetched {len(page_data)} posts (total: {len(all_posts)})") + + print(f"\nTotal Posts: {len(all_posts)}") + print(json.dumps({"data": all_posts[:5]}, indent=4, sort_keys=True)) # Print first 5 as example + +if __name__ == "__main__": + main() diff --git a/python/timelines/home_timeline.py b/python/timelines/home_timeline.py deleted file mode 100644 index f8a8d23..0000000 --- a/python/timelines/home_timeline.py +++ /dev/null @@ -1,83 +0,0 @@ -""" -Reverse Chronological Home Timeline - X API v2 -============================================== -Endpoint: GET https://api.x.com/2/users/:id/reverse_chronological_timeline -Docs: https://developer.x.com/en/docs/twitter-api/tweets/timelines/api-reference/get-users-id-reverse-chronological-timeline - -Authentication: OAuth 1.0a or OAuth 2.0 (User Context) -Required env vars: CONSUMER_KEY, CONSUMER_SECRET -""" - -from requests_oauthlib import OAuth1Session -import os -import json - -consumer_key = os.environ.get("CONSUMER_KEY") -consumer_secret = os.environ.get("CONSUMER_SECRET") - -# Post fields are adjustable. Options include: -# attachments, author_id, context_annotations, conversation_id, -# created_at, entities, geo, id, in_reply_to_user_id, lang, -# possibly_sensitive, public_metrics, referenced_tweets, source, text -params = {"tweet.fields": "created_at"} - -# Get request token -request_token_url = "https://api.x.com/oauth/request_token" -oauth = OAuth1Session(consumer_key, client_secret=consumer_secret) - -try: - fetch_response = oauth.fetch_request_token(request_token_url) -except ValueError: - print( - "There may have been an issue with the consumer_key or consumer_secret you entered." - ) - -resource_owner_key = fetch_response.get("oauth_token") -resource_owner_secret = fetch_response.get("oauth_token_secret") -print("Got OAuth token: %s" % resource_owner_key) - -# Get authorization -base_authorization_url = "https://api.x.com/oauth/authorize" -authorization_url = oauth.authorization_url(base_authorization_url) -print("Please go here and authorize: %s" % authorization_url) -verifier = input("Paste the PIN here: ") - -# Get the access token -access_token_url = "https://api.x.com/oauth/access_token" -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=resource_owner_key, - resource_owner_secret=resource_owner_secret, - verifier=verifier, -) -oauth_tokens = oauth.fetch_access_token(access_token_url) - -access_token = oauth_tokens["oauth_token"] -access_token_secret = oauth_tokens["oauth_token_secret"] -user_id = oauth_tokens["user_id"] - -# Make the request -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=access_token, - resource_owner_secret=access_token_secret, -) - -# Making the request -response = oauth.get( - "https://api.x.com/2/users/{}/reverse_chronological_timeline".format(user_id), - params=params -) - -if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format(response.status_code, response.text) - ) - -print("Response code: {}".format(response.status_code)) - -# Saving the response as JSON -json_response = response.json() -print(json.dumps(json_response, indent=4, sort_keys=True)) diff --git a/python/timelines/reverse-chron-home-timeline.py b/python/timelines/reverse-chron-home-timeline.py deleted file mode 100644 index 7b09c66..0000000 --- a/python/timelines/reverse-chron-home-timeline.py +++ /dev/null @@ -1,112 +0,0 @@ -import base64 -import hashlib -import os -import re -import json -import requests -from requests.auth import AuthBase, HTTPBasicAuth -from requests_oauthlib import OAuth2Session - -# First, you will need to enable OAuth 2.0 in your App’s auth settings in the Developer Portal to get your client ID. -# Inside your terminal you will need to set an enviornment variable -# export CLIENT_ID='your-client-id' -client_id = os.environ.get("CLIENT_ID") - -# If you have selected a type of App that is a confidential client you will need to set a client secret. -# Confidential Clients securely authenticate with the authorization server. - -# Inside your terminal you will need to set an enviornment variable -# export CLIENT_SECRET='your-client-secret' - -# Remove the comment on the following line if you are using a confidential client -# client_secret = os.environ.get("CLIENT_SECRET") - -# Replace the following URL with your callback URL, which can be obtained from your App's auth settings. -redirect_uri = "https://www.example.com" - -# Set the scopes -scopes = ["tweet.read", "users.read", "offline.access"] - -# Create a code verifier -code_verifier = base64.urlsafe_b64encode(os.urandom(30)).decode("utf-8") -code_verifier = re.sub("[^a-zA-Z0-9]+", "", code_verifier) - -# Create a code challenge -code_challenge = hashlib.sha256(code_verifier.encode("utf-8")).digest() -code_challenge = base64.urlsafe_b64encode(code_challenge).decode("utf-8") -code_challenge = code_challenge.replace("=", "") - -# Start an OAuth 2.0 session -oauth = OAuth2Session(client_id, redirect_uri=redirect_uri, scope=scopes) - -# Create an authorize URL -auth_url = "https://twitter.com/i/oauth2/authorize" -authorization_url, state = oauth.authorization_url( - auth_url, code_challenge=code_challenge, code_challenge_method="S256" -) - -# Visit the URL to authorize your App to make requests on behalf of a user -print( - "Visit the following URL to authorize your App on behalf of your Twitter handle in a browser:" -) -print(authorization_url) - -# Paste in your authorize URL to complete the request -authorization_response = input( - "Paste in the full URL after you've authorized your App:\n" -) - -# Fetch your access token -token_url = "https://api.x.com/2/oauth2/token" - -# The following line of code will only work if you are using a type of App that is a public client -auth = False - -# If you are using a confidential client you will need to pass in basic encoding of your client ID and client secret. - -# Please remove the comment on the following line if you are using a type of App that is a confidential client -# auth = HTTPBasicAuth(client_id, client_secret) - -token = oauth.fetch_token( - token_url=token_url, - authorization_response=authorization_response, - auth=auth, - client_id=client_id, - include_client_id=True, - code_verifier=code_verifier, -) - -# Your access token -access = token["access_token"] - -# Make a request to the users/me endpoint to get your user ID -user_me = requests.request( - "GET", - "https://api.x.com/2/users/me", - headers={"Authorization": "Bearer {}".format(access)}, -).json() - -# -# -# Now that we have user authorization, let's look up their home timeline. -# -# - -# Set the user. This defaults to the ID of the authorizing user. -user_id = user_me["data"]["id"] - -# Set the url. -url = "https://api.x.com/2/users/{}/timelines/reverse_chronological".format(user_id) - -headers = { - "Authorization": "Bearer {}".format(access), - "User-Agent": "ReverseChronSampleCode", -} -response = requests.request("GET", url, headers=headers) -if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format(response.status_code, response.text) - ) -print("Response code: {}".format(response.status_code)) -json_response = response.json() -print(json.dumps(json_response, indent=4, sort_keys=True)) diff --git a/python/timelines/user_mentions.py b/python/timelines/user_mentions.py deleted file mode 100644 index 4b9aca8..0000000 --- a/python/timelines/user_mentions.py +++ /dev/null @@ -1,58 +0,0 @@ -import requests -import os -import json - -# To set your environment variables in your terminal run the following line: -# export 'BEARER_TOKEN'='' -bearer_token = os.environ.get("BEARER_TOKEN") - - -def create_url(): - # Replace with user ID below - user_id = 2244994945 - return "https://api.x.com/2/users/{}/mentions".format(user_id) - - -def get_params(): - # Tweet fields are adjustable. - # Options include: - # attachments, author_id, context_annotations, - # conversation_id, created_at, entities, geo, id, - # in_reply_to_user_id, lang, non_public_metrics, organic_metrics, - # possibly_sensitive, promoted_metrics, public_metrics, referenced_tweets, - # source, text, and withheld - return {"tweet.fields": "created_at"} - - -def bearer_oauth(r): - """ - Method required by bearer token authentication. - """ - - r.headers["Authorization"] = f"Bearer {bearer_token}" - r.headers["User-Agent"] = "v2UserMentionsPython" - return r - - -def connect_to_endpoint(url, params): - response = requests.request("GET", url, auth=bearer_oauth, params=params) - print(response.status_code) - if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format( - response.status_code, response.text - ) - ) - return response.json() - - -def main(): - url = create_url() - params = get_params() - json_response = connect_to_endpoint(url, params) - print(json.dumps(json_response, indent=4, sort_keys=True)) - - -if __name__ == "__main__": - main() - \ No newline at end of file diff --git a/python/timelines/user_posts.py b/python/timelines/user_posts.py deleted file mode 100644 index a691277..0000000 --- a/python/timelines/user_posts.py +++ /dev/null @@ -1,57 +0,0 @@ -""" -User Posts Timeline - X API v2 -============================== -Endpoint: GET https://api.x.com/2/users/:id/tweets -Docs: https://developer.x.com/en/docs/twitter-api/tweets/timelines/api-reference/get-users-id-tweets - -Authentication: Bearer Token (App-only) or OAuth (User Context) -Required env vars: BEARER_TOKEN -""" - -import requests -import os -import json - -bearer_token = os.environ.get("BEARER_TOKEN") - - -def create_url(): - # Replace with the user ID you want to get posts for - user_id = "2244994945" - return "https://api.x.com/2/users/{}/tweets".format(user_id) - - -def get_params(): - # Post fields are adjustable. Options include: - # attachments, author_id, context_annotations, conversation_id, - # created_at, entities, geo, id, in_reply_to_user_id, lang, - # possibly_sensitive, public_metrics, referenced_tweets, source, text - return {"tweet.fields": "created_at"} - - -def bearer_oauth(r): - """ - Method required by bearer token authentication. - """ - r.headers["Authorization"] = f"Bearer {bearer_token}" - r.headers["User-Agent"] = "v2UserPostsPython" - return r - - -def connect_to_endpoint(url, params): - response = requests.request("GET", url, auth=bearer_oauth, params=params) - print(response.status_code) - if response.status_code != 200: - raise Exception(response.status_code, response.text) - return response.json() - - -def main(): - url = create_url() - params = get_params() - json_response = connect_to_endpoint(url, params) - print(json.dumps(json_response, indent=4, sort_keys=True)) - - -if __name__ == "__main__": - main() diff --git a/python/timelines/user_tweets.py b/python/timelines/user_tweets.py deleted file mode 100644 index 8f547ea..0000000 --- a/python/timelines/user_tweets.py +++ /dev/null @@ -1,57 +0,0 @@ -import requests -import os -import json - -# To set your environment variables in your terminal run the following line: -# export 'BEARER_TOKEN'='' -bearer_token = os.environ.get("BEARER_TOKEN") - - -def create_url(): - # Replace with user ID below - user_id = 2244994945 - return "https://api.x.com/2/users/{}/tweets".format(user_id) - - -def get_params(): - # Tweet fields are adjustable. - # Options include: - # attachments, author_id, context_annotations, - # conversation_id, created_at, entities, geo, id, - # in_reply_to_user_id, lang, non_public_metrics, organic_metrics, - # possibly_sensitive, promoted_metrics, public_metrics, referenced_tweets, - # source, text, and withheld - return {"tweet.fields": "created_at"} - - -def bearer_oauth(r): - """ - Method required by bearer token authentication. - """ - - r.headers["Authorization"] = f"Bearer {bearer_token}" - r.headers["User-Agent"] = "v2UserTweetsPython" - return r - - -def connect_to_endpoint(url, params): - response = requests.request("GET", url, auth=bearer_oauth, params=params) - print(response.status_code) - if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format( - response.status_code, response.text - ) - ) - return response.json() - - -def main(): - url = create_url() - params = get_params() - json_response = connect_to_endpoint(url, params) - print(json.dumps(json_response, indent=4, sort_keys=True)) - - -if __name__ == "__main__": - main() diff --git a/python/usage/get_usage.py b/python/usage/get_usage.py index 7042699..6a1677d 100644 --- a/python/usage/get_usage.py +++ b/python/usage/get_usage.py @@ -10,44 +10,25 @@ Returns the number of posts read from the API. """ -import requests import os import json +from xdk import Client bearer_token = os.environ.get("BEARER_TOKEN") - - -def create_url(): - return "https://api.x.com/2/usage/tweets" - - -def get_params(): - return {"days": 7} - - -def bearer_oauth(r): - """ - Method required by bearer token authentication. - """ - r.headers["Authorization"] = f"Bearer {bearer_token}" - r.headers["User-Agent"] = "v2UsagePython" - return r - - -def connect_to_endpoint(url, params): - response = requests.get(url, auth=bearer_oauth, params=params) - print(response.status_code) - if response.status_code != 200: - raise Exception(response.status_code, response.text) - return response.json() - +client = Client(bearer_token=bearer_token) def main(): - url = create_url() - params = get_params() - json_response = connect_to_endpoint(url, params) - print(json.dumps(json_response, indent=4, sort_keys=True)) - + # Get usage statistics for tweets + # days: Number of days to retrieve usage for (default: 7) + # usage_fields: Fields to include in the response (optional) + response = client.usage.get(days=7) + + # Access data attribute safely + response_data = getattr(response, 'data', None) + if response_data: + print(json.dumps(response_data, indent=4, sort_keys=True)) + else: + print(json.dumps(response, indent=4, sort_keys=True)) if __name__ == "__main__": main() diff --git a/python/usage/get_usage_tweets.py b/python/usage/get_usage_tweets.py deleted file mode 100644 index 23ad0d8..0000000 --- a/python/usage/get_usage_tweets.py +++ /dev/null @@ -1,38 +0,0 @@ -import requests -import os -import json - -# To set your enviornment variables in your terminal run the following line: -# export 'BEARER_TOKEN'='' -bearer_token = os.environ.get("BEARER_TOKEN") - -def bearer_oauth(r): - """ - Method required by bearer token authentication. - """ - - r.headers["Authorization"] = f"Bearer {bearer_token}" - r.headers["User-Agent"] = "v2UsageTweetsPython" - return r - - -def connect_to_endpoint(url): - response = requests.request("GET", url, auth=bearer_oauth) - print(response.status_code) - if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format( - response.status_code, response.text - ) - ) - return response.json() - - -def main(): - url = "https://api.x.com/2/usage/tweets" - json_response = connect_to_endpoint(url) - print(json.dumps(json_response, indent=4, sort_keys=True)) - - -if __name__ == "__main__": - main() diff --git a/python/users/block.py b/python/users/block.py deleted file mode 100644 index 77da5db..0000000 --- a/python/users/block.py +++ /dev/null @@ -1,81 +0,0 @@ -""" -Block User - X API v2 -===================== -Endpoint: POST https://api.x.com/2/users/:id/blocking -Docs: https://developer.x.com/en/docs/twitter-api/users/blocks/api-reference/post-users-user_id-blocking - -Authentication: OAuth 1.0a (User Context) -Required env vars: CONSUMER_KEY, CONSUMER_SECRET -""" - -from requests_oauthlib import OAuth1Session -import os -import json - -consumer_key = os.environ.get("CONSUMER_KEY") -consumer_secret = os.environ.get("CONSUMER_SECRET") - -# Replace with your own user ID -user_id = "your-user-id" - -# Replace with the user ID you want to block -payload = {"target_user_id": "target-user-id"} - -# Get request token -request_token_url = "https://api.x.com/oauth/request_token" -oauth = OAuth1Session(consumer_key, client_secret=consumer_secret) - -try: - fetch_response = oauth.fetch_request_token(request_token_url) -except ValueError: - print( - "There may have been an issue with the consumer_key or consumer_secret you entered." - ) - -resource_owner_key = fetch_response.get("oauth_token") -resource_owner_secret = fetch_response.get("oauth_token_secret") -print("Got OAuth token: %s" % resource_owner_key) - -# Get authorization -base_authorization_url = "https://api.x.com/oauth/authorize" -authorization_url = oauth.authorization_url(base_authorization_url) -print("Please go here and authorize: %s" % authorization_url) -verifier = input("Paste the PIN here: ") - -# Get the access token -access_token_url = "https://api.x.com/oauth/access_token" -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=resource_owner_key, - resource_owner_secret=resource_owner_secret, - verifier=verifier, -) -oauth_tokens = oauth.fetch_access_token(access_token_url) - -access_token = oauth_tokens["oauth_token"] -access_token_secret = oauth_tokens["oauth_token_secret"] - -# Make the request -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=access_token, - resource_owner_secret=access_token_secret, -) - -# Making the request -response = oauth.post( - "https://api.x.com/2/users/{}/blocking".format(user_id), json=payload -) - -if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format(response.status_code, response.text) - ) - -print("Response code: {}".format(response.status_code)) - -# Saving the response as JSON -json_response = response.json() -print(json.dumps(json_response, indent=4, sort_keys=True)) diff --git a/python/users/block_a_user.py b/python/users/block_a_user.py deleted file mode 100644 index 2523aa6..0000000 --- a/python/users/block_a_user.py +++ /dev/null @@ -1,77 +0,0 @@ -from requests_oauthlib import OAuth1Session -import os -import json - -# In your terminal please set your environment variables by running the following lines of code. -# export 'CONSUMER_KEY'='' -# export 'CONSUMER_SECRET'='' - -consumer_key = os.environ.get("CONSUMER_KEY") -consumer_secret = os.environ.get("CONSUMER_SECRET") - - -# Be sure to replace your-user-id with your own user ID or one of an authenticating user -# You can find a user ID by using the user lookup endpoint -id = "your-user-id" - -# Be sure to add replace id-to-block with the user id you wish to block. -payload = {"target_user_id": "id-to-block"} - -# Get request token -request_token_url = "https://api.x.com/oauth/request_token" -oauth = OAuth1Session(consumer_key, client_secret=consumer_secret) - -try: - fetch_response = oauth.fetch_request_token(request_token_url) -except ValueError: - print( - "There may have been an issue with the consumer_key or consumer_secret you entered." - ) - -resource_owner_key = fetch_response.get("oauth_token") -resource_owner_secret = fetch_response.get("oauth_token_secret") -print("Got OAuth token: %s" % resource_owner_key) - -# Get authorization -base_authorization_url = "https://api.x.com/oauth/authorize" -authorization_url = oauth.authorization_url(base_authorization_url) -print("Please go here and authorize: %s" % authorization_url) -verifier = input("Paste the PIN here: ") - -# Get the access token -access_token_url = "https://api.x.com/oauth/access_token" -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=resource_owner_key, - resource_owner_secret=resource_owner_secret, - verifier=verifier, -) -oauth_tokens = oauth.fetch_access_token(access_token_url) - -access_token = oauth_tokens["oauth_token"] -access_token_secret = oauth_tokens["oauth_token_secret"] - -# Make the request -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=access_token, - resource_owner_secret=access_token_secret, -) - -# Making the request -response = oauth.post( - "https://api.x.com/2/users/{}/blocking".format(id), json=payload -) - -if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format(response.status_code, response.text) - ) - -print("Response code: {}".format(response.status_code)) - -# Saving the response as JSON -json_response = response.json() -print(json.dumps(json_response, indent=4, sort_keys=True)) diff --git a/python/users/blocked.py b/python/users/blocked.py deleted file mode 100644 index 7bb4a0c..0000000 --- a/python/users/blocked.py +++ /dev/null @@ -1,84 +0,0 @@ -""" -Blocked Users Lookup - X API v2 -=============================== -Endpoint: GET https://api.x.com/2/users/:id/blocking -Docs: https://developer.x.com/en/docs/twitter-api/users/blocks/api-reference/get-users-blocking - -Authentication: OAuth 1.0a (User Context) -Required env vars: CONSUMER_KEY, CONSUMER_SECRET -""" - -from requests_oauthlib import OAuth1Session -import os -import json - -consumer_key = os.environ.get("CONSUMER_KEY") -consumer_secret = os.environ.get("CONSUMER_SECRET") - -# User fields are adjustable. Options include: -# created_at, description, entities, id, location, name, -# pinned_tweet_id, profile_image_url, protected, -# public_metrics, url, username, verified, and withheld -fields = "user.fields=created_at,description" -params = {"user.fields": fields} - -# Get request token -request_token_url = "https://api.x.com/oauth/request_token" -oauth = OAuth1Session(consumer_key, client_secret=consumer_secret) - -try: - fetch_response = oauth.fetch_request_token(request_token_url) -except ValueError: - print( - "There may have been an issue with the consumer_key or consumer_secret you entered." - ) - -resource_owner_key = fetch_response.get("oauth_token") -resource_owner_secret = fetch_response.get("oauth_token_secret") -print("Got OAuth token: %s" % resource_owner_key) - -# Get authorization -base_authorization_url = "https://api.x.com/oauth/authorize" -authorization_url = oauth.authorization_url(base_authorization_url) -print("Please go here and authorize: %s" % authorization_url) -verifier = input("Paste the PIN here: ") - -# Get the access token -access_token_url = "https://api.x.com/oauth/access_token" -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=resource_owner_key, - resource_owner_secret=resource_owner_secret, - verifier=verifier, -) -oauth_tokens = oauth.fetch_access_token(access_token_url) - -access_token = oauth_tokens["oauth_token"] -access_token_secret = oauth_tokens["oauth_token_secret"] - -# Make the request -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=access_token, - resource_owner_secret=access_token_secret, -) - -user_id = oauth_tokens["user_id"] - -# Making the request -response = oauth.get( - "https://api.x.com/2/users/{}/blocking".format(user_id), params=params -) - -if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format(response.status_code, response.text) - ) - -print("Response code: {}".format(response.status_code)) - -# Saving the response as JSON -json_response = response.json() -print(json.dumps(json_response, indent=4, sort_keys=True)) diff --git a/python/users/followers.py b/python/users/followers.py deleted file mode 100644 index 35f87de..0000000 --- a/python/users/followers.py +++ /dev/null @@ -1,53 +0,0 @@ -""" -User Followers Lookup - X API v2 -================================ -Endpoint: GET https://api.x.com/2/users/:id/followers -Docs: https://developer.x.com/en/docs/twitter-api/users/follows/api-reference/get-users-id-followers - -Authentication: Bearer Token (App-only) or OAuth (User Context) -Required env vars: BEARER_TOKEN -""" - -import requests -import os -import json - -bearer_token = os.environ.get("BEARER_TOKEN") - - -def create_url(): - # Replace with the user ID you want to get followers for - user_id = "2244994945" - return "https://api.x.com/2/users/{}/followers".format(user_id) - - -def get_params(): - return {"user.fields": "created_at"} - - -def bearer_oauth(r): - """ - Method required by bearer token authentication. - """ - r.headers["Authorization"] = f"Bearer {bearer_token}" - r.headers["User-Agent"] = "v2FollowersLookupPython" - return r - - -def connect_to_endpoint(url, params): - response = requests.request("GET", url, auth=bearer_oauth, params=params) - print(response.status_code) - if response.status_code != 200: - raise Exception(response.status_code, response.text) - return response.json() - - -def main(): - url = create_url() - params = get_params() - json_response = connect_to_endpoint(url, params) - print(json.dumps(json_response, indent=4, sort_keys=True)) - - -if __name__ == "__main__": - main() diff --git a/python/users/followers_lookup.py b/python/users/followers_lookup.py deleted file mode 100644 index ea51170..0000000 --- a/python/users/followers_lookup.py +++ /dev/null @@ -1,50 +0,0 @@ -import requests -import os -import json - -# To set your environment variables in your terminal run the following line: -# export 'BEARER_TOKEN'='' -bearer_token = os.environ.get("BEARER_TOKEN") - - -def create_url(): - # Replace with user ID below - user_id = 2244994945 - return "https://api.x.com/2/users/{}/followers".format(user_id) - - -def get_params(): - return {"user.fields": "created_at"} - - -def bearer_oauth(r): - """ - Method required by bearer token authentication. - """ - - r.headers["Authorization"] = f"Bearer {bearer_token}" - r.headers["User-Agent"] = "v2FollowersLookupPython" - return r - - -def connect_to_endpoint(url, params): - response = requests.request("GET", url, auth=bearer_oauth, params=params) - print(response.status_code) - if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format( - response.status_code, response.text - ) - ) - return response.json() - - -def main(): - url = create_url() - params = get_params() - json_response = connect_to_endpoint(url, params) - print(json.dumps(json_response, indent=4, sort_keys=True)) - - -if __name__ == "__main__": - main() diff --git a/python/users/following.py b/python/users/following.py deleted file mode 100644 index dba3fb3..0000000 --- a/python/users/following.py +++ /dev/null @@ -1,53 +0,0 @@ -""" -User Following Lookup - X API v2 -================================ -Endpoint: GET https://api.x.com/2/users/:id/following -Docs: https://developer.x.com/en/docs/twitter-api/users/follows/api-reference/get-users-id-following - -Authentication: Bearer Token (App-only) or OAuth (User Context) -Required env vars: BEARER_TOKEN -""" - -import requests -import os -import json - -bearer_token = os.environ.get("BEARER_TOKEN") - - -def create_url(): - # Replace with the user ID you want to get following for - user_id = "2244994945" - return "https://api.x.com/2/users/{}/following".format(user_id) - - -def get_params(): - return {"user.fields": "created_at"} - - -def bearer_oauth(r): - """ - Method required by bearer token authentication. - """ - r.headers["Authorization"] = f"Bearer {bearer_token}" - r.headers["User-Agent"] = "v2FollowingLookupPython" - return r - - -def connect_to_endpoint(url, params): - response = requests.request("GET", url, auth=bearer_oauth, params=params) - print(response.status_code) - if response.status_code != 200: - raise Exception(response.status_code, response.text) - return response.json() - - -def main(): - url = create_url() - params = get_params() - json_response = connect_to_endpoint(url, params) - print(json.dumps(json_response, indent=4, sort_keys=True)) - - -if __name__ == "__main__": - main() diff --git a/python/users/following_lookup.py b/python/users/following_lookup.py deleted file mode 100644 index be136e5..0000000 --- a/python/users/following_lookup.py +++ /dev/null @@ -1,50 +0,0 @@ -import requests -import os -import json - -# To set your environment variables in your terminal run the following line: -# export 'BEARER_TOKEN'='' -bearer_token = os.environ.get("BEARER_TOKEN") - - -def create_url(): - # Replace with user ID below - user_id = 2244994945 - return "https://api.x.com/2/users/{}/following".format(user_id) - - -def get_params(): - return {"user.fields": "created_at"} - - -def bearer_oauth(r): - """ - Method required by bearer token authentication. - """ - - r.headers["Authorization"] = f"Bearer {bearer_token}" - r.headers["User-Agent"] = "v2FollowingLookupPython" - return r - - -def connect_to_endpoint(url, params): - response = requests.request("GET", url, auth=bearer_oauth, params=params) - print(response.status_code) - if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format( - response.status_code, response.text - ) - ) - return response.json() - - -def main(): - url = create_url() - params = get_params() - json_response = connect_to_endpoint(url, params) - print(json.dumps(json_response, indent=4, sort_keys=True)) - - -if __name__ == "__main__": - main() diff --git a/python/users/get_blocking.py b/python/users/get_blocking.py new file mode 100644 index 0000000..3d3f4eb --- /dev/null +++ b/python/users/get_blocking.py @@ -0,0 +1,91 @@ +""" +Blocked Users Lookup - X API v2 +=============================== +Endpoint: GET https://api.x.com/2/users/:id/blocking +Docs: https://developer.x.com/en/docs/twitter-api/users/blocks/api-reference/get-users-blocking + +Authentication: OAuth 2.0 (User Context) +Required env vars: CLIENT_ID, CLIENT_SECRET +""" + +import os +import json +from xdk import Client +from xdk.oauth2_auth import OAuth2PKCEAuth +from requests.exceptions import HTTPError + +# The code below sets the client ID and client secret from your environment variables +# To set environment variables on macOS or Linux, run the export commands below from the terminal: +# export CLIENT_ID='YOUR-CLIENT-ID' +# export CLIENT_SECRET='YOUR-CLIENT-SECRET' +client_id = os.environ.get("CLIENT_ID") +client_secret = os.environ.get("CLIENT_SECRET") + +# Replace the following URL with your callback URL, which can be obtained from your App's auth settings. +redirect_uri = "https://example.com" + +# Set the scopes +scopes = ["tweet.read", "users.read", "offline.access", "block.read"] + +def main(): + # Step 1: Create PKCE instance + auth = OAuth2PKCEAuth( + client_id=client_id, + client_secret=client_secret, + redirect_uri=redirect_uri, + scope=scopes + ) + + # Step 2: Get authorization URL + auth_url = auth.get_authorization_url() + print("Visit the following URL to authorize your App on behalf of your X handle in a browser:") + print(auth_url) + + # Step 3: Handle callback + callback_url = input("Paste the full callback URL here: ") + + # Step 4: Exchange code for tokens + tokens = auth.fetch_token(authorization_response=callback_url) + access_token = tokens["access_token"] + + # Step 5: Create client + client = Client(access_token=access_token) + + # Step 6: Get the authenticated user's ID + me_response = client.users.get_me() + user_id = me_response.data["id"] + + # Step 7: Get blocked users with automatic pagination + # User fields are adjustable, options include: + # created_at, description, entities, id, location, name, + # pinned_tweet_id, profile_image_url, protected, + # public_metrics, url, username, verified, and withheld + all_users = [] + try: + for page in client.users.get_blocking( + user_id, + max_results=100, + user_fields=["created_at", "description"] + ): + # Access data attribute (model uses extra='allow' so data should be available) + # Use getattr with fallback in case data field is missing from response + page_data = getattr(page, 'data', []) or [] + all_users.extend(page_data) + print(f"Fetched {len(page_data)} users (total: {len(all_users)})") + + print(f"\nTotal Blocked Users: {len(all_users)}") + print(json.dumps({"data": all_users[:5]}, indent=4, sort_keys=True)) # Print first 5 as example + except HTTPError as e: + print(f"Error occurred: {e}") + if hasattr(e.response, 'json'): + try: + error_data = e.response.json() + if 'errors' in error_data: + print("Detailed errors:") + print(json.dumps(error_data['errors'], indent=2)) + except: + pass + raise + +if __name__ == "__main__": + main() diff --git a/python/users/get_followers.py b/python/users/get_followers.py new file mode 100644 index 0000000..93eecee --- /dev/null +++ b/python/users/get_followers.py @@ -0,0 +1,39 @@ +""" +User Followers Lookup - X API v2 +================================ +Endpoint: GET https://api.x.com/2/users/:id/followers +Docs: https://developer.x.com/en/docs/twitter-api/users/follows/api-reference/get-users-id-followers + +Authentication: Bearer Token (App-only) or OAuth (User Context) +Required env vars: BEARER_TOKEN +""" + +import os +import json +from xdk import Client + +bearer_token = os.environ.get("BEARER_TOKEN") +client = Client(bearer_token=bearer_token) + +# Replace with the user ID you want to get followers for +user_id = "2244994945" + +def main(): + # Get followers with automatic pagination + all_users = [] + for page in client.users.get_followers( + user_id, + max_results=100, + user_fields=["created_at"] + ): + # Access data attribute (model uses extra='allow' so data should be available) + # Use getattr with fallback in case data field is missing from response + page_data = getattr(page, 'data', []) or [] + all_users.extend(page_data) + print(f"Fetched {len(page_data)} users (total: {len(all_users)})") + + print(f"\nTotal Followers: {len(all_users)}") + print(json.dumps({"data": all_users[:5]}, indent=4, sort_keys=True)) # Print first 5 as example + +if __name__ == "__main__": + main() diff --git a/python/users/get_following.py b/python/users/get_following.py new file mode 100644 index 0000000..7b7c83d --- /dev/null +++ b/python/users/get_following.py @@ -0,0 +1,39 @@ +""" +User Following Lookup - X API v2 +================================ +Endpoint: GET https://api.x.com/2/users/:id/following +Docs: https://developer.x.com/en/docs/twitter-api/users/follows/api-reference/get-users-id-following + +Authentication: Bearer Token (App-only) or OAuth (User Context) +Required env vars: BEARER_TOKEN +""" + +import os +import json +from xdk import Client + +bearer_token = os.environ.get("BEARER_TOKEN") +client = Client(bearer_token=bearer_token) + +# Replace with the user ID you want to get following for +user_id = "2244994945" + +def main(): + # Get following with automatic pagination + all_users = [] + for page in client.users.get_following( + user_id, + max_results=100, + user_fields=["created_at"] + ): + # Access data attribute (model uses extra='allow' so data should be available) + # Use getattr with fallback in case data field is missing from response + page_data = getattr(page, 'data', []) or [] + all_users.extend(page_data) + print(f"Fetched {len(page_data)} users (total: {len(all_users)})") + + print(f"\nTotal Following: {len(all_users)}") + print(json.dumps({"data": all_users[:5]}, indent=4, sort_keys=True)) # Print first 5 as example + +if __name__ == "__main__": + main() diff --git a/python/users/get_muting.py b/python/users/get_muting.py new file mode 100644 index 0000000..e84509f --- /dev/null +++ b/python/users/get_muting.py @@ -0,0 +1,91 @@ +""" +Muted Users Lookup - X API v2 +============================= +Endpoint: GET https://api.x.com/2/users/:id/muting +Docs: https://developer.x.com/en/docs/twitter-api/users/mutes/api-reference/get-users-muting + +Authentication: OAuth 2.0 (User Context) +Required env vars: CLIENT_ID, CLIENT_SECRET +""" + +import os +import json +from xdk import Client +from xdk.oauth2_auth import OAuth2PKCEAuth +from requests.exceptions import HTTPError + +# The code below sets the client ID and client secret from your environment variables +# To set environment variables on macOS or Linux, run the export commands below from the terminal: +# export CLIENT_ID='YOUR-CLIENT-ID' +# export CLIENT_SECRET='YOUR-CLIENT-SECRET' +client_id = os.environ.get("CLIENT_ID") +client_secret = os.environ.get("CLIENT_SECRET") + +# Replace the following URL with your callback URL, which can be obtained from your App's auth settings. +redirect_uri = "https://example.com" + +# Set the scopes +scopes = ["tweet.read", "users.read", "offline.access", "mute.read"] + +def main(): + # Step 1: Create PKCE instance + auth = OAuth2PKCEAuth( + client_id=client_id, + client_secret=client_secret, + redirect_uri=redirect_uri, + scope=scopes + ) + + # Step 2: Get authorization URL + auth_url = auth.get_authorization_url() + print("Visit the following URL to authorize your App on behalf of your X handle in a browser:") + print(auth_url) + + # Step 3: Handle callback + callback_url = input("Paste the full callback URL here: ") + + # Step 4: Exchange code for tokens + tokens = auth.fetch_token(authorization_response=callback_url) + access_token = tokens["access_token"] + + # Step 5: Create client + client = Client(access_token=access_token) + + # Step 6: Get the authenticated user's ID + me_response = client.users.get_me() + user_id = me_response.data["id"] + + # Step 7: Get muted users with automatic pagination + # User fields are adjustable, options include: + # created_at, description, entities, id, location, name, + # pinned_tweet_id, profile_image_url, protected, + # public_metrics, url, username, verified, and withheld + all_users = [] + try: + for page in client.users.get_muting( + user_id, + max_results=100, + user_fields=["created_at", "description"] + ): + # Access data attribute (model uses extra='allow' so data should be available) + # Use getattr with fallback in case data field is missing from response + page_data = getattr(page, 'data', []) or [] + all_users.extend(page_data) + print(f"Fetched {len(page_data)} users (total: {len(all_users)})") + + print(f"\nTotal Muted Users: {len(all_users)}") + print(json.dumps({"data": all_users[:5]}, indent=4, sort_keys=True)) # Print first 5 as example + except HTTPError as e: + print(f"Error occurred: {e}") + if hasattr(e.response, 'json'): + try: + error_data = e.response.json() + if 'errors' in error_data: + print("Detailed errors:") + print(json.dumps(error_data['errors'], indent=2)) + except: + pass + raise + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/python/users/get_user_by_usernams_user_context.py b/python/users/get_user_by_usernams_user_context.py new file mode 100644 index 0000000..056e382 --- /dev/null +++ b/python/users/get_user_by_usernams_user_context.py @@ -0,0 +1,74 @@ +""" +User Lookup (User Context) - X API v2 +===================================== +Endpoint: GET https://api.x.com/2/users/by +Docs: https://developer.x.com/en/docs/twitter-api/users/lookup/api-reference/get-users-by + +Authentication: OAuth 2.0 (User Context) +Required env vars: CLIENT_ID, CLIENT_SECRET +""" + +import os +import json +from xdk import Client +from xdk.oauth2_auth import OAuth2PKCEAuth + +# The code below sets the client ID and client secret from your environment variables +# To set environment variables on macOS or Linux, run the export commands below from the terminal: +# export CLIENT_ID='YOUR-CLIENT-ID' +# export CLIENT_SECRET='YOUR-CLIENT-SECRET' +client_id = os.environ.get("CLIENT_ID") +client_secret = os.environ.get("CLIENT_SECRET") + +# Replace the following URL with your callback URL, which can be obtained from your App's auth settings. +redirect_uri = "https://example.com" + +# Set the scopes +scopes = ["tweet.read", "users.read", "offline.access"] + +# Specify the usernames that you want to lookup (list, up to 100) +usernames = ["XDevelopers", "API"] + +def main(): + # Step 1: Create PKCE instance + auth = OAuth2PKCEAuth( + client_id=client_id, + client_secret=client_secret, + redirect_uri=redirect_uri, + scope=scopes + ) + + # Step 2: Get authorization URL + auth_url = auth.get_authorization_url() + print("Visit the following URL to authorize your App on behalf of your X handle in a browser:") + print(auth_url) + + # Step 3: Handle callback + callback_url = input("Paste the full callback URL here: ") + + # Step 4: Exchange code for tokens + tokens = auth.fetch_token(authorization_response=callback_url) + access_token = tokens["access_token"] + + # Step 5: Create client + client = Client(access_token=access_token) + + # Step 6: Get users + # User fields are adjustable, options include: + # created_at, description, entities, id, location, name, + # pinned_tweet_id, profile_image_url, protected, + # public_metrics, url, username, verified, and withheld + response = client.users.get_by_usernames( + usernames=usernames, + user_fields=["created_at", "description"] + ) + + # Access data attribute safely + response_data = getattr(response, 'data', None) + if response_data: + print(json.dumps(response_data, indent=4, sort_keys=True)) + else: + print(json.dumps(response, indent=4, sort_keys=True)) + +if __name__ == "__main__": + main() diff --git a/python/users/get_users_by_usernames_bearer_token.py b/python/users/get_users_by_usernames_bearer_token.py new file mode 100644 index 0000000..453e353 --- /dev/null +++ b/python/users/get_users_by_usernames_bearer_token.py @@ -0,0 +1,40 @@ +""" +User Lookup - X API v2 +====================== +Endpoint: GET https://api.x.com/2/users/by +Docs: https://developer.x.com/en/docs/twitter-api/users/lookup/api-reference/get-users-by + +Authentication: Bearer Token (App-only) or OAuth (User Context) +Required env vars: BEARER_TOKEN +""" + +import os +import json +from xdk import Client + +bearer_token = os.environ.get("BEARER_TOKEN") +client = Client(bearer_token=bearer_token) + +# Specify the usernames that you want to lookup (list, up to 100) +usernames = ["XDevelopers", "API"] + +def main(): + # User fields are adjustable, options include: + # created_at, description, entities, id, location, name, + # pinned_tweet_id, profile_image_url, protected, + # public_metrics, url, username, verified, and withheld + response = client.users.get_by_usernames( + usernames=usernames, + user_fields=["description", "created_at"] + ) + + # Access data attribute safely + response_data = getattr(response, 'data', None) + if response_data: + print(json.dumps(response_data, indent=4, sort_keys=True)) + else: + print(json.dumps(response, indent=4, sort_keys=True)) + + +if __name__ == "__main__": + main() diff --git a/python/users/get_users_me_user_context.py b/python/users/get_users_me_user_context.py index 95cdafa..8f02294 100644 --- a/python/users/get_users_me_user_context.py +++ b/python/users/get_users_me_user_context.py @@ -1,73 +1,65 @@ -from requests_oauthlib import OAuth1Session +""" +Authenticated User Lookup (Me) - X API v2 +========================================= +Endpoint: GET https://api.x.com/2/users/me +Docs: https://developer.x.com/en/docs/twitter-api/users/lookup/api-reference/get-users-me + +Authentication: OAuth 2.0 (User Context) +Required env vars: CLIENT_ID, CLIENT_SECRET +""" + import os import json +from xdk import Client +from xdk.oauth2_auth import OAuth2PKCEAuth -# In your terminal please set your environment variables by running the following lines of code. -# export 'CONSUMER_KEY'='' -# export 'CONSUMER_SECRET'='' - -consumer_key = os.environ.get("CONSUMER_KEY") -consumer_secret = os.environ.get("CONSUMER_SECRET") +# The code below sets the client ID and client secret from your environment variables +# To set environment variables on macOS or Linux, run the export commands below from the terminal: +# export CLIENT_ID='YOUR-CLIENT-ID' +# export CLIENT_SECRET='YOUR-CLIENT-SECRET' +client_id = os.environ.get("CLIENT_ID") +client_secret = os.environ.get("CLIENT_SECRET") -# User fields are adjustable, options include: -# created_at, description, entities, id, location, name, -# pinned_tweet_id, profile_image_url, protected, -# public_metrics, url, username, verified, and withheld -fields = "created_at,description" -params = {"user.fields": fields} +# Replace the following URL with your callback URL, which can be obtained from your App's auth settings. +redirect_uri = "https://example.com" -# Get request token -request_token_url = "https://api.x.com/oauth/request_token" -oauth = OAuth1Session(consumer_key, client_secret=consumer_secret) +# Set the scopes +scopes = ["tweet.read", "users.read", "offline.access"] -try: - fetch_response = oauth.fetch_request_token(request_token_url) -except ValueError: - print( - "There may have been an issue with the consumer_key or consumer_secret you entered." +def main(): + # Step 1: Create PKCE instance + auth = OAuth2PKCEAuth( + client_id=client_id, + client_secret=client_secret, + redirect_uri=redirect_uri, + scope=scopes ) - -resource_owner_key = fetch_response.get("oauth_token") -resource_owner_secret = fetch_response.get("oauth_token_secret") -print("Got OAuth token: %s" % resource_owner_key) - -# # Get authorization -base_authorization_url = "https://api.x.com/oauth/authorize" -authorization_url = oauth.authorization_url(base_authorization_url) -print("Please go here and authorize: %s" % authorization_url) -verifier = input("Paste the PIN here: ") - -# Get the access token -access_token_url = "https://api.x.com/oauth/access_token" -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=resource_owner_key, - resource_owner_secret=resource_owner_secret, - verifier=verifier, -) -oauth_tokens = oauth.fetch_access_token(access_token_url) - -access_token = oauth_tokens["oauth_token"] -access_token_secret = oauth_tokens["oauth_token_secret"] - -# Make the request -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=access_token, - resource_owner_secret=access_token_secret, -) - -response = oauth.get("https://api.x.com/2/users/me", params=params) - -if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format(response.status_code, response.text) + + # Step 2: Get authorization URL + auth_url = auth.get_authorization_url() + print("Visit the following URL to authorize your App on behalf of your X handle in a browser:") + print(auth_url) + + # Step 3: Handle callback + callback_url = input("Paste the full callback URL here: ") + + # Step 4: Exchange code for tokens + tokens = auth.fetch_token(authorization_response=callback_url) + access_token = tokens["access_token"] + + # Step 5: Create client + client = Client(access_token=access_token) + + # Step 6: Get authenticated user info + # User fields are adjustable, options include: + # created_at, description, entities, id, location, name, + # pinned_tweet_id, profile_image_url, protected, + # public_metrics, url, username, verified, and withheld + response = client.users.get_me( + user_fields=["created_at", "description"] ) + + print(json.dumps(response.data, indent=4, sort_keys=True)) -print("Response code: {}".format(response.status_code)) - -json_response = response.json() - -print(json.dumps(json_response, indent=4, sort_keys=True)) +if __name__ == "__main__": + main() diff --git a/python/users/get_users_with_bearer_token.py b/python/users/get_users_with_bearer_token.py deleted file mode 100644 index 4bc7c91..0000000 --- a/python/users/get_users_with_bearer_token.py +++ /dev/null @@ -1,52 +0,0 @@ -import requests -import os -import json - -# To set your enviornment variables in your terminal run the following line: -# export 'BEARER_TOKEN'='' -bearer_token = os.environ.get("BEARER_TOKEN") - - -def create_url(): - # Specify the usernames that you want to lookup below - # You can enter up to 100 comma-separated values. - usernames = "usernames=TwitterDev,TwitterAPI" - user_fields = "user.fields=description,created_at" - # User fields are adjustable, options include: - # created_at, description, entities, id, location, name, - # pinned_tweet_id, profile_image_url, protected, - # public_metrics, url, username, verified, and withheld - url = "https://api.x.com/2/users/by?{}&{}".format(usernames, user_fields) - return url - - -def bearer_oauth(r): - """ - Method required by bearer token authentication. - """ - - r.headers["Authorization"] = f"Bearer {bearer_token}" - r.headers["User-Agent"] = "v2UserLookupPython" - return r - - -def connect_to_endpoint(url): - response = requests.request("GET", url, auth=bearer_oauth,) - print(response.status_code) - if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format( - response.status_code, response.text - ) - ) - return response.json() - - -def main(): - url = create_url() - json_response = connect_to_endpoint(url) - print(json.dumps(json_response, indent=4, sort_keys=True)) - - -if __name__ == "__main__": - main() diff --git a/python/users/get_users_with_user_context.py b/python/users/get_users_with_user_context.py deleted file mode 100644 index 295e285..0000000 --- a/python/users/get_users_with_user_context.py +++ /dev/null @@ -1,75 +0,0 @@ -from requests_oauthlib import OAuth1Session -import os -import json - -# In your terminal please set your environment variables by running the following lines of code. -# export 'CONSUMER_KEY'='' -# export 'CONSUMER_SECRET'='' - -consumer_key = os.environ.get("CONSUMER_KEY") -consumer_secret = os.environ.get("CONSUMER_SECRET") - -# User fields are adjustable, options include: -# created_at, description, entities, id, location, name, -# pinned_tweet_id, profile_image_url, protected, -# public_metrics, url, username, verified, and withheld -fields = "created_at,description" -params = {"usernames": "TwitterDev,TwitterAPI", "user.fields": fields} - -# Get request token -request_token_url = "https://api.x.com/oauth/request_token" -oauth = OAuth1Session(consumer_key, client_secret=consumer_secret) - -try: - fetch_response = oauth.fetch_request_token(request_token_url) -except ValueError: - print( - "There may have been an issue with the consumer_key or consumer_secret you entered." - ) - -resource_owner_key = fetch_response.get("oauth_token") -resource_owner_secret = fetch_response.get("oauth_token_secret") -print("Got OAuth token: %s" % resource_owner_key) - -# # Get authorization -base_authorization_url = "https://api.x.com/oauth/authorize" -authorization_url = oauth.authorization_url(base_authorization_url) -print("Please go here and authorize: %s" % authorization_url) -verifier = input("Paste the PIN here: ") - -# Get the access token -access_token_url = "https://api.x.com/oauth/access_token" -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=resource_owner_key, - resource_owner_secret=resource_owner_secret, - verifier=verifier, -) -oauth_tokens = oauth.fetch_access_token(access_token_url) - -access_token = oauth_tokens["oauth_token"] -access_token_secret = oauth_tokens["oauth_token_secret"] - -# Make the request -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=access_token, - resource_owner_secret=access_token_secret, -) - -response = oauth.get( - "https://api.x.com/2/users/by", params=params -) - -if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format(response.status_code, response.text) - ) - -print("Response code: {}".format(response.status_code)) - -json_response = response.json() - -print(json.dumps(json_response, indent=4, sort_keys=True)) diff --git a/python/users/lookup.py b/python/users/lookup.py deleted file mode 100644 index fb984e6..0000000 --- a/python/users/lookup.py +++ /dev/null @@ -1,59 +0,0 @@ -""" -User Lookup - X API v2 -====================== -Endpoint: GET https://api.x.com/2/users/by -Docs: https://developer.x.com/en/docs/twitter-api/users/lookup/api-reference/get-users-by - -Authentication: Bearer Token (App-only) or OAuth (User Context) -Required env vars: BEARER_TOKEN -""" - -import requests -import os -import json - -bearer_token = os.environ.get("BEARER_TOKEN") - - -def create_url(): - # Specify the usernames to lookup (up to 100 comma-separated) - usernames = "usernames=XDevelopers,X" - - # User fields are adjustable. Options include: - # created_at, description, entities, id, location, name, - # pinned_tweet_id, profile_image_url, protected, - # public_metrics, url, username, verified, and withheld - user_fields = "user.fields=description,created_at" - url = "https://api.x.com/2/users/by?{}&{}".format(usernames, user_fields) - return url - - -def bearer_oauth(r): - """ - Method required by bearer token authentication. - """ - r.headers["Authorization"] = f"Bearer {bearer_token}" - r.headers["User-Agent"] = "v2UserLookupPython" - return r - - -def connect_to_endpoint(url): - response = requests.request("GET", url, auth=bearer_oauth) - print(response.status_code) - if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format( - response.status_code, response.text - ) - ) - return response.json() - - -def main(): - url = create_url() - json_response = connect_to_endpoint(url) - print(json.dumps(json_response, indent=4, sort_keys=True)) - - -if __name__ == "__main__": - main() diff --git a/python/users/lookup_blocks.py b/python/users/lookup_blocks.py deleted file mode 100644 index 623c13a..0000000 --- a/python/users/lookup_blocks.py +++ /dev/null @@ -1,77 +0,0 @@ -from requests_oauthlib import OAuth1Session -import os -import json - -# To set your enviornment variables in your terminal run the following line: -# export 'CONSUMER_KEY'='' -# export 'CONSUMER_SECRET'='' - -consumer_key = os.environ.get("CONSUMER_KEY") -consumer_secret = os.environ.get("CONSUMER_SECRET") - -# Be sure to replace your-user-id with your own user ID or one of an authenticating user -# You can find a user ID by using the user lookup endpoint -id = "your-user-id" - -params = {"user.fields": "created_at,description"} -# User fields are adjustable, options include: -# created_at, description, entities, id, location, name, -# pinned_tweet_id, profile_image_url, protected, -# public_metrics, url, username, verified, and withheld - -request_token_url = "https://api.x.com/oauth/request_token" -oauth = OAuth1Session(consumer_key, client_secret=consumer_secret) - -try: - fetch_response = oauth.fetch_request_token(request_token_url) -except ValueError: - print( - "There may have been an issue with the consumer_key or consumer_secret you entered." - ) - -resource_owner_key = fetch_response.get("oauth_token") -resource_owner_secret = fetch_response.get("oauth_token_secret") -print("Got OAuth token: %s" % resource_owner_key) - -# Get authorization -base_authorization_url = "https://api.x.com/oauth/authorize" -authorization_url = oauth.authorization_url(base_authorization_url) -print("Please go here and authorize: %s" % authorization_url) -verifier = input("Paste the PIN here: ") - -# Get the access token -access_token_url = "https://api.x.com/oauth/access_token" -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=resource_owner_key, - resource_owner_secret=resource_owner_secret, - verifier=verifier, -) -oauth_tokens = oauth.fetch_access_token(access_token_url) - - -access_token = oauth_tokens["oauth_token"] -access_token_secret = oauth_tokens["oauth_token_secret"] - -# Make the request -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=access_token, - resource_owner_secret=access_token_secret, -) - -response = oauth.get( - "https://api.x.com/2/users/{}/blocking".format(id), params=params -) - -if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format( - response.status_code, response.text) - ) - -print("Response code: {}".format(response.status_code)) -json_response = response.json() -print(json.dumps(json_response, indent=4, sort_keys=True)) diff --git a/python/users/lookup_mutes.py b/python/users/lookup_mutes.py deleted file mode 100644 index 298bb58..0000000 --- a/python/users/lookup_mutes.py +++ /dev/null @@ -1,79 +0,0 @@ -from requests_oauthlib import OAuth1Session -import os -import json - -# To set your enviornment variables in your terminal run the following line: -# export 'CONSUMER_KEY'='' -# export 'CONSUMER_SECRET'='' - -consumer_key = os.environ.get("CONSUMER_KEY") -consumer_secret = os.environ.get("CONSUMER_SECRET") - -# Be sure to replace your-user-id with your own user ID or one of an authenticating user -# You can find a user ID by using the user lookup endpoint -id = "your-user-id" - -params = {"user.fields": "created_at,description"} - - -# User fields are adjustable, options include: -# created_at, description, entities, id, location, name, -# pinned_tweet_id, profile_image_url, protected, -# public_metrics, url, username, verified, and withheld - -request_token_url = "https://api.x.com/oauth/request_token" -oauth = OAuth1Session(consumer_key, client_secret=consumer_secret) - -try: - fetch_response = oauth.fetch_request_token(request_token_url) -except ValueError: - print( - "There may have been an issue with the consumer_key or consumer_secret you entered." - ) - -resource_owner_key = fetch_response.get("oauth_token") -resource_owner_secret = fetch_response.get("oauth_token_secret") -print("Got OAuth token: %s" % resource_owner_key) - -# Get authorization -base_authorization_url = "https://api.x.com/oauth/authorize" -authorization_url = oauth.authorization_url(base_authorization_url) -print("Please go here and authorize: %s" % authorization_url) -verifier = input("Paste the PIN here: ") - -# Get the access token -access_token_url = "https://api.x.com/oauth/access_token" -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=resource_owner_key, - resource_owner_secret=resource_owner_secret, - verifier=verifier, -) -oauth_tokens = oauth.fetch_access_token(access_token_url) - - -access_token = oauth_tokens["oauth_token"] -access_token_secret = oauth_tokens["oauth_token_secret"] - -# Make the request -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=access_token, - resource_owner_secret=access_token_secret, -) - -response = oauth.get( - "https://api.x.com/2/users/{}/muting".format(id),params=params -) - -if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format( - response.status_code, response.text) - ) - -print("Response code: {}".format(response.status_code)) -json_response = response.json() -print(json.dumps(json_response, indent=4, sort_keys=True)) \ No newline at end of file diff --git a/python/users/me.py b/python/users/me.py deleted file mode 100644 index 819ea46..0000000 --- a/python/users/me.py +++ /dev/null @@ -1,80 +0,0 @@ -""" -Authenticated User Lookup (Me) - X API v2 -========================================= -Endpoint: GET https://api.x.com/2/users/me -Docs: https://developer.x.com/en/docs/twitter-api/users/lookup/api-reference/get-users-me - -Authentication: OAuth 1.0a or OAuth 2.0 (User Context) -Required env vars: CONSUMER_KEY, CONSUMER_SECRET -""" - -from requests_oauthlib import OAuth1Session -import os -import json - -consumer_key = os.environ.get("CONSUMER_KEY") -consumer_secret = os.environ.get("CONSUMER_SECRET") - -# User fields are adjustable. Options include: -# created_at, description, entities, id, location, name, -# pinned_tweet_id, profile_image_url, protected, -# public_metrics, url, username, verified, and withheld -fields = "user.fields=description,created_at" -params = {"user.fields": fields} - -# Get request token -request_token_url = "https://api.x.com/oauth/request_token" -oauth = OAuth1Session(consumer_key, client_secret=consumer_secret) - -try: - fetch_response = oauth.fetch_request_token(request_token_url) -except ValueError: - print( - "There may have been an issue with the consumer_key or consumer_secret you entered." - ) - -resource_owner_key = fetch_response.get("oauth_token") -resource_owner_secret = fetch_response.get("oauth_token_secret") -print("Got OAuth token: %s" % resource_owner_key) - -# Get authorization -base_authorization_url = "https://api.x.com/oauth/authorize" -authorization_url = oauth.authorization_url(base_authorization_url) -print("Please go here and authorize: %s" % authorization_url) -verifier = input("Paste the PIN here: ") - -# Get the access token -access_token_url = "https://api.x.com/oauth/access_token" -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=resource_owner_key, - resource_owner_secret=resource_owner_secret, - verifier=verifier, -) -oauth_tokens = oauth.fetch_access_token(access_token_url) - -access_token = oauth_tokens["oauth_token"] -access_token_secret = oauth_tokens["oauth_token_secret"] - -# Make the request -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=access_token, - resource_owner_secret=access_token_secret, -) - -# Making the request -response = oauth.get("https://api.x.com/2/users/me", params=params) - -if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format(response.status_code, response.text) - ) - -print("Response code: {}".format(response.status_code)) - -# Saving the response as JSON -json_response = response.json() -print(json.dumps(json_response, indent=4, sort_keys=True)) diff --git a/python/users/mute.py b/python/users/mute.py deleted file mode 100644 index ce37e70..0000000 --- a/python/users/mute.py +++ /dev/null @@ -1,81 +0,0 @@ -""" -Mute User - X API v2 -==================== -Endpoint: POST https://api.x.com/2/users/:id/muting -Docs: https://developer.x.com/en/docs/twitter-api/users/mutes/api-reference/post-users-user_id-muting - -Authentication: OAuth 1.0a (User Context) -Required env vars: CONSUMER_KEY, CONSUMER_SECRET -""" - -from requests_oauthlib import OAuth1Session -import os -import json - -consumer_key = os.environ.get("CONSUMER_KEY") -consumer_secret = os.environ.get("CONSUMER_SECRET") - -# Replace with your own user ID -user_id = "your-user-id" - -# Replace with the user ID you want to mute -payload = {"target_user_id": "target-user-id"} - -# Get request token -request_token_url = "https://api.x.com/oauth/request_token" -oauth = OAuth1Session(consumer_key, client_secret=consumer_secret) - -try: - fetch_response = oauth.fetch_request_token(request_token_url) -except ValueError: - print( - "There may have been an issue with the consumer_key or consumer_secret you entered." - ) - -resource_owner_key = fetch_response.get("oauth_token") -resource_owner_secret = fetch_response.get("oauth_token_secret") -print("Got OAuth token: %s" % resource_owner_key) - -# Get authorization -base_authorization_url = "https://api.x.com/oauth/authorize" -authorization_url = oauth.authorization_url(base_authorization_url) -print("Please go here and authorize: %s" % authorization_url) -verifier = input("Paste the PIN here: ") - -# Get the access token -access_token_url = "https://api.x.com/oauth/access_token" -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=resource_owner_key, - resource_owner_secret=resource_owner_secret, - verifier=verifier, -) -oauth_tokens = oauth.fetch_access_token(access_token_url) - -access_token = oauth_tokens["oauth_token"] -access_token_secret = oauth_tokens["oauth_token_secret"] - -# Make the request -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=access_token, - resource_owner_secret=access_token_secret, -) - -# Making the request -response = oauth.post( - "https://api.x.com/2/users/{}/muting".format(user_id), json=payload -) - -if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format(response.status_code, response.text) - ) - -print("Response code: {}".format(response.status_code)) - -# Saving the response as JSON -json_response = response.json() -print(json.dumps(json_response, indent=4, sort_keys=True)) diff --git a/python/users/mute_a_user.py b/python/users/mute_a_user.py deleted file mode 100644 index 7a664a7..0000000 --- a/python/users/mute_a_user.py +++ /dev/null @@ -1,77 +0,0 @@ -from requests_oauthlib import OAuth1Session -import os -import json - -# In your terminal please set your environment variables by running the following lines of code. -# export 'CONSUMER_KEY'='' -# export 'CONSUMER_SECRET'='' - -consumer_key = os.environ.get("CONSUMER_KEY") -consumer_secret = os.environ.get("CONSUMER_SECRET") - - -# Be sure to replace your-user-id with your own user ID or one of an authenticating user -# You can find a user ID by using the user lookup endpoint -id = "your-user-id" - -# Be sure to replace id-to-mute with the user id you wish to mute. -payload = {"target_user_id": "id-to-mute"} - -# Get request token -request_token_url = "https://api.x.com/oauth/request_token" -oauth = OAuth1Session(consumer_key, client_secret=consumer_secret) - -try: - fetch_response = oauth.fetch_request_token(request_token_url) -except ValueError: - print( - "There may have been an issue with the consumer_key or consumer_secret you entered." - ) - -resource_owner_key = fetch_response.get("oauth_token") -resource_owner_secret = fetch_response.get("oauth_token_secret") -print("Got OAuth token: %s" % resource_owner_key) - -# Get authorization -base_authorization_url = "https://api.x.com/oauth/authorize" -authorization_url = oauth.authorization_url(base_authorization_url) -print("Please go here and authorize: %s" % authorization_url) -verifier = input("Paste the PIN here: ") - -# Get the access token -access_token_url = "https://api.x.com/oauth/access_token" -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=resource_owner_key, - resource_owner_secret=resource_owner_secret, - verifier=verifier, -) -oauth_tokens = oauth.fetch_access_token(access_token_url) - -access_token = oauth_tokens["oauth_token"] -access_token_secret = oauth_tokens["oauth_token_secret"] - -# Make the request -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=access_token, - resource_owner_secret=access_token_secret, -) - -# Making the request -response = oauth.post( - "https://api.x.com/2/users/{}/muting".format(id), json=payload -) - -if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format(response.status_code, response.text) - ) - -print("Response code: {}".format(response.status_code)) - -# Saving the response as JSON -json_response = response.json() -print(json.dumps(json_response, indent=4, sort_keys=True)) diff --git a/python/users/mute_user.py b/python/users/mute_user.py new file mode 100644 index 0000000..34fc956 --- /dev/null +++ b/python/users/mute_user.py @@ -0,0 +1,68 @@ +""" +Mute User - X API v2 +==================== +Endpoint: POST https://api.x.com/2/users/:id/muting +Docs: https://developer.x.com/en/docs/twitter-api/users/mutes/api-reference/post-users-user_id-muting + +Authentication: OAuth 2.0 (User Context) +Required env vars: CLIENT_ID, CLIENT_SECRET +""" + +import os +import json +from xdk import Client +from xdk.oauth2_auth import OAuth2PKCEAuth + +# The code below sets the client ID and client secret from your environment variables +# To set environment variables on macOS or Linux, run the export commands below from the terminal: +# export CLIENT_ID='YOUR-CLIENT-ID' +# export CLIENT_SECRET='YOUR-CLIENT-SECRET' +client_id = os.environ.get("CLIENT_ID") +client_secret = os.environ.get("CLIENT_SECRET") + +# Replace the following URL with your callback URL, which can be obtained from your App's auth settings. +redirect_uri = "https://example.com" + +# Set the scopes +scopes = ["tweet.read", "users.read", "tweet.write", "offline.access", "mute.write"] + +# Be sure to replace your-user-id with your own user ID or one of an authenticated user +# You can find a user ID by using the user lookup endpoint +user_id = "your-user-id" + +# Be sure to replace id-to-mute with the user id you wish to mute. +target_user_id = "id-to-mute" + +def main(): + # Step 1: Create PKCE instance + auth = OAuth2PKCEAuth( + client_id=client_id, + client_secret=client_secret, + redirect_uri=redirect_uri, + scope=scopes + ) + + # Step 2: Get authorization URL + auth_url = auth.get_authorization_url() + print("Visit the following URL to authorize your App on behalf of your X handle in a browser:") + print(auth_url) + + # Step 3: Handle callback + callback_url = input("Paste the full callback URL here: ") + + # Step 4: Exchange code for tokens + tokens = auth.fetch_token(authorization_response=callback_url) + access_token = tokens["access_token"] + + # Step 5: Create client + client = Client(access_token=access_token) + + # Step 6: Mute the user + payload = {"target_user_id": target_user_id} + response = client.users.mute_user(user_id, body=payload) + + print("Response code: 200") + print(json.dumps(response.data, indent=4, sort_keys=True)) + +if __name__ == "__main__": + main() diff --git a/python/users/muted.py b/python/users/muted.py deleted file mode 100644 index 01aaa29..0000000 --- a/python/users/muted.py +++ /dev/null @@ -1,84 +0,0 @@ -""" -Muted Users Lookup - X API v2 -============================= -Endpoint: GET https://api.x.com/2/users/:id/muting -Docs: https://developer.x.com/en/docs/twitter-api/users/mutes/api-reference/get-users-muting - -Authentication: OAuth 1.0a (User Context) -Required env vars: CONSUMER_KEY, CONSUMER_SECRET -""" - -from requests_oauthlib import OAuth1Session -import os -import json - -consumer_key = os.environ.get("CONSUMER_KEY") -consumer_secret = os.environ.get("CONSUMER_SECRET") - -# User fields are adjustable. Options include: -# created_at, description, entities, id, location, name, -# pinned_tweet_id, profile_image_url, protected, -# public_metrics, url, username, verified, and withheld -fields = "user.fields=created_at,description" -params = {"user.fields": fields} - -# Get request token -request_token_url = "https://api.x.com/oauth/request_token" -oauth = OAuth1Session(consumer_key, client_secret=consumer_secret) - -try: - fetch_response = oauth.fetch_request_token(request_token_url) -except ValueError: - print( - "There may have been an issue with the consumer_key or consumer_secret you entered." - ) - -resource_owner_key = fetch_response.get("oauth_token") -resource_owner_secret = fetch_response.get("oauth_token_secret") -print("Got OAuth token: %s" % resource_owner_key) - -# Get authorization -base_authorization_url = "https://api.x.com/oauth/authorize" -authorization_url = oauth.authorization_url(base_authorization_url) -print("Please go here and authorize: %s" % authorization_url) -verifier = input("Paste the PIN here: ") - -# Get the access token -access_token_url = "https://api.x.com/oauth/access_token" -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=resource_owner_key, - resource_owner_secret=resource_owner_secret, - verifier=verifier, -) -oauth_tokens = oauth.fetch_access_token(access_token_url) - -access_token = oauth_tokens["oauth_token"] -access_token_secret = oauth_tokens["oauth_token_secret"] - -# Make the request -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=access_token, - resource_owner_secret=access_token_secret, -) - -user_id = oauth_tokens["user_id"] - -# Making the request -response = oauth.get( - "https://api.x.com/2/users/{}/muting".format(user_id), params=params -) - -if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format(response.status_code, response.text) - ) - -print("Response code: {}".format(response.status_code)) - -# Saving the response as JSON -json_response = response.json() -print(json.dumps(json_response, indent=4, sort_keys=True)) diff --git a/python/users/unblock.py b/python/users/unblock.py deleted file mode 100644 index be374b8..0000000 --- a/python/users/unblock.py +++ /dev/null @@ -1,81 +0,0 @@ -""" -Unblock User - X API v2 -======================= -Endpoint: DELETE https://api.x.com/2/users/:source_user_id/blocking/:target_user_id -Docs: https://developer.x.com/en/docs/twitter-api/users/blocks/api-reference/delete-users-user_id-blocking - -Authentication: OAuth 1.0a (User Context) -Required env vars: CONSUMER_KEY, CONSUMER_SECRET -""" - -from requests_oauthlib import OAuth1Session -import os -import json - -consumer_key = os.environ.get("CONSUMER_KEY") -consumer_secret = os.environ.get("CONSUMER_SECRET") - -# Replace with your own user ID -user_id = "your-user-id" - -# Replace with the user ID you want to unblock -target_user_id = "target-user-id" - -# Get request token -request_token_url = "https://api.x.com/oauth/request_token" -oauth = OAuth1Session(consumer_key, client_secret=consumer_secret) - -try: - fetch_response = oauth.fetch_request_token(request_token_url) -except ValueError: - print( - "There may have been an issue with the consumer_key or consumer_secret you entered." - ) - -resource_owner_key = fetch_response.get("oauth_token") -resource_owner_secret = fetch_response.get("oauth_token_secret") -print("Got OAuth token: %s" % resource_owner_key) - -# Get authorization -base_authorization_url = "https://api.x.com/oauth/authorize" -authorization_url = oauth.authorization_url(base_authorization_url) -print("Please go here and authorize: %s" % authorization_url) -verifier = input("Paste the PIN here: ") - -# Get the access token -access_token_url = "https://api.x.com/oauth/access_token" -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=resource_owner_key, - resource_owner_secret=resource_owner_secret, - verifier=verifier, -) -oauth_tokens = oauth.fetch_access_token(access_token_url) - -access_token = oauth_tokens["oauth_token"] -access_token_secret = oauth_tokens["oauth_token_secret"] - -# Make the request -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=access_token, - resource_owner_secret=access_token_secret, -) - -# Making the request -response = oauth.delete( - "https://api.x.com/2/users/{}/blocking/{}".format(user_id, target_user_id) -) - -if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format(response.status_code, response.text) - ) - -print("Response code: {}".format(response.status_code)) - -# Saving the response as JSON -json_response = response.json() -print(json.dumps(json_response, indent=4, sort_keys=True)) diff --git a/python/users/unblock_a_user.py b/python/users/unblock_a_user.py deleted file mode 100644 index 62ea052..0000000 --- a/python/users/unblock_a_user.py +++ /dev/null @@ -1,81 +0,0 @@ -from requests_oauthlib import OAuth1Session -import os -import json - -# In your terminal please set your environment variables by running the following lines of code. -# export 'CONSUMER_KEY'='' -# export 'CONSUMER_SECRET'='' - -consumer_key = os.environ.get("CONSUMER_KEY") -consumer_secret = os.environ.get("CONSUMER_SECRET") - - -# Be sure to replace your-user-id with your own user ID or one of an authenticated user -# You can find a user ID by using the user lookup endpoint -source_user_id = "your-user-id" - -# Be sure to add replace id-to-unblock with the id of the user you wish to unblock. -# You can find a user ID by using the user lookup endpoint -target_user_id = "id-to-unblock" - - -# Get request token -request_token_url = "https://api.x.com/oauth/request_token" -oauth = OAuth1Session(consumer_key, client_secret=consumer_secret) - -try: - fetch_response = oauth.fetch_request_token(request_token_url) -except ValueError: - print( - "There may have been an issue with the consumer_key or consumer_secret you entered." - ) - -resource_owner_key = fetch_response.get("oauth_token") -resource_owner_secret = fetch_response.get("oauth_token_secret") -print("Got OAuth token: %s" % resource_owner_key) - -# Get authorization -base_authorization_url = "https://api.x.com/oauth/authorize" -authorization_url = oauth.authorization_url(base_authorization_url) -print("Please go here and authorize: %s" % authorization_url) -verifier = input("Paste the PIN here: ") - -# Get the access token -access_token_url = "https://api.x.com/oauth/access_token" -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=resource_owner_key, - resource_owner_secret=resource_owner_secret, - verifier=verifier, -) -oauth_tokens = oauth.fetch_access_token(access_token_url) - -access_token = oauth_tokens["oauth_token"] -access_token_secret = oauth_tokens["oauth_token_secret"] - -# Make the request -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=access_token, - resource_owner_secret=access_token_secret, -) - -# Making the request -response = oauth.delete( - "https://api.x.com/2/users/{}/blocking/{}".format(id, target_user_id) -) - -if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format(response.status_code, response.text) - ) - -print("Response code: {}".format(response.status_code)) - -# Saving the response as JSON -json_response = response.json() -print(json.dumps(json_response, indent=4, sort_keys=True)) - -# Note: If you were following the user you blocked, you have removed your follow and will have to refollow the user, even if you did unblock the user. diff --git a/python/users/unmute.py b/python/users/unmute.py deleted file mode 100644 index b1d607f..0000000 --- a/python/users/unmute.py +++ /dev/null @@ -1,81 +0,0 @@ -""" -Unmute User - X API v2 -====================== -Endpoint: DELETE https://api.x.com/2/users/:source_user_id/muting/:target_user_id -Docs: https://developer.x.com/en/docs/twitter-api/users/mutes/api-reference/delete-users-user_id-muting - -Authentication: OAuth 1.0a (User Context) -Required env vars: CONSUMER_KEY, CONSUMER_SECRET -""" - -from requests_oauthlib import OAuth1Session -import os -import json - -consumer_key = os.environ.get("CONSUMER_KEY") -consumer_secret = os.environ.get("CONSUMER_SECRET") - -# Replace with your own user ID -user_id = "your-user-id" - -# Replace with the user ID you want to unmute -target_user_id = "target-user-id" - -# Get request token -request_token_url = "https://api.x.com/oauth/request_token" -oauth = OAuth1Session(consumer_key, client_secret=consumer_secret) - -try: - fetch_response = oauth.fetch_request_token(request_token_url) -except ValueError: - print( - "There may have been an issue with the consumer_key or consumer_secret you entered." - ) - -resource_owner_key = fetch_response.get("oauth_token") -resource_owner_secret = fetch_response.get("oauth_token_secret") -print("Got OAuth token: %s" % resource_owner_key) - -# Get authorization -base_authorization_url = "https://api.x.com/oauth/authorize" -authorization_url = oauth.authorization_url(base_authorization_url) -print("Please go here and authorize: %s" % authorization_url) -verifier = input("Paste the PIN here: ") - -# Get the access token -access_token_url = "https://api.x.com/oauth/access_token" -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=resource_owner_key, - resource_owner_secret=resource_owner_secret, - verifier=verifier, -) -oauth_tokens = oauth.fetch_access_token(access_token_url) - -access_token = oauth_tokens["oauth_token"] -access_token_secret = oauth_tokens["oauth_token_secret"] - -# Make the request -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=access_token, - resource_owner_secret=access_token_secret, -) - -# Making the request -response = oauth.delete( - "https://api.x.com/2/users/{}/muting/{}".format(user_id, target_user_id) -) - -if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format(response.status_code, response.text) - ) - -print("Response code: {}".format(response.status_code)) - -# Saving the response as JSON -json_response = response.json() -print(json.dumps(json_response, indent=4, sort_keys=True)) diff --git a/python/users/unmute_a_user.py b/python/users/unmute_a_user.py deleted file mode 100644 index 268e545..0000000 --- a/python/users/unmute_a_user.py +++ /dev/null @@ -1,79 +0,0 @@ -from requests_oauthlib import OAuth1Session -import os -import json - -# In your terminal please set your environment variables by running the following lines of code. -# export 'CONSUMER_KEY'='' -# export 'CONSUMER_SECRET'='' - -consumer_key = os.environ.get("CONSUMER_KEY") -consumer_secret = os.environ.get("CONSUMER_SECRET") - - -# Be sure to replace your-user-id with your own user ID or one of an authenticated user -# You can find a user ID by using the user lookup endpoint -source_user_id = "your-user-id" - -# Be sure to add replace id-to-unmute with the id of the user you wish to unmute. -# You can find a user ID by using the user lookup endpoint -target_user_id = "id-to-unmute" - - -# Get request token -request_token_url = "https://api.x.com/oauth/request_token" -oauth = OAuth1Session(consumer_key, client_secret=consumer_secret) - -try: - fetch_response = oauth.fetch_request_token(request_token_url) -except ValueError: - print( - "There may have been an issue with the consumer_key or consumer_secret you entered." - ) - -resource_owner_key = fetch_response.get("oauth_token") -resource_owner_secret = fetch_response.get("oauth_token_secret") -print("Got OAuth token: %s" % resource_owner_key) - -# Get authorization -base_authorization_url = "https://api.x.com/oauth/authorize" -authorization_url = oauth.authorization_url(base_authorization_url) -print("Please go here and authorize: %s" % authorization_url) -verifier = input("Paste the PIN here: ") - -# Get the access token -access_token_url = "https://api.x.com/oauth/access_token" -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=resource_owner_key, - resource_owner_secret=resource_owner_secret, - verifier=verifier, -) -oauth_tokens = oauth.fetch_access_token(access_token_url) - -access_token = oauth_tokens["oauth_token"] -access_token_secret = oauth_tokens["oauth_token_secret"] - -# Make the request -oauth = OAuth1Session( - consumer_key, - client_secret=consumer_secret, - resource_owner_key=access_token, - resource_owner_secret=access_token_secret, -) - -# Making the request -response = oauth.delete( - "https://api.x.com/2/users/{}/muting/{}".format(id, target_user_id) -) - -if response.status_code != 200: - raise Exception( - "Request returned an error: {} {}".format(response.status_code, response.text) - ) - -print("Response code: {}".format(response.status_code)) - -# Saving the response as JSON -json_response = response.json() -print(json.dumps(json_response, indent=4, sort_keys=True)) diff --git a/python/users/unmute_user.py b/python/users/unmute_user.py new file mode 100644 index 0000000..5060013 --- /dev/null +++ b/python/users/unmute_user.py @@ -0,0 +1,68 @@ +""" +Unmute User - X API v2 +====================== +Endpoint: DELETE https://api.x.com/2/users/:source_user_id/muting/:target_user_id +Docs: https://developer.x.com/en/docs/twitter-api/users/mutes/api-reference/delete-users-user_id-muting + +Authentication: OAuth 2.0 (User Context) +Required env vars: CLIENT_ID, CLIENT_SECRET +""" + +import os +import json +from xdk import Client +from xdk.oauth2_auth import OAuth2PKCEAuth + +# The code below sets the client ID and client secret from your environment variables +# To set environment variables on macOS or Linux, run the export commands below from the terminal: +# export CLIENT_ID='YOUR-CLIENT-ID' +# export CLIENT_SECRET='YOUR-CLIENT-SECRET' +client_id = os.environ.get("CLIENT_ID") +client_secret = os.environ.get("CLIENT_SECRET") + +# Replace the following URL with your callback URL, which can be obtained from your App's auth settings. +redirect_uri = "https://example.com" + +# Set the scopes +scopes = ["tweet.read", "users.read", "tweet.write", "offline.access", "mute.write"] + +# Be sure to replace your-user-id with your own user ID or one of an authenticated user +# You can find a user ID by using the user lookup endpoint +user_id = "your-user-id" + +# Be sure to replace id-to-unmute with the id of the user you wish to unmute. +# You can find a user ID by using the user lookup endpoint +target_user_id = "id-to-unmute" + +def main(): + # Step 1: Create PKCE instance + auth = OAuth2PKCEAuth( + client_id=client_id, + client_secret=client_secret, + redirect_uri=redirect_uri, + scope=scopes + ) + + # Step 2: Get authorization URL + auth_url = auth.get_authorization_url() + print("Visit the following URL to authorize your App on behalf of your X handle in a browser:") + print(auth_url) + + # Step 3: Handle callback + callback_url = input("Paste the full callback URL here: ") + + # Step 4: Exchange code for tokens + tokens = auth.fetch_token(authorization_response=callback_url) + access_token = tokens["access_token"] + + # Step 5: Create client + client = Client(access_token=access_token) + + # Step 6: Unmute the user + response = client.users.unmute_user(user_id, target_user_id) + + print("Response code: 200") + print(json.dumps(response.data, indent=4, sort_keys=True)) + +if __name__ == "__main__": + main()