#!/usr/bin/env python3
# this program let markad run on a video directory to build all missing markad files
# see markad_video -h and markad_video.conf for more information

import sys
import os
import signal
import subprocess
import fnmatch
import argparse
import configparser
import getpass
import pwd
import grp
import logging
import logging.handlers
import time
import datetime
import shutil
import atexit
import pathlib
import filecmp
import glob



def signal_handler(sig, frame):
    log.esyslog('you pressed Ctrl+C!')

    curPath.KillMarkad()
    if curPath.root is not None:
        try:
            os.remove(curPath.root+"/marks")
        except FileNotFoundError:
            pass

        try:
            os.remove(curPath.root+"/markad.pid")
        except FileNotFoundError:
            pass
    sys.exit(1)


class PidFile:
    def __init__(self):
        self.pidFile = "/tmp/markad_videos.pid"
        self.pid = os.getpid()

    def WritePidFile(self):
        f = open(self.pidFile, 'w')
        f.write(str(self.pid))
        f.close()

    def DeletePidFile(self):
        os.remove(self.pidFile)

    def CheckPidFile(self):
        if os.path.exists(self.pidFile):
            log.esyslog("markad_video is running, do not start twice")
            return(True)
        else: return(False)


class Log:
    def __init__(self):
        self.syslog = logging.getLogger(__name__)
        self.syslog.setLevel(logging.DEBUG)
        handler = logging.handlers.SysLogHandler(address = '/dev/log')
        formatter = logging.Formatter('%(module)s: %(message)s')
        handler.setFormatter(formatter)
        self.syslog.addHandler(handler)

    def esyslog(self, message):
        if config.loglevel >= 1:
            self.syslog.error(message)
            print("ERROR:",message)

    def isyslog(self, message):
        if config.loglevel >= 2:
            self.syslog.info(message)
            if config.verbose:
                print("INFO:",message)

    def dsyslog(self, message):
        if config.loglevel >= 3:
            self.syslog.debug(message)
            if config.verbose:
                print("DEBUG:",message)

    def tsyslog(self, message):
        if config.loglevel >= 4:
            self.syslog.trace(message)
            if config.verbose:
                print("TRACE:",message)


