20 de mayo de 2015

Canal de videos de YouTube con API v3 embebido en una página con Javascript.

Aunque mi fuerte no es el desarrollo de software, me gusta ensayar y desarrollar soluciones que sirvan a las empresas. Hace poco fue necesario desarrollar un canal para mostrar los videos subidos a un canal por una empresa. La solución con la API v2 se encuentra en varias páginas de internet y ha sido implementada por varias páginas con bastante éxito; sin embargo con el cambio de la API v2 a la API v3 aparecieron inconvenientes y las páginas que dependían de esta implementación empezaron a recibir la notificación por parte de YouTube desde el 22 de abril y a principios de mayo estos desarrollos dejaron de funcionar definitivamente.

Aunque en la página de la API v3 de Youtube aparecen varios ejemplos, todos dependen de la autenticación con OAuth. Para desarrollarla con la API KEY no aparecen ejemplos y me tomó bastante tiempo desarrollarla.

Pues bien, sin más preámbulos explicaré la forma para desarrollarlo haciendo modificaciones en la conocida implementación en la API v2.

El código original desarrollado por Simone Gianni en Fiddle puede encontrarse en http://jsfiddle.net/SimoneGianni/NmvA9/ y es el siguiente:



/*
Copyright 2011 : Simone Gianni <simoneg@apache.org>

Released under The Apache License 2.0
http://www.apache.org/licenses/LICENSE-2.0

*/

(function() {
    function createPlayer(jqe, video, options) {
        var ifr = $('iframe', jqe);
        if (ifr.length === 0) {
            ifr = $('<iframe scrolling="no">');
            ifr.addClass('player');
        }
        var src = 'http://www.youtube.com/embed/' + video.id;
        if (options.playopts) {
            src += '?';
            for (var k in options.playopts) {
                src+= k + '=' + options.playopts[k] + '&';
            }
            src += '_a=b';
        }
        ifr.attr('src', src);
        jqe.append(ifr);
    }
  
    function createCarousel(jqe, videos, options) {
        var car = $('div.carousel', jqe);
        if (car.length === 0) {
            car = $('<div>');
            car.addClass('carousel');
            jqe.append(car);
           
        }
        $.each(videos, function(i,video) {
            options.thumbnail(car, video, options);
        });
    }
   
    function createThumbnail(jqe, video, options) {
        var imgurl = video.thumbnails[0].url;
        var img = $('img[src="' + imgurl + '"]');
        if (img.length !== 0) return;
        img = $('<img>');   
        img.addClass('thumbnail');
        jqe.append(img);
        img.attr('src', imgurl);
        img.attr('title', video.title);
        img.click(function() {
            options.player(options.maindiv, video, $.extend(true,{},options,{playopts:{autoplay:1}}));
        });
    }
   
    var defoptions = {
        autoplay: false,
        user: null,
        carousel: createCarousel,
        player: createPlayer,
        thumbnail: createThumbnail,
        loaded: function() {},
        playopts: {
            autoplay: 0,
            egm: 1,
            autohide: 1,
            fs: 1,
            showinfo: 0
        }
    };
   
   
    $.fn.extend({
        youTubeChannel: function(options) {
            var md = $(this);
            md.addClass('youtube');
            md.addClass('youtube-channel');
            var allopts = $.extend(true, {}, defoptions, options);
            allopts.maindiv = md;
            $.getJSON('http://gdata.youtube.com/feeds/users/' + allopts.user + '/uploads?alt=json-in-script&format=5&callback=?', null, function(data) {
                var feed = data.feed;
                var videos = [];
                $.each(feed.entry, function(i, entry) {
                    var video = {
                        title: entry.title.$t,
                        id: entry.id.$t.match('[^/]*$'),
                        thumbnails: entry.media$group.media$thumbnail
                    };
                    videos.push(video);
                });
                allopts.allvideos = videos;
                allopts.carousel(md, videos, allopts);
                allopts.player(md, videos[0], allopts);
                allopts.loaded(videos, allopts);
            });
        }
    });
   
})();
       
