<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Mi media center</title>
	<atom:link href="http://www.mimediacenter.info/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.mimediacenter.info</link>
	<description>Ideas para llevar la experiencia multimedia al salón</description>
	<lastBuildDate>Tue, 30 Apr 2013 00:33:43 +0000</lastBuildDate>
	<language>es-ES</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.4.2</generator>
		<item>
		<title>Como programar add-ons en XBMC: Leyendo datos de fuentes complicadas (continuación)</title>
		<link>http://www.mimediacenter.info/2013/04/30/como-programar-add-ons-en-xbmc-leyendo-datos-de-fuentes-complicadas-continuacion/</link>
		<comments>http://www.mimediacenter.info/2013/04/30/como-programar-add-ons-en-xbmc-leyendo-datos-de-fuentes-complicadas-continuacion/#comments</comments>
		<pubDate>Tue, 30 Apr 2013 00:33:43 +0000</pubDate>
		<dc:creator>Jesus</dc:creator>
				<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[como programar addon xbmc]]></category>

		<guid isPermaLink="false">http://www.mimediacenter.info/?p=1378</guid>
		<description><![CDATA[Este tutorial forma parte de la serie Cómo programar un add-on de XBMC Continuando con la entrada de ayer, y hablando sobre cómo leer datos de sitios web que presentan alguna dificultad especial, hoy voy a detenerme un poco en los pasos necesarios para acceder a sitios protegidos mediante usuario y contraseña. Es bastante habitual [...]]]></description>
			<content:encoded><![CDATA[<blockquote><p>Este tutorial forma parte de la serie <a href="http://www.mimediacenter.info/tag/como-programar-addon-xbmc/">Cómo programar un add-on de XBMC</a></p></blockquote>
<p>Continuando con la entrada de ayer, y hablando sobre cómo leer datos de sitios web que presentan alguna dificultad especial, hoy voy a detenerme un poco en los pasos necesarios para acceder a sitios protegidos mediante usuario y contraseña.</p>
<p>Es bastante habitual encontrarse sitios web que requieren un login o identificación, como los foros que ocultan los enlaces si no tienes cuenta, los sitios tipo red social como Series.ly donde los usuarios escriben y aporta, o incluso los sitios web privados a los que sólo se puede acceder mediante invitación.</p>
<p>En realidad el problema del login es muy sencillo de resolver, ya que el truco está en mantener una sesión en el sitio web y eso se consigue mediante cookies. La función <a href="http://www.mimediacenter.info/plugintools/referencia/read_body_and_headers/">read_body_and_headers</a> de <a href="http://www.mimediacenter.info/plugintools/">PluginTools</a> soporta cookies, así que esto va a ser fácil.</p>
<p><span id="more-1378"></span></p>
<h2>Paso 1: Usar Firebug para ver cómo funciona el login</h2>
<p>Un gran principio universal es que hay que utilizar la herramienta apropiada a cada problema, y para desarrollar plugins la herramienta es el navegador <a href="http://www.mozilla.org/es-ES/firefox/new/">Firefox</a> con el plugin <a href="http://getfirebug.com/">Firebug</a> instalado.</p>
<p>Este plugin tiene muchas funciones, pero la que necesitamos ahora es la pestaña de &#8220;Red&#8221; donde se graba la conversación entre el navegador y el sitio web. Con ambos instalados vamos a acceder a la web de mega-spain.com para entender cómo funciona el proceso de login.</p>
<p>Abre la URL de Mega-Spain en Firefox y pulsa sobre el botón &#8220;Visitante&#8221; que hay en la esquina superior derecha. Rellena los datos en el formulario de login pero no le des todavía al botón &#8220;Ingresar&#8221;.</p>
<p><img class="aligncenter size-full wp-image-1403" title="Preparado para el login" src="http://www.mimediacenter.info/wp-content/uploads/2013/04/login-1.jpg" alt="Preparado para el login" width="600" /></p>
<p>Pulsa en el icono de la cucaracha de Firebug para abrirlo en la zona inferior de la pantalla.</p>
<p><img class="aligncenter size-full wp-image-1403" title="Abriendo Firebug para la grabacion" src="http://www.mimediacenter.info/wp-content/uploads/2013/04/login-2.jpg" alt="Abriendo Firebug para la grabacion" width="600" /></p>
<p>Selecciona ahora la pestaña de &#8220;Red&#8221; en Firebug, pulsa en &#8220;Limpiar&#8221; en caso de que hubiera algo grabado previamente y pulsa el botón &#8220;Ingresar&#8221; para que haga el login.</p>
<p>La petición que hagas, la respuesta que obtengas y todos los elementos necesarios para pintarla (imágenes, scripts, estilos, etc.) quedarán grabados por Firebug.</p>
<p><img class="aligncenter size-full wp-image-1403" title="Grabación realizada" src="http://www.mimediacenter.info/wp-content/uploads/2013/04/login-3.jpg" alt="Grabación realizada" width="600" /></p>
<p>Fíjate en que la primera línea es la del envío del login, se trata de un envío POST a una URL.</p>
<p><img class="aligncenter size-full wp-image-1403" title="Detalle de la línea que contiene el login" src="http://www.mimediacenter.info/wp-content/uploads/2013/04/login-4.jpg" alt="Detalle de la línea que contiene el login" width="600" /></p>
<p>Si pulsas en la pestaña &#8220;Post&#8221; verás exactamente lo que has enviado. La sección &#8220;Fuente&#8221; recoge el valor además tal como se ha enviado, justo lo que necesitamos.</p>
<p><img class="aligncenter size-full wp-image-1403" title="Detalle del formato en que se envía el login" src="http://www.mimediacenter.info/wp-content/uploads/2013/04/login-5.jpg" alt="Detalle del formato en que se envía el login" width="600" /></p>
<p>Así que para hacer el login tenemos que enviar a la URL &#8220;http://www.mega-spain.com/index.php?action=login2&#8243; una petición POST indicando en el cuerpo los valores &#8220;user=tvalacarta&amp;passwrd=accede&#8221;. Fácil ¿no?</p>
<h2>Paso 2: Activar las cookies</h2>
<p>De la información que ha grabado Firebug podemos extraer dos detalles adicionales que son importantes.</p>
<p>El primero es que la respuesta a nuestro envío POST incluye la cabecera &#8220;Set-Cookie&#8221;, mediante la cual el servidor web indica al navegador que debe almacenar una cookie.</p>
<p><img class="aligncenter size-full wp-image-1403" title="Cabeceras de envío del login" src="http://www.mimediacenter.info/wp-content/uploads/2013/04/login-6.jpg" alt="Cabeceras de envío del login" width="600" /></p>
<p>Esta cookie será enviada automáticamente por el navegador en sucesivas peticiones, y es precisamente lo que el servidor utiliza para relacionar todas las peticiones que recibe como pertenecientes a un mismo usuario. Esto lo hará <a href="http://www.mimediacenter.info/plugintools/">PluginTools</a> por tí exactamente igual que un navegador, ya que la función <a href="http://www.mimediacenter.info/plugintools/referencia/read_body_and_headers/">read_body_and_headers</a> mantiene las cookies en un fichero en disco y las actualiza en cada petición.</p>
<p>Otro detalle importante es que la respuesta incluye una cabecera &#8220;Location&#8221;, que es una redirección mediante la que el servidor indica al navegador que debe saltar a una dirección distinta. Fíjate que Firefox hace el salto de forma automática, y cuando llames a <a href="http://www.mimediacenter.info/plugintools/referencia/read_body_and_headers/">read_body_and_headers</a> se hará lo mismo a menos que indiques que no se sigan las redirecciones.</p>
<h2>Paso 3: Enviar la información de login</h2>
<p>Recopilando toda la información que hemos encontrado gracias a Firebug, concluimos que la forma de hacer el login por código es poner al principio de tu plugin estas líneas:</p>
<pre class="codigo">custom_post="user=tvalacarta&amp;passwrd=accede"
body,response_headers = plugintools.read_body_and_headers("http://www.mega-spain.com", post=custom_post)</pre>
<p>Tampoco ha resultado tan difícil, ¿no?</p>
<p>Cuando hayas ejecutado estas líneas, las cookies de la sesión se cargarán en el almacén de cookies de cada usuario. Todas las llamadas que se hagan a partir de ahí serán interpretadas por el servidor como si las hubiera realizado el usuario identificado.</p>
<h2>Tratar las redirecciones manualmente</h2>
<p>Resuelto el problema del login, hay un par de trucos más que es conveniente aprender para tener a mano cuando hacen falta. El primero de ellos tiene relación con la cabecera &#8220;Location&#8221; que hemos visto más arriba.</p>
<p>El comportamiento por defecto de un navegador es hacer una petición, y si la respuesta incluye una cabecera &#8220;Location&#8221; se usa la URL que especifica la cabecera como nueva dirección de salto.</p>
<p>En ocasiones es conveniente utilizar directamente la URL que se indica en la cabecera Location, y para eso basta con indicar el parámetro &#8220;follow_redirects&#8221; a False.</p>
<pre class="codigo">body,response_headers = plugintools.read_body_and_headers("http://www.mimediacenter.info", follow_redirects=False)</pre>
<p>Lo más normal es que el cuerpo de la respuesta venga vacío, pero lo que te interesa es la cabecera así que tendrás que recorrer la lista de cabeceras de la respuesta:</p>
<pre class="codigo">location=""
for name,value in response_headers:
    if name=="location":
        location=value</pre>
<p>Fíjate en que el nombre de la cabecera va en minúsculas.</p>
<h2>Aumentar el timeout cuando el sitio web es lento</h2>
<p>El último parámetro que queda por ver en la función &#8220;<a href="http://www.mimediacenter.info/plugintools/referencia/read_body_and_headers/">read_body_and_headers</a>&#8221; te permite especificar un valor de timeout superior al que viene por defecto en tu intérprete de Python.</p>
<p>Es un problema habitual en los scripts de Python que se produzcan problemas debido a un timeout muy pequeño, lo que hace que algunas llamadas remotas fallen cuando de otra forma podrían haber funcionado.</p>
<p>Basta poner un valor de timeout suficientemente alto (en segundos) para que las llamadas remotas tengan más paciencia.</p>
<pre class="codigo">body,response_headers = plugintools.read_body_and_headers("http://www.mimediacenter.info", timeout=30*60)</pre>
<p>Si el servidor es rápido el timeout no tiene ninguna influencia en el resultado, pero un timeout muy alto hará que la aplicación se quede bloqueada esperando.</p>
<h2>Activar información de log ampliada</h2>
<p>Cuando tienes que hacer cosas avanzadas es bueno ver exactamente el tipo de información que se envía y obtiene en cada petición, de forma que puedas entender por qué acabas teniendo el resultado que esperas.</p>
<p>En caso de que lo necesites puedes aumentar el nivel de detalle que se muestra en el log con dos variables que encontrarás en las primeras líneas del código fuente del módulo plugintools.py.</p>
<pre class="codigo">module_log_enabled = False
http_debug_log_enabled = False</pre>
<p>Si pones la primera variable <strong>module_log_enabled</strong> a <strong>True</strong>, conseguirás que las funciones de <a href="http://www.mimediacenter.info/plugintools/">PluginTools</a> muestren información de depuración en el log. Todas las funciones escribirán en el log su nombre al ser invocadas, y la información relevante en cada caso como resultado de su ejecución.</p>
<p>La segunda variable <strong>http_debug_log_enabled</strong> puesta a <strong>True</strong> activa el log de depuración del módulo de Python urllib2, lo que te permitirá ver en el log todas las cabeceras HTTP.</p>
<p>Mucha información, pero en ocasiones imprescindible. No olvides desactivarla cuando vayas a usar tu plugin en el día a día, el fichero de log puede hacerse enorme.</p>
<h2>Próxima entrada</h2>
<p>Con esta entrada estamos llegando ya a la recta final de esta serie de tutoriales. En la próxima entrada veremos cómo utilizar metadatos extendidos en la lista de items. Eso nos permitirá especificar colores, negritas, duración de los vídeos, etc.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mimediacenter.info/2013/04/30/como-programar-add-ons-en-xbmc-leyendo-datos-de-fuentes-complicadas-continuacion/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Como programar add-ons en XBMC: Leyendo datos de fuentes complicadas</title>
		<link>http://www.mimediacenter.info/2013/04/28/como-programar-add-ons-en-xbmc-leyendo-datos-de-fuentes-complicadas/</link>
		<comments>http://www.mimediacenter.info/2013/04/28/como-programar-add-ons-en-xbmc-leyendo-datos-de-fuentes-complicadas/#comments</comments>
		<pubDate>Sun, 28 Apr 2013 07:36:21 +0000</pubDate>
		<dc:creator>Jesus</dc:creator>
				<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[como programar addon xbmc]]></category>

		<guid isPermaLink="false">http://www.mimediacenter.info/?p=1167</guid>
		<description><![CDATA[Este tutorial forma parte de la serie Cómo programar un add-on de XBMC Después de una interrupción de tres meses (increíble cómo pasa el tiempo), por fin he encontrado un hueco para continuar los tutoriales de programación de add-ons abordando algunos de los problemas que te encontrarás cuando programes add-ons en el mundo real. Y [...]]]></description>
			<content:encoded><![CDATA[<blockquote><p>Este tutorial forma parte de la serie <a href="http://www.mimediacenter.info/tag/como-programar-addon-xbmc/">Cómo programar un add-on de XBMC</a></p></blockquote>
<p>Después de una interrupción de tres meses (increíble cómo pasa el tiempo), por fin he encontrado un hueco para continuar los tutoriales de programación de add-ons abordando algunos de los problemas que te encontrarás cuando programes add-ons en el mundo real.</p>
<p>Y es que no todos los sitios web son sencillos cuando quieres acceder con un plugin, así que en ocasiones es necesario acudir a algunos trucos para conseguir tu objetivo.</p>
<p>He tenido que hacer algunas mejoras en la librería Plugin Tools para permitirle hacer algunos de estos trucos, así que la entrada de hoy empieza explicando en qué consisten estas mejoras para verlas luego en acción sobre casos prácticos.</p>
<p><span id="more-1167"></span></p>
<h2>Añadiendo más funciones de HTTP en PluginTools</h2>
<p>Los ejemplos que hemos visto hasta ahora han utilizado la función &#8220;read&#8221; de <a href="http://www.mimediacenter.info/plugintools/">PluginTools</a> de una forma muy sencilla: le pasas la URL que quieres leer y te devuelve una cadena con el contenido de esa URL.</p>
<pre class="codigo">body = plugintools.read("http://www.mimediacenter.info")</pre>
<p>Cuando esto no funcione habrá que recurrir a la nueva función &#8220;read_body_and_headers&#8221; de PluginTools, como una versión mejorada de la función &#8220;read&#8221; que permitirá un montón de posibilidades nuevas:</p>
<pre class="codigo">body,response_headers = plugintools.read_body_and_headers("http://www.mimediacenter.info", headers=request_headers, post=custom_post, follow_redirects=True, timeout=10)</pre>
<p>Entre las que se incluyen:</p>
<ul>
<li>Gestión de cookies transparente</li>
<li>Cabeceras personalizadas (parámetro &#8220;headers&#8221;)</li>
<li>Aumentar el tiempo de espera ante conexiones lentas (parámetro &#8220;timeout&#8221;)</li>
<li>Tratamiento automático de páginas comprimidas con Gzip</li>
<li>Envios POST (parámetro &#8220;post&#8221;)</li>
<li>Procesar las redirecciones manualmente (parámetro &#8220;follow_redirects&#8221;)</li>
<li>Acceder a las cabeceras de respuesta</li>
<li>Información de depuración adicional</li>
</ul>
<p>El diseño de la función puede que no sea muy elegante, pero lo que perseguía era tener una función compacta, rápida y sencilla. Si quieres una librería para hacer esto de una forma más &#8220;pythonica&#8221; puedes recurrir a la librería <a href="python-requests.org">Python Requests</a>, o a la popular <a href="http://wwwsearch.sourceforge.net/mechanize/">Mechanize</a>. Ambas muy utilizadas y recomendables.</p>
<p>Ahora vamos con algunos ejemplos de uso de &#8220;read_body_and_headers&#8221;.</p>
<h2>Que hacer si el sitio web verifica el User-Agent</h2>
<p>Empecemos con un caso sencillo. Cuando haces una llamada HTTP utilizando un navegador cualquiera, dentro de la llamada se envía una cabecera especial llamada <a href="http://es.wikipedia.org/wiki/Agente_de_usuario">&#8220;User-Agent&#8221;</a> que identifica el navegador que está haciendo la llamada.</p>
<p>Este es el ejemplo de lo que se envía en una llamada HTTP hecha con Firefox para leer la página principal de este blog:</p>
<pre class="codigo">GET / HTTP/1.1
Host: www.mimediacenter.info
<strong>User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:20.0) Gecko/20100101 Firefox/20.0</strong>
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: es-ES,es;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: keep-alive</pre>
<p>Puedes observar que una de las líneas empieza por &#8220;User-Agent&#8221; e identifica al navegador exacto con el que has hecho la petición:</p>
<pre class="codigo">Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:20.0) Gecko/20100101 Firefox/20.0</pre>
<p>Sin embargo cuando haces una llamada HTTP desde Python usando la función &#8220;read&#8221; de PluginTools, el navegador empleado es el módulo estándar urllib2 de Python. Y el User-Agent que se manda así lo indica:</p>
<pre class="codigo">GET / HTTP/1.1
<strong>User-Agent: Python-urllib/2.1</strong>
Host: www.mimediacenter.info
Accept: */*</pre>
<p>Puedes ver que en este caso la llamada tiene menos cabeceras, y que el User-Agent identifica claramente a Python como originador de la misma:</p>
<pre class="codigo">Python-urllib/2.1</pre>
<p>El caso es que hay sitios web que detectan el User-Agent y lo utilizan con diversos fines, como mostrar un sitio web adaptado al navegador desde el que accedes (útil para móviles) o incluso para bloquear el acceso a ciertos dispositivos.</p>
<p>Por suerte HTTP es un protocolo abierto y bien documentado, de hecho <a href="http://tools.ietf.org/html/rfc2616">su especificación es una lectura muy recomendable si te dedicas a esto</a>. Con la suficiente habilidad es fácil engañar a cualquier servidor web, y en este caso no podría ser más sencillo ya que basta con enviar la cabecera User-Agent que queramos para que el sitio web no sea capaz de identificarnos como un plugin.</p>
<p>Esto del User-Agent es tan importante que por defecto la función &#8220;read_body_and_headers&#8221; de PluginTools utiliza un User-Agent de ordenador, concretamente Firefox 18.0 para Mac, siempre que la usas. Si quieres indicar cualquier otro User-Agent basta con que añadas una cabecera HTTP con el parámetro &#8220;headers&#8221;.</p>
<pre class="codigo">body,response_headers = plugintools.read_body_and_headers("http://www.mimediacenter.info", headers=[["User-Agent","Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_3) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.65 Safari/537.31"]])</pre>
<p>Verás que &#8220;headers&#8221; es una lista de cabeceras, que contiene a su vez dos elementos para el nombre de la cabecera y el valor. En el ejemplo la petición se lanza identificándose como &#8220;Google Chrome&#8221; para Mac.</p>
<pre class="codigo">GET / HTTP/1.1
<strong>User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_3) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.65 Safari/537.31</strong>
Host: www.mimediacenter.info
Accept: */*</pre>
<p>Una forma de hacer lo mismo pero más legible, especialmente cuando necesitas añadir varias cabeceras, es añadirlas una por una al array en lugar de declararlo todo en la misma línea:</p>
<pre class="codigo">
request_headers=[]
request_headers.append(["User-Agent","Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_3) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.65 Safari/537.31"])
body,response_headers = plugintools.read_body_and_headers("http://www.mimediacenter.info", headers=request_headers)</pre>
<p>Cuestión de gustos, pero la legibilidad del código es importante <img src='http://www.mimediacenter.info/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<h2>Qué hacer si el sitio web verifica el Referer</h2>
<p>Si User-Agent es la cabecera que se envía para que el sitio web sepa qué programa estás utilizando, <a href="http://en.wikipedia.org/wiki/HTTP_referer">Referer</a> es la cabecera que se envía para informarle de la página desde donde vienes.</p>
<p>Esta información se utiliza en los sitios web para seguir la navegación del usuario (saber el camino que sigue en un sitio web), y también se utiliza en muchos casos como medida de protección contra el <a href="http://es.wikipedia.org/wiki/Hot-linking">hot-linking</a>.</p>
<p>Te la encontrarás por ejemplo si quieres datos de una página que se encuentran dentro de un iframe, o cuando quieras realizar una llamada AJAX para resolver la paginación. Son casos bastante habituales, y los detectarás cuando pidas una página y el sitio web te devuelva otra, o un error.</p>
<p>La solución es tan sencilla como añadir una segunda cabecera a nuestro ejemplo, poniendo una nueva cabecera &#8220;Referer&#8221; en la lista para indicar la página de origen que el sitio web esté esperando.</p>
<p>Supongamos que para acceder a la página principal de Plugin Tools en Mi Media Center (http://www.mimediacenter.info/plugintools) fuera necesario hacerlo desde la página principal del sitio (http://www.mimediacenter.info). Bastará con indicar la URL de la página principal como &#8220;Referer&#8221; al hacer la petición.</p>
<pre class="codigo">
request_headers=[]
request_headers.append(["User-Agent","Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_3) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.65 Safari/537.31"])
request_headers.append(["Referer","http://www.mimediacenter.info/"])
body,response_headers = plugintools.read_body_and_headers("http://www.mimediacenter.info/plugintools/", headers=request_headers)</pre>
<p>Puedes ver ejemplos de sitios web que utilizan la verificación del Referer en el código fuente de pelisalacarta, por ejemplo <a href="https://code.google.com/p/xbmc-tvalacarta/source/browse/trunk/pelisalacarta/pelisalacarta/channels/animeid.py">AnimeID</a>, <a href="https://code.google.com/p/xbmc-tvalacarta/source/browse/trunk/pelisalacarta/pelisalacarta/channels/beeg.py">Beeg</a>, <a href="https://code.google.com/p/xbmc-tvalacarta/source/browse/trunk/pelisalacarta/pelisalacarta/channels/cuevana.py">Cuevana</a>, <a href="https://code.google.com/p/xbmc-tvalacarta/source/browse/trunk/pelisalacarta/pelisalacarta/channels/jkanime.py">JKAnime</a>, <a href="https://code.google.com/p/xbmc-tvalacarta/source/browse/trunk/pelisalacarta/pelisalacarta/channels/tucinecom.py">Tucinecom</a>, &#8230;</p>
<h2>Próxima entrada</h2>
<p>Todavía quedan algunos trucos más que contar, pero esta entrada ya se está haciendo demasiado larga. En la próxima entrada veremos algunos más incluyendo cómo resolver el caso de un sitio web que requiere login.</p>
<p>Descarga ya la nueva versión de <a href="http://www.mimediacenter.info/plugintools">Plugin Tools</a> y anímate a hacer tus propios proyectos, es fácil <img src='http://www.mimediacenter.info/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.mimediacenter.info/2013/04/28/como-programar-add-ons-en-xbmc-leyendo-datos-de-fuentes-complicadas/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Aprovecha la capacidad del formato MKV para organizar tu colección de vídeos</title>
		<link>http://www.mimediacenter.info/2013/01/20/aprovecha-la-capacidad-del-formato-mkv-para-organizar-tu-coleccion-de-videos/</link>
		<comments>http://www.mimediacenter.info/2013/01/20/aprovecha-la-capacidad-del-formato-mkv-para-organizar-tu-coleccion-de-videos/#comments</comments>
		<pubDate>Sat, 19 Jan 2013 23:26:01 +0000</pubDate>
		<dc:creator>Jesus</dc:creator>
				<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[mkv]]></category>
		<category><![CDATA[mkvmerge]]></category>

		<guid isPermaLink="false">http://www.mimediacenter.info/?p=1198</guid>
		<description><![CDATA[Aprovechando unos días tranquilos hace poco me decidí por fin a organizar mi colección de pelis. En primer lugar porque ocupan un espacio considerable en disco y hace tiempo que había detectado formas de mejorarlo y tener más espacio libre, pero también para tenerlas mejor clasificadas. Entre otras cosas pensé en aprovechar la capacidad del [...]]]></description>
			<content:encoded><![CDATA[<p>Aprovechando unos días tranquilos hace poco me decidí por fin a organizar mi colección de pelis. En primer lugar porque ocupan un espacio considerable en disco y hace tiempo que había detectado formas de mejorarlo y tener más espacio libre, pero también para tenerlas mejor clasificadas.</p>
<p>Entre otras cosas pensé en aprovechar la capacidad del formato MKV a la hora de gestionar vídeos complejos, para almacenar las películas con sus subtítulos (que tengo en ficheros separados en muchos casos), eliminar las cadenas de audio en otros idiomas, unir las películas que están partidas en varios ficheros, y cosas por el estilo.</p>
<p>Tengo unas notas dispersas sobre los comandos que se deben utilizar para cada caso, y he pensado que podría ser interesante recopilarlos todos en esta entrada.</p>
<p>Hay una estupenda herramienta visual para hacerlo casi todo, llamada <a href="http://greatdreamers.cn/projects/mkvtoolnix/doc/guide/es/mkvmerge-gui.html">mkvmerge GUI</a>, pero encuentro una pesadez usarla para procesar muchos vídeos. La línea de comandos es mucho más ágil para esto, y te permite hacer scripts para procesar los vídeos en bloque.<br />
<span id="more-1198"></span></p>
<h2>Cómo unir todas las partes de un vídeo en un único fichero MKV (sin recomprimir)</h2>
<p>Algo bastante habitual es tener una peli grabada en varios ficheros, muchas veces a causa de la práctica que había antes de separar las pelis largas en ficheros del tamaño de un CD (700MB).</p>
<p>Sorprendentemente el formato MKV permite tener los dos fragmentos de vídeo en el mismo fichero, y los reproduce uno detrás de otro sin saltos como si nunca hubieran estado separados.</p>
<p>Para conseguir esto debes usar el comando &#8220;mkvmerge&#8221; y unir todas las partes con la siguiente sintaxis, donde &#8220;salida.mkv&#8221; es el archivo que vas a conseguir al final y &#8220;parte1.avi&#8221;, &#8220;parte2.avi&#8221; y &#8220;parte3.avi&#8221; son cada uno de los fragmentos:</p>
<pre class="comando">mkvmerge -o salida.mkv parte1.avi +parte2.avi +parte3.avi ...</pre>
<p>Ten cuidado de que cada símbolo &#8220;+&#8221; tenga un espacio antes, y de que no lo tenga después. Es importante.</p>
<p>Veamos un ejemplo, donde tengo la película de &#8220;Tron&#8221; en dos ficheros &#8220;Tron (CD1).avi&#8221; y &#8220;Tron (CD2).avi&#8221;.</p>
<pre class="comando">
jesus@mediaserver:~$ <strong>mkvmerge -o Tron.mkv Tron\ \(CD1\).avi +Tron\ \(CD2\).avi</strong> 
mkvmerge v5.1.0 ('And so it goes') creado el Feb  1 2012 11:31:23
'Tron (CD1).avi': Using the demultiplexer for the format 'AVI'.
'Tron (CD2).avi': Using the demultiplexer for the format 'AVI'.
'Tron (CD1).avi' pista 0: Using the output module for the format 'MPEG-4'.
'Tron (CD1).avi' pista 1: Using the output module for the format 'MP3'.
'Tron (CD2).avi' pista 0: Using the output module for the format 'MPEG-4'.
'Tron (CD2).avi' pista 1: Using the output module for the format 'MP3'.
El archivo Tron.mkv ha sido abierto para su escritura.
Uniendo la pista 1 del archivo n.º 1 ('Tron (CD2).avi') a la pista 1 del archivo n.º 0 ('Tron (CD1).avi').
Uniendo la pista 0 del archivo n.º 1 ('Tron (CD2).avi') a la pista 0 del archivo n.º 0 ('Tron (CD1).avi').
Progreso: 100%
El índice está siendo escrito...
Muxing took 1 minuto 14 segundos.
</pre>
<p>Al final del proceso conviene abrir el resultado con un reproductor. Comprueba que la duración es coherente y salta por varios puntos de la película para verificar que se vea bien y el audio está sincronizado, ya que si el fichero de entrada está corrupto podrías tener un vídeo incompleto en la salida.</p>
<h2>Cómo convertir un fichero AVI a uno MKV (sin recomprimir)</h2>
<p>En realidad el formato .AVI no es el mejor del mundo, pero si tienes un vídeo en .AVI que te hayas descargado de Internet tampoco es necesario que lo conviertas de formato. Y convertirlo a MKV no va a hacer que tenga más calidad, eso es un mito <img src='http://www.mimediacenter.info/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Sin embargo si eres de los que te gusta tener todo ordenadito y con la misma extensión, debes saber que puedes convertir el formato de cualquier vídeo a .MKV sin recomprimirlo (y por tanto sin pérdida de calidad alguna) usando el comando mkvmerge.</p>
<pre class="comando">mkvmerge -o salida.mkv entrada.avi</pre>
<p>Y un ejemplo:</p>
<pre class="comando">
jesus@mediaserver:~$ <strong>mkvmerge -o Tron.mkv Tron.avi</strong>
mkvmerge v5.1.0 ('And so it goes') creado el Feb  1 2012 11:31:23
'Tron.avi': Using the demultiplexer for the format 'AVI'.
'Tron.avi' pista 0: Using the output module for the format 'MPEG-4'.
'Tron.avi' pista 1: Using the output module for the format 'MP3'.
El archivo Tron.mkv ha sido abierto para su escritura.
Progreso: 100%
El índice está siendo escrito...
Muxing took 2 minutos 5 segundos.
jesus@mediaserver:~$ 
</pre>
<h2>Cómo quitar cadenas de audio en otros idiomas</h2>
<p>A mí me gusta ver cine en versión original (depende de la peli) pero a la hora de guardarlas para mi colección no me gusta hacerlo más que con el audio en español. Puedes grabar una peli con varias cadenas de audio y subtítulos, por supuesto, pero el audio es algo que ocupa espacio y especialmente si está codificado con AC3.</p>
<p>La forma de extraer las cadenas de audio que no quieres es volver a grabar el vídeo en un nuevo fichero, pero copiando sólo las cadenas de audio que te interesan. Lo primero es identificar la cadena de audio &#8220;buena&#8221; con el comando:</p>
<pre class="comando">mkvmerge -i entrada.mkv</pre>
<p>Para a continuación crear un nuevo fichero indicando el número de la cadena de audio &#8220;buena&#8221;:</p>
<pre class="comando">mkvmerge -o salida.mkv --atracks NUMERO entrada.mkv</pre>
<p>O los &#8220;números&#8221; si quieres conservar más de de una cadena de audio:</p>
<pre class="comando">mkvmerge -o salida.mkv --atracks NUMERO,NUMERO entrada.mkv</pre>
<p>Veamos un ejemplo con la peli de &#8220;Wanted&#8221; que tengo en mi disco.</p>
<pre class="comando">
jesus@mediaserver:/media/CINE$ <strong>mkvmerge -i Wanted\ \(2008\)\ \[720p\].mkv</strong> 
Archivo 'Wanted (2008) [720p].mkv': contenedor: Matroska
La ID de la pista 1: video (V_MPEG4/ISO/AVC)
La ID de la pista 2: audio (A_AC3)
La ID de la pista 3: audio (A_AC3)
La ID de la pista 4: subtitles (S_TEXT/UTF8)
jesus@mediaserver:/media/CINE$ 
</pre>
<p>Como ves, tiene dos pistas de audio y una de subtítulos. Lo normal es que la primera cadena de audio sea en español y la siguiente en inglés, pero puedes asegurarte usando el comando &#8220;mkvinfo&#8221;.</p>
<pre class="comando">jesus@mediaserver:/media/CINE$ <strong>mkvinfo Wanted\ \(2008\)\ \[720p\].mkv</strong>
...
| + Una pista
|  + Número de pista: 2
...
|  + Idioma: spa
|  + Nombre: Castellano AC3 5.1
</pre>
<p>De forma que el audio en español es la cadena 2. Ahora vamos con mkvmerge:</p>
<pre class="comando">
jesus@mediaserver:/media/CINE$ <strong>mkvmerge -o salida/Wanted\ \(2008\)\ \[720p\].mkv --atracks 2 Wanted\ \(2008\)\ \[720p\].mkv</strong> 
mkvmerge v5.1.0 ('And so it goes') creado el Feb  1 2012 11:31:23
'Wanted (2008) [720p].mkv': Using the demultiplexer for the format 'Matroska'.
'Wanted (2008) [720p].mkv' pista 1: Using the output module for the format 'AVC/h.264'.
'Wanted (2008) [720p].mkv' pista 2: Using the output module for the format 'AC3'.
'Wanted (2008) [720p].mkv' pista 4: Using the output module for the format 'text subtitles'.
El archivo salida/Wanted (2008) [720p].mkv ha sido abierto para su escritura.
Progreso: 100%
El índice está siendo escrito...
Muxing took 1 minuto 8 segundos.
jesus@mediaserver:/media/CINE$
</pre>
<p>El resultado es un fichero que pasa de 2,6GB a 2,2GB.</p>
<pre class="comando">
-rwxrwxrwx 1 jesus jesus 2,6G jul 13  2010 Wanted (2008) [720p].mkv
-rw-rw-r-- 1 jesus jesus 2,2G ene 19 19:24 salida/Wanted (2008) [720p].mkv
</pre>
<p>Para ser exactos el tamaño se redujo en 354MB. No está mal para 1 minuto de procesamiento, si haces esto con 100 pelis tendrás 35GB libres más en tu disco. Y yo tengo más de 100 <img src='http://www.mimediacenter.info/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<h2>Cómo añadir audio en otros idiomas</h2>
<p>Si lo que quieres hacer es la operación contraria es más sencillo todavía. Y es realmente sencillo porque es para lo que se diseñó la herramienta mkvmerge: para construir archivos MKV a partir de diferentes elementos.</p>
<pre class="comando">mkvmerge -o salida.mkv video.mp4 audio.aac</pre>
<p>Observa que este caso es muy similar al que usábamos para concatenar dos vídeos, pero no utilizamos el símbolo &#8220;+&#8221;.</p>
<h2>Cómo añadir subtítulos desde un fichero externo</h2>
<p>Algo muy habitual es descargarte la peli por un lado, y los subtítulos por otro. En mi caso ocurre a menudo con los documentales de la BBC que descargo de mvgroup.org, y acabo teniendo un montón de ficheritos al lado de cada vídeo.</p>
<p>El comando para hacer esto con mkvmerge es el mismo que en el caso anterior, ya que la cadena de subtítulos no es más que una pista adicional para añadir al vídeo.</p>
<pre class="comando">mkvmerge -o salida.mkv video.mp4 subtitulo.srt</pre>
<p>Aunque <a href="https://bbs.archlinux.org/viewtopic.php?id=54488">si el subtítulo es UTF-8</a> debes tener en cuenta algún parámetro más:</p>
<pre class="comando">mkvmerge -o salida.mkv video.mp4 --sub-charset 0:UTF8 -s 0 -D -A subtitulo.srt</pre>
<p>Veamos un ejemplo, de estos tengo bastantes, de una peli con dos cadenas de audio.</p>
<pre class="comando">
jesus@mediaserver:/media/CINE$ <strong>mkvmerge -i Toy\ Story\ 3\ \[HDrip\]-original.mkv</strong> 
Archivo 'Toy Story 3 [HDrip]-original.mkv': contenedor: Matroska
La ID de la pista 1: video (V_MS/VFW/FOURCC, XVID)
La ID de la pista 2: audio (A_AC3)
La ID de la pista 3: audio (A_AC3)
</pre>
<p>Añadimos dos archivos de subtítulos:</p>
<pre class="comando">
jesus@mediaserver:/media/CINE$ <strong>mkvmerge -o Toy\ Story\ 3\ \[HDrip\].mkv Toy\ Story\ 3\ \[HDrip\]-final.mkv Toy\ Story\ 3\ \[HDrip\]\ es.srt Toy\ Story\ 3\ \[HDrip\]\ inglés.srt</strong> 
mkvmerge v5.1.0 ('And so it goes') creado el Feb  1 2012 11:31:23
'Toy Story 3 [HDrip]-final.mkv': Using the demultiplexer for the format 'Matroska'.
'Toy Story 3 [HDrip] es.srt': Using the demultiplexer for the format 'SRT subtitles'.
'Toy Story 3 [HDrip] inglés.srt': Using the demultiplexer for the format 'SRT subtitles'.
'Toy Story 3 [HDrip]-final.mkv' pista 1: Using the output module for the format 'MPEG-4'.
'Toy Story 3 [HDrip]-final.mkv' pista 2: Using the output module for the format 'AC3'.
'Toy Story 3 [HDrip]-final.mkv' pista 3: Using the output module for the format 'AC3'.
'Toy Story 3 [HDrip] es.srt' pista 0: Using the output module for the format 'text subtitles'.
'Toy Story 3 [HDrip] inglés.srt' pista 0: Using the output module for the format 'text subtitles'.
El archivo Toy Story 3 [HDrip].mkv ha sido abierto para su escritura.
Progreso: 100%
El índice está siendo escrito...
Muxing took 58 segundos.
</pre>
<p>Para acabar teniendo un archivo con 2 pistas de audio y dos subtítulos:</p>
<pre class="comando">
jesus@mediaserver:/media/CINE$ <strong>mkvmerge -i Toy\ Story\ 3\ \[HDrip\].mkv</strong> 
Archivo 'Toy Story 3 [HDrip].mkv': contenedor: Matroska
La ID de la pista 1: video (V_MS/VFW/FOURCC, XVID)
La ID de la pista 2: audio (A_AC3)
La ID de la pista 3: audio (A_AC3)
La ID de la pista 4: subtitles (S_TEXT/UTF8)
La ID de la pista 5: subtitles (S_TEXT/UTF8)
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.mimediacenter.info/2013/01/20/aprovecha-la-capacidad-del-formato-mkv-para-organizar-tu-coleccion-de-videos/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Cómo programar add-ons en XBMC: Un add-on más completo (continuación)</title>
		<link>http://www.mimediacenter.info/2013/01/13/como-programar-add-ons-en-xbmc-un-add-on-mas-completo-continuacion/</link>
		<comments>http://www.mimediacenter.info/2013/01/13/como-programar-add-ons-en-xbmc-un-add-on-mas-completo-continuacion/#comments</comments>
		<pubDate>Sat, 12 Jan 2013 23:37:55 +0000</pubDate>
		<dc:creator>Jesus</dc:creator>
				<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[como programar addon xbmc]]></category>

		<guid isPermaLink="false">http://www.mimediacenter.info/?p=1241</guid>
		<description><![CDATA[Este tutorial forma parte de la serie Cómo programar un add-on de XBMC Ayer vimos cómo añadir la sección de vídeos de la web oficial de Disney Junior, analizando paso a paso la extracción de los vídeos del listado, cómo añadirlos a la lista de items de XBMC, y cómo reproducir un vídeo seleccionado por [...]]]></description>
			<content:encoded><![CDATA[<blockquote><p>Este tutorial forma parte de la serie <a href="http://www.mimediacenter.info/tag/como-programar-addon-xbmc/">Cómo programar un add-on de XBMC</a></p></blockquote>
<p>Ayer vimos cómo añadir la sección de vídeos de la web oficial de Disney Junior, analizando paso a paso la extracción de los vídeos del listado, cómo añadirlos a la lista de items de XBMC, y cómo reproducir un vídeo seleccionado por el usuario.</p>
<p>Hoy terminamos el add-on añadiendo otra sección para ver los vídeos del canal de YouTube de Disney Junior, muy útil porque tiene una playlist para cada una de las series incluyendo algunos extras como el karaoke &#8220;Canta con Disney Junior&#8221;.</p>
<p>También veremos cómo utilizar el teclado en pantalla de XBMC para incluir un buscador, que nos permita acceder fácilmente a una lista de resultados relevantes en YouTube, y cómo utilizar el sistema de configuración de un add-on en XBMC para dejar que el usuario personalice algunos aspectos.</p>
<p>¿Comenzamos?</p>
<p><span id="more-1241"></span></p>
<h2>Las series del canal de YouTube</h2>
<p>Si recuerdas el <a href="http://www.mimediacenter.info/2012/12/11/como-programar-add-ons-en-xbmc-funcionamiento-de-un-add-on-paso-a-paso/">add-on con el que empezó esta serie de tutoriales</a>, uno sencillito que permitía acceder a los vídeos de mi propio canal de YouTube, verás que hacer lo mismo con cualquier otro canal de YouTube no es más complicado que cambiar el ID del canal en el código.</p>
<p>Sin embargo ese add-on utilizaba el API de YouTube para obtener la lista de vídeos subidos al canal</p>
<pre class="prettyprint">http://gdata.youtube.com/feeds/api/users/<strong>tvalacarta</strong>/<strong>uploads</strong></pre>
<p>pero para el de Disney Junior lo que nos interesa es tener la lista de las &#8220;playlists&#8221; que el propietario del canal ha definido. </p>
<pre class="prettyprint">http://gdata.youtube.com/feeds/api/users/<strong>DisneyJuniorES</strong>/<strong>playlists</strong></pre>
<p>De esta forma al seleccionar la opción &#8220;Canal de YouTube&#8221; obtendremos una lista de las series de Disney Junior, y al seleccionarlas podremos obtener una lista de vídeos de esa serie. Cada niño tiene sus preferencias.</p>
<p>Aunque podríamos parsear el XML que nos devuelve YouTube usando las librerías de XML de Python, probablemente de una forma más elegante, lo normal en un add-on va a ser encontrarse HTML así que vamos a usar expresiones regulares. Además quedará más compacto, créeme.</p>
<p>Como la estructura de un feed RSS es una sucesión de tags &lt;entry&gt; para cada vídeo, con la información del vídeo dentro de esos tags, vamos a utilizar una forma un poco distinta de extraer los datos.</p>
<p>En primer lugar vamos a utilizar una expresión regular sencilla que nos va a devolver un array con el texto que hay dentro de cada uno de los bloques &lt;entry&gt;.</p>
<pre class="prettyprint">
119 # Show all YouTube playlists for the selected channel
120 def youtube_playlists(params):
121     plugintools.log("disneyjunior.youtube_playlists "+repr(params))
122
123     # Fetch video list from YouTube feed
124     data = plugintools.read( params.get("url") )
125     plugintools.log("data="+data)
126    
127     # Extract items from feed
128     pattern = ""
129     matches = plugintools.find_multiple_matches(data,"&lt;entry(.*?)&lt;/entry&gt;")
</pre>
<p>Y ahora vamos a recorrer ese array extrayendo los datos de los vídeos para añadirlos a la lista de items de XBMC. Como dentro de un tag &lt;entry&gt; sólo hay un vídeo, usaremos la función <a href="http://www.mimediacenter.info/plugintools/referencia/find_single_match/" title="find_single_match">find_single_match</a> de Plugin Tools para sacar los valores.</p>
<pre class="prettyprint">    
131     for entry in matches:
132         plugintools.log("entry="+entry)
</pre>
<p>El título está entre los tags &lt;title&gt;, pero utilizaremos una curiosa expresión regular en este caso.</p>
<pre class="prettyprint">    
135         title = plugintools.find_single_match(entry,"&lt;titl[^&gt;]+&gt;([^&lt;]+)&lt;/title&gt;")
</pre>
<p>Si utilizo como expresión regular</p>
<p>&lt;title&gt;([^&lt;]+)&lt;/title&gt;</p>
<p>El patrón fallará cuando se encuentre con cosas como esta:</p>
<pre>
"&lt;title &gt;Ejemplo&lt;/title&gt;
"&lt;title lang="es"&gt;Ejemplo&lt;/title&gt;
...
</pre>
<p>Así que sustituyo &lt;title&gt; por &lt;titl[^&gt;]+&gt; de forma que cuando el patrón haya encontrado las primeras letras del nombre del tag &#8220;titl&#8221;, deje de buscar para ir directamente al cierre de tag &#8220;&gt;&#8221;. Esto nos lo habríamos evitado usando un parser XML tradicional, pero el truco es útil también en HTML <img src='http://www.mimediacenter.info/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>El resto de elementos del feed se extraen de forma similar. El argumento del vídeo está en el tag &lt;media:description&gt;, la imagen en el tag &lt;media:thumbnail&gt; y la URL de la lista de vídeos en el tag &lt;content&gt; que tiene como atributo type &#8220;application/atom+xml;type=feed&#8221;.</p>
<p>Observa que hay un caracter &#8220;\&#8221; antes de los símbolos &#8220;=&#8221;, &#8220;+&#8221; y &#8220;;&#8221; debido a que tienen un significado especial dentro de una expresión regular, pero en este caso nos interesa su valor literal. Queremos la cadena &#8220;atom+xml&#8221;, y no la interpretación de &#8220;uno o más&#8221; que tiene el símbolo &#8220;+&#8221;.</p>
<pre class="prettyprint">    
136         plot = plugintools.find_single_match(entry,"&lt;media\:descriptio[^&gt;]+&gt;([^&lt;]+)&lt;/media\:description&gt;")
137         thumbnail = plugintools.find_single_match(entry,"&lt;media\:thumbnail url='([^']+)'")
138         url = plugintools.find_single_match(entry,"&lt;content type\='application/atom\+xml\;type\=feed' src='([^']+)'/&gt;")
139 
140         # Appends a new item to the xbmc item list
141         plugintools.add_item( action="youtube_videos" , title=title , plot=plot , url=url , thumbnail=thumbnail , folder=True )
</pre>
<p>Al añadir cada elemento a la lista de items de XBMC indicamos la acción &#8220;youtube_videos&#8221;, que mostrará la lista de vídeos incluidos en la playlist de la URL.</p>
<p>Con esto ya tenemos la lista de playlists del canal, no tenemos que preocuparnos de la paginación como en el plugin de &#8220;Mi media center&#8221; ya que la llamada de YouTube no permite paginación y siempre devuelve la lista completa.</p>
<p><img src="http://www.mimediacenter.info/wp-content/uploads/2013/01/playlists-de-disney-junior.jpg" alt="" title="playlists-de-disney-junior" width="620" height="349" class="aligncenter size-full wp-image-1270" /></p>
<h2>Los vídeos de cada serie</h2>
<p>Como la URL de la lista de vídeos está en el parámetro &#8220;url&#8221;, y lo que estamos procesando es nuevamente un feed XML, la función &#8220;youtube_videos&#8221; acaba siendo muy similar a la anterior así que no vamos a verla en detalle.</p>
<p>Observa únicamente que en este caso la URL que añadimos tiene el esquema &#8220;plugin://plugin.video.youtube/&#8221;, ya que estamos componiéndola de forma que al seleccionar el vídeo se llame al add-on de YouTube para su reproducción. Y como el elemento que añadimos en este paso es directamente reproducible, lo marcamos como &#8220;folder=False&#8221; para que XBMC sepa que no tiene que descender más.</p>
<pre class="prettyprint">
144 # Show all YouTube videos for the selected playlist
145 def youtube_videos(params):
146     plugintools.log("disneyjunior.youtube_videos "+repr(params))
147
148     # Fetch video list from YouTube feed
149     data = plugintools.read( params.get("url") )
150     plugintools.log("data="+data)
151    
152     # Extract items from feed
153     pattern = ""
154     matches = plugintools.find_multiple_matches(data,"&lt;entry(.*?)&lt;/entry&gt;")
155     
156     for entry in matches:
157         plugintools.log("entry="+entry)
158         
159         # Not the better way to parse XML, but clean and easy
160         title = plugintools.find_single_match(entry,"&lt;titl[^&gt;]+&gt;([^&lt;]+)&lt;/title&gt;")
161         title = title.replace("Disney Junior España | ","")
162         plot = plugintools.find_single_match(entry,"&lt;summa[^&gt;]+&gt;([^&lt;]+)&lt;/summa")
163         thumbnail = plugintools.find_single_match(entry,"&lt;media\:thumbnail url='([^']+)'")
164         video_id = plugintools.find_single_match(entry,"http\://www.youtube.com/watch\?v\=([0-9A-Za-z_-]{11})")
165         url = "plugin://plugin.video.youtube/?path=/root/video&#038;action=play_video&#038;videoid="+video_id
166
167         # Appends a new item to the xbmc item list
168         plugintools.add_item( action="play" , title=title , plot=plot , url=url , thumbnail=thumbnail , isPlayable=True, folder=False )
</pre>
<p><img src="http://www.mimediacenter.info/wp-content/uploads/2013/01/disney-junior-videos-de-una-playlist.jpg" alt="" title="disney-junior-videos-de-una-playlist" width="620" height="349" class="aligncenter size-full wp-image-1271" /></p>
<p>Cuando el usuario selecciona un vídeo se llama a la función &#8220;play&#8221;.</p>
<h2>Reproducción del vídeo</h2>
<p>La función &#8220;play&#8221; es muy sencilla, a diferencia del caso de &#8220;disneyweb_play&#8221; que veíamos ayer, ya que la URL que viene como parámetro es directamente algo que XBMC sabe reproducir.</p>
<pre class="prettyprint">
169 # Play selected vieo
170 def play(params):
171     plugintools.play_resolved_url( params.get("url") )
</pre>
<p>Una simple llamada a <a href="http://www.mimediacenter.info/plugintools/referencia/play_resolved_url/">play_resolved_url</a> de Plugin Tools le indica a XBMC que puede empezar la reproducción.</p>
<h2>Configuración</h2>
<p>Antes de ver el buscador es necesario conocer primero cómo funciona el mecanismo que XBMC pone a disposición de los add-ons para gestionar los parámetros de configuración. Esto es así porque el buscador hace uso de algunos de estos parámetros.</p>
<p>Para que tu add-on tenga configuración tienes que crear un fichero &#8220;settings.xml&#8221; dentro del directorio &#8220;resources&#8221;, donde especificar uno por uno los parámetros que vas a emplear.</p>
<pre>
&lt;?xml version="1.0" encoding="utf-8" standalone="yes"?&gt;
&lt;settings&gt;
    &lt;setting id="youtube_channel_id" type="text" option="writeable" label="30006" default="DisneyJuniorES"/&gt;
    &lt;setting id="youtube_language" type="text" option="writeable" label="30007" default="es"/&gt;
    &lt;setting id="last_search" type="text" option="writeable" label="30001" default="la casa de mickey mouse"/&gt;
&lt;/settings&gt;
</pre>
<p>En este caso he definido 3 parámetros</p>
<ul>
<li><strong>youtube_channel_id</strong>: Indica el ID del canal de YouTube que se mostrará cuando el usuario seleccione esta opción, con un valor por defecto de &#8220;DisneyJuniorES&#8221; que es la versión española. Puedes poner &#8220;DisneyJuniorLA&#8221;, &#8220;DisneyJuniorUK&#8221;, &#8230; o cualquier otro <img src='http://www.mimediacenter.info/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </li>
<li><strong>youtube_language</strong>: Indica el idioma de los resultados de búsqueda, por defecto &#8220;es&#8221; para que salgan vídeos en español pero puedes poner cualquier código de idioma ISO.</li>
<li><strong>last_search</strong>: Es la última búsqueda que has introducido, para que la siguiente vez que uses el buscador la recuerde y te la proponga</li>
</ul>
<p>Observa que los parámetros tienen un atributo &#8220;type&#8221; que te permite indicar &#8220;text&#8221;, como en este caso, pero hay otros muchos tipos como &#8220;number&#8221;, &#8220;folder&#8221;, &#8230; La lista completa está <a href="http://wiki.xbmc.org/index.php?title=Addon_Settings">en la Wiki de XBMC</a>.</p>
<p>El texto que se muestra al usuario está en el atributo &#8220;label&#8221;, donde puedes poner directamente una cadena de texto o como en mi caso el ID de la cadena en el fichero strings.xml. Así el diálogo de configuración estará también traducido al idioma del usuario.</p>
<p>Con este fichero presente tu add-on ya es configurable, y si en la lista de add-ons instalados seleccionas la opción &#8220;Configuración del Add-on&#8221; con el menú contextual podrás acceder al diálogo de configuración.</p>
<p>Como esto es algo complejo para el usuario yo prefiero poner una opción dentro del add-on para abrir el cuadro de diálogo, en este caso una que llama a la función &#8220;preferences&#8221; que a su vez encarga de abrir este cuadro de diálogo.</p>
<p>Y lo hace con la función <a href="http://www.mimediacenter.info/plugintools/referencia/open_settings_dialog/">open_settings_dialog</a> de Plugin Tools.</p>
<pre class="prettyprint">
173 # Open preferences dialog
174 def preferences(params):
175     plugintools.log("disneyjunior.preferences "+repr(params))
176
177     plugintools.open_settings_dialog()
</pre>
<p>En el siguiente punto veremos cómo se implementa el buscador, y de paso cómo leer y escribir los valores de los parámetros de configuración desde el código de tu add-on.</p>
<p><img src="http://www.mimediacenter.info/wp-content/uploads/2013/01/disney-junior-configuracion-del-addon.jpg" alt="" title="disney-junior-configuracion-del-addon" width="620" height="349" class="aligncenter size-full wp-image-1272" /></p>
<h2>Buscador</h2>
<p>La función que XBMC ejecuta cuando seleccionas el buscador es muy sencilla, lo único que hace es leer el valor de &#8220;last_search&#8221; en la configuración para ver la última búsqueda que escribiste. Para ello utiliza la función <a href="http://www.mimediacenter.info/plugintools/referencia/get_setting/">get_setting</a>.</p>
<p>Luego abre el teclado usando la función <a href="http://www.mimediacenter.info/plugintools/referencia/keyboard_input/">keyboard_input</a>, almacena el resultado de nuevo en &#8220;last_search&#8221; usando la función <a href="http://www.mimediacenter.info/plugintools/referencia/set_setting/">set_setting</a>.</p>
<pre class="prettyprint">
179 # Open a popup dialog for input search terms, then call the result function
180 def search(params):
181     plugintools.log("disneyjunior.search "+repr(params))
182
183     last_search = plugintools.get_setting("last_search")
184     texto = plugintools.keyboard_input(last_search)
185     plugintools.set_setting("last_search",texto)
186
187     params["texto"]=texto
188    
189     youtube_search(params)
</pre>
<p>Una vez que tiene el texto tecleado lo almacena como un parámetro &#8220;texto&#8221; y llama a la función &#8220;youtube_search&#8221;, que es similar a las anteriores ya que procesa un feed XML de YouTube con los resultados.</p>
<p><img src="http://www.mimediacenter.info/wp-content/uploads/2013/01/disney-junior-buscador.jpg" alt="" title="disney-junior-buscador" width="620" height="349" class="aligncenter size-full wp-image-1273" /></p>
<p>La única diferencia es que la llamada al API de YouTube es diferente. Usa el servicio &#8220;videos&#8221; de YouTube indicando en el parámetro &#8220;q&#8221; el texto que el usuario ha tecleado, y en el parámetro &#8220;lr&#8221; el idioma que ha puesto en la configuración.</p>
<pre class="prettyprint">
191 # Show first 50 videos from YouTube that matches a search string
192 def youtube_search(params):
193     plugintools.log("disneyjunior.search "+repr(params))
194
195     # Fetch video list from YouTube feed
196     data = plugintools.read( "https://gdata.youtube.com/feeds/api/videos?q="+params.get("texto").replace(" ","+")+"&#038;orderby=published&#038;start-index=1&#038;max-results=50&#038;v=2&#038;lr="+plugintools.get_setting("youtube_language") )
197     plugintools.log("data="+data)
198    
199     # Extract items from feed
200     pattern = ""
201     matches = plugintools.find_multiple_matches(data,"&lt;entry(.*?)&lt;/entry&gt;")
202    
203     for entry in matches:
204         plugintools.log("entry="+entry)
205        
206         # Not the better way to parse XML, but clean and easy
207         title = plugintools.find_single_match(entry,"&lt;titl[^&gt;]+&gt;([^&lt;]+)&lt;/title&gt;")
208         plot = plugintools.find_single_match(entry,"&lt;summa[^&gt;]+&gt;([^&lt;]+)&lt;/summa")
209         thumbnail = plugintools.find_single_match(entry,"&lt;media\:thumbnail url='([^']+)'")
210         video_id = plugintools.find_single_match(entry,"http\://www.youtube.com/watch\?v\=([0-9A-Za-z_-]{11})")
211         if video_id=="":
212             video_id = plugintools.find_single_match(entry,"https\://www.youtube.com/watch\?v\=([0-9A-Za-z_-]{11})")
213         url = "plugin://plugin.video.youtube/?path=/root/video&#038;action=play_video&#038;videoid="+video_id
214
215         # Appends a new item to the xbmc item list
216         plugintools.add_item( action="play" , title=title , plot=plot , url=url , thumbnail=thumbnail , isPlayable=True, folder=False )
</pre>
<p>El resultado son los primeros 50 elementos que coinciden con el texto buscado, en el idioma elegido por el usuario. Y la acción de cada vídeo individual es la misma función &#8220;play&#8221; que en el caso anterior.</p>
<h2>Mensajes al usuario</h2>
<p>No he utilizado en este caso mensajes para el usuario, pero la librería Plugin Tools incluye una función <a href="http://www.mimediacenter.info/plugintools/referencia/message/">message</a> que te permite mostrar una alerta en caso necesario.</p>
<pre class="prettyprint">plugintools.message("Disney Junior","Ejemplo de mensaje")</pre>
<p><img src="http://www.mimediacenter.info/wp-content/uploads/2013/01/disney-junior-mensaje.jpg" alt="" title="disney-junior-mensaje" width="620" height="349" class="aligncenter size-full wp-image-1274" /></p>
<h2>Descarga el add-on de Disney Junior</h2>
<p>Aunque estaba en la entrada de ayer, incluyo de nuevo el enlace al add-on completo para que puedas descargarlo y estudiarlo cómodamente. Es totalmente funcional, también puedes usarlo para ver algún vídeo si quieres <img src='http://www.mimediacenter.info/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<blockquote><p><a href="http://www.mimediacenter.info/descargas/plugin.video.disneyjunior-1.0.0.zip">http://www.mimediacenter.info/descargas/plugin.video.disneyjunior-1.0.0.zip</a></p></blockquote>
<h2>Próxima entrega</h2>
<p>Ya queda poco para llegar al final de esta serie de tutoriales sobre cómo programar add-ons para XBMC, espero que te estén gustando y que te animen a desarrollar tus propios add-ons <img src='http://www.mimediacenter.info/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>En la próxima entrega veremos algunas técnicas para leer datos de sitios web que no son tan sencillos, como sitios que requieran usuario y contraseña o que requieran cookies. Aprovecharé para ampliar la funcionalidad de Plugin Tools de nuevo para hacer que resulte sencillo.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mimediacenter.info/2013/01/13/como-programar-add-ons-en-xbmc-un-add-on-mas-completo-continuacion/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Cómo programar add-ons en XBMC: Un add-on más completo</title>
		<link>http://www.mimediacenter.info/2013/01/12/como-programar-add-ons-en-xbmc-un-add-on-mas-completo/</link>
		<comments>http://www.mimediacenter.info/2013/01/12/como-programar-add-ons-en-xbmc-un-add-on-mas-completo/#comments</comments>
		<pubDate>Fri, 11 Jan 2013 23:48:47 +0000</pubDate>
		<dc:creator>Jesus</dc:creator>
				<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[como programar addon xbmc]]></category>

		<guid isPermaLink="false">http://www.mimediacenter.info/?p=1161</guid>
		<description><![CDATA[Este tutorial forma parte de la serie Cómo programar un add-on de XBMC Estamos a mitad de camino de este tutorial, pero ya tienes el conocimiento necesario para hacer un add-on bastante completo. Espero que a estas alturas ya te hayas convencido de que es algo relativamente sencillo sin necesidad de saber demasiado de programación. [...]]]></description>
			<content:encoded><![CDATA[<blockquote><p>Este tutorial forma parte de la serie <a href="http://www.mimediacenter.info/tag/como-programar-addon-xbmc/">Cómo programar un add-on de XBMC</a></p></blockquote>
<p>Estamos a mitad de camino de este tutorial, pero ya tienes el conocimiento necesario para hacer un add-on bastante completo. Espero que a estas alturas ya te hayas convencido de que es algo relativamente sencillo sin necesidad de saber demasiado de programación. Y ya sabes <a href="http://www.mimediacenter.info/2012/12/29/como-programar-add-ons-en-xbmc-patrones-basicos-con-expresiones-regulares/">cómo obtener datos de una página HTML usando expresiones regulares</a>, que es lo más difícil.</p>
<p>Así que antes de entrar en la recta final vamos construir un add-on paso a paso desde cero, con el objetivo de afianzar lo que has aprendido en las entregas anteriores y de paso divertirte un poco.</p>
<p>Te aconsejo que elijas un sitio web que te guste como fuente de vídeos, para mí he elegido hacer un add-on completo que permita ver los vídeos de Disney Junior tanto en la web oficial como en YouTube. No se trata de un add-on demasiado complejo, como podrás comprobar enseguida, pero no va a desmerecer en nada a cualquiera de los que puedes encontrar publicados en muchos repositorios <img src='http://www.mimediacenter.info/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Puedes elegir tu propia fuente para hacer el add-on, siguiendo los mismos pasos que yo voy a dar, o construir conmigo este interesante proyecto.<br />
<span id="more-1161"></span></p>
<h2>Ficheros de identificación</h2>
<p>Escribir el <a href="http://www.mimediacenter.info/2012/12/25/como-programar-add-ons-en-xbmc-los-ficheros-de-identificacion/">fichero addon.xml</a> es el primer paso, así tendrás algo con lo que probar las primeras líneas de código que vayas escribiendo. Aquí va el mío donde verás que he cogido el del <a href="http://www.mimediacenter.info/2012/12/11/como-programar-add-ons-en-xbmc-funcionamiento-de-un-add-on-paso-a-paso/">ejemplo de &#8220;Mi Mediacenter&#8221;</a> cambiando el id del add-on (lo he llamado plugin.video.disneyjunior), el nombre (&#8220;Disney Junior&#8221;) y las descripciones:</p>
<pre>
&lt;?xml version="1.0" encoding="UTF-8" standalone="yes"?&gt;
&lt;addon id="plugin.video.disneyjunior"
    name="Disney Junior"
    version="1.0.0"
    provider-name="tvalacarta"&gt;
  &lt;requires&gt;
    &lt;import addon="xbmc.python" version="2.0"/&gt;
    &lt;import addon="plugin.video.youtube" version="3.0.0"/&gt;
  &lt;/requires&gt;
  &lt;extension point="xbmc.python.pluginsource" library="default.py"&gt;
    &lt;provides&gt;video&lt;/provides&gt;
  &lt;/extension&gt;
  &lt;extension point="xbmc.addon.metadata"&gt;
    &lt;summary lang="en"&gt;Disney Junior&lt;/summary&gt;
    &lt;description lang="en"&gt;Watch online Disney Junior videos (spanish)&lt;/description&gt;
    &lt;summary lang="es"&gt;Disney Junior&lt;/summary&gt;
    &lt;description lang="es"&gt;Todos los vídeos de Disney Junior online en Español&lt;/description&gt;
    &lt;platform&gt;all&lt;/platform&gt;
  &lt;/extension&gt;
&lt;/addon&gt;
</pre>
<p>Hacer el logo y el fanart requerirá un poco de práctica al principio, pero basta con que sepas manejar un programa de edición de imágenes donde puedas recortar y cambiar de tamaño. Un logo a 256&#215;256 en PNG, y un fanart a 1280&#215;720 en JPG. Ambos sacados de la web de Disney Junior y con algo de ayuda de Google.</p>
<p><img class="aligncenter size-full wp-image-1206" title="El add-on de Disney Junior para XBMC, con su logo y fanart" src="http://www.mimediacenter.info/wp-content/uploads/2013/01/disney-junior-fanart.jpg" alt="El add-on de Disney Junior para XBMC, con su logo y fanart" width="620" height="349" /></p>
<h2>Un menú de navegación</h2>
<p>Un add-on que tenga algo más que unos pocos vídeos necesita un menú para que el usuario pueda elegir lo que quiere hacer. En mi caso tengo bastante claro el menú que tiene que tener un add-on de Disney Junior, porque conozco los gustos de mi hija pequeña.</p>
<p>Primero una opción &#8220;Web oficial&#8221; que muestre todos los vídeos de la web oficial de Disney Junior, seguido de otra opción &#8220;Canal de YouTube&#8221; para acceder a las playlists que la cadena tiene en su canal oficial de YouTube. Luego una entrada para recurrir al buscador, ya que solemos ponerle capítulos de Mickey Mouse buscándolos en YouTube, y por último una opción para configurar el add-on.</p>
<p><img src="http://www.mimediacenter.info/wp-content/uploads/2013/01/disney-junior-menu-principal.jpg" alt="" title="El menú principal del add-on de Disney Junior" width="620" height="349" class="aligncenter size-full wp-image-1214" /></p>
<p>Hacer el menú es muy sencillo porque no hay que llamar a ningún sitio, simplemente añadir 4 elementos a la lista de items. En el fichero &#8220;default.py&#8221; de este add-on está hecho con estas líneas.</p>
<pre class="prettyprint">
44 # Main menu
45 def main_list(params):
46    plugintools.log("disneyjunior.main_list "+repr(params))
47
48    plugintools.add_item( 
49        action="disneyweb", 
50        title=plugintools.get_localized_string(T_OFFICIAL_WEBSITE) ,
51        url="http://www.disney.es/disney-junior/contenido/video.jsp" ,
52        folder=True )
53    
54    plugintools.add_item(
55        action="youtube_playlists",
56        title=plugintools.get_localized_string(T_YOUTUBE_CHANNEL),
57        url="http://gdata.youtube.com/feeds/api/users/"+YOUTUBE_CHANNEL_ID+"/playlists?v=2&#038;start-index=1&#038;max-results=30",
58        folder=True )
59    
60    plugintools.add_item( action="search",
61        title=plugintools.get_localized_string(T_SEARCH) )
62    
63    plugintools.add_item( action="preferences",
64        title=plugintools.get_localized_string(T_PREFERENCES),
65        folder = False )
</pre>
<p>Observarás que los títulos no están escritos directamente:</p>
<pre class="prettyprint">title = "Canal de YouTube"</pre>
<p>sino que utilizan la función <a href="http://www.mimediacenter.info/plugintools/referencia/get_localized_string">get_localized_string</a> de <a href="http://www.mimediacenter.info/plugintools/">Plugin Tools</a> y un identificador numérico para la cadena de texto:</p>
<pre class="prettyprint">title = plugintools.get_localized_string(30003)</pre>
<p>o mejor el identificador numérico de la cadena lo ponemos como una constante para mayor legibilidad:</p>
<pre class="prettyprint">T_YOUTUBE_CHANNEL=30003
title = plugintools.get_localized_string(T_YOUTUBE_CHANNEL)</pre>
<p>Esto es así por el sistema que proporciona XBMC para tener un add-on donde los textos están adaptados al idioma de cada usuario. Es un poco lioso, pero simple y potente.</p>
<p>La idea es que a los textos que quieres traducir les asocias un identificador numérico (30003 en el ejemplo), y los escribes en un fichero &#8220;strings.xml&#8221; dentro del directorio &#8220;resources/language/Spanish&#8221;, &#8220;resources/language/English&#8221;, etc. Uno para cada idioma.</p>
<pre>
&lt;?xml version="1.0" encoding="utf-8" standalone="yes"?&gt;
&lt;strings&gt;
    &lt;string id="30001"&gt;Última búsqueda&lt;/string&gt;
    &lt;string id="30002"&gt;Web oficial&lt;/string&gt;
    &lt;string id="30003"&gt;Canal de YouTube&lt;/string&gt;
    &lt;string id="30004"&gt;Buscador ...&lt;/string&gt;
    &lt;string id="30005"&gt;Configuración ...&lt;/string&gt;
    &lt;string id="30006"&gt;ID del canal de YouTube ...&lt;/string&gt;
    &lt;string id="30007"&gt;Idioma para los resultados del buscador&lt;/string&gt;
&lt;/strings&gt;
</pre>
<p>Luego los pones en tu código usando la función <a href="http://www.mimediacenter.info/plugintools/referencia/get_localized_string">get_localized_string</a> a la que le pasas el identificador numérico.</p>
<p>Si el usuario tiene su XBMC en inglés, se leerá el fichero strings.xml del directorio &#8220;resources/language/English&#8221;. Si lo tiene en español, de &#8220;resources/language/Spanish&#8221;, etc. Si no pones literales en el idioma del usuario se cogerá por defecto los que estén en inglés, así que no olvides poner al menos ese idioma.</p>
<h2>Mostrando los vídeos de la web oficial</h2>
<p>Abriendo la zona de vídeos de la web de Disney Junior encontrarás el reproductor, y la lista de vídeos disponibles debajo. A mi hija le encanta porque pones un vídeo, y a partir de ahí los reproduce uno detrás de otro en carrusel.</p>
<p><img src="http://www.mimediacenter.info/wp-content/uploads/2013/01/captura-web-disney-junior.jpg" alt="" title="captura-web-disney-junior" width="620" height="404" class="aligncenter size-full wp-image-1228" /></p>
<p>Si le das en Firefox a &#8220;Herramientas / Desarrollador web / Código fuente de la página&#8221; accedes al HTML, y si buscas dentro del HTML la cadena del título de uno de los vídeos encontrarás enseguida el bloque de HTML que representa a cada vídeo.</p>
<p><img src="http://www.mimediacenter.info/wp-content/uploads/2013/01/html-de-video-en-disney-junior.jpg" alt="" title="html-de-video-en-disney-junior" width="620" height="90" class="aligncenter size-full wp-image-1229" /></p>
<p>Yo lo que suelo hacer para facilitar el trabajo es copiar el HTML que me interesa en cuanto lo localizo, lo pego en el módulo Python que estoy desarrollando dentro de un bloque de comentario, y lo utilizo como punto de partida para construir la expresión regular.</p>
<pre class="prettyprint">
'''
&lt;div class="promo" style="background-image: url(/cms_res/disney-junior/images/promo_support/promo_holders/video.png);"&gt;
    &lt;a href="/disney-junior/contenido/video/canta_con_dj_arcoiris.jsp " class="promoLinkTracking"&gt;&lt;img src="/cms_res/disney-junior/images/video/canta_dj_arco_iris_164x104.jpg" class="promo_image" alt=""/&gt;&lt;/a&gt;
    &lt;div class="promo_title_3row"&gt;&lt;p&gt;Canta con DJ: La canción del arco iris&lt;/p&gt;&lt;/div&gt;
    &lt;a class="playlist_button_large"  href="" ref="canta_con_dj_arcoiris"&gt;&lt;img src="/cms_res/disney-junior/images/promo_support/playlist_add_icon.png" alt="" /&gt;&lt;/a&gt;
&lt;/div&gt;
'''
</pre>
<p>A continuación pego el html tal como está dentro de una variable, para ir sustituyendo paso a paso y cometer los menos errores posibles:</p>
<pre class="prettyprint">
pattern ='&lt;div class="promo" style="background-image: url(/cms_res/disney-junior/images/promo_support/promo_holders/video.png);"&gt;'
pattern+='&lt;a href="/disney-junior/contenido/video/canta_con_dj_arcoiris.jsp " class="promoLinkTracking"&gt;&lt;img src="/cms_res/disney-junior/images/video/canta_dj_arco_iris_164x104.jpg" class="promo_image" alt=""/&gt;&lt;/a&gt;'
pattern+='&lt;div class="promo_title_3row"&gt;&lt;p&gt;Canta con DJ: La canción del arco iris&lt;/p&gt;&lt;/div&gt;'
pattern+='&lt;a class="playlist_button_large"  href="" ref="canta_con_dj_arcoiris"&gt;&lt;img src="/cms_res/disney-junior/images/promo_support/playlist_add_icon.png" alt="" /&gt;&lt;/a&gt;'
pattern+='&lt;/div&gt;'
</pre>
<p>Y entonces empiezo a sustituir. Del primer tag sólo me interesa el principio ya que sirve para marcar el comienzo del patrón, así que dejo un trozo y luego utilizo el patrón [^&lt;]+ para saltar al siguiente tag.</p>
<pre class="prettyprint">
pattern  = '&lt;div class="promo"[^&lt;]+'
</pre>
<p>El segundo tag del bloque tiene el enlace al vídeo en el atributo href y entre comillas, así que uso el patrón [^"]+ y lo marco entre paréntesis porque me interesa el contenido. Y a continuación salto al siguiente tag con [^&lt;]+:</p>
<pre class="prettyprint">
pattern += '&lt;a href="([^"]+)"[^&lt;]+'
</pre>
<p>Ahora viene un tag de imagen que necesito para tener la captura del vídeo, aunque esté en la misma línea del texto lo dejo separado para mayor legibilidad.</p>
<p>Cojo la URL de la imagen con el mismo patrón [^"]+ que antes, también entre paréntesis, y salto al siguiente tag con [^&lt;]+:</p>
<pre class="prettyprint">
pattern += '&lt;img src="([^"]+)"[^&lt;]+'
</pre>
<p>Ya tengo la URL del vídeo y su imagen, sólo necesito el título para poder mostrar la información completa en el add-on. Así que salto los tags que vienen a continuación hasta encontrar el tag &lt;p&gt; que contiene el título. Como es un valor que está entre tags y no en un atributo, utilizo el patrón ([^&lt;]+).</p>
<pre class="prettyprint">
pattern += '&lt;/a[^&lt;]+'
pattern += '&lt;div[^&lt;]+'
pattern += '&lt;p&gt;([^&lt;]+)&lt;/p&gt;'
</pre>
<p>Podría <a href="http://www.mimediacenter.info/2012/12/31/como-programar-add-ons-en-xbmc-patrones-avanzados-con-expresiones-regulares/">haber usado (.*?) para saltar todos los elementos</a> e ir directamente al título, pero intento guardar ese recurso cuando es realmente necesario. De esa forma consigo que la carga de los items sea lo más rápida posible.</p>
<p>Antes de poner el código de este bloque nos falta un detalle. Para evitar que haya algún elemento que coincida con el patrón que acabamos de escribir, pero que no corresponda con un vídeo, voy a limitar la zona de la página donde usaré la expresión regular al bloque donde están los vídeos contenidos.</p>
<p>Observa que todos los vídeos de la página están dentro de una zona que empieza con un &lt;div&gt; concreto, y acaban en una zona delimitada por la siguiente que también empieza con otro &lt;div&gt; concreto.</p>
<p><img src="http://www.mimediacenter.info/wp-content/uploads/2013/01/disney-junior-comienzo-videos.jpg" alt="" title="disney-junior-comienzo-videos" width="620" height="193" class="aligncenter size-full wp-image-1230" /></p>
<p>(aquí están todos los vídeos&#8230;)</p>
<p><img src="http://www.mimediacenter.info/wp-content/uploads/2013/01/disney-junior-fin-videos.jpg" alt="" title="disney-junior-fin-videos" width="620" height="295" class="aligncenter size-full wp-image-1231" /> </p>
<p>Para delimitar el área de trabajo de la expresión regular a la zona entre estos dos tags, leo la página con <a href="http://www.mimediacenter.info/plugintools/referencia/read">read</a> y la guardo en la variable &#8220;data&#8221;</p>
<pre class="prettyprint">
data = plugintools.read( params.get("url") )
</pre>
<p>para inmediatamente después quedarme con la parte donde están los vídeos utilizando el patrón &lt;div id=&#8221;video_main_promos_inner&#8221;&gt;(.*?)&lt;div id=&#8221;content_index_navigation&#8221;&gt;. Que viene a ser &#8220;todo lo que está entre el primer div y el segundo&#8221;.</p>
<pre class="prettyprint">
data = plugintools.find_single_match( data , '&lt;div id="video_main_promos_inner"&gt;(.*?)&lt;div id="content_index_navigation"&gt;')
</pre>
<p>Ya tengo todo lo necesario para escribir la función &#8220;disneyweb&#8221; que extrae los vídeos y los añade a la lista de items de XBMC:</p>
<pre class="prettyprint">
67 # Show all videos from the official website
68 def disneyweb(params):
69     plugintools.log("disneyjunior.disneyweb "+repr(params))
70 
71     # Fetch video list page
72     data = plugintools.read( params.get("url") )
73     data = plugintools.find_single_match( data , '&lt;div id="video_main_promos_inner"&gt;(.*?)&lt;div id="content_index_navigation"&gt;')
74     
75     # Extract items
76     '''
77     &lt;div class="promo" style="background-image: url(/cms_res/disney-junior/images/promo_support/promo_holders/video.png);"&gt;
78         &lt;a href="/disney-junior/contenido/video/canta_con_dj_arcoiris.jsp " class="promoLinkTracking"&gt;&lt;img src="/cms_res/disney-junior/images/video/canta_dj_arco_iris_164x104.jpg" class="promo_image" alt=""/&gt;&lt;/a&gt;
79         &lt;div class="promo_title_3row"&gt;&lt;p&gt;Canta con DJ: La canción del arco iris&lt;/p&gt;&lt;/div&gt;
80         &lt;a class="playlist_button_large"  href="" ref="canta_con_dj_arcoiris"&gt;&lt;img src="/cms_res/disney-junior/images/promo_support/playlist_add_icon.png" alt="" /&gt;&lt;/a&gt;
81     &lt;/div&gt;
82     '''
83     pattern  = '&lt;div class="promo"[^&lt;]+'
84     pattern += '&lt;a href="([^"]+)"[^&lt;]+'
85     pattern += '&lt;img src="([^"]+)"[^&lt;]+'
86     pattern += '&lt;/a[^&lt;]+'
87     pattern += '&lt;div[^&lt;]+'
88     pattern += '&lt;p&gt;([^&lt;]+)&lt;/p&gt;'
89     matches = plugintools.find_multiple_matches(data,pattern)
</pre>
<p>En este punto tengo en la variable &#8220;matches&#8221; la lista de videos, donde cada elemento de la lista es a su vez una lista con url, imagen y título, sólo falta añadirlos a la lista de items con la función <a href="http://www.mimediacenter.info/plugintools/referencia/add_item">add_item</a> de <a href="http://www.mimediacenter.info/plugintools/">Plugin Tools</a>.</p>
<pre class="prettyprint">    
91     for scrapedurl, scrapedthumbnail, scrapedtitle in matches:
92         # Not the better way to parse XML, but clean and easy
93         title = scrapedtitle
94         thumbnail = urlparse.urljoin( params.get("url") , scrapedthumbnail )
95         url = urlparse.urljoin( params.get("url") , scrapedurl.strip() )
96         plot = ""
97 
98         # Appends a new item to the xbmc item list
99         plugintools.add_item( action="disneyweb_play" , title=title , plot=plot , url=url ,thumbnail=thumbnail , isPlayable=True, folder=False )
</pre>
<p>Observa que la URL y la imagen (o thumbnail) se añaden usando primero la función estándar de Python &#8220;urljoin&#8221;, lo que viene bien cuando te encuentras con URL relativas en lugar de absolutas. Esta función crea una URL utilizando el primer parámetro como URL base, y el segundo como ruta relativa.</p>
<p>Y observa también que el elemento que añadimos a la lista de items no es una carpeta (folder=False), porque cuando el usuario seleccione uno de estos items simplemente se reproducirá el vídeo con la función &#8220;disneyweb_play&#8221;. No va a ser necesario que el usuario descienda más niveles, y por eso lo marcamos como &#8220;no carpeta&#8221;.</p>
<p><img src="http://www.mimediacenter.info/wp-content/uploads/2013/01/disney-junior-en-xbmc.jpg" alt="" title="disney-junior-en-xbmc" width="620" height="349" class="aligncenter size-full wp-image-1234" /></p>
<h2>Reproducción del vídeo</h2>
<p>Cuando el usuario elija un vídeo de la lista anterior, XBMC llamará a la acción &#8220;disneyweb_play&#8221; y le pasará como parámetro la URL del vídeo elegido entre otras cosas.</p>
<p>Lo primero que hay que hacer es leer esa URL para tener la información del vídeo, usando la función <a href="http://www.mimediacenter.info/plugintools/referencia/read">read</a> nuevamente:</p>
<pre class="prettyprint">
101 # Play one video from the official website
102 def disneyweb_play(params):
103     plugintools.log("disneyjunior.disneyweb_play "+repr(params))
104 
105     # Fetch page
106     data = plugintools.read( params.get("url") )
</pre>
<p>Y ahora utilizar esa información para deducir la URL que hay que darle al reproductor de XBMC. En este caso es fácil porque la URL utiliza el protocolo &#8220;RTMPE&#8221;, y está en el código HTML separada en dos líneas diferentes de forma bastante clara:</p>
<pre class="prettyprint">
	<b>config.firstVideoSource = 'winnie_heffa_woozles.mp4';</b>
	config.htmlContainerName = 'video_player';
	config.loop = false;
	config.autoplay = true;
	<b>config.rtmpeServer = 'rtmpe://cp121902.edgefcs.net/ondemand/';</b>
</pre>
<p>Así que sólo tenemos que extraer los dos fragmentos y componerlos para tener la URL completa.</p>
<pre class="prettyprint">
108     url_start = plugintools.find_single_match( data , "config.rtmpeServer \= '([^']+)'")
109     plugintools.log("disneyjunior.disneyweb_play url_start="+url_start)
110 
111     url_end = plugintools.find_single_match( data , "config.firstVideoSource \= '([^']+)'")
112     plugintools.log("disneyjunior.disneyweb_play url_end="+url_end)
113    
114     url = url_start + url_end
115     plugintools.log("disneyjunior.disneyweb_play url="+url)
116 
117     plugintools.play_resolved_url( url )
</pre>
<p>Con <a href="http://www.mimediacenter.info/plugintools/referencia/play_resolved_url">play_resolved_url</a> le decimos a XBMC que está listo para la reproducción, así que directamente empezará a verse el vídeo.</p>
<h2>Próxima entrega</h2>
<p>La extensión de esta entrada me obliga a dividirla en dos, todavía queda ver cómo montar la sección del canal de YouTube aunque resulta similar a la del ejemplo que vimos al principio de esta serie de tutoriales.</p>
<p>También veremos cómo funciona el buscador y la configuración, pero si has llegado hasta aquí y quieres echarle un vistazo al add-on terminado descargándotelo desde este enlace.</p>
<blockquote><p><a href="http://www.mimediacenter.info/descargas/plugin.video.disneyjunior-1.0.0.zip">http://www.mimediacenter.info/descargas/plugin.video.disneyjunior-1.0.0.zip</a></p></blockquote>
<p>Si no tienes hijos en edad de &#8220;La Casa de Mickey Mouse&#8221;, pónselo a tus sobrinos. Seguro que sus padres te preguntan cómo pueden instalárselo ellos también <img src='http://www.mimediacenter.info/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.mimediacenter.info/2013/01/12/como-programar-add-ons-en-xbmc-un-add-on-mas-completo/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Cómo programar add-ons en XBMC: Patrones avanzados con expresiones regulares</title>
		<link>http://www.mimediacenter.info/2012/12/31/como-programar-add-ons-en-xbmc-patrones-avanzados-con-expresiones-regulares/</link>
		<comments>http://www.mimediacenter.info/2012/12/31/como-programar-add-ons-en-xbmc-patrones-avanzados-con-expresiones-regulares/#comments</comments>
		<pubDate>Mon, 31 Dec 2012 06:00:14 +0000</pubDate>
		<dc:creator>Jesus</dc:creator>
				<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[como programar addon xbmc]]></category>

		<guid isPermaLink="false">http://www.mimediacenter.info/?p=1116</guid>
		<description><![CDATA[Este tutorial forma parte de la serie Cómo programar un add-on de XBMC Ayer vimos un patrón muy simple, que te permite extraer el texto que hay entre los tags de apertura y cierre de un elemento HTML (o XML), y también vimos cómo extraer el valor de un atributo. Si tenemos en cuenta que [...]]]></description>
			<content:encoded><![CDATA[<blockquote><p>Este tutorial forma parte de la serie <a href="http://www.mimediacenter.info/tag/como-programar-addon-xbmc/">Cómo programar un add-on de XBMC</a></p></blockquote>
<p>Ayer vimos un patrón muy simple, que te permite extraer el texto que hay entre los tags de apertura y cierre de un elemento HTML (o XML), y también vimos cómo extraer el valor de un atributo. Si tenemos en cuenta que en HTML todo son tags o atributos, parece que con estos dos patrones deberíamos tener resuelto cualquier problema ¿no?</p>
<p>En realidad se resuelven la mayoría de los casos, pero estos patrones tienen dos limitaciones importantes que vamos a intentar resolver usando las dos técnicas que se describen en esta entrada.</p>
<p>La primera limitación está en el hecho de que en HTML unos tags pueden estar dentro de otros, lo que complica bastante la elaboración de expresiones regulares cuando sólo buscas los símbolos &#8220;&lt;&#8221; y &#8220;&gt;&#8221;.</p>
<p>Y la segunda limitación, más práctica que tecnológica, está en la dificultad que pueden llegar a tener las expresiones regulares en las páginas HTML más complejas. Esto hace muy difícil la depuración, y el posterior mantenimiento, por lo que en este caso atacaremos el problema con un enfoque pragmático que nos permitirá hacer más fácil la tarea.</p>
<p><span id="more-1116"></span></p>
<h2>El patrón más potente</h2>
<p>Si bien es cierto que los dos patrones vistos hasta ahora permiten resolver la mayoría de los casos, puedes encontrarte con construcciones HTML tan complejas que acabarían resultando en una expresión regular descomunal. Lo que además de ser difícil de depurar, acaba resultando muy frágil ante cualquier cambio que se realice en la página.</p>
<p>Basta que aparezca un tag intercalado, o algún espacio en blanco inesperado, para que tu sistema falle.</p>
<p>Imagina que quieres extraer el argumento de un vídeo, algo que en muchas páginas web se suele incluir dentro de un elemento &#8220;div&#8221; de una forma similar a esta:</p>
<pre class="quote2">
&lt;div class="argumento"&gt;
<strong>&lt;strong&gt;Blade Runner&lt;/strong&gt; es una película de ciencia ficción estadounidense, 
dirigida por &lt;a href="http://es.wikipedia.org/wiki/Ridley_Scott"&gt;Ridley Scott&lt;/a&gt;,
estrenada en 1982 y basada parcialmente en la novela de Philip K. Dick ¿Sueñan los
androides con ovejas eléctricas?</strong>&lt;/div&gt;
</pre>
<p>Si tenemos en cuenta que los enlaces y negritas del argumento van a cambiar de una peli a otra ¿cómo hacer un patrón que extraiga el argumento?</p>
<p>Pues la verdad es que hay una forma muy sencilla, usando en la expresión regular el patrón de &#8220;cualquier caracter hasta encontrar X&#8221;. Esto se hace con este símbolo:</p>
<pre class="quote2">.*?</pre>
<p>El &#8220;.&#8221; significa &#8220;cualquier carácter&#8221;, el &#8220;*&#8221; significa que puede aparecer &#8220;0 o más veces&#8221;, y el &#8220;?&#8221; aplicado aquí representa &#8220;la más corta de las subcadenas&#8221;.</p>
<p>Así que podemos extraer el argumento diciendo &#8220;todo lo que esté después de &lt;div class=&#8221;argumento&#8221;&gt; y hasta que encuentres el primer &lt;/div&gt;&#8221;, utilizando un patrón de este tipo:</p>
<pre class="quote2">&lt;div class="argumento"&gt;<strong>(.*?)</strong>&lt;/div&gt;</pre>
<p>Veamos el resultado:</p>
<pre class="prettyprint">
plugintools.find_multiple_matches(cadena,'<strong>&lt;div class="argumento"&gt;(.*?)&lt;/div&gt;</strong>')
->
['&lt;strong&gt;Blade Runner&lt;/strong&gt; es una película de ciencia ficción estadounidense,
dirigida por &lt;a href="http://es.wikipedia.org/wiki/Ridley_Scott"&gt;Ridley Scott&lt;/a&gt;, 
estrenada en 1982 y basada parcialmente en la novela de Philip K. Dick ¿Sueñan los
androides con ovejas eléctricas?']</pre>
<p>Esto también es aplicable para los casos de la entrada de ayer, y además de una forma mucho más sencilla que la que se explicaba.</p>
<p>Buscar el título de la peli del ejemplo se haría con un patrón que podríamos leer como &#8220;empieza por &lt;h3&gt; y luego acepta cualquier cosa hasta encontrar &lt;/h3&gt;&#8221;. Vendría a ser algo así:</p>
<pre class="quote2"><strong>&lt;h3&gt;(.*?)&lt;/h3&gt;</strong></pre>
<p>Y podemos comprobar que nos lleva al mismo resultado que ayer:</p>
<pre class="prettyprint">
plugintools.find_multiple_matches(cadena,"<strong>&lt;h3&gt;(.*?)&lt;/h3&gt;</strong>")
->
["Blade Runner","Transformers"]</pre>
<p>Sin embargo el uso de este patrón tiene una trampa, motivo por el cual no lo expliqué al principio y que debes tener en cuenta al usarlo.</p>
<p>Este patrón es computacionalmente mucho más complejo que el anterior, lo que significa que si buscas usando un patrón que tiene muchos símbolos &#8220;.*?&#8221; puede llegar a resultar muy lento encontrar caracteres con él, especialmente en cadenas de texto muy grandes.</p>
<h2>Buscando un sólo valor</h2>
<p>Hasta ahora hemos buscado todo lo que coincidiera con nuestro patrón, pero si sólo estás buscando un valor es mejor utilizar la función &#8220;find_single_match&#8221; de <a href="http://www.mimediacenter.info/plugintools/">PluginTools</a>. </p>
<p>Donde &#8220;find_multiple_matches&#8221; devuelve una lista, esta función &#8220;find_single_match&#8221; devolverá una cadena sólo con el primer valor encontrado, y si no encuentra nada devolverá una cadena vacía.</p>
<pre class="prettyprint">
plugintools.find_single_match(cadena,'<strong>&lt;div class="argumento"&gt;(.*?)&lt;/div&gt;</strong>')
->
'&lt;strong&gt;Blade Runner&lt;/strong&gt; es una película de ciencia ficción estadounidense,
dirigida por &lt;a href="http://es.wikipedia.org/wiki/Ridley_Scott"&gt;Ridley Scott&lt;/a&gt;, 
estrenada en 1982 y basada parcialmente en la novela de Philip K. Dick ¿Sueñan los
androides con ovejas eléctricas?'</pre>
<p>Esto viene muy bien para afinar la búsqueda, lo que nos lleva al último punto de expresiones regulares de este tutorial.</p>
<h2>Usar varios pasos para afinar la búsqueda</h3>
<p>Con lo que hemos visto en estas dos últimas entradas, es fácil entender el esquema básico de funcionamiento de un add-on y cómo las expresiones regulares permiten sacar los datos de la página web para añadirlos a la lista de items de XBMC.</p>
<p>Supongamos que la lista de pelis está en una página de esta forma:</p>
<pre class="quote2">&lt;a href="http://www.iskalatan.com/transformers"&gt;Transformers&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://www.iskalatan.com/blade-runner"&gt;Blade Runner&lt;/a&gt;&lt;br/&gt;
...</pre>
<p>Así que usamos este código en el add-on:</p>
<pre class="prettyprint">
# 1) Lee la página web de origen
data = plugintools.read( params.get("url") )

# 2) Extrae los datos
pattern = '&lt;a href="([^"]+)"&gt;([^&lt;]+)&lt;/a&gt;'
matches = plugintools.find_multiple_matches(data,pattern)

# 3) Añade los datos a la lista de items de XBMC
for title,url in matches:
    plugintools.add_item( action="show_mirrors" , title=title , url=url, folder=True )
</pre>
<p>Pero es más que probable que al ejecutar esto en una página web real nos encontremos con que aparecen más entradas de las que esperábamos. ¿A qué se debe?</p>
<p>Se debe a que nuestro patrón es tan común que prácticamente todos los links coincidirán. Todos los elementos  &#8220;a&#8221; que tengan un atributo &#8220;href&#8221; coincidirán con ese patrón, así que aparecerán como entradas en el listado de items nuestras pelis pero también otros tipos de enlaces.</p>
<p>La solución es buscar la zona del HTML en la que están las películas, puesto que probablemente estén dentro de un &#8220;div&#8221; o una tabla, y aplicar el patrón sólo a ese trozo de la cadena. Es lo mismo, pero hecho en dos pasos:</p>
<pre class="prettyprint">
# 1) Lee la página web de origen
data = plugintools.read( params.get("url") )

# 2.1) Delimita la búsqueda al contenedor donde estan las pelis
data = plugintools.find_single_match(data,'&lt;div id="container"&gt;(.*?)&lt;/div&gt;')

# 2.2) Extrae los datos
pattern = '&lt;a href="([^"]+)"&gt;([^&lt;]+)&lt;/a&gt;'
matches = plugintools.find_multiple_matches(data,pattern)

# 3) Añade los datos a la lista de items de XBMC
for title,url in matches:
    plugintools.add_item( action="show_mirrors" , title=title , url=url, folder=True )
</pre>
<p>Esta es una técnica potente. Puedes ahorrártela haciendo un patrón lo suficientemente elaborado para que encuentre exactamente lo que buscas, pero descubrirás que de esta forma el segundo patrón siempre es más fácil de preparar.</p>
<h2>Próxima entrega</h2>
<p>Para que veas lo aplicables que son estas fórmulas, te invito a revisar uno por uno <a href="https://code.google.com/p/xbmc-tvalacarta/source/browse/#svn%2Ftrunk%2Fpelisalacarta%2Fpelisalacarta%2Fchannels">todos los canales de pelisalacarta siguiendo este enlace</a>.</p>
<p>Verás que en todos ellos se repiten una y otra vez las técnicas de expresiones regulares descritas, sin usar expresiones más complejas excepto en casos especiales.</p>
<p>Así que recopilemos lo que necesitamos saber para empezar:</p>
<pre class="quote2">
<strong>&lt;tag&gt;([^&lt;]+)&lt;/tag&gt;</strong> para extraer el texto entre dos tags
<strong>"([^"]+)"</strong> para extraer el valor de un atributo
<strong>\d+</strong> para saltar números
<strong>\s+</strong> para saltar espacios en blanco
<strong>(.*?)</strong> cuando la cosa se pone complicada
</pre>
<p>Con estas herramientas ya podemos sacar datos de cualquier página web, siempre que podamos leerla. Así que en la próxima entrada veremos cómo hacer un add-on algo más completo que el que vimos <a href="http://www.mimediacenter.info/2012/12/11/como-programar-add-ons-en-xbmc-funcionamiento-de-un-add-on-paso-a-paso/">hace unos días</a>.</p>
<p>Esta era la parte más complicada, a partir de aquí todo va a ser mucho más sencillo.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mimediacenter.info/2012/12/31/como-programar-add-ons-en-xbmc-patrones-avanzados-con-expresiones-regulares/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Cómo programar add-ons en XBMC: Patrones básicos con expresiones regulares</title>
		<link>http://www.mimediacenter.info/2012/12/29/como-programar-add-ons-en-xbmc-patrones-basicos-con-expresiones-regulares/</link>
		<comments>http://www.mimediacenter.info/2012/12/29/como-programar-add-ons-en-xbmc-patrones-basicos-con-expresiones-regulares/#comments</comments>
		<pubDate>Sat, 29 Dec 2012 22:21:26 +0000</pubDate>
		<dc:creator>Jesus</dc:creator>
				<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[como programar addon xbmc]]></category>

		<guid isPermaLink="false">http://www.mimediacenter.info/?p=1072</guid>
		<description><![CDATA[Este tutorial es el cuarto de la serie Cómo programar un add-on de XBMC Las expresiones regulares son extrañamente complejas. Al menos siempre lo han sido para mí, que aún recuerdo los sudores fríos que me entraban cuando las estudiaba en clase de Álgebra. Siempre pensé que luego nunca me iba a topar con ellas [...]]]></description>
			<content:encoded><![CDATA[<blockquote><p>Este tutorial es el cuarto de la serie <a href="http://www.mimediacenter.info/tag/como-programar-addon-xbmc/">Cómo programar un add-on de XBMC</a></p></blockquote>
<p>Las expresiones regulares son extrañamente complejas.</p>
<p>Al menos siempre lo han sido para mí, que aún recuerdo los sudores fríos que me entraban cuando las estudiaba en clase de Álgebra. Siempre pensé que luego nunca me iba a topar con ellas en el mundo real&#8230; ironías del destino <img src='http://www.mimediacenter.info/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Una expresión regular es una forma de representar un patrón de texto, una cadena que quieres encontrar dentro de un texto. Por ejemplo si quieres sacar los números que hay en este texto</p>
<pre class="quote2">Nací el <strong>10</strong> de abril del <strong>2017</strong>. ¿Cuánto vivire?</pre>
<p>puedes usar la expresión regular </p>
<pre class="quote2">\d+</pre>
<p>El símbolo &#8220;d&#8221; representa a un número, junto con el símbolo &#8220;+&#8221; que viene a decir que ese número puede repetirse una o más veces. Se pone un &#8220;\&#8221; delante del símbolo &#8220;d&#8221; para distinguirlo de la letra &#8220;d&#8221;.</p>
<p>El resultado buscar en esa frase con ese patrón usando la función &#8220;find_multiple_matches&#8221; de <a href="http://www.mimediacenter.info/plugintools/">PluginTools</a> nos devuelve una lista con dos elementos:</p>
<pre class="prettyprint">
cadena = "Nací el 10 de abril del 2017. ¿Cuánto vivire?"
patron = "\d+"
plugintools.find_multiple_matches(cadena,patron)
->
["10","2017"]</pre>
<p><span id="more-1072"></span><br />
En un add-on de XBMC se utilizan las expresiones regulares como un mecanismo eficiente para buscar en una página HTML los elementos que quieren incluir en la lista de items. Los títulos y portadas de un listado de películas, por ejemplo. Si recuerdas la <a href="http://www.mimediacenter.info/2012/12/11/como-programar-add-ons-en-xbmc-funcionamiento-de-un-add-on-paso-a-paso/">entrada donde explicaba el funcionamiento básico de un add-on</a>, las expresiones regulares se utilizan fundamentalmente en el momento de &#8220;extracción de datos&#8221;.</p>
<p>Lo que te vas a encontrar en una página HTML es algo como esto:</p>
<pre class="quote2">&lt;h3&gt;<strong>Blade Runner</strong>&lt;/h3&gt;&lt;a href="<strong>http://www.marsilomena.com/blade-runner</strong>"&gt;Pulsa aqui
para ver Blade Runner&lt;h3&gt;&lt;br/&gt;
&lt;h3&gt;<strong>Transformers</strong>&lt;/h3&gt;&lt;a href="<strong>http://www.marsilomena.com/transformers</strong>"&gt;Pulsa aqui
para ver Transformers&lt;h3&gt;
...</pre>
<p>Y lo que tú necesitas es meter esa página web en una cadena de texto, y usar expresiones regulares para obtener una lista con los siguientes elementos que luego añadirás a la lista de items de XBMC:</p>
<pre class="quote2">
[
["Blade Runner","http://www.marsilomena.com/blade-runner"],
["Transformers","http://www.marsilomena.com/transformers"]
]
</pre>
<p>Puedes usar otras técnicas para extraer datos, como un parser <strong>ElementTree</strong> si los datos están en XML, o un parser <strong>simplejson</strong> si están en JSON. Pero probablemente la mejor solución para procesar el HTML del mundo real pasa por usar expresiones regulares, y como también vale en el resto de casos te conviene tener algunos trucos en la maleta para poder recurrir a ellos cuando te surja la necesidad.</p>
<h2>Patrones básicos</h2>
<p>Hay muchos símbolos para representar patrones en una expresión regular, como usar &#8220;\d&#8221; para representar un número o &#8220;\s&#8221; para representar un espacio en blanco. Para una descripción en profundidad te recomiendo leer la documentación básica de <a href="http://docs.python.org/2/library/re.html">expresiones regulares en Python</a> o hacerte con un buen libro.</p>
<p>Si lo que quieres es usar expresiones regulares en tu add-on sin ser un doctorado en matemáticas, sigue leyendo y verás que los patrones utilizados para extraer datos del HTML suelen ser siempre los mismos. Y además resultan muy sencillos.</p>
<h2>Obtener el valor de un tag</h2>
<p>Habrás observado que el título de la peli está en el ejemplo entre tags &#8220;h3&#8243;:</p>
<pre class="quote2">&lt;h3&gt;<strong>Blade Runner</strong>&lt;/h3&gt;...
&lt;h3&gt;<strong>Transformers</strong>&lt;/h3&gt;...
</pre>
<p>La mejor forma de sacar el título del vídeo en el ejemplo anterior es usar este patrón:</p>
<pre class="quote2">&lt;h3&gt;<strong>[^&lt;]+</strong>&lt;/h3&gt;</pre>
<p>Los símbolos &#8220;[" y "]&#8221; encierran una expresión más compleja que puede utilizarse con el símbolo &#8220;+&#8221; (que si recuerdas representaba &#8220;una o más veces&#8221;). Así pues, en este caso el patrón buscado es &#8220;&lt;h3&gt;&#8221; seguido de uno o más caracteres, para terminar en &#8220;&lt;/h3&gt;&#8221;. Como no sabemos cuál es el título del vídeo, utilizamos como carácter cualquiera que no sea el &#8220;&lt;&#8221;, ya que marcaría el final del tag. Eso se representa poniendo el acento circunflejo &#8220;^&#8221; delante del caracter.</p>
<p>Así pues &#8220;[^&lt;]+&#8221; puede leerse como <em>&#8220;uno o más caracteres que no sean &lt;&#8221;</em>.</p>
<p>Y el patrón completo podemos leerlo como <em>&#8220;una cadena empieza por &lt;h3&gt;, y luego tiene cualquier cosa excepto &#8220;&lt;&#8221; para terminar en &lt;/h3&gt;&#8221;</em>.</p>
<p>Este patrón coincidirá con dos subcadenas en el texto, y las devolverá en un array:</p>
<pre class="prettyprint">
plugintools.find_multiple_matches(cadena,"&lt;h3&gt;[^<]+&lt;/h3&gt;")
->
["&lt;h3&gt;Blade Runner&lt;/h3&gt;","&lt;h3&gt;Transformers&lt;/h3&gt;"]</pre>
<p>Como lo que te interesa no es el tag h3 entero, sino que solamente quieres obtener el valor que hay dentro, lo que haces es indicar entre paréntesis qué parte es la que quieres extraer.</p>
<pre class="quote2">&lt;h3&gt;<strong>([^&lt;]+)</strong>&lt;/h3&gt;</pre>
<p>Y esta vez el array será sólo con los títulos.</p>
<pre class="prettyprint">
plugintools.find_multiple_matches(cadena,"&lt;h3&gt;([^<])+&lt;/h3&gt;")
->
["Blade Runner","Transformers"]</pre>
<p><br/></p>
<h2>Obtener el valor de un atributo</h2>
<p>Verás que el patrón <em>&#8220;cualquier caracter que no sea X&#8221;</em> es muy útil para procesar el HTML, y vamos a usarlo ahora para extraer el enlace al vídeo. Tomemos el ejemplo anterior:</p>
<pre class="quote2">&lt;h3&gt;<strong>Blade Runner</strong>&lt;/h3&gt;&lt;a href="<strong>http://www.marsilomena.com/blade-runner</strong>"&gt;Pulsa aqui
para ver Blade Runner&lt;/a&gt;&lt;br/&gt;
&lt;h3&gt;<strong>Transformers</strong>&lt;/h3&gt;&lt;a href="<strong>http://www.marsilomena.com/transformers</strong>"&gt;Pulsa aqui
para ver Transformers&lt;/a&gt;
...</pre>
<p>No sólo nos interesa el título del vídeo</p>
<pre class="quote2"><strong>&lt;h3&gt;([^&lt;]+)&lt;/h3&gt;</strong></pre>
<p>sino que también nos interesa el enlace:</p>
<pre class="quote2">&lt;h3&gt;([^&lt;]+)&lt;/h3&gt;<strong>&lt;a href="([^"]+)"&gt;Pulsa aqui para ver [^&lt;]+&lt;/a&gt;</strong></pre>
<p>Así que usamos el patrón que nos dice que el atributo es <em>&#8220;cualquier caracter que no sea una comilla&#8221;</em>. Como hemos incluido el patrón para el título y el patrón para el enlace entre paréntesis, nos devuelve una lista cuyos elementos son a su vez una lista (tupla) con los títulos y los enlaces encontrados.</p>
<pre class="quote2">
find_multiple_matches(cadena,patron)
->
[
('Blade Runner', 'http://www.marsilomena.com/blade-runner'),
('Transformers', 'http://www.marsilomena.com/transformers')
]
</pre>
<p>El truco vale para cualquier expresión, por ejemplo es igualmente aplicable si el atributo estuviera expresado con comillas simples:</p>
<pre class="quote2">&lt;h3"&gt;([^&lt;]+)&lt;/h3&gt;&lt;a href='<strong>([^']+)</strong>'&gt;Pulsa aqui para ver [^&lt;]+&lt;/a&gt;</pre>
<p>Observa que en la parte del texto que está dentro del tag &#8220;a&#8221; no hemos puesto paréntesis, ya que tenemos el título del principio así que no lo necesitamos de nuevo.</p>
<h2>Como tratar el espacio en blanco entre tags</h2>
<p>En el ejemplo anterior los tags &#8220;h3&#8243; y &#8220;a&#8221; están juntos, pero podría ocurrir que estuvieran separados por espacios en blanco o incluso por saltos de línea.</p>
<pre class="quote2">&lt;h3&gt;<strong>Blade Runner</strong>&lt;/h3&gt;
&lt;a href="<strong>http://www.marsilomena.com/blade-runner</strong>"&gt;Pulsa aqui
para ver Blade Runner&lt;/a&gt;&lt;br/&gt;
&lt;h3&gt;<strong>Transformers</strong>&lt;/h3&gt;
&lt;a href="<strong>http://www.marsilomena.com/transformers</strong>"&gt;Pulsa aqui
para ver Transformers&lt;/a&gt;
...</pre>
<p>En ese caso modificaríamos el patrón para usar el símbolo de &#8220;uno o más espacios en blanco&#8221;, o &#8220;\s+&#8221;:</p>
<pre class="quote2">&lt;h3"&gt;([^&lt;]+)&lt;/h3&gt;<strong>\s+</strong>&lt;a href="([^"]+)"&gt;Pulsa aqui para ver [^&lt;]+&lt;/a&gt;</pre>
<p>Otra técnica consiste en ignorar cualquier carácter hasta el comienzo siguiente tag, que es más complicado de leer pero tiene la ventaja de cubrir más casos.</p>
<pre class="quote2">&lt;h3"&gt;([^&lt;]+)&lt;/h3&gt;<strong>[^&lt;]+</strong>&lt;a href="([^"]+)"&gt;Pulsa aqui para ver [^&lt;]+&lt;/a&gt;</pre>
<p>Y hasta aquí, prácticamente todo lo que necesitas saber para procesar HTML. Si ya sabes extraer valores de los tags, y también de los atributos de los tags, ¿qué más podrías necesitar saber?</p>
<h2>Próxima entrada</h2>
<p>Esta entrada se estaba haciendo demasiado larga, así que continuaremos mañana con algunas técnicas algo más avanzadas para resolver otros problemas más complejos pero también habituales en el procesamiento de HTML.</p>
<p>Veremos cómo usar expresiones regulares para manejar los tags que están unos dentro de otros, donde el truco de buscar el símbolo &#8220;&lt;&#8221; no sirve, y también veremos algunas técnicas para que las expresiones regulares no se hagan demasiado complejas usando la extracción en dos pasos.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mimediacenter.info/2012/12/29/como-programar-add-ons-en-xbmc-patrones-basicos-con-expresiones-regulares/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Como programar add-ons en XBMC: Los ficheros de identificación</title>
		<link>http://www.mimediacenter.info/2012/12/25/como-programar-add-ons-en-xbmc-los-ficheros-de-identificacion/</link>
		<comments>http://www.mimediacenter.info/2012/12/25/como-programar-add-ons-en-xbmc-los-ficheros-de-identificacion/#comments</comments>
		<pubDate>Tue, 25 Dec 2012 11:00:52 +0000</pubDate>
		<dc:creator>Jesus</dc:creator>
				<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[como programar addon xbmc]]></category>

		<guid isPermaLink="false">http://www.mimediacenter.info/?p=926</guid>
		<description><![CDATA[Este tutorial es el tercero de la serie Cómo programar un add-on de XBMC A la hora de hacer un add-on la parte más compleja es lógicamente la de programación, pero también es importante conocer los 3 ficheros que permiten una correcta publicación dentro de XBMC y que deben situarse en el directorio principal del [...]]]></description>
			<content:encoded><![CDATA[<blockquote><p>Este tutorial es el tercero de la serie <a href="http://www.mimediacenter.info/tag/como-programar-addon-xbmc/">Cómo programar un add-on de XBMC</a></p></blockquote>
<p>A la hora de hacer un add-on la parte más compleja es lógicamente la de programación, pero también es importante conocer los 3 ficheros que permiten una correcta publicación dentro de XBMC y que <strong>deben situarse en el directorio principal del add-on</strong>. Hablamos del logo, el fanart y el fichero addon.xml.</p>
<p>Con la edición de la información recogida en el fichero addon.xml podrás darle a tu add-on el título y la descripción que quieras, incluso en varios idiomas. El logo del canal es la imagen que aparece en el listado de add-ons para distinguirlo, normalmente junto al título aunque puede depender del skin que uses. Y el fanart es la imagen de fondo que aparece cuando has seleccionado el addon, como elemento meramente decorativo.</p>
<p>Veámoslo en detalle.</p>
<p><span id="more-926"></span></p>
<h2>El logo y el fanart</h2>
<p><img style="float: left;" src="http://www.mimediacenter.info/wp-content/uploads/2012/12/icon.png" alt="El logo del add-on de ejemplo en XBMC" title="El logo del add-on de ejemplo en XBMC" width="125" height="125" class="alignleft size-full wp-image-933" />El logo distingue al add-on cuando el usuario está viendo la lista de add-ons instalados, o cuando quiere instalar uno nuevo.</p>
<p>Es un fichero pequeño, grabado en formato PNG y debe llamarse exactamente <strong>&#8220;icon.png&#8221;</strong>. Debe tener un tamaño de 256&#215;256 pixels de acuerdo con las <a href="http://wiki.xbmc.org/index.php?title=Add-on_development#Guidelines_for_images">guías de estilo de XBMC</a>, y debes procurar que sea claro cuando se ve desde cierta distancia ya que la mayoría de usuarios de XBMC lo va a ver desde el sofá. No es obligatorio incluir un logotipo para tu add-on, aunque es muy recomendable.</p>
<p>El fanart o imagen de fondo, por el contrario, es una imagen grandota que sirve para personalizar un poco más la apariencia de tu add-on en XBMC. En este caso para que el tamaño del fichero no sea excesivo se utiliza el formato JPEG, es recomendable no exceder 1280&#215;720 pixels de resolución, y debe llamarse <strong>&#8220;fanart.jpg&#8221;</strong>. Es opcional incluir un fanart en tu add-on, de hecho hay muchos que no lo tienen.</p>
<p><img src="http://www.mimediacenter.info/wp-content/uploads/2012/12/fanart1.jpg" alt="" title="fanart1" width="600" height="338" class="aligncenter size-full wp-image-1048" /></p>
<p><img src="http://www.mimediacenter.info/wp-content/uploads/2012/12/fanart2.jpg" alt="" title="fanart2" width="600" height="338" class="aligncenter size-full wp-image-1049" /></p>
<h2>El fichero addon.xml</h3>
<p>El tercer fichero, y el único obligatorio en la estructura del add-on, es el fichero &#8220;addon.xml&#8221;. Contiene el identificador de tu add-on, su nombre, el nombre del autor&#8230; veamos el de nuestro add-on de ejemplo paso a paso:</p>
<pre class="prettyprint">
1  &lt;?xml version="1.0" encoding="UTF-8" standalone="yes"?&gt;
2  &lt;addon id="plugin.video.mimediacenter"
3   name="Mi media center"
4   version="1.0.2"
5   provider-name="tvalacarta"&gt;
6    &lt;requires&gt;
7      &lt;import addon="xbmc.python" version="2.0"/&gt;
8      &lt;import addon="plugin.video.youtube" version="3.0.0"/&gt;
9    &lt;/requires&gt;
10   &lt;extension point="xbmc.python.pluginsource" library="default.py"&gt;
11     &lt;provides&gt;video&lt;/provides&gt;
12   &lt;/extension&gt;
13   &lt;extension point="xbmc.addon.metadata"&gt;
14     &lt;summary lang="en"&gt;Mi media center&lt;/summary&gt;
15     &lt;description lang="en"&gt;Ideas para llevar la experiencia multimedia al salón&lt;/description&gt;
16     &lt;summary lang="es"&gt;Mi media center&lt;/summary&gt;
17     &lt;description lang="es"&gt;Ideas para llevar la experiencia multimedia al salón&lt;/description&gt;
18     &lt;platform&gt;all&lt;/platform&gt;
19   &lt;/extension&gt;
20 &lt;/addon&gt;
</pre>
<p>Hay cuatro bloques importantes que deben rellenarse cuando desarrollas tu propio add-on, lo normal suele ser buscar un fichero ya hecho y modificarlo según tus necesidades.</p>
<pre class="prettyprint">
2  &lt;addon id="plugin.video.mimediacenter"
3   name="Mi media center"
4   version="1.0.2"
5   provider-name="tvalacarta"&gt;
</pre>
<p>El primer bloque es muy importante porque hay varios aspectos del funcionamiento del add-on que dependerán de estos valores, especificados como atributos del XML.</p>
<ul>
<li><strong>id</strong>: Es el identificador interno del add-on. Debe coincidir con el nombre de directorio que emplees en el ZIP, y será utilizado en el código para acceder a cosas como la configuración.</li>
<li><strong>name</strong>: El nombre con el que el usuario verá el add-on.</li>
<li><strong>version</strong>: Visible en pantalla, y utilizado para las actualizaciones.</li>
<li><strong>provider-name</strong>: Nombre del autor / autores.</li>
</ul>
<pre class="prettyprint">
6    &lt;requires&gt;
7      &lt;import addon="xbmc.python" version="2.0"/&gt;
8      &lt;import addon="plugin.video.youtube" version="3.0.0"/&gt;
9    &lt;/requires&gt;
</pre>
<p>En este segundo bloque se declaran las dependencias que tiene tu add-on con otros add-ons publicados, ya sea en el repositorio oficial o en el tuyo propio. La dependencia con &#8220;xbmc.python&#8221; versión 2.0 declara que tu add-on es para XBMC Eden y posteriores.</p>
<pre class="prettyprint">
10   &lt;extension point="xbmc.python.pluginsource" library="default.py"&gt;
11     &lt;provides&gt;video&lt;/provides&gt;
12   &lt;/extension&gt;
</pre>
<p>Este punto describe el módulo que se ejecutará dentro del add-on cuando el usuario lo seleccione (llamado normalmente &#8220;default.py&#8221; por convención), y la distinción de si el add-on es de vídeo, audio, etc. Lo que pongas aquí determina en qué menú aparece el add-on.</p>
<pre class="prettyprint">
13   &lt;extension point="xbmc.addon.metadata"&gt;
14     &lt;summary lang="en"&gt;Mi media center&lt;/summary&gt;
15     &lt;description lang="en"&gt;Ideas para llevar la experiencia multimedia al salón&lt;/description&gt;
16     &lt;summary lang="es"&gt;Mi media center&lt;/summary&gt;
17     &lt;description lang="es"&gt;Ideas para llevar la experiencia multimedia al salón&lt;/description&gt;
18     &lt;platform&gt;all&lt;/platform&gt;
19   &lt;/extension&gt;
</pre>
<p>Descripción del add-on en varios idiomas, conviene poner al menos la versión en inglés para que todo el mundo pueda verla ya que es la utilizada por defecto. Qué valores se visualizarán en cada caso depende del skin del usuario.</p>
<h2>El empaquetado</h2>
<p>Los add-ons se distribuyen en ficheros ZIP, que por convención se llaman utilizando el identificador del add-on y la versión siguiendo este esquema:</p>
<p><strong>identificador-version.zip</strong></p>
<p>Por ejemplo</p>
<p><strong>plugin.video.mimediacenter-1.0.2.zip</strong></p>
<p>Realmente no es necesario seguir esta convención, puedes darle al fichero ZIP el nombre que tú quieras siempre que la estructura interna sea la correcta.</p>
<p>Dentro del ZIP tiene que estar todo en un directorio que se llame igual que el identificador del add-on, y tiene que tener al menos el fichero <strong>addon.xml</strong> y el módulo .py de arranque.</p>
<pre>
Archive:  plugin.video.mimediacenter-1.0.2.zip
 Length    Size  Ratio Name
-------- ------- ----- ----
   35821   12288  66%  plugin.video.mimediacenter/LICENSE.txt
     796     337  58%  plugin.video.mimediacenter/addon.xml
    2965    1083  64%  plugin.video.mimediacenter/default.py
  155007  152729   2%  plugin.video.mimediacenter/fanart.jpg
   50730   50669   0%  plugin.video.mimediacenter/icon.png
    3935    1385  65%  plugin.video.mimediacenter/plugintools.py
-------- -------  ---  -------
  249254  218491  12%  6 files
</pre>
<h2>Próxima entrada</h2>
<p>Y eso es todo por hoy. En la siguiente entrega volveremos a la programación para ver con detalle el uso de expresiones regulares en la extracción de datos, para ayudarte a que les pierdas el miedo.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mimediacenter.info/2012/12/25/como-programar-add-ons-en-xbmc-los-ficheros-de-identificacion/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Como programar add-ons en XBMC: Funcionamiento de un add-on paso a paso</title>
		<link>http://www.mimediacenter.info/2012/12/11/como-programar-add-ons-en-xbmc-funcionamiento-de-un-add-on-paso-a-paso/</link>
		<comments>http://www.mimediacenter.info/2012/12/11/como-programar-add-ons-en-xbmc-funcionamiento-de-un-add-on-paso-a-paso/#comments</comments>
		<pubDate>Mon, 10 Dec 2012 23:25:22 +0000</pubDate>
		<dc:creator>Jesus</dc:creator>
				<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[como programar addon xbmc]]></category>

		<guid isPermaLink="false">http://www.mimediacenter.info/?p=947</guid>
		<description><![CDATA[Este tutorial es el segundo de la serie Cómo programar un add-on de XBMC Esta serie de tutoriales va a guiarte paso a paso en la construcción de un add-on para XBMC, usando la librería Plugin Tools y un ejemplo de add-on totalmente operativo como punto de partida. Veremos cómo funciona por dentro este add-on, [...]]]></description>
			<content:encoded><![CDATA[<blockquote><p>Este tutorial es el segundo de la serie <a href="http://www.mimediacenter.info/tag/como-programar-addon-xbmc/">Cómo programar un add-on de XBMC</a></p></blockquote>
<p>Esta serie de tutoriales va a guiarte paso a paso en la construcción de un add-on para XBMC, usando la librería <a href="http://www.mimediacenter.info/plugintools/">Plugin Tools</a> y un ejemplo de add-on totalmente operativo como punto de partida. Veremos cómo funciona por dentro este add-on, como mejorarlo, e incluso cómo publicarlo en el repositorio oficial de XBMC o en un repositorio propio.</p>
<p>Para empezar te recomiendo que descargues el add-on de ejemplo que acompaña a la distribución de la librería Plugin Tools, y lo instales en tu equipo.</p>
<p><a href="http://www.mimediacenter.info/descargas/plugin.video.mimediacenter-1.0.2.zip">http://www.mimediacenter.info/descargas/plugin.video.mimediacenter-1.0.2.zip</a></p>
<p>Este add-on permite extraer y ver desde XBMC los <a href="http://www.youtube.com/user/tvalacarta">vídeos de mi canal de YouTube</a>, y utiliza a su vez el add-on oficial de YouTube para la reproducción. Si no tienes el add-on de YouTube se instalará automáticamente cuando vayas a ver cualquier vídeo.</p>
<p><img src="http://www.mimediacenter.info/wp-content/uploads/2012/12/addon-xbmc-instalar-youtube-automaticamente.jpg" alt="Tu add-on para XBMC: Instalar dependencia con el add-on de YouTube" title="Tu add-on para XBMC: Instalar dependencia con el add-on de YouTube" width="600" height="231" class="aligncenter size-full wp-image-932" /></p>
<p><span id="more-947"></span></p>
<h2>Instalación del add-on y preparación del entorno de desarrollo</h2>
<p>Puedes descargar e instalar el add-on en XBMC siguiendo el procedimiento habitual, <a href="http://www.youtube.com/watch?v=lXAEuUdpuiw">desde XBMC con la opción de &#8220;Instalar desde fichero ZIP&#8221;</a> o descomprimiéndolo <a href="http://www.mimediacenter.info/2011/11/09/como-instalar-un-addon-manualmente-en-xbmc-dharma-y-eden/">manualmente en el directorio de los add-ons</a>.</p>
<p>Publicar un add-on en XBMC no implica nada más que tener un directorio con el nombre correcto en la carpeta &#8220;addons&#8221;, y si quieres quitarlo de XBMC basta con que borres ese directorio.</p>
<p>Yo lo que hago habitualmente es trabajar sobre una carpeta donde almaceno todos los plugins (/Users/jesus/Plugins) y luego crear un enlace simbólico en el directorio de los add-ons de XBMC. De esa forma tengo todos los plugins en el mismo sitio, y sólo publico en XBMC aquel con el que estoy trabajando.</p>
<p>Los enlaces simbólicos pueden aplicarse en cualquier sistema, que yo sepa. Las instrucciones desde el terminal en mi Mac son:</p>
<pre class="prettyprint">$ cd /Users/jesus/Library/Application\ Support/XBMC/addons
$ ln -s /Users/jesus/Plugins/plugin.video.mimediacenter plugin.video.mimediacenter</pre>
<p>Tengas donde tengas el código fuente del add-on, ya sea en la carpeta de XBMC o en un directorio separado como en mi caso, configura tu IDE favorito o simplemente prepara un editor de texto para empezar.</p>
<h2>¿Qué hace el add-on de ejemplo?</h2>
<p>La función de este add-on es sencilla. Basándose en el <a href="https://developers.google.com/youtube/2.0/developers_guide_protocol_video_feeds">API de YouTube</a>, se descarga el feed de vídeos de mi canal de YouTube desde esta URL:</p>
<p><a href="http://gdata.youtube.com/feeds/api/users/tvalacarta/uploads">http://gdata.youtube.com/feeds/api/users/tvalacarta/uploads</a></p>
<p>De ahí extrae los vídeos ordenados por fecha de subida, y los muestra de forma que el usuario puede verlos directamente desde XBMC.</p>
<p><img src="http://www.mimediacenter.info/wp-content/uploads/2012/12/addon-xbmc-mimediacenter.jpg" alt="El Add-on de XBMC para Mi media center" title="El Add-on de XBMC para Mi media center" width="600" height="338" class="aligncenter size-full wp-image-967" /></p>
<h2>Punto de entrada</h2>
<p>Para averiguar cual es el punto en el que comienza la ejecución del add-on debes abrir el fichero addon.xml, buscar el elemento de extensión &#8220;xbmc.python.pluginsource&#8221; y verás que su atributo &#8220;library&#8221; indica el módulo principal.</p>
<pre class="prettyprint">
10  &lt;extension point="xbmc.python.pluginsource" library="default.py"&gt;
</pre>
<p>Si abres el módulo default.py verás que tras definir las funciones que va a utilizar lo único que hace es ejecutar la primera de ellas: &#8220;run&#8221;.</p>
<pre class="prettyprint">
22 # Entry point
23 def run():
24    plugintools.log("tvalacarta.run")
25    
26    # Get params
27    params = plugintools.get_params()
28    
29    if params.get("action") is None:
30        main_list(params)
31    else:
32        action = params.get("action")
33        exec action+"(params)"
34    
35    plugintools.close_item_list()
</pre>
<p>La función &#8220;run&#8221; se ejecutará cuando abras el add-on la primera vez, y  cada vez que el usuario haga una selección. Veamos su funcionamiento paso a paso:</p>
<pre class="prettyprint">
24    plugintools.log("tvalacarta.run")
</pre>
<p>Esta línea añade al log de XBMC una entrada, que nos permitirá trazar en caso necesario por donde ha transcurrido la ejecución de nuestro código.</p>
<pre class="prettyprint">
26    # Get params
27    params = plugintools.get_params()
</pre>
<p>El paso de parámetros a un add-on se realiza en XBMC siguiendo un esquema de URL de este tipo:</p>
<pre class="prettyprint">
plugin://plugin.video.nombredeladdon/?parametro1=valor1&#038;parametro2=valor2
</pre>
<p>Esta función <a href="http://www.mimediacenter.info/plugintools/referencia/get_params/">get_params</a> de plugintools lo que hace es extraer los parámetros y ponerlos en un diccionario para facilitar su acceso más adelante.</p>
<pre class="prettyprint">
29    if params.get("action") is None:
30        main_list(params)
31    else:
32        action = params.get("action")
33        exec action+"(params)"
</pre>
<p>Según este condicional, si hay un parámetro &#8220;action&#8221; que tiene el nombre de la función a ejecutar, le pasa el control a esa función pasándole el diccionario de parámetros. En caso de que no haya un parámetro &#8220;action&#8221;, la función llamada por defecto es &#8220;main_list&#8221;.</p>
<pre class="prettyprint">
35    plugintools.close_item_list()
</pre>
<p>La función que ejecute el add-on se encargará de añadir elementos a la lista de items de XBMC, y con esta llamada a <a href="http://www.mimediacenter.info/plugintools/referencia/close_item_list/">close_item_list</a> indicamos a XBMC que ya hemos terminado de añadir items. En este punto el control pasa de nuevo al usuario.</p>
<h2>La función principal</h2>
<p>El add-on del ejemplo sólo tiene dos funciones, una para leer los elementos del feed y la otra para reproducir el elemento elegido. En posteriores entregas de esta guía lo mejoraremos para añadir cosas como menús estáticos, configuración, buscador, etc.</p>
<p>Esta es la función &#8220;main_list()&#8221; completa, donde se hace la magia.</p>
<pre class="prettyprint">
37 # Main menu
38 def main_list(params):
39     plugintools.log("tvalacarta.main_list "+repr(params))
40
41     # On first page, pagination parameters are fixed
42     if params.get("url") is None:
43         params["url"] = "http://gdata.youtube.com/feeds/api/users/"+YOUTUBE_CHANNEL_ID+"/uploads?start-index=1&#038;max-results=10"
44 
45     # Fetch video list from YouTube feed
46     data = plugintools.read( params.get("url") )
47    
48     # Extract items from feed
49     pattern = ""
50     matches = plugintools.find_multiple_matches(data,"&lt;entry&gt;(.*?)&lt;/entry&gt;")
51    
52     for entry in matches:
53         plugintools.log("entry="+entry)
54        
55         # Not the better way to parse XML, but clean and easy
56         title = plugintools.find_single_match(entry,"&lt;titl[^&gt;]+&gt;([^&lt;]+)&lt;/title&gt;")
57         plot = plugintools.find_single_match(entry,"&lt;media\:descriptio[^&gt;]+&gt;([^&lt;]+)&lt;/media\:description&gt;")
58         thumbnail = plugintools.find_single_match(entry,"&lt;media\:thumbnail url='([^']+)'")
59         video_id = plugintools.find_single_match(entry,"http\://www.youtube.com/watch\?v\=([0-9A-Za-z_-]{11})")
60         url = "plugin://plugin.video.youtube/?path=/root/video&#038;action=play_video&#038;videoid="+video_id
61
62         # Appends a new item to the xbmc item list
63         plugintools.add_item( action="play" , title=title , plot=plot , url=url ,thumbnail=thumbnail , isPlayable=True, folder=False )
64     
65     # Calculates next page URL from actual URL
66     start_index = int( plugintools.find_single_match( params.get("url") ,"start-index=(\d+)") )
67     max_results = int( plugintools.find_single_match( params.get("url") ,"max-results=(\d+)") )
68     next_page_url = "http://gdata.youtube.com/feeds/api/users/"+YOUTUBE_CHANNEL_ID+"/uploads?start-index=%d&#038;max-results=%d" % ( start_index+max_results , max_results)
69
70     plugintools.add_item( action="main_list" , title="&lt;&lt; Next page" , url=next_page_url , folder=True )
</pre>
<p>No es tan complicado como parece, ya que en la mayoría de los casos el add-on hace su trabajo en tres etapas bien diferenciadas.</p>
<ul>
<li><strong>Leer la fuente</strong>: Se lee el html de la página con la que se va a trabajar</li>
<li><strong>Extraer datos de la fuente</strong>: Se extraen los elementos de la página que contienen la información relevante.</li>
<li><strong>Construir la lista de items de XBMC</strong>: Combinando la información extraída se informa a XBMC de los elementos que debe mostrar.</li>
</ul>
<p>Veámoslo paso a paso.</p>
<h2>Primera etapa: Leer la fuente</h2>
<p>Saltando la línea que traza la entrada a la función en la línea 39, lo primero que encontramos es esto:</p>
<pre class="prettyprint">
41     # On first page, pagination parameters are fixed
42     if params.get("url") is None:
43         params["url"] = "http://gdata.youtube.com/feeds/api/users/"+YOUTUBE_CHANNEL_ID+"/uploads?start-index=1&#038;max-results=10"
</pre>
<p>La URL de que se sacan los datos vendrá en un parámetro &#8220;url&#8221; en las siguientes invocaciones, pero la primera invocación no especifica ningún parámetro así que se asigna un valor por defecto usando el API de YouTube. Fíjate que añadimos los parámetros &#8220;start-index&#8221; y &#8220;max-results&#8221;, que hacen la petición de 10 elementos empezando por el 1. Usaremos esto para la paginación un poco más adelante.</p>
<pre class="prettyprint">
45     # Fetch video list from YouTube feed
46     data = plugintools.read( params.get("url") )
</pre>
<p>Ahora que estamos seguros de que la URL está en el parámetro &#8220;url&#8221;, podemos usarlo para descargar el contenido que se va a mostrar en el add-on, y para ello se hace uso de la función <a href="http://www.mimediacenter.info/plugintools/referencia/read/">read</a> de plugintools. Esta función es muy sencilla por dentro en este punto, pero la complicaremos más a medida que necesitemos más.</p>
<h2>Segunda etapa: Extraer los datos de la fuente</h2>
<p>Esta es siempre la parte más compleja, cuando es necesario extraer los datos de lo que hemos descargado para convertirlos en elementos estructurados. Es complejo porque implica (normalmente) el uso de expresiones regulares, y las expresiones regulares dan un poco de miedo.</p>
<p>En este caso particular podríamos haber utilizado librerías de procesamiento de XML, pero para mantener el ejemplo sencillo he pensado que mejor atacábamos el problema con expresiones regulares.</p>
<p>Hagámoslo en dos pasos.</p>
<p>En primer lugar vamos a extraer todos los elementos &#8220;&lt;entry&gt;&#8221; que hay en el XML que nos hemos descargado, usando la función <a href="http://www.mimediacenter.info/plugintools/referencia/find_multiple_matches/">find_multiple_matches</a> de plugintools. Recibe dos parámetros, el string con los datos que hemos descargado y la expresión regular a aplicar. Y devuelve una lista con lo que ha encontrado. No hagas caso a la línea 49, en este caso sobra aunque viene bien tenerla para futuros usos.</p>
<pre class="prettyprint">
48     # Extract items from feed
49     pattern = ""
50     matches = plugintools.find_multiple_matches(data,"&lt;entry&gt;(.*?)&lt;/entry&gt;")
51    
52     for entry in matches:
53         plugintools.log("entry="+entry)
</pre>
<p>Ahora que tenemos elementos &#8220;entry&#8221; en un array, podemos procesarlos uno por uno usando la función <a href="http://www.mimediacenter.info/plugintools/referencia/find_single_match/">find_single_match</a> de plugintools.</p>
<pre class="prettyprint">
56         title = plugintools.find_single_match(entry,"&lt;titl[^&gt;]+&gt;([^&lt;]+)&lt;/title&gt;")
57         plot = plugintools.find_single_match(entry,"&lt;media\:descriptio[^&gt;]+&gt;([^&lt;]+)&lt;/media\:description&gt;")
58         thumbnail = plugintools.find_single_match(entry,"&lt;media\:thumbnail url='([^']+)'")
59         video_id = plugintools.find_single_match(entry,"http\://www.youtube.com/watch\?v\=([0-9A-Za-z_-]{11})")
</pre>
<p>Para cada elemento &#8220;entry&#8221; obtenemos el título (title), la descripción (plot), la imagen (thumbnail) y el id que asigna YouTube al vídeo (video_id). Este es el valor que espera el add-on de YouTube en XBMC.</p>
<p>Si no entiendes muy bien la sintaxis de las expresiones regulares no te preocupes, volveremos a ello en próximas entregas de este tutorial y verás que son bastante sencillas en este caso concreto.</p>
<h2>Tercera etapa: Construir la lista de items de XBMC</h2>
<p>Ya solo queda añadir el elemento a la lista de &#8220;items&#8221; de XBMC, lo que hacemos nuevamente con la función <a href="http://www.mimediacenter.info/plugintools/referencia/add_item/">add_item</a> de plugintools. </p>
<pre class="prettyprint">
60         url = "plugin://plugin.video.youtube/?path=/root/video&#038;action=play_video&#038;videoid="+video_id
61
62         # Appends a new item to the xbmc item list
63         plugintools.add_item( action="play" , title=title , plot=plot , url=url ,thumbnail=thumbnail , isPlayable=True, folder=False )
</pre>
<p>Un item de XBMC no es más que un título y una URL, aunque podemos ampliarlo con un thumbnail, descripción, fanart, productora de la peli, calidad del vídeo, &#8230; De momento vamos a limitarlo a los cuatro elementos que hemos extraido y deduciendo la URL a partir del video_id.</p>
<p>Observa que la URL del elemento es la llamada al add-on de YouTube, pasándole el video_id tal como lo hemos encontrado en el paso anterior.</p>
<p>Observa también que el parámetro &#8220;folder&#8221; de add_item está a False, indicando que cuando el usuario seleccione este elemento no va a encontrar niveles adicionales de navegación. Este parámetro &#8220;folder=False&#8221; se reserva normalmente para los vídeos.</p>
<h2>Paginación</h2>
<p>La descarga de datos desde la URL de YouTube está limitada a los 10 primeros elementos, pero cualquier canal de YouTube tiene muchos más vídeos. ¿Cómo hacer para que el usuario pueda ir descargando los 10 siguientes, con un elemento de tipo &#8220;Next page&#8221; como en la captura de pantalla del add-on?</p>
<pre class="prettyprint">
65     # Calculates next page URL from actual URL
66     start_index = int( plugintools.find_single_match( params.get("url") ,"start-index=(\d+)") )
67     max_results = int( plugintools.find_single_match( params.get("url") ,"max-results=(\d+)") )
</pre>
<p>Lo primero es averiguar por qué número de elemento vamos, y para ello utilizamos nuevamente find_single_match y una expresión regular. Miramos a ver qué URL se ha empleado para la lista actual, y extraemos de ella el valor de start_index y max_results.</p>
<pre class="prettyprint">
68     next_page_url = "http://gdata.youtube.com/feeds/api/users/"+YOUTUBE_CHANNEL_ID+"/uploads?start-index=%d&#038;max-results=%d" % ( start_index+max_results , max_results)
69
70     plugintools.add_item( action="main_list" , title="&lt;&lt; Next page" , url=next_page_url , folder=True )
</pre>
<p>Con esos dos valores deducimos los que deberían emplearse en la URL de la siguiente página (max_results debe ser el mismo, y start_index será 11 para la segunda página, 21 para la tercera, &#8230;) y añadimos un nuevo item usando add_item. Cuidando que esta vez el parámetro &#8220;folder&#8221; sea &#8220;True&#8221;, porque al elegir este item sí que van a obtenerse más items.</p>
<h2>Respondiendo a la selección del usuario</h2>
<p>Ya tenemos los items de los 10 primeros vídeos, y un item adicional para que el usuario pueda avanzar a la siguiente página.</p>
<p>Ahora bien, ¿cómo continúa la navegación del usuario a partir de este punto?</p>
<p>Es sencillo.</p>
<p>Una vez añadidos los items la función &#8220;main_list&#8221; termina, y la función &#8220;run()&#8221; finaliza la ejecución llamando a &#8220;plugintools.close_item_list()&#8221; como hemos visto más arriba. Así XBMC sabe que la lista ha terminado de cargarse, quita la espiral de carga y muestra al usuario la lista de items.</p>
<p>Cuando el usuario elija un ítem se volverá a invocar al add-on, pasándole como parámetros todos los del item tal como especificamos en la llamada a la función &#8220;add_item&#8221; para añadirlo.</p>
<p>Y esta es la clave, porque si queremos que la selección de un item dispare una acción concreta sólo tenemos que indicar la acción que queremos en el parámetro &#8220;action&#8221;. Y luego definir una función con ese nombre en nuestro add-on.</p>
<p>Siguiendo nuestro ejemplo, cuando el usuario elija un vídeo se repetirá el ciclo anterior pero invocando esta vez a la función &#8220;play&#8221;. Y esta función se encarga de reproducir el vídeo:</p>
<pre class="prettyprint">
72 def play(params):
73     plugintools.play_resolved_url( params.get("url") )
</pre>
<p>Si por el contrario el usuario elige el elemento de página siguiente, la función llamada será &#8220;main_list&#8221; porque es la acción que se especificó al añadir este último item. Y como la URL pasada como parámetro será la que extrae los próximos 10 items, obtendremos como resultado la siguiente página.</p>
<h2>Próxima entrada</h2>
<p>La entrada de hoy ha sido algo más larga de lo que esperaba, pero si comprendes cómo funciona el add-on de ejemplo te debería resultar sencillo hacer un buen número de add-ons distintos.</p>
<p>Antes de explicar otras técnicas, mañana nos detendremos en ver cómo se personalizan los ficheros de identificación del add-on para que puedas empezar a hacer tus primeros proyectos.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mimediacenter.info/2012/12/11/como-programar-add-ons-en-xbmc-funcionamiento-de-un-add-on-paso-a-paso/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Cómo programar add-ons en XBMC: Tipos de Add-ons</title>
		<link>http://www.mimediacenter.info/2012/12/10/como-programar-add-ons-en-xbmc-tipos-de-add-ons/</link>
		<comments>http://www.mimediacenter.info/2012/12/10/como-programar-add-ons-en-xbmc-tipos-de-add-ons/#comments</comments>
		<pubDate>Mon, 10 Dec 2012 00:32:46 +0000</pubDate>
		<dc:creator>Jesus</dc:creator>
				<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[como programar addon xbmc]]></category>

		<guid isPermaLink="false">http://www.mimediacenter.info/?p=798</guid>
		<description><![CDATA[Este tutorial es el primero de la serie Cómo programar un add-on de XBMC XBMC es una aplicación diseñada para convertirse en ese programa que utilizas en casa para disfrutar de tus vídeos, de tu música, de tus fotografías. Puedes hacer lo mismo con diferentes dispositivos, pero XBMC es la pieza central del control multimedia [...]]]></description>
			<content:encoded><![CDATA[<blockquote><p>Este tutorial es el primero de la serie <a href="http://www.mimediacenter.info/tag/como-programar-addon-xbmc/">Cómo programar un add-on de XBMC</a></p></blockquote>
<p>XBMC es una aplicación diseñada para convertirse en ese programa que utilizas en casa para disfrutar de tus vídeos, de tu música, de tus fotografías. Puedes hacer lo mismo con diferentes dispositivos, pero XBMC es la pieza central del control multimedia en tu casa.</p>
<p>Además de un reproductor de vídeo muy avanzado capaz de reproducir cualquier cosa, una función de biblioteca para gestionar tu colección de forma muy completa, la mejor conectividad que puedes encontrar y funcionamiento garantizado en multitud de sistemas operativos de ordenadores y dispositivos, XBMC tiene la posibilidad de incorporar extensiones denominadas &#8220;Add-ons&#8221;.</p>
<p>Estas extensiones permiten añadir nuevas funciones, como juegos o redes sociales, pero sobre todo permiten acceder a contenidos que se encuentran en Internet (videos, música y fotografías entre otros) sin salir de la interfaz de XBMC. Es la experiencia de navegar por Internet desde tu sofá.</p>
<p><span id="more-798"></span></p>
<h2>Por qué este tutorial</h2>
<p>A pesar de que existen otros tutoriales sobre cómo desarrollar estos add-ons circulando por Internet, la documentación no ha sido tradicionalmente el punto fuerte de XBMC como ocurre a menudo con los proyectos open source.</p>
<p>Hace tiempo que tengo pensado escribir este tutorial para aportar mi granito de arena en forma de documentación, y también para que exista un tutorial en castellano para los que no se manejan demasiado con el inglés.</p>
<p>Mi intención es traducirlo también al inglés, pero eso no ocurrirá hasta que no esté terminado <img src='http://www.mimediacenter.info/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<h2>Tipos de add-ons</h2>
<p>Hay muchas clases de add-ons, aunque en realidad la mayor parte de ellos son subsistemas internos del propio media center. Subsistemas que han sido desarrollados como módulos para que si en algún momento es necesario reemplazarlos, sea fácil hacerlo.</p>
<p>Es posible leer la <a href="http://wiki.xbmc.org/index.php?title=Add-on_development#Types_of_extension">lista completa de tipos de add-ons en la wiki de XBMC</a>, e incluye funciones conocidas como los skins (<strong>xbmc.gui.skin</strong>), los scrapers que conectan la biblioteca con repositorios externos (<strong>xbmc.metadata.scraper</strong>) o el módulo de predicción metereológica (<strong>xbmc.python.weather</strong>). Pero también hay otras funciones más desconocidas para el usuario medio como los servicios en segundo plano (<strong>xbmc.service</strong>) o la interfaz web (<strong>xbmc.gui.webinterface</strong>).</p>
<p>Sin embargo hay 4 tipos de add-ons que proporcionan las extensiones más interesantes. Son los que añaden nuevas fuentes para <strong>vídeos</strong>, <strong>música</strong> y <strong>fotografía</strong>. Y un tipo especial que es el add-on de <strong>programas</strong>, principalmente destinado a recoger el resto de opciones.</p>
<h2>Add-on de video</h2>
<p>Accesibles desde el menú de &#8220;Vídeos&#8221; en XBMC, al ejecutar un add-on de vídeo se obtiene como resultado una lista de elementos que pueden ser &#8220;carpetas&#8221; o &#8220;ficheros&#8221;, siguiendo el símil de las carpetas y ficheros de tu disco. Una &#8220;carpeta&#8221; es un elemento que al seleccionarlo devuelve otra lista de elementos, y un &#8220;fichero&#8221; es directamente algo que se puede reproducir.</p>
<p>Lo más habitual es que el addon obtenga los elementos de estas carpetas y ficheros virtuales leyendo un sitio web,  extrayendo mediante expresiones regulares los enlaces a categorías o canales para presentarlos como &#8220;carpetas&#8221; y extrayendo los enlaces a los vídeos para presentarlos como &#8220;ficheros&#8221;.</p>
<p>Un buen ejemplo de esto es el acceso a las conferencias del add-on &#8220;TED Talks&#8221; por autores. La lista de autores son las carpetas, puesto que al seleccionarlas obtienes todas las ponencias de ese autor, y a su vez las ponencias son los &#8220;ficheros&#8221; ya que al seleccionarlas puedes ver el vídeo sin más. Imagínate que tienes las ponencias descargadas en tu ordenador y clasificadas en carpetas con el nombre del autor, y verás que tiene sentido.</p>
<p><img src="http://www.mimediacenter.info/wp-content/uploads/2012/12/addons-xbmc-carpetas-en-ted-talks.jpg" alt="Add-ons para XBMC: Carpetas en TED Talks" title="Add-on para XBMC: Carpetas en TED Talks" width="280"/> <img src="http://www.mimediacenter.info/wp-content/uploads/2012/12/addons-xbmc-ficheros-en-ted-talks.png" alt="Add-ons para XBMC: Ficheros en TED Talks" title="Add-on para XBMC: Ficheros en TED Talks" width="280"/></p>
<p>Hay muchos ejemplos de add-ons de vídeo, y en mi caso son los que más uso con diferencia. Están los add-ons oficiales de XBMC y menos &#8220;conflictivos&#8221;, como el add-on para acceder a YouTube, las TED Talks o la Academia Khan. Y luego están los add-ons que acceden a televisiones, películas y series. En esta categoría están mis add-ons más conocidos (tvalacarta y pelisalcarta), pero también otros muy populares como icefilms y 1channel.</p>
<h2>Add-on de audio</h2>
<p>El add-on de audio tiene muchas similitudes con el add-on de vídeo, en cuanto a la estructuración por &#8220;carpetas&#8221; y &#8220;ficheros&#8221;, pero lógicamente su finalidad es escuchar música, radio y cosas por el estilo. Si es el tipo de add-on que te interesa verás que hay pocas diferencias en su desarrollo respecto al add-on de vídeo.</p>
<p>Los mejores ejemplos de este tipo de add-on los tienes en el de Shoutcast, Grooveshark o Icecast.</p>
<p><img src="http://www.mimediacenter.info/wp-content/uploads/2012/12/addons-xbmc-shoutcast-2.jpg" alt="Add-ons para XBMC: Shoutcast" title="Add-ons para XBMC: Shoutcast" width="600" height="338" class="aligncenter size-full wp-image-918" /></p>
<h2>Add-on de fotografía</h2>
<p>De la misma forma que en el caso anterior, un add-on de fotografía añade contenido a XBMC incorporando &#8220;carpetas&#8221; y &#8220;ficheros&#8221; virtuales para navegar. También es muy similar en su estructura y desarrollo al add-on de vídeo y al de música.</p>
<p>Los ejemplos más populares de este tipo de add-ons son los relacionados con fotografía profesional, como 500px o The Big Picture (muy recomendable), o los relacionados con tus álbumes de fotos personales como Picasa o Flickr.</p>
<p><img src="http://www.mimediacenter.info/wp-content/uploads/2012/12/addons-xbmc-the-big-picture.png" alt="Add-ons para XBMC: The Big Picture" title="Add-ons para XBMC: The Big Picture" width="600" height="338" class="aligncenter size-full wp-image-919" /></p>
<h2>Programa</h2>
<p>Es una categoría reservada para los add-ons que no encajan en las anteriores, puedes encontrar algunos que carecen totalmente de interfaz de usuario como TvTunes (que completa tus series descargando sus melodías) o Artwork downloader (que descarga fanarts adicionales). Y también puedes encontrar algunos que son aplicaciones completas dentro de XBMC, como el add-on para navegar por foros &#8220;Forum Browser&#8221;.</p>
<h2>Próxima entrada</h2>
<p>La entrada de mañana describirá cómo funciona el add-on de vídeo que viene <a href="http://www.mimediacenter.info/plugintools">como ejemplo de la librería &#8220;Plugin Tools&#8221;</a>, para descubrir los principales aspectos internos de un add-on y su comunicación con XBMC.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mimediacenter.info/2012/12/10/como-programar-add-ons-en-xbmc-tipos-de-add-ons/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