class Config:
    def __init__(self):  # define the default configuration
        self.verbose = False
        self.config = "/etc/markad_videos.conf"
        self.path = "/media/Video/VDR"
        self.bindir = "/usr/bin"
        self.user = "vdr"
        self.group = "vdr"
        self.minfree = 0
        self.maxrecordings = 1000
        self.backupmarks = False
        self.backuplogo = None
        self.logocachedir = "/var/lib/markad"
        self.nice = 19
        self.loglevel = 1
        self.checkOnly = False
        self.vps = False
        self.pts = False

        self.markad_loglevel = 1
        self.autologo = 2
        self.fulldecode = False
        self.smartencode = False
        self.fullencode = None
        self.hwaccel = None
        self.threads = 1
        self.log2rec=False
        self.vps=False
        self.cut=False
        self.ac3reencode=False

        self.mirror_path = None
        self.mirror_movies = "movies"
        self.mirror_series = "series"
        self.mirror_update = "/media/Video/VDR"

    def ConfigFile(self):
        if not os.path.exists(self.config):
            log.isyslog("configfile /etc/markad_videos.conf does not exists")
            return()
        config = configparser.ConfigParser()
        config.read(self.config)

        try:
            ret = config.getboolean('GLOBAL', 'verbose')
        except (configparser.NoSectionError, configparser.NoOptionError):
            ret = False
        if ret: self.verbose = ret

        try:
            ret = config.get('GLOBAL', 'path')
        except (configparser.NoSectionError, configparser.NoOptionError):
            ret = None
        if ret is not None: self.path = ret

        try:
            ret = config.getint('GLOBAL', 'minfree')
        except (configparser.NoSectionError, configparser.NoOptionError):
            ret = None
        if ret is not None: self.minfree = ret

        try:
            ret = config.getint('GLOBAL', 'nice')
        except (configparser.NoSectionError, configparser.NoOptionError):
            ret = None
        if ret is not None: self.nice = ret

        try:
            ret = config.getboolean('GLOBAL', 'backupmarks')
        except (configparser.NoSectionError, configparser.NoOptionError):
            ret = False
        if ret: self.backupmarks = ret

        try:
            ret = config.get('GLOBAL', 'backuplogo')
        except (configparser.NoSectionError, configparser.NoOptionError):
            ret = None
        if ret: self.backuplogo = ret

        try:
            ret = config.getint('GLOBAL', 'loglevel')
        except (configparser.NoSectionError, configparser.NoOptionError):
            ret = None
        if ret is not None: self.loglevel = ret

        try:
            ret = config.getint('MARKAD', 'loglevel')
        except (configparser.NoSectionError, configparser.NoOptionError):
            ret = None
        if ret is not None: self.markad_loglevel = ret

        try:
            ret = config.get('MARKAD', 'bindir')
        except (configparser.NoSectionError, configparser.NoOptionError):
            ret = None
        if ret is not None: self.bindir = ret

        try:
            ret = config.get('MARKAD', 'user')
        except (configparser.NoSectionError, configparser.NoOptionError):
            ret = None
        if ret is not None: self.user = ret

        try:
            ret = config.get('MARKAD', 'group')
        except (configparser.NoSectionError, configparser.NoOptionError):
            ret = None
        if ret is not None: self.group = ret

        try:
            ret = config.get('MARKAD', 'logocachedir')
        except (configparser.NoSectionError, configparser.NoOptionError):
            ret = None
        if ret is not None: self.logocachedir = ret

        try:
            ret = config.getint('MARKAD', 'autologo')
        except (configparser.NoSectionError, configparser.NoOptionError):
            ret = None
        if ret is not None: self.autologo = ret

        try:
            ret = config.getboolean('MARKAD', 'fulldecode')
        except (configparser.NoSectionError, configparser.NoOptionError):
            ret = False
        if ret: self.fulldecode = ret

        try:
            ret = config.getboolean('MARKAD', 'smartencode')
        except (configparser.NoSectionError, configparser.NoOptionError):
            ret = False
        if ret: self.smartencode = ret

        try:
            ret = config.getint('MARKAD', 'threads')
        except (configparser.NoSectionError, configparser.NoOptionError):
            ret = None
        if ret is not None: self.threads = ret

        try:
            ret = config.getboolean('MARKAD', 'log2rec')
        except (configparser.NoSectionError, configparser.NoOptionError):
            ret = False
        if ret: self.log2rec = ret

        try:
            ret = config.getboolean('MARKAD', 'vps')
        except (configparser.NoSectionError, configparser.NoOptionError):
            ret = False
        if ret: self.vps = ret


        try:
            ret = config.getboolean('MARKAD', 'cut')
        except (configparser.NoSectionError, configparser.NoOptionError):
            ret = False
        if ret: self.cut = ret

        try:
            ret = config.getboolean('MARKAD', 'ac3reencode')
        except (configparser.NoSectionError, configparser.NoOptionError):
            ret = False
        if ret: self.ac3reencode = ret

        try:
            ret = config.get('MIRROR', 'path')
        except (configparser.NoSectionError, configparser.NoOptionError):
            ret = None
        if ret is not None: self.mirror_path = ret

        try:
            ret = config.get('MIRROR', 'movies')
        except (configparser.NoSectionError, configparser.NoOptionError):
            ret = None
        if ret is not None: self.mirror_movies = ret

        try:
            ret = config.get('MIRROR', 'series')
        except (configparser.NoSectionError, configparser.NoOptionError):
            ret = None
        if ret is not None: self.mirror_series = ret

        try:
            ret = config.get('MIRROR', 'update')
        except (configparser.NoSectionError, configparser.NoOptionError):
            ret = None
        if ret is not None: self.mirror_update = ret

    def Arguments(self):
        args = parser.parse_args()
        if args.verbose: self.verbose = args.verbose
        if args.path is not None: self.path = args.path
        if args.bindir is not None: self.bindir = args.bindir
        if args.logocachedir is not None: self.logocachedir = args.logocachedir
        if args.user is not None: self.user = args.user
        if args.group is not None: self.group = args.group
        if args.loglevel is not None: self.loglevel = args.loglevel
        if args.markad_loglevel is not None: self.markad_loglevel = args.markad_loglevel
        if args.nice is not None: self.nice = args.nice
        if args.minfree is not None: self.minfree = args.minfree
        if args.maxrecordings is not None: self.maxrecordings = args.maxrecordings
        if args.autologo is not None: self.autologo = args.autologo
        if args.threads is not None: self.threads = args.threads
        if args.log2rec: self.log2rec = args.log2rec
        if args.fulldecode: self.fulldecode = args.fulldecode
        if args.smartencode: self.smartencode = args.smartencode
        if args.fullencode: self.fullencode = args.fullencode
        if args.hwaccel: self.hwaccel = args.hwaccel
        if args.cut: self.cut = args.cut
        if args.checkOnly: self.checkOnly = args.checkOnly
        if args.vps: self.vps = args.vps
        if args.pts: self.pts = args.pts
        if args.ac3reencode: self.ac3reencode = args.ac3reencode
        if args.backupmarks: self.backupmarks = args.backupmarks
        if args.backuplogo: self.backuplogo = args.backuplogo
        if args.mirror_path is not None: self.mirror_path = args.mirror_path


