| 1 | #!/usr/bin/python
|
|---|
| 2 |
|
|---|
| 3 | # vim:ts=4 sw=4 nowrap:
|
|---|
| 4 |
|
|---|
| 5 | # system imports
|
|---|
| 6 | import os
|
|---|
| 7 | import sys
|
|---|
| 8 | import shlex
|
|---|
| 9 | import code
|
|---|
| 10 | import getopt
|
|---|
| 11 | from datetime import datetime
|
|---|
| 12 | # MythTV imports
|
|---|
| 13 | from MythLog import *
|
|---|
| 14 |
|
|---|
| 15 |
|
|---|
| 16 | # create logging object
|
|---|
| 17 | log = MythLog(INFO, '%(levelname)s - %(message)s', 'MythDB')
|
|---|
| 18 |
|
|---|
| 19 | # check for dependency
|
|---|
| 20 | try:
|
|---|
| 21 | import MySQLdb
|
|---|
| 22 | except:
|
|---|
| 23 | log.Msg(CRITICAL, "MySQLdb (python-mysqldb) is required but is not found.")
|
|---|
| 24 | sys.exit(1)
|
|---|
| 25 |
|
|---|
| 26 |
|
|---|
| 27 |
|
|---|
| 28 | class MythDB:
|
|---|
| 29 | """
|
|---|
| 30 | A connection to the mythtv database.
|
|---|
| 31 | """
|
|---|
| 32 | def __init__(self, args):
|
|---|
| 33 | # Setup connection variables
|
|---|
| 34 | dbconn = {
|
|---|
| 35 | 'host' : None,
|
|---|
| 36 | 'name' : None,
|
|---|
| 37 | 'user' : None,
|
|---|
| 38 | 'pass' : None
|
|---|
| 39 | }
|
|---|
| 40 |
|
|---|
| 41 | # Try to read the mysql.txt file used by MythTV.
|
|---|
| 42 | # Order taken from libs/libmyth/mythcontext.cpp
|
|---|
| 43 | config_files = [
|
|---|
| 44 | '/usr/local/share/mythtv/mysql.txt',
|
|---|
| 45 | '/usr/share/mythtv/mysql.txt',
|
|---|
| 46 | '/usr/local/etc/mythtv/mysql.txt',
|
|---|
| 47 | '/etc/mythtv/mysql.txt',
|
|---|
| 48 | os.path.expanduser('~/.mythtv/mysql.txt'),
|
|---|
| 49 | ]
|
|---|
| 50 | if 'MYTHCONFDIR' in os.environ:
|
|---|
| 51 | config_locations.append('%s/mysql.txt' % os.environ['MYTHCONFDIR'])
|
|---|
| 52 |
|
|---|
| 53 | found_config = False
|
|---|
| 54 | for config_file in config_files:
|
|---|
| 55 | try:
|
|---|
| 56 | config = shlex.shlex(open(config_file))
|
|---|
| 57 | config.wordchars += "."
|
|---|
| 58 | except:
|
|---|
| 59 | continue
|
|---|
| 60 |
|
|---|
| 61 | dbconn['host'] = None
|
|---|
| 62 | dbconn['name'] = None
|
|---|
| 63 | dbconn['user'] = None
|
|---|
| 64 | dbconn['pass'] = None
|
|---|
| 65 | token = config.get_token()
|
|---|
| 66 | while token != config.eof and not found_config:
|
|---|
| 67 | if token == "DBHostName":
|
|---|
| 68 | if config.get_token() == "=":
|
|---|
| 69 | dbconn['host'] = config.get_token()
|
|---|
| 70 | elif token == "DBName":
|
|---|
| 71 | if config.get_token() == "=":
|
|---|
| 72 | dbconn['name'] = config.get_token()
|
|---|
| 73 | elif token == "DBUserName":
|
|---|
| 74 | if config.get_token() == "=":
|
|---|
| 75 | dbconn['user'] = config.get_token()
|
|---|
| 76 | elif token == "DBPassword":
|
|---|
| 77 | if config.get_token() == "=":
|
|---|
| 78 | dbconn['pass'] = config.get_token()
|
|---|
| 79 | token = config.get_token()
|
|---|
| 80 | if dbconn['host'] != None and dbconn['name'] != None and dbconn['user'] != None and dbconn['pass'] != None:
|
|---|
| 81 | log.Msg(INFO, 'Using config %s', config_file)
|
|---|
| 82 | found_config = True
|
|---|
| 83 | break
|
|---|
| 84 |
|
|---|
| 85 | # Overrides from command line parameters
|
|---|
| 86 | try:
|
|---|
| 87 | opts, args = getopt.getopt(args, '', ['dbhost=', 'user=', 'pass=', 'database='])
|
|---|
| 88 | for o, a in opts:
|
|---|
| 89 | if o == '--dbhost':
|
|---|
| 90 | dbconn['host'] = a
|
|---|
| 91 | if o == '--user':
|
|---|
| 92 | dbconn['user'] = a
|
|---|
| 93 | if o == '--pass':
|
|---|
| 94 | dbconn['pass'] = a
|
|---|
| 95 | if o == '--database':
|
|---|
| 96 | dbconn['name'] = a
|
|---|
| 97 | except:
|
|---|
| 98 | pass
|
|---|
| 99 |
|
|---|
| 100 | if not dbconn['host'] and not found_config:
|
|---|
| 101 | raise MythError('Unable to find MythTV configuration file')
|
|---|
| 102 |
|
|---|
| 103 | try:
|
|---|
| 104 | self.db = MySQLdb.connect(user=dbconn['user'], host=dbconn['host'], passwd=dbconn['pass'], db=dbconn['name'])
|
|---|
| 105 | log.Msg(INFO, 'DB Connection info (host:%s, name:%s, user:%s, pass:%s)', dbconn['host'], dbconn['name'], dbconn['user'], dbconn['pass'])
|
|---|
| 106 | except:
|
|---|
| 107 | raise MythError('Connection failed for \'%s\'@\'%s\' to database %s using password %s' % (dbconn['user'], dbconn['host'], dbconn['name'], dbconn['pass']))
|
|---|
| 108 |
|
|---|
| 109 |
|
|---|
| 110 |
|
|---|
| 111 | def getAllSettings(self, hostname=None):
|
|---|
| 112 | """
|
|---|
| 113 | Returns values for all settings.
|
|---|
| 114 |
|
|---|
| 115 | Returns None if there are no settings. If multiple rows are
|
|---|
| 116 | found (multiple hostnames), returns the value of the first one.
|
|---|
| 117 | """
|
|---|
| 118 | log.Msg(DEBUG, 'Retrieving all setting for host %s', hostname)
|
|---|
| 119 | c = self.db.cursor()
|
|---|
| 120 | if hostname is None:
|
|---|
| 121 | c.execute("""
|
|---|
| 122 | SELECT value, data
|
|---|
| 123 | FROM settings
|
|---|
| 124 | WHERE hostname IS NULL""")
|
|---|
| 125 | else:
|
|---|
| 126 | c.execute("""
|
|---|
| 127 | SELECT value, data
|
|---|
| 128 | FROM settings
|
|---|
| 129 | WHERE hostname LIKE('%s%%')""" %
|
|---|
| 130 | (hostname)
|
|---|
| 131 | )
|
|---|
| 132 | rows = c.fetchall()
|
|---|
| 133 | c.close()
|
|---|
| 134 |
|
|---|
| 135 | if rows:
|
|---|
| 136 | return rows
|
|---|
| 137 | else:
|
|---|
| 138 | return None
|
|---|
| 139 |
|
|---|
| 140 |
|
|---|
| 141 |
|
|---|
| 142 | def getSetting(self, value, hostname=None):
|
|---|
| 143 | """
|
|---|
| 144 | Returns the value for the given MythTV setting.
|
|---|
| 145 |
|
|---|
| 146 | Returns None if the setting was not found. If multiple rows are
|
|---|
| 147 | found (multiple hostnames), returns the value of the first one.
|
|---|
| 148 | """
|
|---|
| 149 | log.Msg(DEBUG, 'Looking for setting %s for host %s', value, hostname)
|
|---|
| 150 | c = self.db.cursor()
|
|---|
| 151 | if hostname is None:
|
|---|
| 152 | c.execute("""
|
|---|
| 153 | SELECT data
|
|---|
| 154 | FROM settings
|
|---|
| 155 | WHERE value LIKE('%s') AND hostname IS NULL LIMIT 1""" %
|
|---|
| 156 | (value))
|
|---|
| 157 | else:
|
|---|
| 158 | c.execute("""
|
|---|
| 159 | SELECT data
|
|---|
| 160 | FROM settings
|
|---|
| 161 | WHERE value LIKE('%s') AND hostname LIKE('%s%%') LIMIT 1""" %
|
|---|
| 162 | (value, hostname))
|
|---|
| 163 | row = c.fetchone()
|
|---|
| 164 | c.close()
|
|---|
| 165 |
|
|---|
| 166 | if row:
|
|---|
| 167 | return row[0]
|
|---|
| 168 | else:
|
|---|
| 169 | return None
|
|---|
| 170 |
|
|---|
| 171 |
|
|---|
| 172 |
|
|---|
| 173 | def cursor(self):
|
|---|
| 174 | return self.db.cursor()
|
|---|
| 175 |
|
|---|
| 176 |
|
|---|
| 177 |
|
|---|
| 178 | if __name__ == '__main__':
|
|---|
| 179 | banner = "'mdb' is a MythDB instance."
|
|---|
| 180 | try:
|
|---|
| 181 | import readline, rlcompleter
|
|---|
| 182 | except:
|
|---|
| 183 | pass
|
|---|
| 184 | else:
|
|---|
| 185 | readline.parse_and_bind("tab: complete")
|
|---|
| 186 | banner = banner + " TAB completion is available."
|
|---|
| 187 | mdb = MythDB(sys.argv[1:])
|
|---|
| 188 | namespace = globals().copy()
|
|---|
| 189 | namespace.update(locals())
|
|---|
| 190 | code.InteractiveConsole(namespace).interact(banner)
|
|---|