22 from __future__
import division
23 from __future__
import print_function
24 from builtins
import range
25 from builtins
import object
26 from past.utils
import old_div
30 from datetime
import timedelta
32 from distros.mythtv_data.orddict
import OrdDict
33 from distros.mythtv_data.uuiddb
import UuidDb
38 _BE = MythTV.MythBE(db=_DB)
39 _SETTINGS = _DB.settings[_DB.gethostname()]
47 return (_SETTINGS.BackendServerIP
is not None)
51 for name
in [
'version',
'branch',
'protocol',
'libapi',
'qtversion']:
52 data[name] =
'Unknown'
54 executables = (
'mythutil',
'mythbackend',
'mythfrontend')
56 for executable
in executables:
57 execpath = os.path.join(MythTV.static.INSTALL_PREFIX,
60 cmd = MythTV.System(execpath)
61 res = cmd.command(
'--version')
68 names = {
'MythTV Version' :
'version',
69 'MythTV Branch' :
'branch',
70 'Network Protocol':
'protocol',
71 'Library API' :
'libapi',
72 'QT Version' :
'qtversion'}
74 for line
in res.decode().split(
'\n'):
76 prop, val = line.split(
':')
77 data[names[prop.strip()]] = val.strip()
82 def td_to_secs(self,td):
return td.days*86400 + td.seconds
90 data = {
'scheduled': rdata,
95 progs = list(MythTV.Recorded.getAllEntries())
96 upcoming = list(_BE.getUpcomingRecordings())
97 livetv = [prog
for prog
in progs
if prog.recgroup ==
'LiveTV']
98 recs = [prog
for prog
in progs
if prog.recgroup !=
'LiveTV']
99 expireable = [prog
for prog
in recs
if prog.autoexpire]
102 for dataset
in (recs, expireable, livetv, upcoming):
105 deltas = [rec.endtime-rec.starttime
for rec
in dataset]
107 deltas = [rec.recendts-rec.recstartts
for rec
in dataset]
115 rdata.count = len(recs)
116 rdata.size = sum([rec.filesize
for rec
in recs])
117 rdata.time = times[0]
119 edata.count = len(expireable)
120 edata.size = sum([rec.filesize
for rec
in expireable])
121 edata.time = times[1]
123 ldata.count = len(livetv)
124 ldata.size = sum([rec.filesize
for rec
in livetv])
125 ldata.time = times[2]
127 udata.count = len(upcoming)
128 udata.time = times[3]
130 return {
'recordings': data}
139 recs = list(MythTV.OldRecorded.getAllEntries())
146 maxage = MythTV.utility.datetime(2001,1,1,0,0)
149 if (rec.starttime < oldest.starttime)
and (rec.starttime > maxage):
151 data.rectime += self.
td_to_secs(rec.endtime - rec.starttime)
152 if rec.recstatus == -3:
153 shows.append(rec.title)
156 data.db_age = self.
td_to_secs(MythTV.utility.datetime.now() - oldest.starttime)
157 data.showcount = len(set(shows))
158 return {
'historical': data}
165 usedsources = list(set([inp.sourceid
for inp
in CaptureCard.getAllEntries()]))
166 grabbers = list(set([
VideoSource(id).xmltvgrabber
for id
in usedsources]))
167 data.sourcecount = len(usedsources)
168 data.grabbers = grabbers
173 data.timezone =
'Unknown'
176 res = _BE.backendCommand(
'QUERY_TIME_ZONE').split(
'[]:[]')
177 data.timezone = res[0]
178 data.tzoffset = int(res[1])
182 def processdirs(paths):
188 stat = os.statvfs(path)
189 bsize = stat.f_frsize
190 total += stat.f_blocks*bsize
191 free += stat.f_bfree*bsize
206 sgnames = [rec.storagegroup
for rec
in MythTV.Recorded.getAllEntries()]
207 sgnames += [rec.storagegroup
for rec
in MythTV.Record.getAllEntries()]
208 sgnames = list(set(sgnames))
211 for host
in set([_DB.gethostname(), _BE.hostname]):
212 for sgname
in sgnames:
213 for sg
in _DB.getStorageGroup(sgname, host):
215 sgs.append(sg.dirname)
216 data.rectotal, data.recfree = processdirs(sgs)
218 sgs = [sg.dirname
for sg
in _DB.getStorageGroup(
'Videos', _DB.gethostname())
if sg.local]
219 data.videototal, data.videofree = processdirs(sgs)
221 return {
'storage': data}
227 return bool(int(val))
229 def _read_file(filename):
232 with open(filename,
'r')
as f:
234 firstline = line.split()
243 alsasnd =
"/proc/asound/version"
244 osssnd =
"/dev/sndstat"
246 if os.path.exists(alsasnd):
248 version = _read_file(alsasnd)[-1].rstrip(
".")
250 elif os.path.exists(osssnd):
251 version = _read_file(osssnd)[1]
254 return snd_type , version
256 def _process_search(processname):
258 for line
in os.popen(
"ps xa"):
259 fields = line.split()
261 process = fields[4].split(
"/")
262 if processname
in process :
268 if _process_search(
"jackd")
or _process_search(
"jackdbus"):
275 if _process_search(
"pulseaudio"):
283 data.device = _SETTINGS.AudioOutputDevice
284 data.passthrudevice = _SETTINGS.PassThruOutputDevice
285 data.passthruoverride = _bool(_SETTINGS.PassThruDeviceOverride)
286 data.stereopcm = _bool(_SETTINGS.StereoPCM)
287 data.sr_override = _bool(_SETTINGS.Audio48kOverride)
288 data.maxchannels = _SETTINGS.MaxChannels
289 data.defaultupmix = _bool(_SETTINGS.AudioDefaultUpmix)
290 data.upmixtype = _SETTINGS.AudioUpmixType
292 for k,v
in ((
'AC3PassThru',
'ac3'), (
'DTSPassThru',
'dts'),
293 (
'HBRPassthru',
'hbr'), (
'EAC3PassThru',
'eac3'),
294 (
'TrueHDPassThru',
'truehd'), (
'DTSHDPassThru',
'dtshd')):
295 if _bool(_SETTINGS[k]):
298 data.volcontrol = _bool(_SETTINGS.MythControlsVolume)
299 data.mixerdevice = _SETTINGS.MixerDevice
300 data.mixercontrol = _SETTINGS.MixerControl
302 data.pulse = _pulse()
303 data.audio_sys, data.audio_sys_version = _oss_alsa()
305 return {
'audio': data}
308 class DisplayProfileGroups( MythTV.database.DBData ):
pass
309 class DisplayProfiles(
OrdDict ):
310 def __new__(cls, *args, **kwargs):
311 inst = super(DisplayProfiles, cls).__new__(cls, *args, **kwargs)
312 inst.__dict__[
'_profilegroupid'] =
None
313 inst.__dict__[
'_profileid'] =
None
314 inst.__dict__[
'_db'] =
None
317 def __init__(self, profilegroupid, profileid, db=None):
318 self.
_db = MythTV.database.DBCache(db=db)
322 cursor.execute(
"""SELECT value,data FROM displayprofiles
323 WHERE profilegroupid=%s
325 (profilegroupid, profileid))
326 for k,v
in cursor.fetchall():
330 def fromProfileGroup(cls, profilegroupid, db=None):
331 db = MythTV.database.DBCache(db=db)
333 cursor.execute(
"""SELECT DISTINCT(profileid)
335 WHERE profilegroupid=%s""",
337 for profileid
in cursor.fetchall():
338 yield cls(profilegroupid, profileid[0], db)
341 data.name = _SETTINGS.DefaultVideoPlaybackProfile
344 profilegroupid = DisplayProfileGroups((data.name, _DB.gethostname()), _DB)\
346 for profile
in DisplayProfiles.fromProfileGroup(profilegroupid, _DB):
348 d.decoder = profile.pref_decoder
349 d.deint_pri = profile.pref_deint0
350 d.deint_sec = profile.pref_deint1
351 d.renderer = profile.pref_videorenderer
352 d.filters = profile.pref_filters
353 data.profiles.append(d)
355 return {
'playbackprofile':data}
361 c.execute(
"""SELECT VERSION()""")
362 data.version = c.fetchone()[0]
364 c.execute(
"""SHOW ENGINES""")
365 data.engines = [r[0]
for r
in c.fetchall()]
367 c.execute(
"""SHOW TABLE STATUS WHERE NAME='settings'""")
368 data.usedengine = c.fetchone()[1]
371 c.execute(
"""SELECT value,data FROM settings
372 WHERE value LIKE '%SchemaVer'""")
373 for k,v
in c.fetchall():
376 return {
'database':data}
380 avg = old_div(sum(data),len(data))
381 return avg, (old_div(sum([(d-avg)**2
for d
in data]),len(data)))**.5
386 data.match_stddev = 0
388 data.place_stddev = 0
390 r = re.compile(
'Scheduled ([0-9]*) items in [0-9.]* = ([0-9.]*) match \+ ([0-9.]*) place')
394 c.execute(
"""SELECT details FROM mythlog
395 WHERE module='scheduler'
396 AND message='Scheduled items'""")
398 runs = [r.match(d[0]).groups()
for d
in c.fetchall()]
401 return {
'scheduler': data}
403 a,s = stddev([float(r[2])
for r
in runs])
404 for i,r
in reversed(list(enumerate(runs))):
405 if abs(float(r[2]) - a) > (3*s):
410 count = [float(r[0])
for r
in runs]
411 match = [float(r[1])
for r
in runs]
412 place = [float(r[2])
for r
in runs]
414 data.count = int(old_div(sum(count),len(count)))
415 data.match_avg, data.match_stddev = stddev(match)
416 data.place_avg, data.place_stddev = stddev(place)
418 return {
'scheduler': data}
426 virtualtypes = (
'DVB',
'HDHOMERUN',
'SATIP',
'ASI')
428 for card
in CaptureCard.getAllEntries(db=_DB):
429 isvirt = (card.cardtype
in virtualtypes)
430 loc = card.videodevice+
'@'+card.hostname
431 if card.cardtype
not in cardtypes:
432 cardtypes[card.cardtype] = [loc]
435 if loc
not in cardtypes[card.cardtype]:
436 cardtypes[card.cardtype].append(loc)
441 data = {
'tuners':
dict([(k,len(v))
for k,v
in list(cardtypes.items())])}
443 data[
'vtpertuner'] = old_div(sum(virtual),float(virtual[0]))
447 smoltfile=os.path.expanduser(
'~') +
"/.mythtv/smolt.info"
450 config_file= open(smoltfile)
451 for line
in config_file:
453 if line
and line[0] !=
"#" and line[-1] !=
"=":
454 var,val = line.rsplit(
"=",1)
455 config[var.strip()] = val.strip(
"\"")
460 myth_systemrole = config[
"systemtype" ]
462 myth_systemrole =
'0'
465 mythremote = config[
"remote" ]
467 mythremote =
'unknown'
470 return myth_systemrole , mythremote
474 c.execute(
"""SELECT level,count(level) FROM logging GROUP BY level""")
475 levels = (
'EMERG',
'ALERT',
'CRIT',
'ERR',
476 'WARNING',
'NOTICE',
'INFO')
479 for level,count
in c.fetchall():
480 if level
in range(len(levels)):
481 counts[levels[level]] = count
483 for k,v
in list(counts.items()):
484 counts[k] = old_div(v,total)
485 return {
'logurgency':counts}
502 self.
_data.update(func())
506 self.
_data.theme = _SETTINGS.Theme
507 if _DB.settings.NULL.country
is not None:
508 self.
_data.country = _DB.settings.NULL.country
510 self.
_data.country = _SETTINGS.Country
511 self.
_data.channel_count = len([c
for c
in MythTV.Channel.getAllEntries()
if c.visible])
512 if _DB.settings.NULL.Language
is not None:
513 self.
_data.language = _DB.settings.NULL.Language.lower()
514 elif _SETTINGS.Language
is not None:
515 self.
_data.language = _SETTINGS.Language.lower()
518 self.
_data.language =
'not set'
521 if _DB.settings.NULL.SystemUUID
is None:
522 _DB.settings.NULL.SystemUUID =
UuidDb().gen_uuid()
523 self.
_data.uuid = _DB.settings.NULL.SystemUUID
534 for k,v
in sorted(data.items()):
535 lines.append(
'- %s:\n %s \n' %(k,v))
542 lines.append(
'MythTV Features')
543 lines.append(
'-----------------------------')
550 print(
'\n'.join(lines))
559 if __name__ ==
'__main__':
561 pp = pprint.PrettyPrinter()
562 pp.pprint(get_data())