class CompareMarks:
    def __init__(self, fileName1, fileName2):
        self.fileName1 = fileName1
        self.fileName2 = fileName2
        self.rc = True

        file1 = open(self.fileName1, 'r')
        file2 = open(self.fileName2, 'r')

        while True:
           line1 = file1.readline()
           line2 = file2.readline()

           # if line is empty end of file is reached
           if not line1 and not line2:  # both file have same count of lines
               break

           if not line1 or not line2:   # one file has more lines
               self.rc = False
               break

           self.pos1 = line1.find(" (");
           self.pos2 = line1.find(")");

           # check VDR key packet number
           if self.pos1 < 0 or self.pos2 < 0:
               self.rc = False
               break
           self.frameNumer1 = line1[self.pos1 + 2:self.pos2]
           self.pos1 = line2.find(" (");
           self.pos2 = line2.find(")");
           if self.pos1 < 0 or self.pos2 < 0:
               self.rc = False
               break
           self.frameNumer2 = line2[self.pos1 + 2:self.pos2]
           if abs(int(self.frameNumer1) - int(self.frameNumer2)) > 50:
               self.rc = False
               break

           # check markad internal pasition
           self.pos1 = line1.find(") <");
           self.pos2 = line1.find(">");
           if self.pos1 > 0 and self.pos2 > 0:
               self.frameNumer1 = line1[self.pos1 + 1 + 2:self.pos2]
               self.pos1 = line2.find(") <");
               self.pos2 = line2.find(">");
               if self.pos1 > 0 and self.pos2 > 0:
                   self.frameNumer2 = line2[self.pos1 + 1 + 2:self.pos2]
                   if abs(int(self.frameNumer1) - int(self.frameNumer2)) > 10:
                       self.rc = False
                       break

        file1.close()
        file2.close()
    def __bool__(self): return self.rc


