def _hasRecordingProcess(self):
       pidInfo = OSTools.getProcessPID(self._recordCmd.Command)
       if pidInfo is None:
           xtime.sleep(2) # in case of adjacent films
           pidInfo = OSTools.getProcessPID(self._recordCmd.Command)
 
       return pidInfo is not None 
    def _argusWait(self,secondsToWait):
        startTime = datetime.now() 
        
        #self._log("Observing recorder queue for %s. Use 'sleepModeOn' for VCR mode"%OSTools.convertSecondsToString(secondsToWait))
        self._log("Observing recorder queue until %s. Execute 'sleepModeOn' for VCR mode"%OSTools.showDateTimeWithOffset(secondsToWait))
        lastQCheck=None
        while (OSTools.getDifferenceInSeconds(datetime.now(),startTime) < secondsToWait):
            xtime.sleep(self.PRERUN_SECONDS)
            path=self._config().getRecQueuePath()
            try:
                currentModificationTime=OSTools.getLastModificationTime(path)
            except OSError as osError:
                currentModificationTime=0.0
                self._config().logError("Error checking rec file:"+osError.strerror) 
                print("Error checking rec file")                       
            #check for socket or file changes... 
            if lastQCheck is None:
                lastQCheck=currentModificationTime #we came from a queue check-so thats the last time we checked 
            if currentModificationTime-lastQCheck>0:
                self._log("Rec Q modified-looking for jobs")
                return False
            if self._daemon.isVCRPolicyChangeRequested(): 
                return False
 
        return True
 def launchRecording(self,recInfo):
     #As opposed to a previous version no AT queue is used. Reason: recording needs to be supervised 
     #anyhow, so there is need for a supervising/scheduling process
     channel = recInfo.getEPGInfo().getChannel()
     OSTools.ensureDirectory(self._config.getRecordingPath(),channel.getEscapedName())
     jobID= recInfo.getEPGInfo().getJobID()
     self._syncRecordIndex(jobID)
     scheduler= Recorder(self._config,self._recordCmd,self._recordPartIndex)
     return scheduler.scheduleRecording(recInfo)            
Exemple #4
0
def main():
    if OSTools.checkIfInstanceRunning("RecorderWebServer"): 
        global KXD
        argv = sys.argv
        #OSTools.changeWorkingDirectory(argv[0]) 
        OSTools.changeWorkingDirectory(OSTools.getWorkingDirectory()) 
        port = argv[1]
        tmp = argv[2].encode('utf-8')
        KXD = base64.b64encode(tmp).decode('utf-8')
        runHTTPServer(port)
 def __init__(self,):
     self._config = Config()
     self._setUpLogging()
     self.epgUpdater = EpgUpdater(self._config)
     OSTools.ensureDirectory(self._config.getRecordingPath(),'')
     self._inhibitor = OSTools.Inhibitor()
     self._recordCmd = DVBDevice.getRecordCommander()
     self._lastJobId="0"
     self._recordPartIndex=0
     self.isActive=True
     self._daemonPolicy = None
    def createMaintenanceRecord(self):
        maintenanceDurance = 15*60;
        nextStart = OSTools.getDateTimeWithOffset(self.MAINT_DAY)

        maintMsg = "creating maintenance entry for %s" %(OSTools.dateTimeAsString(nextStart))
        self._config.logInfo(maintMsg)
        print(maintMsg)
   
        maint = RecordingInfo(None);
        maint.setExecutionTime(nextStart)
        maint.setDurance(maintenanceDurance)
        return maint
    def createMaintenanceRecord(self):
        maintenanceDurance = 15*60;
        nextStart = OSTools.getDateTimeWithOffset(self.MAINT_DAY)

        maintMsg = "creating maintenance entry for %s" %(OSTools.dateTimeAsString(nextStart))
        self._config.logInfo(maintMsg)
        print maintMsg
   
        maint = RecordingInfo(None);
        maint.setExecutionTime(nextStart)
        maint.setDurance(maintenanceDurance)
        return maint
 def _wasWakeupScheduled(self,startTime):
     now = datetime.now()
     secondsToWait = OSTools.getDifferenceInSeconds(startTime, now)
     duranceStr = OSTools.convertSecondsToString(secondsToWait)
     self._log("Delta durance to scheduled wakeup:"+duranceStr)
     
     if secondsToWait > self.PRERUN_SECONDS:
         self._log("Suspend interrupted by user-> going into Server mode!")
         return False
     if secondsToWait>0:
         self._log("Waiting until record starts:"+duranceStr)
         xtime.sleep(secondsToWait)
     return True
 def _suspendDevice(self,seconds):
     coolDown=20 #mediaclient needs time to shutdown
     duranceStr = OSTools.convertSecondsToString(seconds)
     self._log("Going to sleep for %s" %(duranceStr))
     logging.shutdown();
     xtime.sleep(coolDown)
     mode = OSTools.RTC_SLEEP
     if Config.SUSPEND_MODE == Config.MODE_HIBERNATE:
         mode=OSTools.RTC_HIBERNATE
     result=OSTools.rtcWake(seconds-coolDown, mode)
     #back online
     self._daemon._setUpLogging()
     self._log(str(result[0].decode('utf8'))+":"+str(result[1].decode('utf8')))        
     self._log("Woke up")
