Share Pastebin
Guest
Public paste!

Untitled

By: a guest | May 4th, 2010 | Syntax: Python | Size: 8.52 KB | Hits: 55 | Expires: Never
Copy text to clipboard
  1. #!/usr/bin/env python
  2.  
  3.  
  4. # NOTE: this script requires MythTV 0.23+fixes r24420 or newer.
  5. # For older versions, you can try applying this patch to the python bindings:
  6. #   http://svn.mythtv.org/trac/changeset/24420
  7.  
  8.  
  9. # schema version that this code expects
  10. schema_version = 1000
  11.  
  12.  
  13. # default number of timeout days
  14. timeout = 30
  15.  
  16.  
  17. # if any of these are not None, the given value(s) will be used to create a
  18. # database connection
  19. dbhost = None
  20. dbname = None
  21. dbuser = None
  22. dbpass = None
  23.  
  24.  
  25. # includes
  26. from sys import argv, exit
  27. from MythTV import OldRecorded
  28. from MythTV import MythDB, MythLog
  29.  
  30.  
  31. # print optional message, usage info, and then exit with the given code or not
  32. def __usage(exitmsg='', exitcode=0, shouldexit=True):
  33.   if len(exitmsg): print exitmsg
  34.   print 'Usage: %s [options]' % argv[0]
  35.   if shouldexit: exit(exitcode)
  36.  
  37.  
  38. # utility funciton: sotr list of commands by priority
  39. def __commandprioritycmp(a, b):
  40.   return cmp(a[1], b[1])
  41.  
  42.  
  43. # utility funciton: connect and return a MythDB object
  44. def __db_connect(schemacheck=True):
  45.  
  46.   # connect
  47.   args = []
  48.   if dbhost: args.append( ('DBHostName', dbhost) )
  49.   if dbname: args.append( ('DBName', dbname) )
  50.   if dbuser: args.append( ('DBUserName', dbuser) )
  51.   if dbpass: args.append( ('DBPassword', dbpass) )
  52.   db = MythDB(args=args)
  53.   log = MythLog(module='RerecordLater', lstr='important')
  54.  
  55.   # schema version check
  56.   if schemacheck:
  57.  
  58.     if db.settings.NULL.RerecordLaterDBSchemaVer == None:
  59.       # first time run, auto install
  60.       log(
  61.         MythLog.IMPORTANT,
  62.         'RerecordLater database does not exist, creating it.'
  63.       )
  64.       action_install(db)
  65.     else:
  66.  
  67.       dbversion = int(db.settings.NULL.RerecordLaterDBSchemaVer)
  68.    
  69.       # db schema too new ?
  70.       if dbversion > schema_version:
  71.         log(
  72.           MythLog.IMPORTANT,
  73.           'The schema version in the database (%d) is newer than the RerecordLater program (%d). Please update to the appropriate version of RerecordLater.' %
  74.           ( dbversion, schema_version )
  75.         )
  76.         exit(3)
  77.  
  78.       # db schema too old?
  79.       elif dbversion < schema_version:
  80.         log(
  81.           MythLog.IMPORTANT,
  82.           'The schema version in the database (%d) is older than the RerecordLater program (%d). Updating it.' %
  83.           ( dbversion, schema_version )
  84.         )
  85.         action_database_upgrade(db)
  86.  
  87.       # correct db schema version?
  88.       else:
  89.         pass
  90.  
  91.   return db
  92.  
  93.  
  94. # --help handler
  95. def action_help():
  96.   __usage('', 0, False)
  97.   # TODO: iterate ARGT and print a nice list
  98.   exit(0)
  99.  
  100.  
  101. # --rerecord handler
  102. def action_rerecord(chanid, starttime):
  103.  
  104.   db = __db_connect()
  105.  
  106.   # normally comes from argv as a string, make it an int
  107.   chanid = int(chanid)
  108.  
  109.   # search for old recordings with chanid/starttime
  110.   q = db.searchOldRecorded(chanid=chanid, starttime=starttime)
  111.   if q:
  112.     for oldrec in q:
  113.       if not oldrec.duplicate:
  114.         # This recording was set to re-record. this is where we take action.
  115.         # It is told *not* to rerecord now and will be flipped back on after
  116.         # the timeout period.
  117.         db.cursor().execute("""
  118.          INSERT INTO rerecordlater
  119.          SET
  120.            chanid = %d,
  121.             starttime = "%s",
  122.             timeout = NOW() + INTERVAL %d DAY
  123.        """ % ( chanid, starttime, timeout ) )
  124.         oldrec.setDuplicate(True)
  125.  
  126.  
  127. # --reschedule handler
  128. def action_reschedule():
  129.  
  130.   # connect
  131.   db = __db_connect()
  132.   c = db.cursor()
  133.  
  134.   # get rerecordlater records where the timeout has expired
  135.   c.execute("""
  136.    SELECT chanid, starttime
  137.    FROM rerecordlater
  138.    WHERE timeout <= NOW()
  139.  """)
  140.   for rec in c.fetchall():
  141.     # find the oldrecorded record and re-allow dupes.
  142.     q = db.searchOldRecorded(chanid=rec[0], starttime=rec[1])
  143.     for oldrec in q: oldrec.setDuplicate(False)
  144.     c.execute("""
  145.      DELETE FROM rerecordlater
  146.      WHERE chanid = %d AND starttime = "%s"
  147.    """ % ( rec[0], rec[1] ) )
  148.  
  149.  
  150. # --legacy handler
  151. def action_legacy():
  152.   # Find recordings that were set to duplicate
  153.   q = db.searchOldRecorded(duplicate=0)
  154.   for oldrec in q: action_rerecord(oldrec.chanid, oldrec.starttime)
  155.  
  156.  
  157. # --install handler
  158. def action_install(db=None):
  159.   if not db: db = __db_connect(schemacheck=False)
  160.   db.cursor().execute("""
  161.    CREATE TABLE IF NOT EXISTS rerecordlater(
  162.      chanid INT(10) UNSIGNED,
  163.      starttime datetime,
  164.      timeout datetime
  165.    )
  166.  """)
  167.   db.settings.NULL.RerecordLaterDBSchemaVer = schema_version
  168.  
  169.  
  170. # --database-upgrade handler
  171. def action_database_upgrade(db=None):
  172.   if not db: db = __db_connect()
  173.   # TODO: update system when needed. The idea is to iterate
  174.   # from db_schema_version+1 through the current version and
  175.   # execute a function called database_upgrade_[n] where [n]
  176.   # is a particular schema version. Each of these functions
  177.   # should have the ability to update the database from the
  178.   # previous version, so executing them in a row will upgrade
  179.   # from whatever the current db version is to current schema.
  180.  
  181.  
  182. # argument handler functions
  183. def arg_timeout(x):
  184.   global timeout
  185.   timeout = int(x)
  186. def arg_dbhost(x):
  187.   global dbhost
  188.   dbhost = x
  189. def arg_dbname(x):
  190.   global dbname
  191.   dbname = x
  192. def arg_dbuser(x):
  193.   global dbuser
  194.   dbuser = x
  195. def arg_dbpass(x):
  196.   global dbpass
  197.   dbpass = x
  198.  
  199.  
  200. # argt entries are (action, priority, param count, param names, description)
  201. ARGT = {
  202.  
  203.   'legacy': (
  204.     action_legacy, 10, 0, '',
  205.     'Add programs that are marked re-recordable and are not already handled by this script. Use this to seed the database at installation time.'
  206.   ),
  207.  
  208.   'rerecord': (
  209.     action_rerecord, 20, 2, '(CHANID) (STARTTIME)',
  210.     'Specify a program that should be re-recorded.'
  211.   ),
  212.  
  213.   'reschedule': (
  214.     action_reschedule, 30, 0, '',
  215.     'Mark programs where the timeout has expired as OK to re-record. Run daily. Recommended: put --update on the "mythfilldatabase ran" system event.'
  216.   ),
  217.  
  218.   'install': (
  219.     action_install, -20, 0, '',
  220.     'Initialize the database. If it already exists, does nothing. Happens automatically if the program is run without an existing database.'
  221.   ),
  222.  
  223.   'database-upgrade': (
  224.     action_database_upgrade, -10, 0, '',
  225.     'Initialize the database. If it already exists, does nothing. Happens automatically if the program is run without an existing database.'
  226.   ),
  227.  
  228.   'timeout': (
  229.     arg_timeout, 0, 1, '(DAYS)',
  230.     'Number of days before marked programs will time out. Not used during --reschedule.'
  231.   ),
  232.  
  233.   'host': (
  234.     arg_dbhost, 0, 1, '(HOST)',
  235.     'Database host. NOTE: if no database information is given, UPnP'
  236.   ),
  237.  
  238.   'database': (
  239.     arg_dbname, 0, 1, '(NAME)',
  240.     'Database name.'
  241.   ),
  242.  
  243.   'user': (
  244.     arg_dbuser, 0, 1, '(USER)',
  245.     'Database user name.'
  246.   ),
  247.  
  248.   'password': (
  249.     arg_dbpass, 0, 1, '(PASS)',
  250.     'Database password.'
  251.   ),
  252.  
  253.   'help': (
  254.     action_help, -5, 0, '',
  255.     'Display help.'
  256.   ),
  257.  
  258. }
  259.  
  260.  
  261. if __name__ == '__main__':
  262.  
  263.   #MythLog._setlevel('database')
  264.  
  265.   argc = len(argv)
  266.   if argc < 2: __usage()
  267.  
  268.   # process arguments
  269.  
  270.   # first, put them into groups with --optionname and user values
  271.   i = 1
  272.   command = []
  273.   commands = []
  274.   while i < argc:
  275.  
  276.     # if argv[i] starts with '--', append and clear
  277.     if argv[i][0:2] == '--':
  278.       if len(command): commands.append(command)
  279.       command = []
  280.  
  281.     # if this is the first item in the command, resolve an ARGT entry
  282.     if not len(command):
  283.       # look up the ARGT by name
  284.       argname = argv[i][2:]
  285.       try: argt = ARGT[argname]
  286.       except KeyError:
  287.         __usage(
  288.           'Unknown argument "%s". Try %s --help for detailed __usage instructions.' %
  289.           (argname, argv[0]), 1
  290.         )
  291.       # append function, paramc, priority to the command
  292.       command.append(argt[0])
  293.       command.append(argt[1])
  294.       command.append(argt[2])
  295.     else:
  296.       # this isn't the first item in the command, it's a user param, append
  297.       command.append(argv[i])
  298.     i += 1
  299.   if len(command): commands.append(command)
  300.  
  301.   # sort by priority
  302.   commands.sort(__commandprioritycmp)
  303.  
  304.   # now handle each argument
  305.   for command in commands:
  306.     # print repr(command) # use to check the order and view command arrays
  307.     # check the parameter count for this argument type against received argc
  308.     paramc = len(command)-3
  309.     if paramc != command[2]:
  310.       __usage(
  311.         'The "%s" argument takes %d parameter values, %d given.' %
  312.         (argname, command[2], paramc), 2
  313.       )
  314.  
  315.     # evaluate
  316.     args = command[3:]
  317.     command[0](*args)