def refreshPlaylist(): lib = librarysync.LibrarySync() dialog = xbmcgui.Dialog() try: # First remove playlists utils.deletePlaylists() # Remove video nodes utils.deleteNodes() # Refresh views lib.refreshViews() dialog.notification( heading=lang(29999), message=lang(33069), icon="special://home/addons/plugin.video.emby/icon.png", time=1000, sound=False) except Exception as e: log("Refresh playlists/nodes failed: %s" % e, 1) dialog.notification(heading=lang(29999), message=lang(33070), icon=xbmcgui.NOTIFICATION_ERROR, time=1000, sound=False)
def tvshows(self, embycursor, kodicursor, pdialog): # Get shows from emby emby_db = embydb.Embydb_Functions(embycursor) tvshows = TVShows(embycursor, kodicursor, pdialog) views = emby_db.getView_byType('tvshows') views += emby_db.getView_byType('mixed') log.info("Media folders: %s" % views) for view in views: # Get items per view if pdialog: pdialog.update( heading=lang(29999), message="%s %s..." % (lang(33020), view['name'])) all_tvshows = self.emby.getShows(view['id'], dialog=pdialog) tvshows.add_all("Series", all_tvshows, view) else: log.debug("TVShows finished.") return True
def refreshPlaylist(): if window('emby_online') != "true": log.info("server is offline") return lib = librarysync.LibrarySync() dialog = xbmcgui.Dialog() try: # First remove playlists Playlist().delete_playlists() # Remove video nodes VideoNodes().deleteNodes() # Refresh views lib.refreshViews() dialog.notification( heading=lang(29999), message=lang(33069), icon="special://home/addons/emby.for.kodi/icon.png", time=1000, sound=False) except Exception as e: log.exception("Refresh playlists/nodes failed: %s" % e) dialog.notification( heading=lang(29999), message=lang(33070), icon=xbmcgui.NOTIFICATION_ERROR, time=1000, sound=False)
def update_library(self, path=False): if debug.get(): log('remove_video setting set to %s' % (setting('remove_video'))) if path and setting('remove_video') == 'true': if debug.get(): log('removing video from video library %s' % (path)) videolibrary.remove_video(path) if debug.get(): log('update_library setting set to %s' % (setting('update_library'))) if setting('update_library') == 'true': if debug.get(): log('updating whole video library %s' % (path)) xbmc.executebuiltin('UpdateLibrary(video)') while not xbmc.getCondVisibility('Library.IsScanningVideo'): pass while xbmc.getCondVisibility('Library.IsScanningVideo'): xbmc.sleep(20) percent = (self.current - 1) * 100 / self.steps if self.enable: self.bar.update(percent, info('name'), lang(30531) % (self.module_title, lang(30513))) self.current += 1 self.module_current += 1 log('Progress.update_library: self.current=%s, self.module_current=%s' % (self.current, self.module_current))
def __run(self): """ Do the work """ log.debug('Show sync info thread started') # cache local variables because it's faster total = self.total dialog = self.dialog thread_stopped = self.thread_stopped dialog.create("%s %s: %s %s" % (lang(39714), self.item_type, str(total), lang(39715))) total = 2 * total totalProgress = 0 while thread_stopped() is False: with LOCK: get_progress = GET_METADATA_COUNT process_progress = PROCESS_METADATA_COUNT viewName = PROCESSING_VIEW_NAME totalProgress = get_progress + process_progress try: percentage = int(float(totalProgress) / float(total) * 100.0) except ZeroDivisionError: percentage = 0 dialog.update(percentage, message="%s %s. %s %s: %s" % (get_progress, lang(39712), process_progress, lang(39713), viewName)) # Sleep for x milliseconds sleep(200) dialog.close() log.debug('Show sync info thread terminated')
def musicvideos(self, embycursor, kodicursor, pdialog): # Get musicvideos from emby emby_db = embydb.Embydb_Functions(embycursor) mvideos = MusicVideos(embycursor, kodicursor, pdialog) views = emby_db.getView_byType('musicvideos') log.info("Media folders: %s" % views) for view in views: log.info("Processing: %s", view) # Get items per view viewId = view['id'] viewName = view['name'] if pdialog: pdialog.update( heading=lang(29999), message="%s %s..." % (lang(33019), viewName)) # Initial or repair sync all_mvideos = self.emby.getMusicVideos(viewId, dialog=pdialog) mvideos.add_all("MusicVideo", all_mvideos, view) else: log.debug("MusicVideos finished.") return True
def movies(self, embycursor, kodicursor, pdialog): # Get movies from emby emby_db = embydb.Embydb_Functions(embycursor) movies = Movies(embycursor, kodicursor, pdialog) views = emby_db.getView_byType('movies') views += emby_db.getView_byType('mixed') log.info("Media folders: %s" % views) ##### PROCESS MOVIES ##### for view in views: log.info("Processing: %s", view) view_name = view['name'] # Get items per view if pdialog: pdialog.update(heading=lang(29999), message="%s %s..." % (lang(33017), view_name)) all_movies = self.emby.getMovies(view['id'], dialog=pdialog) movies.add_all("Movie", all_movies, view) log.debug("Movies finished.") ##### PROCESS BOXSETS ##### if pdialog: pdialog.update(heading=lang(29999), message=lang(33018)) boxsets = self.emby.getBoxset(dialog=pdialog) movies.add_all("BoxSet", boxsets) log.debug("Boxsets finished.") return True
def _play(cls, data): item_ids = data['ItemIds'] command = data['PlayCommand'] playlist_ = playlist.Playlist() if command == 'PlayNow': startat = data.get('StartPositionTicks', 0) playlist_.play_all(item_ids, startat) dialog(type_="notification", heading="{emby}", message="%s %s" % (len(item_ids), lang(33004)), icon="{emby}", sound=False) elif command == 'PlayNext': new_playlist = playlist_.modify_playlist(item_ids) dialog(type_="notification", heading="{emby}", message="%s %s" % (len(item_ids), lang(33005)), icon="{emby}", sound=False) player = xbmc.Player() if not player.isPlaying(): # Only start the playlist if nothing is playing player.play(new_playlist)
def onInit(self): self.message = self.getControl(MESSAGE) self.message_box = self.getControl(MESSAGE_BOX) self.busy = self.getControl(BUSY) self.list_ = self.getControl(LIST) for server in self.servers: server_type = "wifi" if server.get('ExchangeToken') else "network" self.list_.addItem( self._add_listitem(server['Name'], server['Id'], server_type)) self.getControl(USER_NAME).setLabel( "%s %s" % (lang(33000), self.username.decode('utf-8'))) if self.user_image is not None: self.getControl(USER_IMAGE).setImage(self.user_image) if not self.emby_connect: # Change connect user self.getControl(EMBY_CONNECT).setLabel("[UPPERCASE][B]" + lang(30618) + "[/B][/UPPERCASE]") if self.servers: self.setFocus(self.list_)
def _AutoPickPMS(self): """ Will try to pick PMS based on machineIdentifier saved in file settings but only once Returns server or None if unsuccessful """ httpsUpdated = False checkedPlexTV = False server = None while True: if httpsUpdated is False: serverlist = self._getServerList() for item in serverlist: if item.get('machineIdentifier') == self.serverid: server = item if server is None: name = settings('plex_servername') log.warn('The PMS you have used before with a unique ' 'machineIdentifier of %s and name %s is ' 'offline' % (self.serverid, name)) # "PMS xyz offline" self.dialog.notification(addonName, '%s %s' % (name, lang(39213)), xbmcgui.NOTIFICATION_ERROR, 7000, False) return chk = self._checkServerCon(server) if chk == 504 and httpsUpdated is False: # Not able to use HTTP, try HTTPs for now server['scheme'] = 'https' httpsUpdated = True continue if chk == 401: log.warn('Not yet authorized for Plex server %s' % server['name']) if self.CheckPlexTVSignIn() is True: if checkedPlexTV is False: # Try again checkedPlexTV = True httpsUpdated = False continue else: log.warn('Not authorized even though we are signed ' ' in to plex.tv correctly') self.dialog.ok(addonName, '%s %s' % lang(39214) + server['name']) return else: return # Problems connecting elif chk >= 400 or chk is False: log.warn('Problems connecting to server %s. chk is %s' % (server['name'], chk)) return log.info('We found a server to automatically connect to: %s' % server['name']) return server
def chooseServer(): """ Lets user choose from list of PMS """ log.info("Choosing PMS server requested, starting") import initialsetup setup = initialsetup.InitialSetup() server = setup.pick_pms(showDialog=True) if server is None: log.error('We did not connect to a new PMS, aborting') plex_command('SUSPEND_USER_CLIENT', 'False') plex_command('SUSPEND_LIBRARY_THREAD', 'False') return log.info("User chose server %s" % server['name']) setup.write_pms_to_settings(server) if not __LogOut(): return from utils import wipe_database # Wipe Kodi and Plex database as well as playlists and video nodes wipe_database() # Log in again __LogIn() log.info("Choosing new PMS complete") # '<PMS> connected' dialog('notification', lang(29999), '%s %s' % (server['name'], lang(39220)), icon='{plex}', time=3000, sound=False)
def _AutoPickPMS(self): """ Will try to pick PMS based on machineIdentifier saved in file settings but only once Returns server or None if unsuccessful """ httpsUpdated = False checkedPlexTV = False server = None while True: if httpsUpdated is False: serverlist = self._getServerList() for item in serverlist: if item.get('machineIdentifier') == self.serverid: server = item if server is None: name = settings('plex_servername') log.warn('The PMS you have used before with a unique ' 'machineIdentifier of %s and name %s is ' 'offline' % (self.serverid, name)) # "PMS xyz offline" if settings('show_pms_offline') == 'true': self.dialog.notification(addonName, '%s %s' % (name, lang(39213)), xbmcgui.NOTIFICATION_ERROR, 7000, False) return chk = self._checkServerCon(server) if chk == 504 and httpsUpdated is False: # Not able to use HTTP, try HTTPs for now server['scheme'] = 'https' httpsUpdated = True continue if chk == 401: log.warn('Not yet authorized for Plex server %s' % server['name']) if self.CheckPlexTVSignIn() is True: if checkedPlexTV is False: # Try again checkedPlexTV = True httpsUpdated = False continue else: log.warn('Not authorized even though we are signed ' ' in to plex.tv correctly') self.dialog.ok(addonName, '%s %s' % lang(39214) + server['name']) return else: return # Problems connecting elif chk >= 400 or chk is False: log.warn('Problems connecting to server %s. chk is %s' % (server['name'], chk)) return log.info('We found a server to automatically connect to: %s' % server['name']) return server
def emby_backup(): # Create a backup at specified location path = settings('backupPath') # filename default_value = "Kodi%s.%s" % (xbmc.getInfoLabel('System.BuildVersion')[:2], xbmc.getInfoLabel('System.Date(dd-mm-yy)')) folder_name = dialog(type_="input", heading=lang(33089), defaultt=default_value) if not folder_name: return backup = os.path.join(path, folder_name) log.info("Backup: %s", backup) # Create directory if xbmcvfs.exists(backup+"\\"): log.info("Existing directory!") if not dialog(type_="yesno", heading="{emby}", line1=lang(33090)): return emby_backup() shutil.rmtree(backup) # Addon_data addon_data = xbmc.translatePath("special://profile/addon_data/emby.for.kodi").decode('utf-8') try: shutil.copytree(src=addon_data, dst=os.path.join(backup, "addon_data", "emby.for.kodi")) except shutil.Error as error: log.error(error) # Database files database_folder = os.path.join(backup, "Database") if not xbmcvfs.mkdir(database_folder): try: os.makedirs(database_folder) except OSError as error: log.error(error) dialog(type_="ok", heading="{emby}", line1="Failed to create backup") return # Emby database emby_path = database.emby_database() xbmcvfs.copy(emby_path, os.path.join(database_folder, ntpath.basename(emby_path))) # Videos database video_path = database.video_database() xbmcvfs.copy(video_path, os.path.join(database_folder, ntpath.basename(video_path))) # Music database if settings('enableMusic') == "true": music_path = database.music_database() xbmcvfs.copy(music_path, os.path.join(database_folder, ntpath.basename(music_path))) dialog(type_="ok", heading="{emby}", line1="%s: %s" % (lang(33091), backup))
def resetAuth(): # User tried login and failed too many times resp = xbmcgui.Dialog().yesno(heading=lang(30132), line1=lang(33050)) if resp: log("Reset login attempts.", 1) window('emby_serverStatus', value="Auth") else: xbmc.executebuiltin('Addon.OpenSettings(plugin.video.emby)')
def _auto_pick_pms(self): """ Will try to pick PMS based on machineIdentifier saved in file settings but only once Returns server or None if unsuccessful """ https_updated = False checked_plex_tv = False server = None while True: if https_updated is False: serverlist = PF.discover_pms(self.plex_token) for item in serverlist: if item.get('machineIdentifier') == self.serverid: server = item if server is None: name = settings('plex_servername') LOG.warn( 'The PMS you have used before with a unique ' 'machineIdentifier of %s and name %s is ' 'offline', self.serverid, name) return chk = self._check_pms_connectivity(server) if chk == 504 and https_updated is False: # switch HTTPS to HTTP or vice-versa if server['scheme'] == 'https': server['scheme'] = 'http' else: server['scheme'] = 'https' https_updated = True continue if chk == 401: LOG.warn('Not yet authorized for Plex server %s', server['name']) if self.check_plex_tv_sign_in() is True: if checked_plex_tv is False: # Try again checked_plex_tv = True https_updated = False continue else: LOG.warn('Not authorized even though we are signed ' ' in to plex.tv correctly') dialog( 'ok', lang(29999), '%s %s' % (lang(39214), try_encode(server['name']))) return else: return # Problems connecting elif chk >= 400 or chk is False: LOG.warn('Problems connecting to server %s. chk is %s', server['name'], chk) return LOG.info('We found a server to automatically connect to: %s', server['name']) return server
def compare_boxsets(self): if self.pdialog: self.pdialog.update(heading=lang(29999), message=lang(33027)) boxsets = dict(self.emby_db.get_checksum('BoxSet')) emby_boxsets = self.emby.getBoxset(dialog=self.pdialog) return self.compare("BoxSet", emby_boxsets['Items'], boxsets)
def __rate_lib(self, progress): progress.start_module(lang(30204), self.RATE_LIB_STEPS) try: if not self.episodeid: raise Exception(lang(30601)) progress.update(lang(30522)) # updating rating utilxbmc.set_episode_rating(self.episodeid, self.rating) except Exception, e: dialog.error(e.message)
def compare_songs(self): if self.pdialog: self.pdialog.update(heading=lang(29999), message="%s Songs..." % lang(33031)) songs = dict(self.emby_db.get_checksum('Audio')) emby_songs = self.emby.getSongs(basic=True, dialog=self.pdialog) return self.compare("Audio", emby_songs['Items'], songs)
def __preserve_playcount(self, progress): progress.start_module(lang(30701), self.PRESERVE_PLAYCOUNT_STEPS) try: if not self.movieid: raise Exception(lang(30604)) progress.update(lang(30598)) # setting old playcount utilxbmc.set_movie_playcount(self.movieid, self.playcount) except Exception, e: dialog.error(e.message)
def __set_tag(self, progress): progress.start_module(lang(30702), self.SET_TAG_STEPS) try: if not self.movieid: raise Exception(lang(30604)) progress.update(lang(30597)) # setting tag utilxbmc.set_movie_tag(self.movieid, self.tag) except Exception, e: dialog.error(e.message)
def compare_albums(self): if self.pdialog: self.pdialog.update(heading=lang(29999), message="%s Albums..." % lang(33031)) albums = dict(self.emby_db.get_checksum('MusicAlbum')) emby_albums = self.emby.getAlbums(basic=True, dialog=self.pdialog) return self.compare("MusicAlbum", emby_albums['Items'], albums)
def __rate_lib(self, progress): progress.start_module(lang(30204), self.RATE_LIB_STEPS) try: if not self.movieid: raise Exception(lang(30604)) progress.update(lang(30522)) # updating rating log("Movie ID is %d" % self.movieid) utilxbmc.set_movie_rating(self.movieid, self.rating) except Exception, e: dialog.error(e.message)
def fullTextureCacheSync(self): """ This method will sync all Kodi artwork to textures13.db and cache them locally. This takes diskspace! """ if not dialog('yesno', "Image Texture Cache", lang(39250)): return log.info("Doing Image Cache Sync") # ask to rest all existing or not if dialog('yesno', "Image Texture Cache", lang(39251)): log.info("Resetting all cache data first") # Remove all existing textures first path = translatePath("special://thumbnails/") if exists(path): rmtree(path, ignore_errors=True) # remove all existing data from texture DB connection = kodiSQL('texture') cursor = connection.cursor() query = 'SELECT tbl_name FROM sqlite_master WHERE type=?' cursor.execute(query, ('table', )) rows = cursor.fetchall() for row in rows: tableName = row[0] if tableName != "version": query = "DELETE FROM ?" cursor.execute(query, (tableName, )) connection.commit() connection.close() # Cache all entries in video DB connection = kodiSQL('video') cursor = connection.cursor() # dont include actors query = "SELECT url FROM art WHERE media_type != ?" cursor.execute(query, ('actor', )) result = cursor.fetchall() total = len(result) log.info("Image cache sync about to process %s video images" % total) connection.close() for url in result: self.cacheTexture(url[0]) # Cache all entries in music DB connection = kodiSQL('music') cursor = connection.cursor() cursor.execute("SELECT url FROM art") result = cursor.fetchall() total = len(result) log.info("Image cache sync about to process %s music images" % total) connection.close() for url in result: self.cacheTexture(url[0])
def __move(self, progress): progress.start_module(lang(30132), self.MOVE_STEPS) try: progress.update(lang(30590)) # detecting library place lib_source = os.path.dirname(os.path.dirname(os.path.dirname(self.path))) if self.destination == lib_source: raise Exception(lang(30602)) progress.update(lang(30506)) # moving files source = os.path.dirname(self.path) match = os.path.splitext(os.path.basename(self.path))[0] count = utilfile.count_manage_files(self.alt_method, source, match) if not dialog.warning(lang(30132), count): raise Exception(lang(30609)) log("Episode: move source path: %s" % source) if setting('fm_episodes_structure') == '0': # multiple folders destination = os.path.join(self.destination, self.path.split(os.sep)[-3], self.path.split(os.sep)[-2]) log("Episode: move destination (multiple) |alt_method=%s|: %s" % (self.alt_method, destination)) else: # single folder destination = os.path.join(self.destination, self.path.split(os.sep)[-2]) log("Episode: move destination (single) |alt_method=%s|: %s" % (self.alt_method, destination)) utilfile.move_files(self.alt_method, source, destination, match, True) progress.update(lang(30513)) # updating library progress.update_library(self.path) self.path = os.path.join(destination, os.path.basename(self.path)) self.episodeid = utilxbmc.get_episodeid_by_path(self.path) if self.episodeid: # if still in lib source folders progress.update(lang(30514)) # setting watched utilxbmc.set_episode_playcount(self.episodeid, self.playcount+1) except OSError: dialog.error(lang(30610)) except ValueError as err: ValueErrorHandler(err) except Exception, e: dialog.error(e.message)
def fastSync(self): lastSync = settings('LastIncrementalSync') if not lastSync: lastSync = "2010-01-01T00:00:00Z" lastSyncTime = utils.convertDate(lastSync) log.info("Last sync run: %s" % lastSyncTime) # get server RetentionDateTime try: result = self.doUtils( "{server}/emby/Emby.Kodi.SyncQueue/GetServerDateTime?format=json" ) retention_time = result['RetentionDateTime'] except Exception as error: log.error(error) retention_time = "2010-01-01T00:00:00Z" retention_time = utils.convertDate(retention_time) log.info("RetentionDateTime: %s" % retention_time) # if last sync before retention time do a full sync if retention_time > lastSyncTime: log.info( "Fast sync server retention insufficient, fall back to full sync" ) return False params = {'LastUpdateDT': lastSync} if settings('enableMusic') != "true": params['filter'] = "music" url = "{server}/emby/Emby.Kodi.SyncQueue/{UserId}/GetItems?format=json" try: result = self.doUtils(url, parameters=params) processlist = { 'added': result['ItemsAdded'], 'update': result['ItemsUpdated'], 'userdata': result['UserDataChanged'], 'remove': result['ItemsRemoved'] } except Exception as error: # To be reviewed to only catch specific errors. log.error(error) log.error("Failed to retrieve latest updates using fast sync.") xbmcgui.Dialog().ok(lang(29999), lang(33095)) return False else: log.info("Fast sync changes: %s" % result) for action in processlist: self.triage_items(action, processlist[action]) return True
def _connect_to_server(self, server, port): server_address = "%s:%s" % (server, port) self._message("%s %s..." % (lang(30610), server_address)) result = self.connect_manager.connectToAddress(server_address) if result['State'] == CONN_STATE['Unavailable']: self._message(lang(30609)) return False else: self._server = result['Servers'][0] return True
def __rate_tag(self, progress): progress.start_module(lang(30205), self.RATE_TAG_STEPS) try: if not self.movieid: raise Exception(lang(30604)) progress.update(lang(30524)) # setting tag tag = setting("rt_movies_tag_text") if "%s" in tag: tag = tag % self.rating utilxbmc.set_movie_tag(self.movieid, tag) except Exception, e: dialog.error(e.message)
def compare_mvideos(self, view): view_id = view['id'] view_name = view['name'] if self.pdialog: self.pdialog.update(heading=lang(29999), message="%s %s..." % (lang(33028), view_name)) mvideos = dict(self.emby_db.get_checksum_by_view('MusicVideo', view_id)) emby_mvideos = self.emby.getMusicVideos(view_id, basic=True, dialog=self.pdialog) return self.compare("MusicVideo", emby_mvideos['Items'], mvideos, view)
def __rate_lib(self, progress): progress.start_module(lang(30204), self.RATE_LIB_STEPS) try: if not self.episodeid: raise Exception(lang(30601)) progress.update(lang(30522)) # updating rating utilxbmc.set_episode_rating(self.episodeid, self.rating) except Exception as e: if debug.get(): log(debug.traceback.print_exc(), xbmc.LOGERROR) debug.exception_dialog(e) finally: progress.finish_module()
def __set_tag(self, progress): progress.start_module(lang(30702), self.SET_TAG_STEPS) try: if not self.movieid: raise Exception(lang(30604)) progress.update(lang(30597)) # setting tag utilxbmc.set_movie_tag(self.movieid, self.tag) except Exception as e: if debug.get(): log(debug.traceback.print_exc(), xbmc.LOGERROR) debug.exception_dialog(e) finally: progress.finish_module()
def _delete_item(self): delete = True if settings('skipContextMenu') != "true": if not dialog(type_="yesno", heading=addonName, line1=lang(33041)): log.info("User skipped deletion for: %s", self.item_id) delete = False if delete: log.info("Deleting Plex item with id %s", self.item_id) if delete_item_from_pms(self.item_id) is False: dialog(type_="ok", heading="{plex}", line1=lang(30414))
def __preserve_playcount(self, progress): progress.start_module(lang(30701), self.PRESERVE_PLAYCOUNT_STEPS) try: if not self.movieid: raise Exception(lang(30604)) progress.update(lang(30598)) # setting old playcount utilxbmc.set_movie_playcount(self.movieid, self.playcount) except Exception as e: if debug.get(): log(debug.traceback.print_exc(), xbmc.LOGERROR) debug.exception_dialog(e) finally: progress.finish_module()
def _delete_item(self): delete = True if settings('skipContextMenu') != "true": if not dialog("yesno", heading=lang(29999), line1=lang(33041)): log.info("User skipped deletion for: %s", self.item_id) delete = False if delete: log.info("Deleting Plex item with id %s", self.item_id) if delete_item_from_pms(self.item_id) is False: dialog("ok", heading="{plex}", line1=lang(30414))
def _delete_item(self): """ Delete item on PMS """ delete = True if settings('skipContextMenu') != "true": if not dialog("yesno", heading="{plex}", line1=lang(33041)): LOG.info("User skipped deletion for: %s", self.plex_id) delete = False if delete: LOG.info("Deleting Plex item with id %s", self.plex_id) if delete_item_from_pms(self.plex_id) is False: dialog("ok", heading="{plex}", line1=lang(30414))
def fastSync(self): lastSync = settings('LastIncrementalSync') if not lastSync: lastSync = "2010-01-01T00:00:00Z" lastSyncTime = utils.convertDate(lastSync) log.info("Last sync run: %s" % lastSyncTime) # get server RetentionDateTime try: result = self.doUtils("{server}/emby/Emby.Kodi.SyncQueue/GetServerDateTime?format=json") retention_time = result['RetentionDateTime'] except Exception as error: log.error(error) retention_time = "2010-01-01T00:00:00Z" retention_time = utils.convertDate(retention_time) log.info("RetentionDateTime: %s" % retention_time) # if last sync before retention time do a full sync if retention_time > lastSyncTime: log.info("Fast sync server retention insufficient, fall back to full sync") return False params = {'LastUpdateDT': lastSync} if settings('enableMusic') != "true": params['filter'] = "music" url = "{server}/emby/Emby.Kodi.SyncQueue/{UserId}/GetItems?format=json" try: result = self.doUtils(url, parameters=params) processlist = { 'added': result['ItemsAdded'], 'update': result['ItemsUpdated'], 'userdata': result['UserDataChanged'], 'remove': result['ItemsRemoved'] } except Exception as error: # To be reviewed to only catch specific errors. log.error(error) log.error("Failed to retrieve latest updates using fast sync.") xbmcgui.Dialog().ok(lang(29999), lang(33095)) return False else: log.info("Fast sync changes: %s" % result) for action in processlist: self.triage_items(action, processlist[action]) return True
def deviceid(self): deviceId_old = window('plex_client_Id') from clientinfo import getDeviceId try: deviceId = getDeviceId(reset=True) except Exception as e: log.error('Failed to generate a new device Id: %s' % e) dialog('ok', lang(29999), lang(33032)) else: log.info('Successfully removed old device ID: %s New deviceId:' '%s' % (deviceId_old, deviceId)) # 'Kodi will now restart to apply the changes' dialog('ok', lang(29999), lang(33033)) executebuiltin('RestartApp')
def _set_access(self): try: self.doutils.downloadUrl("{server}/emby/Users?format=json") except Exception as error: if self._has_access and "restricted" in error: self._has_access = False log.info("access is restricted") else: if not self._has_access: self._has_access = True window('emby_serverStatus', clear=True) log.info("access is granted") xbmcgui.Dialog().notification(lang(29999), lang(33007))
def __delete(self, progress): progress.start_module(lang(30132), self.DELETE_STEPS) try: progress.update(lang(30516)) # deleting files source = os.path.dirname(self.path) remove_empty = setting('fm_movies_remove_empty') == 'true' if setting('fm_movies_structure') == '0': # multiple folders count = utilfile.count_manage_directory(self.alt_method, source) if not dialog.warning(lang(30132), count): raise Exception(lang(30609)) utilfile.delete_directory(self.alt_method, source) else: # single folder match = os.path.splitext(os.path.basename(self.path))[0] count = utilfile.count_manage_files(self.alt_method, source, match) log("Movie.__delete: match=%s" % match) if not dialog.warning(lang(30132), count): raise Exception(lang(30609)) utilfile.delete_files(self.alt_method, source, match, remove_empty) progress.update(lang(30513)) # updating library progress.update_library(self.path) self.movieid = None self.path = None except OSError: dialog.error(lang(30610)) except ValueError as err: ValueErrorHandler(err) except Exception as e: if debug.get(): log(debug.traceback.print_exc(), xbmc.LOGERROR) debug.exception_dialog(e) finally: progress.finish_module()
def __delete(self, progress): progress.start_module(lang(30133), self.DELETE_STEPS) try: progress.update(lang(30516)) # deleting files source = os.path.dirname(self.path) remove_empty = setting("fm_movie_remove_empty") == "true" if setting("fm_movies_structure") == "0": # multiple folders count = utilfile.count_manage_directory(self.alt_method, source) if not dialog.warning(lang(30133), count): raise Exception(lang(30609)) utilfile.delete_directory(self.alt_method, source) else: # single folder match = os.path.splitext(os.path.basename(self.path))[0] count = utilfile.count_manage_files(self.alt_method, source, match) log("Movie: delete match: %s" % match) if not dialog.warning(lang(30133), count): raise Exception(lang(30609)) utilfile.delete_files(self.alt_method, source, match, remove_empty) progress.update(lang(30513)) # updating library progress.update_library(self.path) self.movieid = None self.path = None except OSError: dialog.error(lang(30610)) except ValueError as err: ValueErrorHandler(err) except Exception, e: dialog.error(e.message)
def isDirectPlay(self): # Requirement: Filesystem, Accessible path if settings('playFromStream') == "true": # User forcing to play via HTTP log.info("Can't direct play, play from HTTP enabled.") return False videotrack = self.item['MediaSources'][0]['Name'] transcodeH265 = settings('transcodeH265') videoprofiles = [x['Profile'] for x in self.item['MediaSources'][0]['MediaStreams'] if 'Profile' in x] transcodeHi10P = settings('transcodeHi10P') if transcodeHi10P == "true" and "H264" in videotrack and "High 10" in videoprofiles: return False if transcodeH265 in ("1", "2", "3") and ("HEVC" in videotrack or "H265" in videotrack): # Avoid H265/HEVC depending on the resolution resolution = int(videotrack.split("P", 1)[0]) res = { '1': 480, '2': 720, '3': 1080 } log.info("Resolution is: %sP, transcode for resolution: %sP+" % (resolution, res[transcodeH265])) if res[transcodeH265] <= resolution: return False canDirectPlay = self.item['MediaSources'][0]['SupportsDirectPlay'] # Make sure direct play is supported by the server if not canDirectPlay: log.info("Can't direct play, server doesn't allow/support it.") return False location = self.item['LocationType'] if location == "FileSystem": # Verify the path if not self.fileExists(): log.info("Unable to direct play.") log.info(self.directPlay()) xbmcgui.Dialog().ok( heading=lang(29999), line1=lang(33011), line2=(self.directPlay())) sys.exit() return True
def path_validation(cls, path): # Verify if direct path is accessible or not verify_path = path if not os.path.supports_unicode_filenames: verify_path = path.encode('utf-8') if window('emby_pathverified') != "true" and not xbmcvfs.exists(verify_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 _startup(self): serverId = settings('serverId') if(serverId != None): serverId = hashlib.md5(serverId).hexdigest() ga = GoogleAnalytics() ga.sendEventData("Application", "Startup", serverId) try: ga.sendEventData("Version", "OS", platform.platform()) ga.sendEventData("Version", "Python", platform.python_version()) except Exception: pass # Start up events self.warn_auth = True username = self.userclient_thread.get_username() if settings('connectMsg') == "true" and username: # Get additional users add_users = settings('additionalUsers') if add_users: add_users = ", "+", ".join(add_users.split(',')) dialog(type_="notification", heading="{emby}", message=("%s %s%s" % (lang(33000), username.decode('utf-8'), add_users.decode('utf-8'))), icon="{emby}", time=2000, sound=False) return True
def update(self, msg): percent = self.current * 100 / self.steps if self.enable: self.bar.update(percent, info('name'), lang(30531) % (self.module_title, msg)) self.current += 1 self.module_current += 1 log('update: self.current=%s, self.module_current=%s' % (self.current, self.module_current))
def _rate_song(self): conn = kodiSQL('music') cursor = conn.cursor() query = "SELECT rating FROM song WHERE idSong = ?" cursor.execute(query, (self.kodi_id,)) try: value = cursor.fetchone()[0] current_value = int(round(float(value), 0)) except TypeError: pass else: new_value = dialog("numeric", 0, lang(30411), str(current_value)) if new_value > -1: new_value = int(new_value) if new_value > 5: new_value = 5 if settings('enableUpdateSongRating') == "true": musicutils.updateRatingToFile(new_value, self.api.get_file_path()) query = "UPDATE song SET rating = ? WHERE idSong = ?" cursor.execute(query, (new_value, self.kodi_id,)) conn.commit() finally: cursor.close()
def update_library(self, path=False): if path and setting('remove_video') == 'true': videolibrary.remove_video(path) if setting('update_library') == 'true': xbmc.executebuiltin('UpdateLibrary(video)') while not xbmc.getCondVisibility('Library.IsScanningVideo'): pass while xbmc.getCondVisibility('Library.IsScanningVideo'): xbmc.sleep(20) percent = (self.current-1) * 100 / self.steps if self.enable: if utilxbmc.version() >= 13: self.bar = xbmcgui.DialogProgressBG() else: self.bar = xbmcgui.DialogProgress() self.bar.create(info('name')) self.bar.update(percent, info('name'), lang(30531) % (self.module_title, lang(30513)))
def _server_restarting(cls): if settings('supressRestartMsg') == "true": dialog(type_="notification", heading="{emby}", message=lang(33006), icon="{emby}") window('emby_online', value="false")
def resetAuth(): # User tried login and failed too many times resp = dialog('yesno', heading="{plex}", line1=lang(39206)) if resp == 1: log.info("Reset login attempts.") window('plex_serverStatus', value="Auth") else: executebuiltin('Addon.OpenSettings(plugin.video.plexkodiconnect)')
def compare_artists(self, view): all_embyartistsIds = set() update_list = list() if self.pdialog: self.pdialog.update(heading=lang(29999), message="%s Artists..." % lang(33031)) artists = dict(self.emby_db.get_checksum('MusicArtist')) album_artists = dict(self.emby_db.get_checksum('AlbumArtist')) emby_artists = self.emby.getArtists(view['id'], dialog=self.pdialog) for item in emby_artists['Items']: if self.should_stop(): return False item_id = item['Id'] API = api.API(item) all_embyartistsIds.add(item_id) if item_id in artists: if artists[item_id] != API.get_checksum(): # Only update if artist is not in Kodi or checksum is different update_list.append(item_id) elif album_artists.get(item_id) != API.get_checksum(): # Only update if artist is not in Kodi or checksum is different update_list.append(item_id) #compare_to.pop(item_id, None) log.info("Update for Artist: %s", update_list) emby_items = self.emby.getFullItems(update_list) total = len(update_list) if self.pdialog: self.pdialog.update(heading="Processing Artists / %s items" % total) # Process additions and updates if emby_items: self.process_all("MusicArtist", "update", emby_items, total) # Process removals for artist in artists: if artist not in all_embyartistsIds and artists[artist] is not None: self.remove(artist)
def content_pop(self, name): # 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=self.new_time, sound=False)
def hasAccess(self): # hasAccess is verified in service.py result = self.doUtils.downloadUrl("{server}/emby/Users?format=json") if result == False: # Access is restricted, set in downloadutils.py via exception log("Access is restricted.", 1) self.HasAccess = False elif window('emby_online') != "true": # Server connection failed pass elif window('emby_serverStatus') == "restricted": log("Access is granted.", 1) self.HasAccess = True window('emby_serverStatus', clear=True) xbmcgui.Dialog().notification(lang(29999), lang(33007))