def _fichero_entrada_multiple(request, v): n = v.plantilla.tipovideo_set.count() FicheroEntradaFormSet = inlineformset_factory( Video, FicheroEntrada, formset=RequiredBaseInlineFormSet, form=FicheroEntradaForm, extra=n, max_num=n, can_delete=False, ) tipos = v.plantilla.tipovideo_set.all().order_by("id") if request.method == "POST": formset = FicheroEntradaFormSet(request.POST, instance=v) if formset.is_valid(): instances = formset.save(commit=False) for i in range(n): instances[i].fichero = os.path.normpath(config.get_option("VIDEO_INPUT_PATH") + instances[i].fichero) instances[i].video = v instances[i].tipo = tipos[i] instances[i].save() return redirect("postproduccion.views.resumen_video", v.id) else: formset = FicheroEntradaFormSet(instance=v) for i in range(n): formset.forms[i].titulo = tipos[i].nombre if formset.forms[i].initial: formset.forms[i].initial["fichero"] = os.path.join( "/", os.path.relpath(formset.forms[i].initial["fichero"], config.get_option("VIDEO_INPUT_PATH")) ) return render_to_response( "section-nueva-paso2-ficheros.html", {"v": v, "formset": formset}, context_instance=RequestContext(request) )
def _fichero_entrada_simple(request, v, type = None): if request.method == 'POST': form = FicheroEntradaForm(request.POST, instance = v.ficheroentrada_set.all()[0]) if v.ficheroentrada_set.count() else FicheroEntradaForm(request.POST) if form.is_valid(): fe = form.save(commit = False) fe.video = v fe.fichero = os.path.normpath(config.get_option('VIDEO_INPUT_PATH') + fe.fichero) fe.save() if type == 'reemplazar_video': queue.enqueue_copy(v) v.set_status('DEF') messages.success(request, "Vídeo reemplazado y encolado para su procesado") return redirect('postproduccion.views.estado_video', v.id) else: return redirect('postproduccion.views.resumen_video', v.id) else: if v.ficheroentrada_set.count(): fe = v.ficheroentrada_set.all()[0] fe.fichero = os.path.join('/', os.path.relpath(fe.fichero, config.get_option('VIDEO_INPUT_PATH'))) form = FicheroEntradaForm(instance = fe) else: form = FicheroEntradaForm() if type == 'reemplazar_video': return render_to_response("postproduccion/section-reemplazar-video.html", { 'v' : v, 'form' : form }, context_instance=RequestContext(request)) else: return render_to_response("postproduccion/section-nueva-paso2-fichero.html", { 'v' : v, 'form' : form }, context_instance=RequestContext(request))
def get_flow(): return OAuth2WebServerFlow(client_id = config.get_option('YT_PUBLISHER_CLIENT_ID'), client_secret = config.get_option('YT_PUBLISHER_CLIENT_SECRET'), scope = YOUTUBE_SCOPES, redirect_uri = urljoin(config.get_option('SITE_URL'), reverse('oauth2callback')), approval_prompt='force', access_type = 'offline')
def calculate_preview_size(v): [width, height, ratio] = get_tec_data(v.tecdata.xml_data) max_width = float(config.get_option('MAX_PREVIEW_WIDTH')) max_height = float(config.get_option('MAX_PREVIEW_HEIGHT')) # Hace los pixels cuadrados if ratio > 0: width = height * ratio else: try: height = width / ratio except ZeroDivisionError: pass # Reduce el ancho if width > max_width: r = max_width / width width *= r height *= r # Reduce el alto if height > max_height: r = max_height / height width *= r height *= r # Hace el tamaño par (necesario para algunos codecs) width = int((width + 1) / 2) * 2 height = int((height + 1) / 2) * 2 return dict({'width' : width, 'height' : height, 'ratio' : ratio})
def embed_metadata(filename, metadata): """ Incrusta la metadata al video final """ if not os.path.exists(filename): return False command = "'%s' -config %s %s '%s'" % ( config.get_option('EXIFTOOL_PATH'), config.get_option('EXIFTOOL_CONFIG'), metadata, filename ) p = subprocess.Popen( shlex.split(str(command)), stdout=subprocess.PIPE, stderr=subprocess.STDOUT ) out, err = p.communicate() # Esperar a finalizar # Borrar video original try: os.unlink(filename + '_original') except: pass return True
def get_file_info(filename): command = "%s --Output=XML %s" % (config.get_option('MEDIAINFO_PATH'), filename) xml_data = subprocess.Popen(shlex.split(str(command)), stdout=subprocess.PIPE).communicate()[0] command = "%s %s" % (config.get_option('MEDIAINFO_PATH'), filename) txt_data = subprocess.Popen(shlex.split(str(command)), stdout=subprocess.PIPE).communicate()[0] return [xml_data, txt_data]
def _register_entry(): lock.acquire() current = int(config.get_option('CURRENT_LOG_SIZE')) if config.get_option('CURRENT_LOG_SIZE') else 0 if current >= int(config.get_option('LOG_MAX_LINES')): _logrotate() current = 1 else: current += 1 config.set_option('CURRENT_LOG_SIZE', current) lock.release()
def send_validation_mail_to_user(v, operador): """ Envía un correo para avisar al usuario de que su producción ya ha sido validada. """ try: send_mail( config.get_option('VALIDATED_MAIL_SUBJECT'), generate_validation_mail_message(v, operador), config.get_option('RETURN_EMAIL'), [v.email] ) except: return None return v
def send_published_mail_to_user(r): """ Envía un correo para avisar al usuario de que su producción ya ha sido publicada. """ try: send_mail( config.get_option('PUBLISHED_MAIL_SUBJECT'), generate_published_mail_message(r), config.get_option('RETURN_EMAIL'), [r.video.email] ) except: return None return True
def create_preview(video, logfile, pid_notifier = None): # Actualiza el estado del vídeo video.set_status('PRP') # Obtiene los nombres de ficheros origen y destino src = video.fichero dst = os.path.join(config.get_option('PREVIEWS_PATH'), utils.generate_safe_filename(video.titulo, video.informeproduccion.fecha_produccion.date(), ".flv")) # Crea el objecto previsualización pv = Previsualizacion(video = video, fichero = dst) pv.save() # Calcula las dimensiones de la previsualización. size = calculate_preview_size(video) # Codifica la previsualización. utils.ensure_dir(pv.fichero) if encode_preview(src, dst, size, logfile, pid_notifier) != 0: video.set_status('COM') try: os.unlink(dst) except: pass return False # Actualiza el estado del vídeo video.set_status('PTU') return True
def copy_video(video, logfile): # Actualiza el estado del vídeo video.set_status('PRV') # Obtiene los nombres de ficheros origen y destino src = video.ficheroentrada_set.all()[0].fichero dst = os.path.join(config.get_option('VIDEO_LIBRARY_PATH'), utils.generate_safe_filename(video.titulo, video.informeproduccion.fecha_produccion.date(), os.path.splitext(src)[1])) video.fichero = dst video.save() # Copia el fichero. utils.ensure_dir(video.fichero) try: shutil.copy(src, dst) os.write(logfile, '%s -> %s\n' % (src, dst)) os.chmod(dst, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP) os.write(logfile, 'chmod: 640\n') except IOError as error: os.write(logfile, error.__str__()) video.set_status('DEF') return False # Obtiene la información técnica del vídeo copiado. generate_tecdata(video) # Actualiza el estado del vídeo if video.informeproduccion.aprobacion: video.set_status('COM') else: video.set_status('PTO') return True
def feed(request): channel_data = get_channel_data() channel = dict() channel['id'] = channel_data['id'] channel['title'] = channel_data['snippet']['title'] channel['description'] = channel_data['snippet']['description'] channel['logo'] = channel_data['snippet']['thumbnails']['default']['url'] feed = dict() feed['build'] = formatdate(time.mktime(datetime.now().timetuple())) feed['baseurl'] = config.get_option(u'SITE_URL') video_list = get_all_public_video_data(channel['id']) items = list() for v in video_list: item = dict() item['id'] = v['id'] item['title'] = v['snippet']['title'] item['description'] = v['snippet']['description'] published_at = datetime.strptime(v['snippet']['publishedAt'], "%Y-%m-%dT%H:%M:%S.000Z") item['published'] = dict() item['published']['short'] = published_at.date().isoformat() item['published']['long'] = formatdate(time.mktime(published_at.timetuple())) item['thumbnail'] = v['snippet']['thumbnails']['high'] item['category'] = v['snippet']['tags'][-1] if 'tags' in item: item['tags'] = u','.join(v['snippet']['tags'][:-1]) items.append(item) return render_to_response("yt_publisher/yt-feed.html", { 'channel' : channel, 'feed' : feed, 'items' : items }, context_instance=RequestContext(request))
def send_custom_mail_to_user(v, texto, operador): """ Envía un correo personalizado al usuario para solicitar la aprobación y los metadatos de un vídeo. """ v = create_token(v) try: send_mail( config.get_option('CUSTOM_MAIL_SUBJECT'), generate_custom_mail_message(v, texto, operador), config.get_option('RETURN_EMAIL'), [v.email] ) except: return None return v
def available_slots(): """ Devuelve el número de puestos libres para iniciar el proceso de codificación. """ return int(config.get_option('MAX_ENCODING_TASKS')) - \ Cola.objects.count_actives()
def send_mail_to_user(v): """ Envía un correo al usuario para solicitar la aprobación y los metadatos de un vídeo. """ v = create_token(v) try: send_mail( config.get_option('NOTIFY_MAIL_SUBJECT'), generate_mail_message(v), config.get_option('RETURN_EMAIL'), [v.email] ) except: return None return v
def _fichero_entrada_multiple(request, v, type = None): n = v.plantilla.tipovideo_set.count() FicheroEntradaFormSet = inlineformset_factory(Video, FicheroEntrada, formset = RequiredBaseInlineFormSet, form = FicheroEntradaForm, extra = n, max_num = n, can_delete = False) tipos = v.plantilla.tipovideo_set.all().order_by('id') if request.method == 'POST': formset = FicheroEntradaFormSet(request.POST, instance = v) if v.ficheroentrada_set.count() else FicheroEntradaFormSet(request.POST) print "previo" if formset.is_valid(): instances = formset.save(commit = False) for i in range(n): instances[i].fichero = os.path.normpath(config.get_option('VIDEO_INPUT_PATH') + instances[i].fichero) instances[i].video = v instances[i].tipo = tipos[i] instances[i].save() if type == 'reemplazar_video': queue.enqueue_pil(v) v.set_status('DEF') messages.success(request, "Vídeo reemplazado y encolado para su procesado") return redirect('postproduccion.views.estado_video', v.id) else: return redirect('postproduccion.views.resumen_video', v.id) else: formset = FicheroEntradaFormSet(instance = v) for i in range(n): formset.forms[i].titulo = tipos[i].nombre if formset.forms[i].initial: formset.forms[i].initial['fichero'] = os.path.join('/', os.path.relpath(formset.forms[i].initial['fichero'], config.get_option('VIDEO_INPUT_PATH'))) if type == 'reemplazar_video': return render_to_response("postproduccion/section-reemplazar-videos.html", { 'v' : v, 'formset' : formset }, context_instance=RequestContext(request)) else: return render_to_response("postproduccion/section-nueva-paso2-ficheros.html", { 'v' : v, 'formset' : formset }, context_instance=RequestContext(request))
def get_expire_time(t): """ Devuelve la fecha de caducidad de un token. """ return t.instante + timedelta( days=int(config.get_option('TOKEN_VALID_DAYS')) )
def get_token_url(v): """ Devuelve la url del ticket de usuario correspondiente al vídeo dado. """ return urljoin( config.get_option('SITE_URL'), reverse('postproduccion.views.aprobacion_video', args=(v.token.token,)) )
def _fichero_entrada_simple(request, v): if request.method == 'POST': form = FicheroEntradaForm(request.POST, instance = v.ficheroentrada_set.all()[0]) if v.ficheroentrada_set.count() else FicheroEntradaForm(request.POST) if form.is_valid(): fe = form.save(commit = False) fe.video = v fe.fichero = os.path.normpath(config.get_option('VIDEO_INPUT_PATH') + fe.fichero) fe.save() return redirect('postproduccion.views.resumen_video', v.id) else: if v.ficheroentrada_set.count(): fe = v.ficheroentrada_set.all()[0] fe.fichero = os.path.join('/', os.path.relpath(fe.fichero, config.get_option('VIDEO_INPUT_PATH'))) form = FicheroEntradaForm(instance = fe) else: form = FicheroEntradaForm() return render_to_response("postproduccion/section-nueva-paso2-fichero.html", { 'v' : v, 'form' : form }, context_instance=RequestContext(request))
def make_streamable(filename, logfile, pid_notifier = None): command = "'%s' -inter 0.5 '%s' -tmp '%s'" % (config.get_option('MP4BOX_PATH'), filename, os.path.dirname(filename)) p = subprocess.Popen(shlex.split(str(command)), stdout = subprocess.PIPE, stderr = subprocess.STDOUT) if pid_notifier: pid_notifier(p.pid) os.write(logfile, p.communicate()[0])
def status(request): # Programas externos avconvver = utils.avconv_version() meltver = utils.melt_version() mediainfover = utils.mediainfo_version() mp4boxver = utils.mp4box_version() exes = { "AVCONV": { "path": config.get_option("AVCONV_PATH"), "status": True if avconvver else False, "version": avconvver, }, "MELT": {"path": config.get_option("MELT_PATH"), "status": True if meltver else False, "version": meltver}, "crontab": { "path": config.get_option("CRONTAB_PATH"), "status": utils.is_exec(config.get_option("CRONTAB_PATH")), "version": "N/A", }, "mediainfo": { "path": config.get_option("MEDIAINFO_PATH"), "status": True if mediainfover else False, "version": mediainfover, }, "MP4Box": { "path": config.get_option("MP4BOX_PATH"), "status": True if mp4boxver else False, "version": mp4boxver, }, } # Directorios dirs = dict() for i in [("library", "VIDEO_LIBRARY_PATH"), ("input", "VIDEO_INPUT_PATH"), ("previews", "PREVIEWS_PATH")]: data = {"path": config.get_option(i[1])} if utils.check_dir(data["path"]): df = utils.df(data["path"]) data["info"] = {"total": df[0], "used": df[1], "left": df[2], "perc": df[3], "mount": df[4]} dirs[i[0]] = data # Tareas Programadas if request.method == "POST": if "status_process" in request.POST: if request.POST["status_process"] == "1": crontab.stop("procesar_video") messages.warning(request, "Tareas programadas de codificación desactivadas") else: crontab.start("procesar_video") messages.success(request, "Tareas programadas de codificacion activadas") if "status_publish" in request.POST: if request.POST["status_publish"] == "1": crontab.stop("publicar_video") messages.warning(request, "Tareas programadas de publicación desactivadas") else: crontab.start("publicar_video") messages.success(request, "Tareas programadas de publicación activadas") cron = {"process": crontab.status("procesar_video"), "publish": crontab.status("publicar_video")} return render_to_response( "section-status.html", {"exes": exes, "dirs": dirs, "cron": cron}, context_instance=RequestContext(request) )
def clean_fichero(self): data = self.cleaned_data['fichero'] try: str(data) except UnicodeEncodeError: raise forms.ValidationError("El campo no debe contener tíldes ni caracteres especiales") if not is_video_file(os.path.normpath(config.get_option('VIDEO_INPUT_PATH') + data)): raise ValidationError(u"El fichero no es un formato de vídeo reconocido") return data
def mediainfo_version(): fpath = config.get_option('MEDIAINFO_PATH') if is_exec(fpath): command = "%s --Version" % fpath data = subprocess.Popen(shlex.split(str(command)), stdout = subprocess.PIPE, stderr = subprocess.PIPE).communicate()[0] try: return re.search('(v[0-9\.]+)$', data).group(1) except AttributeError: return None
def generate_validation_mail_message(v, operador): (nombre, titulo, vid, fecha) = (v.autor, v.titulo, v.id, v.informeproduccion.fecha_grabacion) return Template(config.get_option('VALIDATED_MAIL_MESSAGE')).render(Context({ 'nombre' : nombre, 'titulo' : titulo, 'vid' : vid, 'fecha' : fecha, 'operador' : operador, }))
def generate_published_mail_message(r): (nombre, titulo, vid, fecha, url) = (r.video.autor, r.video.titulo, r.video.id, r.fecha, r.enlace) return Template(config.get_option('PUBLISHED_MAIL_MESSAGE')).render(Context({ 'nombre' : nombre, 'titulo' : titulo, 'vid' : vid, 'fecha' : fecha, 'url' : url, }))
def mp4box_version(): fpath = config.get_option('MP4BOX_PATH') if is_exec(fpath): command = "%s -version" % fpath data = subprocess.Popen(shlex.split(str(command)), stdout = subprocess.PIPE, stderr = subprocess.STDOUT).communicate()[0] try: return re.search('version (\S*)', data).group(1) except AttributeError: return None
def locked_get(self): credentials = None raw = config.get_option(self.__STORAGE_OPTION_KEY__) if raw: credentials = pickle.loads(base64.b64decode(raw)) credentials.set_store(self) return credentials
def avconv_version(): fpath = config.get_option('AVCONV_PATH') if is_exec(fpath): command = "%s -version" % fpath data = subprocess.Popen(shlex.split(str(command)), stdout = subprocess.PIPE, stderr = subprocess.STDOUT).communicate()[0] try: return re.match('avconv version ([\.0-9]+)', data).group(1) except AttributeError: return None
def execute_upload(v, category): php_path = config.get_option('CB_PUBLISHER_PHP_PATH') p = subprocess.Popen(php_path, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) messages = p.communicate(input=get_uploader_code(v, category))[0] if p.returncode == 0: return None else: return messages
def _logrotate(): for i in range(int(config.get_option('MAX_NUM_LOGFILES')) - 1, 1, -1): if os.path.isfile('%s.%s.gz' % (LOGFILE, i)): os.rename('%s.%s.gz' % (LOGFILE, i), '%s.%s.gz' % (LOGFILE, i + 1)) if os.path.isfile('%s.%s' % (LOGFILE, 1)): os.rename('%s.%s' % (LOGFILE, 1), '%s.%s' % (LOGFILE, 2)) _compress_file('%s.%s' % (LOGFILE, 2)) if os.path.isfile(LOGFILE): os.rename(LOGFILE, '%s.%s' % (LOGFILE, 1)) open(LOGFILE, 'w').close()