Reproducir videos con MPV, mediante Python.

La reproducción de videos es una de las formas favoritas de entretenimiento de la gran mayoría de los seres humanos. Ya sean películas, documentales, video clips, grabaciones privadas o cualquier otro formato existente.

Nos pasamos gran parte de nuestro tiempo libre, o incluso no tan libre, visualizando todo tipo de contenidos audio visuales, especialmente del inmenso océano de material videográfico que es YouTube.

MPV es un reproductor multimedia gratuito, de código abierto y multiplataforma.

En Mac se puede instalar facilmente utilizando brew, con la siguiente instrucción en la terminal.

brew install mpv

MPV es un reproductor que funciona a través de la consola. Si lo que quieres es una interfaz gráfica, puedes utilizar IINA. Esta aplicación utiliza MPV como reproductor, dotándolo de una interfaz gráfica más amigable.

Con Python podemos exprimir las grandes características que nos ofrece MPV, ejecutando scrips que reproduzcan listas de video, todos los videos de una o varias carpetas, reproducir trozos aleatorios de videos, con secuencias que comienzan y acaban de forma aleatoria.

Este es el código para reproducir un archivo de video:

from subprocess import call

def reproduce(archivo, comienzo, resolucion, final):
    try:
        call('mpv "' +  archivo + '" – start=' + comienzo + ' – geometry=' + resolucion + ' – length=' + final, shell = True)
    except:
        print("Error al Reproducir Momento")

archivo = "" # Ruta del archivo
comienzo = "00:00:00"
resolucion = "45%"
final = "2:00:00"

reproduce(archivo, comienzo, resolucion, final)

Los parámetros que necesitamos pasar a la función son:

  • Archivo. La ruta del archivo que vamos a reproducir.
  • Comienzo. Donde empieza a reproducirse el archivo. Si queremos que empiece en el minuto 5, le pasamos 00:05:00
  • Resolución. El tamaño que tendrá la ventana de reproducción.
  • Final. El punto en el que se detendrá la reproducción, contando desde el momento que comienza la reproducción. En otras palabras, si la reproducción comienza en el minuto 5 (00:05:00), y queremos reproducir 15 segundos (00:00:15), la reproducción se detendrá en el minuto 5:15

Para listar todos los subdirectorios de una carpeta, devuelve los archivos contenidos en todas las subcarpetas encontradas.

from os.path import isfile, isdir, join

def listdir_recurd(files_list, root, folder, checked_folders):

    if (folder != root):
        checked_folders.append(folder)
        
    for f in listdir(folder):
        d = join(folder, f)       

        if isdir(d) and d not in checked_folders:
            listdir_recurd(files_list, root, d, checked_folders)
        else:
            if isfile(d):  # si no hago esto, inserta en la lista el nombre de las carpetas ignoradas
                files_list.append(join(folder, f))

    return files_list

Para obtener un tiempo aleatorio.

import random

def tiempo_aleatorio(tMin, tSeg):
    minutos = random.randint(0, tMin)
    segundos = random.randint(0, tSeg)

    tiempo = "00:%s:%s" %(minutos, segundos)
    return tiempo

Obtener la duración de un video, para ello debemos tener instalada la aplicación exiftool. Sabiendo la duración del video, calculamos un punto de inicio y fin aleatorio, sin exceder la duración real del video.

import subprocess

def duracion_escena(escena):
    datos = subprocess.check_output(['exiftool', escena]).decode('utf-8')

    dic = {}
    for line in datos.splitlines():
        valores = line.split(" : ",1)
        dic[valores[0].strip()] = valores[1].strip()

    duracion = dic['Track Duration']

    dura = duracion.split(":")
    minutos = int(dura[0]) + int(dura[1])

    resultado = tiempo_aleatorio(minutos, 59)

    return resultado

Desordenar una lista obtenida con la función anterior listdir_recurd.

import random

def random_sin_repetir(lista):
    for _ in range(0,len(lista)):
        result = random.choice(lista)
        yield result
        lista.remove(result)

El reproductor MPV dispone de infinidad de parametros para controlar la reproducción de videos, puedes ver más información aqui.

Share

Conocer las tarifas de luz cada hora, script en python

Las tarifas de luz son cada día más caras, por lo que tenemos que mirar muy bien cuándo realizamos nuestros consumos. Es cierto que muchos electrodomésticos no se pueden desconectar, como es la nevera, pero por ejemplo la lavadora, secadora o secador de pelo, podemos y debemos utilizarlos entre los rangos de horas que la electricidad es más barata.

Para las tarifas (PVPC) Precios Voluntarios para el Pequeño Consumidor.

Según la tarifa de luz eléctrica que tengamos contratada, el precio de la luz en cada zona horario es diferente.