Exemple #10
0
    def prepareFilmPage(self):
        style = '<style>body { float:left;} div {white-space: nowrap;padding:2px;margin:0px;font-family: Helvetica, Arial, sans-serif;font-size:0.85em;} .evenrow {background-color: #F8E0D7;} .oddrow {background-color: #F8EEEE;} .back {float:right}</style>'
        htmlStart = '<!DOCTYPE html><html><head><meta content="text/html; charset=UTF-8">' + style + '<title>Recorded Films</title><body>'
        htmlend = '--- End ---</body></html>'
        htmlBack = '<div class= back><a href="./Log.html">Back to Log</a></div>'
        srcFile = self._config.getLoggingPath()
        srcFile = OSTools.ensureFile(srcFile, "Filmlist.txt")

        destFile = self._config.getFilePath(self._config.getWebPath(),
                                            "Films.html")
        with codecs.open(srcFile, 'r', encoding="utf-8") as logFile:
            logLines = logFile.readlines()

        isEven = False
        with open(destFile, 'w+') as htmlFile:
            htmlFile.write(htmlStart)
            htmlFile.write("<b> The film list</b>")
            htmlFile.write(htmlBack)
            for line in logLines:
                if isEven:
                    divid = "evenrow"
                else:
                    divid = "oddrow"
                hack = self.utf8ToHTMLUmlauts(line)
                htmlFile.write('<div class="' + divid + '">' + hack + "</div>")
                isEven = not isEven
            htmlFile.write(htmlend)
 def __linkLogging(self):
     # ../../../VideoRecorder/src/log/
     # NO! That is where the command shell sits: currentPath=os.getcwd()
     destFile = self._config.getFilePath(self._config.getWebPath(), "Log.txt")
     srcFile = self._config.getLoggingPath();
     srcFile = OSTools.ensureFile(srcFile, "dvb_suspend.log")
     self._config.logInfo("Linking file:" + srcFile)
     if not os.path.lexists(destFile):
         os.symlink(srcFile, destFile)
 def _secondsUntilNextRun(self,startTime,prerunSeconds):
     now = datetime.now()
     secondsUntilStart = OSTools.getDifferenceInSeconds(startTime, now)
     secondsToSleep = secondsUntilStart - prerunSeconds #wake up a minute+ before
     if secondsToSleep < prerunSeconds:
         self._log("Next run in less than %s seconds"%(str(secondsUntilStart))) #sleep until time is ready.... no hibernate
         if secondsUntilStart > 0:
             self._log("Waiting to launch...."+str(secondsUntilStart))
             xtime.sleep(secondsUntilStart)
         return 0
     return secondsToSleep
 def _getDaysSinceLastEPGUpdate(self):
     path = self._config.getEPGTimestampPath()
     if OSTools.fileExists(path):
         with open(path, 'r') as aFile:
             currentDate=aFile.read()
         try:
             checkDate = datetime.strptime(currentDate,self.EPG_TS_Template)
             delta = datetime.now()-checkDate
             return delta.days
         except ValueError:
             self._log("Error reading EPG Timestamp:"+str(currentDate))
     return -1
