2016-03-13 06:56:02 +11:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
|
|
##################################################################################################
|
|
|
|
|
|
|
|
import json
|
|
|
|
import requests
|
|
|
|
import logging
|
|
|
|
|
|
|
|
import clientinfo
|
2016-07-25 13:39:40 +10:00
|
|
|
from utils import window
|
2016-03-13 06:56:02 +11:00
|
|
|
|
|
|
|
##################################################################################################
|
|
|
|
|
|
|
|
# Disable requests logging
|
|
|
|
from requests.packages.urllib3.exceptions import InsecureRequestWarning, InsecurePlatformWarning
|
|
|
|
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
|
|
|
|
requests.packages.urllib3.disable_warnings(InsecurePlatformWarning)
|
2016-07-25 13:39:40 +10:00
|
|
|
|
|
|
|
log = logging.getLogger("EMBY."+__name__)
|
2016-03-13 06:56:02 +11:00
|
|
|
|
|
|
|
##################################################################################################
|
|
|
|
|
|
|
|
|
|
|
|
class ConnectUtils():
|
2016-03-31 14:32:59 +11:00
|
|
|
|
2016-03-13 06:56:02 +11:00
|
|
|
# Borg - multiple instances, shared state
|
|
|
|
_shared_state = {}
|
|
|
|
clientInfo = clientinfo.ClientInfo()
|
|
|
|
|
|
|
|
# Requests session
|
|
|
|
c = None
|
|
|
|
timeout = 30
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
|
2016-06-18 13:03:28 +10:00
|
|
|
self.__dict__ = self._shared_state
|
2016-03-13 06:56:02 +11:00
|
|
|
|
|
|
|
|
|
|
|
def setUserId(self, userId):
|
|
|
|
# Reserved for userclient only
|
|
|
|
self.userId = userId
|
2016-07-25 13:39:40 +10:00
|
|
|
log.debug("Set connect userId: %s" % userId)
|
2016-03-13 06:56:02 +11:00
|
|
|
|
|
|
|
def setServer(self, server):
|
|
|
|
# Reserved for userclient only
|
|
|
|
self.server = server
|
2016-07-25 13:39:40 +10:00
|
|
|
log.debug("Set connect server: %s" % server)
|
2016-03-13 06:56:02 +11:00
|
|
|
|
|
|
|
def setToken(self, token):
|
|
|
|
# Reserved for userclient only
|
|
|
|
self.token = token
|
2016-07-25 13:39:40 +10:00
|
|
|
log.debug("Set connect token: %s" % token)
|
2016-03-13 06:56:02 +11:00
|
|
|
|
|
|
|
|
|
|
|
def startSession(self):
|
|
|
|
|
|
|
|
self.deviceId = self.clientInfo.getDeviceId()
|
|
|
|
|
|
|
|
# User is identified from this point
|
|
|
|
# Attach authenticated header to the session
|
|
|
|
verify = False
|
|
|
|
header = self.getHeader()
|
|
|
|
|
|
|
|
# If user enabled host certificate verification
|
|
|
|
try:
|
|
|
|
verify = self.sslverify
|
|
|
|
if self.sslclient is not None:
|
|
|
|
verify = self.sslclient
|
|
|
|
except:
|
2016-07-25 13:39:40 +10:00
|
|
|
log.info("Could not load SSL settings.")
|
2016-03-31 14:32:59 +11:00
|
|
|
|
2016-03-13 06:56:02 +11:00
|
|
|
# Start session
|
|
|
|
self.c = requests.Session()
|
|
|
|
self.c.headers = header
|
|
|
|
self.c.verify = verify
|
|
|
|
# Retry connections to the server
|
|
|
|
self.c.mount("http://", requests.adapters.HTTPAdapter(max_retries=1))
|
|
|
|
self.c.mount("https://", requests.adapters.HTTPAdapter(max_retries=1))
|
|
|
|
|
2016-07-25 13:39:40 +10:00
|
|
|
log.info("Requests session started on: %s" % self.server)
|
2016-03-13 06:56:02 +11:00
|
|
|
|
|
|
|
def stopSession(self):
|
|
|
|
try:
|
|
|
|
self.c.close()
|
2016-07-25 13:39:40 +10:00
|
|
|
except Exception:
|
|
|
|
log.warn("Requests session could not be terminated")
|
2016-03-13 06:56:02 +11:00
|
|
|
|
|
|
|
def getHeader(self, authenticate=True):
|
|
|
|
|
2016-03-31 14:32:59 +11:00
|
|
|
version = self.clientInfo.getVersion()
|
2016-03-13 06:56:02 +11:00
|
|
|
|
|
|
|
if not authenticate:
|
|
|
|
# If user is not authenticated
|
|
|
|
header = {
|
|
|
|
|
|
|
|
'X-Application': "Kodi/%s" % version,
|
|
|
|
'Content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
|
|
|
|
'Accept': "application/json"
|
2016-03-31 14:32:59 +11:00
|
|
|
}
|
2016-07-25 13:39:40 +10:00
|
|
|
log.info("Header: %s" % header)
|
2016-03-31 14:32:59 +11:00
|
|
|
|
2016-03-13 06:56:02 +11:00
|
|
|
else:
|
|
|
|
token = self.token
|
|
|
|
# Attached to the requests session
|
|
|
|
header = {
|
|
|
|
|
|
|
|
'Content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
|
|
|
|
'Accept': "application/json",
|
|
|
|
'X-Application': "Kodi/%s" % version,
|
|
|
|
'X-Connect-UserToken': token
|
2016-03-31 14:32:59 +11:00
|
|
|
}
|
2016-07-25 13:39:40 +10:00
|
|
|
log.info("Header: %s" % header)
|
2016-03-31 14:32:59 +11:00
|
|
|
|
2016-03-13 06:56:02 +11:00
|
|
|
return header
|
|
|
|
|
|
|
|
def doUrl(self, url, data=None, postBody=None, rtype="GET",
|
|
|
|
parameters=None, authenticate=True, timeout=None):
|
|
|
|
|
2016-07-25 13:39:40 +10:00
|
|
|
log.debug("=== ENTER connectUrl ===")
|
2016-06-18 13:03:28 +10:00
|
|
|
|
2016-03-13 06:56:02 +11:00
|
|
|
default_link = ""
|
2016-06-18 13:03:28 +10:00
|
|
|
|
2016-03-13 06:56:02 +11:00
|
|
|
if timeout is None:
|
|
|
|
timeout = self.timeout
|
|
|
|
|
|
|
|
# Get requests session
|
|
|
|
try:
|
|
|
|
# If connect user is authenticated
|
|
|
|
if authenticate:
|
2016-03-31 14:32:59 +11:00
|
|
|
try:
|
2016-03-13 06:56:02 +11:00
|
|
|
c = self.c
|
|
|
|
# Replace for the real values
|
|
|
|
url = url.replace("{server}", self.server)
|
|
|
|
url = url.replace("{UserId}", self.userId)
|
|
|
|
|
|
|
|
# Prepare request
|
|
|
|
if rtype == "GET":
|
|
|
|
r = c.get(url, json=postBody, params=parameters, timeout=timeout)
|
|
|
|
elif rtype == "POST":
|
|
|
|
r = c.post(url, data=data, timeout=timeout)
|
|
|
|
elif rtype == "DELETE":
|
|
|
|
r = c.delete(url, json=postBody, timeout=timeout)
|
|
|
|
|
|
|
|
except AttributeError:
|
|
|
|
# request session does not exists
|
|
|
|
self.server = "https://connect.emby.media/service"
|
|
|
|
self.userId = window('embyco_currUser')
|
|
|
|
self.token = window('embyco_accessToken%s' % self.userId)
|
|
|
|
|
|
|
|
header = self.getHeader()
|
|
|
|
verifyssl = False
|
|
|
|
|
|
|
|
# If user enables ssl verification
|
|
|
|
try:
|
|
|
|
verifyssl = self.sslverify
|
|
|
|
if self.sslclient is not None:
|
|
|
|
verifyssl = self.sslclient
|
|
|
|
except AttributeError:
|
|
|
|
pass
|
2016-03-31 14:32:59 +11:00
|
|
|
|
2016-03-13 06:56:02 +11:00
|
|
|
# Prepare request
|
|
|
|
if rtype == "GET":
|
|
|
|
r = requests.get(url,
|
|
|
|
json=postBody,
|
|
|
|
params=parameters,
|
|
|
|
headers=header,
|
|
|
|
timeout=timeout,
|
|
|
|
verify=verifyssl)
|
|
|
|
|
|
|
|
elif rtype == "POST":
|
|
|
|
r = requests.post(url,
|
|
|
|
data=data,
|
|
|
|
headers=header,
|
|
|
|
timeout=timeout,
|
|
|
|
verify=verifyssl)
|
|
|
|
# If user is not authenticated
|
|
|
|
else:
|
|
|
|
header = self.getHeader(authenticate=False)
|
|
|
|
verifyssl = False
|
|
|
|
|
|
|
|
# If user enables ssl verification
|
|
|
|
try:
|
|
|
|
verifyssl = self.sslverify
|
|
|
|
if self.sslclient is not None:
|
|
|
|
verifyssl = self.sslclient
|
|
|
|
except AttributeError:
|
|
|
|
pass
|
2016-03-31 14:32:59 +11:00
|
|
|
|
2016-03-13 06:56:02 +11:00
|
|
|
# Prepare request
|
|
|
|
if rtype == "GET":
|
|
|
|
r = requests.get(url,
|
|
|
|
json=postBody,
|
|
|
|
params=parameters,
|
|
|
|
headers=header,
|
|
|
|
timeout=timeout,
|
|
|
|
verify=verifyssl)
|
|
|
|
|
|
|
|
elif rtype == "POST":
|
|
|
|
r = requests.post(url,
|
|
|
|
data=data,
|
|
|
|
headers=header,
|
|
|
|
timeout=timeout,
|
|
|
|
verify=verifyssl)
|
|
|
|
|
|
|
|
##### THE RESPONSE #####
|
2016-07-25 13:39:40 +10:00
|
|
|
log.info(r.url)
|
|
|
|
log.info(r)
|
2016-03-13 06:56:02 +11:00
|
|
|
|
|
|
|
if r.status_code == 204:
|
|
|
|
# No body in the response
|
2016-07-25 13:39:40 +10:00
|
|
|
log.info("====== 204 Success ======")
|
2016-03-13 06:56:02 +11:00
|
|
|
|
|
|
|
elif r.status_code == requests.codes.ok:
|
2016-03-31 14:32:59 +11:00
|
|
|
|
|
|
|
try:
|
2016-03-13 06:56:02 +11:00
|
|
|
# UNICODE - JSON object
|
|
|
|
r = r.json()
|
2016-07-25 13:39:40 +10:00
|
|
|
log.info("====== 200 Success ======")
|
|
|
|
log.info("Response: %s" % r)
|
2016-03-13 06:56:02 +11:00
|
|
|
return r
|
|
|
|
|
|
|
|
except:
|
|
|
|
if r.headers.get('content-type') != "text/html":
|
2016-07-25 13:39:40 +10:00
|
|
|
log.info("Unable to convert the response for: %s" % url)
|
2016-03-13 06:56:02 +11:00
|
|
|
else:
|
|
|
|
r.raise_for_status()
|
2016-03-31 14:32:59 +11:00
|
|
|
|
2016-03-13 06:56:02 +11:00
|
|
|
##### EXCEPTIONS #####
|
|
|
|
|
|
|
|
except requests.exceptions.ConnectionError as e:
|
|
|
|
# Make the addon aware of status
|
|
|
|
pass
|
|
|
|
|
|
|
|
except requests.exceptions.ConnectTimeout as e:
|
2016-07-25 13:39:40 +10:00
|
|
|
log.warn("Server timeout at: %s" % url)
|
2016-03-13 06:56:02 +11:00
|
|
|
|
|
|
|
except requests.exceptions.HTTPError as e:
|
|
|
|
|
|
|
|
if r.status_code == 401:
|
|
|
|
# Unauthorized
|
|
|
|
pass
|
|
|
|
|
|
|
|
elif r.status_code in (301, 302):
|
|
|
|
# Redirects
|
|
|
|
pass
|
|
|
|
elif r.status_code == 400:
|
|
|
|
# Bad requests
|
|
|
|
pass
|
|
|
|
|
|
|
|
except requests.exceptions.SSLError as e:
|
2016-07-25 13:39:40 +10:00
|
|
|
log.warn("Invalid SSL certificate for: %s" % url)
|
2016-03-13 06:56:02 +11:00
|
|
|
|
|
|
|
except requests.exceptions.RequestException as e:
|
2016-07-25 13:39:40 +10:00
|
|
|
log.warn("Unknown error connecting to: %s" % url)
|
2016-03-13 06:56:02 +11:00
|
|
|
|
2016-06-18 13:03:28 +10:00
|
|
|
return default_link
|