$(function() {
    $('#player').youTubeChannel({user:'youtube'});
}); 


y contiene además un código en HTML para cargar el canal.

Con un poco de búsqueda encontré la página http://stackoverflow.com/questions/22613903/youtube-api-v3-get-list-of-users-videos de la cual tomé el siguiente código para recuperar la lista de videos:


// Get Uploads Playlist
$.get(
   "https://www.googleapis.com/youtube/v3/channels",{
   part : 'contentDetails',
   forUsername : 'USER_CHANNEL_NAME',
   key: 'YOUR_API_KEY'},
   function(data) {
      $.each( data.items, function( i, item ) {
          pid = item.contentDetails.relatedPlaylists.uploads;
          getVids(pid);
      });
  }
);

//Get Videos
function getVids(pid){
    $.get(
        "https://www.googleapis.com/youtube/v3/playlistItems",{
        part : 'snippet',
        maxResults : 20,
        playlistId : pid,
        key: 'YOUR_API_KEY'},
        function(data) {
            var results;
            $.each( data.items, function( i, item ) {
                results = '<li>'+ item.snippet.title +'</li>';
                $('#results').append(results);
            });
        }
    );
}


<!--In your HTML -->
<ul id="results"></ul>



Y finalmente combinando ambos códigos se encuentra lo siguiente:

Lo primero que se debe cambiar en el segundo código es que no queremos obtener solamente el título sino además el thumbnail del video y el id del video para poderlo reproducir; así que se cambia la línea:

results = '<li>'+ item.snippet.title +'</li>';

por

            var video = {
                        title: item.snippet.title,
                        id: item.snippet.resourceId.videoId,
                        thumbnails: item.snippet.thumbnails.default
                    };
            videos.push(video);

y se elimina la línea

$('#results').append(results);

Ahora, claramente con el cambio de la API no nos servirá la instrucción:

