diff --git a/resources/lib/itemtypes.py b/resources/lib/itemtypes.py
index 72b660c1..6748debd 100644
--- a/resources/lib/itemtypes.py
+++ b/resources/lib/itemtypes.py
@@ -18,6 +18,7 @@ import embydb_functions as embydb
 import kodidb_functions as kodidb
 import read_embyserver as embyserver
 import musicutils
+from objects import Movies, MusicVideos, TVShows, Music
 from utils import window, settings, language as lang, kodiSQL
 
 #################################################################################################
@@ -61,6 +62,7 @@ class Items(object):
 
             'Movie': Movies,
             'BoxSet': Movies,
+            'MusicVideo': MusicVideos,
             'Series': TVShows,
             'Season': TVShows,
             'Episode': TVShows,
@@ -101,102 +103,28 @@ class Items(object):
                 if music_enabled:
                     musicconn = kodiSQL('music')
                     musiccursor = musicconn.cursor()
-                    items_process = itemtypes[itemtype](embycursor, musiccursor)
+                    items_process = itemtypes[itemtype](embycursor, musiccursor, pdialog)
                 else:
                     # Music is not enabled, do not proceed with itemtype
                     continue
             else:
                 update_videolibrary = True
-                items_process = itemtypes[itemtype](embycursor, kodicursor)
+                items_process = itemtypes[itemtype](embycursor, kodicursor, pdialog)
 
-            if itemtype == "Movie":
-                actions = {
-                    'added': items_process.added,
-                    'update': items_process.add_update,
-                    'userdata': items_process.updateUserdata,
-                    'remove': items_process.remove
-                }
-            elif itemtype == "BoxSet":
-                actions = {
-                    'added': items_process.added_boxset,
-                    'update': items_process.add_updateBoxset,
-                    'remove': items_process.remove
-                }
-            elif itemtype == "MusicVideo":
-                actions = {
-                    'added': items_process.added,
-                    'update': items_process.add_update,
-                    'userdata': items_process.updateUserdata,
-                    'remove': items_process.remove
-                }
-            elif itemtype == "Series":
-                actions = {
-                    'added': items_process.added,
-                    'update': items_process.add_update,
-                    'userdata': items_process.updateUserdata,
-                    'remove': items_process.remove
-                }
-            elif itemtype == "Season":
-                actions = {
-                    'added': items_process.added_season,
-                    'update': items_process.add_updateSeason,
-                    'remove': items_process.remove
-                }
-            elif itemtype == "Episode":
-                actions = {
-                    'added': items_process.added_episode,
-                    'update': items_process.add_updateEpisode,
-                    'userdata': items_process.updateUserdata,
-                    'remove': items_process.remove
-                }
-            elif itemtype == "MusicAlbum":
-                actions = {
-                    'added': items_process.added_album,
-                    'update': items_process.add_updateAlbum,
-                    'userdata': items_process.updateUserdata,
-                    'remove': items_process.remove
-                }
-            elif itemtype in ("MusicArtist", "AlbumArtist"):
-                actions = {
-                    'added': items_process.added,
-                    'update': items_process.add_updateArtist,
-                    'remove': items_process.remove
-                }
-            elif itemtype == "Audio":
-                actions = {
-                    'added': items_process.added_song,
-                    'update': items_process.add_updateSong,
-                    'userdata': items_process.updateUserdata,
-                    'remove': items_process.remove
-                }
-            else:
-                log.info("Unsupported itemtype: %s." % itemtype)
-                actions = {}
+            '''
 
             if actions.get(process):
 
-                if process == "remove":
-                    for item in itemlist:
-                        actions[process](item)
+            if process == "remove":
+                for item in itemlist:
+                    actions[process](item)'''
 
-                elif process == "added":
-                    actions[process](itemlist, pdialog)
-            
-                else:
-                    processItems = emby.getFullItems(itemlist)
-                    for item in processItems:
-
-                        title = item['Name']
-
-                        if itemtype == "Episode":
-                            title = "%s - %s" % (item.get('SeriesName', "Unknown"), title)
-
-                        if pdialog:
-                            percentage = int((float(count) / float(total))*100)
-                            pdialog.update(percentage, message=title)
-                            count += 1
-
-                        actions[process](item)
+            if process == "added":
+                processItems = itemlist
+                items_process.add_all(itemtype, itemlist)
+            else:
+                processItems = emby.getFullItems(itemlist)
+                items_process.process_all(itemtype, process, processItems, total)
 
 
             if musicconn is not None:
@@ -205,2266 +133,4 @@ class Items(object):
                 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=lang(29999),
