class WebRecorder(): ''' API methods are called by the RecorderPlugin in the RecorderWebService module. ''' # signal modes # TODO change mode to STATUS und ERROR... MSG_STATUS = MessageListener.MSG_STATUS # MSG_EPG = MessageListener.MSG_EPG MSG_REFRESH = MessageListener.MSG_REFRESH # Modes or types of rec? (MODE_DATA, MODE_REC, MODE_BLOCK) = range(0xA0, 0xA3) (TYPE_HEAD, TYPE_PROG, TYPE_INFO) = range(3) def __init__(self): ''' starts the app ''' self.configuration = Config() self.configuration.setupLogging("webdvb.log") self._lastMessage = None ml = MessageListener(); ml.addListener(ml.MSG_STATUS, self.storeLastMessage) # ml.addListener(ml.MSG_EPG, this.storeLastMessage) ml.addListener(ml.MSG_REFRESH, self.storeLastMessage) channelReader = ChannelReader() cPath = self.configuration.getChannelFilePath() channelReader.readChannels(cPath) self.channelList = channelReader.getChannels() self.progProvider = EPGProgramProvider(self, self.channelList, self.configuration) self._lastEpgRead = 0.0 # self._readCachedEpgData() self.checkEPGData() def _readCachedEpgData(self): ml = MessageListener(); if not self.channelList: ml.signalMessage(self.MSG_STATUS, "Where is that channel.conf? RTF!") return ml.signalMessage(self.MSG_STATUS, "Reading programm info") msg = "Idle" try: self.progProvider.readEPGCache() ml.signalMessage(self.MSG_REFRESH, "Program info read") # enforces a new list except IOError: msg = "No EPG data" except Exception, ex: msg = "Error reading cached EPG Data: " + str(ex.args[0]) self.configuration.getLogger().exception(msg) print msg self.configuration.logInfo(msg) ml.signalMessage(self.MSG_STATUS, msg)
class DVBRecorder(): ''' startup main class ''' def __init__(self): ''' starts the app ''' self.configuration = Config() self.configuration.setupLogging("dvb.log") channelReader = ChannelReader() cPath = self.configuration.getChannelFilePath() channelReader.readChannels(cPath) self.channelList = channelReader.getChannels() self.progProvider = EPGProgramProvider(self, self.channelList, self.configuration) recView = RecorderView(self.progProvider) ml = MessageListener() ml.addListener(ml.MSG_STATUS, recView.setStatusLine) ml.addListener(ml.MSG_EPG, recView.notifyEPGStatus) ml.addListener(ml.MSG_REFRESH, recView.refreshProgrammInfos) t1 = ReaderThread(False, self._readCachedEpgData) t1.start() recView.openView() #returns on close t1.join() def _readCachedEpgData(self): ml = MessageListener() if not self.channelList: ml.signalMessage(ml.MSG_STATUS, "Where is that channel.conf? RTF!") return ml.signalMessage(ml.MSG_STATUS, "Reading programm info") msg = "Idle" try: self.progProvider.readEPGCache() ml.signalMessage(ml.MSG_REFRESH) # enforces a new list except IOError: msg = "No EPG data" except Exception as ex: msg = "Error reading cached EPG Data: " + str(ex.args[0]) self.configuration.logInfo(msg) ml.signalMessage(ml.MSG_STATUS, msg) ##callback for the epg program provider: def readEPGDeviceData(self): self._EPGThread = ReaderThread(False, self._collectEPGFromDevice) #TEST code: self._EPGThread = ReaderThread(False,self._readEPGSimData) self._EPGThread.start() def _collectEPGFromDevice(self): ml = MessageListener() ml.signalMessage(ml.MSG_EPG, True) ml.signalMessage(ml.MSG_STATUS, "Retrieving new EPG data") epgUpdater = self.progProvider.getEPGUpdater() epgUpdater.updateDatabase() if epgUpdater.hasError(): ml.signalMessage(ml.MSG_STATUS, epgUpdater.getErrorMessage()) ml.signalMessage(ml.MSG_EPG, False) return ml.signalMessage(ml.MSG_REFRESH) # enforces redraw! ml.signalMessage(ml.MSG_STATUS, "EPG data up to date !") ml.signalMessage(ml.MSG_EPG, False) # def _readEPGSimData(self): # rawEPGPath = "/home/matze/JWSP/py1/VideoRecorder/src/xmltv/rawepg.xmltv" # with open(rawEPGPath, 'r') as aFile: # dvbList=aFile.readlines() # # epgReader=EpgReader(self.channelList) # for xmls in dvbList: # print "parse xml" # epgReader.parseXML_TVString(xmls,UTC=True) # # infoDictionary = epgReader.getInfoDictionary() # self.progProvider.updateProgramms(infoDictionary) # ml = MessageListener(); # ml.signalMessage(ml.MODE_REFRESH)# enforces redraw! # ml.signalMessage(ml.MODE_STATUS,"EPG data up to date !") # ml.signalMessage(ml.MODE_EPG,False) def _getEPGDevice(self): return DVBDevice.getGrabber(self.channelList, self.configuration) def persistEPGData(self): self.configuration.logInfo("Saving data...") epgUpdater = self.progProvider.getEPGUpdater() self.progProvider.getAutoSelector().saveAutoSelectData() epgUpdater.persistDatabase() if epgUpdater.hasError(): self.configuration.logError("Error saving xml data")
class WebRecorder(): ''' API methods are called by the RecorderPlugin in the RecorderWebService module. ''' # signal modes # TODO change mode to STATUS und ERROR... MSG_STATUS = MessageListener.MSG_STATUS # MSG_EPG = MessageListener.MSG_EPG MSG_REFRESH = MessageListener.MSG_REFRESH # Modes or types of rec? (MODE_DATA, MODE_REC, MODE_BLOCK) = list(range(0xA0, 0xA3)) (TYPE_HEAD, TYPE_PROG, TYPE_INFO) = list(range(3)) def __init__(self): ''' starts the app ''' self.configuration = Config() self.configuration.setupLogging("webdvb.log") self._lastMessage = None ml = MessageListener() ml.addListener(ml.MSG_STATUS, self.storeLastMessage) # ml.addListener(ml.MSG_EPG, this.storeLastMessage) ml.addListener(ml.MSG_REFRESH, self.storeLastMessage) channelReader = ChannelReader() cPath = self.configuration.getChannelFilePath() channelReader.readChannels(cPath) self.channelList = channelReader.getChannels() self.progProvider = EPGProgramProvider(self, self.channelList, self.configuration) self._lastEpgRead = 0.0 # self._readCachedEpgData() self.checkEPGData() def _readCachedEpgData(self): ml = MessageListener() if not self.channelList: ml.signalMessage(self.MSG_STATUS, "Where is that channel.conf? RTF!") return ml.signalMessage(self.MSG_STATUS, "Reading programm info") msg = "Idle" try: self.progProvider.readEPGCache() ml.signalMessage(self.MSG_REFRESH, "Program info read") # enforces a new list except IOError: msg = "No EPG data" except Exception as ex: msg = "Error reading cached EPG Data: " + str(ex.args[0]) self.configuration.getLogger().exception(msg) print(msg) self.configuration.logInfo(msg) ml.signalMessage(self.MSG_STATUS, msg) def _getEPGDevice(self): return DVBDevice.getGrabber(self.channelList, self.configuration) def _collectEPGFromDevice(self): epgUpdater = self.progProvider.getEPGUpdater() self._updater.updateDatabase() if epgUpdater.hasError(): MessageListener().signalMessage(self.MSG_STATUS, epgUpdater.getErrorMessage()) ''' API to Recorder plugin Basic idea: should be json objects ''' def storeLastMessage(self, message): self._lastMessage = message def getLastSignal(self): msg = self._lastMessage self._lastMessage = None return msg def readEPGDeviceData(self): self._collectEPGFromDevice() def getChannelList(self): channelNames = [] for channel in self.channelList: channelNames.append(channel.getName()) jchannels = json.dumps(channelNames) return jchannels def getProgrammInfoForChannel(self, aChannelString): daytoDayList = self.progProvider.getInfosForChannel(aChannelString) jDayToDayArray = self._formatProgramList(daytoDayList) jInfos = json.dumps(jDayToDayArray) return jInfos def toggleRecordMode(self, jsonString): jsonDict = json.loads(jsonString) epgInfo = self._lookupEPGInfoFromJSON(jsonDict) forceRemove = jsonDict["type"] == self.TYPE_INFO if epgInfo is not None: self.progProvider.toggleRecordInfo(epgInfo, forceRemove) result = self._formatProgramRow(epgInfo) else: jsonDict["error"] = "Entry not found" result = jsonDict if self._lastMessage is not None: result["error"] = self.getLastSignal() return json.dumps(result) def getFilterList(self, searchTuple): channelName = searchTuple[0] filterString = searchTuple[1] epgInfoList = self.progProvider.searchInChannel( channelName, filterString) jDayToDayArray = self._formatProgramList(epgInfoList) return json.dumps(jDayToDayArray) def getAutoSelectList(self): autoselectList = self.progProvider.getAutoSelector( ).getAutoSelectionList() jList = self._formatAutoSelectList(autoselectList) return json.dumps(jList) def addToAutoSelection(self, jsonString): jsonDict = json.loads(jsonString) epgInfo = self._lookupEPGInfoFromJSON(jsonDict) autoSelector = self.progProvider.getAutoSelector() autoSelector.addAutoSelectPreference(epgInfo) autoSelector.saveAutoSelectData() def saveAutoSelectionSetting(self, jsonString): # weekmode has changed. single entry. update & save jsonDict = json.loads(jsonString) hourString = jsonDict["timetext"] # Text is unicode!! titleString = jsonDict["text"] channelName = jsonDict["chanID"] weekModeString = jsonDict["weekMode"] autoSelector = self.progProvider.getAutoSelector() autoSelector.updateWeekMode(hourString, titleString, channelName, weekModeString) autoSelector.saveAutoSelectData() def removeFromAutoSelection(self, jsonString): # NOTE: json makes unicode out of the string jsonDict = json.loads(jsonString) hourString = jsonDict["timetext"] titleString = jsonDict["text"] channelName = jsonDict["chanID"] autoSelector = self.progProvider.getAutoSelector() autoSelector.removeFromAutoSelectPreference(hourString, str(titleString), str(channelName)) autoSelector.saveAutoSelectData() def getRecordingList(self): recInfoList = self.progProvider.getRecordQueue().getRecList() jList = self._formatRecordingList(recInfoList) return json.dumps(jList) #### dict: {u'marginStop': 600, u'marginStart': 300, u'jobID': u'1'} def updateRecorderMargins(self, jsonString): jsonList = json.loads(jsonString) recInfoList = self.progProvider.getRecordQueue().getRecList() for jEntry in jsonList: jobID = jEntry["jobID"] found = next((recEntry for recEntry in recInfoList if recEntry.getEPGInfo().getJobID() == jobID), None) if found: found.setMarginStart(jEntry["marginStart"]) found.setMarginStop(jEntry["marginStop"]) self.progProvider.getRecordQueue()._storeRecordQueue(recInfoList) ''' search the database for a string "cmd":"SEARCH_ALL","arg":"test","data":""} ''' def searchAll(self, searchString): epgInfoList = self.progProvider.searchAll(searchString) #jDayToDayArray = self._formatProgramList(epgInfoList) #return json.dumps(jDayToDayArray) #maybe sort them per channel? jDayList = [] for epgInfo in epgInfoList: jInfo = self._formatProgramRow(epgInfo) jDayList.append(jInfo) errorMsg = None if len(jDayList) == 0: errorMsg = "Nothing found" jAnswer = {"type": self.TYPE_INFO, "error": errorMsg, "list": jDayList} return json.dumps(jAnswer) ''' reread epg info if a modification took place.If changes took place (like a daemon epg update) update the database ''' def checkEPGData(self): fileName = self.configuration.getCachedXMLTVFilePath() currentModificationtime = 0 try: currentModificationtime = OSTools.getLastModificationTime(fileName) except OSError as osError: msg = "CheckEpgData:" + osError.strerror self.configuration.logError(msg) self.storeLastMessage(msg) return # if self._lastEpgRead is None: # self._lastEpgRead= currentModificationtime-100 if currentModificationtime - self._lastEpgRead > 60: self._lastEpgRead = currentModificationtime self._readCachedEpgData() ''' End of WebRecorder API -- Helper/conversion methods -- aka WebViewGenerator? ''' def _formatHeader(self, epgInfo): header = epgInfo.getStartTime().strftime("%A %d %B") headerText = "<b>%s</b>" % header return { "type": self.TYPE_HEAD, "text": headerText, "time": None } def _formatProgramRow(self, epgInfo): epgTime = epgInfo.getStartTimeString() epgDate = epgInfo.getDateString() title = epgInfo.getTitle() duration = str(epgInfo.getDuration()) description = epgInfo.getDescription() # TODO: Formating is client work- only the data! programText = "<b>%s</b><br>%s<small><i> Duration: %s</i></small>" % ( title, description, duration) jobID = None if epgInfo.isMarkedForRecord(): recmode = self.MODE_REC jobID = epgInfo.getJobID() elif epgInfo.isBlockedForRecord(): recmode = self.MODE_BLOCK else: recmode = self.MODE_DATA return { "type": self.TYPE_PROG, "text": programText, "time": epgTime, "date": epgDate, "recordMode": recmode, "jobID": jobID, "title": title, "channel": epgInfo.getChannel().getName(), "epgOK": epgInfo.isConsistent, "error": None } def _formatProgramList(self, daytoDayList): jDayToDayArray = [] for singleDayList in daytoDayList: jDayList = [] # adds the header - setting the date only # TODO: Empty singleDayList! Should not happen if len(singleDayList) == 0: print("ERROR: Empty single day list") continue headerText = self._formatHeader(singleDayList[0]) for epgInfo in singleDayList: jInfo = self._formatProgramRow(epgInfo) jDayList.append(jInfo) jDayObject = { "head": headerText, "list": jDayList } jDayToDayArray.append(jDayObject) if len(jDayToDayArray) == 0: return self.asJsonError("No data", self.getLastSignal()) return jDayToDayArray def asJsonError(self, errorMsg, argumentString): reason = argumentString if not reason: reason = errorMsg return {"type": self.TYPE_INFO, "error": errorMsg, "args": reason} def _lookupEPGInfoFromJSON(self, jsonData): aChannelString = jsonData["channel"] dayString = jsonData["date"] timeString = jsonData["time"] # Note JSON data always uses unicode - convert it to byte encoding it to uf8 daytoDayList = self.progProvider.getInfosForChannel(aChannelString) # Well... get the right DAY first.... for singleDayList in daytoDayList: if singleDayList[0].getDateString() in dayString: for epgInfo in singleDayList: if epgInfo.getStartTimeString() in timeString: return epgInfo return None def _formatAutoSelectList(self, autoSelectList): jDayList = [] for autoSelection in autoSelectList: timeString = autoSelection.getHourListString() title = autoSelection.getTitle() chanID = autoSelection.getChannelID() weekMode = autoSelection.getWeekMode() jInfo = { "type": self.TYPE_INFO, "timetext": timeString, "text": title, "title": title, "chanID": chanID, "weekMode": weekMode, "error": None } jDayList.append(jInfo) jsonASList = { "weekTypes": ["Mo-Fri", "Sa-Su", "Mo-Su"], "elements": jDayList } return jsonASList def _formatRecordingList(self, recInfoList): jDayList = [] for recInfo in recInfoList: jInfo = self._formatRecordingRow(recInfo) jDayList.append(jInfo) return jDayList def _formatRecordingRow(self, recInfo): epgInfo = recInfo.getEPGInfo() epgTime = epgInfo.getStartTimeString() epgDate = epgInfo.getDateString() theDay = epgInfo.getStartTime().strftime("%a %d") start = epgInfo.getStartTime().strftime("%H:%M-") end = epgInfo.getEndTime().strftime("%H:%M") channel = epgInfo.getChannel().getName() formatTime = "<b>%s</b><i> %s</i><br><small>%s%s</small>" % ( channel, theDay, start, end) title = epgInfo.getTitle() description = epgInfo.getDescription() jobID = epgInfo.getJobID() marginStart = recInfo.getMarginAsString(recInfo.marginStart) marginStop = recInfo.getMarginAsString(recInfo.marginEnd) if len(jobID) > 0: programText = "<b>%s</b><br>%s <i>(%s)</i>" % (title, description, jobID) else: programText = "<b>%s</b><br>%s" % (title, description) return { "type": self.TYPE_INFO, "timetext": formatTime, "text": programText, "time": epgTime, "date": epgDate, "jobID": jobID, "title": title, "channel": channel, "marginStart": marginStart, "marginStop": marginStop, "error": None }