Exemple #14
0
def main(argv=None):
    if OSTools.checkIfInstanceRunning("DVBRecorder"):
        recorder = DVBRecorder()
        recorder.persistEPGData()
        ##TODO: Store config data
        #        if recorder.configuration.STATE_USE_ENERGY_SAVER:
        #            path = recorder.configuration.HomeDir+"/EnergySaver.py"
        #            runEnergySaver(path,recorder)
        recorder.configuration.logInfo("Exit")
        recorder.configuration.logClose()

    print("Goodbye")
    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()
 def _monitorCurrentRecording(self,recProcess,recordingJob):
     done = False
     #this is testing:
     emergencyCount=0;
     
     jobID=recordingJob.getEPGInfo().getJobID()
     isRecurrentWriteError=False
     recPath = self._config.getRecordingPath()
     videoSize=OSTools.getDirectorySize(recPath)
     xtime.sleep(self.HEARTBEAT)
     self._log("Monitoring JOB "+jobID)
     while not done:
         result = recProcess.poll()
         isAlive = result is None
         if isAlive:
             currentSize = OSTools.getDirectorySize(recPath)
             delta = currentSize - videoSize
             print(("JOB "+jobID+" - bytes written:"+str(delta))) #live sign- not logging
             videoSize = currentSize
             if delta == 0:
                 self._log("JOB "+jobID+" does not write any data")
                 if isRecurrentWriteError:
                     done=True
                     self._log("Terminating Rec process, preventing reschedule.. ")
                     recProcess.terminate()
                     self.__handleProcessTermination(recProcess)
                 isRecurrentWriteError=True #only on retry permitted
         else:
             self._log("Quit JOB "+jobID)
             self.__handleProcessTermination(recProcess)
             done=True
             
         if not done:
             #Ensure that an adjacent job can follow - decrease the wait time
             gludu=recordingJob.getGluedDurance()
             endtime = OSTools.addToDateTime(recordingJob.getExecutionTime(),gludu)
             delta = max(10,OSTools.getDifferenceInSeconds(endtime,datetime.now()))
             sleepTime = min(self.HEARTBEAT,delta)
             if sleepTime != self.HEARTBEAT:
                 emergencyCount+=1;
                 endTimeString=endtime.strftime("%H:%M.%S")
                 startTimeString = recordingJob.getExecutionTime().strftime("%H:%M.%S")
                 self._log("Stopping in seconds: %d (Info Start: %s expected end: %s with dur %d)"%(sleepTime,startTimeString,endTimeString,gludu))#log only the fragments
                 if emergencyCount > 10:
                     self._log("REC Q error- force process termination")
                     recProcess.terminate()
                     self.__handleProcessTermination(recProcess)
                     done=True
             xtime.sleep(sleepTime)
             
     self._log("JOB "+jobID+" is done")
     OSTools.syncFiles()
Exemple #17
0
    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()