Con la tarifa 2.0.A, el precio de la luz por horas es bastante uniforme, variando entre la hora más barata a la más cara un 14%, el precio de la hora más barata se sitúa en torno a los 0,095 € y la más cara a 0,110 €.

La tarifa 2.0.DHA, con dos discriminaciones horarias, divide el día en dos franjas, de 10 de la noche a las 12 del medio día del día siguiente, esta es la tarifa con las horas más baratas, en torno a los 0,05 €, recuerda que cada hora varia el precio. Y la franja de 12 del mediodía a 10 de la noche el precio por hora oscila entre los 0,12 €. La diferencia entre las horas baratas y las horas caras es de un 175%. Si tu consumo se realiza principalmente entre la franja con las horas más baratas, es muy recomendable utilizar esta tarifa.

La tarifa 2.0.DHS es muy similar a la tarifa 2.0.DHA, esta indicada para la carga de vehículos eléctricos. Las horas nocturnas son un poco más baratas que en la tarifa anterior.

Los valores indicados son los precios oficiales, y están referidos al Término de Facturación de Energía Activa del PVPC, de la Tarifa general (2.0.A), Tarifa discriminación horaria también llamada tarifa nocturna (2.0.DHA), y Vehículo eléctrico (2.0.DHS). 

Para obtener el precio real de la electricidad en cada franja horaria disponemos de la API de esios.

Los códigos de la api para cada una de las tarifas son:

  • 2.0.A – 10229
  • 2.0.DHA – 10230
  • 2.0.DHS – 10231

Para poder utilizar la API de esios, debemos utilizar un TOKEN. Este TOKEN debemos solicitarlo en la siguiente dirección de correo, consultasios@ree.es.

El código Python:

import requests
import json

TOKEN = "poner aqui el token"


url = 'https://api.esios.ree.es/indicators/10230'
headers = {'Accept':'application/json; application/vnd.esios-api-v2+json','Content-Type':'application/json','Host':'api.esios.ree.es','Authorization':'Token token=' + TOKEN}

response = requests.get(url, headers=headers)

if response.status_code == 200:
    json_data = json.loads(response.text)

    valores = json_data['indicator']['values']

    precios = [x['value'] for x in valores]
    
    hora = 0
    for precio in precios:
        print("%s horas - %s €" %(str(hora).zfill(2), str(round(precio/1000, 4))))
        hora += 1

    
    valor_min = min(precios)
    valor_max = max(precios)
    valor_med = round(statistics.mean(precios),2)
    
    print("Precio mínimo: %s" % str(valor_min/1000))
    print("Precio máximo: %s" % str(valor_max/1000))
    print("Precio medio: %s" % str(valor_med/1000))

El código anterior descarga la tarifa 2.0.DHA (10230). Cambiando el parametro de la url, despues de indicators, el código corresponde a la tarifa que queremos consultar.

Se obtiene el precio de cada fracción de hora, la hora y el precio mínimo, máximo, y el valor medio.

Resultado:

00 horas - 0.0547 €
01 horas - 0.0435 €
02 horas - 0.0471 €
03 horas - 0.0459 €
04 horas - 0.044 €
05 horas - 0.0434 €
06 horas - 0.0465 €
07 horas - 0.0615 €
08 horas - 0.0588 €
09 horas - 0.0545 €
10 horas - 0.0524 €
11 horas - 0.0571 €
12 horas - 0.0574 €
13 horas - 0.1209 €
14 horas - 0.1207 €
15 horas - 0.1213 €
16 horas - 0.1205 €
17 horas - 0.1227 €
18 horas - 0.1274 €
19 horas - 0.1253 €
20 horas - 0.1237 €
21 horas - 0.1238 €
22 horas - 0.1202 €
23 horas - 0.0519 €
Precio mínimo: 0.04344
Precio máximo: 0.12742
Precio medio: 0.08105

Share

17 trucos para Python

Sin lugar a dudas Python se ha convertido en el lenguaje más versátil de la última decada.

Es posible utilizarlo para multitud de propósitos; realizar scripts de mantenimiento, crear sofisticadas paginas web, aprendizaje automático (Machine Learning), desarrollo de aplicaciones de escritorio, análisis de datos, juegos, entre otras muchas más.

Y ademas es multi-plataforma, se puede utilizar en Windows, Mac, Linux y dispositivos móviles iOS y Android.

Os traemos 17 útiles trucos para Python:

Generar UUID. Los UUID son identificadores únicos universales compuesto de 32 dígitos hexadecimales, formando 5 grupos separados por guiones, 8-4-4-4-12.

import uuid
nuevo_id = uuid.uuid4()

Ver listas, diccionarios y sobre todo json con más claridad. Para ello utilizamos la función pprint.

import requests
import pprint

url = "https://randomuser.me/api/?results=1"
users = requests.get(url).json()

pprint.pprint(users)

