Skip to content

Commit

Permalink
Merge pull request #29 from RileyXX/improve-api-status-code-handling
Browse files Browse the repository at this point in the history
Improve api status code handling
  • Loading branch information
RileyXX authored May 20, 2023
2 parents 010d28d + b28eeff commit 3821988
Show file tree
Hide file tree
Showing 6 changed files with 103 additions and 66 deletions.
40 changes: 7 additions & 33 deletions IMDBTraktSyncer/IMDBTraktSyncer.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,6 @@ def main():
try:

#Get credentials
trakt_client_id = verifyCredentials.trakt_client_id
trakt_client_secret = verifyCredentials.trakt_client_secret
trakt_access_token = verifyCredentials.trakt_access_token
imdb_username = verifyCredentials.imdb_username
imdb_password = verifyCredentials.imdb_password

Expand Down Expand Up @@ -108,7 +105,7 @@ def main():
print("\nStopping script...")
raise SystemExit

trakt_ratings, trakt_reviews = traktData.getTraktData(trakt_client_id, trakt_access_token)
trakt_ratings, trakt_reviews = traktData.getTraktData()
imdb_ratings, imdb_reviews = imdbData.getImdbData(imdb_username, imdb_password, driver, directory, wait)

#Get trakt and imdb ratings and filter out trakt ratings with missing imdb id
Expand Down Expand Up @@ -168,16 +165,7 @@ def remove_duplicates_and_filter(lst, key, min_comment_length=None):
print('Setting Trakt Ratings')

# Set the API endpoints
oauth_url = "https://api.trakt.tv/oauth/token"
rate_url = "https://api.trakt.tv/sync/ratings"

# Set the headers
headers = {
"Content-Type": "application/json",
"trakt-api-version": "2",
"trakt-api-key": trakt_client_id,
"Authorization": f"Bearer {trakt_access_token}"
}

# Count the total number of items to rate
num_items = len(trakt_ratings_to_set)
Expand Down Expand Up @@ -221,12 +209,9 @@ def remove_duplicates_and_filter(lst, key, min_comment_length=None):
print(f"Rating episode ({item_count} of {num_items}): {item['Title']} ({item['Year']}): {item['Rating']}/10 on Trakt")

# Make the API call to rate the item
response = requests.post(rate_url, headers=headers, json=data)
while response.status_code == 429:
print("Rate limit exceeded. Waiting for 1 second...")
time.sleep(1)
response = requests.post(rate_url, headers=headers, json=data)
if response.status_code != 201:
response = errorHandling.make_trakt_request(rate_url, payload=data)

if response is None:
print(f"Error rating {item}: {response.content}")

print('Setting Trakt Ratings Complete')
Expand Down Expand Up @@ -281,13 +266,6 @@ def remove_duplicates_and_filter(lst, key, min_comment_length=None):
imdb_id = review['ID']
comment = review['Comment']
media_type = review['Type'] # 'movie', 'show', or 'episode'

headers = {
"Content-Type": "application/json",
"trakt-api-version": "2",
"trakt-api-key": trakt_client_id,
"Authorization": f"Bearer {trakt_access_token}"
}

url = f"https://api.trakt.tv/comments"

Expand All @@ -313,13 +291,9 @@ def remove_duplicates_and_filter(lst, key, min_comment_length=None):
"imdb": episode_id
}
}

response = requests.post(url, headers=headers, json=data)
while response.status_code == 429:
print("Rate limit exceeded. Waiting for 1 second...")
time.sleep(1)
response = requests.post(url, headers=headers, json=data)
if response.status_code == 201:

response = errorHandling.make_trakt_request(url, payload=data)
if response:
print(f"Submitted comment ({item_count} of {num_items}): {review['Title']} ({review['Year']}) on Trakt")
else:
print(f"Failed to submit comment ({item_count} of {num_items}): {review['Title']} ({review['Year']}) on Trakt")
Expand Down
9 changes: 5 additions & 4 deletions IMDBTraktSyncer/authTrakt.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import requests
import time
try:
from IMDBTraktSyncer import errorHandling
except:
import errorHandling

def authenticate(client_id, client_secret):
CLIENT_ID = client_id
Expand Down Expand Up @@ -38,10 +42,7 @@ def authenticate(client_id, client_secret):
}

# Make the request to get the access token
response = requests.post('https://api.trakt.tv/oauth/token', headers=headers, json=data)
while response.status_code == 429:
time.sleep(1)
response = requests.post('https://api.trakt.tv/oauth/token', headers=headers, json=data)
response = errorHandling.make_trakt_request('https://api.trakt.tv/oauth/token', payload=data)

# Parse the JSON response from the API
json_data = response.json()
Expand Down
78 changes: 77 additions & 1 deletion IMDBTraktSyncer/errorHandling.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import traceback
import requests
try:
from IMDBTraktSyncer import verifyCredentials
except:
import verifyCredentials

def report_error(error_message):
github_issue_url = "https://github.com/RileyXX/IMDB-Trakt-Syncer/issues/new?template=bug_report.yml"
Expand All @@ -11,4 +16,75 @@ def report_error(error_message):
print(traceback_info)
print("-" * 50)
print(f"Submit the error here: {github_issue_url}")
print("-" * 50)
print("-" * 50)

def make_trakt_request(url, headers=None, params=None, payload=None, max_retries=3):
if headers is None:
headers = {
'Content-Type': 'application/json',
'trakt-api-version': '2',
'trakt-api-key': verifyCredentials.trakt_client_id,
'Authorization': f'Bearer {verifyCredentials.trakt_access_token}'
}

retry_delay = 5 # seconds between retries
retry_attempts = 0