class CheckPath:
    def __init__(self, root, files):
        self.root = root
        self.files = files
        self.mirror_type = None
        self.mirror_name = None
        self.isRunning = False;

        if config.mirror_path is not None:
            log.tsyslog("get name to mirror video from "+self.root)
            if self.root.find("/"+config.mirror_movies+"/") > 0:
                self.mirror_type = config.mirror_movies
                (head, tail) = os.path.split(root)
                (head, self.mirror_name) = os.path.split(head)
                self.mirror_name = config.mirror_path + "/" + config.mirror_movies + "/" + self.mirror_name + ".ts"
            elif self.root.find("/"+config.mirror_series+"/") > 0:
                self.mirror_type = config.mirror_series
                (head, tail) = os.path.split(root)
                (head, episode) = os.path.split(head)
                (head, season) = os.path.split(head)
                (head, title) = os.path.split(head)
                if title == config.mirror_series:   # no season information
                    title = season
                    self.mirror_name = title + "/" + episode
                else:
                    season=season.replace("Staffel_","")
                    (episodeNr,episodeText) = episode.split("._",1)
                    self.mirror_name = title + "/s" + season + "e" + episodeNr + "-" + episodeText
                self.mirror_name = config.mirror_path + "/" + config.mirror_series + "/" + self.mirror_name + ".ts"
            else:
                log.esyslog("no valid type of video for mirroring found in path: "+self.root)
                return
            log.tsyslog("type of video mirror: " + self.mirror_type)
            log.dsyslog("video mirror file name: " + self.mirror_name)

    def CheckFreeSpace(self):
        if (self.root.find('TODO') != -1):
            return(False)
        total, used, free = shutil.disk_usage(self.root)
        freeGB = free // (2**30)
        if freeGB < config.minfree:
            log.isyslog("not enough disk space: "+str(freeGB)+" GB for "+self.root)
            return(False)
        return(True)


    def NeedMarks(self):
        isMarksNotFound = True
        isCutNotFound = True
        isVideoDir = False
        if (not config.cut):  # if not to cut do not search for cut ts file
            isCutNotFound = False
        isInfoFound = False
        isIndexFound = False
        isLogo = False
        hadLogo = False
        if self.root.find(".del") > 0:
            log.dsyslog("recording is deleted "+self.root)
            return(False)
        self.files.sort()
        fileCompareMarks = None
        fileCompareLogo = None
        for actFile in self.files:
            if not os.path.exists(root+"/"+actFile):
                log.isyslog("directory was deleted "+root);
                return(False)
            if actFile == ".timer": continue
            if actFile == "markad.log": continue
            if actFile == "-markad.log": continue  # ignore test log file
            if actFile == "resume": continue
            if fnmatch.fnmatch(actFile,'000??.ts'):
                isVideoDir = True
                continue
            if fnmatch.fnmatch(actFile,'*.ts'): # other ts file is the recording cut
                isCutNotFound = False
                continue
            if actFile == "info.epg2vdr": continue
            if actFile == "markad.vps": continue
            if actFile == "vps.log": continue
            if actFile == ".nodelete": continue
            if actFile == "encoder": continue
            if actFile == "encoder.temp": continue
            if actFile == "encoder.mbtree": continue
            if actFile == "encoder.mbtree.temp": continue
            if actFile == "fanart.jpg": continue # from tvscraper
            if actFile == "poster.jpg": continue # from tvscraper
            if actFile == "tvscraper.json": continue # from tvscraper
            if actFile == "info":
                isInfoFound = True
                continue
            if actFile == "index":
                isIndexFound = True
                mTime = datetime.datetime.fromtimestamp(os.stat(root+"/"+actFile).st_mtime)
                now = datetime.datetime.now()
                difference = (now - mTime).total_seconds()
                if difference < 60:
                    self.isRunning = True;
                    log.dsyslog("recording is running "+self.root)
                    return(False)
                continue

            if actFile == "marks":
                isMarksNotFound = False
                continue
            if actFile == "-marks":  # ignore test marks
                continue

            if fnmatch.fnmatch(actFile,'marks_*'):
                if not isMarksNotFound:  # log different backup marks only if we have a marks file
                    if fileCompareMarks is None: fileCompareMarks = actFile
                    else:
                        rc = CompareMarks(self.root+"/"+fileCompareMarks, self.root+"/"+actFile)
                        if not rc:
                            log.isyslog("marks is different in recording: " + self.root)
                            log.isyslog(fileCompareMarks)
                            log.isyslog(actFile)
                        else:
                            log.dsyslog("delete: "+ self.root+"/"+fileCompareMarks);
                            os.remove(self.root+"/"+fileCompareMarks);
                        fileCompareMarks = actFile
                continue

            if fnmatch.fnmatch(actFile,'F__*'):
                continue
            if fnmatch.fnmatch(actFile,'logo__*'):
                hadLogo = True
                if fileCompareLogo is None: fileCompareLogo = actFile
                else:
                    logElemets1 = fileCompareLogo.split("__");
                    logElemets2 = actFile.split("__");
                    if (logElemets1[1] == logElemets2[1]) :
                        rc = filecmp.cmp(self.root+"/"+fileCompareLogo, self.root+"/"+actFile)
                        if not rc:
                            log.isyslog("logo is different in recording: " + self.root)
                            log.isyslog(fileCompareLogo)
                            log.isyslog(actFile)
                        else:
                            log.dsyslog("delete: "+ self.root+"/"+fileCompareLogo);
                            os.remove(self.root+"/"+fileCompareLogo);
                    fileCompareLogo = actFile
                continue
            if fnmatch.fnmatch(actFile,'*.pgm'):
                isLogo = True
                continue

            if actFile == "markad.pid":
                log.isyslog("markad is running "+self.root)
                return(False)
            log.isyslog("unexpected file found: "+self.root+"/"+actFile)

        if not isLogo and not isMarksNotFound and hadLogo and isVideoDir:
            log.esyslog("no logo file found "+self.root)
        if not isInfoFound and isVideoDir:
            log.esyslog("no info file found "+self.root)
            return(False)
        if not isIndexFound and isVideoDir:
            log.esyslog("no index found "+self.root)
            return(False)
        return((isMarksNotFound or isCutNotFound) and isVideoDir)

    def ConvertPath(self, path):
        newPath = path.replace('&','\\&')
        newPath = newPath.replace('(','\\(')
        newPath = newPath.replace(')','\\)')
        newPath = newPath.replace("'","\\\'")
        newPath = newPath.replace(';','\\;')
        return(newPath)

    def CheckMirrorDelete(self):
        if self.mirror_name is not None and self.root.find(".del") <= 0 and not self.isRunning:
            if not os.path.exists(self.mirror_name):
                log.isyslog("mirror video was deleted: "+self.mirror_name)
                delDir = self.root.replace(".rec", ".del")
                os.rename(self.root, delDir)
                os.system("touch "+self.ConvertPath(config.mirror_update)+"/.update")

    def RunMarkad(self):
        if not config.checkOnly:
            if config.maxrecordings <= 0:
                log.isyslog("maximum recording limit reached")
                exit(0)
            # remove debug pictures
            for filename in glob.glob(self.root + "/F__*.pgm"):
                os.remove(filename)
            config.maxrecordings -= 1
            cmd = '%s/markad --logocachedir=%s --loglevel=%i --autologo=%i --threads=%i' % (config.bindir, config.logocachedir, config.markad_loglevel, config.autologo, config.threads)
            if config.nice != 19: cmd = cmd + " --priority=" + str(config.nice)
            if config.log2rec: cmd = cmd + " --log2rec"
            if config.vps: cmd = cmd + " --vps"
            if config.fulldecode: cmd = cmd + " --fulldecode"
            if config.smartencode: cmd = cmd + " --smartencode"
            if config.fullencode: cmd = cmd + " --fullencode=" + config.fullencode
            if config.hwaccel: cmd = cmd + " --hwaccel=" + config.hwaccel
            if config.cut: cmd = cmd + " --cut"
            if config.ac3reencode: cmd = cmd + " --ac3reencode"
            if config.pts: cmd = cmd + " --pts"
            cmd = cmd + ' - ' + self.ConvertPath(self.root)
            log.dsyslog("markad call: "+cmd)
            self.process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
            self.process.wait()
            if config.backupmarks:
                self.BackupMarks()

            if config.backuplogo is not None:
                    self.BackupLogo()

            if config.mirror_path is not None:
                if self.mirror_name is not None and self.mirror_type is not None:
                    (head, tail) = os.path.split(self.mirror_name)
                    os.makedirs(head, exist_ok=True)
                    cmd='cat '+self.ConvertPath(self.root)+'/00*.ts > ' + self.ConvertPath(self.mirror_name)
                    log.dsyslog("cat call: " + cmd)
                    os.system(cmd)
                else:
                    log.esyslog('no valid mirror name %s or mirror type found %s' % (self.mirror_name, self.mirror_type))

    def BackupMarks(self):
        markadVersion = subprocess.run([config.bindir+"/markad", "--version"], stdout=subprocess.PIPE)
        wordList = markadVersion.stdout.decode('utf-8').split(" ")
        append = wordList[1] + "-" + wordList [2]
        append = append.replace("(","")
        append = append.replace(")","")
        append = append.replace(".","")
        now = datetime.datetime.now()
        append = now.strftime("%Y-%m-%d_%H-%M-%S") + "_V"+append
        cmd = "cp " + self.ConvertPath(self.root) + "/marks " + self.ConvertPath(self.root) + "/marks_" + append
        os.system(cmd)

    def BackupLogo(self):
        for file in os.listdir(self.root):
            if file.endswith(".pgm") and not file.startswith("logo__") and not file.startswith("F__"):
                log.dsyslog("backup logo file " + file)
                markadVersion = subprocess.run([config.bindir+"/markad", "--version"], stdout=subprocess.PIPE)
                wordList = markadVersion.stdout.decode('utf-8').split(" ")
                append = wordList[1] + "-" + wordList [2]
                append = append.replace("(","")
                append = append.replace(")","")
                append = append.replace(".","")
                now = datetime.datetime.now()
                append = now.strftime("%Y-%m-%d_%H-%M-%S") + "_V"+append
                cmd = "cp " + self.ConvertPath(self.root) + "/" + file + " " + self.ConvertPath(self.root) + "/logo__" + file + "__" + append + ".pgm"
                os.system(cmd)
                elements = self.root.split("/");
                count = len(elements)
                if "Staffel" in elements[count - 3]:
                    centralLogoName =  elements[count - 4] + "_" + elements[count - 3] + "_" + elements[count - 2]
                else:
                    centralLogoName =  elements[count - 3] + "_" + elements[count - 2]
                cmd = "cp " + self.ConvertPath(self.root) + "/" + file + " " + config.backuplogo + "/" + file + "_" + self.ConvertPath(centralLogoName) + ".pgm"
                log.dsyslog("taget " + cmd)
                os.system(cmd)

    def KillMarkad(self):
        self.process.send_signal(signal.SIGINT)
        log.esyslog("killed markad")



