Guía 17 – Mejorar la visualización de videos

Este ejemplo surge de la necesidad de mejorar la solución estándar que facilita PHPRunner para la visualización de videos.

Según hacía el ejemplo, evalué que también podía ser muy interesante para los usuarios de PHPRunner aprender a gestionar y visualizar la posibilidad que tiene el producto de subir diferentes ficheros y almacenar estos en File System del servidor, manteniendo la referencia a los ficheros en un campo de la base de datos en  formato JSON (formato estándar que utiliza PHPRunner). He hecho un conjunto de funciones  de gran utilidad para los usuarios que utilizan este tipo de almacenamiento.

Objetivo

Utilizar un plugin de visualización de videos que sea más moderno y mejores prestaciones, que el que tiene el producto de forma estándar. Además, enseñar y facilitar una serie de funciones que mejora la gestión  de este tipo de campos.

DEMO: https://fhumanes.com/videos 

Solución Técnica

Para mostrar las posibilidades he utiliza una única tabla con 3 campos.

SELECT
  id_videos,
  title,
  videos,
  videos videos2,
  videos videos3
FROM videos

Como podéis ver, el campo «videos» está 3 veces, porque vamos a utilizar 3 formas de representar los mismos datos.


Ya vemos en la página LIST que podemos ofrecer 3 formas de representar el contenido:

  • Informar de forma textual del contenido de ficheros que tiene el campo
  • Facilitar las miniaturas de las imágenes (sólo imágenes) que hay en el campo
  • Facilitar la primera de las imágenes, difuminada, y encima el resumen del contenido del campo.

Este es el aspecto que tiene PHPRunner para visualizar 2 ficheros en formato MP4, que se han subido a un campo.

Como podéis apreciar es bastante anticuado y poco práctico, de ahí que un usuario me haya solicitado algún plugin que mejore la representación y sea más funcional.

Para producir esta mejora he utilizado el plugin Videojs, que dispone de esta URL para su documentación y descarga.
Video.js – Make your player yours | Video.js (videojs.com).

Los aspectos  resultantes de utilizar este plugin y de las funciones hechas son:

Igual que en la página LIST, en esta página VIEW se ven 3 formatos distintos de la información.

En el campo videos3 es donde podemos ver el plugin cuyas características más importantes son:

  • Un zona de visualización con una imagen de portada del contenido del video.
  • Un menú (a la izquierda) con todos los videos, cada uno con su portada.
  • El nombre de cada video, que lo toma del nombre del fichero.

El ejemplo asocia imagen de portada al video por tener el mismo nombre de fichero.

En este caso, al haber sólo un vídeo aparece este y se elimina el menú de los videos.

¿Cómo se ha hecho?

En el proyecto de ejemplo, que estará al final del artículo para poderlo descargar, en el apartado de Custom File he puesto:

  • Directorio videojs, que son los fuentes del plugin.
  • El fichero analysis_of_files.php, que son el conjunto de funciones para tratar el contenido de los campos de almacenamiento de los datos de los ficheros.
  • El fichero custom_image_style.css, que lo utilizo para la visualización de contenidos en páginas LIST.
  • El fichero custom_video.css, que describe la personalización de la presentación de los videos en páginas VIEW.

analysis_of_files.php

<?php
// Funcines para reconocer los ficheros contenidos en un campo de almacenamiento de ficheros
// Functions to recognize the files contained in a field

function countFiles($field){
  $fileArray = my_json_decode($field);
  return count($fileArray);
}

function countImagesVideos($field) {
  $fileArray = my_json_decode($field);
  $countImage = 0;
  $countVideo = 0;
  foreach ($fileArray as &$file) {	
    $type = $file['type'];
    $parts = explode("/", $type);
    switch ($parts[0]) {
    case "video":
        $countVideo += 1;
        break;
    case "image":
        $countImage += 1;
        break;
    }
  }
  return array($countImage, $countVideo);
  }