while retry_attempts < max_retries:
response = None
try:
if payload is None:
if params:
response = requests.get(url, headers=headers, params=params)
else:
response = requests.get(url, headers=headers)
else:
response = requests.post(url, headers=headers, json=payload)

if response.status_code in [200, 201, 204]:
return response # Request succeeded, return response
elif response.status_code in [429, 500, 502, 503, 504, 520, 521, 522]:
# Server overloaded or rate limit exceeded, retry after delay
retry_attempts += 1
time.sleep(retry_delay)
retry_delay *= 2 # Exponential backoff for retries
else:
# Handle other status codes as needed
error_message = get_trakt_message(response.status_code)
print(f"Request failed with status code {response.status_code}: {error_message}")
return None

except requests.exceptions.RequestException as e:
print(f"Request failed with exception: {e}")
return None

print("Max retry attempts reached with Trakt API, request failed.")
return None

def get_trakt_message(status_code):
error_messages = {
200: "Success",
201: "Success - new resource created (POST)",
204: "Success - no content to return (DELETE)",
400: "Bad Request - request couldn't be parsed",
401: "Unauthorized - OAuth must be provided",
403: "Forbidden - invalid API key or unapproved app",
404: "Not Found - method exists, but no record found",
405: "Method Not Found - method doesn't exist",
409: "Conflict - resource already created",
412: "Precondition Failed - use application/json content type",
420: "Account Limit Exceeded - list count, item count, etc",
422: "Unprocessable Entity - validation errors",
423: "Locked User Account - have the user contact support",
426: "VIP Only - user must upgrade to VIP",
429: "Rate Limit Exceeded",
500: "Server Error - please open a support ticket",
502: "Service Unavailable - server overloaded (try again in 30s)",
503: "Service Unavailable - server overloaded (try again in 30s)",
504: "Service Unavailable - server overloaded (try again in 30s)",
520: "Service Unavailable - Cloudflare error",
521: "Service Unavailable - Cloudflare error",
522: "Service Unavailable - Cloudflare error"
}

return error_messages.get(status_code, "Unknown error")
15 changes: 4 additions & 11 deletions IMDBTraktSyncer/imdbData.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@
from chromedriver_py import binary_path
try:
from IMDBTraktSyncer import verifyCredentials
from IMDBTraktSyncer import errorHandling
except:
import verifyCredentials
import errorHandling

def getImdbData(imdb_username, imdb_password, driver, directory, wait):
# Process IMDB Ratings and Reviews
Expand Down Expand Up @@ -68,17 +70,8 @@ def getImdbData(imdb_username, imdb_password, driver, directory, wait):

def get_media_type(imdb_id):
url = f"https://api.trakt.tv/search/imdb/{imdb_id}"
headers = {
"Content-Type": "application/json",
"trakt-api-version": "2",
"trakt-api-key": verifyCredentials.trakt_client_id
}

response = requests.get(url, headers=headers)
while response.status_code == 429:
time.sleep(1)
response = requests.get(url, headers=headers)
if response.status_code == 200:
response = errorHandling.make_trakt_request(url)
if response:
results = response.json()
if results:
media_type = results[0]['type']
Expand Down
25 changes: 9 additions & 16 deletions IMDBTraktSyncer/traktData.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,21 @@
import json
import requests
import time
try:
from IMDBTraktSyncer import errorHandling
except:
import errorHandling

def getTraktData(trakt_client_id, trakt_access_token):
def getTraktData():
# Process Trakt Ratings and Comments
print('Processing Trakt Ratings and Comments')

headers = {
'Content-Type': 'application/json',
'trakt-api-version': '2',
'trakt-api-key': trakt_client_id,
'Authorization': f'Bearer {trakt_access_token}'
}

time.sleep(1) # avoid trakt rate limit
response = requests.get('https://api.trakt.tv/users/me', headers=headers)
response = errorHandling.make_trakt_request('https://api.trakt.tv/users/me')
json_data = json.loads(response.text)
username = json_data['username']

# Get Trakt Ratings
time.sleep(1) # avoid trakt rate limit
response = requests.get(f'https://api.trakt.tv/users/{username}/ratings', headers=headers)
response = errorHandling.make_trakt_request(f'https://api.trakt.tv/users/{username}/ratings')
json_data = json.loads(response.text)

movie_ratings = []
Expand All @@ -47,15 +42,13 @@ def getTraktData(trakt_client_id, trakt_access_token):
trakt_ratings = movie_ratings + show_ratings + episode_ratings

# Get Trakt Comments
time.sleep(1) # avoid trakt rate limit
response = requests.get(f'https://api.trakt.tv/users/{username}/comments', headers=headers)
response = errorHandling.make_trakt_request(f'https://api.trakt.tv/users/{username}/comments')
json_data = json.loads(response.text)
total_pages = response.headers.get('X-Pagination-Page-Count')
trakt_comments = []

for page in range(1, int(total_pages) + 1):
time.sleep(1) # avoid trakt rate limit
response = requests.get(f'https://api.trakt.tv/users/{username}/comments', headers=headers, params={'page': page})
response = errorHandling.make_trakt_request(f'https://api.trakt.tv/users/{username}/comments', params={'page': page})
json_data = json.loads(response.text)

for comment in json_data:
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
with codecs.open(os.path.join(here, "README.md"), encoding="utf-8") as fh:
long_description = "\n" + fh.read()

VERSION = '1.2.0'
VERSION = '1.2.1'
DESCRIPTION = 'This python script will sync user ratings for Movies and TV Shows both ways between Trakt and IMDB.'

# Setting up
Expand Down

0 comments on commit 3821988

Please sign in to comment.