def push_one_file(self, f): file_info = VideoDetails() file_info['valid'] = transcode.supported_format(f['path']) temp_share = config.get_server('temp_share', '') temp_share_path = '' if temp_share: for name, data in config.getShares(): if temp_share == name: temp_share_path = data.get('path') mime = 'video/mpeg' if config.isHDtivo(f['tsn']): for m in ['video/mp4', 'video/bif']: if transcode.tivo_compatible(f['path'], f['tsn'], m)[0]: mime = m break if (mime == 'video/mpeg' and transcode.mp4_remuxable(f['path'], f['tsn'])): new_path = transcode.mp4_remux(f['path'], f['name'], f['tsn'], temp_share_path) if new_path: mime = 'video/mp4' f['name'] = new_path if temp_share_path: ip = config.get_ip() port = config.getPort() container = quote(temp_share) + '/' f['url'] = 'http://%s:%s/%s' % (ip, port, container) if file_info['valid']: file_info.update(self.metadata_full(f['path'], f['tsn'], mime)) url = f['url'] + quote(f['name']) title = file_info['seriesTitle'] if not title: title = file_info['title'] source = file_info['seriesId'] if not source: source = title subtitle = file_info['episodeTitle'] try: m = mind.getMind(f['tsn']) m.pushVideo( tsn = f['tsn'], url = url, description = file_info['description'], duration = file_info['duration'] / 1000, size = file_info['size'], title = title, subtitle = subtitle, source = source, mime = mime, tvrating = file_info['tvRating']) except Exception, msg: logger.error(msg)
def __est_size(self, full_path, tsn="", mime=""): # Size is estimated by taking audio and video bit rate adding 2% if transcode.tivo_compatible(full_path, tsn, mime)[0]: return int(os.stat(unicode(full_path, "utf-8")).st_size) else: # Must be re-encoded audioBPS = config.getMaxAudioBR(tsn) * 1000 # audioBPS = config.strtod(config.getAudioBR(tsn)) videoBPS = transcode.select_videostr(full_path, tsn) bitrate = audioBPS + videoBPS return int((self.__duration(full_path) / 1000) * (bitrate * 1.02 / 8))
def __est_size(self, full_path, tsn='', mime=''): # Size is estimated by taking audio and video bit rate adding 2% if transcode.tivo_compatible(full_path, tsn, mime)[0]: return os.path.getsize(unicode(full_path, 'utf-8')) else: # Must be re-encoded audioBPS = config.getMaxAudioBR(tsn) * 1000 #audioBPS = config.strtod(config.getAudioBR(tsn)) videoBPS = transcode.select_videostr(full_path, tsn) bitrate = audioBPS + videoBPS return int( (self.__duration(full_path) / 1000) * (bitrate * 1.02 / 8))
def push_one_file(self, f): file_info = VideoDetails() file_info['valid'] = transcode.supported_format(f['path']) mime = 'video/mpeg' if config.isHDtivo(f['tsn']): for m in ['video/mp4', 'video/bif']: if transcode.tivo_compatible(f['path'], f['tsn'], m)[0]: mime = m break if (mime == 'video/mpeg' and transcode.mp4_remuxable(f['path'], f['tsn'])): new_path = transcode.mp4_remux(f['path'], f['name'], f['tsn']) if new_path: mime = 'video/mp4' f['name'] = new_path if file_info['valid']: file_info.update(self.metadata_full(f['path'], f['tsn'], mime)) url = f['url'] + quote(f['name']) title = file_info['seriesTitle'] if not title: title = file_info['title'] source = file_info['seriesId'] if not source: source = title subtitle = file_info['episodeTitle'] try: m = mind.getMind(f['tsn']) m.pushVideo( tsn = f['tsn'], url = url, description = file_info['description'], duration = file_info['duration'] / 1000, size = file_info['size'], title = title, subtitle = subtitle, source = source, mime = mime, tvrating = file_info['tvRating']) except Exception, msg: logger.error(msg)
def push_one_file(self, f): file_info = VideoDetails() file_info["valid"] = transcode.supported_format(f["path"]) mime = "video/mpeg" if config.isHDtivo(f["tsn"]): for m in ["video/mp4", "video/bif"]: if transcode.tivo_compatible(f["path"], f["tsn"], m)[0]: mime = m break if mime == "video/mpeg" and transcode.mp4_remuxable(f["path"], f["tsn"]): new_path = transcode.mp4_remux(f["path"], f["name"], f["tsn"]) if new_path: mime = "video/mp4" f["name"] = new_path if file_info["valid"]: file_info.update(self.metadata_full(f["path"], f["tsn"], mime)) url = f["url"] + quote(f["name"]) title = file_info["seriesTitle"] if not title: title = file_info["title"] source = file_info["seriesId"] if not source: source = title subtitle = file_info["episodeTitle"] try: m = mind.getMind(f["tsn"]) m.pushVideo( tsn=f["tsn"], url=url, description=file_info["description"], duration=file_info["duration"] / 1000, size=file_info["size"], title=title, subtitle=subtitle, source=source, mime=mime, tvrating=file_info["tvRating"], ) except Exception, msg: logger.error(msg)
def push_one_file(self, f): file_info = VideoDetails() file_info['valid'] = transcode.supported_format(f['path']) temp_share = config.get_server('temp_share', '') temp_share_path = '' remux_path = os.path.dirname(f['path']) if temp_share: for name, data in config.getShares(): if temp_share == name: temp_share_path = data.get('path') remux_path = temp_share_path mime = 'video/mpeg' if config.isHDtivo(f['tsn']): for m in ['video/mp4', 'video/bif']: if transcode.tivo_compatible(f['path'], f['tsn'], m)[0]: mime = m break if (mime == 'video/mpeg' and transcode.mp4_remuxable(f['path'], f['tsn'])): if config.get_freeSpace(remux_path, f['path']): new_path = transcode.mp4_remux(f['path'], f['name'], f['tsn'], temp_share_path) if new_path: mime = 'video/mp4' f['name'] = new_path if temp_share_path: ip = config.get_ip() port = config.getPort() container = quote(temp_share) + '/' f['url'] = 'http://%s:%s/%s' % (ip, port, container) else: logger.warning('Not enough disk space to perform remux, ' + 'transcoding instead.') if file_info['valid']: file_info.update(self.metadata_full(f['path'], f['tsn'], mime)) url = f['url'] + quote(f['name']) title = file_info['seriesTitle'] if not title: title = file_info['title'] source = file_info['seriesId'] if not source: source = title subtitle = file_info['episodeTitle'] try: m = mind.getMind(f['tsn']) m.pushVideo( tsn = f['tsn'], url = url, description = file_info['description'], duration = file_info['duration'] / 1000, size = file_info['size'], title = title, subtitle = subtitle, source = source, mime = mime, tvrating = file_info['tvRating']) except ValueError, msg: if 'usernamePasswordError' in msg: if f['name'].endswith('.pyTivo-temp'): fname = os.path.join(remux_path, os.path.basename(f['name'])) fname = unicode(fname, 'utf-8') os.remove(fname) logger.debug(fname + ' has been removed')
def metadata_full(self, full_path, tsn='', mime=''): data = {} vInfo = transcode.video_info(full_path) if ((int(vInfo['vHeight']) >= 720 and config.getTivoHeight >= 720) or (int(vInfo['vWidth']) >= 1280 and config.getTivoWidth >= 1280)): data['showingBits'] = '4096' data.update(metadata.basic(full_path)) if full_path[-5:].lower() == '.tivo': data.update(metadata.from_tivo(full_path)) if full_path[-4:].lower() == '.wtv': data.update(metadata.from_mscore(vInfo['rawmeta'])) if 'episodeNumber' in data: try: ep = int(data['episodeNumber']) except: ep = 0 data['episodeNumber'] = str(ep) if config.getDebug() and 'vHost' not in data: compatible, reason = transcode.tivo_compatible(full_path, tsn, mime) if compatible: transcode_options = {} else: transcode_options = transcode.transcode(True, full_path, '', tsn, mime) data['vHost'] = ( ['TRANSCODE=%s, %s' % (['YES', 'NO'][compatible], reason)] + ['SOURCE INFO: '] + ["%s=%s" % (k, v) for k, v in sorted(vInfo.items(), reverse=True)] + ['TRANSCODE OPTIONS: '] + ["%s" % (v) for k, v in transcode_options.items()] + ['SOURCE FILE: ', os.path.basename(full_path)] ) now = datetime.utcnow() if 'time' in data: if data['time'].lower() == 'file': mtime = os.stat(unicode(full_path, 'utf-8')).st_mtime if (mtime < 0): mtime = 0 try: now = datetime.utcfromtimestamp(mtime) except: logger.warning('Bad file time on ' + full_path) elif data['time'].lower() == 'oad': now = isodt(data['originalAirDate']) else: try: now = isodt(data['time']) except: logger.warning('Bad time format: ' + data['time'] + ' , using current time') duration = self.__duration(full_path) duration_delta = timedelta(milliseconds = duration) min = duration_delta.seconds / 60 sec = duration_delta.seconds % 60 hours = min / 60 min = min % 60 data.update({'time': now.isoformat(), 'startTime': now.isoformat(), 'stopTime': (now + duration_delta).isoformat(), 'size': self.__est_size(full_path, tsn, mime), 'duration': duration, 'iso_duration': ('P%sDT%sH%sM%sS' % (duration_delta.days, hours, min, sec))}) return data
def send_file(self, handler, path, query): mime = 'video/x-tivo-mpeg' tsn = handler.headers.getheader('tsn', '') tivo_name = config.tivo_names.get(tsn, tsn) is_tivo_file = (path[-5:].lower() == '.tivo') if 'Format' in query: mime = query['Format'][0] needs_tivodecode = (is_tivo_file and mime == 'video/mpeg') compatible = (not needs_tivodecode and transcode.tivo_compatible(path, tsn, mime)[0]) try: # "bytes=XXX-" offset = int(handler.headers.getheader('Range')[6:-1]) except: offset = 0 if needs_tivodecode: valid = bool(config.get_bin('tivodecode') and config.get_server('tivo_mak')) else: valid = True if valid and offset: valid = ((compatible and offset < os.stat(path).st_size) or (not compatible and transcode.is_resumable(path, offset))) #faking = (mime in ['video/x-tivo-mpeg-ts', 'video/x-tivo-mpeg'] and faking = (mime == 'video/x-tivo-mpeg' and not (is_tivo_file and compatible)) fname = unicode(path, 'utf-8') thead = '' if faking: thead = self.tivo_header(tsn, path, mime) if compatible: size = os.stat(fname).st_size + len(thead) handler.send_response(200) handler.send_header('Content-Length', size - offset) handler.send_header('Content-Range', 'bytes %d-%d/%d' % (offset, size - offset - 1, size)) else: handler.send_response(206) handler.send_header('Transfer-Encoding', 'chunked') handler.send_header('Content-Type', mime) handler.end_headers() logger.info('[%s] Start sending "%s" to %s' % (time.strftime('%d/%b/%Y %H:%M:%S'), fname, tivo_name)) start = time.time() count = 0 if valid: if compatible: if faking and not offset: handler.wfile.write(thead) logger.debug('"%s" is tivo compatible' % fname) f = open(fname, 'rb') try: if mime == 'video/mp4': count = qtfaststart.process(f, handler.wfile, offset) else: if offset: offset -= len(thead) f.seek(offset) while True: block = f.read(512 * 1024) if not block: break handler.wfile.write(block) count += len(block) except Exception, msg: logger.info(msg) f.close() else: logger.debug('"%s" is not tivo compatible' % fname) if offset: count = transcode.resume_transfer(path, handler.wfile, offset) else: count = transcode.transcode(False, path, handler.wfile, tsn, mime, thead)
def Push(self, handler, query): tsn = query['tsn'][0] for key in config.tivo_names: if config.tivo_names[key] == tsn: tsn = key break tivo_name = config.tivo_names.get(tsn, tsn) container = quote(query['Container'][0].split('/')[0]) ip = config.get_ip() port = config.getPort() baseurl = 'http://%s:%s' % (ip, port) if config.getIsExternal(tsn): exturl = config.get_server('externalurl') if exturl: baseurl = exturl else: ip = self.readip() baseurl = 'http://%s:%s' % (ip, port) path = self.get_local_base_path(handler, query) files = query.get('File', []) for f in files: file_path = path + os.path.normpath(f) file_info = VideoDetails() file_info['valid'] = transcode.supported_format(file_path) mime = 'video/mpeg' if config.isHDtivo(tsn): for m in ['video/mp4', 'video/bif']: if transcode.tivo_compatible(file_path, tsn, m)[0]: mime = m break if file_info['valid']: file_info.update(self.metadata_full(file_path, tsn, mime)) url = baseurl + '/%s%s' % (container, quote(f)) title = file_info['seriesTitle'] if not title: title = file_info['title'] source = file_info['seriesId'] if not source: source = title subtitle = file_info['episodeTitle'] try: m = mind.getMind(tsn) m.pushVideo( tsn = tsn, url = url, description = file_info['description'], duration = file_info['duration'] / 1000, size = file_info['size'], title = title, subtitle = subtitle, source = source, mime = mime, tvrating = file_info['tvRating']) except Exception, e: handler.send_response(500) handler.end_headers() handler.wfile.write('%s\n\n%s' % (e, traceback.format_exc() )) raise logger.info('[%s] Queued "%s" for Push to %s' % (time.strftime('%d/%b/%Y %H:%M:%S'), unicode(file_path, 'utf-8'), tivo_name))
def metadata_full(self, full_path, tsn='', mime='', mtime=None): data = {} vInfo = transcode.video_info(full_path) if ((int(vInfo['vHeight']) >= 720 and config.getTivoHeight >= 720) or (int(vInfo['vWidth']) >= 1280 and config.getTivoWidth >= 1280)): data['showingBits'] = '4096' data.update(metadata.basic(full_path, mtime)) if full_path[-5:].lower() == '.tivo': data.update(metadata.from_tivo(full_path)) if full_path[-4:].lower() == '.wtv': data.update(metadata.from_mscore(vInfo['rawmeta'])) if 'episodeNumber' in data: try: ep = int(data['episodeNumber']) except: ep = 0 data['episodeNumber'] = str(ep) if config.getDebug() and 'vHost' not in data: compatible, reason = transcode.tivo_compatible( full_path, tsn, mime) if compatible: transcode_options = [] else: transcode_options = transcode.transcode( True, full_path, '', None, False, tsn, mime) data['vHost'] = ( ['TRANSCODE=%s, %s' % (['YES', 'NO'][compatible], reason)] + ['SOURCE INFO: '] + [ "%s=%s" % (k, v) for k, v in sorted(vInfo.items(), reverse=True) ] + ['TRANSCODE OPTIONS: '] + transcode_options + ['SOURCE FILE: ', os.path.basename(full_path)]) now = datetime.utcnow() if 'time' in data: if data['time'].lower() == 'file': if not mtime: mtime = os.path.getmtime(unicode(full_path, 'utf-8')) try: now = datetime.utcfromtimestamp(mtime) except: logger.warning('Bad file time on ' + full_path) elif data['time'].lower() == 'oad': now = isodt(data['originalAirDate']) else: try: now = isodt(data['time']) except: logger.warning('Bad time format: ' + data['time'] + ' , using current time') duration = self.__duration(full_path) duration_delta = timedelta(milliseconds=duration) min = duration_delta.seconds / 60 sec = duration_delta.seconds % 60 hours = min / 60 min = min % 60 data.update({ 'time': now.isoformat(), 'startTime': now.isoformat(), 'stopTime': (now + duration_delta).isoformat(), 'size': self.__est_size(full_path, tsn, mime), 'duration': duration, 'iso_duration': ('P%sDT%sH%sM%sS' % (duration_delta.days, hours, min, sec)) }) return data
tivo_mak = config.get_tsn('tivo_mak', tsn) has_tivolibre = bool(config.get_bin('tivolibre')) has_tivodecode = bool(config.get_bin('tivodecode')) use_tivolibre = False if has_tivolibre and bool(config.get_server('tivolibre_upload', True)): use_tivolibre = True if 'Format' in query: mime = query['Format'][0] needs_converion = (((is_tivo_file and is_tivo_ts) or (is_tivo_file and not has_tivolibre)) and mime == 'video/mpeg') compatible = (not needs_converion and transcode.tivo_compatible(path, tsn, mime)[0]) try: # "bytes=XXX-" offset = int(handler.headers.getheader('Range')[6:-1]) except: offset = 0 if needs_converion: valid = bool((has_tivodecode or has_tivolibre) and tivo_mak) else: valid = True if valid and offset: valid = ((compatible and offset < os.path.getsize(path)) or (not compatible and transcode.is_resumable(path, offset)))
def send_file(self, handler, path, query): mime = 'video/x-tivo-mpeg' tsn = handler.headers.getheader('tsn', '') try: assert (tsn) tivo_name = config.tivos[tsn].get('name', tsn) except: tivo_name = handler.address_string() is_tivo_file = (path[-5:].lower() == '.tivo') if 'Format' in query: mime = query['Format'][0] needs_tivodecode = (is_tivo_file and mime == 'video/mpeg') compatible = (not needs_tivodecode and transcode.tivo_compatible(path, tsn, mime)[0]) try: # "bytes=XXX-" offset = int(handler.headers.getheader('Range')[6:-1]) except: offset = 0 if needs_tivodecode: valid = bool( config.get_bin('tivodecode') and config.get_server('tivo_mak')) else: valid = True if valid and offset: valid = ((compatible and offset < os.path.getsize(path)) or (not compatible and transcode.is_resumable(path, offset))) #faking = (mime in ['video/x-tivo-mpeg-ts', 'video/x-tivo-mpeg'] and faking = (mime == 'video/x-tivo-mpeg' and not (is_tivo_file and compatible)) fname = unicode(path, 'utf-8') thead = '' if faking: thead = self.tivo_header(tsn, path, mime) if compatible: size = os.path.getsize(fname) + len(thead) handler.send_response(200) handler.send_header('Content-Length', size - offset) handler.send_header( 'Content-Range', 'bytes %d-%d/%d' % (offset, size - offset - 1, size)) else: handler.send_response(206) handler.send_header('Transfer-Encoding', 'chunked') handler.send_header('Content-Type', mime) handler.end_headers() logger.info('[%s] Start sending "%s" to %s' % (time.strftime('%d/%b/%Y %H:%M:%S'), fname, tivo_name)) start = time.time() count = 0 if valid: if compatible: if faking and not offset: handler.wfile.write(thead) logger.debug('"%s" is tivo compatible' % fname) f = open(fname, 'rb') try: if mime == 'video/mp4': count = qtfaststart.process(f, handler.wfile, offset) else: if offset: offset -= len(thead) f.seek(offset) while True: block = f.read(512 * 1024) if not block: break handler.wfile.write(block) count += len(block) except Exception, msg: logger.info(msg) f.close() else: logger.debug('"%s" is not tivo compatible' % fname) if offset: count = transcode.resume_transfer(path, handler.wfile, offset) else: count = transcode.transcode(False, path, handler.wfile, tsn, mime, thead)
def metadata_full(self, full_path, tsn="", mime=""): data = {} vInfo = transcode.video_info(full_path) if (int(vInfo["vHeight"]) >= 720 and config.getTivoHeight >= 720) or ( int(vInfo["vWidth"]) >= 1280 and config.getTivoWidth >= 1280 ): data["showingBits"] = "4096" data.update(metadata.basic(full_path)) if full_path[-5:].lower() == ".tivo": data.update(metadata.from_tivo(full_path)) if full_path[-4:].lower() == ".wtv": data.update(metadata.from_mscore(vInfo["rawmeta"])) if "episodeNumber" in data: try: ep = int(data["episodeNumber"]) except: ep = 0 data["episodeNumber"] = str(ep) if config.getDebug() and "vHost" not in data: compatible, reason = transcode.tivo_compatible(full_path, tsn, mime) if compatible: transcode_options = {} else: transcode_options = transcode.transcode(True, full_path, "", tsn, mime) data["vHost"] = ( ["TRANSCODE=%s, %s" % (["YES", "NO"][compatible], reason)] + ["SOURCE INFO: "] + ["%s=%s" % (k, v) for k, v in sorted(vInfo.items(), reverse=True)] + ["TRANSCODE OPTIONS: "] + ["%s" % (v) for k, v in transcode_options.items()] + ["SOURCE FILE: ", os.path.basename(full_path)] ) now = datetime.utcnow() if "time" in data: if data["time"].lower() == "file": mtime = os.stat(unicode(full_path, "utf-8")).st_mtime if mtime < 0: mtime = 0 try: now = datetime.utcfromtimestamp(mtime) except: logger.warning("Bad file time on " + full_path) elif data["time"].lower() == "oad": now = isodt(data["originalAirDate"]) else: try: now = isodt(data["time"]) except: logger.warning("Bad time format: " + data["time"] + " , using current time") duration = self.__duration(full_path) duration_delta = timedelta(milliseconds=duration) min = duration_delta.seconds / 60 sec = duration_delta.seconds % 60 hours = min / 60 min = min % 60 data.update( { "time": now.isoformat(), "startTime": now.isoformat(), "stopTime": (now + duration_delta).isoformat(), "size": self.__est_size(full_path, tsn, mime), "duration": duration, "iso_duration": ("P%sDT%sH%sM%sS" % (duration_delta.days, hours, min, sec)), } ) return data
def send_file(self, handler, path, query): mime = "video/x-tivo-mpeg" tsn = handler.headers.getheader("tsn", "") tivo_name = config.tivo_names.get(tsn, tsn) is_tivo_file = path[-5:].lower() == ".tivo" if "Format" in query: mime = query["Format"][0] needs_tivodecode = is_tivo_file and mime == "video/mpeg" compatible = not needs_tivodecode and transcode.tivo_compatible(path, tsn, mime)[0] try: # "bytes=XXX-" offset = int(handler.headers.getheader("Range")[6:-1]) except: offset = 0 if needs_tivodecode: valid = bool(config.get_bin("tivodecode") and config.get_server("tivo_mak")) else: valid = True if valid and offset: valid = (compatible and offset < os.stat(path).st_size) or ( not compatible and transcode.is_resumable(path, offset) ) # faking = (mime in ['video/x-tivo-mpeg-ts', 'video/x-tivo-mpeg'] and faking = mime == "video/x-tivo-mpeg" and not (is_tivo_file and compatible) fname = unicode(path, "utf-8") thead = "" if faking: thead = self.tivo_header(tsn, path, mime) if compatible: size = os.stat(fname).st_size + len(thead) handler.send_response(200) handler.send_header("Content-Length", size - offset) handler.send_header("Content-Range", "bytes %d-%d/%d" % (offset, size - offset - 1, size)) else: handler.send_response(206) handler.send_header("Transfer-Encoding", "chunked") handler.send_header("Content-Type", mime) handler.send_header("Connection", "close") handler.end_headers() logger.info('[%s] Start sending "%s" to %s' % (time.strftime("%d/%b/%Y %H:%M:%S"), fname, tivo_name)) start = time.time() count = 0 if valid: if compatible: if faking and not offset: handler.wfile.write(thead) logger.debug('"%s" is tivo compatible' % fname) f = open(fname, "rb") try: if mime == "video/mp4": count = qtfaststart.process(f, handler.wfile, offset) else: if offset: offset -= len(thead) f.seek(offset) while True: block = f.read(512 * 1024) if not block: break handler.wfile.write(block) count += len(block) except Exception, msg: logger.info(msg) f.close() else: logger.debug('"%s" is not tivo compatible' % fname) if offset: count = transcode.resume_transfer(path, handler.wfile, offset) else: count = transcode.transcode(False, path, handler.wfile, tsn, mime, thead)