Crea una sola cadena a partir de todos los elementos de una lista.

a = ["Python", "es", "el", "mejor"]
print(" ".join(a))

Listar los archivos de un directorio, sin mostrar los ocultos.

import os

def ls2(path): 
    return [obj.name for obj in os.scandir(path) if obj.is_file() and not obj.name.startswith('.')]

Mover archivos entre carpetas.

import shutil

shutil.move(archivo_origen, archivo_destino)

Iniciar un servidor estático en directorio local.

# En Mac y Linux 
python -m SimpleHTTPServer

# Windows 
python -m http.server

Mostar notificaciones en Mac.

import os

def notify(title, text):
    os.system("""
              osascript -e 'display notification "{}" with title "{}"'
              """.format(text, title))

Explorar las librerías. Muestra un listado con las funciones que contienen.

import requests
import collections

dir(requests)
dir(collections)

Valor por defecto en diccionario, si no existe la clave.

nombres = {1:'Casa', 2:'Patio', 3:'Jardin', 4:'Terraza'}
def  control(code):
    #return 'Zona: %s!' % nombres[code] #Expresión normal
    return 'Zona: %s!' % nombres.get(code, 'El lugar no exite')

print(control(5))

Sumar minutos a una hora.

from datetime import datetime, date, time, timedelta

ahora = datetime.now()
hora_actual = time(ahora.hour, ahora.minute, ahora.second)
minutos = (datetime.combine(datetime.date(ahora), hora_actual) + timedelta(minutes = 30)).time()

print(minutos)

Sumar dias a una fecha.

from datetime import datetime, date, time, timedelta

ahora = datetime.now()
nuevaFecha = ahora.date() + timedelta(days = 10)

print(nuevaFecha)

Evitar la salida de datos en Jupyter Notebook.

%%capture

a = ["Python", "es", "el", "mejor"]
print(" ".join(a))

Eliminar carácteres no alfanumericos.

import re

s = "La casa tiene && $$ %% Goteras de Caballo"
s = re.sub('[^0-9a-zA-Z]+', ' ', s)

print(s)

Reimportar modulo.

reload(modulo)

Emojis. Emojis con caracteres Unicode.

print(chr(128513))

Crea un diccionario a partir de 2 listas.

keys = ["a", "b", "c", "d", "e"]
valores = [1,2,3,4,5]

zipped = dict(zip(keys, valores))

print(zipped)

Ocultar el password al pedirlo por consola.

import getpass
usuario = raw_input("Introduce usuario: ")
password = getpass.getpass("Introduce password: ")
print(usuario, password)

Share

Paginación con Django y Python

En muchos proyectos la paginación resulta esencial, ya que sin dicha función, una pagina web podría ser eterna y no acabar nunca.

Es muy habitual ver las técnicas de paginación en los blog o en las galerías de imágenes. Aunque hoy en día también se utiliza mucho la paginación infinita, puede que tu proyecto no se adapte bien a esta modalidad y precises la clásica paginación manual.

Hoy traemos un código para implementar la paginación en proyectos realizados con Django, pero es muy fácil adaptarlo a otro Framework o lenguaje.

El trabajo duro lo realiza una función, que nos devuelve los valores que serán mostrados en la paginación.

Función Python:

def muestra_paginacion(actual, fin):
    total = 9
    grupo = 4

    if fin > 9:
        if actual - grupo > 1:
            if actual + grupo >= fin:
                pag = orden_paginacion(fin - total, total, fin)
            else:
                pag = orden_paginacion(actual - grupo, total, fin)
        else:
            pag = orden_paginacion(1, total, fin)
    else:
        pag = orden_paginacion(1, fin, fin)

    return pag

def orden_paginacion(inicio, total, ultimo):
    valores = []
    x = range(total)
    for n in x:
        valores.append(inicio + n)

    # Si contiene más de 9
    if ultimo > 9:
        decenas = int(ultimo/10)
        for n in range(decenas):
            valores.append((n+1)*10)


    return valores
  • Actual. Es la pagina actual.
  • Fin. Es el total de paginas.
  • Total. La variable total, es el grupo de elementos del 1 al 9.
  • Grupo. Especifica el número de elementos a la izquierda y derecha del elemento seleccionado. Ejemplo: 1 – 2 – 3 – 4 – 5 – 6 – 7 – 8 – 9

Ejemplo de como se vera una paginación de 51 paginas, pagina número 1 seleccionada.

Pagina 33 seleccionada.

Código html:

