Ticket #6885: pyth.updates2.patch
File pyth.updates2.patch, 27.8 KB (added by , 15 years ago) |
---|
-
mythtv/bindings/python/MythTV/MythVideo.py
27 27 if not host: # If a hostname was not supplied then use the local host name 28 28 host = gethostname() 29 29 30 # Get storagegroup table field names 31 table_names = self.getTableFieldNames(u'storagegroup') 30 ret = [] 31 for i in db.getStorageGroup('Videos',host): 32 ret.append(i['dirname']) 32 33 33 cur = self.db.cursor() 34 # Check is there are storage groups for the supplied host or default to the local host 35 try: 36 cur.execute(u"select * from storagegroup") 37 except MySQLdb.Error, e: 38 log.Msg(INFO, u"! Error: Reading storagegroup MythTV table: %d: %s\n" % (e.args[0], e.args[1])) 34 if ret: 35 return ret 36 else: 39 37 return None 40 38 41 videos_dir = []42 while True:43 data_id = cur.fetchone()44 if not data_id:45 break46 record = {}47 i = 048 for elem in data_id:49 if table_names[i] == 'groupname' or table_names[i] == 'hostname' or table_names[i] == 'dirname':50 record[table_names[i]] = elem51 i+=152 if record['hostname'].lower() == host.lower() and record['groupname'] == u'Videos':53 # Add a slash if mussing to any storage group dirname54 if record['dirname'][-1:] == '/':55 videos_dir.append(record['dirname'])56 else:57 videos_dir.append(record['dirname']+u'/')58 continue59 cur.close()60 61 if not len(videos_dir):62 return None63 64 return videos_dir65 # end getStorageGroups66 67 39 def pruneMetadata(self): 68 40 """ 69 41 Removes metadata from the database for files that no longer exist. … … 102 74 if os.path.exists(filename): # Handle multiple Videos SGs for one backend 103 75 break 104 76 else: 105 log. Msg(INFO, u'%s not exist, removing metadata...',filename)77 log.info('Videometadata',u'%s not exist, removing metadata...'% filename) 106 78 rmMetadata(intid) 107 79 c.close() 108 80 … … 115 87 This function should have been called getCategoryId 116 88 """ 117 89 c = self.db.cursor() 118 c.execute("SELECT intid FROM videocategory WHERE lower(category) = %s", (genre_name,)) 90 c.execute("""SELECT intid FROM videocategory 91 WHERE lower(category) = %s""", (genre_name,)) 119 92 row = c.fetchone() 120 93 c.close() 121 94 … … 124 97 125 98 # Insert a new genre. 126 99 c = self.db.cursor() 127 c.execute("INSERT INTO videocategory(category) VALUES (%s)", (genre_name.capitalize(),)) 100 c.execute("""INSERT INTO videocategory(category) 101 VALUES (%s)""", (genre_name.capitalize(),)) 128 102 newid = c.lastrowid 129 103 c.close() 130 104 … … 322 296 c.close() 323 297 return intid 324 298 else: 325 log. Msg(DEBUG, 'Updating metadata for %s',id)299 log.debug('Videometadata', 'Updating metadata for %s' % id) 326 300 format_string = ', '.join(['%s = %%s' % d for d in data]) 327 301 sql = "UPDATE videometadata SET %s WHERE intid = %%s" % format_string 328 302 sql_values = data.values() … … 341 315 c = self.db.cursor() 342 316 if isinstance(video, str): 343 317 if video[0] !='/' and host == None: # Protect against accidental multiple deletions on SG's 344 log. Msg(WARNING, u"Attempting to delete a video for a storage group when the hostname is not supplied. That could potentially remove the videometadata on multiple backends " +318 log.warning('Metadata delete', u"Attempting to delete a video for a storage group when the hostname is not supplied. That could potentially remove the videometadata on multiple backends " + 345 319 u"for videometadata: %s" % video) 346 320 return 347 321 intid = self.getMetadataId(video, host) 348 322 if intid == None: 349 log. Msg(WARNING, u"Attempt to delete a video that does not exist " +323 log.warning('Metadata delete', u"Attempt to delete a video that does not exist " + 350 324 u"for videometadata: %s" % video) 351 325 return 352 326 c.execute("DELETE FROM videometadata WHERE intid = %s", (intid,)) … … 354 328 elif isinstance(video, int) or isinstance(video, long): 355 329 c.execute("DELETE FROM videometadata WHERE intid = %s", (video,)) 356 330 else: 357 log. Msg(WARNING, "Attempt to delete non-str, non-int item" +331 log.warning('Metadata delete', "Attempt to delete non-str, non-int item" + 358 332 "from videometadata: %s" % str(video)) 359 333 # Clean up this video's relationships to Genres, Country and Cast 360 334 self.cleanGenres(video) -
mythtv/bindings/python/MythTV/MythTV.py
20 20 from MythDB import * 21 21 from MythLog import * 22 22 23 log = MythLog(CRITICAL, ' #%(levelname)s - %(message)s', 'MythTV')23 log = MythLog(CRITICAL, 'MythTV.py') 24 24 25 25 RECSTATUS = { 26 26 'TunerBusy': -8, … … 59 59 self.master_port = int(self.db.getSetting('MasterServerPort')) 60 60 61 61 if not self.master_host: 62 log. Msg(CRITICAL,'Unable to find MasterServerIP in database')62 log.critical('Settings','Unable to find MasterServerIP in database') 63 63 sys.exit(1) 64 64 if not self.master_port: 65 log. Msg(CRITICAL,'Unable to find MasterServerPort in database')65 log.critical('Settings','Unable to find MasterServerPort in database') 66 66 sys.exit(1) 67 67 68 68 try: … … 71 71 self.socket.connect((self.master_host, self.master_port)) 72 72 res = self.backendCommand('MYTH_PROTO_VERSION %s' % PROTO_VERSION).split(BACKEND_SEP) 73 73 if res[0] == 'REJECT': 74 log. Msg(CRITICAL, 'Backend has version %s and we speak version %s', res[1], PROTO_VERSION)74 log.critical('Protocol Mismatch',"Backend has version %s and we speak version %s" % (res[1], PROTO_VERSION)) 75 75 sys.exit(1) 76 76 res = self.backendCommand('ANN %s %s 0' % (conn_type, socket.gethostname())) 77 77 if res != 'OK': 78 log. Msg(CRITICAL, 'Unexpected answer to ANN command: %s',res)78 log.critical('Protocol Error',"Unexpected answer to ANN command: %s" % res) 79 79 else: 80 log. Msg(INFO, 'Successfully connected mythbackend at %s:%d', self.master_host, self.master_port)80 log.info('Info',"Successfully connected mythbackend at %s:%d" % (self.master_host, self.master_port)) 81 81 except socket.error, e: 82 log. Msg(CRITICAL, 'Couldn\'t connect to %s:%d (is the backend running)', self.master_host, self.master_port)82 log.critical('Protocol Error',"Couldn't connect to %s:%d (is the backend running)" % (self.master_host, self.master_port)) 83 83 sys.exit(1) 84 84 85 85 def __del__(self): … … 114 114 return u''.join(data) 115 115 116 116 command = u'%-8d%s' % (len(data), data) 117 log. Msg(DEBUG, 'Sending command: %s',command)117 log.debug('Info','Sending command: %s' % command) 118 118 self.socket.send(command) 119 119 return recv() 120 120 … … 126 126 res = self.backendCommand('QUERY_GETALLPENDING').split(BACKEND_SEP) 127 127 has_conflict = int(res.pop(0)) 128 128 num_progs = int(res.pop(0)) 129 log. Msg(DEBUG, '%s pending recordings',num_progs)129 log.debug('Info','%s pending recordings' % num_progs) 130 130 for i in range(num_progs): 131 131 programs.append(Program(res[i * PROGRAM_FIELDS:(i * PROGRAM_FIELDS) 132 132 + PROGRAM_FIELDS])) … … 139 139 programs = [] 140 140 res = self.backendCommand('QUERY_GETALLSCHEDULED').split(BACKEND_SEP) 141 141 num_progs = int(res.pop(0)) 142 log. Msg(DEBUG, '%s scheduled recordings',num_progs)142 log.debug('Info','%s scheduled recordings' % num_progs) 143 143 for i in range(num_progs): 144 144 programs.append(Program(res[i * PROGRAM_FIELDS:(i * PROGRAM_FIELDS) 145 145 + PROGRAM_FIELDS])) … … 242 242 243 243 def getRecordings(self): 244 244 """ 245 Returns a listof all Program objects which have already recorded245 Returns a tuple of all Program objects which have already recorded 246 246 """ 247 247 programs = [] 248 res = self.backendCommand('QUERY_RECORDINGS Play').split( '[]:[]')248 res = self.backendCommand('QUERY_RECORDINGS Play').split(BACKEND_SEP) 249 249 num_progs = int(res.pop(0)) 250 log. Msg(DEBUG, '%s total recordings',num_progs)250 log.debug('Info','%s total recordings' % num_progs) 251 251 for i in range(num_progs): 252 252 programs.append(Program(res[i * PROGRAM_FIELDS:(i * PROGRAM_FIELDS) 253 253 + PROGRAM_FIELDS])) 254 254 return tuple(programs) 255 255 256 def getExpiring(self): 257 """ 258 Returns a tuple of all Program objects nearing expiration 259 """ 260 programs = [] 261 res = self.backendCommand('QUERY_GETEXPIRING').split(BACKEND_SEP) 262 num_progs = int(res.pop(0)) 263 log.debug('Info','%s recordings to be expired' % num_progs) 264 for i in range(num_progs): 265 programs.append(Program(res[i * PROGRAM_FIELDS:(i * PROGRAM_FIELDS) 266 + PROGRAM_FIELDS])) 267 return tuple(programs) 268 256 269 def getCheckfile(self,program): 257 270 """ 258 271 Returns location of recording in file system … … 329 342 res = self.backendCommand('QUERY_LOAD').split(BACKEND_SEP) 330 343 return (float(res[0]),float(res[1]),float(res[2])) 331 344 345 def getUptime(self): 346 """ 347 Returns machine uptime in seconds 348 """ 349 return self.backendCommand('QUERY_UPTIME') 350 332 351 def getSGList(self,host,sg,path): 333 352 """ 334 353 Returns a tuple of directories and files … … 382 401 port = self.db.getSetting("NetworkControlPort",host) 383 402 return Frontend(host,port) 384 403 404 def getLastGuideData(self): 405 """ 406 Returns the last date for which guide data is available 407 On error, 0000-00-00 00:00 is returned 408 """ 409 return self.backendCommand('QUERY_GUIDEDATATHROUGH') 410 385 411 def joinInt(self,high,low): 386 412 """ 387 413 Returns a single long from a pair of signed integers … … 414 440 elif mode == 'w': 415 441 write = 1 416 442 else: 417 log. Msg(CRITICAL, 'Invalid FileTransfer mode given')443 log.critical('Filetransfer', 'Invalid FileTransfer mode given') 418 444 sys.exit(1) 419 445 if isinstance(file, Program): 420 446 match = regex.match(file.filename) … … 426 452 self.port = 6543 427 453 elif isinstance(file, tuple): 428 454 if len(file) != 3: 429 log. Msg(CRITICAL, 'Incorrect FileTransfer() input size')455 log.critical('Filetransfer', 'Incorrect FileTransfer() input size') 430 456 sys.exit(1) 431 457 else: 432 458 self.host = file[0] … … 436 462 elif isinstance(file, str): 437 463 match = regex.match(file) 438 464 if match is None: 439 log. Msg(CRITICAL, 'Incorrect FileTransfer() input string: %s' % file)465 log.critical('Filetransfer', 'Incorrect FileTransfer() input string: %s' % file) 440 466 sys.exit(1) 441 467 self.sgroup = match.group('group') 442 468 self.host = match.group('host') … … 447 473 if self.port is None: 448 474 self.port = 6543 449 475 else: 450 log. Msg(CRITICAL, 'Improper input to FileTransfer()')476 log.critical('Filetransfer', 'Improper input to FileTransfer()') 451 477 sys.exit(1) 452 478 453 479 try: … … 456 482 self.datsock.connect((self.host, self.port)) 457 483 res = self.send('MYTH_PROTO_VERSION %s' % PROTO_VERSION).split(BACKEND_SEP) 458 484 if res[0] == 'REJECT': 459 log. Msg(CRITICAL, 'Backend has version %s and we speak version %s', res[1], PROTO_VERSION)485 log.critical('Filetransfer', 'Backend has version %s and we speak version %s' % (res[1], PROTO_VERSION)) 460 486 sys.exit(1) 461 487 res = self.send('ANN FileTransfer %s %d %d %d%s%s%s%s' % (socket.gethostname(), write, False, -1, BACKEND_SEP, self.filename, BACKEND_SEP, self.sgroup)) 462 488 if res.split(BACKEND_SEP)[0] != 'OK': 463 log. Msg(CRITICAL, 'Unexpected answer to ANN command: %s',res)489 log.critical('Filetransfer', 'Unexpected answer to ANN command: %s' % res) 464 490 else: 465 log. Msg(INFO, 'Successfully connected mythbackend at %s:%d', self.host, self.port)491 log.info('Filetransfer', 'Successfully connected mythbackend at %s:%d' % (self.host, self.port)) 466 492 sp = res.split(BACKEND_SEP) 467 493 self.sockno = int(sp[1]) 468 494 self.pos = 0 469 495 self.size = (int(sp[2]) + (int(sp[3])<0))*2**32 + int(sp[3]) 470 496 471 497 except socket.error, e: 472 log. Msg(CRITICAL, 'Couldn\'t connect to %s:%d (is the backend running)', self.host, self.port)498 log.critical('Filetransfer', "Couldn't connect to %s:%d (is the backend running)" % (self.host, self.port)) 473 499 sys.exit(1) 474 500 475 501 def __del__(self): … … 481 507 482 508 def send(self,data): 483 509 command = '%-8d%s' % (len(data), data) 484 log. Msg(DEBUG, 'Sending command: %s',command)510 log.debug('Filetransfer', 'Sending command: %s' % command) 485 511 self.datsock.send(command) 486 512 return self.recv() 487 513 … … 521 547 Read a block of data, requests over 64KB will be buffered internally 522 548 """ 523 549 if self.mode != 'r': 524 print 'Error: attempting to read from a write-only socket'550 log.critical('FileTransfer Error','Attempting to read from a write-only socket') 525 551 return 526 552 if size == 0: 527 553 return '' … … 550 576 Write a block of data, requests over 64KB will be buffered internally 551 577 """ 552 578 if self.mode != 'w': 553 print 'Error: attempting to write to a read-only socket'579 log.critical('FileTransfer Error','Attempting to write to a read-only socket') 554 580 return 555 581 size = len(data) 556 582 buff = '' … … 588 614 if offset < -self.size: 589 615 offset = -self.size 590 616 else: 591 log. Msg(CRITICAL, 'Whence can only be 0, 1, or 2')617 log.critical('Filetransfer', 'Whence can only be 0, 1, or 2') 592 618 593 619 curhigh,curlow = self.comsock.splitInt(self.pos) 594 620 offhigh,offlow = self.comsock.splitInt(offset) … … 626 652 if self.recv()[:28] != "MythFrontend Network Control": 627 653 self.socket.close() 628 654 self.socket = None 629 raise Exception('FrontendConnect','Connected socket does not belong to a mythfrontend')655 raise MythError('Connected socket does not belong to a mythfrontend') 630 656 self.isConnected = True 631 657 632 658 def disconnect(self): -
mythtv/bindings/python/MythTV/MythLog.py
1 1 """ 2 2 Provides simple logging and exception classes. 3 3 """ 4 from MythDB import * 5 from socket import gethostname 6 from datetime import datetime 7 from sys import version_info 4 8 5 import logging 9 db = MythDB() 6 10 7 11 # Vars to imporove readability 8 CRITICAL = logging.CRITICAL 9 FATAL = logging.FATAL 10 ERROR = logging.ERROR 11 WARNING = logging.WARNING 12 INFO = logging.INFO 13 DEBUG = logging.DEBUG 12 ALL = 8 13 DEBUG = 7 14 INFO = 6 15 NOTICE = 5 16 WARNING = 4 17 ERROR = 3 18 CRITICAL = 2 19 ALERT = 1 20 EMERGENCY = 0 14 21 15 22 class MythLog: 16 23 """ 17 24 A simple logging class 18 25 """ 19 def __init__(self, level, format, instance):20 self.log = logging.getLogger(instance)21 self.log.setLevel(level)22 self.ch = logging.StreamHandler()23 self.ch.setFormatter(logging.Formatter(format))24 self.log.addHandler(self.ch)25 26 26 def Msg(self, level, msg, *args, **kwargs): 27 self.log.log(level, msg, *args, **kwargs) 27 priority = WARNING 28 28 29 def __init__(self, priority=WARNING, module='pythonbindings', mode=3): 30 self.setPriority(priority) 31 if isinstance(module,str): 32 self.mod = module 33 self.host = gethostname() 34 self.mode = mode 35 if db.getSetting('LogEnabled') == 0: 36 self.mode %= 2 37 38 def setPriority(self, priority): 39 if priority in range(0,9): 40 self.priority = priority 41 42 def log(self, priority, message, detail=''): 43 if priority > self.priority: 44 return 45 now = datetime.now() 46 nowstr = None 47 if (version_info[0] > 2) | (version_info[1] > 5): 48 nowstr = now.strftime('%Y-%m-%d %H:%M:%S.%f')[:-3] 49 else: 50 nowstr = now.strftime('%Y-%m-%d %H:%M:%S.000') 51 if self.mode & 1: 52 if len(detail): 53 print "%s %s: %s -- %s" % (nowstr, self.mod, message, detail) 54 else: 55 print "%s %s: %s" % (nowstr, self.mod, message) 56 if self.mode & 2: 57 cursor = db.cursor() 58 cursor.execute("""INSERT INTO mythlog 59 (module, priority, logdate, host, message, details) 60 VALUES (%s, %s, %s, %s, %s, %s)""", 61 (self.mod,priority,now,self.host,message,detail)) 62 63 def all(self, message, detail=''): 64 self.log(ALL,message,detail) 65 66 def debug(self, message, detail=''): 67 self.log(DEBUG,message,detail) 68 69 def info(self, message, detail=''): 70 self.log(INFO,message,detail) 71 72 def notice(self, message, detail=''): 73 self.log(NOTICE,message,detail) 74 75 def warning(self, message, detail=''): 76 self.log(WARNING,message,detail) 77 78 def error(self, message, detail=''): 79 self.log(ERROR,message,detail) 80 81 def critical(self, message, detail=''): 82 self.log(CRITICAL,message,detail) 83 84 def alert(self, message, detail=''): 85 self.log(ALERT,message,detail) 86 87 def emergency(self, message, detail=''): 88 self.log(EMERGENCY,message,detail) 89 29 90 class MythError: 30 91 """ 31 92 A simple exception class … … 36 97 def __repr__(self): 37 98 print ': ' + self.message 38 99 100 39 101 # vim: ts=4 sw=4: -
mythtv/bindings/python/MythTV/MythDB.py
9 9 import code 10 10 import getopt 11 11 from datetime import datetime 12 13 12 from MythLog import * 14 13 14 #from MythLog import MythError 15 15 16 # create logging object 16 log = MythLog(CRITICAL, '#%(levelname)s - %(message)s', 'MythDB')17 #log = MythLog(CRITICAL, 'MythDB.py') 17 18 18 19 # check for dependency 19 20 try: 20 21 import MySQLdb 21 22 except: 22 log.Msg(CRITICAL, "MySQLdb (python-mysqldb) is required but is not found.") 23 sys.exit(1) 23 raise MythError("MySQLdb (python-mysqldb) is required but is not found.") 24 24 25 25 class MythDB: 26 26 """ … … 73 73 pass 74 74 75 75 if dbconn['host'] != None and dbconn['name'] != None and dbconn['user'] != None and dbconn['pass'] != None: 76 log.Msg(INFO, 'Using config %s', config_file)76 # log.Msg(INFO, 'Using config %s', config_file) 77 77 found_config = True 78 78 break 79 79 … … 97 97 98 98 try: 99 99 self.db = MySQLdb.connect(user=dbconn['user'], host=dbconn['host'], passwd=dbconn['pass'], db=dbconn['name'], use_unicode=True, charset='utf8') 100 log.Msg(INFO, 'DB Connection info (host:%s, name:%s, user:%s, pass:%s)', dbconn['host'], dbconn['name'], dbconn['user'], dbconn['pass'])100 # log.Msg(INFO, 'DB Connection info (host:%s, name:%s, user:%s, pass:%s)', dbconn['host'], dbconn['name'], dbconn['user'], dbconn['pass']) 101 101 except: 102 102 raise MythError('Connection failed for \'%s\'@\'%s\' to database %s using password %s' % (dbconn['user'], dbconn['host'], dbconn['name'], dbconn['pass'])) 103 103 … … 108 108 Returns None if there are no settings. If multiple rows are 109 109 found (multiple hostnames), returns the value of the first one. 110 110 """ 111 log.Msg(DEBUG, 'Retrieving all setting for host %s', hostname)111 # log.Msg(DEBUG, 'Retrieving all setting for host %s', hostname) 112 112 c = self.db.cursor() 113 113 if hostname is None: 114 114 c.execute(""" … … 116 116 FROM settings 117 117 WHERE hostname IS NULL""") 118 118 else: 119 hostname += '%'; 119 120 c.execute(""" 120 121 SELECT value, data 121 122 FROM settings 122 WHERE hostname LIKE( '%s%%')""" %123 WHERE hostname LIKE(%s)""", 123 124 (hostname)) 124 125 rows = c.fetchall() 125 126 c.close() … … 136 137 Returns None if the setting was not found. If multiple rows are 137 138 found (multiple hostnames), returns the value of the first one. 138 139 """ 139 log.Msg(DEBUG, 'Looking for setting %s for host %s', value, hostname)140 # log.Msg(DEBUG, 'Looking for setting %s for host %s', value, hostname) 140 141 c = self.db.cursor() 141 142 if hostname is None: 142 143 c.execute(""" 143 144 SELECT data 144 145 FROM settings 145 WHERE value LIKE( '%s') AND hostname IS NULL LIMIT 1""" %146 (value ))146 WHERE value LIKE(%s) AND hostname IS NULL LIMIT 1""", 147 (value,)) 147 148 else: 149 hostname += '%' 148 150 c.execute(""" 149 151 SELECT data 150 152 FROM settings 151 WHERE value LIKE( '%s') AND hostname LIKE('%s%%') LIMIT 1""" %153 WHERE value LIKE(%s) AND hostname LIKE(%s) LIMIT 1""", 152 154 (value, hostname)) 153 155 row = c.fetchone() 154 156 c.close() … … 162 164 """ 163 165 Sets the value for the given MythTV setting. 164 166 """ 165 log.Msg(DEBUG, 'Setting %s for host %s to %s', value, hostname, data)167 # log.Msg(DEBUG, 'Setting %s for host %s to %s', value, hostname, data) 166 168 c = self.db.cursor() 167 169 ws = None 168 170 ss = None 171 t = None 169 172 170 173 if hostname is None: 171 ws = "WHERE value LIKE ('%s') AND hostname IS NULL" % (value) 172 ss = "(value,data) VALUES ('%s','%s')" % (value, data) 174 ws = "WHERE value LIKE (%s) AND hostname IS NULL" 175 ss = "(data,value) VALUES (%s,%s)" 176 t = (data, value) 173 177 else: 174 ws = "WHERE value LIKE ('%s') AND hostname LIKE ('%s%%')" % (value, hostname) 175 ss = "(value,data,hostname) VALUES ('%s','%s','%s')" % (value, data, hostname) 178 hostname += '%' 179 ws = "WHERE value LIKE (%s) AND hostname LIKE (%s)" 180 ss = "(data, value, hostname) VALUES (%s,%s,%s)" 181 t = (data, value, hostname) 176 182 177 if c.execute("""UPDATE settings SET data %s LIMIT 1""" % ws) == 0:178 c.execute("""INSERT INTO settings %s""" % ss )183 if c.execute("""UPDATE settings SET data=%%s %s LIMIT 1""" % ws, t) == 0: 184 c.execute("""INSERT INTO settings %s""" % ss, t) 179 185 c.close() 180 186 181 187 def getCast(self, chanid, starttime, roles=None): … … 187 193 """ 188 194 if roles is None: 189 195 c = self.db.cursor() 190 length = c.execute("SELECT name,role FROM people,credits WHERE people.person=credits.person AND chanid=%d AND starttime=%d ORDER BY role" % (chanid, starttime)) 196 length = c.execute("""SELECT name,role 197 FROM people,credits 198 WHERE people.person=credits.person 199 AND chanid=%s AND starttime=%s 200 ORDER BY role""", (chanid, starttime)) 191 201 if length == 0: 192 202 return () 193 203 crole = None … … 208 218 return dict 209 219 elif isinstance(roles,str): 210 220 c = self.db.cursor() 211 length = c.execute("SELECT name FROM people,credits WHERE people.person=credits.person AND chanid=%d AND starttime=%d AND role='%s'" % (chanid, starttime, roles)) 221 length = c.execute("""SELECT name 222 FROM people,credits 223 WHERE people.person=credits.person 224 AND chanid=%s AND starttime=%s 225 AND role=%s""", (chanid, starttime, roles)) 212 226 if length == 0: 213 227 return () 214 228 names = [] … … 217 231 return tuple(names) 218 232 elif isinstance(roles,tuple): 219 233 c = self.db.cursor() 220 length = c.execute("SELECT name FROM people,credits WHERE people.person=credits.person AND chanid=%d AND starttime=%d AND role IN %s" % (chanid, starttime, roles)) 234 length = c.execute("""SELECT name 235 FROM people,credits 236 WHERE people.person=credits.person 237 AND chanid='%s' AND starttime='%s' 238 AND role IN %s"""% (chanid, starttime, roles)) 221 239 if length == 0: 222 240 return () 223 241 names = [] … … 225 243 names.append(name[0]) 226 244 return tuple(names) 227 245 246 def getStorageGroup(self, group=None, host=None): 247 """ 248 Returns tuple of dictionaries containing storage group directories 249 with the fields 'id', 'group', 'host', and 'dirname' 250 Takes an optional group and host for filtering 251 """ 252 c = self.db.cursor() 253 q1 = 'SELECT * FROM storagegroup' 254 q2 = 'ORDER BY id' 255 if host: 256 host += '%' 257 if group and host: 258 c.execute("""%s 259 WHERE groupname=%%s 260 AND hostname like %%s 261 %s""" % (q1,q2), (group, host)) 262 elif group: 263 c.execute("""%s 264 WHERE groupname=%%s 265 %s""" % (q1,q2), (group,)) 266 elif host: 267 c.execute("""%s 268 WHERE hostname like %%s 269 %s""" % (q1,q2), (host,)) 270 else: 271 c.execute("""%s %s""" % (q1,q2)) 272 ret = [] 273 for i in c.fetchall(): 274 if not i[3][-1] == '/': 275 i[3] += '/' 276 ret.append({'id':i[0], 'group':i[1], 'host':i[2], 'dirname':i[3]}) 277 return tuple(ret) 278 279 def getChannels(self): 280 """ 281 Returns a tuple of channel object defined in the database 282 """ 283 channels = [] 284 c = self.db.cursor() 285 c.execute("""SELECT * FROM channel""") 286 for row in c.fetchall(): 287 channels.append(Channel(row)) 288 c.close() 289 return tuple(channels) 290 291 def getChannel(self,chanid): 292 """ 293 Returns a single channel object for the given chanid 294 """ 295 c = self.db.cursor() 296 if c.execute("""SELECT * FROM channel 297 WHERE chanid=%s""", (chanid,)): 298 return Channel(c.fetchone()) 299 else: 300 return None 301 302 def getGuideData(self, chanid, date): 303 """ 304 Returns tuple of guide data for one channel on one date 305 """ 306 guide = [] 307 c = self.db.cursor() 308 c.execute("""SELECT * FROM program 309 WHERE chanid=%s AND DATE(starttime)=%s""", 310 (chanid,date)) 311 for show in c.fetchall(): 312 guide.append(Guide(show)) 313 c.close() 314 return tuple(guide) 315 228 316 def cursor(self): 229 317 return self.db.cursor() 230 318 … … 251 339 if self.mythdb is None: 252 340 self.mythdb = MythDB() 253 341 c = self.mythdb.cursor() 254 c.execute("SELECT chanid,starttime FROM jobqueue WHERE id=%d" % self.jobid) 342 c.execute("""SELECT chanid,starttime FROM jobqueue 343 WHERE id=%s""", (self.jobid)) 255 344 self.chanid, self.starttime = c.fetchone() 256 345 c.close() 257 346 … … 260 349 self.mythdb = MythDB() 261 350 if self.jobid is None: 262 351 c = self.mythdb.cursor() 263 c.execute("SELECT id FROM jobqueue WHERE chanid=%d AND starttime=%d" % (self.chanid, self.starttime)) 352 c.execute(""""SELECT id FROM jobqueue 353 WHERE chanid=%s AND starttime=%s""", 354 (self.chanid, self.starttime)) 264 355 self.jobid = c.fetchone()[0] 265 356 c.close() 266 357 return self.jobid … … 270 361 self.mythdb = MythDB() 271 362 if self.host is None: 272 363 c = self.mythdb.cursor() 273 c.execute("SELECT hostname FROM jobqueue WHERE id=%d" % self.jobid) 364 c.execute("""SELECT hostname FROM jobqueue 365 WHERE id=%s""", (self.jobid)) 274 366 self.host = c.fetchone()[0] 275 367 c.close() 276 368 return self.host … … 279 371 if self.mythdb is None: 280 372 self.mythdb = MythDB() 281 373 c = self.mythdb.cursor() 282 c.execute("UPDATE jobqueue SET comment='%s' WHERE id=%d" % (comment,self.jobid)) 374 c.execute("""UPDATE jobqueue SET comment=%s 375 WHERE id=%s""", (comment,self.jobid)) 283 376 c.close() 284 377 285 378 def setStatus(self,status): 286 379 if self.mythdb is None: 287 380 self.mythdb = MythDB() 288 381 c = self.mythdb.cursor() 289 c.execute("UPDATE jobqueue SET status=%d WHERE id=%d" % (status,self.jobid)) 382 c.execute("""UPDATE jobqueue SET status=%s 383 WHERE id=%s""", (status,self.jobid)) 290 384 c.close() 291 385 386 class Channel: 387 """ 388 Represents a single channel from the channel table 389 """ 390 def __str__(self): 391 return "%s (%s)" % (self.chanid, self.name) 392 393 def __repr__(self): 394 return "%s (%s)" % (self.chanid, self.name) 395 396 def __init__(self,data): 397 """ 398 Load data into object 399 """ 400 self.chanid = data[0] 401 self.channum = data[1] 402 self.freqid = data[2] 403 self.sourceid = data[3] 404 self.callsign = data[4] 405 self.name = data[5] 406 self.icon = data[6] 407 self.finetune = data[7] 408 self.videofilters = data[8] 409 self.xmltvid = data[9] 410 self.recpriority = data[10] 411 self.contrast = data[11] 412 self.brightness = data[12] 413 self.colour = data[13] 414 self.hue = data[14] 415 self.tvformat = data[15] 416 self.visible = data[16] 417 self.outputfiters = data[17] 418 self.useonairguide = data[18] 419 self.mplexid = data[19] 420 self.serviceid = data[20] 421 self.tmoffset = data[21] 422 self.atsc_major_chan = data[22] 423 self.atsc_minor_chan = data[23] 424 self.last_record = data[24] 425 self.default_authority = data[25] 426 self.commmethod = data[26] 427 428 class Guide: 429 """ 430 Represents a single program from the program guide 431 """ 432 def __str__(self): 433 return "%s (%s)" % (self.title, self.starttime.strftime('%Y-%m-%d %H:%M:%S')) 434 435 def __repr__(self): 436 return "%s (%s)" % (self.title, self.starttime.strftime('%Y-%m-%d %H:%M:%S')) 437 438 def __init__(self,data): 439 """ 440 Load data into the object 441 """ 442 self.chanid = data[0] 443 self.starttime = data[1] 444 self.endtime = data[2] 445 self.title = data[3] 446 self.subtitle = data[4] 447 self.description = data[5] 448 self.category = data[6] 449 self.category_type = data[7] 450 self.airdate = data[8] 451 self.stars = data[9] 452 self.previouslyshown = data[10] 453 self.title_pronounce = data[11] 454 self.stereo = data[12] 455 self.subtitled = data[13] 456 self.hdtv = data[14] 457 self.closecaptioned = data[15] 458 self.partnumber = data[16] 459 self.parttotal = data[17] 460 self.seriesid = data[18] 461 self.originalairdate = data[19] 462 self.showtype = data[20] 463 self.colorcode = data[21] 464 self.syndicatedepisodenumber = data[22] 465 self.programid = data[23] 466 self.manualid = data[24] 467 self.generic = data[25] 468 self.listingsource = data[26] 469 self.first = data[27] 470 self.last = data[28] 471 self.audioprop = data[29] 472 self.subtitletypes = data[30] 473 self.videoprop = data[31] 474 475 476 292 477 if __name__ == '__main__': 293 478 banner = "'mdb' is a MythDB instance." 294 479 try: