diff --git a/addon.xml b/addon.xml
index 67c54a29..1a78b02f 100644
--- a/addon.xml
+++ b/addon.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
 <addon  id="plugin.video.emby"
         name="Emby" 
-        version="2.2.10"
+        version="2.2.11"
         provider-name="Emby.media">
   <requires>
     <import addon="xbmc.python" version="2.1.0"/>
diff --git a/changelog.txt b/changelog.txt
index 3a2da525..93b264fb 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,3 +1,8 @@
+version 2.2.11
+- Preparation for feature requests
+- Add option to refresh Emby items via context menu
+- Minor fixes
+
 version 2.2.10
 - Add keymap action for delete content: RunPlugin(plugin://plugin.video.emby?mode=delete)
 - Fix various bugs
diff --git a/contextmenu.py b/contextmenu.py
index c91da6a1..b690fd8f 100644
--- a/contextmenu.py
+++ b/contextmenu.py
@@ -10,149 +10,159 @@ 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)
+#################################################################################################
 
+_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 api
 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
+from utils import Logging, settings, language as lang, kodiSQL
+log = Logging('ContextMenu').log
 
-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.
+# Kodi contextmenu item to configure the emby settings
 if __name__ == '__main__':
-    itemid = xbmc.getInfoLabel("ListItem.DBID").decode("utf-8")
-    itemtype = xbmc.getInfoLabel("ListItem.DBTYPE").decode("utf-8")
+
+    kodiId = xbmc.getInfoLabel('ListItem.DBID').decode('utf-8')
+    itemType = xbmc.getInfoLabel('ListItem.DBTYPE').decode('utf-8')
+    itemId = ""
     
-    emby = embyserver.Read_EmbyServer()
+    if not itemType:
+
+        if xbmc.getCondVisibility("Container.Content(albums)"):
+            itemType = "album"
+        elif xbmc.getCondVisibility("Container.Content(artists)"):
+            itemType = "artist"
+        elif xbmc.getCondVisibility("Container.Content(songs)"):
+            itemType = "song"
+        elif xbmc.getCondVisibility("Container.Content(pictures)"):
+            itemType = "picture"
+        else:
+            log("ItemType is unknown.")
+
+    if (not kodiId or kodiId == "-1") and xbmc.getInfoLabel("ListItem.Property(embyid)"):
+        itemId = xbmc.getInfoLabel("ListItem.Property(embyid)")
     
-    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')
+    elif kodiId and itemType:
+        embyconn = kodiSQL('emby')
         embycursor = embyconn.cursor()
         emby_db = embydb.Embydb_Functions(embycursor)
-        item = emby_db.getItem_byKodiId(itemid, itemtype)
+        item = emby_db.getItem_byKodiId(kodiId, itemType)
         embycursor.close()
-        if item: embyid = item[0]
-    
-    logMsg("Contextmenu opened for embyid: %s  - itemtype: %s" %(embyid,itemtype))
+        try:
+            itemId = item[0]
+        except TypeError:
+            pass
 
-    if embyid:
-        item = emby.getItem(embyid)
+    
+    log("Found ItemId: %s ItemType: %s" % (itemId, itemType), 1)
+    if itemId:
+
+        dialog = xbmcgui.Dialog()
+
+        emby = embyserver.Read_EmbyServer()
+        item = emby.getItem(itemId)
         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()
+        options = []
 
-            if options[ret] == utils.language(30408):
-                #Open addon settings
+        if favourite:
+            # Remove from emby favourites
+            options.append(lang(30406))
+        else:
+            # Add to emby favourites
+            options.append(lang(30405)) 
+
+        if itemType == "song":
+            # Set custom song rating
+            options.append(lang(30407))
+        
+        # Refresh item
+        options.append(lang(30410))
+        # Delete item
+        options.append(lang(30409))
+        # Addon settings
+        options.append(lang(30408))
+        
+        # Display select dialog and process results
+        resp = xbmcgui.Dialog().select(lang(30401), options)
+        if resp > -1:
+            selected = options[resp]
+
+            if selected == lang(30410):
+                # Refresh item
+                emby.refreshItem(itemId)
+            elif selected == lang(30405):
+                # Add favourite
+                emby.updateUserRating(itemId, favourite=True)
+            elif selected == lang(30406):
+                # Delete favourite
+                emby.updateUserRating(itemId, favourite=False)
+            elif selected == lang(30407):
+                # Update song rating
+                kodiconn = kodiSQL('music')
+                kodicursor = kodiconn.cursor()
+                query = "SELECT rating FROM song WHERE idSong = ?"
+                kodicursor.execute(query, (kodiId,))
+                try:
+                    value = kodicursor.fetchone()[0]
+                    current_value = int(round(float(value),0))
+                except TypeError:
+                    pass
+                else:
+                    new_value = dialog.numeric(0, lang(30411), str(current_value))
+                    if new_value > -1:
+                        
+                        new_value = int(new_value)
+                        if new_value > 5:
+                            new_value = 5
+
+                        if settings('enableUpdateSongRating') == "true":
+                            musicutils.updateRatingToFile(new_value, API.getFilePath())
+
+                        query = "UPDATE song SET rating = ? WHERE idSong = ?"
+                        kodicursor.execute(query, (new_value, kodiId,))
+                        kodiconn.commit()
+                        
+                        '''if settings('enableExportSongRating') == "true":
+                            like, favourite, deletelike = musicutils.getEmbyRatingFromKodiRating(new_value)
+                            emby.updateUserRating(itemId, like, favourite, deletelike)'''
+                finally:
+                    kodicursor.close()
+
+            elif selected == lang(30408):
+                # Open addon settings
                 xbmc.executebuiltin("Addon.OpenSettings(plugin.video.emby)")
                 
-            if options[ret] == utils.language(30409):
-                #delete item from the server
+            elif selected == lang(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 settings('skipContextMenu') != "true":
+                    resp = dialog.yesno(
+                                heading=lang(29999),
+                                line1=lang(33041))
                     if not resp:
-                        logMsg("User skipped deletion for: %s." % embyid, 1)
+                        log("User skipped deletion for: %s." % itemId, 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")'''
+                    log("Deleting request: %s" % itemId, 0)
+                    emby.deleteItem(itemId)
             
             xbmc.sleep(500)
-            xbmc.executebuiltin("Container.Update")
\ No newline at end of file
+            xbmc.executebuiltin('Container.Refresh')
\ No newline at end of file
diff --git a/default.py b/default.py
index 2a9ff290..3912b4f5 100644
--- a/default.py
+++ b/default.py
@@ -12,30 +12,32 @@ 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)
+_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 entrypoint
 import utils
+from utils import Logging, window, language as lang
+log = Logging('Default').log
 
 #################################################################################################
 
-enableProfiling = False
 
-class Main:
+class Main():
 
 
     # MAIN ENTRY POINT
+    #@utils.profiling()
     def __init__(self):
 
         # Parse parameters
         base_url = sys.argv[0]
         params = urlparse.parse_qs(sys.argv[2][1:])
-        xbmc.log("Parameter string: %s" % sys.argv[2])
+        log("Parameter string: %s" % sys.argv[2], 0)
         try:
             mode = params['mode'][0]
             itemid = params.get('id')
@@ -70,11 +72,13 @@ class Main:
             embypath = sys.argv[2][1:]
             embyid = params.get('id',[""])[0]
             entrypoint.getExtraFanArt(embyid,embypath)
+            return
             
         if "/Extras" in sys.argv[0] or "/VideoFiles" in sys.argv[0]:
             embypath = sys.argv[2][1:]
             embyid = params.get('id',[""])[0]
-            entrypoint.getVideoFiles(embyid,embypath)
+            entrypoint.getVideoFiles(embyid, embypath)
+            return
 
         if modes.get(mode):
             # Simple functions
@@ -86,11 +90,11 @@ class Main:
                 limit = int(params['limit'][0])
                 modes[mode](itemid, limit)
             
-            elif mode in ["channels","getsubfolders"]:
+            elif mode in ("channels","getsubfolders"):
                 modes[mode](itemid)
                 
             elif mode == "browsecontent":
-                modes[mode]( itemid, params.get('type',[""])[0], params.get('folderid',[""])[0] )
+                modes[mode](itemid, params.get('type',[""])[0], params.get('folderid',[""])[0])
 
             elif mode == "channelsfolder":
                 folderid = params['folderid'][0]
@@ -102,16 +106,17 @@ class Main:
             # Other functions
             if mode == "settings":
                 xbmc.executebuiltin('Addon.OpenSettings(plugin.video.emby)')
+            
             elif mode in ("manualsync", "fastsync", "repair"):
-                if utils.window('emby_online') != "true":
+                
+                if window('emby_online') != "true":
                     # Server is not online, do not run the sync
-                    xbmcgui.Dialog().ok(heading="Emby for Kodi",
-                                        line1=("Unable to run the sync, the add-on is not "
-                                               "connected to the Emby server."))
-                    utils.logMsg("EMBY", "Not connected to the emby server.", 1)
+                    xbmcgui.Dialog().ok(heading=lang(29999),
+                                        line1=lang(33034))
+                    log("Not connected to the emby server.", 1)
                     return
                     
-                if utils.window('emby_dbScan') != "true":
+                if window('emby_dbScan') != "true":
                     import librarysync
                     lib = librarysync.LibrarySync()
                     if mode == "manualsync":
@@ -121,35 +126,17 @@ class Main:
                     else:
                         lib.fullSync(repair=True)
                 else:
-                    utils.logMsg("EMBY", "Database scan is already running.", 1)
+                    log("Database scan is already running.", 1)
                     
             elif mode == "texturecache":
                 import artwork
-                artwork.Artwork().FullTextureCacheSync()
+                artwork.Artwork().fullTextureCacheSync()
+            
             else:
                 entrypoint.doMainListing()
 
-                      
-if ( __name__ == "__main__" ):
-    xbmc.log('plugin.video.emby started')
-
-    if enableProfiling:
-        import cProfile
-        import pstats
-        import random
-        from time import gmtime, strftime
-        addonid      = addon_.getAddonInfo('id').decode( 'utf-8' )
-        datapath     = os.path.join( xbmc.translatePath( "special://profile/" ).decode( 'utf-8' ), "addon_data", addonid )
-        
-        filename = os.path.join( datapath, strftime( "%Y%m%d%H%M%S",gmtime() ) + "-" + str( random.randrange(0,100000) ) + ".log" )
-        cProfile.run( 'Main()', filename )
-        
-        stream = open( filename + ".txt", 'w')
-        p = pstats.Stats( filename, stream = stream )
-        p.sort_stats( "cumulative" )
-        p.print_stats()
-    
-    else:
-        Main()
-    
-    xbmc.log('plugin.video.emby stopped')
\ No newline at end of file
+           
+if __name__ == "__main__":
+    log('plugin.video.emby started', 1)
+    Main()
+    log('plugin.video.emby stopped', 1)
\ No newline at end of file
diff --git a/resources/language/English/strings.xml b/resources/language/English/strings.xml
index 1a145adc..ee2dc385 100644
--- a/resources/language/English/strings.xml
+++ b/resources/language/English/strings.xml
@@ -1,56 +1,28 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes"?>
 <strings>
+
     <!-- Add-on settings -->
+    <string id="29999">Emby for Kodi</string>
     <string id="30000">Primary Server Address</string><!-- Verified -->
     <string id="30002">Play from HTTP instead of SMB</string><!-- Verified -->
     <string id="30004">Log level</string><!-- Verified -->
-    <string id="30005">Username: </string>
-    <string id="30006">Password: </string>
-    <string id="30007">Network Username: </string>
-    <string id="30008">Network Password: </string>
-    <string id="30009">Transcode: </string>
-    <string id="30010">Enable Performance Profiling</string>
-    <string id="30011">Local caching system</string>
-
-    <string id="30014">Emby</string>
-    <string id="30015">Network</string>    
-    <string id="30016">Device Name</string>        
-
+    <string id="30016">Device Name</string><!-- Verified -->
     <string id="30022">Advanced</string>
     <string id="30024">Username</string><!-- Verified -->
-    
     <string id="30030">Port Number</string><!-- Verified -->
-    <string id="30036">Number of recent Movies to show:</string>    
-    <string id="30037">Number of recent TV episodes to show:</string>    
-    <string id="30035">Number of recent Music Albums to show:</string>    
-    <string id="30038">Mark watched at start of playback:</string>    
-    <string id="30039">Set Season poster for episodes</string>
 
-    <string id="30040">Genre Filter ...</string>
-    <string id="30041">Play All from Here</string>
+    <string id="30035">Number of recent Music Albums to show:</string>
+    <string id="30036">Number of recent Movies to show:</string>
+    <string id="30037">Number of recent TV episodes to show:</string>
+
     <string id="30042">Refresh</string>
     <string id="30043">Delete</string>
-    <string id="30046">Add Movie to CouchPotato</string>
-    
     <string id="30044">Incorrect Username/Password</string>
     <string id="30045">Username not found</string>
-    
     <string id="30052">Deleting</string>
     <string id="30053">Waiting for server to delete</string>
     
-    <string id="30059">Server Default</string>
-    <string id="30060">Title</string>
-    <string id="30061">Year</string>
-    <string id="30062">Premiere Date</string>
-    <string id="30063">Date Created</string>
-    <string id="30064">Critic Rating</string>
-    <string id="30065">Community Rating</string>
-    <string id="30066">Play Count</string>
-    <string id="30067">Budget</string>
-    <!-- Runtime added as 30226 below -->
-    
     <string id="30068">Sort By</string>
-    
     <string id="30069">None</string>
     <string id="30070">Action</string>
     <string id="30071">Adventure</string>
@@ -75,73 +47,44 @@
     
     <string id="30090">Genre Filter</string>
     <string id="30091">Confirm file deletion</string><!-- Verified -->
-    <string id="30092">Delete this item? This action will delete media and associated data files.</string>
     
-    <string id="30093">Mark Watched</string>
-    <string id="30094">Mark Unwatched</string>
-    <string id="30095">Add to Favorites</string>
-    <string id="30096">Remove from Favorites</string>
-    <string id="30097">Sort By ...</string>
+    <string id="30093">Mark watched</string>
+    <string id="30094">Mark unwatched</string>
+
+    <string id="30097">Sort by</string>
     <string id="30098">Sort Order Descending</string>
     <string id="30099">Sort Order Ascending</string>
-    <string id="30100">Show People</string>
 
     <!-- resume dialog -->
     <string id="30105">Resume</string>
     <string id="30106">Resume from</string>
     <string id="30107">Start from beginning</string>
     
-    <string id="30110">Interface</string>
-    <string id="30111">Include Stream Info</string>
-    <string id="30112">Include People</string>
-    <string id="30113">Include Overview</string>
     <string id="30114">Offer delete after playback</string><!-- Verified -->
     <string id="30115">For Episodes</string><!-- Verified -->
     <string id="30116">For Movies</string><!-- Verified -->
-    <string id="30117">Background Art Refresh Rate (seconds)</string>
+
     <string id="30118">Add Resume Percent</string>
     <string id="30119">Add Episode Number</string>
     <string id="30120">Show Load Progress</string>
     <string id="30121">Loading Content</string>
     <string id="30122">Retrieving Data</string>
+
     <string id="30125">Done</string>
-    <string id="30126">Processing Item : </string>
-    <string id="30128">Play Error</string>
-    <string id="30129">This item is not playable</string>    
-    <string id="30130">Local path detected</string>
-    <string id="30131">Your MB3 Server contains local paths.  Please change server paths to UNC or change XBMB3C setting 'Play from Stream' to true.  Path: </string>
-    <string id="30132">Warning</string>
-    <string id="30133">Debug logging enabled.</string>
-    <string id="30134">This will affect performance.</string>
+    <string id="30132">Warning</string><!-- Verified -->
     <string id="30135">Error</string>
-    <string id="30136">Monitoring service is not running</string>
-    <string id="30137">If you have just installed please restart Kodi</string>
     <string id="30138">Search</string>
     
-    <string id="30139">Enable Theme Music (Requires Restart)</string>
-    <string id="30140"> - Loop Theme Music</string>
-    <string id="30141">Enable Background Image (Requires Restart)</string>
-    <string id="30142">Services</string>
-    
-    <string id="30150">Skin does not support setting views</string>
-    <string id="30151">Select item action (Requires Restart)</string>
-    
-    <string id="30156">Sort NextUp by Show Title</string>    
     <string id="30157">Enable Enhanced Images (eg CoverArt)</string><!-- Verified -->
     <string id="30158">Metadata</string>
     <string id="30159">Artwork</string>
     <string id="30160">Video Quality</string><!-- Verified -->
     
-    <string id="30161">Enable Suggested Loader (Requires Restart)</string>
-    <string id="30162">Add Season Number</string>     
-    <string id="30163">Flatten Seasons</string>     
-    
-    <string id="30164">Direct Play - HTTP</string>     
-    <string id="30165">Direct Play</string>     
+    <string id="30165">Direct Play</string><!-- Verified -->
     <string id="30166">Transcoding</string>     
     <string id="30167">Server Detection Succeeded</string>     
     <string id="30168">Found server</string>     
-    <string id="30169">Address : </string>     
+    <string id="30169">Address:</string>     
     
     <!-- Video nodes -->
     <string id="30170">Recently Added TV Shows</string><!-- Verified -->
@@ -171,38 +114,24 @@
     <string id="30194">TV Genres</string>              
     <string id="30195">TV Networks</string>            
     <string id="30196">TV Actors</string>              
-    <string id="30197">Playlists</string>              
-    <string id="30198">Search</string>              
-    <string id="30199">Set Views</string>              
-    
-    <string id="30200">Select User</string>              
-    <string id="30201">Profiling enabled.</string>              
-    <string id="30202">Please remember to turn off when finished testing.</string>              
-    <string id="30203">Error in ArtworkRotationThread</string>              
+    <string id="30197">Playlists</string>
+
+    <string id="30199">Set Views</string>
+    <string id="30200">Select User</string><!-- Verified -->           
     <string id="30204">Unable to connect to server</string>         
-    <string id="30205">Error in LoadMenuOptionsThread</string>     
-    
-    <string id="30206">Enable Playlists Loader (Requires Restart)</string>   
     
     <string id="30207">Songs</string>
     <string id="30208">Albums</string>
     <string id="30209">Album Artists</string>
     <string id="30210">Artists</string>
     <string id="30211">Music Genres</string>
-    
-    <string id="30212">Enable Theme Videos (Requires Restart)</string>
-    <string id="30213"> - Loop Theme Videos</string>
-    
-    <string id="30216">AutoPlay remaining episodes in a season</string> 
-    <string id="30218">Compress Artwork</string>
-    <string id="30220">Latest </string>
-    <string id="30221">In Progress </string>
-    <string id="30222">NextUp </string>
+
+    <string id="30220">Latest</string>
+    <string id="30221">In Progress</string>
+    <string id="30222">NextUp</string>
     <string id="30223">User Views</string>
     <string id="30224">Report Metrics</string>
-    <string id="30225">Use Kodi Sorting</string>
-    <string id="30226">Runtime</string>
-    
+
     <string id="30227">Random Movies</string>
     <string id="30228">Random Episodes</string>
     <string id="30229">Random Items</string><!-- Verified -->
@@ -214,15 +143,9 @@
     <string id="30238">Sync Movie BoxSets</string>
     
     <string id="30239">Reset local Kodi database</string><!-- Verified -->
-    <string id="30240">Enable watched/resume status sync</string>
-    <string id="30241">DB Sync Indication:</string>
-    <string id="30242">Play Count Sync Indication:</string>
     <string id="30243">Enable HTTPS</string><!-- Verified -->
     <string id="30245">Force Transcoding Codecs</string>
     
-    <string id="30246">Enable Netflix style next up notification</string>
-    <string id="30247">  - The number of seconds before the end to show the notification</string>
-    <string id="30248">Show Emby Info dialog on play/select action</string>
     <string id="30249">Enable server connection message on startup</string><!-- Verified -->
     
     <string id="30251">Recently added Home Videos</string><!-- Verified -->
@@ -252,14 +175,13 @@
     
     <!-- contextmenu -->
     <string id="30401">Emby options</string>
-    <string id="30402">Clear like for this item</string>
-    <string id="30403">Like this item</string>
-    <string id="30404">Dislike this item</string>
     <string id="30405">Add to Emby favorites</string>
     <string id="30406">Remove from Emby favorites</string>
     <string id="30407">Set custom song rating</string>
     <string id="30408">Emby addon settings</string>
     <string id="30409">Delete item from the server</string>
+    <string id="30410">Refresh this item</string>
+    <string id="30411">Set custom song rating (0-5)</string>
 
     <!-- add-on settings -->
     <string id="30500">Verify Host SSL Certificate</string>
@@ -299,7 +221,8 @@
     <string id="30534">Server messages</string>
     <string id="30535">Generate a new device Id</string>
     <string id="30536">Sync when screensaver is deactivated</string>
-    <string id="30537">Force Transcode Hi10P</string>    
+    <string id="30537">Force Transcode Hi10P</string>
+    <string id="30538">Disabled</string>
 
     <!-- service add-on -->
     <string id="33000">Welcome</string>
@@ -337,4 +260,60 @@
     <string id="33032">Failed to generate a new device Id. See your logs for more information.</string>
     <string id="33033">A new device Id has been generated. Kodi will now restart.</string>
 
-</strings>
+    <string id="33034">Proceed with the following server?</string>
+    <string id="33035">Caution! If you choose Native mode, certain Emby features will be missing, such as: Emby cinema mode, direct stream/transcode options and parental access schedule.</string>
+    <string id="33036">Addon (Default)</string>
+    <string id="33037">Native (Direct Paths)</string>
+    <string id="33038">Add network credentials to allow Kodi access to your content? Important: Kodi will need to be restarted to see the credentials. They can also be added at a later time.</string>
+    <string id="33039">Disable Emby music library?</string>
+    <string id="33040">Direct stream the music library? Select this option if the music library will be remotely accessed.</string>
+    <string id="33041">Delete file(s) from Emby Server? This will also delete the file(s) from disk!</string>
+    <string id="33042">Running the caching process may take some time. Continue anyway?</string>
+    <string id="33043">Artwork cache sync</string>
+    <string id="33044">Reset existing artwork cache?</string>
+    <string id="33045">Updating artwork cache:</string>
+    <string id="33046">Waiting for all threads to exit:</string>
+    <string id="33047">Kodi can't locate file:</string>
+    <string id="33048">You may need to verify your network credentials in the add-on settings or use the Emby path substitution to format your path correctly (Emby dashboard > library). Stop syncing?</string>
+    <string id="33049">Added:</string>
+    <string id="33050">If you fail to log in too many times, the Emby server might lock your account. Proceed anyway?</string>
+    <string id="33051">Live TV Channels (experimental)</string>
+    <string id="33052">Live TV Recordings (experimental)</string>
+    <string id="33053">Settings</string>
+    <string id="33054">Add user to session</string>
+    <string id="33055">Refresh Emby playlists/Video nodes</string>
+    <string id="33056">Perform manual sync</string>
+    <string id="33057">Repair local database (force update all content)</string>
+    <string id="33058">Perform local database reset</string>
+    <string id="33059">Cache all artwork</string>
+    <string id="33060">Sync Emby Theme Media to Kodi</string>
+    <string id="33061">Add/Remove user from the session</string>
+    <string id="33062">Add user</string>
+    <string id="33063">Remove user</string>
+    <string id="33064">Remove user from the session</string>
+    <string id="33065">Success!</string>
+    <string id="33066">Removed from viewing session:</string>
+    <string id="33067">Added to viewing session:</string>
+    <string id="33068">Unable to add/remove user from the session.</string>
+    <string id="33069">The task succeeded</string>
+    <string id="33070">The task failed</string>
+    <string id="33071">Direct Stream</string>
+    <string id="33072">Playback method for your themes</string>
+    <string id="33073">The settings file does not exist in TV Tunes. Change a setting and run the task again.</string>
+    <string id="33074">Are you sure you want to reset your local Kodi database?</string>
+    <string id="33075">Modify/Remove network credentials</string>
+    <string id="33076">Modify</string>
+    <string id="33077">Remove</string>
+    <string id="33078">Removed:</string>
+    <string id="33079">Enter the network username</string>
+    <string id="33080">Enter the network password</string>
+    <string id="33081">Added network credentials for:</string>
+    <string id="33082">Input the server name or IP address as indicated in your emby library paths. For example, the server name: \\\\SERVER-PC\\path\\ is "SERVER-PC"</string>
+    <string id="33083">Modify the server name or IP address</string>
+    <string id="33084">Enter the server name or IP address</string>
+    <string id="33085">Could not reset the database. Try again.</string>
+    <string id="33086">Remove all cached artwork?</string>
+    <string id="33087">Reset all Emby add-on settings?</string>
+    <string id="33088">Database reset has completed, Kodi will now restart to apply the changes.</string>
+
+</strings>
\ No newline at end of file
diff --git a/resources/lib/api.py b/resources/lib/api.py
index 97ad4178..e5641e52 100644
--- a/resources/lib/api.py
+++ b/resources/lib/api.py
@@ -5,7 +5,7 @@
 ##################################################################################################
 
 import clientinfo
-import utils
+from utils import Logging, settings
 
 ##################################################################################################
 
@@ -13,17 +13,16 @@ import utils
 class API():
 
     def __init__(self, item):
+
+        global log
+        log = Logging(self.__class__.__name__).log
+        
         # item is the api response
         self.item = item
 
         self.clientinfo = clientinfo.ClientInfo()
         self.addonName = self.clientinfo.getAddonName()
 
-    def logMsg(self, msg, lvl=1):
-
-        className = self.__class__.__name__
-        utils.logMsg("%s %s" % (self.addonName, className), msg, lvl)
-
 
     def getUserData(self):
         # Default
@@ -223,7 +222,7 @@ class API():
         resume = 0
         if resume_seconds:
             resume = round(float(resume_seconds), 6)
-            jumpback = int(utils.settings('resumeJumpBack'))
+            jumpback = int(settings('resumeJumpBack'))
             if resume > jumpback:
                 # To avoid negative bookmark
                 resume = resume - jumpback
diff --git a/resources/lib/artwork.py b/resources/lib/artwork.py
index 9885829c..f2cd0a32 100644
--- a/resources/lib/artwork.py
+++ b/resources/lib/artwork.py
@@ -12,9 +12,9 @@ import xbmc
 import xbmcgui
 import xbmcvfs
 
-import utils
 import clientinfo
 import image_cache_thread
+from utils import Logging, window, settings, language as lang, kodiSQL
 
 #################################################################################################
 
@@ -29,24 +29,25 @@ class Artwork():
     imageCacheThreads = []
     imageCacheLimitThreads = 0
 
+
     def __init__(self):
+
+        global log
+        log = Logging(self.__class__.__name__).log
+
         self.clientinfo = clientinfo.ClientInfo()
         self.addonName = self.clientinfo.getAddonName()
 
-        self.enableTextureCache = utils.settings('enableTextureCache') == "true"
-        self.imageCacheLimitThreads = int(utils.settings("imageCacheLimit"))
+        self.enableTextureCache = settings('enableTextureCache') == "true"
+        self.imageCacheLimitThreads = int(settings('imageCacheLimit'))
         self.imageCacheLimitThreads = int(self.imageCacheLimitThreads * 5)
-        utils.logMsg("Using Image Cache Thread Count: " + str(self.imageCacheLimitThreads), 1)
+        log("Using Image Cache Thread Count: %s" % 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)
+        self.userId = window('emby_currUser')
+        self.server = window('emby_server%s' % self.userId)
 
 
     def double_urlencode(self, text):
@@ -56,8 +57,8 @@ class Artwork():
         return text
 
     def single_urlencode(self, text):
-
-        text = urllib.urlencode({'blahblahblah':text.encode("utf-8")}) #urlencode needs a utf- string
+        # urlencode needs a utf- string
+        text = urllib.urlencode({'blahblahblah':text.encode("utf-8")}) 
         text = text[13:]
 
         return text.decode("utf-8") #return the result again as unicode
@@ -164,130 +165,138 @@ class Artwork():
         except TypeError:
             pass
 
-    def FullTextureCacheSync(self):
+    def fullTextureCacheSync(self):
         # This method will sync all Kodi artwork to textures13.db
         # and cache them locally. This takes diskspace!
+        dialog = xbmcgui.Dialog()
 
-        if not xbmcgui.Dialog().yesno("Image Texture Cache", "Running the image cache process can take some time.", "Are you sure you want continue?"):
+        if not dialog.yesno(
+                    heading=lang(29999),
+                    line1=lang(33042)):
             return
 
-        self.logMsg("Doing Image Cache Sync", 1)
+        log("Doing Image Cache Sync", 1)
 
-        dialog = xbmcgui.DialogProgress()
-        dialog.create("Emby for Kodi", "Image Cache Sync")
+        pdialog = xbmcgui.DialogProgress()
+        pdialog.create(lang(29999), lang(33043))
 
         # 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)
+        if dialog.yesno(lang(29999), lang(33044)):
+            log("Resetting all cache data first.", 1)
+            
             # Remove all existing textures first
-            path = xbmc.translatePath("special://thumbnails/").decode('utf-8')
+            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')))
+                            path = os.path.join(path+dir.decode('utf-8'),file.decode('utf-8'))
+                            xbmcvfs.delete(path)
                         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()
+            connection = kodiSQL('texture')
+            cursor = connection.cursor()
+            cursor.execute('SELECT tbl_name FROM sqlite_master WHERE type="table"')
+            rows = cursor.fetchall()
             for row in rows:
                 tableName = row[0]
-                if(tableName != "version"):
-                    texturecursor.execute("DELETE FROM " + tableName)
-            textureconnection.commit()
-            texturecursor.close()
+                if tableName != "version":
+                    cursor.execute("DELETE FROM " + tableName)
+            connection.commit()
+            cursor.close()
 
         # Cache all entries in video DB
-        connection = utils.kodiSQL('video')
+        connection = 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
+        log("Image cache sync about to process %s images" % total, 1)
         cursor.close()
 
+        count = 0
+        for url in result:
+            
+            if pdialog.iscanceled():
+                break
+
+            percentage = int((float(count) / float(total))*100)
+            message = "%s of %s (%s)" % (count, total, self.imageCacheThreads)
+            pdialog.update(percentage, "%s %s" % (lang(33045), message))
+            self.cacheTexture(url[0])
+            count += 1
+        
         # Cache all entries in music DB
-        connection = utils.kodiSQL('music')
+        connection = 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
+        log("Image cache sync about to process %s images" % total, 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:
+        count = 0
+        for url in result:
+            
+            if pdialog.iscanceled():
+                break
+
+            percentage = int((float(count) / float(total))*100)
+            message = "%s of %s" % (count, total)
+            pdialog.update(percentage, "%s %s" % (lang(33045), message))
+            self.cacheTexture(url[0])
+            count += 1
+        
+        pdialog.update(100, "%s %s" % (lang(33046), len(self.imageCacheThreads)))
+        log("Waiting for all threads to exit", 1)
+        
+        while len(self.imageCacheThreads):
             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)
+            pdialog.update(100, "%s %s" % (lang(33046), len(self.imageCacheThreads)))
+            log("Waiting for all threads to exit: %s" % len(self.imageCacheThreads), 1)
             xbmc.sleep(500)
 
-        dialog.close()
+        pdialog.close()
 
-    def addWorkerImageCacheThread(self, urlToAdd):
+    def addWorkerImageCacheThread(self, url):
 
-        while(True):
+        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):
+            if len(self.imageCacheThreads) < self.imageCacheLimitThreads:
                 newThread = image_cache_thread.image_cache_thread()
-                newThread.setUrl(self.double_urlencode(urlToAdd))
+                newThread.setUrl(self.double_urlencode(url))
                 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)
+                log("Waiting for empty queue spot: %s" % len(self.imageCacheThreads), 2)
                 xbmc.sleep(50)
 
-
-    def CacheTexture(self, url):
+    def cacheTexture(self, url):
         # Cache a single image url to the texture cache
         if url and self.enableTextureCache:
-            self.logMsg("Processing: %s" % url, 2)
+            log("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
+            if not self.imageCacheLimitThreads:
+                # 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"
+                                        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))
@@ -397,7 +406,7 @@ class Artwork():
 
             except TypeError: # Add the artwork
                 cacheimage = True
