diff --git a/contextmenu.py b/contextmenu.py
index 3b367ab2..c91da6a1 100644
--- a/contextmenu.py
+++ b/contextmenu.py
@@ -1,159 +1,158 @@
-# -*- coding: utf-8 -*-
-
-#################################################################################################
-
-import os
-import sys
-import urlparse
-
-import xbmc
-import xbmcaddon
-import xbmcgui
-
-addon_ = xbmcaddon.Addon(id='plugin.video.emby')
-addon_path = addon_.getAddonInfo('path').decode('utf-8')
-base_resource = xbmc.translatePath(os.path.join(addon_path, 'resources', 'lib')).decode('utf-8')
-sys.path.append(base_resource)
-
-import artwork
-import utils
-import clientinfo
-import downloadutils
-import librarysync
-import read_embyserver as embyserver
-import embydb_functions as embydb
-import kodidb_functions as kodidb
-import musicutils as musicutils
-import api
-
-def logMsg(msg, lvl=1):
-    utils.logMsg("%s %s" % ("EMBY", "Contextmenu"), msg, lvl)
-
-
-#Kodi contextmenu item to configure the emby settings
-#for now used to set ratings but can later be used to sync individual items etc.
-if __name__ == '__main__':
-    itemid = xbmc.getInfoLabel("ListItem.DBID").decode("utf-8")
-    itemtype = xbmc.getInfoLabel("ListItem.DBTYPE").decode("utf-8")
-    
-    emby = embyserver.Read_EmbyServer()
-    
-    embyid = ""
-    if not itemtype and xbmc.getCondVisibility("Container.Content(albums)"): itemtype = "album"
-    if not itemtype and xbmc.getCondVisibility("Container.Content(artists)"): itemtype = "artist"
-    if not itemtype and xbmc.getCondVisibility("Container.Content(songs)"): itemtype = "song"
-    if not itemtype and xbmc.getCondVisibility("Container.Content(pictures)"): itemtype = "picture"
-    
-    if (not itemid or itemid == "-1") and xbmc.getInfoLabel("ListItem.Property(embyid)"):
-        embyid = xbmc.getInfoLabel("ListItem.Property(embyid)")
-    else:
-        embyconn = utils.kodiSQL('emby')
-        embycursor = embyconn.cursor()
-        emby_db = embydb.Embydb_Functions(embycursor)
-        item = emby_db.getItem_byKodiId(itemid, itemtype)
-        embycursor.close()
-        if item: embyid = item[0]
-    
-    logMsg("Contextmenu opened for embyid: %s  - itemtype: %s" %(embyid,itemtype))
-
-    if embyid:
-        item = emby.getItem(embyid)
-        API = api.API(item)
-        userdata = API.getUserData()
-        likes = userdata['Likes']
-        favourite = userdata['Favorite']
-        
-        options=[]
-        if likes == True:
-            #clear like for the item
-            options.append(utils.language(30402))
-        if likes == False or likes == None:
-            #Like the item
-            options.append(utils.language(30403))
-        if likes == True or likes == None:
-            #Dislike the item
-            options.append(utils.language(30404)) 
-        if favourite == False:
-            #Add to emby favourites
-            options.append(utils.language(30405)) 
-        if favourite == True:
-            #Remove from emby favourites
-            options.append(utils.language(30406))
-        if itemtype == "song":
-            #Set custom song rating
-            options.append(utils.language(30407))
-        
-        #delete item
-        options.append(utils.language(30409))
-        
-        #addon settings
-        options.append(utils.language(30408))
-        
-        #display select dialog and process results
-        header = utils.language(30401)
-        ret = xbmcgui.Dialog().select(header, options)
-        if ret != -1:
-            if options[ret] == utils.language(30402):
-                emby.updateUserRating(embyid, deletelike=True)
-            if options[ret] == utils.language(30403):
-                emby.updateUserRating(embyid, like=True)
-            if options[ret] == utils.language(30404):
-                emby.updateUserRating(embyid, like=False)
-            if options[ret] == utils.language(30405):
-                emby.updateUserRating(embyid, favourite=True)
-            if options[ret] == utils.language(30406):
-                emby.updateUserRating(embyid, favourite=False)
-            if options[ret] == utils.language(30407):
-                kodiconn = utils.kodiSQL('music')
-                kodicursor = kodiconn.cursor()
-                query = ' '.join(("SELECT rating", "FROM song", "WHERE idSong = ?" ))
-                kodicursor.execute(query, (itemid,))
-                currentvalue = int(round(float(kodicursor.fetchone()[0]),0))
-                newvalue = xbmcgui.Dialog().numeric(0, "Set custom song rating (0-5)", str(currentvalue))
-                if newvalue:
-                    newvalue = int(newvalue)
-                    if newvalue > 5: newvalue = "5"
-                    if utils.settings('enableUpdateSongRating') == "true":
-                        musicutils.updateRatingToFile(newvalue, API.getFilePath())
-                    if utils.settings('enableExportSongRating') == "true":
-                        like, favourite, deletelike = musicutils.getEmbyRatingFromKodiRating(newvalue)
-                        emby.updateUserRating(embyid, like, favourite, deletelike)
-                    query = ' '.join(( "UPDATE song","SET rating = ?", "WHERE idSong = ?" ))
-                    kodicursor.execute(query, (newvalue,itemid,))
-                    kodiconn.commit()
-
-            if options[ret] == utils.language(30408):
-                #Open addon settings
-                xbmc.executebuiltin("Addon.OpenSettings(plugin.video.emby)")
-                
-            if options[ret] == utils.language(30409):
-                #delete item from the server
-                delete = True
-                if utils.settings('skipContextMenu') != "true":
-                    resp = xbmcgui.Dialog().yesno(
-                                            heading="Confirm delete",
-                                            line1=("Delete file from Emby Server? This will "
-                                                    "also delete the file(s) from disk!"))
-                    if not resp:
-                        logMsg("User skipped deletion for: %s." % embyid, 1)
-                        delete = False
-                
-                if delete:
-                    import downloadutils
-                    doUtils = downloadutils.DownloadUtils()
-                    url = "{server}/emby/Items/%s?format=json" % embyid
-                    logMsg("Deleting request: %s" % embyid, 0)
-                    doUtils.downloadUrl(url, type="DELETE")
-
-                '''if utils.settings('skipContextMenu') != "true":
-                    if xbmcgui.Dialog().yesno(
-                                        heading="Confirm delete",
-                                        line1=("Delete file on Emby Server? This will "
-                                                "also delete the file(s) from disk!")):
-                        import downloadutils
-                        doUtils = downloadutils.DownloadUtils()
-                        url = "{server}/emby/Items/%s?format=json" % embyid
-                        doUtils.downloadUrl(url, type="DELETE")'''
-            
-            xbmc.sleep(500)
+# -*- coding: utf-8 -*-
+
+#################################################################################################
+
+import os
+import sys
+import urlparse
+
+import xbmc
+import xbmcaddon
+import xbmcgui
+
+addon_ = xbmcaddon.Addon(id='plugin.video.emby')
+addon_path = addon_.getAddonInfo('path').decode('utf-8')
+base_resource = xbmc.translatePath(os.path.join(addon_path, 'resources', 'lib')).decode('utf-8')
+sys.path.append(base_resource)
+
+import artwork
+import utils
+import clientinfo
+import downloadutils
+import librarysync
+import read_embyserver as embyserver
+import embydb_functions as embydb
+import kodidb_functions as kodidb
+import musicutils as musicutils
+import api
+
+def logMsg(msg, lvl=1):
+    utils.logMsg("%s %s" % ("EMBY", "Contextmenu"), msg, lvl)
+
+
+#Kodi contextmenu item to configure the emby settings
+#for now used to set ratings but can later be used to sync individual items etc.
+if __name__ == '__main__':
+    itemid = xbmc.getInfoLabel("ListItem.DBID").decode("utf-8")
+    itemtype = xbmc.getInfoLabel("ListItem.DBTYPE").decode("utf-8")
+    
+    emby = embyserver.Read_EmbyServer()
+    
+    embyid = ""
+    if not itemtype and xbmc.getCondVisibility("Container.Content(albums)"): itemtype = "album"
+    if not itemtype and xbmc.getCondVisibility("Container.Content(artists)"): itemtype = "artist"
+    if not itemtype and xbmc.getCondVisibility("Container.Content(songs)"): itemtype = "song"
+    if not itemtype and xbmc.getCondVisibility("Container.Content(pictures)"): itemtype = "picture"
+    
+    if (not itemid or itemid == "-1") and xbmc.getInfoLabel("ListItem.Property(embyid)"):
+        embyid = xbmc.getInfoLabel("ListItem.Property(embyid)")
+    else:
+        embyconn = utils.kodiSQL('emby')
+        embycursor = embyconn.cursor()
+        emby_db = embydb.Embydb_Functions(embycursor)
+        item = emby_db.getItem_byKodiId(itemid, itemtype)
+        embycursor.close()
+        if item: embyid = item[0]
+    
+    logMsg("Contextmenu opened for embyid: %s  - itemtype: %s" %(embyid,itemtype))
+
+    if embyid:
+        item = emby.getItem(embyid)
+        API = api.API(item)
+        userdata = API.getUserData()
+        likes = userdata['Likes']
+        favourite = userdata['Favorite']
+        
+        options=[]
+        if likes == True:
+            #clear like for the item
+            options.append(utils.language(30402))
+        if likes == False or likes == None:
+            #Like the item
+            options.append(utils.language(30403))
+        if likes == True or likes == None:
+            #Dislike the item
+            options.append(utils.language(30404)) 
+        if favourite == False:
+            #Add to emby favourites
+            options.append(utils.language(30405)) 
+        if favourite == True:
+            #Remove from emby favourites
+            options.append(utils.language(30406))
+        if itemtype == "song":
+            #Set custom song rating
+            options.append(utils.language(30407))
+        
+        #delete item
+        options.append(utils.language(30409))
+        
+        #addon settings
+        options.append(utils.language(30408))
+        
+        #display select dialog and process results
+        header = utils.language(30401)
+        ret = xbmcgui.Dialog().select(header, options)
+        if ret != -1:
+            if options[ret] == utils.language(30402):
+                emby.updateUserRating(embyid, deletelike=True)
+            if options[ret] == utils.language(30403):
+                emby.updateUserRating(embyid, like=True)
+            if options[ret] == utils.language(30404):
+                emby.updateUserRating(embyid, like=False)
+            if options[ret] == utils.language(30405):
+                emby.updateUserRating(embyid, favourite=True)
+            if options[ret] == utils.language(30406):
+                emby.updateUserRating(embyid, favourite=False)
+            if options[ret] == utils.language(30407):
+                kodiconn = utils.kodiSQL('music')
+                kodicursor = kodiconn.cursor()
+                query = ' '.join(("SELECT rating", "FROM song", "WHERE idSong = ?" ))
+                kodicursor.execute(query, (itemid,))
+                currentvalue = int(round(float(kodicursor.fetchone()[0]),0))
+                newvalue = xbmcgui.Dialog().numeric(0, "Set custom song rating (0-5)", str(currentvalue))
+                if newvalue:
+                    newvalue = int(newvalue)
+                    if newvalue > 5: newvalue = "5"
+                    if utils.settings('enableUpdateSongRating') == "true":
+                        musicutils.updateRatingToFile(newvalue, API.getFilePath())
+                    if utils.settings('enableExportSongRating') == "true":
+                        like, favourite, deletelike = musicutils.getEmbyRatingFromKodiRating(newvalue)
+                        emby.updateUserRating(embyid, like, favourite, deletelike)
+                    query = ' '.join(( "UPDATE song","SET rating = ?", "WHERE idSong = ?" ))
+                    kodicursor.execute(query, (newvalue,itemid,))
+                    kodiconn.commit()
+
+            if options[ret] == utils.language(30408):
+                #Open addon settings
+                xbmc.executebuiltin("Addon.OpenSettings(plugin.video.emby)")
+                
+            if options[ret] == utils.language(30409):
+                #delete item from the server
+                delete = True
+                if utils.settings('skipContextMenu') != "true":
+                    resp = xbmcgui.Dialog().yesno(
+                                            heading="Confirm delete",
+                                            line1=("Delete file from Emby Server? This will "
+                                                    "also delete the file(s) from disk!"))
+                    if not resp:
+                        logMsg("User skipped deletion for: %s." % embyid, 1)
+                        delete = False
+                
+                if delete:
+                    import downloadutils
+                    doUtils = downloadutils.DownloadUtils()
+                    url = "{server}/emby/Items/%s?format=json" % embyid
+                    logMsg("Deleting request: %s" % embyid, 0)
+                    doUtils.downloadUrl(url, action_type="DELETE")
+
+                '''if utils.settings('skipContextMenu') != "true":
+                    if xbmcgui.Dialog().yesno(
+                                        heading="Confirm delete",
+                                        line1=("Delete file on Emby Server? This will "
+                                                "also delete the file(s) from disk!")):
+                        import downloadutils
+                        doUtils = downloadutils.DownloadUtils()
+                        doUtils.downloadUrl("{server}/emby/Items/%s?format=json" % embyid, action_type="DELETE")'''
+            
+            xbmc.sleep(500)
             xbmc.executebuiltin("Container.Update")
