Usar la foto del día de Bing en tu aplicación

La mejor característica del motor de búsqueda Bing es que cada día tiene una foto muy bonita en el fondo de su página de inicio. Actualmente, estoy trabajando en una aplicación muy grande, que tiene una pantalla de inicio y pensé en crear un diseño similar al de Bing con diferentes imágenes de fondo todos los días. Por supuesto, esto requeriría algún tipo de servicio web, y un poco de trabajo de vez en cuando a la hora de seleccionar las imágenes. Básicamente, tendrías que reinventar la rueda. Por suerte, la foto del día se puede descargar fácilmente de Bing ejecutando un pequeño script que he desarrollado.

La información sobre la foto del día está disponible en varios formatos, proporcionada por los propios desarrolladores de Bing gracias a una sencilla API. Los datos de la foto se pueden descargar en formato XML, RSS o JSON a través de los siguientes enlaces (cogeremos la información en inglés porque es más completa):

XML: http://www.bing.com/HPImageArchive.aspx?format=xml&idx=0&n=1&mkt=en-US
RSS: http://www.bing.com/HPImageArchive.aspx?format=rss&idx=0&n=1&mkt=en-US
JSON: http://www.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1&mkt=en-US

Yo, particularmente, escogí la información en XML ya que el framework que utilizo tiene soporte LINQ, por lo que parsear un XML no es un gran problema. Quería que el código sea compacto, así que me decanté por el formato XML definitivamente.

El código XML

El tag raíz del XML es images, que puede contener múltiples etiquetas image. En el URL de la solicitud, si se cambia el parámetro n de 1 a 10, recibirás las imágenes de los últimos 10 días. Cada nodo image tiene sus derechos de autor y su nodo copyright, que alberga la información sobre los derechos de autor de la imagen y el enlace al copyright asociado. La URL de la imagen está dentro del nodo url.

El tag images puede tener puntos calientes. Estos puntos calientes son zonas especiales de la imagen. Si el puntero del ratón está sobre una zona interactiva, se mostrará un pequeño tooltip con información relacionada. Esta característica no me interesaba, por lo que tampoco la implementé.

Después de los datos de image, podemos ver el nodo tooltip, que contiene los datos del tooltip para crear un slide con las imágenes. Estos datos se pueden utilizar como información para los diversos botones del slide como play, pause, next o previous. Los datos se muestran en el idioma solicitado.

 <?xml version="1.0" encoding="utf-8" ?>
<images>
  <image>
    <startdate>20151028</startdate>
    <fullstartdate>201510280000</fullstartdate>
    <enddate>20151029</enddate>
    <url>/az/hprichbg/rb/StagUK_EN-US9650313735_1366x768.jpg</url>
    <urlBase>/az/hprichbg/rb/StagUK_EN-US9650313735</urlBase>
    <copyright>A male red deer in London&rsquo;s Richmond Park,
    England (&copy; Ian Schofield/Offset)</copyright>
    <copyrightlink>http://www.bing.com/search?
        q=red+deer+(animal)&amp;form=hpcapt</copyrightlink>
    <drk>1</drk>
    <top>1</top>
    <bot>1</bot>
    <hotspots>
      <hotspot>
        <desc>You have a little something on your antler.</desc>
        <link>http://www.bing.com/images/search?q=red+deer+
        (Cervus+elaphus)&amp;FORM=hphot1</link>
        <query>There, you got it</query>
        <LocX>15</LocX>
        <LocY>33</LocY>
      </hotspot>
      <hotspot>
        <desc>This time of year in the European wilderness&hellip;</desc>
        <link>http://www.bing.com/videos/search?q=Red+Deer+Rut+
        Fight&amp;Form=hphot2#view=detail&
            amp;mid=2A889A1A464E79E32F582A889A1A464E79E32F58</link>
        <query>These males put those antlers to dangerous use</query>
        <LocX>37</LocX>
        <LocY>42</LocY>
      </hotspot>
      <hotspot>
        <desc>There's no need to trek deep into the woods to see these stags.</desc>
        <link>http://www.bing.com/search?q=richmond+park+london&amp;form=hphot3</link>
        <query>This one lives in the middle of an urban center</query>
        <LocX>66</LocX>
        <LocY>33</LocY>
      </hotspot>
    </hotspots>
    <messages></messages>
  </image>
  <tooltips>
    <loadMessage>
      <message>Bet&ouml;lt&eacute;s...</message>
    </loadMessage>
    <previousImage>
      <text>Elozo</text>
    </previousImage>
    <nextImage>
      <text>K&ouml;vetkezo</text>
    </nextImage>
    <play>
      <text>J&aacute;t&eacute;k</text>
    </play>
    <pause>
      <text>Sz&uuml;net</text>
    </pause>
  </tooltips>