function arrayImages($field) {
  $return = [];
  $fileArray = my_json_decode($field);
  foreach ($fileArray as &$file) {	
    $type = $file['type'];
    $parts = explode("/", $type);
    if ( $parts[0] == 'image' ) {
        $return[] = $file['usrName'];
    }
  }
  return $return;
}

function onlyImages($field) {
  $numDelete = 0;
  $fileArray = my_json_decode($field);
  $return = $fileArray;
  for ($i = 0; $i < count($fileArray); $i++) {
    $type = $fileArray[$i]['type'];
    $parts = explode("/", $type);
    if ( $parts[0] <> 'image' ) {
         unset($return[$i]);
         $numDelete += 1;
    }
  }
  $return = my_json_encode($return);
  return $return;
}

function arrayVideos($field) {
  $return = [];
  $fileArray = my_json_decode($field);
  foreach ($fileArray as &$file) {	
    $type = $file['type'];
    $parts = explode("/", $type);
    if ( $parts[0] == 'video' ) {
        $return[] = $file['usrName'];
    }
  }
  return $return;
}

function searchImageOfVideo($field,$nameVideo) {
  $fileArray = my_json_decode($field);
  $parts = explode(".", $nameVideo);
  $name = $parts[0]; // name without extension

  foreach ($fileArray as &$file) {	
    $type = $file['type'];
    $parts = explode("/", $type);
    if($parts[0] == 'image') {
      $parts2 = explode(".", $file['usrName']);
      if ( $parts2[0] == $name ) { // Found File image equal name to the video file
          return array(true, $file['usrName']);
      }
    }
  }
  return array(false, NULL);
}

function searchMimeType($field,$nameFile) {
  $fileArray = my_json_decode($field);

  foreach ($fileArray as &$file) {	

    if($file['usrName'] == $nameFile) {
        return $file['type'];
    }
  }
  return '';
}

Para incluir el código (página LIST) he utilizado el evento list page:Before record processed:

include_once "MyCode/analysis_of_files.php";

$countFiles = countFiles($data['videos']);
$countTypes = countImagesVideos($data['videos']);
$countImage = $countTypes[0];
$countVideo = $countTypes[1];
$data['videos'] = 'Files: <strong>'.$countFiles.'</strong><BR> Images: <strong>'.$countImage.'</strong><BR> Videos: <strong>'.$countVideo.'</strong>';

$data['videos2'] = onlyImages($data['videos2']);


//   List Video3 ---------------------------------------------
$arrayImages = arrayImages($data['videos3']);
$countFiles = countFiles($data['videos3']);
$countTypes = countImagesVideos($data['videos3']);
$countImage = $countTypes[0];
$countVideo = $countTypes[1];

if ( $countImage <> 0 ) { // There are images

$img = '<img src="mfhandler.php?file='.$arrayImages[0].
        '&table=videos&field=videos3&'.
        'pageType=list&page=list&key1='.$data['id_videos'].
        '" class="img-thumbnail" alt="'.$arrayImages[0].'" width="150" height="100">';

$textCount = 'Files: <strong>'.$countFiles.'</strong><BR> Images: <strong>'.$countImage.'</strong><BR> Videos: <strong>'.$countVideo.'</strong>';
$data['videos3'] = <<<EOT
<link REL="stylesheet" href="MyCode/custom_image_style.css" type="text/css">
<div class="custom_image_container">
  $img
  <div class="custom_image_top-left">$textCount</div>
</div> 
EOT;

} else {
$data['videos3'] = 'Files: <strong>'.$countFiles.'</strong><BR> Images: <strong>'.$countImage.'</strong><BR> Videos: <strong>'.$countVideo.'</strong>';
}


return true;

Para incluir el código (página VIEW) he utilizado el evento Process record values:

include_once "MyCode/analysis_of_files.php";

$values['videos2'] = onlyImages($values['videos2']);