\ No newline at end of file
diff --git a/resources/lib/artwork.py b/resources/lib/artwork.py
index c5781e07..79fb617c 100644
--- a/resources/lib/artwork.py
+++ b/resources/lib/artwork.py
@@ -1,604 +1,604 @@
-# -*- coding: utf-8 -*-
-
-#################################################################################################
-
-import json
-import requests
-import os
-import urllib
-from sqlite3 import OperationalError
-
-import xbmc
-import xbmcgui
-import xbmcvfs
-
-import utils
-import clientinfo
-import image_cache_thread
-
-#################################################################################################
-
-
-class Artwork():
-
-    xbmc_host = 'localhost'
-    xbmc_port = None
-    xbmc_username = None
-    xbmc_password = None
-
-    imageCacheThreads = []
-    imageCacheLimitThreads = 0
-
-    def __init__(self):
-        self.clientinfo = clientinfo.ClientInfo()
-        self.addonName = self.clientinfo.getAddonName()
-
-        self.enableTextureCache = utils.settings('enableTextureCache') == "true"
-        self.imageCacheLimitThreads = int(utils.settings("imageCacheLimit"))
-        self.imageCacheLimitThreads = int(self.imageCacheLimitThreads * 5);
-        utils.logMsg("Using Image Cache Thread Count: " + str(self.imageCacheLimitThreads), 1)
-
-        if not self.xbmc_port and self.enableTextureCache:
-            self.setKodiWebServerDetails()
-
-        self.userId = utils.window('emby_currUser')
-        self.server = utils.window('emby_server%s' % self.userId)
-
-    def logMsg(self, msg, lvl=1):
-        className = self.__class__.__name__
-        utils.logMsg("%s %s" % (self.addonName, className), msg, lvl)
-
-
-    def double_urlencode(self, text):
-        text = self.single_urlencode(text)
-        text = self.single_urlencode(text)
-
-        return text
-
-    def single_urlencode(self, text):
-
-        text = urllib.urlencode({'blahblahblah':text.encode("utf-8")}) #urlencode needs a utf- string
-        text = text[13:]
-
-        return text.decode("utf-8") #return the result again as unicode
-
-    def setKodiWebServerDetails(self):
-        # Get the Kodi webserver details - used to set the texture cache
-        web_query = {
-
-            "jsonrpc": "2.0",
-            "id": 1,
-            "method": "Settings.GetSettingValue",
-            "params": {
-
-                "setting": "services.webserver"
-            }
-        }
-        result = xbmc.executeJSONRPC(json.dumps(web_query))
-        result = json.loads(result)
-        try:
-            xbmc_webserver_enabled = result['result']['value']
-        except TypeError:
-            xbmc_webserver_enabled = False
-
-        if not xbmc_webserver_enabled:
-            # Enable the webserver, it is disabled
-            web_port = {
-
-                "jsonrpc": "2.0",
-                "id": 1,
-                "method": "Settings.SetSettingValue",
-                "params": {
-
-                    "setting": "services.webserverport",
-                    "value": 8080
-                }
-            }
-            result = xbmc.executeJSONRPC(json.dumps(web_port))
-            self.xbmc_port = 8080
-
-            web_user = {
-
-                "jsonrpc": "2.0",
-                "id": 1,
-                "method": "Settings.SetSettingValue",
-                "params": {
-
-                    "setting": "services.webserver",
-                    "value": True
-                }
-            }
-            result = xbmc.executeJSONRPC(json.dumps(web_user))
-            self.xbmc_username = "kodi"
-
-
-        # Webserver already enabled
-        web_port = {
-
-            "jsonrpc": "2.0",
-            "id": 1,
-            "method": "Settings.GetSettingValue",
-            "params": {
-
-                "setting": "services.webserverport"
-            }
-        }
-        result = xbmc.executeJSONRPC(json.dumps(web_port))
-        result = json.loads(result)
-        try:
-            self.xbmc_port = result['result']['value']
-        except TypeError:
-            pass
-
-        web_user = {
-
-            "jsonrpc": "2.0",
-            "id": 1,
-            "method": "Settings.GetSettingValue",
-            "params": {
-
-                "setting": "services.webserverusername"
-            }
-        }
-        result = xbmc.executeJSONRPC(json.dumps(web_user))
-        result = json.loads(result)
-        try:
-            self.xbmc_username = result['result']['value']
-        except TypeError:
-            pass
-
-        web_pass = {
-
-            "jsonrpc": "2.0",
-            "id": 1,
-            "method": "Settings.GetSettingValue",
-            "params": {
-
-                "setting": "services.webserverpassword"
-            }
-        }
-        result = xbmc.executeJSONRPC(json.dumps(web_pass))
-        result = json.loads(result)
-        try:
-            self.xbmc_password = result['result']['value']
-        except TypeError:
-            pass
-
-    def FullTextureCacheSync(self):
-        # This method will sync all Kodi artwork to textures13.db
-        # and cache them locally. This takes diskspace!
-
-        if not xbmcgui.Dialog().yesno("Image Texture Cache", "Running the image cache process can take some time.", "Are you sure you want continue?"):
-            return
-
-        self.logMsg("Doing Image Cache Sync", 1)
-
-        dialog = xbmcgui.DialogProgress()
-        dialog.create("Emby for Kodi", "Image Cache Sync")
-
-        # ask to rest all existing or not
-        if xbmcgui.Dialog().yesno("Image Texture Cache", "Reset all existing cache data first?", ""):
-            self.logMsg("Resetting all cache data first", 1)
-            # Remove all existing textures first
-            path = xbmc.translatePath("special://thumbnails/").decode('utf-8')
-            if xbmcvfs.exists(path):
-                allDirs, allFiles = xbmcvfs.listdir(path)
-                for dir in allDirs:
-                    allDirs, allFiles = xbmcvfs.listdir(path+dir)
-                    for file in allFiles:
-                        if os.path.supports_unicode_filenames:
-                            xbmcvfs.delete(os.path.join(path+dir.decode('utf-8'),file.decode('utf-8')))
-                        else:
-                            xbmcvfs.delete(os.path.join(path.encode('utf-8')+dir,file))
-
-            # remove all existing data from texture DB
-            textureconnection = utils.kodiSQL('texture')
-            texturecursor = textureconnection.cursor()
-            texturecursor.execute('SELECT tbl_name FROM sqlite_master WHERE type="table"')
-            rows = texturecursor.fetchall()
-            for row in rows:
-                tableName = row[0]
-                if(tableName != "version"):
-                    texturecursor.execute("DELETE FROM " + tableName)
-            textureconnection.commit()
-            texturecursor.close()
-
-        # Cache all entries in video DB
-        connection = utils.kodiSQL('video')
-        cursor = connection.cursor()
-        cursor.execute("SELECT url FROM art WHERE media_type != 'actor'") # dont include actors
-        result = cursor.fetchall()
-        total = len(result)
-        count = 1
-        percentage = 0
-        self.logMsg("Image cache sync about to process " + str(total) + " images", 1)
-        for url in result:
-            if dialog.iscanceled():
-                break
-            percentage = int((float(count) / float(total))*100)
-            textMessage = str(count) + " of " + str(total) + " (" + str(len(self.imageCacheThreads)) + ")"
-            dialog.update(percentage, "Updating Image Cache: " + textMessage)
-            self.CacheTexture(url[0])
-            count += 1
-        cursor.close()
-
-        # Cache all entries in music DB
-        connection = utils.kodiSQL('music')
-        cursor = connection.cursor()
-        cursor.execute("SELECT url FROM art")
-        result = cursor.fetchall()
-        total = len(result)
-        count = 1
-        percentage = 0
-        self.logMsg("Image cache sync about to process " + str(total) + " images", 1)
-        for url in result:
-            if dialog.iscanceled():
-                break
-            percentage = int((float(count) / float(total))*100)
-            textMessage = str(count) + " of " + str(total)
-            dialog.update(percentage, "Updating Image Cache: " + textMessage)
-            self.CacheTexture(url[0])
-            count += 1
-        cursor.close()
-
-        dialog.update(100, "Waiting for all threads to exit: " + str(len(self.imageCacheThreads)))
-        self.logMsg("Waiting for all threads to exit", 1)
-        while len(self.imageCacheThreads) > 0:
-            for thread in self.imageCacheThreads:
-                if thread.isFinished:
-                    self.imageCacheThreads.remove(thread)
-            dialog.update(100, "Waiting for all threads to exit: " + str(len(self.imageCacheThreads)))
-            self.logMsg("Waiting for all threads to exit: " + str(len(self.imageCacheThreads)), 1)
-            xbmc.sleep(500)
-
-        dialog.close()
-
-    def addWorkerImageCacheThread(self, urlToAdd):
-
-        while(True):
-            # removed finished
-            for thread in self.imageCacheThreads:
-                if thread.isFinished:
-                    self.imageCacheThreads.remove(thread)
-
-            # add a new thread or wait and retry if we hit our limit
-            if(len(self.imageCacheThreads) < self.imageCacheLimitThreads):
-                newThread = image_cache_thread.image_cache_thread()
-                newThread.setUrl(self.double_urlencode(urlToAdd))
-                newThread.setHost(self.xbmc_host, self.xbmc_port)
-                newThread.setAuth(self.xbmc_username, self.xbmc_password)
-                newThread.start()
-                self.imageCacheThreads.append(newThread)
-                return
-            else:
-                self.logMsg("Waiting for empty queue spot: " + str(len(self.imageCacheThreads)), 2)
-                xbmc.sleep(50)
-
-
-    def CacheTexture(self, url):
-        # Cache a single image url to the texture cache
-        if url and self.enableTextureCache:
-            self.logMsg("Processing: %s" % url, 2)
-
-            if(self.imageCacheLimitThreads == 0 or self.imageCacheLimitThreads == None):
-                #Add image to texture cache by simply calling it at the http endpoint
-
-                url = self.double_urlencode(url)
-                try: # Extreme short timeouts so we will have a exception.
-                    response = requests.head(
-                                        url=(
-                                            "http://%s:%s/image/image://%s"
-                                            % (self.xbmc_host, self.xbmc_port, url)),
-                                        auth=(self.xbmc_username, self.xbmc_password),
-                                        timeout=(0.01, 0.01))
-                # We don't need the result
-                except: pass
-
-            else:
-                self.addWorkerImageCacheThread(url)
-
-
-    def addArtwork(self, artwork, kodiId, mediaType, cursor):
-        # Kodi conversion table
-        kodiart = {
-
-            'Primary': ["thumb", "poster"],
-            'Banner': "banner",
-            'Logo': "clearlogo",
-            'Art': "clearart",
-            'Thumb': "landscape",
-            'Disc': "discart",
-            'Backdrop': "fanart",
-            'BoxRear': "poster"
-        }
-
-        # Artwork is a dictionary
-        for art in artwork:
-
-            if art == "Backdrop":
-                # Backdrop entry is a list
-                # Process extra fanart for artwork downloader (fanart, fanart1, fanart2...)
-                backdrops = artwork[art]
-                backdropsNumber = len(backdrops)
-
-                query = ' '.join((
-
-                    "SELECT url",
-                    "FROM art",
-                    "WHERE media_id = ?",
-                    "AND media_type = ?",
-                    "AND type LIKE ?"
-                ))
-                cursor.execute(query, (kodiId, mediaType, "fanart%",))
-                rows = cursor.fetchall()
-
-                if len(rows) > backdropsNumber:
-                    # More backdrops in database. Delete extra fanart.
-                    query = ' '.join((
-
-                        "DELETE FROM art",
-                        "WHERE media_id = ?",
-                        "AND media_type = ?",
-                        "AND type LIKE ?"
-                    ))
-                    cursor.execute(query, (kodiId, mediaType, "fanart_",))
-
-                # Process backdrops and extra fanart
-                index = ""
-                for backdrop in backdrops:
-                    self.addOrUpdateArt(
-                        imageUrl=backdrop,
-                        kodiId=kodiId,
-                        mediaType=mediaType,
-                        imageType="%s%s" % ("fanart", index),
-                        cursor=cursor)
-
-                    if backdropsNumber > 1:
-                        try: # Will only fail on the first try, str to int.
-                            index += 1
-                        except TypeError:
-                            index = 1
-
-            elif art == "Primary":
-                # Primary art is processed as thumb and poster for Kodi.
-                for artType in kodiart[art]:
-                    self.addOrUpdateArt(
-                        imageUrl=artwork[art],
-                        kodiId=kodiId,
-                        mediaType=mediaType,
-                        imageType=artType,
-                        cursor=cursor)
-
-            elif kodiart.get(art):
-                # Process the rest artwork type that Kodi can use
-                self.addOrUpdateArt(
-                    imageUrl=artwork[art],
-                    kodiId=kodiId,
-                    mediaType=mediaType,
-                    imageType=kodiart[art],
-                    cursor=cursor)
-
-    def addOrUpdateArt(self, imageUrl, kodiId, mediaType, imageType, cursor):
-        # Possible that the imageurl is an empty string
-        if imageUrl:
-            cacheimage = False
-
-            query = ' '.join((
-
-                "SELECT url",
-                "FROM art",
-                "WHERE media_id = ?",
-                "AND media_type = ?",
-                "AND type = ?"
-            ))
-            cursor.execute(query, (kodiId, mediaType, imageType,))
-            try: # Update the artwork
-                url = cursor.fetchone()[0]
-
-            except TypeError: # Add the artwork
-                cacheimage = True
-                self.logMsg("Adding Art Link for kodiId: %s (%s)" % (kodiId, imageUrl), 2)
-
-                query = (
-                    '''
-                    INSERT INTO art(media_id, media_type, type, url)
-
-                    VALUES (?, ?, ?, ?)
-                    '''
-                )
-                cursor.execute(query, (kodiId, mediaType, imageType, imageUrl))
-
-            else: # Only cache artwork if it changed
-                if url != imageUrl:
-                    cacheimage = True
-
-                    # Only for the main backdrop, poster
-                    if (utils.window('emby_initialScan') != "true" and
-                            imageType in ("fanart", "poster")):
-                        # Delete current entry before updating with the new one
-                        self.deleteCachedArtwork(url)
-
-                    self.logMsg(
-                        "Updating Art url for %s kodiId: %s (%s) -> (%s)"
-                        % (imageType, kodiId, url, imageUrl), 1)
-
-                    query = ' '.join((
-
-                        "UPDATE art",
-                        "SET url = ?",
-                        "WHERE media_id = ?",
-                        "AND media_type = ?",
-                        "AND type = ?"
-                    ))
-                    cursor.execute(query, (imageUrl, kodiId, mediaType, imageType))
-
-            # Cache fanart and poster in Kodi texture cache
-            if cacheimage and imageType in ("fanart", "poster"):
-                self.CacheTexture(imageUrl)
-
-    def deleteArtwork(self, kodiid, mediatype, cursor):
-
-        query = ' '.join((
-
-            "SELECT url, type",
-            "FROM art",
-            "WHERE media_id = ?",
-            "AND media_type = ?"
-        ))
-        cursor.execute(query, (kodiid, mediatype,))
-        rows = cursor.fetchall()
-        for row in rows:
-
-            url = row[0]
-            imagetype = row[1]
-            if imagetype in ("poster", "fanart"):
-                self.deleteCachedArtwork(url)
-
-    def deleteCachedArtwork(self, url):
-        # Only necessary to remove and apply a new backdrop or poster
-        connection = utils.kodiSQL('texture')
-        cursor = connection.cursor()
-
-        try:
-            cursor.execute("SELECT cachedurl FROM texture WHERE url = ?", (url,))
-            cachedurl = cursor.fetchone()[0]
-
-        except TypeError:
-            self.logMsg("Could not find cached url.", 1)
-
-        except OperationalError:
-            self.logMsg("Database is locked. Skip deletion process.", 1)
-
-        else: # Delete thumbnail as well as the entry
-            thumbnails = xbmc.translatePath("special://thumbnails/%s" % cachedurl).decode('utf-8')
-            self.logMsg("Deleting cached thumbnail: %s" % thumbnails, 1)
-            xbmcvfs.delete(thumbnails)
-
-            try:
-                cursor.execute("DELETE FROM texture WHERE url = ?", (url,))
-                connection.commit()
-            except OperationalError:
-                self.logMsg("Issue deleting url from cache. Skipping.", 2)
-
-        finally:
-            cursor.close()
-
-    def getPeopleArtwork(self, people):
-        # append imageurl if existing
-        for person in people:
-
-            personId = person['Id']
-            tag = person.get('PrimaryImageTag')
-
-            image = ""
-            if tag:
-                image = (
-                    "%s/emby/Items/%s/Images/Primary?"
-                    "MaxWidth=400&MaxHeight=400&Index=0&Tag=%s"
-                    % (self.server, personId, tag))
-
-            person['imageurl'] = image
-
-        return people
-
-    def getUserArtwork(self, itemid, itemtype):
-        # Load user information set by UserClient
-        image = ("%s/emby/Users/%s/Images/%s?Format=original"
-                    % (self.server, itemid, itemtype))
-        return image
-
-    def getAllArtwork(self, item, parentInfo=False):
-
-        itemid = item['Id']
-        artworks = item['ImageTags']
-        backdrops = item.get('BackdropImageTags',[])
-
-        maxHeight = 10000
-        maxWidth = 10000
-        customquery = ""
-
-        if utils.settings('compressArt') == "true":
-            customquery = "&Quality=90"
-
-        if utils.settings('enableCoverArt') == "false":
-            customquery += "&EnableImageEnhancers=false"
-
-        allartworks = {
-
-            'Primary': "",
-            'Art': "",
-            'Banner': "",
-            'Logo': "",
-            'Thumb': "",
-            'Disc': "",
-            'Backdrop': []
-        }
-
-        # Process backdrops
-        for index, tag in enumerate(backdrops):
-            artwork = (
-                "%s/emby/Items/%s/Images/Backdrop/%s?"
-                "MaxWidth=%s&MaxHeight=%s&Format=original&Tag=%s%s"
-                % (self.server, itemid, index, maxWidth, maxHeight, tag, customquery))
-            allartworks['Backdrop'].append(artwork)
-
-        # Process the rest of the artwork
-        for art in artworks:
-            # Filter backcover
-            if art != "BoxRear":
-                tag = artworks[art]
-                artwork = (
-                    "%s/emby/Items/%s/Images/%s/0?"
-                    "MaxWidth=%s&MaxHeight=%s&Format=original&Tag=%s%s"
-                    % (self.server, itemid, art, maxWidth, maxHeight, tag, customquery))
-                allartworks[art] = artwork
-
-        # Process parent items if the main item is missing artwork
-        if parentInfo:
-
-            # Process parent backdrops
-            if not allartworks['Backdrop']:
-
-                parentId = item.get('ParentBackdropItemId')
-                if parentId:
-                    # If there is a parentId, go through the parent backdrop list
-                    parentbackdrops = item['ParentBackdropImageTags']
-
-                    for index, tag in enumerate(parentbackdrops):
-                        artwork = (
-                            "%s/emby/Items/%s/Images/Backdrop/%s?"
-                            "MaxWidth=%s&MaxHeight=%s&Format=original&Tag=%s%s"
-                            % (self.server, parentId, index, maxWidth, maxHeight, tag, customquery))
-                        allartworks['Backdrop'].append(artwork)
-
-            # Process the rest of the artwork
-            parentartwork = ['Logo', 'Art', 'Thumb']
-            for parentart in parentartwork:
-
-                if not allartworks[parentart]:
-
-                    parentId = item.get('Parent%sItemId' % parentart)
-                    if parentId:
-
-                        parentTag = item['Parent%sImageTag' % parentart]
-                        artwork = (
-                            "%s/emby/Items/%s/Images/%s/0?"
-                            "MaxWidth=%s&MaxHeight=%s&Format=original&Tag=%s%s"
-                            % (self.server, parentId, parentart,
-                                maxWidth, maxHeight, parentTag, customquery))
-                        allartworks[parentart] = artwork
-
-            # Parent album works a bit differently
-            if not allartworks['Primary']:
-
-                parentId = item.get('AlbumId')
-                if parentId and item.get('AlbumPrimaryImageTag'):
-
-                    parentTag = item['AlbumPrimaryImageTag']
-                    artwork = (
-                        "%s/emby/Items/%s/Images/Primary/0?"
-                        "MaxWidth=%s&MaxHeight=%s&Format=original&Tag=%s%s"
-                        % (self.server, parentId, maxWidth, maxHeight, parentTag, customquery))
-                    allartworks['Primary'] = artwork
-
+# -*- coding: utf-8 -*-
+
+#################################################################################################
+
+import json
+import requests
+import os
+import urllib
+from sqlite3 import OperationalError
+
+import xbmc
+import xbmcgui
+import xbmcvfs
+
+import utils
+import clientinfo
+import image_cache_thread
+
+#################################################################################################
+
+
+class Artwork():
+
+    xbmc_host = 'localhost'
+    xbmc_port = None
+    xbmc_username = None
+    xbmc_password = None
+
+    imageCacheThreads = []
+    imageCacheLimitThreads = 0
+
+    def __init__(self):
+        self.clientinfo = clientinfo.ClientInfo()
+        self.addonName = self.clientinfo.getAddonName()
+
+        self.enableTextureCache = utils.settings('enableTextureCache') == "true"
+        self.imageCacheLimitThreads = int(utils.settings("imageCacheLimit"))
+        self.imageCacheLimitThreads = int(self.imageCacheLimitThreads * 5)
+        utils.logMsg("Using Image Cache Thread Count: " + str(self.imageCacheLimitThreads), 1)
+
+        if not self.xbmc_port and self.enableTextureCache:
+            self.setKodiWebServerDetails()
+
+        self.userId = utils.window('emby_currUser')
+        self.server = utils.window('emby_server%s' % self.userId)
+
+    def logMsg(self, msg, lvl=1):
+        className = self.__class__.__name__
+        utils.logMsg("%s %s" % (self.addonName, className), msg, lvl)
+
+
+    def double_urlencode(self, text):
+        text = self.single_urlencode(text)
+        text = self.single_urlencode(text)
+
+        return text
+
+    def single_urlencode(self, text):
+
+        text = urllib.urlencode({'blahblahblah':text.encode("utf-8")}) #urlencode needs a utf- string
+        text = text[13:]
+
+        return text.decode("utf-8") #return the result again as unicode
+
+    def setKodiWebServerDetails(self):
+        # Get the Kodi webserver details - used to set the texture cache
+        web_query = {
+
+            "jsonrpc": "2.0",
+            "id": 1,
+            "method": "Settings.GetSettingValue",
+            "params": {
+
+                "setting": "services.webserver"
+            }
+        }
+        result = xbmc.executeJSONRPC(json.dumps(web_query))
+        result = json.loads(result)
+        try:
+            xbmc_webserver_enabled = result['result']['value']
+        except TypeError:
+            xbmc_webserver_enabled = False
+
+        if not xbmc_webserver_enabled:
+            # Enable the webserver, it is disabled
+            web_port = {
+
+                "jsonrpc": "2.0",
+                "id": 1,
+                "method": "Settings.SetSettingValue",
+                "params": {
+
+                    "setting": "services.webserverport",
+                    "value": 8080
+                }
+            }
+            result = xbmc.executeJSONRPC(json.dumps(web_port))
+            self.xbmc_port = 8080
+
+            web_user = {
+
+                "jsonrpc": "2.0",
+                "id": 1,
+                "method": "Settings.SetSettingValue",
+                "params": {
+
+                    "setting": "services.webserver",
+                    "value": True
+                }
+            }
+            result = xbmc.executeJSONRPC(json.dumps(web_user))
+            self.xbmc_username = "kodi"
+
+
+        # Webserver already enabled
+        web_port = {
+
+            "jsonrpc": "2.0",
+            "id": 1,
+            "method": "Settings.GetSettingValue",
+            "params": {
+
+                "setting": "services.webserverport"
+            }
+        }
+        result = xbmc.executeJSONRPC(json.dumps(web_port))
+        result = json.loads(result)
+        try:
+            self.xbmc_port = result['result']['value']
+        except TypeError:
+            pass
+
+        web_user = {
+
+            "jsonrpc": "2.0",
+            "id": 1,
+            "method": "Settings.GetSettingValue",
+            "params": {
+
+                "setting": "services.webserverusername"
+            }
+        }
+        result = xbmc.executeJSONRPC(json.dumps(web_user))
+        result = json.loads(result)
+        try:
+            self.xbmc_username = result['result']['value']
+        except TypeError:
+            pass
+
+        web_pass = {
+
+            "jsonrpc": "2.0",
+            "id": 1,
+            "method": "Settings.GetSettingValue",
+            "params": {
+
+                "setting": "services.webserverpassword"
+            }
+        }
+        result = xbmc.executeJSONRPC(json.dumps(web_pass))
+        result = json.loads(result)
+        try:
+            self.xbmc_password = result['result']['value']
+        except TypeError:
+            pass
+
+    def FullTextureCacheSync(self):
+        # This method will sync all Kodi artwork to textures13.db
+        # and cache them locally. This takes diskspace!
+
+        if not xbmcgui.Dialog().yesno("Image Texture Cache", "Running the image cache process can take some time.", "Are you sure you want continue?"):
+            return
+
+        self.logMsg("Doing Image Cache Sync", 1)
+
+        dialog = xbmcgui.DialogProgress()
+        dialog.create("Emby for Kodi", "Image Cache Sync")
+
+        # ask to rest all existing or not
+        if xbmcgui.Dialog().yesno("Image Texture Cache", "Reset all existing cache data first?", ""):
+            self.logMsg("Resetting all cache data first", 1)
+            # Remove all existing textures first
+            path = xbmc.translatePath("special://thumbnails/").decode('utf-8')
+            if xbmcvfs.exists(path):
+                allDirs, allFiles = xbmcvfs.listdir(path)
+                for dir in allDirs:
+                    allDirs, allFiles = xbmcvfs.listdir(path+dir)
+                    for file in allFiles:
+                        if os.path.supports_unicode_filenames:
+                            xbmcvfs.delete(os.path.join(path+dir.decode('utf-8'),file.decode('utf-8')))
+                        else:
+                            xbmcvfs.delete(os.path.join(path.encode('utf-8')+dir,file))
+
+            # remove all existing data from texture DB
+            textureconnection = utils.kodiSQL('texture')
+            texturecursor = textureconnection.cursor()
+            texturecursor.execute('SELECT tbl_name FROM sqlite_master WHERE type="table"')
+            rows = texturecursor.fetchall()
+            for row in rows:
+                tableName = row[0]
+                if(tableName != "version"):
+                    texturecursor.execute("DELETE FROM " + tableName)
+            textureconnection.commit()
+            texturecursor.close()
+
+        # Cache all entries in video DB
+        connection = utils.kodiSQL('video')
+        cursor = connection.cursor()
+        cursor.execute("SELECT url FROM art WHERE media_type != 'actor'") # dont include actors
+        result = cursor.fetchall()
+        total = len(result)
+        count = 1
+        percentage = 0
+        self.logMsg("Image cache sync about to process " + str(total) + " images", 1)
+        for url in result:
+            if dialog.iscanceled():
+                break
+            percentage = int((float(count) / float(total))*100)
+            textMessage = str(count) + " of " + str(total) + " (" + str(len(self.imageCacheThreads)) + ")"
+            dialog.update(percentage, "Updating Image Cache: " + textMessage)
+            self.CacheTexture(url[0])
+            count += 1
+        cursor.close()
+
+        # Cache all entries in music DB
+        connection = utils.kodiSQL('music')
+        cursor = connection.cursor()
+        cursor.execute("SELECT url FROM art")
+        result = cursor.fetchall()
+        total = len(result)
+        count = 1
+        percentage = 0
+        self.logMsg("Image cache sync about to process " + str(total) + " images", 1)
+        for url in result:
+            if dialog.iscanceled():
+                break
+            percentage = int((float(count) / float(total))*100)
+            textMessage = str(count) + " of " + str(total)
+            dialog.update(percentage, "Updating Image Cache: " + textMessage)
+            self.CacheTexture(url[0])
+            count += 1
+        cursor.close()
+
+        dialog.update(100, "Waiting for all threads to exit: " + str(len(self.imageCacheThreads)))
+        self.logMsg("Waiting for all threads to exit", 1)
+        while len(self.imageCacheThreads) > 0:
+            for thread in self.imageCacheThreads:
+                if thread.isFinished:
+                    self.imageCacheThreads.remove(thread)
+            dialog.update(100, "Waiting for all threads to exit: " + str(len(self.imageCacheThreads)))
+            self.logMsg("Waiting for all threads to exit: " + str(len(self.imageCacheThreads)), 1)
+            xbmc.sleep(500)
+
+        dialog.close()
+
+    def addWorkerImageCacheThread(self, urlToAdd):
+
+        while(True):
+            # removed finished
+            for thread in self.imageCacheThreads:
+                if thread.isFinished:
+                    self.imageCacheThreads.remove(thread)
+
+            # add a new thread or wait and retry if we hit our limit
+            if(len(self.imageCacheThreads) < self.imageCacheLimitThreads):
+                newThread = image_cache_thread.image_cache_thread()
+                newThread.setUrl(self.double_urlencode(urlToAdd))
+                newThread.setHost(self.xbmc_host, self.xbmc_port)
+                newThread.setAuth(self.xbmc_username, self.xbmc_password)
+                newThread.start()
+                self.imageCacheThreads.append(newThread)
+                return
+            else:
+                self.logMsg("Waiting for empty queue spot: " + str(len(self.imageCacheThreads)), 2)
+                xbmc.sleep(50)
+
+
+    def CacheTexture(self, url):
+        # Cache a single image url to the texture cache
+        if url and self.enableTextureCache:
+            self.logMsg("Processing: %s" % url, 2)
+
+            if(self.imageCacheLimitThreads == 0 or self.imageCacheLimitThreads == None):
+                #Add image to texture cache by simply calling it at the http endpoint
+
+                url = self.double_urlencode(url)
+                try: # Extreme short timeouts so we will have a exception.
+                    response = requests.head(
+                                        url=(
+                                            "http://%s:%s/image/image://%s"
+                                            % (self.xbmc_host, self.xbmc_port, url)),
+                                        auth=(self.xbmc_username, self.xbmc_password),
+                                        timeout=(0.01, 0.01))
+                # We don't need the result
+                except: pass
+
+            else:
+                self.addWorkerImageCacheThread(url)
+
+
+    def addArtwork(self, artwork, kodiId, mediaType, cursor):
+        # Kodi conversion table
+        kodiart = {
+
+            'Primary': ["thumb", "poster"],
+            'Banner': "banner",
+            'Logo': "clearlogo",
+            'Art': "clearart",
+            'Thumb': "landscape",
+            'Disc': "discart",
+            'Backdrop': "fanart",
+            'BoxRear': "poster"
+        }
+
+        # Artwork is a dictionary
+        for art in artwork:
+
+            if art == "Backdrop":
+                # Backdrop entry is a list
+                # Process extra fanart for artwork downloader (fanart, fanart1, fanart2...)
+                backdrops = artwork[art]
+                backdropsNumber = len(backdrops)
+
+                query = ' '.join((
+
+                    "SELECT url",
+                    "FROM art",
+                    "WHERE media_id = ?",
+                    "AND media_type = ?",
+                    "AND type LIKE ?"
+                ))
+                cursor.execute(query, (kodiId, mediaType, "fanart%",))
+                rows = cursor.fetchall()
+
+                if len(rows) > backdropsNumber:
+                    # More backdrops in database. Delete extra fanart.
+                    query = ' '.join((
+
+                        "DELETE FROM art",
+                        "WHERE media_id = ?",
+                        "AND media_type = ?",
+                        "AND type LIKE ?"
+                    ))
+                    cursor.execute(query, (kodiId, mediaType, "fanart_",))
+
+                # Process backdrops and extra fanart
+                index = ""
+                for backdrop in backdrops:
+                    self.addOrUpdateArt(
+                        imageUrl=backdrop,
+                        kodiId=kodiId,
+                        mediaType=mediaType,
+                        imageType="%s%s" % ("fanart", index),
+                        cursor=cursor)
+
+                    if backdropsNumber > 1:
+                        try: # Will only fail on the first try, str to int.
+                            index += 1
+                        except TypeError:
+                            index = 1
+
+            elif art == "Primary":
+                # Primary art is processed as thumb and poster for Kodi.
+                for artType in kodiart[art]:
+                    self.addOrUpdateArt(
+                        imageUrl=artwork[art],
+                        kodiId=kodiId,
+                        mediaType=mediaType,
+                        imageType=artType,
+                        cursor=cursor)
+
+            elif kodiart.get(art):
+                # Process the rest artwork type that Kodi can use
+                self.addOrUpdateArt(
+                    imageUrl=artwork[art],
+                    kodiId=kodiId,
+                    mediaType=mediaType,
+                    imageType=kodiart[art],
+                    cursor=cursor)
+
+    def addOrUpdateArt(self, imageUrl, kodiId, mediaType, imageType, cursor):
+        # Possible that the imageurl is an empty string
+        if imageUrl:
+            cacheimage = False
+
+            query = ' '.join((
+
+                "SELECT url",
+                "FROM art",
+                "WHERE media_id = ?",
+                "AND media_type = ?",
+                "AND type = ?"
+            ))
+            cursor.execute(query, (kodiId, mediaType, imageType,))
+            try: # Update the artwork
+                url = cursor.fetchone()[0]
+
+            except TypeError: # Add the artwork
+                cacheimage = True
+                self.logMsg("Adding Art Link for kodiId: %s (%s)" % (kodiId, imageUrl), 2)
+
+                query = (
+                    '''
+                    INSERT INTO art(media_id, media_type, type, url)
+
+                    VALUES (?, ?, ?, ?)
+                    '''
+                )
+                cursor.execute(query, (kodiId, mediaType, imageType, imageUrl))
+
+            else: # Only cache artwork if it changed
+                if url != imageUrl:
+                    cacheimage = True
+
+                    # Only for the main backdrop, poster
+                    if (utils.window('emby_initialScan') != "true" and
+                            imageType in ("fanart", "poster")):
+                        # Delete current entry before updating with the new one
+                        self.deleteCachedArtwork(url)
+
+                    self.logMsg(
+                        "Updating Art url for %s kodiId: %s (%s) -> (%s)"
+                        % (imageType, kodiId, url, imageUrl), 1)
+
+                    query = ' '.join((
+
+                        "UPDATE art",
+                        "SET url = ?",
+                        "WHERE media_id = ?",
+                        "AND media_type = ?",
+                        "AND type = ?"
+                    ))
+                    cursor.execute(query, (imageUrl, kodiId, mediaType, imageType))
+
+            # Cache fanart and poster in Kodi texture cache
+            if cacheimage and imageType in ("fanart", "poster"):
+                self.CacheTexture(imageUrl)
+
+    def deleteArtwork(self, kodiid, mediatype, cursor):
+
+        query = ' '.join((
+
+            "SELECT url, type",
+            "FROM art",
+            "WHERE media_id = ?",
+            "AND media_type = ?"
+        ))
+        cursor.execute(query, (kodiid, mediatype,))
+        rows = cursor.fetchall()
+        for row in rows:
+
+            url = row[0]
+            imagetype = row[1]
+            if imagetype in ("poster", "fanart"):
+                self.deleteCachedArtwork(url)
+
+    def deleteCachedArtwork(self, url):
+        # Only necessary to remove and apply a new backdrop or poster
+        connection = utils.kodiSQL('texture')
+        cursor = connection.cursor()
+
+        try:
+            cursor.execute("SELECT cachedurl FROM texture WHERE url = ?", (url,))
+            cachedurl = cursor.fetchone()[0]
+
+        except TypeError:
+            self.logMsg("Could not find cached url.", 1)
+
+        except OperationalError:
+            self.logMsg("Database is locked. Skip deletion process.", 1)
+
+        else: # Delete thumbnail as well as the entry
+            thumbnails = xbmc.translatePath("special://thumbnails/%s" % cachedurl).decode('utf-8')
+            self.logMsg("Deleting cached thumbnail: %s" % thumbnails, 1)
+            xbmcvfs.delete(thumbnails)
+
+            try:
+                cursor.execute("DELETE FROM texture WHERE url = ?", (url,))
+                connection.commit()
+            except OperationalError:
+                self.logMsg("Issue deleting url from cache. Skipping.", 2)
+
+        finally:
+            cursor.close()
+
+    def getPeopleArtwork(self, people):
+        # append imageurl if existing
+        for person in people:
+
+            personId = person['Id']
+            tag = person.get('PrimaryImageTag')
+
+            image = ""
+            if tag:
+                image = (
+                    "%s/emby/Items/%s/Images/Primary?"
+                    "MaxWidth=400&MaxHeight=400&Index=0&Tag=%s"
+                    % (self.server, personId, tag))
+
+            person['imageurl'] = image
+
+        return people
+
+    def getUserArtwork(self, itemid, itemtype):
+        # Load user information set by UserClient
+        image = ("%s/emby/Users/%s/Images/%s?Format=original"
+                    % (self.server, itemid, itemtype))
+        return image
+
+    def getAllArtwork(self, item, parentInfo=False):
+
+        itemid = item['Id']
+        artworks = item['ImageTags']
+        backdrops = item.get('BackdropImageTags',[])
+
+        maxHeight = 10000
+        maxWidth = 10000
+        customquery = ""
+
+        if utils.settings('compressArt') == "true":
+            customquery = "&Quality=90"
+
+        if utils.settings('enableCoverArt') == "false":
+            customquery += "&EnableImageEnhancers=false"
+
+        allartworks = {
+
+            'Primary': "",
+            'Art': "",
+            'Banner': "",
+            'Logo': "",
+            'Thumb': "",
+            'Disc': "",
+            'Backdrop': []
+        }
+
+        # Process backdrops
+        for index, tag in enumerate(backdrops):
+            artwork = (
+                "%s/emby/Items/%s/Images/Backdrop/%s?"
+                "MaxWidth=%s&MaxHeight=%s&Format=original&Tag=%s%s"
+                % (self.server, itemid, index, maxWidth, maxHeight, tag, customquery))
+            allartworks['Backdrop'].append(artwork)
+
+        # Process the rest of the artwork
+        for art in artworks:
+            # Filter backcover
+            if art != "BoxRear":
+                tag = artworks[art]
+                artwork = (
+                    "%s/emby/Items/%s/Images/%s/0?"
+                    "MaxWidth=%s&MaxHeight=%s&Format=original&Tag=%s%s"
+                    % (self.server, itemid, art, maxWidth, maxHeight, tag, customquery))
+                allartworks[art] = artwork
+
+        # Process parent items if the main item is missing artwork
+        if parentInfo:
+
+            # Process parent backdrops
+            if not allartworks['Backdrop']:
+
+                parentId = item.get('ParentBackdropItemId')
+                if parentId:
+                    # If there is a parentId, go through the parent backdrop list
+                    parentbackdrops = item['ParentBackdropImageTags']
+
+                    for index, tag in enumerate(parentbackdrops):
+                        artwork = (
+                            "%s/emby/Items/%s/Images/Backdrop/%s?"
+                            "MaxWidth=%s&MaxHeight=%s&Format=original&Tag=%s%s"
+                            % (self.server, parentId, index, maxWidth, maxHeight, tag, customquery))
+                        allartworks['Backdrop'].append(artwork)
+
+            # Process the rest of the artwork
+            parentartwork = ['Logo', 'Art', 'Thumb']
+            for parentart in parentartwork:
+
+                if not allartworks[parentart]:
+
+                    parentId = item.get('Parent%sItemId' % parentart)
+                    if parentId:
+
+                        parentTag = item['Parent%sImageTag' % parentart]
+                        artwork = (
+                            "%s/emby/Items/%s/Images/%s/0?"
+                            "MaxWidth=%s&MaxHeight=%s&Format=original&Tag=%s%s"
+                            % (self.server, parentId, parentart,
+                                maxWidth, maxHeight, parentTag, customquery))
+                        allartworks[parentart] = artwork
+
+            # Parent album works a bit differently
+            if not allartworks['Primary']:
+
+                parentId = item.get('AlbumId')
+                if parentId and item.get('AlbumPrimaryImageTag'):
+
+                    parentTag = item['AlbumPrimaryImageTag']
+                    artwork = (
+                        "%s/emby/Items/%s/Images/Primary/0?"
+                        "MaxWidth=%s&MaxHeight=%s&Format=original&Tag=%s%s"
+                        % (self.server, parentId, maxWidth, maxHeight, parentTag, customquery))
+                    allartworks['Primary'] = artwork
+
         return allartworks