-                    message="%s %s" % (lang(33049), name),
-                    icon="special://home/addons/plugin.video.emby/icon.png",
-                    time=time,
-                    sound=False)
-
-
-class Movies(Items):
-
-    
-    def __init__(self, embycursor, kodicursor):
-        Items.__init__(self, embycursor, kodicursor)
-
-    def added(self, items, pdialog):
-
-        total = len(items)
-        count = 0
-        for movie in items:
-                
-            title = movie['Name']
-            if pdialog:
-                percentage = int((float(count) / float(total))*100)
-                pdialog.update(percentage, message=title)
-                count += 1
-            self.add_update(movie)
-            if not pdialog and self.contentmsg:
-                self.contentPop(title, self.newvideo_time)
-
-    def added_boxset(self, items, pdialog):
-
-        total = len(items)
-        count = 0
-        for boxset in items:
-
-            if pdialog:
-                percentage = int((float(count) / float(total))*100)
-                pdialog.update(percentage, message=boxset['Name'])
-                count += 1
-            self.add_updateBoxset(boxset)
-
-
-    def add_update(self, item, viewtag=None, viewid=None):
-        # Process single movie
-        kodicursor = self.kodicursor
-        emby_db = self.emby_db
-        artwork = self.artwork
-        API = api.API(item)
-
-        # 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
-        update_item = True
-        itemid = item['Id']
-        emby_dbitem = emby_db.getItem_byId(itemid)
-        try:
-            movieid = emby_dbitem[0]
-            fileid = emby_dbitem[1]
-            pathid = emby_dbitem[2]
-            log.info("movieid: %s fileid: %s pathid: %s" % (movieid, fileid, pathid))
-        
-        except TypeError:
-            update_item = False
-            log.debug("movieid: %s not found." % itemid)
-            # movieid
-            kodicursor.execute("select coalesce(max(idMovie),0) from movie")
-            movieid = kodicursor.fetchone()[0] + 1
-
-        else:
-            # Verification the item is still in Kodi
-            query = "SELECT * FROM movie WHERE idMovie = ?"
-            kodicursor.execute(query, (movieid,))
-            try:
-                kodicursor.fetchone()[0]
-            except TypeError:
-                # item is not found, let's recreate it.
-                update_item = False
-                log.info("movieid: %s missing from Kodi, repairing the entry." % movieid)
-
-        if not viewtag or not viewid:
-            # Get view tag from emby
-            viewtag, viewid, mediatype = self.emby.getView_embyId(itemid)
-            log.debug("View tag found: %s" % viewtag)
-
-        # fileId information
-        checksum = API.get_checksum()
-        dateadded = API.get_date_created()
-        userdata = API.get_userdata()
-        playcount = userdata['PlayCount']
-        dateplayed = userdata['LastPlayedDate']
-
-        # item details
-        people = API.get_people()
-        writer = " / ".join(people['Writer'])
-        director = " / ".join(people['Director'])
-        genres = item['Genres']
-        title = item['Name']
-        plot = API.get_overview()
-        shortplot = item.get('ShortOverview')
-        tagline = API.get_tagline()
-        votecount = item.get('VoteCount')
-        rating = item.get('CommunityRating')
-        year = item.get('ProductionYear')
-        imdb = API.get_provider('Imdb')
-        sorttitle = item['SortName']
-        runtime = API.get_runtime()
-        mpaa = API.get_mpaa()
-        genre = " / ".join(genres)
-        country = API.get_country()
-        studios = API.get_studios()
-        try:
-            studio = studios[0]
-        except IndexError:
-            studio = None
-
-        if item.get('LocalTrailerCount'):
-            # There's a local trailer
-            url = (
-                "{server}/emby/Users/{UserId}/Items/%s/LocalTrailers?format=json"
-                % itemid
-            )
-            result = self.doUtils.downloadUrl(url)
-            try:
-                trailer = "plugin://plugin.video.emby/trailer/?id=%s&mode=play" % result[0]['Id']
-            except IndexError:
-                log.info("Failed to process local trailer.")
-                trailer = None
-        else:
-            # Try to get the youtube trailer
-            try:
-                trailer = item['RemoteTrailers'][0]['Url']
-            except (KeyError, IndexError):
-                trailer = None
-            else:    
-                try:
-                    trailerId = trailer.rsplit('=', 1)[1]
-                except IndexError:
-                    log.info("Failed to process trailer: %s" % trailer)
-                    trailer = None
-                else:
-                    trailer = "plugin://plugin.video.youtube/play/?video_id=%s" % trailerId
-
-        
-        ##### GET THE FILE AND PATH #####
-        playurl = API.get_file_path()
-
-        if "\\" in playurl:
-            # Local path
-            filename = playurl.rsplit("\\", 1)[1]
-        else: # Network share
-            filename = playurl.rsplit("/", 1)[1]
-
-        if self.directpath:
-            # Direct paths is set the Kodi way
-            if not self.pathValidation(playurl):
-                return False
-            
-            path = playurl.replace(filename, "")
-            window('emby_pathverified', value="true")
-        else:
-            # Set plugin path and media flags using real filename
-            path = "plugin://plugin.video.emby.movies/"
-            params = {
-
-                'filename': filename.encode('utf-8'),
-                'id': itemid,
-                'dbid': movieid,
-                'mode': "play"
-            }
-            filename = "%s?%s" % (path, urllib.urlencode(params))
-
-
-        ##### UPDATE THE MOVIE #####
-        if update_item:
-            log.info("UPDATE movie itemid: %s - Title: %s" % (itemid, title))
-
-            # Update the movie entry
-            if self.kodiversion > 16:
-                query = ' '.join((
-                    
-                    "UPDATE movie",
-                    "SET c00 = ?, c01 = ?, c02 = ?, c03 = ?, c04 = ?, c05 = ?, c06 = ?,",
-                        "c07 = ?, c09 = ?, c10 = ?, c11 = ?, c12 = ?, c14 = ?, c15 = ?,",
-                        "c16 = ?, c18 = ?, c19 = ?, c21 = ?, premiered = ?",
-                    "WHERE idMovie = ?"
-                ))
-                kodicursor.execute(query, (title, plot, shortplot, tagline, votecount, rating,
-                    writer, year, imdb, sorttitle, runtime, mpaa, genre, director, title, studio,
-                    trailer, country, year, movieid))
-            else:
-                query = ' '.join((
-                    
-                    "UPDATE movie",
-                    "SET c00 = ?, c01 = ?, c02 = ?, c03 = ?, c04 = ?, c05 = ?, c06 = ?,",
-                        "c07 = ?, c09 = ?, c10 = ?, c11 = ?, c12 = ?, c14 = ?, c15 = ?,",
-                        "c16 = ?, c18 = ?, c19 = ?, c21 = ?",
-                    "WHERE idMovie = ?"
-                ))
-                kodicursor.execute(query, (title, plot, shortplot, tagline, votecount, rating,
-                    writer, year, imdb, sorttitle, runtime, mpaa, genre, director, title, studio,
-                    trailer, country, movieid))
-
-            # Update the checksum in emby table
-            emby_db.updateReference(itemid, checksum)
-        
-        ##### OR ADD THE MOVIE #####
-        else:
-            log.info("ADD movie itemid: %s - Title: %s" % (itemid, title))
-            
-            # Add path
-            pathid = self.kodi_db.addPath(path)
-            # Add the file
-            fileid = self.kodi_db.addFile(filename, pathid)
-            
-            # Create the movie entry
-            if self.kodiversion > 16:
-                query = (
-                    '''
-                    INSERT INTO movie(
-                        idMovie, idFile, c00, c01, c02, c03, c04, c05, c06, c07, 
-                        c09, c10, c11, c12, c14, c15, c16, c18, c19, c21, premiered)
-
-                    VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
-                    '''
-                )
-                kodicursor.execute(query, (movieid, fileid, title, plot, shortplot, tagline,
-                    votecount, rating, writer, year, imdb, sorttitle, runtime, mpaa, genre,
-                    director, title, studio, trailer, country, year))
-            else:
-                query = (
-                    '''
-                    INSERT INTO movie(
-                        idMovie, idFile, c00, c01, c02, c03, c04, c05, c06, c07, 
-                        c09, c10, c11, c12, c14, c15, c16, c18, c19, c21)
-
-                    VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
-                    '''
-                )
-                kodicursor.execute(query, (movieid, fileid, title, plot, shortplot, tagline,
-                    votecount, rating, writer, year, imdb, sorttitle, runtime, mpaa, genre,
-                    director, title, studio, trailer, country))
-
-            # Create the reference in emby table
-            emby_db.addReference(itemid, movieid, "Movie", "movie", fileid, pathid, None, checksum, viewid)
-
-        # Update the path
-        query = ' '.join((
-
-            "UPDATE path",
-            "SET strPath = ?, strContent = ?, strScraper = ?, noUpdate = ?",
-            "WHERE idPath = ?"
-        ))
-        kodicursor.execute(query, (path, "movies", "metadata.local", 1, pathid))
-
-        # Update the file
-        query = ' '.join((
-
-            "UPDATE files",
-            "SET idPath = ?, strFilename = ?, dateAdded = ?",
-            "WHERE idFile = ?"
-        ))
-        kodicursor.execute(query, (pathid, filename, dateadded, fileid))
-        
-        # Process countries
-        if 'ProductionLocations' in item:
-            self.kodi_db.addCountries(movieid, item['ProductionLocations'], "movie")
-        # Process cast
-        people = artwork.get_people_artwork(item['People'])
-        self.kodi_db.addPeople(movieid, people, "movie")
-        # Process genres
-        self.kodi_db.addGenres(movieid, genres, "movie")
-        # Process artwork
-        artwork.add_artwork(artwork.get_all_artwork(item), movieid, "movie", kodicursor)
-        # Process stream details
-        streams = API.get_media_streams()
-        self.kodi_db.addStreams(fileid, streams, runtime)
-        # Process studios
-        self.kodi_db.addStudios(movieid, studios, "movie")
-        # Process tags: view, emby tags
-        tags = [viewtag]
-        tags.extend(item['Tags'])
-        if userdata['Favorite']:
-            tags.append("Favorite movies")
-        log.info("Applied tags: %s", tags)
-        self.kodi_db.addTags(movieid, tags, "movie")
-        # Process playstates
-        resume = API.adjust_resume(userdata['Resume'])
-        total = round(float(runtime), 6)
-        self.kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed)
-
-    def add_updateBoxset(self, boxset):
-
-        emby = self.emby
-        emby_db = self.emby_db
-        artwork = self.artwork
-
-        boxsetid = boxset['Id']
-        title = boxset['Name']
-        checksum = boxset['Etag']
-        emby_dbitem = emby_db.getItem_byId(boxsetid)
-        try:
-            setid = emby_dbitem[0]
-
-        except TypeError:
-            setid = self.kodi_db.createBoxset(title)
-
-        # Process artwork
-        artwork.add_artwork(artwork.get_all_artwork(boxset), setid, "set", self.kodicursor)
-        
-        # Process movies inside boxset
-        current_movies = emby_db.getItemId_byParentId(setid, "movie")
-        process = []
-        try:
-            # Try to convert tuple to dictionary
-            current = dict(current_movies)
-        except ValueError:
-            current = {}
-
-        # Sort current titles
-        for current_movie in current:
-            process.append(current_movie)
-
-        # New list to compare
-        for movie in emby.getMovies_byBoxset(boxsetid)['Items']:
-
-            itemid = movie['Id']
-
-            if not current.get(itemid):
-                # Assign boxset to movie
-                emby_dbitem = emby_db.getItem_byId(itemid)
-                try:
-                    movieid = emby_dbitem[0]
-                except TypeError:
-                    log.info("Failed to add: %s to boxset." % movie['Name'])
-                    continue
-
-                log.info("New addition to boxset %s: %s" % (title, movie['Name']))
-                self.kodi_db.assignBoxset(setid, movieid)
-                # Update emby reference
-                emby_db.updateParentId(itemid, setid)
-            else:
-                # Remove from process, because the item still belongs
-                process.remove(itemid)
-
-        # Process removals from boxset
-        for movie in process:
-            movieid = current[movie]
-            log.info("Remove from boxset %s: %s" % (title, movieid))
-            self.kodi_db.removefromBoxset(movieid)
-            # Update emby reference
-            emby_db.updateParentId(movie, None)
-
-        # Update the reference in the emby table
-        emby_db.addReference(boxsetid, setid, "BoxSet", mediatype="set", checksum=checksum)
-
-    def updateUserdata(self, item):
-        # This updates: Favorite, LastPlayedDate, Playcount, PlaybackPositionTicks
-        # Poster with progress bar
-        emby_db = self.emby_db
-        API = api.API(item)
-        
-        # Get emby information
-        itemid = item['Id']
-        checksum = API.get_checksum()
-        userdata = API.get_userdata()
-        runtime = API.get_runtime()
-
-        # Get Kodi information
-        emby_dbitem = emby_db.getItem_byId(itemid)
-        try:
-            movieid = emby_dbitem[0]
-            fileid = emby_dbitem[1]
-            log.info("Update playstate for movie: %s fileid: %s" % (item['Name'], fileid))
-        except TypeError:
-            return
-
-        # Process favorite tags
-        if userdata['Favorite']:
-            self.kodi_db.addTag(movieid, "Favorite movies", "movie")
-        else:
-            self.kodi_db.removeTag(movieid, "Favorite movies", "movie")
-
-        # Process playstates
-        playcount = userdata['PlayCount']
-        dateplayed = userdata['LastPlayedDate']
-        resume = API.adjust_resume(userdata['Resume'])
-        total = round(float(runtime), 6)
-
-        log.debug("%s New resume point: %s" % (itemid, resume))
-
-        self.kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed)
-        emby_db.updateReference(itemid, checksum)
-
-    def remove(self, itemid):
-        # Remove movieid, fileid, emby reference
-        emby_db = self.emby_db
-        kodicursor = self.kodicursor
-        artwork = self.artwork
-
-        emby_dbitem = emby_db.getItem_byId(itemid)
-        try:
-            kodiid = emby_dbitem[0]
-            fileid = emby_dbitem[1]
-            mediatype = emby_dbitem[4]
-            log.info("Removing %sid: %s fileid: %s" % (mediatype, kodiid, fileid))
-        except TypeError:
-            return
-
-        # Remove the emby reference
-        emby_db.removeItem(itemid)
-        # Remove artwork
-        artwork.delete_artwork(kodiid, mediatype, kodicursor)
-
-        if mediatype == "movie":
-            # Delete kodi movie and file
-            kodicursor.execute("DELETE FROM movie WHERE idMovie = ?", (kodiid,))
-            kodicursor.execute("DELETE FROM files WHERE idFile = ?", (fileid,))
-
-        elif mediatype == "set":
-            # Delete kodi boxset
-            boxset_movies = emby_db.getItem_byParentId(kodiid, "movie")
-            for movie in boxset_movies:
-                embyid = movie[0]
-                movieid = movie[1]
-                self.kodi_db.removefromBoxset(movieid)
-                # Update emby reference
-                emby_db.updateParentId(embyid, None)
-
-            kodicursor.execute("DELETE FROM sets WHERE idSet = ?", (kodiid,))
-
-        log.info("Deleted %s %s from kodi database" % (mediatype, itemid))
-
-class MusicVideos(Items):
-
-    
-    def __init__(self, embycursor, kodicursor):
-        Items.__init__(self, embycursor, kodicursor)
-
-    def added(self, items, pdialog):
-
-        total = len(items)
-        count = 0
-        for mvideo in items:
-
-            title = mvideo['Name']
-            if pdialog:
-                percentage = int((float(count) / float(total))*100)
-                pdialog.update(percentage, message=title)
-                count += 1
-            self.add_update(mvideo)
-            if not pdialog and self.contentmsg:
-                self.contentPop(title, self.newvideo_time)
-
-
-    def add_update(self, item, viewtag=None, viewid=None):
-        # Process single music video
-        kodicursor = self.kodicursor
-        emby_db = self.emby_db
-        artwork = self.artwork
-        API = api.API(item)
-
-        if item.get('LocationType') == "Virtual": # TODO: Filter via api instead
-            log.info("Skipping virtual episode: %s", item['Name'])
-            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
-        update_item = True
-        itemid = item['Id']
-        emby_dbitem = emby_db.getItem_byId(itemid)
-        try:
-            mvideoid = emby_dbitem[0]
-            fileid = emby_dbitem[1]
-            pathid = emby_dbitem[2]
-            log.info("mvideoid: %s fileid: %s pathid: %s" % (mvideoid, fileid, pathid))
-        
-        except TypeError:
-            update_item = False
-            log.debug("mvideoid: %s not found." % itemid)
-            # mvideoid
-            kodicursor.execute("select coalesce(max(idMVideo),0) from musicvideo")
-            mvideoid = kodicursor.fetchone()[0] + 1
-
-        else:
-            # Verification the item is still in Kodi
-            query = "SELECT * FROM musicvideo WHERE idMVideo = ?"
-            kodicursor.execute(query, (mvideoid,))
-            try:
-                kodicursor.fetchone()[0]
-            except TypeError:
-                # item is not found, let's recreate it.
-                update_item = False
-                log.info("mvideoid: %s missing from Kodi, repairing the entry." % mvideoid)
-
-        if not viewtag or not viewid:
-            # Get view tag from emby
-            viewtag, viewid, mediatype = self.emby.getView_embyId(itemid)
-            log.debug("View tag found: %s" % viewtag)
-
-        # fileId information
-        checksum = API.get_checksum()
-        dateadded = API.get_date_created()
-        userdata = API.get_userdata()
-        playcount = userdata['PlayCount']
-        dateplayed = userdata['LastPlayedDate']
-
-        # item details
-        runtime = API.get_runtime()
-        plot = API.get_overview()
-        title = item['Name']
-        year = item.get('ProductionYear')
-        genres = item['Genres']
-        genre = " / ".join(genres)
-        studios = API.get_studios()
-        studio = " / ".join(studios)
-        artist = " / ".join(item.get('Artists'))
-        album = item.get('Album')
-        track = item.get('Track')
-        people = API.get_people()
-        director = " / ".join(people['Director'])
-
-        
-        ##### GET THE FILE AND PATH #####
-        playurl = API.get_file_path()
-
-        if "\\" in playurl:
-            # Local path
-            filename = playurl.rsplit("\\", 1)[1]
-        else: # Network share
-            filename = playurl.rsplit("/", 1)[1]
-
-        if self.directpath:
-            # Direct paths is set the Kodi way
-            if not self.pathValidation(playurl):
-                return False
-            
-            path = playurl.replace(filename, "")
-            window('emby_pathverified', value="true")
-        else:
-            # Set plugin path and media flags using real filename
-            path = "plugin://plugin.video.emby.musicvideos/"
-            params = {
-
-                'filename': filename.encode('utf-8'),
-                'id': itemid,
-                'dbid': mvideoid,
-                'mode': "play"
-            }
-            filename = "%s?%s" % (path, urllib.urlencode(params))
-
-
-        ##### UPDATE THE MUSIC VIDEO #####
-        if update_item:
-            log.info("UPDATE mvideo itemid: %s - Title: %s" % (itemid, title))
-            
-            # Update path
-            query = "UPDATE path SET strPath = ? WHERE idPath = ?"
-            kodicursor.execute(query, (path, pathid))
-
-            # Update the filename
-            query = "UPDATE files SET strFilename = ?, dateAdded = ? WHERE idFile = ?"
-            kodicursor.execute(query, (filename, dateadded, fileid))
-
-            # Update the music video entry
-            query = ' '.join((
-                
-                "UPDATE musicvideo",
-                "SET c00 = ?, c04 = ?, c05 = ?, c06 = ?, c07 = ?, c08 = ?, c09 = ?, c10 = ?,",
-                    "c11 = ?, c12 = ?"
-                "WHERE idMVideo = ?"
-            ))
-            kodicursor.execute(query, (title, runtime, director, studio, year, plot, album,
-                artist, genre, track, mvideoid))
-
-            # Update the checksum in emby table
-            emby_db.updateReference(itemid, checksum)
-        
-        ##### OR ADD THE MUSIC VIDEO #####
-        else:
-            log.info("ADD mvideo itemid: %s - Title: %s" % (itemid, title))
-            
-            # Add path
-            query = ' '.join((
-
-                "SELECT idPath",
-                "FROM path",
-                "WHERE strPath = ?"
-            ))
-            kodicursor.execute(query, (path,))
-            try:
-                pathid = kodicursor.fetchone()[0]
-            except TypeError:
-                kodicursor.execute("select coalesce(max(idPath),0) from path")
-                pathid = kodicursor.fetchone()[0] + 1
-                query = (
-                    '''
-                    INSERT OR REPLACE INTO path(
-                        idPath, strPath, strContent, strScraper, noUpdate)
-
-                    VALUES (?, ?, ?, ?, ?)
-                    '''
-                )
-                kodicursor.execute(query, (pathid, path, "musicvideos", "metadata.local", 1))
-
-            # Add the file
-            kodicursor.execute("select coalesce(max(idFile),0) from files")
-            fileid = kodicursor.fetchone()[0] + 1
-            query = (
-                '''
-                INSERT INTO files(
-                    idFile, idPath, strFilename, dateAdded)
-
-                VALUES (?, ?, ?, ?)
-                '''
-            )
-            kodicursor.execute(query, (fileid, pathid, filename, dateadded))
-            
-            # Create the musicvideo entry
-            query = (
-                '''
-                INSERT INTO musicvideo(
-                    idMVideo, idFile, c00, c04, c05, c06, c07, c08, c09, c10, c11, c12)
-
-                VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
-                '''
-            )
-            kodicursor.execute(query, (mvideoid, fileid, title, runtime, director, studio,
-                year, plot, album, artist, genre, track))
-
-            # Create the reference in emby table
-            emby_db.addReference(itemid, mvideoid, "MusicVideo", "musicvideo", fileid, pathid,
-                checksum=checksum, mediafolderid=viewid)
-
-        
-        # Process cast
-        people = item['People']
-        artists = item['ArtistItems']
-        for artist in artists:
-            artist['Type'] = "Artist"
-        people.extend(artists)
-        people = artwork.get_people_artwork(people)
-        self.kodi_db.addPeople(mvideoid, people, "musicvideo")
-        # Process genres
-        self.kodi_db.addGenres(mvideoid, genres, "musicvideo")
-        # Process artwork
-        artwork.add_artwork(artwork.get_all_artwork(item), mvideoid, "musicvideo", kodicursor)
-        # Process stream details
-        streams = API.get_media_streams()
-        self.kodi_db.addStreams(fileid, streams, runtime)
-        # Process studios
-        self.kodi_db.addStudios(mvideoid, studios, "musicvideo")
-        # Process tags: view, emby tags
-        tags = [viewtag]
-        tags.extend(item['Tags'])
-        if userdata['Favorite']:
-            tags.append("Favorite musicvideos")
-        self.kodi_db.addTags(mvideoid, tags, "musicvideo")
-        # Process playstates
-        resume = API.adjust_resume(userdata['Resume'])
-        total = round(float(runtime), 6)
-        self.kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed)
-
-    def updateUserdata(self, item):
-        # This updates: Favorite, LastPlayedDate, Playcount, PlaybackPositionTicks
-        # Poster with progress bar
-        emby_db = self.emby_db
-        API = api.API(item)
-        
-        # Get emby information
-        itemid = item['Id']
-        checksum = API.get_checksum()
-        userdata = API.get_userdata()
-        runtime = API.get_runtime()
-
-        # Get Kodi information
-        emby_dbitem = emby_db.getItem_byId(itemid)
-        try:
-            mvideoid = emby_dbitem[0]
-            fileid = emby_dbitem[1]
-            log.info(
-                "Update playstate for musicvideo: %s fileid: %s"
-                % (item['Name'], fileid))
-        except TypeError:
-            return
-
-        # Process favorite tags
-        if userdata['Favorite']:
-            self.kodi_db.addTag(mvideoid, "Favorite musicvideos", "musicvideo")
-        else:
-            self.kodi_db.removeTag(mvideoid, "Favorite musicvideos", "musicvideo")
-
-        # Process playstates
-        playcount = userdata['PlayCount']
-        dateplayed = userdata['LastPlayedDate']
-        resume = API.adjust_resume(userdata['Resume'])
-        total = round(float(runtime), 6)
-
-        self.kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed)
-        emby_db.updateReference(itemid, checksum)
-
-    def remove(self, itemid):
-        # Remove mvideoid, fileid, pathid, emby reference
-        emby_db = self.emby_db
-        kodicursor = self.kodicursor
-        artwork = self.artwork
-
-        emby_dbitem = emby_db.getItem_byId(itemid)
-        try:
-            mvideoid = emby_dbitem[0]
-            fileid = emby_dbitem[1]
-            pathid = emby_dbitem[2]
-            log.info("Removing mvideoid: %s fileid: %s" % (mvideoid, fileid, pathid))
-        except TypeError:
-            return
-
-        # Remove artwork
-        query = ' '.join((
-
-            "SELECT url, type",
-            "FROM art",
-            "WHERE media_id = ?",
-            "AND media_type = 'musicvideo'"
-        ))
-        kodicursor.execute(query, (mvideoid,))
-        for row in kodicursor.fetchall():
-            
-            url = row[0]
-            imagetype = row[1]
-            if imagetype in ("poster", "fanart"):
-                artwork.delete_cached_artwork(url)
-
-        kodicursor.execute("DELETE FROM musicvideo WHERE idMVideo = ?", (mvideoid,))
-        kodicursor.execute("DELETE FROM files WHERE idFile = ?", (fileid,))
-        if self.directpath:
-            kodicursor.execute("DELETE FROM path WHERE idPath = ?", (pathid,))
-        self.embycursor.execute("DELETE FROM emby WHERE emby_id = ?", (itemid,))
-
-        log.info("Deleted musicvideo %s from kodi database" % itemid)
-
-class TVShows(Items):
-
-
-    def __init__(self, embycursor, kodicursor):
-        Items.__init__(self, embycursor, kodicursor)
-
-    def added(self, items, pdialog):
-        
-        total = len(items)
-        count = 0
-        for tvshow in items:
-
-            title = tvshow['Name']
-            if pdialog:
-                percentage = int((float(count) / float(total))*100)
-                pdialog.update(percentage, message=title)
-                count += 1
-            self.add_update(tvshow)
-            # Add episodes
-            all_episodes = self.emby.getEpisodesbyShow(tvshow['Id'])
-            self.added_episode(all_episodes['Items'], pdialog)
-
-    def added_season(self, items, pdialog):
-        
-        total = len(items)
-        count = 0
-        for season in items:
-
-            title = "%s - %s" % (season.get('SeriesName', "Unknown"), season['Name'])
-            if pdialog:
-                percentage = int((float(count) / float(total))*100)
-                pdialog.update(percentage, message=title)
-                count += 1
-            self.add_updateSeason(season)
-            # Add episodes
-            all_episodes = self.emby.getEpisodesbySeason(season['Id'])
-            self.added_episode(all_episodes['Items'], pdialog)
-
-    def added_episode(self, items, pdialog):
-        
-        total = len(items)
-        count = 0
-        for episode in items:
-            title = "%s - %s" % (episode.get('SeriesName', "Unknown"), episode['Name'])
-            if pdialog:
-                percentage = int((float(count) / float(total))*100)
-                pdialog.update(percentage, message=title)
-                count += 1
-            self.add_updateEpisode(episode)
-            if not pdialog and self.contentmsg:
-                self.contentPop(title, self.newvideo_time)
-
-
-    def add_update(self, item, viewtag=None, viewid=None):
-        # Process single tvshow
-        kodicursor = self.kodicursor
-        emby = self.emby
-        emby_db = self.emby_db
-        artwork = self.artwork
-        API = api.API(item)
-
-        if settings('syncEmptyShows') == "false" and not item.get('RecursiveItemCount'):
-            log.info("Skipping empty show: %s" % item['Name'])
-            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
-        update_item = True
-        force_episodes = False
-        itemid = item['Id']
-        emby_dbitem = emby_db.getItem_byId(itemid)
-        try:
-            showid = emby_dbitem[0]
-            pathid = emby_dbitem[2]
-            log.info("showid: %s pathid: %s" % (showid, pathid))
-        
-        except TypeError:
-            update_item = False
-            log.debug("showid: %s not found." % itemid)
-            kodicursor.execute("select coalesce(max(idShow),0) from tvshow")
-            showid = kodicursor.fetchone()[0] + 1
-
-        else:
-            # Verification the item is still in Kodi
-            query = "SELECT * FROM tvshow WHERE idShow = ?"
-            kodicursor.execute(query, (showid,))
-            try:
-                kodicursor.fetchone()[0]
-            except TypeError:
-                # item is not found, let's recreate it.
-                update_item = False
-                log.info("showid: %s missing from Kodi, repairing the entry." % showid)
-                # Force re-add episodes after the show is re-created.
-                force_episodes = True
-
-
-        if viewtag is None or viewid is None:
-            # Get view tag from emby
-            viewtag, viewid, mediatype = emby.getView_embyId(itemid)
-            log.debug("View tag found: %s" % viewtag)
-
-        # fileId information
-        checksum = API.get_checksum()
-        dateadded = API.get_date_created()
-        userdata = API.get_userdata()
-        playcount = userdata['PlayCount']
-        dateplayed = userdata['LastPlayedDate']
-
-        # item details
-        genres = item['Genres']
-        title = item['Name']
-        plot = API.get_overview()
-        rating = item.get('CommunityRating')
-        premieredate = API.get_premiere_date()
-        tvdb = API.get_provider('Tvdb')
-        sorttitle = item['SortName']
-        mpaa = API.get_mpaa()
-        genre = " / ".join(genres)
-        studios = API.get_studios()
-        studio = " / ".join(studios)
-
-        # Verify series pooling
-        if not update_item and tvdb:
-            query = "SELECT idShow FROM tvshow WHERE C12 = ?"
-            kodicursor.execute(query, (tvdb,))
-            try:
-                temp_showid = kodicursor.fetchone()[0]
-            except TypeError:
-                pass
-            else:
-                emby_other = emby_db.getItem_byKodiId(temp_showid, "tvshow")
-                if emby_other and viewid == emby_other[2]:
-                    log.info("Applying series pooling for %s", title)
-                    emby_other_item = emby_db.getItem_byId(emby_other[0])
-                    showid = emby_other_item[0]
-                    pathid = emby_other_item[2]
-                    log.info("showid: %s pathid: %s" % (showid, pathid))
-                    # Create the reference in emby table
-                    emby_db.addReference(itemid, showid, "Series", "tvshow", pathid=pathid,
-                                        checksum=checksum, mediafolderid=viewid)
-                    update_item = True
-
-        
-        ##### GET THE FILE AND PATH #####
-        playurl = API.get_file_path()
-
-        if self.directpath:
-            # Direct paths is set the Kodi way
-            if "\\" in playurl:
-                # Local path
-                path = "%s\\" % playurl
-                toplevelpath = "%s\\" % dirname(dirname(path))
-            else:
-                # Network path
-                path = "%s/" % playurl
-                toplevelpath = "%s/" % dirname(dirname(path))
-
-            if not self.pathValidation(path):
-                return False
-
-            window('emby_pathverified', value="true")
-        else:
-            # Set plugin path
-            toplevelpath = "plugin://plugin.video.emby.tvshows/"
-            path = "%s%s/" % (toplevelpath, itemid)
-
-
-        ##### UPDATE THE TVSHOW #####
-        if update_item:
-            log.info("UPDATE tvshow itemid: %s - Title: %s" % (itemid, title))
-
-            # Update the tvshow entry
-            query = ' '.join((
-                
-                "UPDATE tvshow",
-                "SET c00 = ?, c01 = ?, c04 = ?, c05 = ?, c08 = ?, c09 = ?,",
-                    "c12 = ?, c13 = ?, c14 = ?, c15 = ?",
-                "WHERE idShow = ?"
-            ))
-            kodicursor.execute(query, (title, plot, rating, premieredate, genre, title,
-                tvdb, mpaa, studio, sorttitle, showid))
-
-            # Update the checksum in emby table
-            emby_db.updateReference(itemid, checksum)
-        
-        ##### OR ADD THE TVSHOW #####
-        else:
-            log.info("ADD tvshow itemid: %s - Title: %s" % (itemid, title))
-            
-            # Add top path
-            toppathid = self.kodi_db.addPath(toplevelpath)
-            query = ' '.join((
-
-                "UPDATE path",
-                "SET strPath = ?, strContent = ?, strScraper = ?, noUpdate = ?",
-                "WHERE idPath = ?"
-            ))
-            kodicursor.execute(query, (toplevelpath, "tvshows", "metadata.local", 1, toppathid))
-            
-            # Add path
-            pathid = self.kodi_db.addPath(path)
-            
-            # Create the tvshow entry
-            query = (
-                '''
-                INSERT INTO tvshow(
-                    idShow, c00, c01, c04, c05, c08, c09, c12, c13, c14, c15) 
-
-                VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
-                '''
-            )
-            kodicursor.execute(query, (showid, title, plot, rating, premieredate, genre,
-                title, tvdb, mpaa, studio, sorttitle))
-
-            # Link the path
-            query = "INSERT INTO tvshowlinkpath(idShow, idPath) values(?, ?)"
-            kodicursor.execute(query, (showid, pathid))
-
-            # Create the reference in emby table
-            emby_db.addReference(itemid, showid, "Series", "tvshow", pathid=pathid,
-                                checksum=checksum, mediafolderid=viewid)
-
-        # Update the path
-        query = ' '.join((
-
-            "UPDATE path",
-            "SET strPath = ?, strContent = ?, strScraper = ?, noUpdate = ?",
-            "WHERE idPath = ?"
-        ))
-        kodicursor.execute(query, (path, None, None, 1, pathid))
-        
-        # Process cast
-        people = artwork.get_people_artwork(item['People'])
-        self.kodi_db.addPeople(showid, people, "tvshow")
-        # Process genres
-        self.kodi_db.addGenres(showid, genres, "tvshow")
-        # Process artwork
-        artwork.add_artwork(artwork.get_all_artwork(item), showid, "tvshow", kodicursor)
-        # Process studios
-        self.kodi_db.addStudios(showid, studios, "tvshow")
-        # Process tags: view, emby tags
-        tags = [viewtag]
-        tags.extend(item['Tags'])
-        if userdata['Favorite']:
-            tags.append("Favorite tvshows")
-        self.kodi_db.addTags(showid, tags, "tvshow")
-        # Process seasons
-        all_seasons = emby.getSeasons(itemid)
-        for season in all_seasons['Items']:
-            self.add_updateSeason(season, showid=showid)
-        else:
-            # Finally, refresh the all season entry
-            seasonid = self.kodi_db.addSeason(showid, -1)
-            # Process artwork
-            artwork.add_artwork(artwork.get_all_artwork(item), seasonid, "season", kodicursor)
-
-        if force_episodes:
-            # We needed to recreate the show entry. Re-add episodes now.
-            log.info("Repairing episodes for showid: %s %s" % (showid, title))
-            all_episodes = emby.getEpisodesbyShow(itemid)
-            self.added_episode(all_episodes['Items'], None)
-
-    def add_updateSeason(self, item, showid=None):
-
-        kodicursor = self.kodicursor
-        emby_db = self.emby_db
-        artwork = self.artwork
-
-        seasonnum = item.get('IndexNumber', 1)
-
-        if showid is None:
-            try:
-                seriesId = item['SeriesId']
-                showid = emby_db.getItem_byId(seriesId)[0]
-            except KeyError:
-                return
-            except TypeError:
-                # Show is missing, update show instead.
-                show = self.emby.getItem(seriesId)
-                self.add_update(show)
-                return
-        
-        seasonid = self.kodi_db.addSeason(showid, seasonnum, item['Name'])
-        
-        if item['LocationType'] != "Virtual":
-            # Create the reference in emby table
-            emby_db.addReference(item['Id'], seasonid, "Season", "season", parentid=showid)
-
-        # Process artwork
-        artwork.add_artwork(artwork.get_all_artwork(item), seasonid, "season", kodicursor)
-
-    def add_updateEpisode(self, item):
-        # Process single episode
-        kodicursor = self.kodicursor
-        emby_db = self.emby_db
-        artwork = self.artwork
-        API = api.API(item)
-
-        if item.get('LocationType') == "Virtual": # TODO: Filter via api instead
-            log.info("Skipping virtual episode: %s", item['Name'])
-            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
-        update_item = True
-        itemid = item['Id']
-        emby_dbitem = emby_db.getItem_byId(itemid)
-        try:
-            episodeid = emby_dbitem[0]
-            fileid = emby_dbitem[1]
-            pathid = emby_dbitem[2]
-            log.info("episodeid: %s fileid: %s pathid: %s" % (episodeid, fileid, pathid))
-        
-        except TypeError:
-            update_item = False
-            log.debug("episodeid: %s not found." % itemid)
-            # episodeid
-            kodicursor.execute("select coalesce(max(idEpisode),0) from episode")
-            episodeid = kodicursor.fetchone()[0] + 1
-
-        else:
-            # Verification the item is still in Kodi
-            query = "SELECT * FROM episode WHERE idEpisode = ?"
-            kodicursor.execute(query, (episodeid,))
-            try:
-                kodicursor.fetchone()[0]
-            except TypeError:
-                # item is not found, let's recreate it.
-                update_item = False
-                log.info("episodeid: %s missing from Kodi, repairing the entry." % episodeid)
-
-        # fileId information
-        checksum = API.get_checksum()
-        dateadded = API.get_date_created()
-        userdata = API.get_userdata()
-        playcount = userdata['PlayCount']
-        dateplayed = userdata['LastPlayedDate']
-
-        # item details
-        people = API.get_people()
-        writer = " / ".join(people['Writer'])
-        director = " / ".join(people['Director'])
-        title = item['Name']
-        plot = API.get_overview()
-        rating = item.get('CommunityRating')
-        runtime = API.get_runtime()
-        premieredate = API.get_premiere_date()
-
-        # episode details
-        try:
-            seriesId = item['SeriesId']
-        except KeyError:
-            # Missing seriesId, skip
-            log.error("Skipping: %s. SeriesId is missing." % itemid)
-            return False
-            
-        season = item.get('ParentIndexNumber')
-        episode = item.get('IndexNumber', -1)
-       
-        if season is None:
-            if item.get('AbsoluteEpisodeNumber'):
-                # Anime scenario
-                season = 1
-                episode = item['AbsoluteEpisodeNumber']
-            else:
-                season = -1 if "Specials" not in item['Path'] else 0
-
-        # Specials ordering within season
-        if item.get('AirsAfterSeasonNumber'):
-            airsBeforeSeason = item['AirsAfterSeasonNumber']
-            airsBeforeEpisode = 4096 # Kodi default number for afterseason ordering
-        else:
-            airsBeforeSeason = item.get('AirsBeforeSeasonNumber')
-            airsBeforeEpisode = item.get('AirsBeforeEpisodeNumber')
-
-        # Append multi episodes to title
-        if item.get('IndexNumberEnd'):              
-            title = "| %02d | %s" % (item['IndexNumberEnd'], title)
-
-        # Get season id
-        show = emby_db.getItem_byId(seriesId)
-        try:
-            showid = show[0]
-        except TypeError:
-            # Show is missing from database
-            show = self.emby.getItem(seriesId)
-            self.add_update(show)
-            show = emby_db.getItem_byId(seriesId)
-            try:
-                showid = show[0]
-            except TypeError:
-                log.error("Skipping: %s. Unable to add series: %s." % (itemid, seriesId))
-                return False
-
-        seasonid = self.kodi_db.addSeason(showid, season)
-
-        
-        ##### GET THE FILE AND PATH #####
-        playurl = API.get_file_path()
-
-        if "\\" in playurl:
-            # Local path
-            filename = playurl.rsplit("\\", 1)[1]
-        else: # Network share
-            filename = playurl.rsplit("/", 1)[1]
-
-        if self.directpath:
-            # Direct paths is set the Kodi way
-            if not self.pathValidation(playurl):
-                return False
-            
-            path = playurl.replace(filename, "")
-            window('emby_pathverified', value="true")
-        else:
-            # Set plugin path and media flags using real filename
-            path = "plugin://plugin.video.emby.tvshows/%s/" % seriesId
-            params = {
-
-                'filename': filename.encode('utf-8'),
-                'id': itemid,
-                'dbid': episodeid,
-                'mode': "play"
-            }
-            filename = "%s?%s" % (path, urllib.urlencode(params))
-
-
-        ##### UPDATE THE EPISODE #####
-        if update_item:
-            log.info("UPDATE episode itemid: %s - Title: %s" % (itemid, title))
-
-            # Update the movie entry
-            if self.kodiversion in (16, 17):
-                # Kodi Jarvis, Krypton
-                query = ' '.join((
-                
-                    "UPDATE episode",
-                    "SET c00 = ?, c01 = ?, c03 = ?, c04 = ?, c05 = ?, c09 = ?, c10 = ?,",
-                        "c12 = ?, c13 = ?, c14 = ?, c15 = ?, c16 = ?, idSeason = ?, idShow = ?",
-                    "WHERE idEpisode = ?"
-                ))
-                kodicursor.execute(query, (title, plot, rating, writer, premieredate,
-                    runtime, director, season, episode, title, airsBeforeSeason,
-                    airsBeforeEpisode, seasonid, showid, episodeid))
-            else:
-                query = ' '.join((
-                    
-                    "UPDATE episode",
-                    "SET c00 = ?, c01 = ?, c03 = ?, c04 = ?, c05 = ?, c09 = ?, c10 = ?,",
-                        "c12 = ?, c13 = ?, c14 = ?, c15 = ?, c16 = ?, idShow = ?",
-                    "WHERE idEpisode = ?"
-                ))
-                kodicursor.execute(query, (title, plot, rating, writer, premieredate,
-                    runtime, director, season, episode, title, airsBeforeSeason,
-                    airsBeforeEpisode, showid, episodeid))
-
-            # Update the checksum in emby table
-            emby_db.updateReference(itemid, checksum)
-            # Update parentid reference
-            emby_db.updateParentId(itemid, seasonid)
-        
-        ##### OR ADD THE EPISODE #####
-        else:
-            log.info("ADD episode itemid: %s - Title: %s" % (itemid, title))
-            
-            # Add path
-            pathid = self.kodi_db.addPath(path)
-            # Add the file
-            fileid = self.kodi_db.addFile(filename, pathid)
-            
-            # Create the episode entry
-            if self.kodiversion in (16, 17):
-                # Kodi Jarvis, Krypton
-                query = (
-                    '''
-                    INSERT INTO episode(
-                        idEpisode, idFile, c00, c01, c03, c04, c05, c09, c10, c12, c13, c14,
-                        idShow, c15, c16, idSeason)
-
-                    VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
-                    '''
-                )
-                kodicursor.execute(query, (episodeid, fileid, title, plot, rating, writer,
-                    premieredate, runtime, director, season, episode, title, showid,
-                    airsBeforeSeason, airsBeforeEpisode, seasonid))
-            else:
-                query = (
-                    '''
-                    INSERT INTO episode(
-                        idEpisode, idFile, c00, c01, c03, c04, c05, c09, c10, c12, c13, c14,
-                        idShow, c15, c16)
-
-                    VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
-                    '''
-                )
-                kodicursor.execute(query, (episodeid, fileid, title, plot, rating, writer,
-                    premieredate, runtime, director, season, episode, title, showid,
-                    airsBeforeSeason, airsBeforeEpisode))
-
-            # Create the reference in emby table
-            emby_db.addReference(itemid, episodeid, "Episode", "episode", fileid, pathid,
-                seasonid, checksum)
-
-        # Update the path
-        query = ' '.join((
-
-            "UPDATE path",
-            "SET strPath = ?, strContent = ?, strScraper = ?, noUpdate = ?",
-            "WHERE idPath = ?"
-        ))
-        kodicursor.execute(query, (path, None, None, 1, pathid))
-
-        # Update the file
-        query = ' '.join((
-
-            "UPDATE files",
-            "SET idPath = ?, strFilename = ?, dateAdded = ?",
-            "WHERE idFile = ?"
-        ))
-        kodicursor.execute(query, (pathid, filename, dateadded, fileid))
-        
-        # Process cast
-        people = artwork.get_people_artwork(item['People'])
-        self.kodi_db.addPeople(episodeid, people, "episode")
-        # Process artwork
-        artworks = artwork.get_all_artwork(item)
-        artwork.add_update_art(artworks['Primary'], episodeid, "episode", "thumb", kodicursor)
-        # Process stream details
-        streams = API.get_media_streams()
-        self.kodi_db.addStreams(fileid, streams, runtime)
-        # Process playstates
-        resume = API.adjust_resume(userdata['Resume'])
-        total = round(float(runtime), 6)
-        self.kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed)
-        if not self.directpath and resume:
-            # Create additional entry for widgets. This is only required for plugin/episode.
-            temppathid = self.kodi_db.getPath("plugin://plugin.video.emby.tvshows/")
-            tempfileid = self.kodi_db.addFile(filename, temppathid)
-            query = ' '.join((
-
-                "UPDATE files",
-                "SET idPath = ?, strFilename = ?, dateAdded = ?",
-                "WHERE idFile = ?"
-            ))
-            kodicursor.execute(query, (temppathid, filename, dateadded, tempfileid))
-            self.kodi_db.addPlaystate(tempfileid, resume, total, playcount, dateplayed)
-
-    def updateUserdata(self, item):
-        # This updates: Favorite, LastPlayedDate, Playcount, PlaybackPositionTicks
-        # Poster with progress bar
-        emby_db = self.emby_db
-        API = api.API(item)
-        
-        # Get emby information
-        itemid = item['Id']
-        checksum = API.get_checksum()
-        userdata = API.get_userdata()
-        runtime = API.get_runtime()
-        dateadded = API.get_date_created()
-
-        # Get Kodi information
-        emby_dbitem = emby_db.getItem_byId(itemid)
-        try:
-            kodiid = emby_dbitem[0]
-            fileid = emby_dbitem[1]
-            mediatype = emby_dbitem[4]
-            log.info(
-                "Update playstate for %s: %s fileid: %s"
-                % (mediatype, item['Name'], fileid))
-        except TypeError:
-            return
-
-        # Process favorite tags
-        if mediatype == "tvshow":
-            if userdata['Favorite']:
-                self.kodi_db.addTag(kodiid, "Favorite tvshows", "tvshow")
-            else:
-                self.kodi_db.removeTag(kodiid, "Favorite tvshows", "tvshow")
-        elif mediatype == "episode":
-            # Process playstates
-            playcount = userdata['PlayCount']
-            dateplayed = userdata['LastPlayedDate']
-            resume = API.adjust_resume(userdata['Resume'])
-            total = round(float(runtime), 6)
-
-            log.debug("%s New resume point: %s" % (itemid, resume))
-
-            self.kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed)
-            if not self.directpath and not resume:
-                # Make sure there's no other bookmarks created by widget.
-                filename = self.kodi_db.getFile(fileid)
-                self.kodi_db.removeFile("plugin://plugin.video.emby.tvshows/", filename)
-
-            if not self.directpath and resume:
-                # Create additional entry for widgets. This is only required for plugin/episode.
-                filename = self.kodi_db.getFile(fileid)
-                temppathid = self.kodi_db.getPath("plugin://plugin.video.emby.tvshows/")
-                tempfileid = self.kodi_db.addFile(filename, temppathid)
-                query = ' '.join((
-
-                    "UPDATE files",
-                    "SET idPath = ?, strFilename = ?, dateAdded = ?",
-                    "WHERE idFile = ?"
-                ))
-                self.kodicursor.execute(query, (temppathid, filename, dateadded, tempfileid))
-                self.kodi_db.addPlaystate(tempfileid, resume, total, playcount, dateplayed)
-
-        emby_db.updateReference(itemid, checksum)
-
-    def remove(self, itemid):
-        # Remove showid, fileid, pathid, emby reference
-        emby_db = self.emby_db
-        embycursor = self.embycursor
-        kodicursor = self.kodicursor
-        artwork = self.artwork
-
-        emby_dbitem = emby_db.getItem_byId(itemid)
-        try:
-            kodiid = emby_dbitem[0]
-            fileid = emby_dbitem[1]
-            pathid = emby_dbitem[2]
-            parentid = emby_dbitem[3]
-            mediatype = emby_dbitem[4]
-            log.info("Removing %s kodiid: %s fileid: %s" % (mediatype, kodiid, fileid))
-        except TypeError:
-            return
-
-        ##### PROCESS ITEM #####
-
-        # Remove the emby reference
-        emby_db.removeItem(itemid)
-
-
-        ##### IF EPISODE #####
-
-        if mediatype == "episode":
-            # Delete kodi episode and file, verify season and tvshow
-            self.removeEpisode(kodiid, fileid)
-
-            # Season verification
-            season = emby_db.getItem_byKodiId(parentid, "season")
-            try:
-                showid = season[1]
-            except TypeError:
-                return
-            
-            season_episodes = emby_db.getItem_byParentId(parentid, "episode")
-            if not season_episodes:
-                self.removeSeason(parentid)
-                emby_db.removeItem(season[0])
-
-            # Show verification
-            show = emby_db.getItem_byKodiId(showid, "tvshow")
-            query = ' '.join((
-
-                "SELECT totalCount",
-                "FROM tvshowcounts",
-                "WHERE idShow = ?"
-            ))
-            kodicursor.execute(query, (showid,))
-            result = kodicursor.fetchone()
-            if result and result[0] is None:
-                # There's no episodes left, delete show and any possible remaining seasons
-                seasons = emby_db.getItem_byParentId(showid, "season")
-                for season in seasons:
-                    self.removeSeason(season[1])
-                else:
-                    # Delete emby season entries
-                    emby_db.removeItems_byParentId(showid, "season")
-                self.removeShow(showid)
-                emby_db.removeItem(show[0])
-
-        ##### IF TVSHOW #####
-
-        elif mediatype == "tvshow":
-            # Remove episodes, seasons, tvshow
-            seasons = emby_db.getItem_byParentId(kodiid, "season")
-            for season in seasons:
-                seasonid = season[1]
-                season_episodes = emby_db.getItem_byParentId(seasonid, "episode")
-                for episode in season_episodes:
-                    self.removeEpisode(episode[1], episode[2])
-                else:
-                    # Remove emby episodes
-                    emby_db.removeItems_byParentId(seasonid, "episode")
-            else:
-                # Remove emby seasons
-                emby_db.removeItems_byParentId(kodiid, "season")
-
-            # Remove tvshow
-            self.removeShow(kodiid)
-
-        ##### IF SEASON #####
-
-        elif mediatype == "season":
-            # Remove episodes, season, verify tvshow
-            season_episodes = emby_db.getItem_byParentId(kodiid, "episode")
-            for episode in season_episodes:
-                self.removeEpisode(episode[1], episode[2])
-            else:
-                # Remove emby episodes
-                emby_db.removeItems_byParentId(kodiid, "episode")
-            
-            # Remove season
-            self.removeSeason(kodiid)
-
-            # Show verification
-            seasons = emby_db.getItem_byParentId(parentid, "season")
-            if not seasons:
-                # There's no seasons, delete the show
-                self.removeShow(parentid)
-                emby_db.removeItem_byKodiId(parentid, "tvshow")
-
-        log.info("Deleted %s: %s from kodi database" % (mediatype, itemid))
-
-    def removeShow(self, kodiid):
-        
-        kodicursor = self.kodicursor
-        self.artwork.delete_artwork(kodiid, "tvshow", kodicursor)
-        kodicursor.execute("DELETE FROM tvshow WHERE idShow = ?", (kodiid,))
-        log.debug("Removed tvshow: %s." % kodiid)
-
-    def removeSeason(self, kodiid):
-        
-        kodicursor = self.kodicursor
-
-        self.artwork.delete_artwork(kodiid, "season", kodicursor)
-        kodicursor.execute("DELETE FROM seasons WHERE idSeason = ?", (kodiid,))
-        log.debug("Removed season: %s." % kodiid)
-
-    def removeEpisode(self, kodiid, fileid):
-
-        kodicursor = self.kodicursor
-
-        self.artwork.delete_artwork(kodiid, "episode", kodicursor)
-        kodicursor.execute("DELETE FROM episode WHERE idEpisode = ?", (kodiid,))
-        kodicursor.execute("DELETE FROM files WHERE idFile = ?", (fileid,))
-        log.debug("Removed episode: %s." % kodiid)
-
-class Music(Items):
-
-
-    def __init__(self, embycursor, musiccursor):
-        
-        Items.__init__(self, embycursor, musiccursor)
-
-        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):
-        
-        total = len(items)
-        count = 0
-        for artist in items:
-
-            if pdialog:
-                percentage = int((float(count) / float(total))*100)
-                pdialog.update(percentage, message=artist['Name'])
-                count += 1
-            self.add_updateArtist(artist)
-            # Add albums
-            all_albums = self.emby.getAlbumsbyArtist(artist['Id'])
-            self.added_album(all_albums['Items'], pdialog)
-
-    def added_album(self, items, pdialog):
-        
-        total = len(items)
-        count = 0
-        for album in items:
-
-            if pdialog:
-                percentage = int((float(count) / float(total))*100)
-                pdialog.update(percentage, message=album['Name'])
-                count += 1
-            self.add_updateAlbum(album)
-            # Add songs
-            all_songs = self.emby.getSongsbyAlbum(album['Id'])
-            self.added_song(all_songs['Items'], pdialog)
-
-    def added_song(self, items, pdialog):
-        
-        total = len(items)
-        count = 0
-        for song in items:
-
-            if pdialog:
-                percentage = int((float(count) / float(total))*100)
-                pdialog.update(percentage, message=song['Name'])
-                count += 1
-            self.add_updateSong(song)
-            if not pdialog and self.contentmsg:
-                self.contentPop(song['Name'], self.newmusic_time)
-
-    def add_updateArtist(self, item, artisttype="MusicArtist"):
-        # Process a single artist
-        kodicursor = self.kodicursor
-        emby_db = self.emby_db
-        artwork = self.artwork
-        API = api.API(item)
-
-        update_item = True
-        itemid = item['Id']
-        emby_dbitem = emby_db.getItem_byId(itemid)
-        try:
-            artistid = emby_dbitem[0]
-        except TypeError:
-            update_item = False
-            log.debug("artistid: %s not found." % itemid)
-
-        ##### The artist details #####
-        lastScraped = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
-        dateadded = API.get_date_created()
-        checksum = API.get_checksum()
-
-        name = item['Name']
-        musicBrainzId = API.get_provider('MusicBrainzArtist')
-        genres = " / ".join(item.get('Genres'))
-        bio = API.get_overview()
-
-        # Associate artwork
-        artworks = artwork.get_all_artwork(item, parent_info=True)
-        thumb = artworks['Primary']
-        backdrops = artworks['Backdrop'] # List
-
-        if thumb:
-            thumb = "<thumb>%s</thumb>" % thumb
-        if backdrops:
-            fanart = "<fanart>%s</fanart>" % backdrops[0]
-        else:
-            fanart = ""
-
-
-        ##### UPDATE THE ARTIST #####
-        if update_item:
-            log.info("UPDATE artist itemid: %s - Name: %s" % (itemid, name))
-            # Update the checksum in emby table
-            emby_db.updateReference(itemid, checksum)
-
-        ##### OR ADD THE ARTIST #####
-        else:
-            log.info("ADD artist itemid: %s - Name: %s" % (itemid, name))
-            # 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)
-            # Create the reference in emby table
-            emby_db.addReference(itemid, artistid, artisttype, "artist", checksum=checksum)
-            
-
-        # Process the artist
-        if self.kodiversion in (16, 17):
-            query = ' '.join((
-
-                "UPDATE artist",
-                "SET strGenres = ?, strBiography = ?, strImage = ?, strFanart = ?,",
-                    "lastScraped = ?",
-                "WHERE idArtist = ?"
-            ))
-            kodicursor.execute(query, (genres, bio, thumb, fanart, lastScraped, artistid))
-        else:
-            query = ' '.join((
-
-                "UPDATE artist",
-                "SET strGenres = ?, strBiography = ?, strImage = ?, strFanart = ?,",
-                    "lastScraped = ?, dateAdded = ?",
-                "WHERE idArtist = ?"
-            ))
-            kodicursor.execute(query, (genres, bio, thumb, fanart, lastScraped,
-                    dateadded, artistid))
-
-
-        # Update artwork
-        artwork.add_artwork(artworks, artistid, "artist", kodicursor)
-
-    def add_updateAlbum(self, item):
-        # Process a single artist
-        emby = self.emby
-        kodicursor = self.kodicursor
-        emby_db = self.emby_db
-        artwork = self.artwork
-        API = api.API(item)
-
-        update_item = True
-        itemid = item['Id']
-        emby_dbitem = emby_db.getItem_byId(itemid)
-        try:
-            albumid = emby_dbitem[0]
-        except TypeError:
-            update_item = False
-            log.debug("albumid: %s not found." % itemid)
-
-        ##### The album details #####
-        lastScraped = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
-        dateadded = API.get_date_created()
-        userdata = API.get_userdata()
-        checksum = API.get_checksum()
-
-        name = item['Name']
-        musicBrainzId = API.get_provider('MusicBrainzAlbum')
-        year = item.get('ProductionYear')
-        genres = item.get('Genres')
-        genre = " / ".join(genres)
-        bio = API.get_overview()
-        rating = userdata['UserRating']
-        artists = item['AlbumArtists']
-        if not artists:
-            artists = item['ArtistItems']
-        artistname = []
-        for artist in artists:
-            artistname.append(artist['Name'])
-        artistname = " / ".join(artistname)
-
-        # Associate artwork
-        artworks = artwork.get_all_artwork(item, parent_info=True)
-        thumb = artworks['Primary']
-        if thumb:
-            thumb = "<thumb>%s</thumb>" % thumb
-
-        ##### UPDATE THE ALBUM #####
-        if update_item:
-            log.info("UPDATE album itemid: %s - Name: %s" % (itemid, name))
-            # Update the checksum in emby table
-            emby_db.updateReference(itemid, checksum)
-
-        ##### OR ADD THE ALBUM #####
-        else:
-            log.info("ADD album itemid: %s - Name: %s" % (itemid, name))
-            # 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)
-            # Create the reference in emby table
-            emby_db.addReference(itemid, albumid, "MusicAlbum", "album", checksum=checksum)
-
-
-        # Process the album info
-        if self.kodiversion == 17:
-            # Kodi Krypton
-            query = ' '.join((
-
-                "UPDATE album",
-                "SET strArtists = ?, iYear = ?, strGenres = ?, strReview = ?, strImage = ?,",
-                    "iUserrating = ?, lastScraped = ?, strReleaseType = ?",
-                "WHERE idAlbum = ?"
-            ))
-            kodicursor.execute(query, (artistname, year, genre, bio, thumb, rating, lastScraped,
-                "album", albumid))
-        elif self.kodiversion == 16:
-            # Kodi Jarvis
-            query = ' '.join((
-
-                "UPDATE album",
-                "SET strArtists = ?, iYear = ?, strGenres = ?, strReview = ?, strImage = ?,",
-                    "iRating = ?, lastScraped = ?, strReleaseType = ?",
-                "WHERE idAlbum = ?"
-            ))
-            kodicursor.execute(query, (artistname, year, genre, bio, thumb, rating, lastScraped,
-                "album", albumid))
-        elif self.kodiversion == 15:
-            # Kodi Isengard
-            query = ' '.join((
-
-                "UPDATE album",
-                "SET strArtists = ?, iYear = ?, strGenres = ?, strReview = ?, strImage = ?,",
-                    "iRating = ?, lastScraped = ?, dateAdded = ?, strReleaseType = ?",
-                "WHERE idAlbum = ?"
-            ))
-            kodicursor.execute(query, (artistname, year, genre, bio, thumb, rating, lastScraped,
-                dateadded, "album", albumid))
-        else:
-            # Kodi Helix
-            query = ' '.join((
-
-                "UPDATE album",
-                "SET strArtists = ?, iYear = ?, strGenres = ?, strReview = ?, strImage = ?,",
-                    "iRating = ?, lastScraped = ?, dateAdded = ?",
-                "WHERE idAlbum = ?"
-            ))
-            kodicursor.execute(query, (artistname, year, genre, bio, thumb, rating, lastScraped,
-                dateadded, albumid))
-
-        # Associate the parentid for emby reference
-        parentId = item.get('ParentId')
-        if parentId is not None:
-            emby_dbartist = emby_db.getItem_byId(parentId)
-            try:
-                artistid = emby_dbartist[0]
-            except TypeError:
-                # Artist does not exist in emby database.
-                artist = emby.getItem(parentId)
-                # Item may not be an artist, verification necessary.
-                if artist.get('Type') == "MusicArtist":
-                    # Update with the parentId, for remove reference
-                    emby_db.addReference(parentId, parentId, "MusicArtist", "artist")
-                    emby_db.updateParentId(itemid, parentId)
-            else:
-                # Update emby reference with the artistid
-                emby_db.updateParentId(itemid, artistid)
-
-        # Assign main artists to album
-        for artist in artists:
-            artistname = artist['Name']
-            artistId = artist['Id']
-            emby_dbartist = emby_db.getItem_byId(artistId)
-            try:
-                artistid = emby_dbartist[0]
-            except TypeError:
-                # Artist does not exist in emby database, create the reference
-                artist = emby.getItem(artistId)
-                self.add_updateArtist(artist, artisttype="AlbumArtist")
-                emby_dbartist = emby_db.getItem_byId(artistId)
-                artistid = emby_dbartist[0]
-            else:
-                # Best take this name over anything else.
-                query = "UPDATE artist SET strArtist = ? WHERE idArtist = ?"
-                kodicursor.execute(query, (artistname, artistid,))
-
-            # Add artist to album
-            query = (
-                '''
-                INSERT OR REPLACE INTO album_artist(idArtist, idAlbum, strArtist)
-
-                VALUES (?, ?, ?)
-                '''
-            )
-            kodicursor.execute(query, (artistid, albumid, artistname))
-            # Update discography
-            query = (
-                '''
-                INSERT OR REPLACE INTO discography(idArtist, strAlbum, strYear)
-
-                VALUES (?, ?, ?)
-                '''
-            )
-            kodicursor.execute(query, (artistid, name, year))
-            # Update emby reference with parentid
-            emby_db.updateParentId(artistId, albumid)
-
-        # Add genres
-        self.kodi_db.addMusicGenres(albumid, genres, "album")
-        # Update artwork
-        artwork.add_artwork(artworks, albumid, "album", kodicursor)
-
-    def add_updateSong(self, item):
-        # Process single song
-        kodicursor = self.kodicursor
-        emby = self.emby
-        emby_db = self.emby_db
-        artwork = self.artwork
-        API = api.API(item)
-
-        update_item = True
-        itemid = item['Id']
-        emby_dbitem = emby_db.getItem_byId(itemid)
-        try:
-            songid = emby_dbitem[0]
-            pathid = emby_dbitem[2]
-            albumid = emby_dbitem[3]
-        except TypeError:
-            update_item = False
-            log.debug("songid: %s not found." % itemid)
-            
-        ##### The song details #####
-        checksum = API.get_checksum()
-        dateadded = API.get_date_created()
-        userdata = API.get_userdata()
-        playcount = userdata['PlayCount']
-        dateplayed = userdata['LastPlayedDate']
-
-        # item details
-        title = item['Name']
-        musicBrainzId = API.get_provider('MusicBrainzTrackId')
-        genres = item.get('Genres')
-        genre = " / ".join(genres)
-        artists = " / ".join(item['Artists'])
-        tracknumber = item.get('IndexNumber', 0)
-        disc = item.get('ParentIndexNumber', 1)
-        if disc == 1:
-            track = tracknumber
-        else:
-            track = disc*2**16 + tracknumber
-        year = item.get('ProductionYear')
-        duration = API.get_runtime()
-        rating = userdata['UserRating']
-
-        #if enabled, try to get the rating from file and/or emby
-        if not self.directstream:
-            rating, comment, hasEmbeddedCover = musicutils.getAdditionalSongTags(itemid, rating, API, kodicursor, emby_db, self.enableimportsongrating, self.enableexportsongrating, self.enableupdatesongrating)
-        else:
-            hasEmbeddedCover = False
-            comment = API.get_overview()
-            
-            
-        ##### GET THE FILE AND PATH #####
-        if self.directstream:
-            path = "%s/emby/Audio/%s/" % (self.server, itemid)
-            extensions = ['mp3', 'aac', 'ogg', 'oga', 'webma', 'wma', 'flac']
-
-            if 'Container' in item and item['Container'].lower() in extensions:
-                filename = "stream.%s?static=true" % item['Container']
-            else:
-                filename = "stream.mp3?static=true"
-        else:
-            playurl = API.get_file_path()
-
-            if "\\" in playurl:
-                # Local path
-                filename = playurl.rsplit("\\", 1)[1]
-            else: # Network share
-                filename = playurl.rsplit("/", 1)[1]
-
-            # Direct paths is set the Kodi way
-            if not self.pathValidation(playurl):
-                return False
-            
-            path = playurl.replace(filename, "")
-            window('emby_pathverified', value="true")
-
-        ##### UPDATE THE SONG #####
-        if update_item:
-            log.info("UPDATE song itemid: %s - Title: %s" % (itemid, title))
-            
-            # Update path
-            query = "UPDATE path SET strPath = ? WHERE idPath = ?"
-            kodicursor.execute(query, (path, pathid))
-
-            # Update the song entry
-            query = ' '.join((
-                
-                "UPDATE song",
-                "SET idAlbum = ?, strArtists = ?, strGenres = ?, strTitle = ?, iTrack = ?,",
-                    "iDuration = ?, iYear = ?, strFilename = ?, iTimesPlayed = ?, lastplayed = ?,",
-                    "rating = ?, comment = ?",
-                "WHERE idSong = ?"
-            ))
-            kodicursor.execute(query, (albumid, artists, genre, title, track, duration, year,
-                filename, playcount, dateplayed, rating, comment, songid))
-
-            # Update the checksum in emby table
-            emby_db.updateReference(itemid, checksum)
-        
-        ##### OR ADD THE SONG #####
-        else:
-            log.info("ADD song itemid: %s - Title: %s" % (itemid, title))
-            
-            # Add path
-            pathid = self.kodi_db.addPath(path)
-
-            try:
-                # Get the album
-                emby_dbalbum = emby_db.getItem_byId(item['AlbumId'])
-                albumid = emby_dbalbum[0]
-            except KeyError:
-                # Verify if there's an album associated.
-                album_name = item.get('Album')
-                if album_name:
-                    log.info("Creating virtual music album for song: %s." % itemid)
-                    albumid = self.kodi_db.addAlbum(album_name, API.get_provider('MusicBrainzAlbum'))
-                    emby_db.addReference("%salbum%s" % (itemid, albumid), albumid, "MusicAlbum_", "album")
-                else:
-                    # No album Id associated to the song.
-                    log.error("Song itemid: %s has no albumId associated." % itemid)
-                    return False
-
-            except TypeError:
-                # No album found. Let's create it
-                log.info("Album database entry missing.")
-                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]
-                    log.info("Found albumid: %s" % albumid)
-                except TypeError:
-                    # No album found, create a single's album
-                    log.info("Failed to add album. Creating singles.")
-                    kodicursor.execute("select coalesce(max(idAlbum),0) from album")
-                    albumid = kodicursor.fetchone()[0] + 1
-                    if self.kodiversion == 16:
-                        # Kodi Jarvis
-                        query = (
-                            '''
-                            INSERT INTO album(idAlbum, strGenres, iYear, strReleaseType)
-
-                            VALUES (?, ?, ?, ?)
-                            '''
-                        )
-                        kodicursor.execute(query, (albumid, genre, year, "single"))
-                    elif self.kodiversion == 15:
-                        # Kodi Isengard
-                        query = (
-                            '''
-                            INSERT INTO album(idAlbum, strGenres, iYear, dateAdded, strReleaseType)
-
-                            VALUES (?, ?, ?, ?, ?)
-                            '''
-                        )
-                        kodicursor.execute(query, (albumid, genre, year, dateadded, "single"))
-                    else:
-                        # Kodi Helix
-                        query = (
-                            '''
-                            INSERT INTO album(idAlbum, strGenres, iYear, dateAdded)
-
-                            VALUES (?, ?, ?, ?)
-                            '''
-                        )
-                        kodicursor.execute(query, (albumid, genre, year, dateadded))
-            
-            # Create the song entry
-            kodicursor.execute("select coalesce(max(idSong),0) from song")
-            songid = kodicursor.fetchone()[0] + 1
-            query = (
-                '''
-                INSERT INTO song(
-                    idSong, idAlbum, idPath, strArtists, strGenres, strTitle, iTrack,
-                    iDuration, iYear, strFileName, strMusicBrainzTrackID, iTimesPlayed, lastplayed,
-                    rating)
-
-                VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
-                '''
-            )
-            kodicursor.execute(query, (songid, albumid, pathid, artists, genre, title, track,
-                duration, year, filename, musicBrainzId, playcount, dateplayed, rating))
-
-            # Create the reference in emby table
-            emby_db.addReference(itemid, songid, "Audio", "song", pathid=pathid, parentid=albumid,
-                checksum=checksum)
-
-        
-        # Link song to album
-        query = (
-            '''
-            INSERT OR REPLACE INTO albuminfosong(
-                idAlbumInfoSong, idAlbumInfo, iTrack, strTitle, iDuration)
-            
-            VALUES (?, ?, ?, ?, ?)
-            '''
-        )
-        kodicursor.execute(query, (songid, albumid, track, title, duration))
-        
-        # Link song to artists
-        for index, artist in enumerate(item['ArtistItems']):
-
-            artist_name = artist['Name']
-            artist_eid = artist['Id']
-            artist_edb = emby_db.getItem_byId(artist_eid)
-            try:
-                artistid = artist_edb[0]
-            except TypeError:
-                # Artist is missing from emby database, add it.
-                artist_full = emby.getItem(artist_eid)
-                self.add_updateArtist(artist_full)
-                artist_edb = emby_db.getItem_byId(artist_eid)
-                artistid = artist_edb[0]
-            finally:
-                if self.kodiversion >= 17:
-                    # Kodi Krypton
-                    query = (
-                        '''
-                        INSERT OR REPLACE INTO song_artist(idArtist, idSong, idRole, iOrder, strArtist)
-    
-                        VALUES (?, ?, ?, ?, ?)
-                        '''
-                    )
-                    kodicursor.execute(query, (artistid, songid, 1, index, artist_name))
-                    
-                    # May want to look into only doing this once?
-                    query = ( 
-                        '''
-                        INSERT OR REPLACE INTO role(idRole, strRole)
-    
-                        VALUES (?, ?)
-                        '''
-                    )
-                    kodicursor.execute(query, (1, 'Composer'))                
-                else:
-                    query = (
-                        '''
-                        INSERT OR REPLACE INTO song_artist(idArtist, idSong, iOrder, strArtist)
-    
-                        VALUES (?, ?, ?, ?)
-                        '''
-                    )
-                    kodicursor.execute(query, (artistid, songid, index, artist_name))
-               
-        # Verify if album artist exists
-        album_artists = []
-        for artist in item['AlbumArtists']:
-
-            artist_name = artist['Name']
-            album_artists.append(artist_name)
-            artist_eid = artist['Id']
-            artist_edb = emby_db.getItem_byId(artist_eid)
-            try:
-                artistid = artist_edb[0]
-            except TypeError:
-                # Artist is missing from emby database, add it.
-                artist_full = emby.getItem(artist_eid)
-                self.add_updateArtist(artist_full)
-                artist_edb = emby_db.getItem_byId(artist_eid)
-                artistid = artist_edb[0]
-            finally:
-                query = (
-                    '''
-                    INSERT OR REPLACE INTO album_artist(idArtist, idAlbum, strArtist)
-
-                    VALUES (?, ?, ?)
-                    '''
-                )
-                kodicursor.execute(query, (artistid, albumid, artist_name))
-                # Update discography
-                if item.get('Album'):
-                    query = (
-                        '''
-                        INSERT OR REPLACE INTO discography(idArtist, strAlbum, strYear)
-
-                        VALUES (?, ?, ?)
-                        '''
-                    )
-                    kodicursor.execute(query, (artistid, item['Album'], 0))
-        else:
-            album_artists = " / ".join(album_artists)
-            query = ' '.join((
-
-                "SELECT strArtists",
-                "FROM album",
-                "WHERE idAlbum = ?"
-            ))
-            kodicursor.execute(query, (albumid,))
-            result = kodicursor.fetchone()
-            if result and result[0] != album_artists:
-                # Field is empty
-                if self.kodiversion in (16, 17):
-                    # Kodi Jarvis, Krypton
-                    query = "UPDATE album SET strArtists = ? WHERE idAlbum = ?"
-                    kodicursor.execute(query, (album_artists, albumid))
-                elif self.kodiversion == 15:
-                    # Kodi Isengard
-                    query = "UPDATE album SET strArtists = ? WHERE idAlbum = ?"
-                    kodicursor.execute(query, (album_artists, albumid))
-                else:
-                    # Kodi Helix
-                    query = "UPDATE album SET strArtists = ? WHERE idAlbum = ?"
-                    kodicursor.execute(query, (album_artists, albumid))
-
-        # Add genres
-        self.kodi_db.addMusicGenres(songid, genres, "song")
-        
-        # Update artwork
-        allart = artwork.get_all_artwork(item, parent_info=True)
-        if hasEmbeddedCover:
-            allart["Primary"] = "image://music@" + artwork.single_urlencode( playurl )
-        artwork.add_artwork(allart, songid, "song", kodicursor)
-
-        if item.get('AlbumId') is None:
-            # Update album artwork
-            artwork.add_artwork(allart, albumid, "album", kodicursor)
-
-    def updateUserdata(self, item):
-        # This updates: Favorite, LastPlayedDate, Playcount, PlaybackPositionTicks
-        # Poster with progress bar
-        kodicursor = self.kodicursor
-        emby_db = self.emby_db
-        API = api.API(item)
-
-        # Get emby information
-        itemid = item['Id']
-        checksum = API.get_checksum()
-        userdata = API.get_userdata()
-        runtime = API.get_runtime()
-        rating = userdata['UserRating']
-
-        # Get Kodi information
-        emby_dbitem = emby_db.getItem_byId(itemid)
-        try:
-            kodiid = emby_dbitem[0]
-            mediatype = emby_dbitem[4]
-            log.info("Update playstate for %s: %s" % (mediatype, item['Name']))
-        except TypeError:
-            return
-
-        if mediatype == "song":
-            
-            #should we ignore this item ?
-            #happens when userdata updated by ratings method
-            if window("ignore-update-%s" %itemid):
-                window("ignore-update-%s" %itemid,clear=True)
-                return
-                
-            # Process playstates
-            playcount = userdata['PlayCount']
-            dateplayed = userdata['LastPlayedDate']
-            
-            #process item ratings
-            rating, comment, hasEmbeddedCover = musicutils.getAdditionalSongTags(itemid, rating, API, kodicursor, emby_db, self.enableimportsongrating, self.enableexportsongrating, self.enableupdatesongrating)
-            
-            query = "UPDATE song SET iTimesPlayed = ?, lastplayed = ?, rating = ? WHERE idSong = ?"
-            kodicursor.execute(query, (playcount, dateplayed, rating, kodiid))
-
-        elif mediatype == "album":
-            # Process playstates
-            if self.kodiversion >= 17:
-                query = "UPDATE album SET fRating = ? WHERE idAlbum = ?"
-            else:
-                query = "UPDATE album SET iRating = ? WHERE idAlbum = ?"            
-            kodicursor.execute(query, (rating, kodiid))
-
-        emby_db.updateReference(itemid, checksum)
-
-    def remove(self, itemid):
-        # Remove kodiid, fileid, pathid, emby reference
-        emby_db = self.emby_db
-        kodicursor = self.kodicursor
-        artwork = self.artwork
-
-        emby_dbitem = emby_db.getItem_byId(itemid)
-        try:
-            kodiid = emby_dbitem[0]
-            mediatype = emby_dbitem[4]
-            log.info("Removing %s kodiid: %s" % (mediatype, kodiid))
-        except TypeError:
-            return
-
-        ##### PROCESS ITEM #####
-
-        # Remove the emby reference
-        emby_db.removeItem(itemid)
-
-
-        ##### IF SONG #####
-
-        if mediatype == "song":
-            # Delete song
-            self.removeSong(kodiid)
-            # This should only address single song scenario, where server doesn't actually
-            # create an album for the song. 
-            emby_db.removeWildItem(itemid)
-
-            for item in emby_db.getItem_byWildId(itemid):
-
-                item_kid = item[0]
-                item_mediatype = item[1]
-
-                if item_mediatype == "album":
-                    childs = emby_db.getItem_byParentId(item_kid, "song")
-                    if not childs:
-                        # Delete album
-                        self.removeAlbum(item_kid)
-
-        ##### IF ALBUM #####
-
-        elif mediatype == "album":
-            # Delete songs, album
-            album_songs = emby_db.getItem_byParentId(kodiid, "song")
-            for song in album_songs:
-                self.removeSong(song[1])
-            else:
-                # Remove emby songs
-                emby_db.removeItems_byParentId(kodiid, "song")
-
-            # Remove the album
-            self.removeAlbum(kodiid)
-
-        ##### IF ARTIST #####
-
-        elif mediatype == "artist":
-            # Delete songs, album, artist
-            albums = emby_db.getItem_byParentId(kodiid, "album")
-            for album in albums:
-                albumid = album[1]
-                album_songs = emby_db.getItem_byParentId(albumid, "song")
-                for song in album_songs:
-                    self.removeSong(song[1])
-                else:
-                    # Remove emby song
-                    emby_db.removeItems_byParentId(albumid, "song")
-                    # Remove emby artist
-                    emby_db.removeItems_byParentId(albumid, "artist")
-                    # Remove kodi album
-                    self.removeAlbum(albumid)
-            else:
-                # Remove emby albums
-                emby_db.removeItems_byParentId(kodiid, "album")
-
-            # Remove artist
-            self.removeArtist(kodiid)
-
-        log.info("Deleted %s: %s from kodi database" % (mediatype, itemid))
-
-    def removeSong(self, kodiId):
-
-        kodicursor = self.kodicursor
-
-        self.artwork.delete_artwork(kodiId, "song", self.kodicursor)
-        self.kodicursor.execute("DELETE FROM song WHERE idSong = ?", (kodiId,))
-
-    def removeAlbum(self, kodiId):
-
-        self.artwork.delete_artwork(kodiId, "album", self.kodicursor)
-        self.kodicursor.execute("DELETE FROM album WHERE idAlbum = ?", (kodiId,))
-
-    def removeArtist(self, kodiId):
-
-        self.artwork.delete_artwork(kodiId, "artist", self.kodicursor)
-        self.kodicursor.execute("DELETE FROM artist WHERE idArtist = ?", (kodiId,))
\ No newline at end of file
+        return (True, update_videolibrary)
\ No newline at end of file
diff --git a/resources/lib/librarysync.py b/resources/lib/librarysync.py
index 5d8857f1..19aaec77 100644
--- a/resources/lib/librarysync.py
+++ b/resources/lib/librarysync.py
@@ -21,7 +21,8 @@ import kodidb_functions as kodidb
 import read_embyserver as embyserver
 import userclient
 import videonodes
