Exemplo n.º 1
0
    def start(self):
        ''' Main sync process.
        '''
        LOG.info("starting sync with %s", self.sync['Libraries'])
        save_sync(self.sync)
        start_time = datetime.datetime.now()

        for library in list(self.sync['Libraries']):

            self.process_library(library)

            if not library.startswith(
                    'Boxsets:') and library not in self.sync['Whitelist']:
                self.sync['Whitelist'].append(library)

            self.sync['Libraries'].pop(self.sync['Libraries'].index(library))
            self._restore_point({})

        elapsed = datetime.datetime.now() - start_time
        settings('SyncInstallRunDone.bool', True)
        self.library.save_last_sync()
        save_sync(self.sync)

        xbmc.executebuiltin('UpdateLibrary(video)')
        dialog("notification",
               heading="{emby}",
               message="%s %s" % (_(33025), str(elapsed).split('.')[0]),
               icon="{emby}",
               sound=False)
        LOG.info("Full sync completed in: %s", str(elapsed).split('.')[0])
Exemplo n.º 2
0
    def mapping(self):

        ''' Load the mapping of the full sync.
            This allows us to restore a previous sync.
        '''
        if self.sync['Libraries']:

            if not dialog("yesno", heading="{jellyfin}", line1=translate(33102)):

                if not dialog("yesno", heading="{jellyfin}", line1=translate(33173)):
                    dialog("ok", heading="{jellyfin}", line1=translate(33122))

                    raise LibraryException("ProgressStopped")
                else:
                    self.sync['Libraries'] = []
                    self.sync['RestorePoint'] = {}
        else:
            LOG.info("generate full sync")
            libraries = []

            for library in self.get_libraries():

                if library[2] in ('movies', 'tvshows', 'musicvideos', 'music', 'mixed'):
                    libraries.append({'Id': library[0], 'Name': library[1], 'Media': library[2]})

            libraries = self.select_libraries(libraries)

            if [x['Media'] for x in libraries if x['Media'] in ('movies', 'mixed')]:
                self.sync['Libraries'].append("Boxsets:")

        save_sync(self.sync)
Exemplo n.º 3
0
    def startup(self):
        ''' Run at startup. 
            Check databases. 
            Check for the server plugin.
        '''
        self.started = True
        Views().get_views()
        Views().get_nodes()

        try:
            if get_sync()['Libraries']:
                self.sync_libraries()

            elif not settings('SyncInstallRunDone.bool'):

                with self.sync(self, self.server) as sync:
                    sync.libraries()

                Views().get_nodes()
                xbmc.executebuiltin('ReloadSkin()')

                return True

            self.get_fast_sync()

            return True
        except LibraryException as error:
            LOG.error(error.status)

            if error.status in 'SyncLibraryLater':

                dialog("ok", heading="{emby}", line1=_(33129))
                settings('SyncInstallRunDone.bool', True)
                sync = get_sync()
                sync['Libraries'] = []
                save_sync(sync)

                return True

            elif error.status == 'CompanionMissing':

                dialog("ok", heading="{emby}", line1=_(33099))
                settings('kodiCompanion.bool', False)

                return True

            elif error.status == 'StopWriteCalled':
                self.verify_libs = True

            raise

        except Exception as error:
            LOG.exception(error)

        return False
Exemplo n.º 4
0
    def get_views(self):
        ''' Get the media folders. Add or remove them. Do not proceed if issue getting libraries.
        '''
        media = {
            'movies': "Movie",
            'tvshows': "Series",
            'musicvideos': "MusicVideo"
        }

        try:
            libraries = self.get_libraries()
        except IndexError as error:
            LOG.error(error)

            return

        self.sync['SortedViews'] = [x['Id'] for x in libraries]

        for library in libraries:

            if library['Type'] == 'Channel':
                library['Media'] = "channels"
            else:
                library['Media'] = library.get(
                    'OriginalCollectionType',
                    library.get('CollectionType', "mixed"))

            self.add_library(library)

        with Database('emby') as embydb:

            views = emby_db.EmbyDatabase(embydb.cursor).get_views()
            sorted_views = self.sync['SortedViews']
            whitelist = self.sync['Whitelist']
            removed = []

            for view in views:

                if view[0] not in sorted_views:
                    removed.append(view[0])

        if removed:

            event('RemoveLibrary', {'Id': ','.join(removed)})
            for library_id in removed:

                if library_id in sorted_views:
                    sorted_views.remove(library_id)

                if library_id in whitelist:
                    whitelist.remove(library_id)

        save_sync(self.sync)
