def add_user(): ''' Add or remove users from the default server session. ''' if not window('jellyfin_online.bool'): return session = TheVoid('GetSession', {}).get() users = TheVoid('GetUsers', {'IsDisabled': False, 'IsHidden': False}).get() current = session[0]['AdditionalUsers'] result = dialog("select", translate(33061), [translate(33062), translate(33063)] if current else [translate(33062)]) if result < 0: return if not result: # Add user eligible = [x for x in users if x['Id'] not in [current_user['UserId'] for current_user in current]] resp = dialog("select", translate(33064), [x['Name'] for x in eligible]) if resp < 0: return user = eligible[resp] event('AddUser', {'Id': user['Id'], 'Add': True}) else: # Remove user resp = dialog("select", translate(33064), [x['UserName'] for x in current]) if resp < 0: return user = current[resp] event('AddUser', {'Id': user['UserId'], 'Add': False})
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)
def _get_server(self, method, data): ''' Retrieve the Emby server. ''' try: if not data.get('ServerId'): raise Exception("ServerId undefined.") if method != 'LoadServer' and data['ServerId'] not in self.servers: try: connect.Connect().register(data['ServerId']) self.server_instance(data['ServerId']) except Exception as error: LOG.error(error) dialog("ok", heading="{emby}", line1=_(33142)) return server = Emby(data['ServerId']).get_client() except Exception: server = Emby().get_client() return server
def changelog(): version = client.get_version() resp = dialog("select", heading="{emby}", list=[version, _(33212)]) if resp < 0: return if resp: src = "https://api.github.com/repos/MediaBrowser/plugin.video.emby/releases/latest" else: src = "https://api.github.com/repos/MediaBrowser/plugin.video.emby/releases/tags/%s" % version try: response = requests.get(src) response.raise_for_status() response.encoding = 'utf-8' response = response.json() response['body'] = "[B]%s[/B]\n\n%s" % (response['name'], response['body']) response['body'] = response['body'].replace('**:', '[/B]').replace('**', '[B]').replace('*', '-') dialog("textviewer", heading="{emby}", text=response['body']) except Exception as error: LOG.error(error) dialog("notification", heading="{emby}", message=_(33204), icon="{emby}", time=1000, sound=False) return
def cache_textures(self): ''' This method will sync all Kodi artwork to textures13.db and cache them locally. This takes diskspace! ''' if not dialog("yesno", heading="{emby}", line1=_(33042)): LOG.info("<[ cache textures ]") return pdialog = xbmcgui.DialogProgress() pdialog.create(_('addon_name'), _(33045)) if dialog("yesno", heading="{emby}", line1=_(33044)): self.delete_all_cache() self._cache_all_video_entries(pdialog) self._cache_all_music_entries(pdialog) pdialog.update(100, "%s: %s" % (_(33046), len(self.queue.queue))) while len(self.threads): if pdialog.iscanceled(): break remaining = len(self.queue.queue) pdialog.update(100, "%s: %s" % (_(33046), remaining)) LOG.info("Waiting for all threads to exit: %s (%s)", len(self.threads), remaining) xbmc.sleep(500) pdialog.close()
def set_web_server(self): ''' Enable the webserver if not enabled. This is used to cache artwork. Will only test once, if it fails, user will be notified only once. ''' if settings('enableTextureCache.bool'): get_setting = JSONRPC('Settings.GetSettingValue') if not self.get_web_server(): set_setting = JSONRPC('Settings.SetSetingValue') set_setting.execute({'setting': "services.webserverport", 'value': 8080}) set_setting.execute({'setting': "services.webserver", 'value': True}) if not self.get_web_server(): settings('enableTextureCache.bool', False) dialog("ok", heading="{emby}", line1=_(33103)) return result = get_setting.execute({'setting': "services.webserverport"}) settings('webServerPort', str(result['result']['value'] or "")) result = get_setting.execute({'setting': "services.webserverusername"}) settings('webServerUser', str(result['result']['value'] or "")) result = get_setting.execute({'setting': "services.webserverpassword"}) settings('webServerPass', str(result['result']['value'] or "")) settings('useWebServer.bool', True)
def run(self): while True: try: item = self.queue.get(timeout=3) except Queue.Empty: break time = self.music_time if item[0] == 'Audio' else self.video_time if time and ( not self.player.isPlayingVideo() or xbmc.getCondVisibility('VideoPlayer.Content(livetv)')): dialog("notification", heading="%s %s" % (_(33049), item[0]), message=item[1], icon="{emby}", time=time, sound=False) self.queue.task_done() if window('emby_should_stop.bool'): break LOG.info("--<[ q:notify/%s ]", id(self)) self.is_done = True
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])
def get_fast_sync(self): new_fast_sync = compare_version(self.server['auth/server-version'], "4.2.0.23") enable_fast_sync = False 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"): enable_fast_sync = True break if new_fast_sync > 0: self.fast_sync(enable_fast_sync) elif enable_fast_sync: if not self.fast_sync_plugin(): dialog("ok", heading="{emby}", line1=_(33128)) raise Exception("Failed to retrieve latest updates") else: raise LibraryException('CompanionMissing') LOG.info("--<[ retrieve changes ]")
def service(self): ''' Keeps the service monitor going. Exit on Kodi shutdown or profile switch. if profile switch happens more than once, Threads depending on abortRequest will not trigger. ''' self.monitor = objects.monitor.Monitor() self.monitor.service = self self.connect = connect.Connect() self.player = self['monitor'].player self._server() while self.running: if window('emby_online.bool'): if self['profile'] != window('emby_kodiProfile'): LOG.info("[ profile switch ] %s", self['profile']) break if self['player'].isPlaying( ) and self['player'].is_playing_file( self['player'].get_playing_file()): difference = datetime.today() - self['last_progress'] if difference.seconds > 4: self['last_progress'] = datetime.today() update = (datetime.today() - self['last_progress_report']).seconds > 40 event('ReportProgressRequested', {'Report': update}) if update: self['last_progress_report'] = datetime.today() if not WEBSERVICE.is_alive(): LOG.info("[ restarting due to socket disconnect ]") window('emby.restart.bool', True) if window('emby.restart.bool'): dialog("notification", heading="{emby}", message=_(33193), icon="{emby}", time=1000, sound=False) raise Exception('RestartService') if self.waitForAbort(1): break self.shutdown() raise Exception("ExitService")
def service(self): ''' Keeps the service monitor going. Exit on Kodi shutdown or profile switch. if profile switch happens more than once, Threads depending on abortRequest will not trigger. ''' self.monitor = monitor.Monitor() player = self.monitor.player self.connect = connect.Connect() self.start_default() self.settings['mode'] = settings('useDirectPaths') while self.running: if window('jellyfin_online.bool'): if self.settings['profile'] != window('jellyfin_kodiProfile'): LOG.info("[ profile switch ] %s", self.settings['profile']) break if player.isPlaying() and player.is_playing_file( player.get_playing_file()): difference = datetime.today( ) - self.settings['last_progress'] if difference.seconds > 10: self.settings['last_progress'] = datetime.today() update = (datetime.today() - self.settings['last_progress_report'] ).seconds > 250 event('ReportProgressRequested', {'Report': update}) if update: self.settings[ 'last_progress_report'] = datetime.today() if window('jellyfin.restart.bool'): window('jellyfin.restart', clear=True) dialog("notification", heading="{jellyfin}", message=translate(33193), icon="{jellyfin}", time=1000, sound=False) raise Exception('RestartService') if self.waitForAbort(1): break self.shutdown() raise Exception("ExitService")
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
def _is_mode(self): ''' Setup playback mode. If native mode selected, check network credentials. ''' value = dialog("yesno", heading=_('playback_mode'), line1=_(33035), nolabel=_('addon_mode'), yeslabel=_('native_mode')) settings('useDirectPaths', value="1" if value else "0") if value: dialog("ok", heading="{jellyfin}", line1=_(33145))
def __init__(self, library, server): ''' You can call all big syncing methods here. Initial, update, repair, remove. ''' self.__dict__ = self._shared_state if self.running: dialog("ok", heading="{emby}", line1=_(33197)) raise Exception("Sync is already running.") self.library = library self.server = server
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
def __init__(self, library, library_id=None, update=False): ''' Map the syncing process and start the sync. Ensure only one sync is running. ''' self.__dict__ = self._shared_state window('emby_sync.bool', True) if not settings('dbSyncScreensaver.bool'): xbmc.executebuiltin('InhibitIdleShutdown(true)') self.screensaver = get_screensaver() set_screensaver(value="") if not self.running: self.running = True self.library = library self.direct_path = settings('useDirectPaths') == "1" self.update_library = update self.server = Emby() self.sync = get_sync() if library_id: libraries = library_id.split(',') for selected in libraries: if selected not in [x.replace('Mixed:', "") for x in self.sync['Libraries']]: library = self.get_libraries(selected) if library: self.sync['Libraries'].append("Mixed:%s" % selected if library[1] == 'mixed' else selected) if library[1] in ('mixed', 'movies'): self.sync['Libraries'].append('Boxsets:%s' % selected) else: self.sync['Libraries'].append(selected) else: self.mapping() xmls.sources() if not xmls.advanced_settings() and self.sync['Libraries']: self.start() else: self.running = False else: dialog("ok", heading="{emby}", line1=_(33197)) raise Exception("Sync is already running.")
def check_update(self, forced=False): ''' Check for objects build version and compare. This pulls a dict that contains all the information for the build needed. ''' LOG.info("--[ check updates/%s ]", objects.version) kodi = "DEV" if settings('devMode.bool') else xbmc.getInfoLabel( 'System.BuildVersion') try: versions = requests.get( 'http://kodi.emby.media/Public%20testing/Dependencies/databases.json' ).json() build = find(versions, kodi) if not build: raise Exception("build %s incompatible?!" % kodi) label, zipfile = build.split('-', 1) if label == 'DEV' and forced: LOG.info("--[ force/objects/%s ]", label) elif label == objects.version: LOG.info("--[ objects/%s ]", objects.version) return False get_objects(zipfile, label + '.zip') self.reload_objects() dialog("notification", heading="{emby}", message=_(33156), icon="{emby}") LOG.info("--[ new objects/%s ]", objects.version) try: if compare_version(self.settings['addon_version'], objects.embyversion) < 0: dialog("ok", heading="{emby}", line1="%s %s" % (_(33160), objects.embyversion)) except Exception: pass except Exception as error: LOG.exception(error) return True
def reset_kodi(): with Database() as videodb: videodb.cursor.execute( "SELECT tbl_name FROM sqlite_master WHERE type='table'") for table in videodb.cursor.fetchall(): name = table[0] if name != 'version': videodb.cursor.execute("DELETE FROM " + name) if settings('enableMusic.bool') or dialog( "yesno", heading="{jellyfin}", line1=translate(33162)): with Database('music') as musicdb: musicdb.cursor.execute( "SELECT tbl_name FROM sqlite_master WHERE type='table'") for table in musicdb.cursor.fetchall(): name = table[0] if name != 'version': musicdb.cursor.execute("DELETE FROM " + name) LOG.info("[ reset kodi ]")
def _set_intros(self, item): ''' if we have any play them when the movie/show is not being resumed. ''' intros = TheVoid('GetIntros', {'ServerId': self.server_id, 'Id': item['Id']}).get() if intros['Items']: enabled = True if settings('askCinema') == "true": resp = dialog("yesno", heading="{emby}", line1=_(33016)) if not resp: enabled = False LOG.info("Skip trailers.") if enabled: for intro in intros['Items']: listitem = xbmcgui.ListItem() LOG.info("[ intro/%s ] %s", intro['Id'], intro['Name']) play = playutils.PlayUtils(intro, False, self.server_id, self.server) source = play.select_source(play.get_sources()) self.set_listitem(intro, listitem, intro=True) listitem.setPath(intro['PlaybackInfo']['Path']) playutils.set_properties(intro, intro['PlaybackInfo']['Method'], self.server_id) self.stack.append([intro['PlaybackInfo']['Path'], listitem]) window('emby.skip.%s' % intro['Id'], value="true")
def _set_intros(self, item): ''' if we have any play them when the movie/show is not being resumed. ''' intros = self.api_client.get_intros(item['Id']) if intros['Items']: enabled = True if settings('askCinema') == "true": resp = dialog("yesno", "{jellyfin}", translate(33016)) if not resp: enabled = False LOG.info("Skip trailers.") if enabled: for intro in intros['Items']: listitem = xbmcgui.ListItem() LOG.info("[ intro/%s ] %s", intro['Id'], intro['Name']) play = playutils.PlayUtils(intro, False, self.server_id, self.server, self.api_client) play.select_source(play.get_sources()) self.set_listitem(intro, listitem, intro=True) listitem.setPath(intro['PlaybackInfo']['Path']) playutils.set_properties(intro, intro['PlaybackInfo']['Method'], self.server_id) self.stack.append([intro['PlaybackInfo']['Path'], listitem]) window('jellyfin.skip.%s' % intro['Id'], value="true")
def fast_sync(self): ''' Movie and userdata not provided by server yet. ''' last_sync = settings('LastIncrementalSync') include = [] filters = ["tvshows", "boxsets", "musicvideos", "music", "movies"] sync = get_sync() LOG.info("--[ retrieve changes ] %s", last_sync) # Get the item type of each synced library and build list of types to request for item_id in sync['Whitelist']: library = self.server.jellyfin.get_item(item_id) library_type = library.get('CollectionType') if library_type in filters: include.append(library_type) # Include boxsets if movies are synced if 'movies' in include: include.append('boxsets') # Filter down to the list of library types we want to exclude query_filter = list(set(filters) - set(include)) try: updated = [] userdata = [] removed = [] # Get list of updates from server for synced library types and populate work queues result = self.server.jellyfin.get_sync_queue( last_sync, ",".join([x for x in query_filter])) updated.extend(result['ItemsAdded']) updated.extend(result['ItemsUpdated']) userdata.extend(result['UserDataChanged']) removed.extend(result['ItemsRemoved']) total = len(updated) + len(userdata) if total > int(settings('syncIndicator') or 99): ''' Inverse yes no, in case the dialog is forced closed by Kodi. ''' if dialog("yesno", "{jellyfin}", translate(33172).replace('{number}', str(total)), nolabel=translate(107), yeslabel=translate(106)): LOG.warning("Large updates skipped.") return True self.updated(updated) self.userdata(userdata) self.removed(removed) except Exception as error: LOG.exception(error) return False return True
def select_libraries(self, libraries): ''' Select all or certain libraries to be whitelisted. ''' choices = [x['Name'] for x in libraries] choices.insert(0, translate(33121)) selection = dialog("multi", translate(33120), choices) if selection is None: raise LibraryException('LibrarySelection') elif not selection: LOG.info("Nothing was selected.") raise LibraryException('SyncLibraryLater') if 0 in selection: selection = list(range(1, len(libraries) + 1)) selected_libraries = [] for x in selection: library = libraries[x - 1] if library['Media'] != 'mixed': selected_libraries.append(library['Id']) else: selected_libraries.append("Mixed:%s" % library['Id']) self.sync['Libraries'] = selected_libraries return [libraries[x - 1] for x in selection]
def run(self): import objects ''' Workaround for playing folders only (context menu on a series/season folder > play) Due to plugin paths being returned within the strm, the entries are mislabelled. Queue items after the first item was setup and started playing via plugin above. ''' xbmc.sleep(200) # Let Kodi catch up LOG.info("-->[ folder play ]") play = None position = 1 # play folder should always create a new playlist. while True: if not window('emby.playlist.plugin.bool' ): # default.py wait for initial item to start up try: try: params = self.server.queue.get(timeout=0.01) except Queue.Empty: break server = params.get('server') if not server and not window('emby_online.bool'): dialog("notification", heading="{emby}", message=_(33146), icon=xbmcgui.NOTIFICATION_ERROR) raise Exception("NotConnected") play = objects.PlayStrm(params, server) position = play.play_folder(position) except Exception as error: LOG.exception(error) xbmc.Player().stop() # mute failed playback pop up xbmc.PlayList(xbmc.PLAYLIST_VIDEO).clear() self.server.queue.queue.clear() break self.server.queue.task_done() self.server.threads.remove(self) self.server.pending = [] LOG.info("--<[ folder play ]")
def onSettingsChanged(self): ''' React to setting changes that impact window values. ''' if window('emby_should_stop.bool'): return if settings('logLevel') != self['log_level']: log_level = settings('logLevel') window('emby_logLevel', str(log_level)) self['logLevel'] = log_level LOG.warn("New log level: %s", log_level) if settings('enableContext.bool') != self['enable_context']: window('emby_context', settings('enableContext')) self['enable_context'] = settings('enableContext.bool') LOG.warn("New context setting: %s", self['enable_context']) if settings('enableContextTranscode.bool' ) != self['enable_context_transcode']: window('emby_context_transcode', settings('enableContextTranscode')) self['enable_context_transcode'] = settings( 'enableContextTranscode.bool') LOG.warn("New context transcode setting: %s", self['enable_context_transcode']) if settings('useDirectPaths') != self['mode'] and self[ 'library'] and self['library'].started: self['mode'] = settings('useDirectPaths') LOG.warn("New playback mode setting: %s", self['mode']) if not self['mode_warn']: self['mode_warn'] = True if dialog("yesno", heading="{emby}", line1=_(33118)): xbmc.executebuiltin( 'RunPlugin(plugin://plugin.video.emby/?mode=reset)') if settings('kodiCompanion.bool') != self['kodi_companion']: self['kodi_companion'] = settings('kodiCompanion.bool') if not self['kodi_companion']: dialog("ok", heading="{emby}", line1=_(33138))
def select_libraries(self, mode=None): ''' Select from libraries synced. Either update or repair libraries. Send event back to service.py ''' modes = { 'SyncLibrarySelection': 'SyncLibrary', 'RepairLibrarySelection': 'RepairLibrary', 'AddLibrarySelection': 'SyncLibrary', 'RemoveLibrarySelection': 'RemoveLibrary' } sync = get_sync() whitelist = [x.replace('Mixed:', "") for x in sync['Whitelist']] libraries = [] with Database('jellyfin') as jellyfindb: db = jellyfin_db.JellyfinDatabase(jellyfindb.cursor) if mode in ('SyncLibrarySelection', 'RepairLibrarySelection', 'RemoveLibrarySelection'): for library in sync['Whitelist']: name = db.get_view_name(library.replace('Mixed:', "")) libraries.append({'Id': library, 'Name': name}) else: available = [x for x in sync['SortedViews'] if x not in whitelist] for library in available: name, media = db.get_view(library) if media in ('movies', 'tvshows', 'musicvideos', 'mixed', 'music'): libraries.append({'Id': library, 'Name': name}) choices = [x['Name'] for x in libraries] choices.insert(0, translate(33121)) titles = { "RepairLibrarySelection": 33199, "SyncLibrarySelection": 33198, "RemoveLibrarySelection": 33200, "AddLibrarySelection": 33120 } title = titles.get(mode, "Failed to get title {}".format(mode)) selection = dialog("multi", translate(title), choices) if selection is None: return if 0 in selection: selection = list(range(1, len(libraries) + 1)) selected_libraries = [] for x in selection: library = libraries[x - 1] selected_libraries.append(library['Id']) event(modes[mode], {'Id': ','.join([libraries[x - 1]['Id'] for x in selection]), 'Update': mode == 'SyncLibrarySelection'})
def onSettingsChanged(self): ''' React to setting changes that impact window values. ''' if window('jellyfin_should_stop.bool'): return if settings('logLevel') != self.settings['log_level']: log_level = settings('logLevel') window('jellyfin_logLevel', str(log_level)) self.settings['logLevel'] = log_level LOG.info("New log level: %s", log_level) if settings('enableContext.bool') != self.settings['enable_context']: window('jellyfin_context', settings('enableContext')) self.settings['enable_context'] = settings('enableContext.bool') LOG.info("New context setting: %s", self.settings['enable_context']) if settings('enableContextTranscode.bool' ) != self.settings['enable_context_transcode']: window('jellyfin_context_transcode', settings('enableContextTranscode')) self.settings['enable_context_transcode'] = settings( 'enableContextTranscode.bool') LOG.info("New context transcode setting: %s", self.settings['enable_context_transcode']) if settings('useDirectPaths' ) != self.settings['mode'] and self.library_thread.started: self.settings['mode'] = settings('useDirectPaths') LOG.info("New playback mode setting: %s", self.settings['mode']) if not self.settings.get('mode_warn'): self.settings['mode_warn'] = True dialog("yesno", heading="{jellyfin}", line1=translate(33118)) if settings('kodiCompanion.bool') != self.settings['kodi_companion']: self.settings['kodi_companion'] = settings('kodiCompanion.bool') if not self.settings['kodi_companion']: dialog("ok", heading="{jellyfin}", line1=translate(33138))
def fast_sync(self): ''' Movie and userdata not provided by server yet. ''' last_sync = settings('LastIncrementalSync') filters = ["tvshows", "boxsets", "musicvideos", "music", "movies"] sync = get_sync() LOG.info("--[ retrieve changes ] %s", last_sync) try: updated = [] userdata = [] removed = [] for media in filters: result = self.server.jellyfin.get_sync_queue(last_sync, ",".join([x for x in filters if x != media])) updated.extend(result['ItemsAdded']) updated.extend(result['ItemsUpdated']) userdata.extend(result['UserDataChanged']) removed.extend(result['ItemsRemoved']) total = len(updated) + len(userdata) if total > int(settings('syncIndicator') or 99): ''' Inverse yes no, in case the dialog is forced closed by Kodi. ''' if dialog("yesno", heading="{jellyfin}", line1=translate(33172).replace('{number}', str(total)), nolabel=translate(107), yeslabel=translate(106)): LOG.warning("Large updates skipped.") return True self.updated(updated) self.userdata(userdata) self.removed(removed) """ result = self.server.jellyfin.get_sync_queue(last_sync) self.userdata(result['UserDataChanged']) self.removed(result['ItemsRemoved']) filters.extend(["tvshows", "boxsets", "musicvideos", "music"]) # Get only movies. result = self.server.jellyfin.get_sync_queue(last_sync, ",".join(filters)) self.updated(result['ItemsAdded']) self.updated(result['ItemsUpdated']) self.userdata(result['UserDataChanged']) self.removed(result['ItemsRemoved']) """ except Exception as error: LOG.exception(error) return False return True
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])
def delete_item(self): delete = True if not settings('skipContextMenu.bool'): if not dialog("yesno", "{jellyfin}", translate(33015)): delete = False if delete: TheVoid('DeleteItem', {'ServerId': self.server, 'Id': self.item['Id']})
def delete_item(self): delete = True if not settings('skipContextMenu.bool'): if not dialog("yesno", heading="{emby}", line1=_(33015)): delete = False if delete: TheVoid('DeleteItem', {'ServerId': self.server, 'Id': self.item['Id']})