Inicio > Aplicación, Delphi, Threads > Obtener información de una canción

Obtener información de una canción

Share Button

images (2)El tema de esta entrada ha surgido a partir de la necesidad de obtener esta información de una canción, para un programa  que en breve os presentaré en otra entrada del blog.
Esta parte no tiene que ver directamente con el tema de esa entrada, pero sí me ha parecido interesante y tal vez útil para otras personas, así que me he decidido a publicar estas líneas al respecto, ya que en la otra no tiene cabida.

El problema es sencillo; A partir de los datos básicos de un tema musical (título y/o artista) necesito obtener algo de información de esa canción. En mi caso me interesaba el título del álbum y una caratula (aunque se puede obtener más).

Hay varios servicios en Internet que os ofrecen la posibilidad de acceder a esta información.

http://www.lastfm.es/api

http://www.freecovers.net/api/

https://www.apple.com/itunes/affiliates/resources/documentation/itunes-store-web-service-search-api.html

images (3) En esta ocasión me he decantado por iTunes, por la facilidad de uso y porque no hace falta registrarse. Hay algunos otros cuya utilización es gratuita, pero requieren un registro y el uso de una APIKey. En este caso, por simple sencillez, me he decantado por este. Además, ya me ofrece (con creces) los datos que para este ejemplo estaba buscando.

En esta página podeís acceder a la información de la API para realizar búsquedas en iTunes.

Como podéis ver es bastante sencilla de utilizar.

Para el ejemplo utilizaremos, el parámetro de búsqueda term y un número de resultados limit, aunque hay más como podéis ver en la documentación.

Una vez realizamos la llamada, al webservice, la respuesta la obtenemos en formato JSON.

Por ejemplo, para una llamada como esta:

https://itunes.apple.com/search?term=Alex+Ubago+gaviotas&limit=2

Obtendremos usa respuesta como esta:

{
“resultCount”: 1,
“results”: [
{
“wrapperType”: “track”,
“kind”: “song”,
“artistId”: 496159,
“collectionId”: 101175279,
“trackId”: 101174058,
“artistName”: “Alex Ubago”,
“collectionName”: “Cien Gaviotas Dónde Irán – Un Tributo a Duncan Dhu”,
“trackName”: “Esos Ojos Negros”,
“collectionCensoredName”: “Cien Gaviotas Dónde Irán – Un Tributo a Duncan Dhu”,
“trackCensoredName”: “Esos Ojos Negros”,
“collectionArtistId”: 36270,
“collectionArtistName”: “Various Artists”,
“artistViewUrl”: “
https://itunes.apple.com/us/artist/alex-ubago/id496159?uo=4″,
“collectionViewUrl”: “
https://itunes.apple.com/us/album/esos-ojos-negros/id101175279?i=101174058&uo=4″,
“trackViewUrl”: “
https://itunes.apple.com/us/album/esos-ojos-negros/id101175279?i=101174058&uo=4″,
“previewUrl”: “
http://a1292.phobos.apple.com/us/r1000/074/Music/e4/1e/fd/mzm.pzsyztgl.aac.p.m4a”,
“artworkUrl30”: “
http://a1.mzstatic.com/us/r30/Music/8b/a2/d8/mzi.nrwneagp.30×30-50.jpg”,
“artworkUrl60”: “
http://a5.mzstatic.com/us/r30/Music/8b/a2/d8/mzi.nrwneagp.60×60-50.jpg”,
“artworkUrl100”: “
http://a5.mzstatic.com/us/r30/Music/8b/a2/d8/mzi.nrwneagp.100×100-75.jpg”,
“collectionPrice”: 12.99,
“trackPrice”: 0.99,
“releaseDate”: “2005-10-03T07:00:00Z”,
“collectionExplicitness”: “notExplicit”,
“trackExplicitness”: “notExplicit”,
“discCount”: 1,
“discNumber”: 1,
“trackCount”: 17,
“trackNumber”: 3,
“trackTimeMillis”: 230267,
“country”: “USA”,
“currency”: “USD”,
“primaryGenreName”: “Latin”,
“radioStationUrl”: “
https://itunes.apple.com/station/idra.101174058″
    }
]
}

En este caso nos devuelve un único resultado (he realizado la búsqueda expresamente para que sólo devuelva 1), pero si hubiera más, dado que hemos añadido el parámetro limit=2, obtendríamos sólo los 2 primeros.

Vemos además que en la respuesta, el primer ítem nos devuelve el número de elementos que llegan en el resultado. A partir de ahí es fácil realizar el “parse” de la respuesta.

json1En el ejemplo que os adjunto más abajo he utilizado para hacerlo la librería LkJSON de Leonid Koninin, que podéis encontrar en SourceForge, para extraer los datos y que ya había utilizado en alguna entrada anterior. Si estáis utilizando una de las versiones nuevas de Delphi, sabéis que ya incluyen librería para JSON, incluso podéis obtener la respuesta y utilizar directamente componentes como TRESTResponse y TRESTResponseAdapter.

Con un código como el que veis a continuación podemos obtener la lista de elementos que nos devuelve la web y almacenarlos en un array; De forma similar podríamos utilizar un TDataSet (derivado).

0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
TInfoTrack = record
  ArtistName:string;
  CollectionName:string;
  TrackName:string;
  Imagen100:string;
  Genero:string;
  Anyo:Integer;
  PathImage:string;
end;
 
TInfoTrackArray = array of TInfoTrack;
 
….
 
var
  obj:TlkJSONobject;
   objData:TlkJSONobject;
  objRes:TlkJSONlist;
  i:integer;
  str:string;