Exemplo n.º 5
0
    def process_library(self, library_id):
        ''' Add a library by it's id. Create a node and a playlist whenever appropriate.
        '''
        media = {
            'movies': self.movies,
            'musicvideos': self.musicvideos,
            'tvshows': self.tvshows,
            'music': self.music
        }
        try:
            if library_id.startswith('Boxsets:'):

                if library_id.endswith('Refresh'):
                    self.refresh_boxsets()
                else:
                    self.boxsets(
                        library_id.split('Boxsets:')[1]
                        if len(library_id) > len('Boxsets:') else None)

                return

            library = self.server.jellyfin.get_item(
                library_id.replace('Mixed:', ""))

            if library_id.startswith('Mixed:'):
                for mixed in ('movies', 'tvshows'):

                    media[mixed](library)
                    self.sync['RestorePoint'] = {}
            else:
                if library['CollectionType']:
                    settings('enableMusic.bool', True)

                media[library['CollectionType']](library)
        except LibraryException as error:

            if error.status == 'StopCalled':
                save_sync(self.sync)

                raise

        except Exception as error:
            LOG.exception(error)

            if 'Failed to validate path' not in error:

                dialog("ok", heading="{jellyfin}", line1=translate(33119))
                LOG.error("full sync exited unexpectedly")
                save_sync(self.sync)

            raise
Exemplo n.º 6
0
    def start(self):
        
        ''' Main sync process.
        '''
        LOG.info("starting sync with %s", self.sync['Libraries'])
        save_sync(self.sync)
        start_time = datetime.datetime.now()

        if not settings('dbSyncScreensaver.bool'):

            xbmc.executebuiltin('InhibitIdleShutdown(true)')
            screensaver = get_screensaver()
            set_screensaver(value="")

        try:
            for library in list(self.sync['Libraries']):

                self.process_library(library)

                if not library.startswith('Boxsets:') and library not in self.sync['Whitelist']:
                    self.sync['Whitelist'].append(library)

                self.sync['Libraries'].pop(self.sync['Libraries'].index(library))
                self.sync['RestorePoint'] = {}
        except Exception as error:

            if not settings('dbSyncScreensaver.bool'):

                xbmc.executebuiltin('InhibitIdleShutdown(false)')
                set_screensaver(value=screensaver)

            raise

        elapsed = datetime.datetime.now() - start_time
        settings('SyncInstallRunDone.bool', True)
        self.library.save_last_sync()
        save_sync(self.sync)

        xbmc.executebuiltin('UpdateLibrary(video)')
        dialog("notification", heading="{emby}", message="%s %s" % (_(33025), str(elapsed).split('.')[0]),
               icon="{emby}", sound=False)
        LOG.info("Full sync completed in: %s", str(elapsed).split('.')[0])
Exemplo n.º 7
0
    def get_views(self):
        ''' Get the media folders. Add or remove them. Do not proceed if issue getting libraries.
        '''
        try:
            libraries = self.get_libraries()
        except IndexError as error:
            LOG.exception(error)

            return

        self.sync['SortedViews'] = [x['Id'] for x in libraries]

        for library in libraries:

            if library['Type'] == 'Channel':
                library['Media'] = "channels"
            else:
                library['Media'] = library.get(
                    'OriginalCollectionType',
                    library.get('CollectionType', "mixed"))

            self.add_library(library)

        with Database('jellyfin') as jellyfindb:

            views = jellyfin_db.JellyfinDatabase(jellyfindb.cursor).get_views()
            removed = []

            for view in views:

                if view[0] not in self.sync['SortedViews']:
                    removed.append(view[0])

            if removed:
                event('RemoveLibrary', {'Id': ','.join(removed)})

        save_sync(self.sync)
