jellyfin-kodi/resources/lib/userclient.py

324 lines
10 KiB
Python
Raw Normal View History

2016-03-31 18:40:47 +00:00
# -*- coding: utf-8 -*-
##################################################################################################
2016-09-27 02:50:58 +00:00
import json
import logging
2016-03-31 18:40:47 +00:00
import threading
import xbmc
import xbmcgui
import artwork
import connectmanager
2016-03-31 18:40:47 +00:00
import downloadutils
import read_embyserver as embyserver
from utils import window, settings, language as lang
##################################################################################################
log = logging.getLogger("EMBY."+__name__)
2016-03-31 18:40:47 +00:00
##################################################################################################
class UserClient(threading.Thread):
_shared_state = {} # Borg
2016-03-31 18:40:47 +00:00
_stop_thread = False
_user = None
_server = None
2016-03-31 18:40:47 +00:00
_auth = True
_has_access = True
2016-03-31 18:40:47 +00:00
def __init__(self):
self.__dict__ = self._shared_state
self.doutils = downloadutils.DownloadUtils()
self.download = self.doutils.downloadUrl
self.emby = embyserver.Read_EmbyServer()
2016-09-09 23:12:30 +00:00
self.connectmanager = connectmanager.ConnectManager()
2016-04-03 20:51:26 +00:00
2016-03-31 18:40:47 +00:00
threading.Thread.__init__(self)
@classmethod
def get_username(cls):
return settings('username') or settings('connectUsername') or None
2016-03-31 18:40:47 +00:00
def get_user(self, data=None):
2016-03-31 18:40:47 +00:00
if data is not None:
self._user = data
self._set_user_server()
2016-04-03 20:51:26 +00:00
return self._user
2016-03-31 18:40:47 +00:00
def get_server_details(self):
return self._server
2016-03-31 18:40:47 +00:00
@classmethod
def get_server(cls):
2016-03-31 18:40:47 +00:00
###$ Begin migration $###
if settings('server') == "":
http = "https" if settings('https') == "true" else "http"
host = settings('ipaddress')
port = settings('port')
2016-03-31 18:40:47 +00:00
if host and port:
settings('server', value="%s://%s:%s" % (http, host, port))
log.info("server address migration completed")
###$ End migration $###
2016-03-31 18:40:47 +00:00
return settings('server') or None
2016-03-31 18:40:47 +00:00
def verify_server(self):
2016-03-31 18:40:47 +00:00
url = "%s/emby/Users/Public?format=json" % self.get_server()
result = self.download(url, authenticate=False)
if result != "": # Specific verification, due to possibility of returning empty dict
return True
2016-03-31 18:40:47 +00:00
else:
# Server connection failed
return False
2016-03-31 18:40:47 +00:00
@classmethod
def get_ssl(cls):
"""
Returns boolean value or path to certificate
True: Verify ssl
False: Don't verify connection
"""
certificate = settings('sslcert')
if certificate != "None":
return certificate
2016-04-03 20:51:26 +00:00
return True if settings('sslverify') == "true" else False
2016-03-31 18:40:47 +00:00
def get_access(self):
2016-03-31 18:40:47 +00:00
if not self._has_access:
self._set_access()
2016-03-31 18:40:47 +00:00
return self._has_access
2016-03-31 18:40:47 +00:00
def _set_access(self):
2016-03-31 18:40:47 +00:00
try:
self.download("{server}/emby/Users?format=json")
except Warning as error:
if self._has_access and "restricted" in error:
self._has_access = False
2016-09-27 06:33:09 +00:00
log.info("access is restricted")
2016-03-31 18:40:47 +00:00
else:
if not self._has_access:
self._has_access = True
window('emby_serverStatus', clear=True)
2016-09-27 06:33:09 +00:00
log.info("access is granted")
xbmcgui.Dialog().notification(lang(29999), lang(33007))
2016-03-31 18:40:47 +00:00
@classmethod
def get_userid(cls):
2016-03-31 18:40:47 +00:00
###$ Begin migration $###
if settings('userId') == "":
settings('userId', value=settings('userId%s' % settings('username')))
log.info("userid migration completed")
###$ End migration $###
2016-03-31 18:40:47 +00:00
return settings('userId') or None
2016-03-31 18:40:47 +00:00
@classmethod
def get_token(cls):
2016-03-31 18:40:47 +00:00
###$ Begin migration $###
if settings('token') == "":
settings('token', value=settings('accessToken'))
log.info("token migration completed")
###$ End migration $###
2016-03-31 18:40:47 +00:00
return settings('token') or None
2016-03-31 18:55:25 +00:00
def _set_user_server(self):
2016-04-03 20:51:26 +00:00
2016-10-20 07:39:37 +00:00
user = self.download("{server}/emby/Users/{UserId}?format=json")
settings('username', value=user['Name'])
self._user = user
if "PrimaryImageTag" in self._user:
window('EmbyUserImage',
2016-09-10 11:15:58 +00:00
value=artwork.Artwork().get_user_artwork(self._user['Id'], 'Primary'))
2016-03-31 18:40:47 +00:00
2016-09-05 08:38:57 +00:00
self._server = self.download("{server}/emby/System/Configuration?format=json")
settings('markPlayed', value=str(self._server['MaxResumePct']))
def _authenticate(self):
if not self.get_server() or not self.get_username():
log.info('missing server or user information')
self._auth = False
2016-03-31 18:40:47 +00:00
elif self.get_token():
try:
self._load_user()
except Warning:
log.info("token is invalid")
2016-09-06 22:43:15 +00:00
self._reset_client()
2016-03-31 18:40:47 +00:00
else:
log.info("current user: %s", self.get_username())
log.info("current userid: %s", self.get_userid())
log.debug("current token: %s", self.get_token())
2016-03-31 18:40:47 +00:00
return
2016-04-03 20:51:26 +00:00
2016-03-31 18:40:47 +00:00
##### AUTHENTICATE USER #####
server = self.get_server()
username = self.get_username().decode('utf-8')
2016-03-31 18:40:47 +00:00
try:
user = self.connectmanager.login_manual(server, username)
except RuntimeError:
window('emby_serverStatus', value="stop")
self._auth = False
return
2016-03-31 18:40:47 +00:00
else:
log.info("user: %s", user)
settings('username', value=user['User']['Name'])
settings('token', value=user['AccessToken'])
settings('userId', value=user['User']['Id'])
xbmcgui.Dialog().notification(lang(29999),
"%s %s!" % (lang(33000), username))
self._load_user(authenticated=True)
window('emby_serverStatus', clear=True)
2016-03-31 18:40:47 +00:00
def _load_user(self, authenticated=False):
2016-03-31 18:40:47 +00:00
doutils = self.doutils
2016-03-31 18:40:47 +00:00
userid = self.get_userid()
server = self.get_server()
token = self.get_token()
# Set properties
2016-09-27 06:33:09 +00:00
# TODO: Remove old reference once code converted
window('emby_currUser', value=userid)
window('emby_server%s' % userid, value=server)
window('emby_accessToken%s' % userid, value=token)
2016-09-27 06:33:09 +00:00
server_json = {
'UserId': userid,
'Server': server,
'ServerId': settings('serverId'),
'Token': token,
'SSL': self.get_ssl()
}
# Set downloadutils.py values
doutils.set_session(**server_json)
# Test the validity of the current token
if not authenticated:
try:
self.download("{server}/emby/Users/{UserId}?format=json")
except Warning as error:
if "401" in error:
# Token is not longer valid
raise
2016-10-20 07:39:37 +00:00
# verify user access
self._set_access()
2016-09-06 22:43:15 +00:00
# Start downloadutils.py session
2016-09-27 02:50:58 +00:00
doutils.start_session()
2016-09-06 22:43:15 +00:00
# Set _user and _server
self._set_user_server()
2016-09-27 02:50:58 +00:00
def load_connect_servers(self):
# Set connect servers
if not settings('connectUsername'):
return
2016-09-27 06:33:09 +00:00
2016-09-27 02:50:58 +00:00
servers = self.connectmanager.get_connect_servers()
added_servers = []
for server in servers:
if server['Id'] != settings('serverId'):
# TODO: SSL setup
self.doutils.add_server(server, False)
added_servers.append(server['Id'])
2016-09-27 06:33:09 +00:00
2016-09-27 02:50:58 +00:00
# Set properties
log.info(added_servers)
window('emby_servers.json', value=added_servers)
2016-09-27 02:50:58 +00:00
def _reset_client(self):
log.info("reset UserClient authentication")
settings('accessToken', value="")
window('emby_accessToken', clear=True)
log.info("user token revoked.")
self._user = None
self.auth = None
2016-04-03 20:51:26 +00:00
2016-09-09 23:12:30 +00:00
current_state = self.connectmanager.get_state()
for server in current_state['Servers']:
if server['Id'] == settings('serverId'):
# Update token
server['AccessToken'] = None
self.connectmanager.update_token(current_state['Servers'], server)
2016-03-31 18:40:47 +00:00
def run(self):
monitor = xbmc.Monitor()
2016-09-27 06:33:09 +00:00
log.warn("----====# Starting UserClient #====----")
2016-03-31 18:40:47 +00:00
while not self._stop_thread:
2016-03-31 18:40:47 +00:00
status = window('emby_serverStatus')
if status:
# Verify the connection status to server
if status == "restricted":
# Parental control is restricting access
self._has_access = False
2016-03-31 18:40:47 +00:00
elif status == "401":
# Unauthorized access, revoke token
window('emby_serverStatus', value="auth")
self._reset_client()
2016-03-31 18:40:47 +00:00
if self._auth and self._user is None:
2016-03-31 18:40:47 +00:00
# Try to authenticate user
status = window('emby_serverStatus')
if not status or status == "auth":
2016-03-31 18:40:47 +00:00
# Set auth flag because we no longer need
# to authenticate the user
self._auth = False
self._authenticate()
2016-03-31 18:40:47 +00:00
if not self._auth and self._user is None:
2016-03-31 18:40:47 +00:00
# If authenticate failed.
server = self.get_server()
username = self.get_username()
2016-03-31 18:40:47 +00:00
status = window('emby_serverStatus')
2016-04-03 20:51:26 +00:00
2016-03-31 18:40:47 +00:00
# The status Stop is for when user cancelled password dialog.
if server and username and status != "stop":
2016-03-31 18:40:47 +00:00
# Only if there's information found to login
log.info("Server found: %s", server)
log.info("Username found: %s", username)
self._auth = True
2016-04-03 20:51:26 +00:00
2016-03-31 18:40:47 +00:00
if monitor.waitForAbort(1):
# Abort was requested while waiting. We should exit
break
2016-04-03 20:51:26 +00:00
2016-09-27 02:50:58 +00:00
self.doutils.stop_session()
2016-09-27 06:33:09 +00:00
log.warn("#====---- UserClient Stopped ----====#")
2016-03-31 18:40:47 +00:00
def stop_client(self):
self._stop_thread = True