-from utils import window, settings, language as lang
+from objects import Movies, MusicVideos, TVShows, Music
+from utils import window, settings, language as lang, should_stop
 from ga_client import GoogleAnalytics
 
 ##################################################################################################
@@ -186,15 +187,6 @@ class LibrarySync(threading.Thread):
         finally:
             settings('LastIncrementalSync', value=lastSync)
 
-    def shouldStop(self):
-        # Checkpoint during the syncing process
-        if self.monitor.abortRequested():
-            return True
-        elif window('emby_shouldStop') == "true":
-            return True
-        else: # Keep going
-            return False
-
     def dbCommit(self, connection):
         # Central commit, verifies if Kodi database update is running
         kodidb_scan = window('emby_kodiScan') == "true"
@@ -209,7 +201,7 @@ class LibrarySync(threading.Thread):
                 log.info("Flag still active, but will try to commit")
                 window('emby_kodiScan', clear=True)
 
-            if self.shouldStop():
+            if should_stop():
                 log.info("Commit unsuccessful. Sync terminated.")
                 break
 
@@ -618,7 +610,7 @@ class LibrarySync(threading.Thread):
 
         # Get movies from emby
         emby_db = embydb.Embydb_Functions(embycursor)
-        movies = itemtypes.Movies(embycursor, kodicursor)
+        movies = Movies(embycursor, kodicursor, pdialog)
 
         views = emby_db.getView_byType('movies')
         views += emby_db.getView_byType('mixed')