# start of main program
signal.signal(signal.SIGINT, signal_handler)
log = Log()

parser = argparse.ArgumentParser(description='run markad on all new VDR recordings')
parser.add_argument('-v', '--verbose', dest="verbose", action='store_true', default=False, help='log to std out')
parser.add_argument('-l', '--loglevel=', metavar="<level>", type=int, choices=range(0, 5), dest="loglevel", action="store", help='sets --loglevel to the specified value, 0=no logging 1=error 2=info 3=debug 4=trace (default 1)')
parser.add_argument('--markad_loglevel=', metavar="<level>", type=int, choices=range(0, 5), dest="markad_loglevel", action="store", help='sets --loglevel for markad to the specified value, 0=no logging 1=error 2=info 3=debug 4=trace (default 1)')
parser.add_argument('-p', '--path=', dest="path",  metavar="<path>", action="store", help='path to the VDR recording directory (default: /media/Video/VDR)')
parser.add_argument('--nice=', dest="nice",  metavar="<value>", choices=range(0, 20), action="store", help='set niceness of scheduling priority (default 19)')
parser.add_argument('--minfree=', metavar="GB", type=int, dest="minfree", action="store", help='minimum free disk space in GBs for all disk consuming operations (default 0 no limit)')
parser.add_argument('--maxrecordings=', metavar="", type=int, dest="maxrecordings", action="store", help='maximum recordings to process (default 1000)')
parser.add_argument('--bindir', dest="bindir",  metavar="<DIR>", action="store", help='use DIR as location for markad executable (default: /usr/bin)')
parser.add_argument('--backupmarks', dest="backupmarks", action='store_true', default=False, help='make a versioned backup of the marks file')
parser.add_argument('--backuplogo=', dest="backuplogo", metavar="<user>", action='store', default=None, help='make a versioned backup of the logo file in the recording directory and a central backup to target path')
parser.add_argument('--logocachedir', dest="logocachedir",  metavar="<directory>", action="store", help='directory where logos stored, default /var/lib/markad')
parser.add_argument('--autologo=', metavar="<option>", type=int, choices=range(0, 3), dest="autologo", action="store", help='sets --autologo of markad to the specified value, see markad for more detailsi (default 2)')
parser.add_argument('--fulldecode', dest="fulldecode", action='store_true', default=False, help='sets --fulldecode of markad to the specified value, see markad for more details')
parser.add_argument('--smartencode', dest="smartencode", action='store_true', default=False, help='sets --smartencode of markad to the specified value, see markad for more details')
parser.add_argument('--fullencode=', dest="fullencode",  metavar="<streams>", action="store", help='streams to encode (best or all)')
parser.add_argument('--hwaccel=', dest="hwaccel",  metavar="<hwaccel_method>", action="store", help='hwaccel')
parser.add_argument('--threads=', metavar="<number>", type=int, choices=range(1, 17), dest="threads", action="store", help='sets --threads of markad to the specified value, see markad for more details (default 1)')
parser.add_argument('--log2rec', dest="log2rec", action='store_true', default=False, help='sets --log2rec of markad to the specified value, see markad for more details')
parser.add_argument('--cut', dest="cut", action='store_true', default=False, help='sets --cut of markad to the specified value, see markad for more details')
parser.add_argument('--ac3reencode', dest="ac3reencode", action='store_true', default=False, help='sets --ac3reencode of markad to the specified value, see markad for more details')
parser.add_argument('--mirror_path=', dest="mirror_path",  metavar="<path>", action="store", help='path to the video mirror directory (default: None)')
parser.add_argument('--checkonly', dest="checkOnly", action='store_true', default=False, help='only check marks file, no markad will executed')
parser.add_argument('--vps', dest="vps", action='store_true', default=False, help='usr vps events to optimize marks')
parser.add_argument('--pts', dest="pts", action='store_true', default=False, help='additional save PTS based timestamp in marks (only for debug)')
parser.add_argument('--user=', dest="user",  metavar="<user>", action="store", help='run markad as <user> (default: vdr)')
parser.add_argument('--group=', dest="group",  metavar="<group>", action="store", help='run markad as <group> (default: vdr)')

