diff --git a/resources/lib/API.py b/resources/lib/API.py
deleted file mode 100644
index d15822bb..00000000
--- a/resources/lib/API.py
+++ /dev/null
@@ -1,378 +0,0 @@
-# -*- coding: utf-8 -*-
-
-##################################################################################################
-
-import clientinfo
-import utils
-
-##################################################################################################
-
-
-class API():
-
-    def __init__(self, item):
-
-        self.item = item
-        self.clientinfo = clientinfo.ClientInfo()
-        self.addonName = self.clientinfo.getAddonName()
-
-    def logMsg(self, msg, lvl=1):
-
-        className = self.__class__.__name__
-        utils.logMsg("%s %s" % (self.addonName, className), msg, lvl)
-
-
-    def getUserData(self):
-        # Default
-        favorite = False
-        playcount = None
-        played = False
-        lastPlayedDate = None
-        resume = 0
-        rating = 0
-
-        try:
-            userdata = self.item['UserData']
-        
-        except KeyError: # No userdata found.
-            pass
-
-        else:
-            favorite = userdata['IsFavorite']
-            likes = userdata.get('Likes')
-            # Rating for album and songs
-            if favorite:
-                rating = 5
-            elif likes:
-                rating = 3
-            elif likes == False:
-                rating = 1
-            else:
-                rating = 0
-
-            lastPlayedDate = userdata.get('LastPlayedDate')
-            if lastPlayedDate:
-                lastPlayedDate = lastPlayedDate.split('.')[0].replace('T', " ")
-            
-            if userdata['Played']:
-                # Playcount is tied to the watch status
-                played = True
-                playcount = userdata['PlayCount']
-                if playcount == 0:
-                    playcount = 1
-
-                if lastPlayedDate is None:
-                    lastPlayedDate = self.getDateCreated()
-
-            playbackPosition = userdata.get('PlaybackPositionTicks')
-            if playbackPosition:
-                resume = playbackPosition / 10000000.0
-
-        return {
-
-            'Favorite': favorite,
-            'PlayCount': playcount,
-            'Played': played,
-            'LastPlayedDate': lastPlayedDate,
-            'Resume': resume,
-            'Rating': rating
-        }
-
-    def getPeople(self):
-        # Process People
-        director = []
-        writer = []
-        cast = []
-
-        try:
-            people = self.item['People']
-        
-        except KeyError:
-            pass
-        
-        else:
-            for person in people:
-
-                type = person['Type']
-                name = person['Name']
-
-                if "Director" in type:
-                    director.append(name)
-                elif "Actor" in type:
-                    cast.append(name)
-                elif type in ("Writing", "Writer"):
-                    writer.append(name)
-
-        return {
-
-            'Director': director,
-            'Writer': writer,
-            'Cast': cast
-        }
-
-    def getMediaStreams(self):
-        item = self.item
-        videotracks = []
-        audiotracks = []
-        subtitlelanguages = []
-
-        try:
-            media_streams = item['MediaSources'][0]['MediaStreams']
-
-        except KeyError:
-            media_streams = item['MediaStreams']
-
-        for media_stream in media_streams:
-            # Sort through Video, Audio, Subtitle
-            stream_type = media_stream['Type']
-            codec = media_stream.get('Codec', "").lower()
-            profile = media_stream.get('Profile', "").lower()
-
-            if stream_type == "Video":
-                # Height, Width, Codec, AspectRatio, AspectFloat, 3D
-                track = {
-
-                    'videocodec': codec,
-                    'height': media_stream.get('Height'),
-                    'width': media_stream.get('Width'),
-                    'video3DFormat': item.get('Video3DFormat'),
-                    'aspectratio': 1.85
-                }
-
-                try:
-                    container = item['MediaSources'][0]['Container'].lower()
-                except:
-                    container = ""
-
-                # Sort codec vs container/profile
-                if "msmpeg4" in codec:
-                    track['videocodec'] = "divx"
-                elif "mpeg4" in codec:
-                    if "simple profile" in profile or not profile:
-                        track['videocodec'] = "xvid"
-                elif "h264" in codec:
-                    if container in ("mp4", "mov", "m4v"):
-                        track['videocodec'] = "avc1"
-
-                # Aspect ratio
-                if item.get('AspectRatio'):
-                    # Metadata AR
-                    aspectratio = item['AspectRatio']
-                else: # File AR
-                    aspectratio = media_stream.get('AspectRatio', "0")
-
-                try:
-                    aspectwidth, aspectheight = aspectratio.split(':')
-                    track['aspectratio'] = round(float(aspectwidth) / float(aspectheight), 6)
-                
-                except ValueError:
-                    width = track['width']
-                    height = track['height']
-
-                    if width and height:
-                        track['aspectratio'] = round(float(width / height), 6)
-
-                videotracks.append(track)
-
-            elif stream_type == "Audio":
-                # Codec, Channels, language
-                track = {
-                    
-                    'audiocodec': codec,
-                    'channels': media_stream.get('Channels'),
-                    'audiolanguage': media_stream.get('Language')
-                }
-
-                if "dca" in codec and "dts-hd ma" in profile:
-                    track['audiocodec'] = "dtshd_ma"
-
-                audiotracks.append(track)
-
-            elif stream_type == "Subtitle":
-                # Language
-                subtitlelanguages.append(media_stream.get('Language', "Unknown"))
-
-        return {
-
-            'video': videotracks, 
-            'audio': audiotracks,
-            'subtitle': subtitlelanguages
-        }
-
-    def getRuntime(self):
-        item = self.item
-        try:
-            runtime = item['RunTimeTicks'] / 10000000.0
-        
-        except KeyError:
-            runtime = item.get('CumulativeRunTimeTicks', 0) / 10000000.0
-
-        return runtime
-
-    def adjustResume(self, resume_seconds):
-
-        resume = 0
-        if resume_seconds:
-            resume = round(float(resume_seconds), 6)
-            jumpback = int(utils.settings('resumeJumpBack'))
-            if resume > jumpback:
-                # To avoid negative bookmark
-                resume = resume - jumpback
-
-        return resume
-
-    def getStudios(self):
-        # Process Studios
-        item = self.item
-        studios = []
-
-        try:
-            studio = item['SeriesStudio']
-            studios.append(self.verifyStudio(studio))
-        
-        except KeyError:
-            studioList = item['Studios']
-            for studio in studioList:
-
-                name = studio['Name']
-                studios.append(self.verifyStudio(name))
-        
-        return studios
-
-    def verifyStudio(self, studioName):
-        # Convert studio for Kodi to properly detect them
-        studios = {
-
-            'abc (us)': "ABC",
-            'fox (us)': "FOX",
-            'mtv (us)': "MTV",
-            'showcase (ca)': "Showcase",
-            'wgn america': "WGN"
-        }
-
-        return studios.get(studioName.lower(), studioName)
-
-    def getChecksum(self):
-        # Use the etags checksum and userdata
-        item = self.item
-        userdata = item['UserData']
-
-        checksum = "%s%s%s%s%s%s" % (
-            
-            item['Etag'], 
-            userdata['Played'],
-            userdata['IsFavorite'],
-            userdata['PlaybackPositionTicks'],
-            userdata.get('UnplayedItemCount', ""),
-            userdata.get('LastPlayedDate', "")
-        )
-
-        return checksum
-
-    def getGenres(self):
-        item = self.item
-        all_genres = ""
-        genres = item.get('Genres', item.get('SeriesGenres'))
-
-        if genres:
-            all_genres = " / ".join(genres)
-
-        return all_genres
-
-    def getDateCreated(self):
-
-        try:
-            dateadded = self.item['DateCreated']
-            dateadded = dateadded.split('.')[0].replace('T', " ")
-        except KeyError:
-            dateadded = None
-
-        return dateadded
-
-    def getPremiereDate(self):
-
-        try:
-            premiere = self.item['PremiereDate']
-            premiere = premiere.split('.')[0].replace('T', " ")
-        except KeyError:
-            premiere = None
-
-        return premiere
-
-    def getOverview(self):
-
-        try:
-            overview = self.item['Overview']
-            overview = overview.replace("\"", "\'")
-            overview = overview.replace("\n", " ")
-            overview = overview.replace("\r", " ")
-        except KeyError:
-            overview = ""
-
-        return overview
-
-    def getTagline(self):
-
-        try:
-            tagline = self.item['Taglines'][0]
-        except IndexError:
-            tagline = None
-
-        return tagline
-
-    def getProvider(self, providername):
-
-        try:
-            provider = self.item['ProviderIds'][providername]
-        except KeyError:
-            provider = None
-
-        return provider
-
-    def getMpaa(self):
-        # Convert more complex cases
-        mpaa = self.item.get('OfficialRating', "")
-        
-        if mpaa in ("NR", "UR"):
-            # Kodi seems to not like NR, but will accept Not Rated
-            mpaa = "Not Rated"
-
-        return mpaa
-
-    def getCountry(self):
-
-        try:
-            country = self.item['ProductionLocations'][0]
-        except IndexError:
-            country = None
-
-        return country
-
-    def getFilePath(self):
-
-        item = self.item
-        try:
-            filepath = item['Path']
-
-        except KeyError:
-            filepath = ""
-
-        else:
-            if "\\\\" in filepath:
-                # append smb protocol
-                filepath = filepath.replace("\\\\", "smb://")
-                filepath = filepath.replace("\\", "/")
-
-            if item.get('VideoType'):
-                videotype = item['VideoType']
-                # Specific format modification
-                if 'Dvd'in videotype:
-                    filepath = "%s/VIDEO_TS/VIDEO_TS.IFO" % filepath
-                elif 'Bluray' in videotype:
-                    filepath = "%s/BDMV/index.bdmv" % filepath
-            
-            if "\\" in filepath:
-                # Local path scenario, with special videotype
-                filepath = filepath.replace("/", "\\")
-
-        return filepath
\ No newline at end of file
diff --git a/resources/lib/DownloadUtils.py b/resources/lib/DownloadUtils.py
deleted file mode 100644
index 04d2da85..00000000
--- a/resources/lib/DownloadUtils.py
+++ /dev/null
@@ -1,347 +0,0 @@
-import xbmc
-import xbmcgui
-import xbmcaddon
-
-import requests
-import json
-import logging
-
-import Utils as utils
-from ClientInformation import ClientInformation
-from requests.packages.urllib3.exceptions import InsecureRequestWarning
-
-# Disable requests logging
-requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
-#logging.getLogger("requests").setLevel(logging.WARNING)
-
-class DownloadUtils():
-    
-    # Borg - multiple instances, shared state
-    _shared_state = {}
-    clientInfo = ClientInformation()
-
-    addonName = clientInfo.getAddonName()
-    addon = xbmcaddon.Addon()
-    WINDOW = xbmcgui.Window(10000)
-
-    # Requests session
-    s = None
-    timeout = 60
-
-    def __init__(self):
-
-        self.__dict__ = self._shared_state
-
-    def logMsg(self, msg, lvl=1):
-
-        self.className = self.__class__.__name__
-        utils.logMsg("%s %s" % (self.addonName, self.className), msg, int(lvl))
-
-    def setUsername(self, username):
-        # Reserved for UserClient only
-        self.username = username
-        self.logMsg("Set username: %s" % username, 2)
-
-    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 setSSL(self, ssl, sslclient):
-        # Reserved for UserClient only
-        self.sslverify = ssl
-        self.sslclient = sslclient
-        self.logMsg("Verify SSL host certificate: %s" % ssl, 2)
-        self.logMsg("SSL client side certificate: %s" % sslclient, 2)
-
-    def postCapabilities(self, deviceId):
-
-        # Post settings to session
-        url = "{server}/mediabrowser/Sessions/Capabilities/Full"
-        data = {
-            'PlayableMediaTypes': "Audio,Video",
-            'SupportsMediaControl': True,
-            'SupportedCommands': (
-                
-                "MoveUp,MoveDown,MoveLeft,MoveRight,Select,"
-                "Back,ToggleContextMenu,ToggleFullscreen,ToggleOsdMenu,"
-                "GoHome,PageUp,NextLetter,GoToSearch,"
-                "GoToSettings,PageDown,PreviousLetter,TakeScreenshot,"
-                "VolumeUp,VolumeDown,ToggleMute,SendString,DisplayMessage,"
-                "SetAudioStreamIndex,SetSubtitleStreamIndex,"
-
-                "Mute,Unmute,SetVolume,"
-                "Play,Playstate,PlayNext"
-            )
-        }
-
-        self.logMsg("Capabilities URL: %s" % url, 2)
-        self.logMsg("PostData: %s" % data, 2)
-
-        try:
-            self.downloadUrl(url, postBody=data, type="POST")
-            self.logMsg("Posted capabilities to %s" % self.server, 1)
-        except:
-            self.logMsg("Posted capabilities failed.")
-
-        # Attempt at getting sessionId
-        url = "{server}/mediabrowser/Sessions?DeviceId=%s&format=json" % deviceId
-
-        try:
-            result = self.downloadUrl(url)
-            self.logMsg("Session: %s" % result, 2)
-            
-            sessionId = result[0][u'Id']
-            self.logMsg("SessionId: %s" % sessionId)
-            self.WINDOW.setProperty("sessionId%s" % self.username, sessionId)
-        except:
-            self.logMsg("Failed to retrieve sessionId.", 1)
-        else:
-            # Post any permanent additional users
-            additionalUsers = utils.settings('additionalUsers').split(',')
-            self.logMsg("List of permanent users that should be added to the session: %s" % str(additionalUsers), 1)
-            # Get the user list from server to get the userId
-            url = "{server}/mediabrowser/Users?format=json"
-            result = self.downloadUrl(url)
-
-            if result:
-                for user in result:
-                    username = user['Name'].lower()
-                    userId = user['Id']
-                    for additional in additionalUsers:
-                        addUser = additional.decode('utf-8').lower()
-                        if username in addUser:
-                            url = "{server}/mediabrowser/Sessions/%s/Users/%s" % (sessionId, userId)
-                            postdata = {}
-                            self.downloadUrl(url, postBody=postdata, type="POST")
-                            #xbmcgui.Dialog().notification("Success!", "%s added to viewing session" % username, time=1000)
-
-    def startSession(self):
-
-        self.deviceId = self.clientInfo.getMachineId()
-
-        # User is identified from this point
-        # Attach authenticated header to the session
-        verify = None
-        cert = None
-        header = self.getHeader()
-
-        # If user enabled host certificate verification
-        try:
-            verify = self.sslverify
-            cert = self.sslclient
-        except:
-            self.logMsg("Could not load SSL settings.", 1)
-        
-        # Start session
-        self.s = requests.Session()
-        self.s.headers = header
-        self.s.verify = verify
-        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)
-
-    def stopSession(self):
-        try:
-            self.s.close()
-        except:
-            self.logMsg("Requests session could not be terminated.", 1)
-
-    def getHeader(self, authenticate=True):
-
-        clientInfo = self.clientInfo
-
-        deviceName = clientInfo.getDeviceName()
-        deviceId = clientInfo.getMachineId()
-        version = clientInfo.getVersion()
-
-        if not authenticate:
-            # If user is not authenticated
-            auth = 'MediaBrowser Client="Kodi", Device="%s", DeviceId="%s", Version="%s"' % (deviceName, deviceId, version)
-            header = {'Content-type': 'application/json', 'Accept-encoding': 'gzip', 'Accept-Charset': 'UTF-8,*', 'Authorization': auth}      
-            
-            self.logMsg("Header: %s" % header, 2)
-            return header
-        
-        else:
-            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 = {'Content-type': 'application/json', 'Accept-encoding': 'gzip', 'Accept-Charset': 'UTF-8,*', 'Authorization': auth, 'X-MediaBrowser-Token': token}        
-                    
-            self.logMsg("Header: %s" % header, 2)
-            return header
-
-    def downloadUrl(self, url, postBody=None, type="GET", authenticate=True):
-        
-        self.logMsg("=== ENTER downloadUrl ===", 2)
-
-        WINDOW = self.WINDOW
-        timeout = self.timeout
-        default_link = ""
-
-        try:
-
-            # If user is authenticated
-            if (authenticate):
-                # Get requests session
-                try: 
-                    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)
-
-                    self.logMsg("URL: %s" % url, 2)
-                    # Prepare request
-                    if type == "GET":
-                        r = s.get(url, json=postBody, timeout=timeout)
-                    elif type == "POST":
-                        r = s.post(url, json=postBody, timeout=timeout)
-                    elif type == "DELETE":
-                        r = s.delete(url, json=postBody, timeout=timeout)
-                
-                except AttributeError:
-                    
-                    # Get user information
-                    self.username = WINDOW.getProperty('currUser')
-                    self.userId = WINDOW.getProperty('userId%s' % self.username)
-                    self.server = WINDOW.getProperty('server%s' % self.username)
-                    self.token = WINDOW.getProperty('accessToken%s' % self.username)
-                    header = self.getHeader()
-                    verifyssl = False
-                    cert = None
-
-                    # IF user enables ssl verification
-                    try:
-                        if utils.settings('sslverify') == "true":
-                            verifyssl = True
-                        if utils.settings('sslcert') != "None":
-                            cert = utils.settings('sslcert')
-                    except:
-                        self.logMsg("Could not load SSL settings.", 1)
-                        pass
-
-                    # Replace for the real values and append api_key
-                    url = url.replace("{server}", self.server, 1)
-                    url = url.replace("{UserId}", self.userId, 1)
-
-                    self.logMsg("URL: %s" % url, 2)
-                    # Prepare request
-                    if type == "GET":
-                        r = requests.get(url, json=postBody, headers=header, timeout=timeout, cert=cert, verify=verifyssl)
-                    elif type == "POST":
-                        r = requests.post(url, json=postBody, headers=header, timeout=timeout, cert=cert, verify=verifyssl)
-                    elif type == "DELETE":
-                        r = requests.delete(url, json=postBody, headers=header, timeout=timeout, cert=cert, verify=verifyssl)
-
-            # If user is not authenticated
-            elif not authenticate:
-                
-                self.logMsg("URL: %s" % url, 2)
-                header = self.getHeader(authenticate=False)
-                verifyssl = False
-
-                # If user enables ssl verification
-                try:
-                    verifyssl = self.sslverify
-                except AttributeError:
-                    pass
-                
-                # Prepare request
-                if type == "GET":
-                    r = requests.get(url, json=postBody, headers=header, timeout=timeout, verify=verifyssl)
-                elif type == "POST":
-                    r = requests.post(url, json=postBody, headers=header, timeout=timeout, verify=verifyssl)
-        
-            # Process the response
-            if r.status_code == 204:
-                # No body in the response
-                self.logMsg("====== 204 Success ======", 2)
-                return default_link
-
-            elif r.status_code == requests.codes.ok:
-                try: 
-                    # UTF-8 - JSON object
-                    r = r.json()
-                    self.logMsg("====== 200 Success ======", 2)
-                    self.logMsg("Response: %s" % r, 2)
-                    return r
-                except:
-                    if r.headers.get('content-type') == "text/html":
-                        pass
-                    else:
-                        self.logMsg("Unable to convert the response for: %s" % url, 1)
-            else:
-                r.raise_for_status()
-
-            return default_link
-        
-        # TO REVIEW EXCEPTIONS
-        except requests.exceptions.ConnectionError as e:
-            # Make the addon aware of status
-            if WINDOW.getProperty("Server_online") != "false":
-                self.logMsg("Server unreachable at: %s" % url, 0)
-                self.logMsg(e, 2)
-                WINDOW.setProperty("Server_online", "false")
-            pass
-
-        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")
-
-                if 'x-application-error-code' in r.headers:
-                    if r.headers['X-Application-Error-Code'] == "ParentalControl":
-                        # Parental control - access restricted
-                        WINDOW.setProperty("Server_status", "restricted")
-                        xbmcgui.Dialog().notification("Emby server", "Access restricted.", xbmcgui.NOTIFICATION_ERROR, time=5000)
-                        return False
-                    elif r.headers['X-Application-Error-Code'] == "UnauthorizedAccessException":
-                        # User tried to do something his emby account doesn't allow - admin restricted in some way
-                        pass
-
-                elif (status == "401") or (status == "Auth"):
-                    pass
-
-                else:
-                    # Tell UserClient token has been revoked.
-                    WINDOW.setProperty("Server_status", "401")
-                    self.logMsg("HTTP Error: %s" % e, 0)
-                    xbmcgui.Dialog().notification("Error connecting", "Unauthorized.", xbmcgui.NOTIFICATION_ERROR)
-                    return 401
-
-            elif (r.status_code == 301) or (r.status_code == 302):
-                # Redirects
-                pass
-            elif r.status_code == 400:
-                # Bad requests
-                pass
-
-        except requests.exceptions.SSLError as e:
-            self.logMsg("Invalid SSL certificate for: %s" % url, 0)
-            self.logMsg(e, 1)
-
-        except requests.exceptions.RequestException as e:
-            self.logMsg("Unknown error connecting to: %s" % url, 0)
-            self.logMsg(e, 1)
-
-        return default_link
diff --git a/resources/lib/Entrypoint.py b/resources/lib/Entrypoint.py
deleted file mode 100644
index 95a5a327..00000000
--- a/resources/lib/Entrypoint.py
+++ /dev/null
@@ -1,694 +0,0 @@
-import xbmcaddon
-import xbmcplugin
-import xbmc
-import xbmcgui
-import xbmcvfs
-import os, sys
-import threading
-import json
-import urllib
-import time
-
-WINDOW = xbmcgui.Window(10000)
-
-import Utils as utils
-from ClientInformation import ClientInformation
-from PlaybackUtils import PlaybackUtils
-from PlayUtils import PlayUtils
-from DownloadUtils import DownloadUtils
-from ReadEmbyDB import ReadEmbyDB
-from API import API
-from UserPreferences import UserPreferences
-
-
-##### Play items via plugin://plugin.video.emby/ #####
-def doPlayback(id):
-    url = "{server}/mediabrowser/Users/{UserId}/Items/%s?format=json&ImageTypeLimit=1" % id
-    result = DownloadUtils().downloadUrl(url)
-    item = PlaybackUtils().PLAY(result, setup="default")
-
-#### DO RESET AUTH #####    
-def resetAuth():
-    # User tried login and failed too many times
-    resp = xbmcgui.Dialog().yesno("Warning", "Emby might lock your account if you fail to log in too many times. Proceed anyway?")
-    if resp == 1:
-        xbmc.log("Reset login attempts.")
-        WINDOW.setProperty("Server_status", "Auth")
-    else:
-        xbmc.executebuiltin('Addon.OpenSettings(plugin.video.emby)')
-
-### ADD ADDITIONAL USERS ###
-def addUser():
-
-    doUtils = DownloadUtils()
-    clientInfo = ClientInformation()
-    currUser = WINDOW.getProperty("currUser")
-    deviceId = clientInfo.getMachineId()
-    deviceName = clientInfo.getDeviceName()
-
-    # Get session
-    url = "{server}/mediabrowser/Sessions?DeviceId=%s" % deviceId
-    result = doUtils.downloadUrl(url)
-    
-    try:
-        sessionId = result[0][u'Id']
-        additionalUsers = result[0][u'AdditionalUsers']
-        # Add user to session
-        userlist = {}
-        users = []
-        url = "{server}/mediabrowser/Users?IsDisabled=false&IsHidden=false"
-        result = doUtils.downloadUrl(url)
-
-        # pull the list of users
-        for user in result:
-            name = user[u'Name']
-            userId = user[u'Id']
-            if currUser not in name:
-                userlist[name] = userId
-                users.append(name)
-
-        # Display dialog if there's additional users
-        if additionalUsers:
-
-            option = xbmcgui.Dialog().select("Add/Remove user from the session", ["Add user", "Remove user"])
-            # Users currently in the session
-            additionalUserlist = {}
-            additionalUsername = []
-            # Users currently in the session
-            for user in additionalUsers:
-                name = user[u'UserName']
-                userId = user[u'UserId']
-                additionalUserlist[name] = userId
-                additionalUsername.append(name)
-
-            if option == 1:
-                # User selected Remove user
-                resp = xbmcgui.Dialog().select("Remove user from the session", additionalUsername)
-                if resp > -1:
-                    selected = additionalUsername[resp]
-                    selected_userId = additionalUserlist[selected]
-                    url = "{server}/mediabrowser/Sessions/%s/Users/%s" % (sessionId, selected_userId)
-                    postdata = {}
-                    doUtils.downloadUrl(url, postBody=postdata, type="DELETE")
-                    xbmcgui.Dialog().notification("Success!", "%s removed from viewing session" % selected, time=1000)
-
-                    # clear picture
-                    position = WINDOW.getProperty('EmbyAdditionalUserPosition.' + selected_userId)
-                    WINDOW.clearProperty('EmbyAdditionalUserImage.' + str(position))
-                    return
-                else:
-                    return
-
-            elif option == 0:
-                # User selected Add user
-                for adduser in additionalUsername:
-                    try: # Remove from selected already added users. It is possible they are hidden.
-                        users.remove(adduser)
-                    except: pass
-
-            elif option < 0:
-                # User cancelled
-                return
-
-        # Subtract any additional users
-        xbmc.log("Displaying list of users: %s" % users)
-        resp = xbmcgui.Dialog().select("Add user to the session", users)
-        # post additional user
-        if resp > -1:
-            selected = users[resp]
-            selected_userId = userlist[selected]
-            url = "{server}/mediabrowser/Sessions/%s/Users/%s" % (sessionId, selected_userId)
-            postdata = {}
-            doUtils.downloadUrl(url, postBody=postdata, type="POST")
-            xbmcgui.Dialog().notification("Success!", "%s added to viewing session" % selected, time=1000)
-
-    except:
-        xbmc.log("Failed to add user to session.")
-        xbmcgui.Dialog().notification("Error", "Unable to add/remove user from the session.", xbmcgui.NOTIFICATION_ERROR)
-
-    try:
-        # Add additional user images
-        #always clear the individual items first
-        totalNodes = 10
-        for i in range(totalNodes):
-            if not WINDOW.getProperty('EmbyAdditionalUserImage.' + str(i)):
-                break
-            WINDOW.clearProperty('EmbyAdditionalUserImage.' + str(i))
-
-        url = "{server}/mediabrowser/Sessions?DeviceId=%s" % deviceId
-        result = doUtils.downloadUrl(url)
-        additionalUsers = result[0][u'AdditionalUsers']
-        count = 0
-        for additionaluser in additionalUsers:
-            url = "{server}/mediabrowser/Users/%s?format=json" % (additionaluser[u'UserId'])
-            result = doUtils.downloadUrl(url)
-            WINDOW.setProperty("EmbyAdditionalUserImage." + str(count),API().getUserArtwork(result,"Primary"))
-            WINDOW.setProperty("EmbyAdditionalUserPosition." + str(additionaluser[u'UserId']),str(count))
-            count +=1
-    except:
-        pass
-
-# THEME MUSIC/VIDEOS
-def getThemeMedia():
-
-    doUtils = DownloadUtils()
-    playUtils = PlayUtils()
-    
-    currUser = WINDOW.getProperty('currUser')
-    server = WINDOW.getProperty('server%s' % currUser)
-    playback = None
-
-    library = xbmc.translatePath("special://profile/addon_data/plugin.video.emby/library/").decode('utf-8')
-
-    # Choose playback method
-    resp = xbmcgui.Dialog().select("Choose playback method for your themes", ["Direct Play", "Direct Stream"])
-    if resp == 0:
-        # Direct Play
-        playback = "DirectPlay"
-    elif resp == 1:
-        # Direct Stream
-        playback = "DirectStream"
-    else:return
-
-    # Set custom path for user
-    tvtunes_path = xbmc.translatePath("special://profile/addon_data/script.tvtunes/").decode('utf-8')
-    if xbmcvfs.exists(tvtunes_path):
-        tvtunes = xbmcaddon.Addon(id="script.tvtunes")
-        tvtunes.setSetting('custom_path_enable', "true")
-        tvtunes.setSetting('custom_path', library)
-        xbmc.log("TV Tunes custom path is enabled and set.")
-    else:
-        # if it does not exist this will not work so warn user, often they need to edit the settings first for it to be created.
-        dialog = xbmcgui.Dialog()
-        dialog.ok('Warning', 'The settings file does not exist in tvtunes. Go to the tvtunes addon and change a setting, then come back and re-run')
-        return
-        
-
-    # Create library directory
-    if not xbmcvfs.exists(library):
-        xbmcvfs.mkdir(library)
-
-    # Get every user view Id
-    userViews = []
-    url = "{server}/mediabrowser/Users/{UserId}/Items?format=json"
-    result = doUtils.downloadUrl(url)
-    
-    for view in result[u'Items']:
-        userviewId = view[u'Id']
-        userViews.append(userviewId)
-
-
-    # Get Ids with Theme Videos
-    itemIds = {}
-    for view in userViews:
-        url = "{server}/mediabrowser/Users/{UserId}/Items?HasThemeVideo=True&ParentId=%s&format=json" % view
-        result = doUtils.downloadUrl(url)
-        if result[u'TotalRecordCount'] != 0:
-            for item in result[u'Items']:
-                itemId = item[u'Id']
-                folderName = item[u'Name']
-                folderName = utils.normalize_string(folderName.encode('utf-8'))
-                itemIds[itemId] = folderName
-
-    # Get paths for theme videos
-    for itemId in itemIds:
-        nfo_path = xbmc.translatePath("special://profile/addon_data/plugin.video.emby/library/%s/" % itemIds[itemId])
-        # Create folders for each content
-        if not xbmcvfs.exists(nfo_path):
-            xbmcvfs.mkdir(nfo_path)
-        # Where to put the nfos
-        nfo_path = "%s%s" % (nfo_path, "tvtunes.nfo")
-
-        url = "{server}/mediabrowser/Items/%s/ThemeVideos?format=json" % itemId
-        result = doUtils.downloadUrl(url)
-
-        # Create nfo and write themes to it
-        nfo_file = open(nfo_path, 'w')
-        pathstowrite = ""
-        # May be more than one theme
-        for theme in result[u'Items']:  
-            if playback == "DirectPlay":
-                playurl = playUtils.directPlay(theme)
-            else:
-                playurl = playUtils.directStream(result, server, theme[u'Id'], "ThemeVideo")
-            pathstowrite += ('<file>%s</file>' % playurl.encode('utf-8'))
-        
-        # Check if the item has theme songs and add them   
-        url = "{server}/mediabrowser/Items/%s/ThemeSongs?format=json" % itemId
-        result = doUtils.downloadUrl(url)
-
-        # May be more than one theme
-        for theme in result[u'Items']:  
-            if playback == "DirectPlay":
-                playurl = playUtils.directPlay(theme)
-            else:
-                playurl = playUtils.directStream(result, server, theme[u'Id'], "Audio")
-            pathstowrite += ('<file>%s</file>' % playurl.encode('utf-8'))
-
-        nfo_file.write(
-            '<tvtunes>%s</tvtunes>' % pathstowrite
-        )
-        # Close nfo file
-        nfo_file.close()
-
-    # Get Ids with Theme songs
-    musicitemIds = {}
-    for view in userViews:
-        url = "{server}/mediabrowser/Users/{UserId}/Items?HasThemeSong=True&ParentId=%s&format=json" % view
-        result = doUtils.downloadUrl(url)
-        if result[u'TotalRecordCount'] != 0:
-            for item in result[u'Items']:
-                itemId = item[u'Id']
-                folderName = item[u'Name']
-                folderName = utils.normalize_string(folderName.encode('utf-8'))
-                musicitemIds[itemId] = folderName
-
-    # Get paths
-    for itemId in musicitemIds:
-        
-        # if the item was already processed with video themes back out
-        if itemId in itemIds:
-            continue
-        
-        nfo_path = xbmc.translatePath("special://profile/addon_data/plugin.video.emby/library/%s/" % musicitemIds[itemId])
-        # Create folders for each content
-        if not xbmcvfs.exists(nfo_path):
-            xbmcvfs.mkdir(nfo_path)
-        # Where to put the nfos
-        nfo_path = "%s%s" % (nfo_path, "tvtunes.nfo")
-        
-        url = "{server}/mediabrowser/Items/%s/ThemeSongs?format=json" % itemId
-        result = doUtils.downloadUrl(url)
-
-        # Create nfo and write themes to it
-        nfo_file = open(nfo_path, 'w')
-        pathstowrite = ""
-        # May be more than one theme
-        for theme in result[u'Items']:  
-            if playback == "DirectPlay":
-                playurl = playUtils.directPlay(theme)
-            else:
-                playurl = playUtils.directStream(result, server, theme[u'Id'], "Audio")
-            pathstowrite += ('<file>%s</file>' % playurl.encode('utf-8'))
-
-        nfo_file.write(
-            '<tvtunes>%s</tvtunes>' % pathstowrite
-        )
-        # Close nfo file
-        nfo_file.close()
-
-def userPreferences():
-    doUtils = DownloadUtils()
-    addonSettings = xbmcaddon.Addon(id='plugin.video.emby')
-    userPreferencesPage = UserPreferences("script-emby-kodi-UserPreferences.xml", addonSettings.getAddonInfo('path'), "default", "1080i")
-    url = "{server}/mediabrowser/Users/{UserId}" 
-    result = doUtils.downloadUrl(url)
-    configuration = result[u'Configuration']
-    userPreferencesPage.setConfiguration(configuration)
-    userPreferencesPage.setName(result[u'Name'])
-    userPreferencesPage.setImage(API().getUserArtwork(result,"Primary"))
-    
-    userPreferencesPage.doModal()
-    if userPreferencesPage.isSave():
-        url = "{server}/mediabrowser/Users/{UserId}/Configuration"
-        postdata = userPreferencesPage.getConfiguration()
-        doUtils.downloadUrl(url, postBody=postdata, type="POST")
-
-##### BROWSE EMBY CHANNELS #####    
-def BrowseChannels(id, folderid=None):
-    
-    _addon_id   =   int(sys.argv[1])
-    _addon_url  =   sys.argv[0]
-    
-    xbmcplugin.setContent(int(sys.argv[1]), 'files')
-    if folderid:
-        url = "{server}/mediabrowser/Channels/" + id + "/Items?userid={UserId}&folderid=" + folderid + "&format=json"
-    else:
-        if id == "0": # id 0 is the root channels folder
-            url = "{server}/mediabrowser/Channels?{UserId}&format=json"
-        else:
-            url = "{server}/mediabrowser/Channels/" + id + "/Items?userid={UserId}&format=json"
-
-    results = DownloadUtils().downloadUrl(url)
-    if results:
-        result = results.get("Items")
-        if(result == None):
-            result = []
-
-        item_count = len(result)
-        current_item = 1;
-            
-        for item in result:
-            id=str(item.get("Id")).encode('utf-8')
-            type=item.get("Type").encode('utf-8')
-            
-            
-            if(item.get("Name") != None):
-                tempTitle = item.get("Name")
-                tempTitle=tempTitle.encode('utf-8')
-            else:
-                tempTitle = "Missing Title"
-                
-            if type=="ChannelFolderItem":
-                isFolder = True
-            else:
-                isFolder = False
-            item_type = str(type).encode('utf-8')
-            
-            if(item.get("ChannelId") != None):
-               channelId = str(item.get("ChannelId")).encode('utf-8')
-            
-            channelName = ''   
-            if(item.get("ChannelName") != None):
-               channelName = item.get("ChannelName").encode('utf-8')   
-               
-            if(item.get("PremiereDate") != None):
-                premieredatelist = (item.get("PremiereDate")).split("T")
-                premieredate = premieredatelist[0]
-            else:
-                premieredate = ""
-            
-            #mediaStreams=API().getMediaStreams(item, True)
-                    
-            #people = API().getPeople(item)
-            
-            # Process Genres
-            genre = API().getGenre(item)
-                    
-            # Process UserData
-            userData = item.get("UserData")
-            PlaybackPositionTicks = '100'
-            overlay = "0"
-            favorite = "False"
-            seekTime = 0
-            if(userData != None):
-                if userData.get("Played") != True:
-                    overlay = "7"
-                    watched = "true"
-                else:
-                    overlay = "6"
-                    watched = "false"
-                if userData.get("IsFavorite") == True:
-                    overlay = "5"
-                    favorite = "True"
-                else:
-                    favorite = "False"
-                if userData.get("PlaybackPositionTicks") != None:
-                    PlaybackPositionTicks = str(userData.get("PlaybackPositionTicks"))
-                    reasonableTicks = int(userData.get("PlaybackPositionTicks")) / 1000
-                    seekTime = reasonableTicks / 10000
-            
-            playCount = 0
-            if(userData != None and userData.get("Played") == True):
-                playCount = 1
-            # Populate the details list
-            details={'title'        : tempTitle,
-                     'channelname'  : channelName,
-                     'plot'         : item.get("Overview"),
-                     'Overlay'      : overlay,
-                     'playcount'    : str(playCount)}
-            
-            if item.get("Type") == "ChannelVideoItem":
-                xbmcplugin.setContent(_addon_id, 'movies')
-            elif item.get("Type") == "ChannelAudioItem":
-                xbmcplugin.setContent(_addon_id, 'songs')
-
-            # Populate the extraData list
-            extraData={'thumb'        : API().getArtwork(item, "Primary")  ,
-                       'fanart_image' : API().getArtwork(item, "Backdrop") ,
-                       'poster'       : API().getArtwork(item, "poster") , 
-                       'tvshow.poster': API().getArtwork(item, "tvshow.poster") ,
-                       'banner'       : API().getArtwork(item, "Banner") ,
-                       'clearlogo'    : API().getArtwork(item, "Logo") ,
-                       'discart'      : API().getArtwork(item, "Disc") ,
-                       'clearart'     : API().getArtwork(item, "Art") ,
-                       'landscape'    : API().getArtwork(item, "Thumb") ,
-                       'id'           : id ,
-                       'rating'       : item.get("CommunityRating"),
-                       'year'         : item.get("ProductionYear"),
-                       'premieredate' : premieredate,
-                       'genre'        : genre,
-                       'playcount'    : str(playCount),
-                       'itemtype'     : item_type}
-                       
-            if extraData['thumb'] == '':
-                extraData['thumb'] = extraData['fanart_image']
-                
-            liz = xbmcgui.ListItem(tempTitle)
-
-            artTypes=['poster', 'tvshow.poster', 'fanart_image', 'clearlogo', 'discart', 'banner', 'clearart', 'landscape', 'small_poster', 'tiny_poster', 'medium_poster','small_fanartimage', 'medium_fanartimage', 'medium_landscape', 'fanart_noindicators']
-            
-            for artType in artTypes:
-                imagePath=str(extraData.get(artType,''))
-                liz=PlaybackUtils().setArt(liz,artType, imagePath)
-            
-            liz.setThumbnailImage(API().getArtwork(item, "Primary"))
-            liz.setIconImage('DefaultTVShows.png')
-            #liz.setInfo( type="Video", infoLabels={ "Rating": item.get("CommunityRating") })
-            #liz.setInfo( type="Video", infoLabels={ "Plot": item.get("Overview") })
-            
-            if type=="Channel":
-                file = _addon_url + "?id=%s&mode=channels"%id
-                xbmcplugin.addDirectoryItem(handle=_addon_id, url=file, listitem=liz, isFolder=True)
-            
-            elif isFolder == True:
-                file = _addon_url + "?id=%s&mode=channelsfolder&folderid=%s" %(channelId, id)
-                xbmcplugin.addDirectoryItem(handle=_addon_id, url=file, listitem=liz, isFolder=True)
-            else:
-                file = _addon_url + "?id=%s&mode=play"%id
-                liz.setProperty('IsPlayable', 'true')
-                xbmcplugin.addDirectoryItem(handle=_addon_id, url=file, listitem=liz)
-
-    xbmcplugin.endOfDirectory(handle=int(sys.argv[1]))
-
-##### GET NEXTUP EPISODES FOR TAGNAME #####    
-def getNextUpEpisodes(tagname,limit):
-    count=0
-
-    #if the addon is called with nextup parameter, we return the nextepisodes list of the given tagname
-    xbmcplugin.setContent(int(sys.argv[1]), 'episodes')
-    # First we get a list of all the in-progress TV shows - filtered by tag
-    json_query_string = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetTVShows", "params": { "sort": { "order": "descending", "method": "lastplayed" }, "filter": {"and": [{"operator":"true", "field":"inprogress", "value":""}, {"operator": "is", "field": "tag", "value": "%s"}]}, "properties": [ "title", "studio", "mpaa", "file", "art" ]  }, "id": "libTvShows"}' %tagname)
-    
-    json_result = json.loads(json_query_string)
-    # If we found any, find the oldest unwatched show for each one.
-    if json_result.has_key('result') and json_result['result'].has_key('tvshows'):
-        for item in json_result['result']['tvshows']:
-
-            # If Ignore Specials is true only choose episodes from seasons greater than 0.
-            if utils.settings("ignoreSpecialsNextEpisodes")=="true":
-                json_query2 = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetEpisodes", "params": { "tvshowid": %d, "sort": {"method":"episode"}, "filter": {"and": [ {"field": "playcount", "operator": "lessthan", "value":"1"}, {"field": "season", "operator": "greaterthan", "value": "0"} ]}, "properties": [ "title", "playcount", "season", "episode", "showtitle", "plot", "file", "rating", "resume", "tvshowid", "art", "streamdetails", "firstaired", "runtime", "writer", "dateadded", "lastplayed" ], "limits":{"end":1}}, "id": "1"}' %item['tvshowid'])
-            else:
-                json_query2 = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetEpisodes", "params": { "tvshowid": %d, "sort": {"method":"episode"}, "filter": {"field": "playcount", "operator": "lessthan", "value":"1"}, "properties": [ "title", "playcount", "season", "episode", "showtitle", "plot", "file", "rating", "resume", "tvshowid", "art", "streamdetails", "firstaired", "runtime", "writer", "dateadded", "lastplayed" ], "limits":{"end":1}}, "id": "1"}' %item['tvshowid'])
-
-            if json_query2:
-                json_query2 = json.loads(json_query2)
-                if json_query2.has_key('result') and json_query2['result'].has_key('episodes'):
-                    for item in json_query2['result']['episodes']:
-                        liz = createListItem(item)
-                        xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=item['file'], listitem=liz)
-                        count +=1
-            if count == limit:
-                break
-    xbmcplugin.endOfDirectory(handle=int(sys.argv[1]))
-
-def getInProgressEpisodes(tagname,limit):
-    count = 0
-    #if the addon is called with inprogressepisodes parameter, we return the inprogressepisodes list of the given tagname
-    xbmcplugin.setContent(int(sys.argv[1]), 'episodes')
-    # First we get a list of all the in-progress TV shows - filtered by tag
-    json_query_string = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetTVShows", "params": { "sort": { "order": "descending", "method": "lastplayed" }, "filter": {"and": [{"operator":"true", "field":"inprogress", "value":""}, {"operator": "contains", "field": "tag", "value": "%s"}]}, "properties": [ "title", "studio", "mpaa", "file", "art" ]  }, "id": "libTvShows"}' %tagname)
-    json_result = json.loads(json_query_string)
-    # If we found any, find all in progress episodes for each one.
-    if json_result.has_key('result') and json_result['result'].has_key('tvshows'):
-        for item in json_result['result']['tvshows']:
-            json_query2 = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetEpisodes", "params": { "tvshowid": %d, "sort": {"method":"episode"}, "filter": {"field": "inprogress", "operator": "true", "value":""}, "properties": [ "title", "playcount", "season", "episode", "showtitle", "plot", "file", "rating", "resume", "tvshowid", "art", "cast", "streamdetails", "firstaired", "runtime", "writer", "dateadded", "lastplayed" ]}, "id": "1"}' %item['tvshowid'])
-
-            if json_query2:
-                json_query2 = json.loads(json_query2)
-                if json_query2.has_key('result') and json_query2['result'].has_key('episodes'):
-                    for item in json_query2['result']['episodes']:
-                        liz = createListItem(item)
-                        xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=item['file'], listitem=liz)
-                        count +=1
-            if count == limit:
-                break
-    xbmcplugin.endOfDirectory(handle=int(sys.argv[1]))
-
-def getRecentEpisodes(tagname,limit):
-    #if the addon is called with recentepisodes parameter, we return the recentepisodes list of the given tagname
-    xbmcplugin.setContent(int(sys.argv[1]), 'episodes')
-    # First we get a list of all the TV shows - filtered by tag
-    json_query_string = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetTVShows", "params": { "sort": { "order": "descending", "method": "dateadded" }, "properties": [ "title","sorttitle" ], "filter": {"operator": "contains", "field": "tag", "value": "%s"} }, "id": "libTvShows"}' %tagname)    
-    json_result = json.loads(json_query_string)
-    
-    # If we found any, put all tv show id's in a list
-    if json_result.has_key('result') and json_result['result'].has_key('tvshows'):
-        alltvshowIds = list()
-        for tvshow in json_result['result']['tvshows']:
-            alltvshowIds.append(tvshow["tvshowid"])
-        alltvshowIds = set(alltvshowIds)
-        
-        #get all recently added episodes
-        json_query2 = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetEpisodes", "params": { "sort": {"order": "descending", "method": "dateadded"}, "filter": {"field": "playcount", "operator": "lessthan", "value":"1"}, "properties": [ "title", "playcount", "season", "episode", "showtitle", "plot", "file", "rating", "resume", "tvshowid", "art", "streamdetails", "firstaired", "runtime", "cast", "writer", "dateadded", "lastplayed" ]}, "limits":{"end":%d}, "id": "1"}' %limit)
-        count = 0
-        if json_query2:
-            json_query2 = json.loads(json_query2)
-            if json_query2.has_key('result') and json_query2['result'].has_key('episodes'):
-                for item in json_query2['result']['episodes']:
-                    if item["tvshowid"] in alltvshowIds:
-                        liz = createListItem(item)
-                        xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=item['file'], listitem=liz)
-                        count += 1
-                    if count == limit:
-                        break
-    xbmcplugin.endOfDirectory(handle=int(sys.argv[1]))
-    
-def createListItem(item):
-       
-    liz = xbmcgui.ListItem(item['title'])
-    liz.setInfo( type="Video", infoLabels={ "Title": item['title'] })
-    liz.setProperty('IsPlayable', 'true')
-    liz.setInfo( type="Video", infoLabels={ "duration": str(item['runtime']/60) })
-    
-    if "episode" in item:
-        episode = "%.2d" % float(item['episode'])
-        liz.setInfo( type="Video", infoLabels={ "Episode": item['episode'] })
-    
-    if "season" in item:
-        season = "%.2d" % float(item['season'])
-        liz.setInfo( type="Video", infoLabels={ "Season": item['season'] })
-        
-    if season and episode:
-        episodeno = "s%se%s" %(season,episode)
-        liz.setProperty("episodeno", episodeno)
-        
-    if "firstaired" in item:
-        liz.setInfo( type="Video", infoLabels={ "Premiered": item['firstaired'] })
-    
-    plot = item['plot']
-    liz.setInfo( type="Video", infoLabels={ "Plot": plot })
-    
-    if "showtitle" in item:
-        liz.setInfo( type="Video", infoLabels={ "TVshowTitle": item['showtitle'] })
-    
-    if "rating" in item:
-        liz.setInfo( type="Video", infoLabels={ "Rating": str(round(float(item['rating']),1)) })
-    liz.setInfo( type="Video", infoLabels={ "Playcount": item['playcount'] })
-    if "director" in item:
-        liz.setInfo( type="Video", infoLabels={ "Director": " / ".join(item['director']) })
-    if "writer" in item:
-        liz.setInfo( type="Video", infoLabels={ "Writer": " / ".join(item['writer']) })
-        
-    if "cast" in item:
-        listCast = []
-        listCastAndRole = []
-        for castmember in item["cast"]:
-            listCast.append( castmember["name"] )
-            listCastAndRole.append( (castmember["name"], castmember["role"]) ) 
-        cast = [listCast, listCastAndRole]
-        liz.setInfo( type="Video", infoLabels={ "Cast": cast[0] })
-        liz.setInfo( type="Video", infoLabels={ "CastAndRole": cast[1] })
-    
-    liz.setProperty("resumetime", str(item['resume']['position']))
-    liz.setProperty("totaltime", str(item['resume']['total']))
-    liz.setArt(item['art'])
-    liz.setThumbnailImage(item['art'].get('thumb',''))
-    liz.setIconImage('DefaultTVShows.png')
-    liz.setProperty("dbid", str(item['episodeid']))
-    liz.setProperty("fanart_image", item['art'].get('tvshow.fanart',''))
-    for key, value in item['streamdetails'].iteritems():
-        for stream in value:
-            liz.addStreamInfo( key, stream )
-    
-    return liz
-    
-##### GET EXTRAFANART FOR LISTITEM #####
-def getExtraFanArt():
-    itemPath = ""
-    embyId = ""
-    
-    #get extrafanart for listitem - this will only be used for skins that actually call the listitem's path + fanart dir... 
-    try:
-        #only do this if the listitem has actually changed
-        itemPath = xbmc.getInfoLabel("ListItem.FileNameAndPath")
-            
-        if not itemPath:
-            itemPath = xbmc.getInfoLabel("ListItem.Path")
-        
-        if ("/tvshows/" in itemPath or "/musicvideos/" in itemPath or "/movies/" in itemPath):
-            embyId = itemPath.split("/")[-2]
-            
-            utils.logMsg("%s %s" % ("Emby addon", "getExtraFanArt"), "requesting extraFanArt for Id: " + embyId, 1)
-
-            #we need to store the images locally for this to work because of the caching system in xbmc
-            fanartDir = xbmc.translatePath("special://thumbnails/emby/" + embyId + "/")
-            
-            if not xbmcvfs.exists(fanartDir):
-                #download the images to the cache directory
-                xbmcvfs.mkdir(fanartDir)
-                item = ReadEmbyDB().getFullItem(embyId)
-                if item != None:
-                    if item.has_key("BackdropImageTags"):
-                        if(len(item["BackdropImageTags"]) > 0):
-                            WINDOW = xbmcgui.Window(10000)
-                            username = WINDOW.getProperty('currUser')
-                            server = WINDOW.getProperty('server%s' % username)
-                            totalbackdrops = len(item["BackdropImageTags"])
-                            count = 0
-                            for backdrop in item["BackdropImageTags"]: 
-                                backgroundUrl = "%s/mediabrowser/Items/%s/Images/Backdrop/%s/?MaxWidth=10000&MaxHeight=10000&Format=original&Tag=%s&EnableImageEnhancers=false" % (server, embyId, str(count), backdrop)
-                                count += 1
-                                fanartFile = os.path.join(fanartDir,"fanart" + backdrop + ".jpg")
-                                li = xbmcgui.ListItem(backdrop, path=fanartFile)
-                                xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=fanartFile, listitem=li)
-                                xbmcvfs.copy(backgroundUrl,fanartFile) 
-                
-            else:
-                #use existing cached images
-                dirs, files = xbmcvfs.listdir(fanartDir)
-                count = 1
-                for file in files:
-                    count +=1
-                    li = xbmcgui.ListItem(file, path=os.path.join(fanartDir,file))
-                    xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=os.path.join(fanartDir,file), listitem=li)
-    except Exception as e:
-        utils.logMsg("%s %s" % ("Emby addon", "Error in getExtraFanArt"), str(e), 1)
-        pass
-    
-    #always do endofdirectory to prevent errors in the logs
-    xbmcplugin.endOfDirectory(int(sys.argv[1]))
-
-def addDirectoryItem(label, path, folder=True):
-    li = xbmcgui.ListItem(label, path=path)
-    li.setThumbnailImage("special://home/addons/plugin.video.emby/icon.png")
-    li.setArt({"fanart":"special://home/addons/plugin.video.emby/fanart.jpg"})
-    li.setArt({"landscape":"special://home/addons/plugin.video.emby/fanart.jpg"})
-    xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=path, listitem=li, isFolder=folder)    
-    
-# if the addon is called without parameters we show the listing...    
-def doMainListing():
-    
-    xbmcplugin.setContent(int(sys.argv[1]), 'files')    
-    #get emby nodes from the window props
-    embyProperty = WINDOW.getProperty("Emby.nodes.total")
-    if embyProperty:
-        totalNodes = int(embyProperty)
-        for i in range(totalNodes):
-            path = WINDOW.getProperty("Emby.nodes.%s.index" %str(i))
-            if not path:
-                path = WINDOW.getProperty("Emby.nodes.%s.content" %str(i))
-            label = WINDOW.getProperty("Emby.nodes.%s.title" %str(i))
-            if path:
-                addDirectoryItem(label, path)
-    
-    # some extra entries for settings and stuff. TODO --> localize the labels
-    addDirectoryItem("Settings", "plugin://plugin.video.emby/?mode=settings")
-    addDirectoryItem("Perform manual sync", "plugin://plugin.video.emby/?mode=manualsync")
-    addDirectoryItem("Add user to session", "plugin://plugin.video.emby/?mode=adduser")
-    addDirectoryItem("Configure user preferences", "plugin://plugin.video.emby/?mode=userprefs")
-    addDirectoryItem("Perform local database reset (full resync)", "plugin://plugin.video.emby/?mode=reset")
-    addDirectoryItem("Cache all images to Kodi texture cache (advanced)", "plugin://plugin.video.emby/?mode=texturecache")
-    addDirectoryItem("Sync Emby Theme Media to Kodi", "plugin://plugin.video.emby/?mode=thememedia")
-    
-    xbmcplugin.endOfDirectory(int(sys.argv[1]))
\ No newline at end of file
diff --git a/resources/lib/KodiMonitor.py b/resources/lib/KodiMonitor.py
deleted file mode 100644
index 2d4dc943..00000000
--- a/resources/lib/KodiMonitor.py
+++ /dev/null
@@ -1,150 +0,0 @@
-#################################################################################################
-# Kodi  Monitor
-# Watched events that occur in Kodi, like setting media watched
-#################################################################################################
-
-import xbmc
-import xbmcgui
-import xbmcaddon
-import json
-
-import Utils as utils
-from WriteKodiVideoDB import WriteKodiVideoDB
-from ReadKodiDB import ReadKodiDB
-from PlayUtils import PlayUtils
-from DownloadUtils import DownloadUtils
-from PlaybackUtils import PlaybackUtils
-
-
-class Kodi_Monitor( xbmc.Monitor ):
-    
-    WINDOW = xbmcgui.Window(10000)
-
-    def __init__(self, *args, **kwargs):
-        xbmc.Monitor.__init__(self)
-
-    def logMsg(self, msg, lvl = 1):
-
-        className = self.__class__.__name__
-        utils.logMsg("%s %s" % ("EMBY", className), msg, int(lvl))
-
-    def onScanStarted(self, library):
-        utils.window('kodiScan', value="true")
-        self.logMsg("Kodi library scan running.", 2)
-
-    def onScanFinished(self, library):
-        utils.window('kodiScan', clear=True)
-        self.logMsg("Kodi library scan finished.", 2)
-        
-    #this library monitor is used to detect a watchedstate change by the user through the library
-    #as well as detect when a library item has been deleted to pass the delete to the Emby server
-    def onNotification  (self, sender, method, data):
-
-        WINDOW = self.WINDOW
-        downloadUtils = DownloadUtils()
-        #player started playing an item - 
-        if ("Playlist.OnAdd" in method or "Player.OnPlay" in method):
-
-            jsondata = json.loads(data)
-            if jsondata:
-                if jsondata.has_key("item"):
-                    if jsondata.get("item").has_key("id") and jsondata.get("item").has_key("type"):
-                        id = jsondata.get("item").get("id")
-                        type = jsondata.get("item").get("type")
-                        
-                        if (utils.settings('useDirectPaths')=='true' and not type == "song") or (type == "song" and utils.settings('enableMusicSync') == "true"):
-                            
-                            if type == "song":
-                                connection = utils.KodiSQL('music')
-                                cursor = connection.cursor()
-                                embyid = ReadKodiDB().getEmbyIdByKodiId(id, type, connection, cursor)
-                                cursor.close()
-                            else:    
-                                embyid = ReadKodiDB().getEmbyIdByKodiId(id,type)
-
-                            if embyid:
-
-                                url = "{server}/mediabrowser/Users/{UserId}/Items/%s?format=json" % embyid
-                                result = downloadUtils.downloadUrl(url)
-                                self.logMsg("Result: %s" % result, 2)
-                                
-                                playurl = None
-                                count = 0
-                                while not playurl and count < 2:
-                                    try:
-                                        playurl = xbmc.Player().getPlayingFile()
-                                    except RuntimeError:
-                                        xbmc.sleep(200)
-                                    else:
-                                        listItem = xbmcgui.ListItem()
-                                        PlaybackUtils().setProperties(playurl, result, listItem)
-
-                                        if type == "song" and utils.settings('directstreammusic') == "true":
-                                            utils.window('%splaymethod' % playurl, value="DirectStream")
-                                        else:
-                                            utils.window('%splaymethod' % playurl, value="DirectPlay")
-
-                                    count += 1
-        
-        if method == "VideoLibrary.OnUpdate":
-            # Triggers 4 times, the following is only for manually marking as watched/unwatched
-            jsondata = json.loads(data)
-            
-            try:
-                playcount = jsondata.get('playcount')
-                item = jsondata['item']['id']
-                type = jsondata['item']['type']
-                prop = utils.window('Played%s%s' % (type, item))
-            except:
-                self.logMsg("Could not process VideoLibrary.OnUpdate data.", 1)
-            else:
-                self.logMsg("VideoLibrary.OnUpdate: %s" % data, 2)
-                if prop != "true":
-                    # Set property to prevent the multi triggering
-                    utils.window('Played%s%s' % (type, item), "true")
-                    WriteKodiVideoDB().updatePlayCountFromKodi(item, type, playcount)
-
-                self.clearProperty(type, item)
-                    
-        if method == "System.OnWake":
-            xbmc.sleep(10000) #Allow network to wake up
-            WINDOW.setProperty("OnWakeSync", "true")
-
-        if method == "VideoLibrary.OnRemove":
-            xbmc.log('Intercepted remove from sender: ' + sender + ' method: ' + method + ' data: ' + data)
-            jsondata = json.loads(data)
-            id = ReadKodiDB().getEmbyIdByKodiId(jsondata.get("id"), jsondata.get("type"))
-            if id == None:
-                return            
-            xbmc.log("Deleting Emby ID: " + id + " from database")
-            connection = utils.KodiSQL()
-            cursor = connection.cursor()
-            cursor.execute("DELETE FROM emby WHERE emby_id = ?", (id,))
-            connection.commit()
-            cursor.close
-            
-            if jsondata:
-                if jsondata.get("type") == "episode" or "movie":
-                    url='{server}/mediabrowser/Items?Ids=' + id + '&format=json'
-                    #This is a check to see if the item exists on the server, if it doesn't it may have already been deleted by another client
-                    result = DownloadUtils().downloadUrl(url)
-                    item = result.get("Items")[0]
-                    if data:
-                        return_value = xbmcgui.Dialog().yesno("Confirm Delete", "Delete file on Emby Server?")
-                        if return_value:
-                            url='{server}/mediabrowser/Items/' + id
-                            xbmc.log('Deleting via URL: ' + url)
-                            DownloadUtils().downloadUrl(url, type="DELETE")
-
-        elif method == "Playlist.OnClear":
-            self.logMsg("Clear playback properties.", 2)
-            utils.window('propertiesPlayback', clear=True)
-                            
-    def clearProperty(self, type, id):
-        # The sleep is necessary since VideoLibrary.OnUpdate
-        # triggers 4 times in a row.
-        xbmc.sleep(100)
-        utils.window('Played%s%s' % (type,id), clear=True)
-            
-        # Clear the widget cache
-        utils.window('clearwidgetcache', value="clear")
\ No newline at end of file
diff --git a/resources/lib/LibrarySync.py b/resources/lib/LibrarySync.py
deleted file mode 100644
index f50c88e2..00000000
--- a/resources/lib/LibrarySync.py
+++ /dev/null
@@ -1,1191 +0,0 @@
-#################################################################################################
-# LibrarySync
-#################################################################################################
-
-import xbmc
-import xbmcgui
-import xbmcaddon
-import xbmcvfs
-import json
-import sqlite3
-import inspect
-import threading
-import urllib
-from datetime import datetime, timedelta, time
-from itertools import chain
-import urllib2
-import os
-
-import KodiMonitor
-from API import API
-import Utils as utils
-from ClientInformation import ClientInformation
-from DownloadUtils import DownloadUtils
-from ReadEmbyDB import ReadEmbyDB
-from ReadKodiDB import ReadKodiDB
-from WriteKodiVideoDB import WriteKodiVideoDB
-from WriteKodiMusicDB import WriteKodiMusicDB
-from VideoNodes import VideoNodes
-
-addondir = xbmc.translatePath(xbmcaddon.Addon(id='plugin.video.emby').getAddonInfo('profile'))
-dataPath = os.path.join(addondir,"library")
-movieLibrary = os.path.join(dataPath,'movies')
-tvLibrary = os.path.join(dataPath,'tvshows')
-
-WINDOW = xbmcgui.Window( 10000 )
-
-class LibrarySync(threading.Thread):
-
-    _shared_state = {}
-
-    KodiMonitor = KodiMonitor.Kodi_Monitor()
-    clientInfo = ClientInformation()
-
-    addonName = clientInfo.getAddonName()
-
-    updateItems = []
-    userdataItems = []
-    removeItems = []
-    forceUpdate = False
-
-    def __init__(self, *args):
-
-        self.__dict__ = self._shared_state
-        threading.Thread.__init__(self, *args)
-
-    def logMsg(self, msg, lvl=1):
-
-        className = self.__class__.__name__
-        utils.logMsg("%s %s" % (self.addonName, className), msg, int(lvl))
-        
-    def FullLibrarySync(self,manualRun=False):
-        
-        startupDone = WINDOW.getProperty("startup") == "done"
-        syncInstallRunDone = utils.settings("SyncInstallRunDone") == "true"
-        performMusicSync = utils.settings("enableMusicSync") == "true"
-        dbSyncIndication = utils.settings("dbSyncIndication") == "true"
-
-        ### BUILD VIDEO NODES LISTING ###
-        VideoNodes().buildVideoNodesListing()
-        ### CREATE SOURCES ###
-        if utils.settings("Sources") != "true":
-            # Only create sources once
-            self.logMsg("Sources.xml created.", 0)
-            utils.createSources()
-            utils.settings("Sources", "true")  
-        
-        # just do a incremental sync if that is what is required
-        if(utils.settings("useIncSync") == "true" and utils.settings("SyncInstallRunDone") == "true") and manualRun == False:
-            utils.logMsg("Sync Database", "Using incremental sync instead of full sync useIncSync=True)", 0)
-            
-            du = DownloadUtils()
-            
-            lastSync = utils.settings("LastIncrenetalSync")
-            if(lastSync == None or len(lastSync) == 0):
-                lastSync = "2010-01-01T00:00:00Z"
-            utils.logMsg("Sync Database", "Incremental Sync Setting Last Run Time Loaded : " + lastSync, 0)
-
-            lastSync = urllib2.quote(lastSync)
-            
-            url = "{server}/Emby.Kodi.SyncQueue/{UserId}/GetItems?LastUpdateDT=" + lastSync + "&format=json"
-            utils.logMsg("Sync Database", "Incremental Sync Get Items URL : " + url, 0)
-            
-            try:
-                results = du.downloadUrl(url)
-                changedItems = results["ItemsUpdated"] + results["ItemsAdded"]
-                removedItems = results["ItemsRemoved"]
-                userChanges = results["UserDataChanged"]                
-            except:
-                utils.logMsg("Sync Database", "Incremental Sync Get Changes Failed", 0)
-                pass
-            else:
-                maxItems = int(utils.settings("incSyncMaxItems"))
-                utils.logMsg("Sync Database", "Incremental Sync Changes : " + str(results), 0)
-                if(len(changedItems) < maxItems and len(removedItems) < maxItems and len(userChanges) < maxItems):
-                
-                    WINDOW.setProperty("startup", "done")
-                    
-                    LibrarySync().remove_items(removedItems)
-                    LibrarySync().update_items(changedItems)
-                    LibrarySync().user_data_update(userChanges)
-                    
-                    return True
-                else:
-                    utils.logMsg("Sync Database", "Too Many For Incremental Sync (" + str(maxItems) + "), changedItems" + str(len(changedItems)) + " removedItems:" + str(len(removedItems)) + " userChanges:" + str(len(userChanges)), 0)
-        
-        #set some variable to check if this is the first run
-        WINDOW.setProperty("SyncDatabaseRunning", "true")     
-        
-        #show the progress dialog
-        pDialog = None
-        if (syncInstallRunDone == False or dbSyncIndication or manualRun):
-            pDialog = xbmcgui.DialogProgressBG()
-            pDialog.create('Emby for Kodi', 'Performing full sync')
-        
-        if(WINDOW.getProperty("SyncDatabaseShouldStop") ==  "true"):
-            utils.logMsg("Sync Database", "Can not start SyncDatabaseShouldStop=True", 0)
-            return True
-
-        try:
-            completed = True
-                        
-            ### PROCESS VIDEO LIBRARY ###
-            
-            #create the sql connection to video db
-            connection = utils.KodiSQL("video")
-            cursor = connection.cursor()
-            
-            #Add the special emby table
-            cursor.execute("CREATE TABLE IF NOT EXISTS emby(emby_id TEXT, kodi_id INTEGER, media_type TEXT, checksum TEXT, parent_id INTEGER, kodi_file_id INTEGER)")
-            try:
-                cursor.execute("ALTER TABLE emby ADD COLUMN kodi_file_id INTEGER")
-            except: pass
-            self.dbCommit(connection)
-            
-            # sync movies
-            self.MoviesFullSync(connection,cursor,pDialog)
-            
-            if (self.ShouldStop()):
-                return False
-            
-            #sync Tvshows and episodes
-            self.TvShowsFullSync(connection,cursor,pDialog)
-            
-            if (self.ShouldStop()):
-                return False
-                    
-            # sync musicvideos
-            self.MusicVideosFullSync(connection,cursor,pDialog)
-            
-            #close sql connection
-            cursor.close()
-            
-            ### PROCESS MUSIC LIBRARY ###
-            if performMusicSync:
-                #create the sql connection to music db
-                connection = utils.KodiSQL("music")
-                cursor = connection.cursor()
-                
-                #Add the special emby table
-                cursor.execute("CREATE TABLE IF NOT EXISTS emby(emby_id TEXT, kodi_id INTEGER, media_type TEXT, checksum TEXT, parent_id INTEGER, kodi_file_id INTEGER)")
-                try:
-                    cursor.execute("ALTER TABLE emby ADD COLUMN kodi_file_id INTEGER")
-                except: pass
-                self.dbCommit(connection)
-                
-                self.MusicFullSync(connection,cursor,pDialog)
-                cursor.close()
-            
-            # set the install done setting
-            if(syncInstallRunDone == False and completed):
-                utils.settings("SyncInstallRunDone", "true")
-                utils.settings("dbCreatedWithVersion", self.clientInfo.getVersion())    
-            
-            # Commit all DB changes at once and Force refresh the library
-            #xbmc.executebuiltin("UpdateLibrary(video)")
-            #self.updateLibrary("video")
-            #xbmc.executebuiltin("UpdateLibrary(music)")
-            
-            # set prop to show we have run for the first time
-            WINDOW.setProperty("startup", "done")
-            
-            # tell any widgets to refresh because the content has changed
-            WINDOW.setProperty("widgetreload", datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
-            
-            self.SaveLastSync()
-            
-        finally:
-            WINDOW.setProperty("SyncDatabaseRunning", "false")
-            utils.logMsg("Sync DB", "syncDatabase Exiting", 0)
-
-        if(pDialog != None):
-            pDialog.close()
-        
-        return True
-        
-    def SaveLastSync(self):
-        # save last sync time
-
-        du = DownloadUtils()    
-        url = "{server}/Emby.Kodi.SyncQueue/GetServerDateTime?format=json"
-            
-        try:
-            results = du.downloadUrl(url)
-            lastSync = results["ServerDateTime"]
-            self.logMsg("Sync Database, Incremental Sync Using Server Time: %s" % lastSync, 0)
-            lastSync = datetime.strptime(lastSync, "%Y-%m-%dT%H:%M:%SZ")
-            lastSync = (lastSync - timedelta(minutes=5)).strftime('%Y-%m-%dT%H:%M:%SZ')
-            self.logMsg("Sync Database, Incremental Sync Using Server Time -5 min: %s" % lastSync, 0)
-        except:
-            lastSync = (datetime.utcnow() - timedelta(minutes=5)).strftime('%Y-%m-%dT%H:%M:%SZ')
-            self.logMsg("Sync Database, Incremental Sync Using Client Time -5 min: %s" % lastSync, 0)
-            
-        self.logMsg("Sync Database, Incremental Sync Setting Last Run Time Saved: %s" % lastSync, 0)
-        utils.settings("LastIncrenetalSync", lastSync)
-
-    def MoviesFullSync(self,connection, cursor, pDialog):
-               
-        views = ReadEmbyDB().getCollections("movies")
-        
-        allKodiMovieIds = list()
-        allEmbyMovieIds = list()
-        
-        for view in views:
-            
-            allEmbyMovies = ReadEmbyDB().getMovies(view.get('id'))
-            allKodiMovies = ReadKodiDB().getKodiMovies(connection, cursor)
-            
-            for kodimovie in allKodiMovies:
-                allKodiMovieIds.append(kodimovie[1])
-            
-            title = view.get('title')
-            content = view.get('content')
-
-            if content == "mixed":
-                title = "%s - Movies" % title
-            
-            for kodimovie in allKodiMovies:
-                allKodiMovieIds.append(kodimovie[1])
-            
-            total = len(allEmbyMovies) + 1
-            count = 1
-            
-            #### PROCESS ADDS AND UPDATES ###
-            for item in allEmbyMovies:
-                
-                if (self.ShouldStop()):
-                    return False
-                
-                if not item.get('IsFolder'):                    
-                    allEmbyMovieIds.append(item["Id"])
-                    
-                    if(pDialog != None):
-                        progressTitle = "Processing " + view.get('title') + " (" + str(count) + " of " + str(total) + ")"
-                        percentage = int(((float(count) / float(total)) * 100))
-                        pDialog.update(percentage, "Emby for Kodi - Running Sync", progressTitle)
-                        count += 1        
-                    
-                    kodiMovie = None
-                    for kodimovie in allKodiMovies:
-                        if kodimovie[1] == item["Id"]:
-                            kodiMovie = kodimovie
-                          
-                    if kodiMovie == None:
-                        WriteKodiVideoDB().addOrUpdateMovieToKodiLibrary(item["Id"],connection, cursor, title)
-                    else:
-                        if kodiMovie[2] != API().getChecksum(item):
-                            WriteKodiVideoDB().addOrUpdateMovieToKodiLibrary(item["Id"],connection, cursor, title)
-          
-          
-       
-        #### PROCESS BOX SETS #####
-        utils.logMsg("Sync Movies", "BoxSet Sync Started", 1)
-        boxsets = ReadEmbyDB().getBoxSets()
-            
-        total = len(boxsets) + 1
-        count = 1
-        for boxset in boxsets:
-            if(pDialog != None):
-                progressTitle = "Processing BoxSets" + " (" + str(count) + " of " + str(total-1) + ")"
-                percentage = int(((float(count) / float(total)) * 100))
-                pDialog.update(percentage, "Emby for Kodi - Running Sync", progressTitle)
-                count += 1
-            if(self.ShouldStop()):
-                return False                
-            boxsetMovies = ReadEmbyDB().getMoviesInBoxSet(boxset["Id"])
-            WriteKodiVideoDB().addBoxsetToKodiLibrary(boxset, connection, cursor)
-                
-            WriteKodiVideoDB().removeMoviesFromBoxset(boxset, connection, cursor)
-            for boxsetMovie in boxsetMovies:
-                if(self.ShouldStop()):
-                    return False
-                WriteKodiVideoDB().updateBoxsetToKodiLibrary(boxsetMovie,boxset, connection, cursor)
-                    
-        utils.logMsg("Sync Movies", "BoxSet Sync Finished", 1)
-            
-        #### PROCESS DELETES #####
-        allEmbyMovieIds = set(allEmbyMovieIds)
-        for kodiId in allKodiMovieIds:
-            if not kodiId in allEmbyMovieIds:
-                WINDOW.setProperty(kodiId,"deleted")
-                WriteKodiVideoDB().deleteItemFromKodiLibrary(kodiId, connection, cursor)
-                
-        ### commit all changes to database ###
-        self.dbCommit(connection)
-
-    def MusicVideosFullSync(self,connection,cursor, pDialog):
-               
-        allKodiMusicvideoIds = list()
-        allEmbyMusicvideoIds = list()
-            
-        allEmbyMusicvideos = ReadEmbyDB().getMusicVideos()
-        allKodiMusicvideos = ReadKodiDB().getKodiMusicVideos(connection, cursor)
-        
-        for kodivideo in allKodiMusicvideos:
-            allKodiMusicvideoIds.append(kodivideo[1])
-        
-        total = len(allEmbyMusicvideos) + 1
-        count = 1
-        
-        #### PROCESS ADDS AND UPDATES ###
-        for item in allEmbyMusicvideos:
-            
-            if (self.ShouldStop()):
-                return False
-            
-            if not item.get('IsFolder'):                    
-                allEmbyMusicvideoIds.append(item["Id"])
-                
-                if(pDialog != None):
-                    progressTitle = "Processing MusicVideos (" + str(count) + " of " + str(total) + ")"
-                    percentage = int(((float(count) / float(total)) * 100))
-                    pDialog.update(percentage, "Emby for Kodi - Running Sync", progressTitle)
-                    count += 1        
-                
-                kodiVideo = None
-                for kodivideo in allKodiMusicvideos:
-                    if kodivideo[1] == item["Id"]:
-                        kodiVideo = kodivideo
-                      
-                if kodiVideo == None:
-                    WriteKodiVideoDB().addOrUpdateMusicVideoToKodiLibrary(item["Id"],connection, cursor)
-                else:
-                    if kodiVideo[2] != API().getChecksum(item):
-                        WriteKodiVideoDB().addOrUpdateMusicVideoToKodiLibrary(item["Id"],connection, cursor)
-            
-        #### PROCESS DELETES #####
-        allEmbyMusicvideoIds = set(allEmbyMusicvideoIds)
-        for kodiId in allKodiMusicvideoIds:
-            if not kodiId in allEmbyMusicvideoIds:
-                WINDOW.setProperty(kodiId,"deleted")
-                WriteKodiVideoDB().deleteItemFromKodiLibrary(kodiId, connection, cursor)
-                
-        ### commit all changes to database ###
-        self.dbCommit(connection)
-    
-    def TvShowsFullSync(self,connection,cursor,pDialog):
-               
-        views = ReadEmbyDB().getCollections("tvshows")
-        
-        allKodiTvShowIds = list()
-        allEmbyTvShowIds = list()
-                
-        for view in views:
-            
-            allEmbyTvShows = ReadEmbyDB().getTvShows(view.get('id'))
-            allKodiTvShows = ReadKodiDB().getKodiTvShows(connection, cursor)
-            
-            title = view.get('title')
-            content = view.get('content')
-
-            if content == "mixed":
-                title = "%s - TV Shows" % title
-            
-            total = len(allEmbyTvShows) + 1
-            count = 1
-            
-            for kodishow in allKodiTvShows:
-                allKodiTvShowIds.append(kodishow[1])
-            
-            #### TVSHOW: PROCESS ADDS AND UPDATES ###
-            for item in allEmbyTvShows:
-                
-                if (self.ShouldStop()):
-                    return False
-                
-                if(pDialog != None):
-                    progressTitle = "Processing " + view.get('title') + " (" + str(count) + " of " + str(total) + ")"
-                    percentage = int(((float(count) / float(total)) * 100))
-                    pDialog.update(percentage, "Emby for Kodi - Running Sync", progressTitle)
-                    count += 1                   
-
-                if utils.settings('syncEmptyShows') == "true" or (item.get('IsFolder') and item.get('RecursiveItemCount') != 0):
-                    allEmbyTvShowIds.append(item["Id"])
-                    
-                    #build a list with all Id's and get the existing entry (if exists) in Kodi DB
-                    kodiShow = None
-                    for kodishow in allKodiTvShows:
-                        if kodishow[1] == item["Id"]:
-                            kodiShow = kodishow
-                          
-                    if kodiShow == None:
-                        # Tv show doesn't exist in Kodi yet so proceed and add it
-                        WriteKodiVideoDB().addOrUpdateTvShowToKodiLibrary(item["Id"],connection, cursor, title)
-                    else:
-                        # If there are changes to the item, perform a full sync of the item
-                        if kodiShow[2] != API().getChecksum(item):
-                            WriteKodiVideoDB().addOrUpdateTvShowToKodiLibrary(item["Id"],connection, cursor, title)
-                            
-                    #### PROCESS EPISODES ######
-                    self.EpisodesFullSync(connection,cursor,item["Id"])
-            
-        #### TVSHOW: PROCESS DELETES #####
-        allEmbyTvShowIds = set(allEmbyTvShowIds)
-        for kodiId in allKodiTvShowIds:
-            if not kodiId in allEmbyTvShowIds:
-                WINDOW.setProperty(kodiId,"deleted")
-                WriteKodiVideoDB().deleteItemFromKodiLibrary(kodiId, connection, cursor)
-                
-        ### commit all changes to database ###
-        self.dbCommit(connection)
-         
-    def EpisodesFullSync(self,connection,cursor,showId):
-        
-        WINDOW = xbmcgui.Window( 10000 )
-        
-        allKodiEpisodeIds = list()
-        allEmbyEpisodeIds = list()
-        
-        # Get the kodi parent id
-        cursor.execute("SELECT kodi_id FROM emby WHERE emby_id=?",(showId,))
-        try:
-            kodiShowId = cursor.fetchone()[0]
-        except:
-            self.logMsg("Unable to find show itemId:%s" % showId, 1)
-            return
-        
-        allEmbyEpisodes = ReadEmbyDB().getEpisodes(showId)
-        allKodiEpisodes = ReadKodiDB().getKodiEpisodes(connection, cursor, kodiShowId)
-        
-        for kodiepisode in allKodiEpisodes:
-            allKodiEpisodeIds.append(kodiepisode[1])
-
-        #### EPISODES: PROCESS ADDS AND UPDATES ###
-        for item in allEmbyEpisodes:
-            
-            if (self.ShouldStop()):
-                    return False    
-            
-            allEmbyEpisodeIds.append(item["Id"])
-            
-            #get the existing entry (if exists) in Kodi DB
-            kodiEpisode = None
-            for kodiepisode in allKodiEpisodes:
-                if kodiepisode[1] == item["Id"]:
-                    kodiEpisode = kodiepisode
-                  
-            if kodiEpisode == None:
-                # Episode doesn't exist in Kodi yet so proceed and add it
-                WriteKodiVideoDB().addOrUpdateEpisodeToKodiLibrary(item["Id"], kodiShowId, connection, cursor)
-            else:
-                # If there are changes to the item, perform a full sync of the item
-                if kodiEpisode[2] != API().getChecksum(item):
-                    WriteKodiVideoDB().addOrUpdateEpisodeToKodiLibrary(item["Id"], kodiShowId, connection, cursor)
-        
-        #### EPISODES: PROCESS DELETES #####
-        allEmbyEpisodeIds = set(allEmbyEpisodeIds)
-        for kodiId in allKodiEpisodeIds:
-            if (not kodiId in allEmbyEpisodeIds):
-                WINDOW.setProperty(kodiId,"deleted")
-                WriteKodiVideoDB().deleteItemFromKodiLibrary(kodiId, connection, cursor)
-                
-    def MusicFullSync(self, connection,cursor, pDialog):
-
-        self.ProcessMusicArtists(connection,cursor,pDialog)
-        self.dbCommit(connection)
-        self.ProcessMusicAlbums(connection,cursor,pDialog)
-        self.dbCommit(connection)
-        self.ProcessMusicSongs(connection,cursor,pDialog)
-        
-        ### commit all changes to database ###
-        self.dbCommit(connection)
-    
-    def ProcessMusicSongs(self,connection,cursor,pDialog):
-               
-        allKodiSongIds = list()
-        allEmbySongIds = list()
-        
-        allEmbySongs = ReadEmbyDB().getMusicSongsTotal()
-        allKodiSongs = ReadKodiDB().getKodiMusicSongs(connection, cursor)
-        
-        for kodisong in allKodiSongs:
-            allKodiSongIds.append(kodisong[1])
-            
-        total = len(allEmbySongs) + 1
-        count = 1    
-        
-        #### PROCESS SONGS ADDS AND UPDATES ###
-        for item in allEmbySongs:
-            
-            if (self.ShouldStop()):
-                return False
-                             
-            allEmbySongIds.append(item["Id"])
-            
-            if(pDialog != None):
-                progressTitle = "Processing Music Songs (" + str(count) + " of " + str(total) + ")"
-                percentage = int(((float(count) / float(total)) * 100))
-                pDialog.update(percentage, "Emby for Kodi - Running Sync", progressTitle)
-                count += 1        
-            
-            kodiSong = None
-            for kodisong in allKodiSongs:
-                if kodisong[1] == item["Id"]:
-                    kodiSong = kodisong
-                  
-            if kodiSong == None:
-                WriteKodiMusicDB().addOrUpdateSongToKodiLibrary(item,connection, cursor)
-            else:
-                if kodiSong[2] != API().getChecksum(item):
-                    WriteKodiMusicDB().addOrUpdateSongToKodiLibrary(item,connection, cursor)
-        
-        #### PROCESS DELETES #####
-        allEmbySongIds = set(allEmbySongIds)
-        for kodiId in allKodiSongIds:
-            if not kodiId in allEmbySongIds:
-                WINDOW.setProperty(kodiId,"deleted")
-                WriteKodiMusicDB().deleteItemFromKodiLibrary(kodiId, connection, cursor)
-        
-    def ProcessMusicArtists(self,connection,cursor,pDialog):
-               
-        allKodiArtistIds = list()
-        allEmbyArtistIds = list()
-        
-        allEmbyArtists = ReadEmbyDB().getMusicArtistsTotal()
-        allKodiArtists = ReadKodiDB().getKodiMusicArtists(connection, cursor)
-        
-        for kodiartist in allKodiArtists:
-            allKodiArtistIds.append(kodiartist[1])
-            
-        total = len(allEmbyArtists) + 1
-        count = 1    
-        
-        #### PROCESS ARTIST ADDS AND UPDATES ###
-        for item in allEmbyArtists:
-            
-            if (self.ShouldStop()):
-                return False
-                             
-            allEmbyArtistIds.append(item["Id"])
-            
-            if(pDialog != None):
-                progressTitle = "Processing Music Artists (" + str(count) + " of " + str(total) + ")"
-                percentage = int(((float(count) / float(total)) * 100))
-                pDialog.update(percentage, "Emby for Kodi - Running Sync", progressTitle)
-                count += 1        
-            
-            kodiArtist = None
-            for kodiartist in allKodiArtists:
-                if kodiartist[1] == item["Id"]:
-                    kodiArtist = kodiartist
-                  
-            if kodiArtist == None:
-                WriteKodiMusicDB().addOrUpdateArtistToKodiLibrary(item,connection, cursor)
-            else:
-                if kodiArtist[2] != API().getChecksum(item):
-                    WriteKodiMusicDB().addOrUpdateArtistToKodiLibrary(item,connection, cursor)
-        
-        #### PROCESS DELETES #####
-        allEmbyArtistIds = set(allEmbyArtistIds)
-        for kodiId in allKodiArtistIds:
-            if not kodiId in allEmbyArtistIds:
-                WINDOW.setProperty(kodiId,"deleted")
-                WriteKodiMusicDB().deleteItemFromKodiLibrary(kodiId, connection, cursor)
-    
-    def ProcessMusicAlbums(self,connection,cursor,pDialog):
-               
-        allKodiAlbumIds = list()
-        allEmbyAlbumIds = list()
-        
-        allEmbyAlbums = ReadEmbyDB().getMusicAlbumsTotal()
-        allKodiAlbums = ReadKodiDB().getKodiMusicAlbums(connection, cursor)
-        
-        for kodialbum in allKodiAlbums:
-            allKodiAlbumIds.append(kodialbum[1])
-            
-        total = len(allEmbyAlbums) + 1
-        count = 1    
-        
-        #### PROCESS SONGS ADDS AND UPDATES ###
-        for item in allEmbyAlbums:
-            
-            if (self.ShouldStop()):
-                return False
-                             
-            allEmbyAlbumIds.append(item["Id"])
-            
-            if(pDialog != None):
-                progressTitle = "Processing Music Albums (" + str(count) + " of " + str(total) + ")"
-                percentage = int(((float(count) / float(total)) * 100))
-                pDialog.update(percentage, "Emby for Kodi - Running Sync", progressTitle)
-                count += 1        
-            
-            kodiAlbum = None
-            for kodialbum in allKodiAlbums:
-                if kodialbum[1] == item["Id"]:
-                    kodiAlbum = kodialbum
-                  
-            if kodiAlbum == None:
-                WriteKodiMusicDB().addOrUpdateAlbumToKodiLibrary(item,connection, cursor)
-            else:
-                if kodiAlbum[2] != API().getChecksum(item):
-                    WriteKodiMusicDB().addOrUpdateAlbumToKodiLibrary(item,connection, cursor)
-        
-        #### PROCESS DELETES #####
-        allEmbyAlbumIds = set(allEmbyAlbumIds)
-        for kodiId in allKodiAlbumIds:
-            if not kodiId in allEmbyAlbumIds:
-                WINDOW.setProperty(kodiId,"deleted")
-                WriteKodiMusicDB().deleteItemFromKodiLibrary(kodiId, connection, cursor)
-    
-    def IncrementalSync(self, itemList):
-        
-        startupDone = WINDOW.getProperty("startup") == "done"
-        
-        #only perform incremental scan when full scan is completed 
-        if startupDone:
-        
-            #this will only perform sync for items received by the websocket
-            dbSyncIndication = utils.settings("dbSyncIndication") == "true"
-            performMusicSync = utils.settings("enableMusicSync") == "true"
-            WINDOW.setProperty("SyncDatabaseRunning", "true")
-            
-            #show the progress dialog               
-            pDialog = None
-            if (dbSyncIndication and xbmc.Player().isPlaying() == False):
-                pDialog = xbmcgui.DialogProgressBG()
-                pDialog.create('Emby for Kodi', 'Incremental Sync')
-                self.logMsg("Doing LibraryChanged : Show Progress IncrementalSync()", 0);
-            
-            connection = utils.KodiSQL("video")
-            cursor = connection.cursor()
-            
-            try:
-                #### PROCESS MOVIES ####
-                views = ReadEmbyDB().getCollections("movies")
-                for view in views:
-                    allEmbyMovies = ReadEmbyDB().getMovies(view.get('id'), itemList)
-                    count = 1
-                    total = len(allEmbyMovies) + 1
-                    for item in allEmbyMovies:
-                        if(pDialog != None):
-                            progressTitle = "Incremental Sync "+ " (" + str(count) + " of " + str(total) + ")"
-                            percentage = int(((float(count) / float(total)) * 100))
-                            pDialog.update(percentage, "Emby for Kodi - Incremental Sync Movies", progressTitle)
-                            count = count + 1
-                        if not item.get('IsFolder'):
-                            WriteKodiVideoDB().addOrUpdateMovieToKodiLibrary(item["Id"],connection, cursor, view.get('title'))
-                            
-                #### PROCESS BOX SETS #####
-                boxsets = ReadEmbyDB().getBoxSets()
-                count = 1
-                total = len(boxsets) + 1
-                for boxset in boxsets:
-                    if(boxset["Id"] in itemList):
-                        utils.logMsg("IncrementalSync", "Updating box Set : " + str(boxset["Name"]), 1)
-                        boxsetMovies = ReadEmbyDB().getMoviesInBoxSet(boxset["Id"])
-                        WriteKodiVideoDB().addBoxsetToKodiLibrary(boxset, connection, cursor)
-                        if(pDialog != None):
-                            progressTitle = "Incremental Sync "+ " (" + str(count) + " of " + str(total) + ")"
-                            percentage = int(((float(count) / float(total)) * 100))
-                            pDialog.update(percentage, "Emby for Kodi - Incremental Sync BoxSet", progressTitle)
-                            count = count + 1
-                        WriteKodiVideoDB().removeMoviesFromBoxset(boxset, connection, cursor)
-                        for boxsetMovie in boxsetMovies:
-                            WriteKodiVideoDB().updateBoxsetToKodiLibrary(boxsetMovie, boxset, connection, cursor)      
-                    else:
-                        utils.logMsg("IncrementalSync", "Skipping Box Set : " + boxset["Name"], 1)
-                        
-                #### PROCESS TV SHOWS ####
-                views = ReadEmbyDB().getCollections("tvshows")              
-                for view in views:
-                    allEmbyTvShows = ReadEmbyDB().getTvShows(view.get('id'),itemList)
-                    count = 1
-                    total = len(allEmbyTvShows) + 1
-                    for item in allEmbyTvShows:
-                        if(pDialog != None):
-                            progressTitle = "Incremental Sync "+ " (" + str(count) + " of " + str(total) + ")"
-                            percentage = int(((float(count) / float(total)) * 100))
-                            pDialog.update(percentage, "Emby for Kodi - Incremental Sync Tv", progressTitle)
-                            count = count + 1                    
-                        if utils.settings('syncEmptyShows') == "true" or (item.get('IsFolder') and item.get('RecursiveItemCount') != 0):
-                            kodiId = WriteKodiVideoDB().addOrUpdateTvShowToKodiLibrary(item["Id"],connection, cursor, view.get('title'))
-                
-                
-                #### PROCESS OTHERS BY THE ITEMLIST ######
-                count = 1
-                total = len(itemList) + 1
-                for item in itemList:
-                        
-                    if(pDialog != None):
-                        progressTitle = "Incremental Sync "+ " (" + str(count) + " of " + str(total) + ")"
-                        percentage = int(((float(count) / float(total)) * 100))
-                        pDialog.update(percentage, "Emby for Kodi - Incremental Sync Items", progressTitle)
-                        count = count + 1                           
-                        
-                    MBitem = ReadEmbyDB().getItem(item)
-                    itemType = MBitem.get('Type', "")
-
-                    #### PROCESS EPISODES ######
-                    if "Episode" in itemType:
-
-                        #get the tv show
-                        cursor.execute("SELECT kodi_id FROM emby WHERE media_type='tvshow' AND emby_id=?", (MBitem.get("SeriesId"),))
-                        result = cursor.fetchone()
-                        if result:
-                            kodi_show_id = result[0]
-                        else:
-                            kodi_show_id = None
-
-                        if kodi_show_id:
-                            WriteKodiVideoDB().addOrUpdateEpisodeToKodiLibrary(MBitem["Id"], kodi_show_id, connection, cursor)
-                        else:
-                            #tv show doesn't exist
-                            #perform full tvshow sync instead so both the show and episodes get added
-                            self.TvShowsFullSync(connection,cursor,None)
-
-                    elif "Season" in itemType:
-
-                        #get the tv show
-                        cursor.execute("SELECT kodi_id FROM emby WHERE media_type='tvshow' AND emby_id=?", (MBitem.get("SeriesId"),))
-                        result = cursor.fetchone()
-                        if result:
-                            kodi_show_id = result[0]
-                            # update season
-                            WriteKodiVideoDB().updateSeasons(MBitem["SeriesId"], kodi_show_id, connection, cursor)
-                    
-                    #### PROCESS BOXSETS ######
-                    elif "BoxSet" in itemType:
-                        boxsetMovies = ReadEmbyDB().getMoviesInBoxSet(boxset["Id"])
-                        WriteKodiVideoDB().addBoxsetToKodiLibrary(boxset,connection, cursor)
-                        
-                        for boxsetMovie in boxsetMovies:
-                            WriteKodiVideoDB().updateBoxsetToKodiLibrary(boxsetMovie,boxset, connection, cursor)
-
-                    #### PROCESS MUSICVIDEOS ####
-                    elif "MusicVideo" in itemType:
-                        if not MBitem.get('IsFolder'):                    
-                            WriteKodiVideoDB().addOrUpdateMusicVideoToKodiLibrary(MBitem["Id"],connection, cursor)
-                        
-                ### commit all changes to database ###
-                self.dbCommit(connection)
-                cursor.close()
-
-                ### PROCESS MUSIC LIBRARY ###
-                if performMusicSync:
-                    connection = utils.KodiSQL("music")
-                    cursor = connection.cursor()
-                    for item in itemList:
-                        MBitem = ReadEmbyDB().getItem(item)
-                        itemType = MBitem.get('Type', "")
-                        
-                        if "MusicArtist" in itemType:
-                            WriteKodiMusicDB().addOrUpdateArtistToKodiLibrary(MBitem, connection, cursor)
-                        if "MusicAlbum" in itemType:
-                            WriteKodiMusicDB().addOrUpdateAlbumToKodiLibrary(MBitem, connection, cursor)
-                        if "Audio" in itemType:
-                            WriteKodiMusicDB().addOrUpdateSongToKodiLibrary(MBitem, connection, cursor)    
-                    self.dbCommit(connection)
-                    cursor.close()
-
-            finally:
-                if(pDialog != None):
-                    pDialog.close()
-
-                #self.updateLibrary("video")
-                WINDOW.setProperty("SyncDatabaseRunning", "false")
-                # tell any widgets to refresh because the content has changed
-                WINDOW.setProperty("widgetreload", datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
-
-    def removefromDB(self, itemList, deleteEmbyItem = False):
-    
-        dbSyncIndication = utils.settings("dbSyncIndication") == "true"
-    
-        #show the progress dialog               
-        pDialog = None
-        if (dbSyncIndication and xbmc.Player().isPlaying() == False):
-            pDialog = xbmcgui.DialogProgressBG()
-            pDialog.create('Emby for Kodi', 'Incremental Sync')    
-            self.logMsg("Doing LibraryChanged : Show Progress removefromDB()", 0);
-            
-        # Delete from Kodi before Emby
-        # To be able to get mediaType
-        doUtils = DownloadUtils()
-        video = {}
-        music = []
-        
-        # Database connection to myVideosXX.db
-        connectionvideo = utils.KodiSQL()
-        cursorvideo = connectionvideo.cursor()
-        # Database connection to myMusicXX.db
-        connectionmusic = utils.KodiSQL("music")
-        cursormusic = connectionmusic.cursor()
-
-        count = 1
-        total = len(itemList) + 1          
-        for item in itemList:
-        
-            if(pDialog != None):
-                progressTitle = "Incremental Sync "+ " (" + str(count) + " of " + str(total) + ")"
-                percentage = int(((float(count) / float(total)) * 100))
-                pDialog.update(percentage, "Emby for Kodi - Incremental Sync Delete ", progressTitle)
-                count = count + 1   
-                
-            # Sort by type for database deletion
-            try: # Search video database
-                self.logMsg("Check video database.", 1)
-                cursorvideo.execute("SELECT media_type FROM emby WHERE emby_id = ?", (item,))
-                mediatype = cursorvideo.fetchone()[0]
-                video[item] = mediatype
-                #video.append(itemtype)
-            except:
-                self.logMsg("Check music database.", 1)
-                try: # Search music database
-                    cursormusic.execute("SELECT media_type FROM emby WHERE emby_id = ?", (item,))
-                    cursormusic.fetchone()[0]
-                    music.append(item)
-                except: self.logMsg("Item %s is not found in Kodi database." % item, 1)
-
-        if len(video) > 0:
-            connection = connectionvideo
-            cursor = cursorvideo
-            # Process video library
-            count = 1
-            total = len(video) + 1                
-            for item in video:
-
-                if(pDialog != None):
-                    progressTitle = "Incremental Sync "+ " (" + str(count) + " of " + str(total) + ")"
-                    percentage = int(((float(count) / float(total)) * 100))
-                    pDialog.update(percentage, "Emby for Kodi - Incremental Sync Delete ", progressTitle)
-                    count = count + 1   
-                
-                type = video[item]
-                self.logMsg("Doing LibraryChanged: Items Removed: Calling deleteItemFromKodiLibrary: %s" % item, 1)
-
-                if "episode" in type:
-                    # Get the TV Show Id for reference later
-                    showId = ReadKodiDB().getShowIdByEmbyId(item, connection, cursor)
-                    self.logMsg("ShowId: %s" % showId, 1)
-                WriteKodiVideoDB().deleteItemFromKodiLibrary(item, connection, cursor)
-                # Verification
-                if "episode" in type:
-                    showTotalCount = ReadKodiDB().getShowTotalCount(showId, connection, cursor)
-                    self.logMsg("ShowTotalCount: %s" % showTotalCount, 1)
-                    # If there are no episodes left
-                    if showTotalCount == 0 or showTotalCount == None:
-                        # Delete show
-                        embyId = ReadKodiDB().getEmbyIdByKodiId(showId, "tvshow", connection, cursor)
-                        self.logMsg("Message: Doing LibraryChanged: Deleting show: %s" % embyId, 1)
-                        WriteKodiVideoDB().deleteItemFromKodiLibrary(embyId, connection, cursor)
-
-            self.dbCommit(connection)
-        # Close connection
-        cursorvideo.close()
-
-        if len(music) > 0:
-            connection = connectionmusic
-            cursor = cursormusic
-            #Process music library
-            if utils.settings('enableMusicSync') == "true":
-
-                for item in music:
-                    self.logMsg("Message : Doing LibraryChanged : Items Removed : Calling deleteItemFromKodiLibrary (musiclibrary): " + item, 0)
-                    WriteKodiMusicDB().deleteItemFromKodiLibrary(item, connection, cursor)
-
-                self.dbCommit(connection)
-        # Close connection
-        cursormusic.close()
-
-        if deleteEmbyItem:
-            for item in itemList:
-                url = "{server}/mediabrowser/Items/%s" % item
-                self.logMsg('Deleting via URL: %s' % url)
-                doUtils.downloadUrl(url, type = "DELETE")                            
-                xbmc.executebuiltin("Container.Refresh")
-
-        if(pDialog != None):
-            pDialog.close()
-              
-    def setUserdata(self, listItems):
-    
-        dbSyncIndication = utils.settings("dbSyncIndication") == "true"
-        musicenabled = utils.settings('enableMusicSync') == "true"
-    
-        #show the progress dialog               
-        pDialog = None
-        if (dbSyncIndication and xbmc.Player().isPlaying() == False):
-            pDialog = xbmcgui.DialogProgressBG()
-            pDialog.create('Emby for Kodi', 'Incremental Sync')
-            self.logMsg("Doing LibraryChanged : Show Progress setUserdata()", 0);
-
-        # We need to sort between video and music database
-        video = []
-        music = []
-        # Database connection to myVideosXX.db
-        connectionvideo = utils.KodiSQL()
-        cursorvideo = connectionvideo.cursor()
-        # Database connection to myMusicXX.db
-        connectionmusic = utils.KodiSQL('music')
-        cursormusic = connectionmusic.cursor()
-
-        count = 1
-        total = len(listItems) + 1        
-        for userdata in listItems:
-            # Sort between video and music
-            itemId = userdata['ItemId']
-                        
-            if(pDialog != None):
-                progressTitle = "Incremental Sync "+ " (" + str(count) + " of " + str(total) + ")"
-                percentage = int(((float(count) / float(total)) * 100))
-                pDialog.update(percentage, "Emby for Kodi - Incremental Sync User Data ", progressTitle)
-                count = count + 1               
-            
-            cursorvideo.execute("SELECT media_type FROM emby WHERE emby_id = ?", (itemId,))
-            try: # Search video database
-                self.logMsg("Check video database.", 2)
-                mediatype = cursorvideo.fetchone()[0]
-                video.append(userdata)
-            except:
-                if musicenabled:
-                    cursormusic.execute("SELECT media_type FROM emby WHERE emby_id = ?", (itemId,))
-                    try: # Search music database
-                        self.logMsg("Check the music database.", 2)
-                        mediatype = cursormusic.fetchone()[0]
-                        music.append(userdata)
-                    except: self.logMsg("Item %s is not found in Kodi database." % itemId, 1)
-                else:
-                    self.logMsg("Item %s is not found in Kodi database." % itemId, 1)
-
-        if len(video) > 0:
-            connection = connectionvideo
-            cursor = cursorvideo
-            # Process the userdata update for video library
-            count = 1
-            total = len(video) + 1              
-            for userdata in video:
-                if(pDialog != None):
-                    progressTitle = "Incremental Sync "+ " (" + str(count) + " of " + str(total) + ")"
-                    percentage = int(((float(count) / float(total)) * 100))
-                    pDialog.update(percentage, "Emby for Kodi - Incremental Sync User Data ", progressTitle)
-                    count = count + 1
-                WriteKodiVideoDB().updateUserdata(userdata, connection, cursor)
-
-            self.dbCommit(connection)
-            #self.updateLibrary("video")
-        # Close connection
-        cursorvideo.close()
-
-        if len(music) > 0:
-            connection = connectionmusic
-            cursor = cursormusic
-            #Process music library
-            count = 1
-            total = len(video) + 1
-            # Process the userdata update for music library
-            if musicenabled:
-                for userdata in music:
-                    if(pDialog != None):
-                        progressTitle = "Incremental Sync "+ " (" + str(count) + " of " + str(total) + ")"
-                        percentage = int(((float(count) / float(total)) * 100))
-                        pDialog.update(percentage, "Emby for Kodi - Incremental Sync User Data ", progressTitle)
-                        count = count + 1
-                    WriteKodiMusicDB().updateUserdata(userdata, connection, cursor)
-
-                self.dbCommit(connection)
-                #xbmc.executebuiltin("UpdateLibrary(music)")
-        # Close connection
-        cursormusic.close()
-        
-        if(pDialog != None):
-            pDialog.close()
-
-    def remove_items(self, itemsRemoved):
-        # websocket client
-        if(len(itemsRemoved) > 0):
-            self.logMsg("Doing LibraryChanged : Processing Deleted : " + str(itemsRemoved), 0)        
-            self.removeItems.extend(itemsRemoved)
-
-    def update_items(self, itemsToUpdate):
-        # websocket client
-        if(len(itemsToUpdate) > 0):
-            self.logMsg("Doing LibraryChanged : Processing Added and Updated : " + str(itemsToUpdate), 0)
-            self.updateItems.extend(itemsToUpdate)
-            
-    def user_data_update(self, userDataList):
-        # websocket client
-        if(len(userDataList) > 0):
-            self.logMsg("Doing LibraryChanged : Processing User Data Changed : " + str(userDataList), 0)
-            self.userdataItems.extend(userDataList)
-
-    def dbCommit(self, connection):
-        # Central commit, will verify if Kodi database
-        kodidb_scan = utils.window('kodiScan') == "true"
-
-        while kodidb_scan:
-            
-            self.logMsg("Kodi scan running. Waiting...", 1)
-            kodidb_scan = utils.window('kodiScan') == "true"
-
-            if self.KodiMonitor.waitForAbort(1):
-                # Abort was requested while waiting. We should exit
-                self.logMsg("Commit unsuccessful.", 1)
-                break
-        else:
-            connection.commit()
-            self.logMsg("Commit successful.", 1)
-
-    def updateLibrary(self, type):
-
-        self.logMsg("Updating %s library." % type, 1)
-        utils.window('kodiScan', value="true")
-        xbmc.executebuiltin('UpdateLibrary(%s)' % type)
-
-    def ShouldStop(self):
-            
-        if(xbmc.abortRequested):
-            return True
-
-        if(WINDOW.getProperty("SyncDatabaseShouldStop") == "true"):
-            return True
-
-        return False
-        
-    def checkDBVersion(self, currVersion, minVersion):
-        currMajor, currMinor, currPatch = currVersion.split(".")
-        minMajor, minMinor, minPatch = minVersion.split(".")
-        if currMajor > minMajor:
-            return True
-        elif currMajor == minMajor and currMinor > minMinor:
-            return True
-        elif currMajor == minMajor and currMinor == minMinor and currPatch >= minPatch:
-            return True
-        else:
-            return False
-
-    def run(self):
-    
-        try:
-            self.run_internal()
-        except Exception as e:
-            xbmcgui.Dialog().ok("Emby for Kodi", "Library sync thread has crashed!", "You will need to restart Kodi.", "Please report this on the forum, we will need your log.")
-            raise
-
-    def run_internal(self):
-
-        startupComplete = False
-        kodiProfile = xbmc.translatePath("special://profile")
-
-        self.logMsg("--- Starting Library Sync Thread ---", 0)
-
-        while not self.KodiMonitor.abortRequested():
-
-            # In the event the server goes offline after
-            # the thread has already been started.
-            while self.suspendClient == True:
-                # The service.py will change self.suspendClient to False
-                if self.KodiMonitor.waitForAbort(5):
-                    # Abort was requested while waiting. We should exit
-                    break
-
-            # Check if the version of Emby for Kodi the DB was created with is recent enough - controled by Window property set at top of service _INIT_
-            
-            # START TEMPORARY CODE
-            # Only get in here for a while, can be removed later
-            if utils.settings("dbCreatedWithVersion")=="" and utils.settings("SyncInstallRunDone") == "true":
-                self.logMsg("Unknown DB version", 0)
-                return_value = xbmcgui.Dialog().yesno("DB Version", "Can't detect version of Emby for Kodi the DB was created with.\nWas it at least version " + utils.window('minDBVersion') + "?")
-                if return_value == 0:
-                    utils.settings("dbCreatedWithVersion","0.0.0")
-                    self.logMsg("DB version out of date according to user", 0)
-                else:
-                    utils.settings("dbCreatedWithVersion", utils.window('minDBVersion'))   
-                    self.logMsg("DB version okay according to user", 0)                    
-            # END TEMPORARY CODE
-        
-            if (utils.settings("SyncInstallRunDone") == "true" and self.checkDBVersion(utils.settings("dbCreatedWithVersion"), utils.window('minDBVersion'))==False and utils.window('minDBVersionCheck') != "true"):
-                self.logMsg("DB version out of date according to check", 0)
-                return_value = xbmcgui.Dialog().yesno("DB Version", "Detected the DB needs to be recreated for\nthis version of Emby for Kodi.\nProceed?")
-                if return_value == 0:
-                    self.logMsg("DB version out of date !!! USER IGNORED !!!", 0)
-                    xbmcgui.Dialog().ok("Emby for Kodi","Emby for Kodi may not work\ncorrectly until the database is reset.\n")
-                    utils.window('minDBVersionCheck', value="true")
-                else:
-                    utils.reset()
-            
-            # Library sync
-            if not startupComplete:
-                
-                # Verify the database for videos
-                videodb = utils.getKodiVideoDBPath()
-                if not xbmcvfs.exists(videodb):
-                    # Database does not exists.
-                    self.logMsg("The current Kodi version is incompatible with the Emby for Kodi add-on. Please visit here, to see currently supported Kodi versions: https://github.com/MediaBrowser/Emby.Kodi/wiki", 0)
-                    xbmcgui.Dialog().ok("Emby Warning", "Cancelling the database syncing process. Current Kodi version: %s is unsupported. Please verify your logs for more info." % xbmc.getInfoLabel('System.BuildVersion'))
-                    break
-
-                # Run full sync
-                self.logMsg("DB Version: " + utils.settings("dbCreatedWithVersion"), 0)
-                self.logMsg("Doing_Db_Sync: syncDatabase (Started)", 1)
-                startTime = datetime.now()
-                libSync = self.FullLibrarySync()
-                elapsedTime = datetime.now() - startTime
-                self.logMsg("Doing_Db_Sync: syncDatabase (Finished in: %s) %s" % (str(elapsedTime).split('.')[0], libSync), 1)
-
-                if libSync:
-                    startupComplete = True
-
-            # Set via Kodi Monitor event
-            if utils.window('OnWakeSync') == "true" and utils.window('Server_online') == "true":
-                utils.window("OnWakeSync", clear=True)
-                if utils.window("SyncDatabaseRunning") != "true":
-                    self.logMsg("Doing_Db_Sync Post Resume: syncDatabase (Started)", 0)
-                    libSync = self.FullLibrarySync()
-                    self.logMsg("Doing_Db_Sync Post Resume: syncDatabase (Finished) " + str(libSync), 0)
-
-            
-            doSaveLastSync = False
-            
-            if len(self.updateItems) > 0 and utils.window('kodiScan') != "true":
-                # Add or update items
-                self.logMsg("Processing items: %s" % (str(self.updateItems)), 1)
-                listItems = self.updateItems
-                self.updateItems = []
-                self.IncrementalSync(listItems)
-                self.forceUpdate = True
-                doSaveLastSync = True
-
-            if len(self.userdataItems) > 0 and utils.window('kodiScan') != "true":
-                # Process userdata changes only
-                self.logMsg("Processing items: %s" % (str(self.userdataItems)), 1)
-                listItems = self.userdataItems
-                self.userdataItems = []
-                self.setUserdata(listItems)
-                self.forceUpdate = True
-                doSaveLastSync = True
-
-            if len(self.removeItems) > 0 and utils.window('kodiScan') != "true":
-                # Remove item from Kodi library
-                self.logMsg("Removing items: %s" % self.removeItems, 1)
-                listItems = self.removeItems
-                self.removeItems = []
-                self.removefromDB(listItems)
-                self.forceUpdate = True
-                doSaveLastSync = True
-                
-            if doSaveLastSync == True:
-                self.SaveLastSync()
-
-            if self.forceUpdate and not self.updateItems and not self.userdataItems and not self.removeItems:
-                # Force update Kodi library
-                self.forceUpdate = False
-                self.updateLibrary("video")
-
-            if utils.window("kodiProfile_emby") != kodiProfile:
-                # Profile change happened, terminate this thread
-                self.logMsg("Kodi profile was: %s and changed to: %s. Terminating Library thread." % (kodiProfile, utils.window("kodiProfile_emby")), 1)
-                break
-
-            if self.KodiMonitor.waitForAbort(1):
-                # Abort was requested while waiting. We should exit
-                break
-
-        self.logMsg("--- Library Sync Thread stopped ---", 0)
-
-    def suspendClient(self):
-        self.suspendClient = True
-        self.logMsg("--- Library Sync Thread paused ---", 0)
-
-    def resumeClient(self):
-        self.suspendClient = False
-        self.logMsg("--- Library Sync Thread resumed ---", 0)
\ No newline at end of file
diff --git a/resources/lib/PlayUtils.py b/resources/lib/PlayUtils.py
deleted file mode 100644
index e8b9be58..00000000
--- a/resources/lib/PlayUtils.py
+++ /dev/null
@@ -1,364 +0,0 @@
-# -*- coding: utf-8 -*-
-
-#################################################################################################
-
-import xbmc
-import xbmcgui
-import xbmcvfs
-
-from ClientInformation import ClientInformation
-import Utils as utils
-
-#################################################################################################
-
-class PlayUtils():
-
-    clientInfo = ClientInformation()
-    addonName = clientInfo.getAddonName()
-
-    def logMsg(self, msg, lvl=1):
-        
-        className = self.__class__.__name__
-        utils.logMsg("%s %s" % (self.addonName, className), msg, int(lvl))
-
-    def getPlayUrl(self, server, id, result):
-
-        if self.isDirectPlay(result,True):
-            # Try direct play
-            playurl = self.directPlay(result)
-            if playurl:
-                self.logMsg("File is direct playing.", 1)
-                utils.window("%splaymethod" % playurl.encode('utf-8'), value="DirectPlay")
-
-        elif self.isDirectStream(result):
-            # Try direct stream
-            playurl = self.directStream(result, server, id)
-            if playurl:
-                self.logMsg("File is direct streaming.", 1)
-                utils.window("%splaymethod" % playurl, value="DirectStream")
-
-        elif self.isTranscoding(result):
-            # Try transcoding
-            playurl = self.transcoding(result, server, id)
-            if playurl:
-                self.logMsg("File is transcoding.", 1)
-                utils.window("%splaymethod" % playurl, value="Transcode")
-        
-        else: # Error
-            utils.window("playurlFalse", value="true")
-            return
-
-        return playurl.encode('utf-8')
-
-
-    def isDirectPlay(self, result, dialog = False):
-        # Requirements for Direct play:
-        # FileSystem, Accessible path
-        if utils.settings('playFromStream') == "true":
-            # User forcing to play via HTTP instead of SMB
-            self.logMsg("Can't direct play: Play from HTTP is enabled.", 1)
-            return False
-
-        # Avoid H265 1080p
-        if (utils.settings('transcodeH265') == "true" and 
-            result['MediaSources'][0]['Name'].startswith("1080P/H265")):
-            self.logMsg("Option to transcode 1080P/H265 enabled.", 1)
-            return False
-
-        canDirectPlay = result['MediaSources'][0]['SupportsDirectPlay']
-        # Make sure it's supported by server
-        if not canDirectPlay:
-            self.logMsg("Can't direct play: Server does not allow or support it.", 1)
-            return False
-
-        location = result['LocationType']
-        # File needs to be "FileSystem"
-        if 'FileSystem' in location:
-            # Verify if path is accessible
-            if self.fileExists(result):
-                return True
-            else:
-                self.logMsg("Unable to direct play. Verify the following path is accessible by the device: %s. You might also need to add SMB credentials in the add-on settings." % result['MediaSources'][0]['Path'], 1)
-                if dialog:
-                    
-                    failCount = int(utils.settings('directSteamFailedCount'))
-                    self.logMsg("Direct Play failCount: %s." % failCount, 1)
-                    
-                    if failCount < 2:
-                        # Let user know that direct play failed
-                        utils.settings('directSteamFailedCount', value=str(failCount + 1))
-                        xbmcgui.Dialog().notification("Emby server", "Unable to direct play. Verify your log for more information.", icon="special://home/addons/plugin.video.emby/icon.png", sound=False)
-                    elif utils.settings('playFromStream') != "true":
-                        # Permanently set direct stream as true
-                        utils.settings('playFromStream', value="true")
-                        xbmcgui.Dialog().notification("Emby server", "Enabled play from HTTP in add-on settings.", icon="special://home/addons/plugin.video.emby/icon.png", sound=False)
-
-                return False
-
-    def directPlay(self, result):
-
-        try:
-            playurl = result['MediaSources'][0]['Path']
-        except KeyError:
-            playurl = result['Path']
-
-        if 'VideoType' in result:
-            # Specific format modification
-            if 'Dvd' in result['VideoType']:
-                playurl = "%s/VIDEO_TS/VIDEO_TS.IFO" % playurl
-            elif 'BluRay' in result['VideoType']:
-                playurl = "%s/BDMV/index.bdmv" % playurl
-
-        # Network - SMB protocol
-        if "\\\\" in playurl:
-            smbuser = utils.settings('smbusername')
-            smbpass = utils.settings('smbpassword')
-            # Network share
-            if smbuser:
-                playurl = playurl.replace("\\\\", "smb://%s:%s@" % (smbuser, smbpass))
-            else:
-                playurl = playurl.replace("\\\\", "smb://")
-            playurl = playurl.replace("\\", "/")
-            
-        if "apple.com" in playurl:
-            USER_AGENT = "QuickTime/7.7.4"
-            playurl += "?|User-Agent=%s" % USER_AGENT
-
-        return playurl
-
-
-    def isDirectStream(self, result):
-        # Requirements for Direct stream:
-        # FileSystem or Remote, BitRate, supported encoding
-
-        # Avoid H265 1080p
-        if (utils.settings('transcodeH265') == "true" and 
-            result['MediaSources'][0]['Name'].startswith("1080P/H265")):
-            self.logMsg("Option to transcode 1080P/H265 enabled.", 1)
-            return False
-
-        canDirectStream = result['MediaSources'][0]['SupportsDirectStream']
-        # Make sure it's supported by server
-        if not canDirectStream:
-            return False
-
-        location = result['LocationType']
-        # File can be FileSystem or Remote, not Virtual
-        if 'Virtual' in location:
-            self.logMsg("File location is virtual. Can't proceed.", 1)
-            return False
-
-        # Verify BitRate
-        if not self.isNetworkQualitySufficient(result):
-            self.logMsg("The network speed is insufficient to playback the file.", 1)
-            return False
-
-        return True
-  
-    def directStream(self, result, server, id, type = "Video"):
-
-        if result['Path'].endswith('.strm'):
-            # Allow strm loading when direct streaming
-            playurl = self.directPlay(result)
-            return playurl
-        
-        if "ThemeVideo" in type:
-            playurl = "%s/mediabrowser/Videos/%s/stream?static=true" % (server, id)
-
-        elif "Video" in type:
-            playurl = "%s/mediabrowser/Videos/%s/stream?static=true" % (server, id)
-        
-        elif "Audio" in type:
-            playurl = "%s/mediabrowser/Audio/%s/stream.mp3" % (server, id)
-        
-        return playurl
-
-
-    def isTranscoding(self, result):
-        # Last resort, no requirements
-        # BitRate
-        canTranscode = result['MediaSources'][0]['SupportsTranscoding']
-        # Make sure it's supported by server
-        if not canTranscode:
-            return False
-
-        location = result['LocationType']
-        # File can be FileSystem or Remote, not Virtual
-        if 'Virtual' in location:
-            return False
-
-        return True
-
-    def transcoding(self, result, server, id):
-
-        if result['Path'].endswith('.strm'):
-            # Allow strm loading when transcoding
-            playurl = self.directPlay(result)
-            return playurl
-
-        # Play transcoding
-        deviceId = self.clientInfo.getMachineId()
-        playurl = "%s/mediabrowser/Videos/%s/master.m3u8?mediaSourceId=%s" % (server, id, id)
-        playurl = "%s&VideoCodec=h264&AudioCodec=ac3&MaxAudioChannels=6&deviceId=%s&VideoBitrate=%s" % (playurl, deviceId, self.getVideoBitRate()*1000)
-        
-        playurl = self.audioSubsPref(playurl, result.get('MediaSources'))
-        self.logMsg("Playurl: %s" % playurl, 1)
-        
-        return playurl
-        
-
-    def isNetworkQualitySufficient(self, result):
-        # Works out if the network quality can play directly or if transcoding is needed
-        settingsVideoBitRate = self.getVideoBitRate()
-        settingsVideoBitRate = settingsVideoBitRate * 1000
-
-        try:
-            mediaSources = result['MediaSources']
-            sourceBitRate = int(mediaSources[0]['Bitrate'])
-        except KeyError:
-            self.logMsg("Bitrate value is missing.", 1)
-        else:
-            self.logMsg("The video quality selected is: %s, the video bitrate required to direct stream is: %s." % (settingsVideoBitRate, sourceBitRate), 1)
-            if settingsVideoBitRate < sourceBitRate:
-                return False
-        
-        return True
-      
-    def getVideoBitRate(self):
-        # get the addon video quality
-        videoQuality = utils.settings('videoBitRate')
-        bitrate = {
-
-            '0': 664,
-            '1': 996,
-            '2': 1320,
-            '3': 2000,
-            '4': 3200,
-            '5': 4700,
-            '6': 6200,
-            '7': 7700,
-            '8': 9200,
-            '9': 10700,
-            '10': 12200,
-            '11': 13700,
-            '12': 15200,
-            '13': 16700,
-            '14': 18200,
-            '15': 20000,
-            '16': 40000,
-            '17': 100000,
-            '18': 1000000
-        }
-
-        # max bit rate supported by server (max signed 32bit integer)
-        return bitrate.get(videoQuality, 2147483)
-            
-    def fileExists(self, result):
-        
-        if 'Path' not in result:
-            # File has no path in server
-            return False
-
-        # Convert Emby path to a path we can verify
-        path = self.directPlay(result)
-
-        try:
-            pathexists = xbmcvfs.exists(path)
-        except:
-            pathexists = False
-
-        # Verify the device has access to the direct path
-        if pathexists:
-            # Local or Network path
-            self.logMsg("Path exists.", 2)
-            return True
-        elif ":" not in path:
-            # Give benefit of the doubt for nfs.
-            self.logMsg("Can't verify path (assumed NFS). Still try direct play.", 2)
-            return True
-        else:
-            self.logMsg("Path is detected as follow: %s. Try direct streaming." % path, 2)
-            return False
-
-    def audioSubsPref(self, url, mediaSources):
-        # For transcoding only
-        # Present the list of audio to select from
-        audioStreamsList = {}
-        audioStreams = []
-        audioStreamsChannelsList = {}
-        subtitleStreamsList = {}
-        subtitleStreams = ['No subtitles']
-        selectAudioIndex = ""
-        selectSubsIndex = ""
-        playurlprefs = "%s" % url
-
-        mediaStream = mediaSources[0].get('MediaStreams')
-        for stream in mediaStream:
-            # Since Emby returns all possible tracks together, have to sort them.
-            index = stream['Index']
-            type = stream['Type']
-
-            if 'Audio' in type:
-                codec = stream['Codec']
-                channelLayout = stream['ChannelLayout']
-               
-                try:
-                    track = "%s - %s - %s %s" % (index, stream['Language'], codec, channelLayout)
-                except:
-                    track = "%s - %s %s" % (index, codec, channelLayout)
-                
-                audioStreamsChannelsList[index] = stream['Channels']
-                audioStreamsList[track] = index
-                audioStreams.append(track)
-
-            elif 'Subtitle' in type:
-                try:
-                    track = "%s - %s" % (index, stream['Language'])
-                except:
-                    track = "%s - %s" % (index, stream['Codec'])
-
-                default = stream['IsDefault']
-                forced = stream['IsForced']
-                if default:
-                    track = "%s - Default" % track
-                if forced:
-                    track = "%s - Forced" % track
-
-                subtitleStreamsList[track] = index
-                subtitleStreams.append(track)
-
-
-        if len(audioStreams) > 1:
-            resp = xbmcgui.Dialog().select("Choose the audio stream", audioStreams)
-            if resp > -1:
-                # User selected audio
-                selected = audioStreams[resp]
-                selectAudioIndex = audioStreamsList[selected]
-                playurlprefs += "&AudioStreamIndex=%s" % selectAudioIndex
-            else: # User backed out of selection
-                playurlprefs += "&AudioStreamIndex=%s" % mediaSources[0]['DefaultAudioStreamIndex']
-        else: # There's only one audiotrack.
-            selectAudioIndex = audioStreamsList[audioStreams[0]]
-            playurlprefs += "&AudioStreamIndex=%s" % selectAudioIndex
-
-        if len(subtitleStreams) > 1:
-            resp = xbmcgui.Dialog().select("Choose the subtitle stream", subtitleStreams)
-            if resp == 0:
-                # User selected no subtitles
-                pass
-            elif resp > -1:
-                # User selected subtitles
-                selected = subtitleStreams[resp]
-                selectSubsIndex = subtitleStreamsList[selected]
-                playurlprefs += "&SubtitleStreamIndex=%s" % selectSubsIndex
-            else: # User backed out of selection
-                playurlprefs += "&SubtitleStreamIndex=%s" % mediaSources[0].get('DefaultSubtitleStreamIndex', "")
-
-        # Get number of channels for selected audio track
-        audioChannels = audioStreamsChannelsList.get(selectAudioIndex, 0)
-        if audioChannels > 2:
-            playurlprefs += "&AudioBitrate=384000"
-        else:
-            playurlprefs += "&AudioBitrate=192000"
-
-        return playurlprefs
\ No newline at end of file
diff --git a/resources/lib/PlaybackUtils.py b/resources/lib/PlaybackUtils.py
deleted file mode 100644
index 1172e52b..00000000
--- a/resources/lib/PlaybackUtils.py
+++ /dev/null
@@ -1,462 +0,0 @@
-# -*- coding: utf-8 -*-
-
-#################################################################################################
-
-import datetime
-import json as json
-import sys
-
-import xbmc
-import xbmcaddon
-import xbmcplugin
-import xbmcgui
-
-from API import API
-from DownloadUtils import DownloadUtils
-from PlayUtils import PlayUtils
-from ClientInformation import ClientInformation
-import Utils as utils
-
-#################################################################################################
-
-class PlaybackUtils():
-    
-    clientInfo = ClientInformation()
-    doUtils = DownloadUtils()
-    api = API()
-
-    addon = xbmcaddon.Addon()
-    language = addon.getLocalizedString
-    addonName = clientInfo.getAddonName()
-
-    def logMsg(self, msg, lvl=1):
-        
-        className = self.__class__.__name__
-        utils.logMsg("%s %s" % (self.addonName, className), msg, int(lvl))
-
-    def PLAY(self, result, setup = "service"):
-
-        self.logMsg("PLAY Called", 1)
-
-        api = self.api
-        doUtils = self.doUtils
-        username = utils.window('currUser')
-        server = utils.window('server%s' % username)
-
-        id = result['Id']
-        userdata = result['UserData']
-        # Get the playurl - direct play, direct stream or transcoding
-        playurl = PlayUtils().getPlayUrl(server, id, result)
-        listItem = xbmcgui.ListItem()
-
-        if utils.window('playurlFalse') == "true":
-            # Playurl failed - set in PlayUtils.py
-            utils.window('playurlFalse', clear=True)
-            self.logMsg("Failed to retrieve the playback path/url or dialog was cancelled.", 1)
-            return xbmcplugin.setResolvedUrl(int(sys.argv[1]), False, listItem)
-
-        
-        ############### -- SETUP MAIN ITEM ################
-            
-        # Set listitem and properties for main item
-        self.logMsg("Returned playurl: %s" % playurl, 1)
-        listItem.setPath(playurl)
-        self.setProperties(playurl, result, listItem)
-
-        mainArt = API().getArtwork(result, "Primary")
-        listItem.setThumbnailImage(mainArt)
-        listItem.setIconImage(mainArt)
-        
-
-        ############### ORGANIZE CURRENT PLAYLIST ################
-        
-        homeScreen = xbmc.getCondVisibility('Window.IsActive(home)')
-        playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO)
-        startPos = max(playlist.getposition(), 0) # Can return -1
-        sizePlaylist = playlist.size()
-
-        propertiesPlayback = utils.window('propertiesPlayback') == "true"
-        introsPlaylist = False
-        dummyPlaylist = False
-        currentPosition = startPos
-
-        self.logMsg("Playlist start position: %s" % startPos, 2)
-        self.logMsg("Playlist plugin position: %s" % currentPosition, 2)
-        self.logMsg("Playlist size: %s" % sizePlaylist, 2)
-
-
-        ############### RESUME POINT ################
-        
-        # Resume point for widget only
-        timeInfo = api.getTimeInfo(result)
-        jumpBackSec = int(utils.settings('resumeJumpBack'))
-        seekTime = round(float(timeInfo.get('ResumeTime')), 6)
-        if seekTime > jumpBackSec:
-            # To avoid negative bookmark
-            seekTime = seekTime - jumpBackSec
-
-        # Show the additional resume dialog if launched from a widget
-        if homeScreen and seekTime:
-            # Dialog presentation
-            displayTime = str(datetime.timedelta(seconds=(int(seekTime))))
-            display_list = ["%s %s" % (self.language(30106), displayTime), self.language(30107)]
-            resume_result = xbmcgui.Dialog().select(self.language(30105), display_list)
-
-            if resume_result == 0:
-                # User selected to resume, append resume point to listitem
-                listItem.setProperty('StartOffset', str(seekTime))
-            
-            elif resume_result > 0:
-                # User selected to start from beginning
-                seekTime = 0
-
-            else: # User cancelled the dialog
-                self.logMsg("User cancelled resume dialog.", 1)
-                return xbmcplugin.setResolvedUrl(int(sys.argv[1]), False, listItem)
-
-        # We need to ensure we add the intro and additional parts only once.
-        # Otherwise we get a loop.
-        if not propertiesPlayback:
-
-            utils.window('propertiesPlayback', value="true")
-            self.logMsg("Setting up properties in playlist.")
-            
-            ############### -- CHECK FOR INTROS ################
-
-            if utils.settings('disableCinema') == "false" and not seekTime:
-                # if we have any play them when the movie/show is not being resumed
-                url = "{server}/mediabrowser/Users/{UserId}/Items/%s/Intros?format=json&ImageTypeLimit=1&Fields=Etag" % id    
-                intros = doUtils.downloadUrl(url)
-
-                if intros['TotalRecordCount'] != 0:
-                    getTrailers = True
-
-                    if utils.settings('askCinema') == "true":
-                        resp = xbmcgui.Dialog().yesno("Emby Cinema Mode", "Play trailers?")
-                        if not resp:
-                            # User selected to not play trailers
-                            getTrailers = False
-                            self.logMsg("Skip trailers.", 1)
-                    
-                    if getTrailers:
-                        for intro in intros['Items']:
-                            # The server randomly returns intros, process them.
-                            introId = intro['Id']
-                            
-                            introPlayurl = PlayUtils().getPlayUrl(server, introId, intro)
-                            introListItem = xbmcgui.ListItem()
-                            self.logMsg("Adding Intro: %s" % introPlayurl, 1)
-
-                            # Set listitem and properties for intros
-                            self.setProperties(introPlayurl, intro, introListItem)
-                            self.setListItemProps(server, introId, introListItem, intro)
-                            
-                            playlist.add(introPlayurl, introListItem, index=currentPosition)
-                            introsPlaylist = True
-                            currentPosition += 1
-
-
-            ############### -- ADD MAIN ITEM ONLY FOR HOMESCREEN ###############
-
-            if homeScreen and not sizePlaylist:
-                # Extend our current playlist with the actual item to play only if there's no playlist first
-                self.logMsg("Adding main item to playlist.", 1)
-                self.setListItemProps(server, id, listItem, result)
-                playlist.add(playurl, listItem, index=currentPosition)
-            
-            # Ensure that additional parts are played after the main item
-            currentPosition += 1
-
-
-            ############### -- CHECK FOR ADDITIONAL PARTS ################
-            
-            if result.get('PartCount'):
-                # Only add to the playlist after intros have played
-                partcount = result['PartCount']
-                url = "{server}/mediabrowser/Videos/%s/AdditionalParts" % id
-                parts = doUtils.downloadUrl(url)
-
-                for part in parts['Items']:
-
-                    partId = part['Id']
-                    additionalPlayurl = PlayUtils().getPlayUrl(server, partId, part)
-                    additionalListItem = xbmcgui.ListItem()
-                    self.logMsg("Adding additional part: %s" % partcount, 1)
-
-                    # Set listitem and properties for each additional parts
-                    self.setProperties(additionalPlayurl, part, additionalListItem)
-                    self.setListItemProps(server, partId, additionalListItem, part)
-
-                    playlist.add(additionalPlayurl, additionalListItem, index=currentPosition)
-                    currentPosition += 1
-
-            
-            ############### ADD DUMMY TO PLAYLIST #################
-
-            if (not homeScreen and introsPlaylist) or (homeScreen and sizePlaylist > 0):
-                # Playlist will fail on the current position. Adding dummy url
-                dummyPlaylist = True
-                self.logMsg("Adding dummy url to counter the setResolvedUrl error.", 2)
-                playlist.add(playurl, index=startPos)
-                currentPosition += 1
-                
-
-        # We just skipped adding properties. Reset flag for next time.
-        elif propertiesPlayback:
-            self.logMsg("Resetting properties playback flag.", 2)
-            utils.window('propertiesPlayback', clear=True)
-
-
-        self.verifyPlaylist()
-
-        ############### PLAYBACK ################
-        
-        if not homeScreen and not introsPlaylist:
-            
-            self.logMsg("Processed as a single item.", 1)
-            xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, listItem)
-
-        elif dummyPlaylist:
-            # Added a dummy file to the playlist because the first item is going to fail automatically.
-            self.logMsg("Processed as a playlist. First item is skipped.", 1)
-            xbmcplugin.setResolvedUrl(int(sys.argv[1]), False, listItem)
-
-        else:
-            self.logMsg("Play as a regular item.", 1)
-            xbmc.Player().play(playlist, startpos=startPos)
-
-                
-    def verifyPlaylist(self):
-        
-        playlistitems = '{"jsonrpc": "2.0", "method": "Playlist.GetItems", "params": { "playlistid": 1 }, "id": 1}'
-        items = xbmc.executeJSONRPC(playlistitems)
-        self.logMsg(items, 2)
-
-    def removeFromPlaylist(self, pos):
-
-        playlistremove = '{"jsonrpc": "2.0", "method": "Playlist.Remove", "params": { "playlistid": 1, "position": %d }, "id": 1}' % pos
-        result = xbmc.executeJSONRPC(playlistremove)
-        self.logMsg(result, 1)
-
-
-    def externalSubs(self, id, playurl, mediaSources):
-
-        username = utils.window('currUser')
-        server = utils.window('server%s' % username)
-        externalsubs = []
-        mapping = {}
-
-        mediaStream = mediaSources[0].get('MediaStreams')
-        kodiindex = 0
-        for stream in mediaStream:
-            
-            index = stream['Index']
-            # Since Emby returns all possible tracks together, have to pull only external subtitles.
-            # IsTextSubtitleStream if true, is available to download from emby.
-            if "Subtitle" in stream['Type'] and stream['IsExternal'] and stream['IsTextSubtitleStream']:
-                
-                playmethod = utils.window("%splaymethod" % playurl)
-
-                if "DirectPlay" in playmethod:
-                    # Direct play, get direct path
-                    url = PlayUtils().directPlay(stream)
-                elif "DirectStream" in playmethod: # Direct stream
-                    url = "%s/Videos/%s/%s/Subtitles/%s/Stream.srt" % (server, id, id, index)
-                
-                # map external subtitles for mapping
-                mapping[kodiindex] = index
-                externalsubs.append(url)
-                kodiindex += 1
-        
-        mapping = json.dumps(mapping)
-        utils.window('%sIndexMapping' % playurl, value=mapping)
-
-        return externalsubs
-
-
-    def setProperties(self, playurl, result, listItem):
-        # Set runtimeticks, type, refresh_id and item_id
-        id = result.get('Id')
-        type = result.get('Type', "")
-
-        utils.window("%sruntimeticks" % playurl, value=str(result.get('RunTimeTicks')))
-        utils.window("%stype" % playurl, value=type)
-        utils.window("%sitem_id" % playurl, value=id)
-
-        if type == "Episode":
-            utils.window("%srefresh_id" % playurl, value=result.get('SeriesId'))
-        else:
-            utils.window("%srefresh_id" % playurl, value=id)
-
-        if utils.window("%splaymethod" % playurl) != "Transcode":
-            # Only for direct play and direct stream
-            # Append external subtitles to stream
-            subtitleList = self.externalSubs(id, playurl, result['MediaSources'])
-            listItem.setSubtitles(subtitleList)
-
-    def setArt(self, list, name, path):
-        
-        if name in ("thumb", "fanart_image", "small_poster", "tiny_poster", "medium_landscape", "medium_poster", "small_fanartimage", "medium_fanartimage", "fanart_noindicators"):
-            list.setProperty(name, path)
-        else:
-            list.setArt({name:path})
-        
-        return list
-    
-    def setListItemProps(self, server, id, listItem, result):
-        # Set up item and item info
-        api = self.api
-
-        type = result.get('Type')
-        people = api.getPeople(result)
-        studios = api.getStudios(result)
-
-        metadata = {
-            
-            'title': result.get('Name', "Missing name"),
-            'year': result.get('ProductionYear'),
-            'plot': api.getOverview(result),
-            'director': people.get('Director'),
-            'writer': people.get('Writer'),
-            'mpaa': api.getMpaa(result),
-            'genre': api.getGenre(result),
-            'studio': " / ".join(studios),
-            'aired': api.getPremiereDate(result),
-            'rating': result.get('CommunityRating'),
-            'votes': result.get('VoteCount')
-        }
-
-        if "Episode" in type:
-            # Only for tv shows
-            thumbId = result.get('SeriesId')
-            season = result.get('ParentIndexNumber', -1)
-            episode = result.get('IndexNumber', -1)
-            show = result.get('SeriesName', "")
-
-            metadata['TVShowTitle'] = show
-            metadata['season'] = season
-            metadata['episode'] = episode
-
-        listItem.setProperty('IsPlayable', 'true')
-        listItem.setProperty('IsFolder', 'false')
-        listItem.setLabel(metadata['title'])
-        listItem.setInfo('video', infoLabels=metadata)
-
-        # Set artwork for listitem
-        self.setArt(listItem,'poster', API().getArtwork(result, "Primary"))
-        self.setArt(listItem,'tvshow.poster', API().getArtwork(result, "SeriesPrimary"))
-        self.setArt(listItem,'clearart', API().getArtwork(result, "Art"))
-        self.setArt(listItem,'tvshow.clearart', API().getArtwork(result, "Art"))
-        self.setArt(listItem,'clearlogo', API().getArtwork(result, "Logo"))
-        self.setArt(listItem,'tvshow.clearlogo', API().getArtwork(result, "Logo"))
-        self.setArt(listItem,'discart', API().getArtwork(result, "Disc"))
-        self.setArt(listItem,'fanart_image', API().getArtwork(result, "Backdrop"))
-        self.setArt(listItem,'landscape', API().getArtwork(result, "Thumb"))
-    
-    def seekToPosition(self, seekTo):
-        # Set a loop to wait for positive confirmation of playback
-        count = 0
-        while not xbmc.Player().isPlaying():
-            count += 1
-            if count >= 10:
-                return
-            else:
-                xbmc.sleep(500)
-            
-        # Jump to seek position
-        count = 0
-        while xbmc.Player().getTime() < (seekToTime - 5) and count < 11: # only try 10 times
-            count += 1
-            xbmc.Player().seekTime(seekTo)
-            xbmc.sleep(100)
-    
-    def PLAYAllItems(self, items, startPositionTicks):
-        
-        self.logMsg("== ENTER: PLAYAllItems ==")
-        self.logMsg("Items: %s" % items)
-
-        doUtils = self.doUtils
-
-        playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO)
-        playlist.clear()
-        started = False
-
-        for itemId in items:
-            self.logMsg("Adding Item to playlist: %s" % itemId, 1)
-            url = "{server}/mediabrowser/Users/{UserId}/Items/%s?format=json" % itemId
-            result = doUtils.downloadUrl(url)
-
-            addition = self.addPlaylistItem(playlist, result)
-            if not started and addition:
-                started = True
-                self.logMsg("Starting Playback Pre", 1)
-                xbmc.Player().play(playlist)
-
-        if not started:
-            self.logMsg("Starting Playback Post", 1)
-            xbmc.Player().play(playlist)
-
-        # Seek to position
-        if startPositionTicks:
-            seekTime = startPositionTicks / 10000000.0
-            self.seekToPosition(seekTime)
-    
-    def AddToPlaylist(self, itemIds):
-
-        self.logMsg("== ENTER: PLAYAllItems ==")
-        
-        doUtils = self.doUtils
-        playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO)
-
-        for itemId in itemIds:
-            self.logMsg("Adding Item to Playlist: %s" % itemId)
-            url = "{server}/mediabrowser/Users/{UserId}/Items/%s?format=json" % itemId
-            result = doUtils.downloadUrl(url)
-
-            self.addPlaylistItem(playlist, result)
-        
-        return playlist
-    
-    def addPlaylistItem(self, playlist, item):
-
-        id = item['Id']
-        username = utils.window('currUser')
-        server = utils.window('server%s' % username)
-
-        playurl = PlayUtils().getPlayUrl(server, id, item)
-        
-        if utils.window('playurlFalse') == "true":
-            # Playurl failed - set in PlayUtils.py
-            utils.window('playurlFalse', clear=True)
-            self.logMsg("Failed to retrieve the playback path/url or dialog was cancelled.", 1)
-            return
-
-        self.logMsg("Playurl: %s" % playurl)
-
-        thumb = API().getArtwork(item, "Primary")
-        listItem = xbmcgui.ListItem(path=playurl, iconImage=thumb, thumbnailImage=thumb)
-        self.setListItemProps(server, id, listItem, item)
-        self.setProperties(playurl, item, listItem)
-
-        playlist.add(playurl, listItem)
-
-    # Not currently being used
-    '''def PLAYAllEpisodes(self, items):
-        WINDOW = xbmcgui.Window(10000)
-
-        username = WINDOW.getProperty('currUser')
-        userid = WINDOW.getProperty('userId%s' % username)
-        server = WINDOW.getProperty('server%s' % username)
-        
-        playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO)
-        playlist.clear()        
-        
-        for item in items:
-        
-            item_url = "{server}/mediabrowser/Users/{UserId}/Items/%s?format=json&ImageTypeLimit=1" % item["Id"]
-            jsonData = self.downloadUtils.downloadUrl(item_url)
-            
-            item_data = jsonData
-            self.addPlaylistItem(playlist, item_data, server, userid)
-        
-        xbmc.Player().play(playlist)'''
\ No newline at end of file
diff --git a/resources/lib/Player.py b/resources/lib/Player.py
deleted file mode 100644
index 0b760a88..00000000
--- a/resources/lib/Player.py
+++ /dev/null
@@ -1,440 +0,0 @@
-# -*- coding: utf-8 -*-
-
-#################################################################################################
-
-import json as json
-
-import xbmc
-import xbmcgui
-
-from DownloadUtils import DownloadUtils
-from WebSocketClient import WebSocketThread
-from ClientInformation import ClientInformation
-from LibrarySync import LibrarySync
-import Utils as utils
-
-#################################################################################################
-
-class Player( xbmc.Player ):
-
-    # Borg - multiple instances, shared state
-    _shared_state = {}
-
-    xbmcplayer = xbmc.Player()
-    doUtils = DownloadUtils()
-    clientInfo = ClientInformation()
-    ws = WebSocketThread()
-    librarySync = LibrarySync()
-
-    addonName = clientInfo.getAddonName()
-
-    played_information = {}
-    playStats = {}
-    currentFile = None
-
-    def __init__(self, *args):
-
-        self.__dict__ = self._shared_state
-        self.logMsg("Starting playback monitor.", 2)
-
-    def logMsg(self, msg, lvl=1):
-        
-        self.className = self.__class__.__name__
-        utils.logMsg("%s %s" % (self.addonName, self.className), msg, int(lvl))
-
-    def GetPlayStats(self):
-        return self.playStats
-
-    def onPlayBackStarted( self ):
-        # Will be called when xbmc starts playing a file
-        xbmcplayer = self.xbmcplayer
-        self.stopAll()
-
-        # Get current file
-        try:
-            currentFile = xbmcplayer.getPlayingFile()
-            xbmc.sleep(300)
-        except:
-            currentFile = ""
-            count = 0
-            while not currentFile:
-                xbmc.sleep(100)
-                try:
-                    currentFile = xbmcplayer.getPlayingFile()
-                except: pass
-
-                if count == 5: # try 5 times
-                    self.logMsg("Cancelling playback report...", 1)
-                    break
-                else: count += 1
-
-
-        if currentFile:
-
-            self.currentFile = currentFile
-            
-            # We may need to wait for info to be set in kodi monitor
-            itemId = utils.window("%sitem_id" % currentFile)
-            tryCount = 0
-            while not itemId:
-                
-                xbmc.sleep(200)
-                itemId = utils.window("%sitem_id" % currentFile)
-                if tryCount == 20: # try 20 times or about 10 seconds
-                    self.logMsg("Could not find itemId, cancelling playback report...", 1)
-                    break
-                else: tryCount += 1
-            
-            else:
-                self.logMsg("ONPLAYBACK_STARTED: %s ITEMID: %s" % (currentFile, itemId), 0)
-
-                # Only proceed if an itemId was found.
-                runtime = utils.window("%sruntimeticks" % currentFile)
-                refresh_id = utils.window("%srefresh_id" % currentFile)
-                playMethod = utils.window("%splaymethod" % currentFile)
-                itemType = utils.window("%stype" % currentFile)
-                seekTime = xbmcplayer.getTime()
-
-
-                # Get playback volume
-                volume_query = '{"jsonrpc": "2.0", "method": "Application.GetProperties", "params": {"properties": ["volume","muted"]}, "id": 1}'
-                result = xbmc.executeJSONRPC(volume_query)
-                result = json.loads(result)
-                result = result.get('result')
-
-                volume = result.get('volume')
-                muted = result.get('muted')
-
-                # Postdata structure to send to Emby server
-                url = "{server}/mediabrowser/Sessions/Playing"
-                postdata = {
-
-                    'QueueableMediaTypes': "Video",
-                    'CanSeek': True,
-                    'ItemId': itemId,
-                    'MediaSourceId': itemId,
-                    'PlayMethod': playMethod,
-                    'VolumeLevel': volume,
-                    'PositionTicks': int(seekTime * 10000000),
-                    'IsMuted': muted
-                }
-
-                # Get the current audio track and subtitles
-                if playMethod == "Transcode":
-                    # property set in PlayUtils.py
-                    postdata['AudioStreamIndex'] = utils.window("%sAudioStreamIndex" % currentFile)
-                    postdata['SubtitleStreamIndex'] = utils.window("%sSubtitleStreamIndex" % currentFile)
-
-                else:
-                    # Get the current kodi audio and subtitles and convert to Emby equivalent
-                    track_query = '{"jsonrpc": "2.0", "method": "Player.GetProperties",  "params": {"playerid": 1,"properties": ["currentsubtitle","currentaudiostream","subtitleenabled"]} , "id": 1}'
-                    result = xbmc.executeJSONRPC(track_query)
-                    result = json.loads(result)
-                    result = result.get('result')
-
-                    try: # Audio tracks
-                        indexAudio = result['currentaudiostream']['index']
-                    except (KeyError, TypeError):
-                        indexAudio = 0
-                    
-                    try: # Subtitles tracks
-                        indexSubs = result['currentsubtitle']['index']
-                    except (KeyError, TypeError):
-                        indexSubs = 0
-
-                    try: # If subtitles are enabled
-                        subsEnabled = result['subtitleenabled']
-                    except (KeyError, TypeError):
-                        subsEnabled = ""
-
-                    # Postdata for the audio
-                    postdata['AudioStreamIndex'] = indexAudio + 1
-                    
-                    # Postdata for the subtitles
-                    if subsEnabled and len(xbmc.Player().getAvailableSubtitleStreams()) > 0:
-                        
-                        # Number of audiotracks to help get Emby Index
-                        audioTracks = len(xbmc.Player().getAvailableAudioStreams())
-                        mapping = utils.window("%sIndexMapping" % currentFile)
-
-                        if mapping: # Set in PlaybackUtils.py
-                            
-                            self.logMsg("Mapping for external subtitles index: %s" % mapping, 2)
-                            externalIndex = json.loads(mapping)
-
-                            if externalIndex.get(str(indexSubs)):
-                                # If the current subtitle is in the mapping
-                                postdata['SubtitleStreamIndex'] = externalIndex[str(indexSubs)]
-                            else:
-                                # Internal subtitle currently selected
-                                postdata['SubtitleStreamIndex'] = indexSubs - len(externalIndex) + audioTracks + 1
-                        
-                        else: # Direct paths enabled scenario or no external subtitles set
-                            postdata['SubtitleStreamIndex'] = indexSubs + audioTracks + 1
-                    else:
-                        postdata['SubtitleStreamIndex'] = ""
-                
-
-                # Post playback to server
-                self.logMsg("Sending POST play started: %s." % postdata, 2)
-                self.doUtils.downloadUrl(url, postBody=postdata, type="POST")
-                
-                # Ensure we do have a runtime
-                try:
-                    runtime = int(runtime)
-                except ValueError:
-                    runtime = xbmcplayer.getTotalTime()
-                    self.logMsg("Runtime is missing, grabbing runtime from Kodi player: %s" % runtime, 1)
-
-                # Save data map for updates and position calls
-                data = {
-                    
-                    'runtime': runtime,
-                    'item_id': itemId,
-                    'refresh_id': refresh_id,
-                    'currentfile': currentFile,
-                    'AudioStreamIndex': postdata['AudioStreamIndex'],
-                    'SubtitleStreamIndex': postdata['SubtitleStreamIndex'],
-                    'playmethod': playMethod,
-                    'Type': itemType,
-                    'currentPosition': int(seekTime)
-                }
-                
-                self.played_information[currentFile] = data
-                self.logMsg("ADDING_FILE: %s" % self.played_information, 1)
-
-                # log some playback stats
-                '''if(itemType != None):
-                    if(self.playStats.get(itemType) != None):
-                        count = self.playStats.get(itemType) + 1
-                        self.playStats[itemType] = count
-                    else:
-                        self.playStats[itemType] = 1
-                        
-                if(playMethod != None):
-                    if(self.playStats.get(playMethod) != None):
-                        count = self.playStats.get(playMethod) + 1
-                        self.playStats[playMethod] = count
-                    else:
-                        self.playStats[playMethod] = 1'''
-
-    def reportPlayback(self):
-        
-        self.logMsg("reportPlayback Called", 2)
-        xbmcplayer = self.xbmcplayer
-
-        # Get current file
-        currentFile = self.currentFile
-        data = self.played_information.get(currentFile)
-
-        # only report playback if emby has initiated the playback (item_id has value)
-        if data:
-            # Get playback information
-            itemId = data['item_id']
-            audioindex = data['AudioStreamIndex']
-            subtitleindex = data['SubtitleStreamIndex']
-            playTime = data['currentPosition']
-            playMethod = data['playmethod']
-            paused = data.get('paused', False)
-
-
-            # Get playback volume
-            volume_query = '{"jsonrpc": "2.0", "method": "Application.GetProperties", "params": {"properties": ["volume","muted"]}, "id": 1}'
-            result = xbmc.executeJSONRPC(volume_query)
-            result = json.loads(result)
-            result = result.get('result')
-
-            volume = result.get('volume')
-            muted = result.get('muted')
-
-
-            # Postdata for the websocketclient report
-            postdata = {
-
-                'QueueableMediaTypes': "Video",
-                'CanSeek': True,
-                'ItemId': itemId,
-                'MediaSourceId': itemId,
-                'PlayMethod': playMethod,
-                'PositionTicks': int(playTime * 10000000),
-                'IsPaused': paused,
-                'VolumeLevel': volume,
-                'IsMuted': muted
-            }
-
-            if playMethod == "Transcode":
-                # Track can't be changed, keep reporting the same index
-                postdata['AudioStreamIndex'] = audioindex
-                postdata['AudioStreamIndex'] = subtitleindex
-
-            else:
-                # Get current audio and subtitles track
-                track_query = '{"jsonrpc": "2.0", "method": "Player.GetProperties",  "params": {"playerid":1,"properties": ["currentsubtitle","currentaudiostream","subtitleenabled"]} , "id": 1}'
-                result = xbmc.executeJSONRPC(track_query)
-                result = json.loads(result)
-                result = result.get('result')
-
-                try: # Audio tracks
-                    indexAudio = result['currentaudiostream']['index']
-                except (KeyError, TypeError):
-                    indexAudio = 0
-                
-                try: # Subtitles tracks
-                    indexSubs = result['currentsubtitle']['index']
-                except (KeyError, TypeError):
-                    indexSubs = 0
-
-                try: # If subtitles are enabled
-                    subsEnabled = result['subtitleenabled']
-                except (KeyError, TypeError):
-                    subsEnabled = ""
-
-                # Postdata for the audio
-                data['AudioStreamIndex'], postdata['AudioStreamIndex'] = [indexAudio + 1] * 2
-                
-                # Postdata for the subtitles
-                if subsEnabled and len(xbmc.Player().getAvailableSubtitleStreams()) > 0:
-                    
-                    # Number of audiotracks to help get Emby Index
-                    audioTracks = len(xbmc.Player().getAvailableAudioStreams())
-                    mapping = utils.window("%sIndexMapping" % currentFile)
-
-                    if mapping: # Set in PlaybackUtils.py
-                        
-                        self.logMsg("Mapping for external subtitles index: %s" % mapping, 2)
-                        externalIndex = json.loads(mapping)
-
-                        if externalIndex.get(str(indexSubs)):
-                            # If the current subtitle is in the mapping
-                            data['SubtitleStreamIndex'], postdata['SubtitleStreamIndex'] = [externalIndex[str(indexSubs)]] * 2
-                        else:
-                            # Internal subtitle currently selected
-                            data['SubtitleStreamIndex'], postdata['SubtitleStreamIndex'] = [indexSubs - len(externalIndex) + audioTracks + 1] * 2
-                    
-                    else: # Direct paths enabled scenario or no external subtitles set
-                        data['SubtitleStreamIndex'], postdata['SubtitleStreamIndex'] = [indexSubs + audioTracks + 1] * 2
-                else:
-                    data['SubtitleStreamIndex'], postdata['SubtitleStreamIndex'] = [""] * 2
-
-            # Report progress via websocketclient
-            postdata = json.dumps(postdata)
-            self.logMsg("Report: %s" % postdata, 2)
-            self.ws.sendProgressUpdate(postdata)
-
-    def onPlayBackPaused( self ):
-
-        currentFile = self.currentFile
-        self.logMsg("PLAYBACK_PAUSED: %s" % currentFile, 2)
-
-        if self.played_information.get(currentFile):
-            self.played_information[currentFile]['paused'] = True
-        
-            self.reportPlayback()
-
-    def onPlayBackResumed( self ):
-
-        currentFile = self.currentFile
-        self.logMsg("PLAYBACK_RESUMED: %s" % currentFile, 2)
-
-        if self.played_information.get(currentFile):
-            self.played_information[currentFile]['paused'] = False
-        
-            self.reportPlayback()
-
-    def onPlayBackSeek( self, time, seekOffset ):
-        # Make position when seeking a bit more accurate
-        currentFile = self.currentFile
-        self.logMsg("PLAYBACK_SEEK: %s" % currentFile, 2)
-
-        if self.played_information.get(currentFile):
-            position = self.xbmcplayer.getTime()
-            self.played_information[currentFile]['currentPosition'] = position
-
-            self.reportPlayback()
-    
-    def onPlayBackStopped( self ):
-        # Will be called when user stops xbmc playing a file
-        self.logMsg("ONPLAYBACK_STOPPED", 2)
-        self.stopAll()
-
-    def onPlayBackEnded( self ):
-        # Will be called when xbmc stops playing a file
-        self.logMsg("ONPLAYBACK_ENDED", 2)
-        self.stopAll()
-
-    def stopAll(self):
-
-        if not self.played_information:
-            return 
-            
-        self.logMsg("Played_information: %s" % self.played_information, 1)
-        # Process each items
-        for item in self.played_information:
-            
-            data = self.played_information.get(item)
-            if data:
-                
-                self.logMsg("Item path: %s" % item, 2)
-                self.logMsg("Item data: %s" % data, 2)
-
-                runtime = data['runtime']
-                currentPosition = data['currentPosition']
-                itemId = data['item_id']
-                refresh_id = data['refresh_id']
-                currentFile = data['currentfile']
-                type = data['Type']
-                playMethod = data['playmethod']
-
-                if currentPosition and runtime:
-                    percentComplete = (currentPosition * 10000000) / int(runtime)
-                    markPlayedAt = float(utils.settings('markPlayed')) / 100
-
-                    self.logMsg("Percent complete: %s Mark played at: %s" % (percentComplete, markPlayedAt), 1)
-                    # Prevent manually mark as watched in Kodi monitor > WriteKodiVideoDB().UpdatePlaycountFromKodi()
-                    utils.window('SkipWatched%s' % itemId, "true")
-
-                    self.stopPlayback(data)
-                    offerDelete = utils.settings('offerDelete') == "true"
-                    offerTypeDelete = False
-
-                    if type == "Episode" and utils.settings('offerDeleteTV') == "true":
-                        offerTypeDelete = True
-
-                    elif type == "Movie" and utils.settings('offerDeleteMovies') == "true":
-                        offerTypeDelete = True
-
-                    if percentComplete >= markPlayedAt and offerDelete and offerTypeDelete:
-                        # Make the bigger setting be able to disable option easily.
-                        self.logMsg("Offering deletion for: %s." % itemId, 1)
-                        return_value = xbmcgui.Dialog().yesno("Offer Delete", "Delete %s" % currentFile.split("/")[-1], "on Emby Server?")
-                        if return_value:
-                            # Delete Kodi entry before Emby
-                            listItem = [itemId]
-                            LibrarySync().removefromDB(listItem, True)
-                    
-                # Stop transcoding
-                if playMethod == "Transcode":
-                    self.logMsg("Transcoding for %s terminated." % itemId, 1)
-                    deviceId = self.clientInfo.getMachineId()
-                    url = "{server}/mediabrowser/Videos/ActiveEncodings?DeviceId=%s" % deviceId
-                    self.doUtils.downloadUrl(url, type="DELETE")
-    
-        self.played_information.clear()
-    
-    def stopPlayback(self, data):
-        
-        self.logMsg("stopPlayback called", 2)
-        
-        itemId = data['item_id']
-        currentPosition = data['currentPosition']
-        positionTicks = int(currentPosition * 10000000)
-
-        url = "{server}/mediabrowser/Sessions/Playing/Stopped"
-        postdata = {
-            
-            'ItemId': itemId,
-            'MediaSourceId': itemId,
-            'PositionTicks': positionTicks
-        }
-            
-        self.doUtils.downloadUrl(url, postBody=postdata, type="POST")
\ No newline at end of file
diff --git a/resources/lib/UserClient.py b/resources/lib/UserClient.py
deleted file mode 100644
index f95f9291..00000000
--- a/resources/lib/UserClient.py
+++ /dev/null
@@ -1,460 +0,0 @@
-#################################################################################################
-# UserClient thread
-#################################################################################################
-
-import xbmc
-import xbmcgui
-import xbmcaddon
-import xbmcvfs
-
-import threading
-import hashlib
-import json as json
-
-import KodiMonitor
-import Utils as utils
-from ClientInformation import ClientInformation
-from DownloadUtils import DownloadUtils
-from Player import Player
-from API import API
-
-
-class UserClient(threading.Thread):
-
-    # Borg - multiple instances, shared state
-    _shared_state = {}
-
-    clientInfo = ClientInformation()
-    doUtils = DownloadUtils()
-    KodiMonitor = KodiMonitor.Kodi_Monitor()
-    
-    addonName = clientInfo.getAddonName()
-    addon = xbmcaddon.Addon()
-    WINDOW = xbmcgui.Window(10000)
-
-    stopClient = False
-    logLevel = int(addon.getSetting('logLevel'))
-    auth = True
-    retry = 0
-
-    currUser = None
-    currUserId = None
-    currServer = None
-    currToken = None
-    HasAccess = True
-    AdditionalUser = []
-
-    def __init__(self, *args):
-
-        self.__dict__ = self._shared_state
-        threading.Thread.__init__(self, *args)
-
-    def logMsg(self, msg, lvl=1):
-        
-        className = self.__class__.__name__
-        utils.logMsg("%s %s" % (self.addonName, className), str(msg), int(lvl))
-
-    def getUsername(self):
-
-        username = utils.settings('username')
-
-        if (username == ""):
-            self.logMsg("No username saved.", 2)
-            return ""
-
-        return username
-
-    def getAdditionalUsers(self):
-
-        additionalUsers = utils.settings('additionalUsers')
-        
-        if additionalUsers:
-            self.AdditionalUser = additionalUsers.split(',')
-
-    def getLogLevel(self):
-
-        try:
-            logLevel = int(utils.settings('logLevel'))
-        except:
-            logLevel = 0
-        
-        return logLevel
-
-    def getUserId(self):
-
-        username = self.getUsername()
-        w_userId = self.WINDOW.getProperty('userId%s' % username)
-        s_userId = utils.settings('userId%s' % username)
-
-        # Verify the window property
-        if (w_userId != ""):
-            self.logMsg("Returning userId from WINDOW for username: %s UserId: %s" % (username, w_userId), 2)
-            return w_userId
-        # Verify the settings
-        elif (s_userId != ""):
-            self.logMsg("Returning userId from SETTINGS for username: %s userId: %s" % (username, s_userId), 2)
-            return s_userId
-        # No userId found
-        else:
-            self.logMsg("No userId saved for username: %s." % username)
-            return
-
-    def getServer(self, prefix=True):
-
-        alternate = utils.settings('altip') == "true"
-
-        # For https support
-        HTTPS = utils.settings('https')
-        host = utils.settings('ipaddress')
-        port = utils.settings('port')
-        # Alternate host
-        if alternate:
-            HTTPS = utils.settings('secondhttps')
-            host = utils.settings('secondipaddress')
-            port = utils.settings('secondport')
-            
-        server = host + ":" + port
-        
-        if host == "":
-            self.logMsg("No server information saved.", 2)
-            return ""
-
-        # If https is true
-        if prefix and (HTTPS == "true"):
-            server = "https://%s" % server
-            return server
-        # If https is false
-        elif prefix and (HTTPS == "false"):
-            server = "http://%s" % server
-            return server
-        # If only the host:port is required
-        elif (prefix == False):
-            return server
-
-    def getToken(self):
-
-        username = self.getUsername()
-        w_token = self.WINDOW.getProperty('accessToken%s' % username)
-        s_token = utils.settings('accessToken')
-        
-        # Verify the window property
-        if (w_token != ""):
-            self.logMsg("Returning accessToken from WINDOW for username: %s accessToken: %s" % (username, w_token), 2)
-            return w_token
-        # Verify the settings
-        elif (s_token != ""):
-            self.logMsg("Returning accessToken from SETTINGS for username: %s accessToken: %s" % (username, s_token), 2)
-            self.WINDOW.setProperty('accessToken%s' % username, s_token)
-            return s_token
-        else:
-            self.logMsg("No token found.")
-            return ""
-
-    def getSSLverify(self):
-        # Verify host certificate
-        s_sslverify = utils.settings('sslverify')
-        if utils.settings('altip') == "true":
-            s_sslverify = utils.settings('secondsslverify')
-
-        if s_sslverify == "true":
-            return True
-        else:
-            return False
-
-    def getSSL(self):
-        # Client side certificate
-        s_cert = utils.settings('sslcert')
-        if utils.settings('altip') == "true":
-            s_cert = utils.settings('secondsslcert')
-
-        if s_cert == "None":
-            return None
-        else:
-            return s_cert
-
-    def setUserPref(self):
-
-        player = Player()
-        server = self.getServer()
-        userId = self.getUserId()
-
-        url = "{server}/mediabrowser/Users/{UserId}?format=json"
-        result = self.doUtils.downloadUrl(url)
-
-        # Set user image for skin display
-        self.WINDOW.setProperty("EmbyUserImage",API().getUserArtwork(result,"Primary"))
-
-        # Load the resume point from Emby and set as setting
-        url = "{server}/mediabrowser/System/Configuration?format=json"
-        result = self.doUtils.downloadUrl(url)
-
-        utils.settings('markPlayed', value=str(result['MaxResumePct']))
-
-        return True
-
-    def getPublicUsers(self):
-
-        server = self.getServer()
-
-        # Get public Users
-        url = "%s/mediabrowser/Users/Public?format=json" % server
-        result = self.doUtils.downloadUrl(url, authenticate=False)
-        
-        users = []
-        
-        if (result != ""):
-            users = result
-        else:
-            # Server connection failed
-            return False
-
-        return users
-
-    def hasAccess(self):
-
-        url = "{server}/mediabrowser/Users"
-        result = self.doUtils.downloadUrl(url)
-        
-        if result is False:
-            # Access is restricted
-            self.logMsg("Access is restricted.")
-            self.HasAccess = False
-            return
-        elif self.WINDOW.getProperty('Server_online') != "true":
-            # Server connection failed
-            return
-
-        if self.WINDOW.getProperty("Server_status") == "restricted":
-            self.logMsg("Access is granted.")
-            self.HasAccess = True
-            self.WINDOW.setProperty("Server_status", "")
-            xbmcgui.Dialog().notification("Emby server", "Access is enabled.")
-        return
-
-    def loadCurrUser(self, authenticated=False):
-
-        WINDOW = self.WINDOW
-        doUtils = self.doUtils
-        username = self.getUsername()
-
-        # Only to be used if token exists
-        self.currUserId = self.getUserId()
-        self.currServer = self.getServer()
-        self.currToken = self.getToken()
-        self.ssl = self.getSSLverify()
-        self.sslcert = self.getSSL()
-
-        # Test the validity of current token
-        if authenticated == False:
-            url = "%s/mediabrowser/Users/%s" % (self.currServer, self.currUserId)
-            WINDOW.setProperty("currUser", username)
-            WINDOW.setProperty("accessToken%s" % username, self.currToken)
-            result = doUtils.downloadUrl(url)
-            if result == 401:
-                # Token is no longer valid
-                self.resetClient()
-                return False
-
-        # Set to windows property
-        WINDOW.setProperty("currUser", username)
-        WINDOW.setProperty("accessToken%s" % username, self.currToken)
-        WINDOW.setProperty("server%s" % username, self.currServer)
-        WINDOW.setProperty("server_%s" % username, self.getServer(prefix=False))
-        WINDOW.setProperty("userId%s" % username, self.currUserId)
-
-        # Set DownloadUtils values
-        doUtils.setUsername(username)
-        doUtils.setUserId(self.currUserId)
-        doUtils.setServer(self.currServer)
-        doUtils.setToken(self.currToken)
-        doUtils.setSSL(self.ssl, self.sslcert)
-        # parental control - let's verify if access is restricted
-        self.hasAccess()
-        # Start DownloadUtils session
-        doUtils.startSession()
-        self.getAdditionalUsers()
-
-        self.currUser = username
-        # Set user preferences in settings
-        self.setUserPref()
-
-    def authenticate(self):
-
-        WINDOW = self.WINDOW
-        addon = self.addon
-
-        username = self.getUsername()
-        server = self.getServer()
-        addondir = xbmc.translatePath(self.addon.getAddonInfo('profile')).decode('utf-8')
-        hasSettings   = xbmcvfs.exists("%ssettings.xml" % addondir)
-
-        # If there's no settings.xml
-        if (hasSettings == 0):
-            self.logMsg("No settings.xml found.")
-            self.auth = False
-            return
-        # If no user information
-        if (server == "") or (username == ""):
-            self.logMsg("Missing server information.")
-            self.auth = False
-            return
-        # If there's a token
-        if (self.getToken() != ""):
-            result = self.loadCurrUser()
-
-            if result == False:
-                pass
-            else:
-                self.logMsg("Current user: %s" % self.currUser, 0)
-                self.logMsg("Current userId: %s" % self.currUserId, 0)
-                self.logMsg("Current accessToken: %s" % self.currToken, 0)
-                return
-        
-        users = self.getPublicUsers()
-        password = ""
-        
-        # Find user in list
-        for user in users:
-            name = user[u'Name']
-            userHasPassword = False
-
-            if (unicode(username, 'utf-8') in name):
-                # Verify if user has a password
-                if (user.get("HasPassword") == True):
-                    userHasPassword = True
-                # If user has password
-                if (userHasPassword):
-                    password = xbmcgui.Dialog().input("Enter password for user: %s" % username, option=xbmcgui.ALPHANUM_HIDE_INPUT)
-                    # If password dialog is cancelled
-                    if (password == ""):
-                        self.logMsg("No password entered.", 0)
-                        self.WINDOW.setProperty("Server_status", "Stop")
-                        self.auth = False
-                        return
-                break
-        else:
-            # Manual login, user is hidden
-            password = xbmcgui.Dialog().input("Enter password for user: %s" % username, option=xbmcgui.ALPHANUM_HIDE_INPUT)
-            
-        sha1 = hashlib.sha1(password)
-        sha1 = sha1.hexdigest()    
-
-        # Authenticate username and password
-        url = "%s/mediabrowser/Users/AuthenticateByName?format=json" % server
-        data = {'username': username, 'password': sha1}
-        self.logMsg(data, 2)
-
-        result = self.doUtils.downloadUrl(url, postBody=data, type="POST", authenticate=False)
-
-        accessToken = None
-        try:
-            self.logMsg("Auth_Reponse: %s" % result, 1)
-            accessToken = result[u'AccessToken']
-        except:
-            pass
-
-        if (result != None and accessToken != None):
-            self.currUser = username
-            xbmcgui.Dialog().notification("Emby server", "Welcome %s!" % self.currUser)
-            userId = result[u'User'][u'Id']
-            utils.settings("accessToken", accessToken)
-            utils.settings("userId%s" % username, userId)
-            self.logMsg("User Authenticated: %s" % accessToken)
-            self.loadCurrUser(authenticated=True)
-            self.WINDOW.setProperty("Server_status", "")
-            self.retry = 0
-            return
-        else:
-            self.logMsg("User authentication failed.")
-            utils.settings("accessToken", "")
-            utils.settings("userId%s" % username, "")
-            xbmcgui.Dialog().ok("Error connecting", "Invalid username or password.")
-            
-            # Give two attempts at entering password
-            self.retry += 1
-            if self.retry == 2:
-                self.logMsg("Too many retries. You can retry by selecting the option in the addon settings.")
-                self.WINDOW.setProperty("Server_status", "Stop")
-                xbmcgui.Dialog().ok("Error connecting", "Failed to authenticate too many times. You can retry by selecting the option in the addon settings.")
-            
-            self.auth = False
-            return
-
-    def resetClient(self):
-
-        username = self.getUsername()
-        self.logMsg("Reset UserClient authentication.", 1)
-        if (self.currToken != None):
-            # In case of 401, removed saved token
-            utils.settings("accessToken", "")
-            self.WINDOW.setProperty("accessToken%s" % username, "")
-            self.currToken = None
-            self.logMsg("User token has been removed.", 1)
-        
-        self.auth = True
-        self.currUser = None
-        return
-        
-
-    def run(self):
-
-        self.logMsg("|---- Starting UserClient ----|", 0)
-
-        while not self.KodiMonitor.abortRequested():
-
-            # Verify the log level
-            currLogLevel = self.getLogLevel()
-            if self.logLevel != currLogLevel:
-                # Set new log level
-                self.logLevel = currLogLevel
-                self.logMsg("New Log Level: %s" % currLogLevel, 0)
-                self.WINDOW.setProperty('getLogLevel', str(currLogLevel)) 
-
-            if (self.WINDOW.getProperty("Server_status") != ""):
-                status = self.WINDOW.getProperty("Server_status")
-                
-                if status == "restricted":
-                    # Parental control is restricting access
-                    self.HasAccess = False
-
-                elif status == "401":
-                    self.WINDOW.setProperty("Server_status", "Auth")
-                    # Revoked token
-                    self.resetClient()
-
-            if self.auth and (self.currUser == None):
-                status = self.WINDOW.getProperty("Server_status")
-                
-                if (status == "") or (status == "Auth"):
-                    self.auth = False
-                    self.authenticate()
-                
-            if (self.auth == False) and (self.currUser == None):
-                # Only if there's information found to login
-                server = self.getServer()
-                username = self.getUsername()
-                status = self.WINDOW.getProperty("Server_status")
-
-                # If user didn't enter a password when prompted
-                if status == "Stop":
-                    pass
-                
-                elif (server != "") and (username != ""):
-                    self.logMsg("Server found: %s" % server)
-                    self.logMsg("Username found: %s" % username)
-                    self.auth = True
-
-            # If stopping the client didn't work
-            if self.stopClient == True:
-                break
-                
-            if self.KodiMonitor.waitForAbort(1):
-                # Abort was requested while waiting. We should exit
-                break
-        
-        self.doUtils.stopSession()    
-        self.logMsg("|---- UserClient Stopped ----|", 0)
-
-    def stopClient(self):
-        # As last resort
-        self.stopClient = True
\ No newline at end of file
diff --git a/resources/lib/Utils.py b/resources/lib/Utils.py
deleted file mode 100644
index 73c49c95..00000000
--- a/resources/lib/Utils.py
+++ /dev/null
@@ -1,425 +0,0 @@
-#################################################################################################
-# utils 
-#################################################################################################
-
-import xbmc
-import xbmcgui
-import xbmcaddon
-import xbmcvfs
-import json
-import os
-import cProfile
-import pstats
-import time
-import inspect
-import sqlite3
-import string
-import unicodedata
-import xml.etree.ElementTree as etree
-
-from API import API
-from PlayUtils import PlayUtils
-from DownloadUtils import DownloadUtils
-
-downloadUtils = DownloadUtils()
-addon = xbmcaddon.Addon()
-language = addon.getLocalizedString
-
- 
-def logMsg(title, msg, level = 1):
-    
-    WINDOW = xbmcgui.Window(10000)
-    # Get the logLevel set in UserClient
-    logLevel = int(WINDOW.getProperty('getLogLevel'))
-    
-    if(logLevel >= level):
-        if(logLevel == 2): # inspect.stack() is expensive
-            try:
-                xbmc.log(title + " -> " + inspect.stack()[1][3] + " : " + str(msg))
-            except UnicodeEncodeError:
-                xbmc.log(title + " -> " + inspect.stack()[1][3] + " : " + str(msg.encode('utf-8')))
-        else:
-            try:
-                xbmc.log(title + " -> " + str(msg))
-            except UnicodeEncodeError:
-                xbmc.log(title + " -> " + str(msg.encode('utf-8')))
-
-def convertEncoding(data):
-    #nasty hack to make sure we have a unicode string
-    try:
-        return data.decode('utf-8')
-    except:
-        return data
-          
-def KodiSQL(type="video"):
-    
-    if type == "music":
-        dbPath = getKodiMusicDBPath()
-    elif type == "texture":
-        dbPath = xbmc.translatePath("special://database/Textures13.db").decode('utf-8')
-    else:
-        dbPath = getKodiVideoDBPath()
-    
-    connection = sqlite3.connect(dbPath)
-    return connection
-
-def getKodiVideoDBPath():
-
-    kodibuild = xbmc.getInfoLabel('System.BuildVersion')[:2]
-    dbVersion = {
-
-        "13": 78,   # Gotham
-        "14": 90,   # Helix
-        "15": 93,   # Isengard
-        "16": 99    # Jarvis
-    }
-
-    dbPath = xbmc.translatePath(
-                    "special://database/MyVideos%s.db"
-                    % dbVersion.get(kodibuild, "")).decode('utf-8')
-    return dbPath
-
-def getKodiMusicDBPath():
-
-    kodibuild = xbmc.getInfoLabel('System.BuildVersion')[:2]
-    dbVersion = {
-
-        "13": 46,   # Gotham
-        "14": 48,   # Helix
-        "15": 52,   # Isengard
-        "16": 56    # Jarvis
-    }
-
-    dbPath = xbmc.translatePath(
-                    "special://database/MyMusic%s.db"
-                    % dbVersion.get(kodibuild, "")).decode('utf-8')
-    return dbPath
-    
-def prettifyXml(elem):
-    rough_string = etree.tostring(elem, "utf-8")
-    reparsed = minidom.parseString(rough_string)
-    return reparsed.toprettyxml(indent="\t")
-
-def startProfiling():
-    pr = cProfile.Profile()
-    pr.enable()
-    return pr
-    
-def stopProfiling(pr, profileName):
-    pr.disable()
-    ps = pstats.Stats(pr)
-    
-    addondir = xbmc.translatePath(xbmcaddon.Addon(id='plugin.video.emby').getAddonInfo('profile'))    
-    
-    fileTimeStamp = time.strftime("%Y-%m-%d %H-%M-%S")
-    tabFileNamepath = os.path.join(addondir, "profiles")
-    tabFileName = os.path.join(addondir, "profiles" , profileName + "_profile_(" + fileTimeStamp + ").tab")
-    
-    if not xbmcvfs.exists(tabFileNamepath):
-        xbmcvfs.mkdir(tabFileNamepath)
-    
-    f = open(tabFileName, 'wb')
-    f.write("NumbCalls\tTotalTime\tCumulativeTime\tFunctionName\tFileName\r\n")
-    for (key, value) in ps.stats.items():
-        (filename, count, func_name) = key
-        (ccalls, ncalls, total_time, cumulative_time, callers) = value
-        try:
-            f.write(str(ncalls) + "\t" + "{:10.4f}".format(total_time) + "\t" + "{:10.4f}".format(cumulative_time) + "\t" + func_name + "\t" + filename + "\r\n")
-        except ValueError:
-            f.write(str(ncalls) + "\t" + "{0}".format(total_time) + "\t" + "{0}".format(cumulative_time) + "\t" + func_name + "\t" + filename + "\r\n")
-    f.close()
-
-def indent(elem, level=0):
-    # Prettify xml trees
-    i = "\n" + level*"  "
-    if len(elem):
-        if not elem.text or not elem.text.strip():
-          elem.text = i + "  "
-        if not elem.tail or not elem.tail.strip():
-          elem.tail = i
-        for elem in elem:
-          indent(elem, level+1)
-        if not elem.tail or not elem.tail.strip():
-          elem.tail = i
-    else:
-        if level and (not elem.tail or not elem.tail.strip()):
-          elem.tail = i
-
-def createSources():
-    # To make Master lock compatible
-    path = xbmc.translatePath("special://profile/").decode("utf-8")
-    xmlpath = "%ssources.xml" % path
-
-    if xbmcvfs.exists(xmlpath):
-        # Modify the existing file
-        try:
-            xmlparse = etree.parse(xmlpath)
-        except:
-            root = etree.Element('sources')
-        else:
-            root = xmlparse.getroot()
-
-        video = root.find('video')
-        if video is None:
-            video = etree.SubElement(root, 'video')
-    else:
-        # We need to create the file
-        root = etree.Element('sources')
-        video = etree.SubElement(root, 'video')
-
-
-    # Add elements
-    etree.SubElement(video, 'default', attrib={'pathversion': "1"})
-    
-    # First dummy source
-    source_one = etree.SubElement(video, 'source')
-    etree.SubElement(source_one, 'name').text = "Emby"
-    etree.SubElement(source_one, 'path', attrib={'pathversion': "1"}).text = (
-
-            "smb://embydummy/dummypath1/"
-        )
-    etree.SubElement(source_one, 'allowsharing').text = "true"
-    
-    # Second dummy source
-    source_two = etree.SubElement(video, 'source')
-    etree.SubElement(source_two, 'name').text = "Emby"
-    etree.SubElement(source_two, 'path', attrib={'pathversion': "1"}).text = (
-
-            "smb://embydummy/dummypath2/"
-        )
-    etree.SubElement(source_two, 'allowsharing').text = "true"
-
-    try:
-        indent(root)
-    except:pass
-    etree.ElementTree(root).write(xmlpath)
-
-def pathsubstitution(add=True):
-
-    path = xbmc.translatePath('special://userdata').decode('utf-8')
-    xmlpath = "%sadvancedsettings.xml" % path
-    xmlpathexists = xbmcvfs.exists(xmlpath)
-
-    # original address
-    originalServer = settings('ipaddress')
-    originalPort = settings('port')
-    originalHttp = settings('https') == "true"
-
-    if originalHttp:
-        originalHttp = "https"
-    else:
-        originalHttp = "http"
-
-    # Process add or deletion
-    if add:
-        # second address
-        secondServer = settings('secondipaddress')
-        secondPort = settings('secondport')
-        secondHttp = settings('secondhttps') == "true"
-
-        if secondHttp:
-            secondHttp = "https"
-        else:
-            secondHttp = "http"
-
-        logMsg("EMBY", "Original address: %s://%s:%s, alternate is: %s://%s:%s" % (originalHttp, originalServer, originalPort, secondHttp, secondServer, secondPort), 1)
-
-        if xmlpathexists:
-            # we need to modify the file.
-            try:
-                xmlparse = etree.parse(xmlpath)
-            except: # Document is blank
-                root = etree.Element('advancedsettings')
-            else:
-                root = xmlparse.getroot()
-            
-            pathsubs = root.find('pathsubstitution')
-            if pathsubs is None:
-                pathsubs = etree.SubElement(root, 'pathsubstitution')
-        else:
-            # we need to create the file.
-            root = etree.Element('advancedsettings')
-            pathsubs = etree.SubElement(root, 'pathsubstitution')
-        
-        substitute = etree.SubElement(pathsubs, 'substitute')
-        # From original address
-        etree.SubElement(substitute, 'from').text = "%s://%s:%s" % (originalHttp, originalServer, originalPort)
-        # To secondary address
-        etree.SubElement(substitute, 'to').text = "%s://%s:%s" % (secondHttp, secondServer, secondPort)
-
-        etree.ElementTree(root).write(xmlpath)
-        settings('pathsub', "true")
-
-    else: # delete the path substitution, we don't need it anymore.
-        logMsg("EMBY", "Alternate address is disabled, removing path substitution for: %s://%s:%s" % (originalHttp, originalServer, originalPort), 1)
-
-        xmlparse = etree.parse(xmlpath)
-        root = xmlparse.getroot()
-        
-        iterator = root.getiterator("pathsubstitution")
-
-        for substitutes in iterator:
-            for substitute in substitutes:
-                frominsert = substitute.find(".//from").text == "%s://%s:%s" % (originalHttp, originalServer, originalPort)
-
-                if frominsert:
-                    # Found a match, in case there's more than one substitution.
-                    substitutes.remove(substitute)
-
-        etree.ElementTree(root).write(xmlpath)
-        settings('pathsub', "false")
-
-
-def settings(setting, value = None):
-    # Get or add addon setting
-    addon = xbmcaddon.Addon()
-    if value:
-        addon.setSetting(setting, value)
-    else:
-        return addon.getSetting(setting)
-
-def window(property, value = None, clear = False):
-    # Get or set window property
-    WINDOW = xbmcgui.Window(10000)
-    if clear:
-        WINDOW.clearProperty(property)
-    elif value:
-        WINDOW.setProperty(property, value)
-    else:
-        return WINDOW.getProperty(property)
-
-def normalize_string(text):
-    # For theme media, do not modify unless
-    # modified in TV Tunes
-    text = text.replace(":", "")
-    text = text.replace("/", "-")
-    text = text.replace("\\", "-")
-    text = text.replace("<", "")
-    text = text.replace(">", "")
-    text = text.replace("*", "")
-    text = text.replace("?", "")
-    text = text.replace('|', "")
-    text = text.strip()
-    # Remove dots from the last character as windows can not have directories
-    # with dots at the end
-    text = text.rstrip('.')
-    text = unicodedata.normalize('NFKD', unicode(text, 'utf-8')).encode('ascii', 'ignore')
-
-    return text
-
-def normalize_nodes(text):
-    # For video nodes
-    text = text.replace(":", "")
-    text = text.replace("/", "-")
-    text = text.replace("\\", "-")
-    text = text.replace("<", "")
-    text = text.replace(">", "")
-    text = text.replace("*", "")
-    text = text.replace("?", "")
-    text = text.replace('|', "")
-    text = text.replace('(', "")
-    text = text.replace(')', "")
-    text = text.strip()
-    # Remove dots from the last character as windows can not have directories
-    # with dots at the end
-    text = text.rstrip('.')
-    text = unicodedata.normalize('NFKD', unicode(text, 'utf-8')).encode('ascii', 'ignore')
-    
-    return text
-
-def reloadProfile():
-    # Useful to reload the add-on without restarting Kodi.
-    profile = xbmc.getInfoLabel('System.ProfileName')
-    xbmc.executebuiltin("LoadProfile(%s)" % profile)
-   
-
-def reset():
-
-    WINDOW = xbmcgui.Window( 10000 )
-    return_value = xbmcgui.Dialog().yesno("Warning", "Are you sure you want to reset your local Kodi database?")
-
-    if return_value == 0:
-        return
-
-    # Because the settings dialog could be open
-    # it seems to override settings so we need to close it before we reset settings.
-    xbmc.executebuiltin("Dialog.Close(all,true)")
-    
-    #cleanup video nodes
-    import shutil
-    path = "special://profile/library/video/"
-    if xbmcvfs.exists(path):
-        allDirs, allFiles = xbmcvfs.listdir(path)
-        for dir in allDirs:
-            if dir.startswith("Emby "):
-                shutil.rmtree(xbmc.translatePath("special://profile/library/video/" + dir))
-        for file in allFiles:
-                if file.startswith("emby"):
-                    xbmcvfs.delete(path + file)
-
-    settings('SyncInstallRunDone', "false")
-    
-    # Ask if user information should be deleted too.
-    return_user = xbmcgui.Dialog().yesno("Warning", "Reset all Emby Addon settings?")
-    if return_user == 1:
-        WINDOW.setProperty('deletesettings', "true")
-        addon = xbmcaddon.Addon()
-        addondir = xbmc.translatePath(addon.getAddonInfo('profile')).decode('utf-8')
-        dataPath = "%ssettings.xml" % addondir
-        xbmcvfs.delete(dataPath)
-        logMsg("EMBY", "Deleting: settings.xml", 1)
-    
-    # first stop any db sync
-    WINDOW.setProperty("SyncDatabaseShouldStop", "true")
-    
-    count = 0
-    while(WINDOW.getProperty("SyncDatabaseRunning") == "true"):
-        xbmc.log("Sync Running, will wait : " + str(count))
-        count += 1
-        if(count > 10):
-            dialog = xbmcgui.Dialog()
-            dialog.ok('Warning', 'Could not stop DB sync, you should try again.')
-            return
-        xbmc.sleep(1000)
-       
-    # delete video db table data
-    print "Doing Video DB Reset"
-    connection = KodiSQL("video")
-    cursor = connection.cursor( )
-    cursor.execute('SELECT tbl_name FROM sqlite_master WHERE type="table"')
-    rows = cursor.fetchall()
-    for row in rows:
-        tableName = row[0]
-        if(tableName != "version"):
-            cursor.execute("DELETE FROM " + tableName)
-    cursor.execute("DROP TABLE IF EXISTS emby")
-    connection.commit()
-    cursor.close()
-    
-    if settings('enableMusicSync') == "true":
-        # delete video db table data
-        print "Doing Music DB Reset"
-        connection = KodiSQL("music")
-        cursor = connection.cursor( )
-        cursor.execute('SELECT tbl_name FROM sqlite_master WHERE type="table"')
-        rows = cursor.fetchall()
-        for row in rows:
-            tableName = row[0]
-            if(tableName != "version"):
-                cursor.execute("DELETE FROM " + tableName)
-        cursor.execute("DROP TABLE IF EXISTS emby")
-        connection.commit()
-        cursor.close()
-        
-    
-    # reset the install run flag
-    #settings('SyncInstallRunDone', "false")
-    #WINDOW.setProperty("SyncInstallRunDone", "false")
-
-    dialog = xbmcgui.Dialog()
-    # Reload would work instead of restart since the add-on is a service.
-    #dialog.ok('Emby Reset', 'Database reset has completed, Kodi will now restart to apply the changes.')
-    #WINDOW.clearProperty("SyncDatabaseShouldStop")
-    #reloadProfile()
-    dialog.ok('Emby Reset', 'Database reset has completed, Kodi will now restart to apply the changes.')
-    xbmc.executebuiltin("RestartApp")
\ No newline at end of file
diff --git a/resources/lib/VideoNodes.py b/resources/lib/VideoNodes.py
deleted file mode 100644
index 056ee13f..00000000
--- a/resources/lib/VideoNodes.py
+++ /dev/null
@@ -1,466 +0,0 @@
-#################################################################################################
-# VideoNodes - utils to create video nodes listings in kodi for the emby addon
-#################################################################################################
-
-
-import xbmc
-import xbmcgui
-import xbmcaddon
-import xbmcvfs
-import json
-import os
-import shutil
-#import common elementree because cElementree has issues with kodi
-import xml.etree.ElementTree as etree
-
-import Utils as utils
-
-from ReadEmbyDB import ReadEmbyDB
-WINDOW = xbmcgui.Window(10000)
-
-addonSettings = xbmcaddon.Addon()
-language = addonSettings.getLocalizedString
-
-class VideoNodes():   
-       
-   
-    def buildVideoNodeForView(self, tagname, type, windowPropId):
-        #this method will build a video node for a particular Emby view (= tag in kodi)
-        #we set some window props here to for easy future reference and to be used in skins (for easy access only)
-        tagname_normalized = utils.normalize_nodes(tagname.encode('utf-8'))
-        
-        libraryPath = xbmc.translatePath("special://profile/library/video/Emby - %s/" %tagname_normalized)
-        kodiVersion = 14
-        if xbmc.getInfoLabel("System.BuildVersion").startswith("15") or xbmc.getInfoLabel("System.BuildVersion").startswith("16"):
-            kodiVersion = 15
-        
-        #create tag node - index
-        xbmcvfs.mkdir(libraryPath)
-        nodefile = os.path.join(libraryPath, "index.xml")
-        root = etree.Element("node", {"order":"0"})
-        etree.SubElement(root, "label").text = tagname
-        etree.SubElement(root, "icon").text = "special://home/addons/plugin.video.emby/icon.png"
-        path = "library://video/Emby - %s/" %tagname_normalized
-        WINDOW.setProperty("Emby.nodes.%s.index" %str(windowPropId),path)
-        try:
-            etree.ElementTree(root).write(nodefile, xml_declaration=True)
-        except:
-            etree.ElementTree(root).write(nodefile)
-        
-        #create tag node - all items
-        nodefile = os.path.join(libraryPath, tagname_normalized + "_all.xml")
-        root = etree.Element("node", {"order":"1", "type":"filter"})
-        etree.SubElement(root, "label").text = tagname
-        etree.SubElement(root, "match").text = "all"
-        etree.SubElement(root, "content").text = type
-        etree.SubElement(root, "icon").text = "special://home/addons/plugin.video.emby/icon.png"
-        etree.SubElement(root, "order", {"direction":"ascending"}).text = "sorttitle"
-        Rule = etree.SubElement(root, "rule", {"field":"tag","operator":"is"})
-        WINDOW.setProperty("Emby.nodes.%s.title" %str(windowPropId),tagname)
-        path = "library://video/Emby - %s/%s_all.xml"%(tagname_normalized,tagname_normalized)
-        WINDOW.setProperty("Emby.nodes.%s.path" %str(windowPropId),"ActivateWindow(Video,%s,return)"%path)
-        WINDOW.setProperty("Emby.nodes.%s.content" %str(windowPropId),path)
-        WINDOW.setProperty("Emby.nodes.%s.type" %str(windowPropId),type)
-        etree.SubElement(Rule, "value").text = tagname
-        try:
-            etree.ElementTree(root).write(nodefile, xml_declaration=True)
-        except:
-            etree.ElementTree(root).write(nodefile)
-        
-        #create tag node - recent items
-        nodefile = os.path.join(libraryPath, tagname_normalized + "_recent.xml")
-        root = etree.Element("node", {"order":"2", "type":"filter"})
-        if type == "tvshows":
-            label = language(30170)
-        else:
-            label = language(30174)
-        etree.SubElement(root, "label").text = label
-        etree.SubElement(root, "match").text = "all"
-        etree.SubElement(root, "content").text = type
-        etree.SubElement(root, "icon").text = "special://home/addons/plugin.video.emby/icon.png"
-        Rule = etree.SubElement(root, "rule", {"field":"tag","operator":"is"})
-        etree.SubElement(Rule, "value").text = tagname
-        etree.SubElement(root, "order", {"direction":"descending"}).text = "dateadded"
-        #set limit to 25 --> currently hardcoded --> TODO: add a setting for this ?
-        etree.SubElement(root, "limit").text = "25"
-        #exclude watched items --> currently hardcoded --> TODO: add a setting for this ?
-        Rule2 = etree.SubElement(root, "rule", {"field":"playcount","operator":"is"})
-        etree.SubElement(Rule2, "value").text = "0"
-        WINDOW.setProperty("Emby.nodes.%s.recent.title" %str(windowPropId),label)
-        path = "library://video/Emby - %s/%s_recent.xml"%(tagname_normalized,tagname_normalized)
-        WINDOW.setProperty("Emby.nodes.%s.recent.path" %str(windowPropId),"ActivateWindow(Video,%s,return)"%path)
-        WINDOW.setProperty("Emby.nodes.%s.recent.content" %str(windowPropId),path)
-        try:
-            etree.ElementTree(root).write(nodefile, xml_declaration=True)
-        except:
-            etree.ElementTree(root).write(nodefile)
-        
-        #create tag node - inprogress items
-        nodefile = os.path.join(libraryPath, tagname_normalized + "_progress.xml")
-        root = etree.Element("node", {"order":"3", "type":"filter"})
-        if type == "tvshows":
-            label = language(30171)
-        else:
-            label = language(30177)
-        etree.SubElement(root, "label").text = label
-        etree.SubElement(root, "match").text = "all"
-        etree.SubElement(root, "content").text = type
-        etree.SubElement(root, "icon").text = "special://home/addons/plugin.video.emby/icon.png"
-        Rule = etree.SubElement(root, "rule", {"field":"tag","operator":"is"})
-        etree.SubElement(Rule, "value").text = tagname
-        #set limit to 25 --> currently hardcoded --> TODO: add a setting for this ?
-        etree.SubElement(root, "limit").text = "25"
-        Rule2 = etree.SubElement(root, "rule", {"field":"inprogress","operator":"true"})
-        WINDOW.setProperty("Emby.nodes.%s.inprogress.title" %str(windowPropId),label)
-        path = "library://video/Emby - %s/%s_progress.xml"%(tagname_normalized,tagname_normalized)
-        WINDOW.setProperty("Emby.nodes.%s.inprogress.path" %str(windowPropId),"ActivateWindow(Video,%s,return)"%path)
-        WINDOW.setProperty("Emby.nodes.%s.inprogress.content" %str(windowPropId),path)
-        try:
-            etree.ElementTree(root).write(nodefile, xml_declaration=True)
-        except:
-            etree.ElementTree(root).write(nodefile)
-        
-        #some movies-only nodes
-        if type == "movies":
-            
-            #unwatched movies
-            nodefile = os.path.join(libraryPath, tagname_normalized + "_unwatched.xml")
-            root = etree.Element("node", {"order":"4", "type":"filter"})
-            label = language(30189)
-            etree.SubElement(root, "label").text = label
-            etree.SubElement(root, "match").text = "all"
-            etree.SubElement(root, "content").text = "movies"
-            etree.SubElement(root, "icon").text = "special://home/addons/plugin.video.emby/icon.png"
-            Rule = etree.SubElement(root, "rule", {"field":"tag","operator":"is"})
-            etree.SubElement(Rule, "value").text = tagname
-            Rule = etree.SubElement(root, "rule", {"field":"playcount","operator":"is"})
-            etree.SubElement(Rule, "value").text = "0"
-            etree.SubElement(root, "order", {"direction":"ascending"}).text = "sorttitle"
-            Rule2 = etree.SubElement(root, "rule", {"field":"playcount","operator":"is"})
-            etree.SubElement(Rule2, "value").text = "0"
-            WINDOW.setProperty("Emby.nodes.%s.unwatched.title" %str(windowPropId),label)
-            path = "library://video/Emby - %s/%s_unwatched.xml"%(tagname_normalized,tagname_normalized)
-            WINDOW.setProperty("Emby.nodes.%s.unwatched.path" %str(windowPropId),"ActivateWindow(Video,%s,return)"%path)
-            WINDOW.setProperty("Emby.nodes.%s.unwatched.content" %str(windowPropId),path)
-            try:
-                etree.ElementTree(root).write(nodefile, xml_declaration=True)
-            except:
-                etree.ElementTree(root).write(nodefile)
-            
-            #sets
-            nodefile = os.path.join(libraryPath, tagname_normalized + "_sets.xml")
-            root = etree.Element("node", {"order":"9", "type":"filter"})
-            label = xbmc.getLocalizedString(20434)
-            etree.SubElement(root, "label").text = label
-            etree.SubElement(root, "match").text = "all"
-            etree.SubElement(root, "group").text = "sets"
-            etree.SubElement(root, "content").text = type
-            etree.SubElement(root, "icon").text = "special://home/addons/plugin.video.emby/icon.png"
-            etree.SubElement(root, "order", {"direction":"ascending"}).text = "sorttitle"
-            Rule = etree.SubElement(root, "rule", {"field":"tag","operator":"is"})
-            etree.SubElement(Rule, "value").text = tagname
-            WINDOW.setProperty("Emby.nodes.%s.sets.title" %str(windowPropId),label)
-            path = "library://video/Emby - %s/%s_sets.xml"%(tagname_normalized,tagname_normalized)
-            WINDOW.setProperty("Emby.nodes.%s.sets.path" %str(windowPropId),"ActivateWindow(Video,%s,return)"%path)
-            WINDOW.setProperty("Emby.nodes.%s.sets.content" %str(windowPropId),path)
-            try:
-                etree.ElementTree(root).write(nodefile, xml_declaration=True)
-            except:
-                etree.ElementTree(root).write(nodefile)
-
-        #create tag node - genres
-        nodefile = os.path.join(libraryPath, tagname_normalized + "_genres.xml")
-        root = etree.Element("node", {"order":"9", "type":"filter"})
-        label = xbmc.getLocalizedString(135)
-        etree.SubElement(root, "label").text = label
-        etree.SubElement(root, "match").text = "all"
-        etree.SubElement(root, "group").text = "genres"
-        etree.SubElement(root, "content").text = type
-        etree.SubElement(root, "icon").text = "special://home/addons/plugin.video.emby/icon.png"
-        etree.SubElement(root, "order", {"direction":"ascending"}).text = "sorttitle"
-        Rule = etree.SubElement(root, "rule", {"field":"tag","operator":"is"})
-        etree.SubElement(Rule, "value").text = tagname
-        WINDOW.setProperty("Emby.nodes.%s.genres.title" %str(windowPropId),label)
-        path = "library://video/Emby - %s/%s_genres.xml"%(tagname_normalized,tagname_normalized)
-        WINDOW.setProperty("Emby.nodes.%s.genres.path" %str(windowPropId),"ActivateWindow(Video,%s,return)"%path)
-        WINDOW.setProperty("Emby.nodes.%s.genres.content" %str(windowPropId),path)
-        
-        try:
-            etree.ElementTree(root).write(nodefile, xml_declaration=True)
-        except:
-            etree.ElementTree(root).write(nodefile)
-        
-        #create tag node - random items
-        nodefile = os.path.join(libraryPath, tagname_normalized + "_random.xml")
-        root = etree.Element("node", {"order":"10", "type":"filter"})
-        label = language(30229)
-        etree.SubElement(root, "label").text = label
-        etree.SubElement(root, "match").text = "all"
-        etree.SubElement(root, "content").text = type
-        etree.SubElement(root, "icon").text = "special://home/addons/plugin.video.emby/icon.png"
-        Rule = etree.SubElement(root, "rule", {"field":"tag","operator":"is"})
-        etree.SubElement(Rule, "value").text = tagname
-        #set limit to 25 --> currently hardcoded --> TODO: add a setting for this ?
-        etree.SubElement(root, "limit").text = "25"
-        etree.SubElement(root, "order", {"direction":"ascending"}).text = "random"
-        WINDOW.setProperty("Emby.nodes.%s.random.title" %str(windowPropId),label)
-        path = "library://video/Emby - %s/%s_random.xml"%(tagname_normalized,tagname_normalized)
-        WINDOW.setProperty("Emby.nodes.%s.random.path" %str(windowPropId),"ActivateWindow(Video,%s,return)"%path)
-        WINDOW.setProperty("Emby.nodes.%s.random.content" %str(windowPropId),path)
-        try:
-            etree.ElementTree(root).write(nodefile, xml_declaration=True)
-        except:
-            etree.ElementTree(root).write(nodefile)
-        
-        #create tag node - recommended items
-        nodefile = os.path.join(libraryPath, tagname_normalized + "_recommended.xml")
-        root = etree.Element("node", {"order":"10", "type":"filter"})
-        label = language(30230)
-        etree.SubElement(root, "label").text = label
-        etree.SubElement(root, "match").text = "all"
-        etree.SubElement(root, "content").text = type
-        etree.SubElement(root, "icon").text = "special://home/addons/plugin.video.emby/icon.png"
-        Rule = etree.SubElement(root, "rule", {"field":"tag","operator":"is"})
-        etree.SubElement(Rule, "value").text = tagname
-        Rule2 = etree.SubElement(root, "rule", {"field":"playcount","operator":"is"})
-        etree.SubElement(Rule2, "value").text = "0"
-        Rule3 = etree.SubElement(root, "rule", {"field":"rating","operator":"greaterthan"})
-        etree.SubElement(Rule3, "value").text = "7"
-        #set limit to 25 --> currently hardcoded --> TODO: add a setting for this ?
-        etree.SubElement(root, "limit").text = "25"
-        etree.SubElement(root, "order", {"direction":"descending"}).text = "rating"
-        WINDOW.setProperty("Emby.nodes.%s.random.title" %str(windowPropId),label)
-        path = "library://video/Emby - %s/%s_recommended.xml"%(tagname_normalized,tagname_normalized)
-        WINDOW.setProperty("Emby.nodes.%s.recommended.path" %str(windowPropId),"ActivateWindow(Video,%s,return)"%path)
-        WINDOW.setProperty("Emby.nodes.%s.recommended.content" %str(windowPropId),path)
-        try:
-            etree.ElementTree(root).write(nodefile, xml_declaration=True)
-        except:
-            etree.ElementTree(root).write(nodefile)
-        
-        #### TAGS ONLY FOR TV SHOWS COLLECTIONS ####
-        if type == "tvshows":    
-            
-            #as from kodi isengard you can use tags for episodes to filter
-            #for below isengard we still use the plugin's entrypoint to build a listing
-            if kodiVersion == 15:
-                #create tag node - recent episodes
-                nodefile = os.path.join(libraryPath, tagname_normalized + "_recent_episodes.xml")
-                root = etree.Element("node", {"order":"3", "type":"filter"})
-                label = language(30175)
-                etree.SubElement(root, "label").text = label
-                etree.SubElement(root, "match").text = "all"
-                etree.SubElement(root, "content").text = "episodes"
-                etree.SubElement(root, "icon").text = "special://home/addons/plugin.video.emby/icon.png"
-                etree.SubElement(root, "order", {"direction":"descending"}).text = "dateadded"
-                Rule = etree.SubElement(root, "rule", {"field":"tag","operator":"is"})
-                etree.SubElement(Rule, "value").text = tagname
-                #set limit to 25 --> currently hardcoded --> TODO: add a setting for this ?
-                etree.SubElement(root, "limit").text = "25"
-                #exclude watched items --> currently hardcoded --> TODO: add a setting for this ?
-                Rule2 = etree.SubElement(root, "rule", {"field":"playcount","operator":"is"})
-                etree.SubElement(Rule2, "value").text = "0"
-                WINDOW.setProperty("Emby.nodes.%s.recentepisodes.title" %str(windowPropId),label)
-                path = "library://video/Emby - %s/%s_recent_episodes.xml"%(tagname_normalized,tagname_normalized)
-                WINDOW.setProperty("Emby.nodes.%s.recentepisodes.path" %str(windowPropId),"ActivateWindow(Video,%s,return)"%path)
-                WINDOW.setProperty("Emby.nodes.%s.recentepisodes.content" %str(windowPropId),path)
-                try:
-                    etree.ElementTree(root).write(nodefile, xml_declaration=True)
-                except:
-                    etree.ElementTree(root).write(nodefile)
-                
-                #create tag node - inprogress episodes
-                nodefile = os.path.join(libraryPath, tagname_normalized + "_progress_episodes.xml")
-                root = etree.Element("node", {"order":"4", "type":"filter"})
-                label = language(30178)
-                etree.SubElement(root, "label").text = label
-                etree.SubElement(root, "match").text = "all"
-                etree.SubElement(root, "content").text = "episodes"
-                etree.SubElement(root, "icon").text = "special://home/addons/plugin.video.emby/icon.png"
-                Rule = etree.SubElement(root, "rule", {"field":"tag","operator":"is"})
-                etree.SubElement(Rule, "value").text = tagname
-                #set limit to 25 --> currently hardcoded --> TODO: add a setting for this ?
-                etree.SubElement(root, "limit").text = "25"
-                Rule2 = etree.SubElement(root, "rule", {"field":"inprogress","operator":"true"})
-                WINDOW.setProperty("Emby.nodes.%s.inprogressepisodes.title" %str(windowPropId),label)
-                path = "library://video/Emby - %s/%s_progress_episodes.xml"%(tagname_normalized,tagname_normalized)
-                WINDOW.setProperty("Emby.nodes.%s.inprogressepisodes.path" %str(windowPropId),"ActivateWindow(Video,%s,return)"%path)
-                WINDOW.setProperty("Emby.nodes.%s.inprogressepisodes.content" %str(windowPropId),path)
-                try:
-                    etree.ElementTree(root).write(nodefile, xml_declaration=True)
-                except:
-                    etree.ElementTree(root).write(nodefile)
-                    
-            if kodiVersion == 14:
-                #create tag node - recent episodes
-                nodefile = os.path.join(libraryPath, tagname_normalized + "_recent_episodes.xml")
-                root = etree.Element("node", {"order":"4", "type":"folder"})
-                label = language(30175)
-                etree.SubElement(root, "label").text = label
-                etree.SubElement(root, "content").text = "episodes"
-                etree.SubElement(root, "icon").text = "special://home/addons/plugin.video.emby/icon.png"
-                path = "plugin://plugin.video.emby/?id=%s&mode=recentepisodes&limit=25" %tagname
-                etree.SubElement(root, "path").text = path
-                WINDOW.setProperty("Emby.nodes.%s.recentepisodes.title" %str(windowPropId),label)
-                path = "library://video/Emby - %s/%s_recent_episodes.xml"%(tagname_normalized,tagname_normalized)
-                WINDOW.setProperty("Emby.nodes.%s.recentepisodes.path" %str(windowPropId),"ActivateWindow(Video,%s,return)"%path)
-                WINDOW.setProperty("Emby.nodes.%s.recentepisodes.content" %str(windowPropId),path)
-                try:
-                    etree.ElementTree(root).write(nodefile, xml_declaration=True)
-                except:
-                    etree.ElementTree(root).write(nodefile)
-                
-                #create tag node - inprogress items
-                nodefile = os.path.join(libraryPath, tagname_normalized + "_progress_episodes.xml")
-                root = etree.Element("node", {"order":"5", "type":"folder"})
-                label = language(30178)
-                etree.SubElement(root, "label").text = label
-                etree.SubElement(root, "content").text = "episodes"
-                etree.SubElement(root, "icon").text = "special://home/addons/plugin.video.emby/icon.png"
-                path = "plugin://plugin.video.emby/?id=%s&mode=inprogressepisodes&limit=25" %tagname
-                etree.SubElement(root, "path").text = path
-                WINDOW.setProperty("Emby.nodes.%s.inprogressepisodes.title" %str(windowPropId),label)
-                path = "library://video/Emby - %s/%s_progress_episodes.xml"%(tagname_normalized,tagname_normalized)
-                WINDOW.setProperty("Emby.nodes.%s.inprogressepisodes.path" %str(windowPropId),"ActivateWindow(Video,%s,return)"%path)
-                WINDOW.setProperty("Emby.nodes.%s.inprogressepisodes.content" %str(windowPropId),path)
-                try:
-                    etree.ElementTree(root).write(nodefile, xml_declaration=True)
-                except:
-                    etree.ElementTree(root).write(nodefile)
-            
-            #create tag node - nextup items
-            #for nextup we always use the dynamic content approach with the plugin's entrypoint because it involves a custom query
-            nodefile = os.path.join(libraryPath, tagname_normalized + "_nextup_episodes.xml")
-            root = etree.Element("node", {"order":"6", "type":"folder"})
-            label = language(30179)
-            etree.SubElement(root, "label").text = label
-            etree.SubElement(root, "content").text = "episodes"
-            path = "plugin://plugin.video.emby/?id=%s&mode=nextup&limit=25" %tagname
-            etree.SubElement(root, "path").text = path
-            etree.SubElement(root, "icon").text = "special://home/addons/plugin.video.emby/icon.png"
-            WINDOW.setProperty("Emby.nodes.%s.nextepisodes.title" %str(windowPropId),label)
-            path = "library://video/Emby - %s/%s_nextup_episodes.xml"%(tagname_normalized,tagname_normalized)
-            WINDOW.setProperty("Emby.nodes.%s.nextepisodes.path" %str(windowPropId),"ActivateWindow(Video,%s,return)"%path)
-            WINDOW.setProperty("Emby.nodes.%s.nextepisodes.content" %str(windowPropId),path)        
-            try:
-                etree.ElementTree(root).write(nodefile, xml_declaration=True)
-            except:
-                etree.ElementTree(root).write(nodefile)
-    
-    def buildVideoNodesListing(self):
-            
-        try:
-        
-            # the library path doesn't exist on all systems
-            if not xbmcvfs.exists("special://profile/library/"):
-                xbmcvfs.mkdir("special://profile/library") 
-            if not xbmcvfs.exists("special://profile/library/video/"):
-                #we need to copy over the default items
-                shutil.copytree(xbmc.translatePath("special://xbmc/system/library/video"), xbmc.translatePath("special://profile/library/video"))
-            
-            #always cleanup existing Emby video nodes first because we don't want old stuff to stay in there
-            path = "special://profile/library/video/"
-            if xbmcvfs.exists(path):
-                allDirs, allFiles = xbmcvfs.listdir(path)
-                for dir in allDirs:
-                    if dir.startswith("Emby "):
-                        shutil.rmtree(xbmc.translatePath("special://profile/library/video/" + dir))
-                for file in allFiles:
-                    if file.startswith("emby"):
-                        xbmcvfs.delete(path + file)
-            
-            #we build up a listing and set window props for all nodes we created
-            #the window props will be used by the main entry point to quickly build up the listing and can be used in skins (like titan) too for quick reference
-            #comment marcelveldt: please leave the window props as-is because I will be referencing them in titan skin...
-            totalNodesCount = 0
-            
-            #build the listing for all views
-            views_movies = ReadEmbyDB().getCollections("movies")
-            if views_movies:
-                for view in views_movies:
-                    title = view.get('title')
-                    content = view.get('content')
-                    if content == "mixed":
-                        title = "%s - Movies" % title
-                    self.buildVideoNodeForView(title, "movies", totalNodesCount)
-                    totalNodesCount +=1
-                    
-            views_shows = ReadEmbyDB().getCollections("tvshows")
-            if views_shows:
-                for view in views_shows:
-                    title = view.get('title')
-                    content = view.get('content')
-                    if content == "mixed":
-                        title = "%s - TV Shows" % title
-                    self.buildVideoNodeForView(title, "tvshows", totalNodesCount)
-                    totalNodesCount +=1
-
-            #create tag node for emby channels
-            nodefile = os.path.join(xbmc.translatePath("special://profile/library/video"), "emby_channels.xml")
-            root = etree.Element("node", {"order":"1", "type":"folder"})
-            label = language(30173)
-            etree.SubElement(root, "label").text = label
-            etree.SubElement(root, "content").text = "movies"
-            etree.SubElement(root, "path").text = "plugin://plugin.video.emby/?id=0&mode=channels"
-            etree.SubElement(root, "icon").text = "special://home/addons/plugin.video.emby/icon.png"
-            WINDOW.setProperty("Emby.nodes.%s.title" %str(totalNodesCount),label)
-            WINDOW.setProperty("Emby.nodes.%s.type" %str(totalNodesCount),"channels")
-            path = "library://video/emby_channels.xml"
-            WINDOW.setProperty("Emby.nodes.%s.path" %str(totalNodesCount),"ActivateWindow(Video,%s,return)"%path)
-            WINDOW.setProperty("Emby.nodes.%s.content" %str(totalNodesCount),path)
-            totalNodesCount +=1        
-            try:
-                etree.ElementTree(root).write(nodefile, xml_declaration=True)
-            except:
-                etree.ElementTree(root).write(nodefile)
-                   
-            #create tag node - favorite shows
-            nodefile = os.path.join(xbmc.translatePath("special://profile/library/video"),"emby_favorite_shows.xml")
-            root = etree.Element("node", {"order":"1", "type":"filter"})
-            label = language(30181)
-            etree.SubElement(root, "label").text = label
-            etree.SubElement(root, "match").text = "all"
-            etree.SubElement(root, "content").text = "tvshows"
-            etree.SubElement(root, "icon").text = "special://home/addons/plugin.video.emby/icon.png"
-            etree.SubElement(root, "order", {"direction":"ascending"}).text = "sorttitle"
-            Rule = etree.SubElement(root, "rule", {"field":"tag","operator":"is"})
-            etree.SubElement(Rule, "value").text = "Favorite tvshows" #do not localize the tagname itself
-            WINDOW.setProperty("Emby.nodes.%s.title" %str(totalNodesCount),label)
-            WINDOW.setProperty("Emby.nodes.%s.type" %str(totalNodesCount),"favourites")
-            path = "library://video/emby_favorite_shows.xml"
-            WINDOW.setProperty("Emby.nodes.%s.path" %str(totalNodesCount),"ActivateWindow(Video,%s,return)"%path)
-            WINDOW.setProperty("Emby.nodes.%s.content" %str(totalNodesCount),path)
-            totalNodesCount +=1
-            try:
-                etree.ElementTree(root).write(nodefile, xml_declaration=True)
-            except:
-                etree.ElementTree(root).write(nodefile)
-            
-            #create tag node - favorite movies
-            nodefile = os.path.join(xbmc.translatePath("special://profile/library/video"),"emby_favorite_movies.xml")
-            root = etree.Element("node", {"order":"1", "type":"filter"})
-            label = language(30180)
-            etree.SubElement(root, "label").text = label
-            etree.SubElement(root, "match").text = "all"
-            etree.SubElement(root, "content").text = "movies"
-            etree.SubElement(root, "icon").text = "special://home/addons/plugin.video.emby/icon.png"
-            etree.SubElement(root, "order", {"direction":"ascending"}).text = "sorttitle"
-            Rule = etree.SubElement(root, "rule", {"field":"tag","operator":"is"})
-            etree.SubElement(Rule, "value").text = "Favorite movies" #do not localize the tagname itself
-            WINDOW.setProperty("Emby.nodes.%s.title" %str(totalNodesCount),label)
-            WINDOW.setProperty("Emby.nodes.%s.type" %str(totalNodesCount),"favourites")
-            path = "library://video/emby_favorite_movies.xml"
-            WINDOW.setProperty("Emby.nodes.%s.path" %str(totalNodesCount),"ActivateWindow(Video,%s,return)"%path)
-            WINDOW.setProperty("Emby.nodes.%s.content" %str(totalNodesCount),path)
-            totalNodesCount +=1
-            try:
-                etree.ElementTree(root).write(nodefile, xml_declaration=True)
-            except:
-                etree.ElementTree(root).write(nodefile)
-            
-            WINDOW.setProperty("Emby.nodes.total", str(totalNodesCount))               
-                
-
-        except Exception as e:
-            utils.logMsg("Emby addon","Error while creating videonodes listings, restart required ?")
-            print e    
\ No newline at end of file