@@ -628,39 +620,18 @@ class LibrarySync(threading.Thread):
         for view in views:
 
             log.info("Processing: %s", view)
-            
-            if self.shouldStop():
-                return False
+            view_name = view['name']
 
             # Get items per view
             if pdialog:
                 pdialog.update(
                         heading=lang(29999),
-                        message="%s %s..." % (lang(33017), view['name']))
+                        message="%s %s..." % (lang(33017), view_name))
 
-            # Initial or repair sync
-            all_embymovies = self.emby.getMovies(view['id'], dialog=pdialog)
-            total = all_embymovies['TotalRecordCount']
-            embymovies = all_embymovies['Items']
-
-            if pdialog:
-                pdialog.update(heading="Processing %s / %s items" % (view['name'], total))
-
-            count = 0
-            for embymovie in embymovies:
-                # Process individual movies
-                if self.shouldStop():
-                    return False
-
-                title = embymovie['Name']
-                if pdialog:
-                    percentage = int((float(count) / float(total))*100)
-                    pdialog.update(percentage, message=title)
-                    count += 1
-                movies.add_update(embymovie, view['name'], view['id'])
-        else:
-            log.debug("Movies finished.")
+            all_movies = self.emby.getMovies(view['id'], dialog=pdialog)
+            movies.add_all("Movie", all_movies, view)
 
+        log.debug("Movies finished.")
 
         ##### PROCESS BOXSETS #####
         if pdialog:
@@ -668,25 +639,9 @@ class LibrarySync(threading.Thread):
 
         boxsets = self.emby.getBoxset(dialog=pdialog)
         total = boxsets['TotalRecordCount']
-        embyboxsets = boxsets['Items']
 
-        if pdialog:
-            pdialog.update(heading="Processing Boxsets / %s items" % total)
-
-        count = 0
-        for boxset in embyboxsets:
-            # Process individual boxset
-            if self.shouldStop():
-                return False
-
-            title = boxset['Name']
-            if pdialog:
-                percentage = int((float(count) / float(total))*100)
-                pdialog.update(percentage, message=title)
-                count += 1
-            movies.add_updateBoxset(boxset)
-        else:
-            log.debug("Boxsets finished.")
+        movies.process_all("BoxSet", "added", boxsets['Items'], total)
+        log.debug("Boxsets finished.")
 
         return True
 
@@ -694,15 +649,13 @@ class LibrarySync(threading.Thread):
 
         # Get musicvideos from emby
         emby_db = embydb.Embydb_Functions(embycursor)
-        mvideos = itemtypes.MusicVideos(embycursor, kodicursor)
+        mvideos = MusicVideos(embycursor, kodicursor, pdialog)
 
         views = emby_db.getView_byType('musicvideos')
         log.info("Media folders: %s" % views)
 
         for view in views:
-
-            if self.shouldStop():
-                return False
+            log.info("Processing: %s", view)
 
             # Get items per view
             viewId = view['id']
@@ -714,25 +667,9 @@ class LibrarySync(threading.Thread):
                         message="%s %s..." % (lang(33019), viewName))
 
             # Initial or repair sync
-            all_embymvideos = self.emby.getMusicVideos(viewId, dialog=pdialog)
-            total = all_embymvideos['TotalRecordCount']
-            embymvideos = all_embymvideos['Items']
+            all_mvideos = self.emby.getMusicVideos(viewId, dialog=pdialog)
+            mvideos.add_all("MusicVideo", all_mvideos, view)
 
-            if pdialog:
-                pdialog.update(heading="Processing %s / %s items" % (viewName, total))
-
-            count = 0
-            for embymvideo in embymvideos:
-                # Process individual musicvideo
-                if self.shouldStop():
-                    return False
-
-                title = embymvideo['Name']
-                if pdialog:
-                    percentage = int((float(count) / float(total))*100)
-                    pdialog.update(percentage, message=title)
-                    count += 1
-                mvideos.add_update(embymvideo, viewName, viewId)
         else:
             log.debug("MusicVideos finished.")
 
@@ -742,7 +679,7 @@ class LibrarySync(threading.Thread):
 
         # Get shows from emby
         emby_db = embydb.Embydb_Functions(embycursor)
-        tvshows = itemtypes.TVShows(embycursor, kodicursor)
+        tvshows = TVShows(embycursor, kodicursor, pdialog)
 
         views = emby_db.getView_byType('tvshows')
         views += emby_db.getView_byType('mixed')
@@ -750,47 +687,15 @@ class LibrarySync(threading.Thread):
 
         for view in views:
 
-            if self.shouldStop():
-                return False
-
             # Get items per view
             if pdialog:
                 pdialog.update(
                         heading=lang(29999),
                         message="%s %s..." % (lang(33020), view['name']))
 
-            all_embytvshows = self.emby.getShows(view['id'], dialog=pdialog)
-            total = all_embytvshows['TotalRecordCount']
-            embytvshows = all_embytvshows['Items']
+            all_tvshows = self.emby.getShows(view['id'], dialog=pdialog)
+            tvshows.add_all("Series", all_tvshows, view)
 
-            if pdialog:
-                pdialog.update(heading="Processing %s / %s items" % (view['name'], total))
-
-            count = 0
-            for embytvshow in embytvshows:
-                # Process individual show
-                if self.shouldStop():
-                    return False
-
-                title = embytvshow['Name']
-                if pdialog:
-                    percentage = int((float(count) / float(total))*100)
-                    pdialog.update(percentage, message=title)
-                    count += 1
-                tvshows.add_update(embytvshow, view['name'], view['id'])
-
-                # Process episodes
-                all_episodes = self.emby.getEpisodesbyShow(embytvshow['Id'])
-                for episode in all_episodes['Items']:
-
-                    # Process individual show
-                    if self.shouldStop():
-                        return False
-
-                    episodetitle = episode['Name']
-                    if pdialog:
-                        pdialog.update(percentage, message="%s - %s" % (title, episodetitle))
-                    tvshows.add_updateEpisode(episode)
         else:
             log.debug("TVShows finished.")
 
@@ -799,41 +704,21 @@ class LibrarySync(threading.Thread):
     def music(self, embycursor, kodicursor, pdialog):
         # Get music from emby
         emby_db = embydb.Embydb_Functions(embycursor)
-        music = itemtypes.Music(embycursor, kodicursor)
+        music = Music(embycursor, kodicursor, pdialog)
 
-        process = {
+        views = emby_db.getView_byType('music')
+        log.info("Media folders: %s", views)
 
-            'artists': [self.emby.getArtists, music.add_updateArtist],
-            'albums': [self.emby.getAlbums, music.add_updateAlbum],
-            'songs': [self.emby.getSongs, music.add_updateSong]
-        }
-        for itemtype in ['artists', 'albums', 'songs']:
+        # Add music artists and everything will fall into place
+        if pdialog:
+            pdialog.update(heading=lang(29999),
+                           message="%s Music..." % lang(33021))
 
-            if pdialog:
-                pdialog.update(
-                    heading=lang(29999),
-                    message="%s %s..." % (lang(33021), itemtype))
+        for view in views:
+            all_artists = self.emby.getArtists(view['id'], dialog=pdialog)
+            music.add_all("MusicArtist", all_artists)
 
-            all_embyitems = process[itemtype][0](dialog=pdialog)
-            total = all_embyitems['TotalRecordCount']
-            embyitems = all_embyitems['Items']
-
-            if pdialog:
-                pdialog.update(heading="Processing %s / %s items" % (itemtype, total))
-
-            count = 0
-            for embyitem in embyitems:
-                # Process individual item
-                if self.shouldStop():
-                    return False
-                if pdialog:
-                    percentage = int((float(count) / float(total))*100)
-                    pdialog.update(percentage, message=embyitem['Name'])
-                    count += 1
-
-                process[itemtype][1](embyitem)
-            else:
-                log.debug("%s finished." % itemtype)
+        log.debug("Finished syncing music")
 
         return True
 
@@ -1123,447 +1008,13 @@ class ManualSync(LibrarySync):
 
 
     def movies(self, embycursor, kodicursor, pdialog):
-
-        # 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')
-        log.info("Media folders: %s" % views)
-
-        # Pull the list of movies and boxsets in Kodi
-        try:
-            all_kodimovies = dict(emby_db.get_checksum('Movie'))
-        except ValueError:
-            all_kodimovies = {}
-
-        try:
-            all_kodisets = dict(emby_db.get_checksum('BoxSet'))
-        except ValueError:
-            all_kodisets = {}
-
-        all_embymoviesIds = set()
-        all_embyboxsetsIds = set()
-        updatelist = []
-
-        ##### PROCESS MOVIES #####
-        for view in views:
-
-            if self.shouldStop():
-                return False
-
-            # Get items per view
-            viewId = view['id']
-            viewName = view['name']
-
-            if pdialog:
-                pdialog.update(
-                        heading=lang(29999),
-                        message="%s %s..." % (lang(33026), viewName))
-
-            all_embymovies = self.emby.getMovies(viewId, basic=True, dialog=pdialog)
-            for embymovie in all_embymovies['Items']:
-
-                if self.shouldStop():
-                    return False
-
-                API = api.API(embymovie)
-                itemid = embymovie['Id']
-                all_embymoviesIds.add(itemid)
-
-
-                if all_kodimovies.get(itemid) != API.get_checksum():
-                    # Only update if movie is not in Kodi or checksum is different
-                    updatelist.append(itemid)
-
-            log.info("Movies to update for %s: %s" % (viewName, updatelist))
-            embymovies = self.emby.getFullItems(updatelist)
-            total = len(updatelist)
-            del updatelist[:]
-
-            if pdialog:
-                pdialog.update(heading="Processing %s / %s items" % (viewName, total))
-
-            count = 0
-            for embymovie in embymovies:
-                # Process individual movies
-                if self.shouldStop():
-                    return False
-
-                if pdialog:
-                    percentage = int((float(count) / float(total))*100)
-                    pdialog.update(percentage, message=embymovie['Name'])
-                    count += 1
-                movies.add_update(embymovie, viewName, viewId)
-
-        ##### PROCESS BOXSETS #####
-
-        boxsets = self.emby.getBoxset(dialog=pdialog)
-        embyboxsets = []
-
-        if pdialog:
-            pdialog.update(heading=lang(29999), message=lang(33027))
-
-        for boxset in boxsets['Items']:
-
-            if self.shouldStop():
-                return False
-
-            # Boxset has no real userdata, so using etag to compare
-            itemid = boxset['Id']
-            all_embyboxsetsIds.add(itemid)
-
-            if all_kodisets.get(itemid) != boxset['Etag']:
-                # Only update if boxset is not in Kodi or boxset['Etag'] is different
-                updatelist.append(itemid)
-                embyboxsets.append(boxset)
-
-        log.info("Boxsets to update: %s" % updatelist)
-        total = len(updatelist)
-
-        if pdialog:
-            pdialog.update(heading="Processing Boxsets / %s items" % total)
-
-        count = 0
-        for boxset in embyboxsets:
-            # Process individual boxset
-            if self.shouldStop():
-                return False
-
-            if pdialog:
-                percentage = int((float(count) / float(total))*100)
-                pdialog.update(percentage, message=boxset['Name'])
-                count += 1
-            movies.add_updateBoxset(boxset)
-
-        ##### PROCESS DELETES #####
-
-        for kodimovie in all_kodimovies:
-            if kodimovie not in all_embymoviesIds:
-                movies.remove(kodimovie)
-        else:
-            log.info("Movies compare finished.")
-
-        for boxset in all_kodisets:
-            if boxset not in all_embyboxsetsIds:
-                movies.remove(boxset)
-        else:
-            log.info("Boxsets compare finished.")
-
-        return True
+        return Movies(embycursor, kodicursor, pdialog).compare_all()
 
     def musicvideos(self, embycursor, kodicursor, pdialog):