Exemplo n.º 8
0
    def get_views(self):
        ''' Get the media folders. Add or remove them.
        '''
        media = {
            'movies': "Movie",
            'tvshows': "Series",
            'musicvideos': "MusicVideo"
        }
        libraries = self.get_libraries()
        self.sync['SortedViews'] = [x['Id'] for x in libraries]

        for library in libraries:

            if library['Type'] == 'Channel':
                library['Media'] = "channels"
            else:
                library['Media'] = library.get(
                    'OriginalCollectionType',
                    library.get('CollectionType', "mixed"))

            self.add_library(library)

        with Database('emby') as embydb:

            views = emby_db.EmbyDatabase(embydb.cursor).get_views()
            removed = []

            for view in views:

                if view[0] not in self.sync['SortedViews']:
                    removed.append(view[0])

            if removed:
                event('RemoveLibrary', {'Id': ','.join(removed)})

        save_sync(self.sync)
Exemplo n.º 9
0
 def _restore_point(self, restore):
     ''' Assign the restore point and save the sync status.
     '''
     self.sync['RestorePoint'] = restore
     save_sync(self.sync)
Exemplo n.º 10
0
    def remove_library(self, library_id, dialog):
        ''' Remove library by their id from the Kodi database.
        '''
        MEDIA = self.library.MEDIA
        direct_path = self.library.direct_path

        with Database('emby') as embydb:

            db = emby_db.EmbyDatabase(embydb.cursor)
            library = db.get_view(library_id.replace('Mixed:', ""))
            items = db.get_item_by_media_folder(
                library_id.replace('Mixed:', ""))
            media = 'music' if library[1] == 'music' else 'video'

            if items:
                count = 0

                with self.library.music_database_lock if media == 'music' else self.library.database_lock:
                    with Database(media) as kodidb:

                        if library[1] == 'mixed':

                            movies = [x for x in items if x[1] == 'Movie']
                            tvshows = [x for x in items if x[1] == 'Series']

                            obj = MEDIA['Movie'](self.server, embydb, kodidb,
                                                 direct_path)['Remove']

                            for item in movies:

                                obj(item[0])
                                dialog.update(int(
                                    (float(count) / float(len(items)) * 100)),
                                              heading="%s: %s" %
                                              (_('addon_name'), library[0]))
                                count += 1

                            obj = MEDIA['Series'](self.server, embydb, kodidb,
                                                  direct_path)['Remove']

                            for item in tvshows:

                                obj(item[0])
                                dialog.update(int(
                                    (float(count) / float(len(items)) * 100)),
                                              heading="%s: %s" %
                                              (_('addon_name'), library[0]))
                                count += 1
                        else:
                            obj = MEDIA[items[0][1]](self.server, embydb,
                                                     kodidb,
                                                     direct_path)['Remove']

                            for item in items:

                                obj(item[0])
                                dialog.update(int(
                                    (float(count) / float(len(items)) * 100)),
                                              heading="%s: %s" %
                                              (_('addon_name'), library[0]))
                                count += 1

        self.sync = get_sync()

        if library_id in self.sync['Whitelist']:
            self.sync['Whitelist'].remove(library_id)

        elif 'Mixed:%s' % library_id in self.sync['Whitelist']:
            self.sync['Whitelist'].remove('Mixed:%s' % library_id)

        save_sync(self.sync)