\ No newline at end of file
diff --git a/resources/lib/downloadutils.py b/resources/lib/downloadutils.py
index 194a8333..a74ee6f2 100644
--- a/resources/lib/downloadutils.py
+++ b/resources/lib/downloadutils.py
@@ -97,7 +97,7 @@ class DownloadUtils():
         self.logMsg("Capabilities URL: %s" % url, 2)
         self.logMsg("Postdata: %s" % data, 2)
 
-        self.downloadUrl(url, postBody=data, type="POST")
+        self.downloadUrl(url, postBody=data, action_type="POST")
         self.logMsg("Posted capabilities to %s" % self.server, 2)
 
         # Attempt at getting sessionId
@@ -140,7 +140,7 @@ class DownloadUtils():
                                     "{server}/emby/Sessions/%s/Users/%s?format=json"
                                     % (sessionId, userId)
                             )
-                            self.downloadUrl(url, postBody={}, type="POST")
+                            self.downloadUrl(url, postBody={}, action_type="POST")
 
 
     def startSession(self):
diff --git a/resources/lib/entrypoint.py b/resources/lib/entrypoint.py
index f71ac305..bc81ad0a 100644
--- a/resources/lib/entrypoint.py
+++ b/resources/lib/entrypoint.py
@@ -166,7 +166,7 @@ def deleteItem():
     doUtils = downloadutils.DownloadUtils()
     url = "{server}/emby/Items/%s?format=json" % embyid
     utils.logMsg("EMBY delete", "Deleting request: %s" % embyid, 0)