// ---------------- For field "video3" ------------------
$arrayVideos = arrayVideos($values['videos3']);
$countVideos = count($arrayVideos);
if ( $countVideos <> 0 ) { // There are videos
$part = searchImageOfVideo($values['videos3'],$arrayVideos[0]);
$nameVideo = '';
$img = '';
if ($part[0] == true ) { // There is a video image file
    $nameVideo = $part[1];
    $img0 .= 'poster="mfhandler.php?file='.$nameVideo.
        '&table=videos&field=videos3&'.
        'pageType=view&page=view&key1='.$values['id_videos'].
        '" ';
}
$src0 = 'src="mfhandler.php?file='.$arrayVideos[0].
        '&table=videos&field=videos3&'.
        'pageType=view&page=view&key1='.$values['id_videos'].'"'.
        ' type="'.searchMimeType($values['videos3'],$arrayVideos[0]).'" ';  // First video

// ---- More of 1 video ---------------------
$div_playList = '';
$playList = '';
if ($countVideos > 1 ) {
$div_playList = <<<EOT
<div class="vjs-playlist">
<!--
  The contents of this element will be filled based on the
  currently loaded playlist
-->
</div>
EOT;

$playList = ' player.playlist([';
foreach ($arrayVideos as &$file) {	
$parts = explode(".", $file);
$name = $parts[0];
$src = 'src: "mfhandler.php?file='.$file.
        '&table=videos&field=videos3&'.
        'pageType=view&page=view&key1='.$values['id_videos'].'"'.
        ', type: "'.searchMimeType($values['videos3'],$file).'" '; 

$parts = searchImageOfVideo($values['videos3'],$file);
$img = '';
if ($parts[0] == true ) { // There is a video image file
    $nameVideo = $parts[1];
    $img = 'src: "mfhandler.php?file='.$nameVideo.
        '&table=videos&field=videos3&'.
        'pageType=view&page=view&key1='.$values['id_videos'].
        '" ';
}

$playList .= <<<EOT
{
name: '$name',
sources: [
  { $src },
],
thumbnail: [
  {
   $img
  }
]
},
EOT;
}
$playList .=<<<EOT
]);

// Initialize the playlist-ui plugin with no option (i.e. the defaults).
player.playlistUi();
EOT;
}

$values['videos3'] = <<<EOT
<link href="MyCode/videojs/video-js.css" rel="stylesheet">
<link href="MyCode/custom_video.css" rel="stylesheet">
<link href="MyCode/videojs/plugin/videojs-playlist-ui.css" rel="stylesheet">

<div class="player-container">
 <video
  id="custom_video"
  class="video-js"
  height="200"
  width="400"
  $img0
  controls>
  <source $src0 >
 </video>
$div_playList
</div>

<script src="MyCode/videojs/video.js"></script>
<script src="MyCode/videojs/plugin/videojs-playlist.js"></script>
<script src="MyCode/videojs/plugin/videojs-playlist-ui.js"></script>
<script>
 var player = videojs('custom_video');

 player.ready(function() {
 var promise = player.play();
 if (promise !== undefined) {
    promise.then(function() {
      console.log('AutoPlay yes');
    }).catch(function(error) {
      console.log('AutoPlay no');
    });
 }
 });

$playList
</script>
EOT;
}

Espero y deseo que os sea de interés lo mostrado en el ejemplo y para cualquier consulta podéis contactar conmigo a través de mi email [email protected].

El ejemplo está hecho en PHPRunner 10.5 y en el zip descargable está el proyecto, el backup de la tabla utilizada y el directorio files que contiene los ficheros que hace referencia en el contenido de la tabla.

Adjuntos

Archivo Tamaño de archivo Descargas
zip PHPRunner 10.5, backup de DB y directorio FILES (05/06/2021) 18 MB 504

Blog personal para facilitar soporte gratuito a usuarios de React y PHPRunner