Exemple #18
0
    def prepareLogFile(self, lineStart, lineCount):
        #read the log file, prepare it and put it into the log file text?
        self.log("Getting Log request")

        srcFile = self._config.getLoggingPath()
        srcFile = OSTools.ensureFile(srcFile, "dvb_suspend.log")
        destFile = self._config.getFilePath(self._config.getWebPath(),
                                            "Log.html")
        style = '<style>body { float:left;} div {white-space: nowrap;padding:2px;margin:0px;font-family: Helvetica, Arial, sans-serif;font-size:0.85em;} .evenrow {background-color: #F8E0D7;} .oddrow {background-color: #F8EEEE;}</style>'

        htmlStart = '<!DOCTYPE html><html><head><meta content="text/html; charset=UTF-8">' + style + '<title>Micro Recorder Log</title><body>'
        htmlend = '--- End ---</body></html>'
        htmlmore = '<a href="./Log.html?NXT">Log more?</a></body></html>'
        htmlFilms = '<a href="./Films.html">Show Films</a>'

        with codecs.open(srcFile, 'r', encoding='utf-8') as logFile:
            logLines = logFile.readlines()

        startIndex = len(logLines)
        reqLines = lineStart + lineCount
        reqEnd = max(0, startIndex - reqLines)
        print(("start:", startIndex, " to:", reqEnd))
        #aRange=reversed(range(reqEnd,startIndex))

        isEven = False
        with open(destFile, 'w+') as htmlFile:
            htmlFile.write(htmlStart)
            htmlFile.write("<b> The Logs (newest first) </b>")
            htmlFile.write(htmlFilms)
            #for line in logLines:
            lineIndex = startIndex
            while lineIndex > reqEnd:
                lineIndex -= 1
                line = logLines[lineIndex]
                if isEven:
                    divid = "evenrow"
                else:
                    divid = "oddrow"
                htmlFile.write('<div class="' + divid + '">' + line + "</div>")
                isEven = not isEven
            if reqEnd == 0:
                htmlFile.write(htmlend)
            else:
                htmlFile.write(htmlmore)
    def prepareLogFile(self,lineStart,lineCount):
        #read the log file, prepare it and put it into the log file text?
        self.log("Getting Log request")
        
        srcFile = self._config.getLoggingPath();
        srcFile = OSTools.ensureFile(srcFile, "dvb_suspend.log")
        destFile = self._config.getFilePath(self._config.getWebPath(), "Log.html")
        style ='<style>body { float:left;} div {white-space: nowrap;padding:2px;margin:0px;font-family: Helvetica, Arial, sans-serif;font-size:0.85em;} .evenrow {background-color: #F8E0D7;} .oddrow {background-color: #F8EEEE;}</style>'  

        htmlStart = '<!DOCTYPE html><html><head><meta content="text/html; charset=UTF-8">'+style+'<title>Micro Recorder Log</title><body>'
        htmlend = '--- End ---</body></html>'
        htmlmore = '<a href="./Log.html?NXT">Log more?</a></body></html>'

        with codecs.open(srcFile, 'r',"utf-8") as logFile:
            logLines = logFile.readlines()
 
       
        startIndex = len(logLines)
        reqLines = lineStart+lineCount
        reqEnd = max(0,startIndex-reqLines)
        print "start:",startIndex," to:",reqEnd
        #aRange=reversed(range(reqEnd,startIndex))   
 
        isEven=False
        with open(destFile, 'w+') as htmlFile:
            htmlFile.write(htmlStart)
            htmlFile.write("<b> The Logs (newest first) </b>")  
            #for line in logLines:
            lineIndex = startIndex
            while lineIndex > reqEnd:
                lineIndex-=1;
                line=logLines[lineIndex]
                asccode = line.encode('ascii', 'xmlcharrefreplace') #makes utf8 readable!
                if isEven:
                    divid="evenrow"
                else:
                    divid="oddrow"
                htmlFile.write('<div class="'+divid+'">'+asccode+"</div>")
                isEven=not isEven
            if reqEnd==0:
                htmlFile.write(htmlend)
            else:
                htmlFile.write(htmlmore)      
 def adddirgui(self):
     self.addfile(OSTools.browse4dir(self, "Open dir to add"))
 def handleNoJobs(self):
     if self._daemon.isServerPolicyChangeRequested():
         return;
     self._daemon._stopQueue() #make sure in case that hibernation fails and logging is still active
     OSTools.saveEnergy(OSTools.RTC_HIBERNATE)
     self._daemon._exit()
 def _isPolicyChangeRequested(self,markerFile):
     if OSTools.fileExists(markerFile):
         OSTools.removeFile(markerFile)
         return True
     return False
    def addfilegui(self, path=None, prefonly=False):
        guiparam = {}
        guiparam['path'] = StringVar()
        guiparam['device'] = IntVar()
        guiparam['destchoice'] = IntVar()
        guiparam['dest'] = StringVar()
        guiparam['destfinal'] = StringVar()
        guiparam['returnval'] = BooleanVar(False)
        guiparam['taglan'] = StringVar()
        guiparam['sublan'] = StringVar()
        guiparam['movieset'] = StringVar()

        GP = self.getglobalparamcbk()

        if path != None:
            guiparam['path'].set(path)

        guiparam['destchoice'].set(1)
        if GP['DESTDIR'] != "":
            guiparam['dest'].set(GP['DESTDIR'])
            if GP['FINALDIR'] != "":
                guiparam['destfinal'].set(GP['FINALDIR'])
                guiparam['destchoice'].set(3)
            else:
                guiparam['destchoice'].set(2)
        guiparam['device'].set(GP['DEVICECONFS'])
        guiparam['taglan'].set(GP['TAGLAN'])
        guiparam['sublan'].set(GP['SUBLAN'])
        guiparam['movieset'].set(GP['MOVIESET'])

        filep = Toplevel(self, padx=10, pady=10)
        filep.protocol("WM_DELETE_WINDOW", "pass")

        if not prefonly:
            f = Frame(filep, border=1, relief=SUNKEN, padx=2, pady=2)
            f.pack(anchor=W, fill=BOTH)
            f.grid_columnconfigure(0, weight=1)

            Label(f, text="Select the file to transcode:").grid(row=0, column=0)
            Entry(f, textvariable=guiparam['path']).grid(row=1, column=0, sticky=W + E)
            Button(f, text="Browse", command=lambda: OSTools.browse4filename(filep, "Open file to transcode", [
                ("Video files", ("*avi", "*.mkv", "*.mp4")), ("All files", "*.*")], guiparam['path'])).grid(row=1,
                                                                                                            column=1,
                                                                                                            sticky=W + E)

        Label(filep, text="Encoding paramaters").pack(anchor=W)
        f = Frame(filep, border=1, relief=SUNKEN, padx=2, pady=2)
        f.pack(anchor=W, fill=BOTH)
        Label(f, text="Select the device to transcode to:").pack(anchor=W)
        for i in range(len(self.devicelabels)):
            Radiobutton(f, text=self.devicelabels[i], variable=guiparam['device'], value=i).pack(anchor=W)
        f = Frame(filep, border=1, relief=SUNKEN, padx=2, pady=2)
        f.pack(anchor=W, fill=BOTH)
        f.grid_columnconfigure(1, weight=1)
        f.grid_columnconfigure(3, weight=1)
        Label(f, text="Select output dir (Please read the manual):").grid(row=0, column=0)
        Radiobutton(f, text="Same dir as source", variable=guiparam['destchoice'], value=1).grid(row=1, column=0,
                                                                                                 sticky=W)
        Radiobutton(f, text="To this dir", variable=guiparam['destchoice'], value=2).grid(row=2, column=0, sticky=W)
        Radiobutton(f, text="First to one dir and then to another", variable=guiparam['destchoice'], value=3).grid(
            row=3, column=0, sticky=W)
        Entry(f, textvariable=guiparam['dest']).grid(row=2, column=1, sticky=W + E)
        Entry(f, textvariable=guiparam['dest']).grid(row=3, column=1, sticky=W + E)
        Entry(f, textvariable=guiparam['destfinal']).grid(row=3, column=3, sticky=W + E)
        Button(f, text="Browse", command=lambda: OSTools.browse4dir(filep, "Select directory", guiparam['dest'])).grid(
            row=2, column=2, sticky=W + E)
        Button(f, text="Browse", command=lambda: OSTools.browse4dir(filep, "Select directory", guiparam['dest'])).grid(
            row=3, column=2, sticky=W + E)
        Button(f, text="Browse",
               command=lambda: OSTools.browse4dir(filep, "Select directory", guiparam['destfinal'])).grid(row=3,
                                                                                                          column=4,
                                                                                                          sticky=W + E)

        f = Frame(filep, border=1, relief=SUNKEN, padx=2, pady=2)
        f.pack(anchor=W, fill=BOTH)
        f.grid_columnconfigure(1, weight=1)
        f.grid_columnconfigure(3, weight=1)
        Label(f, text="Tag langugage ID (en for english, fr for french, etc...):").grid(row=0, column=0)
        Entry(f, textvariable=guiparam['taglan']).grid(row=0, column=1, sticky=W + E)

        f = Frame(filep, border=1, relief=SUNKEN, padx=2, pady=2)
        f.pack(anchor=W, fill=BOTH)
        f.grid_columnconfigure(1, weight=1)
        f.grid_columnconfigure(3, weight=1)

        Label(f, text="XBMC .nfo prefs").grid(row=1, column=0)
        Label(f,
              text="Subtitle download langugage ID (empty for no download, eng for english, fre for french, etc...):").grid(
            row=2, column=0)
        Entry(f, textvariable=guiparam['sublan']).grid(row=2, column=1, sticky=W + E)
        Label(f, text="Movie set (empty for None):").grid(row=3, column=0)
        Entry(f, textvariable=guiparam['movieset']).grid(row=3, column=1, sticky=W + E)

        f = Frame(filep, padx=2, pady=2)
        f.pack()
        Button(f, text="Go", command=lambda: guiparam['returnval'].set(True), width=20).grid(row=0, column=0, sticky=W)
        Button(f, text="Cancel", command=lambda: guiparam['returnval'].set(False), width=20).grid(row=0, column=1,
                                                                                                  sticky=E)

        self.wait_variable(guiparam['returnval'])
        filep.destroy()

        return guiparam
    def addfilegui(self, path=None, prefonly=False):
        guiparam = {}
        guiparam['path'] = StringVar()
        guiparam['device'] = IntVar()
        guiparam['destchoice'] = IntVar()
        guiparam['dest'] = StringVar()
        guiparam['destfinal'] = StringVar()
        guiparam['returnval'] = BooleanVar(False)
        guiparam['taglan'] = StringVar()
        guiparam['sublan'] = StringVar()
        guiparam['movieset'] = StringVar()

        GP = self.getglobalparamcbk()

        if path != None:
            guiparam['path'].set(path)

        guiparam['destchoice'].set(1)
        if GP['DESTDIR'] != "":
            guiparam['dest'].set(GP['DESTDIR'])
            if GP['FINALDIR'] != "":
                guiparam['destfinal'].set(GP['FINALDIR'])
                guiparam['destchoice'].set(3)
            else:
                guiparam['destchoice'].set(2)
        guiparam['device'].set(GP['DEVICECONFS'])
        guiparam['taglan'].set(GP['TAGLAN'])
        guiparam['sublan'].set(GP['SUBLAN'])
        guiparam['movieset'].set(GP['MOVIESET'])

        filep = Toplevel(self, padx=10, pady=10)
        filep.protocol("WM_DELETE_WINDOW", "pass")

        if not prefonly:
            f = Frame(filep, border=1, relief=SUNKEN, padx=2, pady=2)
            f.pack(anchor=W, fill=BOTH)
            f.grid_columnconfigure(0, weight=1)

            Label(f, text="Select the file to transcode:").grid(row=0,
                                                                column=0)
            Entry(f, textvariable=guiparam['path']).grid(row=1,
                                                         column=0,
                                                         sticky=W + E)
            Button(f,
                   text="Browse",
                   command=lambda: OSTools.browse4filename(
                       filep, "Open file to transcode", [
                           ("Video files", ("*avi", "*.mkv", "*.mp4")),
                           ("All files", "*.*")
                       ], guiparam['path'])).grid(row=1,
                                                  column=1,
                                                  sticky=W + E)

        Label(filep, text="Encoding paramaters").pack(anchor=W)
        f = Frame(filep, border=1, relief=SUNKEN, padx=2, pady=2)
        f.pack(anchor=W, fill=BOTH)
        Label(f, text="Select the device to transcode to:").pack(anchor=W)
        for i in range(len(self.devicelabels)):
            Radiobutton(f,
                        text=self.devicelabels[i],
                        variable=guiparam['device'],
                        value=i).pack(anchor=W)
        f = Frame(filep, border=1, relief=SUNKEN, padx=2, pady=2)
        f.pack(anchor=W, fill=BOTH)
        f.grid_columnconfigure(1, weight=1)
        f.grid_columnconfigure(3, weight=1)
        Label(f, text="Select output dir (Please read the manual):").grid(
            row=0, column=0)
        Radiobutton(f,
                    text="Same dir as source",
                    variable=guiparam['destchoice'],
                    value=1).grid(row=1, column=0, sticky=W)
        Radiobutton(f,
                    text="To this dir",
                    variable=guiparam['destchoice'],
                    value=2).grid(row=2, column=0, sticky=W)
        Radiobutton(f,
                    text="First to one dir and then to another",
                    variable=guiparam['destchoice'],
                    value=3).grid(row=3, column=0, sticky=W)
        Entry(f, textvariable=guiparam['dest']).grid(row=2,
                                                     column=1,
                                                     sticky=W + E)
        Entry(f, textvariable=guiparam['dest']).grid(row=3,
                                                     column=1,
                                                     sticky=W + E)
        Entry(f, textvariable=guiparam['destfinal']).grid(row=3,
                                                          column=3,
                                                          sticky=W + E)
        Button(f,
               text="Browse",
               command=lambda: OSTools.browse4dir(filep, "Select directory",
                                                  guiparam['dest'])).grid(
                                                      row=2,
                                                      column=2,
                                                      sticky=W + E)
        Button(f,
               text="Browse",
               command=lambda: OSTools.browse4dir(filep, "Select directory",
                                                  guiparam['dest'])).grid(
                                                      row=3,
                                                      column=2,
                                                      sticky=W + E)
        Button(f,
               text="Browse",
               command=lambda: OSTools.browse4dir(filep, "Select directory",
                                                  guiparam['destfinal'])).grid(
                                                      row=3,
                                                      column=4,
                                                      sticky=W + E)

        f = Frame(filep, border=1, relief=SUNKEN, padx=2, pady=2)
        f.pack(anchor=W, fill=BOTH)
        f.grid_columnconfigure(1, weight=1)
        f.grid_columnconfigure(3, weight=1)
        Label(f,
              text="Tag langugage ID (en for english, fr for french, etc...):"
              ).grid(row=0, column=0)
        Entry(f, textvariable=guiparam['taglan']).grid(row=0,
                                                       column=1,
                                                       sticky=W + E)

        f = Frame(filep, border=1, relief=SUNKEN, padx=2, pady=2)
        f.pack(anchor=W, fill=BOTH)
        f.grid_columnconfigure(1, weight=1)
        f.grid_columnconfigure(3, weight=1)

        Label(f, text="XBMC .nfo prefs").grid(row=1, column=0)
        Label(
            f,
            text=
            "Subtitle download langugage ID (empty for no download, eng for english, fre for french, etc...):"
        ).grid(row=2, column=0)
        Entry(f, textvariable=guiparam['sublan']).grid(row=2,
                                                       column=1,
                                                       sticky=W + E)
        Label(f, text="Movie set (empty for None):").grid(row=3, column=0)
        Entry(f, textvariable=guiparam['movieset']).grid(row=3,
                                                         column=1,
                                                         sticky=W + E)

        f = Frame(filep, padx=2, pady=2)
        f.pack()
        Button(f,
               text="Go",
               command=lambda: guiparam['returnval'].set(True),
               width=20).grid(row=0, column=0, sticky=W)
        Button(f,
               text="Cancel",
               command=lambda: guiparam['returnval'].set(False),
               width=20).grid(row=0, column=1, sticky=E)

        self.wait_variable(guiparam['returnval'])
        filep.destroy()

        return guiparam
 def getEndTime(self):
     return OSTools.addToDateTime(self._execTime, self._duranceInSeconds)
 def __setupDirectories(self):
     OSTools.ensureDirectory(self.DataDir,self.LogPath)
     OSTools.ensureDirectory(self.DataDir,self.XMLPath)
 def isMaintenanceNeeded(self,recInfo):
     maintenanceDurance = 15*60;
     nextStart = OSTools.getDateTimeWithOffset(self.MAINT_DAY)
     maintEnd = OSTools.addToDateTime(nextStart, maintenanceDurance)
     scheduledStartTime = recInfo.getEPGInfo().getStartTime()
     return maintEnd <= scheduledStartTime
 def _isTimeLeftForEPGUpdate(self,nextStartTime):
     now = datetime.now()
     seconds = OSTools.getDifferenceInSeconds(nextStartTime, now)
     return seconds > self.HEARTBEAT*10
        print(("dispatched command::"+cmdText))
        self._config.logInfo("command sent: \n"+cmdText+" | scheduled at:"+timeString)
        #TODO: process still alive - even if done -- still syncing???
        return process