-    doUtils.downloadUrl(url, type="DELETE")
+    doUtils.downloadUrl(url, action_type="DELETE")
 
 ##### ADD ADDITIONAL USERS #####
 def addUser():
@@ -221,7 +221,7 @@ def addUser():
                     selected = additionalUsername[resp]
                     selected_userId = additionalUserlist[selected]
                     url = "{server}/emby/Sessions/%s/Users/%s" % (sessionId, selected_userId)
-                    doUtils.downloadUrl(url, postBody={}, type="DELETE")
+                    doUtils.downloadUrl(url, postBody={}, action_type="DELETE")
                     dialog.notification(
                             heading="Success!",
                             message="%s removed from viewing session" % selected,
@@ -254,7 +254,7 @@ def addUser():
             selected = users[resp]
             selected_userId = userlist[selected]
             url = "{server}/emby/Sessions/%s/Users/%s" % (sessionId, selected_userId)
-            doUtils.downloadUrl(url, postBody={}, type="POST")
+            doUtils.downloadUrl(url, postBody={}, action_type="POST")
             dialog.notification(
                     heading="Success!",
                     message="%s added to viewing session" % selected,
diff --git a/resources/lib/initialsetup.py b/resources/lib/initialsetup.py
index e23c9001..7bf0dbb9 100644
--- a/resources/lib/initialsetup.py
+++ b/resources/lib/initialsetup.py
@@ -176,8 +176,8 @@ class InitialSetup():
         sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_LOOP, 1)
         sock.setsockopt(socket.IPPROTO_IP, socket.SO_REUSEADDR, 1)
         
-        self.logMsg("MultiGroup      : %s" % str(MULTI_GROUP), 2);
-        self.logMsg("Sending UDP Data: %s" % MESSAGE, 2);
+        self.logMsg("MultiGroup      : %s" % str(MULTI_GROUP), 2)
+        self.logMsg("Sending UDP Data: %s" % MESSAGE, 2)
         sock.sendto(MESSAGE, MULTI_GROUP)
     
         try:
diff --git a/resources/lib/itemtypes.py b/resources/lib/itemtypes.py
index 78699375..e27862c6 100644
--- a/resources/lib/itemtypes.py
+++ b/resources/lib/itemtypes.py
@@ -260,7 +260,6 @@ class Movies(Items):
         # Process single movie
         kodicursor = self.kodicursor
         emby_db = self.emby_db
-        kodi_db = self.kodi_db
         artwork = self.artwork
         API = api.API(item)
 
@@ -422,9 +421,9 @@ class Movies(Items):
             self.logMsg("ADD movie itemid: %s - Title: %s" % (itemid, title), 1)
             
             # Add path
-            pathid = kodi_db.addPath(path)
+            pathid = self.kodi_db.addPath(path)
             # Add the file
-            fileid = kodi_db.addFile(filename, pathid)
+            fileid = self.kodi_db.addFile(filename, pathid)
             
             # Create the movie entry
             query = (
@@ -462,35 +461,34 @@ class Movies(Items):
         kodicursor.execute(query, (pathid, filename, dateadded, fileid))
         
         # Process countries
-        kodi_db.addCountries(movieid, item['ProductionLocations'], "movie")
+        self.kodi_db.addCountries(movieid, item['ProductionLocations'], "movie")
         # Process cast
         people = artwork.getPeopleArtwork(item['People'])
-        kodi_db.addPeople(movieid, people, "movie")
+        self.kodi_db.addPeople(movieid, people, "movie")
         # Process genres
-        kodi_db.addGenres(movieid, genres, "movie")
+        self.kodi_db.addGenres(movieid, genres, "movie")
         # Process artwork
         artwork.addArtwork(artwork.getAllArtwork(item), movieid, "movie", kodicursor)
         # Process stream details
         streams = API.getMediaStreams()
-        kodi_db.addStreams(fileid, streams, runtime)
+        self.kodi_db.addStreams(fileid, streams, runtime)
         # Process studios
-        kodi_db.addStudios(movieid, studios, "movie")
+        self.kodi_db.addStudios(movieid, studios, "movie")
         # Process tags: view, emby tags
         tags = [viewtag]
         tags.extend(item['Tags'])
         if userdata['Favorite']:
             tags.append("Favorite movies")
-        kodi_db.addTags(movieid, tags, "movie")
+        self.kodi_db.addTags(movieid, tags, "movie")
         # Process playstates
         resume = API.adjustResume(userdata['Resume'])
         total = round(float(runtime), 6)
-        kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed)
+        self.kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed)
 
     def add_updateBoxset(self, boxset):
 
         emby = self.emby
         emby_db = self.emby_db