</images>

Implementación

La parte interesante del código se encuentra en el archivo BingWallPaperClient.cs, que implementa la funcionalidad de descarga. La implementación utiliza el cacheo de imágenes. La imagen y la información del copyright se almacenan en un directorio temporal del usuario. Si existe el archivo temporal y no hace más de 24 horas que se descargó, entonces no se requiere ninguna descarga. Los datos de image se pueden usar tanto en WPF y Windows Forms Projects, debido a que ambos subsistemas soportan la carga de archivos JPEG.

La función Download está disponible como sincróna y como un método asíncrono.

using System;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Xml.Linq;

namespace BingPhotoOfDayClient
{
    /// 
    /// A class designed to download the bing photo of the day
    /// 
    public class BingWallPaperClient
    {
        private readonly string _feed;
        private readonly string _tempfilename;
        private readonly string _tempcoppyright;
        private bool _loadcalled;

        /// 
        /// Creates a new instance of the Bing photo downloader
        /// 
        public BingWallPaperClient()
        {
            var tempdir = Environment.ExpandEnvironmentVariables("%temp%");
            _tempfilename = Path.Combine(tempdir, "bingphotooftheday.jpg");
            _tempcoppyright = Path.Combine(tempdir, "bingphotooftheday.txt");
            _loadcalled = false;

            //photo of the day data in xml format
            _feed = "http://www.bing.com/HPImageArchive.aspx?
            		format=xml&idx=0&n=1&mkt=en-US";
        }

        /// 
        /// Downloads the photo of the day synchronously
        /// 
        public void DownLoad()
        {
            bool downloadneeded = true;
            if (File.Exists(_tempfilename))
            {
                FileInfo fi = new FileInfo(_tempfilename);
                if ((DateTime.UtcNow - fi.LastWriteTimeUtc).TotalHours < 24)
                {
                    downloadneeded = false;
                }
            }

            if (File.Exists(_tempcoppyright))
            {
                CoppyRightData = File.ReadAllText(_tempcoppyright);
                downloadneeded = false;
            }
            else downloadneeded = true;

            _loadcalled = true;
            if (!downloadneeded) return;

            var document = XDocument.Load(_feed).Elements().Elements().FirstOrDefault();

            var url = (from i in document.Elements()
                       where i.Name == "url"
                       select i.Value.ToString()).FirstOrDefault();

            var imgurl = "http://www.bing.com" + url;

            var copyright = (from i in document.Elements()
                             where i.Name == "copyright"
                             select i.Value.ToString()).FirstOrDefault();
            var cplink = (from i in document.Elements()
                          where i.Name == "copyrightlink"
                          select i.Value.ToString()).FirstOrDefault();

            CoppyRightData = copyright + "rn" + cplink;
            File.WriteAllText(_tempcoppyright, CoppyRightData);

            using (var client = new WebClient())
            {
                client.DownloadFile(imgurl, _tempfilename);
            }
        }

        /// 
        /// Asyncronous & awaitable version of the download routine
        /// 
        /// An awaitable task
        public Task DownloadAsync()
        {
            return Task.Run(() =>
            {
                DownLoad();
            });
        }

        /// 
        /// Gets the Photo of the day in a WPF complaint ImageSource
        /// 
        public ImageSource WPFPhotoOfTheDay
        {
            get
            {
                if (!_loadcalled)
                   throw new InvalidOperationException("Call the DownLoad() method first");
                return new BitmapImage(new Uri(_tempfilename));
            }
        }
        /// 
        /// Gets the Photo of the day in a Windows Forms complaint ImageSource
        /// 
        public Bitmap WFPhotoOfTheDay
        {
            get
            {
                if (!_loadcalled)
                    throw new InvalidOperationException("Call the DownLoad() method first");
                return new Bitmap(_tempfilename);
            }
        }

        /// 
        /// CoppyRight data information
        /// 
        public string CoppyRightData
        {
            get;
            private set;
        }
    }
}

Espero que os haya gustado este artículo y, como digo siempre, sepáis implementarlo en vuestro futuros proyectos. ¿Y a ti? ¿Te gusta esa característica de Bing? Indícanoslo en los comentarios...

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP