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 xbmcgui
import xbmcaddon
import urllib
import urllib2
import httplib
import hashlib
import StringIO
import gzip
import sys
import inspect
import json as json
from random import randrange
from uuid import uuid4 as uuid4
import requests
import json
import logging
import Utils as utils
from ClientInformation import ClientInformation
import encodings
import time
import traceback
# Disable requests logging
logging.getLogger("requests").setLevel(logging.WARNING)
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)
authOk = self.authenticate()
if(authOk == ""):
if(suppress == False):
xbmcgui.Dialog().ok(self.getString(30044), self.getString(30044))
return ""
userid = WINDOW.getProperty("userid" + userName)
if(userid == "" and suppress == False):
xbmcgui.Dialog().ok(self.getString(30045),self.getString(30045))
self.logMsg("userid : " + userid)
self.postcapabilities()
return userid
def postcapabilities(self):
self.logMsg("postcapabilities called")
# Set Capabilities
server = self.getServer()
# Borg - multiple instances, shared state
_shared_state = {}
clientInfo = ClientInformation()
machineId = clientInfo.getMachineId()
# get session id
url = "%s/mediabrowser/Sessions?DeviceId=%s&format=json" % (server, machineId)
self.logMsg("Session URL : " + url);
jsonData = self.downloadUrl(url)
self.logMsg("Session JsonData : " + jsonData)
result = json.loads(jsonData)
self.logMsg("Session JsonData : " + str(result))
sessionId = result[0].get("Id")
self.logMsg("Session Id : " + str(sessionId))
addonName = clientInfo.getAddonName()
addonId = clientInfo.getAddonId()
addon = xbmcaddon.Addon(id=addonId)
WINDOW = xbmcgui.Window(10000)
# post capability data
#playableMediaTypes = "Audio,Video,Photo"
# Requests session
s = None
timeout = 30
def __init__(self):
self.__dict__ = self._shared_state
self.className = self.__class__.__name__
def logMsg(self, msg, lvl=1):
utils.logMsg("%s %s" % (self.addonName, self.className), str(msg), int(lvl))
def setUsername(self, username):
# Reserved for UserClient only
self.username = username
self.logMsg("Set username: %s" % username, 1)
def setUserId(self, userId):
# Reserved for UserClient only
self.userId = userId
self.logMsg("Set userId: %s" % userId, 2)
def setServer(self, server):
# Reserved for UserClient only
self.server = server
self.logMsg("Set server: %s" % server, 2)
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"
#supportedCommands = "Play,Playstate,DisplayContent,GoHome,SendString,GoToSettings,DisplayMessage,PlayNext"
supportedCommands = "Play,Playstate,SendString,DisplayMessage,PlayNext"
url = "%s/mediabrowser/Sessions/Capabilities?Id=%s&PlayableMediaTypes=%s&SupportedCommands=%s&SupportsMediaControl=True" % (server, sessionId, playableMediaTypes, supportedCommands)
postData = {}
#postData["Id"] = sessionId;
#postData["PlayableMediaTypes"] = "Video";
#postData["SupportedCommands"] = "MoveUp";
stringdata = json.dumps(postData)
self.logMsg("Capabilities URL : " + url);
self.logMsg("Capabilities Data : " + stringdata)
# 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=stringdata, type="POST")
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')
# Start session
self.s = requests.Session()
self.s.headers.update(header)
self.s.cert = cert
# Retry connections to the server
self.s.mount("http://", requests.adapters.HTTPAdapter(max_retries=1))
self.s.mount("https://", requests.adapters.HTTPAdapter(max_retries=1))
self.logMsg("Requests session started on: %s" % self.server)
self.postCapabilities(self.deviceId)
def imageUrl(self, id, type, index, width, height):
# To move to API.py
return "%s/mediabrowser/Items/%s/Images/%s?MaxWidth=%s&MaxHeight=%s&Index=%s" % (self.server, id, type, width, height, index)
server = self.getServer()
def getHeader(self, authenticate=True):
return "%s/mediabrowser/Items/%s/Images/%s?MaxWidth=%s&MaxHeight=%s&Index=%s" % (server, id, type, width, height, index)
clientInfo = self.clientInfo
def getAuthHeader(self, authenticate=True):
clientInfo = ClientInformation()
txt_mac = clientInfo.getMachineId()
deviceName = clientInfo.getDeviceName()
deviceId = clientInfo.getMachineId()
version = clientInfo.getVersion()
deviceName = self.addonSettings.getSetting('deviceName')
deviceName = deviceName.replace("\"", "_")
username = self.WINDOW.getProperty("currUser")
if not authenticate:
# If user is not authenticated
auth = 'MediaBrowser Client="Kodi", Device="%s", DeviceId="%s", Version="%s"' % (deviceName, deviceId, version)
header = {"Accept-encoding": "gzip", "Accept-Charset": "UTF-8,*", "Authorization": auth}
self.logMsg("Header: %s" % header, 2)
return header
if(authenticate == False):
authString = "MediaBrowser Client=\"Kodi\",Device=\"" + deviceName + "\",DeviceId=\"" + txt_mac + "\",Version=\"" + version + "\""
headers = {"Accept-encoding": "gzip", "Accept-Charset" : "UTF-8,*", "Authorization" : authString}
return headers
else:
userid = self.getUserId()
authString = "MediaBrowser UserId=\"" + userid + "\",Client=\"Kodi\",Device=\"" + deviceName + "\",DeviceId=\"" + txt_mac + "\",Version=\"" + version + "\""
headers = {"Accept-encoding": "gzip", "Accept-Charset" : "UTF-8,*", "Authorization" : authString}
userId = self.userId
token = self.token
# Attached to the requests session
auth = 'MediaBrowser UserId="%s", Client="Kodi", Device="%s", DeviceId="%s", Version="%s"' % (userId, deviceName, deviceId, version)
header = {"Accept-encoding": "gzip", "Accept-Charset": "UTF-8,*", "Authorization": auth, "X-MediaBrowser-Token": token}
authToken = self.WINDOW.getProperty("accessToken%s" % username)
if(authToken != ""):
headers["X-MediaBrowser-Token"] = authToken
self.logMsg("Header: %s" % header, 2)
return header
self.logMsg("Authentication Header : " + str(headers),2)
return headers
def downloadUrl(self, url, postBody=None, type="GET", authenticate=True):
def downloadUrl(self, url, suppress=False, postBody=None, type="GET", popup=0, authenticate=True ):
self.logMsg("== ENTER: getURL ==",2)
self.logMsg("=== ENTER downloadUrl ===", 2)
if(authenticate == True and suppress == True):
token = self.authenticate(retreive=False)
if(token == ""):
self.logMsg("No auth info set and suppress is true so returning no data!")
return ""
WINDOW = self.WINDOW
timeout = self.timeout
default_link = ""
self.TotalUrlCalls = self.TotalUrlCalls + 1
if(self.LogCalls):
stackString = ""
for f in inspect.stack():
stackString = stackString + "\r - " + str(f)
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 = ""
https = None
self.logMsg("URL: %s" % url, 1)
# 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:
if url[0:5] == "https":
serversplit = 2
urlsplit = 3
elif url[0:4] == "http":
serversplit = 2
urlsplit = 3
else:
serversplit = 0
urlsplit = 1
r.raise_for_status()
https = self.addonSettings.getSetting('https')
server = url.split('/')[serversplit]
urlPath = "/"+"/".join(url.split('/')[urlsplit:])
self.logMsg("DOWNLOAD_URL = " + url,2)
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:
if r.status_code == 204:
# No response in body
self.logMsg("====== 204 Success ======", 1)
return default_link
# Response code 200
elif r.status_code == requests.codes.ok:
try:
data = conn.getresponse()
break
# UTF-8 - JSON object
r = r.json()
self.logMsg("====== 200 Success ======", 1)
return r
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("Unable to convert the response for: %s" % url, 1)
self.logMsg("GET URL HEADERS : " + str(data.getheaders()), level=2)
return default_link
# 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)
# TO REVIEW EXCEPTIONS
except requests.exceptions.ConnectionError as e:
self.logMsg("Server unreachable at: %s" % url, 0)
self.logMsg(e, 1)
elif ( int(data.status) == 301 ) or ( int(data.status) == 302 ):
try:
conn.close()
except:
pass
return data.getheader('Location')
except requests.exceptions.ConnectTimeout as e:
self.logMsg("Server timeout at: %s" % url, 0)
self.logMsg(e, 1)
elif int(data.status) == 401:
WINDOW = xbmcgui.Window(10000)
except requests.exceptions.HTTPError as e:
if r.status_code == 401:
# Unauthorized
status = WINDOW.getProperty("Server_status")
# Prevent multiple re-auth
if (status == "401") or (status == "Auth"):
pass
else:
# Tell UserClient token has been revoked.
WINDOW.setProperty("Server_status", "401")
error = "HTTP response error: " + str(data.status) + " " + str(data.reason)
xbmc.log(error)
#xbmcgui.Dialog().ok(self.getString(30135),"Reason: %s" % data.reason) #self.getString(30044),
self.logMsg("HTTP Error: %s" % e, 0)
try:
conn.close()
except:
elif (r.status_code == 301) or (r.status_code == 302):
# Redirects
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:
elif r.status_code == 400:
# Bad requests
pass
return link
except requests.exceptions.RequestException as e:
self.logMsg("Unknown error connecting to: %s" % url, 0)
self.logMsg(e, 1)
def FormatException(self):
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"
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)
return default_link