-        kodi_db = self.kodi_db
         artwork = self.artwork
 
         boxsetid = boxset['Id']
@@ -501,7 +499,7 @@ class Movies(Items):
             setid = emby_dbitem[0]
 
         except TypeError:
-            setid = kodi_db.createBoxset(title)
+            setid = self.kodi_db.createBoxset(title)
 
         # Process artwork
         artwork.addArtwork(artwork.getAllArtwork(boxset), setid, "set", self.kodicursor)
@@ -534,7 +532,7 @@ class Movies(Items):
                     continue
 
                 self.logMsg("New addition to boxset %s: %s" % (title, movie['Name']), 1)
-                kodi_db.assignBoxset(setid, movieid)
+                self.kodi_db.assignBoxset(setid, movieid)
                 # Update emby reference
                 emby_db.updateParentId(itemid, setid)
             else:
@@ -545,7 +543,7 @@ class Movies(Items):
         for movie in process:
             movieid = current[movie]
             self.logMsg("Remove from boxset %s: %s" % (title, movieid))
-            kodi_db.removefromBoxset(movieid)
+            self.kodi_db.removefromBoxset(movieid)
             # Update emby reference
             emby_db.updateParentId(movie, None)
 
@@ -556,7 +554,6 @@ class Movies(Items):
         # This updates: Favorite, LastPlayedDate, Playcount, PlaybackPositionTicks
         # Poster with progress bar
         emby_db = self.emby_db