{% if ultimo > 1 %}
        <span class="paginacion">
            <div class="navegacion">
                    <nav data-pagination>
                        <ul>

                        {% if actual > 5 and ultimo > 9 %}                           
                            <li><a href="{% url 'Tematica_DVD' tema_buscado %}?page=1">1</a>
                            <li><a href=#10>…</a>
                        {% endif %}
                            

                        {% for n in pag %}
                            {% if n == actual %}
                                <li class=current><a href=#>{{ actual }}</a>
                            {% else %}
                                <li><a href="{% url 'Tematica_DVD' tema_buscado %}?page={{ n }}">{{ n }}</a>

                            {% endif %}         
                        {% endfor %}

                        {% if ultimo != actual and ultimo > 9 %}
                            <li><a href=#10>…</a>
                            <li><a href="{% url 'Tematica_DVD' tema_buscado %}?page={{ ultimo }}">{{ ultimo }}</a>
                        {% endif %}
                            
                        </ul>
                    </nav>
            </div>
         </span>
        {% endif %}

Como se ve en la imagen superior, la paginación mostrará las cuatro paginas anteriores y las cuatro posteriores a la pagina seleccionada. también mostrará las decenas de todas las paginas entre la primera y la última, 10,20,30,40….

Cuando la paginación sea inferior a 10, se mostrará de esta forma.

Share

Generar mapas con datos estadísticos, con Python y Plotly

Si necesitas representar diferentes datos estadísticos sobre un mapa del mundo o de un continente o zona del planeta determinado, existe una herramienta muy potente que te permite de forma fácil realizar esta tarea.

Con Python y la librería Plotly podrás mostrar tus datos estadísticos sobre diferentes zonas geográficas.

El código es bien sencillo, y es altamente configurable. Para que Plotly ubique los datos en cada país, es necesario incluir el nombre de dicho país en los datos, el nombre debe estar en formato internacional, por ejemplo “Estados Unidos” debe ser “United States of America“.

import funciones_db as db
import plotly.graph_objects as go
import plotly.offline as opy

datos = db.actores_paises()

fig = go.Figure(go.Choropleth(
    locations = datos['pais'],
    locationmode = "country names",
    z = datos['total'],
    text = datos['pais_a'],
    colorscale = 'Hot',
    autocolorscale = False,
    reversescale = True,
    marker_line_color = '#efefef',
    marker_line_width = 0.5,
    colorbar_ticksuffix = '%',
    colorbar_title = 'Actores',
    )
)

fig.update_layout(
    title_text = 'Número de Actores por Países',
    showlegend = False,
    geo = dict(
        scope = 'world',
        resolution = 50,
        projection_type = 'miller',
        showcoastlines = True,
        showocean = True,
        showcountries = True,
        oceancolor = '#eaeaea',
        lakecolor = '#eaeaea',
        coastlinecolor = '#dadada'
    )
)

fig.show()

En el ejemplo los datos se extraen de una base de datos.

  • locations: Indica el país al que pertenece el dato.
  • locationmode = “country names”: Indica la forma en la que se mostrara la información, es este caso por países. Si llos datos son para un determinado país y quieres mostrar los datos por provincias o estados, se debe cambiar este parametro.
  • colorscale: La paleta de colores que mostrará los datos. Algunas de las paletas disponibles; Brwnyl, Agsunset, Sunsetdark, Magenta, Sunset, Purpor, Purp, Tealgrn, Teal, Bluyl, Aggrnyl, Emrld, Darkmint, Blugrn, Mint, Pinkyl, Peach, Oryel, Redor, Burgyl, Burg, tempo, amp, speed, matter, algae, dense, deep, gray, ice, solar, haline, thermal, turbid, YlOrRd, YlOrBr, YlGnBu, YlGn, Reds, RdPu, RdBu, Purples, Greys, Greens, Rainbow. Lista completa, aqui.
  • scope: Es la parte del globo terraqueo que se mostrará. world, para mostrar todos los continentes. Otros valores para cada continente; “usa” | “europe” | “asia” | “africa” | “north america” | “south america”.
  • projection_type: Es el tipo de mapa que se representará. Admite los siguientes valores; equirectangular, mercator, orthographic, natural earth, kavrayskiy7, miller, robinson, eckert4, azimuthal equal area, azimuthal equidistant, conic equal area, conic conformal, conic equidistant, gnomonic, stereographic, mollweide, hammer, transverse mercator, albers usa, winkel tripel, aitoff, sinusoidal.
  • También es posible personalizar y mostrar/ocultar otros datos del mapa, como la separación de los paises o el color de los oceanos.
  • El código genera un archivo en html, que se abre directamente en el navegador por defecto del sistema.

Algunos ejemplos con Plotly, cambiando los parametros; colorscale, scope y projection_type.

Para visualizar los datos de cada país, tan solo debemos pasar el cursor del ratón por encima de dicho país.

Los mapas pueden ser facilmente incluidos en proyecto de dJango, directamento o a través de javascript.

Plotly es una herramienta muy completa, la cual también permite realizar infinidad de graficas estadisticas a parte de los mapas. Más información de esta completa libreria aqui.

Share