def main():

    argv = sys.argv
    if len(argv)==1:
        RecorderDaemon().run()
    else:
        cmd = argv[1]
        if "epg" in cmd.lower():
            RecorderDaemon().readEPGData()
            return 0;
        if "job" in cmd.lower():
            job = RecorderDaemon()._getNextJob()
            if job is None:
                print("No jobs pending")
            else:
                print(("Next Job @"+str(job.getExecutionTime())))
            return 0; 
        
        print("start daemon with no args.. Use 'getEpg' to read EPG or 'showJobs' for pending jobs")
        return 1;
if __name__ =="__main__":
    if OSTools.checkIfInstanceRunning("RecorderDaemon"):
        OSTools.changeWorkingDirectory(OSTools.getWorkingDirectory())
        sys.exit(main())
    else:
        print("Daemon already running...") 
 def readEPGData(self):
     path = self._config.getEPGTimestampPath() 
     if OSTools.fileExists(path):
         OSTools.removeFile(path)
     self._updateEPGData()
 def isMaintenanceNeeded(self,recInfo):
     maintenanceDurance = 15*60;
     nextStart = OSTools.getDateTimeWithOffset(self.MAINT_DAY)
     maintEnd = OSTools.addToDateTime(nextStart, maintenanceDurance)
     scheduledStartTime = recInfo.getEPGInfo().getStartTime()
     return maintEnd <= scheduledStartTime
    def openPrefs(self):
        guiparam = {}
        guiparam['destdir'] = StringVar()
        guiparam['localroot'] = StringVar()
        guiparam['remoteroot'] = StringVar()
        guiparam['taglan'] = StringVar()
        guiparam['sublan'] = StringVar()
        guiparam['movieset'] = StringVar()
        guiparam['force'] = IntVar()
        guiparam['remoterelat'] = IntVar()
        guiparam['moviefilter'] = StringVar()
        guiparam['returnval'] = BooleanVar(False)

        GP = self.mediaPrez.GetGlobalParam()

        guiparam['destdir'].set(GP['DESTDIR'])
        guiparam['localroot'].set(GP['LOCALROOT'])
        guiparam['remoteroot'].set(GP['REMOTEROOT'])
        guiparam['taglan'].set(GP['TAGLAN'])
        guiparam['sublan'].set(GP['SUBLAN'])
        guiparam['movieset'].set(GP['MOVIESET'])
        guiparam['force'].set(GP['FORCERELOAD'])
        guiparam['remoterelat'].set(GP['REMOTERELAT'])
        guiparam['moviefilter'].set(GP['MOVIEFILTER'])

        filep = Toplevel(self, padx=10, pady=10)
        filep.protocol("WM_DELETE_WINDOW", "pass")

        Label(filep, text="Options").pack(anchor=W)
        f = Frame(filep, border=1, relief=SUNKEN, padx=2, pady=2)
        f.pack(anchor=W, fill=BOTH, expand=1)
        # f.grid_columnconfigure(0,weight=1)
        f.grid_columnconfigure(1, weight=1)
        # f.grid_columnconfigure(2,weight=1)
        rowi = 0
        Label(f, text="Select output dir:").grid(row=rowi, column=0)
        Entry(f, textvariable=guiparam['destdir']).grid(row=rowi, column=1, sticky=W + E)
        Button(f, text="Browse",
               command=lambda: OSTools.browse4dir(filep, "Destination directory", guiparam['destdir'])).grid(row=rowi,
                                                                                                             column=2,
                                                                                                             sticky=W + E)
        rowi = rowi + 1
        Label(f, text="Local root dir:").grid(row=rowi, column=0)
        Entry(f, textvariable=guiparam['localroot']).grid(row=rowi, column=1, sticky=W + E)
        Button(f, text="Browse",
               command=lambda: OSTools.browse4dir(filep, "Local root directory", guiparam['localroot'])).grid(row=rowi,
                                                                                                              column=2,
                                                                                                              sticky=W + E)
        rowi = rowi + 1
        Label(f, text="Remote root dir:").grid(row=rowi, column=0)
        Entry(f, textvariable=guiparam['remoteroot']).grid(row=rowi, column=1, sticky=W + E)
        Button(f, text="Browse",
               command=lambda: OSTools.browse4dir(filep, "Remote root directory", guiparam['remoteroot'])).grid(
            row=rowi, column=2, sticky=W + E)
        rowi = rowi + 1
        Checkbutton(f, text="Remote dir is relative", variable=guiparam['remoterelat']).grid(row=rowi, column=0,
                                                                                             sticky=W + E)
        Button(f, text="Remote is PCH/Popcorn",
               command=lambda: guiparam['remoteroot'].set("file:///opt/sybhttpd/localhost.drives/HARD_DISK/")).grid(
            row=rowi, column=2, sticky=W + E)

        rowi = 0
        f = Frame(filep, border=1, relief=SUNKEN, padx=2, pady=2)
        f.pack(anchor=W, fill=BOTH, expand=1)
        # f.grid_columnconfigure(0,weight=1)
        f.grid_columnconfigure(1, weight=1)
        Label(f, text="Filter for videos file (.avi,.mkv ...):").grid(row=rowi, column=0)
        Entry(f, textvariable=guiparam['moviefilter']).grid(row=rowi, column=1, sticky=W + E)

        rowi = rowi + 1
        Label(f, text="Tag langugage ID (en for english, fr for french, etc...):").grid(row=rowi, column=0)
        Entry(f, textvariable=guiparam['taglan']).grid(row=rowi, column=1, sticky=W + E)
        rowi = rowi + 1
        Checkbutton(f, text="Force reload from the web", variable=guiparam['force']).grid(row=rowi, column=1,
                                                                                          sticky=W + E)
        f.pack(anchor=W, fill=BOTH, expand=1)

        rowi = 0
        f = Frame(filep, border=1, relief=SUNKEN, padx=2, pady=2)
        f.pack(anchor=W, fill=BOTH, expand=1)
        # f.grid_columnconfigure(0,weight=1)
        f.grid_columnconfigure(1, weight=1)
        Label(f, text="XBMC .nfo prefs:").grid(row=rowi, column=0)

        rowi = rowi + 1
        Label(f, text="Subtitles langugage ID (empty for none, fre for french, eng for english, etc...):").grid(
            row=rowi, column=0)
        Entry(f, textvariable=guiparam['sublan']).grid(row=rowi, column=1, sticky=W + E)
        rowi = rowi + 1
        Label(f, text="Movie set (empty for None):").grid(row=rowi, column=0)
        Entry(f, textvariable=guiparam['movieset']).grid(row=rowi, column=1, sticky=W + E)

        f.pack(anchor=W, fill=BOTH, expand=1)

        f = Frame(filep, padx=2, pady=2)
        f.pack()
        Button(f, text="Go", command=lambda: guiparam['returnval'].set(True), width=20).grid(row=0, column=0, sticky=W)
        Button(f, text="Cancel", command=lambda: guiparam['returnval'].set(False), width=20).grid(row=0, column=1,
                                                                                                  sticky=E)

        self.wait_variable(guiparam['returnval'])
        filep.destroy()

        if guiparam['returnval'].get():
            GP['DESTDIR'] = guiparam['destdir'].get()
            GP['LOCALROOT'] = guiparam['localroot'].get()
            GP['REMOTEROOT'] = guiparam['remoteroot'].get()
            GP['TAGLAN'] = guiparam['taglan'].get()
            GP['SUBLAN'] = guiparam['sublan'].get()
            GP['MOVIESET'] = guiparam['movieset'].get()
            GP['FORCERELOAD'] = guiparam['force'].get()
            GP['REMOTERELAT'] = guiparam['remoterelat'].get()
            GP['MOVIEFILTER'] = guiparam['moviefilter'].get()
            self.updateMovieFilter(GP['MOVIEFILTER'])
            self.mediaPrez.SetGlobalParam(GP)
 def __setupDirectories(self):
     OSTools.ensureDirectory(self.LogDir, self.LogPath)
     OSTools.ensureDirectory(self.DataDir, self.XMLPath)
 def addbtn(self):
     self.addfile(OSTools.browse4filename(self, "Open file to add",
                                          [("Video files", ("*avi", "*.mkv", "*.mp4")), ("All files", "*.*")]))
     return False
 def getEndTime(self):
     return OSTools.addToDateTime(self._execTime, self._duranceInSeconds)