Exemplo n.º 11
0
    def startup(self):
        ''' Run at startup. 
            Check databases. 
            Check for the server plugin.
        '''
        Views().get_views()
        Views().get_nodes()

        try:
            if get_sync()['Libraries']:

                try:
                    with FullSync(self, self.server) as sync:
                        sync.libraries()

                    Views().get_nodes()
                except Exception as error:
                    LOG.error(error)

            elif not settings('SyncInstallRunDone.bool'):

                with FullSync(self, self.server) as sync:
                    sync.libraries()

                Views().get_nodes()

                return True

            if settings('SyncInstallRunDone.bool'):
                if settings('kodiCompanion.bool'):

                    for plugin in self.server['api'].get_plugins():
                        if plugin['Name'] in ("Emby.Kodi Sync Queue",
                                              "Kodi companion"):

                            if not self.fast_sync():
                                dialog("ok", heading="{emby}", line1=_(33128))

                                raise Exception(
                                    "Failed to retrieve latest updates")

                            LOG.info("--<[ retrieve changes ]")

                            break
                    else:
                        raise LibraryException('CompanionMissing')

            return True
        except LibraryException as error:
            LOG.error(error.status)

            if error.status in 'SyncLibraryLater':

                dialog("ok", heading="{emby}", line1=_(33129))
                settings('SyncInstallRunDone.bool', True)
                sync = get_sync()
                sync['Libraries'] = []
                save_sync(sync)

                return True

            elif error.status == 'CompanionMissing':

                dialog("ok", heading="{emby}", line1=_(33099))
                settings('kodiCompanion.bool', False)

                return True

        except Exception as error:
            LOG.exception(error)

        return False
Exemplo n.º 12
0
    def startup(self):
        ''' Run at startup.
            Check databases.
            Check for the server plugin.
        '''
        self.test_databases()

        Views().get_views()
        Views().get_nodes()

        try:
            if get_sync()['Libraries']:

                try:
                    with FullSync(self, self.server) as sync:
                        sync.libraries()

                    Views().get_nodes()
                except Exception as error:
                    LOG.exception(error)

            elif not settings('SyncInstallRunDone.bool'):

                with FullSync(self, self.server) as sync:
                    sync.libraries()

                Views().get_nodes()

                return True

            if settings('SyncInstallRunDone.bool'):
                if settings('kodiCompanion.bool'):

                    if self.server.jellyfin.check_companion_installed():

                        if not self.fast_sync():
                            dialog("ok", "{jellyfin}", translate(33128))

                            raise Exception(
                                "Failed to retrieve latest updates")

                        LOG.info("--<[ retrieve changes ]")

                    else:
                        raise LibraryException('CompanionMissing')

            return True
        except LibraryException as error:
            LOG.error(error.status)

            if error.status in 'SyncLibraryLater':

                dialog("ok", "{jellyfin}", translate(33129))
                settings('SyncInstallRunDone.bool', True)
                sync = get_sync()
                sync['Libraries'] = []
                save_sync(sync)

                return True

            elif error.status == 'CompanionMissing':

                dialog("ok", "{jellyfin}", translate(33099))
                settings('kodiCompanion.bool', False)

                return True

        except Exception as error:
            LOG.exception(error)

        return False
Exemplo n.º 13
0
    def remove_library(self, library_id, dialog):
        ''' Remove library by their id from the Kodi database.
        '''
        direct_path = self.library.direct_path

        with Database('jellyfin') as jellyfindb:

            db = jellyfin_db.JellyfinDatabase(jellyfindb.cursor)
            library = db.get_view(library_id.replace('Mixed:', ""))
            items = db.get_item_by_media_folder(
                library_id.replace('Mixed:', ""))
            media = 'music' if library[1] == 'music' else 'video'

            if media == 'music':
                settings('MusicRescan.bool', False)

            if items:
                count = 0

                with self.library.music_database_lock if media == 'music' else self.library.database_lock:
                    with Database(media) as kodidb:

                        if library[1] == 'mixed':

                            movies = [x for x in items if x[1] == 'Movie']
                            tvshows = [x for x in items if x[1] == 'Series']

                            obj = Movies(self.server, jellyfindb, kodidb,
                                         direct_path).remove

                            for item in movies:

                                obj(item[0])
                                dialog.update(
                                    int((float(count) / float(len(items)) *
                                         100)),
                                    heading="%s: %s" %
                                    (translate('addon_name'), library[0]))
                                count += 1

                            obj = TVShows(self.server, jellyfindb, kodidb,
                                          direct_path).remove

                            for item in tvshows:

                                obj(item[0])
                                dialog.update(
                                    int((float(count) / float(len(items)) *
                                         100)),
                                    heading="%s: %s" %
                                    (translate('addon_name'), library[0]))
                                count += 1
                        else:
                            default_args = (self.server, jellyfindb, kodidb,
                                            direct_path)
                            for item in items:
                                if item[1] in ('Series', 'Season', 'Episode'):
                                    TVShows(*default_args).remove(item[0])
                                elif item[1] in ('Movie', 'BoxSet'):
                                    Movies(*default_args).remove(item[0])
                                elif item[1] in ('MusicAlbum', 'MusicArtist',
                                                 'AlbumArtist', 'Audio'):
                                    Music(*default_args).remove(item[0])
                                elif item[1] == 'MusicVideo':
                                    MusicVideos(*default_args).remove(item[0])

                                dialog.update(
                                    int((float(count) / float(len(items)) *
                                         100)),
                                    heading="%s: %s" %
                                    (translate('addon_name'), library[0]))
                                count += 1

        self.sync = get_sync()

        if library_id in self.sync['Whitelist']:
            self.sync['Whitelist'].remove(library_id)

        elif 'Mixed:%s' % library_id in self.sync['Whitelist']:
            self.sync['Whitelist'].remove('Mixed:%s' % library_id)

        save_sync(self.sync)