-                self.logMsg("Adding Art Link for kodiId: %s (%s)" % (kodiId, imageUrl), 2)
+                log("Adding Art Link for kodiId: %s (%s)" % (kodiId, imageUrl), 2)
 
                 query = (
                     '''
@@ -413,13 +422,12 @@ class Artwork():
                     cacheimage = True
 
                     # Only for the main backdrop, poster
-                    if (utils.window('emby_initialScan') != "true" and
+                    if (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)"
+                    log("Updating Art url for %s kodiId: %s (%s) -> (%s)"
                         % (imageType, kodiId, url, imageUrl), 1)
 
                     query = ' '.join((
@@ -434,9 +442,9 @@ class Artwork():
 
             # Cache fanart and poster in Kodi texture cache
             if cacheimage and imageType in ("fanart", "poster"):
-                self.CacheTexture(imageUrl)
+                self.cacheTexture(imageUrl)
 
-    def deleteArtwork(self, kodiid, mediatype, cursor):
+    def deleteArtwork(self, kodiId, mediaType, cursor):
 
         query = ' '.join((
 
@@ -445,18 +453,18 @@ class Artwork():
             "WHERE media_id = ?",
             "AND media_type = ?"
         ))
-        cursor.execute(query, (kodiid, mediatype,))
+        cursor.execute(query, (kodiId, mediaType,))
         rows = cursor.fetchall()
         for row in rows:
 
             url = row[0]
-            imagetype = row[1]
-            if imagetype in ("poster", "fanart"):
+            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')
+        connection = kodiSQL('texture')
         cursor = connection.cursor()
 
         try:
@@ -464,21 +472,21 @@ class Artwork():
             cachedurl = cursor.fetchone()[0]
 
         except TypeError:
-            self.logMsg("Could not find cached url.", 1)
+            log("Could not find cached url.", 1)
 
         except OperationalError:
-            self.logMsg("Database is locked. Skip deletion process.", 1)
+            log("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)
+            log("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)
+                log("Issue deleting url from cache. Skipping.", 2)
 
         finally:
             cursor.close()
@@ -501,26 +509,26 @@ class Artwork():
 
         return people
 
-    def getUserArtwork(self, itemid, itemtype):
+    def getUserArtwork(self, itemId, itemType):
         # Load user information set by UserClient
         image = ("%s/emby/Users/%s/Images/%s?Format=original"
-                    % (self.server, itemid, itemtype))
+                    % (self.server, itemId, itemType))
         return image
 
     def getAllArtwork(self, item, parentInfo=False):
 
         itemid = item['Id']
         artworks = item['ImageTags']
-        backdrops = item.get('BackdropImageTags',[])
+        backdrops = item.get('BackdropImageTags', [])
 
         maxHeight = 10000
         maxWidth = 10000
         customquery = ""
 
-        if utils.settings('compressArt') == "true":
+        if settings('compressArt') == "true":
             customquery = "&Quality=90"
 
-        if utils.settings('enableCoverArt') == "false":
+        if settings('enableCoverArt') == "false":
             customquery += "&EnableImageEnhancers=false"
 
         allartworks = {
@@ -601,4 +609,4 @@ class Artwork():
                         % (self.server, parentId, maxWidth, maxHeight, parentTag, customquery))
                     allartworks['Primary'] = artwork
 
-        return allartworks
+        return allartworks
\ No newline at end of file
diff --git a/resources/lib/clientinfo.py b/resources/lib/clientinfo.py
index 8b3fe655..d5550388 100644
--- a/resources/lib/clientinfo.py
+++ b/resources/lib/clientinfo.py
@@ -9,7 +9,7 @@ import xbmc
 import xbmcaddon
 import xbmcvfs
 
-import utils
+from utils import Logging, window, settings
 
 #################################################################################################
 
@@ -19,14 +19,12 @@ class ClientInfo():
 
     def __init__(self):
 
+        global log
+        log = Logging(self.__class__.__name__).log
+
         self.addon = xbmcaddon.Addon()
         self.addonName = self.getAddonName()
 
-    def logMsg(self, msg, lvl=1):
-
-        className = self.__class__.__name__
-        utils.logMsg("%s %s" % (self.addonName, className), msg, lvl)
-
 
     def getAddonName(self):
         # Used for logging
@@ -42,11 +40,11 @@ class ClientInfo():
 
     def getDeviceName(self):
 
-        if utils.settings('deviceNameOpt') == "false":
+        if settings('deviceNameOpt') == "false":
             # Use Kodi's deviceName
             deviceName = xbmc.getInfoLabel('System.FriendlyName').decode('utf-8')
         else:
-            deviceName = utils.settings('deviceName')
+            deviceName = settings('deviceName')
             deviceName = deviceName.replace("\"", "_")
             deviceName = deviceName.replace("/", "_")
 
@@ -71,16 +69,18 @@ class ClientInfo():
 
     def getDeviceId(self, reset=False):
 
-        clientId = utils.window('emby_deviceId')
+        clientId = window('emby_deviceId')
         if clientId:
             return clientId
 
         addon_path = self.addon.getAddonInfo('path').decode('utf-8')
         if os.path.supports_unicode_filenames:
-            GUID_file = xbmc.translatePath(os.path.join(addon_path, "machine_guid")).decode('utf-8')
+            path = os.path.join(addon_path, "machine_guid")
         else:
-            GUID_file = xbmc.translatePath(os.path.join(addon_path.encode("utf-8"), "machine_guid")).decode('utf-8')
-
+            path = os.path.join(addon_path.encode('utf-8'), "machine_guid")
+        
+        GUID_file = xbmc.translatePath(path).decode('utf-8')
+        
         if reset and xbmcvfs.exists(GUID_file):
             # Reset the file
             xbmcvfs.delete(GUID_file)
@@ -88,14 +88,14 @@ class ClientInfo():
         GUID = xbmcvfs.File(GUID_file)
         clientId = GUID.read()
         if not clientId:
-            self.logMsg("Generating a new deviceid...", 1)
+            log("Generating a new deviceid...", 1)
             clientId = str("%012X" % uuid4())
             GUID = xbmcvfs.File(GUID_file, 'w')
             GUID.write(clientId)
 
         GUID.close()
 
-        self.logMsg("DeviceId loaded: %s" % clientId, 1)
-        utils.window('emby_deviceId', value=clientId)
+        log("DeviceId loaded: %s" % clientId, 1)
+        window('emby_deviceId', value=clientId)
         
         return clientId
\ No newline at end of file
diff --git a/resources/lib/connect.py b/resources/lib/connect.py
index 2bd5c05d..87dbc2e1 100644
--- a/resources/lib/connect.py
+++ b/resources/lib/connect.py
@@ -6,8 +6,8 @@ import json
 import requests
 import logging
 
-import utils
 import clientinfo
+from utils import Logging, window
 
 ##################################################################################################
 
@@ -34,28 +34,26 @@ class ConnectUtils():
 
     def __init__(self):
 
+        global log
+        log = Logging(self.__class__.__name__).log
+
         self.__dict__ = self._shared_state
 
-    def logMsg(self, msg, lvl=1):
-
-        className = self.__class__.__name__
-        utils.logMsg("%s %s" % (self.addonName, className), msg, lvl)
-
 
     def setUserId(self, userId):
         # Reserved for userclient only
         self.userId = userId
-        self.logMsg("Set connect userId: %s" % userId, 2)
+        log("Set connect userId: %s" % userId, 2)
 
     def setServer(self, server):
         # Reserved for userclient only
         self.server = server
-        self.logMsg("Set connect server: %s" % server, 2)
+        log("Set connect server: %s" % server, 2)
 
     def setToken(self, token):
         # Reserved for userclient only
         self.token = token
-        self.logMsg("Set connect token: %s" % token, 2)
+        log("Set connect token: %s" % token, 2)
 
 
     def startSession(self):
@@ -73,7 +71,7 @@ class ConnectUtils():
             if self.sslclient is not None:
                 verify = self.sslclient
         except:
-            self.logMsg("Could not load SSL settings.", 1)
+            log("Could not load SSL settings.", 1)
 
         # Start session
         self.c = requests.Session()
@@ -83,13 +81,13 @@ class ConnectUtils():
         self.c.mount("http://", requests.adapters.HTTPAdapter(max_retries=1))
         self.c.mount("https://", requests.adapters.HTTPAdapter(max_retries=1))
 
-        self.logMsg("Requests session started on: %s" % self.server, 1)
+        log("Requests session started on: %s" % self.server, 1)
 
     def stopSession(self):
         try:
             self.c.close()
         except Exception as e:
-            self.logMsg("Requests session could not be terminated: %s" % e, 1)
+            log("Requests session could not be terminated: %s" % e, 1)
 
     def getHeader(self, authenticate=True):
 
@@ -103,7 +101,7 @@ class ConnectUtils():
                 'Content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
                 'Accept': "application/json"
             }
-            self.logMsg("Header: %s" % header, 1)
+            log("Header: %s" % header, 1)
 
         else:
             token = self.token
@@ -115,17 +113,17 @@ class ConnectUtils():
                 'X-Application': "Kodi/%s" % version,
                 'X-Connect-UserToken': token
             }
-            self.logMsg("Header: %s" % header, 1)
+            log("Header: %s" % header, 1)
 
         return header
 
     def doUrl(self, url, data=None, postBody=None, rtype="GET",
                 parameters=None, authenticate=True, timeout=None):
 
-        window = utils.window
-
-        self.logMsg("=== ENTER connectUrl ===", 2)
+        log("=== ENTER connectUrl ===", 2)
+        
         default_link = ""
+        
         if timeout is None:
             timeout = self.timeout
 
@@ -209,25 +207,25 @@ class ConnectUtils():
                                     verify=verifyssl)
 
             ##### THE RESPONSE #####
-            self.logMsg(r.url, 1)
-            self.logMsg(r, 1)
+            log(r.url, 1)
+            log(r, 1)
 
             if r.status_code == 204:
                 # No body in the response
-                self.logMsg("====== 204 Success ======", 1)
+                log("====== 204 Success ======", 1)
 
             elif r.status_code == requests.codes.ok:
 
                 try:
                     # UNICODE - JSON object
                     r = r.json()
-                    self.logMsg("====== 200 Success ======", 1)
-                    self.logMsg("Response: %s" % r, 1)
+                    log("====== 200 Success ======", 1)
+                    log("Response: %s" % r, 1)
                     return r
 
                 except:
                     if r.headers.get('content-type') != "text/html":
-                        self.logMsg("Unable to convert the response for: %s" % url, 1)
+                        log("Unable to convert the response for: %s" % url, 1)
             else:
                 r.raise_for_status()
 
@@ -238,8 +236,8 @@ class ConnectUtils():
             pass
 
         except requests.exceptions.ConnectTimeout as e:
-            self.logMsg("Server timeout at: %s" % url, 0)
-            self.logMsg(e, 1)
+            log("Server timeout at: %s" % url, 0)
+            log(e, 1)
 
         except requests.exceptions.HTTPError as e:
 
@@ -255,11 +253,11 @@ class ConnectUtils():
                 pass
 
         except requests.exceptions.SSLError as e:
-            self.logMsg("Invalid SSL certificate for: %s" % url, 0)
-            self.logMsg(e, 1)
+            log("Invalid SSL certificate for: %s" % url, 0)
+            log(e, 1)
 
         except requests.exceptions.RequestException as e:
-            self.logMsg("Unknown error connecting to: %s" % url, 0)
-            self.logMsg(e, 1)
+            log("Unknown error connecting to: %s" % url, 0)
+            log(e, 1)
 
-        return default_link
+        return default_link
\ No newline at end of file
diff --git a/resources/lib/downloadutils.py b/resources/lib/downloadutils.py
index a74ee6f2..ea55e7d1 100644
--- a/resources/lib/downloadutils.py
+++ b/resources/lib/downloadutils.py
@@ -9,14 +9,15 @@ import logging
 import xbmc
 import xbmcgui
 
-import utils
 import clientinfo
+from utils import Logging, window, settings
 
 ##################################################################################################
 
 # Disable requests logging
-from requests.packages.urllib3.exceptions import InsecureRequestWarning
+from requests.packages.urllib3.exceptions import InsecureRequestWarning, InsecurePlatformWarning
 requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
+requests.packages.urllib3.disable_warnings(InsecurePlatformWarning)
 #logging.getLogger('requests').setLevel(logging.WARNING)
 
 ##################################################################################################
@@ -36,40 +37,38 @@ class DownloadUtils():
 
     def __init__(self):
 
+        global log
+        log = Logging(self.__class__.__name__).log
+
         self.__dict__ = self._shared_state
 
-    def logMsg(self, msg, lvl=1):
-
-        className = self.__class__.__name__
-        utils.logMsg("%s %s" % (self.addonName, className), msg, lvl)
-
 
     def setUsername(self, username):
         # Reserved for userclient only
         self.username = username
-        self.logMsg("Set username: %s" % username, 2)
+        log("Set username: %s" % username, 2)
 
     def setUserId(self, userId):
         # Reserved for userclient only
         self.userId = userId
-        self.logMsg("Set userId: %s" % userId, 2)
+        log("Set userId: %s" % userId, 2)
 
     def setServer(self, server):
         # Reserved for userclient only
         self.server = server
-        self.logMsg("Set server: %s" % server, 2)
+        log("Set server: %s" % server, 2)
 
     def setToken(self, token):
         # Reserved for userclient only
         self.token = token
-        self.logMsg("Set token: %s" % token, 2)
+        log("Set token: %s" % token, 2)
 
     def setSSL(self, ssl, sslclient):
         # Reserved for userclient only
         self.sslverify = ssl
         self.sslclient = sslclient
-        self.logMsg("Verify SSL host certificate: %s" % ssl, 2)
-        self.logMsg("SSL client side certificate: %s" % sslclient, 2)
+        log("Verify SSL host certificate: %s" % ssl, 2)
+        log("SSL client side certificate: %s" % sslclient, 2)
 
 
     def postCapabilities(self, deviceId):
@@ -94,11 +93,11 @@ class DownloadUtils():
             )
         }
 
-        self.logMsg("Capabilities URL: %s" % url, 2)
-        self.logMsg("Postdata: %s" % data, 2)
+        log("Capabilities URL: %s" % url, 2)
+        log("Postdata: %s" % data, 2)
 
         self.downloadUrl(url, postBody=data, action_type="POST")
-        self.logMsg("Posted capabilities to %s" % self.server, 2)
+        log("Posted capabilities to %s" % self.server, 2)
 
         # Attempt at getting sessionId
         url = "{server}/emby/Sessions?DeviceId=%s&format=json" % deviceId
@@ -107,20 +106,19 @@ class DownloadUtils():
             sessionId = result[0]['Id']
 
         except (KeyError, TypeError):
-            self.logMsg("Failed to retrieve sessionId.", 1)
+            log("Failed to retrieve sessionId.", 1)
 
         else:
-            self.logMsg("Session: %s" % result, 2)
-            self.logMsg("SessionId: %s" % sessionId, 1)
-            utils.window('emby_sessionId', value=sessionId)
+            log("Session: %s" % result, 2)
+            log("SessionId: %s" % sessionId, 1)
+            window('emby_sessionId', value=sessionId)
 
             # Post any permanent additional users
-            additionalUsers = utils.settings('additionalUsers')
+            additionalUsers = settings('additionalUsers')
             if additionalUsers:
 
                 additionalUsers = additionalUsers.split(',')
-                self.logMsg(
-                    "List of permanent users added to the session: %s"
+                log("List of permanent users added to the session: %s"
                     % additionalUsers, 1)
 
                 # Get the user list from server to get the userId
@@ -158,7 +156,7 @@ class DownloadUtils():
             if self.sslclient is not None:
                 verify = self.sslclient
         except:
-            self.logMsg("Could not load SSL settings.", 1)
+            log("Could not load SSL settings.", 1)
 
         # Start session
         self.s = requests.Session()
@@ -168,18 +166,18 @@ class DownloadUtils():
         self.s.mount("http://", requests.adapters.HTTPAdapter(max_retries=1))
         self.s.mount("https://", requests.adapters.HTTPAdapter(max_retries=1))
 
-        self.logMsg("Requests session started on: %s" % self.server, 1)
+        log("Requests session started on: %s" % self.server, 1)
 
     def stopSession(self):
         try:
             self.s.close()
         except:
-            self.logMsg("Requests session could not be terminated.", 1)
+            log("Requests session could not be terminated.", 1)
 
     def getHeader(self, authenticate=True):
 
         deviceName = self.clientInfo.getDeviceName()
-        deviceName = utils.normalize_string(deviceName.encode('utf-8'))
+        deviceName = deviceName.encode('utf-8')
         deviceId = self.clientInfo.getDeviceId()
         version = self.clientInfo.getVersion()
 
@@ -195,7 +193,7 @@ class DownloadUtils():
                 'Accept-Charset': 'UTF-8,*',
                 'Authorization': auth
             }
-            self.logMsg("Header: %s" % header, 2)
+            log("Header: %s" % header, 2)
 
         else:
             userId = self.userId
@@ -212,19 +210,20 @@ class DownloadUtils():
                 'Authorization': auth,
                 'X-MediaBrowser-Token': token
             }
-            self.logMsg("Header: %s" % header, 2)
+            log("Header: %s" % header, 2)
 
         return header
 
-    def downloadUrl(self, url, postBody=None, action_type="GET", parameters=None, authenticate=True):
+    def downloadUrl(self, url, postBody=None, action_type="GET", parameters=None,
+                    authenticate=True):
 
-        self.logMsg("=== ENTER downloadUrl ===", 2)
+        log("=== ENTER downloadUrl ===", 2)
 
         default_link = ""
 
         try:
             # If user is authenticated
-            if (authenticate):
+            if authenticate:
                 # Get requests session
                 try:
                     s = self.s
@@ -243,18 +242,18 @@ class DownloadUtils():
                 except AttributeError:
                     # request session does not exists
                     # Get user information
-                    self.userId = utils.window('emby_currUser')
-                    self.server = utils.window('emby_server%s' % self.userId)
-                    self.token = utils.window('emby_accessToken%s' % self.userId)
+                    self.userId = window('emby_currUser')
+                    self.server = window('emby_server%s' % self.userId)
+                    self.token = window('emby_accessToken%s' % self.userId)
                     header = self.getHeader()
                     verifyssl = False
                     cert = None
 
                     # IF user enables ssl verification
-                    if utils.settings('sslverify') == "true":
+                    if settings('sslverify') == "true":
                         verifyssl = True
-                    if utils.settings('sslcert') != "None":
-                        verifyssl = utils.settings('sslcert')
+                    if settings('sslcert') != "None":
+                        verifyssl = settings('sslcert')
 
                     # Replace for the real values
                     url = url.replace("{server}", self.server)
@@ -314,23 +313,23 @@ class DownloadUtils():
                                     verify=verifyssl)
 
             ##### THE RESPONSE #####
-            self.logMsg(r.url, 2)
+            log(r.url, 2)
             if r.status_code == 204:
                 # No body in the response
-                self.logMsg("====== 204 Success ======", 2)
+                log("====== 204 Success ======", 2)
 
             elif r.status_code == requests.codes.ok:
 
                 try:
                     # UNICODE - JSON object
                     r = r.json()
-                    self.logMsg("====== 200 Success ======", 2)
-                    self.logMsg("Response: %s" % r, 2)
+                    log("====== 200 Success ======", 2)
+                    log("Response: %s" % r, 2)
                     return r
 
                 except:
                     if r.headers.get('content-type') != "text/html":
-                        self.logMsg("Unable to convert the response for: %s" % url, 1)
+                        log("Unable to convert the response for: %s" % url, 1)
             else:
                 r.raise_for_status()
 
@@ -338,26 +337,26 @@ class DownloadUtils():
 
         except requests.exceptions.ConnectionError as e:
             # Make the addon aware of status
-            if utils.window('emby_online') != "false":
-                self.logMsg("Server unreachable at: %s" % url, 0)
-                self.logMsg(e, 2)
-                utils.window('emby_online', value="false")
+            if window('emby_online') != "false":
+                log("Server unreachable at: %s" % url, 0)
+                log(e, 2)
+                window('emby_online', value="false")
 
         except requests.exceptions.ConnectTimeout as e:
-            self.logMsg("Server timeout at: %s" % url, 0)
-            self.logMsg(e, 1)
+            log("Server timeout at: %s" % url, 0)
+            log(e, 1)
 
         except requests.exceptions.HTTPError as e:
 
             if r.status_code == 401:
                 # Unauthorized
-                status = utils.window('emby_serverStatus')
+                status = window('emby_serverStatus')
 
                 if 'X-Application-Error-Code' in r.headers:
                     # Emby server errors
                     if r.headers['X-Application-Error-Code'] == "ParentalControl":
                         # Parental control - access restricted
-                        utils.window('emby_serverStatus', value="restricted")
+                        window('emby_serverStatus', value="restricted")
                         xbmcgui.Dialog().notification(
                                                 heading="Emby server",
                                                 message="Access restricted.",
@@ -371,8 +370,8 @@ class DownloadUtils():
 
                 elif status not in ("401", "Auth"):
                     # Tell userclient token has been revoked.
-                    utils.window('emby_serverStatus', value="401")
-                    self.logMsg("HTTP Error: %s" % e, 0)
+                    window('emby_serverStatus', value="401")
+                    log("HTTP Error: %s" % e, 0)
                     xbmcgui.Dialog().notification(
                                             heading="Error connecting",
                                             message="Unauthorized.",
@@ -387,11 +386,11 @@ class DownloadUtils():
                 pass
 
         except requests.exceptions.SSLError as e:
-            self.logMsg("Invalid SSL certificate for: %s" % url, 0)
-            self.logMsg(e, 1)
+            log("Invalid SSL certificate for: %s" % url, 0)
+            log(e, 1)
 
         except requests.exceptions.RequestException as e:
-            self.logMsg("Unknown error connecting to: %s" % url, 0)
-            self.logMsg(e, 1)
+            log("Unknown error connecting to: %s" % url, 0)
+            log(e, 1)
 
         return default_link
\ No newline at end of file
diff --git a/resources/lib/embydb_functions.py b/resources/lib/embydb_functions.py
index cfebd5ff..73e808d8 100644
--- a/resources/lib/embydb_functions.py
+++ b/resources/lib/embydb_functions.py
@@ -2,8 +2,10 @@
 
 #################################################################################################
 
-import utils
+from sqlite3 import OperationalError
+
 import clientinfo
+from utils import Logging
 
 #################################################################################################
 
@@ -13,15 +15,14 @@ class Embydb_Functions():
 
     def __init__(self, embycursor):
 
+        global log
+        log = Logging(self.__class__.__name__).log
+
         self.embycursor = embycursor
 
         self.clientInfo = clientinfo.ClientInfo()
         self.addonName = self.clientInfo.getAddonName()
 
-    def logMsg(self, msg, lvl=1):
-
-        className = self.__class__.__name__
-        utils.logMsg("%s %s" % (self.addonName, className), msg, lvl)
 
     def getViews(self):
 
diff --git a/resources/lib/entrypoint.py b/resources/lib/entrypoint.py
index bc81ad0a..14e08196 100644
--- a/resources/lib/entrypoint.py
+++ b/resources/lib/entrypoint.py
@@ -24,28 +24,27 @@ import playlist
 import playbackutils as pbutils
 import playutils
 import api
-
+from utils import Logging, window, settings, language as lang
+log = Logging('Entrypoint').log
 
 #################################################################################################
 
 
-def doPlayback(itemid, dbid):
+def doPlayback(itemId, dbId):
 
     emby = embyserver.Read_EmbyServer()
-    item = emby.getItem(itemid)
-    pbutils.PlaybackUtils(item).play(itemid, dbid)
+    item = emby.getItem(itemId)
+    pbutils.PlaybackUtils(item).play(itemId, dbId)
 
 ##### DO RESET AUTH #####
 def resetAuth():
     # User tried login and failed too many times
     resp = xbmcgui.Dialog().yesno(
-                heading="Warning",
-                line1=(
-                    "Emby might lock your account if you fail to log in too many times. "
-                    "Proceed anyway?"))
-    if resp == 1:
-        utils.logMsg("EMBY", "Reset login attempts.", 1)
-        utils.window('emby_serverStatus', value="Auth")
+                heading=lang(30132),
+                line1=lang(33050))
+    if resp:
+        log("Reset login attempts.", 1)
+        window('emby_serverStatus', value="Auth")
     else:
         xbmc.executebuiltin('Addon.OpenSettings(plugin.video.emby)')
 
@@ -57,65 +56,80 @@ def addDirectoryItem(label, path, folder=True):
     xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=path, listitem=li, isFolder=folder)
 
 def doMainListing():
+
     xbmcplugin.setContent(int(sys.argv[1]), 'files')    
     # Get emby nodes from the window props
-    embyprops = utils.window('Emby.nodes.total')
+    embyprops = window('Emby.nodes.total')
     if embyprops:
         totalnodes = int(embyprops)
         for i in range(totalnodes):
-            path = utils.window('Emby.nodes.%s.index' % i)
+            path = window('Emby.nodes.%s.index' % i)
             if not path:
-                path = utils.window('Emby.nodes.%s.content' % i)
-            label = utils.window('Emby.nodes.%s.title' % i)
-            node_type = utils.window('Emby.nodes.%s.type' % i)
-            #because we do not use seperate entrypoints for each content type, we need to figure out which items to show in each listing.
-            #for now we just only show picture nodes in the picture library video nodes in the video library and all nodes in any other window
-            if path and xbmc.getCondVisibility("Window.IsActive(Pictures)") and node_type == "photos":
-                addDirectoryItem(label, path)
-            elif path and xbmc.getCondVisibility("Window.IsActive(VideoLibrary)") and node_type != "photos":
-                addDirectoryItem(label, path)
-            elif path and not xbmc.getCondVisibility("Window.IsActive(VideoLibrary) | Window.IsActive(Pictures) | Window.IsActive(MusicLibrary)"):
-                addDirectoryItem(label, path)
+                path = window('Emby.nodes.%s.content' % i)
+            label = window('Emby.nodes.%s.title' % i)
+            node = window('Emby.nodes.%s.type' % i)
+            
+            ''' because we do not use seperate entrypoints for each content type,
+                we need to figure out which items to show in each listing.
+                for now we just only show picture nodes in the picture library
+                video nodes in the video library and all nodes in any other window '''
 
-    #experimental live tv nodes
-    addDirectoryItem("Live Tv Channels (experimental)", "plugin://plugin.video.emby/?mode=browsecontent&type=tvchannels&folderid=root")
-    addDirectoryItem("Live Tv Recordings (experimental)", "plugin://plugin.video.emby/?mode=browsecontent&type=recordings&folderid=root")
+            '''if path and xbmc.getCondVisibility("Window.IsActive(Pictures)") and node == "photos":
+                addDirectoryItem(label, path)
+            elif path and xbmc.getCondVisibility("Window.IsActive(VideoLibrary)")
+                and node != "photos":
+                addDirectoryItem(label, path)
+            elif path and not xbmc.getCondVisibility("Window.IsActive(VideoLibrary) |
+                 Window.IsActive(Pictures) | Window.IsActive(MusicLibrary)"):
+                addDirectoryItem(label, path)'''
+
+            if path:
+                if xbmc.getCondVisibility("Window.IsActive(Pictures)") and node == "photos":
+                    addDirectoryItem(label, path)
+                elif xbmc.getCondVisibility("Window.IsActive(VideoLibrary)") and node != "photos":
+                    addDirectoryItem(label, path)
+                elif not xbmc.getCondVisibility("Window.IsActive(VideoLibrary) | Window.IsActive(Pictures) | Window.IsActive(MusicLibrary)"):
+                    addDirectoryItem(label, path)
+
+    # experimental live tv nodes
+    if not xbmc.getCondVisibility("Window.IsActive(Pictures)"):
+        addDirectoryItem(lang(33051),
+            "plugin://plugin.video.emby/?mode=browsecontent&type=tvchannels&folderid=root")
+        addDirectoryItem(lang(33052),
+            "plugin://plugin.video.emby/?mode=browsecontent&type=recordings&folderid=root")
 
     # some extra entries for settings and stuff. TODO --> localize the labels
-    addDirectoryItem("Network credentials", "plugin://plugin.video.emby/?mode=passwords")
-    addDirectoryItem("Settings", "plugin://plugin.video.emby/?mode=settings")
-    addDirectoryItem("Add user to session", "plugin://plugin.video.emby/?mode=adduser")
-    addDirectoryItem("Refresh Emby playlists/nodes", "plugin://plugin.video.emby/?mode=refreshplaylist")
-    addDirectoryItem("Perform manual sync", "plugin://plugin.video.emby/?mode=manualsync")
-    addDirectoryItem("Repair local database (force update all content)", "plugin://plugin.video.emby/?mode=repair")
-    addDirectoryItem("Perform local database reset (full resync)", "plugin://plugin.video.emby/?mode=reset")
-    addDirectoryItem("Cache all images to Kodi texture cache", "plugin://plugin.video.emby/?mode=texturecache")
-    addDirectoryItem("Sync Emby Theme Media to Kodi", "plugin://plugin.video.emby/?mode=thememedia")
+    addDirectoryItem(lang(30517), "plugin://plugin.video.emby/?mode=passwords")
+    addDirectoryItem(lang(33053), "plugin://plugin.video.emby/?mode=settings")
+    addDirectoryItem(lang(33054), "plugin://plugin.video.emby/?mode=adduser")
+    addDirectoryItem(lang(33055), "plugin://plugin.video.emby/?mode=refreshplaylist")
+    addDirectoryItem(lang(33056), "plugin://plugin.video.emby/?mode=manualsync")
+    addDirectoryItem(lang(33057), "plugin://plugin.video.emby/?mode=repair")
+    addDirectoryItem(lang(33058), "plugin://plugin.video.emby/?mode=reset")
+    addDirectoryItem(lang(33059), "plugin://plugin.video.emby/?mode=texturecache")
+    addDirectoryItem(lang(33060), "plugin://plugin.video.emby/?mode=thememedia")
     
     xbmcplugin.endOfDirectory(int(sys.argv[1]))
 
-
 ##### Generate a new deviceId
 def resetDeviceId():
 
     dialog = xbmcgui.Dialog()
-    language = utils.language
 
-    deviceId_old = utils.window('emby_deviceId')
+    deviceId_old = window('emby_deviceId')
     try:
-        utils.window('emby_deviceId', clear=True)
+        window('emby_deviceId', clear=True)
         deviceId = clientinfo.ClientInfo().getDeviceId(reset=True)
     except Exception as e:
-        utils.logMsg("EMBY", "Failed to generate a new device Id: %s" % e, 1)
+        log("Failed to generate a new device Id: %s" % e, 1)
         dialog.ok(
-            heading="Emby for Kodi",
-            line1=language(33032))
+            heading=lang(29999),
+            line1=lang(33032))
     else:
-        utils.logMsg("EMBY", "Successfully removed old deviceId: %s New deviceId: %s"
-                    % (deviceId_old, deviceId), 1)
+        log("Successfully removed old deviceId: %s New deviceId: %s" % (deviceId_old, deviceId), 1)
         dialog.ok(
-            heading="Emby for Kodi",
-            line1=language(33033))
+            heading=lang(29999),
+            line1=lang(33033))
         xbmc.executebuiltin('RestartApp')
 
 ##### Delete Item
@@ -123,50 +137,46 @@ def deleteItem():
 
     # Serves as a keymap action
     if xbmc.getInfoLabel('ListItem.Property(embyid)'): # If we already have the embyid
-        embyid = xbmc.getInfoLabel('ListItem.Property(embyid)')
+        itemId = xbmc.getInfoLabel('ListItem.Property(embyid)')
     else:
-        dbid = xbmc.getInfoLabel('ListItem.DBID')
-        itemtype = xbmc.getInfoLabel('ListItem.DBTYPE')
+        dbId = xbmc.getInfoLabel('ListItem.DBID')
+        itemType = xbmc.getInfoLabel('ListItem.DBTYPE')
 
-        if not itemtype:
+        if not itemType:
 
             if xbmc.getCondVisibility('Container.Content(albums)'):
-                itemtype = "album"
+                itemType = "album"
             elif xbmc.getCondVisibility('Container.Content(artists)'):
-                itemtype = "artist"
+                itemType = "artist"
             elif xbmc.getCondVisibility('Container.Content(songs)'):
-                itemtype = "song"
+                itemType = "song"
             elif xbmc.getCondVisibility('Container.Content(pictures)'):
-                itemtype = "picture"
+                itemType = "picture"
             else:
-                utils.logMsg("EMBY delete", "Unknown type, unable to proceed.", 1)
+                log("Unknown type, unable to proceed.", 1)
                 return
 
         embyconn = utils.kodiSQL('emby')
         embycursor = embyconn.cursor()
         emby_db = embydb.Embydb_Functions(embycursor)
-        item = emby_db.getItem_byKodiId(dbid, itemtype)
+        item = emby_db.getItem_byKodiId(dbId, itemType)
         embycursor.close()
 
         try:
             embyid = item[0]
         except TypeError:
-            utils.logMsg("EMBY delete", "Unknown embyId, unable to proceed.", 1)
+            log("Unknown embyId, unable to proceed.", 1)
             return
 
-    if utils.settings('skipContextMenu') != "true":
+    if 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!"))
+                                heading=lang(29999),
+                                line1=lang(33041))
         if not resp:
-            utils.logMsg("EMBY delete", "User skipped deletion for: %s." % embyid, 1)
+            log("User skipped deletion for: %s." % itemId, 1)
             return
     
-    doUtils = downloadutils.DownloadUtils()
-    url = "{server}/emby/Items/%s?format=json" % embyid
-    utils.logMsg("EMBY delete", "Deleting request: %s" % embyid, 0)
-    doUtils.downloadUrl(url, action_type="DELETE")
+    embyserver.Read_EmbyServer().deleteItem(itemId)
 
 ##### ADD ADDITIONAL USERS #####
 def addUser():
@@ -176,7 +186,7 @@ def addUser():
     clientInfo = clientinfo.ClientInfo()
     deviceId = clientInfo.getDeviceId()
     deviceName = clientInfo.getDeviceName()
-    userid = utils.window('emby_currUser')
+    userid = window('emby_currUser')
     dialog = xbmcgui.Dialog()
 
     # Get session
@@ -203,7 +213,7 @@ def addUser():
         # Display dialog if there's additional users
         if additionalUsers:
 
-            option = dialog.select("Add/Remove user from the session", ["Add user", "Remove user"])
+            option = dialog.select(lang(33061), [lang(33062), lang(33063)])
             # Users currently in the session
             additionalUserlist = {}
             additionalUsername = []
@@ -216,21 +226,21 @@ def addUser():
 
             if option == 1:
                 # User selected Remove user
-                resp = dialog.select("Remove user from the session", additionalUsername)
+                resp = dialog.select(lang(33064), additionalUsername)
                 if resp > -1:
                     selected = additionalUsername[resp]
                     selected_userId = additionalUserlist[selected]
                     url = "{server}/emby/Sessions/%s/Users/%s" % (sessionId, selected_userId)
                     doUtils.downloadUrl(url, postBody={}, action_type="DELETE")
                     dialog.notification(
-                            heading="Success!",
-                            message="%s removed from viewing session" % selected,
+                            heading=lang(29999),
+                            message="%s %s" % (lang(33066), selected),
                             icon="special://home/addons/plugin.video.emby/icon.png",
                             time=1000)
 
                     # clear picture
-                    position = utils.window('EmbyAdditionalUserPosition.%s' % selected_userId)
-                    utils.window('EmbyAdditionalUserImage.%s' % position, clear=True)
+                    position = window('EmbyAdditionalUserPosition.%s' % selected_userId)
+                    window('EmbyAdditionalUserImage.%s' % position, clear=True)
                     return
                 else:
                     return
@@ -247,7 +257,7 @@ def addUser():
                 return
 
         # Subtract any additional users
-        utils.logMsg("EMBY", "Displaying list of users: %s" % users)
+        log("Displaying list of users: %s" % users)
         resp = dialog.select("Add user to the session", users)
         # post additional user
         if resp > -1:
@@ -256,25 +266,25 @@ def addUser():
             url = "{server}/emby/Sessions/%s/Users/%s" % (sessionId, selected_userId)
             doUtils.downloadUrl(url, postBody={}, action_type="POST")
             dialog.notification(
-                    heading="Success!",
-                    message="%s added to viewing session" % selected,
+                    heading=lang(29999),
+                    message="%s %s" % (lang(33067), selected),
                     icon="special://home/addons/plugin.video.emby/icon.png",
                     time=1000)
 
     except:
-        utils.logMsg("EMBY", "Failed to add user to session.")
+        log("Failed to add user to session.")
         dialog.notification(
-                heading="Error",
-                message="Unable to add/remove user from the session.",
+                heading=lang(29999),
+                message=lang(33068),
                 icon=xbmcgui.NOTIFICATION_ERROR)
 
     # Add additional user images
     # always clear the individual items first
     totalNodes = 10
     for i in range(totalNodes):
-        if not utils.window('EmbyAdditionalUserImage.%s' % i):
+        if not window('EmbyAdditionalUserImage.%s' % i):
             break
-        utils.window('EmbyAdditionalUserImage.%s' % i, clear=True)
+        window('EmbyAdditionalUserImage.%s' % i, clear=True)
 
     url = "{server}/emby/Sessions?DeviceId=%s" % deviceId
     result = doUtils.downloadUrl(url)
@@ -284,9 +294,9 @@ def addUser():
         userid = additionaluser['UserId']
         url = "{server}/emby/Users/%s?format=json" % userid
         result = doUtils.downloadUrl(url)
-        utils.window('EmbyAdditionalUserImage.%s' % count,
+        window('EmbyAdditionalUserImage.%s' % count,
             value=art.getUserArtwork(result['Id'], 'Primary'))
-        utils.window('EmbyAdditionalUserPosition.%s' % userid, value=str(count))
+        window('EmbyAdditionalUserPosition.%s' % userid, value=str(count))
         count +=1
 
 ##### THEME MUSIC/VIDEOS #####
@@ -297,7 +307,7 @@ def getThemeMedia():
     playback = None
 
     # Choose playback method
-    resp = dialog.select("Playback method for your themes", ["Direct Play", "Direct Stream"])
+    resp = dialog.select(lang(33072), [lang(30165), lang(33071)])
     if resp == 0:
         playback = "DirectPlay"
     elif resp == 1:
@@ -318,15 +328,11 @@ def getThemeMedia():
         tvtunes = xbmcaddon.Addon(id="script.tvtunes")
         tvtunes.setSetting('custom_path_enable', "true")
         tvtunes.setSetting('custom_path', library)
-        utils.logMsg("EMBY", "TV Tunes custom path is enabled and set.", 1)
+        log("TV Tunes custom path is enabled and set.", 1)
     else:
         # if it does not exist this will not work so warn user
         # often they need to edit the settings first for it to be created.
-        dialog.ok(
-            heading="Warning",
-            line1=(
-                "The settings file does not exist in tvtunes. ",
-                "Go to the tvtunes addon and change a setting, then come back and re-run."))
+        dialog.ok(heading=lang(29999), line1=lang(33073))
         xbmc.executebuiltin('Addon.OpenSettings(script.tvtunes)')
         return
         
@@ -442,8 +448,8 @@ def getThemeMedia():
         nfo_file.close()
 
     dialog.notification(
-            heading="Emby for Kodi",
-            message="Themes added!",
+            heading=lang(29999),
+            message=lang(33069),
             icon="special://home/addons/plugin.video.emby/icon.png",
             time=1000,
             sound=False)
@@ -461,17 +467,17 @@ def refreshPlaylist():
         # Refresh views
         lib.refreshViews()
         dialog.notification(
-                heading="Emby for Kodi",
-                message="Emby playlists/nodes refreshed",
+                heading=lang(29999),
+                message=lang(33069),
                 icon="special://home/addons/plugin.video.emby/icon.png",
                 time=1000,
                 sound=False)
 
     except Exception as e:
-        utils.logMsg("EMBY", "Refresh playlists/nodes failed: %s" % e, 1)
+        log("Refresh playlists/nodes failed: %s" % e, 1)
         dialog.notification(
-            heading="Emby for Kodi",
-            message="Emby playlists/nodes refresh failed",
+            heading=lang(29999),
+            message=lang(33070),
             icon=xbmcgui.NOTIFICATION_ERROR,
             time=1000,
             sound=False)
@@ -480,9 +486,9 @@ def refreshPlaylist():
 def GetSubFolders(nodeindex):
     nodetypes = ["",".recent",".recentepisodes",".inprogress",".inprogressepisodes",".unwatched",".nextepisodes",".sets",".genres",".random",".recommended"]
     for node in nodetypes:
-        title = utils.window('Emby.nodes.%s%s.title' %(nodeindex,node))
+        title = window('Emby.nodes.%s%s.title' %(nodeindex,node))
         if title:
-            path = utils.window('Emby.nodes.%s%s.content' %(nodeindex,node))
+            path = window('Emby.nodes.%s%s.content' %(nodeindex,node))
             addDirectoryItem(title, path)
     xbmcplugin.endOfDirectory(int(sys.argv[1]))
               
@@ -510,7 +516,7 @@ def BrowseContent(viewname, browse_type="", folderid=""):
                 break
     
     if viewname is not None:
-        utils.logMsg("BrowseContent","viewname: %s - type: %s - folderid: %s - filter: %s" %(viewname.decode('utf-8'), browse_type.decode('utf-8'), folderid.decode('utf-8'), filter_type.decode('utf-8')))
+        log("viewname: %s - type: %s - folderid: %s - filter: %s" %(viewname.decode('utf-8'), browse_type.decode('utf-8'), folderid.decode('utf-8'), filter_type.decode('utf-8')))
     #set the correct params for the content type
     #only proceed if we have a folderid
     if folderid:
@@ -795,7 +801,7 @@ def getNextUpEpisodes(tagname, limit):
         pass
     else:
         for item in items:
-            if utils.settings('ignoreSpecialsNextEpisodes') == "true":
+            if settings('ignoreSpecialsNextEpisodes') == "true":
                 query = {
 
                     'jsonrpc': "2.0",
@@ -1043,7 +1049,7 @@ def getExtraFanArt(embyId,embyPath):
         
         if embyId:
             #only proceed if we actually have a emby id
-            utils.logMsg("EMBY", "Requesting extrafanart for Id: %s" % embyId, 0)
+            log("Requesting extrafanart for Id: %s" % embyId, 0)
 
             # We need to store the images locally for this to work
             # because of the caching system in xbmc
@@ -1072,7 +1078,7 @@ def getExtraFanArt(embyId,embyPath):
                         xbmcvfs.copy(backdrop, fanartFile) 
                         count += 1               
             else:
-                utils.logMsg("EMBY", "Found cached backdrop.", 2)
+                log("Found cached backdrop.", 2)
                 # Use existing cached images
                 dirs, files = xbmcvfs.listdir(fanartDir)
                 for file in files:
@@ -1083,7 +1089,7 @@ def getExtraFanArt(embyId,embyPath):
                                             url=fanartFile,
                                             listitem=li)
     except Exception as e:
-        utils.logMsg("EMBY", "Error getting extrafanart: %s" % e, 0)
+        log("Error getting extrafanart: %s" % e, 0)
     
     # Always do endofdirectory to prevent errors in the logs
     xbmcplugin.endOfDirectory(int(sys.argv[1]))
\ No newline at end of file
diff --git a/resources/lib/image_cache_thread.py b/resources/lib/image_cache_thread.py
index 626be481..fdf63d63 100644
--- a/resources/lib/image_cache_thread.py
+++ b/resources/lib/image_cache_thread.py
@@ -1,8 +1,14 @@
+# -*- coding: utf-8 -*-
+
+#################################################################################################
+
 import threading
-import utils
-import xbmc
 import requests
 
+from utils import Logging
+
+#################################################################################################
+
 class image_cache_thread(threading.Thread):
 
     urlToProcess = None
@@ -13,28 +19,32 @@ class image_cache_thread(threading.Thread):
     xbmc_username = ""
     xbmc_password = ""
     
+
     def __init__(self):
-        self.monitor = xbmc.Monitor()
+
+        global log
+        log = Logging(self.__class__.__name__).log
+
         threading.Thread.__init__(self)
-         
-    def logMsg(self, msg, lvl=1):
-        className = self.__class__.__name__
-        utils.logMsg("%s" % className, msg, lvl)
+
         
     def setUrl(self, url):
+
         self.urlToProcess = url
         
     def setHost(self, host, port):
+
         self.xbmc_host = host
         self.xbmc_port = port
         
     def setAuth(self, user, pwd):
+
         self.xbmc_username = user
         self.xbmc_password = pwd
          
     def run(self):
         
-        self.logMsg("Image Caching Thread Processing : " + self.urlToProcess, 2)
+        log("Image Caching Thread Processing: %s" % self.urlToProcess, 2)
         
         try:
             response = requests.head(
@@ -46,7 +56,5 @@ class image_cache_thread(threading.Thread):
         # We don't need the result
         except: pass
         
-        self.logMsg("Image Caching Thread Exited", 2)
-        
-        self.isFinished = True
-        
\ No newline at end of file
+        log("Image Caching Thread Exited", 2)
+        self.isFinished = True
\ No newline at end of file
diff --git a/resources/lib/initialsetup.py b/resources/lib/initialsetup.py
index 7bf0dbb9..da0a5108 100644
--- a/resources/lib/initialsetup.py
+++ b/resources/lib/initialsetup.py
@@ -9,10 +9,10 @@ import xbmc
 import xbmcgui
 import xbmcaddon
 
-import utils
 import clientinfo
 import downloadutils
 import userclient
+from utils import Logging, settings, language as lang, passwordsXML
 
 #################################################################################################
 
@@ -22,74 +22,66 @@ class InitialSetup():
 
     def __init__(self):
 
-        self.addon = xbmcaddon.Addon()
-        self.__language__ = self.addon.getLocalizedString
+        global log
+        log = Logging(self.__class__.__name__).log
 
-        self.clientInfo = clientinfo.ClientInfo()
-        self.addonName = self.clientInfo.getAddonName()
-        self.addonId = self.clientInfo.getAddonId()
-        self.doUtils = downloadutils.DownloadUtils()
+        self.addonId = clientinfo.ClientInfo().getAddonId()
+        self.doUtils = downloadutils.DownloadUtils().downloadUrl
         self.userClient = userclient.UserClient()
-    
-    def logMsg(self, msg, lvl=1):
-
-        className = self.__class__.__name__
-        utils.logMsg("%s %s" % (self.addonName, className), msg, lvl)
 
 
     def setup(self):
         # Check server, user, direct paths, music, direct stream if not direct path.
-        string = self.__language__
         addonId = self.addonId
+        dialog = xbmcgui.Dialog()
 
         ##### SERVER INFO #####
         
-        self.logMsg("Initial setup called.", 2)
+        log("Initial setup called.", 2)
         server = self.userClient.getServer()
 
         if server:
-            self.logMsg("Server is already set.", 2)
+            log("Server is already set.", 2)
             return
         
-        self.logMsg("Looking for server...", 2)
+        log("Looking for server...", 2)
         server = self.getServerDetails()
-        self.logMsg("Found: %s" % server, 2)
+        log("Found: %s" % server, 2)
         try:
             prefix, ip, port = server.replace("/", "").split(":")
         except: # Failed to retrieve server information
-            self.logMsg("getServerDetails failed.", 1)
+            log("getServerDetails failed.", 1)
             xbmc.executebuiltin('Addon.OpenSettings(%s)' % addonId)
             return
         else:
-            server_confirm = xbmcgui.Dialog().yesno(
-                                            heading="Emby for Kodi",
-                                            line1="Proceed with the following server?",
-                                            line2="%s %s" % (string(30169), server))
+            server_confirm = dialog.yesno(
+                                heading=lang(29999),
+                                line1=lang(33034),
+                                line2="%s %s" % (lang(30169), server))
             if server_confirm:
                 # Correct server found
-                self.logMsg("Server is selected. Saving the information.", 1)
-                utils.settings('ipaddress', value=ip)
-                utils.settings('port', value=port)
+                log("Server is selected. Saving the information.", 1)
+                settings('ipaddress', value=ip)
+                settings('port', value=port)
 
                 if prefix == "https":
-                    utils.settings('https', value="true")
+                    settings('https', value="true")
             else:
                 # User selected no or cancelled the dialog
-                self.logMsg("No server selected.", 1)
+                log("No server selected.", 1)
                 xbmc.executebuiltin('Addon.OpenSettings(%s)' % addonId)
                 return
 
         ##### USER INFO #####
         
-        self.logMsg("Getting user list.", 1)
-        
-        url = "%s/emby/Users/Public?format=json" % server
-        result = self.doUtils.downloadUrl(url, authenticate=False)
+        log("Getting user list.", 1)
+
+        result = self.doUtils("%s/emby/Users/Public?format=json" % server, authenticate=False)
         if result == "":
-            self.logMsg("Unable to connect to %s" % server, 1)
+            log("Unable to connect to %s" % server, 1)
             return
 
-        self.logMsg("Response: %s" % result, 2)
+        log("Response: %s" % result, 2)
         # Process the list of users
         usernames = []
         users_hasPassword = []
@@ -103,66 +95,55 @@ class InitialSetup():
                 name = "%s (secure)" % name
             users_hasPassword.append(name)
 
-        self.logMsg("Presenting user list: %s" % users_hasPassword, 1)
-        user_select = xbmcgui.Dialog().select(string(30200), users_hasPassword)
+        log("Presenting user list: %s" % users_hasPassword, 1)
+        user_select = dialog.select(lang(30200), users_hasPassword)
         if user_select > -1:
             selected_user = usernames[user_select]
-            self.logMsg("Selected user: %s" % selected_user, 1)
-            utils.settings('username', value=selected_user)
+            log("Selected user: %s" % selected_user, 1)
+            settings('username', value=selected_user)
         else:
-            self.logMsg("No user selected.", 1)
+            log("No user selected.", 1)
             xbmc.executebuiltin('Addon.OpenSettings(%s)' % addonId)
+            return
 
         ##### ADDITIONAL PROMPTS #####
-        dialog = xbmcgui.Dialog()
 
         directPaths = dialog.yesno(
-                            heading="Playback Mode",
-                            line1=(
-                                "Caution! If you choose Native mode, you "
-                                "will lose access to certain Emby features such as: "
-                                "Emby cinema mode, direct stream/transcode options, "
-                                "parental access schedule."),
-                            nolabel="Addon (Default)",
-                            yeslabel="Native (Direct Paths)")
+                            heading=lang(30511),
+                            line1=lang(33035),
+                            nolabel=lang(33036),
+                            yeslabel=lang(33037))
         if directPaths:
-            self.logMsg("User opted to use direct paths.", 1)
-            utils.settings('useDirectPaths', value="1")
+            log("User opted to use direct paths.", 1)
+            settings('useDirectPaths', value="1")
 
             # ask for credentials
             credentials = dialog.yesno(
-                                heading="Network credentials",
-                                line1= (
-                                    "Add network credentials to allow Kodi access to your "
-                                    "content? Note: Skipping this step may generate a message "
-                                    "during the initial scan of your content if Kodi can't "
-                                    "locate your content."))
+                                heading=lang(30517),
+                                line1= lang(33038))
             if credentials:
-                self.logMsg("Presenting network credentials dialog.", 1)
-                utils.passwordsXML()
+                log("Presenting network credentials dialog.", 1)
+                passwordsXML()
         
         musicDisabled = dialog.yesno(
-                            heading="Music Library",
-                            line1="Disable Emby music library?")
+                            heading=lang(29999),
+                            line1=lang(33039))
         if musicDisabled:
-            self.logMsg("User opted to disable Emby music library.", 1)
-            utils.settings('enableMusic', value="false")
+            log("User opted to disable Emby music library.", 1)
+            settings('enableMusic', value="false")
         else:
             # Only prompt if the user didn't select direct paths for videos
             if not directPaths:
                 musicAccess = dialog.yesno(
-                                    heading="Music Library",
-                                    line1=(
-                                        "Direct stream the music library? Select "
-                                        "this option only if you plan on listening "
-                                        "to music outside of your network."))
+                                    heading=lang(29999),
+                                    line1=lang(33040))
                 if musicAccess:
-                    self.logMsg("User opted to direct stream music.", 1)
-                    utils.settings('streamMusic', value="true")
+                    log("User opted to direct stream music.", 1)
+                    settings('streamMusic', value="true")
                 
     def getServerDetails(self):
 
-        self.logMsg("Getting Server Details from Network", 1)
+        log("Getting Server Details from Network", 1)
         
         MULTI_GROUP = ("<broadcast>", 7359)
         MESSAGE = "who is EmbyServer?"
@@ -176,15 +157,15 @@ 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)
+        log("MultiGroup      : %s" % str(MULTI_GROUP), 2)
+        log("Sending UDP Data: %s" % MESSAGE, 2)
         sock.sendto(MESSAGE, MULTI_GROUP)
     
         try:
             data, addr = sock.recvfrom(1024) # buffer size is 1024 bytes
-            self.logMsg("Received Response: %s" % data)
+            log("Received Response: %s" % data)
         except:
-            self.logMsg("No UDP Response")
+            log("No UDP Response")
             return None
         else:
             # Get the address
diff --git a/resources/lib/itemtypes.py b/resources/lib/itemtypes.py
index 18c90517..934efcee 100644
--- a/resources/lib/itemtypes.py
+++ b/resources/lib/itemtypes.py
@@ -14,11 +14,11 @@ import api
 import artwork
 import clientinfo
 import downloadutils
-import utils
 import embydb_functions as embydb
 import kodidb_functions as kodidb
 import read_embyserver as embyserver
 import musicutils
+from utils import Logging, window, settings, language as lang, kodiSQL
 
 ##################################################################################################
 
@@ -28,6 +28,9 @@ class Items(object):
 
     def __init__(self, embycursor, kodicursor):
 
+        global log
+        log = Logging(self.__class__.__name__).log
+
         self.embycursor = embycursor
         self.kodicursor = kodicursor
 
@@ -35,23 +38,18 @@ class Items(object):
         self.addonName = self.clientInfo.getAddonName()
         self.doUtils = downloadutils.DownloadUtils()
 
-        self.kodiversion = int(xbmc.getInfoLabel("System.BuildVersion")[:2])
-        self.directpath = utils.settings('useDirectPaths') == "1"
-        self.music_enabled = utils.settings('enableMusic') == "true"
-        self.contentmsg = utils.settings('newContent') == "true"
-        self.newvideo_time = int(utils.settings('newvideotime'))*1000
-        self.newmusic_time = int(utils.settings('newmusictime'))*1000
+        self.kodiversion = int(xbmc.getInfoLabel('System.BuildVersion')[:2])
+        self.directpath = settings('useDirectPaths') == "1"
+        self.music_enabled = settings('enableMusic') == "true"
+        self.contentmsg = settings('newContent') == "true"
+        self.newvideo_time = int(settings('newvideotime'))*1000
+        self.newmusic_time = int(settings('newmusictime'))*1000
 
         self.artwork = artwork.Artwork()
         self.emby = embyserver.Read_EmbyServer()
         self.emby_db = embydb.Embydb_Functions(embycursor)
         self.kodi_db = kodidb.Kodidb_Functions(kodicursor)
 
-    def logMsg(self, msg, lvl=1):
-
-        className = self.__class__.__name__
-        utils.logMsg("%s %s" % (self.addonName, className), msg, lvl)
-
 
     def itemsbyId(self, items, process, pdialog=None):
         # Process items by itemid. Process can be added, update, userdata, remove
@@ -81,7 +79,7 @@ class Items(object):
         if total == 0:
             return False
 
-        self.logMsg("Processing %s: %s" % (process, items), 1)
+        log("Processing %s: %s" % (process, items), 1)
         if pdialog:
             pdialog.update(heading="Processing %s: %s items" % (process, total))
 
@@ -102,7 +100,7 @@ class Items(object):
 
             if itemtype in ('MusicAlbum', 'MusicArtist', 'AlbumArtist', 'Audio'):
                 if music_enabled:
-                    musicconn = utils.kodiSQL('music')
+                    musicconn = kodiSQL('music')
                     musiccursor = musicconn.cursor()
                     items_process = itemtypes[itemtype](embycursor, musiccursor)
                 else:
@@ -173,7 +171,7 @@ class Items(object):
                     'remove': items_process.remove
                 }
             else:
-                self.logMsg("Unsupported itemtype: %s." % itemtype, 1)
+                log("Unsupported itemtype: %s." % itemtype, 1)
                 actions = {}
 
             if actions.get(process):
@@ -192,7 +190,7 @@ class Items(object):
                         title = item['Name']
 
                         if itemtype == "Episode":
-                            title = "%s - %s" % (item['SeriesName'], title)
+                            title = "%s - %s" % (item.get('SeriesName', "Unknown"), title)
 
                         if pdialog:
                             percentage = int((float(count) / float(total))*100)
@@ -204,19 +202,31 @@ class Items(object):
 
             if musicconn is not None:
                 # close connection for special types
-                self.logMsg("Updating music database.", 1)
+                log("Updating music database.", 1)
                 musicconn.commit()
                 musiccursor.close()
 
         return (True, update_videolibrary)
 
+    def pathValidation(self, path):
+        # Verify if direct path is accessible or not
+        if window('emby_pathverified') != "true" and not xbmcvfs.exists(path):
+            resp = xbmcgui.Dialog().yesno(
+                        heading=lang(29999),
+                        line1="%s %s. %s" % (lang(33047), path, lang(33048)))
+            if resp:
+                window('emby_shouldStop', value="true")
+                return False
+
+        return True
+
     def contentPop(self, name, time=5000):
         
         if time: 
             # It's possible for the time to be 0. It should be considered disabled in this case.
             xbmcgui.Dialog().notification(
-                    heading="Emby for Kodi",
-                    message="Added: %s" % name,
+                    heading=lang(29999),
+                    message="%s %s" % (lang(33049), name),
                     icon="special://home/addons/plugin.video.emby/icon.png",
                     time=time,
                     sound=False)
@@ -272,11 +282,11 @@ class Movies(Items):
             movieid = emby_dbitem[0]
             fileid = emby_dbitem[1]
             pathid = emby_dbitem[2]
-            self.logMsg("movieid: %s fileid: %s pathid: %s" % (movieid, fileid, pathid), 1)
+            log("movieid: %s fileid: %s pathid: %s" % (movieid, fileid, pathid), 1)
         
         except TypeError:
             update_item = False
-            self.logMsg("movieid: %s not found." % itemid, 2)
+            log("movieid: %s not found." % itemid, 2)
             # movieid
             kodicursor.execute("select coalesce(max(idMovie),0) from movie")
             movieid = kodicursor.fetchone()[0] + 1
@@ -290,12 +300,12 @@ class Movies(Items):
             except TypeError:
                 # item is not found, let's recreate it.
                 update_item = False
-                self.logMsg("movieid: %s missing from Kodi, repairing the entry." % movieid, 1)
+                log("movieid: %s missing from Kodi, repairing the entry." % movieid, 1)
 
         if not viewtag or not viewid:
             # Get view tag from emby
             viewtag, viewid, mediatype = self.emby.getView_embyId(itemid)
-            self.logMsg("View tag found: %s" % viewtag, 2)
+            log("View tag found: %s" % viewtag, 2)
 
         # fileId information
         checksum = API.getChecksum()
@@ -338,7 +348,7 @@ class Movies(Items):
             try:
                 trailer = "plugin://plugin.video.emby/trailer/?id=%s&mode=play" % result[0]['Id']
             except IndexError:
-                self.logMsg("Failed to process local trailer.", 1)
+                log("Failed to process local trailer.", 1)
                 trailer = None
         else:
             # Try to get the youtube trailer
@@ -350,7 +360,7 @@ class Movies(Items):
                 try:
                     trailerId = trailer.rsplit('=', 1)[1]
                 except IndexError:
-                    self.logMsg("Failed to process trailer: %s" % trailer, 1)
+                    log("Failed to process trailer: %s" % trailer, 1)
                     trailer = None
                 else:
                     trailer = "plugin://plugin.video.youtube/play/?video_id=%s" % trailerId
@@ -367,22 +377,11 @@ class Movies(Items):
 
         if self.directpath:
             # Direct paths is set the Kodi way
-            if utils.window('emby_pathverified') != "true" and not xbmcvfs.exists(playurl):
-                # Validate the path is correct with user intervention
-                resp = xbmcgui.Dialog().yesno(
-                                        heading="Can't validate path",
-                                        line1=(
-                                            "Kodi can't locate file: %s. Verify the path. "
-                                            "You may to verify your network credentials in the "
-                                            "add-on settings or use the emby path substitution "
-                                            "to format your path correctly. Stop syncing?"
-                                            % playurl))
-                if resp:
-                    utils.window('emby_shouldStop', value="true")
-                    return False
+            if not self.pathValidation(playurl):
+                return False
             
             path = playurl.replace(filename, "")
-            utils.window('emby_pathverified', value="true")
+            window('emby_pathverified', value="true")
         else:
             # Set plugin path and media flags using real filename
             path = "plugin://plugin.video.emby.movies/"
@@ -398,7 +397,7 @@ class Movies(Items):
 
         ##### UPDATE THE MOVIE #####
         if update_item:
-            self.logMsg("UPDATE movie itemid: %s - Title: %s" % (itemid, title), 1)
+            log("UPDATE movie itemid: %s - Title: %s" % (itemid, title), 1)
 
             # Update the movie entry
             query = ' '.join((
@@ -418,7 +417,7 @@ class Movies(Items):
         
         ##### OR ADD THE MOVIE #####
         else:
-            self.logMsg("ADD movie itemid: %s - Title: %s" % (itemid, title), 1)
+            log("ADD movie itemid: %s - Title: %s" % (itemid, title), 1)
             
             # Add path
             pathid = self.kodi_db.addPath(path)
@@ -528,10 +527,10 @@ class Movies(Items):
                 try:
                     movieid = emby_dbitem[0]
                 except TypeError:
-                    self.logMsg("Failed to add: %s to boxset." % movie['Name'], 1)
+                    log("Failed to add: %s to boxset." % movie['Name'], 1)
                     continue
 
-                self.logMsg("New addition to boxset %s: %s" % (title, movie['Name']), 1)
+                log("New addition to boxset %s: %s" % (title, movie['Name']), 1)
                 self.kodi_db.assignBoxset(setid, movieid)
                 # Update emby reference
                 emby_db.updateParentId(itemid, setid)
@@ -542,7 +541,7 @@ class Movies(Items):
         # Process removals from boxset
         for movie in process:
             movieid = current[movie]
-            self.logMsg("Remove from boxset %s: %s" % (title, movieid))
+            log("Remove from boxset %s: %s" % (title, movieid))
             self.kodi_db.removefromBoxset(movieid)
             # Update emby reference
             emby_db.updateParentId(movie, None)
@@ -567,9 +566,7 @@ class Movies(Items):
         try:
             movieid = emby_dbitem[0]
             fileid = emby_dbitem[1]
-            self.logMsg(
-                "Update playstate for movie: %s fileid: %s"
-                % (item['Name'], fileid), 1)
+            log("Update playstate for movie: %s fileid: %s" % (item['Name'], fileid), 1)
         except TypeError:
             return
 
@@ -585,7 +582,7 @@ class Movies(Items):
         resume = API.adjustResume(userdata['Resume'])
         total = round(float(runtime), 6)
 
-        self.logMsg("%s New resume point: %s" % (itemid, resume))
+        log("%s New resume point: %s" % (itemid, resume))
 
         self.kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed)
         emby_db.updateReference(itemid, checksum)
@@ -601,7 +598,7 @@ class Movies(Items):
             kodiid = emby_dbitem[0]
             fileid = emby_dbitem[1]
             mediatype = emby_dbitem[4]
-            self.logMsg("Removing %sid: %s fileid: %s" % (mediatype, kodiid, fileid), 1)
+            log("Removing %sid: %s fileid: %s" % (mediatype, kodiid, fileid), 1)
         except TypeError:
             return
 
@@ -627,7 +624,7 @@ class Movies(Items):
 
             kodicursor.execute("DELETE FROM sets WHERE idSet = ?", (kodiid,))
 
-        self.logMsg("Deleted %s %s from kodi database" % (mediatype, itemid), 1)
+        log("Deleted %s %s from kodi database" % (mediatype, itemid), 1)
 
 class MusicVideos(Items):
 
@@ -667,11 +664,11 @@ class MusicVideos(Items):
             mvideoid = emby_dbitem[0]
             fileid = emby_dbitem[1]
             pathid = emby_dbitem[2]
-            self.logMsg("mvideoid: %s fileid: %s pathid: %s" % (mvideoid, fileid, pathid), 1)
+            log("mvideoid: %s fileid: %s pathid: %s" % (mvideoid, fileid, pathid), 1)
         
         except TypeError:
             update_item = False
-            self.logMsg("mvideoid: %s not found." % itemid, 2)
+            log("mvideoid: %s not found." % itemid, 2)
             # mvideoid
             kodicursor.execute("select coalesce(max(idMVideo),0) from musicvideo")
             mvideoid = kodicursor.fetchone()[0] + 1
@@ -685,12 +682,12 @@ class MusicVideos(Items):
             except TypeError:
                 # item is not found, let's recreate it.
                 update_item = False
-                self.logMsg("mvideoid: %s missing from Kodi, repairing the entry." % mvideoid, 1)
+                log("mvideoid: %s missing from Kodi, repairing the entry." % mvideoid, 1)
 
         if not viewtag or not viewid:
             # Get view tag from emby
             viewtag, viewid, mediatype = self.emby.getView_embyId(itemid)
-            self.logMsg("View tag found: %s" % viewtag, 2)
+            log("View tag found: %s" % viewtag, 2)
 
         # fileId information
         checksum = API.getChecksum()
@@ -726,22 +723,11 @@ class MusicVideos(Items):
 
         if self.directpath:
             # Direct paths is set the Kodi way
-            if utils.window('emby_pathverified') != "true" and not xbmcvfs.exists(playurl):
-                # Validate the path is correct with user intervention
-                resp = xbmcgui.Dialog().yesno(
-                                        heading="Can't validate path",
-                                        line1=(
-                                            "Kodi can't locate file: %s. Verify the path. "
-                                            "You may to verify your network credentials in the "
-                                            "add-on settings or use the emby path substitution "
-                                            "to format your path correctly. Stop syncing?"
-                                            % playurl))
-                if resp:
-                    utils.window('emby_shouldStop', value="true")
-                    return False
+            if not self.pathValidation(playurl):
+                return False
             
             path = playurl.replace(filename, "")
-            utils.window('emby_pathverified', value="true")
+            window('emby_pathverified', value="true")
         else:
             # Set plugin path and media flags using real filename
             path = "plugin://plugin.video.emby.musicvideos/"
@@ -757,7 +743,7 @@ class MusicVideos(Items):
 
         ##### UPDATE THE MUSIC VIDEO #####
         if update_item:
-            self.logMsg("UPDATE mvideo itemid: %s - Title: %s" % (itemid, title), 1)
+            log("UPDATE mvideo itemid: %s - Title: %s" % (itemid, title), 1)
             
             # Update path
             query = "UPDATE path SET strPath = ? WHERE idPath = ?"
@@ -783,7 +769,7 @@ class MusicVideos(Items):
         
         ##### OR ADD THE MUSIC VIDEO #####
         else:
-            self.logMsg("ADD mvideo itemid: %s - Title: %s" % (itemid, title), 1)
+            log("ADD mvideo itemid: %s - Title: %s" % (itemid, title), 1)
             
             # Add path
             query = ' '.join((
@@ -883,7 +869,7 @@ class MusicVideos(Items):
         try:
             mvideoid = emby_dbitem[0]
             fileid = emby_dbitem[1]
-            self.logMsg(
+            log(
                 "Update playstate for musicvideo: %s fileid: %s"
                 % (item['Name'], fileid), 1)
         except TypeError:
@@ -915,7 +901,7 @@ class MusicVideos(Items):
             mvideoid = emby_dbitem[0]
             fileid = emby_dbitem[1]
             pathid = emby_dbitem[2]
-            self.logMsg("Removing mvideoid: %s fileid: %s" % (mvideoid, fileid, pathid), 1)
+            log("Removing mvideoid: %s fileid: %s" % (mvideoid, fileid, pathid), 1)
         except TypeError:
             return
 
@@ -941,7 +927,7 @@ class MusicVideos(Items):
             kodicursor.execute("DELETE FROM path WHERE idPath = ?", (pathid,))
         self.embycursor.execute("DELETE FROM emby WHERE emby_id = ?", (itemid,))
 
-        self.logMsg("Deleted musicvideo %s from kodi database" % itemid, 1)
+        log("Deleted musicvideo %s from kodi database" % itemid, 1)
 
 class TVShows(Items):
 
@@ -1004,8 +990,8 @@ class TVShows(Items):
         artwork = self.artwork
         API = api.API(item)
 
-        if utils.settings('syncEmptyShows') == "false" and not item['RecursiveItemCount']:
-            self.logMsg("Skipping empty show: %s" % item['Name'], 1)
+        if settings('syncEmptyShows') == "false" and not item.get('RecursiveItemCount'):
+            log("Skipping empty show: %s" % item['Name'], 1)
             return
         # If the item already exist in the local Kodi DB we'll perform a full item update
         # If the item doesn't exist, we'll add it to the database
@@ -1016,11 +1002,11 @@ class TVShows(Items):
         try:
             showid = emby_dbitem[0]
             pathid = emby_dbitem[2]
-            self.logMsg("showid: %s pathid: %s" % (showid, pathid), 1)
+            log("showid: %s pathid: %s" % (showid, pathid), 1)
         
         except TypeError:
             update_item = False
-            self.logMsg("showid: %s not found." % itemid, 2)
+            log("showid: %s not found." % itemid, 2)
             kodicursor.execute("select coalesce(max(idShow),0) from tvshow")
             showid = kodicursor.fetchone()[0] + 1
 
@@ -1033,7 +1019,7 @@ class TVShows(Items):
             except TypeError:
                 # item is not found, let's recreate it.
                 update_item = False
-                self.logMsg("showid: %s missing from Kodi, repairing the entry." % showid, 1)
+                log("showid: %s missing from Kodi, repairing the entry." % showid, 1)
                 # Force re-add episodes after the show is re-created.
                 force_episodes = True
 
@@ -1041,7 +1027,7 @@ class TVShows(Items):
         if viewtag is None or viewid is None:
             # Get view tag from emby
             viewtag, viewid, mediatype = emby.getView_embyId(itemid)
-            self.logMsg("View tag found: %s" % viewtag, 2)
+            log("View tag found: %s" % viewtag, 2)
 
         # fileId information
         checksum = API.getChecksum()
@@ -1078,21 +1064,10 @@ class TVShows(Items):
                 path = "%s/" % playurl
                 toplevelpath = "%s/" % dirname(dirname(path))
 
-            if utils.window('emby_pathverified') != "true" and not xbmcvfs.exists(path):
-                # Validate the path is correct with user intervention
-                resp = xbmcgui.Dialog().yesno(
-                                        heading="Can't validate path",
-                                        line1=(
-                                            "Kodi can't locate file: %s. Verify the path. "
-                                            "You may to verify your network credentials in the "
-                                            "add-on settings or use the emby path substitution "
-                                            "to format your path correctly. Stop syncing?"
-                                            % playurl))
-                if resp:
-                    utils.window('emby_shouldStop', value="true")
-                    return False
+            if not self.pathValidation(playurl):
+                return False
 
-            utils.window('emby_pathverified', value="true")
+            window('emby_pathverified', value="true")
         else:
             # Set plugin path
             toplevelpath = "plugin://plugin.video.emby.tvshows/"
@@ -1101,7 +1076,7 @@ class TVShows(Items):
 
         ##### UPDATE THE TVSHOW #####
         if update_item:
-            self.logMsg("UPDATE tvshow itemid: %s - Title: %s" % (itemid, title), 1)
+            log("UPDATE tvshow itemid: %s - Title: %s" % (itemid, title), 1)
 
             # Update the tvshow entry
             query = ' '.join((
@@ -1119,7 +1094,7 @@ class TVShows(Items):
         
         ##### OR ADD THE TVSHOW #####
         else:
-            self.logMsg("ADD tvshow itemid: %s - Title: %s" % (itemid, title), 1)
+            log("ADD tvshow itemid: %s - Title: %s" % (itemid, title), 1)
             
             # Add top path
             toppathid = self.kodi_db.addPath(toplevelpath)
@@ -1190,7 +1165,7 @@ class TVShows(Items):
 
         if force_episodes:
             # We needed to recreate the show entry. Re-add episodes now.
-            self.logMsg("Repairing episodes for showid: %s %s" % (showid, title), 1)
+            log("Repairing episodes for showid: %s %s" % (showid, title), 1)
             all_episodes = emby.getEpisodesbyShow(itemid)
             self.added_episode(all_episodes['Items'], None)
 
@@ -1239,11 +1214,11 @@ class TVShows(Items):
             episodeid = emby_dbitem[0]
             fileid = emby_dbitem[1]
             pathid = emby_dbitem[2]
-            self.logMsg("episodeid: %s fileid: %s pathid: %s" % (episodeid, fileid, pathid), 1)
+            log("episodeid: %s fileid: %s pathid: %s" % (episodeid, fileid, pathid), 1)
         
         except TypeError:
             update_item = False
-            self.logMsg("episodeid: %s not found." % itemid, 2)
+            log("episodeid: %s not found." % itemid, 2)
             # episodeid
             kodicursor.execute("select coalesce(max(idEpisode),0) from episode")
             episodeid = kodicursor.fetchone()[0] + 1
@@ -1257,7 +1232,7 @@ class TVShows(Items):
             except TypeError:
                 # item is not found, let's recreate it.
                 update_item = False
-                self.logMsg("episodeid: %s missing from Kodi, repairing the entry." % episodeid, 1)
+                log("episodeid: %s missing from Kodi, repairing the entry." % episodeid, 1)
 
         # fileId information
         checksum = API.getChecksum()
@@ -1281,10 +1256,9 @@ class TVShows(Items):
             seriesId = item['SeriesId']
         except KeyError:
             # Missing seriesId, skip
-            self.logMsg("Skipping: %s. SeriesId is missing." % itemid, 1)
+            log("Skipping: %s. SeriesId is missing." % itemid, 1)
             return False
             
-        seriesName = item['SeriesName']
         season = item.get('ParentIndexNumber')
         episode = item.get('IndexNumber', -1)
        
@@ -1320,7 +1294,7 @@ class TVShows(Items):
             try:
                 showid = show[0]
             except TypeError:
-                self.logMsg("Skipping: %s. Unable to add series: %s." % (itemid, seriesId))
+                log("Skipping: %s. Unable to add series: %s." % (itemid, seriesId))
                 return False
 
         seasonid = self.kodi_db.addSeason(showid, season)
@@ -1337,22 +1311,11 @@ class TVShows(Items):
 
         if self.directpath:
             # Direct paths is set the Kodi way
-            if utils.window('emby_pathverified') != "true" and not xbmcvfs.exists(playurl):
-                # Validate the path is correct with user intervention
-                resp = xbmcgui.Dialog().yesno(
-                                        heading="Can't validate path",
-                                        line1=(
-                                            "Kodi can't locate file: %s. Verify the path. "
-                                            "You may to verify your network credentials in the "
-                                            "add-on settings or use the emby path substitution "
-                                            "to format your path correctly. Stop syncing?"
-                                            % playurl))
-                if resp:
-                    utils.window('emby_shouldStop', value="true")
-                    return False
+            if not self.pathValidation(playurl):
+                return False
             
             path = playurl.replace(filename, "")
-            utils.window('emby_pathverified', value="true")
+            window('emby_pathverified', value="true")
         else:
             # Set plugin path and media flags using real filename
             path = "plugin://plugin.video.emby.tvshows/%s/" % seriesId
@@ -1368,7 +1331,7 @@ class TVShows(Items):
 
         ##### UPDATE THE EPISODE #####
         if update_item:
-            self.logMsg("UPDATE episode itemid: %s - Title: %s" % (itemid, title), 1)
+            log("UPDATE episode itemid: %s - Title: %s" % (itemid, title), 1)
 
             # Update the movie entry
             if self.kodiversion in (16, 17):
@@ -1402,7 +1365,7 @@ class TVShows(Items):
         
         ##### OR ADD THE EPISODE #####
         else:
-            self.logMsg("ADD episode itemid: %s - Title: %s" % (itemid, title), 1)
+            log("ADD episode itemid: %s - Title: %s" % (itemid, title), 1)
             
             # Add path
             pathid = self.kodi_db.addPath(path)
@@ -1505,7 +1468,7 @@ class TVShows(Items):
             kodiid = emby_dbitem[0]
             fileid = emby_dbitem[1]
             mediatype = emby_dbitem[4]
-            self.logMsg(
+            log(
                 "Update playstate for %s: %s fileid: %s"
                 % (mediatype, item['Name'], fileid), 1)
         except TypeError:
@@ -1524,7 +1487,7 @@ class TVShows(Items):
             resume = API.adjustResume(userdata['Resume'])
             total = round(float(runtime), 6)
 
-            self.logMsg("%s New resume point: %s" % (itemid, resume))
+            log("%s New resume point: %s" % (itemid, resume))
 
             self.kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed)
             if not self.directpath and not resume:
@@ -1562,7 +1525,7 @@ class TVShows(Items):
             pathid = emby_dbitem[2]
             parentid = emby_dbitem[3]
             mediatype = emby_dbitem[4]
-            self.logMsg("Removing %s kodiid: %s fileid: %s" % (mediatype, kodiid, fileid), 1)
+            log("Removing %s kodiid: %s fileid: %s" % (mediatype, kodiid, fileid), 1)
         except TypeError:
             return
 
@@ -1652,14 +1615,14 @@ class TVShows(Items):
                 self.removeShow(parentid)
                 emby_db.removeItem_byKodiId(parentid, "tvshow")
 
-        self.logMsg("Deleted %s: %s from kodi database" % (mediatype, itemid), 1)
+        log("Deleted %s: %s from kodi database" % (mediatype, itemid), 1)
 
     def removeShow(self, kodiid):
         
         kodicursor = self.kodicursor
         self.artwork.deleteArtwork(kodiid, "tvshow", kodicursor)
         kodicursor.execute("DELETE FROM tvshow WHERE idShow = ?", (kodiid,))
-        self.logMsg("Removed tvshow: %s." % kodiid, 2)
+        log("Removed tvshow: %s." % kodiid, 2)
 
     def removeSeason(self, kodiid):
         
@@ -1667,7 +1630,7 @@ class TVShows(Items):
 
         self.artwork.deleteArtwork(kodiid, "season", kodicursor)
         kodicursor.execute("DELETE FROM seasons WHERE idSeason = ?", (kodiid,))
-        self.logMsg("Removed season: %s." % kodiid, 2)
+        log("Removed season: %s." % kodiid, 2)
 
     def removeEpisode(self, kodiid, fileid):
 
@@ -1676,7 +1639,7 @@ class TVShows(Items):
         self.artwork.deleteArtwork(kodiid, "episode", kodicursor)
         kodicursor.execute("DELETE FROM episode WHERE idEpisode = ?", (kodiid,))
         kodicursor.execute("DELETE FROM files WHERE idFile = ?", (fileid,))
-        self.logMsg("Removed episode: %s." % kodiid, 2)
+        log("Removed episode: %s." % kodiid, 2)
 
 class Music(Items):
 
@@ -1685,12 +1648,12 @@ class Music(Items):
         
         Items.__init__(self, embycursor, musiccursor)
 
-        self.directstream = utils.settings('streamMusic') == "true"
-        self.enableimportsongrating = utils.settings('enableImportSongRating') == "true"
-        self.enableexportsongrating = utils.settings('enableExportSongRating') == "true"
-        self.enableupdatesongrating = utils.settings('enableUpdateSongRating') == "true"
-        self.userid = utils.window('emby_currUser')
-        self.server = utils.window('emby_server%s' % self.userid)
+        self.directstream = settings('streamMusic') == "true"
+        self.enableimportsongrating = settings('enableImportSongRating') == "true"
+        self.enableexportsongrating = settings('enableExportSongRating') == "true"
+        self.enableupdatesongrating = settings('enableUpdateSongRating') == "true"
+        self.userid = window('emby_currUser')
+        self.server = window('emby_server%s' % self.userid)
 
     def added(self, items, pdialog):
         
@@ -1750,7 +1713,7 @@ class Music(Items):
             artistid = emby_dbitem[0]
         except TypeError:
             update_item = False
-            self.logMsg("artistid: %s not found." % itemid, 2)
+            log("artistid: %s not found." % itemid, 2)
 
         ##### The artist details #####
         lastScraped = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
@@ -1777,13 +1740,13 @@ class Music(Items):
 
         ##### UPDATE THE ARTIST #####
         if update_item:
-            self.logMsg("UPDATE artist itemid: %s - Name: %s" % (itemid, name), 1)
+            log("UPDATE artist itemid: %s - Name: %s" % (itemid, name), 1)
             # Update the checksum in emby table
             emby_db.updateReference(itemid, checksum)
 
         ##### OR ADD THE ARTIST #####
         else:
-            self.logMsg("ADD artist itemid: %s - Name: %s" % (itemid, name), 1)
+            log("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 = self.kodi_db.addArtist(name, musicBrainzId)
@@ -1831,7 +1794,7 @@ class Music(Items):
             albumid = emby_dbitem[0]
         except TypeError:
             update_item = False
-            self.logMsg("albumid: %s not found." % itemid, 2)
+            log("albumid: %s not found." % itemid, 2)
 
         ##### The album details #####
         lastScraped = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
@@ -1862,13 +1825,13 @@ class Music(Items):
 
         ##### UPDATE THE ALBUM #####
         if update_item:
-            self.logMsg("UPDATE album itemid: %s - Name: %s" % (itemid, name), 1)
+            log("UPDATE album itemid: %s - Name: %s" % (itemid, name), 1)
             # Update the checksum in emby table
             emby_db.updateReference(itemid, checksum)
 
         ##### OR ADD THE ALBUM #####
         else:
-            self.logMsg("ADD album itemid: %s - Name: %s" % (itemid, name), 1)
+            log("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 = self.kodi_db.addAlbum(name, musicBrainzId)
@@ -2001,7 +1964,7 @@ class Music(Items):
             albumid = emby_dbitem[3]
         except TypeError:
             update_item = False
-            self.logMsg("songid: %s not found." % itemid, 2)
+            log("songid: %s not found." % itemid, 2)
             
         ##### The song details #####
         checksum = API.getChecksum()
@@ -2048,27 +2011,15 @@ class Music(Items):
                 filename = playurl.rsplit("/", 1)[1]
 
             # Direct paths is set the Kodi way
-            if utils.window('emby_pathverified') != "true" and not xbmcvfs.exists(playurl):
-                # Validate the path is correct with user intervention
-                utils.window('emby_directPath', clear=True)
-                resp = xbmcgui.Dialog().yesno(
-                                        heading="Can't validate path",
-                                        line1=(
-                                            "Kodi can't locate file: %s. Verify the path. "
-                                            "You may to verify your network credentials in the "
-                                            "add-on settings or use the emby path substitution "
-                                            "to format your path correctly. Stop syncing?"
-                                            % playurl))
-                if resp:
-                    utils.window('emby_shouldStop', value="true")
-                    return False
+            if not self.pathValidation(playurl):
+                return False
             
             path = playurl.replace(filename, "")
-            utils.window('emby_pathverified', value="true")
+            window('emby_pathverified', value="true")
 
         ##### UPDATE THE SONG #####
         if update_item:
-            self.logMsg("UPDATE song itemid: %s - Title: %s" % (itemid, title), 1)
+            log("UPDATE song itemid: %s - Title: %s" % (itemid, title), 1)
             
             # Update path
             query = "UPDATE path SET strPath = ? WHERE idPath = ?"
@@ -2091,7 +2042,7 @@ class Music(Items):
         
         ##### OR ADD THE SONG #####
         else:
-            self.logMsg("ADD song itemid: %s - Title: %s" % (itemid, title), 1)
+            log("ADD song itemid: %s - Title: %s" % (itemid, title), 1)
             
             # Add path
             pathid = self.kodi_db.addPath(path)
@@ -2104,27 +2055,27 @@ class Music(Items):
                 # Verify if there's an album associated.
                 album_name = item.get('Album')
                 if album_name:
-                    self.logMsg("Creating virtual music album for song: %s." % itemid, 1)
+                    log("Creating virtual music album for song: %s." % itemid, 1)
                     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.
-                    self.logMsg("Song itemid: %s has no albumId associated." % itemid, 1)
+                    log("Song itemid: %s has no albumId associated." % itemid, 1)
                     return False
 
             except TypeError:
                 # No album found. Let's create it
-                self.logMsg("Album database entry missing.", 1)
+                log("Album database entry missing.", 1)
                 emby_albumId = item['AlbumId']
                 album = emby.getItem(emby_albumId)
                 self.add_updateAlbum(album)
                 emby_dbalbum = emby_db.getItem_byId(emby_albumId)
                 try:
                     albumid = emby_dbalbum[0]
-                    self.logMsg("Found albumid: %s" % albumid, 1)
+                    log("Found albumid: %s" % albumid, 1)
                 except TypeError:
                     # No album found, create a single's album
-                    self.logMsg("Failed to add album. Creating singles.", 1)
+                    log("Failed to add album. Creating singles.", 1)
                     kodicursor.execute("select coalesce(max(idAlbum),0) from album")
                     albumid = kodicursor.fetchone()[0] + 1
                     if self.kodiversion == 16:
@@ -2306,7 +2257,7 @@ class Music(Items):
         try:
             kodiid = emby_dbitem[0]
             mediatype = emby_dbitem[4]
-            self.logMsg("Update playstate for %s: %s" % (mediatype, item['Name']), 1)
+            log("Update playstate for %s: %s" % (mediatype, item['Name']), 1)
         except TypeError:
             return
 
@@ -2314,8 +2265,8 @@ class Music(Items):
             
             #should we ignore this item ?
             #happens when userdata updated by ratings method
-            if utils.window("ignore-update-%s" %itemid):
-                utils.window("ignore-update-%s" %itemid,clear=True)
+            if window("ignore-update-%s" %itemid):
+                window("ignore-update-%s" %itemid,clear=True)
                 return
                 
             # Process playstates
@@ -2345,7 +2296,7 @@ class Music(Items):
         try:
             kodiid = emby_dbitem[0]
             mediatype = emby_dbitem[4]
-            self.logMsg("Removing %s kodiid: %s" % (mediatype, kodiid), 1)
+            log("Removing %s kodiid: %s" % (mediatype, kodiid), 1)
         except TypeError:
             return
 
@@ -2413,21 +2364,21 @@ class Music(Items):
             # Remove artist
             self.removeArtist(kodiid)
 
-        self.logMsg("Deleted %s: %s from kodi database" % (mediatype, itemid), 1)
+        log("Deleted %s: %s from kodi database" % (mediatype, itemid), 1)
 
-    def removeSong(self, kodiid):
+    def removeSong(self, kodiId):
 
         kodicursor = self.kodicursor
 
-        self.artwork.deleteArtwork(kodiid, "song", self.kodicursor)
-        self.kodicursor.execute("DELETE FROM song WHERE idSong = ?", (kodiid,))
+        self.artwork.deleteArtwork(kodiId, "song", self.kodicursor)
+        self.kodicursor.execute("DELETE FROM song WHERE idSong = ?", (kodiId,))
 
-    def removeAlbum(self, kodiid):
+    def removeAlbum(self, kodiId):
 
-        self.artwork.deleteArtwork(kodiid, "album", self.kodicursor)
-        self.kodicursor.execute("DELETE FROM album WHERE idAlbum = ?", (kodiid,))
+        self.artwork.deleteArtwork(kodiId, "album", self.kodicursor)
+        self.kodicursor.execute("DELETE FROM album WHERE idAlbum = ?", (kodiId,))
 
-    def removeArtist(self, kodiid):
+    def removeArtist(self, kodiId):
 
-        self.artwork.deleteArtwork(kodiid, "artist", self.kodicursor)
-        self.kodicursor.execute("DELETE FROM artist WHERE idArtist = ?", (kodiid,))
+        self.artwork.deleteArtwork(kodiId, "artist", self.kodicursor)
+        self.kodicursor.execute("DELETE FROM artist WHERE idArtist = ?", (kodiId,))
\ No newline at end of file
diff --git a/resources/lib/kodidb_functions.py b/resources/lib/kodidb_functions.py
index 6c3dd8b1..86981e7b 100644
--- a/resources/lib/kodidb_functions.py
+++ b/resources/lib/kodidb_functions.py
@@ -7,7 +7,7 @@ import xbmc
 import api
 import artwork
 import clientinfo
-import utils
+from utils import Logging
 
 ##################################################################################################
 
@@ -19,16 +19,14 @@ class Kodidb_Functions():
 
     def __init__(self, cursor):
 
+        global log
+        log = Logging(self.__class__.__name__).log
+        
         self.cursor = cursor
         
         self.clientInfo = clientinfo.ClientInfo()
         self.addonName = self.clientInfo.getAddonName()
         self.artwork = artwork.Artwork()
-
-    def logMsg(self, msg, lvl=1):
-
-        className = self.__class__.__name__
-        utils.logMsg("%s %s" % (self.addonName, className), msg, lvl)
         
 
     def addPath(self, path):
@@ -153,7 +151,7 @@ class Kodidb_Functions():
 
                     query = "INSERT INTO country(country_id, name) values(?, ?)"
                     self.cursor.execute(query, (country_id, country))
-                    self.logMsg("Add country to media, processing: %s" % country, 2)
+                    log("Add country to media, processing: %s" % country, 2)
 
                 finally: # Assign country to content
                     query = (
@@ -187,7 +185,7 @@ class Kodidb_Functions():
 
                     query = "INSERT INTO country(idCountry, strCountry) values(?, ?)"
                     self.cursor.execute(query, (idCountry, country))
-                    self.logMsg("Add country to media, processing: %s" % country, 2)
+                    log("Add country to media, processing: %s" % country, 2)
                 
                 finally:
                     # Only movies have a country field
@@ -232,7 +230,7 @@ class Kodidb_Functions():
 
                     query = "INSERT INTO actor(actor_id, name) values(?, ?)"
                     self.cursor.execute(query, (actorid, name))
-                    self.logMsg("Add people to media, processing: %s" % name, 2)
+                    log("Add people to media, processing: %s" % name, 2)
 
                 finally:
                     # Link person to content
@@ -302,7 +300,7 @@ class Kodidb_Functions():
 
                     query = "INSERT INTO actors(idActor, strActor) values(?, ?)"
                     self.cursor.execute(query, (actorid, name))
-                    self.logMsg("Add people to media, processing: %s" % name, 2)
+                    log("Add people to media, processing: %s" % name, 2)
 
                 finally:
                     # Link person to content
@@ -462,7 +460,7 @@ class Kodidb_Functions():
                     
                     query = "INSERT INTO genre(genre_id, name) values(?, ?)"
                     self.cursor.execute(query, (genre_id, genre))
-                    self.logMsg("Add Genres to media, processing: %s" % genre, 2)
+                    log("Add Genres to media, processing: %s" % genre, 2)
                 
                 finally:
                     # Assign genre to item
@@ -507,7 +505,7 @@ class Kodidb_Functions():
 
                     query = "INSERT INTO genre(idGenre, strGenre) values(?, ?)"
                     self.cursor.execute(query, (idGenre, genre))
-                    self.logMsg("Add Genres to media, processing: %s" % genre, 2)
+                    log("Add Genres to media, processing: %s" % genre, 2)
                 
                 finally:
                     # Assign genre to item
@@ -566,7 +564,7 @@ class Kodidb_Functions():
 
                     query = "INSERT INTO studio(studio_id, name) values(?, ?)"
                     self.cursor.execute(query, (studioid, studio))
-                    self.logMsg("Add Studios to media, processing: %s" % studio, 2)
+                    log("Add Studios to media, processing: %s" % studio, 2)
 
                 finally: # Assign studio to item
                     query = (
@@ -597,7 +595,7 @@ class Kodidb_Functions():
 
                     query = "INSERT INTO studio(idstudio, strstudio) values(?, ?)"
                     self.cursor.execute(query, (studioid, studio))
-                    self.logMsg("Add Studios to media, processing: %s" % studio, 2)
+                    log("Add Studios to media, processing: %s" % studio, 2)
 
                 finally: # Assign studio to item
                     if "movie" in mediatype:
@@ -728,7 +726,7 @@ class Kodidb_Functions():
             self.cursor.execute(query, (kodiid, mediatype))
     
         # Add tags
-        self.logMsg("Adding Tags: %s" % tags, 2)
+        log("Adding Tags: %s" % tags, 2)
         for tag in tags:
             self.addTag(kodiid, tag, mediatype)
 
@@ -750,7 +748,7 @@ class Kodidb_Functions():
             except TypeError:
                 # Create the tag, because it does not exist
                 tag_id = self.createTag(tag)
-                self.logMsg("Adding tag: %s" % tag, 2)
+                log("Adding tag: %s" % tag, 2)
 
             finally:
                 # Assign tag to item
@@ -779,7 +777,7 @@ class Kodidb_Functions():
             except TypeError:
                 # Create the tag
                 tag_id = self.createTag(tag)
-                self.logMsg("Adding tag: %s" % tag, 2)
+                log("Adding tag: %s" % tag, 2)
             
             finally:
                 # Assign tag to item
@@ -815,7 +813,7 @@ class Kodidb_Functions():
 
                 query = "INSERT INTO tag(tag_id, name) values(?, ?)"
                 self.cursor.execute(query, (tag_id, name))
-                self.logMsg("Create tag_id: %s name: %s" % (tag_id, name), 2)
+                log("Create tag_id: %s name: %s" % (tag_id, name), 2)
         else:
             # Kodi Helix
             query = ' '.join((
@@ -835,13 +833,13 @@ class Kodidb_Functions():
 
                 query = "INSERT INTO tag(idTag, strTag) values(?, ?)"
                 self.cursor.execute(query, (tag_id, name))
-                self.logMsg("Create idTag: %s name: %s" % (tag_id, name), 2)
+                log("Create idTag: %s name: %s" % (tag_id, name), 2)
 
         return tag_id
 
     def updateTag(self, oldtag, newtag, kodiid, mediatype):
 
-        self.logMsg("Updating: %s with %s for %s: %s" % (oldtag, newtag, mediatype, kodiid), 2)
+        log("Updating: %s with %s for %s: %s" % (oldtag, newtag, mediatype, kodiid), 2)
         
         if self.kodiversion in (15, 16, 17):
             # Kodi Isengard, Jarvis, Krypton
@@ -858,7 +856,7 @@ class Kodidb_Functions():
             except Exception as e:
                 # The new tag we are going to apply already exists for this item
                 # delete current tag instead
-                self.logMsg("Exception: %s" % e, 1)
+                log("Exception: %s" % e, 1)
                 query = ' '.join((
 
                     "DELETE FROM tag_link",
@@ -882,7 +880,7 @@ class Kodidb_Functions():
             except Exception as e:
                 # The new tag we are going to apply already exists for this item
                 # delete current tag instead
-                self.logMsg("Exception: %s" % e, 1)
+                log("Exception: %s" % e, 1)
                 query = ' '.join((
 
                     "DELETE FROM taglinks",
@@ -943,7 +941,7 @@ class Kodidb_Functions():
 
     def createBoxset(self, boxsetname):
 
-        self.logMsg("Adding boxset: %s" % boxsetname, 2)
+        log("Adding boxset: %s" % boxsetname, 2)
         query = ' '.join((
 
             "SELECT idSet",
diff --git a/resources/lib/kodimonitor.py b/resources/lib/kodimonitor.py
index ea1a4f17..16baa487 100644
--- a/resources/lib/kodimonitor.py
+++ b/resources/lib/kodimonitor.py
@@ -11,7 +11,7 @@ import clientinfo
 import downloadutils
 import embydb_functions as embydb
 import playbackutils as pbutils
-import utils
+from utils import Logging, window, settings, kodiSQL
 
 #################################################################################################
 
@@ -21,27 +21,25 @@ class KodiMonitor(xbmc.Monitor):
 
     def __init__(self):
 
+        global log
+        log = Logging(self.__class__.__name__).log
+
         self.clientInfo = clientinfo.ClientInfo()
         self.addonName = self.clientInfo.getAddonName()
         self.doUtils = downloadutils.DownloadUtils()
 
-        self.logMsg("Kodi monitor started.", 1)
-
-    def logMsg(self, msg, lvl=1):
-
-        self.className = self.__class__.__name__
-        utils.logMsg("%s %s" % (self.addonName, self.className), msg, lvl)
+        log("Kodi monitor started.", 1)
 
 
     def onScanStarted(self, library):
-        self.logMsg("Kodi library scan %s running." % library, 2)
+        log("Kodi library scan %s running." % library, 2)
         if library == "video":
-            utils.window('emby_kodiScan', value="true")
+            window('emby_kodiScan', value="true")
             
     def onScanFinished(self, library):
-        self.logMsg("Kodi library scan %s finished." % library, 2)
+        log("Kodi library scan %s finished." % library, 2)
         if library == "video":
-            utils.window('emby_kodiScan', clear=True)
+            window('emby_kodiScan', clear=True)
 
     def onSettingsChanged(self):
         # Monitor emby settings
@@ -50,7 +48,7 @@ class KodiMonitor(xbmc.Monitor):
         '''currentPath = utils.settings('useDirectPaths')
         if utils.window('emby_pluginpath') != currentPath:
             # Plugin path value changed. Offer to reset
-            self.logMsg("Changed to playback mode detected", 1)
+            log("Changed to playback mode detected", 1)
             utils.window('emby_pluginpath', value=currentPath)
             resp = xbmcgui.Dialog().yesno(
                                 heading="Playback mode change detected",
@@ -61,17 +59,17 @@ class KodiMonitor(xbmc.Monitor):
             if resp:
                 utils.reset()'''
 
-        currentLog = utils.settings('logLevel')
-        if utils.window('emby_logLevel') != currentLog:
+        currentLog = settings('logLevel')
+        if window('emby_logLevel') != currentLog:
             # The log level changed, set new prop
-            self.logMsg("New log level: %s" % currentLog, 1)
-            utils.window('emby_logLevel', value=currentLog)
+            log("New log level: %s" % currentLog, 1)
+            window('emby_logLevel', value=currentLog)
 
     def onNotification(self, sender, method, data):
 
         doUtils = self.doUtils
         if method not in ("Playlist.OnAdd"):
-            self.logMsg("Method: %s Data: %s" % (method, data), 1)
+            log("Method: %s Data: %s" % (method, data), 1)
             
         if data:
             data = json.loads(data,'utf-8')
@@ -84,23 +82,23 @@ class KodiMonitor(xbmc.Monitor):
                 kodiid = item['id']
                 item_type = item['type']
             except (KeyError, TypeError):
-                self.logMsg("Item is invalid for playstate update.", 1)
+                log("Item is invalid for playstate update.", 1)
             else:
-                if ((utils.settings('useDirectPaths') == "1" and not item_type == "song") or
-                        (item_type == "song" and utils.settings('enableMusic') == "true")):
+                if ((settings('useDirectPaths') == "1" and not item_type == "song") or
+                        (item_type == "song" and settings('enableMusic') == "true")):
                     # Set up properties for player
-                    embyconn = utils.kodiSQL('emby')
+                    embyconn = kodiSQL('emby')
                     embycursor = embyconn.cursor()
                     emby_db = embydb.Embydb_Functions(embycursor)
                     emby_dbitem = emby_db.getItem_byKodiId(kodiid, item_type)
                     try:
                         itemid = emby_dbitem[0]
                     except TypeError:
-                        self.logMsg("No kodiid returned.", 1)
+                        log("No kodiId returned.", 1)
                     else:
                         url = "{server}/emby/Users/{UserId}/Items/%s?format=json" % itemid
                         result = doUtils.downloadUrl(url)
-                        self.logMsg("Item: %s" % result, 2)
+                        log("Item: %s" % result, 2)
 
                         playurl = None
                         count = 0
@@ -114,12 +112,10 @@ class KodiMonitor(xbmc.Monitor):
                                 listItem = xbmcgui.ListItem()
                                 playback = pbutils.PlaybackUtils(result)
 
-                                if item_type == "song" and utils.settings('streamMusic') == "true":
-                                    utils.window('emby_%s.playmethod' % playurl,
-                                        value="DirectStream")
+                                if item_type == "song" and settings('streamMusic') == "true":
+                                    window('emby_%s.playmethod' % playurl, value="DirectStream")
                                 else:
-                                    utils.window('emby_%s.playmethod' % playurl,
-                                        value="DirectPlay")
+                                    window('emby_%s.playmethod' % playurl, value="DirectPlay")
                                 # Set properties for player.py
                                 playback.setProperties(playurl, listItem)
                     finally:
@@ -134,31 +130,31 @@ class KodiMonitor(xbmc.Monitor):
                 kodiid = item['id']
                 item_type = item['type']
             except (KeyError, TypeError):
-                self.logMsg("Item is invalid for playstate update.", 1)
+                log("Item is invalid for playstate update.", 1)
             else:
                 # Send notification to the server.
-                embyconn = utils.kodiSQL('emby')
+                embyconn = kodiSQL('emby')
                 embycursor = embyconn.cursor()
                 emby_db = embydb.Embydb_Functions(embycursor)
                 emby_dbitem = emby_db.getItem_byKodiId(kodiid, item_type)
                 try:
                     itemid = emby_dbitem[0]
                 except TypeError:
-                    self.logMsg("Could not find itemid in emby database.", 1)
+                    log("Could not find itemid in emby database.", 1)
                 else:
                     # Stop from manually marking as watched unwatched, with actual playback.
-                    if utils.window('emby_skipWatched%s' % itemid) == "true":
+                    if window('emby_skipWatched%s' % itemid) == "true":
                         # property is set in player.py
-                        utils.window('emby_skipWatched%s' % itemid, clear=True)
+                        window('emby_skipWatched%s' % itemid, clear=True)
                     else:
                         # notify the server
                         url = "{server}/emby/Users/{UserId}/PlayedItems/%s?format=json" % itemid
                         if playcount != 0:
                             doUtils.downloadUrl(url, action_type="POST")
-                            self.logMsg("Mark as watched for itemid: %s" % itemid, 1)
+                            log("Mark as watched for itemid: %s" % itemid, 1)
                         else:
                             doUtils.downloadUrl(url, action_type="DELETE")
-                            self.logMsg("Mark as unwatched for itemid: %s" % itemid, 1)
+                            log("Mark as unwatched for itemid: %s" % itemid, 1)
                 finally:
                     embycursor.close()
 
@@ -172,7 +168,7 @@ class KodiMonitor(xbmc.Monitor):
                 kodiid = data['id']
                 type = data['type']
             except (KeyError, TypeError):
-                self.logMsg("Item is invalid for emby deletion.", 1)
+                log("Item is invalid for emby deletion.", 1)
             else:
                 # Send the delete action to the server.
                 embyconn = utils.kodiSQL('emby')
@@ -182,19 +178,19 @@ class KodiMonitor(xbmc.Monitor):
                 try:
                     itemid = emby_dbitem[0]
                 except TypeError:
-                    self.logMsg("Could not find itemid in emby database.", 1)
+                    log("Could not find itemid in emby database.", 1)
                 else:
                     if utils.settings('skipContextMenu') != "true":
                         resp = xbmcgui.Dialog().yesno(
                                                 heading="Confirm delete",
                                                 line1="Delete file on Emby Server?")
                         if not resp:
-                            self.logMsg("User skipped deletion.", 1)
+                            log("User skipped deletion.", 1)
                             embycursor.close()
                             return
 
                     url = "{server}/emby/Items/%s?format=json" % itemid
-                    self.logMsg("Deleting request: %s" % itemid)
+                    log("Deleting request: %s" % itemid)
                     doUtils.downloadUrl(url, action_type="DELETE")
                 finally:
                     embycursor.close()'''
@@ -203,13 +199,13 @@ class KodiMonitor(xbmc.Monitor):
         elif method == "System.OnWake":
             # Allow network to wake up
             xbmc.sleep(10000)
-            utils.window('emby_onWake', value="true")
+            window('emby_onWake', value="true")
 
 
         elif method == "GUI.OnScreensaverDeactivated":
-            if utils.settings('dbSyncScreensaver') == "true":
+            if settings('dbSyncScreensaver') == "true":
                 xbmc.sleep(5000);
-                utils.window('emby_onWake', value="true")
+                window('emby_onWake', value="true")
 
 
         elif method == "Playlist.OnClear":
diff --git a/resources/lib/librarysync.py b/resources/lib/librarysync.py
index d3a441dd..e31a83cb 100644
--- a/resources/lib/librarysync.py
+++ b/resources/lib/librarysync.py
@@ -20,6 +20,7 @@ import kodidb_functions as kodidb
 import read_embyserver as embyserver
 import userclient
 import videonodes
+from utils import Logging, window, settings, language as lang
 
 ##################################################################################################
 
@@ -42,6 +43,9 @@ class LibrarySync(threading.Thread):
 
     def __init__(self):
 
+        global log
+        log = Logging(self.__class__.__name__).log
+
         self.__dict__ = self._shared_state
         self.monitor = xbmc.Monitor()
 
@@ -54,26 +58,20 @@ class LibrarySync(threading.Thread):
 
         threading.Thread.__init__(self)
 
-    def logMsg(self, msg, lvl=1):
-
-        className = self.__class__.__name__
-        utils.logMsg("%s %s" % (self.addonName, className), msg, lvl)
-
 
     def progressDialog(self, title, forced=False):
 
         dialog = None
 
-        if utils.settings('dbSyncIndicator') == "true" or forced:
+        if settings('dbSyncIndicator') == "true" or forced:
             dialog = xbmcgui.DialogProgressBG()
             dialog.create("Emby for Kodi", title)
-            self.logMsg("Show progress dialog: %s" % title, 2)
+            log("Show progress dialog: %s" % title, 2)
 
         return dialog
 
     def startSync(self):
 
-        settings = utils.settings
         # Run at start up - optional to use the server plugin
         if settings('SyncInstallRunDone') == "true":
 
@@ -88,7 +86,7 @@ class LibrarySync(threading.Thread):
 
                 for plugin in result:
                     if plugin['Name'] == "Emby.Kodi Sync Queue":
-                        self.logMsg("Found server plugin.", 2)
+                        log("Found server plugin.", 2)
                         completed = self.fastSync()
                         break
 
@@ -103,37 +101,31 @@ class LibrarySync(threading.Thread):
 
     def fastSync(self):
 
-        lastSync = utils.settings('LastIncrementalSync')
+        lastSync = settings('LastIncrementalSync')
         if not lastSync:
             lastSync = "2010-01-01T00:00:00Z"
 
-        lastSyncTime = utils.convertdate(lastSync)
-        self.logMsg("Last sync run: %s" % lastSyncTime, 1)
+        lastSyncTime = utils.convertDate(lastSync)
+        log("Last sync run: %s" % lastSyncTime, 1)
 
         # get server RetentionDateTime
         result = self.doUtils("{server}/emby/Emby.Kodi.SyncQueue/GetServerDateTime?format=json")
-        retention_time = "2010-01-01T00:00:00Z"
-        if result and result.get('RetentionDateTime'):
-            retention_time = result['RetentionDateTime']
-
-        #Try/except equivalent
-        '''
         try:
             retention_time = result['RetentionDateTime']
         except (TypeError, KeyError):
             retention_time = "2010-01-01T00:00:00Z"
-        '''
 
-        retention_time = utils.convertdate(retention_time)
-        self.logMsg("RetentionDateTime: %s" % retention_time, 1)
+        retention_time = utils.convertDate(retention_time)
+        log("RetentionDateTime: %s" % retention_time, 1)
 
         # if last sync before retention time do a full sync
         if retention_time > lastSyncTime:
-            self.logMsg("Fast sync server retention insufficient, fall back to full sync", 1)
+            log("Fast sync server retention insufficient, fall back to full sync", 1)
             return False
 
         params = {'LastUpdateDT': lastSync}
-        result = self.doUtils("{server}/emby/Emby.Kodi.SyncQueue/{UserId}/GetItems?format=json", parameters=params)
+        url = "{server}/emby/Emby.Kodi.SyncQueue/{UserId}/GetItems?format=json"
+        result = self.doUtils(url, parameters=params)
 
         try:
             processlist = {
@@ -145,11 +137,11 @@ class LibrarySync(threading.Thread):
             }
 
         except (KeyError, TypeError):
-            self.logMsg("Failed to retrieve latest updates using fast sync.", 1)
+            log("Failed to retrieve latest updates using fast sync.", 1)
             return False
 
         else:
-            self.logMsg("Fast sync changes: %s" % result, 1)
+            log("Fast sync changes: %s" % result, 1)
             for action in processlist:
                 self.triage_items(action, processlist[action])
 
@@ -163,60 +155,55 @@ class LibrarySync(threading.Thread):
         result = self.doUtils("{server}/emby/Emby.Kodi.SyncQueue/GetServerDateTime?format=json")
         try: # datetime fails when used more than once, TypeError
             server_time = result['ServerDateTime']
-            server_time = utils.convertdate(server_time)
+            server_time = utils.convertDate(server_time)
 
         except Exception as e:
             # If the server plugin is not installed or an error happened.
-            self.logMsg("An exception occurred: %s" % e, 1)
+            log("An exception occurred: %s" % e, 1)
             time_now = datetime.utcnow()-timedelta(minutes=overlap)
             lastSync = time_now.strftime('%Y-%m-%dT%H:%M:%SZ')
-            self.logMsg("New sync time: client time -%s min: %s" % (overlap, lastSync), 1)
+            log("New sync time: client time -%s min: %s" % (overlap, lastSync), 1)
 
         else:
             lastSync = (server_time - timedelta(minutes=overlap)).strftime('%Y-%m-%dT%H:%M:%SZ')
-            self.logMsg("New sync time: server time -%s min: %s" % (overlap, lastSync), 1)
+            log("New sync time: server time -%s min: %s" % (overlap, lastSync), 1)
 
         finally:
-            utils.settings('LastIncrementalSync', value=lastSync)
+            settings('LastIncrementalSync', value=lastSync)
 
     def shouldStop(self):
         # Checkpoint during the syncing process
         if self.monitor.abortRequested():
             return True
-        elif utils.window('emby_shouldStop') == "true":
+        elif window('emby_shouldStop') == "true":
             return True
         else: # Keep going
             return False
 
     def dbCommit(self, connection):
-
-        window = utils.window
         # Central commit, verifies if Kodi database update is running
         kodidb_scan = window('emby_kodiScan') == "true"
 
         while kodidb_scan:
 
-            self.logMsg("Kodi scan is running. Waiting...", 1)
+            log("Kodi scan is running. Waiting...", 1)
             kodidb_scan = window('emby_kodiScan') == "true"
 
             if self.shouldStop():
-                self.logMsg("Commit unsuccessful. Sync terminated.", 1)
+                log("Commit unsuccessful. Sync terminated.", 1)
                 break
 
             if self.monitor.waitForAbort(1):
                 # Abort was requested while waiting. We should exit
-                self.logMsg("Commit unsuccessful.", 1)
+                log("Commit unsuccessful.", 1)
                 break
         else:
             connection.commit()
-            self.logMsg("Commit successful.", 1)
+            log("Commit successful.", 1)
 
     def fullSync(self, manualrun=False, repair=False, forceddialog=False):
-
-        window = utils.window
-        settings = utils.settings
         # Only run once when first setting up. Can be run manually.
-        music_enabled = utils.settings('enableMusic') == "true"
+        music_enabled = settings('enableMusic') == "true"
 
         xbmc.executebuiltin('InhibitIdleShutdown(true)')
         screensaver = utils.getScreensaver()
@@ -284,7 +271,7 @@ class LibrarySync(threading.Thread):
                 self.dbCommit(kodiconn)
                 embyconn.commit()
                 elapsedTime = datetime.now() - startTime
-                self.logMsg("SyncDatabase (finished %s in: %s)"
+                log("SyncDatabase (finished %s in: %s)"
                     % (itemtype, str(elapsedTime).split('.')[0]), 1)
         else:
             # Close the Kodi cursor
@@ -312,7 +299,7 @@ class LibrarySync(threading.Thread):
                 musicconn.commit()
                 embyconn.commit()
                 elapsedTime = datetime.now() - startTime
-                self.logMsg("SyncDatabase (finished music in: %s)"
+                log("SyncDatabase (finished music in: %s)"
                     % (str(elapsedTime).split('.')[0]), 1)
             musiccursor.close()
 
@@ -333,9 +320,9 @@ class LibrarySync(threading.Thread):
         window('emby_initialScan', clear=True)
         if forceddialog:
             xbmcgui.Dialog().notification(
-                        heading="Emby for Kodi",
+                        heading=lang(29999),
                         message="%s %s %s" %
-                                (message, utils.language(33025), str(elapsedtotal).split('.')[0]),
+                                (message, lang(33025), str(elapsedtotal).split('.')[0]),
                         icon="special://home/addons/plugin.video.emby/icon.png",
                         sound=False)
         return True
@@ -378,7 +365,7 @@ class LibrarySync(threading.Thread):
             if view['type'] == "mixed":
                 sorted_views.append(view['name'])
             sorted_views.append(view['name'])
-        self.logMsg("Sorted views: %s" % sorted_views, 1)
+        log("Sorted views: %s" % sorted_views, 1)
 
         # total nodes for window properties
         self.vnodes.clearProperties()
@@ -415,7 +402,8 @@ class LibrarySync(threading.Thread):
                         'Limit': 1,
                         'IncludeItemTypes': emby_mediatypes[mediatype]
                     } # Get one item from server using the folderid
-                    result = self.doUtils("{server}/emby/Users/{UserId}/Items?format=json", parameters=params)
+                    url = "{server}/emby/Users/{UserId}/Items?format=json"
+                    result = self.doUtils(url, parameters=params)
                     try:
                         verifyitem = result['Items'][0]['Id']
                     except (TypeError, IndexError):
@@ -430,14 +418,14 @@ class LibrarySync(threading.Thread):
                                 # Take the userview, and validate the item belong to the view
                                 if self.emby.verifyView(grouped_view['Id'], verifyitem):
                                     # Take the name of the userview
-                                    self.logMsg("Found corresponding view: %s %s"
+                                    log("Found corresponding view: %s %s"
                                         % (grouped_view['Name'], grouped_view['Id']), 1)
                                     foldername = grouped_view['Name']
                                     break
                         else:
                             # Unable to find a match, add the name to our sorted_view list
                             sorted_views.append(foldername)
-                            self.logMsg("Couldn't find corresponding grouped view: %s" % sorted_views, 1)
+                            log("Couldn't find corresponding grouped view: %s" % sorted_views, 1)
 
                 # Failsafe
                 try:
@@ -453,7 +441,7 @@ class LibrarySync(threading.Thread):
                     current_tagid = view[2]
 
                 except TypeError:
-                    self.logMsg("Creating viewid: %s in Emby database." % folderid, 1)
+                    log("Creating viewid: %s in Emby database." % folderid, 1)
                     tagid = kodi_db.createTag(foldername)
                     # Create playlist for the video library
                     if (foldername not in playlists and
@@ -472,7 +460,7 @@ class LibrarySync(threading.Thread):
                     emby_db.addView(folderid, foldername, viewtype, tagid)
 
                 else:
-                    self.logMsg(' '.join((
+                    log(' '.join((
 
                         "Found viewid: %s" % folderid,
                         "viewname: %s" % current_viewname,
@@ -488,7 +476,7 @@ class LibrarySync(threading.Thread):
 
                     # View was modified, update with latest info
                     if current_viewname != foldername:
-                        self.logMsg("viewid: %s new viewname: %s" % (folderid, foldername), 1)
+                        log("viewid: %s new viewname: %s" % (folderid, foldername), 1)
                         tagid = kodi_db.createTag(foldername)
 
                         # Update view with new info
@@ -553,23 +541,22 @@ class LibrarySync(threading.Thread):
             self.vnodes.singleNode(totalnodes, "channels", "movies", "channels")
             totalnodes += 1
             # Save total
-            utils.window('Emby.nodes.total', str(totalnodes))
+            window('Emby.nodes.total', str(totalnodes))
 
             # Remove any old referenced views
-            self.logMsg("Removing views: %s" % current_views, 1)
+            log("Removing views: %s" % current_views, 1)
             for view in current_views:
                 emby_db.removeView(view)
 
     def movies(self, embycursor, kodicursor, pdialog):
 
-        lang = utils.language
         # Get movies from emby
         emby_db = embydb.Embydb_Functions(embycursor)
         movies = itemtypes.Movies(embycursor, kodicursor)
 
         views = emby_db.getView_byType('movies')
         views += emby_db.getView_byType('mixed')
-        self.logMsg("Media folders: %s" % views, 1)
+        log("Media folders: %s" % views, 1)
 
         ##### PROCESS MOVIES #####
         for view in views:
@@ -580,7 +567,7 @@ class LibrarySync(threading.Thread):
             # Get items per view
             if pdialog:
                 pdialog.update(
-                        heading="Emby for Kodi",
+                        heading=lang(29999),
                         message="%s %s..." % (lang(33017), view['name']))
 
             # Initial or repair sync
@@ -604,12 +591,12 @@ class LibrarySync(threading.Thread):
                     count += 1
                 movies.add_update(embymovie, view['name'], view['id'])
         else:
-            self.logMsg("Movies finished.", 2)
+            log("Movies finished.", 2)
 
 
         ##### PROCESS BOXSETS #####
         if pdialog:
-            pdialog.update(heading="Emby for Kodi", message=lang(33018))
+            pdialog.update(heading=lang(29999), message=lang(33018))
 
         boxsets = self.emby.getBoxset(dialog=pdialog)
         total = boxsets['TotalRecordCount']
@@ -631,7 +618,7 @@ class LibrarySync(threading.Thread):
                 count += 1
             movies.add_updateBoxset(boxset)
         else:
-            self.logMsg("Boxsets finished.", 2)
+            log("Boxsets finished.", 2)
 
         return True
 
@@ -642,7 +629,7 @@ class LibrarySync(threading.Thread):
         mvideos = itemtypes.MusicVideos(embycursor, kodicursor)
 
         views = emby_db.getView_byType('musicvideos')
-        self.logMsg("Media folders: %s" % views, 1)
+        log("Media folders: %s" % views, 1)
 
         for view in views:
 
@@ -655,8 +642,8 @@ class LibrarySync(threading.Thread):
 
             if pdialog:
                 pdialog.update(
-                        heading="Emby for Kodi",
-                        message="%s %s..." % (utils.language(33019), viewName))
+                        heading=lang(29999),
+                        message="%s %s..." % (lang(33019), viewName))
 
             # Initial or repair sync
             all_embymvideos = self.emby.getMusicVideos(viewId, dialog=pdialog)
@@ -679,7 +666,7 @@ class LibrarySync(threading.Thread):
                     count += 1
                 mvideos.add_update(embymvideo, viewName, viewId)
         else:
-            self.logMsg("MusicVideos finished.", 2)
+            log("MusicVideos finished.", 2)
 
         return True
 
@@ -691,7 +678,7 @@ class LibrarySync(threading.Thread):
 
         views = emby_db.getView_byType('tvshows')
         views += emby_db.getView_byType('mixed')
-        self.logMsg("Media folders: %s" % views, 1)
+        log("Media folders: %s" % views, 1)
 
         for view in views:
 
@@ -701,8 +688,8 @@ class LibrarySync(threading.Thread):
             # Get items per view
             if pdialog:
                 pdialog.update(
-                        heading="Emby for Kodi",
-                        message="%s %s..." % (utils.language(33020), view['name']))
+                        heading=lang(29999),
+                        message="%s %s..." % (lang(33020), view['name']))
 
             all_embytvshows = self.emby.getShows(view['id'], dialog=pdialog)
             total = all_embytvshows['TotalRecordCount']
@@ -737,7 +724,7 @@ class LibrarySync(threading.Thread):
                         pdialog.update(percentage, message="%s - %s" % (title, episodetitle))
                     tvshows.add_updateEpisode(episode)
         else:
-            self.logMsg("TVShows finished.", 2)
+            log("TVShows finished.", 2)
 
         return True
 
@@ -756,8 +743,8 @@ class LibrarySync(threading.Thread):
 
             if pdialog:
                 pdialog.update(
-                    heading="Emby for Kodi",
-                    message="%s %s..." % (utils.language(33021), itemtype))
+                    heading=lang(29999),
+                    message="%s %s..." % (lang(33021), itemtype))
 
             all_embyitems = process[itemtype][0](dialog=pdialog)
             total = all_embyitems['TotalRecordCount']
@@ -778,7 +765,7 @@ class LibrarySync(threading.Thread):
 
                 process[itemtype][1](embyitem)
             else:
-                self.logMsg("%s finished." % itemtype, 2)
+                log("%s finished." % itemtype, 2)
 
         return True
 
@@ -799,7 +786,7 @@ class LibrarySync(threading.Thread):
                     itemids.append(item['ItemId'])
                 items = itemids
 
-            self.logMsg("Queue %s: %s" % (process, items), 1)
+            log("Queue %s: %s" % (process, items), 1)
             processlist[process].extend(items)
 
     def incrementalSync(self):
@@ -833,7 +820,7 @@ class LibrarySync(threading.Thread):
         }
         for process_type in ['added', 'update', 'userdata', 'remove']:
 
-            if process[process_type] and utils.window('emby_kodiScan') != "true":
+            if process[process_type] and window('emby_kodiScan') != "true":
 
                 listItems = list(process[process_type])
                 del process[process_type][:] # Reset class list
@@ -871,7 +858,7 @@ class LibrarySync(threading.Thread):
 
         if update_embydb:
             update_embydb = False
-            self.logMsg("Updating emby database.", 1)
+            log("Updating emby database.", 1)
             embyconn.commit()
             self.saveLastSync()
 
@@ -880,8 +867,8 @@ class LibrarySync(threading.Thread):
             self.forceLibraryUpdate = False
             self.dbCommit(kodiconn)
 
-            self.logMsg("Updating video library.", 1)
-            utils.window('emby_kodiScan', value="true")
+            log("Updating video library.", 1)
+            window('emby_kodiScan', value="true")
             xbmc.executebuiltin('UpdateLibrary(video)')
 
         if pDialog:
@@ -893,7 +880,7 @@ class LibrarySync(threading.Thread):
 
     def compareDBVersion(self, current, minimum):
         # It returns True is database is up to date. False otherwise.
-        self.logMsg("current: %s minimum: %s" % (current, minimum), 1)
+        log("current: %s minimum: %s" % (current, minimum), 1)
         currMajor, currMinor, currPatch = current.split(".")
         minMajor, minMinor, minPatch = minimum.split(".")
 
@@ -911,25 +898,22 @@ class LibrarySync(threading.Thread):
         try:
             self.run_internal()
         except Exception as e:
-            utils.window('emby_dbScan', clear=True)
+            window('emby_dbScan', clear=True)
             xbmcgui.Dialog().ok(
-                        heading="Emby for Kodi",
+                        heading=lang(29999),
                         line1=(
                             "Library sync thread has exited! "
                             "You should restart Kodi now. "
                             "Please report this on the forum."))
             raise
-
+    @utils.profiling()
     def run_internal(self):
 
-        lang = utils.language
-        window = utils.window
-        settings = utils.settings
         dialog = xbmcgui.Dialog()
 
         startupComplete = False
 
-        self.logMsg("---===### Starting LibrarySync ###===---", 0)
+        log("---===### Starting LibrarySync ###===---", 0)
 
         while not self.monitor.abortRequested():
 
@@ -947,13 +931,13 @@ class LibrarySync(threading.Thread):
                 uptoDate = self.compareDBVersion(currentVersion, minVersion)
 
                 if not uptoDate:
-                    self.logMsg("Database version out of date: %s minimum version required: %s"
+                    log("Database version out of date: %s minimum version required: %s"
                         % (currentVersion, minVersion), 0)
 
-                    resp = dialog.yesno("Emby for Kodi", lang(33022))
+                    resp = dialog.yesno(lang(29999), lang(33022))
                     if not resp:
-                        self.logMsg("Database version is out of date! USER IGNORED!", 0)
-                        dialog.ok("Emby for Kodi", lang(33023))
+                        log("Database version is out of date! USER IGNORED!", 0)
+                        dialog.ok(lang(29999), lang(33023))
                     else:
                         utils.reset()
 
@@ -967,24 +951,24 @@ class LibrarySync(threading.Thread):
                 videoDb = utils.getKodiVideoDBPath()
                 if not xbmcvfs.exists(videoDb):
                     # Database does not exists
-                    self.logMsg(
+                    log(
                         "The current Kodi version is incompatible "
                         "with the Emby for Kodi add-on. Please visit "
                         "https://github.com/MediaBrowser/Emby.Kodi/wiki "
                         "to know which Kodi versions are supported.", 0)
 
                     dialog.ok(
-                            heading="Emby for Kodi",
+                            heading=lang(29999),
                             line1=lang(33024))
                     break
 
                 # Run start up sync
-                self.logMsg("Database version: %s" % settings('dbCreatedWithVersion'), 0)
-                self.logMsg("SyncDatabase (started)", 1)
+                log("Database version: %s" % settings('dbCreatedWithVersion'), 0)
+                log("SyncDatabase (started)", 1)
                 startTime = datetime.now()
                 librarySync = self.startSync()
                 elapsedTime = datetime.now() - startTime
-                self.logMsg("SyncDatabase (finished in: %s) %s"
+                log("SyncDatabase (finished in: %s) %s"
                     % (str(elapsedTime).split('.')[0], librarySync), 1)
                 # Only try the initial sync once per kodi session regardless
                 # This will prevent an infinite loop in case something goes wrong.
@@ -999,32 +983,32 @@ class LibrarySync(threading.Thread):
                 # Set in kodimonitor.py
                 window('emby_onWake', clear=True)
                 if window('emby_syncRunning') != "true":
-                    self.logMsg("SyncDatabase onWake (started)", 0)
+                    log("SyncDatabase onWake (started)", 0)
                     librarySync = self.startSync()
-                    self.logMsg("SyncDatabase onWake (finished) %s" % librarySync, 0)
+                    log("SyncDatabase onWake (finished) %s" % librarySync, 0)
 
             if self.stop_thread:
                 # Set in service.py
-                self.logMsg("Service terminated thread.", 2)
+                log("Service terminated thread.", 2)
                 break
 
             if self.monitor.waitForAbort(1):
                 # Abort was requested while waiting. We should exit
                 break
 
-        self.logMsg("###===--- LibrarySync Stopped ---===###", 0)
+        log("###===--- LibrarySync Stopped ---===###", 0)
 
     def stopThread(self):
         self.stop_thread = True
-        self.logMsg("Ending thread...", 2)
+        log("Ending thread...", 2)
 
     def suspendThread(self):
         self.suspend_thread = True
-        self.logMsg("Pausing thread...", 0)
+        log("Pausing thread...", 0)
 
     def resumeThread(self):
         self.suspend_thread = False
-        self.logMsg("Resuming thread...", 0)
+        log("Resuming thread...", 0)
 
 
 class ManualSync(LibrarySync):
@@ -1041,14 +1025,13 @@ class ManualSync(LibrarySync):
 
     def movies(self, embycursor, kodicursor, pdialog):
 
-        lang = utils.language
         # Get movies from emby
         emby_db = embydb.Embydb_Functions(embycursor)
         movies = itemtypes.Movies(embycursor, kodicursor)
 
         views = emby_db.getView_byType('movies')
         views += emby_db.getView_byType('mixed')
-        self.logMsg("Media folders: %s" % views, 1)
+        log("Media folders: %s" % views, 1)
 
         # Pull the list of movies and boxsets in Kodi
         try:
@@ -1077,7 +1060,7 @@ class ManualSync(LibrarySync):
 
             if pdialog:
                 pdialog.update(
-                        heading="Emby for Kodi",
+                        heading=lang(29999),
                         message="%s %s..." % (lang(33026), viewName))
 
             all_embymovies = self.emby.getMovies(viewId, basic=True, dialog=pdialog)
@@ -1095,7 +1078,7 @@ class ManualSync(LibrarySync):
                     # Only update if movie is not in Kodi or checksum is different
                     updatelist.append(itemid)
 
-            self.logMsg("Movies to update for %s: %s" % (viewName, updatelist), 1)
+            log("Movies to update for %s: %s" % (viewName, updatelist), 1)
             embymovies = self.emby.getFullItems(updatelist)
             total = len(updatelist)
             del updatelist[:]
@@ -1121,7 +1104,7 @@ class ManualSync(LibrarySync):
         embyboxsets = []
 
         if pdialog:
-            pdialog.update(heading="Emby for Kodi", message=lang(33027))
+            pdialog.update(heading=lang(29999), message=lang(33027))
 
         for boxset in boxsets['Items']:
 
@@ -1137,7 +1120,7 @@ class ManualSync(LibrarySync):
                 updatelist.append(itemid)
                 embyboxsets.append(boxset)
 
-        self.logMsg("Boxsets to update: %s" % updatelist, 1)
+        log("Boxsets to update: %s" % updatelist, 1)
         total = len(updatelist)
 
         if pdialog:
@@ -1161,13 +1144,13 @@ class ManualSync(LibrarySync):
             if kodimovie not in all_embymoviesIds:
                 movies.remove(kodimovie)
         else:
-            self.logMsg("Movies compare finished.", 1)
+            log("Movies compare finished.", 1)
 
         for boxset in all_kodisets:
             if boxset not in all_embyboxsetsIds:
                 movies.remove(boxset)
         else:
-            self.logMsg("Boxsets compare finished.", 1)
+            log("Boxsets compare finished.", 1)
 
         return True
 
@@ -1178,7 +1161,7 @@ class ManualSync(LibrarySync):
         mvideos = itemtypes.MusicVideos(embycursor, kodicursor)
 
         views = emby_db.getView_byType('musicvideos')
-        self.logMsg("Media folders: %s" % views, 1)
+        log("Media folders: %s" % views, 1)
 
         # Pull the list of musicvideos in Kodi
         try:
@@ -1200,8 +1183,8 @@ class ManualSync(LibrarySync):
 
             if pdialog:
                 pdialog.update(
-                        heading="Emby for Kodi",
-                        message="%s %s..." % (utils.language(33028), viewName))
+                        heading=lang(29999),
+                        message="%s %s..." % (lang(33028), viewName))
 
             all_embymvideos = self.emby.getMusicVideos(viewId, basic=True, dialog=pdialog)
             for embymvideo in all_embymvideos['Items']:
@@ -1218,7 +1201,7 @@ class ManualSync(LibrarySync):
                     # Only update if musicvideo is not in Kodi or checksum is different
                     updatelist.append(itemid)
 
-            self.logMsg("MusicVideos to update for %s: %s" % (viewName, updatelist), 1)
+            log("MusicVideos to update for %s: %s" % (viewName, updatelist), 1)
             embymvideos = self.emby.getFullItems(updatelist)
             total = len(updatelist)
             del updatelist[:]
@@ -1245,20 +1228,19 @@ class ManualSync(LibrarySync):
             if kodimvideo not in all_embymvideosIds:
                 mvideos.remove(kodimvideo)
         else:
-            self.logMsg("MusicVideos compare finished.", 1)
+            log("MusicVideos compare finished.", 1)
 
         return True
 
     def tvshows(self, embycursor, kodicursor, pdialog):
 
-        lang = utils.language
         # Get shows from emby
         emby_db = embydb.Embydb_Functions(embycursor)
         tvshows = itemtypes.TVShows(embycursor, kodicursor)
 
         views = emby_db.getView_byType('tvshows')
         views += emby_db.getView_byType('mixed')
-        self.logMsg("Media folders: %s" % views, 1)
+        log("Media folders: %s" % views, 1)
 
         # Pull the list of tvshows and episodes in Kodi
         try:
@@ -1287,7 +1269,7 @@ class ManualSync(LibrarySync):
 
             if pdialog:
                 pdialog.update(
-                        heading="Emby for Kodi",
+                        heading=lang(29999),
                         message="%s %s..." % (lang(33029), viewName))
 
             all_embytvshows = self.emby.getShows(viewId, basic=True, dialog=pdialog)
@@ -1305,7 +1287,7 @@ class ManualSync(LibrarySync):
                     # Only update if movie is not in Kodi or checksum is different
                     updatelist.append(itemid)
 
-            self.logMsg("TVShows to update for %s: %s" % (viewName, updatelist), 1)
+            log("TVShows to update for %s: %s" % (viewName, updatelist), 1)
             embytvshows = self.emby.getFullItems(updatelist)
             total = len(updatelist)
             del updatelist[:]
@@ -1332,7 +1314,7 @@ class ManualSync(LibrarySync):
                 # Get all episodes in view
                 if pdialog:
                     pdialog.update(
-                            heading="Emby for Kodi",
+                            heading=lang(29999),
                             message="%s %s..." % (lang(33030), viewName))
 
                 all_embyepisodes = self.emby.getEpisodes(viewId, basic=True, dialog=pdialog)
@@ -1349,7 +1331,7 @@ class ManualSync(LibrarySync):
                         # Only update if movie is not in Kodi or checksum is different
                         updatelist.append(itemid)
 
-                self.logMsg("Episodes to update for %s: %s" % (viewName, updatelist), 1)
+                log("Episodes to update for %s: %s" % (viewName, updatelist), 1)
                 embyepisodes = self.emby.getFullItems(updatelist)
                 total = len(updatelist)
                 del updatelist[:]
@@ -1363,7 +1345,8 @@ class ManualSync(LibrarySync):
 
                     if pdialog:
                         percentage = int((float(count) / float(total))*100)
-                        pdialog.update(percentage, message="%s - %s" % (episode['SeriesName'], episode['Name']))
+                        title = "%s - %s" % (episode.get('SeriesName', "Unknown"), episode['Name'])
+                        pdialog.update(percentage, message=title)
                         count += 1
                     tvshows.add_updateEpisode(episode)
 
@@ -1373,13 +1356,13 @@ class ManualSync(LibrarySync):
             if koditvshow not in all_embytvshowsIds:
                 tvshows.remove(koditvshow)
         else:
-            self.logMsg("TVShows compare finished.", 1)
+            log("TVShows compare finished.", 1)
 
         for kodiepisode in all_kodiepisodes:
             if kodiepisode not in all_embyepisodesIds:
                 tvshows.remove(kodiepisode)
         else:
-            self.logMsg("Episodes compare finished.", 1)
+            log("Episodes compare finished.", 1)
 
         return True
 
@@ -1419,8 +1402,8 @@ class ManualSync(LibrarySync):
         for data_type in ['artists', 'albums', 'songs']:
             if pdialog:
                 pdialog.update(
-                        heading="Emby for Kodi",
-                        message="%s %s..." % (utils.language(33031), data_type))
+                        heading=lang(29999),
+                        message="%s %s..." % (lang(33031), data_type))
             if data_type != "artists":
                 all_embyitems = process[data_type][0](basic=True, dialog=pdialog)
             else:
@@ -1445,7 +1428,7 @@ class ManualSync(LibrarySync):
                     if all_kodisongs.get(itemid) != API.getChecksum():
                         # Only update if songs is not in Kodi or checksum is different
                         updatelist.append(itemid)
-            self.logMsg("%s to update: %s" % (data_type, updatelist), 1)
+            log("%s to update: %s" % (data_type, updatelist), 1)
             embyitems = self.emby.getFullItems(updatelist)
             total = len(updatelist)
             del updatelist[:]
@@ -1466,15 +1449,15 @@ class ManualSync(LibrarySync):
             if kodiartist not in all_embyartistsIds and all_kodiartists[kodiartist] is not None:
                 music.remove(kodiartist)
         else:
-            self.logMsg("Artist compare finished.", 1)
+            log("Artist compare finished.", 1)
         for kodialbum in all_kodialbums:
             if kodialbum not in all_embyalbumsIds:
                 music.remove(kodialbum)
         else:
-            self.logMsg("Albums compare finished.", 1)
+            log("Albums compare finished.", 1)
         for kodisong in all_kodisongs:
             if kodisong not in all_embysongsIds:
                 music.remove(kodisong)
         else:
-            self.logMsg("Songs compare finished.", 1)
-        return True
+            log("Songs compare finished.", 1)
+        return True
\ No newline at end of file
diff --git a/resources/lib/musicutils.py b/resources/lib/musicutils.py
index b058c5c5..66da24a1 100644
--- a/resources/lib/musicutils.py
+++ b/resources/lib/musicutils.py
@@ -14,20 +14,18 @@ from mutagen import id3
 import base64
 
 import read_embyserver as embyserver
-import utils
+from utils import Logging, window
+log = Logging('MusicTools').log
 
 #################################################################################################
 
 # Helper for the music library, intended to fix missing song ID3 tags on Emby
 
-def logMsg(msg, lvl=1):
-    utils.logMsg("%s %s" % ("Emby", "musictools"), msg, lvl)
-
 def getRealFileName(filename, isTemp=False):
     #get the filename path accessible by python if possible...
     
     if not xbmcvfs.exists(filename):
-        logMsg( "File does not exist! %s" %(filename), 0)
+        log("File does not exist! %s" % filename, 0)
         return (False, "")
     
     #if we use os.path method on older python versions (sunch as some android builds), we need to pass arguments as string
@@ -104,7 +102,7 @@ def getAdditionalSongTags(embyid, emby_rating, API, kodicursor, emby_db, enablei
     elif file_rating is None and not currentvalue:
         return (emby_rating, comment, False)
     
-    logMsg("getAdditionalSongTags --> embyid: %s - emby_rating: %s - file_rating: %s - current rating in kodidb: %s" %(embyid, emby_rating, file_rating, currentvalue))
+    log("getAdditionalSongTags --> embyid: %s - emby_rating: %s - file_rating: %s - current rating in kodidb: %s" %(embyid, emby_rating, file_rating, currentvalue))
     
     updateFileRating = False
     updateEmbyRating = False
@@ -171,7 +169,7 @@ def getAdditionalSongTags(embyid, emby_rating, API, kodicursor, emby_db, enablei
     if updateEmbyRating and enableexportsongrating:
         # sync details to emby server. Translation needed between ID3 rating and emby likes/favourites:
         like, favourite, deletelike = getEmbyRatingFromKodiRating(rating)
-        utils.window("ignore-update-%s" %embyid, "true") #set temp windows prop to ignore the update from webclient update
+        window("ignore-update-%s" %embyid, "true") #set temp windows prop to ignore the update from webclient update
         emby.updateUserRating(embyid, like, favourite, deletelike)
     
     return (rating, comment, hasEmbeddedCover)
@@ -183,7 +181,7 @@ def getSongTags(file):
     hasEmbeddedCover = False
     
     isTemp,filename = getRealFileName(file)
-    logMsg( "getting song ID3 tags for " + filename)
+    log( "getting song ID3 tags for " + filename)
     
     try:
         ###### FLAC FILES #############
@@ -217,14 +215,14 @@ def getSongTags(file):
                     #POPM rating is 0-255 and needs to be converted to 0-5 range
                     if rating > 5: rating = (rating / 255) * 5
         else:
-            logMsg( "Not supported fileformat or unable to access file: %s" %(filename))
+            log( "Not supported fileformat or unable to access file: %s" %(filename))
         
         #the rating must be a round value
         rating = int(round(rating,0))
     
     except Exception as e:
         #file in use ?
-        utils.logMsg("Exception in getSongTags", str(e),0)
+        log("Exception in getSongTags", str(e),0)
         rating = None
     
     #remove tempfile if needed....
@@ -246,7 +244,7 @@ def updateRatingToFile(rating, file):
     xbmcvfs.copy(file, tempfile)
     tempfile = xbmc.translatePath(tempfile).decode("utf-8")
     
-    logMsg( "setting song rating: %s for filename: %s - using tempfile: %s" %(rating,file,tempfile))
+    log( "setting song rating: %s for filename: %s - using tempfile: %s" %(rating,file,tempfile))
     
     if not tempfile:
         return
@@ -263,7 +261,7 @@ def updateRatingToFile(rating, file):
             audio.add(id3.POPM(email="Windows Media Player 9 Series", rating=calcrating, count=1))
             audio.save()
         else:
-            logMsg( "Not supported fileformat: %s" %(tempfile))
+            log( "Not supported fileformat: %s" %(tempfile))
             
         #once we have succesfully written the flags we move the temp file to destination, otherwise not proceeding and just delete the temp
         #safety check: we check the file size of the temp file before proceeding with overwite of original file
@@ -274,14 +272,14 @@ def updateRatingToFile(rating, file):
             xbmcvfs.delete(file)
             xbmcvfs.copy(tempfile,file)
         else:
-            logMsg( "Checksum mismatch for filename: %s - using tempfile: %s  -  not proceeding with file overwite!" %(rating,file,tempfile))
+            log( "Checksum mismatch for filename: %s - using tempfile: %s  -  not proceeding with file overwite!" %(rating,file,tempfile))
         
         #always delete the tempfile
         xbmcvfs.delete(tempfile)
             
     except Exception as e:
         #file in use ?
-        logMsg("Exception in updateRatingToFile %s" %e,0)
+        log("Exception in updateRatingToFile %s" %e,0)
         
     
     
\ No newline at end of file
diff --git a/resources/lib/playbackutils.py b/resources/lib/playbackutils.py
index 4fbbc636..4da87f27 100644
--- a/resources/lib/playbackutils.py
+++ b/resources/lib/playbackutils.py
@@ -16,7 +16,7 @@ import downloadutils
 import playutils as putils
 import playlist
 import read_embyserver as embyserver
-import utils
+from utils import Logging, window, settings, language as lang
 
 #################################################################################################
 
@@ -26,6 +26,9 @@ class PlaybackUtils():
     
     def __init__(self, item):
 
+        global log
+        log = Logging(self.__class__.__name__).log
+
         self.item = item
         self.API = api.API(self.item)
 
@@ -33,28 +36,20 @@ class PlaybackUtils():
         self.addonName = self.clientInfo.getAddonName()
         self.doUtils = downloadutils.DownloadUtils().downloadUrl
 
-        self.userid = utils.window('emby_currUser')
-        self.server = utils.window('emby_server%s' % self.userid)
+        self.userid = window('emby_currUser')
+        self.server = window('emby_server%s' % self.userid)
 
         self.artwork = artwork.Artwork()
         self.emby = embyserver.Read_EmbyServer()
         self.pl = playlist.Playlist()
 
-    def logMsg(self, msg, lvl=1):
-
-        self.className = self.__class__.__name__
-        utils.logMsg("%s %s" % (self.addonName, self.className), msg, lvl)
-
 
     def play(self, itemid, dbid=None):
 
-        window = utils.window
-        settings = utils.settings
-
         listitem = xbmcgui.ListItem()
         playutils = putils.PlayUtils(self.item)
 
-        self.logMsg("Play called.", 1)
+        log("Play called.", 1)
         playurl = playutils.getPlayUrl()
         if not playurl:
             return xbmcplugin.setResolvedUrl(int(sys.argv[1]), False, listitem)
@@ -77,9 +72,9 @@ class PlaybackUtils():
         introsPlaylist = False
         dummyPlaylist = False
 
-        self.logMsg("Playlist start position: %s" % startPos, 2)
-        self.logMsg("Playlist plugin position: %s" % currentPosition, 2)
-        self.logMsg("Playlist size: %s" % sizePlaylist, 2)
+        log("Playlist start position: %s" % startPos, 2)
+        log("Playlist plugin position: %s" % currentPosition, 2)
+        log("Playlist size: %s" % sizePlaylist, 2)
 
         ############### RESUME POINT ################
         
@@ -91,12 +86,11 @@ class PlaybackUtils():
         if not propertiesPlayback:
 
             window('emby_playbackProps', value="true")
-            self.logMsg("Setting up properties in playlist.", 1)
+            log("Setting up properties in playlist.", 1)
 
-            if (not homeScreen and not seektime and 
-                    window('emby_customPlaylist') != "true"):
+            if not homeScreen and not seektime and window('emby_customPlaylist') != "true":
                 
-                self.logMsg("Adding dummy file to playlist.", 2)
+                log("Adding dummy file to playlist.", 2)
                 dummyPlaylist = True
                 playlist.add(playurl, listitem, index=startPos)
                 # Remove the original item from playlist 
@@ -116,18 +110,18 @@ class PlaybackUtils():
                     getTrailers = True
 
                     if settings('askCinema') == "true":
-                        resp = xbmcgui.Dialog().yesno("Emby for Kodi", utils.language(33016))
+                        resp = xbmcgui.Dialog().yesno("Emby for Kodi", lang(33016))
                         if not resp:
                             # User selected to not play trailers
                             getTrailers = False
-                            self.logMsg("Skip trailers.", 1)
+                            log("Skip trailers.", 1)
                     
                     if getTrailers:
                         for intro in intros['Items']:
                             # The server randomly returns intros, process them.
                             introListItem = xbmcgui.ListItem()
                             introPlayurl = putils.PlayUtils(intro).getPlayUrl()
-                            self.logMsg("Adding Intro: %s" % introPlayurl, 1)
+                            log("Adding Intro: %s" % introPlayurl, 1)
 
                             # Set listitem and properties for intros
                             pbutils = PlaybackUtils(intro)
@@ -143,7 +137,7 @@ class PlaybackUtils():
             if homeScreen and not seektime and not sizePlaylist:
                 # Extend our current playlist with the actual item to play
                 # only if there's no playlist first
-                self.logMsg("Adding main item to playlist.", 1)
+                log("Adding main item to playlist.", 1)
                 self.pl.addtoPlaylist(dbid, self.item['Type'].lower())
 
             # Ensure that additional parts are played after the main item
@@ -160,7 +154,7 @@ class PlaybackUtils():
 
                     additionalListItem = xbmcgui.ListItem()
                     additionalPlayurl = putils.PlayUtils(part).getPlayUrl()
-                    self.logMsg("Adding additional part: %s" % partcount, 1)
+                    log("Adding additional part: %s" % partcount, 1)
 
                     # Set listitem and properties for each additional parts
                     pbutils = PlaybackUtils(part)
@@ -174,13 +168,13 @@ class PlaybackUtils():
             if dummyPlaylist:
                 # Added a dummy file to the playlist,
                 # because the first item is going to fail automatically.
-                self.logMsg("Processed as a playlist. First item is skipped.", 1)
+                log("Processed as a playlist. First item is skipped.", 1)
                 return xbmcplugin.setResolvedUrl(int(sys.argv[1]), False, listitem)
                 
 
         # We just skipped adding properties. Reset flag for next time.
         elif propertiesPlayback:
-            self.logMsg("Resetting properties playback flag.", 2)
+            log("Resetting properties playback flag.", 2)
             window('emby_playbackProps', clear=True)
 
         #self.pl.verifyPlaylist()
@@ -190,7 +184,7 @@ class PlaybackUtils():
         if window('emby_%s.playmethod' % playurl) == "Transcode":
             # Filter ISO since Emby does not probe anymore
             if self.item.get('VideoType') == "Iso":
-                self.logMsg("Skipping audio/subs prompt, ISO detected.", 1)
+                log("Skipping audio/subs prompt, ISO detected.", 1)
             else:
                 playurl = playutils.audioSubsPref(playurl, listitem)
                 window('emby_%s.playmethod' % playurl, value="Transcode")
@@ -201,23 +195,22 @@ class PlaybackUtils():
         ############### PLAYBACK ################
 
         if homeScreen and seektime and window('emby_customPlaylist') != "true":
-            self.logMsg("Play as a widget item.", 1)
+            log("Play as a widget item.", 1)
             self.setListItem(listitem)
             xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, listitem)
 
         elif ((introsPlaylist and window('emby_customPlaylist') == "true") or
                 (homeScreen and not sizePlaylist)):
             # Playlist was created just now, play it.
-            self.logMsg("Play playlist.", 1)
+            log("Play playlist.", 1)
             xbmc.Player().play(playlist, startpos=startPos)
 
         else:
-            self.logMsg("Play as a regular item.", 1)
+            log("Play as a regular item.", 1)
             xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, listitem)
 
     def setProperties(self, playurl, listitem):
 
-        window = utils.window
         # Set all properties necessary for plugin path playback
         itemid = self.item['Id']
         itemtype = self.item['Type']
@@ -233,7 +226,7 @@ class PlaybackUtils():
             window('%s.refreshid' % embyitem, value=itemid)
 
         # Append external subtitles to stream
-        playmethod = utils.window('%s.playmethod' % embyitem)
+        playmethod = window('%s.playmethod' % embyitem)
         # Only for direct stream
         if playmethod in ("DirectStream"):
             # Direct play automatically appends external
@@ -272,7 +265,7 @@ class PlaybackUtils():
                 kodiindex += 1
         
         mapping = json.dumps(mapping)
-        utils.window('emby_%s.indexMapping' % playurl, value=mapping)
+        window('emby_%s.indexMapping' % playurl, value=mapping)
 
         return externalsubs
 
diff --git a/resources/lib/player.py b/resources/lib/player.py
index 7f323460..1cc187bb 100644
--- a/resources/lib/player.py
+++ b/resources/lib/player.py
@@ -7,11 +7,11 @@ import json
 import xbmc
 import xbmcgui
 
-import utils
 import clientinfo
 import downloadutils
 import kodidb_functions as kodidb
 import websocket_client as wsc
+from utils import Logging, window, settings, language as lang
 
 #################################################################################################
 
@@ -28,6 +28,9 @@ class Player(xbmc.Player):
 
     def __init__(self):
 
+        global log
+        log = Logging(self.__class__.__name__).log
+
         self.__dict__ = self._shared_state
 
         self.clientInfo = clientinfo.ClientInfo()
@@ -36,20 +39,13 @@ class Player(xbmc.Player):
         self.ws = wsc.WebSocket_Client()
         self.xbmcplayer = xbmc.Player()
 
-        self.logMsg("Starting playback monitor.", 2)
-
-    def logMsg(self, msg, lvl=1):
-        
-        self.className = self.__class__.__name__
-        utils.logMsg("%s %s" % (self.addonName, self.className), msg, lvl)
+        log("Starting playback monitor.", 2)
 
 
     def GetPlayStats(self):
         return self.playStats
 
     def onPlayBackStarted(self):
-
-        window = utils.window
         # Will be called when xbmc starts playing a file
         self.stopAll()
 
@@ -67,7 +63,7 @@ class Player(xbmc.Player):
                 except: pass
 
                 if count == 5: # try 5 times
-                    self.logMsg("Cancelling playback report...", 1)
+                    log("Cancelling playback report...", 1)
                     break
                 else: count += 1
 
@@ -84,12 +80,12 @@ class Player(xbmc.Player):
                 xbmc.sleep(200)
                 itemId = window("emby_%s.itemid" % currentFile)
                 if tryCount == 20: # try 20 times or about 10 seconds
-                    self.logMsg("Could not find itemId, cancelling playback report...", 1)
+                    log("Could not find itemId, cancelling playback report...", 1)
                     break
                 else: tryCount += 1
             
             else:
-                self.logMsg("ONPLAYBACK_STARTED: %s itemid: %s" % (currentFile, itemId), 0)
+                log("ONPLAYBACK_STARTED: %s itemid: %s" % (currentFile, itemId), 0)
 
                 # Only proceed if an itemId was found.
                 embyitem = "emby_%s" % currentFile
@@ -102,7 +98,7 @@ class Player(xbmc.Player):
                 customseek = window('emby_customPlaylist.seektime')
                 if window('emby_customPlaylist') == "true" and customseek:
                     # Start at, when using custom playlist (play to Kodi from webclient)
-                    self.logMsg("Seeking to: %s" % customseek, 1)
+                    log("Seeking to: %s" % customseek, 1)
                     self.xbmcplayer.seekTime(int(customseek)/10000000.0)
                     window('emby_customPlaylist.seektime', clear=True)
 
@@ -189,7 +185,7 @@ class Player(xbmc.Player):
 
                         if mapping: # Set in playbackutils.py
                             
-                            self.logMsg("Mapping for external subtitles index: %s" % mapping, 2)
+                            log("Mapping for external subtitles index: %s" % mapping, 2)
                             externalIndex = json.loads(mapping)
 
                             if externalIndex.get(str(indexSubs)):
@@ -207,7 +203,7 @@ class Player(xbmc.Player):
                 
 
                 # Post playback to server
-                self.logMsg("Sending POST play started: %s." % postdata, 2)
+                log("Sending POST play started: %s." % postdata, 2)
                 self.doUtils(url, postBody=postdata, action_type="POST")
                 
                 # Ensure we do have a runtime
@@ -215,7 +211,7 @@ class Player(xbmc.Player):
                     runtime = int(runtime)
                 except ValueError:
                     runtime = self.xbmcplayer.getTotalTime()
-                    self.logMsg("Runtime is missing, Kodi runtime: %s" % runtime, 1)
+                    log("Runtime is missing, Kodi runtime: %s" % runtime, 1)
 
                 # Save data map for updates and position calls
                 data = {
@@ -232,7 +228,7 @@ class Player(xbmc.Player):
                 }
                 
                 self.played_info[currentFile] = data
-                self.logMsg("ADDING_FILE: %s" % self.played_info, 1)
+                log("ADDING_FILE: %s" % self.played_info, 1)
 
                 # log some playback stats
                 '''if(itemType != None):
@@ -251,7 +247,7 @@ class Player(xbmc.Player):
 
     def reportPlayback(self):
         
-        self.logMsg("reportPlayback Called", 2)
+        log("reportPlayback Called", 2)
 
         # Get current file
         currentFile = self.currentFile
@@ -345,11 +341,11 @@ class Player(xbmc.Player):
                     
                     # Number of audiotracks to help get Emby Index
                     audioTracks = len(xbmc.Player().getAvailableAudioStreams())
-                    mapping = utils.window("emby_%s.indexMapping" % currentFile)
+                    mapping = window("emby_%s.indexMapping" % currentFile)
 
                     if mapping: # Set in PlaybackUtils.py
                         
-                        self.logMsg("Mapping for external subtitles index: %s" % mapping, 2)
+                        log("Mapping for external subtitles index: %s" % mapping, 2)
                         externalIndex = json.loads(mapping)
 
                         if externalIndex.get(str(indexSubs)):
@@ -369,13 +365,13 @@ class Player(xbmc.Player):
 
             # Report progress via websocketclient
             postdata = json.dumps(postdata)
-            self.logMsg("Report: %s" % postdata, 2)
+            log("Report: %s" % postdata, 2)
             self.ws.sendProgressUpdate(postdata)
 
     def onPlayBackPaused(self):
 
         currentFile = self.currentFile
-        self.logMsg("PLAYBACK_PAUSED: %s" % currentFile, 2)
+        log("PLAYBACK_PAUSED: %s" % currentFile, 2)
 
         if self.played_info.get(currentFile):
             self.played_info[currentFile]['paused'] = True
@@ -385,7 +381,7 @@ class Player(xbmc.Player):
     def onPlayBackResumed(self):
 
         currentFile = self.currentFile
-        self.logMsg("PLAYBACK_RESUMED: %s" % currentFile, 2)
+        log("PLAYBACK_RESUMED: %s" % currentFile, 2)
 
         if self.played_info.get(currentFile):
             self.played_info[currentFile]['paused'] = False
@@ -395,7 +391,7 @@ class Player(xbmc.Player):
     def onPlayBackSeek(self, time, seekOffset):
         # Make position when seeking a bit more accurate
         currentFile = self.currentFile
-        self.logMsg("PLAYBACK_SEEK: %s" % currentFile, 2)
+        log("PLAYBACK_SEEK: %s" % currentFile, 2)
 
         if self.played_info.get(currentFile):
             position = self.xbmcplayer.getTime()
@@ -404,39 +400,34 @@ class Player(xbmc.Player):
             self.reportPlayback()
     
     def onPlayBackStopped(self):
-        
-        window = utils.window
         # Will be called when user stops xbmc playing a file
-        self.logMsg("ONPLAYBACK_STOPPED", 2)
+        log("ONPLAYBACK_STOPPED", 2)
         window('emby_customPlaylist', clear=True)
         window('emby_customPlaylist.seektime', clear=True)
         window('emby_playbackProps', clear=True)
-        self.logMsg("Clear playlist properties.", 1)
+        log("Clear playlist properties.", 1)
         self.stopAll()
 
     def onPlayBackEnded(self):
         # Will be called when xbmc stops playing a file
-        self.logMsg("ONPLAYBACK_ENDED", 2)
-        utils.window('emby_customPlaylist.seektime', clear=True)
+        log("ONPLAYBACK_ENDED", 2)
+        window('emby_customPlaylist.seektime', clear=True)
         self.stopAll()
 
     def stopAll(self):
 
-        lang = utils.language
-        settings = utils.settings
-
         if not self.played_info:
             return 
             
-        self.logMsg("Played_information: %s" % self.played_info, 1)
+        log("Played_information: %s" % self.played_info, 1)
         # Process each items
         for item in self.played_info:
             
             data = self.played_info.get(item)
             if data:
                 
-                self.logMsg("Item path: %s" % item, 2)
-                self.logMsg("Item data: %s" % data, 2)
+                log("Item path: %s" % item, 2)
+                log("Item data: %s" % data, 2)
 
                 runtime = data['runtime']
                 currentPosition = data['currentPosition']
@@ -447,7 +438,7 @@ class Player(xbmc.Player):
                 playMethod = data['playmethod']
 
                 # Prevent manually mark as watched in Kodi monitor
-                utils.window('emby_skipWatched%s' % itemid, value="true")
+                window('emby_skipWatched%s' % itemid, value="true")
 
                 if currentPosition and runtime:
                     try:
@@ -457,7 +448,7 @@ class Player(xbmc.Player):
                         percentComplete = 0
                         
                     markPlayedAt = float(settings('markPlayed')) / 100
-                    self.logMsg("Percent complete: %s Mark played at: %s"
+                    log("Percent complete: %s Mark played at: %s"
                         % (percentComplete, markPlayedAt), 1)
 
                     # Send the delete action to the server.
@@ -475,18 +466,18 @@ class Player(xbmc.Player):
                     if percentComplete >= markPlayedAt and offerDelete:
                         resp = xbmcgui.Dialog().yesno(lang(30091), lang(33015), autoclose=120000)
                         if not resp:
-                            self.logMsg("User skipped deletion.", 1)
+                            log("User skipped deletion.", 1)
                             continue
 
                         url = "{server}/emby/Items/%s?format=json" % itemid
-                        self.logMsg("Deleting request: %s" % itemid, 1)
+                        log("Deleting request: %s" % itemid, 1)
                         self.doUtils(url, action_type="DELETE")
 
                 self.stopPlayback(data)
 
                 # Stop transcoding
                 if playMethod == "Transcode":
-                    self.logMsg("Transcoding for %s terminated." % itemid, 1)
+                    log("Transcoding for %s terminated." % itemid, 1)
                     deviceId = self.clientInfo.getDeviceId()
                     url = "{server}/emby/Videos/ActiveEncodings?DeviceId=%s" % deviceId
                     self.doUtils(url, action_type="DELETE")
@@ -495,7 +486,7 @@ class Player(xbmc.Player):
     
     def stopPlayback(self, data):
         
-        self.logMsg("stopPlayback called", 2)
+        log("stopPlayback called", 2)
         
         itemId = data['item_id']
         currentPosition = data['currentPosition']
diff --git a/resources/lib/playlist.py b/resources/lib/playlist.py
index bcd34a46..1f0819b6 100644
--- a/resources/lib/playlist.py
+++ b/resources/lib/playlist.py
@@ -13,7 +13,7 @@ import playutils
 import playbackutils
 import embydb_functions as embydb
 import read_embyserver as embyserver
-import utils
+from utils import Logging, window, settings, language as lang, kodiSQL
 
 #################################################################################################
 
@@ -23,25 +23,21 @@ class Playlist():
 
     def __init__(self):
 
+        global log
+        log = Logging(self.__class__.__name__).log
+
         self.clientInfo = clientinfo.ClientInfo()
         self.addonName = self.clientInfo.getAddonName()
 
-        self.userid = utils.window('emby_currUser')
-        self.server = utils.window('emby_server%s' % self.userid)
+        self.userid = window('emby_currUser')
+        self.server = window('emby_server%s' % self.userid)
 
         self.emby = embyserver.Read_EmbyServer()
 
-    def logMsg(self, msg, lvl=1):
-
-        self.className = self.__class__.__name__
-        utils.logMsg("%s %s" % (self.addonName, self.className), msg, lvl)
-
 
     def playAll(self, itemids, startat):
 
-        window = utils.window
-
-        embyconn = utils.kodiSQL('emby')
+        embyconn = kodiSQL('emby')
         embycursor = embyconn.cursor()
         emby_db = embydb.Embydb_Functions(embycursor)
 
@@ -49,8 +45,8 @@ class Playlist():
         playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO)
         playlist.clear()
 
-        self.logMsg("---*** PLAY ALL ***---", 1)
-        self.logMsg("Items: %s and start at: %s" % (itemids, startat), 1)
+        log("---*** PLAY ALL ***---", 1)
+        log("Items: %s and start at: %s" % (itemids, startat), 1)
 
         started = False
         window('emby_customplaylist', value="true")
@@ -66,14 +62,14 @@ class Playlist():
                 mediatype = embydb_item[4]
             except TypeError:
                 # Item is not found in our database, add item manually
-                self.logMsg("Item was not found in the database, manually adding item.", 1)
+                log("Item was not found in the database, manually adding item.", 1)
                 item = self.emby.getItem(itemid)
                 self.addtoPlaylist_xbmc(playlist, item)
             else:
                 # Add to playlist
                 self.addtoPlaylist(dbid, mediatype)
 
-            self.logMsg("Adding %s to playlist." % itemid, 1)
+            log("Adding %s to playlist." % itemid, 1)
 
             if not started:
                 started = True
@@ -84,12 +80,12 @@ class Playlist():
 
     def modifyPlaylist(self, itemids):
 
-        embyconn = utils.kodiSQL('emby')
+        embyconn = kodiSQL('emby')
         embycursor = embyconn.cursor()
         emby_db = embydb.Embydb_Functions(embycursor)
 
-        self.logMsg("---*** ADD TO PLAYLIST ***---", 1)
-        self.logMsg("Items: %s" % itemids, 1)
+        log("---*** ADD TO PLAYLIST ***---", 1)
+        log("Items: %s" % itemids, 1)
 
         player = xbmc.Player()
         playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO)
@@ -107,7 +103,7 @@ class Playlist():
                 # Add to playlist
                 self.addtoPlaylist(dbid, mediatype)
 
-            self.logMsg("Adding %s to playlist." % itemid, 1)
+            log("Adding %s to playlist." % itemid, 1)
 
         self.verifyPlaylist()
         embycursor.close()
@@ -130,17 +126,17 @@ class Playlist():
         else:
             pl['params']['item'] = {'file': url}
 
-        self.logMsg(xbmc.executeJSONRPC(json.dumps(pl)), 2)
+        log(xbmc.executeJSONRPC(json.dumps(pl)), 2)
 
     def addtoPlaylist_xbmc(self, playlist, item):
 
         playurl = playutils.PlayUtils(item).getPlayUrl()
         if not playurl:
             # Playurl failed
-            self.logMsg("Failed to retrieve playurl.", 1)
+            log("Failed to retrieve playurl.", 1)
             return
 
-        self.logMsg("Playurl: %s" % playurl)
+        log("Playurl: %s" % playurl)
         listitem = xbmcgui.ListItem()
         playbackutils.PlaybackUtils(item).setProperties(playurl, listitem)
 
@@ -164,7 +160,7 @@ class Playlist():
         else:
             pl['params']['item'] = {'file': url}
 
-        self.logMsg(xbmc.executeJSONRPC(json.dumps(pl)), 2)
+        log(xbmc.executeJSONRPC(json.dumps(pl)), 2)
 
     def verifyPlaylist(self):
 
@@ -178,7 +174,7 @@ class Playlist():
                 'playlistid': 1
             }
         }
-        self.logMsg(xbmc.executeJSONRPC(json.dumps(pl)), 2)
+        log(xbmc.executeJSONRPC(json.dumps(pl)), 2)
 
     def removefromPlaylist(self, position):
 
@@ -193,4 +189,4 @@ class Playlist():
                 'position': position
             }
         }
-        self.logMsg(xbmc.executeJSONRPC(json.dumps(pl)), 2)
+        log(xbmc.executeJSONRPC(json.dumps(pl)), 2)
\ No newline at end of file
diff --git a/resources/lib/playutils.py b/resources/lib/playutils.py
index a1de2948..d364bbb3 100644
--- a/resources/lib/playutils.py
+++ b/resources/lib/playutils.py
@@ -7,7 +7,7 @@ import xbmcgui
 import xbmcvfs
 
 import clientinfo
-import utils
+from utils import Logging, window, settings, language as lang
 
 #################################################################################################
 
@@ -17,41 +17,37 @@ class PlayUtils():
     
     def __init__(self, item):
 
+        global log
+        log = Logging(self.__class__.__name__).log
+
         self.item = item
         self.clientInfo = clientinfo.ClientInfo()
         self.addonName = self.clientInfo.getAddonName()
 
-        self.userid = utils.window('emby_currUser')
-        self.server = utils.window('emby_server%s' % self.userid)
-
-    def logMsg(self, msg, lvl=1):
-
-        self.className = self.__class__.__name__
-        utils.logMsg("%s %s" % (self.addonName, self.className), msg, lvl)
+        self.userid = window('emby_currUser')
+        self.server = window('emby_server%s' % self.userid)
     
 
     def getPlayUrl(self):
 
-        window = utils.window
-
         playurl = None
         
-        if (self.item.get('Type') in ("Recording", "TvChannel") and
-                self.item.get('MediaSources') and self.item['MediaSources'][0]['Protocol'] == "Http"):
+        if (self.item.get('Type') in ("Recording", "TvChannel") and self.item.get('MediaSources')
+                and self.item['MediaSources'][0]['Protocol'] == "Http"):
             # Play LiveTV or recordings
-            self.logMsg("File protocol is http (livetv).", 1)
+            log("File protocol is http (livetv).", 1)
             playurl = "%s/emby/Videos/%s/live.m3u8?static=true" % (self.server, self.item['Id'])
             window('emby_%s.playmethod' % playurl, value="Transcode")
 
         elif self.item.get('MediaSources') and self.item['MediaSources'][0]['Protocol'] == "Http":
             # Only play as http, used for channels, or online hosting of content
-            self.logMsg("File protocol is http.", 1)
+            log("File protocol is http.", 1)
             playurl = self.httpPlay()
             window('emby_%s.playmethod' % playurl, value="DirectStream")
 
         elif self.isDirectPlay():
 
-            self.logMsg("File is direct playing.", 1)
+            log("File is direct playing.", 1)
             playurl = self.directPlay()
             playurl = playurl.encode('utf-8')
             # Set playmethod property
@@ -59,14 +55,14 @@ class PlayUtils():
 
         elif self.isDirectStream():
             
-            self.logMsg("File is direct streaming.", 1)
+            log("File is direct streaming.", 1)
             playurl = self.directStream()
             # Set playmethod property
             window('emby_%s.playmethod' % playurl, value="DirectStream")
 
         elif self.isTranscoding():
             
-            self.logMsg("File is transcoding.", 1)
+            log("File is transcoding.", 1)
             playurl = self.transcoding()
             # Set playmethod property
             window('emby_%s.playmethod' % playurl, value="Transcode")
@@ -88,21 +84,18 @@ class PlayUtils():
 
     def isDirectPlay(self):
 
-        lang = utils.language
-        settings = utils.settings
         dialog = xbmcgui.Dialog()
 
-
         # Requirement: Filesystem, Accessible path
         if settings('playFromStream') == "true":
             # User forcing to play via HTTP
-            self.logMsg("Can't direct play, play from HTTP enabled.", 1)
+            log("Can't direct play, play from HTTP enabled.", 1)
             return False
 
         videotrack = self.item['MediaSources'][0]['Name']
         transcodeH265 = settings('transcodeH265')
         videoprofiles = [x['Profile'] for x in self.item['MediaSources'][0]['MediaStreams'] if 'Profile' in x]
-        transcodeHi10P = utils.settings('transcodeHi10P')        
+        transcodeHi10P = settings('transcodeHi10P')        
 
         if transcodeHi10P == "true" and "H264" in videotrack and "High 10" in videoprofiles:
             return False   
@@ -116,7 +109,7 @@ class PlayUtils():
                 '2': 720,
                 '3': 1080
             }
-            self.logMsg("Resolution is: %sP, transcode for resolution: %sP+"
+            log("Resolution is: %sP, transcode for resolution: %sP+"
                 % (resolution, res[transcodeH265]), 1)
             if res[transcodeH265] <= resolution:
                 return False
@@ -124,25 +117,25 @@ class PlayUtils():
         canDirectPlay = self.item['MediaSources'][0]['SupportsDirectPlay']
         # Make sure direct play is supported by the server
         if not canDirectPlay:
-            self.logMsg("Can't direct play, server doesn't allow/support it.", 1)
+            log("Can't direct play, server doesn't allow/support it.", 1)
             return False
 
         location = self.item['LocationType']
         if location == "FileSystem":
             # Verify the path
             if not self.fileExists():
-                self.logMsg("Unable to direct play.")
+                log("Unable to direct play.", 1)
                 try:
                     count = int(settings('failCount'))
                 except ValueError:
                     count = 0
-                self.logMsg("Direct play failed: %s times." % count, 1)
+                log("Direct play failed: %s times." % count, 1)
 
                 if count < 2:
                     # Let the user know that direct play failed
                     settings('failCount', value=str(count+1))
                     dialog.notification(
-                                heading="Emby for Kodi",
+                                heading=lang(29999),
                                 message=lang(33011),
                                 icon="special://home/addons/plugin.video.emby/icon.png",
                                 sound=False)
@@ -151,7 +144,7 @@ class PlayUtils():
                     settings('playFromStream', value="true")
                     settings('failCount', value="0")
                     dialog.notification(
-                                heading="Emby for Kodi",
+                                heading=lang(29999),
                                 message=lang(33012),
                                 icon="special://home/addons/plugin.video.emby/icon.png",
                                 sound=False)
@@ -192,27 +185,26 @@ class PlayUtils():
 
         # Convert path to direct play
         path = self.directPlay()
-        self.logMsg("Verifying path: %s" % path, 1)
+        log("Verifying path: %s" % path, 1)
 
         if xbmcvfs.exists(path):
-            self.logMsg("Path exists.", 1)
+            log("Path exists.", 1)
             return True
 
         elif ":" not in path:
-            self.logMsg("Can't verify path, assumed linux. Still try to direct play.", 1)
+            log("Can't verify path, assumed linux. Still try to direct play.", 1)
             return True
 
         else:
-            self.logMsg("Failed to find file.", 1)
+            log("Failed to find file.", 1)
             return False
 
     def isDirectStream(self):
 
-
         videotrack = self.item['MediaSources'][0]['Name']
-        transcodeH265 = utils.settings('transcodeH265')
+        transcodeH265 = settings('transcodeH265')
         videoprofiles = [x['Profile'] for x in self.item['MediaSources'][0]['MediaStreams'] if 'Profile' in x]
-        transcodeHi10P = utils.settings('transcodeHi10P')        
+        transcodeHi10P = settings('transcodeHi10P')        
 
         if transcodeHi10P == "true" and "H264" in videotrack and "High 10" in videoprofiles:
             return False   
@@ -226,7 +218,7 @@ class PlayUtils():
                 '2': 720,
                 '3': 1080
             }
-            self.logMsg("Resolution is: %sP, transcode for resolution: %sP+"
+            log("Resolution is: %sP, transcode for resolution: %sP+"
                 % (resolution, res[transcodeH265]), 1)
             if res[transcodeH265] <= resolution:
                 return False
@@ -239,7 +231,7 @@ class PlayUtils():
 
         # Verify the bitrate
         if not self.isNetworkSufficient():
-            self.logMsg("The network speed is insufficient to direct stream file.", 1)
+            log("The network speed is insufficient to direct stream file.", 1)
             return False
 
         return True
@@ -258,15 +250,14 @@ class PlayUtils():
 
     def isNetworkSufficient(self):
 
-
         settings = self.getBitrate()*1000
 
         try:
             sourceBitrate = int(self.item['MediaSources'][0]['Bitrate'])
         except (KeyError, TypeError):
-            self.logMsg("Bitrate value is missing.", 1)
+            log("Bitrate value is missing.", 1)
         else:
-            self.logMsg("The add-on settings bitrate is: %s, the video bitrate required is: %s"
+            log("The add-on settings bitrate is: %s, the video bitrate required is: %s"
                 % (settings, sourceBitrate), 1)
             if settings < sourceBitrate:
                 return False
@@ -325,11 +316,10 @@ class PlayUtils():
         }
 
         # max bit rate supported by server (max signed 32bit integer)
-        return bitrate.get(utils.settings('videoBitrate'), 2147483)
+        return bitrate.get(settings('videoBitrate'), 2147483)
 
     def audioSubsPref(self, url, listitem):
 
-        lang = utils.language
         dialog = xbmcgui.Dialog()
         # For transcoding only
         # Present the list of audio to select from
diff --git a/resources/lib/read_embyserver.py b/resources/lib/read_embyserver.py
index 3121a07a..5e62425e 100644
--- a/resources/lib/read_embyserver.py
+++ b/resources/lib/read_embyserver.py
@@ -4,21 +4,22 @@
 
 import xbmc
 
-import utils
 import clientinfo
 import downloadutils
+from utils import Logging, window, settings, kodiSQL
 
 #################################################################################################
 
 
 class Read_EmbyServer():
 
-    limitIndex = int(utils.settings('limitindex'))
+    limitIndex = int(settings('limitindex'))
 
 
     def __init__(self):
 
-        window = utils.window
+        global log
+        log = Logging(self.__class__.__name__).log
 
         self.clientInfo = clientinfo.ClientInfo()
         self.addonName = self.clientInfo.getAddonName()
@@ -27,17 +28,11 @@ class Read_EmbyServer():
         self.userId = window('emby_currUser')
         self.server = 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 split_list(self, itemlist, size):
         # Split up list in pieces of size. Will generate a list of lists
         return [itemlist[i:i+size] for i in range(0, len(itemlist), size)]
 
-
     def getItem(self, itemid):
         # This will return the full item
         item = {}
@@ -60,7 +55,8 @@ class Read_EmbyServer():
                 'Ids': ",".join(itemlist),
                 'Fields': "Etag"
             }
-            result = self.doUtils("{server}/emby/Users/{UserId}/Items?&format=json", parameters=params)
+            url = "{server}/emby/Users/{UserId}/Items?&format=json"
+            result = self.doUtils(url, parameters=params)
             if result:
                 items.extend(result['Items'])
 
@@ -86,7 +82,8 @@ class Read_EmbyServer():
                         "MediaSources,VoteCount"
                 )
             }
-            result = self.doUtils("{server}/emby/Users/{UserId}/Items?format=json", parameters=params)
+            url = "{server}/emby/Users/{UserId}/Items?format=json"
+            result = self.doUtils(url, parameters=params)
             if result:
                 items.extend(result['Items'])
 
@@ -96,14 +93,15 @@ class Read_EmbyServer():
         # Returns ancestors using embyId
         viewId = None
 
-        for view in self.doUtils("{server}/emby/Items/%s/Ancestors?UserId={UserId}&format=json" % itemid):
+        url = "{server}/emby/Items/%s/Ancestors?UserId={UserId}&format=json" % itemid
+        for view in self.doUtils(url):
 
             if view['Type'] == "CollectionFolder":
                 # Found view
                 viewId = view['Id']
 
         # Compare to view table in emby database
-        emby = utils.kodiSQL('emby')
+        emby = kodiSQL('emby')
         cursor_emby = emby.cursor()
         query = ' '.join((
 
@@ -124,7 +122,8 @@ class Read_EmbyServer():
 
         return [viewName, viewId, mediatype]
     
-    def getFilteredSection(self, parentid, itemtype=None, sortby="SortName", recursive=True, limit=None, sortorder="Ascending", filter=""):
+    def getFilteredSection(self, parentid, itemtype=None, sortby="SortName", recursive=True,
+                        limit=None, sortorder="Ascending", filter=""):
         params = {
 
             'ParentId': parentid,
@@ -137,39 +136,54 @@ class Read_EmbyServer():
             'SortBy': sortby,
             'SortOrder': sortorder,
             'Filters': filter,
-            'Fields': ( "Path,Genres,SortName,Studios,Writer,ProductionYear,Taglines,"
-            "CommunityRating,OfficialRating,CumulativeRunTimeTicks,"
-            "Metascore,AirTime,DateCreated,MediaStreams,People,Overview,"
-            "CriticRating,CriticRatingSummary,Etag,ShortOverview,ProductionLocations,"
-            "Tags,ProviderIds,ParentId,RemoteTrailers,SpecialEpisodeNumbers")
+            'Fields': (
+
+                "Path,Genres,SortName,Studios,Writer,ProductionYear,Taglines,"
+                "CommunityRating,OfficialRating,CumulativeRunTimeTicks,"
+                "Metascore,AirTime,DateCreated,MediaStreams,People,Overview,"
+                "CriticRating,CriticRatingSummary,Etag,ShortOverview,ProductionLocations,"
+                "Tags,ProviderIds,ParentId,RemoteTrailers,SpecialEpisodeNumbers"
+            )
         }
         return self.doUtils("{server}/emby/Users/{UserId}/Items?format=json", parameters=params)
     
     def getTvChannels(self):
+        
         params = {
 
             'EnableImages': True,
-            'Fields': ( "Path,Genres,SortName,Studios,Writer,ProductionYear,Taglines,"
-            "CommunityRating,OfficialRating,CumulativeRunTimeTicks,"
-            "Metascore,AirTime,DateCreated,MediaStreams,People,Overview,"
-            "CriticRating,CriticRatingSummary,Etag,ShortOverview,ProductionLocations,"
-            "Tags,ProviderIds,ParentId,RemoteTrailers,SpecialEpisodeNumbers")
+            'Fields': (
+
+                "Path,Genres,SortName,Studios,Writer,ProductionYear,Taglines,"
+                "CommunityRating,OfficialRating,CumulativeRunTimeTicks,"
+                "Metascore,AirTime,DateCreated,MediaStreams,People,Overview,"
+                "CriticRating,CriticRatingSummary,Etag,ShortOverview,ProductionLocations,"
+                "Tags,ProviderIds,ParentId,RemoteTrailers,SpecialEpisodeNumbers"
+            )
         }
-        return self.doUtils("{server}/emby/LiveTv/Channels/?userid={UserId}&format=json", parameters=params)
+        url = "{server}/emby/LiveTv/Channels/?userid={UserId}&format=json"
+        return self.doUtils(url, parameters=params)
     
     def getTvRecordings(self, groupid):
-        if groupid == "root": groupid = ""
+        
+        if groupid == "root":
+            groupid = ""
+        
         params = {
 
             'GroupId': groupid,
             'EnableImages': True,
-            'Fields': ( "Path,Genres,SortName,Studios,Writer,ProductionYear,Taglines,"
-            "CommunityRating,OfficialRating,CumulativeRunTimeTicks,"
-            "Metascore,AirTime,DateCreated,MediaStreams,People,Overview,"
-            "CriticRating,CriticRatingSummary,Etag,ShortOverview,ProductionLocations,"
-            "Tags,ProviderIds,ParentId,RemoteTrailers,SpecialEpisodeNumbers")
+            'Fields': (
+                
+                "Path,Genres,SortName,Studios,Writer,ProductionYear,Taglines,"
+                "CommunityRating,OfficialRating,CumulativeRunTimeTicks,"
+                "Metascore,AirTime,DateCreated,MediaStreams,People,Overview,"
+                "CriticRating,CriticRatingSummary,Etag,ShortOverview,ProductionLocations,"
+                "Tags,ProviderIds,ParentId,RemoteTrailers,SpecialEpisodeNumbers"
+            )
         }
-        return self.doUtils("{server}/emby/LiveTv/Recordings/?userid={UserId}&format=json", parameters=params)
+        url = "{server}/emby/LiveTv/Recordings/?userid={UserId}&format=json"
+        return self.doUtils(url, parameters=params)
     
     def getSection(self, parentid, itemtype=None, sortby="SortName", basic=False, dialog=None):
 
@@ -197,7 +211,7 @@ class Read_EmbyServer():
             items['TotalRecordCount'] = total
 
         except TypeError: # Failed to retrieve
-            self.logMsg("%s:%s Failed to retrieve the server response." % (url, params), 2)
+            log("%s:%s Failed to retrieve the server response." % (url, params), 2)
 
         else:
             index = 0
@@ -239,27 +253,27 @@ class Read_EmbyServer():
                     # Something happened to the connection
                     if not throttled:
                         throttled = True
-                        self.logMsg("Throttle activated.", 1)
+                        log("Throttle activated.", 1)
                     
                     if jump == highestjump:
                         # We already tried with the highestjump, but it failed. Reset value.
-                        self.logMsg("Reset highest value.", 1)
+                        log("Reset highest value.", 1)
                         highestjump = 0
 
                     # Lower the number by half
                     if highestjump:
                         throttled = False
                         jump = highestjump
-                        self.logMsg("Throttle deactivated.", 1)
+                        log("Throttle deactivated.", 1)
                     else:
                         jump = int(jump/4)
-                        self.logMsg("Set jump limit to recover: %s" % jump, 2)
+                        log("Set jump limit to recover: %s" % jump, 2)
                     
                     retry = 0
-                    while utils.window('emby_online') != "true":
+                    while window('emby_online') != "true":
                         # Wait server to come back online
                         if retry == 5:
-                            self.logMsg("Unable to reconnect to server. Abort process.", 1)
+                            log("Unable to reconnect to server. Abort process.", 1)
                             return items
                         
                         retry += 1
@@ -287,7 +301,7 @@ class Read_EmbyServer():
                             increment = 10
 
                         jump += increment
-                        self.logMsg("Increase jump limit to: %s" % jump, 1)
+                        log("Increase jump limit to: %s" % jump, 1)
         return items
 
     def getViews(self, mediatype="", root=False, sortedlist=False):
@@ -304,7 +318,7 @@ class Read_EmbyServer():
         try:
             items = result['Items']
         except TypeError:
-            self.logMsg("Error retrieving views for type: %s" % mediatype, 2)
+            log("Error retrieving views for type: %s" % mediatype, 2)
         else:
             for item in items:
 
@@ -373,15 +387,18 @@ class Read_EmbyServer():
         return belongs
 
     def getMovies(self, parentId, basic=False, dialog=None):
+
         return self.getSection(parentId, "Movie", basic=basic, dialog=dialog)
 
     def getBoxset(self, dialog=None):
+
         return self.getSection(None, "BoxSet", dialog=dialog)
 
     def getMovies_byBoxset(self, boxsetid):
         return self.getSection(boxsetid, "Movie")
 
     def getMusicVideos(self, parentId, basic=False, dialog=None):
+
         return self.getSection(parentId, "MusicVideo", basic=basic, dialog=dialog)
 
     def getHomeVideos(self, parentId):
@@ -389,6 +406,7 @@ class Read_EmbyServer():
         return self.getSection(parentId, "Video")
 
     def getShows(self, parentId, basic=False, dialog=None):
+
         return self.getSection(parentId, "Series", basic=basic, dialog=dialog)
 
     def getSeasons(self, showId):
@@ -404,7 +422,8 @@ class Read_EmbyServer():
             'IsVirtualUnaired': False,
             'Fields': "Etag"
         }
-        result = self.doUtils("{server}/emby/Shows/%s/Seasons?UserId={UserId}&format=json" % showId, parameters=params)
+        url = "{server}/emby/Shows/%s/Seasons?UserId={UserId}&format=json" % showId
+        result = self.doUtils(url, parameters=params)
         if result:
             items = result
 
@@ -422,7 +441,6 @@ class Read_EmbyServer():
 
         return self.getSection(seasonId, "Episode")
 
-
     def getArtists(self, dialog=None):
 
         items = {
@@ -444,7 +462,7 @@ class Read_EmbyServer():
             items['TotalRecordCount'] = total
 
         except TypeError: # Failed to retrieve
-            self.logMsg("%s:%s Failed to retrieve the server response." % (url, params), 2)
+            log("%s:%s Failed to retrieve the server response." % (url, params), 2)
 
         else:
             index = 1
@@ -478,17 +496,20 @@ class Read_EmbyServer():
         return items
 
     def getAlbums(self, basic=False, dialog=None):
+
         return self.getSection(None, "MusicAlbum", sortby="DateCreated", basic=basic, dialog=dialog)
 
     def getAlbumsbyArtist(self, artistId):
+
         return self.getSection(artistId, "MusicAlbum", sortby="DateCreated")
 
     def getSongs(self, basic=False, dialog=None):
+
         return self.getSection(None, "Audio", basic=basic, dialog=dialog)
 
     def getSongsbyAlbum(self, albumId):
-        return self.getSection(albumId, "Audio")
 
+        return self.getSection(albumId, "Audio")
 
     def getAdditionalParts(self, itemId):
 
@@ -497,8 +518,8 @@ class Read_EmbyServer():
             'Items': [],
             'TotalRecordCount': 0
         }
-
-        result = self.doUtils("{server}/emby/Videos/%s/AdditionalParts?UserId={UserId}&format=json" % itemId)
+        url = "{server}/emby/Videos/%s/AdditionalParts?UserId={UserId}&format=json" % itemId
+        result = self.doUtils(url)
         if result:
             items = result
 
@@ -518,23 +539,36 @@ class Read_EmbyServer():
 
         return sorted_items
 
-    def updateUserRating(self, itemid, like=None, favourite=None, deletelike=False):
+    def updateUserRating(self, itemid, favourite=None):
         # Updates the user rating to Emby
-        
+        doUtils = self.doUtils
+
         if favourite:
-            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, action_type="DELETE")
-
-        if not deletelike and like:
-            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, action_type="POST")
-        elif deletelike:
-            self.doUtils("{server}/emby/Users/{UserId}/Items/%s/Rating?format=json" % itemid, action_type="DELETE")
+            url = "{server}/emby/Users/{UserId}/FavoriteItems/%s?format=json" % itemid
+            doUtils(url, action_type="POST")
+        elif not favourite:
+            url = "{server}/emby/Users/{UserId}/FavoriteItems/%s?format=json" % itemid
+            doUtils(url, action_type="DELETE")
         else:
-            self.logMsg("Error processing user rating.", 1)
+            log("Error processing user rating.", 1)
 
-        self.logMsg("Update user rating to emby for itemid: %s "
-                    "| like: %s | favourite: %s | deletelike: %s"
-                    % (itemid, like, favourite, deletelike), 1)
+        log("Update user rating to emby for itemid: %s | favourite: %s" % (itemid, favourite), 1)
+
+    def refreshItem(self, itemid):
+
+        url = "{server}/emby/Items/%s/Refresh?format=json" % itemid
+        params = {
+
+            'Recursive': True,
+            'ImageRefreshMode': "FullRefresh",
+            'MetadataRefreshMode': "FullRefresh",
+            'ReplaceAllImages': False,
+            'ReplaceAllMetadata': True
+
+        }
+        self.doUtils(url, postBody=params, action_type="POST")
+
+    def deleteItem(self, itemid):
+
+        url = "{server}/emby/Items/%s?format=json" % itemId
+        self.doUtils(url, action_type="DELETE")
\ No newline at end of file
diff --git a/resources/lib/userclient.py b/resources/lib/userclient.py
index f068b772..c5d9caeb 100644
--- a/resources/lib/userclient.py
+++ b/resources/lib/userclient.py
@@ -11,9 +11,9 @@ import xbmcaddon
 import xbmcvfs
 
 import artwork
-import utils
 import clientinfo
 import downloadutils
+from utils import Logging, window, settings, language as lang
 
 ##################################################################################################
 
@@ -39,6 +39,9 @@ class UserClient(threading.Thread):
 
     def __init__(self):
 
+        global log
+        log = Logging(self.__class__.__name__).log
+
         self.__dict__ = self._shared_state
         self.addon = xbmcaddon.Addon()
 
@@ -47,25 +50,20 @@ class UserClient(threading.Thread):
 
         threading.Thread.__init__(self)
 
-    def logMsg(self, msg, lvl=1):
-
-        className = self.__class__.__name__
-        utils.logMsg("%s %s" % (self.addonName, className), msg, lvl)
-
 
     def getAdditionalUsers(self):
 
-        additionalUsers = utils.settings('additionalUsers')
+        additionalUsers = settings('additionalUsers')
 
         if additionalUsers:
             self.AdditionalUser = additionalUsers.split(',')
 
     def getUsername(self):
 
-        username = utils.settings('username')
+        username = settings('username')
 
         if not username:
-            self.logMsg("No username saved.", 2)
+            log("No username saved.", 2)
             return ""
 
         return username
@@ -73,7 +71,7 @@ class UserClient(threading.Thread):
     def getLogLevel(self):
 
         try:
-            logLevel = int(utils.settings('logLevel'))
+            logLevel = int(settings('logLevel'))
         except ValueError:
             logLevel = 0
 
@@ -81,9 +79,6 @@ class UserClient(threading.Thread):
 
     def getUserId(self):
 
-        window = utils.window
-        settings = utils.settings
-
         username = self.getUsername()
         w_userId = window('emby_currUser')
         s_userId = settings('userId%s' % username)
@@ -93,22 +88,20 @@ class UserClient(threading.Thread):
             if not s_userId:
                 # Save access token if it's missing from settings
                 settings('userId%s' % username, value=w_userId)
-            self.logMsg("Returning userId from WINDOW for username: %s UserId: %s"
+            log("Returning userId from WINDOW for username: %s UserId: %s"
                 % (username, w_userId), 2)
             return w_userId
         # Verify the settings
         elif s_userId:
-            self.logMsg("Returning userId from SETTINGS for username: %s userId: %s"
+            log("Returning userId from SETTINGS for username: %s userId: %s"
                 % (username, s_userId), 2)
             return s_userId
         # No userId found
         else:
-            self.logMsg("No userId saved for username: %s." % username, 1)
+            log("No userId saved for username: %s." % username, 1)
 
     def getServer(self, prefix=True):
 
-        settings = utils.settings
-
         alternate = settings('altip') == "true"
         if alternate:
             # Alternate host
@@ -124,7 +117,7 @@ class UserClient(threading.Thread):
         server = host + ":" + port
 
         if not host:
-            self.logMsg("No server information saved.", 2)
+            log("No server information saved.", 2)
             return False
 
         # If https is true
@@ -141,9 +134,6 @@ class UserClient(threading.Thread):
 
     def getToken(self):
 
-        window = utils.window
-        settings = utils.settings
-
         username = self.getUsername()
         userId = self.getUserId()
         w_token = window('emby_accessToken%s' % userId)
@@ -154,23 +144,21 @@ class UserClient(threading.Thread):
             if not s_token:
                 # Save access token if it's missing from settings
                 settings('accessToken', value=w_token)
-            self.logMsg("Returning accessToken from WINDOW for username: %s accessToken: %s"
+                log("Returning accessToken from WINDOW for username: %s accessToken: %s"
                 % (username, w_token), 2)
             return w_token
         # Verify the settings
         elif s_token:
-            self.logMsg("Returning accessToken from SETTINGS for username: %s accessToken: %s"
+            log("Returning accessToken from SETTINGS for username: %s accessToken: %s"
                 % (username, s_token), 2)
             window('emby_accessToken%s' % username, value=s_token)
             return s_token
         else:
-            self.logMsg("No token found.", 1)
+            log("No token found.", 1)
             return ""
 
     def getSSLverify(self):
         # Verify host certificate
-        settings = utils.settings
-
         s_sslverify = settings('sslverify')
         if settings('altip') == "true":
             s_sslverify = settings('secondsslverify')
@@ -182,8 +170,6 @@ class UserClient(threading.Thread):
 
     def getSSL(self):
         # Client side certificate
-        settings = utils.settings
-
         s_cert = settings('sslcert')
         if settings('altip') == "true":
             s_cert = settings('secondsslcert')
@@ -201,16 +187,16 @@ class UserClient(threading.Thread):
         self.userSettings = result
         # Set user image for skin display
         if result.get('PrimaryImageTag'):
-            utils.window('EmbyUserImage', value=artwork.Artwork().getUserArtwork(result['Id'], 'Primary'))
+            window('EmbyUserImage', value=artwork.Artwork().getUserArtwork(result['Id'], 'Primary'))
 
         # Set resume point max
         result = doUtils("{server}/emby/System/Configuration?format=json")
-
-        utils.settings('markPlayed', value=str(result['MaxResumePct']))
+        settings('markPlayed', value=str(result['MaxResumePct']))
 
     def getPublicUsers(self):
         # Get public Users
-        result = self.doUtils.downloadUrl("%s/emby/Users/Public?format=json" % self.getServer(), authenticate=False)
+        url = "%s/emby/Users/Public?format=json" % self.getServer()
+        result = self.doUtils.downloadUrl(url, authenticate=False)
         if result != "":
             return result
         else:
@@ -220,13 +206,11 @@ class UserClient(threading.Thread):
 
     def hasAccess(self):
         # hasAccess is verified in service.py
-        window = utils.window
-
         result = self.doUtils.downloadUrl("{server}/emby/Users?format=json")
 
         if result == False:
             # Access is restricted, set in downloadutils.py via exception
-            self.logMsg("Access is restricted.", 1)
+            log("Access is restricted.", 1)
             self.HasAccess = False
 
         elif window('emby_online') != "true":
@@ -234,15 +218,13 @@ class UserClient(threading.Thread):
             pass
 
         elif window('emby_serverStatus') == "restricted":
-            self.logMsg("Access is granted.", 1)
+            log("Access is granted.", 1)
             self.HasAccess = True
             window('emby_serverStatus', clear=True)
-            xbmcgui.Dialog().notification("Emby for Kodi", utils.language(33007))
+            xbmcgui.Dialog().notification(lang(29999), lang(33007))
 
     def loadCurrUser(self, authenticated=False):
 
-        window = utils.window
-
         doUtils = self.doUtils
         username = self.getUsername()
         userId = self.getUserId()
@@ -290,9 +272,6 @@ class UserClient(threading.Thread):
 
     def authenticate(self):
 
-        lang = utils.language
-        window = utils.window
-        settings = utils.settings
         dialog = xbmcgui.Dialog()
 
         # Get /profile/addon_data
@@ -304,12 +283,12 @@ class UserClient(threading.Thread):
 
         # If there's no settings.xml
         if not hasSettings:
-            self.logMsg("No settings.xml found.", 1)
+            log("No settings.xml found.", 1)
             self.auth = False
             return
         # If no user information
         elif not server or not username:
-            self.logMsg("Missing server information.", 1)
+            log("Missing server information.", 1)
             self.auth = False
             return
         # If there's a token, load the user
@@ -319,9 +298,9 @@ class UserClient(threading.Thread):
             if result is False:
                 pass
             else:
-                self.logMsg("Current user: %s" % self.currUser, 1)
-                self.logMsg("Current userId: %s" % self.currUserId, 1)
-                self.logMsg("Current accessToken: %s" % self.currToken, 2)
+                log("Current user: %s" % self.currUser, 1)
+                log("Current userId: %s" % self.currUserId, 1)
+                log("Current accessToken: %s" % self.currToken, 2)
                 return
 
         ##### AUTHENTICATE USER #####
@@ -341,7 +320,7 @@ class UserClient(threading.Thread):
                         option=xbmcgui.ALPHANUM_HIDE_INPUT)
                     # If password dialog is cancelled
                     if not password:
-                        self.logMsg("No password entered.", 0)
+                        log("No password entered.", 0)
                         window('emby_serverStatus', value="Stop")
                         self.auth = False
                         return
@@ -356,37 +335,38 @@ class UserClient(threading.Thread):
 
         # Authenticate username and password
         data = {'username': username, 'password': sha1}
-        self.logMsg(data, 2)
+        log(data, 2)
 
-        result = self.doUtils.downloadUrl("%s/emby/Users/AuthenticateByName?format=json" % server, postBody=data, action_type="POST", authenticate=False)
+        url = "%s/emby/Users/AuthenticateByName?format=json" % server
+        result = self.doUtils.downloadUrl(url, postBody=data, action_type="POST", authenticate=False)
 
         try:
-            self.logMsg("Auth response: %s" % result, 1)
+            log("Auth response: %s" % result, 1)
             accessToken = result['AccessToken']
 
         except (KeyError, TypeError):
-            self.logMsg("Failed to retrieve the api key.", 1)
+            log("Failed to retrieve the api key.", 1)
             accessToken = None
 
         if accessToken is not None:
             self.currUser = username
-            dialog.notification("Emby for Kodi",
+            dialog.notification(lang(29999),
                                 "%s %s!" % (lang(33000), self.currUser.decode('utf-8')))
             settings('accessToken', value=accessToken)
             settings('userId%s' % username, value=result['User']['Id'])
-            self.logMsg("User Authenticated: %s" % accessToken, 1)
+            log("User Authenticated: %s" % accessToken, 1)
             self.loadCurrUser(authenticated=True)
             window('emby_serverStatus', clear=True)
             self.retry = 0
         else:
-            self.logMsg("User authentication failed.", 1)
+            log("User authentication failed.", 1)
             settings('accessToken', value="")
             settings('userId%s' % username, value="")
             dialog.ok(lang(33001), lang(33009))
 
             # Give two attempts at entering password
             if self.retry == 2:
-                self.logMsg("Too many retries. "
+                log("Too many retries. "
                     "You can retry by resetting attempts in the addon settings.", 1)
                 window('emby_serverStatus', value="Stop")
                 dialog.ok(lang(33001), lang(33010))
@@ -396,23 +376,21 @@ class UserClient(threading.Thread):
 
     def resetClient(self):
 
-        self.logMsg("Reset UserClient authentication.", 1)
+        log("Reset UserClient authentication.", 1)
         if self.currToken is not None:
             # In case of 401, removed saved token
-            utils.settings('accessToken', value="")
-            utils.window('emby_accessToken%s' % self.getUserId(), clear=True)
+            settings('accessToken', value="")
+            window('emby_accessToken%s' % self.getUserId(), clear=True)
             self.currToken = None
-            self.logMsg("User token has been removed.", 1)
+            log("User token has been removed.", 1)
 
         self.auth = True
         self.currUser = None
 
     def run(self):
 
-        window = utils.window
-
         monitor = xbmc.Monitor()
-        self.logMsg("----===## Starting UserClient ##===----", 0)
+        log("----===## Starting UserClient ##===----", 0)
 
         while not monitor.abortRequested():
 
@@ -447,8 +425,8 @@ class UserClient(threading.Thread):
                 # The status Stop is for when user cancelled password dialog.
                 if server and username and status != "Stop":
                     # Only if there's information found to login
-                    self.logMsg("Server found: %s" % server, 2)
-                    self.logMsg("Username found: %s" % username, 2)
+                    log("Server found: %s" % server, 2)
+                    log("Username found: %s" % username, 2)
                     self.auth = True
 
 
@@ -461,7 +439,7 @@ class UserClient(threading.Thread):
                 break
 
         self.doUtils.stopSession()
-        self.logMsg("##===---- UserClient Stopped ----===##", 0)
+        log("##===---- UserClient Stopped ----===##", 0)
 
     def stopClient(self):
         # When emby for kodi terminates
diff --git a/resources/lib/utils.py b/resources/lib/utils.py
index 40b711c3..74f216a7 100644
--- a/resources/lib/utils.py
+++ b/resources/lib/utils.py
@@ -9,10 +9,10 @@ import pstats
 import sqlite3
 import StringIO
 import os
-from datetime import datetime, time
 import time
 import unicodedata
 import xml.etree.ElementTree as etree
+from datetime import datetime, time
 
 import xbmc
 import xbmcaddon
@@ -20,66 +20,82 @@ import xbmcgui
 import xbmcvfs
 
 #################################################################################################
+# Main methods
+
+class Logging():
+
+    LOGGINGCLASS = None
 
 
-def logMsg(title, msg, level=1):
+    def __init__(self, classname=""):
 
-    # Get the logLevel set in UserClient
-    try:
-        logLevel = int(window('emby_logLevel'))
-    except ValueError:
-        logLevel = 0
+        self.LOGGINGCLASS = classname
 
-    if logLevel >= level:
+    def log(self, msg, level=1):
 
-        if logLevel == 2: # inspect.stack() is expensive
-            try:
-                xbmc.log("%s -> %s : %s" % (title, inspect.stack()[1][3], msg))
-            except UnicodeEncodeError:
-                xbmc.log("%s -> %s : %s" % (title, inspect.stack()[1][3], msg.encode('utf-8')))
-        else:
-            try:
-                xbmc.log("%s -> %s" % (title, msg))
-            except UnicodeEncodeError:
-                xbmc.log("%s -> %s" % (title, msg.encode('utf-8')))
+        self.logMsg("EMBY %s" % self.LOGGINGCLASS, msg, level)
 
-def window(property, value=None, clear=False, windowid=10000):
+    def logMsg(self, 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))
+                except UnicodeEncodeError:
+                    xbmc.log("%s -> %s : %s" % (title, inspect.stack()[1][3], msg.encode('utf-8')))
+            else:
+                try:
+                    xbmc.log("%s -> %s" % (title, msg))
+                except UnicodeEncodeError:
+                    xbmc.log("%s -> %s" % (title, msg.encode('utf-8')))
+
+# Initiate class for utils.py document logging
+log = Logging('Utils').log
+
+
+def window(property, value=None, clear=False, window_id=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")'''
+    WINDOW = xbmcgui.Window(window_id)
 
     if clear:
         WINDOW.clearProperty(property)
     elif value is not None:
         WINDOW.setProperty(property, value)
-    else: #getproperty returns string so convert to unicode
-        return WINDOW.getProperty(property)#.decode("utf-8")
+    else:
+        return WINDOW.getProperty(property)
 
 def settings(setting, value=None):
     # Get or add addon setting
+    addon = xbmcaddon.Addon(id='plugin.video.emby')
+    
     if value is not None:
-        xbmcaddon.Addon(id='plugin.video.emby').setSetting(setting, value)
-    else:
-        return xbmcaddon.Addon(id='plugin.video.emby').getSetting(setting) #returns unicode object
+        addon.setSetting(setting, value)
+    else: # returns unicode object
+        return addon.getSetting(setting) 
 
-def language(stringid):
-    # Central string retrieval
-    string = xbmcaddon.Addon(id='plugin.video.emby').getLocalizedString(stringid) #returns unicode object
+def language(string_id):
+    # Central string retrieval - unicode
+    string = xbmcaddon.Addon(id='plugin.video.emby').getLocalizedString(string_id) 
     return string
 
+#################################################################################################
+# Database related methods
+
 def kodiSQL(media_type="video"):
 
     if media_type == "emby":
         dbPath = xbmc.translatePath("special://database/emby.db").decode('utf-8')
-    elif media_type == "music":
-        dbPath = getKodiMusicDBPath()
     elif media_type == "texture":
         dbPath = xbmc.translatePath("special://database/Textures13.db").decode('utf-8')
+    elif media_type == "music":
+        dbPath = getKodiMusicDBPath()
     else:
         dbPath = getKodiVideoDBPath()
 
@@ -98,8 +114,8 @@ def getKodiVideoDBPath():
     }
 
     dbPath = xbmc.translatePath(
-                    "special://database/MyVideos%s.db"
-                    % dbVersion.get(xbmc.getInfoLabel('System.BuildVersion')[:2], "")).decode('utf-8')
+                "special://database/MyVideos%s.db"
+                % dbVersion.get(xbmc.getInfoLabel('System.BuildVersion')[:2], "")).decode('utf-8')
     return dbPath
 
 def getKodiMusicDBPath():
@@ -114,10 +130,13 @@ def getKodiMusicDBPath():
     }
 
     dbPath = xbmc.translatePath(
-                    "special://database/MyMusic%s.db"
-                    % dbVersion.get(xbmc.getInfoLabel('System.BuildVersion')[:2], "")).decode('utf-8')
+                "special://database/MyMusic%s.db"
+                % dbVersion.get(xbmc.getInfoLabel('System.BuildVersion')[:2], "")).decode('utf-8')
     return dbPath
 
+#################################################################################################
+# Utility methods
+
 def getScreensaver():
     # Get the current screensaver value
     query = {
@@ -145,141 +164,10 @@ def setScreensaver(value):
             'value': value
         }
     }
-    logMsg("EMBY", "Toggling screensaver: %s %s" % (value, xbmc.executeJSONRPC(json.dumps(query))), 1)
+    result = xbmc.executeJSONRPC(json.dumps(query))
+    log("Toggling screensaver: %s %s" % (value, result), 1)
 
-def reset():
-
-    dialog = xbmcgui.Dialog()
-
-    if dialog.yesno("Warning", "Are you sure you want to reset your local Kodi database?") == 0:
-        return
-
-    # first stop any db sync
-    window('emby_shouldStop', value="true")
-    count = 10
-    while window('emby_dbScan') == "true":
-        logMsg("EMBY", "Sync is running, will retry: %s..." % count)
-        count -= 1
-        if count == 0:
-            dialog.ok("Warning", "Could not stop the database from running. Try again.")
-            return
-        xbmc.sleep(1000)
-
-    # Clean up the playlists
-    deletePlaylists()
-
-    # Clean up the video nodes
-    deleteNodes()
-
-    # Wipe the kodi databases
-    logMsg("EMBY", "Resetting the Kodi video database.", 0)
-    connection = kodiSQL('video')
-    cursor = connection.cursor()
-    cursor.execute('SELECT tbl_name FROM sqlite_master WHERE type="table"')
-    rows = cursor.fetchall()
-    for row in rows:
-        tablename = row[0]
-        if tablename != "version":
-            cursor.execute("DELETE FROM " + tablename)
-    connection.commit()
-    cursor.close()
-
-    if settings('enableMusic') == "true":
-        logMsg("EMBY", "Resetting the Kodi music database.")
-        connection = kodiSQL('music')
-        cursor = connection.cursor()
-        cursor.execute('SELECT tbl_name FROM sqlite_master WHERE type="table"')
-        rows = cursor.fetchall()
-        for row in rows:
-            tablename = row[0]
-            if tablename != "version":
-                cursor.execute("DELETE FROM " + tablename)
-        connection.commit()
-        cursor.close()
-
-    # Wipe the emby database
-    logMsg("EMBY", "Resetting the Emby database.", 0)
-    connection = kodiSQL('emby')
-    cursor = connection.cursor()
-    cursor.execute('SELECT tbl_name FROM sqlite_master WHERE type="table"')
-    rows = cursor.fetchall()
-    for row in rows:
-        tablename = row[0]
-        if tablename != "version":
-            cursor.execute("DELETE FROM " + tablename)
-    cursor.execute('DROP table IF EXISTS emby')
-    cursor.execute('DROP table IF EXISTS view')
-    connection.commit()
-    cursor.close()
-
-    # Offer to wipe cached thumbnails
-    resp = dialog.yesno("Warning", "Remove all cached artwork?")
-    if resp:
-        logMsg("EMBY", "Resetting all cached artwork.", 0)
-        # 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
-        connection = kodiSQL('texture')
-        cursor = connection.cursor()
-        cursor.execute('SELECT tbl_name FROM sqlite_master WHERE type="table"')
-        rows = cursor.fetchall()
-        for row in rows:
-            tableName = row[0]
-            if(tableName != "version"):
-                cursor.execute("DELETE FROM " + tableName)
-        connection.commit()
-        cursor.close()
-
-    # reset the install run flag
-    settings('SyncInstallRunDone', value="false")
-
-    # Remove emby info
-    resp = dialog.yesno("Warning", "Reset all Emby Addon settings?")
-    if resp:
-        # Delete the settings
-        addon = xbmcaddon.Addon()
-        addondir = xbmc.translatePath(addon.getAddonInfo('profile')).decode('utf-8')
-        dataPath = "%ssettings.xml" % addondir
-        xbmcvfs.delete(dataPath)
-        logMsg("EMBY", "Deleting: settings.xml", 1)
-
-    dialog.ok(
-        heading="Emby for Kodi",
-        line1="Database reset has completed, Kodi will now restart to apply the changes.")
-    xbmc.executebuiltin('RestartApp')
-
-def profiling(sortby="cumulative"):
-    # Will print results to Kodi log
-    def decorator(func):
-        def wrapper(*args, **kwargs):
-
-            pr = cProfile.Profile()
-
-            pr.enable()
-            result = func(*args, **kwargs)
-            pr.disable()
-
-            s = StringIO.StringIO()
-            ps = pstats.Stats(pr, stream=s).sort_stats(sortby)
-            ps.print_stats()
-            logMsg("EMBY Profiling", s.getvalue(), 1)
-
-            return result
-
-        return wrapper
-    return decorator
-
-def convertdate(date):
+def convertDate(date):
     try:
         date = datetime.strptime(date, "%Y-%m-%dT%H:%M:%SZ")
     except TypeError:
@@ -344,6 +232,139 @@ def indent(elem, level=0):
         if level and (not elem.tail or not elem.tail.strip()):
           elem.tail = i
 
+def profiling(sortby="cumulative"):
+    # Will print results to Kodi log
+    def decorator(func):
+        def wrapper(*args, **kwargs):
+
+            pr = cProfile.Profile()
+
+            pr.enable()
+            result = func(*args, **kwargs)
+            pr.disable()
+
+            s = StringIO.StringIO()
+            ps = pstats.Stats(pr, stream=s).sort_stats(sortby)
+            ps.print_stats()
+            log(s.getvalue(), 1)
+
+            return result
+
+        return wrapper
+    return decorator
+
+#################################################################################################
+# Addon utilities
+
+def reset():
+
+    dialog = xbmcgui.Dialog()
+
+    if not dialog.yesno(language(29999), language(33074)):
+        return
+
+    # first stop any db sync
+    window('emby_shouldStop', value="true")
+    count = 10
+    while window('emby_dbScan') == "true":
+        log("Sync is running, will retry: %s..." % count)
+        count -= 1
+        if count == 0:
+            dialog.ok(language(29999), language(33085))
+            return
+        xbmc.sleep(1000)
+
+    # Clean up the playlists
+    deletePlaylists()
+
+    # Clean up the video nodes
+    deleteNodes()
+
+    # Wipe the kodi databases
+    log("Resetting the Kodi video database.", 0)
+    connection = kodiSQL('video')
+    cursor = connection.cursor()
+    cursor.execute('SELECT tbl_name FROM sqlite_master WHERE type="table"')
+    rows = cursor.fetchall()
+    for row in rows:
+        tablename = row[0]
+        if tablename != "version":
+            cursor.execute("DELETE FROM " + tablename)
+    connection.commit()
+    cursor.close()
+
+    if settings('enableMusic') == "true":
+        log("Resetting the Kodi music database.", 0)
+        connection = kodiSQL('music')
+        cursor = connection.cursor()
+        cursor.execute('SELECT tbl_name FROM sqlite_master WHERE type="table"')
+        rows = cursor.fetchall()
+        for row in rows:
+            tablename = row[0]
+            if tablename != "version":
+                cursor.execute("DELETE FROM " + tablename)
+        connection.commit()
+        cursor.close()
+
+    # Wipe the emby database
+    log("Resetting the Emby database.", 0)
+    connection = kodiSQL('emby')
+    cursor = connection.cursor()
+    cursor.execute('SELECT tbl_name FROM sqlite_master WHERE type="table"')
+    rows = cursor.fetchall()
+    for row in rows:
+        tablename = row[0]
+        if tablename != "version":
+            cursor.execute("DELETE FROM " + tablename)
+    cursor.execute('DROP table IF EXISTS emby')
+    cursor.execute('DROP table IF EXISTS view')
+    connection.commit()
+    cursor.close()
+
+    # Offer to wipe cached thumbnails
+    resp = dialog.yesno(language(29999), language(33086))
+    if resp:
+        log("Resetting all cached artwork.", 0)
+        # 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
+        connection = kodiSQL('texture')
+        cursor = connection.cursor()
+        cursor.execute('SELECT tbl_name FROM sqlite_master WHERE type="table"')
+        rows = cursor.fetchall()
+        for row in rows:
+            tableName = row[0]
+            if(tableName != "version"):
+                cursor.execute("DELETE FROM " + tableName)
+        connection.commit()
+        cursor.close()
+
+    # reset the install run flag
+    settings('SyncInstallRunDone', value="false")
+
+    # Remove emby info
+    resp = dialog.yesno(language(29999), language(33087))
+    if resp:
+        # Delete the settings
+        addon = xbmcaddon.Addon()
+        addondir = xbmc.translatePath(addon.getAddonInfo('profile')).decode('utf-8')
+        dataPath = "%ssettings.xml" % addondir
+        xbmcvfs.delete(dataPath)
+        log("Deleting: settings.xml", 1)
+
+    dialog.ok(heading=language(29999), line1=language(33088))
+    xbmc.executebuiltin('RestartApp')
+
 def sourcesXML():
     # To make Master lock compatible
     path = xbmc.translatePath("special://profile/").decode('utf-8')
@@ -401,7 +422,7 @@ def passwordsXML():
     credentials = settings('networkCreds')
     if credentials:
         # Present user with options
-        option = dialog.select("Modify/Remove network credentials", ["Modify", "Remove"])
+        option = dialog.select(language(33075), [language(33076), language(33077)])
 
         if option < 0:
             # User cancelled dialog
@@ -413,17 +434,16 @@ def passwordsXML():
                 for path in paths:
                     if path.find('.//from').text == "smb://%s/" % credentials:
                         paths.remove(path)
-                        logMsg("EMBY", "Successfully removed credentials for: %s"
-                                % credentials, 1)
+                        log("Successfully removed credentials for: %s" % credentials, 1)
                         etree.ElementTree(root).write(xmlpath)
                         break
             else:
-                logMsg("EMBY", "Failed to find saved server: %s in passwords.xml" % credentials, 1)
+                log("Failed to find saved server: %s in passwords.xml" % credentials, 1)
 
             settings('networkCreds', value="")
             xbmcgui.Dialog().notification(
-                                heading="Emby for Kodi",
-                                message="%s removed from passwords.xml" % credentials,
+                                heading=language(29999),
+                                message="%s %s" % (language(33078), credentials),
                                 icon="special://home/addons/plugin.video.emby/icon.png",
                                 time=1000,
                                 sound=False)
@@ -431,28 +451,22 @@ def passwordsXML():
 
         elif option == 0:
             # User selected to modify
-            server = dialog.input("Modify the computer name or ip address", credentials)
+            server = dialog.input(language(33083), credentials)
             if not server:
                 return
     else:
         # No credentials added
-        dialog.ok(
-            heading="Network credentials",
-            line1= (
-                "Input the server name or IP address as indicated in your emby library paths. "
-                'For example, the server name: \\\\SERVER-PC\\path\\ is "SERVER-PC".'))
-        server = dialog.input("Enter the server name or IP address")
+        dialog.ok(heading=language(29999), line1=language(33082))
+        server = dialog.input(language(33084))
         if not server:
             return
 
     # Network username
-    user = dialog.input("Enter the network username")
+    user = dialog.input(language(33079))
     if not user:
         return
     # Network password
-    password = dialog.input(
-                        heading="Enter the network password",
-                        option=xbmcgui.ALPHANUM_HIDE_INPUT)
+    password = dialog.input(heading=language(33080), option=xbmcgui.ALPHANUM_HIDE_INPUT)
     if not password:
         return
 
@@ -473,7 +487,7 @@ def passwordsXML():
 
     # Add credentials
     settings('networkCreds', value="%s" % server)
-    logMsg("EMBY", "Added server: %s to passwords.xml" % server, 1)
+    log("Added server: %s to passwords.xml" % server, 1)
     # Prettify and write to file
     try:
         indent(root)
@@ -481,8 +495,8 @@ def passwordsXML():
     etree.ElementTree(root).write(xmlpath)
 
     dialog.notification(
-            heading="Emby for Kodi",
-            message="%s added to passwords.xml" % server,
+            heading=language(29999),
+            message="%s %s" % (language(33081), server),
             icon="special://home/addons/plugin.video.emby/icon.png",
             time=1000,
             sound=False)
@@ -501,7 +515,7 @@ def playlistXSP(mediatype, tagname, viewid, viewtype="", delete=False):
 
     # Create the playlist directory
     if not xbmcvfs.exists(path):
-        logMsg("EMBY", "Creating directory: %s" % path, 1)
+        log("Creating directory: %s" % path, 1)
         xbmcvfs.mkdirs(path)
 
     # Only add the playlist if it doesn't already exists
@@ -509,7 +523,7 @@ def playlistXSP(mediatype, tagname, viewid, viewtype="", delete=False):
 
         if delete:
             xbmcvfs.delete(xsppath)
-            logMsg("EMBY", "Successfully removed playlist: %s." % tagname, 1)
+            log("Successfully removed playlist: %s." % tagname, 1)
 
         return
 
@@ -517,11 +531,11 @@ def playlistXSP(mediatype, tagname, viewid, viewtype="", delete=False):
     itemtypes = {
         'homevideos': "movies"
     }
-    logMsg("EMBY", "Writing playlist file to: %s" % xsppath, 1)
+    log("Writing playlist file to: %s" % xsppath, 1)
     try:
         f = xbmcvfs.File(xsppath, 'w')
     except:
-        logMsg("EMBY", "Failed to create playlist: %s" % xsppath, 1)
+        log("Failed to create playlist: %s" % xsppath, 1)
         return
     else:
         f.write(
@@ -535,7 +549,7 @@ def playlistXSP(mediatype, tagname, viewid, viewtype="", delete=False):
             '</smartplaylist>'
             % (itemtypes.get(mediatype, mediatype), plname, tagname))
         f.close()
-    logMsg("EMBY", "Successfully added playlist: %s" % tagname)
+    log("Successfully added playlist: %s" % tagname, 1)
 
 def deletePlaylists():
 
@@ -557,10 +571,10 @@ def deleteNodes():
             try:
                 shutil.rmtree("%s%s" % (path, dir.decode('utf-8')))
             except:
-                logMsg("EMBY", "Failed to delete directory: %s" % dir.decode('utf-8'))
+                log("Failed to delete directory: %s" % dir.decode('utf-8'), 0)
     for file in files:
         if file.decode('utf-8').startswith('emby'):
             try:
                 xbmcvfs.delete("%s%s" % (path, file.decode('utf-8')))
             except:
-                logMsg("EMBY", "Failed to file: %s" % file.decode('utf-8'))
+                log("Failed to file: %s" % file.decode('utf-8'), 0)
\ No newline at end of file
diff --git a/resources/lib/videonodes.py b/resources/lib/videonodes.py
index f7f63c3c..bf1d20f4 100644
--- a/resources/lib/videonodes.py
+++ b/resources/lib/videonodes.py
@@ -11,6 +11,7 @@ import xbmcvfs
 
 import clientinfo
 import utils
+from utils import Logging, window, language as lang
 
 #################################################################################################
 
@@ -20,16 +21,14 @@ class VideoNodes(object):
 
     def __init__(self):
 
+        global log
+        log = Logging(self.__class__.__name__).log
+
         clientInfo = clientinfo.ClientInfo()
         self.addonName = clientInfo.getAddonName()
 
         self.kodiversion = int(xbmc.getInfoLabel('System.BuildVersion')[:2])
 
-    def logMsg(self, msg, lvl=1):
-
-        className = self.__class__.__name__
-        utils.logMsg("%s %s" % (self.addonName, className), msg, lvl)
-
 
     def commonRoot(self, order, label, tagname, roottype=1):
 
@@ -54,8 +53,6 @@ class VideoNodes(object):
 
     def viewNode(self, indexnumber, tagname, mediatype, viewtype, viewid, delete=False):
 
-        window = utils.window
-
         if viewtype == "mixed":
             dirname = "%s - %s" % (viewid, mediatype)
         else:
@@ -82,7 +79,7 @@ class VideoNodes(object):
                 for file in files:
                     xbmcvfs.delete(nodepath + file)
 
-                self.logMsg("Sucessfully removed videonode: %s." % tagname, 1)
+                log("Sucessfully removed videonode: %s." % tagname, 1)
                 return
 
         # Create index entry
@@ -184,7 +181,7 @@ class VideoNodes(object):
             # Get label
             stringid = nodes[node]
             if node != "1":
-                label = utils.language(stringid)
+                label = lang(stringid)
                 if not label:
                     label = xbmc.getLocalizedString(stringid)
             else:
@@ -319,8 +316,6 @@ class VideoNodes(object):
 
     def singleNode(self, indexnumber, tagname, mediatype, itemtype):
 
-        window = utils.window
-
         tagname = tagname.encode('utf-8')
         cleantagname = utils.normalize_nodes(tagname)
         nodepath = xbmc.translatePath("special://profile/library/video/").decode('utf-8')
@@ -342,7 +337,7 @@ class VideoNodes(object):
             'Favorite tvshows': 30181,
             'channels': 30173
         }
-        label = utils.language(labels[tagname])
+        label = lang(labels[tagname])
         embynode = "Emby.nodes.%s" % indexnumber
         window('%s.title' % embynode, value=label)
         window('%s.path' % embynode, value=windowpath)
@@ -369,9 +364,7 @@ class VideoNodes(object):
 
     def clearProperties(self):
 
-        window = utils.window
-
-        self.logMsg("Clearing nodes properties.", 1)
+        log("Clearing nodes properties.", 1)
         embyprops = window('Emby.nodes.total')
         propnames = [
         
diff --git a/resources/lib/websocket_client.py b/resources/lib/websocket_client.py
index 559cb152..87d1e012 100644
--- a/resources/lib/websocket_client.py
+++ b/resources/lib/websocket_client.py
@@ -14,10 +14,7 @@ import downloadutils
 import librarysync
 import playlist
 import userclient
-import utils
-
-import logging
-logging.basicConfig()
+from utils import Logging, window, settings, language as lang
 
 #################################################################################################
 
@@ -32,6 +29,9 @@ class WebSocket_Client(threading.Thread):
 
     def __init__(self):
 
+        global log
+        log = Logging(self.__class__.__name__).log
+
         self.__dict__ = self._shared_state
         self.monitor = xbmc.Monitor()
         
@@ -43,15 +43,10 @@ class WebSocket_Client(threading.Thread):
         
         threading.Thread.__init__(self)
 
-    def logMsg(self, msg, lvl=1):
-
-        self.className = self.__class__.__name__
-        utils.logMsg("%s %s" % (self.addonName, self.className), msg, lvl)
-
 
     def sendProgressUpdate(self, data):
         
-        self.logMsg("sendProgressUpdate", 2)
+        log("sendProgressUpdate", 2)
         try:
             messageData = {
 
@@ -60,23 +55,21 @@ class WebSocket_Client(threading.Thread):
             }
             messageString = json.dumps(messageData)
             self.client.send(messageString)
-            self.logMsg("Message data: %s" % messageString, 2)
+            log("Message data: %s" % messageString, 2)
 
         except Exception as e:
-            self.logMsg("Exception: %s" % e, 1)
+            log("Exception: %s" % e, 1)
 
     def on_message(self, ws, message):
-        
-        window = utils.window
-        lang = utils.language
 
         result = json.loads(message)
         messageType = result['MessageType']
         data = result['Data']
+        dialog = xbmcgui.Dialog()
 
         if messageType not in ('SessionEnded'):
             # Mute certain events
-            self.logMsg("Message: %s" % message, 1)
+            log("Message: %s" % message, 1)
 
         if messageType == "Play":
             # A remote control play command has been sent from the server.
@@ -84,11 +77,10 @@ class WebSocket_Client(threading.Thread):
             command = data['PlayCommand']
 
             pl = playlist.Playlist()
-            dialog = xbmcgui.Dialog()
 
             if command == "PlayNow":
                 dialog.notification(
-                        heading="Emby for Kodi",
+                        heading=lang(29999),
                         message="%s %s" % (len(itemIds), lang(33004)),
                         icon="special://home/addons/plugin.video.emby/icon.png",
                         sound=False)
@@ -97,7 +89,7 @@ class WebSocket_Client(threading.Thread):
 
             elif command == "PlayNext":
                 dialog.notification(
-                        heading="Emby for Kodi",
+                        heading=lang(29999),
                         message="%s %s" % (len(itemIds), lang(33005)),
                         icon="special://home/addons/plugin.video.emby/icon.png",
                         sound=False)
@@ -126,10 +118,10 @@ class WebSocket_Client(threading.Thread):
                 seekto = data['SeekPositionTicks']
                 seektime = seekto / 10000000.0
                 action(seektime)
-                self.logMsg("Seek to %s." % seektime, 1)
+                log("Seek to %s." % seektime, 1)
             else:
                 action()
-                self.logMsg("Command: %s completed." % command, 1)
+                log("Command: %s completed." % command, 1)
 
             window('emby_command', value="true")
 
@@ -199,11 +191,11 @@ class WebSocket_Client(threading.Thread):
                 
                 header = arguments['Header']
                 text = arguments['Text']
-                xbmcgui.Dialog().notification(
-                                    heading=header,
-                                    message=text,
-                                    icon="special://home/addons/plugin.video.emby/icon.png",
-                                    time=4000)
+                dialog.notification(
+                            heading=header,
+                            message=text,
+                            icon="special://home/addons/plugin.video.emby/icon.png",
+                            time=4000)
 
             elif command == "SendString":
                 
@@ -250,11 +242,11 @@ class WebSocket_Client(threading.Thread):
                     xbmc.executebuiltin(action)
 
         elif messageType == "ServerRestarting":
-            if utils.settings('supressRestartMsg') == "true":
-                xbmcgui.Dialog().notification(
-                                    heading="Emby for Kodi",
-                                    message=lang(33006),
-                                    icon="special://home/addons/plugin.video.emby/icon.png")
+            if settings('supressRestartMsg') == "true":
+                dialog.notification(
+                            heading=lang(29999),
+                            message=lang(33006),
+                            icon="special://home/addons/plugin.video.emby/icon.png")
 
         elif messageType == "UserConfigurationUpdated":
             # Update user data set in userclient
@@ -262,7 +254,7 @@ class WebSocket_Client(threading.Thread):
             self.librarySync.refresh_views = True
 
     def on_close(self, ws):
-        self.logMsg("Closed.", 2)
+        log("Closed.", 2)
 
     def on_open(self, ws):
         self.doUtils.postCapabilities(self.deviceId)
@@ -272,11 +264,10 @@ class WebSocket_Client(threading.Thread):
             # Server is offline
             pass
         else:
-            self.logMsg("Error: %s" % error, 2)
+            log("Error: %s" % error, 2)
 
     def run(self):
 
-        window = utils.window
         loglevel = int(window('emby_logLevel'))
         # websocket.enableTrace(True)
 
@@ -290,7 +281,7 @@ class WebSocket_Client(threading.Thread):
             server = server.replace('http', "ws")
 
         websocket_url = "%s?api_key=%s&deviceId=%s" % (server, token, self.deviceId)
-        self.logMsg("websocket url: %s" % websocket_url, 1)
+        log("websocket url: %s" % websocket_url, 1)
 
         self.client = websocket.WebSocketApp(websocket_url,
                                     on_message=self.on_message,
@@ -298,7 +289,7 @@ class WebSocket_Client(threading.Thread):
                                     on_close=self.on_close)
         
         self.client.on_open = self.on_open
-        self.logMsg("----===## Starting WebSocketClient ##===----", 0)
+        log("----===## Starting WebSocketClient ##===----", 0)
 
         while not self.monitor.abortRequested():
 
@@ -310,10 +301,10 @@ class WebSocket_Client(threading.Thread):
                 # Abort was requested, exit
                 break
 
-        self.logMsg("##===---- WebSocketClient Stopped ----===##", 0)
+        log("##===---- WebSocketClient Stopped ----===##", 0)
 
     def stopClient(self):
 
         self.stopWebsocket = True
         self.client.close()
-        self.logMsg("Stopping thread.", 1)
\ No newline at end of file
+        log("Stopping thread.", 1)
\ No newline at end of file
diff --git a/resources/settings.xml b/resources/settings.xml
index 77d57a33..7ca31f61 100644
--- a/resources/settings.xml
+++ b/resources/settings.xml
@@ -33,7 +33,7 @@
         <setting id="imageCacheLimit" type="enum" label="30513" values="Disabled|5|10|15|20|25" default="0" visible="eq(-1,true)" subsetting="true" />
 		<setting id="syncEmptyShows" type="bool" label="30508" default="false" />
 		<setting id="dbSyncScreensaver" label="30536" type="bool" default="false" />
-		<setting id="useDirectPaths" type="enum" label="30511" values="Addon(Default)|Native(Direct paths)" default="0" />
+		<setting id="useDirectPaths" type="enum" label="30511" lvalues="33036|33037" default="0" />
 		<setting id="enableMusic" type="bool" label="30509" default="true" />
 		<setting id="streamMusic" type="bool" label="30510" default="false" visible="eq(-1,true)" subsetting="true" />
 		<setting type="lsep" label="30523" />
diff --git a/service.py b/service.py
index b54a4a7c..311e00a9 100644
--- a/service.py
+++ b/service.py
@@ -16,9 +16,9 @@ import xbmcvfs
 #################################################################################################
 
 _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)
+_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)
 
 #################################################################################################
 
@@ -28,9 +28,9 @@ import initialsetup
 import kodimonitor
 import librarysync
 import player
-import utils
 import videonodes
 import websocket_client as wsc
+from utils import Logging, window, settings, language as lang
 
 #################################################################################################
 
@@ -49,8 +49,8 @@ class Service():
 
     def __init__(self):
 
-        log = self.logMsg
-        window = utils.window
+        global log
+        log = Logging(self.__class__.__name__).log
 
         self.clientInfo = clientinfo.ClientInfo()
         self.addonName = self.clientInfo.getAddonName()
@@ -58,15 +58,14 @@ class Service():
         self.monitor = xbmc.Monitor()
 
         window('emby_logLevel', value=str(logLevel))
-        window('emby_kodiProfile', value=xbmc.translatePath("special://profile"))
-        window('emby_pluginpath', value=utils.settings('useDirectPaths'))
+        window('emby_kodiProfile', value=xbmc.translatePath('special://profile'))
 
         # Initial logging
         log("======== START %s ========" % self.addonName, 0)
         log("Platform: %s" % (self.clientInfo.getPlatform()), 0)
         log("KODI Version: %s" % xbmc.getInfoLabel('System.BuildVersion'), 0)
         log("%s Version: %s" % (self.addonName, self.clientInfo.getVersion()), 0)
-        log("Using plugin paths: %s" % (utils.settings('useDirectPaths') != "true"), 0)
+        log("Using plugin paths: %s" % (settings('useDirectPaths') == "0"), 0)
         log("Log Level: %s" % logLevel, 0)
 
         # Reset window props for profile switch
@@ -86,22 +85,13 @@ class Service():
         # Set the minimum database version
         window('emby_minDBVersion', value="1.1.63")
 
-    def logMsg(self, msg, lvl=1):
-
-        className = self.__class__.__name__
-        utils.logMsg("%s %s" % (self.addonName, className), msg, lvl)
-
        
     def ServiceEntryPoint(self):
 
-        log = self.logMsg
-        window = utils.window
-        lang = utils.language
-
         # Important: Threads depending on abortRequest will not trigger
         # if profile switch happens more than once.
         monitor = self.monitor
-        kodiProfile = xbmc.translatePath("special://profile")
+        kodiProfile = xbmc.translatePath('special://profile')
 
         # Server auto-detect
         initialsetup.InitialSetup().setup()
@@ -119,7 +109,7 @@ class Service():
             if window('emby_kodiProfile') != kodiProfile:
                 # Profile change happened, terminate this thread and others
                 log("Kodi profile was: %s and changed to: %s. Terminating old Emby thread."
-                    % (kodiProfile, utils.window('emby_kodiProfile')), 1)
+                    % (kodiProfile, window('emby_kodiProfile')), 1)
                 
                 break
             
@@ -167,7 +157,7 @@ class Service():
                     else:
                         # Start up events
                         self.warn_auth = True
-                        if utils.settings('connectMsg') == "true" and self.welcome_msg:
+                        if settings('connectMsg') == "true" and self.welcome_msg:
                             # Reset authentication warnings
                             self.welcome_msg = False
                             # Get additional users
@@ -177,7 +167,7 @@ class Service():
                             else:
                                 add = ""
                             xbmcgui.Dialog().notification(
-                                        heading="Emby for Kodi",
+                                        heading=lang(29999),
                                         message=("%s %s%s!"
                                                 % (lang(33000), user.currUser.decode('utf-8'),
                                                     add.decode('utf-8'))),
@@ -252,7 +242,7 @@ class Service():
                                 break
                             # Alert the user that server is online.
                             xbmcgui.Dialog().notification(
-                                        heading="Emby for Kodi",
+                                        heading=lang(29999),
                                         message=lang(33003),
                                         icon="special://home/addons/plugin.video.emby/icon.png",
                                         time=2000,
@@ -291,7 +281,7 @@ class Service():
         log("======== STOP %s ========" % self.addonName, 0)
 
 # Delay option
-delay = int(utils.settings('startupDelay'))
+delay = int(settings('startupDelay'))
 
 xbmc.log("Delaying emby startup by: %s sec..." % delay)
 if delay and xbmc.Monitor().waitForAbort(delay):