$.getJSON('http://gdata.youtube.com/feeds/api/videos?author=' + allopts.user + '&orderby=published&alt=json-in-script&format=5&callback=?', null, function(data)

y debe ser reemplazada por los códigos que propone la página 2:

// Get Uploads Playlist
$.get(
   "https://www.googleapis.com/youtube/v3/channels",{
   part : 'contentDetails',
   forUsername : 'USER_CHANNEL_NAME',
   key: 'YOUR_API_KEY'},
   function(data) {
      $.each( data.items, function( i, item ) {
          pid = item.contentDetails.relatedPlaylists.uploads;
          getVids(pid);
      });
  }
);

//Get Videos
function getVids(pid){
    $.get(
        "https://www.googleapis.com/youtube/v3/playlistItems",{
        part : 'snippet',
        maxResults : 20,
        playlistId : pid,
        key: 'YOUR_API_KEY'},
        function(data) {
            var results;
            $.each( data.items, function( i, item ) {
                var video = {
                        title: item.snippet.title,
                        id: item.snippet.resourceId.videoId,
                        thumbnails: item.snippet.thumbnails.default
                    };
                    videos.push(video);
            });
        }
    );


Es muy importante tener en cuenta el cambio en la estructura de datos que retorna la API de YouTube; estos cambios implican cambiar estos variables:

title: entry.title.$t debe cambiarse por title: item.snippet.title,

id: entry.id.$t.match('[^/]*$') debe cambiarse por id: item.snippet.resourceId.videoId,

thumbnails: entry.media$group.media$thumbnail debe cambiarse por
thumbnails: item.snippet.thumbnails.default

Una vez realizados estos cambios el código definitivo queda:


/*
Copyright 2011 : Simone Gianni <simoneg@apache.org>

Released under The Apache License 2.0
http://www.apache.org/licenses/LICENSE-2.0

*/

(function() {
    function createPlayer(jqe, video, options) {
        var ifr = $('iframe', jqe);
        if (ifr.length === 0) {
            ifr = $('<iframe scrolling="no">');
            ifr.addClass('player');
        }
        var src = 'http://www.youtube.com/embed/' + video.id;
        if (options.playopts) {
            src += '?';
            for (var k in options.playopts) {
                src+= k + '=' + options.playopts[k] + '&';
            } 
            src += '_a=b';
        }
        ifr.attr('src', src);
        jqe.append(ifr); 
    }
   
    function createCarousel(jqe, videos, options) {
        var car = $('div.carousel', jqe);
        if (car.length === 0) {
            car = $('<div>');
            car.addClass('carousel');
            jqe.append(car);
           
        }
        $.each(videos, function(i,video) {
            options.thumbnail(car, video, options);
        });
    }
   
    function createThumbnail(jqe, video, options) {
        var imgurl = video.thumbnails.url;
        var img = $('img[src="' + imgurl + '"]');
        if (img.length !== 0) return;
        img = $('<img>');   
        img.addClass('thumbnail');
        jqe.append(img);
        img.attr('src', imgurl);
        img.attr('title', video.title);
        img.click(function() {
            options.player(options.maindiv, video, $.extend(true,{},options,{playopts:{autoplay:1}}));
        });
    }
   
    var defoptions = {
        autoplay: false,
        user: null,
        carousel: createCarousel,
        player: createPlayer,
        thumbnail: createThumbnail,
        loaded: function() {},
        playopts: {
            autoplay: 0,
            egm: 1,
            autohide: 1,
            fs: 1,
            showinfo: 0
        }
    };
   
   
    $.fn.extend({
        youTubeChannel: function(options) {
            var md = $(this);
            md.addClass('youtube');
            md.addClass('youtube-channel');
            var allopts = $.extend(true, {}, defoptions, options);
            allopts.maindiv = md;
            // Obtener las playlist
            $.get("https://www.googleapis.com/youtube/v3/channels",{
                part : 'contentDetails',
                forUsername : 'USUARIO_DEL_CANAL',
                key: 'SU_API_KEY'},
                function(data) {
                    $.each( data.items, function( i, item ) {
                        pid = item.contentDetails.relatedPlaylists.uploads;
                        getVids(pid);
                    });
                }
            );
           
            //Obtener la información de cada video
            function getVids(pid){
                $.get("https://www.googleapis.com/youtube/v3/playlistItems",{
                    part : 'snippet',
                    maxResults : 20,
                    playlistId : pid,
                    key: 'SU_API_KEY'},
                    function(data) {
                        var feed = data.feed;
                        var videos = [];
                        $.each( data.items, function( i, item ) {
                            var video = {
                                title: item.snippet.title,
                                id: item.snippet.resourceId.videoId,
                                thumbnails: item.snippet.thumbnails.default
                            };
                        videos.push(video);
                        });
                        allopts.allvideos = videos;
                        allopts.carousel(md, videos, allopts);
                        allopts.player(md, videos[6], allopts);
                        allopts.loaded(videos, allopts);
                    }
                );
            }
        }
    });
})();
       
$(function() {
    $('#player').youTubeChannel({user:'USUARIO_DEL_CANAL'});
});


Con esto queda pendiente solamente el HTML para la página:

<html>
    <head>
    </head>
    <body>
        <div id="player">
        </div>
    </body>
</html>


y el CSS para darle estilo:

#player {
    width: 348px;
    height: 240px;
    overflow: hidden;
    background: gray;
    position: absolute;
    border: solid 2px gray;
}

.youtube .carousel {
    width: 20%;
    height: 100%;
    overflow: auto;
    position: absolute;
    right: 0px;
    z-index: 3;
}

.youtube .thumbnail {
    margin: 2px;
    width: 80%;
    border: 1px solid black; 
}

.youtube iframe.player {
    width: 80%;
    height: 240px; 
    overflow: auto;
    border: 0;
}


Espero que sea de utilidad y si quieren dejar comentarios y sugerencias serán bienvenidas.

6 de diciembre de 2013

A propósito del mundial y los sistemas

Esta mañana oía en las emisoras de radio la noticia del día aparte de la muerte de Nelson Mandela (paz en su tumba a un gran líder): el sorteo de los grupos en el mundial de fútbol Brasil 2013.

A propósito de esto aparecen dos conceptos importantes: equipos y grupos; son conceptos con diferencias fundamentales que en este contexto pueden verse claramente.

Se podría decir para empezar que en el mundial los grupos están conformados por equipos... si, es cierto pero no es generalizable; en términos generales tanto equipos como grupos pueden estar conformados por individuos o por colectividades.

Lo que me interesa resaltar aquí es la forma como funciona y se estructura cada una y qué diferencia a un grupo de un equipo. 

La Real Academia Española define un grupo como "Pluralidad de seres o cosas que forman un conjunto, material o mentalmente considerado."; aunque existen otras definiciones en las cuales incluso se mezcla el significado de grupo o grupo formal con características similares a las de un equipo.

Una definición frecuente de equipo que se encuentra en diversos documentos es: "unidades compuestas por un número de personas indeterminado que se organizan para la realización de una determinada tarea y que están relacionadas entre sí, que como consecuencia de esa relación interactúan dentro del mismo equipo para alcanzar los objetivos que se han propuesto alcanzar, reconociendo que se necesitan las unas a las otras para dicho cumplimiento y reconociéndose con identidad propia como equipo. Además estas exigencias hacen que los roles de sus miembros se deban complementar" (A esta definición no le he podido encontrar autor, agradecería que me dieran una luz en este sentido).


Si se mira en el contexto del mundial los equipos son aquellos que están conformados por un máximo de 23 jugadores (según el reglamento general de la Copa Mundial de la FIFA Brasil 2014 (TM) http://es.fifa.com/mm/document/tournament/competition/01/47/38/17/regulationsfwcbrazil2014_sp.pdf)  y el cuerpo técnico; mientras que los grupos son conformados por cuatro equipos que compiten unos contra otros.

Teniendo en cuenta lo anterior vale la pena resaltar algunas diferencias entre ambos términos:

En el equipo es importante el orden y el rol que desempeña cada miembro que lo compone; en los grupos el orden o el rol de cada integrante no es importante; de hecho cambian según los puntos que obtienen y un equipo que sea cabeza de serie no tiene nada garantizado.

En el equipo existe un objetivo común en el que todos están enfocados; en los grupos cada integrante (equipo) compite contra los otros buscando el beneficio particular.

No existe una identidad propia dentro de cada grupo; mientras que en los equipos si existe.

El grupo se compone mediante sorteos, en los cuales interviene fundamentalmente el azar; el equipo se conforma después de un profundo conocimiento de cada miembro y de unas interacciones que por su efectividad han logrado llegar al mundial y que si son bien aprovechadas y superiores a las de sus rivales, los pueden convertir en campeones mundiales.

Caben aquí varias preguntas para nuestra vida diaria:
¿En las organizaciones/empresas a las que pertenecemos se conforman grupos o equipos?, ¿se tiene en cuenta la estructura/interacciones del equipo de trabajo? ¿se establecen objetivos comunes?, ¿se trabaja por el bien común o por el beneficio individual?.

He conocido organizaciones en las cuales el compromiso y el conocimiento de cada uno de sus miembros ha logrado desarrollar verdaderos equipos y eso se ve reflejado en el rendimiento; en la calidad de sus resultados, en el ambiente de trabajo. Al respecto vale la pena citar las palabras de Peter Senge en su libro La Quinta Disciplina en la Práctica: "Tal vez la idea rectora más perniciosa que ha penetrado en la gestión empresarial occidental en el último medio siglo es que el propósito de la empresa consiste en aumentar al máximo el rendimiento de las inversiones de los accionistas. Si la gente cree esto, toda idea que se exprese quedará subordinada al lucro. ¿Puede asombrarnos que la gente de estas organizaciones carezca de compromiso, que considere que su tarea es prosaica y poco alentadora, que carezca de lealtad hacia la organización?"
Pero para asumir nuestras responsabilidades vale la pena preguntarse ¿en las sociedades nos comportamos como equipos o grupos?; en ciudades grandes como la que habito es común que las personas se quejen del comportamiento de "la gente" pero no asuman su responsabilidad en los resultados que se obtienen, en la calidad de vida que cada uno se está procurando; se arroja basura a la calle y nos quejamos de la suciedad generalizada; no se acatan normas básicas de convivencia y nos quejamos de la falta de tolerancia; no se ejerce control y nos quejamos de la corrupción y la inseguridad, etc. En las sociedades occidentales es común actuar como grupos (sin objetivos comunes, sin interacciones, sin considerar al otro, sin tareas y sin identidad).

Si tomamos como referencia la definición de sistema (como concepto amplio y general, no el que se cae a cada momento y seconvirtió en excusa para tapar problemas de la organización) de Mauricio Fernando Alba Castro en su libro Introducción a la Teoría General de Sistemas y al Análisis de Sistemas de Información  : " Un todo/totalidad/unidad distinguible en un entorno o ambiente con el cual (posiblemente) interactúa; compuesto de elementos que interactúan entre sí y quizas también con el ambiente; forma una unidad tal que sin sus elementos o relaciones deja de ser tal totalidad, aunque eventualmente sea otra"; se pueden encontrar varias similitudes entre ambos conceptos; en mi opinión creo que si el sistema está compuesto personas o individuos se tiene el mismo concepto.

Para cerrar vale la pena retomar las palabras de Jay W. Forrester en su texto Diseñando el Futuro (http://www.clexchange.org/ftp/documents/sdintro/D-4808.pdf) 

"Consideremos el contraste, durante los últimos cien años, entre los avances en nuestra comprensión de la tecnología y la relativa falta de progreso en nuestra comprensión de los sistemas sociales. ¿Cómo se explica una diferencia tan grande? ¿Por qué razón ha avanzado la tecnología tan rápidamente en tanto que los sistemas sociales continúan siendo tan desconcertantes como siempre? La respuesta está en la incapacidad para reconocer que las instituciones sociales son, en realidad, sistemas. No se acepta la idea de que las familias, corporaciones y gobiernos pertenecen a la misma clase de estructuras dinámicas que las refinerías químicas y los pilotos automáticos de los aviones.

Las organizaciones construidas mediante comisiones y por intuición no actúan mejor de lo que lo haría un avión construido con el mismo método. A menudo, grupos de empresas mixtas financian nuevas empresas en que políticas, productos y mercados se escogen de modos que, de antemano, conducen al fracaso. Como en el caso de un mal diseño aeronaútico, que nadie puede pilotar con éxito, estas corporaciones pobremente diseñadas se encuentran más allá de la habilidad de cualquier administrador real."

25 de noviembre de 2009

Marca Personal

Vivimos en un mundo altamente competitivo, vemos cómo cada vez con más frecuencia se reducen las oportunidades de trabajo, se esperan profesionales más capacitados o con más experiencia, con menos edad para asumir los cargos que se ofrecen; sin embargo también es comun encontrar personas muy capacitadas y con amplia experiencia, que no obtienen empleo debido a que están sobrecapacitadas para el perfil que se busca. Desde la revolución industrial, cada vez son más los puestos de trabajo que son reemplazados por computadores y máquinas.

Ante un panorama tan desalentador se podría suponer que no queda otro camino que sentarse a esperar que llegue el turno de ceder el puesto. Que nadie es indispensable en una organización es una realidad innegable y hay quienes proponen una prueba: "para saber si usted es indispensable, basta con que meta el dedo en un vaso de agua, si al sacar el dedo del agua queda el roto entonces usted es indispensable, no hay cómo reemplazarlo".

Ahora bien, ¿es indispensable tomar Coca Cola?, ¿Es más saludable consumir Coca Cola que agua? ¿Es más barato tomar Coca Cola que agua? Probablemente la respuesta sea siempre no, sin embargo es una de las bebidas más consumidas en el mundo. Por otra parte, muchos de nosotros estamos dispuestos a recorrer varios almacenes e incluso viajar a otras ciudades para encontrar un determinado producto de una marca que nos interesa o pedirlo por internet y esperar hasta veinte días para que llegue.

¿Por qué funciona para los productos pero no para nosotros? Para muchos es probablemente dificil hacer la comparación y verse como un producto; sin embargo hay más similitudes de las que se pueda imaginar; cuando hacemos un nuevo amigo es porque su propuesta de valor (forma de ser, conocimientos, pasatiempos) nos interesan, nos seducen. Cuando buscamos una determinada marca de un producto para comprarlo y sin importar el precio lo adquirimos, es porque buscamos precisamente lo que esa marca en particular representa y acaso ¿cada uno de nosotros no posee una serie de atributos que nos identifica?; pues bien, esa es nuestra marca personal y lo que se busca diariamente es precisamente fortalecer y destacar aquellas cosas que nos hacen interesantes para los demás (amigos, pareja, empleadores, etc).

Desarrollar y administrar una marca personal es muy similar a desarrollar y administrar una empresa; se debe definir la plataforma estratégica (Misión, Visión y Objetivos), hacer un análisis FODA, definir precio, producto, forma de distribución y los medios para difundirla. Pero no basta con esto, una marca se debe desarrollar, promocionar las ventajas y características que ofrece. Cuando se compra un producto se espera obtener a cambio la propuesta de valor que este representa y que el valor percibido al adquirir ese bien o producto sea igual o superior a lo que se invirtió para adquirirlo; si esto no ocurre nos sentimos decepcionados. Así mismo es importante que cada vez que interactuemos con alguien pensemos si esa persona realmente está obteniendo la propuesta de valor de mi marca personal; no importa de quién se trate (pareja, amigos, clientes, jefes). El profesor Javier Gómez Arias recomienda que siempre que sea posible monte su stand personal, promocionar su marca, mostrarla al público y enriquecer su red de contactos.

Existen hoy en día empresas de asesoría en branding personal/marca personal y libros como ego-marketing del autor Michael Böhm que nos pueden ayudar a descubrir y potenciar todos esos atributos que respaldan nuestra marca personal; pero nadie mejor que usted para conocer su potencial (deje la falsa modestia), indague con sus amigos acerca de cómo lo ven y probablemente se sorprenderá con las respuestas.

Las redes sociales son más que páginas web para enterarse de los últimos acontecimientos (ya no tan privados) de la vida de medio mundo, bien utilizadas nos sirven para enriquecer nuestra red personal e incluso como medio para la difusión de nuestra marca. Al respecto vale la pena resaltar la red profesional LinkedIn, en la cual se pueden encontrar interesantes oportunidades para difundir nuestra marca personal.

Después de conocer esto (como casi siempre en la vida), nos quedan dos posibilidades frente a los retos del mundo actual: nos desesperamos porque no somos comprendidos por el mundo o rediseñamos nuestra marca personal, le hacemos un relanzamiento y planteamos estrategias para su difusión. Recuerde el reconocido slogan "Alguien busca lo que usted tiene, alguien tiene lo que usted busca".

A modo de reflexión, ¿sabía usted que una de las ventajas del Café de Colombia es precisamente que es una marca que la diferencia del café de cualquier otro lugar del mundo?, ¿que esa misma marca hace que el Café de Colombia sea un producto reconocido?, ¿que eso permitió que el Café de Colombia dejara de ser un commodity para convertirse en una marca? Al respecto me permito recomendar el libro "Juan Valdez: La estrategia detrás de la marca".

El Blog de Nicolas Gomez J.

Blog dedicado a fotografía, café, libros, películas, Teoría General de Sistemas y sus aplicaciones en la administración, etc.

Seguidores