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.
157 lines
5.3 KiB
157 lines
5.3 KiB
#!/usr/bin/env python
|
|
# -*- coding: utf-8 -*-
|
|
#-----------------------
|
|
# Name: tmdb_request.py
|
|
# Python Library
|
|
# Author: Raymond Wagner
|
|
# Purpose: Wrapped urllib2.Request class pre-configured for accessing the
|
|
# TMDb v3 API
|
|
#-----------------------
|
|
|
|
from tmdb_exceptions import *
|
|
from locales import get_locale
|
|
from cache import Cache
|
|
|
|
from urllib import urlencode
|
|
import urllib2
|
|
import json
|
|
|
|
DEBUG = False
|
|
cache = Cache(filename='pytmdb3.cache')
|
|
|
|
#DEBUG = True
|
|
#cache = Cache(engine='null')
|
|
|
|
def set_key(key):
|
|
"""
|
|
Specify the API key to use retrieving data from themoviedb.org. This
|
|
key must be set before any calls will function.
|
|
"""
|
|
if len(key) != 32:
|
|
raise TMDBKeyInvalid("Specified API key must be 128-bit hex")
|
|
try:
|
|
int(key, 16)
|
|
except:
|
|
raise TMDBKeyInvalid("Specified API key must be 128-bit hex")
|
|
Request._api_key = key
|
|
|
|
def set_cache(engine=None, *args, **kwargs):
|
|
"""Specify caching engine and properties."""
|
|
cache.configure(engine, *args, **kwargs)
|
|
|
|
class Request( urllib2.Request ):
|
|
_api_key = None
|
|
_base_url = "http://api.themoviedb.org/3/"
|
|
|
|
@property
|
|
def api_key(self):
|
|
if self._api_key is None:
|
|
raise TMDBKeyMissing("API key must be specified before "+\
|
|
"requests can be made")
|
|
return self._api_key
|
|
|
|
def __init__(self, url, **kwargs):
|
|
"""Return a request object, using specified API path and arguments."""
|
|
kwargs['api_key'] = self.api_key
|
|
self._url = url.lstrip('/')
|
|
self._kwargs = dict([(kwa,kwv) for kwa,kwv in kwargs.items()
|
|
if kwv is not None])
|
|
|
|
locale = get_locale()
|
|
kwargs = {}
|
|
for k,v in self._kwargs.items():
|
|
kwargs[k] = locale.encode(v)
|
|
url = '{0}{1}?{2}'.format(self._base_url, self._url, urlencode(kwargs))
|
|
|
|
urllib2.Request.__init__(self, url)
|
|
self.add_header('Accept', 'application/json')
|
|
self.lifetime = 3600 # 1hr
|
|
|
|
def new(self, **kwargs):
|
|
"""Create a new instance of the request, with tweaked arguments."""
|
|
args = dict(self._kwargs)
|
|
for k,v in kwargs.items():
|
|
if v is None:
|
|
if k in args:
|
|
del args[k]
|
|
else:
|
|
args[k] = v
|
|
obj = self.__class__(self._url, **args)
|
|
obj.lifetime = self.lifetime
|
|
return obj
|
|
|
|
def add_data(self, data):
|
|
"""Provide data to be sent with POST."""
|
|
urllib2.Request.add_data(self, urlencode(data))
|
|
|
|
def open(self):
|
|
"""Open a file object to the specified URL."""
|
|
try:
|
|
if DEBUG:
|
|
print 'loading '+self.get_full_url()
|
|
if self.has_data():
|
|
print ' '+self.get_data()
|
|
return urllib2.urlopen(self)
|
|
except urllib2.HTTPError, e:
|
|
raise TMDBHTTPError(e)
|
|
|
|
def read(self):
|
|
"""Return result from specified URL as a string."""
|
|
return self.open().read()
|
|
|
|
@cache.cached(urllib2.Request.get_full_url)
|
|
def readJSON(self):
|
|
"""Parse result from specified URL as JSON data."""
|
|
url = self.get_full_url()
|
|
try:
|
|
# catch HTTP error from open()
|
|
data = json.load(self.open())
|
|
except TMDBHTTPError, e:
|
|
try:
|
|
# try to load whatever was returned
|
|
data = json.loads(e.response)
|
|
except:
|
|
# cannot parse json, just raise existing error
|
|
raise e
|
|
else:
|
|
# response parsed, try to raise error from TMDB
|
|
handle_status(data, url)
|
|
# no error from TMDB, just raise existing error
|
|
raise e
|
|
handle_status(data, url)
|
|
#if DEBUG:
|
|
# import pprint
|
|
# pprint.PrettyPrinter().pprint(data)
|
|
return data
|
|
|
|
status_handlers = {
|
|
1: None,
|
|
2: TMDBRequestInvalid('Invalid service - This service does not exist.'),
|
|
3: TMDBRequestError('Authentication Failed - You do not have '+\
|
|
'permissions to access this service.'),
|
|
4: TMDBRequestInvalid("Invalid format - This service doesn't exist "+\
|
|
'in that format.'),
|
|
5: TMDBRequestInvalid('Invalid parameters - Your request parameters '+\
|
|
'are incorrect.'),
|
|
6: TMDBRequestInvalid('Invalid id - The pre-requisite id is invalid '+\
|
|
'or not found.'),
|
|
7: TMDBKeyInvalid('Invalid API key - You must be granted a valid key.'),
|
|
8: TMDBRequestError('Duplicate entry - The data you tried to submit '+\
|
|
'already exists.'),
|
|
9: TMDBOffline('This service is tempirarily offline. Try again later.'),
|
|
10: TMDBKeyRevoked('Suspended API key - Access to your account has been '+\
|
|
'suspended, contact TMDB.'),
|
|
11: TMDBError('Internal error - Something went wrong. Contact TMDb.'),
|
|
12: None,
|
|
13: None,
|
|
14: TMDBRequestError('Authentication Failed.'),
|
|
15: TMDBError('Failed'),
|
|
16: TMDBError('Device Denied'),
|
|
17: TMDBError('Session Denied')}
|
|
|
|
def handle_status(data, query):
|
|
status = status_handlers[data.get('status_code', 1)]
|
|
if status is not None:
|
|
status.tmdberrno = data['status_code']
|
|
status.query = query
|
|
raise status
|
|
|