-        kodi_db = self.kodi_db
         API = api.API(item)
         
         # Get emby information
@@ -578,9 +575,9 @@ class Movies(Items):
 
         # Process favorite tags
         if userdata['Favorite']:
-            kodi_db.addTag(movieid, "Favorite movies", "movie")
+            self.kodi_db.addTag(movieid, "Favorite movies", "movie")
         else:
-            kodi_db.removeTag(movieid, "Favorite movies", "movie")
+            self.kodi_db.removeTag(movieid, "Favorite movies", "movie")
 
         # Process playstates
         playcount = userdata['PlayCount']
@@ -590,7 +587,7 @@ class Movies(Items):
 
         self.logMsg("%s New resume point: %s" % (itemid, resume))
 
-        kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed)
+        self.kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed)
         emby_db.updateReference(itemid, checksum)
 
     def remove(self, itemid):
@@ -658,7 +655,6 @@ class MusicVideos(Items):
         # Process single music video
         kodicursor = self.kodicursor
         emby_db = self.emby_db
-        kodi_db = self.kodi_db
         artwork = self.artwork
         API = api.API(item)
 
@@ -849,32 +845,31 @@ class MusicVideos(Items):
             artist['Type'] = "Artist"
         people.extend(artists)
         people = artwork.getPeopleArtwork(people)
-        kodi_db.addPeople(mvideoid, people, "musicvideo")
+        self.kodi_db.addPeople(mvideoid, people, "musicvideo")
         # Process genres
-        kodi_db.addGenres(mvideoid, genres, "musicvideo")
+        self.kodi_db.addGenres(mvideoid, genres, "musicvideo")
         # Process artwork
         artwork.addArtwork(artwork.getAllArtwork(item), mvideoid, "musicvideo", kodicursor)
         # Process stream details
         streams = API.getMediaStreams()
-        kodi_db.addStreams(fileid, streams, runtime)
+        self.kodi_db.addStreams(fileid, streams, runtime)
         # Process studios
-        kodi_db.addStudios(mvideoid, studios, "musicvideo")
+        self.kodi_db.addStudios(mvideoid, studios, "musicvideo")
         # Process tags: view, emby tags
         tags = [viewtag]
         tags.extend(item['Tags'])
         if userdata['Favorite']:
             tags.append("Favorite musicvideos")
-        kodi_db.addTags(mvideoid, tags, "musicvideo")
+        self.kodi_db.addTags(mvideoid, tags, "musicvideo")
         # Process playstates
         resume = API.adjustResume(userdata['Resume'])
         total = round(float(runtime), 6)
-        kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed)
+        self.kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed)
 
     def updateUserdata(self, item):
         # This updates: Favorite, LastPlayedDate, Playcount, PlaybackPositionTicks
         # Poster with progress bar
         emby_db = self.emby_db
-        kodi_db = self.kodi_db
         API = api.API(item)
         
         # Get emby information
@@ -896,9 +891,9 @@ class MusicVideos(Items):
 
         # Process favorite tags
         if userdata['Favorite']:
-            kodi_db.addTag(mvideoid, "Favorite musicvideos", "musicvideo")
+            self.kodi_db.addTag(mvideoid, "Favorite musicvideos", "musicvideo")
         else:
-            kodi_db.removeTag(mvideoid, "Favorite musicvideos", "musicvideo")
+            self.kodi_db.removeTag(mvideoid, "Favorite musicvideos", "musicvideo")
 
         # Process playstates
         playcount = userdata['PlayCount']
@@ -906,7 +901,7 @@ class MusicVideos(Items):
         resume = API.adjustResume(userdata['Resume'])
         total = round(float(runtime), 6)
 
-        kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed)
+        self.kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed)
         emby_db.updateReference(itemid, checksum)
 
     def remove(self, itemid):
@@ -1006,7 +1001,6 @@ class TVShows(Items):
         kodicursor = self.kodicursor
         emby = self.emby
         emby_db = self.emby_db
-        kodi_db = self.kodi_db
         artwork = self.artwork
         API = api.API(item)
 
@@ -1128,7 +1122,7 @@ class TVShows(Items):
             self.logMsg("ADD tvshow itemid: %s - Title: %s" % (itemid, title), 1)
             
             # Add top path
