Hoy he tenido la necesidad de clasificar cientos de archivos de vídeo en función de su duración. En campusMVP manejamos literalmente miles de archivos de vídeo en formato MP4/H2.64 para nuestros cursos, y eso que también tienen en conjunto miles de páginas de teoría y otros recursos, que no solo de vídeo vive el hombre...
Bien, el caso es que la tarea no se antojaba fácil, ya que tenía que sacar un listado con todos esos archivos (eso es fácil) pero obteniendo además su duración en horas (siempre a 00), minutos y segundos.
Por suerte, Windows cuenta de serie con uno de los shells más potentes que existen: PowerShell, del cual ya te he hablado con detalle hace tiempo
Por cierto, ahora PowerShell también existe para Linux y para macOS.
Así que me puse manos a la obra, y es más fácil de lo que parece lograr ese listado, y no solo eso, sino también poder exportarlo a una Excel y otros sistemas.
Vamos a verlo...
Creando un comando de PowerShell
He creado un archivo vacío con el nombre listar-videos-mp4-con-duracion.ps1
, y le he añadido las siguientes líneas, que ahora explicaré:
param ($targetDirectory)
$LengthColumn = 27
$objShell = New-Object -ComObject Shell.Application
Get-ChildItem -LiteralPath $targetDirectory -Include *.mp4 -Recurse -Force | ForEach {
if ($_.Extension -eq ".mp4"){
$objFolder = $objShell.Namespace($_.DirectoryName)
$objFile = $objFolder.ParseName($_.Name)
$Duration = $objFolder.GetDetailsOf($objFile, $LengthColumn)
New-Object PSObject -Property @{
Name = $_.Name
Duration = $Duration
}
}
}
¿Qué es esto? Bueno, pues una función, sin la parte que la define. De este modo podremos llamar directamente al archivo pasándole los parámetros que necesitemos.
La primera línea con param
lo que hace es recibir el parámetro de la función, en este caso la carpeta en la que queremos buscar los vídeos.
El código de la función se basa en el uso de un objeto COM, que ya tiene muchos años llamado Shell.Application
y que se usaba ya con VBSCript para los scripts de Windows Script Host.
O sea, que este script de PowerShell, dada su dependencia en COM, sólo funcionará en Windows, así que ojo.
Este objeto permite obtener las propiedades de cualquier archivo usando el método GetDetalsOf
de una carpeta (sí, cosas raras de la época y sus malos diseños). El problema es que para leer un atributo concreto de un archivo se debe elegir mediante su posición numérica, siendo 0
su nombre, 1
su tamaño en bytes, etc... Pero ¿qué pasa con los atributos extendidos?
Bueno, pues pasa su posición y lo que significa dependen del tipo de archivo (no todos los tipos tienen todos los atributos extendidos) y además su descripción depende del idioma del sistema operativo.
En el caso concreto de los archivos de vídeo (no sólo .mp4), su duración se almacena en la posición 27. ¿Cómo lo sé? Pues podría haber hecho prueba y error e ir probando uno a uno los numeritos, pero gracias al holandés Jaap Brasser y este artículo suyo de PowerShell Magazine, tengo un pequeño script que me permite ver todas las propiedades extendidas de un objeto en mi sistema:
Vale. Pues sabiendo esto, sacar ahora lo demás es muy fácil. Sólo hay que recorrer todas las subcarpetas a partir de la que se le pase al archivo y devolver un objeto nuevo formado por el nombre del archivo y su duración. El resultado es este:
¡Fenomenal! Además no tarda casi nada porque sólo tiene que leer los atributos del archivo, no analizarlos, y puede devolverme esta información para miles de archivos en unos segundos.
Lo bueno, además, es que con PowerShell es muy fácil sacar eso a una ventana interactiva para poder filtrarlos y trabajar con ellos, haciendo esto:
Windows Terminal
.\listar-videos-mp4-con-duracion.ps1 ./_temp | Out-GridView
Encadenando el resultado de nuestro script con la mónada nativa para mostrar la información en un rejilla, obtenemos esto:
Desde esta rejilla podemos ordenar y filtrar, incluyendo criterios más o menos complejos con el desplegable.
Pero si queremos, como era mi caso, poder procesarlos de manera más cómoda, lo que podemos hacer es exportarlos a CSV (archivo separado por comas):
.\listar-videos-mp4-con-duracion.ps1 ./_temp | Export-CSV -Path duraciones.csv -UseCulture -Encoding UTF8 -NoTypeInformation
que lo que hace es crear un archivo con el nombre duraciones.csv
en la misma carpeta en la que está el script .ps1
, usando UTF8 para codificarla y empleando el separador de campos que usemos en la cultura local del sistema (en inglés los CSV se separan por comas, pero en español, curiosamente, son puntos y coma):
Este archivo lo podemos abrir con Excel (o Google Sheets) y así filtrarlo y tratarlo fácilmente con el propósito de análisis que queramos.
Es más, y esto es para los muy vagos como yo, podemos hacer que directamente ya nos lo abra en Excel, simplemente añadiéndole el comando Invoke-Item con la ruta del CSV, que lo abrirá con el programa predeterminado para este tipo de archivos, en mi caso Microsoft Excel:
Fíjate que en este caso no quiero pasarle el resultado del comando anterior a Invoke-Item
, sino que es un comando aparte, por lo que en lugar de separarlo con un pipe (|
), lo hago con un punto y coma (;
).
Bueno, yo lo he usado para obtener la duración de los vídeos, pero podría haberlo hecho para muchas otras cosas variando ligeramente el código.
Te dejo los 2 scripts que he utilizado, el de averiguar los atributos extendidos y el que he usado para el listado, en un archivo ZIP: powershell-listar-duracion-videos-jasoft_org.zip (1KB) para que puedas usarlos directamente si lo deseas.
Ten en cuenta que, más allá de la utilidad directa (que la tiene) la técnica te puede valer de manera general para retocar un poco el script y hacer cosas más complicadas.
¡Espero que te resulte útil!