begin
  // Conseguir la cadena formateada.
  obj := TlkJSONobject.Create();
  // proteccion
  try
    // Parse
    TlkJSONBase(obj) := TlkJSON.ParseText(FResponse.Text);
    // Objeto results?
    if (obj.IndexOfName('results') <> -1) then begin
      // lista de resultados
      TlkJSONBase(objRes) := obj.Field['results'];
      // array de productos
      SetLength(FInfoArray, objRes.Count);
      // Recorrer la lista de productos.
      for i := 0 to (objRes.Count - 1) do begin
        // Datos del producto
        TlkJSONBase(objData) := objRes.Child[i];
        // Obtener datos
        FInfoArray[i].ArtistName := objData.Field['artistName'].Value;
        FInfoArray[i].CollectionName := objData.Field['collectionName'].Value;
        FInfoArray[i].TrackName := objData.Field['trackName'].Value;
        FInfoArray[i].Imagen100 := objData.Field['artworkUrl100'].Value;
        FInfoArray[i].Genero := objData.Field['primaryGenreName'].Value;
        Str := objData.Field['releaseDate'].Value;
        Str := Copy(Str, 1, 4);
        FInfoArray[i].Anyo := StrToIntDef(Str, 0);
      end;
    end;
  finally
    FreeAndNil(obj);
  end;
end;

 

Para hacer la llamada utilizamos los componentes de las Indy como es habitual, aunque en este caso, dado que al servidor se accede mediante el protocolo https, debemos utilizar las librerías necesarias para SSL (Secure Socket Layer) que podéis descargar desde aquí. Tened en cuenta que hay versiones diferentes para 32 y 64 bits.

0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// ini
IdHTTP.ReadTimeout := 30000;
IdSSL :=TIdSSLIOHandlerSocket.Create(nil);
 
IdHTTP.IOHandler := IdSSL;
IdSSL.SSLOptions.Method := sslvTLSv1;
IdSSL.SSLOptions.Mode := sslmUnassigned;
idHTTP.HandleRedirects := True;
 
// Montamos la cadena a solicitar
s := AnsiReplaceText(FArtista, ' ', '+') +
'+' +
AnsiReplaceText(FTitulo, ' ', '+');
s := Format(INI_URL, [s, FNumResults]);
 
// Proteccion para solicitar datos
try
// Obtener resultado
idHTTP.Get(s, ms);

images (4) Todo ello lo he encapsulado en una clase que utiliza threads para hacer la llamada; Según los parámetros de Artista, Título de la canción y número máximo de resultados, obtendrás los datos de la petición y descarga una de las carátulas (100×100) que nos da la respuesta.

 

La clase tiene la siguiente definición:

 

0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//: Thread para obtener info. de una canción
TInfoTrackThread = class(TThread)
  private
  FArtista: string;
  FTitulo: string;
  FResponse: TStrings;
  FInfoArray: TInfoTrackArray;
  FNumResults: integer;
  FID: Integer;
  // Realiza el Parse de la resouesta
  procedure ParseResponseIndo(TS:TStrings);
  // descarga la carátula
  procedure DownloadImage(URLImage, ImageName:string; var imgPath:string);
public
  // Interno
  property ID:Integer read FID write FID;
  // artista que utilizamos para la búsqueda
  property Artista:string read FArtista;
  // Título que utilizamos para la búsqueda
  property Titulo:string read FTitulo;
  // Numero de resultados (máximo)
  property NumResults:integer read FNumResults write FNumResults;
  // La respuesta en formato JSON
  property Response:TStrings read FResponse write FResponse;
  // Array de resultados
  property InfoArray:TInfoTrackArray read FInfoArray write FInfoArray;
  // redefinir métodos de la clase base
  procedure Execute; override;
  constructor Create(ID:Integer; AArtista, ATitulo:string);
  destructor Destroy; override;
end;

Un ejemplo de la llamada podría ser este:

0
1
2
3
4
5
6
7
8
9
10
11
12
13
var
  th:TInfoTrackThread;
begin
 
...
 
  // Crear el thread de búsqueda
  th := TInfoTrackThread.Create(edtArtista.Text, edtCancion.Text);
  th.NumResults := edtNumResults.Value;
  // ini
  th.FreeOnTerminate := True;
  th.OnTerminate := TerminateSearch;
  // ejecutar
  th.Resume;

Una vez finalizada la ejecución podemos acceder a los datos recorriendo el array que nos devuelve el thread con tantos elementos como ítems llegan en la respuesta.

Utilizando esta clase he creado un ejemplo sencillo, que a partir del título y/o el artista os descarga un número de resultados coincidentes con estos términos. El propio thread descarga los datos y la carátula (una de ellas). Aquí podéis ver una pequeña secuencia de cómo funciona…

Secuencia2

La unit que implementa el thread, podéis descargarla desde aquí.

Y el proyecto de ejemplo que la utiliza, podéis descargarlo en los siguientes links.

<CÓDIGO FUENTE DEL PROYECTO>

<EJECUTABLE DEL PROYECTO>

Un saludo y hasta la próxima.

Share Button
Categories: Aplicación, Delphi, Threads Tags: , , ,
  1. Gonzalo
    Domingo, 21 de Septiembre de 2014 a las 15:44 | #1

    Hola! Como puedo instalar las JSON? Gracias

  2. Neftalí
    Domingo, 21 de Septiembre de 2014 a las 18:53 | #2

    @Gonzalo
    Hola Gonzalo.
    Hay varias librerías para tratar JSON y cada una de ellas tendrá una instalación diferente.
    Yo a menudo utilizo lkJSON que no requiere instalación, pues es una unit independiente, no un componente.

  1. Sin trackbacks aún.
What is 8 + 25 ?
Please leave these two fields as-is:
IMPORTANTE! Para continuar, debes contestar la pregunta anterior (para evitar SPAM) :-)