-            toppathid = kodi_db.addPath(toplevelpath)
+            toppathid = self.kodi_db.addPath(toplevelpath)
             query = ' '.join((
 
                 "UPDATE path",
@@ -1138,7 +1132,7 @@ class TVShows(Items):
             kodicursor.execute(query, (toplevelpath, "tvshows", "metadata.local", 1, toppathid))
             
             # Add path
-            pathid = kodi_db.addPath(path)
+            pathid = self.kodi_db.addPath(path)
             
             # Create the tvshow entry
             query = (
@@ -1171,26 +1165,26 @@ class TVShows(Items):
         
         # Process cast
         people = artwork.getPeopleArtwork(item['People'])
-        kodi_db.addPeople(showid, people, "tvshow")
+        self.kodi_db.addPeople(showid, people, "tvshow")
         # Process genres
-        kodi_db.addGenres(showid, genres, "tvshow")
+        self.kodi_db.addGenres(showid, genres, "tvshow")
         # Process artwork
         artwork.addArtwork(artwork.getAllArtwork(item), showid, "tvshow", kodicursor)
         # Process studios
-        kodi_db.addStudios(showid, studios, "tvshow")
+        self.kodi_db.addStudios(showid, studios, "tvshow")
         # Process tags: view, emby tags
         tags = [viewtag]
         tags.extend(item['Tags'])
         if userdata['Favorite']:
             tags.append("Favorite tvshows")
-        kodi_db.addTags(showid, tags, "tvshow")
+        self.kodi_db.addTags(showid, tags, "tvshow")
         # Process seasons
         all_seasons = emby.getSeasons(itemid)
         for season in all_seasons['Items']:
             self.add_updateSeason(season, showid=showid)
         else:
             # Finally, refresh the all season entry
-            seasonid = kodi_db.addSeason(showid, -1)
+            seasonid = self.kodi_db.addSeason(showid, -1)
             # Process artwork
             artwork.addArtwork(artwork.getAllArtwork(item), seasonid, "season", kodicursor)
 
@@ -1204,7 +1198,6 @@ class TVShows(Items):
 
         kodicursor = self.kodicursor
         emby_db = self.emby_db
-        kodi_db = self.kodi_db
         artwork = self.artwork
 
         seasonnum = item.get('IndexNumber', 1)
@@ -1221,7 +1214,7 @@ class TVShows(Items):
                 self.add_update(show)
                 return
         
-        seasonid = kodi_db.addSeason(showid, seasonnum)
+        seasonid = self.kodi_db.addSeason(showid, seasonnum)
         
         if item['LocationType'] != "Virtual":
             # Create the reference in emby table
@@ -1234,7 +1227,6 @@ class TVShows(Items):
         # Process single episode
         kodicursor = self.kodicursor
         emby_db = self.emby_db
-        kodi_db = self.kodi_db
         artwork = self.artwork
         API = api.API(item)
 
@@ -1331,7 +1323,7 @@ class TVShows(Items):
                 self.logMsg("Skipping: %s. Unable to add series: %s." % (itemid, seriesId))
                 return False
 
-        seasonid = kodi_db.addSeason(showid, season)
+        seasonid = self.kodi_db.addSeason(showid, season)
 
         
         ##### GET THE FILE AND PATH #####
@@ -1413,9 +1405,9 @@ class TVShows(Items):
             self.logMsg("ADD episode itemid: %s - Title: %s" % (itemid, title), 1)
             
             # Add path
-            pathid = kodi_db.addPath(path)
+            pathid = self.kodi_db.addPath(path)
             # Add the file
-            fileid = kodi_db.addFile(filename, pathid)
+            fileid = self.kodi_db.addFile(filename, pathid)
             
             # Create the episode entry
             if self.kodiversion in (16, 17):
@@ -1470,21 +1462,21 @@ class TVShows(Items):
         
         # Process cast
         people = artwork.getPeopleArtwork(item['People'])
-        kodi_db.addPeople(episodeid, people, "episode")
+        self.kodi_db.addPeople(episodeid, people, "episode")
         # Process artwork
         artworks = artwork.getAllArtwork(item)
         artwork.addOrUpdateArt(artworks['Primary'], episodeid, "episode", "thumb", kodicursor)
         # Process stream details
         streams = API.getMediaStreams()
-        kodi_db.addStreams(fileid, streams, runtime)
+        self.kodi_db.addStreams(fileid, streams, runtime)
         # Process playstates
         resume = API.adjustResume(userdata['Resume'])
         total = round(float(runtime), 6)
-        kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed)
+        self.kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed)
         if not self.directpath and resume:
             # Create additional entry for widgets. This is only required for plugin/episode.
-            temppathid = kodi_db.getPath("plugin://plugin.video.emby.tvshows/")
-            tempfileid = kodi_db.addFile(filename, temppathid)
+            temppathid = self.kodi_db.getPath("plugin://plugin.video.emby.tvshows/")
+            tempfileid = self.kodi_db.addFile(filename, temppathid)
             query = ' '.join((
 
                 "UPDATE files",
@@ -1492,13 +1484,12 @@ class TVShows(Items):
                 "WHERE idFile = ?"
             ))
             kodicursor.execute(query, (temppathid, filename, dateadded, tempfileid))
-            kodi_db.addPlaystate(tempfileid, resume, total, playcount, dateplayed)
+            self.kodi_db.addPlaystate(tempfileid, resume, total, playcount, dateplayed)
 
     def updateUserdata(self, item):
         # This updates: Favorite, LastPlayedDate, Playcount, PlaybackPositionTicks
         # Poster with progress bar
         emby_db = self.emby_db
-        kodi_db = self.kodi_db
         API = api.API(item)
         
         # Get emby information
@@ -1523,9 +1514,9 @@ class TVShows(Items):
         # Process favorite tags
         if mediatype == "tvshow":
             if userdata['Favorite']:
-                kodi_db.addTag(kodiid, "Favorite tvshows", "tvshow")
+                self.kodi_db.addTag(kodiid, "Favorite tvshows", "tvshow")
             else:
-                kodi_db.removeTag(kodiid, "Favorite tvshows", "tvshow")
+                self.kodi_db.removeTag(kodiid, "Favorite tvshows", "tvshow")
         elif mediatype == "episode":
             # Process playstates
             playcount = userdata['PlayCount']
@@ -1535,17 +1526,17 @@ class TVShows(Items):
 
             self.logMsg("%s New resume point: %s" % (itemid, resume))
 
-            kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed)
+            self.kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed)
             if not self.directpath and not resume:
                 # Make sure there's no other bookmarks created by widget.
-                filename = kodi_db.getFile(fileid)
-                kodi_db.removeFile("plugin://plugin.video.emby.tvshows/", filename)
+                filename = self.kodi_db.getFile(fileid)
+                self.kodi_db.removeFile("plugin://plugin.video.emby.tvshows/", filename)
 
             if not self.directpath and resume:
                 # Create additional entry for widgets. This is only required for plugin/episode.
-                filename = kodi_db.getFile(fileid)
-                temppathid = kodi_db.getPath("plugin://plugin.video.emby.tvshows/")
-                tempfileid = kodi_db.addFile(filename, temppathid)
+                filename = self.kodi_db.getFile(fileid)
+                temppathid = self.kodi_db.getPath("plugin://plugin.video.emby.tvshows/")
+                tempfileid = self.kodi_db.addFile(filename, temppathid)
                 query = ' '.join((
 
                     "UPDATE files",
@@ -1553,7 +1544,7 @@ class TVShows(Items):
                     "WHERE idFile = ?"
                 ))
                 self.kodicursor.execute(query, (temppathid, filename, dateadded, tempfileid))
-                kodi_db.addPlaystate(tempfileid, resume, total, playcount, dateplayed)
+                self.kodi_db.addPlaystate(tempfileid, resume, total, playcount, dateplayed)
 
         emby_db.updateReference(itemid, checksum)
 
@@ -1749,7 +1740,6 @@ class Music(Items):
         # Process a single artist
         kodicursor = self.kodicursor
         emby_db = self.emby_db
-        kodi_db = self.kodi_db
         artwork = self.artwork
         API = api.API(item)
 
@@ -1796,7 +1786,7 @@ class Music(Items):
             self.logMsg("ADD artist itemid: %s - Name: %s" % (itemid, name), 1)
             # safety checks: It looks like Emby supports the same artist multiple times.
             # Kodi doesn't allow that. In case that happens we just merge the artist entries.
-            artistid = kodi_db.addArtist(name, musicBrainzId)
+            artistid = self.kodi_db.addArtist(name, musicBrainzId)
             # Create the reference in emby table
             emby_db.addReference(itemid, artistid, artisttype, "artist", checksum=checksum)
             
@@ -1831,7 +1821,6 @@ class Music(Items):
         emby = self.emby
         kodicursor = self.kodicursor
         emby_db = self.emby_db
-        kodi_db = self.kodi_db
         artwork = self.artwork
         API = api.API(item)
 
@@ -1882,7 +1871,7 @@ class Music(Items):
             self.logMsg("ADD album itemid: %s - Name: %s" % (itemid, name), 1)
             # safety checks: It looks like Emby supports the same artist multiple times.
             # Kodi doesn't allow that. In case that happens we just merge the artist entries.
-            albumid = kodi_db.addAlbum(name, musicBrainzId)
+            albumid = self.kodi_db.addAlbum(name, musicBrainzId)
             # Create the reference in emby table
             emby_db.addReference(itemid, albumid, "MusicAlbum", "album", checksum=checksum)
 
@@ -1991,7 +1980,7 @@ class Music(Items):
             emby_db.updateParentId(artistId, albumid)
 
         # Add genres
-        kodi_db.addMusicGenres(albumid, genres, "album")
+        self.kodi_db.addMusicGenres(albumid, genres, "album")
         # Update artwork
         artwork.addArtwork(artworks, albumid, "album", kodicursor)
 
@@ -2000,7 +1989,6 @@ class Music(Items):
         kodicursor = self.kodicursor
         emby = self.emby
         emby_db = self.emby_db
-        kodi_db = self.kodi_db
         artwork = self.artwork
         API = api.API(item)
 
@@ -2106,7 +2094,7 @@ class Music(Items):
             self.logMsg("ADD song itemid: %s - Title: %s" % (itemid, title), 1)
             
             # Add path
-            pathid = kodi_db.addPath(path)
+            pathid = self.kodi_db.addPath(path)
 
             try:
                 # Get the album
@@ -2117,7 +2105,7 @@ class Music(Items):
                 album_name = item.get('Album')
                 if album_name:
                     self.logMsg("Creating virtual music album for song: %s." % itemid, 1)
-                    albumid = kodi_db.addAlbum(album_name, API.getProvider('MusicBrainzAlbum'))
+                    albumid = self.kodi_db.addAlbum(album_name, API.getProvider('MusicBrainzAlbum'))
                     emby_db.addReference("%salbum%s" % (itemid, albumid), albumid, "MusicAlbum_", "album")
                 else:
                     # No album Id associated to the song.
@@ -2287,7 +2275,7 @@ class Music(Items):
                     kodicursor.execute(query, (album_artists, albumid))
 
         # Add genres
-        kodi_db.addMusicGenres(songid, genres, "song")
+        self.kodi_db.addMusicGenres(songid, genres, "song")
         
         # Update artwork
         allart = artwork.getAllArtwork(item, parentInfo=True)
@@ -2304,7 +2292,6 @@ class Music(Items):
         # Poster with progress bar
         kodicursor = self.kodicursor
         emby_db = self.emby_db
-        kodi_db = self.kodi_db
         API = api.API(item)
 
         # Get emby information
diff --git a/resources/lib/kodidb_functions.py b/resources/lib/kodidb_functions.py
index 5d258d91..6c3dd8b1 100644
--- a/resources/lib/kodidb_functions.py
+++ b/resources/lib/kodidb_functions.py
@@ -424,7 +424,7 @@ class Kodidb_Functions():
                 if "writing" in arttype:
                     arttype = "writer"
 
-                self.artwork.addOrUpdateArt(thumb, actorid, arttype, "thumb", cursor)
+                self.artwork.addOrUpdateArt(thumb, actorid, arttype, "thumb", self.cursor)
 
     def addGenres(self, kodiid, genres, mediatype):
 
