def _startPlayingExistingTheme(self, path): log("startPlayingExistingTheme: Playing existing theme for %s" % path) # Search for the themes themeFiles = ThemeFiles(path) if themeFiles.hasThemes(): playlist = themeFiles.getThemePlaylist() # Stop playing any existing theme self._stopPlayingTheme() xbmc.Player().play(playlist) else: log("No themes found for %s" % path) del themeFiles
def getVideos(self, jsonGet, target): json_query = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.%s", "params": {"properties": ["title", "file", "imdbnumber", "year"], "sort": { "method": "title" } }, "id": 1}' % jsonGet) json_query = unicode(json_query, 'utf-8', errors='ignore') json_response = simplejson.loads(json_query) log(json_response) videolist = [] if ("result" in json_response) and (target in json_response['result']): for item in json_response['result'][target]: # Before we process anything make sure we are not due to shut down if xbmc.abortRequested: return videolist videoItem = {} # Record if this is tvshows or movies videoItem['type'] = target videoItem['title'] = item['title'].encode("utf-8") # The file is actually the path for a TV Show, the video file for movies videoItem['file'] = item['file'] # The name is a bit misleading, it's the ID for whatever scanner was used videoItem['imdbnumber'] = item['imdbnumber'] videoItem['emby'] = False if "plugin.video.emby" in item['file']: if not self.isEmbyEnabled: continue videoItem['emby'] = True # Get the themes if they exist themeFileMgr = ThemeFiles(videoItem['file'], videotitle=item['title']) # Make sure there are themes if not themeFileMgr.hasThemes(): continue checkedId = self.getMetaHandlersID(target, videoItem['title'], item['year']) # Not sure why there would be a video in the library without an ID, but check just in case if videoItem['imdbnumber'] in ["", None]: videoItem['imdbnumber'] = checkedId elif (checkedId not in [None, ""]) and (videoItem['imdbnumber'] != checkedId): log("UploadThemes: ID comparison, Original = %s, checked = %s ... Skipping" % (videoItem['imdbnumber'], checkedId)) continue # Make sure there are themes and the ID is set if videoItem['imdbnumber'] not in ["", None]: requiredThemes = self._getThemesToUpload(target, videoItem['imdbnumber'], themeFileMgr.getThemeLocations()) if len(requiredThemes) > 0: videoItem['themes'] = requiredThemes videolist.append(videoItem) return videolist
def getVideos(self, jsonGet, target): json_query = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.%s", "params": {"properties": ["title", "file", "imdbnumber", "year"], "sort": { "method": "title" } }, "id": 1}' % jsonGet) json_query = unicode(json_query, 'utf-8', errors='ignore') json_response = simplejson.loads(json_query) log(json_response) videolist = [] if ("result" in json_response) and (target in json_response['result']): for item in json_response['result'][target]: # Before we process anything make sure we are not due to shut down if xbmc.abortRequested: return [] videoItem = {} # Record if this is tvshows or movies videoItem['type'] = target videoItem['title'] = item['title'].encode("utf-8") videoItem['year'] = item['year'] # The file is actually the path for a TV Show, the video file for movies videoItem['file'] = item['file'] # The name is a bit misleading, it's the ID for whatever scanner was used videoItem['imdbnumber'] = str(item['imdbnumber']) # Not sure why there would be a video in the library without an ID, but check just in case if videoItem['imdbnumber'] in ["", None]: continue isTvShow = False if target == 'tvshows': isTvShow = True # We have an ID for the video, check to see if we already have # something uploaded with this ID matchedThemeIds = self._getThemes(videoItem['imdbnumber'], isTvShow) if matchedThemeIds not in [None, ""]: log("UploadThemes: Theme for target %s and id %s already in library" % (target, videoItem['imdbnumber'])) continue # Get the themes if they exist themeFileMgr = ThemeFiles(videoItem['file'], videotitle=item['title']) # Make sure there are themes if not themeFileMgr.hasThemes(): continue if (len(themeFileMgr.getThemeLocations()) > 1) and self.skipMultipleThemes: log("UploadThemes: Skipping multiple themes") continue # Check if any of the themes available as suitable for upload requiredThemes = self._getThemesToUpload(videoItem['imdbnumber'], themeFileMgr.getThemeLocations()) if len(requiredThemes) < 1: log("UploadThemes: No Required themes found") continue # This video has themes that are needed videoItem['themes'] = requiredThemes # Also check our local record of things that have already been done if self.isThemeAlreadyUploaded(videoItem): log("UploadThemes: Theme %s already uploaded" % videoItem['imdbnumber']) continue videolist.append(videoItem) # Before returning the list, randonise it so that things are not always in the same order random.shuffle(videolist) return videolist
class TunesBackend(): def __init__(self): self.themePlayer = ThemePlayer() log("### starting TvTunes Backend ###") self.newThemeFiles = ThemeFiles("") self.oldThemeFiles = ThemeFiles("") self.prevThemeFiles = ThemeFiles("") self.delayedStart = DelayedStartTheme() self.isAlive = False # Only used for logging filtering self.lastLoggedThemePath = "" def runAsAService(self): logVideoLibraryNotShowing = True while not xbmc.abortRequested: # Wait a little before starting the check each time xbmc.sleep(200) # Check the forced TV Tunes status at the start of the loop, if this is True # then we don't want to stop themes until the next iteration, this stops the case # where some checks are done and the value changes part was through a single # loop iteration isForcedTvTunesContinue = WindowShowing.isTvTunesOverrideContinuePlaying() # Stop the theme if the shutdown menu appears - it normally means # we are about to shut the system down, so get ahead of the game if WindowShowing.isShutdownMenu(): self.stop(fastFade=True) continue # NOTE: The screensaver kicking in will only be picked up if the option # "Use Visualization if Playing Audio" is disabled if WindowShowing.isScreensaver(): if self.isAlive: log("TunesBackend: Screensaver active") self.stop(fastFade=True) # It may be possible that we stopped for the screen-saver about to kick in # If we are using Gotham or higher, it is possible for us to re-kick off the # screen-saver, otherwise the action of us stopping the theme will reset the # timeout and the user will have to wait longer log("TunesBackend: Restarting screensaver that TvTunes stopped") xbmc.executebuiltin("ActivateScreensaver", True) continue # Check if TvTunes is blocked from playing any themes if xbmcgui.Window(10025).getProperty('TvTunesBlocked') not in [None, ""]: self.stop(fastFade=True) continue if (not WindowShowing.isVideoLibrary()) and (not WindowShowing.isMusicSection()): log("TunesBackend: Video Library no longer visible", logVideoLibraryNotShowing) logVideoLibraryNotShowing = False # End playing cleanly (including any fade out) and then stop everything self.stop() continue else: logVideoLibraryNotShowing = True # There is a valid page selected and there is currently nothing playing if self.isPlayingZone() and not WindowShowing.isTvTunesOverrideContinuePrevious(): newThemes = self.getThemes() if self.newThemeFiles != newThemes: self.newThemeFiles = newThemes # Check if the file path has changed, if so there is a new file to play if self.newThemeFiles != self.oldThemeFiles and self.newThemeFiles.hasThemes(): log("TunesBackend: old path: %s" % self.oldThemeFiles.getPath()) log("TunesBackend: new path: %s" % self.newThemeFiles.getPath()) if self.start_playing(): # Now that playing has started, update the current themes that are being used self.oldThemeFiles = self.newThemeFiles # Check the operations where we are currently running and we need to stop # playing the current theme if self.isAlive: if self.themePlayer.isPlayingTheme(): # There is no theme at this location, so make sure we are stopped if not self.newThemeFiles.hasThemes(): log("TunesBackend: No themes to play for current item") self.themePlayer.endPlaying() self.oldThemeFiles.clear() self.prevThemeFiles.clear() self.delayedStart.clear() self.isAlive = False else: # This will occur when a theme has stopped playing, maybe is is not set to loop # There can be a delay when playing between playlist items, so give it a little # time to start playing the next one themeIsStillPlaying = False maxLoop = 500 while (maxLoop > 0) and (not themeIsStillPlaying): maxLoop = maxLoop - 1 xbmc.sleep(1) if self.themePlayer.isPlayingTheme(): themeIsStillPlaying = True break if not themeIsStillPlaying: log("TunesBackend: playing ended, restoring settings") self.themePlayer.restoreSettings() self.isAlive = False # This is the case where the user has moved from within an area where the themes # to an area where the theme is no longer played, so it will trigger a stop and # reset everything to highlight that nothing is playing if (not self.isPlayingZone()) and (not isForcedTvTunesContinue): self.stop() else: # Check for the case where we are playing the trailer as a theme # video, if so we want to stop the trailer playing when the video # information screen is displayed. If we don't, when the trailer is # started then TvTunes will automatically stop it if Settings.useTrailers() and WindowShowing.isMovieInformation() and self.themePlayer.isPlayingTrailerTheme(): self.stop() # Check to see if the setting to restrict the theme duration is enabled # and if it is we need to stop the current theme playing self.themePlayer.checkEnding() # We have finished running, just make one last check to ensure # we do not need to stop any audio self.stop(True) del self.themePlayer # Works out if the currently displayed area on the screen is something # that is deemed a zone where themes should be played def isPlayingZone(self): if WindowShowing.isTvTunesOverrideContinuePlaying(): return True if WindowShowing.isRecentEpisodesAdded(): return False if WindowShowing.isPluginPath(): return False if WindowShowing.isMovieInformation() and Settings.isPlayVideoInformation(): return True if WindowShowing.isSeasons() and Settings.isPlayTvShowSeasons(): return True if WindowShowing.isEpisodes() and Settings.isPlayTvShowEpisodes(): return True # Only valid if wanting theme on movie list if WindowShowing.isMovies() and Settings.isPlayMovieList(): return True # Only valid if wanting theme on TV list if WindowShowing.isTvShowTitles() and Settings.isPlayTvShowList(): return True # Only valid if wanting theme on Music Video list if WindowShowing.isMusicVideoTitles() and Settings.isPlayMusicVideoList(): return True if WindowShowing.isMusicSection(): return True # Any other area is deemed to be a non play area return False # Locates the path to look for a theme to play based on what is # currently being displayed on the screen def getThemes(self): themePath = "" # Only need the theme path for videos if not WindowShowing.isMusicSection(): # Check if the files are stored in a custom path if Settings.isCustomPathEnabled(): if not WindowShowing.isMovies(): videotitle = xbmc.getInfoLabel("ListItem.TVShowTitle") else: videotitle = xbmc.getInfoLabel("ListItem.Title") videotitle = normalize_string(videotitle) themePath = os_path_join(Settings.getCustomPath(), videotitle) # Looking at the TV Show information page elif WindowShowing.isMovieInformation() and (WindowShowing.isTvShowTitles() or WindowShowing.isTvShows()): themePath = xbmc.getInfoLabel("ListItem.FilenameAndPath") else: themePath = xbmc.getInfoLabel("ListItem.Path") # To try and reduce the amount of "noise" in the logging, where the # same check is logged again and again, we record if it has been # logged for this video, and then do not do it again until the # video changes and what we would print wound be different debug_logging_enabled = False # Only log if something is different from the last time we logged if self.lastLoggedThemePath != themePath: debug_logging_enabled = True self.lastLoggedThemePath = themePath log("TunesBackend: themePath = %s" % themePath, debug_logging_enabled) # Check if the selection is a Movie Set if WindowShowing.isMovieSet(): movieSetMap = self._getMovieSetFileList() if Settings.isCustomPathEnabled(): # Need to make the values part (the path) point to the custom path # rather than the video file for aKey in movieSetMap.keys(): videotitle = normalize_string(aKey) movieSetMap[aKey] = os_path_join(Settings.getCustomPath(), videotitle) if len(movieSetMap) < 1: themefile = ThemeFiles("", debug_logging_enabled=debug_logging_enabled) else: themefile = ThemeFiles(themePath, movieSetMap.values(), debug_logging_enabled=debug_logging_enabled) # When the reference is into the database and not the file system # then don't return it elif themePath.startswith("videodb:"): # If in either the Tv Show List or the Movie list then # need to stop the theme is selecting the back button if WindowShowing.isMovies() or WindowShowing.isTvShowTitles(): themefile = ThemeFiles("", debug_logging_enabled=debug_logging_enabled) else: # Load the previous theme themefile = self.newThemeFiles else: if WindowShowing.isMusicSection(): themefile = MusicThemeFiles(debug_logging_enabled) else: themefile = ThemeFiles(themePath, debug_logging_enabled=debug_logging_enabled) return themefile # Gets the list of movies in a movie set def _getMovieSetFileList(self): # Create a map for Program name to video file movieSetMap = dict() # Check if the selection is a Movie Set if WindowShowing.isMovieSet(): # Get Movie Set Data Base ID dbid = xbmc.getInfoLabel("ListItem.DBID") # Get movies from Movie Set json_query = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetMovieSetDetails", "params": {"setid": %s, "properties": [ "thumbnail" ], "movies": { "properties": [ "file", "title"], "sort": { "order": "ascending", "method": "title" }} },"id": 1 }' % dbid) json_query = unicode(json_query, 'utf-8', errors='ignore') json_query = simplejson.loads(json_query) if ("result" in json_query) and ('setdetails' in json_query['result']): # Get the list of movies paths from the movie set items = json_query['result']['setdetails']['movies'] for item in items: log("TunesBackend: Movie Set file (%s): %s" % (item['title'], item['file'])) movieSetMap[item['title']] = item['file'] return movieSetMap # Returns True is started playing, False is delayed def start_playing(self): playlist = self.newThemeFiles.getThemePlaylist() if self.newThemeFiles.hasThemes(): if self.newThemeFiles == self.prevThemeFiles: log("TunesBackend: Not playing the same files twice %s" % self.newThemeFiles.getPath()) return True # don't play the same tune twice (when moving from season to episodes etc) # Value that will force a quicker than normal fade in and out # this is needed if switching from one theme to the next, we # do not want a long pause starting and stopping fastFadeNeeded = False # Check if a theme is already playing, if there is we will need # to stop it before playing the new theme # Stop any audio playing if self.themePlayer.isPlayingTheme(): fastFadeNeeded = True log("TunesBackend: Stopping previous theme: %s" % self.prevThemeFiles.getPath()) self.themePlayer.endPlaying(fastFade=fastFadeNeeded) # Check if this should be delayed if not self.delayedStart.shouldStartPlaying(self.newThemeFiles): return False # Before we start playing the theme, highlight that TvTunes is active by # Setting the property that confluence reads xbmcgui.Window(10025).setProperty("TvTunesIsAlive", "true") xbmcgui.Window(10025).setProperty("PlayingBackgroundMedia", "true") # Store the new theme that is being played self.prevThemeFiles = self.newThemeFiles self.isAlive = True log("TunesBackend: start playing %s" % self.newThemeFiles.getPath()) self.themePlayer.play(playlist, fastFade=fastFadeNeeded) # Set the option so other add-ons can work out if TvTunes is playing a theme xbmcgui.Window(10025).setProperty("TvTunesIsRunning", "true") else: log("TunesBackend: no themes found for %s" % self.newThemeFiles.getPath()) return True def stop(self, immediate=False, fastFade=False): if self.isAlive: # If video is playing, check to see if it is a theme video if self.themePlayer.isPlayingTheme(): if immediate: log("TunesBackend: Stop playing") self.themePlayer.stop() while self.themePlayer.isPlaying(): xbmc.sleep(50) else: log("TunesBackend: Ending playing") self.themePlayer.endPlaying(fastFade) self.isAlive = False # If currently playing a video file, then we have been overridden, # and we need to restore all the settings, the player callbacks # will not be called, so just force it on stop self.themePlayer.restoreSettings() # Clear all the values stored self.newThemeFiles.clear() self.oldThemeFiles.clear() self.prevThemeFiles.clear() self.delayedStart.clear() # Clear the option used by other add-ons to work out if TvTunes is playing a theme xbmcgui.Window(10025).clearProperty("TvTunesIsRunning") # The following value is added for the Confluence skin to not show what is # currently playing, maybe change this name when we submit the pull request to # Confluence - new name: PlayingBackgroundMedia xbmcgui.Window(10025).clearProperty("TvTunesIsAlive") xbmcgui.Window(10025).clearProperty("PlayingBackgroundMedia") # Clear the Theme Player by resetting it self.themePlayer = ThemePlayer()
class TunesBackend(): def __init__(self): self.themePlayer = ThemePlayer() log("### starting TvTunes Backend ###") self.newThemeFiles = ThemeFiles("") self.oldThemeFiles = ThemeFiles("") self.prevThemeFiles = ThemeFiles("") self.delayedStart = DelayedStartTheme() self.isAlive = False # Only used for logging filtering self.lastLoggedThemePath = "" def runAsAService(self): logVideoLibraryNotShowing = True while not xbmc.abortRequested: # Wait a little before starting the check each time xbmc.sleep(200) # Check the forced TV Tunes status at the start of the loop, if this is True # then we don't want to stop themes until the next iteration, this stops the case # where some checks are done and the value changes part was through a single # loop iteration isForcedTvTunesContinue = WindowShowing.isTvTunesOverrideContinuePlaying() # Stop the theme if the shutdown menu appears - it normally means # we are about to shut the system down, so get ahead of the game if WindowShowing.isShutdownMenu(): self.stop(fastFade=True) continue # NOTE: The screensaver kicking in will only be picked up if the option # "Use Visualization if Playing Audio" is disabled if WindowShowing.isScreensaver(): if self.isAlive: log("TunesBackend: Screensaver active") self.stop(fastFade=True) # It may be possible that we stopped for the screen-saver about to kick in # If we are using Gotham or higher, it is possible for us to re-kick off the # screen-saver, otherwise the action of us stopping the theme will reset the # timeout and the user will have to wait longer log("TunesBackend: Restarting screensaver that TvTunes stopped") xbmc.executebuiltin("ActivateScreensaver", True) continue # Check if TvTunes is blocked from playing any themes if xbmcgui.Window(10025).getProperty('TvTunesBlocked') not in [None, ""]: self.stop(fastFade=True) continue if (not WindowShowing.isVideoLibrary()) and (not WindowShowing.isMusicSection()): log("TunesBackend: Video Library no longer visible", logVideoLibraryNotShowing) logVideoLibraryNotShowing = False # End playing cleanly (including any fade out) and then stop everything self.stop() continue else: logVideoLibraryNotShowing = True # There is a valid page selected and there is currently nothing playing if self.isPlayingZone() and not WindowShowing.isTvTunesOverrideContinuePrevious(): newThemes = self.getThemes() if self.newThemeFiles != newThemes: self.newThemeFiles = newThemes # Check if the file path has changed, if so there is a new file to play if self.newThemeFiles != self.oldThemeFiles and self.newThemeFiles.hasThemes(): log("TunesBackend: old path: %s" % self.oldThemeFiles.getPath()) log("TunesBackend: new path: %s" % self.newThemeFiles.getPath()) if self.start_playing(): # Now that playing has started, update the current themes that are being used self.oldThemeFiles = self.newThemeFiles # Check the operations where wee are currently running and we need to stop # playing the current theme if self.isAlive: if self.themePlayer.isPlayingTheme(): # There is no theme at this location, so make sure we are stopped if not self.newThemeFiles.hasThemes(): log("TunesBackend: No themes to play for current item") self.themePlayer.endPlaying() self.oldThemeFiles.clear() self.prevThemeFiles.clear() self.delayedStart.clear() self.isAlive = False else: # This will occur when a theme has stopped playing, maybe is is not set to loop # There can be a delay when playing between playlist items, so give it a little # time to start playing the next one themeIsStillPlaying = False maxLoop = 500 while (maxLoop > 0) and (not themeIsStillPlaying): maxLoop = maxLoop - 1 xbmc.sleep(1) if self.themePlayer.isPlayingTheme(): themeIsStillPlaying = True break if not themeIsStillPlaying: log("TunesBackend: playing ended, restoring settings") self.themePlayer.restoreSettings() self.isAlive = False # This is the case where the user has moved from within an area where the themes # to an area where the theme is no longer played, so it will trigger a stop and # reset everything to highlight that nothing is playing if (not self.isPlayingZone()) and (not isForcedTvTunesContinue): self.stop() # Check to see if the setting to restrict the theme duration is enabled # and if it is we need to stop the current theme playing self.themePlayer.checkEnding() # We have finished running, just make one last check to ensure # we do not need to stop any audio self.stop(True) del self.themePlayer # Works out if the currently displayed area on the screen is something # that is deemed a zone where themes should be played def isPlayingZone(self): if WindowShowing.isTvTunesOverrideContinuePlaying(): return True if WindowShowing.isRecentEpisodesAdded(): return False if WindowShowing.isPluginPath(): return False if WindowShowing.isMovieInformation() and Settings.isPlayVideoInformation(): return True if WindowShowing.isSeasons() and Settings.isPlayTvShowSeasons(): return True if WindowShowing.isEpisodes() and Settings.isPlayTvShowEpisodes(): return True # Only valid if wanting theme on movie list if WindowShowing.isMovies() and Settings.isPlayMovieList(): return True # Only valid if wanting theme on TV list if WindowShowing.isTvShowTitles() and Settings.isPlayTvShowList(): return True # Only valid if wanting theme on Music Video list if WindowShowing.isMusicVideoTitles() and Settings.isPlayMusicVideoList(): return True if WindowShowing.isMusicSection(): return True # Any other area is deemed to be a non play area return False # Locates the path to look for a theme to play based on what is # currently being displayed on the screen def getThemes(self): themePath = "" # Only need the theme path for videos if not WindowShowing.isMusicSection(): # Check if the files are stored in a custom path if Settings.isCustomPathEnabled(): if not WindowShowing.isMovies(): videotitle = xbmc.getInfoLabel("ListItem.TVShowTitle") else: videotitle = xbmc.getInfoLabel("ListItem.Title") videotitle = normalize_string(videotitle) themePath = os_path_join(Settings.getCustomPath(), videotitle) # Looking at the TV Show information page elif WindowShowing.isMovieInformation() and (WindowShowing.isTvShowTitles() or WindowShowing.isTvShows()): themePath = xbmc.getInfoLabel("ListItem.FilenameAndPath") else: themePath = xbmc.getInfoLabel("ListItem.Path") # To try and reduce the amount of "noise" in the logging, where the # same check is logged again and again, we record if it has been # logged for this video, and then do not do it again until the # video changes and what we would print wound be different debug_logging_enabled = False # Only log if something is different from the last time we logged if self.lastLoggedThemePath != themePath: debug_logging_enabled = True self.lastLoggedThemePath = themePath log("TunesBackend: themePath = %s" % themePath, debug_logging_enabled) # Check if the selection is a Movie Set if WindowShowing.isMovieSet(): movieSetMap = self._getMovieSetFileList() if Settings.isCustomPathEnabled(): # Need to make the values part (the path) point to the custom path # rather than the video file for aKey in movieSetMap.keys(): videotitle = normalize_string(aKey) movieSetMap[aKey] = os_path_join(Settings.getCustomPath(), videotitle) if len(movieSetMap) < 1: themefile = ThemeFiles("", debug_logging_enabled=debug_logging_enabled) else: themefile = ThemeFiles(themePath, movieSetMap.values(), debug_logging_enabled=debug_logging_enabled) # When the reference is into the database and not the file system # then don't return it elif themePath.startswith("videodb:"): # If in either the Tv Show List or the Movie list then # need to stop the theme is selecting the back button if WindowShowing.isMovies() or WindowShowing.isTvShowTitles(): themefile = ThemeFiles("", debug_logging_enabled=debug_logging_enabled) else: # Load the previous theme themefile = self.newThemeFiles else: if WindowShowing.isMusicSection(): themefile = MusicThemeFiles(debug_logging_enabled) else: themefile = ThemeFiles(themePath, debug_logging_enabled=debug_logging_enabled) return themefile # Gets the list of movies in a movie set def _getMovieSetFileList(self): # Create a map for Program name to video file movieSetMap = dict() # Check if the selection is a Movie Set if WindowShowing.isMovieSet(): # Get Movie Set Data Base ID dbid = xbmc.getInfoLabel("ListItem.DBID") # Get movies from Movie Set json_query = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetMovieSetDetails", "params": {"setid": %s, "properties": [ "thumbnail" ], "movies": { "properties": [ "file", "title"], "sort": { "order": "ascending", "method": "title" }} },"id": 1 }' % dbid) json_query = unicode(json_query, 'utf-8', errors='ignore') json_query = simplejson.loads(json_query) if ("result" in json_query) and ('setdetails' in json_query['result']): # Get the list of movies paths from the movie set items = json_query['result']['setdetails']['movies'] for item in items: log("TunesBackend: Movie Set file (%s): %s" % (item['title'], item['file'])) movieSetMap[item['title']] = item['file'] return movieSetMap # Returns True is started playing, False is delayed def start_playing(self): playlist = self.newThemeFiles.getThemePlaylist() if self.newThemeFiles.hasThemes(): if self.newThemeFiles == self.prevThemeFiles: log("TunesBackend: Not playing the same files twice %s" % self.newThemeFiles.getPath()) return True # don't play the same tune twice (when moving from season to episodes etc) # Value that will force a quicker than normal fade in and out # this is needed if switching from one theme to the next, we # do not want a long pause starting and stopping fastFadeNeeded = False # Check if a theme is already playing, if there is we will need # to stop it before playing the new theme # Stop any audio playing if self.themePlayer.isPlayingTheme(): fastFadeNeeded = True log("TunesBackend: Stopping previous theme: %s" % self.prevThemeFiles.getPath()) self.themePlayer.endPlaying(fastFade=fastFadeNeeded) # Check if this should be delayed if not self.delayedStart.shouldStartPlaying(self.newThemeFiles): return False # Before we start playing the theme, highlight that TvTunes is active by # Setting the property that confluence reads xbmcgui.Window(10025).setProperty("TvTunesIsAlive", "true") xbmcgui.Window(10025).setProperty("PlayingBackgroundMedia", "true") # Store the new theme that is being played self.prevThemeFiles = self.newThemeFiles self.isAlive = True log("TunesBackend: start playing %s" % self.newThemeFiles.getPath()) self.themePlayer.play(playlist, fastFade=fastFadeNeeded) # Set the option so other add-ons can work out if TvTunes is playing a theme xbmcgui.Window(10025).setProperty("TvTunesIsRunning", "true") else: log("TunesBackend: no themes found for %s" % self.newThemeFiles.getPath()) return True def stop(self, immediate=False, fastFade=False): if self.isAlive: # If video is playing, check to see if it is a theme video if self.themePlayer.isPlayingTheme(): if immediate: log("TunesBackend: Stop playing") self.themePlayer.stop() while self.themePlayer.isPlaying(): xbmc.sleep(50) else: log("TunesBackend: Ending playing") self.themePlayer.endPlaying(fastFade) self.isAlive = False # If currently playing a video file, then we have been overridden, # and we need to restore all the settings, the player callbacks # will not be called, so just force it on stop self.themePlayer.restoreSettings() # Clear all the values stored self.newThemeFiles.clear() self.oldThemeFiles.clear() self.prevThemeFiles.clear() self.delayedStart.clear() # Clear the option used by other add-ons to work out if TvTunes is playing a theme xbmcgui.Window(10025).clearProperty("TvTunesIsRunning") # The following value is added for the Confluence skin to not show what is # currently playing, maybe change this name when we submit the pull request to # Confluence - new name: PlayingBackgroundMedia xbmcgui.Window(10025).clearProperty("TvTunesIsAlive") xbmcgui.Window(10025).clearProperty("PlayingBackgroundMedia") # Clear the Theme Player by resetting it self.themePlayer = ThemePlayer()
def getVideos(self, jsonGet, target): json_query = xbmc.executeJSONRPC( '{"jsonrpc": "2.0", "method": "VideoLibrary.%s", "params": {"properties": ["title", "file", "imdbnumber", "year"], "sort": { "method": "title" } }, "id": 1}' % jsonGet) json_query = unicode(json_query, 'utf-8', errors='ignore') json_response = simplejson.loads(json_query) log(json_response) videolist = [] if ("result" in json_response) and (target in json_response['result']): for item in json_response['result'][target]: # Before we process anything make sure we are not due to shut down if xbmc.abortRequested: return [] videoItem = {} # Record if this is tvshows or movies videoItem['type'] = target videoItem['title'] = item['title'].encode("utf-8") videoItem['year'] = item['year'] # The file is actually the path for a TV Show, the video file for movies videoItem['file'] = item['file'] # The name is a bit misleading, it's the ID for whatever scanner was used videoItem['imdbnumber'] = str(item['imdbnumber']) # Not sure why there would be a video in the library without an ID, but check just in case if videoItem['imdbnumber'] in ["", None]: continue isTvShow = False if target == 'tvshows': isTvShow = True # We have an ID for the video, check to see if we already have # something uploaded with this ID matchedThemeIds = self._getThemes(videoItem['imdbnumber'], isTvShow) if matchedThemeIds not in [None, ""]: log("UploadThemes: Theme for target %s and id %s already in library" % (target, videoItem['imdbnumber'])) continue # Get the themes if they exist themeFileMgr = ThemeFiles(videoItem['file'], videotitle=item['title']) # Make sure there are themes if not themeFileMgr.hasThemes(): continue if (len(themeFileMgr.getThemeLocations()) > 1) and self.skipMultipleThemes: log("UploadThemes: Skipping multiple themes") continue # Check if any of the themes available as suitable for upload requiredThemes = self._getThemesToUpload( videoItem['imdbnumber'], themeFileMgr.getThemeLocations()) if len(requiredThemes) < 1: log("UploadThemes: No Required themes found") continue # This video has themes that are needed videoItem['themes'] = requiredThemes # Also check our local record of things that have already been done if self.isThemeAlreadyUploaded(videoItem): log("UploadThemes: Theme %s already uploaded" % videoItem['imdbnumber']) continue videolist.append(videoItem) # Before returning the list, randonise it so that things are not always in the same order random.shuffle(videolist) return videolist
class TunesBackend(): def __init__(self): self.themePlayer = Player() self._stop = False log("### starting TvTunes Backend ###") self.newThemeFiles = ThemeFiles("") self.oldThemeFiles = ThemeFiles("") self.prevThemeFiles = ThemeFiles("") self.delayedStart = DelayedStartTheme() # Only used for logging filtering self.lastLoggedThemePath = "" def run(self): try: # Before we actually start playing something, make sure it is OK # to run, need to ensure there are not multiple copies running if not TvTunesStatus.isOkToRun(): return while (not self._stop): # Check the forced TV Tunes status at the start of the loop, if this is True # then we don't want to stop themes until the next iteration, this stops the case # where some checks are done and the value changes part was through a single # loop iteration isForcedTvTunesContinue = WindowShowing.isTvTunesOverrideContinuePlaying() # If shutdown is in progress, stop quickly (no fade out) if WindowShowing.isShutdownMenu() or xbmc.abortRequested: self.stop() break # We only stop looping and exit this script if we leave the Video library # We get called when we enter the library, and the only times we will end # will be if: # 1) A Video is selected to play # 2) We exit to the main menu away from the video view if (not WindowShowing.isVideoLibrary()) or WindowShowing.isScreensaver() or Settings.isTimout(): log("TunesBackend: Video Library no longer visible") # End playing cleanly (including any fade out) and then stop everything if TvTunesStatus.isAlive(): self.themePlayer.endPlaying() self.stop() # It may be possible that we stopped for the screen-saver about to kick in # If we are using Gotham or higher, it is possible for us to re-kick off the # screen-saver, otherwise the action of us stopping the theme will reset the # timeout and the user will have to wait longer if Settings.isTimout() and (Settings.getXbmcMajorVersion() > 12): xbmc.executebuiltin("xbmc.ActivateScreensaver", True) break # There is a valid page selected and there is currently nothing playing if self.isPlayingZone() and not WindowShowing.isTvTunesOverrideContinuePrevious(): newThemes = self.getThemes() if self.newThemeFiles != newThemes: self.newThemeFiles = newThemes # Check if the file path has changed, if so there is a new file to play if self.newThemeFiles != self.oldThemeFiles and self.newThemeFiles.hasThemes(): log("TunesBackend: old path: %s" % self.oldThemeFiles.getPath()) log("TunesBackend: new path: %s" % self.newThemeFiles.getPath()) if self.start_playing(): self.oldThemeFiles = self.newThemeFiles # There is no theme at this location, so make sure we are stopped if not self.newThemeFiles.hasThemes() and self.themePlayer.isPlayingAudio() and TvTunesStatus.isAlive(): self.themePlayer.endPlaying() self.oldThemeFiles.clear() self.prevThemeFiles.clear() self.delayedStart.clear() TvTunesStatus.setAliveState(False) # This will occur when a theme has stopped playing, maybe is is not set to loop if TvTunesStatus.isAlive() and not self.themePlayer.isPlayingAudio(): log("TunesBackend: playing ends") self.themePlayer.restoreSettings() TvTunesStatus.setAliveState(False) # This is the case where the user has moved from within an area where the themes # to an area where the theme is no longer played, so it will trigger a stop and # reset everything to highlight that nothing is playing # Note: TvTunes is still running in this case, just not playing a theme if (not self.isPlayingZone()) and (not isForcedTvTunesContinue): self.newThemeFiles.clear() self.oldThemeFiles.clear() self.prevThemeFiles.clear() self.delayedStart.clear() if self.themePlayer.isPlaying() and TvTunesStatus.isAlive(): log("TunesBackend: end playing") self.themePlayer.endPlaying() TvTunesStatus.setAliveState(False) self.themePlayer.checkEnding() # Wait a little before starting the check again xbmc.sleep(200) except: log("TunesBackend: %s" % traceback.format_exc()) self.stop() # Works out if the currently displayed area on the screen is something # that is deemed a zone where themes should be played def isPlayingZone(self): if WindowShowing.isTvTunesOverrideContinuePlaying(): return True if WindowShowing.isRecentEpisodesAdded(): return False if WindowShowing.isPluginPath(): return False if WindowShowing.isMovieInformation(): return True if WindowShowing.isSeasons(): return True if WindowShowing.isEpisodes(): return True # Only valid if wanting theme on movie list if WindowShowing.isMovies() and Settings.isPlayMovieList(): return True # Only valid if wanting theme on TV list if WindowShowing.isTvShowTitles() and Settings.isPlayTvShowList(): return True # Only valid if wanting theme on Music Video list if WindowShowing.isMusicVideoTitles() and Settings.isPlayMusicVideoList(): return True # Any other area is deemed to be a non play area return False # Locates the path to look for a theme to play based on what is # currently being displayed on the screen def getThemes(self): themePath = "" # Check if the files are stored in a custom path if Settings.isCustomPathEnabled(): if not WindowShowing.isMovies(): videotitle = xbmc.getInfoLabel("ListItem.TVShowTitle") else: videotitle = xbmc.getInfoLabel("ListItem.Title") videotitle = normalize_string(videotitle) themePath = os_path_join(Settings.getCustomPath(), videotitle) # Looking at the TV Show information page elif WindowShowing.isMovieInformation() and (WindowShowing.isTvShowTitles() or WindowShowing.isTvShows()): themePath = xbmc.getInfoLabel("ListItem.FilenameAndPath") else: themePath = xbmc.getInfoLabel("ListItem.Path") # To try and reduce the amount of "noise" in the logging, where the # same check is logged again and again, we record if it has been # logged for this video, and then do not do it again until the # video changes and what we would print wound be different debug_logging_enabled = False # Only log if something is different from the last time we logged if self.lastLoggedThemePath != themePath: debug_logging_enabled = True self.lastLoggedThemePath = themePath log("TunesBackend: themePath = %s" % themePath, debug_logging_enabled) # Check if the selection is a Movie Set if WindowShowing.isMovieSet(): movieSetMap = self._getMovieSetFileList() if Settings.isCustomPathEnabled(): # Need to make the values part (the path) point to the custom path # rather than the video file for aKey in movieSetMap.keys(): videotitle = normalize_string(aKey) movieSetMap[aKey] = os_path_join(Settings.getCustomPath(), videotitle) if len(movieSetMap) < 1: themefile = ThemeFiles("", debug_logging_enabled=debug_logging_enabled) else: themefile = ThemeFiles(themePath, movieSetMap.values(), debug_logging_enabled=debug_logging_enabled) # When the reference is into the database and not the file system # then don't return it elif themePath.startswith("videodb:"): # If in either the Tv Show List or the Movie list then # need to stop the theme is selecting the back button if WindowShowing.isMovies() or WindowShowing.isTvShowTitles(): themefile = ThemeFiles("", debug_logging_enabled=debug_logging_enabled) else: # Load the previous theme themefile = self.newThemeFiles else: themefile = ThemeFiles(themePath, debug_logging_enabled=debug_logging_enabled) return themefile # Gets the list of movies in a movie set def _getMovieSetFileList(self): # Create a map for Program name to video file movieSetMap = dict() # Check if the selection is a Movie Set if WindowShowing.isMovieSet(): # Get Movie Set Data Base ID dbid = xbmc.getInfoLabel("ListItem.DBID") # Get movies from Movie Set json_query = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetMovieSetDetails", "params": {"setid": %s, "properties": [ "thumbnail" ], "movies": { "properties": [ "file", "title"], "sort": { "order": "ascending", "method": "title" }} },"id": 1 }' % dbid) json_query = unicode(json_query, 'utf-8', errors='ignore') json_query = simplejson.loads(json_query) if ("result" in json_query) and ('setdetails' in json_query['result']): # Get the list of movies paths from the movie set items = json_query['result']['setdetails']['movies'] for item in items: log("TunesBackend: Movie Set file (%s): %s" % (item['title'], item['file'])) movieSetMap[item['title']] = item['file'] return movieSetMap # Returns True is started playing, False is delayed def start_playing(self): playlist = self.newThemeFiles.getThemePlaylist() if self.newThemeFiles.hasThemes(): if self.newThemeFiles == self.prevThemeFiles: log("TunesBackend: Not playing the same files twice %s" % self.newThemeFiles.getPath()) return True # don't play the same tune twice (when moving from season to episodes etc) # Value that will force a quicker than normal fade in and out # this is needed if switching from one theme to the next, we # do not want a long pause starting and stopping fastFadeNeeded = False # Check if a theme is already playing, if there is we will need # to stop it before playing the new theme # Stop any audio playing if self.themePlayer.isPlayingAudio(): # and self.prevThemeFiles.hasThemes() fastFadeNeeded = True log("TunesBackend: Stopping previous theme: %s" % self.prevThemeFiles.getPath()) self.themePlayer.endPlaying(fastFade=fastFadeNeeded) # Check if this should be delayed if not self.delayedStart.shouldStartPlaying(self.newThemeFiles): return False # Store the new theme that is being played self.prevThemeFiles = self.newThemeFiles TvTunesStatus.setAliveState(True) log("TunesBackend: start playing %s" % self.newThemeFiles.getPath()) self.themePlayer.play(playlist, fastFade=fastFadeNeeded) else: log("TunesBackend: no themes found for %s" % self.newThemeFiles.getPath()) return True def stop(self): log("TunesBackend: ### Stopping TvTunes Backend ###") if TvTunesStatus.isAlive() and not self.themePlayer.isPlayingVideo(): log("TunesBackend: stop playing") self.themePlayer.stop() while self.themePlayer.isPlayingAudio(): xbmc.sleep(50) TvTunesStatus.setAliveState(False) TvTunesStatus.clearRunningState() # If currently playing a video file, then we have been overridden, # and we need to restore all the settings, the player callbacks # will not be called, so just force it on stop self.themePlayer.restoreSettings() log("TunesBackend: ### Stopped TvTunes Backend ###") self._stop = True
def getThemes(self): themePath = "" # Only need the theme path for videos if not WindowShowing.isMusicSection(): # Check if the files are stored in a custom path if Settings.isCustomPathEnabled(): if not WindowShowing.isMovies(): videotitle = xbmc.getInfoLabel("ListItem.TVShowTitle") else: videotitle = xbmc.getInfoLabel("ListItem.Title") videotitle = normalize_string(videotitle) themePath = os_path_join(Settings.getCustomPath(), videotitle) # Looking at the TV Show information page elif WindowShowing.isMovieInformation() and ( WindowShowing.isTvShowTitles() or WindowShowing.isTvShows()): themePath = xbmc.getInfoLabel("ListItem.FilenameAndPath") else: themePath = xbmc.getInfoLabel("ListItem.Path") # To try and reduce the amount of "noise" in the logging, where the # same check is logged again and again, we record if it has been # logged for this video, and then do not do it again until the # video changes and what we would print wound be different debug_logging_enabled = False # Only log if something is different from the last time we logged if self.lastLoggedThemePath != themePath: debug_logging_enabled = True self.lastLoggedThemePath = themePath log("TunesBackend: themePath = %s" % themePath, debug_logging_enabled) # Check if the selection is a Movie Set if WindowShowing.isMovieSet(): movieSetMap = self._getMovieSetFileList() if Settings.isCustomPathEnabled(): # Need to make the values part (the path) point to the custom path # rather than the video file for aKey in movieSetMap.keys(): videotitle = normalize_string(aKey) movieSetMap[aKey] = os_path_join(Settings.getCustomPath(), videotitle) if len(movieSetMap) < 1: themefile = ThemeFiles( "", debug_logging_enabled=debug_logging_enabled) else: themefile = ThemeFiles( themePath, movieSetMap.values(), debug_logging_enabled=debug_logging_enabled) # When the reference is into the database and not the file system # then don't return it elif themePath.startswith("videodb:"): # If in either the Tv Show List or the Movie list then # need to stop the theme is selecting the back button if WindowShowing.isMovies() or WindowShowing.isTvShowTitles(): themefile = ThemeFiles( "", debug_logging_enabled=debug_logging_enabled) else: # Load the previous theme themefile = self.newThemeFiles else: if WindowShowing.isMusicSection(): themefile = MusicThemeFiles(debug_logging_enabled) else: themefile = ThemeFiles( themePath, debug_logging_enabled=debug_logging_enabled) # Check if no themes were found for this item, there is a case if it is a # TV Show and it is nested Show-Name/Series-X/Episode-Directory/Episode.ext # Then this will not pick up themes in the root of the TV Show directory if (not themefile.hasThemes()) and ( not Settings.isCustomPathEnabled() ) and WindowShowing.isEpisodes(): tvshowTitle = xbmc.getInfoLabel("ListItem.TVShowTitle") if tvshowTitle not in [None, ""]: try: # Make a call to the database to find out the root path of this TV Show filterStr = '{"operator": "is", "field": "title", "value": "%s"}' % tvshowTitle cmd = '{"jsonrpc": "2.0", "method": "VideoLibrary.GetTVShows", "params": {"properties": ["file"], "filter": %s},"id": 1 }' % filterStr json_query = xbmc.executeJSONRPC(cmd) json_query = simplejson.loads(json_query) if ("result" in json_query) and ( 'tvshows' in json_query['result']): # Get the path to the TV Show and compare it to where we were previously # looking tvshowList = json_query['result']['tvshows'] if len(tvshowList) == 1: tvshowPath = json_query['result'][ 'tvshows'][0]['file'] # Make sure we have not already checked this path # We will already have checked the parent path as well if (tvshowPath != themePath) and ( tvshowPath != os_path_split(themePath)[0]): # So we know that we haven't checked the root of this TV Show yet log( "TunesBackend: Checking root TV Show Path = %s" % tvshowPath, debug_logging_enabled) themefile = ThemeFiles( tvshowPath, debug_logging_enabled= debug_logging_enabled) except: log( "TunesBackend: Failed to check root TV Show %s" % traceback.format_exc(), debug_logging_enabled) return themefile