Exemplo n.º 14
0
    def remove_library(self, library_id, dialog):
        ''' Remove library by their id from the Kodi database.
        '''
        MEDIA = self.library.MEDIA
        direct_path = self.library.direct_path

        with Database('jellyfin') as jellyfindb:

            db = jellyfin_db.JellyfinDatabase(jellyfindb.cursor)
            library = db.get_view(library_id.replace('Mixed:', ""))
            items = db.get_item_by_media_folder(
                library_id.replace('Mixed:', ""))
            media = 'music' if library[1] == 'music' else 'video'

            if media == 'music':
                settings('MusicRescan.bool', False)

            if items:
                count = 0

                with self.library.music_database_lock if media == 'music' else self.library.database_lock:
                    with Database(media) as kodidb:

                        if library[1] == 'mixed':

                            movies = [x for x in items if x[1] == 'Movie']
                            tvshows = [x for x in items if x[1] == 'Series']

                            obj = Movies(self.server, jellyfindb, kodidb,
                                         direct_path).remove

                            for item in movies:

                                obj(item[0])
                                dialog.update(int(
                                    (float(count) / float(len(items)) * 100)),
                                              heading="%s: %s" %
                                              (_('addon_name'), library[0]))
                                count += 1

                            obj = TVShows(self.server, jellyfindb, kodidb,
                                          direct_path).remove

                            for item in tvshows:

                                obj(item[0])
                                dialog.update(int(
                                    (float(count) / float(len(items)) * 100)),
                                              heading="%s: %s" %
                                              (_('addon_name'), library[0]))
                                count += 1
                        else:
                            # from mcarlton: I'm not sure what triggers this.
                            # I've added and removed every media type except
                            # for music videos (because i don't have any) and
                            # can't find it, but I'm not comfortable
                            # removing it right now
                            LOG.info('Triggered the mystery function')
                            LOG.debug('Mystery function item type: {}'.format(
                                items[0][1]))
                            obj = MEDIA[items[0][1]](self.server, jellyfindb,
                                                     kodidb,
                                                     direct_path).remove

                            for item in items:

                                obj(item[0])
                                dialog.update(int(
                                    (float(count) / float(len(items)) * 100)),
                                              heading="%s: %s" %
                                              (_('addon_name'), library[0]))
                                count += 1

        self.sync = get_sync()

        if library_id in self.sync['Whitelist']:
            self.sync['Whitelist'].remove(library_id)

        elif 'Mixed:%s' % library_id in self.sync['Whitelist']:
            self.sync['Whitelist'].remove('Mixed:%s' % library_id)

        save_sync(self.sync)