diff --git a/resources/lib/kodimonitor.py b/resources/lib/kodimonitor.py
index c4df4945..f2b5ae86 100644
--- a/resources/lib/kodimonitor.py
+++ b/resources/lib/kodimonitor.py
@@ -154,10 +154,10 @@ class KodiMonitor(xbmc.Monitor):
                         # notify the server
                         url = "{server}/emby/Users/{UserId}/PlayedItems/%s?format=json" % itemid
                         if playcount != 0:
-                            doUtils.downloadUrl(url, type="POST")
+                            doUtils.downloadUrl(url, action_type="POST")
                             self.logMsg("Mark as watched for itemid: %s" % itemid, 1)
                         else:
-                            doUtils.downloadUrl(url, type="DELETE")
+                            doUtils.downloadUrl(url, action_type="DELETE")
                             self.logMsg("Mark as unwatched for itemid: %s" % itemid, 1)
                 finally:
                     embycursor.close()
@@ -195,7 +195,7 @@ class KodiMonitor(xbmc.Monitor):
 
                     url = "{server}/emby/Items/%s?format=json" % itemid
                     self.logMsg("Deleting request: %s" % itemid)
-                    doUtils.downloadUrl(url, type="DELETE")
+                    doUtils.downloadUrl(url, action_type="DELETE")
                 finally:
                     embycursor.close()'''
 
diff --git a/resources/lib/player.py b/resources/lib/player.py
index 91ff2ece..7f323460 100644
--- a/resources/lib/player.py
+++ b/resources/lib/player.py
@@ -208,7 +208,7 @@ class Player(xbmc.Player):
 
                 # Post playback to server
                 self.logMsg("Sending POST play started: %s." % postdata, 2)
-                self.doUtils(url, postBody=postdata, type="POST")
+                self.doUtils(url, postBody=postdata, action_type="POST")
                 
                 # Ensure we do have a runtime
                 try:
@@ -443,7 +443,7 @@ class Player(xbmc.Player):
                 itemid = data['item_id']
                 refresh_id = data['refresh_id']
                 currentFile = data['currentfile']
-                type = data['Type']
+                media_type = data['Type']
                 playMethod = data['playmethod']
 
                 # Prevent manually mark as watched in Kodi monitor
@@ -463,9 +463,9 @@ class Player(xbmc.Player):
                     # Send the delete action to the server.
                     offerDelete = False
 
-                    if type == "Episode" and settings('deleteTV') == "true":
+                    if media_type == "Episode" and settings('deleteTV') == "true":
                         offerDelete = True
-                    elif type == "Movie" and settings('deleteMovies') == "true":
+                    elif media_type == "Movie" and settings('deleteMovies') == "true":
                         offerDelete = True
 
                     if settings('offerDelete') != "true":
@@ -480,7 +480,7 @@ class Player(xbmc.Player):
 
                         url = "{server}/emby/Items/%s?format=json" % itemid
                         self.logMsg("Deleting request: %s" % itemid, 1)
-                        self.doUtils(url, type="DELETE")
+                        self.doUtils(url, action_type="DELETE")
 
                 self.stopPlayback(data)
 
@@ -489,7 +489,7 @@ class Player(xbmc.Player):
                     self.logMsg("Transcoding for %s terminated." % itemid, 1)
                     deviceId = self.clientInfo.getDeviceId()
                     url = "{server}/emby/Videos/ActiveEncodings?DeviceId=%s" % deviceId
-                    self.doUtils(url, type="DELETE")
+                    self.doUtils(url, action_type="DELETE")
     
         self.played_info.clear()
     
@@ -508,4 +508,4 @@ class Player(xbmc.Player):
             'MediaSourceId': itemId,
             'PositionTicks': positionTicks
         }
-        self.doUtils(url, postBody=postdata, type="POST")
\ No newline at end of file
+        self.doUtils(url, postBody=postdata, action_type="POST")
\ No newline at end of file
diff --git a/resources/lib/read_embyserver.py b/resources/lib/read_embyserver.py
index 1af01f40..6eeb5fb6 100644
--- a/resources/lib/read_embyserver.py
+++ b/resources/lib/read_embyserver.py
@@ -522,16 +522,16 @@ class Read_EmbyServer():
         # Updates the user rating to Emby
         
         if favourite:
-            self.doUtils("{server}/emby/Users/{UserId}/FavoriteItems/%s?format=json" % itemid, type="POST")
+            self.doUtils("{server}/emby/Users/{UserId}/FavoriteItems/%s?format=json" % itemid, action_type="POST")
         elif favourite == False:
-            self.doUtils("{server}/emby/Users/{UserId}/FavoriteItems/%s?format=json" % itemid, type="DELETE")
+            self.doUtils("{server}/emby/Users/{UserId}/FavoriteItems/%s?format=json" % itemid, action_type="DELETE")
 
         if not deletelike and like:
-            self.doUtils("{server}/emby/Users/{UserId}/Items/%s/Rating?Likes=true&format=json" % itemid, type="POST")
+            self.doUtils("{server}/emby/Users/{UserId}/Items/%s/Rating?Likes=true&format=json" % itemid, action_type="POST")
         elif not deletelike and like is False:
-            self.doUtils("{server}/emby/Users/{UserId}/Items/%s/Rating?Likes=false&format=json" % itemid, type="POST")
+            self.doUtils("{server}/emby/Users/{UserId}/Items/%s/Rating?Likes=false&format=json" % itemid, action_type="POST")
         elif deletelike:
-            self.doUtils("{server}/emby/Users/{UserId}/Items/%s/Rating?format=json" % itemid, type="DELETE")
+            self.doUtils("{server}/emby/Users/{UserId}/Items/%s/Rating?format=json" % itemid, action_type="DELETE")
 
         self.logMsg("Update user rating to emby for itemid: %s "
                     "| like: %s | favourite: %s | deletelike: %s"
diff --git a/resources/lib/utils.py b/resources/lib/utils.py
index 7b26e1d0..a8b97c0b 100644
--- a/resources/lib/utils.py
+++ b/resources/lib/utils.py
@@ -23,15 +23,15 @@ import xbmcvfs
 
 
 def logMsg(title, msg, level=1):
-    
+
     # Get the logLevel set in UserClient
     try:
         logLevel = int(window('emby_logLevel'))
     except ValueError:
         logLevel = 0
-    
+
     if logLevel >= level:
-        
+
         if logLevel == 2: # inspect.stack() is expensive
             try:
                 xbmc.log("%s -> %s : %s" % (title, inspect.stack()[1][3], msg))
@@ -46,13 +46,13 @@ def logMsg(title, msg, level=1):
 def window(property, value=None, clear=False, windowid=10000):
     # Get or set window property
     WINDOW = xbmcgui.Window(windowid)
-    
+
     #setproperty accepts both string and unicode but utf-8 strings are adviced by kodi devs because some unicode can give issues
     '''if isinstance(property, unicode):
         property = property.encode("utf-8")
     if isinstance(value, unicode):
         value = value.encode("utf-8")'''
-    
+
     if clear:
         WINDOW.clearProperty(property)
     elif value is not None:
@@ -73,7 +73,7 @@ def language(stringid):
     return string
 
 def kodiSQL(media_type="video"):
-    
+
     if media_type == "emby":
         dbPath = xbmc.translatePath("special://database/emby.db").decode('utf-8')
     elif media_type == "music":
@@ -82,7 +82,7 @@ def kodiSQL(media_type="video"):
         dbPath = xbmc.translatePath("special://database/Textures13.db").decode('utf-8')
     else:
         dbPath = getKodiVideoDBPath()
-    
+
     connection = sqlite3.connect(dbPath)
     return connection
 
@@ -143,7 +143,7 @@ def setScreensaver(value):
             'value': value
         }
     }
-    logMsg("EMBY", "Toggling screensaver: %s %s" % (value, xbmc.executeJSONRPC(json.dumps(query))), 1)    
+    logMsg("EMBY", "Toggling screensaver: %s %s" % (value, xbmc.executeJSONRPC(json.dumps(query))), 1)
 
 def reset():
 
@@ -211,7 +211,7 @@ def reset():
     cursor.close()
 
     # Offer to wipe cached thumbnails
-    resp = dialog.yesno("Warning", "Removed all cached artwork?")
+    resp = dialog.yesno("Warning", "Remove all cached artwork?")
     if resp:
         logMsg("EMBY", "Resetting all cached artwork.", 0)
         # Remove all existing textures first
@@ -225,7 +225,7 @@ def reset():
                         xbmcvfs.delete(os.path.join(path+dir.decode('utf-8'),file.decode('utf-8')))
                     else:
                         xbmcvfs.delete(os.path.join(path.encode('utf-8')+dir,file))
-        
+
         # remove all existing data from texture DB
         connection = kodiSQL('texture')
         cursor = connection.cursor()
@@ -237,8 +237,8 @@ def reset():
                 cursor.execute("DELETE FROM " + tableName)
         connection.commit()
         cursor.close()
-    
-    # reset the install run flag  
+
+    # reset the install run flag
     settings('SyncInstallRunDone', value="false")
 
     # Remove emby info
@@ -260,7 +260,7 @@ def profiling(sortby="cumulative"):
     # Will print results to Kodi log
     def decorator(func):
         def wrapper(*args, **kwargs):
-            
+
             pr = cProfile.Profile()
 
             pr.enable()
@@ -304,7 +304,7 @@ def normalize_nodes(text):
     # with dots at the end
     text = text.rstrip('.')
     text = unicodedata.normalize('NFKD', unicode(text, 'utf-8')).encode('ascii', 'ignore')
-    
+
     return text
 
 def normalize_string(text):
@@ -353,7 +353,7 @@ def sourcesXML():
         root = etree.Element('sources')
     else:
         root = xmlparse.getroot()
-        
+
 
     video = root.find('video')
     if video is None:
@@ -365,7 +365,7 @@ def sourcesXML():
     for source in root.findall('.//path'):
         if source.text == "smb://":
             count -= 1
-        
+
         if count == 0:
             # sources already set
             break
@@ -417,7 +417,7 @@ def passwordsXML():
                         break
             else:
                 logMsg("EMBY", "Failed to find saved server: %s in passwords.xml" % credentials, 1)
-            
+
             settings('networkCreds', value="")
             xbmcgui.Dialog().notification(
                                 heading="Emby for Kodi",
@@ -469,7 +469,7 @@ def passwordsXML():
         # Force Kodi to see the credentials without restarting
         xbmcvfs.exists(topath)
 
-    # Add credentials    
+    # Add credentials
     settings('networkCreds', value="%s" % server)
     logMsg("EMBY", "Added server: %s to passwords.xml" % server, 1)
     # Prettify and write to file
@@ -477,7 +477,7 @@ def passwordsXML():
         indent(root)
     except: pass
     etree.ElementTree(root).write(xmlpath)
-    
+
     dialog.notification(
             heading="Emby for Kodi",
             message="%s added to passwords.xml" % server,
@@ -508,7 +508,7 @@ def playlistXSP(mediatype, tagname, viewid, viewtype="", delete=False):
         if delete:
             xbmcvfs.delete(xsppath)
             logMsg("EMBY", "Successfully removed playlist: %s." % tagname, 1)
-        
+
         return
 
     # Using write process since there's no guarantee the xml declaration works with etree