You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

129 lines
6.1 KiB

import logging
logging.basicConfig(
filename='/home/shane/foodie_automator/logs/check_x_capacity.log',
level=logging.DEBUG,
format='%(asctime)s - %(levelname)s - %(message)s'
)
import requests
from requests_oauthlib import OAuth1
from datetime import datetime, timezone
from dotenv import load_dotenv
import os
import time
from foodie_config import X_API_CREDENTIALS
# Load environment variables from .env file
load_dotenv()
# Function to delete a tweet
def delete_tweet(tweet_id, auth):
try:
response = requests.delete(f"https://api.x.com/2/tweets/{tweet_id}", auth=auth)
response.raise_for_status()
logging.info(f"Successfully deleted tweet {tweet_id}")
return True
except Exception as e:
logging.error(f"Failed to delete tweet {tweet_id}: {e}")
return False
# Function to check rate limits for a given author
def check_rate_limits_for_author(username, credentials, retry=False):
logging.info(f"{'Retrying' if retry else 'Checking'} rate limits for {username} (handle: {credentials['x_username']})")
# Retrieve OAuth 1.0a credentials for the author
consumer_key = credentials["api_key"]
consumer_secret = credentials["api_secret"]
access_token = credentials["access_token"]
access_token_secret = credentials["access_token_secret"]
# Validate credentials
if not all([consumer_key, consumer_secret, access_token, access_token_secret]):
logging.error(f"Missing OAuth credentials for {username} in X_API_CREDENTIALS.")
return None
# Set up OAuth 1.0a authentication
auth = OAuth1(consumer_key, consumer_secret, access_token, access_token_secret)
# Add delay to avoid IP-based rate limiting
logging.info(f"Waiting 5 seconds before attempting to post for {username}")
time.sleep(5)
# Try posting a test tweet to get v2 rate limit headers
tweet_id = None
try:
tweet_data = {"text": f"Test tweet to check rate limits for {username} - please ignore"}
response = requests.post("https://api.x.com/2/tweets", json=tweet_data, auth=auth)
response.raise_for_status()
tweet_id = response.json()['data']['id']
logging.info("Successfully posted test tweet for %s: %s", username, response.json())
logging.info("Response Headers for %s: %s", username, response.headers)
# Extract rate limit headers if present
app_limit = response.headers.get('x-app-limit-24hour-limit', 'N/A')
app_remaining = response.headers.get('x-app-limit-24hour-remaining', 'N/A')
app_reset = response.headers.get('x-app-limit-24hour-reset', 'N/A')
logging.info("App 24-Hour Tweet Limit for %s: %s", username, app_limit)
logging.info("App 24-Hour Tweets Remaining for %s: %s", username, app_remaining)
if app_reset != 'N/A':
reset_time = datetime.fromtimestamp(int(app_reset), timezone.utc).strftime('%Y-%m-%d %H:%M:%S UTC')
logging.info("App 24-Hour Reset (Readable) for %s: %s", username, reset_time)
return tweet_id
except requests.exceptions.HTTPError as e:
logging.info("Test Tweet Response Status Code for %s: %s", username, e.response.status_code)
logging.info("Test Tweet Response Headers for %s: %s", username, e.response.headers)
if e.response.status_code == 429:
logging.info("Rate Limit Exceeded for /2/tweets for %s", username)
# Extract user-specific 24-hour limits
user_limit = e.response.headers.get('x-user-limit-24hour-limit', 'N/A')
user_remaining = e.response.headers.get('x-user-limit-24hour-remaining', 'N/A')
user_reset = e.response.headers.get('x-user-limit-24hour-reset', 'N/A')
logging.info("User 24-Hour Tweet Limit for %s: %s", username, user_limit)
logging.info("User 24-Hour Tweets Remaining for %s: %s", username, user_remaining)
logging.info("User 24-Hour Reset (Timestamp) for %s: %s", username, user_reset)
if user_reset != 'N/A':
reset_time = datetime.fromtimestamp(int(user_reset), timezone.utc).strftime('%Y-%m-%d %H:%M:%S UTC')
logging.info("User 24-Hour Reset (Readable) for %s: %s", username, reset_time)
# Extract app-specific 24-hour limits
app_limit = e.response.headers.get('x-app-limit-24hour-limit', 'N/A')
app_remaining = e.response.headers.get('x-app-limit-24hour-remaining', 'N/A')
app_reset = e.response.headers.get('x-app-limit-24hour-reset', 'N/A')
logging.info("App 24-Hour Tweet Limit for %s: %s", username, app_limit)
logging.info("App 24-Hour Tweets Remaining for %s: %s", username, app_remaining)
logging.info("App 24-Hour Reset (Timestamp) for %s: %s", username, app_reset)
if app_reset != 'N/A':
reset_time = datetime.fromtimestamp(int(app_reset), timezone.utc).strftime('%Y-%m-%d %H:%M:%S UTC')
logging.info("App 24-Hour Reset (Readable) for %s: %s", username, reset_time)
return None
except Exception as e:
logging.error("Failed to post test tweet for %s: %s", username, e)
return None
# Main loop to check rate limits for all authors
if __name__ == "__main__":
# First pass: Attempt to post for all authors
successful_tweets = {}
for username, credentials in X_API_CREDENTIALS.items():
tweet_id = check_rate_limits_for_author(username, credentials)
if tweet_id:
successful_tweets[username] = (tweet_id, credentials)
logging.info("-" * 50)
# Delete successful tweets to free up quota
for username, (tweet_id, credentials) in successful_tweets.items():
auth = OAuth1(
credentials["api_key"],
credentials["api_secret"],
credentials["access_token"],
credentials["access_token_secret"]
)
delete_tweet(tweet_id, auth)
# Second pass: Retry for authors that failed
logging.info("Retrying for authors that initially failed...")
for username, credentials in X_API_CREDENTIALS.items():
if username not in successful_tweets:
check_rate_limits_for_author(username, credentials, retry=True)
logging.info("-" * 50)