Exemplo n.º 15
0
    def process_library(self, library_id):
        ''' Add a library by it's id. Create a node and a playlist whenever appropriate.
        '''
        media = {
            'movies': self.movies,
            'musicvideos': self.musicvideos,
            'tvshows': self.tvshows,
            'music': self.music
        }
        try:
            if library_id.startswith('Boxsets:'):
                boxset_library = {}

                # Initial library sync is 'Boxsets:'
                # Refresh from the addon menu is 'Boxsets:Refresh'
                # Incremental syncs are 'Boxsets:$library_id'
                sync_id = library_id.split(':')[1]

                if not sync_id or sync_id == 'Refresh':
                    libraries = self.get_libraries()
                else:
                    _lib = self.get_library(sync_id)
                    libraries = [_lib] if _lib else []

                for entry in libraries:
                    if entry.media_type == 'boxsets':
                        boxset_library = {
                            'Id': entry.view_id,
                            'Name': entry.view_name
                        }
                        break

                if boxset_library:
                    if sync_id == 'Refresh':
                        self.refresh_boxsets(boxset_library)
                    else:
                        self.boxsets(boxset_library)

                return

            library = self.server.jellyfin.get_item(
                library_id.replace('Mixed:', ""))

            if library_id.startswith('Mixed:'):
                for mixed in ('movies', 'tvshows'):

                    media[mixed](library)
                    self.sync['RestorePoint'] = {}
            else:
                if library['CollectionType']:
                    settings('enableMusic.bool', True)

                media[library['CollectionType']](library)
        except LibraryException as error:

            if error.status == 'StopCalled':
                save_sync(self.sync)

                raise

        except PathValidationException:
            raise

        except Exception as error:
            dialog("ok", "{jellyfin}", translate(33119))

            LOG.error("full sync exited unexpectedly")
            LOG.exception(error)

            save_sync(self.sync)

            raise
Exemplo n.º 16
0
    def remove_library(self, library_id, dialog):

        try:
            with Database('emby') as embydb:

                db = emby_db.EmbyDatabase(embydb.cursor)
                library = db.get_view(library_id.replace('Mixed:', ""))
                items = db.get_item_by_media_folder(
                    library_id.replace('Mixed:', ""))
                media = 'music' if library[1] == 'music' else 'video'

                if media == 'music':
                    settings('MusicRescan.bool', False)

                if items:
                    count = 0

                    with self.music_database_lock if media == 'music' else self.database_lock:
                        with Database(media) as kodidb:

                            if library[1] == 'mixed':
                                movies = [x for x in items if x[1] == 'Movie']
                                tvshows = [
                                    x for x in items if x[1] == 'Series'
                                ]

                                obj = MEDIA['Movie'](
                                    self.server, embydb, kodidb,
                                    self.direct_path)['Remove']

                                for item in movies:
                                    obj(item[0])
                                    dialog.update(
                                        int((float(count) / float(len(items)) *
                                             100)),
                                        heading="%s: %s" %
                                        (_('addon_name'), library[0]))
                                    count += 1

                                obj = MEDIA['Series'](
                                    self.server, embydb, kodidb,
                                    self.direct_path)['Remove']

                                for item in tvshows:
                                    obj(item[0])
                                    dialog.update(
                                        int((float(count) / float(len(items)) *
                                             100)),
                                        heading="%s: %s" %
                                        (_('addon_name'), library[0]))
                                    count += 1
                            else:
                                obj = MEDIA[items[0][1]](
                                    self.server, embydb, kodidb,
                                    self.direct_path)['Remove']

                                for item in items:
                                    obj(item[0])
                                    dialog.update(
                                        int((float(count) / float(len(items)) *
                                             100)),
                                        heading="%s: %s" %
                                        (_('addon_name'), library[0]))
                                    count += 1

            sync = get_sync()

            if library_id in sync['Whitelist']:
                sync['Whitelist'].remove(library_id)
            elif 'Mixed:%s' % library_id in sync['Whitelist']:
                sync['Whitelist'].remove('Mixed:%s' % library_id)

            save_sync(sync)
            Views().remove_library(library_id)
        except Exception as error:

            LOG.exception(error)
            dialog.close()

            return False

        Views().get_views()
        Views().get_nodes()

        return True