diff --git a/resources/lib/PlexAPI.py b/resources/lib/PlexAPI.py index 08a68260..4bc08115 100644 --- a/resources/lib/PlexAPI.py +++ b/resources/lib/PlexAPI.py @@ -45,7 +45,7 @@ import xbmcgui import xbmc import xbmcvfs -import clientinfo +import clientinfo as client import downloadutils from utils import window, settings, language as lang, tryDecode, tryEncode, \ DateToKodi @@ -70,7 +70,6 @@ class PlexAPI(): def __init__(self): self.g_PMS = {} self.doUtils = downloadutils.DownloadUtils().downloadUrl - self.client = clientinfo.ClientInfo() def GetPlexLoginFromSettings(self): """ @@ -131,7 +130,7 @@ class PlexAPI(): retrievedPlexLogin, authtoken = self.MyPlexSignIn( plexLogin, plexPassword, - {'X-Plex-Client-Identifier': self.client.getDeviceId()}) + {'X-Plex-Client-Identifier': window('plex_client_Id')}) log.debug("plex.tv username and token: %s, %s" % (plexLogin, authtoken)) if plexLogin == '': @@ -721,7 +720,7 @@ class PlexAPI(): MyPlexURL = 'https://' + MyPlexHost + MyPlexSignInPath # create POST request - xargs = self.client.getXArgsDeviceInfo(options) + xargs = client.getXArgsDeviceInfo(options) request = urllib2.Request(MyPlexURL, None, xargs) request.get_method = lambda: 'POST' @@ -834,7 +833,7 @@ class PlexAPI(): log.info("No user selected.") settings('username', value='') xbmc.executebuiltin('Addon.OpenSettings(%s)' - % self.client.getAddonId()) + % v.ADDON_ID) return False # Only 1 user received, choose that one else: @@ -878,8 +877,7 @@ class PlexAPI(): break if not username: log.error('Failed signing in a user to plex.tv') - xbmc.executebuiltin('Addon.OpenSettings(%s)' - % self.client.getAddonId()) + xbmc.executebuiltin('Addon.OpenSettings(%s)' % v.ADDON_ID) return False return { 'username': username, @@ -1105,7 +1103,7 @@ class PlexAPI(): args['protocol'] = 'http' args['maxAudioBitrate'] = maxAudioBitrate - xargs = self.client.getXArgsDeviceInfo(options) + xargs = client.getXArgsDeviceInfo(options) if not AuthToken == '': xargs['X-Plex-Token'] = AuthToken @@ -1187,7 +1185,6 @@ class API(): self.part = 0 self.mediastream = None self.server = window('pms_server') - self.client = clientinfo.ClientInfo() def setPartNumber(self, number=None): """ @@ -1624,7 +1621,7 @@ class API(): arguments overrule everything """ - xargs = self.client.getXArgsDeviceInfo() + xargs = client.getXArgsDeviceInfo() xargs.update(arguments) if '?' not in url: url = "%s?%s" % (url, urlencode(xargs)) @@ -2253,7 +2250,7 @@ class API(): self.getMediastreamNumber() if quality is None: quality = {} - xargs = self.client.getXArgsDeviceInfo() + xargs = client.getXArgsDeviceInfo() # For DirectPlay, path/key of PART is needed # trailers are 'clip' with PMS xmls if action == "DirectStream": @@ -2273,7 +2270,7 @@ class API(): '/video/:/transcode/universal/start.m3u8?' args = { 'protocol': 'hls', # seen in the wild: 'dash', 'http', 'hls' - 'session': self.client.getDeviceId(), + 'session': window('plex_client_Id'), 'fastSeek': 1, 'path': path, 'mediaIndex': self.mediastream, diff --git a/resources/lib/clientinfo.py b/resources/lib/clientinfo.py index 1bb9bdd9..3b30e01b 100644 --- a/resources/lib/clientinfo.py +++ b/resources/lib/clientinfo.py @@ -1,14 +1,10 @@ # -*- coding: utf-8 -*- ############################################################################### - import logging -from uuid import uuid4 -import xbmc -import xbmcaddon - -from utils import window, settings, tryDecode +from utils import window, settings +import variables as v ############################################################################### @@ -17,111 +13,68 @@ log = logging.getLogger("PLEX."+__name__) ############################################################################### -class ClientInfo(): +def getXArgsDeviceInfo(self, options=None): + """ + Returns a dictionary that can be used as headers for GET and POST + requests. An authentication option is NOT yet added. - def __init__(self): - self.addon = xbmcaddon.Addon() + Inputs: + options: dictionary of options that will override the + standard header options otherwise set. + Output: + header dictionary + """ + xargs = { + 'Accept': '*/*', + 'Connection': 'keep-alive', + "Content-Type": "application/x-www-form-urlencoded", + # "Access-Control-Allow-Origin": "*", + # 'X-Plex-Language': 'en', + 'X-Plex-Device': v.ADDON_NAME, + 'X-Plex-Client-Platform': v.PLATFORM, + 'X-Plex-Device-Name': v.DEVICENAME, + 'X-Plex-Platform': v.PLATFORM, + # 'X-Plex-Platform-Version': 'unknown', + # 'X-Plex-Model': 'unknown', + 'X-Plex-Product': v.ADDON_NAME, + 'X-Plex-Version': v.ADDON_VERSION, + 'X-Plex-Client-Identifier': self.getDeviceId(), + 'X-Plex-Provides': 'client,controller,player', + } + if window('pms_token'): + xargs['X-Plex-Token'] = window('pms_token') + if options is not None: + xargs.update(options) + return xargs - def getXArgsDeviceInfo(self, options=None): - """ - Returns a dictionary that can be used as headers for GET and POST - requests. An authentication option is NOT yet added. - Inputs: - options: dictionary of options that will override the - standard header options otherwise set. - Output: - header dictionary - """ - # Get addon infos - xargs = { - 'Accept': '*/*', - 'Connection': 'keep-alive', - "Content-Type": "application/x-www-form-urlencoded", - # "Access-Control-Allow-Origin": "*", - # 'X-Plex-Language': 'en', - 'X-Plex-Device': self.getAddonName(), - 'X-Plex-Client-Platform': self.getPlatform(), - 'X-Plex-Device-Name': self.getDeviceName(), - 'X-Plex-Platform': self.getPlatform(), - # 'X-Plex-Platform-Version': 'unknown', - # 'X-Plex-Model': 'unknown', - 'X-Plex-Product': self.getAddonName(), - 'X-Plex-Version': self.getVersion(), - 'X-Plex-Client-Identifier': self.getDeviceId(), - 'X-Plex-Provides': 'client,controller,player', - } +def getDeviceId(self, reset=False): + """ + Returns a unique Plex client id "X-Plex-Client-Identifier" from Kodi + settings file. + Also loads Kodi window property 'plex_client_Id' - if window('pms_token'): - xargs['X-Plex-Token'] = window('pms_token') - if options is not None: - xargs.update(options) - return xargs + If id does not exist, create one and save in Kodi settings file. + """ + if reset is True: + window('plex_client_Id', clear=True) + settings('plex_client_Id', value="") - def getAddonName(self): - # Used for logging - return self.addon.getAddonInfo('name') + clientId = window('plex_client_Id') + if clientId: + return clientId - def getAddonId(self): - return "plugin.video.plexkodiconnect" - - def getVersion(self): - return self.addon.getAddonInfo('version') - - def getDeviceName(self): - if settings('deviceNameOpt') == "false": - # Use Kodi's deviceName - deviceName = tryDecode(xbmc.getInfoLabel('System.FriendlyName')) - else: - deviceName = settings('deviceName') - deviceName = deviceName.replace("\"", "_") - deviceName = deviceName.replace("/", "_") - return deviceName - - def getPlatform(self): - if xbmc.getCondVisibility('system.platform.osx'): - return "MacOSX" - elif xbmc.getCondVisibility('system.platform.atv2'): - return "AppleTV2" - elif xbmc.getCondVisibility('system.platform.ios'): - return "iOS" - elif xbmc.getCondVisibility('system.platform.windows'): - return "Windows" - elif xbmc.getCondVisibility('system.platform.raspberrypi'): - return "RaspberryPi" - elif xbmc.getCondVisibility('system.platform.linux'): - return "Linux" - elif xbmc.getCondVisibility('system.platform.android'): - return "Android" - else: - return "Unknown" - - def getDeviceId(self, reset=False): - """ - Returns a unique Plex client id "X-Plex-Client-Identifier" from Kodi - settings file. - Also loads Kodi window property 'plex_client_Id' - - If id does not exist, create one and save in Kodi settings file. - """ - if reset is True: - window('plex_client_Id', clear=True) - settings('plex_client_Id', value="") - - clientId = window('plex_client_Id') - if clientId: - return clientId - - clientId = settings('plex_client_Id') - # Because Kodi appears to cache file settings!! - if clientId != "" and reset is False: - window('plex_client_Id', value=clientId) - log.warn("Unique device Id plex_client_Id loaded: %s" % clientId) - return clientId - - log.warn("Generating a new deviceid.") - clientId = str(uuid4()) - settings('plex_client_Id', value=clientId) + clientId = settings('plex_client_Id') + # Because Kodi appears to cache file settings!! + if clientId != "" and reset is False: window('plex_client_Id', value=clientId) log.warn("Unique device Id plex_client_Id loaded: %s" % clientId) return clientId + + log.warn("Generating a new deviceid.") + from uuid import uuid4 + clientId = str(uuid4()) + settings('plex_client_Id', value=clientId) + window('plex_client_Id', value=clientId) + log.warn("Unique device Id plex_client_Id loaded: %s" % clientId) + return clientId diff --git a/resources/lib/downloadutils.py b/resources/lib/downloadutils.py index 242e6f90..9d50e4d8 100644 --- a/resources/lib/downloadutils.py +++ b/resources/lib/downloadutils.py @@ -9,7 +9,7 @@ import xml.etree.ElementTree as etree import xbmcgui from utils import settings, window, language as lang -import clientinfo +import clientinfo as client ############################################################################### @@ -100,7 +100,6 @@ class DownloadUtils(): # Start session self.s = requests.Session() - client = clientinfo.ClientInfo() self.deviceId = client.getDeviceId() # Attach authenticated header to the session self.s.headers = client.getXArgsDeviceInfo() @@ -139,7 +138,7 @@ class DownloadUtils(): log.info('Request session stopped') def getHeader(self, options=None): - header = clientinfo.ClientInfo().getXArgsDeviceInfo() + header = client.getXArgsDeviceInfo() if options is not None: header.update(options) return header diff --git a/resources/lib/entrypoint.py b/resources/lib/entrypoint.py index 62241288..ab665e7c 100644 --- a/resources/lib/entrypoint.py +++ b/resources/lib/entrypoint.py @@ -15,7 +15,6 @@ import xbmcplugin from utils import window, settings, language as lang from utils import tryDecode, tryEncode, CatchExceptions -import clientinfo import downloadutils import plexdb_functions as plexdb import playbackutils as pbutils @@ -204,8 +203,9 @@ def resetDeviceId(): dialog = xbmcgui.Dialog() deviceId_old = window('plex_client_Id') + from clientinfo import getDeviceId try: - deviceId = clientinfo.ClientInfo().getDeviceId(reset=True) + deviceId = getDeviceId(reset=True) except Exception as e: log.error("Failed to generate a new device Id: %s" % e) dialog.ok(heading=lang(29999), line1=lang(33032)) diff --git a/resources/lib/initialsetup.py b/resources/lib/initialsetup.py index b43c9ad9..2fa3313c 100644 --- a/resources/lib/initialsetup.py +++ b/resources/lib/initialsetup.py @@ -7,12 +7,12 @@ import xbmc import xbmcgui from utils import settings, window, language as lang -import clientinfo import downloadutils from userclient import UserClient -import PlexAPI +from PlexAPI import PlexAPI from PlexFunctions import GetMachineIdentifier, get_PMS_settings +import variables as v ############################################################################### @@ -25,10 +25,8 @@ class InitialSetup(): def __init__(self): log.debug('Entering initialsetup class') - self.clientInfo = clientinfo.ClientInfo() - self.addonId = self.clientInfo.getAddonId() self.doUtils = downloadutils.DownloadUtils().downloadUrl - self.plx = PlexAPI.PlexAPI() + self.plx = PlexAPI() self.dialog = xbmcgui.Dialog() self.server = UserClient().getServer() diff --git a/resources/lib/librarysync.py b/resources/lib/librarysync.py index 4606344f..c792f0dc 100644 --- a/resources/lib/librarysync.py +++ b/resources/lib/librarysync.py @@ -17,7 +17,6 @@ from utils import window, settings, getUnixTimestamp, sourcesXML,\ advancedSettingsXML, getKodiVideoDBPath, tryDecode, deletePlaylists,\ deleteNodes, ThreadMethodsAdditionalSuspend, create_actor_db_index, \ tryEncode -import clientinfo import downloadutils import itemtypes import plexdb_functions as plexdb @@ -372,7 +371,6 @@ class LibrarySync(Thread): self.fullSyncInterval = int(settings('fullSyncInterval')) * 60 - self.clientInfo = clientinfo.ClientInfo() self.user = userclient.UserClient() self.vnodes = videonodes.VideoNodes() self.dialog = xbmcgui.Dialog() @@ -1816,8 +1814,7 @@ class LibrarySync(Thread): log.info("Initial start-up full sync successful") startupComplete = True settings('SyncInstallRunDone', value="true") - settings("dbCreatedWithVersion", - self.clientInfo.getVersion()) + settings("dbCreatedWithVersion", v.ADDON_VERSION) installSyncDone = True else: log.error("Initial start-up full sync unsuccessful") diff --git a/resources/lib/player.py b/resources/lib/player.py index 6181bfd0..7e5d05ff 100644 --- a/resources/lib/player.py +++ b/resources/lib/player.py @@ -9,7 +9,6 @@ import xbmcgui from utils import window, settings, language as lang, DateToKodi, \ getUnixTimestamp -import clientinfo import downloadutils import plexdb_functions as plexdb import kodidb_functions as kodidb @@ -32,14 +31,9 @@ class Player(xbmc.Player): currentFile = None def __init__(self): - self.__dict__ = self._shared_state - - self.clientInfo = clientinfo.ClientInfo() self.doUtils = downloadutils.DownloadUtils().downloadUrl - xbmc.Player.__init__(self) - log.info("Started playback monitor.") def GetPlayStats(self): @@ -409,6 +403,6 @@ class Player(xbmc.Player): log.info("Transcoding for %s terminating" % itemid) self.doUtils( "{server}/video/:/transcode/universal/stop", - parameters={'session': self.clientInfo.getDeviceId()}) + parameters={'session': window('plex_client_Id')}) self.played_info.clear() diff --git a/resources/lib/plexbmchelper/plexsettings.py b/resources/lib/plexbmchelper/plexsettings.py index b5d9e67d..cd289f03 100644 --- a/resources/lib/plexbmchelper/plexsettings.py +++ b/resources/lib/plexbmchelper/plexsettings.py @@ -1,6 +1,6 @@ import logging from utils import guisettingsXML, settings -import clientinfo +import variables as v ############################################################################### @@ -21,7 +21,6 @@ def getGUI(name): def getSettings(): - client = clientinfo.ClientInfo() options = {} options['gdm_debug'] = settings('companionGDMDebugging') @@ -47,10 +46,10 @@ def getSettings(): log.info('Webserver username: %s, password: %s' % (options['user'], options['passwd'])) - options['addonName'] = client.getAddonName() + options['addonName'] = v.ADDON_NAME options['uuid'] = settings('plex_client_Id') - options['platform'] = client.getPlatform() - options['version'] = client.getVersion() + options['platform'] = v.PLATFORM + options['version'] = v.ADDON_VERSION options['plexbmc_version'] = options['version'] options['myplex_user'] = settings('username') try: diff --git a/resources/lib/utils.py b/resources/lib/utils.py index 1d556d2d..57fcc798 100644 --- a/resources/lib/utils.py +++ b/resources/lib/utils.py @@ -20,8 +20,6 @@ import xbmcaddon import xbmcgui import xbmcvfs -from variables import addonName - ############################################################################### log = logging.getLogger("PLEX."+__name__) @@ -420,7 +418,7 @@ def reset(): log.info("Deleting: settings.xml") dialog.ok( - heading=addonName, + heading=language(29999), line1="Database reset has completed, Kodi will now restart to apply the changes.") xbmc.executebuiltin('RestartApp') diff --git a/resources/lib/variables.py b/resources/lib/variables.py index ad6b157d..d3f7a263 100644 --- a/resources/lib/variables.py +++ b/resources/lib/variables.py @@ -1,9 +1,40 @@ # -*- coding: utf-8 -*- import xbmc +from xbmcaddon import Addon +from utils import settings, tryDecode + +ADDON_NAME = 'PlexKodiConnect' +ADDON_ID = 'plugin.video.plexkodiconnect' +ADDON_VERSION = Addon().getAddonInfo('version') KODILANGUAGE = xbmc.getLanguage(xbmc.ISO_639_1) KODIVERSION = int(xbmc.getInfoLabel("System.BuildVersion")[:2]) +if xbmc.getCondVisibility('system.platform.osx'): + PLATFORM = "MacOSX" +elif xbmc.getCondVisibility('system.platform.atv2'): + PLATFORM = "AppleTV2" +elif xbmc.getCondVisibility('system.platform.ios'): + PLATFORM = "iOS" +elif xbmc.getCondVisibility('system.platform.windows'): + PLATFORM = "Windows" +elif xbmc.getCondVisibility('system.platform.raspberrypi'): + PLATFORM = "RaspberryPi" +elif xbmc.getCondVisibility('system.platform.linux'): + PLATFORM = "Linux" +elif xbmc.getCondVisibility('system.platform.android'): + PLATFORM = "Android" +else: + PLATFORM = "Unknown" + +if settings('deviceNameOpt') == "false": + # Use Kodi's deviceName + DEVICENAME = tryDecode(xbmc.getInfoLabel('System.FriendlyName')) +else: + DEVICENAME = settings('deviceName') + DEVICENAME = DEVICENAME.replace("\"", "_") + DEVICENAME = DEVICENAME.replace("/", "_") + # Multiply Plex time by this factor to receive Kodi time PLEX_TO_KODI_TIMEFACTOR = 1.0 / 1000.0 diff --git a/service.py b/service.py index cc22cfe8..ae86eead 100644 --- a/service.py +++ b/service.py @@ -33,7 +33,6 @@ sys.path.append(_base_resource) from utils import settings, window, language as lang from userclient import UserClient -import clientinfo import initialsetup from kodimonitor import KodiMonitor from librarysync import LibrarySync @@ -47,6 +46,7 @@ from PlexCompanion import PlexCompanion from monitor_kodi_play import Monitor_Kodi_Play from playback_starter import Playback_Starter from artwork import Image_Cache_Thread +import variables as v ############################################################################### @@ -80,7 +80,6 @@ class Service(): def __init__(self): - self.clientInfo = clientinfo.ClientInfo() logLevel = self.getLogLevel() self.monitor = xbmc.Monitor() @@ -93,11 +92,10 @@ class Service(): value=settings('fetch_pms_item_number')) # Initial logging - log.warn("======== START %s ========" % lang(29999)) - log.warn("Platform: %s" % (self.clientInfo.getPlatform())) + log.warn("======== START %s ========" % v.ADDON_NAME) + log.warn("Platform: %s" % v.PLATFORM) log.warn("KODI Version: %s" % xbmc.getInfoLabel('System.BuildVersion')) - log.warn("%s Version: %s" - % (lang(29999), self.clientInfo.getVersion())) + log.warn("%s Version: %s" % (v.ADDON_NAME, v.ADDON_VERSION)) log.warn("Using plugin paths: %s" % (settings('useDirectPaths') != "true")) log.warn("Number of sync threads: %s" @@ -340,7 +338,7 @@ class Service(): except: pass - log.warn("======== STOP %s ========" % lang(29999)) + log.warn("======== STOP %s ========" % v.ADDON_NAME) # Delay option delay = int(settings('startupDelay'))