def onInit(self): # Need to clear the list of the default items self.clearList() # Start by adding an option to Play All if len(self.files) > 0: anItem = xbmcgui.ListItem(ADDON.getLocalizedString(32101), path=SourceDetails.getFilenameAndPath()) # Get the first items fanart for the play all option anItem.setProperty("Fanart_Image", self.files[0].getFanArt()) if SourceDetails.getTvShowTitle() != "": anItem.setInfo('video', {'TvShowTitle': SourceDetails.getTvShowTitle()}) if SourceDetails.getTitle() != "": anItem.setInfo('video', {'Title': SourceDetails.getTitle()}) self.addItem(anItem) # Check if we want to have YouTube Extra Support if Settings.isYouTubeSearchSupportEnabled(): # Create the message to the YouTube Plugin li = xbmcgui.ListItem(ADDON.getLocalizedString(32116)) # Need to set the title to get it in the header if SourceDetails.getTvShowTitle() != "": li.setInfo('video', {'TvShowTitle': SourceDetails.getTvShowTitle()}) if SourceDetails.getTitle() != "": li.setInfo('video', {'Title': SourceDetails.getTitle()}) li.setProperty("Fanart_Image", SourceDetails.getFanArt()) li.setProperty("search", "/search/?q=%s+Extras" % urllib.quote_plus(SourceDetails.getTitle().encode('utf8'))) self.addItem(li) # Check if we want to have Vimeo Extra Support if Settings.isVimeoSearchSupportEnabled(): # Create the message to the Vimeo Plugin li = xbmcgui.ListItem(ADDON.getLocalizedString(32122)) # Need to set the title to get it in the header if SourceDetails.getTvShowTitle() != "": li.setInfo('video', {'TvShowTitle': SourceDetails.getTvShowTitle()}) if SourceDetails.getTitle() != "": li.setInfo('video', {'Title': SourceDetails.getTitle()}) li.setProperty("Fanart_Image", SourceDetails.getFanArt()) li.setProperty("search", "/search/?q=%s+Extras" % urllib.quote_plus(SourceDetails.getTitle().encode('utf8'))) self.addItem(li) for anExtra in self.files: log("VideoExtrasWindow: filename: %s" % anExtra.getFilename()) # Create the list item anItem = anExtra.createListItem(path=SourceDetails.getFilenameAndPath(), parentTitle=SourceDetails.getTitle(), tvShowTitle=SourceDetails.getTvShowTitle()) self.addItem(anItem) # Before we return, set back the selected on screen item to the one just watched # This is in the case of a reload if self.lastRecordedListPosition > 0: self.setCurrentListPosition(self.lastRecordedListPosition) xbmcgui.WindowXML.onInit(self)
def start(): global log settings = Settings() settings.getSettings() kl = KodiLogger() if settings.general['elevate_loglevel'] is True: kl.setLogLevel(xbmc.LOGNOTICE) else: kl.setLogLevel(xbmc.LOGDEBUG) log = kl.log log(msg=_('Settings read')) Cache.dispatcher = PubSub_Threaded.Dispatcher(interval=settings.general['TaskFreq'], sleepfxn=xbmc.sleep) log(msg=_('Dispatcher initialized')) subscriberfactory = SubscriberFactory(settings, kl) subscribers = subscriberfactory.createSubscribers() for subscriber in subscribers: Cache.dispatcher.addSubscriber(subscriber) publisherfactory = PublisherFactory(settings, subscriberfactory.topics, Cache.dispatcher, kl, debug) publisherfactory.createPublishers() Cache.publishers = publisherfactory.ipublishers Cache.dispatcher.start() log(msg=_('Dispatcher started')) for p in Cache.publishers: try: p.start() except threading.ThreadError: raise log(msg=_('Publisher(s) started'))
def check(self): # If we have found the correct user, then we need to ensure we are # in the valid time duration and have not exceeded the limit if not self.isEnabled: return True # Check for the case where we didn't get the user ID - this means we are # already shutting down if self.userId in [None, ""]: return False log("UserPinControl: Performing check for user %s" % self.userId) # First check that the current time is within the allowed boundaries localTime = time.localtime() currentTime = (localTime.tm_hour * 60) + localTime.tm_min if self.allowedStartTime > currentTime or self.allowedEndTime < currentTime: log("UserPinControl: User not allowed access until %d to %d currently %d" % (self.allowedStartTime, self.allowedEndTime, currentTime)) self.shutdown(32130) return False # Check if the screensaver is running, if so we need to make sure we do not # class that as time used by the user if xbmc.getCondVisibility("System.ScreenSaverActive"): if self.screensaverStart < 1: self.screensaverStart = currentTime else: # Not the screensaver, check to see if this is the first check # after the screensaver stopped if self.screensaverStart > 0: screensaverDuration = currentTime - self.screensaverStart self.screensaverStart = 0 log("UserPinControl: Updating duration for screensaver, %d minutes" % screensaverDuration) # Now we roll the time forward that we started viewing so that # we are not counting the screensaver self.startedViewing = self.startedViewing + screensaverDuration # Check to see if we need to update the record for how long the user has already been viewing viewingLimit = Settings.getUserViewingLimit(self.userId) self.usedViewingLimit = currentTime - self.startedViewing log("UserPinControl: Time used by user is %d" % self.usedViewingLimit) # Update the settings record for how much this user has viewed so far Settings.setUserViewingUsedTime(self.userId, self.usedViewingLimit) # Now check to see if the user has exceeded their limit if self.usedViewingLimit >= viewingLimit: self.shutdown(32133) return False # Check if we need to warn the user that the time is running out warningTime = Settings.getWarnExpiringTime() if (not self.warningDisplayed) and ((self.usedViewingLimit + warningTime) >= viewingLimit): self.warningDisplayed = True # Calculate the time left remainingTime = viewingLimit - self.usedViewingLimit msg = "%d %s" % (remainingTime, ADDON.getLocalizedString(32134)) xbmcgui.Dialog().notification(ADDON.getLocalizedString(32001).encode('utf-8'), msg, ICON, 3000, False) return True
def _updatePlaylistForSettings(self, playlist): if playlist.size() < 1: return playlist filename = playlist[0].getfilename() duration = self._getVideoDuration(filename) log("Duration is %d for file %s" % (duration, filename)) startTime = 0 # Check if we have a random start time if Settings.isRandomStart(): startTime = random.randint(0, int(duration * 0.75)) clockStart = Settings.getTimeForClock(filename, duration) if clockStart > 0: startTime = clockStart # Set the random start if (startTime > 0) and (duration > 10): listitem = xbmcgui.ListItem() # Record if the theme should start playing part-way through listitem.setProperty('StartOffset', str(startTime)) log("Setting start of %d for %s" % (startTime, filename)) # Remove the old item from the playlist playlist.remove(filename) # Add the new item at the start of the list playlist.add(filename, listitem, 0) return playlist
def _moveToThemeFolder(self, directory): log("moveToThemeFolder: path = %s" % directory) # Handle the case where we have a disk image if (os_path_split(directory)[1] == 'VIDEO_TS') or (os_path_split(directory)[1] == 'BDMV'): directory = os_path_split(directory)[0] dirs, files = list_dir(directory) for aFile in files: m = re.search(Settings.getThemeFileRegEx(directory), aFile, re.IGNORECASE) if m: srcpath = os_path_join(directory, aFile) log("fetchAllMissingThemes: Found match: %s" % srcpath) targetpath = os_path_join(directory, Settings.getThemeDirectory()) # Make sure the theme directory exists if not dir_exists(targetpath): try: xbmcvfs.mkdir(targetpath) except: log("fetchAllMissingThemes: Failed to create directory: %s" % targetpath, True, xbmc.LOGERROR) break else: log("moveToThemeFolder: directory already exists %s" % targetpath) # Add the filename to the path targetpath = os_path_join(targetpath, aFile) if not xbmcvfs.rename(srcpath, targetpath): log("moveToThemeFolder: Failed to move file from %s to %s" % (srcpath, targetpath))
def __init__(self): # special://skin - This path points to the currently active skin's root directory. skinExtrasOverlayBase = xbmc.translatePath("special://skin").decode("utf-8") skinExtrasOverlayBase = os_path_join(skinExtrasOverlayBase, "media") # Now check to see if the user has defines a different overlay image in the # settings, as that is the main one that will be used self.skinExtrasOverlay = Settings.getCustomOverlayImage() self.skinExtrasOverlayList = Settings.getCustomListImage() # Next check the skin specific overlay if self.skinExtrasOverlay in [None, '']: self.skinExtrasOverlay = os_path_join(skinExtrasOverlayBase, "videoextras_overlay.png") if self.skinExtrasOverlayList in [None, '']: self.skinExtrasOverlayList = os_path_join(skinExtrasOverlayBase, "videoextras_overlay_list.png") log("VideoExtrasService: Looking for image overlay file: %s" % self.skinExtrasOverlay) if not xbmcvfs.exists(self.skinExtrasOverlay): log("VideoExtrasService: No custom image, using default") # Add default image setting to skinExtrasOverlay self.skinExtrasOverlay = os_path_join(RES_DIR, "skins") self.skinExtrasOverlay = os_path_join(self.skinExtrasOverlay, "icons") self.skinExtrasOverlay = os_path_join(self.skinExtrasOverlay, "overlay1.png") log("VideoExtrasService: Looking for list image overlay file: %s" % self.skinExtrasOverlayList) if not xbmcvfs.exists(self.skinExtrasOverlayList): log("VideoExtrasService: No custom wide image, using default") # Add default image setting to skinExtrasOverlay self.skinExtrasOverlayList = os_path_join(RES_DIR, "skins") self.skinExtrasOverlayList = os_path_join(self.skinExtrasOverlayList, "icons") self.skinExtrasOverlayList = os_path_join(self.skinExtrasOverlayList, "list1.png") self.forceOverlayOverwrite = False # We now know the file that we are going to use for the overlay # Check to see if this is different from the last overlay file used filename = os_path_join(PROFILE_DIR, "overlay_image_used.txt") try: previousOverlay = None if xbmcvfs.exists(filename): fileHandle = xbmcvfs.File(filename, 'r') previousOverlay = fileHandle.read() fileHandle.close() # Check if the overlay has changed if self.skinExtrasOverlay != previousOverlay: self.forceOverlayOverwrite = True # Update the record of the file we are now using if xbmcvfs.exists(filename): xbmcvfs.delete(filename) fileHandle = xbmcvfs.File(filename, 'w') fileHandle.write(self.skinExtrasOverlay.encode("UTF-8")) fileHandle.close() except: log("VideoExtrasService: Failed to write: %s" % filename, xbmc.LOGERROR) log("VideoExtrasService: %s" % traceback.format_exc(), xbmc.LOGERROR)
def onClick(self, control): WINDOW_LIST_ID = 51 # Check to make sure that this click was for the extras list if control != WINDOW_LIST_ID: return # Check the YouTube Search first, as if there are no Extras on disk # There will not be a PlayAll button and it will just be the YouTube Link youtubePosition = 0 vimeoPosition = 0 if len(self.files) > 0: youtubePosition = youtubePosition + 1 vimeoPosition = vimeoPosition + 1 if Settings.isYouTubeSearchSupportEnabled(): vimeoPosition = vimeoPosition + 1 if self.getCurrentListPosition() == youtubePosition: anItem = self.getListItem(youtubePosition) searchDetails = anItem.getProperty("search") log("VideoExtras: Running YouTube Addon/Plugin with search %s" % searchDetails) xbmc.executebuiltin("RunAddon(plugin.video.youtube,%s)" % searchDetails) return if Settings.isVimeoSearchSupportEnabled() and self.getCurrentListPosition() == vimeoPosition: anItem = self.getListItem(vimeoPosition) searchDetails = anItem.getProperty("search") log("VideoExtras: Running Vimeo Addon/Plugin with search %s" % searchDetails) xbmc.executebuiltin("RunAddon(plugin.video.vimeo,%s)" % searchDetails) return # Check for the Play All case if self.getCurrentListPosition() == 0: ExtrasPlayer.playAll(self.files, SourceDetails.getTitle()) return # Get the item that was clicked on extraItem = self._getCurrentSelection() if extraItem is None: # Something has gone very wrong, there is no longer the item that was selected log("VideoExtrasWindow: Unable to match item to current selection") return # If part way viewed prompt the user for resume or play from beginning if extraItem.getResumePoint() > 0: resumeWindow = VideoExtrasResumeWindow.createVideoExtrasResumeWindow(extraItem.getDisplayResumePoint()) resumeWindow.doModal() # Check the return value, if exit, then we play nothing if resumeWindow.isExit(): return # If requested to restart from beginning, reset the resume point before playing if resumeWindow.isRestart(): extraItem.setResumePoint(0) # Default is to actually resume del resumeWindow ExtrasPlayer.performPlayAction(extraItem, SourceDetails.getTitle())
def getScheduleEntry(self): # Get the current time that we are checking the schedule for localTime = time.localtime() currentTime = (localTime.tm_hour * 60) + localTime.tm_min # Get the current day of the week # 0 = Monday 6 = Sunday today = localTime.tm_wday # Make sure that the day returned is within our expected list if today not in Settings.DAY_TYPE: log("Schedule: Unknown day today %d, setting to everyday" % today) today = Settings.EVERY_DAY # Check if we need to refresh the schedule details from the file # in case they have changed if Settings.getScheduleSetting() == Settings.SCHEDULE_FILE: # Check if the file has changed scheduleFileName = Settings.getScheduleFile() if scheduleFileName not in [None, ""]: if xbmcvfs.exists(scheduleFileName): statFile = xbmcvfs.Stat(scheduleFileName) modified = statFile.st_mtime() if modified != self.lastScheduleModified: log("Schedule: Schedule file has changed (%s)" % str(modified)) # We use the offset to work out if the data has changed if self.idOffset > 0: self.idOffset = 0 else: self.idOffset = 1000 # Clear the existing schedule items self.scheduleDetails = [] # Load the new schedule items self._loadFromFile() # Check the scheduled items to see if any cover the current time for item in self.scheduleDetails: if (item['start'] <= currentTime) and (item['end'] >= currentTime): # Make sure this is for the current day if (today == Settings.EVERY_DAY) or (item['day'] in [Settings.EVERY_DAY, today]): return item['id'] # Check for the case where the time laps over midnight if item['start'] > item['end']: if (currentTime >= item['start']) or (currentTime <= item['end']): # Check to see if we are restricting to day if (today == Settings.EVERY_DAY) or (item['day'] == Settings.EVERY_DAY): return item['id'] else: if (currentTime >= item['start']) and (item['day'] in [Settings.EVERY_DAY, today]): return item['id'] else: # The day is set for the start of the time interval # so if we go over to the next day we need to update # what the expected day is nextDay = Settings.getNextDay(item['day']) if (currentTime <= item['end']) and (item['day'] in [Settings.EVERY_DAY, nextDay]): return item['id'] return -1
def __init__(self, *args): self.scheduleDetails = [] self.idOffset = 0 self.lastScheduleModified = 0 if Settings.getScheduleSetting() == Settings.SCHEDULE_SETTINGS: self._loadFromSettings() elif Settings.getScheduleSetting() == Settings.SCHEDULE_FILE: self._loadFromFile()
def checkPlugins(self): navPath = xbmc.getInfoLabel("Container.FolderPath") if 'plugin://' not in navPath: # No Plugin currently set self.lastPluginChecked = "" return # Check if we are in a plugin location pluginName = xbmc.getInfoLabel("Container.FolderName") if pluginName in [None, "", self.lastPluginChecked]: # No Plugin currently set or this is a Plugin that has already been checked return # If we reach here we have aPlugin that we need to check log("NavigationRestrictions: Checking access to view Plugin: %s" % pluginName) self.lastPluginChecked = pluginName # Check for the case where the user does not want to check plugins # but the Pin Sentry plugin is selected, we always need to check this # as it is how permissions are set if (not Settings.isActivePlugins()) and ('PinSentry' not in pluginName): return securityLevel = 0 # Check to see if the user should have access to this plugin pinDB = PinSentryDB() securityLevel = pinDB.getPluginSecurityLevel(pluginName) if securityLevel < 1: # Check for the special case that we are accessing ourself # in which case we have a minimum security level if 'PinSentry' in pluginName: securityLevel = Settings.getSettingsSecurityLevel() else: log("NavigationRestrictions: No security enabled for plugin %s" % pluginName) return del pinDB # Check if we have already cached the pin number and at which level if PinSentry.getCachedPinLevel() >= securityLevel: log("NavigationRestrictions: Already cached pin at level %d, allowing access" % PinSentry.getCachedPinLevel()) return # Prompt the user for the pin, returns True if they knew it if PinSentry.promptUserForPin(securityLevel): log("NavigationRestrictions: Allowed access to plugin %s" % pluginName) else: log("NavigationRestrictions: Not allowed access to plugin %s which has security level %d" % (pluginName, securityLevel)) # Move back to the Video plugin Screen as they are not allowed where they are at the moment xbmc.executebuiltin("ActivateWindow(Video,addons://sources/video/)", True) # Clear the previous plugin as we will want to prompt for the pin again if the # user navigates there again self.lastPluginChecked = "" PinSentry.displayInvalidPinMessage(securityLevel)
def test(key): global log log = KodiLogger.log import resources.lib.tests.direct_test as direct_test from resources.lib.events import Events import traceback log(msg=_('Running Test for Event: %s') % key) events = Events().AllEvents settings = Settings() settings.getSettings() if settings.general['elevate_loglevel'] is True: KodiLogger.setLogLevel(xbmc.LOGNOTICE) else: KodiLogger.setLogLevel(xbmc.LOGDEBUG) log(msg=_('Settings for test read')) evtsettings = settings.events[key] topic = settings.topicFromSettingsEvent(key) task_key = settings.events[key]['task'] tasksettings = settings.tasks[task_key] testlogger = direct_test.TestLogger() log(msg=_('Creating subscriber for test')) subscriberfactory = SubscriberFactory(settings, testlogger) subscriber = subscriberfactory.createSubscriber(key) if subscriber is not None: log(msg=_('Test subscriber created successfully')) try: kwargs = events[evtsettings['type']]['expArgs'] except KeyError: kwargs = {} testRH = direct_test.TestHandler(direct_test.testMsg(subscriber.taskmanagers[0], tasksettings, kwargs)) subscriber.taskmanagers[0].returnHandler = testRH.testReturnHandler # Run test log(msg=_('Running test')) nMessage = PubSub_Threaded.Message(topic=topic, **kwargs) try: subscriber.notify(nMessage) except Exception: msg = _('Unspecified error during testing') e = sys.exc_info()[0] if hasattr(e, 'message'): msg = str(e.message) msg = msg + '\n' + traceback.format_exc() log(msg=msg) msgList = msg.split('\n') import resources.lib.dialogtb as dialogtb dialogtb.show_textbox('Error', msgList) else: log(msg=_('Test subscriber creation failed due to errors')) msgList = testlogger.retrieveLogAsList() import resources.lib.dialogtb as dialogtb dialogtb.show_textbox('Error', msgList) xbmc.sleep(2000)
def checkSystemSettings(self): # Check if the system restriction is enabled if not Settings.isActiveSystemSettings(): return # Check to see if the main system settings has been selected systemSettings = xbmc.getCondVisibility("Window.IsActive(10004)") addonBrowser = xbmc.getCondVisibility("Window.IsActive(10040)") profiles = xbmc.getCondVisibility("Window.IsActive(10034)") # Check if we are in any of the restricted sections if not systemSettings and not addonBrowser and not profiles: log("NavigationRestrictions: Not is restricted system settings") return # If we have already allowed the user to change settings, no need to check again # Check if we are still in the allowed time limit to edit if int(time.time()) < self.canChangeSettings: return # Need to make sure this user has access to change the settings pinDB = PinSentryDB() securityLevel = pinDB.getPluginSecurityLevel('PinSentry') del pinDB if securityLevel < 1: # If the user hasn't reset the permissions, then set it to the highest # security level available securityLevel = Settings.getSettingsSecurityLevel() log("NavigationRestrictions: Settings screen requires security level %d" % securityLevel) # Check if we have already cached the pin number and at which level if PinSentry.getCachedPinLevel() >= securityLevel: log("NavigationRestrictions: Already cached pin at level %d, allowing access" % PinSentry.getCachedPinLevel()) return # Before we prompt the user we need to close the dialog, otherwise the pin # dialog will appear behind it xbmc.executebuiltin("Dialog.Close(all, true)", True) # Prompt the user for the pin, returns True if they knew it if PinSentry.promptUserForPin(securityLevel): log("NavigationRestrictions: Allowed access to settings") # Allow the user 5 minutes to change the settings self.canChangeSettings = int(time.time()) + 300 xbmcgui.Dialog().notification(ADDON.getLocalizedString(32001).encode('utf-8'), ADDON.getLocalizedString(32110).encode('utf-8'), ICON, 3000, False) else: log("NavigationRestrictions: Not allowed access to settings which has security level %d" % securityLevel) self.canChangeSettings = False PinSentry.displayInvalidPinMessage(securityLevel) # Return the user to the home page as they should not be here xbmc.executebuiltin("ActivateWindow(home)", True)
def onInit(self): xbmcgui.WindowXML.onInit(self) self.volumeCtrl = None # Get the videos to use as a screensaver playlist = self._getPlaylist() # If there is nothing to play, then exit now if playlist is None: self.close() return # Update the playlist with any settings such as random start time self._updatePlaylistForSettings(playlist) # Update the volume if needed self.volumeCtrl = VolumeDrop() self.volumeCtrl.lowerVolume() # Now play the video self.player.play(playlist) # Set the video to loop, as we want it running as long as the screensaver self._setRepeat() log("Started playing") # Now check to see if we are overlaying the time on the screen # Default is hidden timeControl = self.getControl(ScreensaverWindow.TIME_CONTROL) timeControl.setVisible(Settings.isShowTime()) # Check if we need to show the weather weatherControl = self.getControl(ScreensaverWindow.WEATHER_CONTROL) if Settings.getWeatherAddon() not in ["", None]: weatherControl.setVisible(True) else: weatherControl.setVisible(False) # Set the value of the dimming for the video dimLevel = Settings.getDimValue() if dimLevel is not None: log("Setting Dim Level to: %s" % dimLevel) dimControl = self.getControl(ScreensaverWindow.DIM_CONTROL) dimControl.setColorDiffuse(dimLevel) # Set the overlay image self._setOverlayImage() # Update any settings that need to be done after the video is playing self._updatePostPlayingForSettings(playlist)
def displayInvalidPinMessage(level=1): # Invalid Key Notification: Dialog, Popup Notification, None notifType = Settings.getInvalidPinNotificationType() if notifType == Settings.INVALID_PIN_NOTIFICATION_POPUP: cmd = "" if Settings.getNumberOfLevels() > 1: cmd = 'Notification("{0}", "{1} {2}", 3000, "{3}")'.format(ADDON.getLocalizedString(32104).encode('utf-8'), ADDON.getLocalizedString(32211).encode('utf-8'), str(level), ICON) else: cmd = 'Notification("{0}", "{1}", 3000, "{2}")'.format(ADDON.getLocalizedString(32001).encode('utf-8'), ADDON.getLocalizedString(32104).encode('utf-8'), ICON) xbmc.executebuiltin(cmd) elif notifType == Settings.INVALID_PIN_NOTIFICATION_DIALOG: line3 = None if Settings.getNumberOfLevels() > 1: line3 = "%s %d" % (ADDON.getLocalizedString(32211), level) xbmcgui.Dialog().ok(ADDON.getLocalizedString(32001).encode('utf-8'), ADDON.getLocalizedString(32104).encode('utf-8'), line3)
def _doesThemeExist(self, directory, checkParent=False, incAudioThemes=True, incVideoThemes=True): log("doesThemeExist: Checking directory: %s" % directory) # Check for custom theme directory if Settings.isThemeDirEnabled(): themeDir = os_path_join(directory, Settings.getThemeDirectory()) # Check if this directory exists if not dir_exists(themeDir): workingPath = directory # If the path currently ends in the directory separator # then we need to clear an extra one if (workingPath[-1] == os.sep) or (workingPath[-1] == os.altsep): workingPath = workingPath[:-1] # If not check to see if we have a DVD VOB if (os_path_split(workingPath)[1] == 'VIDEO_TS') or (os_path_split(workingPath)[1] == 'BDMV'): # Check the parent of the DVD Dir themeDir = os_path_split(workingPath)[0] themeDir = os_path_join(themeDir, Settings.getThemeDirectory()) directory = themeDir # Check to see if we need to check the parent directory if checkParent: directory = os_path_split(directory)[0] # check if the directory exists before searching if dir_exists(directory): # Generate the regex audioOnly = False videoOnly = False if not incAudioThemes: videoOnly = True if not incVideoThemes: audioOnly = True themeFileRegEx = Settings.getThemeFileRegEx(audioOnly=audioOnly, videoOnly=videoOnly) dirs, files = list_dir(directory) for aFile in files: m = re.search(themeFileRegEx, aFile, re.IGNORECASE) if m: log("doesThemeExist: Found match: " + aFile) return True # Check if an NFO file exists nfoFileName = os_path_join(directory, "tvtunes.nfo") if xbmcvfs.exists(nfoFileName): log("doesThemeExist: Found match: " + nfoFileName) return True return False
def _getAllFilesInDirectory(self, baseDir, includeSubDirs=True): videoFiles = [] dirs, files = list_dir(baseDir) # Get the list of files that are to be excluded collectionCtrl = CollectSets() disabledVideos = collectionCtrl.getDisabledVideos() del collectionCtrl # Get all the files in the current directory for vidFile in files: # Check if this file is excluded if vidFile in disabledVideos: log("Ignoring disabled screensaver video %s" % vidFile) continue fullPath = os_path_join(baseDir, vidFile) videoFiles.append(fullPath) # Now check each directory if includeSubDirs and Settings.isFolderNested(): for aDir in dirs: fullPath = os_path_join(baseDir, aDir) dirContents = self._getAllFilesInDirectory(fullPath) videoFiles = videoFiles + dirContents return videoFiles
def removeCollection(self, name, link): if name in [None, ""]: return collectionCtrl = CollectSets() collectionDetails = collectionCtrl.loadCollection(link) filesToDelete = [] # If the file was not processed just don't display anything if collectionDetails not in [None, ""]: screensaverFolder = Settings.getScreensaverFolder() for videoItem in collectionDetails['videos']: # If theme exists we need to check if we want to delete it if screensaverFolder not in [None, ""]: videoLocation = os_path_join(screensaverFolder, videoItem['filename']) log("VideoScreensaverPlugin: Checking if %s already downloaded to %s" % (videoItem['filename'], videoLocation)) if xbmcvfs.exists(videoLocation): filesToDelete.append(videoLocation) # If there are possible files to delete, then prompt the user to see if we should if len(filesToDelete) > 0: needDelete = xbmcgui.Dialog().yesno(ADDON.getLocalizedString(32005), ADDON.getLocalizedString(32086)) if needDelete: for vidFile in filesToDelete: xbmcvfs.delete(vidFile) # Now remove the actual collection collectionCtrl.removeCustomCollection(name) del collectionCtrl # Now reload the screen to reflect the change xbmc.executebuiltin("Container.Refresh")
def onPlayBackStarted(self): # The first item in a playlist will have already had it's start time # set correctly if it is a clock if self.initialStart is True: self.initialStart = False log("onPlayBackStarted received for initial video") return if self.isPlayingVideo(): # Get the currently playing file filename = self.getPlayingFile() log("onPlayBackStarted received for file %s" % filename) duration = self._getVideoDuration(filename) log("onPlayBackStarted: Duration is %d for file %s" % (duration, filename)) startTime = Settings.getTimeForClock(filename, duration) # Set the clock start time if startTime > 0 and duration > 10: self.seekTime(startTime) else: log("onPlayBackStarted received, but not playing video file") xbmc.Player.onPlayBackStarted(self)
def getFilenameAndPath(): if SourceDetails.filenameAndPath is None: extrasDirName = Settings.getExtrasDirName() if (extrasDirName is None) or (extrasDirName == ""): extrasDirName = "Extras" SourceDetails.filenameAndPath = "%s%s" % (xbmc.getInfoLabel("ListItem.FilenameAndPath"), extrasDirName) return SourceDetails.filenameAndPath
def updateDisplay(self, eventDetails=None): SonosControllerWindow.updateDisplay(self, eventDetails) # Now we have updated the track currently playing read the details out and # set the windows properties for ArtistSlideshow # Only update if the track has changed if self.currentTrack not in [None, '']: # Check if we want to show lyrics for the track, although not part of the # artist slideshow feature (it is part of script.cu.lrclyrics) we treat # this in a similar manner, first set the values lyrics = None if Settings.isLyricsInfoLayout(): lyrics = Lyrics(self.currentTrack, self.getControl(SonosArtistSlideshow.LYRICS), self.lyricListLinesCount) lyrics.setLyricRequest() # Artist Slideshow will set these properties for us xbmcgui.Window(self.windowId).setProperty('CURRENTARTIST', self.currentTrack['artist']) xbmcgui.Window(self.windowId).setProperty('CURRENTTITLE', self.currentTrack['title']) xbmcgui.Window(self.windowId).setProperty('CURRENTALBUM', self.currentTrack['album']) # Check if lyrics are enabled, and set the test if they are if lyrics is not None: self.currentTrack = lyrics.populateLyrics() lyrics.refresh() del lyrics
def _getContextMenu(self, videoItem): ctxtMenu = [] # Check if the file has already been downloaded if self._getVideoLocation(Settings.getScreensaverFolder(), videoItem['filename']) in [None, ""]: # If not already exists, add a download option cmd = self._build_url({'mode': 'download', 'name': videoItem['name'], 'filename': videoItem['filename'], 'primary': videoItem['primary']}) ctxtMenu.append((ADDON.getLocalizedString(32013), 'RunPlugin(%s)' % cmd)) # If not already exists, add a download option cmd = self._build_url({'mode': 'play', 'name': videoItem['name'], 'filename': videoItem['primary']}) ctxtMenu.append((ADDON.getLocalizedString(32019), 'RunPlugin(%s)' % cmd)) else: # If already exists then add a play option cmd = self._build_url({'mode': 'play', 'name': videoItem['name'], 'filename': videoItem['filename']}) ctxtMenu.append((ADDON.getLocalizedString(32015), 'RunPlugin(%s)' % cmd)) # If already exists then add a delete option cmd = self._build_url({'mode': 'delete', 'name': videoItem['name'], 'filename': videoItem['filename']}) ctxtMenu.append((ADDON.getLocalizedString(32014), 'RunPlugin(%s)' % cmd)) # Check if we need a menu item to enable and disable the videos if videoItem['enabled']: cmd = self._build_url({'mode': 'enable', 'disable': 'true', 'filename': videoItem['filename']}) ctxtMenu.append((ADDON.getLocalizedString(32017), 'RunPlugin(%s)' % cmd)) else: cmd = self._build_url({'mode': 'enable', 'disable': 'false', 'filename': videoItem['filename']}) ctxtMenu.append((ADDON.getLocalizedString(32018), 'RunPlugin(%s)' % cmd)) return ctxtMenu
def hasVideoExtras(self, target, dbid, file, title=None): # If the service is on, then we can just check to see if the overlay image exists if Settings.isServiceEnabled(): # Get the path where the file exists rootPath = os_path_join(PROFILE_DIR, target) if not dir_exists(rootPath): # Directory does not exist yet, so can't have extras return False # Generate the name of the file that the overlay will be copied to targetFile = os_path_join(rootPath, ("%d.png" % dbid)) if xbmcvfs.exists(targetFile): return True # Otherwise, need to do the lookup the old fashioned way of looking for the # extras files on the file system (This is much slower) else: videoExtras = VideoExtrasBase(file, target, title) # We are only checking for existence of extras, no need for fanart firstExtraFile = videoExtras.findExtras(True) del videoExtras if firstExtraFile: log("MenuNavigator: Extras found for (%d) %s" % (dbid, file)) return True return False
def _getNewSettingsXml(self): regexSection = '' # Put together the regex section details extrasTag = Settings.getExtrasFileTag() if extrasTag != "": log("Setting Tag Name to: %s" % extrasTag) regexSection = AdvSettings.REGEX_SECTION.format(extrasTag) # Check what the directory name is extrasDir = Settings.getExtrasDirName() log("Setting Directory Name to: %s" % extrasDir) regexSection += AdvSettings.REGEX_SECTION.format('/' + extrasDir + '/') regexSection += AdvSettings.REGEX_SECTION.format('[\\\\\\/]' + extrasDir + '[\\\\\\/]') # Now put together the ignore section ignoreSection = AdvSettings.IGNORE_SECTION.format(regexSection) return ignoreSection
def fetchTheme(self, title, path, originaltitle=None, isTvShow=None, year=None, imdb=None): # If there is already a theme then start playing it self._startPlayingExistingTheme(path) if Settings.isThemeDirEnabled() and self._doesThemeExist(path, True): # Prompt user if we should move themes in the parent # directory into the theme directory moveExistingThemes = xbmcgui.Dialog().yesno(ADDON.getLocalizedString(32105), ADDON.getLocalizedString(32206), ADDON.getLocalizedString(32207)) # Check if we need to move a theme file if moveExistingThemes: log("fetchAllMissingThemes: Moving theme for %s" % title) self._moveToThemeFolder(path) # Stop playing any theme that started self._stopPlayingTheme() # Now reload the screen to reflect the change xbmc.executebuiltin("Container.Refresh") return if originaltitle is not None: originaltitle = normalize_string(originaltitle) # Perform the fetch videoList = [] normtitle = normalize_string(title) videoItem = {'title': normtitle, 'path': path, 'originalTitle': originaltitle, 'isTvShow': isTvShow, 'year': year, 'imdb': imdb} videoList.append(videoItem) TvTunesFetcher(videoList) # Stop playing any theme that started self._stopPlayingTheme() # Now reload the screen to reflect the change xbmc.executebuiltin("Container.Refresh")
def _getNewSettingsXml(self): regexSection = '' # Put together the regex section details # Check what the directory name is themeDir = Settings.getThemeDirectory() log("Setting Directory Name to: %s" % themeDir) regexSection += AdvSettings.REGEX_SECTION.format('/' + themeDir + '/') regexSection += AdvSettings.REGEX_SECTION.format('[\\\\\\/]' + themeDir + '[\\\\\\/]') # Put together the list of file endings videoFileTypes = Settings.getVideoThemeFileExtensions() if videoFileTypes not in [None, ""]: regexSection += AdvSettings.REGEX_SECTION.format('theme([0-9]*)\.(' + videoFileTypes.lower() + '|' + videoFileTypes.upper() + ')$') # Now put together the ignore section ignoreSection = AdvSettings.IGNORE_SECTION.format(regexSection) return ignoreSection
def getPathForVideoItem(self, videoItem): path = "" # Get the path where the theme should be stored if Settings.isCustomPathEnabled(): path = os_path_join(Settings.getCustomPath(), normalize_string(videoItem['title'])) else: path = videoItem['file'] # Handle stacked files that have a custom file name format if path.startswith("stack://"): path = path.replace("stack://", "").split(" , ", 1)[0] # Need to remove the filename from the end as we just want the directory fileExt = os.path.splitext(path)[1] # If this is a file, then get it's parent directory if fileExt is not None and fileExt != "": path = os_path_split(path)[0] return path
def checkVolumeChange(self): # Check to see if the Sonos Volume Redirect is Enabled if not Settings.redirectVolumeControls(): return self.volumeChangeNotification = self.volumeChangeNotification - 1 redirect = xbmcgui.Window(10000).getProperty("SonosVolumeRedirect") while redirect not in [None, ""]: xbmcgui.Window(10000).clearProperty("SonosVolumeRedirect") volumeChange = 0 isMute = False if redirect.lower() == "up": volumeChange = Settings.getVolumeChangeIncrements() elif redirect.lower() == "down": volumeChange = Settings.getVolumeChangeIncrements() * -1 elif redirect.lower() == "mute": isMute = True log("SonosVolumeRedirect: Changing by %d" % volumeChange) # Check to see if it has changed, and if we need to change the sonos value if isMute: # Check the current muted state if sonosDevice.mute: sonosDevice.fullMute(False) else: sonosDevice.fullMute(True) self.volumeChangeNotification = Settings.getChecksPerSecond() * 2 elif volumeChange != 0: sonosDevice.setGroupVolume(sonosDevice.volume + volumeChange, True) self.volumeChangeNotification = Settings.getChecksPerSecond() * 2 redirect = xbmcgui.Window(10000).getProperty("SonosVolumeRedirect") # Check if we have started changing the volume and have now stopped # for a little while if self.volumeChangeNotification == 0: self.volumeChangeNotification = -1 if sonosDevice.mute: xbmcgui.Dialog().notification(ADDON.getLocalizedString(32074), ADDON.getLocalizedString(32075), ICON, 2000, False) else: displayMsg = "%d" % sonosDevice.volume xbmcgui.Dialog().notification(ADDON.getLocalizedString(32074), displayMsg, ICON, 2000, False)
def restoreVolume(self): try: if Settings.isUseAudioSuspend(): xbmc.audioResume() # Don't change the volume unless requested to elif self.screensaverVolume > -1: self._setVolume(self.original_volume) except: log("VolumeDrop: %s" % traceback.format_exc(), xbmc.LOGERROR)
def checkVimeoSettings(): # Check to see if the Vimeo support is enabled if Settings.isVimeoSearchSupportEnabled(): # It is enabled in settings, but we should check to ensure that the # Vimeo addon is actually installed vimeoInstalled = False try: vimeoAddon = xbmcaddon.Addon(id='plugin.video.vimeo') if vimeoAddon not in [None, ""]: vimeoInstalled = True except: # We will get an exception if we can not find the Vimeo addon vimeoInstalled = False if not vimeoInstalled: # There is no Vimeo addon installed, so disable this option in settings log("VideoExtrasService: Disabling Vimeo support as addon not installed") Settings.disableVimeoSearchSupport()
def checkYouTubeSettings(): # Check to see if the YouTube support is enabled if Settings.isYouTubeSearchSupportEnabled(): # It is enabled in settings, but we should check to ensure that the # YouTube addon is actually installed youtubeInstalled = False try: youtubeAddon = xbmcaddon.Addon(id='plugin.video.youtube') if youtubeAddon not in [None, ""]: youtubeInstalled = True except: # We will get an exception if we can not find the YouTube addon youtubeInstalled = False if not youtubeInstalled: # There is no YouTube addon installed, so disable this option in settings log("VideoExtrasService: Disabling YouTube support as addon not installed") Settings.disableYouTubeSearchSupport()
def onSettingsChanged(self): log("TvTunesMonitor: Notification of settings change received") Settings.reloadSettings()
################################## # Main of the Video Screensaver ################################## if __name__ == '__main__': # Check for the case where the screensaver has been launched as a script # But needs to behave like the full screensaver, not just a video player # This is the case for things like screensaver.random if (len(sys.argv) > 1) and ("screensaver" in sys.argv[1]): # Launch the core screensaver script - this will ensure all the pre-checks # are done (like TvTunes) before running the screensaver log("Screensaver started by script with screensaver argument") xbmc.executebuiltin('RunScript(%s)' % (os.path.join(CWD, "default.py"))) else: # Check if we need to load the weather settings weatherAddon = Settings.getWeatherAddon() if weatherAddon not in ["", None]: log("Using weather addon %s" % weatherAddon) xbmc.executebuiltin('RunScript(%s,0)' % weatherAddon, False) # Before we start, make sure that the settings have been updated correctly Settings.cleanAddonSettings() screenWindow = ScreensaverWindow.createScreensaverWindow() xbmcgui.Window(10000).setProperty("VideoScreensaverRunning", "true") didScreensaverTimeout = False try: # Now show the window and block until we exit screensaverTimeout = Settings.screensaverTimeout()
def _updatePostPlayingForSettings(self, playlist): # Check if we need to start at a random location if Settings.isRandomStart() and playlist.size() > 0: # Need to reset the offset to the start so that if it loops # it will play from the start playlist[0].setProperty('StartOffset', "0")
def __init__(self, *args): self.screensaverVolume = Settings.getVolume() if self.screensaverVolume > -1: # Save the volume from before any alterations self.original_volume = self._getVolume()
def _loadFromFile(self): # Get the videos schedule that is stored in the file scheduleFileName = Settings.getScheduleFile() if scheduleFileName in [None, ""]: log("Schedule: No schedule file set") return log("Schedule: Searching for schedule file: %s" % scheduleFileName) # Return False if file does not exist if not xbmcvfs.exists(scheduleFileName): log("Schedule: No schedule file found: %s" % scheduleFileName) return # Save off the time this file was modified statFile = xbmcvfs.Stat(scheduleFileName) self.lastScheduleModified = statFile.st_mtime() log("Schedule: Reading in schedule file with modify time: %s" % str(self.lastScheduleModified)) # The file exists, so start loading it try: # Need to first load the contents of the file into # a string, this is because the XML File Parse option will # not handle formats like smb:// scheduleFile = xbmcvfs.File(scheduleFileName, 'r') scheduleFileStr = scheduleFile.read() scheduleFile.close() # Create an XML parser scheduleXml = ET.ElementTree(ET.fromstring(scheduleFileStr)) rootElement = scheduleXml.getroot() log("Schedule: Root element is = %s" % rootElement.tag) # Check which format if being used if rootElement.tag == "schedule": log("Schedule: Schedule format file detected") # <schedule> # <rule start="14:24" end="14:37" video="video3.mkv" overlay="WindowFrame1.png" /> # </schedule> # Get the directory that the schedule file is in as this might be needed # if we have local paths in the XML file directory = os_path_split(scheduleFileName)[0] # There could be multiple rule entries, so loop through all of them itemNum = self.idOffset + 1 for ruleElem in scheduleXml.findall('rule'): if ruleElem is not None: videoFile = ruleElem.get('video', None) overlayFile = ruleElem.get('overlay', None) startTime = self._convertTimeToMinutes( ruleElem.get('start', "00:00")) endTime = self._convertTimeToMinutes( ruleElem.get('end', "00:00")) day = self._convertDayFormat(ruleElem.get('day', None)) if (videoFile not in [None, ""]) and (startTime not in [ None, "" ]) and (endTime not in [None, ""]): # Make it a full path if it is not already if videoFile.startswith('..') or ( ("/" not in videoFile) and ("\\" not in videoFile)): videoFile = os_path_join(directory, videoFile) if overlayFile not in [None, ""]: if overlayFile.startswith('..') or ( ("/" not in overlayFile) and ("\\" not in overlayFile)): overlayFile = os_path_join( directory, overlayFile) log("Schedule File: Item %d (Start:%d, End:%d) contains video %s" % (itemNum, startTime, endTime, videoFile)) # Check if the video file exists if os_path_isfile(videoFile): details = { 'id': itemNum, 'start': startTime, 'end': endTime, 'day': day, 'video': videoFile, 'overlay': overlayFile } self.scheduleDetails.append(details) else: log("Schedule: File does not exist: %s" % videoFile) itemNum = itemNum + 1 else: log("Schedule: Unknown schedule file format") del scheduleXml except: log( "Schedule: Failed to process schedule file: %s" % scheduleFileName, xbmc.LOGERROR) log("Schedule: %s" % traceback.format_exc(), xbmc.LOGERROR)
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 = 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
class MediathekView(KodiPlugin): def __init__(self): super(MediathekView, self).__init__() self.settings = Settings() self.notifier = Notifier() self.database = Store(self.getNewLogger('Store'), self.notifier, self.settings) def show_main_menu(self): # Search self.addFolderItem(30901, {'mode': "search", 'extendedsearch': False}) # Search all self.addFolderItem(30902, {'mode': "search", 'extendedsearch': True}) # Browse livestreams self.addFolderItem(30903, {'mode': "livestreams"}) # Browse recently added self.addFolderItem(30904, {'mode': "recent", 'channel': 0}) # Browse recently added by channel self.addFolderItem(30905, {'mode': "recentchannels"}) # Browse by Initial->Show self.addFolderItem(30906, {'mode': "initial", 'channel': 0}) # Browse by Channel->Initial->Shows self.addFolderItem(30907, {'mode': "channels"}) # Database Information self.addActionItem(30908, {'mode': "action-dbinfo"}) # Manual database update if self.settings.updmode == 1 or self.settings.updmode == 2: self.addActionItem(30909, {'mode': "action-dbupdate"}) self.endOfDirectory() self._check_outdate() def show_searches(self, extendedsearch=False): self.addFolderItem(30931, { 'mode': "newsearch", 'extendedsearch': extendedsearch }) RecentSearches(self, extendedsearch).load().populate() self.endOfDirectory() def new_search(self, extendedsearch=False): settingid = 'lastsearch2' if extendedsearch is True else 'lastsearch1' headingid = 30902 if extendedsearch is True else 30901 # are we returning from playback ? search = self.addon.getSetting(settingid) if search: # restore previous search self.database.Search(search, FilmUI(self), extendedsearch) else: # enter search term (search, confirmed) = self.notifier.GetEnteredText('', headingid) if len(search) > 2 and confirmed is True: RecentSearches(self, extendedsearch).load().add(search).save() if self.database.Search(search, FilmUI(self), extendedsearch) > 0: self.addon.setSetting(settingid, search) else: # pylint: disable=line-too-long self.info( 'The following ERROR can be ignored. It is caused by the architecture of the Kodi Plugin Engine' ) self.endOfDirectory(False, cacheToDisc=True) # self.show_searches( extendedsearch ) def show_db_info(self): info = self.database.GetStatus() heading = self.language(30907) infostr = self.language({ 'NONE': 30941, 'UNINIT': 30942, 'IDLE': 30943, 'UPDATING': 30944, 'ABORTED': 30945 }.get(info['status'], 30941)) infostr = self.language(30965) % infostr totinfo = self.language(30971) % (info['tot_chn'], info['tot_shw'], info['tot_mov']) updatetype = self.language(30972 if info['fullupdate'] > 0 else 30973) if info['status'] == 'UPDATING' and info['filmupdate'] > 0: updinfo = self.language(30967) % ( updatetype, datetime.datetime.fromtimestamp( info['filmupdate']).strftime('%Y-%m-%d %H:%M:%S'), info['add_chn'], info['add_shw'], info['add_mov']) elif info['status'] == 'UPDATING': updinfo = self.language(30968) % (updatetype, info['add_chn'], info['add_shw'], info['add_mov']) elif info['lastupdate'] > 0 and info['filmupdate'] > 0: updinfo = self.language(30969) % ( updatetype, datetime.datetime.fromtimestamp( info['lastupdate']).strftime('%Y-%m-%d %H:%M:%S'), datetime.datetime.fromtimestamp( info['filmupdate']).strftime('%Y-%m-%d %H:%M:%S'), info['add_chn'], info['add_shw'], info['add_mov'], info['del_chn'], info['del_shw'], info['del_mov']) elif info['lastupdate'] > 0: updinfo = self.language(30970) % ( updatetype, datetime.datetime.fromtimestamp( info['lastupdate']).strftime('%Y-%m-%d %H:%M:%S'), info['add_chn'], info['add_shw'], info['add_mov'], info['del_chn'], info['del_shw'], info['del_mov']) else: updinfo = self.language(30966) xbmcgui.Dialog().textviewer( heading, infostr + '\n\n' + totinfo + '\n\n' + updinfo) def _check_outdate(self, maxage=172800): if self.settings.updmode != 1 and self.settings.updmode != 2: # no check with update disabled or update automatic return if self.database is None: # should never happen self.notifier.ShowOutdatedUnknown() return status = self.database.GetStatus() if status['status'] == 'NONE' or status['status'] == 'UNINIT': # should never happen self.notifier.ShowOutdatedUnknown() return elif status['status'] == 'UPDATING': # great... we are updating. nuthin to show return # lets check how old we are tsnow = int(time.time()) tsold = int(status['lastupdate']) if tsnow - tsold > maxage: self.notifier.ShowOutdatedKnown(status) def init(self): if self.database.Init(): if self.settings.HandleFirstRun(): pass self.settings.HandleUpdateOnStart() def run(self): # save last activity timestamp self.settings.ResetUserActivity() # process operation mode = self.get_arg('mode', None) if mode is None: self.show_main_menu() elif mode == 'search': extendedsearch = self.get_arg('extendedsearch', 'False') == 'True' self.show_searches(extendedsearch) elif mode == 'newsearch': self.new_search(self.get_arg('extendedsearch', 'False') == 'True') elif mode == 'research': search = self.get_arg('search', '') extendedsearch = self.get_arg('extendedsearch', 'False') == 'True' self.database.Search(search, FilmUI(self), extendedsearch) RecentSearches(self, extendedsearch).load().add(search).save() elif mode == 'delsearch': search = self.get_arg('search', '') extendedsearch = self.get_arg('extendedsearch', 'False') == 'True' RecentSearches( self, extendedsearch).load().delete(search).save().populate() self.runBuiltin('Container.Refresh') elif mode == 'livestreams': self.database.GetLiveStreams( FilmUI(self, [xbmcplugin.SORT_METHOD_LABEL])) elif mode == 'recent': channel = self.get_arg('channel', 0) self.database.GetRecents(channel, FilmUI(self)) elif mode == 'recentchannels': self.database.GetRecentChannels(ChannelUI(self, nextdir='recent')) elif mode == 'channels': self.database.GetChannels(ChannelUI(self, nextdir='shows')) elif mode == 'action-dbinfo': self.show_db_info() elif mode == 'action-dbupdate': self.settings.TriggerUpdate() self.notifier.ShowNotification(30963, 30964, time=10000) elif mode == 'initial': channel = self.get_arg('channel', 0) self.database.GetInitials(channel, InitialUI(self)) elif mode == 'shows': channel = self.get_arg('channel', 0) initial = self.get_arg('initial', None) self.database.GetShows(channel, initial, ShowUI(self)) elif mode == 'films': show = self.get_arg('show', 0) self.database.GetFilms(show, FilmUI(self)) elif mode == 'downloadmv': filmid = self.get_arg('id', 0) quality = self.get_arg('quality', 1) Downloader(self).download_movie(filmid, quality) elif mode == 'downloadep': filmid = self.get_arg('id', 0) quality = self.get_arg('quality', 1) Downloader(self).download_episode(filmid, quality) elif mode == 'playwithsrt': filmid = self.get_arg('id', 0) only_sru = self.get_arg('only_set_resolved_url', 'False') == 'True' Downloader(self).play_movie_with_subs(filmid, only_sru) # cleanup saved searches if mode is None or mode != 'search': self.addon.setSetting('lastsearch1', '') if mode is None or mode != 'searchall': self.addon.setSetting('lastsearch2', '') def exit(self): self.database.Exit()
def __init__(self): super(MediathekView, self).__init__() self.settings = Settings() self.notifier = Notifier() self.database = Store(self.getNewLogger('Store'), self.notifier, self.settings)
# Class to detect when something in the system has changed class TvTunesMonitor(xbmc.Monitor): def onSettingsChanged(self): log("TvTunesMonitor: Notification of settings change received") Settings.reloadSettings() ################################## # Main of the TvTunes Service ################################## if __name__ == '__main__': log("Starting TvTunes Service %s" % ADDON.getAddonInfo('version')) # Check if the settings mean we want to reset the volume on startup startupVol = Settings.getStartupVolume() if startupVol < 0: log("TvTunesService: No Volume Change Required") else: log("TvTunesService: Setting volume to %s" % startupVol) executebuiltin('SetVolume(%d)' % startupVol, True) # Make sure the user wants to play themes if Settings.isThemePlayingEnabled(): log("TvTunesService: Theme playing enabled") # Create a monitor so we can reload the settings if they change systemMonitor = TvTunesMonitor() # Start looping to perform the TvTune theme operations
class MediathekViewPlugin(KodiPlugin): """ The main plugin class """ def __init__(self): super(MediathekViewPlugin, self).__init__() self.settings = Settings() self.notifier = Notifier() self.database = Store(self.get_new_logger('Store'), self.notifier, self.settings) self.unicodePath = unicode(self.path, 'utf-8') def show_main_menu(self): """ Creates the main menu of the plugin """ # Search self.add_folder_item(30901, { 'mode': "search", 'extendedsearch': False }, icon=os.path.join(self.unicodePath, 'resources', 'icons', 'search-m.png')) # Search all self.add_folder_item(30902, { 'mode': "search", 'extendedsearch': True }, icon=os.path.join(self.unicodePath, 'resources', 'icons', 'search-m.png')) # Browse livestreams self.add_folder_item(30903, {'mode': "livestreams"}, icon=os.path.join(self.unicodePath, 'resources', 'icons', 'live2-m.png')) # Browse recently added self.add_folder_item(30904, { 'mode': "recent", 'channel': 0 }, icon=os.path.join(self.unicodePath, 'resources', 'icons', 'new-m.png')) # Browse recently added by channel self.add_folder_item(30905, {'mode': "recentchannels"}, icon=os.path.join(self.unicodePath, 'resources', 'icons', 'new-m.png')) # Browse by Initial->Show self.add_folder_item(30906, { 'mode': "initial", 'channel': 0 }, icon=os.path.join(self.unicodePath, 'resources', 'icons', 'movie-m.png')) # Browse by Channel->Initial->Shows self.add_folder_item(30907, {'mode': "channels"}, icon=os.path.join(self.unicodePath, 'resources', 'icons', 'movie-m.png')) # Database Information self.add_action_item(30908, {'mode': "action-dbinfo"}, icon=os.path.join(self.unicodePath, 'resources', 'icons', 'dbinfo-m.png')) # Manual database update if self.settings.updmode == 1 or self.settings.updmode == 2: self.add_action_item(30909, {'mode': "action-dbupdate"}) self.end_of_directory() self._check_outdate() def show_searches(self, extendedsearch=False): """ Fill the search screen with "New Search..." and the list of recent searches Args: extendedsearch(bool, optionsl): If `True`, the searches are performed both in show title and description. Default is `False` """ self.add_folder_item(30931, { 'mode': "newsearch", 'extendedsearch': extendedsearch }, icon=os.path.join(self.unicodePath, 'resources', 'icons', 'search-m.png')) RecentSearches(self, extendedsearch).load().populate() self.end_of_directory() def new_search(self, extendedsearch=False): """ Asks the user to enter his search terms and then performs the search and displays the results. Args: extendedsearch(bool, optionsl): If `True`, the searches are performed both in show title and description. Default is `False` """ settingid = 'lastsearch2' if extendedsearch is True else 'lastsearch1' headingid = 30902 if extendedsearch is True else 30901 # are we returning from playback ? search = self.get_setting(settingid) if search: # restore previous search self.database.search(search, FilmUI(self), extendedsearch) else: # enter search term (search, confirmed) = self.notifier.get_entered_text('', headingid) if len(search) > 2 and confirmed is True: RecentSearches(self, extendedsearch).load().add(search).save() if self.database.search(search, FilmUI(self), extendedsearch) > 0: self.set_setting(settingid, search) else: # pylint: disable=line-too-long self.info( 'The following ERROR can be ignored. It is caused by the architecture of the Kodi Plugin Engine' ) self.end_of_directory(False, cache_to_disc=True) def show_db_info(self): """ Displays current information about the database """ info = self.database.get_status() heading = self.language(30907) infostr = self.language({ 'NONE': 30941, 'UNINIT': 30942, 'IDLE': 30943, 'UPDATING': 30944, 'ABORTED': 30945 }.get(info['status'], 30941)) infostr = self.language(30965) % infostr totinfo = self.language(30971) % (info['tot_chn'], info['tot_shw'], info['tot_mov']) updatetype = self.language(30972 if info['fullupdate'] > 0 else 30973) if info['status'] == 'UPDATING' and info['filmupdate'] > 0: updinfo = self.language(30967) % ( updatetype, datetime.datetime.fromtimestamp( info['filmupdate']).strftime('%Y-%m-%d %H:%M:%S'), info['add_chn'], info['add_shw'], info['add_mov']) elif info['status'] == 'UPDATING': updinfo = self.language(30968) % (updatetype, info['add_chn'], info['add_shw'], info['add_mov']) elif info['lastupdate'] > 0 and info['filmupdate'] > 0: updinfo = self.language(30969) % ( updatetype, datetime.datetime.fromtimestamp( info['lastupdate']).strftime('%Y-%m-%d %H:%M:%S'), datetime.datetime.fromtimestamp( info['filmupdate']).strftime('%Y-%m-%d %H:%M:%S'), info['add_chn'], info['add_shw'], info['add_mov'], info['del_chn'], info['del_shw'], info['del_mov']) elif info['lastupdate'] > 0: updinfo = self.language(30970) % ( updatetype, datetime.datetime.fromtimestamp( info['lastupdate']).strftime('%Y-%m-%d %H:%M:%S'), info['add_chn'], info['add_shw'], info['add_mov'], info['del_chn'], info['del_shw'], info['del_mov']) else: updinfo = self.language(30966) xbmcgui.Dialog().textviewer( heading, infostr + '\n\n' + totinfo + '\n\n' + updinfo) def _check_outdate(self, maxage=172800): if self.settings.updmode != 1 and self.settings.updmode != 2: # no check with update disabled or update automatic return if self.database is None: # should never happen self.notifier.show_outdated_unknown() return status = self.database.get_status() if status['status'] == 'NONE' or status['status'] == 'UNINIT': # should never happen self.notifier.show_outdated_unknown() return elif status['status'] == 'UPDATING': # great... we are updating. nuthin to show return # lets check how old we are tsnow = int(time.time()) tsold = int(status['lastupdate']) if tsnow - tsold > maxage: self.notifier.show_outdated_known(status) def init(self): """ Initialisation of the plugin """ if self.database.init(): if self.settings.handle_first_run(): pass self.settings.handle_update_on_start() def run(self): """ Execution of the plugin """ # save last activity timestamp self.settings.reset_user_activity() # process operation self.info("Plugin invoked with parameters {}", self.args) mode = self.get_arg('mode', None) if mode is None: self.show_main_menu() elif mode == 'search': extendedsearch = self.get_arg('extendedsearch', 'False') == 'True' self.show_searches(extendedsearch) elif mode == 'newsearch': self.new_search(self.get_arg('extendedsearch', 'False') == 'True') elif mode == 'research': search = self.get_arg('search', '') extendedsearch = self.get_arg('extendedsearch', 'False') == 'True' self.database.search(search, FilmUI(self), extendedsearch) RecentSearches(self, extendedsearch).load().add(search).save() elif mode == 'delsearch': search = self.get_arg('search', '') extendedsearch = self.get_arg('extendedsearch', 'False') == 'True' RecentSearches( self, extendedsearch).load().delete(search).save().populate() self.run_builtin('Container.Refresh') elif mode == 'livestreams': self.database.get_live_streams( FilmUI(self, [xbmcplugin.SORT_METHOD_LABEL])) elif mode == 'recent': channel = self.get_arg('channel', 0) self.database.get_recents(channel, FilmUI(self)) elif mode == 'recentchannels': self.database.get_recent_channels(ChannelUI(self, nextdir='recent')) elif mode == 'channels': self.database.get_channels(ChannelUI(self, nextdir='shows')) elif mode == 'action-dbinfo': self.show_db_info() elif mode == 'action-dbupdate': self.settings.trigger_update() self.notifier.show_notification(30963, 30964, time=10000) elif mode == 'initial': channel = self.get_arg('channel', 0) self.database.get_initials(channel, InitialUI(self)) elif mode == 'shows': channel = self.get_arg('channel', 0) initial = self.get_arg('initial', None) self.database.get_shows(channel, initial, ShowUI(self)) elif mode == 'films': show = self.get_arg('show', 0) self.database.get_films(show, FilmUI(self)) elif mode == 'downloadmv': filmid = self.get_arg('id', 0) quality = self.get_arg('quality', 1) Downloader(self).download_movie(filmid, quality) elif mode == 'downloadep': filmid = self.get_arg('id', 0) quality = self.get_arg('quality', 1) Downloader(self).download_episode(filmid, quality) elif mode == 'playwithsrt': filmid = self.get_arg('id', 0) Downloader(self).play_movie_with_subs(filmid) # cleanup saved searches if mode is None or mode != 'newsearch': self.set_setting('lastsearch1', '') self.set_setting('lastsearch2', '') def exit(self): """ Shutdown of the application """ self.database.exit()
def play(self, item=None, listitem=None, windowed=True, fastFade=False): self.tvtunesPlayerStarted = True # if something is already playing, then we do not want # to replace it with the theme if not self.isPlaying(): self.updateVideoRefreshRate(item) # Save the volume from before any alterations self.original_volume = self._getVolume() # Perform and lowering of the sound for theme playing self._lowerVolume() if Settings.isFadeIn(): # Get the current volume - this is our target volume targetVol = self._getVolume() cur_vol_perc = 1 # Calculate how fast to fade the theme, this determines # the number of step to drop the volume in numSteps = 10 if fastFade: numSteps = numSteps / 2 vol_step = targetVol / numSteps # Reduce the volume before starting # do not mute completely else the mute icon shows up self._setVolume(1) # Now start playing before we start increasing the volume xbmc.Player.play(self, item=item, listitem=listitem, windowed=windowed) # Wait until playing has started maxLoop = 100 while (not self.isPlaying()) and ( not xbmc.abortRequested) and (maxLoop > 0): maxLoop = maxLoop - 1 xbmc.sleep(30) for step in range(0, (numSteps - 1)): # If the system is going to be shut down then we need to reset # everything as quickly as possible if WindowShowing.isShutdownMenu() or xbmc.abortRequested: log("ThemePlayer: Shutdown menu detected, cancelling fade in" ) break vol = cur_vol_perc + vol_step log("ThemePlayer: fadeIn_vol: %s" % str(vol)) self._setVolume(vol) cur_vol_perc = vol xbmc.sleep(200) # Make sure we end on the correct volume self._setVolume(targetVol) else: xbmc.Player.play(self, item=item, listitem=listitem, windowed=windowed) if Settings.isLoop(): xbmc.executebuiltin("PlayerControl(RepeatAll)") # We no longer use the JSON method to repeat as it does not work with videos # executeJSONRPC('{ "jsonrpc": "2.0", "method": "Player.SetRepeat", "params": {"playerid": 0, "repeat": "all" }, "id": 1 }') # If we had a random start and we are looping then we need to make sure # when it comes to play the theme for a second time it starts at the beginning # and not from the same mid-point if Settings.isRandomStart(): item[0].setProperty('StartOffset', "0") else: xbmc.executebuiltin("PlayerControl(RepeatOff)") # We no longer use the JSON method to repeat as it does not work with videos # executeJSONRPC('{ "jsonrpc": "2.0", "method": "Player.SetRepeat", "params": {"playerid": 0, "repeat": "off" }, "id": 1 }') # Record the time that playing was started self.startTime = int(time.time()) # Clear the current playlist, as we will re-populate it self.playListItems = [] # Save off the number of items in the playlist if item is not None: self.playlistSize = item.size() log("ThemePlayer: Playlist size = %d" % self.playlistSize) # Store a list of all the tracks in the playlist try: i = 0 while i < self.playlistSize: self.playListItems.append(item[i].getfilename()) i = i + 1 except: log("ThemePlayer: Failed to save off playlist") # Check if we are limiting each track in the list if not Settings.isLoop(): # Already started playing the first, so the remaining number of # tracks is one less than the total self.remainingTracks = self.playlistSize - 1 self._setNextSkipTrackTime(self.startTime) else: self.playlistSize = 1
# Class to detect when something in the system has changed class TvTunesMonitor(xbmc.Monitor): def onSettingsChanged(self): log("TvTunesMonitor: Notification of settings change received") Settings.reloadSettings() ################################## # Main of the TvTunes Service ################################## if __name__ == '__main__': log("Starting TvTunes Service %s" % ADDON.getAddonInfo('version')) # Make sure we have recorded this machines Id Settings.setTvTunesId() # Check if the settings mean we want to reset the volume on startup startupVol = Settings.getStartupVolume() if startupVol < 0: log("TvTunesService: No Volume Change Required") else: log("TvTunesService: Setting volume to %s" % startupVol) xbmc.executebuiltin('SetVolume(%d)' % startupVol, True) # Check if the video info button should be hidden, we do this here as this will be # called when the system is loaded, it can then be read by the skin # when it comes to draw the button WindowShowing.updateHideVideoInfoButton() WindowShowing.updateShowOnContextMenu()
def showAudiobooks(self, directory=None): # Get the setting for the audio book directory audioBookFolder = Settings.getAudioBookFolder() if audioBookFolder in [None, ""]: # Prompt the user to set the eBooks Folder audioBookFolder = xbmcgui.Dialog().browseSingle( 0, ADDON.getLocalizedString(32005), 'files') # Check to make sure the directory is set now if audioBookFolder in [None, ""]: xbmcgui.Dialog().ok(ADDON.getLocalizedString(32001), ADDON.getLocalizedString(32006)) return # Save the directory in settings for future use log("AudioBooksPlugin: Setting Audio Books folder to %s" % audioBookFolder) Settings.setAudioBookFolder(audioBookFolder) # We may be looking at a subdirectory if directory not in [None, ""]: audioBookFolder = directory dirs, files = xbmcvfs.listdir(audioBookFolder) files.sort() dirs.sort() bookDirs = [] # For each directory list allow the user to navigate into it for adir in dirs: if adir.startswith('.'): continue fullDir = os_path_join(audioBookFolder, adir) # Check if this directory is a book directory if self._isAudioBookDir(fullDir): bookDirs.append(fullDir) continue log("AudioBooksPlugin: Adding directory %s" % adir) try: displayName = "[%s]" % adir.encode("utf-8") except: displayName = "[%s]" % adir try: fullDir = fullDir.encode("utf-8") except: pass plot = "" try: plot = "[B]%s[/B]" % adir.encode("utf-8") except: plot = adir # Check if there are any images for this directory iconImage = 'DefaultFolder.png' fanartImage = FANART subDirs, subFiles = xbmcvfs.listdir(fullDir) for fileInDir in subFiles: if fileInDir.lower() in ['fanart.jpg', 'fanart.png']: fanartImage = os_path_join(fullDir, fileInDir) elif fileInDir.lower() in ['folder.jpg', 'folder.png']: iconImage = os_path_join(fullDir, fileInDir) url = self._build_url({'mode': 'directory', 'directory': fullDir}) li = xbmcgui.ListItem(displayName, iconImage=iconImage) li.setProperty("Fanart_Image", fanartImage) li.setInfo('video', {'Plot': plot}) li.addContextMenuItems([], replaceItems=True) xbmcplugin.addDirectoryItem(handle=self.addon_handle, url=url, listitem=li, isFolder=True) m4bAudioBooks = [] for m4bBookFile in files: # Check to ensure that this is an eBook if not m4bBookFile.lower().endswith('.m4b'): log("AudioBooksPlugin: Skipping non audiobook file: %s" % m4bBookFile) continue fullpath = os_path_join(audioBookFolder, m4bBookFile) m4bAudioBooks.append(fullpath) # Get all the audiobook in a nicely sorted order allAudioBooks = sorted(bookDirs + m4bAudioBooks) audioBookHandlers = [] # Now list all of the books for audioBookFile in allAudioBooks: log("AudioBooksPlugin: Adding audiobook %s" % audioBookFile) audioBookHandlers.append( AudioBookHandler.createHandler(audioBookFile)) # Now sort the list by title audioBookHandlers.sort() # Now list all of the books for audioBookHandler in audioBookHandlers: log("AudioBooksPlugin: Processing audiobook %s" % audioBookHandler.getFile()) title = audioBookHandler.getTitle() coverTargetName = audioBookHandler.getCoverImage(True) isRead = False if Settings.isMarkCompletedItems(): if audioBookHandler.isCompleted(): isRead = True displayString = title try: displayString = title.encode("utf-8") except: displayString = title try: log("AudioBooksPlugin: Display title is %s for %s" % (displayString, audioBookFile)) except: # No need to have an error for logging pass plot = "" try: plot = "[B]%s[/B]" % displayString except: plot = displayString if isRead: displayString = '* %s' % displayString url = self._build_url({ 'mode': 'chapters', 'filename': audioBookHandler.getFile(True), 'cover': coverTargetName }) li = xbmcgui.ListItem(displayString, iconImage=coverTargetName) li.setProperty("Fanart_Image", audioBookHandler.getFanArt()) li.setInfo('video', {'Plot': plot}) li.addContextMenuItems(self._getContextMenu(audioBookHandler), replaceItems=True) xbmcplugin.addDirectoryItem(handle=self.addon_handle, url=url, listitem=li, isFolder=True) del audioBookHandler xbmcplugin.endOfDirectory(self.addon_handle)
def showRootMenu(self): # Movies url = self._build_url({ 'mode': 'folder', 'foldername': MenuNavigator.MOVIES }) li = xbmcgui.ListItem(ADDON.getLocalizedString(32201), iconImage=ICON) li.setProperty("Fanart_Image", FANART) li.addContextMenuItems(self._getContextMenu(MenuNavigator.MOVIES), replaceItems=True) xbmcplugin.addDirectoryItem(handle=self.addon_handle, url=url, listitem=li, isFolder=True) # TV Shows url = self._build_url({ 'mode': 'folder', 'foldername': MenuNavigator.TVSHOWS }) li = xbmcgui.ListItem(ADDON.getLocalizedString(32202), iconImage=ICON) li.setProperty("Fanart_Image", FANART) li.addContextMenuItems(self._getContextMenu(MenuNavigator.TVSHOWS), replaceItems=True) xbmcplugin.addDirectoryItem(handle=self.addon_handle, url=url, listitem=li, isFolder=True) # Movie Sets url = self._build_url({ 'mode': 'folder', 'foldername': MenuNavigator.MOVIESETS }) li = xbmcgui.ListItem(ADDON.getLocalizedString(32203), iconImage=ICON) li.setProperty("Fanart_Image", FANART) li.addContextMenuItems(self._getContextMenu(MenuNavigator.MOVIESETS), replaceItems=True) xbmcplugin.addDirectoryItem(handle=self.addon_handle, url=url, listitem=li, isFolder=True) # Music Videos url = self._build_url({ 'mode': 'folder', 'foldername': MenuNavigator.MUSICVIDEOS }) li = xbmcgui.ListItem(ADDON.getLocalizedString(32205), iconImage=ICON) li.setProperty("Fanart_Image", FANART) li.addContextMenuItems(self._getContextMenu(MenuNavigator.MUSICVIDEOS), replaceItems=True) xbmcplugin.addDirectoryItem(handle=self.addon_handle, url=url, listitem=li, isFolder=True) # Plugins if Settings.isActivePlugins(): url = self._build_url({ 'mode': 'folder', 'foldername': MenuNavigator.PLUGINS }) li = xbmcgui.ListItem(ADDON.getLocalizedString(32128), iconImage=ICON) li.setProperty("Fanart_Image", FANART) li.addContextMenuItems([], replaceItems=True) xbmcplugin.addDirectoryItem(handle=self.addon_handle, url=url, listitem=li, isFolder=True) # Files if Settings.isActiveFileSource(): url = self._build_url({ 'mode': 'folder', 'foldername': MenuNavigator.FILESOURCE }) li = xbmcgui.ListItem(ADDON.getLocalizedString(32204), iconImage=ICON) li.setProperty("Fanart_Image", FANART) li.addContextMenuItems([], replaceItems=True) xbmcplugin.addDirectoryItem(handle=self.addon_handle, url=url, listitem=li, isFolder=True) # Classifications url = self._build_url({ 'mode': 'folder', 'foldername': MenuNavigator.CLASSIFICATIONS }) li = xbmcgui.ListItem(ADDON.getLocalizedString(32206), iconImage=ICON) li.setProperty("Fanart_Image", FANART) li.addContextMenuItems([], replaceItems=True) xbmcplugin.addDirectoryItem(handle=self.addon_handle, url=url, listitem=li, isFolder=True) # Add a blank line before the Operations li = xbmcgui.ListItem("", iconImage=ICON) li.setProperty("Fanart_Image", FANART) li.addContextMenuItems([], replaceItems=True) xbmcplugin.addDirectoryItem(handle=self.addon_handle, url="", listitem=li, isFolder=False) # Force Pin Entry url = self._build_url({'mode': 'forcepin', 'foldername': 'none'}) menuItemName = ADDON.getLocalizedString(32213) try: menuItemName = "[%s]" % menuItemName except: pass li = xbmcgui.ListItem(menuItemName, iconImage=ICON) li.setProperty("Fanart_Image", FANART) li.addContextMenuItems([], replaceItems=True) xbmcplugin.addDirectoryItem(handle=self.addon_handle, url=url, listitem=li, isFolder=False) xbmcplugin.endOfDirectory(self.addon_handle)
def showExtras(self, path, target, extrasParentTitle="", extrasDefaultFanArt="", extrasDefaultIconImage=""): # Check if the use database setting is enabled extrasDb = None if Settings.isDatabaseEnabled(): extrasDb = ExtrasDB() # Create the extras class that will be used to process the extras videoExtras = VideoExtrasBase(path, target, extrasParentTitle) # Perform the search command files = videoExtras.findExtras(extrasDb=extrasDb, defaultFanArt=extrasDefaultFanArt) del videoExtras tvShowTitle = "" if target == MenuNavigator.TVSHOWS: tvShowTitle = extrasParentTitle if len(files) > 0: # Start by adding an option to Play All anItem = xbmcgui.ListItem(ADDON.getLocalizedString(32101), path=path) # Get the first items fanart for the play all option anItem.setProperty("Fanart_Image", files[0].getFanArt()) if tvShowTitle != "": anItem.setInfo('video', {'TvShowTitle': tvShowTitle}) if extrasParentTitle != "": anItem.setInfo('video', {'Title': extrasParentTitle}) if extrasDefaultIconImage != "": anItem.setIconImage(extrasDefaultIconImage) anItem.addContextMenuItems([], replaceItems=True) url = self._build_url({ 'mode': 'playallextras', 'foldername': target, 'path': path, 'parentTitle': extrasParentTitle }) xbmcplugin.addDirectoryItem(handle=self.addon_handle, url=url, listitem=anItem, isFolder=False) # Check if we want to have YouTube Extra Support if Settings.isYouTubeSearchSupportEnabled(): self._getVideoPluginLink(extrasParentTitle, 'plugin.video.youtube', 32116, extrasDefaultIconImage, extrasDefaultFanArt) # Check if we want to have Vimeo Extra Support if Settings.isVimeoSearchSupportEnabled(): self._getVideoPluginLink(extrasParentTitle, 'plugin.video.vimeo', 32122, extrasDefaultIconImage, extrasDefaultFanArt) # Add each of the extras to the list to display for anExtra in files: # Create the list item li = anExtra.createListItem( parentTitle=extrasParentTitle, tvShowTitle=tvShowTitle, defaultIconImage=extrasDefaultIconImage) # Hack, if the "TotalTime" and "ResumeTime" are set on the list item # and it is partially watched, then Kodi will display the continue dialog # However we can not get what the user selects from this dialog, so it # will always continue. Found out that we can hack this by clearing # the "TotalTime" property # http://forum.xbmc.org/showthread.php?tid=192627 li.setProperty("TotalTime", "") li.addContextMenuItems([], replaceItems=True) li.addContextMenuItems(self._getContextMenu( anExtra, target, path, extrasParentTitle), replaceItems=True) url = self._build_url({ 'mode': 'playextra', 'foldername': target, 'path': path, 'filename': anExtra.getFilename().encode("utf-8"), 'parentTitle': extrasParentTitle }) xbmcplugin.addDirectoryItem(handle=self.addon_handle, url=url, listitem=li, isFolder=False) xbmcplugin.endOfDirectory(self.addon_handle)
if okToRunVideoScreensaver: try: # Stop TvTunes trying to start while we load the screensaver xbmcgui.Window(10025).setProperty("TvTunesBlocked", "true") # Give a little bit of time for everything to shake out before starting the screensaver # waiting another few seconds to start a screensaver is not going to make a difference # to the user xbmc.sleep(1000) # Check if media (Music or video) is playing already when the screensaver # starts, as the user may want to stop the screensaver running if they are # playing music if not (xbmc.Player().isPlaying() and Settings.isBlockScreensaverIfMediaPlaying()): # When we are called to start the screensaver we need to immediately stop # the screensaver, this is because we want to play a video file, an action # which in itself will cause the screensaver to stop log("Waking screensaver with call to context menu") xbmc.executeJSONRPC( '{"jsonrpc": "2.0", "method": "Input.ContextMenu", "id": 1}' ) # Limit the maximum amount of time to wait for the screensaver to end maxWait = 30 while (not exitMon.isStopScreensaver()) and (maxWait > 0): log("still running default screensaver, waiting for stop" ) xbmc.sleep(100)
def _setList(self, target): items = [] if target == MenuNavigator.PLUGINS: items = self._setPluginList() elif target == MenuNavigator.FILESOURCE: items = self._setFileSourceList() else: # Everything other plugins are forms of video items = self._getVideos(target) # Now add the security details to the list items = self._addSecurityFlags(target, items) # Update the classifications items = self._cleanClassification(target, items) for item in items: # Create the list-item for this video li = xbmcgui.ListItem(item['title'], iconImage=item['thumbnail']) # Remove the default context menu li.addContextMenuItems([], replaceItems=True) # Get the title of the video title = item['title'] try: title = item['title'].encode("utf-8") except: pass # Make sure the dbid is coded correctly dbid = item['dbid'] try: dbid = item['dbid'].encode("utf-8") except: pass # Check if the classification is restricting this item isBlockedByClassification = False if 'mpaa' in item: if item['mpaa'] not in [None, ""]: isBlockedByClassification = True # Add a tick if security is set if item['securityLevel'] != 0: li.setInfo('video', {'PlayCount': 1}) # Not the best display format - but the only way that I can get a number to display # In the list, the problem is it will display 01:00 - but at least it's something if Settings.showSecurityLevelInPlugin(): li.setInfo('video', {'Duration': item['securityLevel']}) elif Settings.isHighlightClassificationUnprotectedVideos(): # If the user wishes to see which files are not protected by one of the rules # currently applied, we put the play signal next to them if not isBlockedByClassification: li.setProperty("TotalTime", "") li.setProperty("ResumeTime", "1") # Handle the case where we want to turn off security for a video if isBlockedByClassification and (item['securityLevel'] == -1): # This is the case where the user has forced access to be allowed, this # is useful if you have classification enabled and you want to allow a # given video for a classification to be unprotected li.setProperty("TotalTime", "") li.setProperty("ResumeTime", "1") li.setProperty("Fanart_Image", item['fanart']) url = self._build_url({ 'mode': 'setsecurity', 'level': item['securityLevel'], 'type': target, 'title': title, 'id': dbid, 'classificationBlocked': str(isBlockedByClassification) }) xbmcplugin.addDirectoryItem(handle=self.addon_handle, url=url, listitem=li, isFolder=False) xbmcplugin.endOfDirectory(self.addon_handle)
def onAction(self, action): # actioncodes from https://github.com/xbmc/xbmc/blob/master/xbmc/guilib/Key.h ACTION_PREVIOUS_MENU = 10 ACTION_NAV_BACK = 92 # For remote control ACTION_PAUSE = 12 ACTION_STOP = 13 ACTION_NEXT_ITEM = 14 ACTION_PREV_ITEM = 15 # The following 4 are active forward and back ACTION_FORWARD = 16 ACTION_REWIND = 17 ACTION_PLAYER_FORWARD = 77 ACTION_PLAYER_REWIND = 78 ACTION_PLAYER_PLAY = 79 ACTION_VOLUME_UP = 88 ACTION_VOLUME_DOWN = 89 ACTION_MUTE = 91 # Values Used in the custom keymap ACTION_FIRST_PAGE = 159 # Next Track ACTION_LAST_PAGE = 160 # Previous Track ACTION_PAGE_UP = 5 # Increase Volume ACTION_PAGE_DOWN = 6 # Decrease Volume ACTION_TOGGLE_WATCHED = 200 # Mute volume if (action == ACTION_PREVIOUS_MENU) or (action == ACTION_NAV_BACK): log("SonosControllerWindow: Close Action received: %s" % str(action.getId())) self.close() else: # Handle remote control commands if ((action == ACTION_PLAYER_PLAY) or (action == ACTION_PAUSE)): # Get the initial state of the device playStatus = self.sonosDevice.get_current_transport_info() # Play/pause is a toggle, so pause if playing if playStatus is not None: if playStatus['current_transport_state'] == 'PLAYING': self.onClick(SonosControllerWindow.BUTTON_PAUSE) else: self.onClick(SonosControllerWindow.BUTTON_PLAY) elif (action == ACTION_STOP): self.onClick(SonosControllerWindow.BUTTON_STOP) elif (action == ACTION_NEXT_ITEM) or (action == ACTION_FIRST_PAGE): self.onClick(SonosControllerWindow.BUTTON_NEXT) elif (action == ACTION_PREV_ITEM) or (action == ACTION_LAST_PAGE): self.onClick(SonosControllerWindow.BUTTON_PREVIOUS) elif (action == ACTION_MUTE) or (action == ACTION_TOGGLE_WATCHED): # Check if currently muted if self.sonosDevice.mute is False: self.onClick(SonosControllerWindow.BUTTON_NOT_MUTED) else: self.onClick(SonosControllerWindow.BUTTON_MUTED) elif (action == ACTION_VOLUME_UP) or (action == ACTION_PAGE_UP): # Get the current slider position volumeSlider = self.getControl( SonosControllerWindow.SLIDER_VOLUME) currentSliderPosition = int(volumeSlider.getPercent()) if currentSliderPosition < 100: # Bump the volume by double the wait time (otherwise we can't skip forward accurately) volumeSlider.setPercent( currentSliderPosition + Settings.getVolumeChangeIncrements()) self.onClick(SonosControllerWindow.SLIDER_VOLUME) elif (action == ACTION_VOLUME_DOWN) or (action == ACTION_PAGE_DOWN): # Get the current slider position volumeSlider = self.getControl( SonosControllerWindow.SLIDER_VOLUME) currentSliderPosition = int(volumeSlider.getPercent()) if currentSliderPosition > 0: # Bump the volume down by double the wait time (otherwise we can't skip forward accurately) volumeSlider.setPercent( currentSliderPosition - Settings.getVolumeChangeIncrements()) self.onClick(SonosControllerWindow.SLIDER_VOLUME) elif ((action == ACTION_FORWARD) or (action == ACTION_PLAYER_FORWARD)): # Get the current slider position seekSlider = self.getControl(SonosControllerWindow.SLIDER_SEEK) currentSliderPosition = int(seekSlider.getPercent()) if currentSliderPosition < 99: # Bump the slider by double the wait time (otherwise we can't skip forward accurately) seekSlider.setPercent(currentSliderPosition + ( int(Settings.getAvoidDuplicateCommands()) * 2)) self.onClick(SonosControllerWindow.SLIDER_SEEK) elif ((action == ACTION_REWIND) or (action == ACTION_PLAYER_REWIND)): # Get the current slider position seekSlider = self.getControl(SonosControllerWindow.SLIDER_SEEK) currentSliderPosition = int(seekSlider.getPercent()) if currentSliderPosition > 0: # Bump the slider down by double the wait time (otherwise we can't skip forward accurately) seekSlider.setPercent(currentSliderPosition - ( int(Settings.getAvoidDuplicateCommands()) * 2)) self.onClick(SonosControllerWindow.SLIDER_SEEK)
def runAsAService(self): logVideoLibraryNotShowing = True while not xbmc.Monitor().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" ) 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
from resources.lib.lyrics import Lyrics ADDON = xbmcaddon.Addon(id='script.sonos') CWD = ADDON.getAddonInfo('path').decode("utf-8") ICON = ADDON.getAddonInfo('icon') RES_DIR = xbmc.translatePath(os.path.join( CWD, 'resources').encode("utf-8")).decode("utf-8") log('script version %s started' % ADDON.getAddonInfo('version')) # The base type of the window depends on if we are just having the basic controls # (In which case it is a dialog, so you can see the rest of the screen) # If we want to use ArtistSlideshow then it needs to be a Window, as it does # not work with dialogs (And we want to full the whole screen anyway) BaseWindow = xbmcgui.WindowXMLDialog if Settings.displayArtistInfo(): BaseWindow = xbmcgui.WindowXML ##################################################### # Main window for the Sonos controller ##################################################### class SonosControllerWindow(BaseWindow): # xbmcgui.WindowXMLDialog ALBUM_ART = 801 ARTIST_LABEL = 802 TITLE_LABEL = 803 ALBUM_LABEL = 804 NEXT_LABEL = 805 TRACK_POSITION_LABEL = 810 DURATION_LABEL = 812
def getScheduleEntry(self): # Get the current time that we are checking the schedule for localTime = time.localtime() currentTime = (localTime.tm_hour * 60) + localTime.tm_min # Get the current day of the week # 0 = Monday 6 = Sunday today = localTime.tm_wday # Make sure that the day returned is within our expected list if today not in Settings.DAY_TYPE: log("Schedule: Unknown day today %d, setting to everyday" % today) today = Settings.EVERY_DAY # Check if we need to refresh the schedule details from the file # in case they have changed if Settings.getScheduleSetting() == Settings.SCHEDULE_FILE: # Check if the file has changed scheduleFileName = Settings.getScheduleFile() if scheduleFileName not in [None, ""]: if xbmcvfs.exists(scheduleFileName): statFile = xbmcvfs.Stat(scheduleFileName) modified = statFile.st_mtime() if modified != self.lastScheduleModified: log("Schedule: Schedule file has changed (%s)" % str(modified)) # We use the offset to work out if the data has changed if self.idOffset > 0: self.idOffset = 0 else: self.idOffset = 1000 # Clear the existing schedule items self.scheduleDetails = [] # Load the new schedule items self._loadFromFile() # Check the scheduled items to see if any cover the current time for item in self.scheduleDetails: if (item['start'] <= currentTime) and (item['end'] >= currentTime): # Make sure this is for the current day if (today == Settings.EVERY_DAY) or (item['day'] in [ Settings.EVERY_DAY, today ]): return item['id'] # Check for the case where the time laps over midnight if item['start'] > item['end']: if (currentTime >= item['start']) or (currentTime <= item['end']): # Check to see if we are restricting to day if (today == Settings.EVERY_DAY) or (item['day'] == Settings.EVERY_DAY): return item['id'] else: if (currentTime >= item['start']) and (item['day'] in [ Settings.EVERY_DAY, today ]): return item['id'] else: # The day is set for the start of the time interval # so if we go over to the next day we need to update # what the expected day is nextDay = Settings.getNextDay(item['day']) if (currentTime <= item['end']) and ( item['day'] in [Settings.EVERY_DAY, nextDay]): return item['id'] return -1
# Remove the busy dialog xbmc.executebuiltin("Dialog.Close(busydialog)") # Check to see if there are any speakers if len(speakers) < 1: xbmcgui.Dialog().ok(ADDON.getLocalizedString(32001), ADDON.getLocalizedString(32014)) else: # Now prompt the user to pick one of the speakers select = xbmcgui.Dialog().select(ADDON.getLocalizedString(32001), speakers.keys()) if select != -1: selectedDisplayName = speakers.keys()[select] log("SonosDiscovery: Entry chosen = %s" % selectedDisplayName) chosenIPAddress = speakers.get(selectedDisplayName)[0] chosenZoneName = speakers.get(selectedDisplayName)[1] chosenIsCoordinator = speakers.get(selectedDisplayName)[2] # Warn the user if they have selected something that is not the zone coordinator if not chosenIsCoordinator: xbmcgui.Dialog().ok( ADDON.getLocalizedString(32001), "%s %s:" % (chosenIPAddress, ADDON.getLocalizedString(32032)), " \"%s\"" % chosenZoneName, ADDON.getLocalizedString(32033)) # Set the selected item into the settings Settings.setIPAddress(chosenIPAddress) Settings.setZoneName(chosenZoneName)
def _setRepeat(self): # Set the video to loop, as we want it running as long as the screensaver repeatType = Settings.getFolderRepeatType() if repeatType is not None: log("Setting Repeat Type to %s" % repeatType) xbmc.executebuiltin("PlayerControl(%s)" % repeatType)
# Import the common settings from resources.lib.settings import log from resources.lib.settings import Settings from resources.lib.sync import LibrarySync from resources.lib.summary import Summary ADDON = xbmcaddon.Addon(id='script.theaudiodb.sync') ################################## # Main of TheAudioDBSync Script ################################## if __name__ == '__main__': log("TheAudioDBSync Service Starting %s" % ADDON.getAddonInfo('version')) # Get the username username = Settings.getUsername() # If the username is not set, then nothing to do yet if username not in [None, ""]: performResync = False if Settings.isUploadRatingsOnStartup(): LibrarySync.checkForChangedTrackRatings(username, False) LibrarySync.checkForChangedAlbumRatings(username, False) # Only check for resync if it is enabled if Settings.isUpdateAlbumRatings() or Settings.isUpdateTrackRatings(): nextResyncTime = Settings.getNextScheduledResyncTime() if nextResyncTime not in [None, "", "0"]: log("Service: Next Sync time is %d" % nextResyncTime)
def _getPlaylist(self): playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO) # Note: The playlist clear option seems to impact all playlist settings, # so will remove the repeat settings on a playlist that is currently playing, # not just this instance - a bit nasty, but not much we can do about it playlist.clear() # Check to see if we should be using a video from the schedule scheduleEntry = self.scheduler.getScheduleEntry() if scheduleEntry != -1: # There is an item scheduled, so check to see if the item has actually changed if scheduleEntry == self.currentScheduleItem: return None # Set the entry we are about to play self.currentScheduleItem = scheduleEntry # Get the actual video file that should be played scheduledVideo = self.scheduler.getScheduleVideo(scheduleEntry) # Do a quick check to see if the video exists if xbmcvfs.exists(scheduledVideo): log("Screensaver video for scheduled item %d is: %s" % (scheduleEntry, scheduledVideo)) playlist.add(scheduledVideo) # Check if we are showing all the videos in a given folder elif Settings.isFolderSelection(): videosFolder = Settings.getScreensaverFolder() # Check if we are dealing with a Folder of videos if videosFolder not in [None, ""]: if dir_exists(videosFolder): self.currentScheduleItem = -1 files = self._getAllFilesInDirectory(videosFolder) # Check if we are limiting to a single folder per session if Settings.isLimitSessionToSingleCollection(): # Select just one file at random singleVideo = random.choice(files) # Check if this file is part of a collection justFilename = (os_path_split(singleVideo))[-1] collectionCtrl = CollectSets() collectionVideos = collectionCtrl.getFilesInSameCollection( justFilename) del collectionCtrl # If it is part of a collection, then limit to only files in # this collection if len(collectionVideos) > 0: log("Screensaver restricting to collection containing %s" % singleVideo) # Check each of the videos to see which are in the collection collectionFileList = [] for aFile in files: # Get just the filename aFilename = (os_path_split(aFile))[-1] if aFilename in collectionVideos: log("Screensaver including collection video %s" % aFile) collectionFileList.append(aFile) else: log("Screensaver excluding non collection video %s" % aFile) else: log("Screensaver restricting to directory containing %s" % singleVideo) # Not in a collection, so just gather the files in the same directory # Get the directory that file was part of parentPath = (os_path_split(singleVideo))[0] # Now only select videos from that directory files = self._getAllFilesInDirectory( parentPath, False) # Now shuffle the playlist to ensure that if there are more # than one video a different one starts each time random.shuffle(files) for vidFile in files: log("Screensaver video in directory is: %s" % vidFile) playlist.add(vidFile) else: # Must be dealing with a single file videoFile = Settings.getScreensaverVideo() # Check to make sure the screensaver video file exists if videoFile not in [None, ""]: if xbmcvfs.exists(videoFile): self.currentScheduleItem = -1 log("Screensaver video is: %s" % videoFile) playlist.add(videoFile) # If there are no videos in the playlist yet, then display an error if playlist.size() < 1: errorLocation = Settings.getScreensaverVideo() if Settings.isFolderSelection(): errorLocation = Settings.getScreensaverFolder() log("No Screensaver file set or not valid %s" % errorLocation) cmd = 'Notification("{0}", "{1}", 3000, "{2}")'.format( ADDON.getLocalizedString(32300).encode('utf-8'), errorLocation, ADDON.getAddonInfo('icon')) xbmc.executebuiltin(cmd) return None return playlist
def setSecurity(self, type, title, id, oldLevel, classBlocked=False, forceLevel=None): log("Setting security for (id:%s) %s" % (id, title)) level = 1 # Check if we need to prompt the user or the new security level has been supplied if forceLevel is None: # Set the new security level to be used if oldLevel > 0: # Default is to disable it if it was enabled level = 0 numLevels = Settings.getNumberOfLevels() if numLevels > 1 or classBlocked: # Need to prompt the user to see which pin they are trying to set displayNameList = [] # Add the option to turn it off displayNameList.append("%s %s" % (ADDON.getLocalizedString(32211), ADDON.getLocalizedString(32013))) for i in range(1, numLevels + 1): secLevStr = str(i) if numLevels < 2: # If there is only one security level, use "On" rather than the number secLevStr = ADDON.getLocalizedString(32014) displayString = "%s %s" % (ADDON.getLocalizedString(32211), secLevStr) displayNameList.append(displayString) # Check if we need the option to disable a classification restriction if classBlocked: displayNameList.append(ADDON.getLocalizedString(32212)) select = xbmcgui.Dialog().select( ADDON.getLocalizedString(32001), displayNameList) if select != -1: level = select if classBlocked and (select >= (len(displayNameList) - 1)): level = -1 log("Setting security level to %d" % level) else: log("Exiting set security as no level selected") return else: level = forceLevel # This could take a little time to set the value so show the busy dialog xbmc.executebuiltin("ActivateWindow(busydialog)") if title not in [None, ""]: pinDB = PinSentryDB() if type == MenuNavigator.TVSHOWS: # Set the security level for this title, setting it to zero # will result in the entry being removed from the database # as the default for an item is unset pinDB.setTvShowSecurityLevel(title, int(id), level) elif type == MenuNavigator.MOVIES: pinDB.setMovieSecurityLevel(title, int(id), level) elif type == MenuNavigator.MOVIESETS: pinDB.setMovieSetSecurityLevel(title, int(id), level) # As well as setting the security on the Movie set, we need # to also set it on each movie in the Movie Set self._setSecurityOnMoviesInMovieSets(int(id), level) elif type == MenuNavigator.MUSICVIDEOS: pinDB.setMusicVideoSecurityLevel(title, int(id), level) elif type == MenuNavigator.PLUGINS: pinDB.setPluginSecurityLevel(title, id, level) elif type == MenuNavigator.FILESOURCE: pinDB.setFileSourceSecurityLevel(title, id, level) elif type == MenuNavigator.CLASSIFICATIONS_MOVIES: pinDB.setMovieClassificationSecurityLevel(id, title, level) elif type == MenuNavigator.CLASSIFICATIONS_TV: pinDB.setTvClassificationSecurityLevel(id, title, level) del pinDB else: # Handle the bulk operations like set All security for the movies self._setBulkSecurity(type, level) xbmc.executebuiltin("Dialog.Close(busydialog)") xbmc.executebuiltin("Container.Refresh")
if displayNotice: json_query = xbmc.executeJSONRPC( '{"jsonrpc": "2.0", "method": "Addons.GetAddonDetails", "params": { "addonid": "repository.urepo", "properties": ["enabled", "broken", "name", "author"] }, "id": 1}' ) json_response = json.loads(json_query) if ("result" in json_response) and ('addon' in json_response['result']): addonItem = json_response['result']['addon'] if (addonItem['enabled'] is True) and (addonItem['broken'] is False) and ( addonItem['type'] == 'xbmc.addon.repository') and ( addonItem['addonid'] == 'repository.urepo'): displayNotice = False if displayNotice: xbmc.executebuiltin( 'Notification("robwebset or URepo Repository Required","github.com/robwebset/repository.robwebset",10000,%s)' % ADDON.getAddonInfo('icon')) else: # Check if we should be running sync when the system starts if Settings.isRunOnStartup(): addonSync = AddonSync() addonSync.startSync() del addonSync else: log("AddonSync: Not running at startup") log("AddonSync: Service Ended")
def __init__(self): self.proxy = ProxyTCPD() self.s = Settings() self.s.log('Proxy Bound to 127.0.0.1:{}'.format(self.proxy.port)) self.proxy_thread = threading.Thread(target=self.proxy.serve_forever) self.s.setSetting('proxy', '127.0.0.1:{}'.format(self.proxy.port))
def setVideoList(self, jsonGet, target): videoItems = self.getVideos(jsonGet, target) for videoItem in videoItems: # Get the path where the theme should be stored path = self.getPathForVideoItem(videoItem) # Create the list-item for this video li = xbmcgui.ListItem(videoItem['title'], iconImage=videoItem['thumbnail']) # Remove the default context menu li.addContextMenuItems([], replaceItems=True) # Set the background image if videoItem['fanart'] is not None: li.setProperty("Fanart_Image", videoItem['fanart']) # If theme already exists flag it using the play count # This will normally put a tick on the GUI if self._doesThemeExist(path): # A theme already exists, see if we are showing only missing themes if self.missingThemesOnly == 1: # skip this theme continue li.setInfo('video', {'PlayCount': 1}) # Check the parent directory elif Settings.isThemeDirEnabled() and self._doesThemeExist( path, True): # The Theme directory is set, there is no theme in there # but we have a theme that will play, so flag it li.setProperty("ResumeTime", "50") if videoItem['originaltitle'] is not None: url = self._build_url({ 'mode': 'findtheme', 'foldername': target, 'path': path.encode("utf-8"), 'title': videoItem['title'].encode("utf-8"), 'isTvShow': videoItem['isTvShow'], 'year': videoItem['year'], 'imdb': videoItem['imdb'], 'originaltitle': videoItem['originaltitle'].encode("utf-8") }) else: url = self._build_url({ 'mode': 'findtheme', 'foldername': target, 'path': path.encode("utf-8"), 'title': videoItem['title'].encode("utf-8"), 'isTvShow': videoItem['isTvShow'], 'year': videoItem['year'], 'imdb': videoItem['imdb'] }) xbmcplugin.addDirectoryItem(handle=self.addon_handle, url=url, listitem=li, isFolder=False) xbmcplugin.endOfDirectory(self.addon_handle)
def _getContextMenu(self, bookHandle): ctxtMenu = [] # Play from resume point secondsIn, chapterPosition = bookHandle.getPosition() if (secondsIn > 0) or (chapterPosition > 1): cmd = self._build_url({ 'mode': 'play', 'filename': bookHandle.getFile(True), 'startTime': secondsIn, 'chapter': chapterPosition }) displayTime = self._getDisplayTimeFromSeconds(secondsIn) displayName = "%s %s" % (ADDON.getLocalizedString(32019), displayTime) if chapterPosition > 1: displayName = "%s (%s: %d)" % (displayName, ADDON.getLocalizedString(32017), chapterPosition) ctxtMenu.append((displayName, 'RunPlugin(%s)' % cmd)) # Play from start cmd = self._build_url({ 'mode': 'play', 'filename': bookHandle.getFile(True), 'startTime': 0, 'chapter': 0 }) ctxtMenu.append( (ADDON.getLocalizedString(32018), 'RunPlugin(%s)' % cmd)) # If this item is not already complete, allow it to be marked as complete if not bookHandle.isCompleted(): # Mark as complete cmd = self._build_url({ 'mode': 'progress', 'filename': bookHandle.getFile(True), 'isComplete': 1, 'startTime': 0 }) ctxtMenu.append( (ADDON.getLocalizedString(32010), 'RunPlugin(%s)' % cmd)) # Clear History cmd = self._build_url({ 'mode': 'clear', 'filename': bookHandle.getFile(True) }) ctxtMenu.append( (ADDON.getLocalizedString(32011), 'RunPlugin(%s)' % cmd)) # Add delete support if it is enabled if Settings.isDeleteSupported(): cmd = self._build_url({ 'mode': 'delete', 'filename': bookHandle.getFile(True) }) ctxtMenu.append( (ADDON.getLocalizedString(32032), 'RunPlugin(%s)' % cmd)) return ctxtMenu