Added Requests

This commit is contained in:
angelblue05 2015-04-21 16:34:56 -05:00
parent ebe03057b0
commit 079fd4e8d9

View file

@ -1,341 +1,225 @@
import xbmc import xbmc
import xbmcgui import xbmcgui
import xbmcaddon import xbmcaddon
import urllib
import urllib2 import requests
import httplib import json
import hashlib import logging
import StringIO
import gzip import Utils as utils
import sys
import inspect
import json as json
from random import randrange
from uuid import uuid4 as uuid4
from ClientInformation import ClientInformation from ClientInformation import ClientInformation
import encodings
import time # Disable requests logging
import traceback logging.getLogger("requests").setLevel(logging.WARNING)
class DownloadUtils(): class DownloadUtils():
WINDOW = xbmcgui.Window(10000)
logLevel = 0
addonSettings = None
getString = None
LogCalls = False
TrackLog = ""
TotalUrlCalls = 0
def __init__(self, *args):
addonId = ClientInformation().getAddonId()
self.addonSettings = xbmcaddon.Addon(id=addonId)
self.addon = xbmcaddon.Addon(id=addonId)
self.getString = self.addonSettings.getLocalizedString
level = self.addonSettings.getSetting('logLevel')
self.logLevel = 0
if(level != None and level != ""):
self.logLevel = int(level)
if(self.logLevel == 2):
self.LogCalls = True
def logMsg(self, msg, level = 1):
if(self.logLevel >= level):
try:
xbmc.log("emby DownloadUtils -> " + str(msg))
except UnicodeEncodeError:
try:
xbmc.log("emby DownloadUtils -> " + str(msg.encode('utf-8')))
except: pass
def getServer(self, prefix=True):
WINDOW = self.WINDOW
username = WINDOW.getProperty("currUser")
if prefix:
server = WINDOW.getProperty("server%s" % username)
else:
server = WINDOW.getProperty("server_%s" % username)
return server
def getUserId(self, suppress=True):
WINDOW = xbmcgui.Window( 10000 )
self.addonSettings = xbmcaddon.Addon(id='plugin.video.emby')
port = self.addonSettings.getSetting('port')
host = self.addonSettings.getSetting('ipaddress')
userName = self.addonSettings.getSetting('username')
userid = WINDOW.getProperty("userid" + userName)
if(userid != None and userid != ""):
self.logMsg("DownloadUtils -> Returning saved (WINDOW) UserID : " + userid + "UserName: " + userName,2)
return userid
userid = self.addonSettings.getSetting("userid" + userName)
if(userid != None and userid != ""):
WINDOW.setProperty("userid" + userName, userid)
self.logMsg("DownloadUtils -> Returning saved (SETTING) UserID : " + userid + "UserName: " + userName,2)
return userid
self.logMsg("Looking for user name: " + userName) # Borg - multiple instances, shared state
_shared_state = {}
clientInfo = ClientInformation()
authOk = self.authenticate() addonName = clientInfo.getAddonName()
if(authOk == ""): addonId = clientInfo.getAddonId()
if(suppress == False): addon = xbmcaddon.Addon(id=addonId)
xbmcgui.Dialog().ok(self.getString(30044), self.getString(30044)) WINDOW = xbmcgui.Window(10000)
return ""
userid = WINDOW.getProperty("userid" + userName) # Requests session
if(userid == "" and suppress == False): s = None
xbmcgui.Dialog().ok(self.getString(30045),self.getString(30045)) timeout = 30
self.logMsg("userid : " + userid) def __init__(self):
self.postcapabilities()
self.__dict__ = self._shared_state
return userid self.className = self.__class__.__name__
def postcapabilities(self): def logMsg(self, msg, lvl=1):
self.logMsg("postcapabilities called")
utils.logMsg("%s %s" % (self.addonName, self.className), str(msg), int(lvl))
# Set Capabilities
server = self.getServer() def setUsername(self, username):
clientInfo = ClientInformation() # Reserved for UserClient only
machineId = clientInfo.getMachineId() self.username = username
self.logMsg("Set username: %s" % username, 1)
# get session id
url = "%s/mediabrowser/Sessions?DeviceId=%s&format=json" % (server, machineId) def setUserId(self, userId):
self.logMsg("Session URL : " + url); # Reserved for UserClient only
jsonData = self.downloadUrl(url) self.userId = userId
self.logMsg("Session JsonData : " + jsonData) self.logMsg("Set userId: %s" % userId, 2)
result = json.loads(jsonData)
self.logMsg("Session JsonData : " + str(result)) def setServer(self, server):
sessionId = result[0].get("Id") # Reserved for UserClient only
self.logMsg("Session Id : " + str(sessionId)) self.server = server
self.logMsg("Set server: %s" % server, 2)
# post capability data
#playableMediaTypes = "Audio,Video,Photo" def setToken(self, token):
# Reserved for UserClient only
self.token = token
self.logMsg("Set token: %s" % token, 2)
def postCapabilities(self, deviceId):
# Get sessionId
url = "{server}/mediabrowser/Sessions?DeviceId=%s&format=json" % deviceId
result = self.downloadUrl(url)
# sessionId result
self.logMsg("Session result: %s" % result, 1)
self.sessionId = result[0][u'Id']
# Settings for capabilities
playableMediaTypes = "Audio,Video" playableMediaTypes = "Audio,Video"
#supportedCommands = "Play,Playstate,DisplayContent,GoHome,SendString,GoToSettings,DisplayMessage,PlayNext"
supportedCommands = "Play,Playstate,SendString,DisplayMessage,PlayNext" supportedCommands = "Play,Playstate,SendString,DisplayMessage,PlayNext"
# Post settings to sessionId
url = "{server}/mediabrowser/Sessions/Capabilities?Id=%s&PlayableMediaTypes=%s&SupportedCommands=%s&SupportsMediaControl=True" % (self.sessionId, playableMediaTypes, supportedCommands)
data = {}
self.logMsg("Capabilities URL: %s" % url, 2)
self.logMsg("PostData: %s" % data, 2)
self.downloadUrl(url, postBody=data, type="POST")
self.logMsg("Posted capabilities to sessionId: %s" % self.sessionId, 1)
def startSession(self):
self.deviceId = self.clientInfo.getMachineId()
# User is identified from this point
# Attach authenticated header to the session
cert = None
header = self.getHeader()
if self.addon.getSetting('sslcert') != "None":
# If user uses HTTPS and has a custom client certificate
cert = self.addon.getSetting('sslcert')
url = "%s/mediabrowser/Sessions/Capabilities?Id=%s&PlayableMediaTypes=%s&SupportedCommands=%s&SupportsMediaControl=True" % (server, sessionId, playableMediaTypes, supportedCommands) # Start session
postData = {} self.s = requests.Session()
#postData["Id"] = sessionId; self.s.headers.update(header)
#postData["PlayableMediaTypes"] = "Video"; self.s.cert = cert
#postData["SupportedCommands"] = "MoveUp"; # Retry connections to the server
stringdata = json.dumps(postData) self.s.mount("http://", requests.adapters.HTTPAdapter(max_retries=1))
self.logMsg("Capabilities URL : " + url); self.s.mount("https://", requests.adapters.HTTPAdapter(max_retries=1))
self.logMsg("Capabilities Data : " + stringdata)
self.logMsg("Requests session started on: %s" % self.server)
self.downloadUrl(url, postBody=stringdata, type="POST") self.postCapabilities(self.deviceId)
def imageUrl(self, id, type, index, width, height): def imageUrl(self, id, type, index, width, height):
# To move to API.py
server = self.getServer() return "%s/mediabrowser/Items/%s/Images/%s?MaxWidth=%s&MaxHeight=%s&Index=%s" % (self.server, id, type, width, height, index)
return "%s/mediabrowser/Items/%s/Images/%s?MaxWidth=%s&MaxHeight=%s&Index=%s" % (server, id, type, width, height, index) def getHeader(self, authenticate=True):
def getAuthHeader(self, authenticate=True): clientInfo = self.clientInfo
clientInfo = ClientInformation()
txt_mac = clientInfo.getMachineId() deviceName = clientInfo.getDeviceName()
deviceId = clientInfo.getMachineId()
version = clientInfo.getVersion() version = clientInfo.getVersion()
deviceName = self.addonSettings.getSetting('deviceName')
deviceName = deviceName.replace("\"", "_")
username = self.WINDOW.getProperty("currUser")
if(authenticate == False): if not authenticate:
authString = "MediaBrowser Client=\"Kodi\",Device=\"" + deviceName + "\",DeviceId=\"" + txt_mac + "\",Version=\"" + version + "\"" # If user is not authenticated
headers = {"Accept-encoding": "gzip", "Accept-Charset" : "UTF-8,*", "Authorization" : authString} auth = 'MediaBrowser Client="Kodi", Device="%s", DeviceId="%s", Version="%s"' % (deviceName, deviceId, version)
return headers header = {"Accept-encoding": "gzip", "Accept-Charset": "UTF-8,*", "Authorization": auth}
self.logMsg("Header: %s" % header, 2)
return header
else: else:
userid = self.getUserId() userId = self.userId
authString = "MediaBrowser UserId=\"" + userid + "\",Client=\"Kodi\",Device=\"" + deviceName + "\",DeviceId=\"" + txt_mac + "\",Version=\"" + version + "\"" token = self.token
headers = {"Accept-encoding": "gzip", "Accept-Charset" : "UTF-8,*", "Authorization" : authString} # Attached to the requests session
auth = 'MediaBrowser UserId="%s", Client="Kodi", Device="%s", DeviceId="%s", Version="%s"' % (userId, deviceName, deviceId, version)
authToken = self.WINDOW.getProperty("accessToken%s" % username) header = {"Accept-encoding": "gzip", "Accept-Charset": "UTF-8,*", "Authorization": auth, "X-MediaBrowser-Token": token}
if(authToken != ""):
headers["X-MediaBrowser-Token"] = authToken
self.logMsg("Authentication Header : " + str(headers),2) self.logMsg("Header: %s" % header, 2)
return headers return header
def downloadUrl(self, url, suppress=False, postBody=None, type="GET", popup=0, authenticate=True ):
self.logMsg("== ENTER: getURL ==",2)
if(authenticate == True and suppress == True): def downloadUrl(self, url, postBody=None, type="GET", authenticate=True):
token = self.authenticate(retreive=False)
if(token == ""):
self.logMsg("No auth info set and suppress is true so returning no data!")
return ""
self.TotalUrlCalls = self.TotalUrlCalls + 1 self.logMsg("=== ENTER downloadUrl ===", 2)
if(self.LogCalls):
stackString = "" WINDOW = self.WINDOW
for f in inspect.stack(): timeout = self.timeout
stackString = stackString + "\r - " + str(f) default_link = ""
self.TrackLog = self.TrackLog + "HTTP_API_CALL : " + url + stackString + "\r"
# If user is authenticated
if (authenticate):
# Get requests session
s = self.s
# Replace for the real values and append api_key
url = url.replace("{server}", self.server, 1)
url = url.replace("{UserId}", self.userId, 1)
url = "%s&api_key=%s" % (url, self.token)
link = "" self.logMsg("URL: %s" % url, 1)
https = None # Prepare request
if type == "GET":
r = s.get(url, params=postBody, timeout=timeout)
elif type == "POST":
r = s.post(url, params=postBody, timeout=timeout)
elif type == "DELETE":
r = s.delete(url, params=postBody, timeout=timeout)
# If user is not authenticated
elif not authenticate:
self.logMsg("URL: %s" % url, 1)
header = self.getHeader(authenticate=False)
# Prepare request
if type == "GET":
r = requests.get(url, params=postBody, headers=header, timeout=timeout, verify=False)
elif type == "POST":
r = requests.post(url, params=postBody, headers=header, timeout=timeout)
# Process the response
try: try:
if url[0:5] == "https": r.raise_for_status()
serversplit = 2
urlsplit = 3
elif url[0:4] == "http":
serversplit = 2
urlsplit = 3
else:
serversplit = 0
urlsplit = 1
https = self.addonSettings.getSetting('https') if r.status_code == 204:
# No response in body
server = url.split('/')[serversplit] self.logMsg("====== 204 Success ======", 1)
urlPath = "/"+"/".join(url.split('/')[urlsplit:]) return default_link
# Response code 200
self.logMsg("DOWNLOAD_URL = " + url,2) elif r.status_code == requests.codes.ok:
self.logMsg("server = " + str(server),2)
self.logMsg("urlPath = " + str(urlPath),2)
if(server[0:1] == ":" or server[-1:] == ":"):
self.logMsg("No server host or port set in url")
return ""
head = self.getAuthHeader(authenticate)
self.logMsg("HEADERS : " + str(head), level=2)
if (https == 'false'):
#xbmc.log("Https disabled.")
conn = httplib.HTTPConnection(server, timeout=30)
elif (https == 'true'):
#xbmc.log("Https enabled.")
conn = httplib.HTTPSConnection(server, timeout=30)
# make the connection and send the request
if(postBody != None):
head["Content-Type"] = "application/x-www-form-urlencoded"
head["Content-Length"] = str(len(postBody))
self.logMsg("POST DATA : " + postBody,2)
conn.request(method=type, url=urlPath, body=postBody, headers=head)
else:
conn.request(method=type, url=urlPath, headers=head)
# get the response
tries = 0
while tries <= 4:
try:
data = conn.getresponse()
break
except:
# TODO: we need to work out which errors we can just quit trying immediately
if(xbmc.abortRequested == True):
return ""
xbmc.sleep(100)
if(xbmc.abortRequested == True):
return ""
tries += 1
if tries == 5:
data = conn.getresponse()
self.logMsg("GET URL HEADERS : " + str(data.getheaders()), level=2)
# process the response
contentType = "none"
if int(data.status) == 200:
retData = data.read()
contentType = data.getheader('content-encoding')
self.logMsg("Data Len Before : " + str(len(retData)), level=2)
if(contentType == "gzip"):
retData = StringIO.StringIO(retData)
gzipper = gzip.GzipFile(fileobj=retData)
link = gzipper.read()
else:
link = retData
self.logMsg("Data Len After : " + str(len(link)), level=2)
self.logMsg("====== 200 returned =======", level=2)
self.logMsg("Content-Type : " + str(contentType), level=2)
self.logMsg(link, level=2)
self.logMsg("====== 200 finished ======", level=2)
elif ( int(data.status) == 301 ) or ( int(data.status) == 302 ):
try: try:
conn.close() # UTF-8 - JSON object
except: r = r.json()
pass self.logMsg("====== 200 Success ======", 1)
return data.getheader('Location') return r
except:
self.logMsg("Unable to convert the response for: %s" % url, 1)
elif int(data.status) == 401: return default_link
WINDOW = xbmcgui.Window(10000)
# TO REVIEW EXCEPTIONS
except requests.exceptions.ConnectionError as e:
self.logMsg("Server unreachable at: %s" % url, 0)
self.logMsg(e, 1)
except requests.exceptions.ConnectTimeout as e:
self.logMsg("Server timeout at: %s" % url, 0)
self.logMsg(e, 1)
except requests.exceptions.HTTPError as e:
if r.status_code == 401:
# Unauthorized
status = WINDOW.getProperty("Server_status") status = WINDOW.getProperty("Server_status")
# Prevent multiple re-auth
if (status == "401") or (status == "Auth"): if (status == "401") or (status == "Auth"):
pass pass
else: else:
# Tell UserClient token has been revoked. # Tell UserClient token has been revoked.
WINDOW.setProperty("Server_status", "401") WINDOW.setProperty("Server_status", "401")
error = "HTTP response error: " + str(data.status) + " " + str(data.reason) self.logMsg("HTTP Error: %s" % e, 0)
xbmc.log(error)
#xbmcgui.Dialog().ok(self.getString(30135),"Reason: %s" % data.reason) #self.getString(30044), elif (r.status_code == 301) or (r.status_code == 302):
# Redirects
try: pass
conn.close() elif r.status_code == 400:
except: # Bad requests
pass
return ""
elif int(data.status) >= 400:
error = "HTTP response error: " + str(data.status) + " " + str(data.reason)
xbmc.log(error)
stack = self.FormatException()
self.logMsg(stack)
if suppress is False:
if popup == 0:
xbmc.executebuiltin("XBMC.Notification(URL error: "+ str(data.reason) +",)")
else:
xbmcgui.Dialog().ok(self.getString(30135),server)
try:
conn.close()
except:
pass
return ""
else:
link = ""
except Exception, msg:
error = "Unable to connect to " + str(server) + " : " + str(msg)
xbmc.log(error)
stack = self.FormatException()
self.logMsg(stack)
if suppress is False:
if popup == 0:
xbmc.executebuiltin("XBMC.Notification(: Connection Error: Error connecting to server,)")
else:
xbmcgui.Dialog().ok(self.getString(30204), str(msg))
pass
else:
try:
conn.close()
except:
pass pass
return link except requests.exceptions.RequestException as e:
self.logMsg("Unknown error connecting to: %s" % url, 0)
def FormatException(self): self.logMsg(e, 1)
exception_list = traceback.format_stack()
exception_list = exception_list[:-2]
exception_list.extend(traceback.format_tb(sys.exc_info()[2]))
exception_list.extend(traceback.format_exception_only(sys.exc_info()[0], sys.exc_info()[1]))
exception_str = "Traceback (most recent call last):\n" return default_link
exception_str += "".join(exception_list)
# Removing the last \n
exception_str = exception_str[:-1]
return exception_str
def __del__(self):
return
# xbmc.log("\rURL_REQUEST_REPORT : Total Calls : " + str(self.TotalUrlCalls) + "\r" + self.TrackLog)