def transcode(jobid=None, chanid=None, starttime=None): ' connect to mythtv database ' db = MythDB() be = MythBE(db=db) logging.info("start transcode") if jobid: job = Job(jobid, db=db) chanid = job.chanid starttime = job.starttime logging.info("%s" % jobid) logging.info("%s" % chanid) logging.info("%s" % starttime) rec = Recorded((chanid, starttime), db=db) ' TODO: get the starttime into the correct format (from 20150827014200 to 2015-08-27 00:42:00-06:00)' ' loop all files in lib_dir that are symlinks and find the one that matches this recording ' for ld in LIBDIR: for dp, dn, files in os.walk(ld): for file in files: filepath = os.path.join(dp,file) if (os.path.islink(filepath)): logging.debug("%s -> %s" % (filepath, os.readlink(filepath))) ' do the transode ' ' update the database for the new file name ' ' update the symlink for the new file name '
def __init__(self): self.db = MythDB() self.be = MythBE(db=db) self.vids = {} self._addCallback = doNothing self._events = [self.handleUpdate] self.be.registerevent(self.handleUpdate)
def __init__(self, host=None): self.db = MythDB() self.db.searchRecorded.handler = Recorded self.be = MythBE(db=self.db) self.log = MythLog(db=self.db) self.set_host(host) self.load_backends() self.load_storagegroups()
def test_repr_004_01(self): """ Test '__repr__' and '__str__' methods of 'MythBE' class. Note: MythBE inherits from 'FileOps', which is inherited from 'BeCache'. """ db = MythDB() be = MythBE(db=db) print() print(repr(be)) print(str(be))
def checkRecordingStatus(self): """Checks whether the backend is currently recording.""" try: recbe = MythBE() for recorder in recbe.getRecorderList(): if recbe.isRecording(recorder): self.isrecording = True break except: # If we can't connect to it then it can't be recording. self.isrecording = False
def load_backends(self): with self.db as c: c.execute("""SELECT hostname FROM settings WHERE value='BackendServerIP'""") hosts = [r[0] for r in c.fetchall()] self.hosts = [] for host in hosts: # try to access all defined hosts, and # store the ones currently accessible try: MythBE(backend=host) self.hosts.append(host) except: pass
def getRecordings(self): """Attempts to connect to MythTV backend and retrieve recordings.""" try: # If we can connect then get recordings and save a local cache. self.be = MythBE() uprecs = self.be.getUpcomingRecordings() self.recs = self.recs_to_dict(uprecs) self.cacheRecs(self.recs) self.backendonline = True except: # Can't connect so we need to set variables accordinly and try # to load data from the cache. self.be = None self.recs = self.loadCache() self.backendonline = False
def main(): """Startup function.""" parser = OptionParser(usage="usage: %prog [options]") parser.add_option("--verbose", action="store_true", default=False, help="enable verbose output of MythTV API") parser.add_option( '-f', "--force", action="store_true", default=False, help="non-interactive mode, answer 'yes' to all questions") parser.add_option('-t', "--title", action="store", type="string", help="limit recordings that match title") opts, _ = parser.parse_args() MythLog._setlevel('unknown' if opts.verbose else 'err') # pylint:disable=protected-access try: backend = MythBE() recs = [ r for r in list(backend.getRecordings()) if r.recgroup == 'Deleted' ] if opts.title: recs = [ r for r in recs if re.findall(opts.title, r.title, re.IGNORECASE) ] if len(recs) == 0: print('no matching recordings found') sys.exit(0) if opts.force: undelete_all(backend, recs) else: interactive_undelete(backend, recs) except MythDBError as e: if e.name == 'DB_CREDENTIALS': print("ERROR: Could not find MythDB host:port OR correct login " "credentials!") sys.exit(-1) else: raise sys.exit(0)
def main(opts): MythBE.getPendingRecordings.handler = MyProgram be = MythBE() now = datetime.now() if not opts.plaintext: print '<h3>Upcoming Recordings:</h3>' print '<div class="schedule">' count = 0 for rec in be.getPendingRecordings(): if not ((opts.filter & 2**0 and rec.is_scheduled) or (opts.filter & 2**1 and rec.is_duplicate) or (opts.filter & 2**2 and rec.is_deactivated) or (opts.filter & 2**3 and rec.is_conflict)): continue if opts.time and (opts.time < rec.recstartts): continue if now > rec.recendts: continue if opts.count and (opts.count <= count): break count += 1 if opts.plaintext: print '{0} - {1}'.format(rec.starttime.strftime('%m/%d, %I:%M %p'), rec.callsign) if rec.subtitle: print '{0.title} - {0.subtitle}'.format(rec) else: print '{0.title}'.format(rec) print rec.description print '' else: print '<a href="#">{0} - {1} - {2}'.format( rec.starttime.strftime('%m/%d, %I:%M %p'), rec.callsign, rec.title), if rec.subtitle: print rec.subtitle, print '<br /><span><strong>{0.title}</strong>'.format(rec), print rec.starttime.strftime('%m/%d, %I:%M %p'), print '<br /><em>{0.description}<br/></span></a><hr />' if not opts.plaintext: print '</div>'
def __init__(self, opts, jobid=None): # Setup for the job to run if jobid: self.thisJob = Job(jobid) self.chanID = self.thisJob.chanid self.startTime = self.thisJob.starttime self.thisJob.update(status=Job.STARTING) # If no job ID given, must be a command line run else: self.thisJob = jobid self.chanID = opts.chanid self.startTime = opts.startdate + " " + opts.starttime + opts.offset self.opts = opts self.type = "none" self.db = MythDB() self.log = MythLog(module='Myth-Rec-to-Vid.py', db=self.db) # Capture the backend host name self.host = self.db.gethostname() # prep objects self.rec = Recorded((self.chanID, self.startTime), db=self.db) self.log( MythLog.GENERAL, MythLog.INFO, 'Using recording', '%s - %s' % (self.rec.title.encode('utf-8'), self.rec.subtitle.encode('utf-8'))) self.vid = Video(db=self.db).create({ 'title': '', 'filename': '', 'host': self.host }) self.bend = MythBE(db=self.db)
def copy(self): stime = time.time() srcsize = self.rec.filesize htime = [stime, stime, stime, stime] self.log(MythLog.GENERAL|MythLog.FILE, MythLog.INFO, "Copying myth://%s@%s/%s"\ % (self.rec.storagegroup, self.rec.hostname, self.rec.basename)\ +" to myth://Videos@%s/%s"\ % (self.vid.host, self.vid.filename)) srcfp = self.rec.open('r') dstfp = self.vid.open('w', nooverwrite=True) if self.job: self.job.setStatus(Job.RUNNING) tsize = 2**24 while tsize == 2**24: tsize = min(tsize, srcsize - dstfp.tell()) dstfp.write(srcfp.read(tsize)) htime.append(time.time()) rate = float(tsize * 4) / (time.time() - htime.pop(0)) remt = (srcsize - dstfp.tell()) / rate if self.job: self.job.setComment("%02d%% complete - %d seconds remaining" %\ (dstfp.tell()*100/srcsize, remt)) srcfp.close() dstfp.close() self.vid.hash = self.vid.getHash() self.log(MythLog.GENERAL | MythLog.FILE, MythLog.INFO, "Transfer Complete", "%d seconds elapsed" % int(time.time() - stime)) if self.opts.reallysafe: if self.job: self.job.setComment("Checking file hashes") self.log(MythLog.GENERAL | MythLog.FILE, MythLog.INFO, "Checking file hashes.") srchash = hashfile(self.rec.open('r')) dsthash = hashfile(self.vid.open('r')) if srchash != dsthash: raise MythError('Source hash (%s) does not match destination hash (%s)' \ % (srchash, dsthash)) elif self.opts.safe: self.log(MythLog.GENERAL | MythLog.FILE, MythLog.INFO, "Checking file sizes.") be = MythBE(db=self.vid._db) try: srcsize = be.getSGFile(self.rec.hostname, self.rec.storagegroup, \ self.rec.basename)[1] dstsize = be.getSGFile(self.vid.host, 'Videos', self.vid.filename)[1] except: raise MythError('Could not query file size from backend') if srcsize != dstsize: raise MythError('Source size (%d) does not match destination size (%d)' \ % (srcsize, dstsize)) if self.job: self.job.setComment("Complete - %d seconds elapsed" % \ (int(time.time()-stime))) self.job.setStatus(Job.FINISHED)
def setUp(self): with add_log_flags(): self.mydb = MythDB() self.mybe = MythBE(db=self.mydb)
def delete(self): be = MythBE(self.host, db=DB) be.deleteFile(self, self.group)
def __init__(self): self.be = MythBE() self.recs = {} self._events = [self.handleAdd, self.handleDelete, self.handleUpdate] for e in self._events: self.be.registerevent(e)
def filepathToScreenshotFromRecording(recording): filepath = filepathFromRecording(recording) return filepath + ".png" db = None db = MythDB() if db == None: print "Database could not be open or found" exit() be = None be = MythBE() if be == None: print "Backend could not be found." #exit() recordings = be.getRecordings() for r in recordings: filepath = filepathFromRecording(r) size = -1 try: size = os.path.getsize(filepath) / 1024 / 1024 except: size = "NaN"
res = int(res) except: res = input('input number. ctrl-c to exit > ') continue if (res <= 0) or (res > len(opts)): res = input('input number within range > ') continue break opt = opts[res - 1] if opt[1] is None: continue else: opt[1](opt[2]) except KeyboardInterrupt: break except EOFError: sys.exit(0) DB = MythDB() BE = MythBE(db=DB) DB.searchRecorded.handler = MyRecorded DB.searchRecorded.dbclass = MyRecorded if __name__ == '__main__': if len(sys.argv) == 2: main(sys.argv[1]) else: main()
def delete(self): be = MythBE(self.hosts[0], db=self.db) be.deleteFile(self, self.group)
def main(): parser = OptionParser(usage="usage: option [option] [option]") maintenancegroup = OptionGroup( parser, "Maintenance", "These options can be used to perform DB cleanup.") maintenancegroup.add_option( "--dedup", action="store_true", default=False, dest="dedup", help="checks for duplicate entries in the Video database") maintenancegroup.add_option("--check_orphans", action="store_true", default=False, dest="check_orphans", help="checks for orphaned DB entries in Video") parser.add_option_group(maintenancegroup) actiongroup = OptionGroup(parser, "Meta Updates", "This option updates Video Meta Data") actiongroup.add_option('--update', action='store_true', default=False, dest='update', help='Updates the video meta data on each entry') parser.add_option_group(actiongroup) othergroup = OptionGroup(parser, 'Other Options', "These options allow for additional controls") othergroup.add_option( '--folder', action='store', type='string', dest='folder', help='Limits actions to Videos in a specified folder,\ example "Movies" would limit to any filename \ starting with Movies/some_video_file.mpg') othergroup.add_option( '--step', action="store_true", default=False, dest='step', help='Steps through each action to allow evaluation of \ process') parser.add_option_group(othergroup) opts, args = parser.parse_args() # if a manual channel and time entry then setup the export with opts # sys.exit(1) # setup the connection to the DB db = MythDB() be = MythBE() #Setup a scanner for all videos in the DB videos = db.searchVideos() # setup a Video object to work with def get_Meta(item): metadata = item.exportMetadata() if not item.filename.startswith('Television'): grab = VideoGrabber('Movie') if item.get('inetref') != '00000000': try: match = grab.grabInetref(item.inetref) item.importMetadata(match) item.plot = match.get('description') item.title = match.get('title') copy_Art(match, item) item.update() return except Exception: print 'grabber failed for: ' + str(item.get('inetref')) print 'trying by name instead' try: results = grab.sortedSearch(item.title) except Exception, e: print 'grabber failed for: ' + str(item.get('inetref')) print e return if len(results) > 0: if len(results) > 1: menu = {} list = 1 for each in results: menu[list]= each.title + ', year: ' + str(each.get('year')) \ + ', inetref: ' + str(each.get('inetref')) list = list + 1 menu[list] = 'Skip to next video\n\n' print '\n' while True: options = menu.keys() options.sort() for entry in options: print entry, menu[entry] try: selection = input("Please Select: ") if selection in range(1, len(results) + 1): listing = results[selection - 1] break elif selection == len(results) + 1: return else: print "Invalid Selection, try again!\n\n" except Exception: print "Invalid Selection, try again!\n\n" else: listing = results[0] try: match = grab.grabInetref(listing.get('inetref')) item.importMetadata(match) item.plot = match.get('description') item.title = match.get('title') copy_Art(match, item) item.update() print 'Full MetaData Import complete for: ' + item.title + '\n' except Exception, e: print 'grabber failed for: ' + str(item.get('inetref')) print e elif len(results) == 0: print 'No MetaData to import for: ' + item.title + '\n'
def showScreen(self): self.surface.fill([0, 0, 0]) if self.be == None: try: recs = [] self.be = MythBE() self.upcomingrecs = self.be.getUpcomingRecordings() for r in self.upcomingrecs: rec = {} rec["title"] = r.title rec["subtitle"] = r.subtitle rec["time"] = r.starttime.strftime("%a %d %b %H:%M") rec["desc"] = r.description recs.append(rec) recorders = MythBE().getRecorderList() for recorder in recorders: if MythBE().isRecording(recorder): self.isrecording = True break self.backendfail = False self.cachedmode = False except: self.backendfail = True if self.backendfail: recs = self.loadCache() if recs: self.backendfail = False self.cachedmode = True if not self.backendfail: self.cacheRecs(recs) screentitle = self.mytitlefont.render("MythTV upcoming recordings", 1, (255, 255, 255)) screenrect = screentitle.get_rect() screenrect.centerx = self.surface.get_rect().centerx screenrect.centery = 20 self.surface.blit(screentitle, screenrect) n = min(len(recs), 5) if n > 0: for i in range(n): mytitlerect = pygame.Rect((0, 0, self.rectwidth, 60)) mytimerect = pygame.Rect((0, 0, self.rectwidth, 30)) mydescrect = pygame.Rect((0, 0, self.rectwidth, 330)) fontcolour = (255, 255, 255) rectcolour = (0, 50, 75) titletext = self.render_textrect(recs[i]["title"], self.myboldfont, mytitlerect, fontcolour, rectcolour, 1) timetext = self.render_textrect(recs[i]["time"], self.myitalicfont, mytimerect, fontcolour, rectcolour, 1) desctext = self.render_textrect(recs[i]["desc"], self.myregularfont, mydescrect, fontcolour, rectcolour, 0, margin=5) self.surface.blit(titletext, ((self.rectwidth * i) + (self.rectgap * (i + 1) + self.rectadjust), 40)) self.surface.blit(timetext, ((self.rectwidth * i) + (self.rectgap * (i + 1) + self.rectadjust), 80)) self.surface.blit(desctext, ((self.rectwidth * i) + (self.rectgap * (i + 1) + self.rectadjust), 105)) if self.cachedmode: mystatus = self.myitalicfont.render( "Backend is offline. Displaying cached recording list", 1, (255, 255, 255)) else: if self.isrecording: recording = "currently" else: recording = "not" mystatus = self.myitalicfont.render( "Backend is online and is " + recording + " recording.", 1, (255, 255, 255)) self.surface.blit(mystatus, (5, 445)) else: failtext = self.myboldfont.render( "No upcoming recordings found.", 1, (255, 255, 255)) failrect = failtext.get_rect() failrect.centerx = self.surface.get_rect().centerx failrect.centery = self.surface.get_rect().centery self.surface.blit(failtext, failrect) else: failtext = self.myboldfont.render("MythTV backend unavailable.", 1, (255, 255, 255)) failrect = failtext.get_rect() failrect.centerx = self.surface.get_rect().centerx failrect.centery = self.surface.get_rect().centery self.surface.blit(failtext, failrect) self.be = None # Scale our surface to the required screensize before sending back scaled = pygame.transform.scale(self.surface, self.screensize) self.screen.blit(scaled, (0, 0)) return self.screen
def getBeObject(databaseObj=getDbObject()): return MythBE(db=databaseObj)
def __init__(self): self.db = MythDB() self.be = MythBE(db=self.db)