-
-        # Get musicvideos from emby
-        emby_db = embydb.Embydb_Functions(embycursor)
-        mvideos = itemtypes.MusicVideos(embycursor, kodicursor)
-
-        views = emby_db.getView_byType('musicvideos')
-        log.info("Media folders: %s" % views)
-
-        # Pull the list of musicvideos in Kodi
-        try:
-            all_kodimvideos = dict(emby_db.get_checksum('MusicVideo'))
-        except ValueError:
-            all_kodimvideos = {}
-
-        all_embymvideosIds = set()
-        updatelist = []
-
-        for view in views:
-
-            if self.shouldStop():
-                return False
-
-            # Get items per view
-            viewId = view['id']
-            viewName = view['name']
-
-            if pdialog:
-                pdialog.update(
-                        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']:
-
-                if self.shouldStop():
-                    return False
-
-                API = api.API(embymvideo)
-                itemid = embymvideo['Id']
-                all_embymvideosIds.add(itemid)
-
-
-                if all_kodimvideos.get(itemid) != API.get_checksum():
-                    # Only update if musicvideo is not in Kodi or checksum is different
-                    updatelist.append(itemid)
-
-            log.info("MusicVideos to update for %s: %s" % (viewName, updatelist))
-            embymvideos = self.emby.getFullItems(updatelist)
-            total = len(updatelist)
-            del updatelist[:]
-
-
-            if pdialog:
-                pdialog.update(heading="Processing %s / %s items" % (viewName, total))
-
-            count = 0
-            for embymvideo in embymvideos:
-                # Process individual musicvideo
-                if self.shouldStop():
-                    return False
-
-                if pdialog:
-                    percentage = int((float(count) / float(total))*100)
-                    pdialog.update(percentage, message=embymvideo['Name'])
-                    count += 1
-                mvideos.add_update(embymvideo, viewName, viewId)
-
-        ##### PROCESS DELETES #####
-
-        for kodimvideo in all_kodimvideos:
-            if kodimvideo not in all_embymvideosIds:
-                mvideos.remove(kodimvideo)
-        else:
-            log.info("MusicVideos compare finished.")
-
-        return True
+        return MusicVideos(embycursor, kodicursor, pdialog).compare_all()
 
     def tvshows(self, embycursor, kodicursor, pdialog):
-
-        # 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')
-        log.info("Media folders: %s" % views)
-
-        # Pull the list of tvshows and episodes in Kodi
-        try:
-            all_koditvshows = dict(emby_db.get_checksum('Series'))
-        except ValueError:
-            all_koditvshows = {}
-
-        log.info("all_koditvshows = %s", all_koditvshows)
-
-        try:
-            all_kodiepisodes = dict(emby_db.get_checksum('Episode'))
-        except ValueError:
-            all_kodiepisodes = {}
-
-        all_embytvshowsIds = set()
-        all_embyepisodesIds = set()
-        updatelist = []
-
-
-        for view in views:
-
-            if self.shouldStop():
-                return False
-
-            # Get items per view
-            viewId = view['id']
-            viewName = view['name']
-
-            if pdialog:
-                pdialog.update(
-                        heading=lang(29999),
-                        message="%s %s..." % (lang(33029), viewName))
-
-            all_embytvshows = self.emby.getShows(viewId, basic=True, dialog=pdialog)
-            for embytvshow in all_embytvshows['Items']:
-
-                if self.shouldStop():
-                    return False
-
-                API = api.API(embytvshow)
-                itemid = embytvshow['Id']
-                all_embytvshowsIds.add(itemid)
-
-
-                if all_koditvshows.get(itemid) != API.get_checksum():
-                    # Only update if movie is not in Kodi or checksum is different
-                    updatelist.append(itemid)
-
-            log.info("TVShows to update for %s: %s" % (viewName, updatelist))
-            embytvshows = self.emby.getFullItems(updatelist)
-            total = len(updatelist)
-            del updatelist[:]
-
-
-            if pdialog:
-                pdialog.update(heading="Processing %s / %s items" % (viewName, total))
-
-            count = 0
-            for embytvshow in embytvshows:
-                # Process individual show
-                if self.shouldStop():
-                    return False
-
-                itemid = embytvshow['Id']
-                title = embytvshow['Name']
-                all_embytvshowsIds.add(itemid)
-                if pdialog:
-                    percentage = int((float(count) / float(total))*100)
-                    pdialog.update(percentage, message=title)
-                    count += 1
-                tvshows.add_update(embytvshow, viewName, viewId)
-
-            else:
-                # Get all episodes in view
-                if pdialog:
-                    pdialog.update(
-                            heading=lang(29999),
-                            message="%s %s..." % (lang(33030), viewName))
-
-                all_embyepisodes = self.emby.getEpisodes(viewId, basic=True, dialog=pdialog)
-                for embyepisode in all_embyepisodes['Items']:
-
-                    if self.shouldStop():
-                        return False
-
-                    API = api.API(embyepisode)
-                    itemid = embyepisode['Id']
-                    all_embyepisodesIds.add(itemid)
-                    if "SeriesId" in embyepisode:
-                        all_embytvshowsIds.add(embyepisode['SeriesId'])
-
-                    if all_kodiepisodes.get(itemid) != API.get_checksum():
-                        # Only update if movie is not in Kodi or checksum is different
-                        updatelist.append(itemid)
-
-                log.info("Episodes to update for %s: %s" % (viewName, updatelist))
-                embyepisodes = self.emby.getFullItems(updatelist)
-                total = len(updatelist)
-                del updatelist[:]
-
-                count = 0
-                for episode in embyepisodes:
-
-                    # Process individual episode
-                    if self.shouldStop():
-                        return False
-
-                    if pdialog:
-                        percentage = int((float(count) / float(total))*100)
-                        title = "%s - %s" % (episode.get('SeriesName', "Unknown"), episode['Name'])
-                        pdialog.update(percentage, message=title)
-                        count += 1
-                    tvshows.add_updateEpisode(episode)
-
-        ##### PROCESS DELETES #####
-
-        log.info("all_embytvshowsIds = %s " % all_embytvshowsIds)
-
-        for koditvshow in all_koditvshows:
-            if koditvshow not in all_embytvshowsIds:
-                tvshows.remove(koditvshow)
-        else:
-            log.info("TVShows compare finished.")
-
-        for kodiepisode in all_kodiepisodes:
-            if kodiepisode not in all_embyepisodesIds:
-                tvshows.remove(kodiepisode)
-        else:
-            log.info("Episodes compare finished.")
-
-        return True
+        return TVShows(embycursor, kodicursor, pdialog).compare_all()
 
     def music(self, embycursor, kodicursor, pdialog):
-
-        # Get music from emby
-        emby_db = embydb.Embydb_Functions(embycursor)
-        music = itemtypes.Music(embycursor, kodicursor)
-
-        # Pull the list of artists, albums, songs
-        try:
-            all_kodiartists = dict(emby_db.get_checksum('MusicArtist'))
-        except ValueError:
-            all_kodiartists = {}
-
-        try:
-            all_kodialbums = dict(emby_db.get_checksum('MusicAlbum'))
-        except ValueError:
-            all_kodialbums = {}
-
-        try:
-            all_kodisongs = dict(emby_db.get_checksum('Audio'))
-        except ValueError:
-            all_kodisongs = {}
-
-        all_embyartistsIds = set()
-        all_embyalbumsIds = set()
-        all_embysongsIds = set()
-        updatelist = []
-
-        process = {
-
-            'artists': [self.emby.getArtists, music.add_updateArtist],
-            'albums': [self.emby.getAlbums, music.add_updateAlbum],
-            'songs': [self.emby.getSongs, music.add_updateSong]
-        }
-        for data_type in ['artists', 'albums', 'songs']:
-            if pdialog:
-                pdialog.update(
-                        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:
-                all_embyitems = process[data_type][0](dialog=pdialog)
-            for embyitem in all_embyitems['Items']:
-                if self.shouldStop():
-                    return False
-                API = api.API(embyitem)
-                itemid = embyitem['Id']
-                if data_type == "artists":
-                    all_embyartistsIds.add(itemid)
-                    if all_kodiartists.get(itemid) != API.get_checksum():
-                        # Only update if artist is not in Kodi or checksum is different
-                        updatelist.append(itemid)
-                elif data_type == "albums":
-                    all_embyalbumsIds.add(itemid)
-                    if all_kodialbums.get(itemid) != API.get_checksum():
-                        # Only update if album is not in Kodi or checksum is different
-                        updatelist.append(itemid)
-                else:
-                    all_embysongsIds.add(itemid)
-                    if all_kodisongs.get(itemid) != API.get_checksum():
-                        # Only update if songs is not in Kodi or checksum is different
-                        updatelist.append(itemid)
-            log.info("%s to update: %s" % (data_type, updatelist))
-            embyitems = self.emby.getFullItems(updatelist)
-            total = len(updatelist)
-            del updatelist[:]
-            if pdialog:
-                pdialog.update(heading="Processing %s / %s items" % (data_type, total))
-            count = 0
-            for embyitem in embyitems:
-                # Process individual item
-                if self.shouldStop():
-                    return False
-                if pdialog:
-                    percentage = int((float(count) / float(total))*100)
-                    pdialog.update(percentage, message=embyitem['Name'])
-                    count += 1
-                process[data_type][1](embyitem)
-        ##### PROCESS DELETES #####
-        for kodiartist in all_kodiartists:
-            if kodiartist not in all_embyartistsIds and all_kodiartists[kodiartist] is not None:
-                music.remove(kodiartist)
-        else:
-            log.info("Artist compare finished.")
-        for kodialbum in all_kodialbums:
-            if kodialbum not in all_embyalbumsIds:
-                music.remove(kodialbum)
-        else:
-            log.info("Albums compare finished.")
-        for kodisong in all_kodisongs:
-            if kodisong not in all_embysongsIds:
-                music.remove(kodisong)
-        else:
-            log.info("Songs compare finished.")
-        return True
\ No newline at end of file
+        return Music(embycursor, kodicursor).compare_all()
diff --git a/resources/lib/objects/__init__.py b/resources/lib/objects/__init__.py
new file mode 100644
index 00000000..5219542a
--- /dev/null
+++ b/resources/lib/objects/__init__.py
@@ -0,0 +1,5 @@
+# Dummy file to make this directory a package.
+from movies import Movies
+from musicvideos import MusicVideos
+from tvshows import TVShows
+from music import Music
diff --git a/resources/lib/objects/common.py b/resources/lib/objects/common.py
new file mode 100644
index 00000000..797c0607
--- /dev/null
+++ b/resources/lib/objects/common.py
@@ -0,0 +1,126 @@
+# -*- coding: utf-8 -*-
+
+##################################################################################################
+
+import logging
+
+import xbmc
+import xbmcgui
+import xbmcvfs
+
+import artwork
+import downloadutils
+import read_embyserver as embyserver
+from utils import window, settings, dialog, language as lang, should_stop
+
+##################################################################################################
+
+log = logging.getLogger("EMBY."+__name__)
+
+##################################################################################################
+
+
+class Items(object):
+
+    pdialog = None
+    title = None
+    count = 0
+    total = 0
+
+
+    def __init__(self, **kwargs):
+
+        self.artwork = artwork.Artwork()
+        self.emby = embyserver.Read_EmbyServer()
+        self.do_url = downloadutils.DownloadUtils().downloadUrl
+        self.should_stop = should_stop
+
+        self.kodi_version = int(xbmc.getInfoLabel('System.BuildVersion')[:2])
+        self.direct_path = settings('useDirectPaths') == "1"
+        self.content_msg = settings('newContent') == "true"
+
+    def path_validation(self, path):
+        # Verify if direct path is accessible or not
+        if window('emby_pathverified') != "true" and not xbmcvfs.exists(path):
+            if dialog(type_="yesno",
+                      heading="{emby}",
+                      line1="%s %s. %s" % (lang(33047), path, lang(33048))):
+
+                window('emby_shouldStop', value="true")
+                return False
+
+        return True
+
+    def content_pop(self):
+        # It's possible for the time to be 0. It should be considered disabled in this case.
+        if not self.pdialog and self.content_msg and self.new_time: 
+            dialog(type_="notification",
+                   heading="{emby}",
+                   message="%s %s" % (lang(33049), name),
+                   icon="{emby}",
+                   time=time,
+                   sound=False)
+
+    def update_pdialog(self):
+
+        if self.pdialog:
+            percentage = int((float(self.count) / float(self.total))*100)
+            self.pdialog.update(percentage, message=self.title)
+
+    def add_all(self, item_type, items, view=None):
+
+        if self.should_stop():
+            return False
+
+        total = items['TotalRecordCount'] if 'TotalRecordCount' in items else len(items)
+        items = items['Items'] if 'Items' in items else items
+
+        if self.pdialog and view:
+            self.pdialog.update(heading="Processing %s / %s items" % (view['name'], total))
+
+        action = self._get_func(item_type, "added")
+        if view:
+            action(items, total, view)
+        else:
+            action(items, total)
+
+    def process_all(self, item_type, action, items, total=None, view=None):
+
+        log.debug("Processing %s: %s", action, items)
+
+        process = self._get_func(item_type, action)
+        self.total = total or len(items)
+        self.count = 0
+
+        for item in items:
+
+            if self.should_stop():
+                return False
+
+            if not process:
+                continue
+
+            self.title = item.get('Name', "unknown")
+            self.update_pdialog()
+
+            process(item)
+            self.count += 1
+
+    def added(self, items, total=None, update=True):
+        # Generator for newly added content
+        if update:
+            self.total = total or len(items)
+            self.count = 0
+
+        for item in items:
+
+            if self.should_stop():
+                break
+
+            self.title = item.get('Name', "unknown")
+
+            yield item
+            self.update_pdialog()
+
+            if update:
+                self.count += 1
diff --git a/resources/lib/objects/movies.py b/resources/lib/objects/movies.py
new file mode 100644
index 00000000..c051272b
--- /dev/null
+++ b/resources/lib/objects/movies.py
@@ -0,0 +1,572 @@
+# -*- coding: utf-8 -*-
+
+##################################################################################################
+
+import logging
+import urllib
+from ntpath import dirname
+from datetime import datetime
+
+import api
+import common
+import downloadutils
+import embydb_functions as embydb
+import kodidb_functions as kodidb
+from utils import window, settings, language as lang, catch_except
+
+##################################################################################################
+
+log = logging.getLogger("EMBY."+__name__)
+
+##################################################################################################
+
+    
+class Movies(common.Items):
+
+    
+    def __init__(self, embycursor, kodicursor, pdialog=None):
+        
+        self.embycursor = embycursor
+        self.emby_db = embydb.Embydb_Functions(self.embycursor)
+        self.kodicursor = kodicursor
+        self.kodi_db = kodidb.Kodidb_Functions(self.kodicursor)
+        self.pdialog = pdialog
+
+        self.new_time = int(settings('newvideotime'))*1000
+        
+        common.Items.__init__(self)
+
+    def _get_func(self, item_type, action):
+
+        if item_type == "Movie":
+            actions = {
+                'added': self.added,
+                'update': self.add_update,
+                'userdata': self.updateUserdata,
+                'remove': self.remove
+            }
+        elif item_type == "BoxSet":
+            actions = {
+                'added': self.add_updateBoxset,
+                'update': self.add_updateBoxset,
+                'remove': self.remove
+            }
+        else:
+            log.info("Unsupported item_type: %s", item_type)
+            actions = {}
+
+        return actions.get(action)
+
+    def compare_all(self):
+        # Pull the list of movies and boxsets in Kodi
+        pdialog = self.pdialog
+        views = self.emby_db.getView_byType('movies')
+        views += self.emby_db.getView_byType('mixed')
+        log.info("Media folders: %s" % views)
+
+        try:
+            all_kodisets = dict(self.emby_db.get_checksum('BoxSet'))
+        except ValueError:
+            all_kodisets = {}
+
+        try:
+            all_kodimovies = dict(self.emby_db.get_checksum('Movie'))
+        except ValueError:
+            all_kodimovies = {}
+
+        all_embymoviesIds = set()
+        all_embyboxsetsIds = set()
+        updatelist = []
+
+        for view in views:
+
+            if self.should_stop():
+                return False
+
+            # Get items per view
+            viewId = view['id']
+            viewName = view['name']
+
+            if pdialog:
+                pdialog.update(
+                        heading=lang(29999),
+                        message="%s %s..." % (lang(33026), viewName))
+
+            all_embymovies = self.emby.getMovies(viewId, basic=True, dialog=pdialog)
+            for embymovie in all_embymovies['Items']:
+
+                if self.should_stop():
+                    return False
+
+                API = api.API(embymovie)
+                itemid = embymovie['Id']
+                all_embymoviesIds.add(itemid)
+
+
+                if all_kodimovies.get(itemid) != API.get_checksum():
+                    # Only update if movie is not in Kodi or checksum is different
+                    updatelist.append(itemid)
+
+            log.info("Movies to update for %s: %s" % (viewName, updatelist))
+            embymovies = self.emby.getFullItems(updatelist)
+            total = len(updatelist)
+            del updatelist[:]
+
+            if pdialog:
+                pdialog.update(heading="Processing %s / %s items" % (viewName, total))
+
+            self.added(embymovies, total, view)
+
+        boxsets = self.emby.getBoxset(dialog=pdialog)
+        embyboxsets = []
+
+        if pdialog:
+            pdialog.update(heading=lang(29999), message=lang(33027))
+
+        for boxset in boxsets['Items']:
+
+            if self.should_stop():
+                return False
+
+            # Boxset has no real userdata, so using etag to compare
+            itemid = boxset['Id']
+            all_embyboxsetsIds.add(itemid)
+
+            if all_kodisets.get(itemid) != boxset['Etag']:
+                # Only update if boxset is not in Kodi or boxset['Etag'] is different
+                updatelist.append(itemid)
+                embyboxsets.append(boxset)
+
+        log.info("Boxsets to update: %s" % updatelist)
+        self.total = len(updatelist)
+
+        if pdialog:
+            pdialog.update(heading="Processing Boxsets / %s items" % total)
+
+        self.count = 0
+        for boxset in embyboxsets:
+            # Process individual boxset
+            if self.should_stop():
+                return False
+            self.title = boxset['Name']
+            self.update_pdialog()
+            self.add_updateBoxset(boxset)
+            self.count += 1
+
+        ##### PROCESS DELETES #####
+
+        for kodimovie in all_kodimovies:
+            if kodimovie not in all_embymoviesIds:
+                self.remove(kodimovie)
+        else:
+            log.info("Movies compare finished.")
+
+        for boxset in all_kodisets:
+            if boxset not in all_embyboxsetsIds:
+                self.remove(boxset)
+        else:
+            log.info("Boxsets compare finished.")
+
+        return True
+
+
+    def added(self, items, total=None, view=None):
+
+        for item in super(Movies, self).added(items, total):
+            if self.add_update(item, view):
+                self.content_pop()
+
+    @catch_except()
+    def add_update(self, item, view=None):
+        # Process single movie
+        kodicursor = self.kodicursor
+        emby_db = self.emby_db
+        artwork = self.artwork
+        API = api.API(item)
+
+        # 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
+        update_item = True
+        itemid = item['Id']
+        emby_dbitem = emby_db.getItem_byId(itemid)
+        try:
+            movieid = emby_dbitem[0]
+            fileid = emby_dbitem[1]
+            pathid = emby_dbitem[2]
+            log.info("movieid: %s fileid: %s pathid: %s" % (movieid, fileid, pathid))
+        
+        except TypeError:
+            update_item = False
+            log.debug("movieid: %s not found." % itemid)
+            # movieid
+            kodicursor.execute("select coalesce(max(idMovie),0) from movie")
+            movieid = kodicursor.fetchone()[0] + 1
+
+        else:
+            # Verification the item is still in Kodi
+            query = "SELECT * FROM movie WHERE idMovie = ?"
+            kodicursor.execute(query, (movieid,))
+            try:
+                kodicursor.fetchone()[0]
+            except TypeError:
+                # item is not found, let's recreate it.
+                update_item = False
+                log.info("movieid: %s missing from Kodi, repairing the entry." % movieid)
+
+        if not view:
+            # Get view tag from emby
+            viewtag, viewid, mediatype = self.emby.getView_embyId(itemid)
+            log.debug("View tag found: %s" % viewtag)
+        else:
+            viewtag = view['name']
+            viewid = view['id']
+
+        # fileId information
+        checksum = API.get_checksum()
+        dateadded = API.get_date_created()
+        userdata = API.get_userdata()
+        playcount = userdata['PlayCount']
+        dateplayed = userdata['LastPlayedDate']
+
+        # item details
+        people = API.get_people()
+        writer = " / ".join(people['Writer'])
+        director = " / ".join(people['Director'])
+        genres = item['Genres']
+        title = item['Name']
+        plot = API.get_overview()
+        shortplot = item.get('ShortOverview')
+        tagline = API.get_tagline()
+        votecount = item.get('VoteCount')
+        rating = item.get('CommunityRating')
+        year = item.get('ProductionYear')
+        imdb = API.get_provider('Imdb')
+        sorttitle = item['SortName']
+        runtime = API.get_runtime()
+        mpaa = API.get_mpaa()
+        genre = " / ".join(genres)
+        country = API.get_country()
+        studios = API.get_studios()
+        try:
+            studio = studios[0]
+        except IndexError:
+            studio = None
+
+        if item.get('LocalTrailerCount'):
+            # There's a local trailer
+            url = (
+                "{server}/emby/Users/{UserId}/Items/%s/LocalTrailers?format=json"
+                % itemid
+            )
+            result = self.do_url(url)
+            try:
+                trailer = "plugin://plugin.video.emby/trailer/?id=%s&mode=play" % result[0]['Id']
+            except IndexError:
+                log.info("Failed to process local trailer.")
+                trailer = None
+        else:
+            # Try to get the youtube trailer
+            try:
+                trailer = item['RemoteTrailers'][0]['Url']
+            except (KeyError, IndexError):
+                trailer = None
+            else:    
+                try:
+                    trailerId = trailer.rsplit('=', 1)[1]
+                except IndexError:
+                    log.info("Failed to process trailer: %s" % trailer)
+                    trailer = None
+                else:
+                    trailer = "plugin://plugin.video.youtube/play/?video_id=%s" % trailerId
+
+        
+        ##### GET THE FILE AND PATH #####
+        playurl = API.get_file_path()
+
+        if "\\" in playurl:
+            # Local path
+            filename = playurl.rsplit("\\", 1)[1]
+        else: # Network share
+            filename = playurl.rsplit("/", 1)[1]
+
+        if self.direct_path:
+            # Direct paths is set the Kodi way
+            if not self.path_validation(playurl):
+                return False
+            
+            path = playurl.replace(filename, "")
+            window('emby_pathverified', value="true")
+        else:
+            # Set plugin path and media flags using real filename
+            path = "plugin://plugin.video.emby.movies/"
+            params = {
+
+                'filename': filename.encode('utf-8'),
+                'id': itemid,
+                'dbid': movieid,
+                'mode': "play"
+            }
+            filename = "%s?%s" % (path, urllib.urlencode(params))
+
+
+        ##### UPDATE THE MOVIE #####
+        if update_item:
+            log.info("UPDATE movie itemid: %s - Title: %s" % (itemid, title))
+
+            # Update the movie entry
+            if self.kodi_version > 16:
+                query = ' '.join((
+                    
+                    "UPDATE movie",
+                    "SET c00 = ?, c01 = ?, c02 = ?, c03 = ?, c04 = ?, c05 = ?, c06 = ?,",
+                        "c07 = ?, c09 = ?, c10 = ?, c11 = ?, c12 = ?, c14 = ?, c15 = ?,",
+                        "c16 = ?, c18 = ?, c19 = ?, c21 = ?, premiered = ?",
+                    "WHERE idMovie = ?"
+                ))
+                kodicursor.execute(query, (title, plot, shortplot, tagline, votecount, rating,
+                    writer, year, imdb, sorttitle, runtime, mpaa, genre, director, title, studio,
+                    trailer, country, year, movieid))
+            else:
+                query = ' '.join((
+                    
+                    "UPDATE movie",
+                    "SET c00 = ?, c01 = ?, c02 = ?, c03 = ?, c04 = ?, c05 = ?, c06 = ?,",
+                        "c07 = ?, c09 = ?, c10 = ?, c11 = ?, c12 = ?, c14 = ?, c15 = ?,",
+                        "c16 = ?, c18 = ?, c19 = ?, c21 = ?",
+                    "WHERE idMovie = ?"
+                ))
+                kodicursor.execute(query, (title, plot, shortplot, tagline, votecount, rating,
+                    writer, year, imdb, sorttitle, runtime, mpaa, genre, director, title, studio,
+                    trailer, country, movieid))
+
+            # Update the checksum in emby table
+            emby_db.updateReference(itemid, checksum)
+        
+        ##### OR ADD THE MOVIE #####
+        else:
+            log.info("ADD movie itemid: %s - Title: %s" % (itemid, title))
+            
+            # Add path
+            pathid = self.kodi_db.addPath(path)
+            # Add the file
+            fileid = self.kodi_db.addFile(filename, pathid)
+            
+            # Create the movie entry
+            if self.kodi_version > 16:
+                query = (
+                    '''
+                    INSERT INTO movie(
+                        idMovie, idFile, c00, c01, c02, c03, c04, c05, c06, c07, 
+                        c09, c10, c11, c12, c14, c15, c16, c18, c19, c21, premiered)
+
+                    VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
+                    '''
+                )
+                kodicursor.execute(query, (movieid, fileid, title, plot, shortplot, tagline,
+                    votecount, rating, writer, year, imdb, sorttitle, runtime, mpaa, genre,
+                    director, title, studio, trailer, country, year))
+            else:
+                query = (
+                    '''
+                    INSERT INTO movie(
+                        idMovie, idFile, c00, c01, c02, c03, c04, c05, c06, c07, 
+                        c09, c10, c11, c12, c14, c15, c16, c18, c19, c21)
+
+                    VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
+                    '''
+                )
+                kodicursor.execute(query, (movieid, fileid, title, plot, shortplot, tagline,
+                    votecount, rating, writer, year, imdb, sorttitle, runtime, mpaa, genre,
+                    director, title, studio, trailer, country))
+
+            # Create the reference in emby table
+            emby_db.addReference(itemid, movieid, "Movie", "movie", fileid, pathid, None, checksum, viewid)
+
+        # Update the path
+        query = ' '.join((
+
+            "UPDATE path",
+            "SET strPath = ?, strContent = ?, strScraper = ?, noUpdate = ?",
+            "WHERE idPath = ?"
+        ))
+        kodicursor.execute(query, (path, "movies", "metadata.local", 1, pathid))
+
+        # Update the file
+        query = ' '.join((
+
+            "UPDATE files",
+            "SET idPath = ?, strFilename = ?, dateAdded = ?",
+            "WHERE idFile = ?"
+        ))
+        kodicursor.execute(query, (pathid, filename, dateadded, fileid))
+        
+        # Process countries
+        if 'ProductionLocations' in item:
+            self.kodi_db.addCountries(movieid, item['ProductionLocations'], "movie")
+        # Process cast
+        people = artwork.get_people_artwork(item['People'])
+        self.kodi_db.addPeople(movieid, people, "movie")
+        # Process genres
+        self.kodi_db.addGenres(movieid, genres, "movie")
+        # Process artwork
+        artwork.add_artwork(artwork.get_all_artwork(item), movieid, "movie", kodicursor)
+        # Process stream details
+        streams = API.get_media_streams()
+        self.kodi_db.addStreams(fileid, streams, runtime)
+        # Process studios
+        self.kodi_db.addStudios(movieid, studios, "movie")
+        # Process tags: view, emby tags
+        tags = [viewtag]
+        tags.extend(item['Tags'])
+        if userdata['Favorite']:
+            tags.append("Favorite movies")
+        log.info("Applied tags: %s", tags)
+        self.kodi_db.addTags(movieid, tags, "movie")
+        # Process playstates
+        resume = API.adjust_resume(userdata['Resume'])
+        total = round(float(runtime), 6)
+        self.kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed)
+
+        return True
+
+    def add_updateBoxset(self, boxset):
+
+        emby = self.emby
+        emby_db = self.emby_db
+        artwork = self.artwork
+
+        boxsetid = boxset['Id']
+        title = boxset['Name']
+        checksum = boxset['Etag']
+        emby_dbitem = emby_db.getItem_byId(boxsetid)
+        try:
+            setid = emby_dbitem[0]
+
+        except TypeError:
+            setid = self.kodi_db.createBoxset(title)
+
+        # Process artwork
+        artwork.add_artwork(artwork.get_all_artwork(boxset), setid, "set", self.kodicursor)
+        
+        # Process movies inside boxset
+        current_movies = emby_db.getItemId_byParentId(setid, "movie")
+        process = []
+        try:
+            # Try to convert tuple to dictionary
+            current = dict(current_movies)
+        except ValueError:
+            current = {}
+
+        # Sort current titles
+        for current_movie in current:
+            process.append(current_movie)
+
+        # New list to compare
+        for movie in emby.getMovies_byBoxset(boxsetid)['Items']:
+
+            itemid = movie['Id']
+
+            if not current.get(itemid):
+                # Assign boxset to movie
+                emby_dbitem = emby_db.getItem_byId(itemid)
+                try:
+                    movieid = emby_dbitem[0]
+                except TypeError:
+                    log.info("Failed to add: %s to boxset." % movie['Name'])
+                    continue
+
+                log.info("New addition to boxset %s: %s" % (title, movie['Name']))
+                self.kodi_db.assignBoxset(setid, movieid)
+                # Update emby reference
+                emby_db.updateParentId(itemid, setid)
+            else:
+                # Remove from process, because the item still belongs
+                process.remove(itemid)
+
+        # Process removals from boxset
+        for movie in process:
+            movieid = current[movie]
+            log.info("Remove from boxset %s: %s" % (title, movieid))
+            self.kodi_db.removefromBoxset(movieid)
+            # Update emby reference
+            emby_db.updateParentId(movie, None)
+
+        # Update the reference in the emby table
+        emby_db.addReference(boxsetid, setid, "BoxSet", mediatype="set", checksum=checksum)
+
+    def updateUserdata(self, item):
+        # This updates: Favorite, LastPlayedDate, Playcount, PlaybackPositionTicks
+        # Poster with progress bar
+        emby_db = self.emby_db
+        API = api.API(item)
+        
+        # Get emby information
+        itemid = item['Id']
+        checksum = API.get_checksum()
+        userdata = API.get_userdata()
+        runtime = API.get_runtime()
+
+        # Get Kodi information
+        emby_dbitem = emby_db.getItem_byId(itemid)
+        try:
+            movieid = emby_dbitem[0]
+            fileid = emby_dbitem[1]
+            log.info("Update playstate for movie: %s fileid: %s" % (item['Name'], fileid))
+        except TypeError:
+            return
+
+        # Process favorite tags
+        if userdata['Favorite']:
+            self.kodi_db.addTag(movieid, "Favorite movies", "movie")
+        else:
+            self.kodi_db.removeTag(movieid, "Favorite movies", "movie")
+
+        # Process playstates
+        playcount = userdata['PlayCount']
+        dateplayed = userdata['LastPlayedDate']
+        resume = API.adjust_resume(userdata['Resume'])
+        total = round(float(runtime), 6)
+
+        log.debug("%s New resume point: %s" % (itemid, resume))
+
+        self.kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed)
+        emby_db.updateReference(itemid, checksum)
+
+    def remove(self, itemid):
+        # Remove movieid, fileid, emby reference
+        emby_db = self.emby_db
+        kodicursor = self.kodicursor
+        artwork = self.artwork
+
+        emby_dbitem = emby_db.getItem_byId(itemid)
+        try:
+            kodiid = emby_dbitem[0]
+            fileid = emby_dbitem[1]
+            mediatype = emby_dbitem[4]
+            log.info("Removing %sid: %s fileid: %s" % (mediatype, kodiid, fileid))
+        except TypeError:
+            return
+
+        # Remove the emby reference
+        emby_db.removeItem(itemid)
+        # Remove artwork
+        artwork.delete_artwork(kodiid, mediatype, kodicursor)
+
+        if mediatype == "movie":
+            # Delete kodi movie and file
+            kodicursor.execute("DELETE FROM movie WHERE idMovie = ?", (kodiid,))
+            kodicursor.execute("DELETE FROM files WHERE idFile = ?", (fileid,))
+
+        elif mediatype == "set":
+            # Delete kodi boxset
+            boxset_movies = emby_db.getItem_byParentId(kodiid, "movie")
+            for movie in boxset_movies:
+                embyid = movie[0]
+                movieid = movie[1]
+                self.kodi_db.removefromBoxset(movieid)
+                # Update emby reference
+                emby_db.updateParentId(embyid, None)
+
+            kodicursor.execute("DELETE FROM sets WHERE idSet = ?", (kodiid,))
+
+        log.info("Deleted %s %s from kodi database" % (mediatype, itemid))
diff --git a/resources/lib/objects/music.py b/resources/lib/objects/music.py
new file mode 100644
index 00000000..a47467f5
--- /dev/null
+++ b/resources/lib/objects/music.py
@@ -0,0 +1,909 @@
+# -*- coding: utf-8 -*-
+
+##################################################################################################
+
+import logging
+import urllib
+from ntpath import dirname
+from datetime import datetime
+
+import api
+import common
+import downloadutils
+import embydb_functions as embydb
+import kodidb_functions as kodidb
+import musicutils
+from utils import window, settings, language as lang, catch_except
+
+##################################################################################################
+
+log = logging.getLogger("EMBY."+__name__)
+
+##################################################################################################
+
+    
+class Music(common.Items):
+
+    
+    def __init__(self, embycursor, kodicursor, pdialog=None):
+        
+        self.embycursor = embycursor
+        self.emby_db = embydb.Embydb_Functions(self.embycursor)
+        self.kodicursor = kodicursor
+        self.kodi_db = kodidb.Kodidb_Functions(self.kodicursor)
+        self.pdialog = pdialog
+
+        self.new_time = int(settings('newmusictime'))*1000
+        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)
+        
+        common.Items.__init__(self)
+
+    def _get_func(self, item_type, action):
+
+        if item_type == "MusicAlbum":
+            actions = {
+                'added': self.added_album,
+                'update': self.add_updateAlbum,
+                'userdata': self.updateUserdata,
+                'remove': self.remove
+            }
+        elif item_type in ("MusicArtist", "AlbumArtist"):
+            actions = {
+                'added': self.added,
+                'update': self.add_updateArtist,
+                'remove': self.remove
+            }
+        elif item_type == "Audio":
+            actions = {
+                'added': self.added_song,
+                'update': self.add_updateSong,
+                'userdata': self.updateUserdata,
+                'remove': self.remove
+            }
+        else:
+            log.info("Unsupported item_type: %s", item_type)
+            actions = {}
+
+        return actions.get(action)
+
+    def compare_all(self):
+        # Pull the list of artists, albums, songs
+        pdialog = self.pdialog
+
+        views = self.emby_db.getView_byType('music')
+        try:
+            all_kodiartists = dict(self.emby_db.get_checksum('MusicArtist'))
+        except ValueError:
+            all_kodiartists = {}
+
+        try:
+            all_kodialbums = dict(self.emby_db.get_checksum('MusicAlbum'))
+        except ValueError:
+            all_kodialbums = {}
+
+        try:
+            all_kodisongs = dict(self.emby_db.get_checksum('Audio'))
+        except ValueError:
+            all_kodisongs = {}
+
+        all_embyartistsIds = set()
+        all_embyalbumsIds = set()
+        all_embysongsIds = set()
+        updatelist = []
+
+        process = {
+
+            'artists': [self.emby.getArtists, self.add_updateArtist],
+            'albums': [self.emby.getAlbums, self.add_updateAlbum],
+            'songs': [self.emby.getSongs, self.add_updateSong]
+        }
+        for view in views:
+            for data_type in ['artists', 'albums', 'songs']:
+                if pdialog:
+                    pdialog.update(
+                            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:
+                    all_embyitems = process[data_type][0](view['id'], dialog=pdialog)
+
+                for embyitem in all_embyitems['Items']:
+                    if self.should_stop():
+                        return False
+                    API = api.API(embyitem)
+                    itemid = embyitem['Id']
+                    if data_type == "artists":
+                        all_embyartistsIds.add(itemid)
+                        if all_kodiartists.get(itemid) != API.get_checksum():
+                            # Only update if artist is not in Kodi or checksum is different
+                            updatelist.append(itemid)
+                    elif data_type == "albums":
+                        all_embyalbumsIds.add(itemid)
+                        if all_kodialbums.get(itemid) != API.get_checksum():
+                            # Only update if album is not in Kodi or checksum is different
+                            updatelist.append(itemid)
+                    else:
+                        all_embysongsIds.add(itemid)
+                        if all_kodisongs.get(itemid) != API.get_checksum():
+                            # Only update if songs is not in Kodi or checksum is different
+                            updatelist.append(itemid)
+                log.info("%s to update: %s" % (data_type, updatelist))
+                embyitems = self.emby.getFullItems(updatelist)
+                self.total = len(updatelist)
+                del updatelist[:]
+                if pdialog:
+                    pdialog.update(heading="Processing %s / %s items" % (data_type, self.total))
+                self.count = 0
+                for embyitem in embyitems:
+                    # Process individual item
+                    if self.should_stop():
+                        return False
+                    self.title = embyitem['Name']
+                    self.update_pdialog()
+                    process[data_type][1](embyitem)
+                    self.count += 1
+        ##### PROCESS DELETES #####
+        for kodiartist in all_kodiartists:
+            if kodiartist not in all_embyartistsIds and all_kodiartists[kodiartist] is not None:
+                self.remove(kodiartist)
+        else:
+            log.info("Artist compare finished.")
+        for kodialbum in all_kodialbums:
+            if kodialbum not in all_embyalbumsIds:
+                self.remove(kodialbum)
+        else:
+            log.info("Albums compare finished.")
+        for kodisong in all_kodisongs:
+            if kodisong not in all_embysongsIds:
+                self.remove(kodisong)
+        else:
+            log.info("Songs compare finished.")
+        return True
+
+
+    def added(self, items, total=None):
+
+        for item in super(Music, self).added(items, total):
+            if self.add_updateArtist(item):
+                # Add albums
+                all_albums = self.emby.getAlbumsbyArtist(item['Id'])
+                self.added_album(all_albums['Items'])
+
+    def added_album(self, items, total=None):
+        
+        update = True if not self.total else False
+
+        for item in super(Music, self).added(items, total, update):
+            self.title = "%s - %s" % (item.get('AlbumArtist', "unknown"), self.title)
+
+            if self.add_updateAlbum(item):
+                # Add songs
+                all_songs = self.emby.getSongsbyAlbum(item['Id'])
+                self.added_song(all_songs['Items'])
+
+    def added_song(self, items, total=None):
+        
+        update = True if not self.total else False
+
+        for item in super(Music, self).added(items, total, update):
+            self.title = "%s - %s" % (item.get('AlbumArtist', "unknown"), self.title)
+
+            if self.add_updateSong(item):
+                self.content_pop()
+
+    @catch_except()
+    def add_updateArtist(self, item, artisttype="MusicArtist"):
+        # Process a single artist
+        kodicursor = self.kodicursor
+        emby_db = self.emby_db
+        artwork = self.artwork
+        API = api.API(item)
+
+        update_item = True
+        itemid = item['Id']
+        emby_dbitem = emby_db.getItem_byId(itemid)
+        try:
+            artistid = emby_dbitem[0]
+        except TypeError:
+            update_item = False
+            log.debug("artistid: %s not found." % itemid)
+
+        ##### The artist details #####
+        lastScraped = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
+        dateadded = API.get_date_created()
+        checksum = API.get_checksum()
+
+        name = item['Name']
+        musicBrainzId = API.get_provider('MusicBrainzArtist')
+        genres = " / ".join(item.get('Genres'))
+        bio = API.get_overview()
+
+        # Associate artwork
+        artworks = artwork.get_all_artwork(item, parent_info=True)
+        thumb = artworks['Primary']
+        backdrops = artworks['Backdrop'] # List
+
+        if thumb:
+            thumb = "<thumb>%s</thumb>" % thumb
+        if backdrops:
+            fanart = "<fanart>%s</fanart>" % backdrops[0]
+        else:
+            fanart = ""
+
+
+        ##### UPDATE THE ARTIST #####
+        if update_item:
+            log.info("UPDATE artist itemid: %s - Name: %s" % (itemid, name))
+            # Update the checksum in emby table
+            emby_db.updateReference(itemid, checksum)
+
+        ##### OR ADD THE ARTIST #####
+        else:
+            log.info("ADD artist itemid: %s - Name: %s" % (itemid, name))
+            # 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)
+            # Create the reference in emby table
+            emby_db.addReference(itemid, artistid, artisttype, "artist", checksum=checksum)
+            
+
+        # Process the artist
+        if self.kodi_version in (16, 17):
+            query = ' '.join((
+
+                "UPDATE artist",
+                "SET strGenres = ?, strBiography = ?, strImage = ?, strFanart = ?,",
+                    "lastScraped = ?",
+                "WHERE idArtist = ?"
+            ))
+            kodicursor.execute(query, (genres, bio, thumb, fanart, lastScraped, artistid))
+        else:
+            query = ' '.join((
+
+                "UPDATE artist",
+                "SET strGenres = ?, strBiography = ?, strImage = ?, strFanart = ?,",
+                    "lastScraped = ?, dateAdded = ?",
+                "WHERE idArtist = ?"
+            ))
+            kodicursor.execute(query, (genres, bio, thumb, fanart, lastScraped,
+                    dateadded, artistid))
+
+
+        # Update artwork
+        artwork.add_artwork(artworks, artistid, "artist", kodicursor)
+
+        return True
+
+    @catch_except()
+    def add_updateAlbum(self, item):
+        # Process a single artist
+        emby = self.emby
+        kodicursor = self.kodicursor
+        emby_db = self.emby_db
+        artwork = self.artwork
+        API = api.API(item)
+
+        update_item = True
+        itemid = item['Id']
+        emby_dbitem = emby_db.getItem_byId(itemid)
+        try:
+            albumid = emby_dbitem[0]
+        except TypeError:
+            update_item = False
+            log.debug("albumid: %s not found." % itemid)
+
+        ##### The album details #####
+        lastScraped = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
+        dateadded = API.get_date_created()
+        userdata = API.get_userdata()
+        checksum = API.get_checksum()
+
+        name = item['Name']
+        musicBrainzId = API.get_provider('MusicBrainzAlbum')
+        year = item.get('ProductionYear')
+        genres = item.get('Genres')
+        genre = " / ".join(genres)
+        bio = API.get_overview()
+        rating = userdata['UserRating']
+        artists = item['AlbumArtists']
+        artistname = []
+        for artist in artists:
+            artistname.append(artist['Name'])
+        artistname = " / ".join(artistname)
+
+        # Associate artwork
+        artworks = artwork.get_all_artwork(item, parent_info=True)
+        thumb = artworks['Primary']
+        if thumb:
+            thumb = "<thumb>%s</thumb>" % thumb
+
+        ##### UPDATE THE ALBUM #####
+        if update_item:
+            log.info("UPDATE album itemid: %s - Name: %s" % (itemid, name))
+            # Update the checksum in emby table
+            emby_db.updateReference(itemid, checksum)
+
+        ##### OR ADD THE ALBUM #####
+        else:
+            log.info("ADD album itemid: %s - Name: %s" % (itemid, name))
+            # 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)
+            # Create the reference in emby table
+            emby_db.addReference(itemid, albumid, "MusicAlbum", "album", checksum=checksum)
+
+
+        # Process the album info
+        if self.kodi_version == 17:
+            # Kodi Krypton
+            query = ' '.join((
+
+                "UPDATE album",
+                "SET strArtists = ?, iYear = ?, strGenres = ?, strReview = ?, strImage = ?,",
+                    "iUserrating = ?, lastScraped = ?, strReleaseType = ?",
+                "WHERE idAlbum = ?"
+            ))
+            kodicursor.execute(query, (artistname, year, genre, bio, thumb, rating, lastScraped,
+                "album", albumid))
+        elif self.kodi_version == 16:
+            # Kodi Jarvis
+            query = ' '.join((
+
+                "UPDATE album",
+                "SET strArtists = ?, iYear = ?, strGenres = ?, strReview = ?, strImage = ?,",
+                    "iRating = ?, lastScraped = ?, strReleaseType = ?",
+                "WHERE idAlbum = ?"
+            ))
+            kodicursor.execute(query, (artistname, year, genre, bio, thumb, rating, lastScraped,
+                "album", albumid))
+        elif self.kodi_version == 15:
+            # Kodi Isengard
+            query = ' '.join((
+
+                "UPDATE album",
+                "SET strArtists = ?, iYear = ?, strGenres = ?, strReview = ?, strImage = ?,",
+                    "iRating = ?, lastScraped = ?, dateAdded = ?, strReleaseType = ?",
+                "WHERE idAlbum = ?"
+            ))
+            kodicursor.execute(query, (artistname, year, genre, bio, thumb, rating, lastScraped,
+                dateadded, "album", albumid))
+        else:
+            # Kodi Helix
+            query = ' '.join((
+
+                "UPDATE album",
+                "SET strArtists = ?, iYear = ?, strGenres = ?, strReview = ?, strImage = ?,",
+                    "iRating = ?, lastScraped = ?, dateAdded = ?",
+                "WHERE idAlbum = ?"
+            ))
+            kodicursor.execute(query, (artistname, year, genre, bio, thumb, rating, lastScraped,
+                dateadded, albumid))
+
+        # Assign main artists to album
+        for artist in item['AlbumArtists']:
+            artistname = artist['Name']
+            artistId = artist['Id']
+            emby_dbartist = emby_db.getItem_byId(artistId)
+            try:
+                artistid = emby_dbartist[0]
+            except TypeError:
+                # Artist does not exist in emby database, create the reference
+                artist = emby.getItem(artistId)
+                self.add_updateArtist(artist, artisttype="AlbumArtist")
+                emby_dbartist = emby_db.getItem_byId(artistId)
+                artistid = emby_dbartist[0]
+            else:
+                # Best take this name over anything else.
+                query = "UPDATE artist SET strArtist = ? WHERE idArtist = ?"
+                kodicursor.execute(query, (artistname, artistid,))
+
+            # Add artist to album
+            query = (
+                '''
+                INSERT OR REPLACE INTO album_artist(idArtist, idAlbum, strArtist)
+
+                VALUES (?, ?, ?)
+                '''
+            )
+            kodicursor.execute(query, (artistid, albumid, artistname))
+            # Update emby reference with parentid
+            emby_db.updateParentId(artistId, albumid)
+
+        for artist in item['ArtistItems']:
+            artistId = artist['Id']
+            emby_dbartist = emby_db.getItem_byId(artistId)
+            try:
+                artistid = emby_dbartist[0]
+            except TypeError:
+                pass
+            else:
+                # Update discography
+                query = (
+                    '''
+                    INSERT OR REPLACE INTO discography(idArtist, strAlbum, strYear)
+
+                    VALUES (?, ?, ?)
+                    '''
+                )
+                kodicursor.execute(query, (artistid, name, year))
+
+        # Add genres
+        self.kodi_db.addMusicGenres(albumid, genres, "album")
+        # Update artwork
+        artwork.add_artwork(artworks, albumid, "album", kodicursor)
+
+        return True
+
+    @catch_except()
+    def add_updateSong(self, item):
+        # Process single song
+        kodicursor = self.kodicursor
+        emby = self.emby
+        emby_db = self.emby_db
+        artwork = self.artwork
+        API = api.API(item)
+
+        update_item = True
+        itemid = item['Id']
+        emby_dbitem = emby_db.getItem_byId(itemid)
+        try:
+            songid = emby_dbitem[0]
+            pathid = emby_dbitem[2]
+            albumid = emby_dbitem[3]
+        except TypeError:
+            update_item = False
+            log.debug("songid: %s not found." % itemid)
+            
+        ##### The song details #####
+        checksum = API.get_checksum()
+        dateadded = API.get_date_created()
+        userdata = API.get_userdata()
+        playcount = userdata['PlayCount']
+        dateplayed = userdata['LastPlayedDate']
+
+        # item details
+        title = item['Name']
+        musicBrainzId = API.get_provider('MusicBrainzTrackId')
+        genres = item.get('Genres')
+        genre = " / ".join(genres)
+        artists = " / ".join(item['Artists'])
+        tracknumber = item.get('IndexNumber', 0)
+        disc = item.get('ParentIndexNumber', 1)
+        if disc == 1:
+            track = tracknumber
+        else:
+            track = disc*2**16 + tracknumber
+        year = item.get('ProductionYear')
+        duration = API.get_runtime()
+        rating = userdata['UserRating']
+
+        #if enabled, try to get the rating from file and/or emby
+        if not self.directstream:
+            rating, comment, hasEmbeddedCover = musicutils.getAdditionalSongTags(itemid, rating, API, kodicursor, emby_db, self.enableimportsongrating, self.enableexportsongrating, self.enableupdatesongrating)
+        else:
+            hasEmbeddedCover = False
+            comment = API.get_overview()
+            
+            
+        ##### GET THE FILE AND PATH #####
+        if self.directstream:
+            path = "%s/emby/Audio/%s/" % (self.server, itemid)
+            extensions = ['mp3', 'aac', 'ogg', 'oga', 'webma', 'wma', 'flac']
+
+            if 'Container' in item and item['Container'].lower() in extensions:
+                filename = "stream.%s?static=true" % item['Container']
+            else:
+                filename = "stream.mp3?static=true"
+        else:
+            playurl = API.get_file_path()
+
+            if "\\" in playurl:
+                # Local path
+                filename = playurl.rsplit("\\", 1)[1]
+            else: # Network share
+                filename = playurl.rsplit("/", 1)[1]
+
+            # Direct paths is set the Kodi way
+            if not self.path_validation(playurl):
+                return False
+            
+            path = playurl.replace(filename, "")
+            window('emby_pathverified', value="true")
+
+        ##### UPDATE THE SONG #####
+        if update_item:
+            log.info("UPDATE song itemid: %s - Title: %s" % (itemid, title))
+            
+            # Update path
+            query = "UPDATE path SET strPath = ? WHERE idPath = ?"
+            kodicursor.execute(query, (path, pathid))
+
+            # Update the song entry
+            query = ' '.join((
+                
+                "UPDATE song",
+                "SET idAlbum = ?, strArtists = ?, strGenres = ?, strTitle = ?, iTrack = ?,",
+                    "iDuration = ?, iYear = ?, strFilename = ?, iTimesPlayed = ?, lastplayed = ?,",
+                    "rating = ?, comment = ?",
+                "WHERE idSong = ?"
+            ))
+            kodicursor.execute(query, (albumid, artists, genre, title, track, duration, year,
+                filename, playcount, dateplayed, rating, comment, songid))
+
+            # Update the checksum in emby table
+            emby_db.updateReference(itemid, checksum)
+        
+        ##### OR ADD THE SONG #####
+        else:
+            log.info("ADD song itemid: %s - Title: %s" % (itemid, title))
+            
+            # Add path
+            pathid = self.kodi_db.addPath(path)
+
+            try:
+                # Get the album
+                emby_dbalbum = emby_db.getItem_byId(item['AlbumId'])
+                albumid = emby_dbalbum[0]
+            except KeyError:
+                # Verify if there's an album associated.
+                album_name = item.get('Album')
+                if album_name:
+                    log.info("Creating virtual music album for song: %s." % itemid)
+                    albumid = self.kodi_db.addAlbum(album_name, API.get_provider('MusicBrainzAlbum'))
+                    emby_db.addReference("%salbum%s" % (itemid, albumid), albumid, "MusicAlbum_", "album")
+                else:
+                    # No album Id associated to the song.
+                    log.error("Song itemid: %s has no albumId associated." % itemid)
+                    return False
+
+            except TypeError:
+                # No album found. Let's create it
+                log.info("Album database entry missing.")
+                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]
+                    log.info("Found albumid: %s" % albumid)
+                except TypeError:
+                    # No album found, create a single's album
+                    log.info("Failed to add album. Creating singles.")
+                    kodicursor.execute("select coalesce(max(idAlbum),0) from album")
+                    albumid = kodicursor.fetchone()[0] + 1
+                    if self.kodi_version == 16:
+                        # Kodi Jarvis
+                        query = (
+                            '''
+                            INSERT INTO album(idAlbum, strGenres, iYear, strReleaseType)
+
+                            VALUES (?, ?, ?, ?)
+                            '''
+                        )
+                        kodicursor.execute(query, (albumid, genre, year, "single"))
+                    elif self.kodi_version == 15:
+                        # Kodi Isengard
+                        query = (
+                            '''
+                            INSERT INTO album(idAlbum, strGenres, iYear, dateAdded, strReleaseType)
+
+                            VALUES (?, ?, ?, ?, ?)
+                            '''
+                        )
+                        kodicursor.execute(query, (albumid, genre, year, dateadded, "single"))
+                    else:
+                        # Kodi Helix
+                        query = (
+                            '''
+                            INSERT INTO album(idAlbum, strGenres, iYear, dateAdded)
+
+                            VALUES (?, ?, ?, ?)
+                            '''
+                        )
+                        kodicursor.execute(query, (albumid, genre, year, dateadded))
+            
+            # Create the song entry
+            kodicursor.execute("select coalesce(max(idSong),0) from song")
+            songid = kodicursor.fetchone()[0] + 1
+            query = (
+                '''
+                INSERT INTO song(
+                    idSong, idAlbum, idPath, strArtists, strGenres, strTitle, iTrack,
+                    iDuration, iYear, strFileName, strMusicBrainzTrackID, iTimesPlayed, lastplayed,
+                    rating)
+
+                VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
+                '''
+            )
+            kodicursor.execute(query, (songid, albumid, pathid, artists, genre, title, track,
+                duration, year, filename, musicBrainzId, playcount, dateplayed, rating))
+
+            # Create the reference in emby table
+            emby_db.addReference(itemid, songid, "Audio", "song", pathid=pathid, parentid=albumid,
+                checksum=checksum)
+
+        
+        # Link song to album
+        query = (
+            '''
+            INSERT OR REPLACE INTO albuminfosong(
+                idAlbumInfoSong, idAlbumInfo, iTrack, strTitle, iDuration)
+            
+            VALUES (?, ?, ?, ?, ?)
+            '''
+        )
+        kodicursor.execute(query, (songid, albumid, track, title, duration))
+        
+        # Link song to artists
+        for index, artist in enumerate(item['ArtistItems']):
+
+            artist_name = artist['Name']
+            artist_eid = artist['Id']
+            artist_edb = emby_db.getItem_byId(artist_eid)
+            try:
+                artistid = artist_edb[0]
+            except TypeError:
+                # Artist is missing from emby database, add it.
+                artist_full = emby.getItem(artist_eid)
+                self.add_updateArtist(artist_full)
+                artist_edb = emby_db.getItem_byId(artist_eid)
+                artistid = artist_edb[0]
+            finally:
+                if self.kodi_version >= 17:
+                    # Kodi Krypton
+                    query = (
+                        '''
+                        INSERT OR REPLACE INTO song_artist(idArtist, idSong, idRole, iOrder, strArtist)
+    
+                        VALUES (?, ?, ?, ?, ?)
+                        '''
+                    )
+                    kodicursor.execute(query, (artistid, songid, 1, index, artist_name))
+                    
+                    # May want to look into only doing this once?
+                    query = ( 
+                        '''
+                        INSERT OR REPLACE INTO role(idRole, strRole)
+    
+                        VALUES (?, ?)
+                        '''
+                    )
+                    kodicursor.execute(query, (1, 'Composer'))                
+                else:
+                    query = (
+                        '''
+                        INSERT OR REPLACE INTO song_artist(idArtist, idSong, iOrder, strArtist)
+    
+                        VALUES (?, ?, ?, ?)
+                        '''
+                    )
+                    kodicursor.execute(query, (artistid, songid, index, artist_name))
+               
+        # Verify if album artist exists
+        album_artists = []
+        for artist in item['AlbumArtists']:
+
+            artist_name = artist['Name']
+            album_artists.append(artist_name)
+            artist_eid = artist['Id']
+            artist_edb = emby_db.getItem_byId(artist_eid)
+            try:
+                artistid = artist_edb[0]
+            except TypeError:
+                # Artist is missing from emby database, add it.
+                artist_full = emby.getItem(artist_eid)
+                self.add_updateArtist(artist_full)
+                artist_edb = emby_db.getItem_byId(artist_eid)
+                artistid = artist_edb[0]
+            finally:
+                query = (
+                    '''
+                    INSERT OR REPLACE INTO album_artist(idArtist, idAlbum, strArtist)
+
+                    VALUES (?, ?, ?)
+                    '''
+                )
+                kodicursor.execute(query, (artistid, albumid, artist_name))
+                # Update discography
+                if item.get('Album'):
+                    query = (
+                        '''
+                        INSERT OR REPLACE INTO discography(idArtist, strAlbum, strYear)
+
+                        VALUES (?, ?, ?)
+                        '''
+                    )
+                    kodicursor.execute(query, (artistid, item['Album'], 0))
+        else:
+            album_artists = " / ".join(album_artists)
+            query = ' '.join((
+
+                "SELECT strArtists",
+                "FROM album",
+                "WHERE idAlbum = ?"
+            ))
+            kodicursor.execute(query, (albumid,))
+            result = kodicursor.fetchone()
+            if result and result[0] != album_artists:
+                # Field is empty
+                if self.kodi_version in (16, 17):
+                    # Kodi Jarvis, Krypton
+                    query = "UPDATE album SET strArtists = ? WHERE idAlbum = ?"
+                    kodicursor.execute(query, (album_artists, albumid))
+                elif self.kodi_version == 15:
+                    # Kodi Isengard
+                    query = "UPDATE album SET strArtists = ? WHERE idAlbum = ?"
+                    kodicursor.execute(query, (album_artists, albumid))
+                else:
+                    # Kodi Helix
+                    query = "UPDATE album SET strArtists = ? WHERE idAlbum = ?"
+                    kodicursor.execute(query, (album_artists, albumid))
+
+        # Add genres
+        self.kodi_db.addMusicGenres(songid, genres, "song")
+        
+        # Update artwork
+        allart = artwork.get_all_artwork(item, parent_info=True)
+        if hasEmbeddedCover:
+            allart["Primary"] = "image://music@" + artwork.single_urlencode( playurl )
+        artwork.add_artwork(allart, songid, "song", kodicursor)
+
+        if item.get('AlbumId') is None:
+            # Update album artwork
+            artwork.add_artwork(allart, albumid, "album", kodicursor)
+
+        return True
+
+    def updateUserdata(self, item):
+        # This updates: Favorite, LastPlayedDate, Playcount, PlaybackPositionTicks
+        # Poster with progress bar
+        kodicursor = self.kodicursor
+        emby_db = self.emby_db
+        API = api.API(item)
+
+        # Get emby information
+        itemid = item['Id']
+        checksum = API.get_checksum()
+        userdata = API.get_userdata()
+        runtime = API.get_runtime()
+        rating = userdata['UserRating']
+
+        # Get Kodi information
+        emby_dbitem = emby_db.getItem_byId(itemid)
+        try:
+            kodiid = emby_dbitem[0]
+            mediatype = emby_dbitem[4]
+            log.info("Update playstate for %s: %s" % (mediatype, item['Name']))
+        except TypeError:
+            return
+
+        if mediatype == "song":
+            
+            #should we ignore this item ?
+            #happens when userdata updated by ratings method
+            if window("ignore-update-%s" %itemid):
+                window("ignore-update-%s" %itemid,clear=True)
+                return
+                
+            # Process playstates
+            playcount = userdata['PlayCount']
+            dateplayed = userdata['LastPlayedDate']
+            
+            #process item ratings
+            rating, comment, hasEmbeddedCover = musicutils.getAdditionalSongTags(itemid, rating, API, kodicursor, emby_db, self.enableimportsongrating, self.enableexportsongrating, self.enableupdatesongrating)
+            
+            query = "UPDATE song SET iTimesPlayed = ?, lastplayed = ?, rating = ? WHERE idSong = ?"
+            kodicursor.execute(query, (playcount, dateplayed, rating, kodiid))
+
+        elif mediatype == "album":
+            # Process playstates
+            if self.kodi_version >= 17:
+                query = "UPDATE album SET fRating = ? WHERE idAlbum = ?"
+            else:
+                query = "UPDATE album SET iRating = ? WHERE idAlbum = ?"            
+            kodicursor.execute(query, (rating, kodiid))
+
+        emby_db.updateReference(itemid, checksum)
+
+    def remove(self, itemid):
+        # Remove kodiid, fileid, pathid, emby reference
+        emby_db = self.emby_db
+        kodicursor = self.kodicursor
+        artwork = self.artwork
+
+        emby_dbitem = emby_db.getItem_byId(itemid)
+        try:
+            kodiid = emby_dbitem[0]
+            mediatype = emby_dbitem[4]
+            log.info("Removing %s kodiid: %s" % (mediatype, kodiid))
+        except TypeError:
+            return
+
+        ##### PROCESS ITEM #####
+
+        # Remove the emby reference
+        emby_db.removeItem(itemid)
+
+
+        ##### IF SONG #####
+
+        if mediatype == "song":
+            # Delete song
+            self.removeSong(kodiid)
+            # This should only address single song scenario, where server doesn't actually
+            # create an album for the song. 
+            emby_db.removeWildItem(itemid)
+
+            for item in emby_db.getItem_byWildId(itemid):
+
+                item_kid = item[0]
+                item_mediatype = item[1]
+
+                if item_mediatype == "album":
+                    childs = emby_db.getItem_byParentId(item_kid, "song")
+                    if not childs:
+                        # Delete album
+                        self.removeAlbum(item_kid)
+
+        ##### IF ALBUM #####
+
+        elif mediatype == "album":
+            # Delete songs, album
+            album_songs = emby_db.getItem_byParentId(kodiid, "song")
+            for song in album_songs:
+                self.removeSong(song[1])
+            else:
+                # Remove emby songs
+                emby_db.removeItems_byParentId(kodiid, "song")
+
+            # Remove the album
+            self.removeAlbum(kodiid)
+
+        ##### IF ARTIST #####
+
+        elif mediatype == "artist":
+            # Delete songs, album, artist
+            albums = emby_db.getItem_byParentId(kodiid, "album")
+            for album in albums:
+                albumid = album[1]
+                album_songs = emby_db.getItem_byParentId(albumid, "song")
+                for song in album_songs:
+                    self.removeSong(song[1])
+                else:
+                    # Remove emby song
+                    emby_db.removeItems_byParentId(albumid, "song")
+                    # Remove emby artist
+                    emby_db.removeItems_byParentId(albumid, "artist")
+                    # Remove kodi album
+                    self.removeAlbum(albumid)
+            else:
+                # Remove emby albums
+                emby_db.removeItems_byParentId(kodiid, "album")
+
+            # Remove artist
+            self.removeArtist(kodiid)
+
+        log.info("Deleted %s: %s from kodi database" % (mediatype, itemid))
+
+    def removeSong(self, kodiId):
+
+        kodicursor = self.kodicursor
+
+        self.artwork.delete_artwork(kodiId, "song", self.kodicursor)
+        self.kodicursor.execute("DELETE FROM song WHERE idSong = ?", (kodiId,))
+
+    def removeAlbum(self, kodiId):
+
+        self.artwork.delete_artwork(kodiId, "album", self.kodicursor)
+        self.kodicursor.execute("DELETE FROM album WHERE idAlbum = ?", (kodiId,))
+
+    def removeArtist(self, kodiId):
+
+        self.artwork.delete_artwork(kodiId, "artist", self.kodicursor)
+        self.kodicursor.execute("DELETE FROM artist WHERE idArtist = ?", (kodiId,))
diff --git a/resources/lib/objects/musicvideos.py b/resources/lib/objects/musicvideos.py
new file mode 100644
index 00000000..03da09b5
--- /dev/null
+++ b/resources/lib/objects/musicvideos.py
@@ -0,0 +1,415 @@
+# -*- coding: utf-8 -*-
+
+##################################################################################################
+
+import logging
+import urllib
+from ntpath import dirname
+from datetime import datetime
+
+import api
+import common
+import downloadutils
+import embydb_functions as embydb
+import kodidb_functions as kodidb
+from utils import window, settings, language as lang, catch_except
+
+##################################################################################################
+
+log = logging.getLogger("EMBY."+__name__)
+
+##################################################################################################
+
+
+class MusicVideos(common.Items):
+
+    
+    def __init__(self, embycursor, kodicursor, pdialog=None):
+        
+        self.embycursor = embycursor
+        self.emby_db = embydb.Embydb_Functions(self.embycursor)
+        self.kodicursor = kodicursor
+        self.kodi_db = kodidb.Kodidb_Functions(self.kodicursor)
+        self.pdialog = pdialog
+        
+        common.Items.__init__(self)
+
+    def _get_func(self, item_type, action):
+
+        if item_type == "MusicVideo":
+            actions = {
+                'added': self.added,
+                'update': self.add_update,
+                'userdata': self.updateUserdata,
+                'remove': self.remove
+            }
+        else:
+            log.info("Unsupported item_type: %s", item_type)
+            actions = {}
+
+        return actions.get(action)
+
+    def compare_all(self):
+        pdialog = self.pdialog
+        # Pull the list of musicvideos in Kodi
+        views = self.emby_db.getView_byType('musicvideos')
+        log.info("Media folders: %s" % views)
+
+        try:
+            all_kodimvideos = dict(self.emby_db.get_checksum('MusicVideo'))
+        except ValueError:
+            all_kodimvideos = {}
+
+        all_embymvideosIds = set()
+        updatelist = []
+
+        for view in views:
+
+            if self.should_stop():
+                return False
+
+            # Get items per view
+            viewId = view['id']
+            viewName = view['name']
+
+            if pdialog:
+                pdialog.update(
+                        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']:
+
+                if self.should_stop():
+                    return False
+
+                API = api.API(embymvideo)
+                itemid = embymvideo['Id']
+                all_embymvideosIds.add(itemid)
+
+
+                if all_kodimvideos.get(itemid) != API.get_checksum():
+                    # Only update if musicvideo is not in Kodi or checksum is different
+                    updatelist.append(itemid)
+
+            log.info("MusicVideos to update for %s: %s" % (viewName, updatelist))
+            embymvideos = self.emby.getFullItems(updatelist)
+            self.total = len(updatelist)
+            del updatelist[:]
+
+
+            if pdialog:
+                pdialog.update(heading="Processing %s / %s items" % (viewName, self.total))
+
+            self.count = 0
+            for embymvideo in embymvideos:
+                # Process individual musicvideo
+                if self.should_stop():
+                    return False
+                self.title = embymvideo['Name']
+                self.update_pdialog()
+                self.add_update(embymvideo, view)
+                self.count += 1
+
+        ##### PROCESS DELETES #####
+
+        for kodimvideo in all_kodimvideos:
+            if kodimvideo not in all_embymvideosIds:
+                self.remove(kodimvideo)
+        else:
+            log.info("MusicVideos compare finished.")
+
+        return True
+
+
+    def added(self, items, total=None, view=None):
+        for item in super(MusicVideos, self).added(items, total, True):
+            if self.add_update(item, view):
+                self.content_pop()
+
+    @catch_except
+    def add_update(self, item, view=None):
+        # Process single music video
+        kodicursor = self.kodicursor
+        emby_db = self.emby_db
+        artwork = self.artwork
+        API = api.API(item)
+
+        # 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
+        update_item = True
+        itemid = item['Id']
+        emby_dbitem = emby_db.getItem_byId(itemid)
+        try:
+            mvideoid = emby_dbitem[0]
+            fileid = emby_dbitem[1]
+            pathid = emby_dbitem[2]
+            log.info("mvideoid: %s fileid: %s pathid: %s" % (mvideoid, fileid, pathid))
+        
+        except TypeError:
+            update_item = False
+            log.debug("mvideoid: %s not found." % itemid)
+            # mvideoid
+            kodicursor.execute("select coalesce(max(idMVideo),0) from musicvideo")
+            mvideoid = kodicursor.fetchone()[0] + 1
+
+        else:
+            # Verification the item is still in Kodi
+            query = "SELECT * FROM musicvideo WHERE idMVideo = ?"
+            kodicursor.execute(query, (mvideoid,))
+            try:
+                kodicursor.fetchone()[0]
+            except TypeError:
+                # item is not found, let's recreate it.
+                update_item = False
+                log.info("mvideoid: %s missing from Kodi, repairing the entry." % mvideoid)
+
+        if not view:
+            # Get view tag from emby
+            viewtag, viewid, mediatype = self.emby.getView_embyId(itemid)
+            log.debug("View tag found: %s" % viewtag)
+        else:
+            viewtag = view['name']
+            viewid = view['id']
+
+        # fileId information
+        checksum = API.get_checksum()
+        dateadded = API.get_date_created()
+        userdata = API.get_userdata()
+        playcount = userdata['PlayCount']
+        dateplayed = userdata['LastPlayedDate']
+
+        # item details
+        runtime = API.get_runtime()
+        plot = API.get_overview()
+        title = item['Name']
+        year = item.get('ProductionYear')
+        genres = item['Genres']
+        genre = " / ".join(genres)
+        studios = API.get_studios()
+        studio = " / ".join(studios)
+        artist = " / ".join(item.get('Artists'))
+        album = item.get('Album')
+        track = item.get('Track')
+        people = API.get_people()
+        director = " / ".join(people['Director'])
+
+        
+        ##### GET THE FILE AND PATH #####
+        playurl = API.get_file_path()
+
+        if "\\" in playurl:
+            # Local path
+            filename = playurl.rsplit("\\", 1)[1]
+        else: # Network share
+            filename = playurl.rsplit("/", 1)[1]
+
+        if self.direct_path:
+            # Direct paths is set the Kodi way
+            if not self.path_validation(playurl):
+                return False
+            
+            path = playurl.replace(filename, "")
+            window('emby_pathverified', value="true")
+        else:
+            # Set plugin path and media flags using real filename
+            path = "plugin://plugin.video.emby.musicvideos/"
+            params = {
+
+                'filename': filename.encode('utf-8'),
+                'id': itemid,
+                'dbid': mvideoid,
+                'mode': "play"
+            }
+            filename = "%s?%s" % (path, urllib.urlencode(params))
+
+
+        ##### UPDATE THE MUSIC VIDEO #####
+        if update_item:
+            log.info("UPDATE mvideo itemid: %s - Title: %s" % (itemid, title))
+            
+            # Update path
+            query = "UPDATE path SET strPath = ? WHERE idPath = ?"
+            kodicursor.execute(query, (path, pathid))
+
+            # Update the filename
+            query = "UPDATE files SET strFilename = ?, dateAdded = ? WHERE idFile = ?"
+            kodicursor.execute(query, (filename, dateadded, fileid))
+
+            # Update the music video entry
+            query = ' '.join((
+                
+                "UPDATE musicvideo",
+                "SET c00 = ?, c04 = ?, c05 = ?, c06 = ?, c07 = ?, c08 = ?, c09 = ?, c10 = ?,",
+                    "c11 = ?, c12 = ?"
+                "WHERE idMVideo = ?"
+            ))
+            kodicursor.execute(query, (title, runtime, director, studio, year, plot, album,
+                artist, genre, track, mvideoid))
+
+            # Update the checksum in emby table
+            emby_db.updateReference(itemid, checksum)
+        
+        ##### OR ADD THE MUSIC VIDEO #####
+        else:
+            log.info("ADD mvideo itemid: %s - Title: %s" % (itemid, title))
+            
+            # Add path
+            query = ' '.join((
+
+                "SELECT idPath",
+                "FROM path",
+                "WHERE strPath = ?"
+            ))
+            kodicursor.execute(query, (path,))
+            try:
+                pathid = kodicursor.fetchone()[0]
+            except TypeError:
+                kodicursor.execute("select coalesce(max(idPath),0) from path")
+                pathid = kodicursor.fetchone()[0] + 1
+                query = (
+                    '''
+                    INSERT OR REPLACE INTO path(
+                        idPath, strPath, strContent, strScraper, noUpdate)
+
+                    VALUES (?, ?, ?, ?, ?)
+                    '''
+                )
+                kodicursor.execute(query, (pathid, path, "musicvideos", "metadata.local", 1))
+
+            # Add the file
+            kodicursor.execute("select coalesce(max(idFile),0) from files")
+            fileid = kodicursor.fetchone()[0] + 1
+            query = (
+                '''
+                INSERT INTO files(
+                    idFile, idPath, strFilename, dateAdded)
+
+                VALUES (?, ?, ?, ?)
+                '''
+            )
+            kodicursor.execute(query, (fileid, pathid, filename, dateadded))
+            
+            # Create the musicvideo entry
+            query = (
+                '''
+                INSERT INTO musicvideo(
+                    idMVideo, idFile, c00, c04, c05, c06, c07, c08, c09, c10, c11, c12)
+
+                VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
+                '''
+            )
+            kodicursor.execute(query, (mvideoid, fileid, title, runtime, director, studio,
+                year, plot, album, artist, genre, track))
+
+            # Create the reference in emby table
+            emby_db.addReference(itemid, mvideoid, "MusicVideo", "musicvideo", fileid, pathid,
+                checksum=checksum, mediafolderid=viewid)
+
+        
+        # Process cast
+        people = item['People']
+        artists = item['ArtistItems']
+        for artist in artists:
+            artist['Type'] = "Artist"
+        people.extend(artists)
+        people = artwork.get_people_artwork(people)
+        self.kodi_db.addPeople(mvideoid, people, "musicvideo")
+        # Process genres
+        self.kodi_db.addGenres(mvideoid, genres, "musicvideo")
+        # Process artwork
+        artwork.add_artwork(artwork.get_all_artwork(item), mvideoid, "musicvideo", kodicursor)
+        # Process stream details
+        streams = API.get_media_streams()
+        self.kodi_db.addStreams(fileid, streams, runtime)
+        # Process studios
+        self.kodi_db.addStudios(mvideoid, studios, "musicvideo")
+        # Process tags: view, emby tags
+        tags = [viewtag]
+        tags.extend(item['Tags'])
+        if userdata['Favorite']:
+            tags.append("Favorite musicvideos")
+        self.kodi_db.addTags(mvideoid, tags, "musicvideo")
+        # Process playstates
+        resume = API.adjust_resume(userdata['Resume'])
+        total = round(float(runtime), 6)
+        self.kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed)
+
+        return True
+
+    def updateUserdata(self, item):
+        # This updates: Favorite, LastPlayedDate, Playcount, PlaybackPositionTicks
+        # Poster with progress bar
+        emby_db = self.emby_db
+        API = api.API(item)
+        
+        # Get emby information
+        itemid = item['Id']
+        checksum = API.get_checksum()
+        userdata = API.get_userdata()
+        runtime = API.get_runtime()
+
+        # Get Kodi information
+        emby_dbitem = emby_db.getItem_byId(itemid)
+        try:
+            mvideoid = emby_dbitem[0]
+            fileid = emby_dbitem[1]
+            log.info(
+                "Update playstate for musicvideo: %s fileid: %s"
+                % (item['Name'], fileid))
+        except TypeError:
+            return
+
+        # Process favorite tags
+        if userdata['Favorite']:
+            self.kodi_db.addTag(mvideoid, "Favorite musicvideos", "musicvideo")
+        else:
+            self.kodi_db.removeTag(mvideoid, "Favorite musicvideos", "musicvideo")
+
+        # Process playstates
+        playcount = userdata['PlayCount']
+        dateplayed = userdata['LastPlayedDate']
+        resume = API.adjust_resume(userdata['Resume'])
+        total = round(float(runtime), 6)
+
+        self.kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed)
+        emby_db.updateReference(itemid, checksum)
+
+    def remove(self, itemid):
+        # Remove mvideoid, fileid, pathid, emby reference
+        emby_db = self.emby_db
+        kodicursor = self.kodicursor
+        artwork = self.artwork
+
+        emby_dbitem = emby_db.getItem_byId(itemid)
+        try:
+            mvideoid = emby_dbitem[0]
+            fileid = emby_dbitem[1]
+            pathid = emby_dbitem[2]
+            log.info("Removing mvideoid: %s fileid: %s" % (mvideoid, fileid, pathid))
+        except TypeError:
+            return
+
+        # Remove artwork
+        query = ' '.join((
+
+            "SELECT url, type",
+            "FROM art",
+            "WHERE media_id = ?",
+            "AND media_type = 'musicvideo'"
+        ))
+        kodicursor.execute(query, (mvideoid,))
+        for row in kodicursor.fetchall():
+            
+            url = row[0]
+            imagetype = row[1]
+            if imagetype in ("poster", "fanart"):
+                artwork.delete_cached_artwork(url)
+
+        kodicursor.execute("DELETE FROM musicvideo WHERE idMVideo = ?", (mvideoid,))
+        kodicursor.execute("DELETE FROM files WHERE idFile = ?", (fileid,))
+        if self.direct_path:
+            kodicursor.execute("DELETE FROM path WHERE idPath = ?", (pathid,))
+        self.embycursor.execute("DELETE FROM emby WHERE emby_id = ?", (itemid,))
+
+        log.info("Deleted musicvideo %s from kodi database" % itemid)
diff --git a/resources/lib/objects/tvshows.py b/resources/lib/objects/tvshows.py
new file mode 100644
index 00000000..bbf22701
--- /dev/null
+++ b/resources/lib/objects/tvshows.py
@@ -0,0 +1,924 @@
+# -*- coding: utf-8 -*-
+
+##################################################################################################
+
+import logging
+import urllib
+from ntpath import dirname
+from datetime import datetime
+
+import api
+import common
+import downloadutils
+import embydb_functions as embydb
+import kodidb_functions as kodidb
+from utils import window, settings, language as lang, catch_except
+
+##################################################################################################
+
+log = logging.getLogger("EMBY."+__name__)
+
+##################################################################################################
+
+    
+class TVShows(common.Items):
+
+    
+    def __init__(self, embycursor, kodicursor, pdialog=None):
+        
+        self.embycursor = embycursor
+        self.emby_db = embydb.Embydb_Functions(self.embycursor)
+        self.kodicursor = kodicursor
+        self.kodi_db = kodidb.Kodidb_Functions(self.kodicursor)
+        self.pdialog = pdialog
+
+        self.new_time = int(settings('newvideotime'))*1000
+        
+        common.Items.__init__(self)
+
+    def _get_func(self, item_type, action):
+
+        if item_type == "Series":
+            actions = {
+                'added': self.added,
+                'update': self.add_update,
+                'userdata': self.updateUserdata,
+                'remove': self.remove
+            }
+        elif item_type == "Season":
+            actions = {
+                'added': self.added_season,
+                'update': self.add_updateSeason,
+                'remove': self.remove
+            }
+        elif item_type == "Episode":
+            actions = {
+                'added': self.added_episode,
+                'update': self.add_updateEpisode,
+                'userdata': self.updateUserdata,
+                'remove': self.remove
+            }
+        else:
+            log.info("Unsupported item_type: %s", item_type)
+            actions = {}
+
+        return actions.get(action)
+
+    def compare_all(self):
+        # Pull the list of movies and boxsets in Kodi
+        pdialog = self.pdialog
+        views = self.emby_db.getView_byType('tvshows')
+        views += self.emby_db.getView_byType('mixed')
+        log.info("Media folders: %s" % views)
+
+        # Pull the list of tvshows and episodes in Kodi
+        try:
+            all_koditvshows = dict(self.emby_db.get_checksum('Series'))
+        except ValueError:
+            all_koditvshows = {}
+
+        log.info("all_koditvshows = %s", all_koditvshows)
+
+        try:
+            all_kodiepisodes = dict(self.emby_db.get_checksum('Episode'))
+        except ValueError:
+            all_kodiepisodes = {}
+
+        all_embytvshowsIds = set()
+        all_embyepisodesIds = set()
+        updatelist = []
+
+
+        for view in views:
+
+            if self.should_stop():
+                return False
+
+            # Get items per view
+            viewId = view['id']
+            viewName = view['name']
+
+            if pdialog:
+                pdialog.update(
+                        heading=lang(29999),
+                        message="%s %s..." % (lang(33029), viewName))
+
+            all_embytvshows = self.emby.getShows(viewId, basic=True, dialog=pdialog)
+            for embytvshow in all_embytvshows['Items']:
+
+                if self.should_stop():
+                    return False
+
+                API = api.API(embytvshow)
+                itemid = embytvshow['Id']
+                all_embytvshowsIds.add(itemid)
+
+
+                if all_koditvshows.get(itemid) != API.get_checksum():
+                    # Only update if movie is not in Kodi or checksum is different
+                    updatelist.append(itemid)
+
+            log.info("TVShows to update for %s: %s" % (viewName, updatelist))
+            embytvshows = self.emby.getFullItems(updatelist)
+            self.total = len(updatelist)
+            del updatelist[:]
+
+
+            if pdialog:
+                pdialog.update(heading="Processing %s / %s items" % (viewName, self.total))
+
+            self.count = 0
+            for embytvshow in embytvshows:
+                # Process individual show
+                if self.should_stop():
+                    return False
+
+                itemid = embytvshow['Id']
+                title = embytvshow['Name']
+                all_embytvshowsIds.add(itemid)
+                self.update_pdialog()
+                
+                self.add_update(embytvshow, view)
+                self.count += 1
+
+            else:
+                # Get all episodes in view
+                if pdialog:
+                    pdialog.update(
+                            heading=lang(29999),
+                            message="%s %s..." % (lang(33030), viewName))
+
+                all_embyepisodes = self.emby.getEpisodes(viewId, basic=True, dialog=pdialog)
+                for embyepisode in all_embyepisodes['Items']:
+
+                    if self.should_stop():
+                        return False
+
+                    API = api.API(embyepisode)
+                    itemid = embyepisode['Id']
+                    all_embyepisodesIds.add(itemid)
+                    if "SeriesId" in embyepisode:
+                        all_embytvshowsIds.add(embyepisode['SeriesId'])
+
+                    if all_kodiepisodes.get(itemid) != API.get_checksum():
+                        # Only update if movie is not in Kodi or checksum is different
+                        updatelist.append(itemid)
+
+                log.info("Episodes to update for %s: %s" % (viewName, updatelist))
+                embyepisodes = self.emby.getFullItems(updatelist)
+                self.total = len(updatelist)
+                del updatelist[:]
+
+                self.count = 0
+                for episode in embyepisodes:
+
+                    # Process individual episode
+                    if self.should_stop():
+                        return False
+                    self.title = "%s - %s" % (episode.get('SeriesName', "Unknown"), episode['Name'])
+                    self.add_updateEpisode(episode)
+                    self.count += 1
+
+        ##### PROCESS DELETES #####
+
+        log.info("all_embytvshowsIds = %s " % all_embytvshowsIds)
+
+        for koditvshow in all_koditvshows:
+            if koditvshow not in all_embytvshowsIds:
+                self.remove(koditvshow)
+        else:
+            log.info("TVShows compare finished.")
+
+        for kodiepisode in all_kodiepisodes:
+            if kodiepisode not in all_embyepisodesIds:
+                self.remove(kodiepisode)
+        else:
+            log.info("Episodes compare finished.")
+
+        return True
+
+
+    def added(self, items, total=None, view=None):
+
+        for item in super(TVShows, self).added(items, total):
+            if self.add_update(item, view):
+                # Add episodes
+                all_episodes = self.emby.getEpisodesbyShow(item['Id'])
+                self.added_episode(all_episodes['Items'])
+
+    def added_season(self, items, total=None, view=None):
+        
+        update = True if not self.total else False
+
+        for item in super(TVShows, self).added(items, total, update):
+            self.title = "%s - %s" % (item.get('SeriesName', "Unknown"), self.title)
+
+            if self.add_updateSeason(item):
+                # Add episodes
+                all_episodes = self.emby.getEpisodesbySeason(item['Id'])
+                self.added_episode(all_episodes['Items'])
+
+    def added_episode(self, items, total=None, view=None):
+
+        update = True if not self.total else False
+
+        for item in super(TVShows, self).added(items, total, update):
+            self.title = "%s - %s" % (item.get('SeriesName', "Unknown"), self.title)
+
+            if self.add_updateEpisode(item):
+                self.content_pop()
+
+    @catch_except()
+    def add_update(self, item, view=None):
+        # Process single tvshow
+        kodicursor = self.kodicursor
+        emby = self.emby
+        emby_db = self.emby_db
+        artwork = self.artwork
+        API = api.API(item)
+
+        if settings('syncEmptyShows') == "false" and not item.get('RecursiveItemCount'):
+            log.info("Skipping empty show: %s" % item['Name'])
+            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
+        update_item = True
+        force_episodes = False
+        itemid = item['Id']
+        emby_dbitem = emby_db.getItem_byId(itemid)
+        try:
+            showid = emby_dbitem[0]
+            pathid = emby_dbitem[2]
+            log.info("showid: %s pathid: %s" % (showid, pathid))
+        
+        except TypeError:
+            update_item = False
+            log.debug("showid: %s not found." % itemid)
+            kodicursor.execute("select coalesce(max(idShow),0) from tvshow")
+            showid = kodicursor.fetchone()[0] + 1
+
+        else:
+            # Verification the item is still in Kodi
+            query = "SELECT * FROM tvshow WHERE idShow = ?"
+            kodicursor.execute(query, (showid,))
+            try:
+                kodicursor.fetchone()[0]
+            except TypeError:
+                # item is not found, let's recreate it.
+                update_item = False
+                log.info("showid: %s missing from Kodi, repairing the entry." % showid)
+                # Force re-add episodes after the show is re-created.
+                force_episodes = True
+
+
+        if view is None:
+            # Get view tag from emby
+            viewtag, viewid, mediatype = emby.getView_embyId(itemid)
+            log.debug("View tag found: %s" % viewtag)
+        else:
+            viewtag = view['name']
+            viewid = view['id']
+
+        # fileId information
+        checksum = API.get_checksum()
+        dateadded = API.get_date_created()
+        userdata = API.get_userdata()
+        playcount = userdata['PlayCount']
+        dateplayed = userdata['LastPlayedDate']
+
+        # item details
+        genres = item['Genres']
+        title = item['Name']
+        plot = API.get_overview()
+        rating = item.get('CommunityRating')
+        premieredate = API.get_premiere_date()
+        tvdb = API.get_provider('Tvdb')
+        sorttitle = item['SortName']
+        mpaa = API.get_mpaa()
+        genre = " / ".join(genres)
+        studios = API.get_studios()
+        studio = " / ".join(studios)
+
+        # Verify series pooling
+        if not update_item and tvdb:
+            query = "SELECT idShow FROM tvshow WHERE C12 = ?"
+            kodicursor.execute(query, (tvdb,))
+            try:
+                temp_showid = kodicursor.fetchone()[0]
+            except TypeError:
+                pass
+            else:
+                emby_other = emby_db.getItem_byKodiId(temp_showid, "tvshow")
+                if emby_other and viewid == emby_other[2]:
+                    log.info("Applying series pooling for %s", title)
+                    emby_other_item = emby_db.getItem_byId(emby_other[0])
+                    showid = emby_other_item[0]
+                    pathid = emby_other_item[2]
+                    log.info("showid: %s pathid: %s" % (showid, pathid))
+                    # Create the reference in emby table
+                    emby_db.addReference(itemid, showid, "Series", "tvshow", pathid=pathid,
+                                        checksum=checksum, mediafolderid=viewid)
+                    update_item = True
+
+        
+        ##### GET THE FILE AND PATH #####
+        playurl = API.get_file_path()
+
+        if self.direct_path:
+            # Direct paths is set the Kodi way
+            if "\\" in playurl:
+                # Local path
+                path = "%s\\" % playurl
+                toplevelpath = "%s\\" % dirname(dirname(path))
+            else:
+                # Network path
+                path = "%s/" % playurl
+                toplevelpath = "%s/" % dirname(dirname(path))
+
+            if not self.path_validation(path):
+                return False
+
+            window('emby_pathverified', value="true")
+        else:
+            # Set plugin path
+            toplevelpath = "plugin://plugin.video.emby.tvshows/"
+            path = "%s%s/" % (toplevelpath, itemid)
+
+
+        ##### UPDATE THE TVSHOW #####
+        if update_item:
+            log.info("UPDATE tvshow itemid: %s - Title: %s" % (itemid, title))
+
+            # Update the tvshow entry
+            query = ' '.join((
+                
+                "UPDATE tvshow",
+                "SET c00 = ?, c01 = ?, c04 = ?, c05 = ?, c08 = ?, c09 = ?,",
+                    "c12 = ?, c13 = ?, c14 = ?, c15 = ?",
+                "WHERE idShow = ?"
+            ))
+            kodicursor.execute(query, (title, plot, rating, premieredate, genre, title,
+                tvdb, mpaa, studio, sorttitle, showid))
+
+            # Update the checksum in emby table
+            emby_db.updateReference(itemid, checksum)
+        
+        ##### OR ADD THE TVSHOW #####
+        else:
+            log.info("ADD tvshow itemid: %s - Title: %s" % (itemid, title))
+            
+            # Add top path
+            toppathid = self.kodi_db.addPath(toplevelpath)
+            query = ' '.join((
+
+                "UPDATE path",
+                "SET strPath = ?, strContent = ?, strScraper = ?, noUpdate = ?",
+                "WHERE idPath = ?"
+            ))
+            kodicursor.execute(query, (toplevelpath, "tvshows", "metadata.local", 1, toppathid))
+            
+            # Add path
+            pathid = self.kodi_db.addPath(path)
+            
+            # Create the tvshow entry
+            query = (
+                '''
+                INSERT INTO tvshow(
+                    idShow, c00, c01, c04, c05, c08, c09, c12, c13, c14, c15) 
+
+                VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
+                '''
+            )
+            kodicursor.execute(query, (showid, title, plot, rating, premieredate, genre,
+                title, tvdb, mpaa, studio, sorttitle))
+
+            # Link the path
+            query = "INSERT INTO tvshowlinkpath(idShow, idPath) values(?, ?)"
+            kodicursor.execute(query, (showid, pathid))
+
+            # Create the reference in emby table
+            emby_db.addReference(itemid, showid, "Series", "tvshow", pathid=pathid,
+                                checksum=checksum, mediafolderid=viewid)
+
+        # Update the path
+        query = ' '.join((
+
+            "UPDATE path",
+            "SET strPath = ?, strContent = ?, strScraper = ?, noUpdate = ?",
+            "WHERE idPath = ?"
+        ))
+        kodicursor.execute(query, (path, None, None, 1, pathid))
+        
+        # Process cast
+        people = artwork.get_people_artwork(item['People'])
+        self.kodi_db.addPeople(showid, people, "tvshow")
+        # Process genres
+        self.kodi_db.addGenres(showid, genres, "tvshow")
+        # Process artwork
+        artwork.add_artwork(artwork.get_all_artwork(item), showid, "tvshow", kodicursor)
+        # Process studios
+        self.kodi_db.addStudios(showid, studios, "tvshow")
+        # Process tags: view, emby tags
+        tags = [viewtag]
+        tags.extend(item['Tags'])
+        if userdata['Favorite']:
+            tags.append("Favorite tvshows")
+        self.kodi_db.addTags(showid, tags, "tvshow")
+        # Process seasons
+        all_seasons = emby.getSeasons(itemid)
+        for season in all_seasons['Items']:
+            self.add_updateSeason(season, showid=showid)
+        else:
+            # Finally, refresh the all season entry
+            seasonid = self.kodi_db.addSeason(showid, -1)
+            # Process artwork
+            artwork.add_artwork(artwork.get_all_artwork(item), seasonid, "season", kodicursor)
+
+        if force_episodes:
+            # We needed to recreate the show entry. Re-add episodes now.
+            log.info("Repairing episodes for showid: %s %s" % (showid, title))
+            all_episodes = emby.getEpisodesbyShow(itemid)
+            self.added_episode(all_episodes['Items'], None)
+
+        return True
+
+    def add_updateSeason(self, item, showid=None):
+
+        kodicursor = self.kodicursor
+        emby_db = self.emby_db
+        artwork = self.artwork
+
+        seasonnum = item.get('IndexNumber', 1)
+
+        if showid is None:
+            try:
+                seriesId = item['SeriesId']
+                showid = emby_db.getItem_byId(seriesId)[0]
+            except KeyError:
+                return
+            except TypeError:
+                # Show is missing, update show instead.
+                show = self.emby.getItem(seriesId)
+                self.add_update(show)
+                return
+        
+        seasonid = self.kodi_db.addSeason(showid, seasonnum, item['Name'])
+        
+        if item['LocationType'] != "Virtual":
+            # Create the reference in emby table
+            emby_db.addReference(item['Id'], seasonid, "Season", "season", parentid=showid)
+
+        # Process artwork
+        artwork.add_artwork(artwork.get_all_artwork(item), seasonid, "season", kodicursor)
+
+        return True
+
+    @catch_except()
+    def add_updateEpisode(self, item):
+        # Process single episode
+        kodicursor = self.kodicursor
+        emby_db = self.emby_db
+        artwork = self.artwork
+        API = api.API(item)
+
+        if item.get('LocationType') == "Virtual": # TODO: Filter via api instead
+            log.info("Skipping virtual episode: %s", item['Name'])
+            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
+        update_item = True
+        itemid = item['Id']
+        emby_dbitem = emby_db.getItem_byId(itemid)
+        try:
+            episodeid = emby_dbitem[0]
+            fileid = emby_dbitem[1]
+            pathid = emby_dbitem[2]
+            log.info("episodeid: %s fileid: %s pathid: %s" % (episodeid, fileid, pathid))
+        
+        except TypeError:
+            update_item = False
+            log.debug("episodeid: %s not found." % itemid)
+            # episodeid
+            kodicursor.execute("select coalesce(max(idEpisode),0) from episode")
+            episodeid = kodicursor.fetchone()[0] + 1
+
+        else:
+            # Verification the item is still in Kodi
+            query = "SELECT * FROM episode WHERE idEpisode = ?"
+            kodicursor.execute(query, (episodeid,))
+            try:
+                kodicursor.fetchone()[0]
+            except TypeError:
+                # item is not found, let's recreate it.
+                update_item = False
+                log.info("episodeid: %s missing from Kodi, repairing the entry." % episodeid)
+
+        # fileId information
+        checksum = API.get_checksum()
+        dateadded = API.get_date_created()
+        userdata = API.get_userdata()
+        playcount = userdata['PlayCount']
+        dateplayed = userdata['LastPlayedDate']
+
+        # item details
+        people = API.get_people()
+        writer = " / ".join(people['Writer'])
+        director = " / ".join(people['Director'])
+        title = item['Name']
+        plot = API.get_overview()
+        rating = item.get('CommunityRating')
+        runtime = API.get_runtime()
+        premieredate = API.get_premiere_date()
+
+        # episode details
+        try:
+            seriesId = item['SeriesId']
+        except KeyError:
+            # Missing seriesId, skip
+            log.error("Skipping: %s. SeriesId is missing." % itemid)
+            return False
+            
+        season = item.get('ParentIndexNumber')
+        episode = item.get('IndexNumber', -1)
+       
+        if season is None:
+            if item.get('AbsoluteEpisodeNumber'):
+                # Anime scenario
+                season = 1
+                episode = item['AbsoluteEpisodeNumber']
+            else:
+                season = -1 if "Specials" not in item['Path'] else 0
+
+        # Specials ordering within season
+        if item.get('AirsAfterSeasonNumber'):
+            airsBeforeSeason = item['AirsAfterSeasonNumber']
+            airsBeforeEpisode = 4096 # Kodi default number for afterseason ordering
+        else:
+            airsBeforeSeason = item.get('AirsBeforeSeasonNumber')
+            airsBeforeEpisode = item.get('AirsBeforeEpisodeNumber')
+
+        # Append multi episodes to title
+        if item.get('IndexNumberEnd'):              
+            title = "| %02d | %s" % (item['IndexNumberEnd'], title)
+
+        # Get season id
+        show = emby_db.getItem_byId(seriesId)
+        try:
+            showid = show[0]
+        except TypeError:
+            # Show is missing from database
+            show = self.emby.getItem(seriesId)
+            self.add_update(show)
+            show = emby_db.getItem_byId(seriesId)
+            try:
+                showid = show[0]
+            except TypeError:
+                log.error("Skipping: %s. Unable to add series: %s." % (itemid, seriesId))
+                return False
+
+        seasonid = self.kodi_db.addSeason(showid, season)
+
+        
+        ##### GET THE FILE AND PATH #####
+        playurl = API.get_file_path()
+
+        if "\\" in playurl:
+            # Local path
+            filename = playurl.rsplit("\\", 1)[1]
+        else: # Network share
+            filename = playurl.rsplit("/", 1)[1]
+
+        if self.direct_path:
+            # Direct paths is set the Kodi way
+            if not self.path_validation(playurl):
+                return False
+            
+            path = playurl.replace(filename, "")
+            window('emby_pathverified', value="true")
+        else:
+            # Set plugin path and media flags using real filename
+            path = "plugin://plugin.video.emby.tvshows/%s/" % seriesId
+            params = {
+
+                'filename': filename.encode('utf-8'),
+                'id': itemid,
+                'dbid': episodeid,
+                'mode': "play"
+            }
+            filename = "%s?%s" % (path, urllib.urlencode(params))
+
+
+        ##### UPDATE THE EPISODE #####
+        if update_item:
+            log.info("UPDATE episode itemid: %s - Title: %s" % (itemid, title))
+
+            # Update the movie entry
+            if self.kodi_version in (16, 17):
+                # Kodi Jarvis, Krypton
+                query = ' '.join((
+                
+                    "UPDATE episode",
+                    "SET c00 = ?, c01 = ?, c03 = ?, c04 = ?, c05 = ?, c09 = ?, c10 = ?,",
+                        "c12 = ?, c13 = ?, c14 = ?, c15 = ?, c16 = ?, idSeason = ?, idShow = ?",
+                    "WHERE idEpisode = ?"
+                ))
+                kodicursor.execute(query, (title, plot, rating, writer, premieredate,
+                    runtime, director, season, episode, title, airsBeforeSeason,
+                    airsBeforeEpisode, seasonid, showid, episodeid))
+            else:
+                query = ' '.join((
+                    
+                    "UPDATE episode",
+                    "SET c00 = ?, c01 = ?, c03 = ?, c04 = ?, c05 = ?, c09 = ?, c10 = ?,",
+                        "c12 = ?, c13 = ?, c14 = ?, c15 = ?, c16 = ?, idShow = ?",
+                    "WHERE idEpisode = ?"
+                ))
+                kodicursor.execute(query, (title, plot, rating, writer, premieredate,
+                    runtime, director, season, episode, title, airsBeforeSeason,
+                    airsBeforeEpisode, showid, episodeid))
+
+            # Update the checksum in emby table
+            emby_db.updateReference(itemid, checksum)
+            # Update parentid reference
+            emby_db.updateParentId(itemid, seasonid)
+        
+        ##### OR ADD THE EPISODE #####
+        else:
+            log.info("ADD episode itemid: %s - Title: %s" % (itemid, title))
+            
+            # Add path
+            pathid = self.kodi_db.addPath(path)
+            # Add the file
+            fileid = self.kodi_db.addFile(filename, pathid)
+            
+            # Create the episode entry
+            if self.kodi_version in (16, 17):
+                # Kodi Jarvis, Krypton
+                query = (
+                    '''
+                    INSERT INTO episode(
+                        idEpisode, idFile, c00, c01, c03, c04, c05, c09, c10, c12, c13, c14,
+                        idShow, c15, c16, idSeason)
+
+                    VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
+                    '''
+                )
+                kodicursor.execute(query, (episodeid, fileid, title, plot, rating, writer,
+                    premieredate, runtime, director, season, episode, title, showid,
+                    airsBeforeSeason, airsBeforeEpisode, seasonid))
+            else:
+                query = (
+                    '''
+                    INSERT INTO episode(
+                        idEpisode, idFile, c00, c01, c03, c04, c05, c09, c10, c12, c13, c14,
+                        idShow, c15, c16)
+
+                    VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
+                    '''
+                )
+                kodicursor.execute(query, (episodeid, fileid, title, plot, rating, writer,
+                    premieredate, runtime, director, season, episode, title, showid,
+                    airsBeforeSeason, airsBeforeEpisode))
+
+            # Create the reference in emby table
+            emby_db.addReference(itemid, episodeid, "Episode", "episode", fileid, pathid,
+                seasonid, checksum)
+
+        # Update the path
+        query = ' '.join((
+
+            "UPDATE path",
+            "SET strPath = ?, strContent = ?, strScraper = ?, noUpdate = ?",
+            "WHERE idPath = ?"
+        ))
+        kodicursor.execute(query, (path, None, None, 1, pathid))
+
+        # Update the file
+        query = ' '.join((
+
+            "UPDATE files",
+            "SET idPath = ?, strFilename = ?, dateAdded = ?",
+            "WHERE idFile = ?"
+        ))
+        kodicursor.execute(query, (pathid, filename, dateadded, fileid))
+        
+        # Process cast
+        people = artwork.get_people_artwork(item['People'])
+        self.kodi_db.addPeople(episodeid, people, "episode")
+        # Process artwork
+        artworks = artwork.get_all_artwork(item)
+        artwork.add_update_art(artworks['Primary'], episodeid, "episode", "thumb", kodicursor)
+        # Process stream details
+        streams = API.get_media_streams()
+        self.kodi_db.addStreams(fileid, streams, runtime)
+        # Process playstates
+        resume = API.adjust_resume(userdata['Resume'])
+        total = round(float(runtime), 6)
+        self.kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed)
+        if not self.direct_path and resume:
+            # Create additional entry for widgets. This is only required for plugin/episode.
+            temppathid = self.kodi_db.getPath("plugin://plugin.video.emby.tvshows/")
+            tempfileid = self.kodi_db.addFile(filename, temppathid)
+            query = ' '.join((
+
+                "UPDATE files",
+                "SET idPath = ?, strFilename = ?, dateAdded = ?",
+                "WHERE idFile = ?"
+            ))
+            kodicursor.execute(query, (temppathid, filename, dateadded, tempfileid))
+            self.kodi_db.addPlaystate(tempfileid, resume, total, playcount, dateplayed)
+
+        return True
+
+    def updateUserdata(self, item):
+        # This updates: Favorite, LastPlayedDate, Playcount, PlaybackPositionTicks
+        # Poster with progress bar
+        emby_db = self.emby_db
+        API = api.API(item)
+        
+        # Get emby information
+        itemid = item['Id']
+        checksum = API.get_checksum()
+        userdata = API.get_userdata()
+        runtime = API.get_runtime()
+        dateadded = API.get_date_created()
+
+        # Get Kodi information
+        emby_dbitem = emby_db.getItem_byId(itemid)
+        try:
+            kodiid = emby_dbitem[0]
+            fileid = emby_dbitem[1]
+            mediatype = emby_dbitem[4]
+            log.info(
+                "Update playstate for %s: %s fileid: %s"
+                % (mediatype, item['Name'], fileid))
+        except TypeError:
+            return
+
+        # Process favorite tags
+        if mediatype == "tvshow":
+            if userdata['Favorite']:
+                self.kodi_db.addTag(kodiid, "Favorite tvshows", "tvshow")
+            else:
+                self.kodi_db.removeTag(kodiid, "Favorite tvshows", "tvshow")
+        elif mediatype == "episode":
+            # Process playstates
+            playcount = userdata['PlayCount']
+            dateplayed = userdata['LastPlayedDate']
+            resume = API.adjust_resume(userdata['Resume'])
+            total = round(float(runtime), 6)
+
+            log.debug("%s New resume point: %s" % (itemid, resume))
+
+            self.kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed)
+            if not self.direct_path and not resume:
+                # Make sure there's no other bookmarks created by widget.
+                filename = self.kodi_db.getFile(fileid)
+                self.kodi_db.removeFile("plugin://plugin.video.emby.tvshows/", filename)
+
+            if not self.direct_path and resume:
+                # Create additional entry for widgets. This is only required for plugin/episode.
+                filename = self.kodi_db.getFile(fileid)
+                temppathid = self.kodi_db.getPath("plugin://plugin.video.emby.tvshows/")
+                tempfileid = self.kodi_db.addFile(filename, temppathid)
+                query = ' '.join((
+
+                    "UPDATE files",
+                    "SET idPath = ?, strFilename = ?, dateAdded = ?",
+                    "WHERE idFile = ?"
+                ))
+                self.kodicursor.execute(query, (temppathid, filename, dateadded, tempfileid))
+                self.kodi_db.addPlaystate(tempfileid, resume, total, playcount, dateplayed)
+
+        emby_db.updateReference(itemid, checksum)
+
+    def remove(self, itemid):
+        # Remove showid, fileid, pathid, emby reference
+        emby_db = self.emby_db
+        embycursor = self.embycursor
+        kodicursor = self.kodicursor
+        artwork = self.artwork
+
+        emby_dbitem = emby_db.getItem_byId(itemid)
+        try:
+            kodiid = emby_dbitem[0]
+            fileid = emby_dbitem[1]
+            pathid = emby_dbitem[2]
+            parentid = emby_dbitem[3]
+            mediatype = emby_dbitem[4]
+            log.info("Removing %s kodiid: %s fileid: %s" % (mediatype, kodiid, fileid))
+        except TypeError:
+            return
+
+        ##### PROCESS ITEM #####
+
+        # Remove the emby reference
+        emby_db.removeItem(itemid)
+
+
+        ##### IF EPISODE #####
+
+        if mediatype == "episode":
+            # Delete kodi episode and file, verify season and tvshow
+            self.removeEpisode(kodiid, fileid)
+
+            # Season verification
+            season = emby_db.getItem_byKodiId(parentid, "season")
+            try:
+                showid = season[1]
+            except TypeError:
+                return
+            
+            season_episodes = emby_db.getItem_byParentId(parentid, "episode")
+            if not season_episodes:
+                self.removeSeason(parentid)
+                emby_db.removeItem(season[0])
+
+            # Show verification
+            show = emby_db.getItem_byKodiId(showid, "tvshow")
+            query = ' '.join((
+
+                "SELECT totalCount",
+                "FROM tvshowcounts",
+                "WHERE idShow = ?"
+            ))
+            kodicursor.execute(query, (showid,))
+            result = kodicursor.fetchone()
+            if result and result[0] is None:
+                # There's no episodes left, delete show and any possible remaining seasons
+                seasons = emby_db.getItem_byParentId(showid, "season")
+                for season in seasons:
+                    self.removeSeason(season[1])
+                else:
+                    # Delete emby season entries
+                    emby_db.removeItems_byParentId(showid, "season")
+                self.removeShow(showid)
+                emby_db.removeItem(show[0])
+
+        ##### IF TVSHOW #####
+
+        elif mediatype == "tvshow":
+            # Remove episodes, seasons, tvshow
+            seasons = emby_db.getItem_byParentId(kodiid, "season")
+            for season in seasons:
+                seasonid = season[1]
+                season_episodes = emby_db.getItem_byParentId(seasonid, "episode")
+                for episode in season_episodes:
+                    self.removeEpisode(episode[1], episode[2])
+                else:
+                    # Remove emby episodes
+                    emby_db.removeItems_byParentId(seasonid, "episode")
+            else:
+                # Remove emby seasons
+                emby_db.removeItems_byParentId(kodiid, "season")
+
+            # Remove tvshow
+            self.removeShow(kodiid)
+
+        ##### IF SEASON #####
+
+        elif mediatype == "season":
+            # Remove episodes, season, verify tvshow
+            season_episodes = emby_db.getItem_byParentId(kodiid, "episode")
+            for episode in season_episodes:
+                self.removeEpisode(episode[1], episode[2])
+            else:
+                # Remove emby episodes
+                emby_db.removeItems_byParentId(kodiid, "episode")
+            
+            # Remove season
+            self.removeSeason(kodiid)
+
+            # Show verification
+            seasons = emby_db.getItem_byParentId(parentid, "season")
+            if not seasons:
+                # There's no seasons, delete the show
+                self.removeShow(parentid)
+                emby_db.removeItem_byKodiId(parentid, "tvshow")
+
+        log.info("Deleted %s: %s from kodi database" % (mediatype, itemid))
+
+    def removeShow(self, kodiid):
+        
+        kodicursor = self.kodicursor
+        self.artwork.delete_artwork(kodiid, "tvshow", kodicursor)
+        kodicursor.execute("DELETE FROM tvshow WHERE idShow = ?", (kodiid,))
+        log.debug("Removed tvshow: %s." % kodiid)
+
+    def removeSeason(self, kodiid):
+        
+        kodicursor = self.kodicursor
+
+        self.artwork.delete_artwork(kodiid, "season", kodicursor)
+        kodicursor.execute("DELETE FROM seasons WHERE idSeason = ?", (kodiid,))
+        log.debug("Removed season: %s." % kodiid)
+
+    def removeEpisode(self, kodiid, fileid):
+
+        kodicursor = self.kodicursor
+
+        self.artwork.delete_artwork(kodiid, "episode", kodicursor)
+        kodicursor.execute("DELETE FROM episode WHERE idEpisode = ?", (kodiid,))
+        kodicursor.execute("DELETE FROM files WHERE idFile = ?", (fileid,))
+        log.debug("Removed episode: %s." % kodiid)
diff --git a/resources/lib/read_embyserver.py b/resources/lib/read_embyserver.py
index 867be38c..3fe6c6c2 100644
--- a/resources/lib/read_embyserver.py
+++ b/resources/lib/read_embyserver.py
@@ -186,7 +186,7 @@ class Read_EmbyServer():
         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):
