def getNextRefreshTS(self): cacheFilePrefix = os.path.basename( Globals().nsCacheFilePrefix ) cacheFileNameRE = re.compile( r'^' + cacheFilePrefix + '\d+$' ) fetchTimeList = [] for file in os.listdir( Globals().nsCacheDir ): if cacheFileNameRE.match( file ): cacheFileName = os.path.join( Globals().nsCacheDir, file ) # Get data fetch time fp = open( cacheFileName, "rb" ) cacheData = cPickle.load( fp ) fp.close() fetchTimeList.append( cacheData['fetch_time'] ) # Keep smaller TS nextTS = -1 for ts in fetchTimeList: if nextTS == -1: nextTS = ts else: if ts < nextTS: nextTS = ts if nextTS == -1: return -1 else: return ( nextTS + self.expiration )
def copyThemeFilesToConfigDir(widget): # Copy files for file in Globals().nsCGuiFiles: source = karamba.readThemeFile(widget, file) dest = open(os.path.join(Globals().nsCGuiBaseDir, file), "w") tools.msgDebug("Copying file: %s" % file, __name__) print >> dest, source dest.close()
def _releaseLock(self): if self.writeFlag: tools.msgDebug("Saving config...", __name__) # Write back to config file fp = open(Globals().nsConfFile, "w") self.write(fp) fp.close() tools.msgDebug("Config saved to %s" % Globals().nsConfFile, __name__) # Release LOCK Config.LOCK = False tools.msgDebug("Config LOCK released", __name__)
def __init__(self): #### User-Agent we use while doing HTTP requests version = Globals().versions kernName = os.popen('uname -s').read()[:-1] kernRel = os.popen('uname -r').read()[:-1] #return "Mozilla/5.0 (compatible; Konqueror/3.5; Linux) KHTML/3.5.6 (like Gecko)" self.userAgent = u"Mozilla/5.0 (compatible; nextShows/%s; %s-%s)" % ( version['nextShows'], kernName, kernRel) #### Set default timeout socket.setdefaulttimeout(10) # 10s
def __init__(self): SafeConfigParser.__init__(self) # LOCK Config() and read configuration file self._acquireLock() # Write Flag # Used to prevent writing back to config file if it was just opened for reading self.writeFlag = False #### Define default config values ### [main] ## Default DEBUG Value self.debug = False ### [gui] ## Filter checkbox self.filter = True ### [shows] ## My Shows self.myShows = [] ### [display] ## Past days to display self.numPastDays = 1 ## Lines self.linesFixed = 10 self.linesMin = 1 self.linesMax = 10 self.linesType = "Fixed" # Values: Fixed / Auto ## Format self.format = "$show:12:...$-S$season:2$E$episode:2$-$title$" ## Theme self.theme = Globals().defaultThemeName ## Date self.dateFormat = "%%d/%%m/%%y" ## Date Separator self.dateSeparator = "/" ## When format self.whenFormat = 0 ### [colors] self.myColors = {} self.myColors['default'] = "#111111" self.myColors['ranges'] = [(-99, -1, "#771111"), (0, 0, "#117711"), (1, 1, "#111177")] ### [misc] self.cacheExpiration = 1 self.browser = "firefox -remote 'openURL($url$,new-tab)'" #### Create necessary dir structure self._initConfigStorage()
def getCachedEpisodeList(self, id): # Cache filename cacheFileName = Globals().nsCacheFilePrefix + str( id ) # Get data tools.msgDebug("Getting data from cache %s..." % cacheFileName, __name__) fp = open( cacheFileName, "rb" ) data = cPickle.load( fp ) fp.close() # Return episode list return data['episode_list']
def checkCacheFile(self, id): # Cache filename cacheFileName = Globals().nsCacheFilePrefix + str( id ) # Check if a file exists for the given id if os.path.isfile( cacheFileName ): # Check if data are still valid currentTS = int( datetime.utcnow().strftime("%s") ) # Show filename cacheFileName = Globals().nsCacheFilePrefix + str( id ) # Get data fetch time fp = open( cacheFileName, "rb" ) cacheData = cPickle.load( fp ) fp.close() cacheFileTS = cacheData['fetch_time'] if ( cacheFileTS + self.expiration ) < currentTS: return self.CACHEFILEOUTDATED else: return self.CACHEFILENOTFOUND return self.CACHEFILEOK
def menuOptionChanged(widget, key, value): global g_configGuiPid karamba.setMenuConfigOption(widget, "config_gui", 0) if key == "config_gui": if g_configGuiPid == None: # Launch config GUI gui = os.path.join(Globals().nsCGuiBaseDir, "launchGUI") cmd = ["python", gui] g_configGuiPid = karamba.executeInteractive(widget, cmd) else: tools.msgDebug("GUI already running", __name__)
def deleteOldCacheFiles(self): tools.msgDebug("Purging cache dir...", __name__) cacheDirContents = os.listdir( Globals().nsCacheDir ) cacheFilePrefix = os.path.basename( Globals().nsCacheFilePrefix ) for id in self.showIds: fileName = cacheFilePrefix + str( id ) if fileName in cacheDirContents: index = cacheDirContents.index( fileName ) cacheDirContents.pop( index ) # Remove unwanted files exitFlag = True for file in cacheDirContents: fileName = os.path.join( Globals().nsCacheDir, file ) try: os.remove( fileName ) tools.msgDebug("Deleted %s..." % fileName, __name__) except: exitFlag = False tools.msgDebug("Error raised while trying to delete %s..." % fileName, __name__) return exitFlag
def _acquireLock(self): # If a LOCK already exist, wait until it is released while Config.LOCK: tools.msgDebug( "Config file LOCKed! Waiting for lock to be released...", __name__) randomize = float(random.randint(0, 1000)) / 1000 time.sleep(randomize) # Acquire LOCK Config.LOCK = True tools.msgDebug("Config LOCK acquired", __name__) # Read config self.read(Globals().nsConfFile) tools.msgDebug("Config read", __name__)
def _initConfigStorage(self): # /!\ Directory tree should be created when the widget launches # Create necessary directories # mode = Globals().nsDirMode # dirs = [ Globals().superKarambaDir, Globals().nsConfDir ] # for dir in dirs: # try: # os.mkdir( dir, mode ) # except OSError: # pass # If no config file is found, create a default one if not os.path.isfile(Globals().nsConfFile): self._createDefaultConfFile()
def createConfigDirs(): # Create dirs mode = Globals().nsDirMode dirs = [ Globals().superKarambaDir, Globals().nsConfDir, Globals().nsCacheDir, Globals().nsCGuiBaseDir ] for dir in Globals().nsCGuiDirs: dirs.append(os.path.join(Globals().nsCGuiBaseDir, dir)) for dir in dirs: try: os.mkdir(dir, mode) tools.msgDebug("Created dir: %s" % dir, __name__) except OSError: pass
def cacheEpisodeList(self, id): # Cache filename cacheFileName = Globals().nsCacheFilePrefix + str( id ) # Get the data parser = TvRage() epList = parser.getEpisodeList( id ) if not epList: return False # In case something went wrong during parsing... showEpList = {} showEpList['fetch_time'] = int( datetime.utcnow().strftime("%s") ) # Timestamp (UTC) showEpList['episode_list'] = epList # Open the file for writing tools.msgDebug("Writing cache file %s..." % cacheFileName, __name__) fp = open( cacheFileName, "wb" ) cPickle.dump( showEpList, fp, cPickle.HIGHEST_PROTOCOL ) fp.close() # At this point we suppose everything hopefully went well return True
def _createDefaultConfFile(self): self.writeFlag = True # Must save the config tools.msgDebug( "Creating default config file %s" % Globals().nsConfFile, __name__) #---------------------------------------------------------------------- # Create necessary sections #sections = ( 'main', 'gui', 'display', 'colors', 'shows', 'misc' ) sections = ('main', 'display', 'colors', 'shows', 'misc') for section in sections: self.add_section(section) # Main self.set("main", "version", "0") self.set("main", "debug", str(self.debug)) # Gui #self.set( "gui", "filter", str(self.filter) ) # Display self.set("display", "past_days", str(self.numPastDays)) self.set("display", "lines_fixed", str(self.linesFixed)) self.set("display", "lines_min", str(self.linesMin)) self.set("display", "lines_max", str(self.linesMax)) self.set("display", "type", str(self.linesType)) self.set("display", "format", str(self.format)) self.set("display", "date_format", str(self.dateFormat)) self.set("display", "date_separator", str(self.dateSeparator)) # Misc self.set("misc", "cache_expiration", str(self.cacheExpiration)) self.set("misc", "browser", str(self.browser)) self.set("misc", "when_format", str(self.whenFormat)) self.set("misc", "theme", str(self.theme)) #---------------------------------------------------------------------- # Set shows self.setShows(self.myShows) # Set color self.setColors(self.myColors)
def refreshFormatPreview(self, text): testFormat = tools.formatEpisode(Globals().sampleEpisode, text) self.ui.lblFormatPreview.setText(u"<u><b>Preview:</b></u> %s" % testFormat)
def initForm(self): # 1st tab labels self.ui.lblResultsDisplayed.setText(u"Displayed results: 0/0") self.ui.lblTrackedShows.setText(u"Tracked shows: 0") # Format Sample fmtSample = u"<u><b>Sample:</b></u> <b>show:</b> %s, <b>title:</b> %s, <b>season</b>: %d, <b>episode</b>: %d" % ( Globals().sampleEpisode['show'], Globals().sampleEpisode['title'], Globals().sampleEpisode['season'], Globals().sampleEpisode['episode']) self.ui.lblFormatSample.setText(fmtSample) #### Versions version = Globals().versions # nextShows Footer Release labelContent = str(self.ui.lblFooterRelease.text()) self.ui.lblFooterRelease.setText(labelContent % version['nextShows']) # nextShows Release (About tab) labelContent = str(self.ui.lblNextShowsVersion.text()) self.ui.lblNextShowsVersion.setText(labelContent % version['nextShows']) # Libs releases (About tab) # Python version a, b, c, d, e = sys.version_info pythonVersion = "%d.%d.%d" % (a, b, c) # labelContent = str(self.ui.lblLibsVersion.text()) self.ui.lblLibsVersion.setText( labelContent % (pythonVersion, QT_VERSION_STR, PYQT_VERSION_STR, version["KDE"])) #### Default values self.ui.spinNumPastDays.setMinimum(0) self.ui.spinNumPastDays.setMaximum(99) #self.ui.spinNumPastDays.setValue(1) self.ui.spinFixedDispLines.setMinimum(1) self.ui.spinFixedDispLines.setMaximum(50) #self.ui.spinFixedDispLines.setValue(10) self.ui.spinMinDispLines.setMinimum(1) self.ui.spinMinDispLines.setMaximum(49) #self.ui.spinMinDispLines.setValue(1) self.ui.spinMaxDispLines.setMinimum(2) self.ui.spinMaxDispLines.setMaximum(50) #self.ui.spinMaxDispLines.setValue(10) # self.ui.spinColorsSingleDay.setMinimum(-99) self.ui.spinColorsSingleDay.setMaximum(99) self.ui.spinColorsSingleDay.setValue(0) self.ui.spinColorsFrom.setMinimum(-99) self.ui.spinColorsFrom.setMaximum(98) self.ui.spinColorsFrom.setValue(0) self.ui.spinColorsTo.setMinimum(-98) self.ui.spinColorsTo.setMaximum(99) self.ui.spinColorsTo.setValue(10) # default color for "Select color" self.ui.lblSelectColor.setPixmap( self.drawPreviewColor(self.lastColorUsed, 36, 36)) # Theme combo self.ui.comboTheme.addItems(Globals().availableThemes) #### #### Read config #### tools.msgDebug(u"Reading config...", __name__) config = Config() # Enable/Disable DEBUG if config.getboolean("main", "debug") == False: tools.msgDebug("Disabling debug messages !", __name__) Globals.DEBUG = False # Get Data self.myShows = config.getShows() self.displayMyShows() self.myColors = config.getColors() self.ui.lblDefaultColor.setPixmap( self.drawPreviewColor(self.myColors['default'], 36, 36)) self.displayMyColors() if config.get("display", "type") == "Fixed": self.ui.radioDispFixedLines.setChecked(True) else: self.ui.radioDispAutoResize.setChecked(True) self.ui.spinNumPastDays.setValue( int(config.get("display", "past_days"))) self.ui.spinFixedDispLines.setValue( int(config.get("display", "lines_fixed"))) self.ui.spinMinDispLines.setValue( int(config.get("display", "lines_min"))) self.ui.spinMaxDispLines.setValue( int(config.get("display", "lines_max"))) self.ui.leditFormat.setText(config.get("display", "format")) self.refreshFormatPreview(str(self.ui.leditFormat.text())) self.ui.spinCacheExpiration.setValue( int(config.get("misc", "cache_expiration"))) self.ui.leditBrowser.setText(config.get("misc", "browser")) # Fallback code since the "theme" key was located in the [display] section # in versions < 2.1.0 try: idx = int(Globals().availableThemes.index( config.get("misc", "theme"))) except: idx = 0 self.ui.comboTheme.setCurrentIndex(idx) # Date Separator # Fallback code since the "date_separator" key doesn't exist in version < 2.1.0 try: sep = config.get("display", "date_separator") except: sep = "/" self.ui.leditDateSeparator.setText(sep) # Date Format dateFormat = config.get("display", "date_format") data = ["%" + a for a in dateFormat.split(sep)] idx = self.ui.comboDateFormat.findData(QVariant(data)) if idx == -1: idx = 0 self.ui.comboDateFormat.setCurrentIndex(idx) config.close() # Reset "Save" button state self.saveRequired(False) tools.msgDebug(u"Done!", __name__)
def _readThemeInfos(self, theme): self.themeName = theme self.themePath = os.path.join("themes", self.themeName) themeInfo = os.path.join(self.themePath, "theme.info") themeInfoContent = karamba.readThemeFile(Applet.widget, themeInfo) if themeInfoContent == "": tools.msgDebug("Error finding/reading %s..." % themeInfo, __name__) # Try to fallback to the default theme self.themeName = Globals().defaultThemeName self.themePath = os.path.join("themes", self.themeName) themeInfo = os.path.join(self.themePath, "theme.info") themeInfoContent = karamba.readThemeFile(Applet.widget, themeInfo) if themeInfoContent == "": tools.msgDebug("Error finding/reading %s..." % themeInfo, __name__) return False ####################################################################### # FIXME: Unfortunately, it is not possible to directly feed ConfigParser # with a str().... # Yep! That's another ugly hack! ####################################################################### tempName = os.tempnam() fp = open(tempName, "w") fp.write(themeInfoContent) fp.close() fp = open(tempName, "r") scp = SafeConfigParser() scp.readfp(fp) fp.close() os.unlink(tempName) ####################################################################### self.themeHeaderImg = os.path.join(self.themePath, scp.get("images", "header")) self.themeHeaderTxtTitle = scp.get("header", "title_text") X = scp.getint("header", "title_pos_x") Y = scp.getint("header", "title_pos_y") self.themeHeaderTxtTitleXY = (X, Y) W = scp.getint("header", "title_width") H = 0 self.themeHeaderTxtTitleWH = (W, H) self.themeHeaderTxtWhen = scp.get("header", "when_text") X = scp.getint("header", "when_pos_x") Y = scp.getint("header", "when_pos_y") self.themeHeaderTxtWhenXY = (X, Y) W = scp.getint("header", "when_width") H = 0 self.themeHeaderTxtWhenWH = (W, H) self.themeBodyImg = os.path.join(self.themePath, scp.get("images", "body")) X = scp.getint("body", "title_pos_x") Y = scp.getint("body", "title_pos_y") self.themeBodyTitleXY = (X, Y) W = scp.getint("body", "title_width") H = scp.getint("body", "title_height") self.themeBodyTitleWH = (W, H) X = scp.getint("body", "when_pos_x") Y = scp.getint("body", "when_pos_y") self.themeBodyWhenXY = (X, Y) W = scp.getint("body", "when_width") H = scp.getint("body", "when_height") self.themeBodyWhenWH = (W, H) self.themeFooterImg = os.path.join(self.themePath, scp.get("images", "footer"))
def initWidget(widget): global g_nextCacheRefresh, g_showList, g_showIds, g_cacheExpiration, g_pastDays, g_linesMin, g_linesMax # Pass the widget reference Applet.widget = widget # Init splash splash = Applet().Splash() splash.show() # Create dir structure splash.setText("Checking config dirs...") createConfigDirs() # Read config splash.setText("Reading config...") config = Config() # Check whether we want DEBUG messages enabled or not if config.getboolean("main", "debug") == False: tools.msgDebug("Disabling debug messages !", __name__) Globals.DEBUG = False # Copy GUI files (if necessary) if Globals().versions['nextShows'] != config.get("main", "version") \ or not "launchGUI" in os.listdir( Globals().nsCGuiBaseDir ): # Init dir structures and copy files splash.setText("Setup GUI...") copyThemeFilesToConfigDir(widget) config.set("main", "version", Globals().versions['nextShows']) # Get other useful infos from config splash.setText("Reading config...") displayType = config.get("display", "type") if displayType == "Fixed": g_linesMax = config.getint("display", "lines_fixed") g_linesMin = g_linesMax else: g_linesMin = config.getint("display", "lines_min") g_linesMax = config.getint("display", "lines_max") g_cacheExpiration = config.getint("misc", "cache_expiration") g_pastDays = config.getint("display", "past_days") applet.colorList = config.getColors() applet.episodeFormatString = config.get("display", "format") applet.browser = config.get("misc", "browser") applet.dateFormat = config.get("display", "date_format") applet.whenFormat = config.getint("misc", "when_format") # Getting the show list splash.setText("Getting show list....") g_showList = config.getShows() # Extract IDs g_showIds = [show['id'] for show in g_showList] # Init cache cache.setExpiration(g_cacheExpiration) cache.showIds = g_showIds # Refresh cache if necessary staledList = cache.getStaledCacheFiles() for id in staledList: for show in g_showList: if show['id'] == id: showName = show['name'] splash.setText("Updating cache: '%s'..." % showName) cache.cacheEpisodeList(id) # Fetch data to display splash.setText("Filtering episodes...") data = Data() episodeList = data.getEpisodeList(g_showIds, g_pastDays, g_linesMax) applet.episodeList = episodeList # Close the splash splash.setText("Done!") splash.hide() # Init widget # Fallback (for compatibility reasons) # "[display] theme=" was moved to "[misc] theme=" try: applet.themeName = config.get("misc", "theme") except: applet.themeName = Globals().defaultThemeName numReturnedEpisode = len(episodeList) if numReturnedEpisode < g_linesMin: themeLines = g_linesMin elif numReturnedEpisode > g_linesMax: themeLines = g_linesMax else: themeLines = numReturnedEpisode applet.themeLines = themeLines applet.drawBackground() applet.printEpisodeList() # Store next cache refresh g_nextCacheRefresh = cache.getNextRefreshTS() # Setup menu entry for config GUI karamba.addMenuConfigOption(widget, "config_gui", "Configure...") karamba.setMenuConfigOption(widget, "config_gui", 0)