# get config values
config = Config()
config.ConfigFile()
config.Arguments()


#set user and group to vdr
username = getpass.getuser()
log.dsyslog("start as user "+username)
if username == "root" and config.user != "root":
    log.dsyslog("drop privileges to user " + config.user)
    try:
        markad_uid = pwd.getpwnam(config.user).pw_uid
    except(KeyError):
        log.esyslog("user "+  config.user + " not found")
        exit(1)
    try:
        markad_gid = grp.getgrnam(config.group).gr_gid
    except(KeyError):
        log.esyslog("group " + config.group + " not found")
        exit(1)
    os.setgroups([]) # Remove group privileges
    # Try setting the new uid/gid
    os.setgid(markad_gid)
    os.setuid(markad_uid)

# PID File
pidFile = PidFile()
if pidFile.CheckPidFile():
    config.checkOnly = True
else:
    pidFile.WritePidFile()
    atexit.register(pidFile.DeletePidFile)

# set nice
os.nice(config.nice)
os.system("ionice -c 3 -p%d" % os.getpid())

log.dsyslog("work on directory " + config.path)

global curPath
for root, dirs, files in sorted(os.walk(config.path)):
    if len(dirs) == 0:
        curPath = CheckPath(root,files)
        if curPath.NeedMarks():
            if not config.checkOnly: log.isyslog("marks missing: " + root)
            if curPath.CheckFreeSpace():
                curPath.RunMarkad()
        else:
            if config.mirror_path is not None:
                curPath.CheckMirrorDelete()