+    def getSection(self, parentid, itemtype=None, sortby="SortName", artist_id=None, basic=False, dialog=None):
 
         items = {
             
@@ -199,6 +199,7 @@ class Read_EmbyServer():
         params = {
 
             'ParentId': parentid,
+            'ArtistIds': artist_id,
             'IncludeItemTypes': itemtype,
             'CollapseBoxSetItems': False,
             'IsVirtualUnaired': False,
@@ -225,6 +226,7 @@ class Read_EmbyServer():
                 params = {
 
                     'ParentId': parentid,
+                    'ArtistIds': artist_id,
                     'IncludeItemTypes': itemtype,
                     'CollapseBoxSetItems': False,
                     'IsVirtualUnaired': False,
@@ -435,10 +437,11 @@ class Read_EmbyServer():
 
         return self.getSection(seasonId, "Episode")
 
-    def getArtists(self, dialog=None):
+    def getArtists(self, parent_id=None, dialog=None):
 
         items = {
 
+            'ParentId': parent_id,
             'Items': [],
             'TotalRecordCount': 0
         }
@@ -459,13 +462,14 @@ class Read_EmbyServer():
             log.debug("%s:%s Failed to retrieve the server response." % (url, params))
 
         else:
-            index = 1
+            index = 0
             jump = self.limitIndex
 
             while index < total:
                 # Get items by chunk to increase retrieval speed at scale
                 params = {
 
+                    'ParentId': parent_id,
                     'Recursive': True,
                     'IsVirtualUnaired': False,
                     'IsMissing': False,
@@ -495,7 +499,7 @@ class Read_EmbyServer():
 
     def getAlbumsbyArtist(self, artistId):
 
-        return self.getSection(artistId, "MusicAlbum", sortby="DateCreated")
+        return self.getSection(None, "MusicAlbum", sortby="DateCreated", artist_id=artistId)
 
     def getSongs(self, basic=False, dialog=None):
 
diff --git a/resources/lib/utils.py b/resources/lib/utils.py
index f24941db..01413d38 100644
--- a/resources/lib/utils.py
+++ b/resources/lib/utils.py
@@ -109,6 +109,15 @@ class JSONRPC(object):
 #################################################################################################
 # Database related methods
 
+def should_stop():
+    # Checkpoint during the syncing process
+    if xbmc.Monitor().abortRequested():
+        return True
+    elif window('emby_shouldStop') == "true":
+        return True
+    else: # Keep going
+        return False
+
 def kodiSQL(media_type="video"):
 
     if media_type == "emby":
@@ -309,6 +318,21 @@ def indent(elem, level=0):
         if level and (not elem.tail or not elem.tail.strip()):
           elem.tail = i
 
+def catch_except(errors=(Exception, ), default_value=False):
+    # Will wrap method with try/except and print parameters for easier debugging
+    def decorator(func):
+        def wrapper(*args, **kwargs):
+            try:
+                return func(*args, **kwargs)
+            except errors as error:
+                log.exception(error)
+                log.error("function: %s \n args: %s \n kwargs: %s",
+                          func.__name__, args, kwargs)
+                return default_value
+
+        return wrapper
+    return decorator
+
 def profiling(sortby="cumulative"):
     # Will print results to Kodi log
     def decorator(func):