Add libechonest into 3rdparty, and add a basic echonest artist info fetcher.

This commit is contained in:
David Sansome 2010-10-02 16:23:33 +00:00
parent 7f3e91226c
commit d035b1abc2
78 changed files with 6287 additions and 12 deletions

545
3rdparty/libechonest/Artist.cpp vendored Normal file
View File

@ -0,0 +1,545 @@
/****************************************************************************************
* Copyright (c) 2010 Leo Franchi <lfranchi@kde.org> *
* *
* This program is free software; you can redistribute it and/or modify it under *
* the terms of the GNU General Public License as published by the Free Software *
* Foundation; either version 2 of the License, or (at your option) any later *
* version. *
* *
* This program is distributed in the hope that it will be useful, but WITHOUT ANY *
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A *
* PARTICULAR PURPOSE. See the GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License along with *
* this program. If not, see <http://www.gnu.org/licenses/>. *
****************************************************************************************/
#include "Artist.h"
#include "Artist_p.h"
#include "ArtistTypes.h"
#include "Parsing_p.h"
Echonest::Artist::Artist()
: d( new ArtistData )
{
}
Echonest::Artist::Artist( const QByteArray& id, const QString& name )
: d( new ArtistData )
{
d->id = id;
d->name = name;
}
Echonest::Artist::Artist(const Echonest::Artist& other)
: d( other.d )
{}
Echonest::Artist& Echonest::Artist::operator=(const Echonest::Artist& artist)
{
d = artist.d;
return *this;
}
Echonest::Artist::~Artist()
{
}
QByteArray Echonest::Artist::id() const
{
return d->id;
}
QString Echonest::Artist::name() const
{
return d->name;
}
void Echonest::Artist::setId(const QByteArray& id)
{
d->id = id;
}
void Echonest::Artist::setName(const QString& name)
{
d->name = name;
}
Echonest::AudioList Echonest::Artist::audio() const
{
return d->audio;
}
void Echonest::Artist::setAudio(const Echonest::AudioList& audio)
{
d->audio = audio;
}
Echonest::BiographyList Echonest::Artist::biographies() const
{
return d->biographies;
}
void Echonest::Artist::setBiographies(const Echonest::BiographyList& bios )
{
d->biographies = bios;
}
Echonest::BlogList Echonest::Artist::blogs() const
{
return d->blogs;
}
void Echonest::Artist::setBlogs(const Echonest::BlogList& blogs )
{
d->blogs = blogs;
}
qreal Echonest::Artist::familiarity() const
{
return d->familiarity;
}
void Echonest::Artist::setFamiliarity(qreal familiar)
{
d->familiarity = familiar;
}
qreal Echonest::Artist::hotttnesss() const
{
return d->hotttnesss;
}
void Echonest::Artist::setHotttnesss(qreal hotttnesss)
{
d->hotttnesss = hotttnesss;
}
Echonest::ArtistImageList Echonest::Artist::images() const
{
return d->images;
}
void Echonest::Artist::setImages(const Echonest::ArtistImageList& imgs)
{
d->images = imgs;
}
Echonest::NewsList Echonest::Artist::news() const
{
return d->news;
}
void Echonest::Artist::setNews(const Echonest::NewsList& news)
{
d->news = news;
}
Echonest::ReviewList Echonest::Artist::reviews() const
{
return d->reviews;
}
void Echonest::Artist::setReviews(const Echonest::ReviewList& reviews)
{
d->reviews = reviews;
}
Echonest::SongList Echonest::Artist::songs() const
{
return d->songs;
}
void Echonest::Artist::setSongs(const Echonest::SongList& songs)
{
d->songs = songs;
}
Echonest::TermList Echonest::Artist::terms() const
{
return d->terms;
}
void Echonest::Artist::setTerms(const Echonest::TermList& terms)
{
d->terms = terms;
}
QUrl Echonest::Artist::amazonUrl() const
{
return d->amazon_url;
}
void Echonest::Artist::setVideos(const Echonest::VideoList& videos)
{
d->videos = videos;
}
void Echonest::Artist::setAmazonUrl(const QUrl& url)
{
d->amazon_url = url;
}
QUrl Echonest::Artist::aolMusicUrl() const
{
return d->aolmusic_url;
}
void Echonest::Artist::setAolMusicUrl(const QUrl& url)
{
d->aolmusic_url = url;
}
QUrl Echonest::Artist::itunesUrl() const
{
return d->itunes_url;
}
void Echonest::Artist::setItunesUrl( const QUrl& url )
{
d->itunes_url = url;
}
QUrl Echonest::Artist::lastFmUrl() const
{
return d->lastfm_url;
}
void Echonest::Artist::setLastFmUrl(const QUrl& url )
{
d->lastfm_url = url;
}
QUrl Echonest::Artist::myspaceUrl() const
{
return d->myspace_url;
}
void Echonest::Artist::setMyspaceUrl( const QUrl& url )
{
d->myspace_url = url;
}
QUrl Echonest::Artist::musicbrainzUrl() const
{
return d->mb_url;
}
void Echonest::Artist::setMusicbrainzUrl(const QUrl& url)
{
d->mb_url = url;
}
Echonest::VideoList Echonest::Artist::videos() const
{
return d->videos;
}
QNetworkReply* Echonest::Artist::fetchAudio(int numResults, int offset) const
{
QUrl url = setupQuery( "audio", numResults, offset );
return Echonest::Config::instance()->nam()->get( QNetworkRequest( url ) );
}
QNetworkReply* Echonest::Artist::fetchBiographies(const QString& license, int numResults, int offset) const
{
QUrl url = setupQuery( "biographies", numResults, offset );
if( !license.isEmpty() )
url.addQueryItem( QLatin1String( "license" ), license );
return Echonest::Config::instance()->nam()->get( QNetworkRequest( url ) );
}
QNetworkReply* Echonest::Artist::fetchBlogs( bool highRelevanceOnly, int numResults, int offset ) const
{
QUrl url = setupQuery( "blogs", numResults, offset );
if( highRelevanceOnly ) // false is default
url.addEncodedQueryItem( "high_relevance", "true" );
return Echonest::Config::instance()->nam()->get( QNetworkRequest( url ) );
}
QNetworkReply* Echonest::Artist::fetchFamiliarity() const
{
QUrl url = setupQuery( "familiarity", 0, -1 );
return Echonest::Config::instance()->nam()->get( QNetworkRequest( url ) );
}
QNetworkReply* Echonest::Artist::fetchHotttnesss(const QString& type) const
{
QUrl url = setupQuery( "hotttnesss", 0, -1 );
if( type != QLatin1String( "normal" ) )
url.addQueryItem( QLatin1String( "type" ), type );
return Echonest::Config::instance()->nam()->get( QNetworkRequest( url ) );
}
QNetworkReply* Echonest::Artist::fetchImages( const QString& license, int numResults, int offset ) const
{
QUrl url = setupQuery( "images", numResults, offset );
if( !license.isEmpty() )
url.addQueryItem( QLatin1String( "license" ), license );
return Echonest::Config::instance()->nam()->get( QNetworkRequest( url ) );
}
QNetworkReply* Echonest::Artist::fetchProfile(Echonest::Artist::ArtistInformation information) const
{
QUrl url = setupQuery( "profile", 0, -1 );
addQueryInformation( url, information );
return Echonest::Config::instance()->nam()->get( QNetworkRequest( url ) );
}
QNetworkReply* Echonest::Artist::fetchNews( bool highRelevanceOnly, int numResults, int offset ) const
{
QUrl url = setupQuery( "news", numResults, offset );
if( highRelevanceOnly ) // false is default
url.addEncodedQueryItem( "high_relevance", "true" );
return Echonest::Config::instance()->nam()->get( QNetworkRequest( url ) );
}
QNetworkReply* Echonest::Artist::fetchReviews(int numResults, int offset) const
{
QUrl url = setupQuery( "reviews", numResults, offset );
return Echonest::Config::instance()->nam()->get( QNetworkRequest( url ) );
}
QNetworkReply* Echonest::Artist::fetchSimilar(const Echonest::Artist::SearchParams& params, Echonest::Artist::ArtistInformation information, int numResults, int offset )
{
QUrl url = Echonest::baseGetQuery( "artist", "similar" );
addQueryInformation( url, information );
if( numResults > 0 )
url.addEncodedQueryItem( "results", QByteArray::number( numResults ) );
if( offset >= 0 )
url.addEncodedQueryItem( "start", QByteArray::number( offset ) );
Echonest::Artist::SearchParams::const_iterator iter = params.constBegin();
for( ; iter < params.constEnd(); ++iter )
url.addQueryItem( QLatin1String( searchParamToString( iter->first ) ), iter->second.toString().replace( QLatin1Char( ' ' ), QLatin1Char( '+' ) ) );
return Echonest::Config::instance()->nam()->get( QNetworkRequest( url ) );
}
QNetworkReply* Echonest::Artist::fetchSongs( Echonest::Artist::ArtistInformation idspace, bool limitToIdSpace, int numResults, int offset ) const
{
QUrl url = setupQuery( "songs", numResults, offset );
addQueryInformation( url, idspace );
if( limitToIdSpace )
url.addEncodedQueryItem( "limit", "true" );
return Echonest::Config::instance()->nam()->get( QNetworkRequest( url ) );
}
QNetworkReply* Echonest::Artist::fetchTerms( Echonest::Artist::TermSorting sorting ) const
{
QUrl url = setupQuery( "terms", 0, -1 );
if( sorting == Echonest::Artist::Weight )
url.addEncodedQueryItem( "sort", "weight" );
else if( sorting == Echonest::Artist::Frequency )
url.addEncodedQueryItem( "sort", "frequency" );
return Echonest::Config::instance()->nam()->get( QNetworkRequest( url ) );
}
QNetworkReply* Echonest::Artist::fetchUrls() const
{
QUrl url = setupQuery( "urls", 0, -1 );
return Echonest::Config::instance()->nam()->get( QNetworkRequest( url ) );
}
QNetworkReply* Echonest::Artist::fetchVideo(int numResults, int offset) const
{
QUrl url = setupQuery( "video", numResults, offset );
return Echonest::Config::instance()->nam()->get( QNetworkRequest( url ) );
}
QNetworkReply* Echonest::Artist::search(const Echonest::Artist::SearchParams& params, Echonest::Artist::ArtistInformation information, bool limit)
{
QUrl url = Echonest::baseGetQuery( "artist", "search" );
Echonest::Artist::SearchParams::const_iterator iter = params.constBegin();
for( ; iter < params.constEnd(); ++iter )
url.addQueryItem( QLatin1String( searchParamToString( iter->first ) ), iter->second.toString().replace( QLatin1Char( ' ' ), QLatin1Char( '+' ) ) );
url.addEncodedQueryItem( "limit", limit ? "true" : "false" );
addQueryInformation( url, information );
return Echonest::Config::instance()->nam()->get( QNetworkRequest( url ) );
}
QNetworkReply* Echonest::Artist::topHottt(Echonest::Artist::ArtistInformation information, int numResults, int offset, bool limit)
{
QUrl url = Echonest::baseGetQuery( "artist", "top_hottt" );
addQueryInformation( url, information );
if( numResults > 0 )
url.addEncodedQueryItem( "results", QByteArray::number( numResults ) );
if( offset >= 0 )
url.addEncodedQueryItem( "start", QByteArray::number( offset ) );
url.addEncodedQueryItem( "limit", limit ? "true" : "false" );
return Echonest::Config::instance()->nam()->get( QNetworkRequest( url ) );
}
QNetworkReply* Echonest::Artist::topTerms(int numResults)
{
QUrl url = Echonest::baseGetQuery( "artist", "top_terms" );
url.addEncodedQueryItem( "results", QByteArray::number( numResults ) );
return Echonest::Config::instance()->nam()->get( QNetworkRequest( url ) );
}
int Echonest::Artist::parseProfile( QNetworkReply* reply ) throw( Echonest::ParseError )
{
Echonest::Parser::checkForErrors( reply );
QXmlStreamReader xml( reply->readAll() );
Echonest::Parser::readStatus( xml );
int numResults = Echonest::Parser::parseArtistInfoOrProfile( xml, *this );
return numResults;
}
Echonest::Artists Echonest::Artist::parseSearch( QNetworkReply* reply ) throw( Echonest::ParseError )
{
Echonest::Parser::checkForErrors( reply );
QXmlStreamReader xml( reply->readAll() );
Echonest::Parser::readStatus( xml );
Echonest::Artists artists = Echonest::Parser::parseArtists( xml );
return artists;
}
Echonest::Artists Echonest::Artist::parseSimilar( QNetworkReply* reply ) throw( Echonest::ParseError )
{
return parseSearch( reply );
}
Echonest::Artists Echonest::Artist::parseTopHottt( QNetworkReply* reply ) throw( Echonest::ParseError )
{
return parseSearch( reply );
}
Echonest::TermList Echonest::Artist::parseTopTerms( QNetworkReply* reply ) throw( Echonest::ParseError )
{
Echonest::Parser::checkForErrors( reply );
QXmlStreamReader xml( reply->readAll() );
Echonest::Parser::readStatus( xml );
Echonest::TermList terms = Echonest::Parser::parseTermList( xml );
return terms;
}
QUrl Echonest::Artist::setupQuery( const QByteArray& methodName, int numResults, int start ) const
{
QUrl url = Echonest::baseGetQuery( "artist", methodName );
if( !d->id.isEmpty() )
url.addEncodedQueryItem( "id", d->id );
else if( !d->name.isEmpty() ) {
QString name = d->name;
name.replace( QLatin1Char( ' ' ), QLatin1Char( '+' ) );
url.addQueryItem( QLatin1String( "name" ), name );
} else {
qWarning() << "Artist method" << methodName << "called on an artist object without name or id!";
return QUrl();
}
if( numResults > 0 )
url.addEncodedQueryItem( "results", QByteArray::number( numResults ) );
if( start >= 0 )
url.addEncodedQueryItem( "start", QByteArray::number( start ) );
return url;
}
QByteArray Echonest::Artist::searchParamToString(Echonest::Artist::SearchParam param)
{
switch( param )
{
case Id:
return "id";
case Name:
return "name";
case Results:
return "results";
case Description:
return "description";
case FuzzyMatch:
return "fuzzy_match";
case MaxFamiliarity:
return "max_familiarity";
case MinFamiliarity:
return "min_familiarity";
case MaxHotttnesss:
return "max_hotttnesss";
case MinHotttnesss:
return "min_hotttnesss";
case Reverse:
return "reverse";
case Sort:
return "sort";
default:
return "";
}
}
void Echonest::Artist::addQueryInformation(QUrl& url, Echonest::Artist::ArtistInformation parts)
{
if( parts.testFlag( Echonest::Artist::Audio ) )
url.addEncodedQueryItem( "bucket", "audio" );
if( parts.testFlag( Echonest::Artist::Biographies ) )
url.addEncodedQueryItem( "bucket", "biographies" );
if( parts.testFlag( Echonest::Artist::Blogs ) )
url.addEncodedQueryItem( "bucket", "blogs" );
if( parts.testFlag( Echonest::Artist::Familiarity ) )
url.addEncodedQueryItem( "bucket", "familiarity" );
if( parts.testFlag( Echonest::Artist::Hotttnesss ) )
url.addEncodedQueryItem( "bucket", "hotttnesss" );
if( parts.testFlag( Echonest::Artist::Images ) )
url.addEncodedQueryItem( "bucket", "images" );
if( parts.testFlag( Echonest::Artist::News ) )
url.addEncodedQueryItem( "bucket", "news" );
if( parts.testFlag( Echonest::Artist::Reviews ) )
url.addEncodedQueryItem( "bucket", "reviews" );
if( parts.testFlag( Echonest::Artist::Terms ) )
url.addEncodedQueryItem( "bucket", "terms" );
if( parts.testFlag( Echonest::Artist::Urls ) )
url.addEncodedQueryItem( "bucket", "urls" );
if( parts.testFlag( Echonest::Artist::Videos ) )
url.addEncodedQueryItem( "bucket", "video" );
if( parts.testFlag( Echonest::Artist::MusicBrainzEntries ) )
url.addEncodedQueryItem( "bucket", "id:musicbrainz" );
if( parts.testFlag( Echonest::Artist::SevenDigitalEntries ) )
url.addEncodedQueryItem( "bucket", "id:7digital" );
if( parts.testFlag( Echonest::Artist::PlaymeEntries ) )
url.addEncodedQueryItem( "bucket", "id:playme" );
}
QDebug Echonest::operator<<(QDebug d, const Echonest::Artist& artist)
{
return d.maybeSpace() << QString::fromLatin1( "Artist(%1, %2)" ).arg( artist.name() ).arg( QString::fromLatin1(artist.id()) );
}

370
3rdparty/libechonest/Artist.h vendored Normal file
View File

@ -0,0 +1,370 @@
/****************************************************************************************
* Copyright (c) 2010 Leo Franchi <lfranchi@kde.org> *
* *
* This program is free software; you can redistribute it and/or modify it under *
* the terms of the GNU General Public License as published by the Free Software *
* Foundation; either version 2 of the License, or (at your option) any later *
* version. *
* *
* This program is distributed in the hope that it will be useful, but WITHOUT ANY *
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A *
* PARTICULAR PURPOSE. See the GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License along with *
* this program. If not, see <http://www.gnu.org/licenses/>. *
****************************************************************************************/
#ifndef ECHONEST_ARTIST_H
#define ECHONEST_ARTIST_H
#include "echonest_export.h"
#include <QDebug>
#include <QSharedData>
#include <QUrl>
#include "Config.h"
#include "ArtistTypes.h"
#include "Song.h"
class QNetworkReply;
class ArtistData;
class Term;
namespace Echonest{
class Biography;
class Artist;
typedef QVector< Artist > Artists;
/**
* This encapsulates an Echo Nest artist---it always holds the basic info of artist id and
* artist name, and can be queried for more data.
*
* It is also possible to fetch more information from a given artist name or ID by creating an Artist
* object yourself and calling the fetch() functions directly.
*/
class ECHONEST_EXPORT Artist
{
public:
enum ArtistInformationFlag {
NoInformation = 0x0000,
Audio = 0x0001,
Biographies = 0x0002,
Blogs = 0x0004,
Familiarity = 0x0008,
Hotttnesss = 0x0010,
Images = 0x0020,
News = 0x0040,
Reviews = 0x0080,
Terms = 0x0100,
Urls = 0x200,
Videos = 0x0400,
MusicBrainzEntries = 0x0800,
SevenDigitalEntries = 0x1000,
PlaymeEntries = 0x2000
};
Q_DECLARE_FLAGS( ArtistInformation, ArtistInformationFlag )
enum TermSorting {
Weight,
Frequency
} ;
/**
* The following are the various search parameters to the search() and similar() functions.
*
* Not all are acceptable for each API call, check the API documentation at
* http://developer.echonest.com/docs/v4/artist.html#search for details.
*
* - id QVector< QByteArray > A list of the artist IDs to be searched (e.g. [ARH6W4X1187B99274F, musicbrainz:artist:a74b1b7f-71a5-4011-9441-d0b5e4122711 ,ARH6W4X1187B99274F^2])
* - name QVector< QString > A list of artist names to be searched (e.g. [Weezer, the beatles ,the beatles^0.5])
* - description QVector< QString > A list of descriptors [ alt-rock,-emo,harp^2 ]
* - results 0 < results < 200, (Default=15) The number of results desired
* - min_results 0 < results < 200, (Default=0) Indicates the minimum number of results to be returned regardless of constraints
* - max_familiarity 0.0 < familiarity < 1.0 The maximum familiarity for returned artists
* - min_familiarity 0.0 < familiarity < 1.0 The minimum familiarity for returned artists
* - max_hotttnesss 0.0 < hotttnesss < 1.0 The maximum hotttnesss for returned artists
* - min_hotttness 0.0 < hotttnesss < 1.0 The minimum hotttnesss for returned artists
* - reverse [true, false] If true, return artists that are disimilar to the seeds
* -sort QString How to sort the results. Options: familiarity-asc, hotttnesss-asc, familiarity-desc, hotttnesss-desc.
*/
enum SearchParam {
Id,
Name,
Results,
Description,
FuzzyMatch,
MaxFamiliarity,
MinFamiliarity,
MaxHotttnesss,
MinHotttnesss,
Reverse,
Sort
};
typedef QPair< Echonest::Artist::SearchParam, QVariant > SearchParamEntry;
typedef QVector< SearchParamEntry > SearchParams;
Artist();
Artist( const QByteArray& id, const QString& name );
Artist( const Artist& other );
Artist& operator=( const Artist& artist );
~Artist();
QByteArray id() const;
void setId( const QByteArray& id );
QString name() const;
void setName( const QString& name );
/**
* The following require fetching from The Echo Nest, so return a QNetworkReply*
* that is ready for parsing when the finished() signal is emitted.
*
* Call parseProfile() on the Artist object to populate it with the result of the
* query.
*
*/
/**
* A list of audio files on the web for this artist.
*/
AudioList audio() const;
void setAudio( const AudioList& );
/**
* A list of biographies for this artist.
*/
BiographyList biographies() const;
void setBiographies( const BiographyList& );
/**
* Blogs about this artist, around the web.
*/
BlogList blogs() const;
void setBlogs( const BlogList& );
/**
* How familiar this artist is.
*/
qreal familiarity() const;
void setFamiliarity( qreal familiar );
/**
* The hotttness of this artist.
*/
qreal hotttnesss() const;
void setHotttnesss( qreal hotttnesss );
/**
* Images related to this artist.
*/
ArtistImageList images() const;
void setImages( const ArtistImageList& );
/**
* News about this artist.
*/
NewsList news() const;
void setNews( const NewsList& );
/**
* Reviews of this artist
*/
ReviewList reviews() const;
void setReviews( const ReviewList& );
/**
* Echo Nest song objects belonging to this artist.
*/
SongList songs() const;
void setSongs( const SongList& );
/**
* Terms describing this artist.
*/
TermList terms() const;
void setTerms( const TermList& );
/**
* Urls pointing to this artists' basic information around the web.
*/
QUrl lastFmUrl() const;
void setLastFmUrl( const QUrl& );
QUrl aolMusicUrl() const;
void setAolMusicUrl( const QUrl& );
QUrl amazonUrl() const;
void setAmazonUrl( const QUrl& );
QUrl itunesUrl() const;
void setItunesUrl( const QUrl& );
QUrl myspaceUrl() const;
void setMyspaceUrl( const QUrl& );
QUrl musicbrainzUrl() const;
void setMusicbrainzUrl( const QUrl& url );
/**
* Videos related to this artist.
*/
VideoList videos() const;
void setVideos( const VideoList& );
/**
* Fetch a list of audio documents found on the web that are related to this artist.
*
* @param numResults Limit how many results are returned
* @param offset The offset of the results, if paging through results in increments.
*/
QNetworkReply* fetchAudio( int numResults = 0, int offset = -1 ) const;
/**
* Fetch a list of biographies for this artist from various places on the web.
*/
QNetworkReply* fetchBiographies( const QString& license = QString(), int numResults = 0, int offset = -1 ) const;
/**
* Fetch a list of blog articles relating to this artist.
*/
QNetworkReply* fetchBlogs( bool highRelevanceOnly = false, int numResults = 0, int offset = -1 ) const;
/**
* Fetch The Echo Nest's numerical estimate of how familiar this artist is to the world.
*/
QNetworkReply* fetchFamiliarity() const;
/**
* Fetch the numerical description of how hot this artist is.
*
* Currently the only supported type is 'normal'
*/
QNetworkReply* fetchHotttnesss( const QString& type = QLatin1String( "normal" ) ) const;
/**
* Fetch a list of images related to this artist.
*/
QNetworkReply* fetchImages( const QString& license = QString(), int numResults = 0, int offset = -1 ) const;
/**
* Fetch a list of news articles found on the web related to this artist.
*/
QNetworkReply* fetchNews( bool highRelevanceOnly = false, int numResults = 0, int offset = -1 ) const;
/**
* Fetch any number of pieces of artist information all at once.
*/
QNetworkReply* fetchProfile( ArtistInformation information ) const;
/**
* Fetch reviews related to the artist.
*/
QNetworkReply* fetchReviews( int numResults = 0, int offset = -1 ) const;
/**
* Fetch a list of songs created by this artist.
*
* The idspace can be used to specify what idspace to return the results in, if none is specifed, The Echo Nest song identifiers
* are used. If limitToIdSpace is true, then only results in the requested idspace are returned.
*/
QNetworkReply* fetchSongs( ArtistInformation idspace = NoInformation, bool limitToIdSpace = false, int numResults = 0, int offset = -1 ) const;
/**
* Fetch a list of the most descriptive terms for this artist.
*/
QNetworkReply* fetchTerms( TermSorting sorting = Frequency ) const;
/**
* Fetch links to the artist's official site, MusicBrainz site, MySpace site, Wikipedia article, Amazon list, and iTunes page.
*/
QNetworkReply* fetchUrls() const;
/**
* Fetch a list of video documents found on the web related to an artist.
*/
QNetworkReply* fetchVideo( int numResults = 0, int offset = -1 ) const;
/**
* Parse a completed QNetworkReply* that has fetched more information about this artist.
* This will update the artist object with the new values that have been fetched.
*
* @return The number of results available on the server.
*/
int parseProfile( QNetworkReply* ) throw( ParseError );
/**
* Fetch a list of similar artists given one or more artists for comparison.
*
* Up to five artist names or ids can be included for the similarity search.
*
*
* So they are passed as a list of [paramname, paramvalue] to be included in the query.
*
* Boosting: This method can take multiple seed artists. You an give a seed artist more or less weight by boosting the artist. A boost is an
* affinity for a seed that gives it more or less weight when making calculations based on the argument. In case seeds are not meant to be equally
* valued, the boost can help clarify where along a spectrum each argument falls. The boost is a positive floating point value, where 1 gives the normal
* weight. It is signified by appending a caret and weight to the argument.
*
* See http://developer.echonest.com/docs/v4/artist.html#similar for boosting examples.
*
* Call parseSimilar() once the returned QNetworkReply* has emitted its finished() signal
*/
static QNetworkReply* fetchSimilar( const SearchParams& params, ArtistInformation information = NoInformation, int numResults = 0, int offset = -1 );
/**
* Search for artists.
*
* Warning: If limit is set to true, at least one idspace must also be provided.
*
* One of name or description is required, but only one can be used in a query at one time
*
*/
static QNetworkReply* search( const SearchParams& params, ArtistInformation information = NoInformation, bool limit = false );
/**
* Fetch a list of the current top artists in terms of hotttnesss.
*
* Warning If limit is set to true, at least one idspace must also be provided in the bucket parameter.
*
*/
static QNetworkReply* topHottt( ArtistInformation information = NoInformation, int numResults = 0, int offset = -1, bool limit = false );
/**
* Fetch a list of the top overall terms.
*/
static QNetworkReply* topTerms( int numResults = 15 );
/**
* Parse the result of a fetchSimilar() call, which returns a list of artists similar to the
* original pair.
*/
static Artists parseSimilar( QNetworkReply* ) throw( ParseError );
/**
* Parse the result of an artist search.
*/
static Artists parseSearch( QNetworkReply* ) throw( ParseError );
/**
* Parse the result of a top hottness query.
*/
static Artists parseTopHottt( QNetworkReply* ) throw( ParseError );
/**
* Parse the result of a top terms query.
*/
static TermList parseTopTerms( QNetworkReply* ) throw( ParseError );
private:
QUrl setupQuery( const QByteArray& methodName, int numResults = 0, int start = -1 ) const;
static QByteArray searchParamToString( SearchParam param );
static void addQueryInformation( QUrl& url, ArtistInformation parts );
QSharedDataPointer<ArtistData> d;
};
ECHONEST_EXPORT QDebug operator<<(QDebug d, const Echonest::Artist& artist);
Q_DECLARE_OPERATORS_FOR_FLAGS(Artist::ArtistInformation)
} // namespace
#endif

572
3rdparty/libechonest/ArtistTypes.cpp vendored Normal file
View File

@ -0,0 +1,572 @@
/****************************************************************************************
* Copyright (c) 2010 Leo Franchi <lfranchi@kde.org> *
* *
* This program is free software; you can redistribute it and/or modify it under *
* the terms of the GNU General Public License as published by the Free Software *
* Foundation; either version 2 of the License, or (at your option) any later *
* version. *
* *
* This program is distributed in the hope that it will be useful, but WITHOUT ANY *
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A *
* PARTICULAR PURPOSE. See the GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License along with *
* this program. If not, see <http://www.gnu.org/licenses/>. *
****************************************************************************************/
#include "ArtistTypes.h"
#include "ArtistTypes_p.h"
#include <QUrl>
#include <QDateTime>
Echonest::ArtistImage::ArtistImage() : d( new ArtistImageData )
{
}
Echonest::ArtistImage::ArtistImage(const Echonest::ArtistImage& other)
{
d = other.d;
}
Echonest::ArtistImage& Echonest::ArtistImage::operator=(const Echonest::ArtistImage& img)
{
d = img.d;
return *this;
}
Echonest::ArtistImage::~ArtistImage()
{
}
QUrl Echonest::ArtistImage::url() const
{
return d->url;
}
void Echonest::ArtistImage::setUrl(const QUrl& url)
{
d->url = url;
}
Echonest::License Echonest::ArtistImage::license() const
{
return d->license;
}
void Echonest::ArtistImage::setLicense(const Echonest::License& license)
{
d->license = license;
}
Echonest::AudioFile::AudioFile() : d( new AudioFileData )
{
}
Echonest::AudioFile::AudioFile(const Echonest::AudioFile& other)
{
d = other.d;
}
Echonest::AudioFile& Echonest::AudioFile::operator=(const Echonest::AudioFile& artist)
{
d = artist.d;
return *this;
}
Echonest::AudioFile::~AudioFile()
{
}
void Echonest::AudioFile::setTitle(const QString& title)
{
d->title = title;
}
QString Echonest::AudioFile::title() const
{
return d->title;
}
QString Echonest::AudioFile::artist() const
{
return d->artist;
}
void Echonest::AudioFile::setArtist(const QString& artist)
{
d->artist = artist;
}
QDateTime Echonest::AudioFile::date() const
{
return d->date;
}
void Echonest::AudioFile::setDate(const QDateTime& date)
{
d->date = date;
}
QString Echonest::AudioFile::release() const
{
return d->release;
}
void Echonest::AudioFile::setRelease(const QString& release)
{
d->release = release;
}
QByteArray Echonest::AudioFile::id() const
{
return d->id;
}
void Echonest::AudioFile::setId(const QByteArray& id)
{
d->id = id;
}
qreal Echonest::AudioFile::length() const
{
return d->length;
}
void Echonest::AudioFile::setLength(qreal length)
{
d->length = length;
}
QUrl Echonest::AudioFile::link() const
{
return d->link;
}
void Echonest::AudioFile::setLink(const QUrl& url)
{
d->link = url;
}
QUrl Echonest::AudioFile::url() const
{
return d->url;
}
void Echonest::AudioFile::setUrl(const QUrl& url)
{
d->url = url;
}
Echonest::Biography::Biography() : d( new BiographyData )
{
}
Echonest::Biography::Biography(const Echonest::Biography& other)
{
d = other.d;
}
Echonest::Biography& Echonest::Biography::operator=(const Echonest::Biography& biblio)
{
d = biblio.d;
return *this;
}
Echonest::Biography::~Biography()
{
}
Echonest::License Echonest::Biography::license() const
{
return d->license;
}
void Echonest::Biography::setLicense(const Echonest::License& license)
{
d->license = license;
}
QString Echonest::Biography::site() const
{
return d->site;
}
void Echonest::Biography::setSite(const QString& site)
{
d->site = site;
}
QString Echonest::Biography::text() const
{
return d->text;
}
void Echonest::Biography::setText(const QString& text)
{
d->text = text;
}
QUrl Echonest::Biography::url() const
{
return d->url;
}
void Echonest::Biography::setUrl(const QUrl& url)
{
d->url = url;
}
Echonest::Blog::Blog() : d( new BlogData )
{
}
Echonest::Blog::Blog(const Echonest::Blog& other) : d( other.d )
{
}
Echonest::Blog& Echonest::Blog::operator=(const Echonest::Blog& other)
{
d = other.d;
return *this;
}
Echonest::Blog::~Blog()
{
}
QDateTime Echonest::Blog::dateFound() const
{
return d->date_found;
}
void Echonest::Blog::setDateFound(const QDateTime& date)
{
d->date_found = date;
}
QDateTime Echonest::Blog::datePosted() const
{
return d->date_posted;
}
void Echonest::Blog::setDatePosted(const QDateTime& date)
{
d->date_posted = date;
}
QByteArray Echonest::Blog::id() const
{
return d->id;
}
void Echonest::Blog::setId(const QByteArray& id)
{
d->id = id;
}
QString Echonest::Blog::name() const
{
return d->name;
}
void Echonest::Blog::setName(const QString& name)
{
d->name = name;
}
QString Echonest::Blog::summary() const
{
return d->summary;
}
void Echonest::Blog::setSummary(const QString& text)
{
d->summary = text;
}
QUrl Echonest::Blog::url() const
{
return d->url;
}
void Echonest::Blog::setUrl(const QUrl& url)
{
d->url = url;
}
Echonest::Review::Review() : d( new ReviewData )
{
}
Echonest::Review::Review(const Echonest::Review& other) : d( other.d )
{
}
Echonest::Review& Echonest::Review::operator=(const Echonest::Review& other)
{
d = other.d;
return *this;
}
Echonest::Review::~Review()
{
}
QDateTime Echonest::Review::dateFound() const
{
return d->date_found;
}
void Echonest::Review::setDateFound(const QDateTime& date)
{
d->date_found = date;
}
QDateTime Echonest::Review::dateReviewed() const
{
return d->date_reviewed;
}
void Echonest::Review::setDateReviewed(const QDateTime& date)
{
d->date_reviewed = date;
}
QByteArray Echonest::Review::id() const
{
return d->id;
}
void Echonest::Review::setId(const QByteArray& id)
{
d->id = id;
}
QUrl Echonest::Review::imageUrl() const
{
return d->image_url;
}
void Echonest::Review::setImageUrl(const QUrl& imageUrl)
{
d->image_url = imageUrl;
}
QString Echonest::Review::name() const
{
return d->name;
}
void Echonest::Review::setName(const QString& name)
{
d->name = name;
}
QString Echonest::Review::release() const
{
return d->release;
}
void Echonest::Review::setRelease(const QString& release)
{
d->release = release;
}
QString Echonest::Review::summary() const
{
return d->summary;
}
void Echonest::Review::setSummary(const QString& text)
{
d->summary = text;
}
QUrl Echonest::Review::url() const
{
return d->url;
}
void Echonest::Review::setUrl(const QUrl& url)
{
d->url = url;
}
Echonest::Term::Term() : d( new TermData )
{
}
Echonest::Term::Term(const Echonest::Term& other) : d( other.d )
{
}
Echonest::Term& Echonest::Term::operator=(const Echonest::Term& other)
{
d = other.d;
return *this;
}
Echonest::Term::~Term()
{
}
qreal Echonest::Term::frequency() const
{
return d->frequency;
}
void Echonest::Term::setFrequency(qreal freq)
{
d->frequency = freq;
}
QString Echonest::Term::name() const
{
return d->name;
}
void Echonest::Term::setName(const QString& name)
{
d->name = name;
}
qreal Echonest::Term::weight() const
{
return d->weight;
}
void Echonest::Term::setWeight(qreal weight)
{
d->weight = weight;
}
Echonest::Video::Video() : d( new VideoData )
{
}
Echonest::Video::Video(const Echonest::Video& other) : d( other.d )
{
}
Echonest::Video& Echonest::Video::operator=(const Echonest::Video& other)
{
d = other.d;
return *this;
}
Echonest::Video::~Video()
{
}
QDateTime Echonest::Video::dateFound() const
{
return d->date_found;
}
void Echonest::Video::setDateFound(const QDateTime& date)
{
d->date_found = date;
}
QByteArray Echonest::Video::id() const
{
return d->id;
}
void Echonest::Video::setId(const QByteArray& id)
{
d->id = id;
}
QUrl Echonest::Video::imageUrl() const
{
return d->image_url;
}
void Echonest::Video::setImageUrl(const QUrl& imageUrl)
{
d->image_url = imageUrl;
}
QString Echonest::Video::site() const
{
return d->site;
}
void Echonest::Video::setSite(const QString& site)
{
d->site = site;
}
QString Echonest::Video::title() const
{
return d->title;
}
void Echonest::Video::setTitle(const QString& title)
{
d->title = title;
}
QUrl Echonest::Video::url() const
{
return d->url;
}
void Echonest::Video::setUrl(const QUrl& url)
{
d->url = url;
}
QDebug Echonest::operator<<(QDebug d, const Echonest::AudioFile& audio)
{
return d.maybeSpace() << QString::fromLatin1( "AudioFile [%1, %2, %3, %4]" ).arg( audio.title() ) .arg( audio.artist() ).arg( audio.release() ).arg( audio.url().toString() );
}
QDebug Echonest::operator<<(QDebug d, const Echonest::Biography& biblio)
{
return d.maybeSpace() << QString::fromLatin1( "Bibliography [%1, %2, %3, %4]" ).arg( biblio.site() ).arg( biblio.url().toString() ).arg( biblio.license().type ).arg( biblio.text().left( 100 ) );
}
QDebug Echonest::operator<<(QDebug d, const Echonest::Blog& blog)
{
return d.maybeSpace() << QString::fromLatin1( "Blog [%1, %2, %3, %4, %5, %6]" ).arg( blog.name() ).arg( blog.datePosted().toString() ).arg( blog.dateFound().toString() ).arg( blog.url().toString() ).arg( QLatin1String( blog.id() ) ).arg( blog.summary().left( 100 ) );
}
QDebug Echonest::operator<<(QDebug d, const Echonest::ArtistImage& img)
{
return d.maybeSpace() << QString::fromLatin1( "ArtistImage [%1, %2]" ).arg( img.url().toString() ).arg( img.license().type );
}
QDebug Echonest::operator<<(QDebug d, const Echonest::Review& review)
{
return d.maybeSpace() << QString::fromLatin1( "Review [%1, %2, %3]" ).arg( review.name() ).arg( review.release() ).arg( review.summary().left( 100 ) );
}
QDebug Echonest::operator<<(QDebug d, const Echonest::Term& term)
{
return d.maybeSpace() << QString::fromLatin1( "Term [%1, %2, %3]" ).arg( term.name() ).arg( term.frequency() ).arg( term.weight() );
}
QDebug Echonest::operator<<(QDebug d, const Echonest::Video& video)
{
return d.maybeSpace() << QString::fromLatin1( "Video [%1, %2, %3]" ).arg( video.title() ).arg( video.site() ).arg( video.url().toString() );
}

390
3rdparty/libechonest/ArtistTypes.h vendored Normal file
View File

@ -0,0 +1,390 @@
/****************************************************************************************
* Copyright (c) 2010 Leo Franchi <lfranchi@kde.org> *
* *
* This program is free software; you can redistribute it and/or modify it under *
* the terms of the GNU General Public License as published by the Free Software *
* Foundation; either version 2 of the License, or (at your option) any later *
* version. *
* *
* This program is distributed in the hope that it will be useful, but WITHOUT ANY *
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A *
* PARTICULAR PURPOSE. See the GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License along with *
* this program. If not, see <http://www.gnu.org/licenses/>. *
****************************************************************************************/
#ifndef ECHONEST_ARTISTTYPES_H
#define ECHONEST_ARTISTTYPES_H
#include "echonest_export.h"
#include "Util.h"
#include <QDebug>
#include <QSharedData>
class QDateTime;
class QUrl;
class AudioFileData;
class BiographyData;
class BlogData;
class ArtistImageData;
class ReviewData;
class TermData;
class VideoData;
namespace Echonest{
/**
* A link to an audio file related to an artist on the web.
*/
class ECHONEST_EXPORT AudioFile
{
public:
AudioFile();
AudioFile( const AudioFile& other );
AudioFile& operator=( const AudioFile& artist );
~AudioFile();
/**
* The title of the audio file.
*/
QString title() const;
void setTitle( const QString& title );
/**
* The artist name that this audio file is related to.
*/
QString artist() const;
void setArtist( const QString& );
/**
* The URL pointing to the audio file.
*/
QUrl url() const;
void setUrl( const QUrl& url );
/**
* The length of the referenced audio file.
*/
qreal length() const;
void setLength( qreal length );
/**
* The link to the website where the audio file is from.
*/
QUrl link() const;
void setLink( const QUrl& url );
/**
* The date that this audio was posted.
*/
QDateTime date() const;
void setDate( const QDateTime& );
/**
* The released album name of this audio file.
*/
QString release() const;
void setRelease( const QString& release );
/**
* The unique identifier for this artist audio file.
*/
QByteArray id() const;
void setId( const QByteArray& id );
private:
QSharedDataPointer<AudioFileData> d;
};
/**
* A biography of an artist, including the full text content
* of the biography itself.
*/
class ECHONEST_EXPORT Biography {
public:
Biography();
Biography( const Biography& other );
Biography& operator=( const Biography& biblio );
~Biography();
/**
* The URL to the biography.
*/
QUrl url() const;
void setUrl( const QUrl& url );
/**
* The text contents of the biography. May be very long.
*/
QString text() const;
void setText( const QString& text );
/**
* The site that this biography is from.
*/
QString site() const;
void setSite( const QString& site );
/**
* The license that this biography is licensed under.
*/
License license() const;
void setLicense( const License& license );
private:
QSharedDataPointer<BiographyData> d;
};
/**
* A blog post about a certain artist or track.
*/
class ECHONEST_EXPORT Blog {
public:
Blog();
Blog( const Blog& other );
Blog& operator=( const Blog& other );
~Blog();
/**
* The name of the blog or news article.
*/
QString name() const;
void setName( const QString& name );
/**
* The URL to the blog post or news article.
*/
QUrl url() const;
void setUrl( const QUrl& url );
/**
* The date when the blog post or news article was posted.
*/
QDateTime datePosted() const;
void setDatePosted( const QDateTime& date );
/**
* The date when this blog post or news article was found by The Echo Nest.
*/
QDateTime dateFound() const;
void setDateFound( const QDateTime& date );
/**
* A short summary of the blog or article.
*/
QString summary() const;
void setSummary( const QString& text );
/**
* The unique identifier for this entry.
*/
QByteArray id() const;
void setId( const QByteArray& id );
private:
QSharedDataPointer<BlogData> d;
};
/**
* A news article about an artist.
*/
typedef Blog NewsArticle;
/**
* An image related to an artist.
*/
class ECHONEST_EXPORT ArtistImage {
public:
ArtistImage();
ArtistImage( const ArtistImage& other );
ArtistImage& operator=( const ArtistImage& img );
~ArtistImage();
/**
* The image url.
*/
QUrl url() const;
void setUrl( const QUrl& url );
/**
* The license that governs this image.
*/
License license() const;
void setLicense( const License& license );
private:
QSharedDataPointer<ArtistImageData> d;
};
/**
* A review of an artist, album, or track.
*/
class ECHONEST_EXPORT Review {
public:
Review();
Review( const Review& other );
Review& operator=( const Review& other );
~Review();
/**
* The name of the review site.
*/
QString name() const;
void setName( const QString& name );
/**
* The URL to the review.
*/
QUrl url() const;
void setUrl( const QUrl& url );
/**
* The date when the review was posted.
*/
QDateTime dateReviewed() const;
void setDateReviewed( const QDateTime& date );
/**
* The date when this review was found and indexed by The Echo Nest
*/
QDateTime dateFound() const;
void setDateFound( const QDateTime& date );
/**
* A summary of the review.
*/
QString summary() const;
void setSummary( const QString& text );
/**
* The url to an image associated with the review, if it exists.
*/
QUrl imageUrl() const;
void setImageUrl( const QUrl& imageUrl );
/**
* The album being reviewed if it is an album review, including specific release info, if it exists.
*/
QString release() const;
void setRelease( const QString& release );
/**
* The unique identifier for this entry.
*/
QByteArray id() const;
void setId( const QByteArray& id );
private:
QSharedDataPointer<ReviewData> d;
};
/**
* A term used to describe an artist or track.
*/
class ECHONEST_EXPORT Term {
public:
Term();
Term( const Term& other );
Term& operator=( const Term& img );
~Term();
/**
* The term name.
*/
QString name() const;
void setName( const QString& name );
/**
* The frequency that this term is mentioned in relation to the artist/track.
*/
qreal frequency() const;
void setFrequency( qreal freq );
/**
* The weight that The Echo Nest assigns to this term.
*/
qreal weight() const;
void setWeight( qreal weight );
private:
QSharedDataPointer<TermData> d;
};
/**
* A link to a video related to an artist.
*/
class ECHONEST_EXPORT Video {
public:
Video();
Video( const Video& other );
Video& operator=( const Video& other );
~Video();
/**
* The title of the video
*/
QString title() const;
void setTitle( const QString& title );
/**
* The URL to the title.
*/
QUrl url() const;
void setUrl( const QUrl& url );
/**
* The site that the video is from.
*/
QString site() const;
void setSite( const QString& site );
/**
* The date when this video was found
*/
QDateTime dateFound() const;
void setDateFound( const QDateTime& date );
/**
* The url to an image associated with this video, if it exists.
*/
QUrl imageUrl() const;
void setImageUrl( const QUrl& imageUrl );
/**
* The unique identifier for this video.
*/
QByteArray id() const;
void setId( const QByteArray& id );
private:
QSharedDataPointer<VideoData> d;
};
ECHONEST_EXPORT QDebug operator<<(QDebug d, const Echonest::AudioFile& artist);
ECHONEST_EXPORT QDebug operator<<(QDebug d, const Echonest::Biography& biblio);
ECHONEST_EXPORT QDebug operator<<(QDebug d, const Echonest::Blog& blog);
ECHONEST_EXPORT QDebug operator<<(QDebug d, const Echonest::ArtistImage& img);
ECHONEST_EXPORT QDebug operator<<(QDebug d, const Echonest::Review& review);
ECHONEST_EXPORT QDebug operator<<(QDebug d, const Echonest::Term& term);
ECHONEST_EXPORT QDebug operator<<(QDebug d, const Echonest::Video& video);
typedef QVector< AudioFile > AudioList;
typedef QVector< Biography > BiographyList;
typedef QVector< Blog > BlogList;
typedef QVector< ArtistImage > ArtistImageList;
typedef QVector< NewsArticle > NewsList;
typedef QVector< Review > ReviewList;
typedef QVector< Term > TermList;
typedef QVector< Video > VideoList;
} // namespace
#endif

166
3rdparty/libechonest/ArtistTypes_p.h vendored Normal file
View File

@ -0,0 +1,166 @@
/****************************************************************************************
* Copyright (c) 2010 Leo Franchi <lfranchi@kde.org> *
* *
* This program is free software; you can redistribute it and/or modify it under *
* the terms of the GNU General Public License as published by the Free Software *
* Foundation; either version 2 of the License, or (at your option) any later *
* version. *
* *
* This program is distributed in the hope that it will be useful, but WITHOUT ANY *
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A *
* PARTICULAR PURPOSE. See the GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License along with *
* this program. If not, see <http://www.gnu.org/licenses/>. *
****************************************************************************************/
#ifndef ECHONEST_ARTISTTYPES_P_H
#define ECHONEST_ARTISTTYPES_P_H
#include "Util.h"
#include <QSharedData>
#include <QString>
#include <QVector>
#include <QDate>
#include <QUrl>
class AudioFileData : public QSharedData
{
public:
AudioFileData() {}
AudioFileData( const AudioFileData& other ) {
title = other.title;
artist = other.artist;
url = other.url;
length = other.length;
link = other.link;
date = other.date;
id = other.id;
release = other.release;
}
QString title;
QString artist;
QUrl url;
qreal length;
QUrl link;
QDateTime date;
QString release;
QByteArray id;
};
class BiographyData : public QSharedData
{
public:
BiographyData() {}
BiographyData( const BiographyData& other ) {
url = other.url;
text = other.text;
site = other.site;
license = other.license;
}
QUrl url;
QString text;
QString site;
Echonest::License license;
};
class BlogData : public QSharedData
{
public:
BlogData() {}
BlogData( const BlogData& other ) {
name = other.name;
url = other.url;
date_posted = other.date_posted;
date_found = other.date_found;
summary = other.summary;
id = other.id;
}
QString name;
QUrl url;
QDateTime date_posted;
QDateTime date_found;
QString summary;
QByteArray id;
};
class ArtistImageData : public QSharedData
{
public:
ArtistImageData() {}
ArtistImageData( const ArtistImageData& other ) {
url = other.url;
license = other.license;
}
QUrl url;
Echonest::License license;
};
class ReviewData : public QSharedData
{
public:
ReviewData() {}
ReviewData( const ReviewData& other ) {
name = other.name;
url = other.url;
summary = other.summary;
date_reviewed = other.date_reviewed;
date_found = other.date_found;
image_url = other.image_url;
release = other.release;
id = other.id;
}
QString name;
QUrl url;
QString summary;
QDateTime date_reviewed;
QDateTime date_found;
QUrl image_url;
QString release;
QByteArray id;
};
class TermData : public QSharedData
{
public:
TermData() {}
TermData( const TermData& other ) {
name = other.name;
frequency = other.frequency;
weight = other.weight;
}
QString name;
qreal frequency;
qreal weight;
};
class VideoData : public QSharedData
{
public:
VideoData() {}
VideoData( const VideoData& other ) {
title = other.title;
url = other.url;
site = other.site;
date_found = other.date_found;
image_url = other.image_url;
id = other.id;
}
QString title;
QUrl url;
QString site;
QDateTime date_found;
QUrl image_url;
QByteArray id;
};
#endif

71
3rdparty/libechonest/Artist_p.h vendored Normal file
View File

@ -0,0 +1,71 @@
/****************************************************************************************
* Copyright (c) 2010 Leo Franchi <lfranchi@kde.org> *
* *
* This program is free software; you can redistribute it and/or modify it under *
* the terms of the GNU General Public License as published by the Free Software *
* Foundation; either version 2 of the License, or (at your option) any later *
* version. *
* *
* This program is distributed in the hope that it will be useful, but WITHOUT ANY *
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A *
* PARTICULAR PURPOSE. See the GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License along with *
* this program. If not, see <http://www.gnu.org/licenses/>. *
****************************************************************************************/
#ifndef ECHONEST_ARTIST_P_H
#define ECHONEST_ARTIST_P_H
#include "Song.h"
#include "ArtistTypes.h"
#include <QSharedData>
#include <QString>
#include <QVector>
namespace Echonest {
class Artist;
}
class ArtistData : public QSharedData
{
public:
ArtistData() : familiarity( -1 ), hotttnesss( -1 ) {}
ArtistData( const QByteArray& id, const QString& name ) : id( id ), name( name ), familiarity( -1 ), hotttnesss( -1 ) {}
ArtistData(const ArtistData& other)
{
id = other.id;
name = other.name;
}
// The following exist in all valid Artist objects
QByteArray id;
QString name;
//The following are populated on demand, and may not exist
Echonest::AudioList audio;
Echonest::BiographyList biographies;
Echonest::BlogList blogs;
qreal familiarity;
qreal hotttnesss;
Echonest::ArtistImageList images;
Echonest::NewsList news;
Echonest::ReviewList reviews;
Echonest::SongList songs;
QVector<Echonest::Artist> similar;
Echonest::TermList terms;
Echonest::VideoList videos;
QUrl lastfm_url;
QUrl aolmusic_url;
QUrl myspace_url;
QUrl amazon_url;
QUrl itunes_url;
QUrl mb_url;
};
#endif

314
3rdparty/libechonest/AudioSummary.cpp vendored Normal file
View File

@ -0,0 +1,314 @@
/****************************************************************************************
* Copyright (c) 2010 Leo Franchi <lfranchi@kde.org> *
* *
* This program is free software; you can redistribute it and/or modify it under *
* the terms of the GNU General Public License as published by the Free Software *
* Foundation; either version 2 of the License, or (at your option) any later *
* version. *
* *
* This program is distributed in the hope that it will be useful, but WITHOUT ANY *
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A *
* PARTICULAR PURPOSE. See the GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License along with *
* this program. If not, see <http://www.gnu.org/licenses/>. *
****************************************************************************************/
#include "AudioSummary.h"
#include "AudioSummary_p.h"
#include <QNetworkReply>
#include "Config.h"
Echonest::AudioSummary::AudioSummary()
: d( new AudioSummaryData )
{
}
Echonest::AudioSummary::AudioSummary(const Echonest::AudioSummary& other)
:d( other.d )
{
}
Echonest::AudioSummary::~AudioSummary()
{}
QDebug Echonest::operator<<(QDebug d, const Echonest::AudioSummary& summary)
{
// d << summary
return d.maybeSpace();
}
Echonest::AudioSummary& Echonest::AudioSummary::operator=(const Echonest::AudioSummary& audio)
{
d = audio.d;
return *this;
}
int Echonest::AudioSummary::analysisStatus() const
{
return d->status;
}
void Echonest::AudioSummary::setAnalysisStatus(int status)
{
d->status = status;
}
qreal Echonest::AudioSummary::analysisTime() const
{
return d->analysis_time;
}
void Echonest::AudioSummary::setAnalysisTime(qreal time)
{
d->analysis_time = time;
}
QString Echonest::AudioSummary::analyzerVersion() const
{
return d->analyzer_version;
}
void Echonest::AudioSummary::setAnalyzerVersion(QString version)
{
d->analyzer_version = version;
}
Echonest::BarList Echonest::AudioSummary::bars() const
{
return d->bars;
}
void Echonest::AudioSummary::setBars(const Echonest::BarList& bars)
{
d->bars = bars;
}
Echonest::BeatList Echonest::AudioSummary::beats() const
{
return d->beats;
}
void Echonest::AudioSummary::setBeats(const Echonest::BeatList& beats)
{
d->beats = beats;
}
Echonest::Analysis::AnalysisStatus Echonest::AudioSummary::detailedStatus() const
{
return Echonest::statusToEnum( d->detailed_status );
}
void Echonest::AudioSummary::setDetailedStatus(Echonest::Analysis::AnalysisStatus status)
{
d->detailed_status = Echonest::statusToString( status );
}
qreal Echonest::AudioSummary::duration() const
{
return d->duration;
}
void Echonest::AudioSummary::setDuration(qreal duration)
{
d->duration = duration;
}
qreal Echonest::AudioSummary::endOfFadeIn() const
{
return d->end_of_fade_in;
}
void Echonest::AudioSummary::setEndOfFadeIn(qreal time)
{
d->end_of_fade_in = time;
}
QNetworkReply* Echonest::AudioSummary::fetchFullAnalysis() const
{
return Echonest::Config::instance()->nam()->get( QNetworkRequest( QUrl( d->analysis_url ) ) );
}
int Echonest::AudioSummary::key() const
{
return d->key;
}
void Echonest::AudioSummary::setKey(int key)
{
d->key = key;
}
qreal Echonest::AudioSummary::keyConfidence() const
{
return d->key_confidence;
}
void Echonest::AudioSummary::setKeyConfidence(qreal confidence)
{
d->key_confidence = confidence;
}
qreal Echonest::AudioSummary::loudness() const
{
return d->loudness;
}
void Echonest::AudioSummary::setLoudness(qreal loudness)
{
d->loudness = loudness;
}
qreal Echonest::AudioSummary::modeConfidence() const
{
return d->mode_confidence;
}
void Echonest::AudioSummary::setModeConfidence(qreal confidence)
{
d->mode_confidence = confidence;
}
qint64 Echonest::AudioSummary::numSamples() const
{
return d->num_samples;
}
void Echonest::AudioSummary::setNumSamples(qint64 num)
{
d->num_samples = num;
}
void Echonest::AudioSummary::parseFullAnalysis(QNetworkReply* reply)
{
}
QString Echonest::AudioSummary::sampleMD5() const
{
return d->sample_md5;
}
void Echonest::AudioSummary::setSampleMD5(const QString& md5)
{
d->sample_md5 = md5;
}
qreal Echonest::AudioSummary::sampleRate() const
{
return d->samplerate;
}
void Echonest::AudioSummary::setSampleRate(qreal sampleRate)
{
d->samplerate = sampleRate;
}
Echonest::SectionList Echonest::AudioSummary::sections() const
{
return d->sections;
}
void Echonest::AudioSummary::setSections(const Echonest::SectionList& sections)
{
d->sections = sections;
}
Echonest::SegmentList Echonest::AudioSummary::segments() const
{
return d->segments;
}
void Echonest::AudioSummary::setSegments(const Echonest::SegmentList& segments)
{
d->segments = segments;
}
void Echonest::AudioSummary::setStartOfFadeOut(qreal time)
{
d->start_of_fade_out = time;
}
Echonest::TatumList Echonest::AudioSummary::tatums() const
{
return d->tatums;
}
void Echonest::AudioSummary::setTatums(const Echonest::TatumList& tatums)
{
d->tatums = tatums;
}
qreal Echonest::AudioSummary::startOfFadeOut() const
{
return d->start_of_fade_out;
}
qreal Echonest::AudioSummary::tempo() const
{
return d->tempo;
}
void Echonest::AudioSummary::setTempo(qreal tempo)
{
d->tempo = tempo;
}
qreal Echonest::AudioSummary::tempoConfidence() const
{
return d->tempo_confidence;
}
void Echonest::AudioSummary::setTempoConfidence(qreal confidence)
{
d->tempo_confidence = confidence;
}
int Echonest::AudioSummary::timeSignature() const
{
return d->time_signature;
}
void Echonest::AudioSummary::setTimeSignature(int timeSignature)
{
d->time_signature = timeSignature;
}
qreal Echonest::AudioSummary::timeSignatureConfidence() const
{
return d->time_signature_confidence;
}
void Echonest::AudioSummary::setTimeSignatureConfidence(qreal confidence)
{
d->time_signature_confidence = confidence;
}
void Echonest::AudioSummary::setTimestamp(qreal timestamp)
{
d->timestamp = timestamp;
}
qreal Echonest::AudioSummary::timestamp() const
{
return d->timestamp;
}
int Echonest::AudioSummary::mode() const
{
return d->mode;
}
void Echonest::AudioSummary::setAnalysisUrl(const QString& analysisUrl)
{
d->analysis_url = analysisUrl;
}
void Echonest::AudioSummary::setMode(int mode)
{
d->mode = mode;
}

227
3rdparty/libechonest/AudioSummary.h vendored Normal file
View File

@ -0,0 +1,227 @@
/****************************************************************************************
* Copyright (c) 2010 Leo Franchi <lfranchi@kde.org> *
* *
* This program is free software; you can redistribute it and/or modify it under *
* the terms of the GNU General Public License as published by the Free Software *
* Foundation; either version 2 of the License, or (at your option) any later *
* version. *
* *
* This program is distributed in the hope that it will be useful, but WITHOUT ANY *
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A *
* PARTICULAR PURPOSE. See the GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License along with *
* this program. If not, see <http://www.gnu.org/licenses/>. *
****************************************************************************************/
#ifndef ECHONEST_AUDIOSUMMARY_H
#define ECHONEST_AUDIOSUMMARY_H
#include "echonest_export.h"
#include <QSharedData>
#include <QDebug>
#include "Util.h"
#include "Util.h"
class QNetworkReply;
class QNetworkReply;
class AudioSummaryData;
namespace Echonest{
/**
* This encapsulates the audio summary of an Echo Nest track or song.
*
* It has two batches of data: the more generic acoustic information about the
* song is always populated, and additional detailed information about the song
* such as bars, beats, segments, tatus, and sections, can be fetched as well as
* an additional step.
*
* This class is implicitly shared.
*/
class ECHONEST_EXPORT AudioSummary
{
public:
AudioSummary();
AudioSummary( const AudioSummary& other );
~AudioSummary();
AudioSummary& operator=( const AudioSummary& audio );
int key() const;
void setKey( int key );
/**
* The track's tempo.
*/
qreal tempo() const;
void setTempo( qreal tempo );
/**
* The track's mode.
*/
int mode() const;
void setMode( int mode );
/**
* The track's time signature, or -1 if it there is one, or 1 if it is
* too complex.
*/
int timeSignature() const;
void setTimeSignature( int timeSignature );
/**
* The duration of the song, in msecs.
*/
qreal duration() const;
void setDuration( qreal duration );
/**
* The loudness of the song, in dB.
*/
qreal loudness() const;
void setLoudness( qreal loudness );
/**
* If you wish to use any of the more detailed track analysis data,
* use this method to begin the fetch. One the returned QNetworkReply*
* has emitted the finished() signal, call parseFullAnalysis.
*/
QNetworkReply* fetchFullAnalysis() const;
/**
* Parses the result of a fetchFullAnalysis() call. This contains
* information such as mode, fadein/fadeout, confidence metrics,
* and the division of the song into bars, beats, sections, and segments.
*/
void parseFullAnalysis( QNetworkReply* reply );
/// The following methods *ALL REQUIRE THAT parseFullAnalysis be called first*
/**
* How long it took to analyze this track.
*/
qreal analysisTime() const;
void setAnalysisTime( qreal time );
/**
* The version of the analyzer used on this track.
*/
QString analyzerVersion() const;
void setAnalyzerVersion( QString version );
/**
* Detailed status information about the analysis
*/
Analysis::AnalysisStatus detailedStatus() const;
void setDetailedStatus( Analysis::AnalysisStatus status );
/**
* The status code of the analysis
*/
int analysisStatus() const;
void setAnalysisStatus( int status );
/**
* The timestamp of the analysis.
*/
qreal timestamp() const;
void setTimestamp( qreal timestamp );
/** ECHONEST_EXPORT
* The sample rate of the track.
*/
qreal sampleRate() const;
void setSampleRate( qreal sampleRate );
/**
* The end of the track's fade in in msec.
*/
qreal endOfFadeIn() const;
void setEndOfFadeIn( qreal time );
/**
* The start of the fade out in msec.
*/
qreal startOfFadeOut() const;
void setStartOfFadeOut( qreal time );
/**
* The confidence of the key item.
*/
qreal keyConfidence() const;
void setKeyConfidence( qreal confidence );
/**
* The confidence of the mode item.
*/
qreal modeConfidence() const;
void setModeConfidence( qreal confidence );
/**
* The confidence of the tempo item.
*/
qreal tempoConfidence() const;
void setTempoConfidence( qreal confidence );
/**
* The confidence of the time signature item.
*/
qreal timeSignatureConfidence() const;
void setTimeSignatureConfidence( qreal confidence );
/**
* The number of samples in this track.
*/
qint64 numSamples() const;
void setNumSamples( qint64 num );
/**
* The MD5 of the sample.
*/
QString sampleMD5() const;
void setSampleMD5( const QString& md5 );
/**
* List of bars that are in the track.
*/
BarList bars() const;
void setBars( const BarList& bars );
/**
* List of beats in the track.
*/
BeatList beats() const;
void setBeats( const BeatList& beats );
/**
* List of sections in the track.
*/
SectionList sections() const;
void setSections( const SectionList& sections );
/**
* List of tatums in the track
*/
TatumList tatums() const;
void setTatums( const TatumList& tatums );
/**
* List of segments in the track with associated acoustic data.
*/
SegmentList segments() const;
void setSegments( const SegmentList& segments );
void setAnalysisUrl( const QString& analysisUrl );
private:
QSharedDataPointer<AudioSummaryData> d;
};
ECHONEST_EXPORT QDebug operator<<(QDebug d, const Echonest::AudioSummary& summary);
} // namespace
#endif

100
3rdparty/libechonest/AudioSummary_p.h vendored Normal file
View File

@ -0,0 +1,100 @@
/****************************************************************************************
* Copyright (c) 2010 Leo Franchi <lfranchi@kde.org> *
* *
* This program is free software; you can redistribute it and/or modify it under *
* the terms of the GNU General Public License as published by the Free Software *
* Foundation; either version 2 of the License, or (at your option) any later *
* version. *
* *
* This program is distributed in the hope that it will be useful, but WITHOUT ANY *
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A *
* PARTICULAR PURPOSE. See the GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License along with *
* this program. If not, see <http://www.gnu.org/licenses/>. *
****************************************************************************************/
#include "Util.h"
#include <QSharedData>
#include <QString>
#include <QUrl>
#include <QVector>
class AudioSummaryData : public QSharedData
{
public:
AudioSummaryData() {}
AudioSummaryData(const AudioSummaryData& other)
{
key = other.key;
tempo = other.tempo;
mode = other.mode;
time_signature = other.time_signature;
duration = other.duration;
loudness = other.loudness;
samplerate = other.samplerate;
analysis_url = other.analysis_url;
analysis_time = other.analysis_time;
analyzer_version = other.analyzer_version;
detailed_status = other.detailed_status;
status = other.status;
timestamp = other.timestamp;
end_of_fade_in = other.end_of_fade_in;
key_confidence = other.key_confidence;
loudness = other.loudness;
mode_confidence = other.mode_confidence;
num_samples = other.num_samples;
sample_md5 = other.sample_md5;
start_of_fade_out = other.start_of_fade_out;
tempo_confidence = other.tempo_confidence;
time_signature = other.time_signature;
time_signature_confidence = other.time_signature_confidence;
bars = other.bars;
beats = other.beats;
sections = other.sections;
tatums = other.tatums;
segments = other.segments;
}
// basic data that always exists in an Audio Summary object
int key;
qreal tempo;
int mode;
int time_signature;
qreal duration;
qreal loudness;
int samplerate;
QUrl analysis_url; // used to fetch the following pieces of data
// meta section
qreal analysis_time;
QString analyzer_version;
QString detailed_status;
int status;
qreal timestamp;
// track section
qreal end_of_fade_in;
qreal key_confidence;
qreal mode_confidence;
qint64 num_samples;
QString sample_md5;
qreal start_of_fade_out;
qreal tempo_confidence;
qreal time_signature_confidence;
Echonest::BarList bars;
Echonest::BeatList beats;
Echonest::SectionList sections;
Echonest::TatumList tatums;
Echonest::SegmentList segments;
};

58
3rdparty/libechonest/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,58 @@
add_definitions(-DQT_NO_CAST_FROM_ASCII -DQT_NO_CAST_TO_ASCII)
set(ECHONEST_LIB_MAJOR_VERSION "0")
set(ECHONEST_LIB_MINOR_VERSION "1")
set(ECHONEST_LIB_PATCH_VERSION "0")
set(ECHONEST_LIB_VERSION "${ECHONEST_LIB_MAJOR_VERSION}.${ECHONEST_LIB_MINOR_VERSION}.${ECHONEST_LIB_PATCH_VERSION}" )
set( ECHONEST_LIB_VERSION_STRING "${ECHONEST_LIB_MAJOR_VERSION}.${ECHONEST_LIB_MINOR_VERSION}.${ECHONEST_LIB_PATCH_VERSION}")
if(CMAKE_COMPILER_IS_GNUCXX)
add_definitions( -Wall -Wundef -Wcast-align -Wchar-subscripts -Wpointer-arith
-Wwrite-strings -Wpacked -Wformat-security -Wmissing-format-attribute
-Wold-style-cast -Woverloaded-virtual -Wnon-virtual-dtor -Werror )
add_definitions( -fvisibility=hidden )
# to be added:
# -Wshadow
# FIXME we might want this one back in, but Qt 4.4.3 spits gazillions of warnings with it on Linux-64:
# -Wconversion
endif(CMAKE_COMPILER_IS_GNUCXX)
include_directories( ${CMAKE_CURRENT_SOURCE_DIR} )
set( LIBECHONEST_SRC
Track.cpp
Song.cpp
Artist.cpp
Playlist.cpp
Config.cpp
Parsing.cpp
AudioSummary.cpp
Util.cpp
ArtistTypes.cpp
)
set( LIBECHONEST_H
Track.h
Song.h
Artist.h
Playlist.h
Config.h
AudioSummary.h
ArtistTypes.h
)
QT4_WRAP_CPP( ${LIBECHONEST_H} )
add_library( echonest STATIC ${LIBECHONEST_SRC} )
target_link_libraries( echonest ${QT_QTCORE_LIBRARY} ${QT_QTNETWORK_LIBRARY} )
set_target_properties( echonest PROPERTIES VERSION ${ECHONEST_LIB_VERSION} SOVERSION ${ECHONEST_LIB_VERSION} )
# Clementine: "install" the headers into the binary directory
foreach(file ${LIBECHONEST_H} echonest_export.h Util.h)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${file}
${CMAKE_CURRENT_BINARY_DIR}/echonest/${file}
COPYONLY)
endforeach(file ${LIBECHONEST_H})

127
3rdparty/libechonest/Config.cpp vendored Normal file
View File

@ -0,0 +1,127 @@
/****************************************************************************************
* Copyright (c) 2010 Leo Franchi <lfranchi@kde.org> *
* *
* This program is free software; you can redistribute it and/or modify it under *
* the terms of the GNU General Public License as published by the Free Software *
* Foundation; either version 2 of the License, or (at your option) any later *
* version. *
* *
* This program is distributed in the hope that it will be useful, but WITHOUT ANY *
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A *
* PARTICULAR PURPOSE. See the GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License along with *
* this program. If not, see <http://www.gnu.org/licenses/>. *
****************************************************************************************/
#include "Config.h"
#include <QNetworkAccessManager>
#include <QDebug>
Echonest::Config* Echonest::Config::s_instance = 0;
QUrl Echonest::baseUrl()
{
QUrl url;
url.setScheme( QLatin1String( "http" ) );
url.setHost( QLatin1String( "developer.echonest.com" ) );
return url;
}
QUrl Echonest::baseGetQuery(const QByteArray& type, const QByteArray& method)
{
QUrl url = baseUrl();
url.setPath( QString::fromLatin1( "/api/v4/%1/%2" ).arg( QLatin1String( type ) ).arg( QLatin1String( method ) ) );
url.addEncodedQueryItem( "api_key", Echonest::Config::instance()->apiKey() );
url.addEncodedQueryItem( "format", "xml" );
return url;
}
Echonest::ParseError::ParseError(Echonest::ErrorType error): exception()
{
type = error;
}
Echonest::ParseError::~ParseError() throw()
{}
Echonest::ErrorType Echonest::ParseError::errorType() const
{
return type;
}
void Echonest::ParseError::setNetworkError( QNetworkReply::NetworkError error )
{
nError = error;
}
QNetworkReply::NetworkError Echonest::ParseError::networkError() const
{
return nError;
}
class Echonest::ConfigPrivate {
public:
ConfigPrivate() : nam( new QNetworkAccessManager )
{
}
~ConfigPrivate()
{
delete nam;
nam = 0;
}
QNetworkAccessManager* nam;
QByteArray apikey;
};
Echonest::Config::Config()
: d( new Echonest::ConfigPrivate )
{
}
Echonest::Config::~Config()
{
delete d;
}
void Echonest::Config::setAPIKey(const QByteArray& apiKey)
{
d->apikey = apiKey;
}
QByteArray Echonest::Config::apiKey() const
{
return d->apikey;
}
void Echonest::Config::setNetworkAccessManager(QNetworkAccessManager* nam)
{
if( !nam )
return;
if( d->nam ) {
delete d->nam;
}
d->nam = nam;
}
QNetworkAccessManager* Echonest::Config::nam() const
{
return d->nam;
}
Echonest::Config* Echonest::Config::instance() {
if ( !s_instance ) {
s_instance = new Config;
}
return s_instance;
}

115
3rdparty/libechonest/Config.h vendored Normal file
View File

@ -0,0 +1,115 @@
/****************************************************************************************
* Copyright (c) 2010 Leo Franchi <lfranchi@kde.org> *
* *
* This program is free software; you can redistribute it and/or modify it under *
* the terms of the GNU General Public License as published by the Free Software *
* Foundation; either version 2 of the License, or (at your option) any later *
* version. *
* *
* This program is distributed in the hope that it will be useful, but WITHOUT ANY *
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A *
* PARTICULAR PURPOSE. See the GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License along with *
* this program. If not, see <http://www.gnu.org/licenses/>. *
****************************************************************************************/
#ifndef ECHONEST_CONFIG_H
#define ECHONEST_CONFIG_H
#include "echonest_export.h"
#include <QByteArray>
#include <QUrl>
#include <exception>
#include <QNetworkReply>
class QNetworkAccessManager;
namespace Echonest{
/// Creates the base URL for all GET and POST requests
QUrl baseUrl();
/// Creates the base URL for GET requests.
QUrl baseGetQuery( const QByteArray& type, const QByteArray& method );
enum ErrorType {
/**
* Echo Nest API errors
*/
UnknownError = -1,
NoError = 0,
MissingAPIKey = 1,
NotAllowed = 2,
RateLimitExceeded = 3,
MissingParameter = 4,
InvalidParameter = 5,
/// libechonest errors
UnfinishedQuery = 6, /// An unfinished QNetworkReply* was passed to the parse function
EmptyResult = 7,
UnknownParseError = 8,
/// QNetworkReply errors
NetworkError = 9
};
class ParseError : public std::exception
{
public:
ParseError( ErrorType error );
virtual ~ParseError() throw();
ErrorType errorType() const;
/**
* If the ErrorType is NetworkError, this value contains the QNetworkReply
* error code that was returned.
*/
void setNetworkError( QNetworkReply::NetworkError error );
QNetworkReply::NetworkError networkError() const;
private:
ErrorType type;
QNetworkReply::NetworkError nError;
};
class ConfigPrivate;
/**
* This singleton contains miscellaneous settings used to access The Echo Nest
*/
class ECHONEST_EXPORT Config {
public:
static Config* instance();
/**
* Set the API key to be used for all API requests. This MUST be set in order
* for any web service calls to work!
*/
void setAPIKey( const QByteArray& apiKey );
QByteArray apiKey() const;
/**
* Set the QNetworkAccessManager to use to make web service requests to
* The Echo Nest.
*
* This will take over control of the object.
*/
void setNetworkAccessManager( QNetworkAccessManager* nam );
QNetworkAccessManager* nam() const;
private:
Config();
~Config();
static Config* s_instance;
ConfigPrivate* d;
};
}
#endif

601
3rdparty/libechonest/Parsing.cpp vendored Normal file
View File

@ -0,0 +1,601 @@
/****************************************************************************************
* Copyright (c) 2010 Leo Franchi <lfranchi@kde.org> *
* *
* This program is free software; you can redistribute it and/or modify it under *
* the terms of the GNU General Public License as published by the Free Software *
* Foundation; either version 2 of the License, or (at your option) any later *
* version. *
* *
* This program is distributed in the hope that it will be useful, but WITHOUT ANY *
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A *
* PARTICULAR PURPOSE. See the GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License along with *
* this program. If not, see <http://www.gnu.org/licenses/>. *
****************************************************************************************/
#include "Parsing_p.h"
#include "Util.h"
#include <QNetworkReply>
#include "Artist.h"
#include <QDateTime>
void Echonest::Parser::checkForErrors( QNetworkReply* reply ) throw( Echonest::ParseError )
{
if( !reply )
throw new ParseError( Echonest::UnknownError );
if( !reply->isFinished() )
throw new ParseError( Echonest::UnfinishedQuery );
if( reply->error() != QNetworkReply::NoError ) {
ParseError* err = new ParseError( Echonest::NetworkError );
err->setNetworkError( reply->error() );
throw err;
}
}
void Echonest::Parser::readStatus( QXmlStreamReader& xml ) throw( Echonest::ParseError )
{
if( xml.readNextStartElement() ) {
// sanity checks
if( xml.name() != QLatin1String( "response" ) )
throw new ParseError( UnknownParseError );
if( xml.readNextStartElement() ) {
if( xml.name() != "status" )
throw new ParseError( UnknownParseError );
// only check the error code for now
xml.readNextStartElement();
double version = xml.readElementText().toDouble();
// TODO use version for something?
Q_UNUSED(version);
xml.readNextStartElement();
Echonest::ErrorType code = static_cast< Echonest::ErrorType >( xml.readElementText().toInt() );
xml.readNextStartElement();
QString msg = xml.readElementText();
xml.readNextStartElement();
if( code != Echonest::NoError ) {
throw new ParseError( code );
}
xml.readNext();
}
} else {
throw new ParseError( UnknownParseError );
}
}
QVector< Echonest::Song > Echonest::Parser::parseSongList( QXmlStreamReader& xml ) throw( Echonest::ParseError )
{
QVector< Echonest::Song > songs;
xml.readNext();
while( !( xml.name() == "songs" && xml.tokenType() == QXmlStreamReader::EndElement ) ) {
// parse a song
songs.append( parseSong( xml ) );
}
return songs;
}
Echonest::Song Echonest::Parser::parseSong( QXmlStreamReader& xml ) throw( Echonest::ParseError )
{
if( xml.name() != "song" )
throw new ParseError( Echonest::UnknownParseError );
Echonest::Song song;
while( !( xml.name() == "song" && xml.tokenType() == QXmlStreamReader::EndElement ) ) {
if( xml.name() == "id" && xml.isStartElement() )
song.setId( xml.readElementText().toLatin1() );
else if( xml.name() == "title" && xml.isStartElement() )
song.setTitle( xml.readElementText() );
else if( xml.name() == "artist_id" && xml.isStartElement() )
song.setArtistId( xml.readElementText().toLatin1() );
else if( xml.name() == "artist_name" && xml.isStartElement() )
song.setArtistName( xml.readElementText() );
else if( xml.name() == "song_hotttnesss" && xml.isStartElement() )
song.setHotttnesss( xml.readElementText().toDouble() );
else if( xml.name() == "artist_hotttnesss" && xml.isStartElement() )
song.setArtistHotttnesss( xml.readElementText().toDouble() );
else if( xml.name() == "artist_familiarity" && xml.isStartElement() )
song.setArtistFamiliarity( xml.readElementText().toDouble() );
else if( xml.name() == "artist_location" && xml.isStartElement() ) {
while( !( xml.name() == "location" && xml.tokenType() == QXmlStreamReader::EndElement ) ) {
xml.readNextStartElement();
if( xml.name() == "location" )
song.setArtistLocation( xml.readElementText() );
}
xml.readNext();
} else if( xml.name() == "audio_summary" && xml.isStartElement() ) {
song.setAudioSummary( parseAudioSummary( xml ) );
}
xml.readNext();
}
xml.readNext(); // skip past the last </song>
return song;
}
Echonest::Track Echonest::Parser::parseTrack( QXmlStreamReader& xml ) throw( Echonest::ParseError )
{
if( xml.name() != "track" ) {
throw new ParseError( Echonest::UnknownParseError );
}
Echonest::Track track;
while( !( xml.name() == "track" && xml.tokenType() == QXmlStreamReader::EndElement ) ) {
if( xml.name() == "id" && xml.isStartElement() )
track.setId( xml.readElementText().toLatin1() );
else if( xml.name() == "title" && xml.isStartElement() )
track.setTitle( xml.readElementText() );
else if( xml.name() == "artist" && xml.isStartElement() )
track.setArtist( xml.readElementText() );
else if( xml.name() == "status" && xml.isStartElement() )
track.setStatus( Echonest::statusToEnum( xml.readElementText() ) );
else if( xml.name() == "analyzer_version" && xml.isStartElement() )
track.setAnalyzerVersion( xml.readElementText() );
else if( xml.name() == "release" && xml.isStartElement() )
track.setRelease( xml.readElementText() );
else if( xml.name() == "audio_md5" && xml.isStartElement() )
track.setAudioMD5( xml.readElementText().toLatin1() );
else if( xml.name() == "bitrate" && xml.isStartElement() )
track.setBitrate( xml.readElementText().toInt() );
else if( xml.name() == "samplerate" && xml.isStartElement() )
track.setSamplerate( xml.readElementText().toInt() );
else if( xml.name() == "md5" && xml.isStartElement() )
track.setMD5( xml.readElementText().toLatin1() );
else if( xml.name() == "audio_summary" && xml.isStartElement() ) {
track.setAudioSummary( parseAudioSummary( xml ) );
continue;
}
xml.readNext();
}
xml.readNext(); // skip past the last
return track;
}
Echonest::AudioSummary Echonest::Parser::parseAudioSummary( QXmlStreamReader& xml ) throw( Echonest::ParseError )
{
if( xml.name() != "audio_summary" ) {
throw new ParseError( Echonest::UnknownParseError );
}
Echonest::AudioSummary summary;
while( !( xml.name() == "audio_summary" && xml.tokenType() == QXmlStreamReader::EndElement ) ) {
if( xml.name() == "key" && xml.isStartElement() )
summary.setKey( xml.readElementText().toInt() );
else if( xml.name() == "analysis_url" && xml.isStartElement() )
summary.setAnalysisUrl( xml.readElementText() );
else if( xml.name() == "tempo" && xml.isStartElement() )
summary.setTempo( xml.readElementText().toDouble() );
else if( xml.name() == "mode" && xml.isStartElement() )
summary.setMode( xml.readElementText().toInt() );
else if( xml.name() == "time_signature" && xml.isStartElement() )
summary.setTimeSignature( xml.readElementText().toInt() );
else if( xml.name() == "duration" && xml.isStartElement() )
summary.setDuration( xml.readElementText().toDouble() );
else if( xml.name() == "loudness" && xml.isStartElement() )
summary.setLoudness( xml.readElementText().toDouble() );
xml.readNext();
}
return summary;
}
Echonest::Artists Echonest::Parser::parseArtists( QXmlStreamReader& xml )
{
// we expect to be in an <artists> start element
if( xml.name() != "artists" || !xml.isStartElement() )
throw new ParseError( Echonest::UnknownParseError );
xml.readNextStartElement();
Echonest::Artists artists;
while( xml.name() != "artists" || !xml.isEndElement() ) {
if( xml.name() != "artist" || !xml.isStartElement() )
throw new Echonest::ParseError( Echonest::UnknownParseError );
Echonest::Artist artist;
while( xml.name() != "artist" || !xml.isEndElement() ) {
parseArtistInfo( xml, artist );
xml.readNextStartElement();
}
artists.append( artist );
xml.readNext();
}
return artists;
}
int Echonest::Parser::parseArtistInfoOrProfile( QXmlStreamReader& xml , Echonest::Artist& artist ) throw( Echonest::ParseError )
{
if( xml.name() == "start" ) { // this is an individual info query, so lets read it
xml.readNextStartElement();
xml.readNext();
int results = -1;
if( xml.name() == "total" ) {
results = xml.readElementText().toInt();
xml.readNextStartElement();
}
parseArtistInfo( xml, artist );
return results;
} else if( xml.name() == "songs" ) {
parseArtistSong( xml, artist );
} else if( xml.name() == "urls" ) { // urls also has no start/total
parseUrls( xml, artist );
} else { // this is either a profile query, or a familiarity or hotttness query, so save all the data we find
while( !( xml.name() == "artist" && xml.tokenType() == QXmlStreamReader::EndElement ) ) {
parseArtistInfo( xml, artist );
xml.readNextStartElement();
}
}
return 0;
}
void Echonest::Parser::parseArtistInfo( QXmlStreamReader& xml, Echonest::Artist& artist ) throw( Echonest::ParseError )
{
// parse each sort of artist information
if( xml.name() == "audio" ) {
parseAudio( xml, artist );
} else if( xml.name() == "biographies" ) {
parseBiographies( xml, artist );
} else if( xml.name() == "familiarity" ) {
artist.setFamiliarity( xml.readElementText().toDouble() );
} else if( xml.name() == "hotttnesss" ) {
artist.setHotttnesss( xml.readElementText().toDouble() );
} else if( xml.name() == "images" ) {
parseImages( xml, artist );
} else if( xml.name() == "news" ) {
parseNewsOrBlogs( xml, artist, true );
} else if( xml.name() == "blogs" ) {
parseNewsOrBlogs( xml, artist, false );
} else if( xml.name() == "reviews" ) {
parseReviews( xml, artist );
} else if( xml.name() == "terms" ) {
parseTerms( xml, artist );
} else if( xml.name() == "urls" ) {
parseTerms( xml, artist );
} else if( xml.name() == "songs" ) {
parseArtistSong( xml, artist );
} else if( xml.name() == "video" ) {
parseVideos( xml, artist );
} else if( xml.name() == "foreign_ids" ) {
parseForeignIds( xml, artist );
} else if( xml.name() == "name" ) {
artist.setName( xml.readElementText() );
} else if( xml.name() == "id" ) {
artist.setId( xml.readElementText().toLatin1() );
}
}
// parse each type of artist attribute
void Echonest::Parser::parseAudio( QXmlStreamReader& xml, Echonest::Artist& artist ) throw( Echonest::ParseError )
{
if( xml.name() != "audio" || xml.tokenType() != QXmlStreamReader::StartElement )
throw new Echonest::ParseError( Echonest::UnknownParseError );
xml.readNextStartElement();
Echonest::AudioList audioList;
while( xml.name() != "audio" || xml.tokenType() != QXmlStreamReader::EndElement ) {
Echonest::AudioFile audio;
do {
xml.readNext();
if( xml.name() == "title" )
audio.setTitle( xml.readElementText() );
else if( xml.name() == "url" )
audio.setUrl( QUrl( xml.readElementText() ) );
else if( xml.name() == "artist" )
audio.setArtist( xml.readElementText() );
else if( xml.name() == "date" )
audio.setDate( QDateTime::fromString( xml.readElementText(), Qt::ISODate ) );
else if( xml.name() == "length" )
audio.setLength( xml.readElementText().toDouble() );
else if( xml.name() == "link" )
audio.setLink( QUrl( xml.readElementText() ) );
else if( xml.name() == "release" )
audio.setRelease( xml.readElementText() );
else if( xml.name() == "id" )
audio.setId( xml.readElementText().toLatin1() );
} while( xml.name() != "audio" || xml.tokenType() != QXmlStreamReader::EndElement );
audioList.append( audio );
xml.readNext();
}
artist.setAudio( audioList );
}
void Echonest::Parser::parseBiographies( QXmlStreamReader& xml, Echonest::Artist& artist ) throw( Echonest::ParseError )
{
if( xml.name() != "biographies" || xml.tokenType() != QXmlStreamReader::StartElement )
throw new Echonest::ParseError( Echonest::UnknownParseError );
xml.readNextStartElement();
Echonest::BiographyList bios;
while( xml.name() != "biographies" || xml.tokenType() != QXmlStreamReader::EndElement ) {
Echonest::Biography bio;
do {
xml.readNext();
if( xml.name() == "text" )
bio.setText( xml.readElementText() );
else if( xml.name() == "site" )
bio.setSite( xml.readElementText() );
else if( xml.name() == "url" )
bio.setUrl( QUrl( xml.readElementText() ) );
else if( xml.name() == "license" )
bio.setLicense( parseLicense( xml) );
} while( xml.name() != "biography" || xml.tokenType() != QXmlStreamReader::EndElement );
bios.append( bio );
xml.readNext();
}
artist.setBiographies( bios );
}
void Echonest::Parser::parseImages( QXmlStreamReader& xml, Echonest::Artist& artist ) throw( Echonest::ParseError )
{
if( xml.name() != "images" || xml.tokenType() != QXmlStreamReader::StartElement )
throw new Echonest::ParseError( Echonest::UnknownParseError );
xml.readNextStartElement();
Echonest::ArtistImageList imgs;
while( xml.name() != "images" || xml.tokenType() != QXmlStreamReader::EndElement ) {
Echonest::ArtistImage img;
do {
xml.readNext();
if( xml.name() == "url" )
img.setUrl( QUrl( xml.readElementText() ) );
else if( xml.name() == "license" )
img.setLicense( parseLicense( xml) );
} while( xml.name() != "image" || xml.tokenType() != QXmlStreamReader::EndElement );
imgs.append( img );
xml.readNext();
}
artist.setImages( imgs );
}
void Echonest::Parser::parseNewsOrBlogs( QXmlStreamReader& xml, Echonest::Artist& artist, bool news ) throw( Echonest::ParseError )
{
if( news && ( xml.name() != "news" || xml.tokenType() != QXmlStreamReader::StartElement ) )
throw new Echonest::ParseError( Echonest::UnknownParseError );
else if( !news && ( xml.name() != "blogs" || xml.tokenType() != QXmlStreamReader::StartElement ) )
throw new Echonest::ParseError( Echonest::UnknownParseError );
xml.readNextStartElement();
Echonest::NewsList newsList;
while( !( ( xml.name() == "news" || xml.name() == "blogs" ) && xml.tokenType() == QXmlStreamReader::EndElement ) ) {
Echonest::NewsArticle news;
do {
xml.readNextStartElement();
if( xml.name() == "name" )
news.setName( xml.readElementText() );
else if( xml.name() == "url" )
news.setUrl( QUrl( xml.readElementText() ) );
else if( xml.name() == "summary" )
news.setSummary( xml.readElementText() );
else if( xml.name() == "date_found" )
news.setDateFound( QDateTime::fromString( xml.readElementText(), Qt::ISODate ) );
else if( xml.name() == "id" )
news.setId( xml.readElementText().toLatin1() );
else if( xml.name() == "date_posted" )
news.setDatePosted( QDateTime::fromString( xml.readElementText(), Qt::ISODate ) );
} while( !( ( xml.name() == "news" || xml.name() == "blog" ) && xml.tokenType() == QXmlStreamReader::EndElement ) );
newsList.append( news );
xml.readNext();
}
if( news )
artist.setNews( newsList );
else
artist.setBlogs( newsList );
}
void Echonest::Parser::parseReviews( QXmlStreamReader& xml, Echonest::Artist& artist ) throw( Echonest::ParseError )
{
if( xml.name() != "reviews" || xml.tokenType() != QXmlStreamReader::StartElement )
throw new Echonest::ParseError( Echonest::UnknownParseError );
xml.readNextStartElement();
Echonest::ReviewList reviews;
while( xml.name() != "reviews" || xml.tokenType() != QXmlStreamReader::EndElement ) {
Echonest::Review review;
do {
xml.readNextStartElement();
if( xml.name() == "url" )
review.setUrl( QUrl( xml.readElementText() ) );
else if( xml.name() == "name" )
review.setName( xml.readElementText() );
else if( xml.name() == "summary" )
review.setSummary( xml.readElementText() );
else if( xml.name() == "date_found" )
review.setDateFound( QDateTime::fromString( xml.readElementText(), Qt::ISODate ) );
else if( xml.name() == "image" )
review.setImageUrl( QUrl( xml.readElementText() ) );
else if( xml.name() == "release" )
review.setRelease( xml.readElementText() );
else if( xml.name() == "id" )
review.setId( xml.readElementText().toLatin1() );
} while( xml.name() != "review" || xml.tokenType() != QXmlStreamReader::EndElement );
reviews.append( review );
xml.readNext();
}
artist.setReviews( reviews );
}
void Echonest::Parser::parseArtistSong( QXmlStreamReader& xml, Echonest::Artist& artist ) throw( Echonest::ParseError )
{
if( xml.name() != "songs" || xml.tokenType() != QXmlStreamReader::StartElement )
throw new Echonest::ParseError( Echonest::UnknownParseError );
xml.readNextStartElement();
Echonest::SongList songs;
while( xml.name() != "songs" || xml.tokenType() != QXmlStreamReader::EndElement ) {
if( xml.name() == "song" && xml.isStartElement() )
{
Echonest::Song song;
while( xml.name() != "song" || !xml.isEndElement() ) {
if( xml.name() == "id" && xml.isStartElement() )
song.setId( xml.readElementText().toLatin1() );
else if( xml.name() == "title" && xml.isStartElement() )
song.setTitle( xml.readElementText() );
xml.readNextStartElement();
}
songs.append( song );
}
xml.readNext();
}
artist.setSongs( songs );
}
void Echonest::Parser::parseTerms( QXmlStreamReader& xml, Echonest::Artist& artist ) throw( Echonest::ParseError )
{
if( xml.name() != "terms" || xml.tokenType() != QXmlStreamReader::StartElement )
throw new Echonest::ParseError( Echonest::UnknownParseError );
artist.setTerms( parseTermList( xml ) );
}
void Echonest::Parser::parseUrls( QXmlStreamReader& xml, Echonest::Artist& artist ) throw( Echonest::ParseError )
{
if( xml.name() != "urls" || xml.tokenType() != QXmlStreamReader::StartElement )
throw new Echonest::ParseError( Echonest::UnknownParseError );
xml.readNextStartElement();
xml.readNextStartElement();
while( xml.name() != "urls" || !xml.isEndElement() ) {
if( xml.name() == "lastfm_url" )
artist.setLastFmUrl( QUrl( xml.readElementText() ) );
else if( xml.name() == "aolmusic_url" )
artist.setAolMusicUrl( QUrl( xml.readElementText() ) );
else if( xml.name() == "myspace_url" )
artist.setMyspaceUrl( QUrl( xml.readElementText() ) );
else if( xml.name() == "amazon_url" )
artist.setAmazonUrl( QUrl( xml.readElementText() ) );
else if( xml.name() == "itunes_url" )
artist.setItunesUrl( QUrl( xml.readElementText() ) );
else if( xml.name() == "mb_url" )
artist.setMusicbrainzUrl( QUrl( xml.readElementText() ) );
xml.readNextStartElement();
}
xml.readNextStartElement();
}
void Echonest::Parser::parseVideos( QXmlStreamReader& xml, Echonest::Artist& artist ) throw( Echonest::ParseError )
{
if( xml.name() != "video" || xml.tokenType() != QXmlStreamReader::StartElement )
throw new Echonest::ParseError( Echonest::UnknownParseError );
Echonest::VideoList videos;
while( xml.name() == "video" && xml.isStartElement() ) {
Echonest::Video video;
while( xml.name() != "video" || !xml.isEndElement() ) {
if( xml.name() == "title" )
video.setTitle( xml.readElementText() );
else if( xml.name() == "url" )
video.setUrl( QUrl( xml.readElementText() ) );
else if( xml.name() == "site" )
video.setSite( xml.readElementText() );
else if( xml.name() == "date_found" )
video.setDateFound( QDateTime::fromString( xml.readElementText(), Qt::ISODate ) );
else if( xml.name() == "image_url" )
video.setImageUrl( QUrl( xml.readElementText() ) );
else if( xml.name() == "id" )
video.setId( xml.readElementText().toLatin1() );
xml.readNextStartElement();
}
videos.append( video );
xml.readNextStartElement();
}
artist.setVideos( videos );
}
Echonest::TermList Echonest::Parser::parseTermList( QXmlStreamReader& xml )
{
if( xml.name() != "terms" || xml.tokenType() != QXmlStreamReader::StartElement )
throw new Echonest::ParseError( Echonest::UnknownParseError );
Echonest::TermList terms;
while( xml.name() == "terms" && xml.isStartElement() ) {
Echonest::Term term;
while( xml.name() != "terms" || !xml.isEndElement() ) {
if( xml.name() == "frequency" )
term.setFrequency( xml.readElementText().toDouble() );
else if( xml.name() == "name" )
term.setName( xml.readElementText() );
else if( xml.name() == "weight" )
term.setWeight( xml.readElementText().toDouble() );
xml.readNextStartElement();
}
terms.append( term );
xml.readNextStartElement();
}
return terms;
}
void Echonest::Parser::parseForeignIds( QXmlStreamReader& xml, Echonest::Artist& artist ) throw( Echonest::ParseError )
{
}
Echonest::License Echonest::Parser::parseLicense( QXmlStreamReader& xml ) throw( Echonest::ParseError )
{
if( xml.name() != "license" || xml.tokenType() != QXmlStreamReader::StartElement )
throw new Echonest::ParseError( Echonest::UnknownParseError );
Echonest::License license;
while( xml.name() != "license" || xml.tokenType() != QXmlStreamReader::EndElement ) {
if( xml.name() == "type" )
license.type = xml.readElementText();
else if( xml.name() == "attribution" )
license.attribution = xml.readElementText();
else if( xml.name() == "url" )
license.url = QUrl( xml.readElementText() );
xml.readNext();
}
xml.readNextStartElement();
return license;
}
QByteArray Echonest::Parser::parsePlaylistSessionId( QXmlStreamReader& xml ) throw( ParseError )
{
if( xml.name() != "session_id" || xml.tokenType() != QXmlStreamReader::StartElement )
throw new Echonest::ParseError( Echonest::UnknownParseError );
QByteArray sessionId = xml.readElementText().toLatin1();
xml.readNext(); //read to next start element
return sessionId;
}

87
3rdparty/libechonest/Parsing_p.h vendored Normal file
View File

@ -0,0 +1,87 @@
/****************************************************************************************
* Copyright (c) 2010 Leo Franchi <lfranchi@kde.org> *
* *
* This program is free software; you can redistribute it and/or modify it under *
* the terms of the GNU General Public License as published by the Free Software *
* Foundation; either version 2 of the License, or (at your option) any later *
* version. *
* *
* This program is distributed in the hope that it will be useful, but WITHOUT ANY *
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A *
* PARTICULAR PURPOSE. See the GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License along with *
* this program. If not, see <http://www.gnu.org/licenses/>. *
****************************************************************************************/
#ifndef ECHONEST_PARSING_P_H
#define ECHONEST_PARSING_P_H
#include "Config.h"
#include <QXmlStreamReader>
#include "Song.h"
#include "Artist.h"
class QNetworkReply;
namespace Echonest
{
namespace Parser
{
/**
* Internal helper parsing functions for QXmlStreamParser
*/
void checkForErrors( QNetworkReply* reply ) throw( ParseError );
// read the start element and then the status element, throwing
// if the result code is not Success
void readStatus( QXmlStreamReader& xml ) throw( ParseError );
// parses a <songs></songs> block and turns them into a list of Song object
QVector< Song > parseSongList( QXmlStreamReader& xml ) throw( ParseError );
// parses a <song></song> block
Song parseSong( QXmlStreamReader& xml ) throw( ParseError );
// parses a <track></track> block
Track parseTrack( QXmlStreamReader& xml ) throw( ParseError );
// parses an <audio_summary> chunk
AudioSummary parseAudioSummary( QXmlStreamReader& xml ) throw( ParseError );
// parses a list of artists in an <artists></artists> block
Echonest::Artists parseArtists( QXmlStreamReader& xml );
// parses the contents of an artist fetch result, expects to be positioned after the readStatus() call
// it could be a profile query, in which case it has a bunch of different artist attributes
// or it could be a single fetch, in which case it starts with result number and offset.
// the results are saved back into the artist
int parseArtistInfoOrProfile( QXmlStreamReader&, Echonest::Artist& artist ) throw( ParseError );
// parse the individual artist attributes
void parseArtistInfo( QXmlStreamReader& xml, Echonest::Artist& artist ) throw( ParseError );
// parse each type of artist attribute
void parseAudio( QXmlStreamReader& xml, Echonest::Artist& artist ) throw( ParseError );
void parseBiographies( QXmlStreamReader& xml, Echonest::Artist& artist ) throw( ParseError );
void parseImages( QXmlStreamReader& xml, Echonest::Artist& artist ) throw( ParseError );
void parseNewsOrBlogs( QXmlStreamReader& xml, Echonest::Artist& artist, bool news = true ) throw( ParseError );
void parseReviews( QXmlStreamReader& xml, Echonest::Artist& artist ) throw( ParseError );
void parseTerms( QXmlStreamReader& xml, Echonest::Artist& artist ) throw( ParseError );
void parseUrls( QXmlStreamReader& xml, Echonest::Artist& artist ) throw( ParseError );
void parseArtistSong( QXmlStreamReader& xml, Echonest::Artist& artist ) throw( ParseError );
void parseVideos( QXmlStreamReader& xml, Echonest::Artist& artist ) throw( ParseError );
void parseForeignIds( QXmlStreamReader& xml, Echonest::Artist& artist ) throw( ParseError );
// parse a list of terms
TermList parseTermList( QXmlStreamReader& xml );
License parseLicense( QXmlStreamReader& xml ) throw( ParseError );
QByteArray parsePlaylistSessionId( QXmlStreamReader& xml ) throw( ParseError );
}
}
#endif

315
3rdparty/libechonest/Playlist.cpp vendored Normal file
View File

@ -0,0 +1,315 @@
/****************************************************************************************
* Copyright (c) 2010 Leo Franchi <lfranchi@kde.org> *
* *
* This program is free software; you can redistribute it and/or modify it under *
* the terms of the GNU General Public License as published by the Free Software *
* Foundation; either version 2 of the License, or (at your option) any later *
* version. *
* *
* This program is distributed in the hope that it will be useful, but WITHOUT ANY *
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A *
* PARTICULAR PURPOSE. See the GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License along with *
* this program. If not, see <http://www.gnu.org/licenses/>. *
****************************************************************************************/
#include "Playlist.h"
#include "Playlist_p.h"
#include "Parsing_p.h"
Echonest::DynamicPlaylist::DynamicPlaylist()
: d( new DynamicPlaylistData )
{
}
Echonest::DynamicPlaylist::DynamicPlaylist(const Echonest::DynamicPlaylist& other)
: d( other.d )
{
}
Echonest::DynamicPlaylist::~DynamicPlaylist()
{
}
Echonest::DynamicPlaylist& Echonest::DynamicPlaylist::operator=(const Echonest::DynamicPlaylist& playlist)
{
d = playlist.d;
return *this;
}
QNetworkReply* Echonest::DynamicPlaylist::start(const Echonest::DynamicPlaylist::PlaylistParams& params)
{
// params are the same, if user passes in format parsing will throw, but it should be expected..
return generateInternal( params, "dynamic" );
}
Echonest::Song Echonest::DynamicPlaylist::parseStart(QNetworkReply* reply) throw( Echonest::ParseError )
{
Echonest::Parser::checkForErrors( reply );
QXmlStreamReader xml( reply->readAll() );
Echonest::Parser::readStatus( xml );
d->sessionId = Echonest::Parser::parsePlaylistSessionId( xml );
Echonest::SongList songs = Echonest::Parser::parseSongList( xml );
if( !songs.size() == 1 )
throw new Echonest::ParseError( UnknownParseError );
d->currentSong = songs.front();
return d->currentSong;
}
QByteArray Echonest::DynamicPlaylist::sessionId() const
{
return d->sessionId;
}
void Echonest::DynamicPlaylist::setSessionId(const QByteArray& id)
{
d->sessionId = id;
}
Echonest::Song Echonest::DynamicPlaylist::currentSong() const
{
return d->currentSong;
}
void Echonest::DynamicPlaylist::setCurrentSong(const Echonest::Song& song)
{
d->currentSong = song;
}
QNetworkReply* Echonest::DynamicPlaylist::fetchNextSong(int rating)
{
QUrl url = Echonest::baseGetQuery( "playlist", "dynamic" );
url.addEncodedQueryItem( "session_id", d->sessionId );
if( rating > 0 )
url.addEncodedQueryItem( "rating", QByteArray::number( rating ) );
return Echonest::Config::instance()->nam()->get( QNetworkRequest( url ) );
}
Echonest::Song Echonest::DynamicPlaylist::parseNextSong(QNetworkReply* reply)
{
return parseStart( reply );
}
QNetworkReply* Echonest::DynamicPlaylist::staticPlaylist(const Echonest::DynamicPlaylist::PlaylistParams& params)
{
return Echonest::DynamicPlaylist::generateInternal( params, "static" );
}
Echonest::SongList Echonest::DynamicPlaylist::parseStaticPlaylist(QNetworkReply* reply) throw( Echonest::ParseError )
{
Echonest::Parser::checkForErrors( reply );
QXmlStreamReader xml( reply->readAll() );
Echonest::Parser::readStatus( xml );
Echonest::SongList songs = Echonest::Parser::parseSongList( xml );
return songs;
}
QNetworkReply* Echonest::DynamicPlaylist::generateInternal(const Echonest::DynamicPlaylist::PlaylistParams& params, const QByteArray& type)
{
QUrl url = Echonest::baseGetQuery( "playlist", type );
Echonest::DynamicPlaylist::PlaylistParams::const_iterator iter = params.constBegin();
for( ; iter < params.constEnd(); ++iter ) {
if( iter->first == Format ) // If it's a format, we have to remove the xml format we automatically specify
url.removeEncodedQueryItem( "format" );
if( iter->first == Type ) { // convert type enum to string
switch( static_cast<Echonest::DynamicPlaylist::ArtistTypeEnum>( iter->second.toInt() ) )
{
case ArtistType:
url.addEncodedQueryItem( playlistParamToString( iter->first ), "artist" );
break;
case ArtistRadioType:
url.addEncodedQueryItem( playlistParamToString( iter->first ), "artist-radio" );
break;
case ArtistDescriptionType:
url.addEncodedQueryItem( playlistParamToString( iter->first ), "artist-description" );
break;
}
} else if( iter->first == Sort ) {
url.addEncodedQueryItem( playlistParamToString( iter->first ), playlistSortToString( static_cast<Echonest::DynamicPlaylist::SortingType>( iter->second.toInt() ) ) );
} else if( iter->first == Pick ) {
url.addEncodedQueryItem( playlistParamToString( iter->first ), playlistArtistPickToString( static_cast<Echonest::DynamicPlaylist::ArtistPick>( iter->second.toInt() ) ) );
} else if( iter->first == SongInformation ){
Echonest::Song::addQueryInformation( url, Echonest::Song::SongInformation( iter->second.value< Echonest::Song::SongInformation >() ) );
} else {
url.addQueryItem( QLatin1String( playlistParamToString( iter->first ) ), iter->second.toString().replace( QLatin1Char( ' ' ), QLatin1Char( '+' ) ) );
}
}
qDebug() << "Creating playlist URL" << url;
return Echonest::Config::instance()->nam()->get( QNetworkRequest( url ) );
}
QByteArray Echonest::DynamicPlaylist::playlistParamToString(Echonest::DynamicPlaylist::PlaylistParam param)
{
switch( param )
{
case Echonest::DynamicPlaylist::Type :
return "type";
case Echonest::DynamicPlaylist::Format :
return "format";
case Echonest::DynamicPlaylist::Pick:
return "artist_pick";
case Echonest::DynamicPlaylist::Variety :
return "variety";
case Echonest::DynamicPlaylist::ArtistId :
return "artist_id";
case Echonest::DynamicPlaylist::Artist :
return "artist";
case Echonest::DynamicPlaylist::SongId :
return "song_id";
case Echonest::DynamicPlaylist::Description :
return "description";
case Echonest::DynamicPlaylist::Results :
return "results";
case Echonest::DynamicPlaylist::MaxTempo :
return "max_tempo";
case Echonest::DynamicPlaylist::MinTempo :
return "min_tempo";
case Echonest::DynamicPlaylist::MaxDuration :
return "max_duration";
case Echonest::DynamicPlaylist::MinDuration :
return "min_duration";
case Echonest::DynamicPlaylist::MaxLoudness :
return "max_loudness";
case Echonest::DynamicPlaylist::MinLoudness :
return "min_loudness";
case Echonest::DynamicPlaylist::ArtistMaxFamiliarity :
return "artist_max_familiarity";
case Echonest::DynamicPlaylist::ArtistMinFamiliarity :
return "artist_min_familiarity";
case Echonest::DynamicPlaylist::ArtistMaxHotttnesss :
return "artist_max_hotttnesss";
case Echonest::DynamicPlaylist::ArtistMinHotttnesss :
return "artist_min_hotttnesss";
case Echonest::DynamicPlaylist::SongMaxHotttnesss :
return "song_max_hotttnesss";
case Echonest::DynamicPlaylist::SongMinHotttnesss :
return "song_min_hotttnesss";
case Echonest::DynamicPlaylist::ArtistMinLongitude :
return "artist_min_longitude";
case Echonest::DynamicPlaylist::ArtistMaxLongitude :
return "artist_max_longitude";
case Echonest::DynamicPlaylist::ArtistMinLatitude :
return "artist_min_latitude";
case Echonest::DynamicPlaylist::ArtistMaxLatitude :
return "artist_max_latitude";
case Echonest::DynamicPlaylist::Mode :
return "mode";
case Echonest::DynamicPlaylist::Key :
return "key";
case Echonest::DynamicPlaylist::SongInformation:
return "bucket";
case Echonest::DynamicPlaylist::Sort :
return "sort";
case Echonest::DynamicPlaylist::Limit :
return "limit";
case Echonest::DynamicPlaylist::Audio :
return "audio";
case Echonest::DynamicPlaylist::DMCA :
return "dmca";
}
return QByteArray();
}
QByteArray Echonest::DynamicPlaylist::playlistArtistPickToString(Echonest::DynamicPlaylist::ArtistPick pick)
{
switch( pick )
{
case PickSongHotttnesssAscending:
return "song_hotttnesss-asc";
case PickTempoAscending:
return "tempo-asc";
case PickDurationAscending:
return "duration-asc";
case PickLoudnessAscending:
return "loudness-asc";
case PickModeAscending:
return "mode-asc";
case PickKeyAscending:
return "key-asc";
case PickSongHotttnesssDescending:
return "song_hotttnesss-desc";
case PickTempoDescending:
return "tempo-desc";
case PickDurationDescending:
return "duration-desc";
case PickLoudnessDescending:
return "loudness-desc";
case PickModeDescending:
return "mode-desc";
case PickKeyDescending:
return "key-desc";
}
return QByteArray();
}
QByteArray Echonest::DynamicPlaylist::playlistSortToString(Echonest::DynamicPlaylist::SortingType sorting)
{
switch( sorting )
{
case SortTempoAscending:
return "tempo-asc";
case SortTempoDescending:
return "tempo-desc";
case SortDurationAscending:
return "duration-asc";
case SortDurationDescending:
return "duration-desc";
case SortArtistFamiliarityAscending:
return "artist_familiarity-asc";
case SortArtistFamiliarityDescending:
return "artist_familiarity-desc";
case SortArtistHotttnessAscending:
return "artist_hotttnesss-asc";
case SortArtistHotttnessDescending:
return "artist_hotttnesss-desc";
case SortSongHotttnesssAscending:
return "song_hotttnesss-asc";
case SortSongHotttnesssDescending:
return "song_hotttnesss-desc";
case SortLatitudeAscending:
return "latitude-asc";
case SortLatitudeDescending:
return "latitude-desc";
case SortLongitudeAscending:
return "longitude-asc";
case SortLongitudeDescending:
return "longitude-desc";
case SortModeAscending:
return "mode-asc";
case SortModeDescending:
return "mode-desc";
case SortKeyAscending:
return "key-asc";
case SortKeyDescending:
return "key-desc";
}
return QByteArray();
}
QDebug Echonest::operator<<(QDebug d, const Echonest::DynamicPlaylist& playlist)
{
d << QString::fromLatin1( "DynamicPlaylist(%1, %2)" ).arg( QLatin1String( playlist.sessionId() ), playlist.currentSong().toString() );
return d.maybeSpace();
}

200
3rdparty/libechonest/Playlist.h vendored Normal file
View File

@ -0,0 +1,200 @@
/****************************************************************************************
* Copyright (c) 2010 Leo Franchi <lfranchi@kde.org> *
* *
* This program is free software; you can redistribute it and/or modify it under *
* the terms of the GNU General Public License as published by the Free Software *
* Foundation; either version 2 of the License, or (at your option) any later *
* version. *
* *
* This program is distributed in the hope that it will be useful, but WITHOUT ANY *
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A *
* PARTICULAR PURPOSE. See the GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License along with *
* this program. If not, see <http://www.gnu.org/licenses/>. *
****************************************************************************************/
#ifndef ECHONEST_PLAYLIST_H
#define ECHONEST_PLAYLIST_H
#include "echonest_export.h"
#include "Song.h"
#include <QSharedData>
#include <QDebug>
class QNetworkReply;
class DynamicPlaylistData;
namespace Echonest{
/**
* This encapsulates an Echo Nest dynamic playlist. It contains a playlist ID and
* the current song, and can fetch the next song.
*
* See http://developer.echonest.com/docs/v4/playlist.html#dynamic
* for more information
*/
class ECHONEST_EXPORT DynamicPlaylist
{
public:
/**
* The types of playlist that can be generated. Artist plays songs for the given artist,
* ArtistRadio takes into account similar artists, adn ArtistDescription plays songs matching
* the given description.
*/
enum ArtistTypeEnum {
ArtistType,
ArtistRadioType,
ArtistDescriptionType
};
/**
* Different ways to sort a generated playlist
*/
enum SortingType {
SortTempoAscending,
SortTempoDescending,
SortDurationAscending,
SortDurationDescending,
SortArtistFamiliarityAscending,
SortArtistFamiliarityDescending,
SortArtistHotttnessAscending,
SortArtistHotttnessDescending,
SortSongHotttnesssAscending,
SortSongHotttnesssDescending,
SortLatitudeAscending,
SortLatitudeDescending,
SortLongitudeAscending,
SortLongitudeDescending,
SortModeAscending,
SortModeDescending,
SortKeyAscending,
SortKeyDescending
};
/**
* Different ways of picking artists in Artist radios.
*/
enum ArtistPick {
PickSongHotttnesssAscending,
PickTempoAscending,
PickDurationAscending,
PickLoudnessAscending,
PickModeAscending,
PickKeyAscending,
PickSongHotttnesssDescending,
PickTempoDescending,
PickDurationDescending,
PickLoudnessDescending,
PickModeDescending,
PickKeyDescending
};
/**
* The various parameters that can be passed to the playlist building
* functions.
*/
enum PlaylistParam {
Type, /// The type of playlist to generate. Value is the DynamicPlaylist::ArtistTypeEnum enum
Format, /// Either xml (default) or xspf. If the result is xspf, the raw xspf playlist is returned, else the xml is parsed and exposed programmatically.
Pick, /// How the artists are picked for each artist in ArtistType playlists. Value is Playlist::ArtistPick enum value.
Variety, /// 0 < variety < 1 The maximum variety of artists to be represented in the playlist. A higher number will allow for more variety in the artists.
ArtistId, /// ID(s) of seed artist(s) for the playlist
Artist, /// Artist names of seeds for playlist
SongId, /// IDs of seed songs for the playlist
Description, /// Textual description for sort of songs that can be included in the playlist
Results, /// 0-100, how many sonsg to include in the playlist, default 15
MaxTempo, /// 0.0 < tempo < 500.0 (BPM) The maximum tempo for any included songs
MinTempo, /// 0.0 < tempo < 500.0 (BPM) the minimum tempo for any included songs
MaxDuration, /// 0.0 < duration < 3600.0 (seconds) the maximum duration of any song on the playlist
MinDuration, /// 0.0 < duration < 3600.0 (seconds) the minimum duration of any song on the playlist
MaxLoudness, /// -100.0 < loudness < 100.0 (dB) the maximum loudness of any song on the playlist
MinLoudness, /// -100.0 < loudness < 100.0 (dB) the minimum loudness of any song on the playlist
ArtistMaxFamiliarity, /// 0.0 < familiarity < 1.0 the maximum artist familiarity for songs in the playlist
ArtistMinFamiliarity, /// 0.0 < familiarity < 1.0 the minimum artist familiarity for songs in the playlist
ArtistMaxHotttnesss, /// 0.0 < hotttnesss < 1.0 the maximum hotttnesss for artists in the playlist
ArtistMinHotttnesss, /// 0.0 < hotttnesss < 1.0 the maximum hotttnesss for artists in the playlist
SongMaxHotttnesss, /// 0.0 < hotttnesss < 1.0 the maximum hotttnesss for songs in the playlist
SongMinHotttnesss, /// 0.0 < hotttnesss < 1.0 the maximum hotttnesss for songs in the playlist
ArtistMinLongitude, /// -180.0 < longitude < 180.0 the minimum longitude for the location of artists in the playlist
ArtistMaxLongitude, /// -180.0 < longitude < 180.0 the maximum longitude for the location of artists in the playlist
ArtistMinLatitude, /// -90.0 < latitude < 90.0 the minimum latitude for the location of artists in the playlist
ArtistMaxLatitude, /// -90.0 < latitude < 90.0 the maximum latitude for the location of artists in the playlist
Mode, /// (minor, major) 0, 1 the mode of songs in the playlist
Key, /// (c, c-sharp, d, e-flat, e, f, f-sharp, g, a-flat, a, b-flat, b) 0 - 11 the key of songs in the playlist
SongInformation, /// what sort of song information should be returned. Should be an Echonest::Song::SongInformation object
Sort, /// SortingType enum, the type of sorting to use,
Limit, /// true, false if true songs will be limited to those that appear in the catalog specified by the id: bucket
Audio, /// true, false, if true songs will be limited to those that have associated audio
DMCA /// true, false Only valid for dynamic playlists. Sets if playlist will follow DMCA rules (see web api doc for details)
};
typedef QPair< PlaylistParam, QVariant > PlaylistParamData;
typedef QVector< PlaylistParamData > PlaylistParams;
DynamicPlaylist();
~DynamicPlaylist();
DynamicPlaylist( const DynamicPlaylist& other );
DynamicPlaylist& operator=( const DynamicPlaylist& playlist );
/**
* Start a dynamic playlist with the given parameters.
* Once the QNetworkReply has finished, pass it to parseStart()
* and the inital song will be populated and returned. The sessionId(), currentSong(),
* and fetchNextSong() methods will then be useful.
*/
QNetworkReply* start( const PlaylistParams& params );
Song parseStart( QNetworkReply* ) throw( ParseError );
/**
* The session id of this dynamic playlist. If the playlist has ended, or has not been started,
* the result is empty.
*
*/
QByteArray sessionId() const;
void setSessionId( const QByteArray& id );
/**
* The current song of this dynamic playlist. Once this song has been played,
* or whenever is desired, call fetchNextSong() to get the next song.
*/
Song currentSong() const;
void setCurrentSong( const Song& song );
/**
* Queries The Echo Nest for the next playable song in this
* dynamic playlist.
*
* Once the query has emitted the finished() signal, pass it to parseNextSong(), which will
* return the new song to play. It will also set the current song to the newly parsed song.
*
* If the playlist has no more songs, the returned song object will be have no name nor id.
*
* @param rating The rating for the song that was just played. Ranges from 1 (lowest) to 5 (highest)
*
*/
QNetworkReply* fetchNextSong( int rating = -1);
Song parseNextSong( QNetworkReply* reply );
/**
* Generate a static playlist, according to the desired criteria.
*/
static QNetworkReply* staticPlaylist( const PlaylistParams& params );
static SongList parseStaticPlaylist( QNetworkReply* reply ) throw( ParseError );
private:
static QByteArray playlistParamToString( PlaylistParam param );
static QNetworkReply* generateInternal( const PlaylistParams& params, const QByteArray& type );
static QByteArray playlistSortToString(SortingType sorting);
static QByteArray playlistArtistPickToString(ArtistPick pick);
QSharedDataPointer<DynamicPlaylistData> d;
};
ECHONEST_EXPORT QDebug operator<<(QDebug d, const Echonest::DynamicPlaylist& playlist);
} // namespace
#endif

34
3rdparty/libechonest/Playlist_p.h vendored Normal file
View File

@ -0,0 +1,34 @@
/****************************************************************************************
* Copyright (c) 2010 Leo Franchi <lfranchi@kde.org> *
* *
* This program is free software; you can redistribute it and/or modify it under *
* the terms of the GNU General Public License as published by the Free Software *
* Foundation; either version 2 of the License, or (at your option) any later *
* version. *
* *
* This program is distributed in the hope that it will be useful, but WITHOUT ANY *
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A *
* PARTICULAR PURPOSE. See the GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License along with *
* this program. If not, see <http://www.gnu.org/licenses/>. *
****************************************************************************************/
#include "Song.h"
#include <QSharedData>
#include <QString>
class DynamicPlaylistData : public QSharedData
{
public:
DynamicPlaylistData() {}
DynamicPlaylistData(const DynamicPlaylistData& other)
{
sessionId = other.sessionId;
currentSong = other.currentSong;
}
QByteArray sessionId;
Echonest::Song currentSong;
};

311
3rdparty/libechonest/Song.cpp vendored Normal file
View File

@ -0,0 +1,311 @@
/****************************************************************************************
* Copyright (c) 2010 Leo Franchi <lfranchi@kde.org> *
* *
* This program is free software; you can redistribute it and/or modify it under *
* the terms of the GNU General Public License as published by the Free Software *
* Foundation; either version 2 of the License, or (at your option) any later *
* version. *
* *
* This program is distributed in the hope that it will be useful, but WITHOUT ANY *
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A *
* PARTICULAR PURPOSE. See the GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License along with *
* this program. If not, see <http://www.gnu.org/licenses/>. *
****************************************************************************************/
#include "Song.h"
#include "Config.h"
#include "Song_p.h"
#include "AudioSummary.h"
#include <QNetworkReply>
#include <QDebug>
#include <QtNetwork/QNetworkReply>
#include "Parsing_p.h"
#include <qxmlstream.h>
Echonest::Song::Song()
: d( new SongData )
{}
Echonest::Song::Song(const QByteArray& id, const QString& title, const QByteArray& artistId, const QString& artistName)
:d( new SongData )
{
d->id = id;
d->title = title;
d->artistId = artistId;
d->artistName = artistName;
}
Echonest::Song::Song(const Echonest::Song& other)
: d( other.d )
{
}
Echonest::Song::~Song()
{
}
Echonest::Song& Echonest::Song::operator=(const Echonest::Song& song)
{
d = song.d;
return *this;
}
QByteArray Echonest::Song::id() const
{
return d->id;
}
void Echonest::Song::setId(const QByteArray& id)
{
d->id = id;
}
QString Echonest::Song::title() const
{
return d->title;
}
void Echonest::Song::setTitle(const QString& title)
{
d->title = title;
}
QByteArray Echonest::Song::artistId() const
{
return d->artistId;
}
void Echonest::Song::setArtistId(const QByteArray& artistId)
{
d->artistId = artistId;
}
QString Echonest::Song::artistName() const
{
return d->artistName;
}
void Echonest::Song::setArtistName(const QString& artistName)
{
d->artistName = artistName;
}
QVector< Echonest::Track > Echonest::Song::tracks() const
{
return d->tracks;
}
void Echonest::Song::setTracks(const QVector< Echonest::Track >& tracks)
{
d->tracks = tracks;
}
qreal Echonest::Song::hotttnesss() const
{
return d->hotttnesss;
}
void Echonest::Song::setHotttnesss(qreal hotttnesss)
{
d->hotttnesss = hotttnesss;
}
qreal Echonest::Song::artistHotttnesss() const
{
return d->artistHotttnesss;
}
void Echonest::Song::setArtistHotttnesss(qreal artistHotttnesss)
{
d->artistHotttnesss = artistHotttnesss;
}
Echonest::AudioSummary Echonest::Song::audioSummary() const
{
return d->audioSummary;
}
void Echonest::Song::setAudioSummary(const Echonest::AudioSummary& summary)
{
d->audioSummary = summary;
}
qreal Echonest::Song::artistFamiliarity() const
{
return d->artistFamiliarity;
}
void Echonest::Song::setArtistFamiliarity(qreal artistFamiliarity)
{
d->artistFamiliarity = artistFamiliarity;
}
QString Echonest::Song::artistLocation() const
{
return d->artistLocation;
}
void Echonest::Song::setArtistLocation(const QString& artistLocation)
{
d->artistLocation = artistLocation;
}
QNetworkReply* Echonest::Song::fetchInformation( Echonest::Song::SongInformation parts ) const
{
QUrl url = Echonest::baseGetQuery( "song", "profile" );
url.addEncodedQueryItem( "id", d->id );
addQueryInformation( url, parts );
qDebug() << "Creating fetchInformation URL" << url;
return Echonest::Config::instance()->nam()->get( QNetworkRequest( url ) );
}
QNetworkReply* Echonest::Song::search( const Echonest::Song::SearchParams& params, Echonest::Song::SongInformation parts )
{
QUrl url = Echonest::baseGetQuery( "song", "search" );
addQueryInformation( url, parts );
SearchParams::const_iterator iter = params.constBegin();
for( ; iter < params.constEnd(); ++iter )
url.addQueryItem( QLatin1String( searchParamToString( iter->first ) ), iter->second.toString() );
qDebug() << "Creating search URL" << url;
return Echonest::Config::instance()->nam()->get( QNetworkRequest( url ) );
}
void Echonest::Song::parseInformation( QNetworkReply* reply ) throw( ParseError )
{
Echonest::Parser::checkForErrors( reply );
QXmlStreamReader xml( reply->readAll() );
Echonest::Parser::readStatus( xml );
// we'll just take the new data. it is given as a list even though it can only have 1 song as we specify the song id
QVector< Echonest::Song > songs = Echonest::Parser::parseSongList( xml );
if( !songs.size() == 1 ) { // no data for this song. returned empty.
return;
}
// copy any non-default values
Echonest::Song newSong = songs.at( 0 );
if( newSong.hotttnesss() >= 0 )
setHotttnesss( newSong.hotttnesss() );
if( newSong.artistHotttnesss() >= 0 )
setArtistHotttnesss( newSong.artistHotttnesss() );
if( newSong.artistFamiliarity() >= 0 )
setArtistFamiliarity( newSong.artistFamiliarity() );
if( !newSong.artistLocation().isEmpty() )
setArtistLocation( newSong.artistLocation() );
}
QVector< Echonest::Song > Echonest::Song::parseSearch( QNetworkReply* reply ) throw( ParseError )
{
Echonest::Parser::checkForErrors( reply );
QXmlStreamReader xml( reply->readAll() );
Echonest::Parser::readStatus( xml );
QVector<Echonest::Song> songs = Echonest::Parser::parseSongList( xml );
return songs;
}
QByteArray Echonest::Song::searchParamToString( Echonest::Song::SearchParam param )
{
switch( param )
{
case Echonest::Song::Title:
return "title";
case Echonest::Song::Artist:
return "artist";
case Echonest::Song::Combined:
return "combined";
case Echonest::Song::Description:
return "description";
case Echonest::Song::ArtistId:
return "artist_id";
case Echonest::Song::Results:
return "results";
case Echonest::Song::MaxTempo:
return "max_tempo";
case Echonest::Song::MinTempo:
return "min_tempo";
case Echonest::Song::MaxDanceability:
return "max_danceability";
case Echonest::Song::MinDanceability:
return "min_danceability";
case Echonest::Song::MaxComplexity:
return "max_complexity";
case Echonest::Song::MinComplexity:
return "min_complexity";
case Echonest::Song::MaxDuration:
return "max_duration";
case Echonest::Song::MinDuration:
return "min_duration";
case Echonest::Song::MaxLoudness:
return "max_loudness";
case Echonest::Song::MinLoudness:
return "min_loudness";
case Echonest::Song::MaxFamiliarity:
return "max_familiarity";
case Echonest::Song::MinFamiliarity:
return "min_familiarity";
case Echonest::Song::MaxHotttnesss:
return "max_hotttnesss";
case Echonest::Song::MinHotttnesss:
return "min_hotttnesss";
case Echonest::Song::MaxLongitude:
return "max_longitude";
case Echonest::Song::MinLongitude:
return "min_longitude";
case Echonest::Song::Mode:
return "mode";
case Echonest::Song::Key:
return "key";
case Echonest::Song::Sort:
return "sort";
}
return QByteArray();
}
void Echonest::Song::addQueryInformation(QUrl& url, Echonest::Song::SongInformation parts)
{
if( parts.testFlag( Echonest::Song::AudioSummaryInformation ) )
url.addEncodedQueryItem( "bucket", "audio_summary" );
if( parts.testFlag( Echonest::Song::Tracks ) )
url.addEncodedQueryItem( "bucket", "tracks" );
if( parts.testFlag( Echonest::Song::Hotttnesss ) )
url.addEncodedQueryItem( "bucket", "song_hotttnesss" );
if( parts.testFlag( Echonest::Song::ArtistHotttnesss ) )
url.addEncodedQueryItem( "bucket", "artist_hotttnesss" );
if( parts.testFlag( Echonest::Song::ArtistFamiliarity ) )
url.addEncodedQueryItem( "bucket", "artist_familiarity" );
if( parts.testFlag( Echonest::Song::ArtistLocation ) )
url.addEncodedQueryItem( "bucket", "artist_location" );
}
QString Echonest::Song::toString() const
{
return QString::fromLatin1( "Song(%1, %2, %3, %4)" ).arg( title() ).arg( artistName() ).arg( QString::fromLatin1( id() ) ).arg( QString::fromLatin1( artistId() ) );
}
QDebug Echonest::operator<<(QDebug d, const Echonest::Song& song)
{
d << song.toString();
return d.maybeSpace();
}

217
3rdparty/libechonest/Song.h vendored Normal file
View File

@ -0,0 +1,217 @@
/****************************************************************************************
* Copyright (c) 2010 Leo Franchi <lfranchi@kde.org> *
* *
* This program is free software; you can redistribute it and/or modify it under *
* the terms of the GNU General Public License as published by the Free Software *
* Foundation; either version 2 of the License, or (at your option) any later *
* version. *
* *
* This program is distributed in the hope that it will be useful, but WITHOUT ANY *
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A *
* PARTICULAR PURPOSE. See the GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License along with *
* this program. If not, see <http://www.gnu.org/licenses/>. *
****************************************************************************************/
#ifndef ECHONEST_SONG_H
#define ECHONEST_SONG_H
#include "echonest_export.h"
#include "Track.h"
#include <QSharedData>
#include <QHash>
#include <QVariant>
#include <QDebug>
#include <QVector>
#include "Config.h"
class QNetworkReply;
class SongData;
namespace Echonest{
class DynamicPlaylist; // forward declare for friend declaration
class AudioSummary;
/**
* This encapsulates an Echo Nest song---use it if you wish to get information about a song,
* search for a song, etc.
*
* This class is implicitly shared.
*/
class ECHONEST_EXPORT Song
{
public:
enum SongInformationFlag {
AudioSummaryInformation = 0x01,
Tracks = 0x02,
Hotttnesss = 0x04,
ArtistHotttnesss = 0x08,
ArtistFamiliarity = 0x10,
ArtistLocation = 0x20
};
Q_DECLARE_FLAGS( SongInformation, SongInformationFlag )
enum SearchParam {
Title,
Artist,
Combined,
Description,
ArtistId,
Results,
MaxTempo,
MinTempo,
MaxDanceability,
MinDanceability,
MaxComplexity,
MinComplexity,
MaxDuration,
MinDuration,
MaxLoudness,
MinLoudness,
MaxFamiliarity,
MinFamiliarity,
MaxHotttnesss,
MinHotttnesss,
MaxLongitude,
MinLongitude,
Mode,
Key,
Sort
};
typedef QPair< Echonest::Song::SearchParam, QVariant > SearchParamData;
typedef QVector< SearchParamData > SearchParams;
Song();
Song( const QByteArray& id, const QString& title, const QByteArray& artistId, const QString& artistName );
Song( const Song& other );
Song& operator=(const Song& song);
~Song();
/**
* The following pieces of data are present in all Song objects, and do not require
* on-demand fetching.
*/
QByteArray id() const;
void setId( const QByteArray& id );
QString title() const;
void setTitle( const QString& title );
QString artistName() const;
void setArtistName( const QString& artistName );
QByteArray artistId() const;
void setArtistId( const QByteArray& artistId );
/**
* The following require fetching from The Echo Nest, so call
* fetchInformation() with the type of data you want first.
*
* If you ask for this information before calling parseInformation()
* with the respective data, the result is undefined.
*/
/**
* The full audio summary and analysis of this song.
*/
AudioSummary audioSummary() const;
void setAudioSummary( const AudioSummary& summary );
/**
* The associated Track objects with acoustic track information
*/
QVector< Track > tracks() const;
void setTracks( const QVector< Track >& tracks );
/**
* The "hotttnesss" metric of this song.
*/
qreal hotttnesss() const;
void setHotttnesss( qreal hotttnesss );
/**
* The "hotttnesss" metric of this song's artist.
*/
qreal artistHotttnesss() const;
void setArtistHotttnesss( qreal artistHotttnesss );
/**
* The familiarity metric of this song's artist.
*/
qreal artistFamiliarity() const;
void setArtistFamiliarity( qreal artistFamiliarity );
/**
* The location of this artist.
*/
QString artistLocation() const;
void setArtistLocation( const QString& artistLocation );
/**
* This fetch the data from The Echo Nest for the requested data, so it
* returns a QNetworkReply*. When the finished() signal is emitted
* from the QNetworkReply object call parseInformation() to save the
* data back to this Song object.
*
*/
QNetworkReply* fetchInformation( SongInformation parts ) const;
/**
* Search for a song from The Echo Nest with the given search parameters. See
* http://developer.echonest.com/docs/v4/song.html#search for a description of the
* parameters and data types.
*
* The result will contain the requested information from the SongInformation flags, and
* can be extracted in the parseSearch() function.
*
*/
static QNetworkReply* search( const SearchParams& params, SongInformation parts );
/**
* Parse the result of the fetchInformation() call.
* For each requested SongInformationFlag in the original request, the respective
* data will be saved to this Song object.
*/
void parseInformation( QNetworkReply* reply ) throw( ParseError );
/**
* Parse the result of the search() call.
*/
static QVector<Song> parseSearch( QNetworkReply* reply ) throw( ParseError );
/**
* Identify a song from a given Echo Nest fingerprint hash code
*
* NOTE this is currently not supported, as the Echo Nest hash code
* generator is not currently open source, so I don't care much
* for it.
*
* static QNetworkReply* identify( ) const;
*/
QString toString() const;
friend class DynamicPlaylist;
private:
static QByteArray searchParamToString( SearchParam param );
static void addQueryInformation( QUrl& url, SongInformation parts );
QSharedDataPointer<SongData> d;
};
typedef QVector< Song > SongList;
ECHONEST_EXPORT QDebug operator<<(QDebug d, const Song &song);
Q_DECLARE_OPERATORS_FOR_FLAGS(Song::SongInformation)
} // namespace
Q_DECLARE_METATYPE( Echonest::Song::SongInformation )
#endif

66
3rdparty/libechonest/Song_p.h vendored Normal file
View File

@ -0,0 +1,66 @@
/****************************************************************************************
* Copyright (c) 2010 Leo Franchi <lfranchi@kde.org> *
* *
* This program is free software; you can redistribute it and/or modify it under *
* the terms of the GNU General Public License as published by the Free Software *
* Foundation; either version 2 of the License, or (at your option) any later *
* version. *
* *
* This program is distributed in the hope that it will be useful, but WITHOUT ANY *
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A *
* PARTICULAR PURPOSE. See the GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License along with *
* this program. If not, see <http://www.gnu.org/licenses/>. *
****************************************************************************************/
#ifndef ECHONEST_SONG_P_H
#define ECHONEST_SONG_P_H
#include "Track.h"
#include "AudioSummary.h"
#include <QSharedData>
#include <QString>
#include <QVector>
class SongData : public QSharedData
{
public:
SongData() : hotttnesss( -1 ), artistHotttnesss( -1 ), artistFamiliarity( -1 ) {}
SongData(const SongData& other)
{
id = other.id;
title = other.title;
artistName = other.artistName;
artistId = other.artistId;
audioSummary = other.audioSummary;
tracks = other.tracks;
hotttnesss = other.hotttnesss;
artistHotttnesss = other.artistHotttnesss;
artistFamiliarity = other.artistFamiliarity;
artistLocation = other.artistLocation;
}
~SongData() {}
QByteArray id;
QString title;
QString artistName;
QByteArray artistId;
// The rest are optional that require manual fetching to populate
Echonest::AudioSummary audioSummary;
QVector<Echonest::Track> tracks;
qreal hotttnesss;
qreal artistHotttnesss;
qreal artistFamiliarity;
QString artistLocation;
};
#endif

247
3rdparty/libechonest/Track.cpp vendored Normal file
View File

@ -0,0 +1,247 @@
/****************************************************************************************
* Copyright (c) 2010 Leo Franchi <lfranchi@kde.org> *
* *
* This program is free software; you can redistribute it and/or modify it under *
* the terms of the GNU General Public License as published by the Free Software *
* Foundation; either version 2 of the License, or (at your option) any later *
* version. *
* *
* This program is distributed in the hope that it will be useful, but WITHOUT ANY *
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A *
* PARTICULAR PURPOSE. See the GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License along with *
* this program. If not, see <http://www.gnu.org/licenses/>. *
****************************************************************************************/
#include "Track.h"
#include "Track_p.h"
#include <QNetworkReply>
#include "Config.h"
#include <qfileinfo.h>
#include "Parsing_p.h"
Echonest::Track::Track()
: d( new TrackData )
{
}
Echonest::Track::Track(const Echonest::Track& other)
: d( other.d )
{}
Echonest::Track::~Track()
{
}
Echonest::Track& Echonest::Track::operator=(const Echonest::Track& track)
{
d = track.d;
return *this;
}
QString Echonest::Track::artist() const
{
return d->artist;
}
void Echonest::Track::setArtist(const QString& artist)
{
d->artist = artist;
}
QString Echonest::Track::title() const
{
return d->title;
}
void Echonest::Track::setTitle(const QString& title)
{
d->title = title;
}
QByteArray Echonest::Track::id() const
{
return d->id;
}
void Echonest::Track::setId(const QByteArray& id)
{
d->id = id;
}
QByteArray Echonest::Track::md5() const
{
return d->md5;
}
void Echonest::Track::setMD5(const QByteArray& md5)
{
d->md5 = md5;
}
QString Echonest::Track::release() const
{
return d->release;
}
void Echonest::Track::setRelease(const QString& release)
{
d->release = release;
}
QString Echonest::Track::analyzerVersion() const
{
return d->analyzer_version;
}
void Echonest::Track::setAnalyzerVersion(const QString& analyzerVersion)
{
d->analyzer_version = analyzerVersion;
}
int Echonest::Track::bitrate() const
{
return d->bitrate;
}
void Echonest::Track::setBitrate(int bitrate)
{
d->bitrate = bitrate;
}
int Echonest::Track::samplerate() const
{
return d->samplerate;
}
void Echonest::Track::setSamplerate(int samplerate)
{
d->samplerate = samplerate;
}
QByteArray Echonest::Track::audioMD5() const
{
return d->audio_md5;
}
void Echonest::Track::setAudioMD5(const QByteArray& md5)
{
d->audio_md5 = md5;
}
Echonest::Analysis::AnalysisStatus Echonest::Track::status() const
{
return Echonest::statusToEnum( d->status );
}
void Echonest::Track::setStatus( Echonest::Analysis::AnalysisStatus status )
{
d->status = Echonest::statusToString( status );
}
Echonest::AudioSummary Echonest::Track::audioSummary() const
{
return d->audio_summary;
}
void Echonest::Track::setAudioSummary( const Echonest::AudioSummary& summary )
{
d->audio_summary = summary;
}
QNetworkReply* Echonest::Track::profileFromTrackId( const QByteArray& id )
{
QUrl url = Echonest::baseGetQuery( "track", "profile" );
url.addEncodedQueryItem( "id", id );
url.addEncodedQueryItem( "bucket", "audio_summary" );
qDebug() << "Creating profileFromTrackId URL" << url;
return Echonest::Config::instance()->nam()->get( QNetworkRequest( url ) );
}
QNetworkReply* Echonest::Track::profileFromMD5( const QByteArray& md5 )
{
QUrl url = Echonest::baseGetQuery( "track", "profile" );
url.addEncodedQueryItem( "md5", md5 );
url.addEncodedQueryItem( "bucket", "audio_summary" );
qDebug() << "Creating profileFromMD5 URL" << url;
return Echonest::Config::instance()->nam()->get( QNetworkRequest( url ) );
}
QNetworkReply* Echonest::Track::uploadLocalFile( const QUrl& localFile, const QByteArray& data, bool waitForResult )
{
QUrl url = Echonest::baseGetQuery( "track", "upload" );
QFileInfo info( localFile.path() );
url.addQueryItem( QLatin1String( "filetype" ), info.suffix() );
url.addEncodedQueryItem( "bucket", "audio_summary" );
url.addEncodedQueryItem( "wait", ( waitForResult ? "true" : "false" ) );
QNetworkRequest request( url );
request.setHeader( QNetworkRequest::ContentTypeHeader, QLatin1String( "application/octet-stream" ) );
// qDebug() << "Uploading local file to" << url;
return Echonest::Config::instance()->nam()->post( request, data );
}
QNetworkReply* Echonest::Track::uploadURL( const QUrl& remoteURL, bool waitForResult )
{
QUrl url = Echonest::baseGetQuery( "track", "upload" );
url.addEncodedQueryItem( "url", remoteURL.toEncoded() );
url.addEncodedQueryItem( "bucket", "audio_summary" );
url.addEncodedQueryItem( "wait", ( waitForResult ? "true" : "false" ) );
qDebug() << "Uploading URL:" << url;
return Echonest::Config::instance()->nam()->post( QNetworkRequest( url ), QByteArray() );
}
QNetworkReply* Echonest::Track::analyzeTrackId( const QByteArray& id, bool wait )
{
QUrl url = Echonest::baseGetQuery( "track", "analyze" );
url.addEncodedQueryItem( "id", id );
url.addEncodedQueryItem( "bucket", "audio_summary" );
url.addEncodedQueryItem( "wait", ( wait ? "true" : "false" ) );
qDebug() << "Creating analyzeTrackId URL" << url;
return Echonest::Config::instance()->nam()->post( QNetworkRequest( url ), QByteArray() );
}
QNetworkReply* Echonest::Track::analyzeTrackMD5( const QByteArray& md5, bool wait )
{
QUrl url = Echonest::baseGetQuery( "track", "analyze" );
url.addEncodedQueryItem( "md5", md5 );
url.addEncodedQueryItem( "bucket", "audio_summary" );
url.addEncodedQueryItem( "wait", ( wait ? "true" : "false" ) );
qDebug() << "Creating analyzeTrackMD5 URL" << url;
return Echonest::Config::instance()->nam()->post( QNetworkRequest( url ), QByteArray() );
}
Echonest::Track Echonest::Track::parseProfile( QNetworkReply* finishedReply ) throw( Echonest::ParseError )
{
Echonest::Parser::checkForErrors( finishedReply );
QByteArray data = finishedReply->readAll();
qDebug() << data;
QXmlStreamReader xml( data );
Echonest::Parser::readStatus( xml );
Echonest::Track track = Echonest::Parser::parseTrack( xml );
return track;
}
QDebug Echonest::operator<<(QDebug d, const Echonest::Track& track)
{
d << QString::fromLatin1( "Track(%1, %2, %3" ).arg( track.title() ).arg( track.artist() ).arg( track.release() );
return d.maybeSpace();
}

185
3rdparty/libechonest/Track.h vendored Normal file
View File

@ -0,0 +1,185 @@
/****************************************************************************************
* Copyright (c) 2010 Leo Franchi <lfranchi@kde.org> *
* *
* This program is free software; you can redistribute it and/or modify it under *
* the terms of the GNU General Public License as published by the Free Software *
* Foundation; either version 2 of the License, or (at your option) any later *
* version. *
* *
* This program is distributed in the hope that it will be useful, but WITHOUT ANY *
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A *
* PARTICULAR PURPOSE. See the GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License along with *
* this program. If not, see <http://www.gnu.org/licenses/>. *
****************************************************************************************/
#ifndef ECHONEST_TRACK_H
#define ECHONEST_TRACK_H
#include "AudioSummary.h"
#include "echonest_export.h"
#include "Util.h"
#include <QObject>
#include <QString>
#include <QDebug>
#include <QSharedData>
#include <QUrl>
#include "Config.h"
class QNetworkReply;
class TrackData;
namespace Echonest
{
/**
* Upload-based Echo Nest Track API. If you want to search The Echo Nest for songs, use the Song API.
* If you want to upload your own files and retrieve the acoustic information about them, use this Track
* class. You can also fetch acoustic information from a track if you have the Track ID or MD5 of the file.
*
* A Track encapsulates the audio analysis from The Echo Nest.
*
* This class is implicitly shared.
*
*/
class ECHONEST_EXPORT Track
{
public:
Track();
Track( const Track& other );
Track& operator=( const Track& track );
~Track();
/**
* The track's artist.
*/
QString artist() const;
void setArtist( const QString& artist );
/**
* The track's title.
*/
QString title() const;
void setTitle( const QString& title );
/**
* The Echo Nest artist ID for this track.
*/
QByteArray id() const;
void setId( const QByteArray& id );
/**
* The MD5 hash of the track.
*/
QByteArray md5() const;
void setMD5( const QByteArray& md5 );
/**
* The album name of this track.
*/
QString release() const;
void setRelease( const QString& release );
/**
* The MD5 hashsum of the audio data.
*/
QByteArray audioMD5() const;
void setAudioMD5( const QByteArray& md5 );
/**
* The analyzer version that was used in this track's analysis.
*/
QString analyzerVersion() const;
void setAnalyzerVersion( const QString& analyzerVersion );
/**
* The samplerate of the track
*/
int samplerate() const;
void setSamplerate( int samplerate );
/**
* The bitrate of the track
*/
int bitrate() const;
void setBitrate( int );
/**
* The analysis status
*/
Analysis::AnalysisStatus status() const;
void setStatus( Analysis::AnalysisStatus );
/**
* The full audio summary of the track. This contains information about the track's bars,
* beats, sections, and detailed segment information as well as more metadata about the song's
* acoustic properties.
*
* Information about how to interpret the results of the audio summary can be found here:
* http://developer.echonest.com/docs/v4/_static/AnalyzeDocumentation_2.2.pdf
*/
AudioSummary audioSummary() const;
void setAudioSummary( const AudioSummary& summary );
/**
* Get a track object from the md5 hash of a song's contents.
*
* Call parseProfile() to get the track itself once the
* QNetworkReply() emits the finished() signal.
*/
static QNetworkReply* profileFromMD5( const QByteArray& md5 );
/**
* Get a track object from an Echo Nest track id.
*
* Call parseProfile() to get the track itself once the
* QNetworkReply() emits the finished() signal.
*/
static QNetworkReply* profileFromTrackId( const QByteArray& id );
/**
* Upload a track to The Echo Nest for analysis. The file can either be
* a local filetype and include the file data as a parameter, or a url to a file on the internet.
*
* When the QNetworkReply emits its finished() signal, you can call parseProfile()
* to get the resulting Track object. Be sure to check the status of the new track,
* as it might be 'pending', which means it is still being analyzed and must be asked
* for again later.
*
* Note that in the case of uploading a local file, the data QByteArray must stay in scope for the
* whole completion of the upload operation.
*/
static QNetworkReply* uploadLocalFile( const QUrl& localFile, const QByteArray& data, bool waitForResult = true );
static QNetworkReply* uploadURL( const QUrl& remoteURL, bool waitForResult = true );
/**
* Analyze a previously uploaded track with the current version of the analyzer.
* It can be referenced by either track ID or file md5.
*/
static QNetworkReply* analyzeTrackId( const QByteArray& id, bool wait = true );
static QNetworkReply* analyzeTrackMD5( const QByteArray& id, bool wait = true );
/**
* Parse the result of a track request, and turn it into a
* Track object.
*
* Call this function after the QNetworkReply* object returned
* from the parse*, upload*, and analyze* emits its finished() signal
*/
static Track parseProfile( QNetworkReply* ) throw( ParseError );
private:
QSharedDataPointer<TrackData> d;
};
ECHONEST_EXPORT QDebug operator<<(QDebug d, const Echonest::Track& track);
} // namespace
#endif

59
3rdparty/libechonest/Track_p.h vendored Normal file
View File

@ -0,0 +1,59 @@
/****************************************************************************************
* Copyright (c) 2010 Leo Franchi <lfranchi@kde.org> *
* *
* This program is free software; you can redistribute it and/or modify it under *
* the terms of the GNU General Public License as published by the Free Software *
* Foundation; either version 2 of the License, or (at your option) any later *
* version. *
* *
* This program is distributed in the hope that it will be useful, but WITHOUT ANY *
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A *
* PARTICULAR PURPOSE. See the GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License along with *
* this program. If not, see <http://www.gnu.org/licenses/>. *
****************************************************************************************/
#ifndef ECHONEST_TRACK_P_H
#define ECHONEST_TRACK_P_H
#include "AudioSummary.h"
#include <QSharedData>
#include <QString>
class TrackData : public QSharedData
{
public:
TrackData() {}
TrackData(const TrackData& other)
{
analyzer_version = other.analyzer_version;
artist = other.artist;
bitrate = other.bitrate;
id = other.id;
md5 = other.md5;
release = other.release;
samplerate = other.samplerate;
status = other.status;
title = other.title;
}
QString artist;
QString analyzer_version;
int bitrate;
QByteArray id;
QByteArray md5;
QString release;
QByteArray audio_md5;
int samplerate;
QString status;
QString title;
Echonest::AudioSummary audio_summary;
};
#endif

49
3rdparty/libechonest/Util.cpp vendored Normal file
View File

@ -0,0 +1,49 @@
/****************************************************************************************
* Copyright (c) 2010 Leo Franchi <lfranchi@kde.org> *
* *
* This program is free software; you can redistribute it and/or modify it under *
* the terms of the GNU General Public License as published by the Free Software *
* Foundation; either version 2 of the License, or (at your option) any later *
* version. *
* *
* This program is distributed in the hope that it will be useful, but WITHOUT ANY *
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A *
* PARTICULAR PURPOSE. See the GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License along with *
* this program. If not, see <http://www.gnu.org/licenses/>. *
****************************************************************************************/
#include "Util.h"
#include <QString>
Echonest::Analysis::AnalysisStatus Echonest::statusToEnum(const QString& status)
{
if( status == QLatin1String("unknown") ) {
return Echonest::Analysis::Unknown;
} else if( status == QLatin1String("pending") ) {
return Echonest::Analysis::Pending;
} else if( status == QLatin1String("complete") ) {
return Echonest::Analysis::Complete;
} else if( status == QLatin1String("error" )) {
return Echonest::Analysis::Error;
}
return Echonest::Analysis::Unknown;
}
QString Echonest::statusToString(Echonest::Analysis::AnalysisStatus status)
{
switch( status )
{
case Echonest::Analysis::Unknown:
return QLatin1String( "unknown" );
case Echonest::Analysis::Pending:
return QLatin1String( "pending" );
case Echonest::Analysis::Complete:
return QLatin1String( "complete" );
case Echonest::Analysis::Error:
return QLatin1String( "error" );
}
return QString();
}

80
3rdparty/libechonest/Util.h vendored Normal file
View File

@ -0,0 +1,80 @@
/****************************************************************************************
* Copyright (c) 2010 Leo Franchi <lfranchi@kde.org> *
* *
* This program is free software; you can redistribute it and/or modify it under *
* the terms of the GNU General Public License as published by the Free Software *
* Foundation; either version 2 of the License, or (at your option) any later *
* version. *
* *
* This program is distributed in the hope that it will be useful, but WITHOUT ANY *
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A *
* PARTICULAR PURPOSE. See the GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License along with *
* this program. If not, see <http://www.gnu.org/licenses/>. *
****************************************************************************************/
#ifndef ECHONEST_UTIL_H
#define ECHONEST_UTIL_H
#include <QVector>
#include <QUrl>
/**
* Some shared declarations
*/
namespace Echonest
{
namespace Analysis
{
enum AnalysisStatus {
Unknown = 0,
Pending = 1,
Complete = 2,
Error = 4
};
}
typedef struct
{
qreal confidence;
qreal duration;
qreal start;
} AudioChunk;
typedef AudioChunk Bar;
typedef AudioChunk Beat;
typedef AudioChunk Section;
typedef AudioChunk Tatum;
typedef struct
{
qreal confidence;
qreal duration;
qreal loudness_max;
qreal loudness_max_time;
qreal loudness_start;
QVector< qreal > pitches;
qreal start;
QVector< qreal > timbre;
} Segment;
typedef QVector< Bar > BarList;
typedef QVector< Beat > BeatList;
typedef QVector< Section > SectionList;
typedef QVector< Tatum > TatumList;
typedef QVector< Segment > SegmentList;
typedef struct {
QUrl url;
QString attribution;
QString type;
} License;
Analysis::AnalysisStatus statusToEnum( const QString& status );
QString statusToString( Analysis::AnalysisStatus status );
}
#endif

28
3rdparty/libechonest/echonest_export.h vendored Normal file
View File

@ -0,0 +1,28 @@
/****************************************************************************************
* Copyright (c) 2010 Leo Franchi <lfranchi@kde.org> *
* *
* This program is free software; you can redistribute it and/or modify it under *
* the terms of the GNU General Public License as published by the Free Software *
* Foundation; either version 2 of the License, or (at your option) any later *
* version. *
* *
* This program is distributed in the hope that it will be useful, but WITHOUT ANY *
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A *
* PARTICULAR PURPOSE. See the GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License along with *
* this program. If not, see <http://www.gnu.org/licenses/>. *
****************************************************************************************/
#ifndef ECHONEST_EXPORT_H
#define ECHONEST_EXPORT_H
#ifdef Q_CC_MSVC
#define ECHONEST_EXPORT __declspec(dllimport)
#elif __GNUC__ >= 4
#define ECHONEST_EXPORT __attribute__ ((visibility("default")))
#else
#define ECHONEST_EXPORT
#endif
#endif

View File

View File

@ -208,6 +208,8 @@ else (USE_SYSTEM_QXT)
endif (NOT APPLE)
endif (USE_SYSTEM_QXT)
set(ECHONEST_INCLUDE_DIRS ${CMAKE_BINARY_DIR}/3rdparty/libechonest)
# Subdirectories
add_subdirectory(src)
if (WIN32)
@ -215,6 +217,7 @@ if (WIN32)
endif (WIN32)
add_subdirectory(3rdparty/universalchardet)
add_subdirectory(3rdparty/fancytabwidget)
add_subdirectory(3rdparty/libechonest)
add_subdirectory(tests)
add_subdirectory(dist)
add_subdirectory(tools/ultimate_lyrics_parser)

View File

@ -1,6 +1,7 @@
<RCC>
<qresource prefix="/">
<file>mainwindow.css</file>
<file>songinfo.css</file>
<file>schema.sql</file>
<file>volumeslider-handle_glow.png</file>
<file>volumeslider-handle.png</file>

8
data/songinfo.css Normal file
View File

@ -0,0 +1,8 @@
QScrollArea {
background: palette(base);
}
QTextEdit {
border: 0px;
}

View File

@ -17,6 +17,7 @@ include_directories(${LIBPROJECTM_INCLUDE_DIRS})
include_directories(${QTSINGLEAPPLICATION_INCLUDE_DIRS})
include_directories(${QTIOCOMPRESSOR_INCLUDE_DIRS})
include_directories(${QXT_INCLUDE_DIRS})
include_directories(${ECHONEST_INCLUDE_DIRS})
cmake_policy(SET CMP0011 NEW)
include(../cmake/AddEngine.cmake)
@ -127,6 +128,11 @@ set(SOURCES
radio/savedradio.cpp
radio/somafmservice.cpp
songinfo/artistinfofetcher.cpp
songinfo/artistinfoprovider.cpp
songinfo/artistinfoview.cpp
songinfo/collapsibleinfopane.cpp
songinfo/echonestartistinfo.cpp
songinfo/htmlscraper.cpp
songinfo/lyricfetcher.cpp
songinfo/lyricprovider.cpp
@ -257,6 +263,11 @@ set(HEADERS
radio/savedradio.h
radio/somafmservice.h
songinfo/artistinfofetcher.h
songinfo/artistinfoprovider.h
songinfo/artistinfoview.h
songinfo/collapsibleinfopane.h
songinfo/echonestartistinfo.h
songinfo/htmlscraper.h
songinfo/lyricfetcher.h
songinfo/lyricprovider.h
@ -681,6 +692,7 @@ add_dependencies(clementine_lib pot)
target_link_libraries(clementine_lib
chardet
fancytabwidget
echonest
${GOBJECT_LIBRARIES}
${GLIB_LIBRARIES}
${TAGLIB_LIBRARIES}

View File

@ -46,6 +46,8 @@
#include <glib-object.h>
#include <glib/gutils.h>
#include <echonest/Config.h>
#ifdef Q_WS_X11
# include <QDBusConnection>
# include <QDBusMetaType>
@ -198,6 +200,9 @@ int main(int argc, char *argv[]) {
NetworkAccessManager network;
Echonest::Config::instance()->setAPIKey("DFLFLJBUF4EGTXHIG");
Echonest::Config::instance()->setNetworkAccessManager(network.network());
// MPRIS DBus interface.
#ifdef Q_WS_X11
qDBusRegisterMetaType<DBusStatus>();

View File

@ -0,0 +1,39 @@
/* This file is part of Clementine.
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#include "artistinfofetcher.h"
#include "echonestartistinfo.h"
ArtistInfoFetcher::ArtistInfoFetcher(QObject* parent)
: QObject(parent),
next_id_(1)
{
AddProvider(new EchoNestArtistInfo(this));
}
void ArtistInfoFetcher::AddProvider(ArtistInfoProvider* provider) {
providers_ << provider;
connect(provider, SIGNAL(ImageReady(int,QUrl)), SIGNAL(ImageReady(int,QUrl)));
connect(provider, SIGNAL(InfoReady(int,QString,QWidget*)), SIGNAL(InfoReady(int,QString,QWidget*)));
}
int ArtistInfoFetcher::FetchInfo(const QString& artist) {
const int id = next_id_ ++;
foreach (ArtistInfoProvider* provider, providers_) {
provider->FetchInfo(id, artist);
}
return id;
}

View File

@ -0,0 +1,46 @@
/* This file is part of Clementine.
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ARTISTINFOFETCHER_H
#define ARTISTINFOFETCHER_H
#include <QObject>
#include <QUrl>
class ArtistInfoProvider;
class ArtistInfoFetcher : public QObject {
Q_OBJECT
public:
ArtistInfoFetcher(QObject* parent = 0);
int FetchInfo(const QString& artist);
signals:
void ImageReady(int id, const QUrl& url);
void InfoReady(int id, const QString& title, QWidget* widget);
private:
void AddProvider(ArtistInfoProvider* provider);
private:
QList<ArtistInfoProvider*> providers_;
int next_id_;
};
#endif // ARTISTINFOFETCHER_H

View File

@ -0,0 +1,22 @@
/* This file is part of Clementine.
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#include "artistinfoprovider.h"
ArtistInfoProvider::ArtistInfoProvider(QObject* parent)
: QObject(parent)
{
}

View File

@ -0,0 +1,36 @@
/* This file is part of Clementine.
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ARTISTINFOPROVIDER_H
#define ARTISTINFOPROVIDER_H
#include <QObject>
#include <QUrl>
class ArtistInfoProvider : public QObject {
Q_OBJECT
public:
ArtistInfoProvider(QObject* parent = 0);
virtual void FetchInfo(int id, const QString& artist) = 0;
signals:
void ImageReady(int id, const QUrl& url);
void InfoReady(int id, const QString& title, QWidget* widget);
};
#endif // ARTISTINFOPROVIDER_H

View File

@ -0,0 +1,95 @@
/* This file is part of Clementine.
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#include "artistinfofetcher.h"
#include "artistinfoview.h"
#include "collapsibleinfopane.h"
#include <QFile>
#include <QScrollArea>
#include <QTextEdit>
#include <QVBoxLayout>
#include <QtDebug>
ArtistInfoView::ArtistInfoView(QWidget *parent)
: SongInfoBase(parent),
fetcher_(new ArtistInfoFetcher(this)),
current_request_id_(-1),
scroll_area_(new QScrollArea),
container_(new QVBoxLayout)
{
connect(fetcher_, SIGNAL(ImageReady(int,QUrl)), SLOT(ImageReady(int,QUrl)));
connect(fetcher_, SIGNAL(InfoReady(int,QString,QWidget*)), SLOT(InfoReady(int,QString,QWidget*)));
// Add the top-level scroll area
setLayout(new QVBoxLayout);
layout()->setContentsMargins(0, 0, 0, 0);
layout()->addWidget(scroll_area_);
// Add a container widget to the scroll area
QWidget* container_widget = new QWidget;
container_widget->setLayout(container_);
container_widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
container_->setSizeConstraint(QLayout::SetNoConstraint);
scroll_area_->setWidget(container_widget);
scroll_area_->setWidgetResizable(true);
// Add a spacer to the bottom of the container
container_->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Fixed, QSizePolicy::Expanding));
// Set stylesheet
QFile stylesheet(":/songinfo.css");
stylesheet.open(QIODevice::ReadOnly);
setStyleSheet(QString::fromAscii(stylesheet.readAll()));
}
ArtistInfoView::~ArtistInfoView() {
}
void ArtistInfoView::AddChild(QWidget* widget) {
children_ << widget;
container_->insertWidget(container_->count() - 1, widget);
widget->show();
}
void ArtistInfoView::Clear() {
qDeleteAll(children_);
children_.clear();
}
void ArtistInfoView::Update(const Song& metadata) {
Clear();
current_request_id_ = fetcher_->FetchInfo(metadata.artist());
}
void ArtistInfoView::ImageReady(int id, const QUrl& url) {
if (id != current_request_id_)
return;
qDebug() << "Image" << url;
}
void ArtistInfoView::InfoReady(int id, const QString& title, QWidget* widget) {
if (id != current_request_id_) {
delete widget;
return;
}
CollapsibleInfoPane* pane = new CollapsibleInfoPane(this);
pane->SetTitle(title);
pane->SetWidget(widget);
AddChild(pane);
}

View File

@ -0,0 +1,54 @@
/* This file is part of Clementine.
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ARTISTINFOVIEW_H
#define ARTISTINFOVIEW_H
#include "songinfobase.h"
class ArtistInfoFetcher;
class QScrollArea;
class QVBoxLayout;
class ArtistInfoView : public SongInfoBase {
Q_OBJECT
public:
ArtistInfoView(QWidget* parent = 0);
~ArtistInfoView();
protected:
void Update(const Song& metadata);
private:
void AddChild(QWidget* widget);
void Clear();
private slots:
void ImageReady(int id, const QUrl& url);
void InfoReady(int id, const QString& title, QWidget* widget);
private:
ArtistInfoFetcher* fetcher_;
int current_request_id_;
QScrollArea* scroll_area_;
QVBoxLayout* container_;
QList<QWidget*> children_;
};
#endif // ARTISTINFOVIEW_H

View File

@ -0,0 +1,99 @@
/* This file is part of Clementine.
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#include "collapsibleinfopane.h"
#include <QStylePainter>
#include <QStyleOption>
#include <QVBoxLayout>
const int CollapsibleInfoPane::kMargin = 6;
const int CollapsibleInfoPane::kTitleHeight = 20;
CollapsibleInfoPane::CollapsibleInfoPane(QWidget* parent)
: QWidget(parent),
widget_(NULL),
expanded_(true)
{
QVBoxLayout* layout = new QVBoxLayout(this);
layout->setContentsMargins(kMargin, kTitleHeight, kMargin, 0);
setLayout(layout);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum);
setMinimumHeight(kTitleHeight);
}
void CollapsibleInfoPane::SetTitle(const QString& title) {
title_ = title;
update();
}
void CollapsibleInfoPane::SetWidget(QWidget* widget) {
if (widget_)
delete widget_;
widget_ = widget;
layout()->addWidget(widget);
}
void CollapsibleInfoPane::Collapse() {
expanded_ = false;
update();
}
void CollapsibleInfoPane::Expand() {
expanded_ = true;
update();
}
void CollapsibleInfoPane::paintEvent(QPaintEvent* e) {
QStylePainter p(this);
QRect title_rect(0, 0, width(), kTitleHeight);
QRect indicator_rect(0, 0, kTitleHeight, kTitleHeight);
QRect text_rect(title_rect);
text_rect.setLeft(kTitleHeight + 6);
// Draw the background
const QColor bg_color_1(palette().color(QPalette::Highlight));
const QColor bg_color_2(palette().color(QPalette::Highlight).lighter(125));
const QColor bg_border(palette().color(QPalette::Dark));
QLinearGradient bg_brush(title_rect.topLeft(), title_rect.bottomLeft());
bg_brush.setColorAt(0.0, bg_color_1);
bg_brush.setColorAt(0.5, bg_color_2);
bg_brush.setColorAt(1.0, bg_color_1);
p.setPen(bg_border);
p.drawLine(title_rect.topLeft(), title_rect.topRight());
p.drawLine(title_rect.bottomLeft(), title_rect.bottomRight());
p.setPen(Qt::NoPen);
p.fillRect(title_rect, bg_brush);
// Draw the expand/collapse indicator
QStyleOption opt;
opt.initFrom(this);
opt.rect = indicator_rect;
opt.state |= QStyle::State_Children;
if (expanded_)
opt.state |= QStyle::State_Open;
p.drawPrimitive(QStyle::PE_IndicatorBranch, opt);
// Draw the title text
p.setPen(palette().color(QPalette::HighlightedText));
p.drawText(text_rect, Qt::AlignLeft | Qt::AlignVCenter, title_);
}

View File

@ -0,0 +1,47 @@
/* This file is part of Clementine.
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef COLLAPSIBLEINFOPANE_H
#define COLLAPSIBLEINFOPANE_H
#include <QWidget>
class CollapsibleInfoPane : public QWidget {
Q_OBJECT
public:
CollapsibleInfoPane(QWidget* parent = 0);
static const int kTitleHeight;
static const int kMargin;
void SetTitle(const QString& title);
void SetWidget(QWidget* widget);
public slots:
void Expand();
void Collapse();
protected:
void paintEvent(QPaintEvent* e);
private:
QString title_;
QWidget* widget_;
bool expanded_;
};
#endif // COLLAPSIBLEINFOPANE_H

View File

@ -0,0 +1,89 @@
/* This file is part of Clementine.
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#include "echonestartistinfo.h"
#include <QTextEdit>
#include <echonest/Artist.h>
#include <boost/scoped_ptr.hpp>
struct EchoNestArtistInfo::Request {
Request(int id) : id_(id), artist_(new Echonest::Artist) {}
int id_;
boost::scoped_ptr<Echonest::Artist> artist_;
QList<QNetworkReply*> pending_replies_;
};
EchoNestArtistInfo::EchoNestArtistInfo(QObject* parent)
: ArtistInfoProvider(parent)
{
}
void EchoNestArtistInfo::FetchInfo(int id, const QString& artist_name) {
boost::shared_ptr<Request> request(new Request(id));
request->artist_->setName(artist_name);
ConnectReply(request, request->artist_->fetchBiographies(), SLOT(BiographiesFinished()));
ConnectReply(request, request->artist_->fetchImages(), SLOT(ImagesFinished()));
requests_ << request;
}
void EchoNestArtistInfo::ConnectReply(
boost::shared_ptr<Request> request, QNetworkReply* reply, const char* slot) {
request->pending_replies_ << reply;
connect(reply, SIGNAL(finished()), slot);
}
EchoNestArtistInfo::RequestPtr EchoNestArtistInfo::ReplyFinished(QNetworkReply* reply) {
reply->deleteLater();
foreach (RequestPtr request, requests_) {
if (request->pending_replies_.contains(reply)) {
request->artist_->parseProfile(reply);
request->pending_replies_.removeAll(reply);
if (request->pending_replies_.isEmpty()) {
requests_.removeAll(request);
}
return request;
}
}
return RequestPtr();
}
void EchoNestArtistInfo::ImagesFinished() {
RequestPtr request = ReplyFinished(qobject_cast<QNetworkReply*>(sender()));
foreach (const Echonest::ArtistImage& image, request->artist_->images()) {
emit ImageReady(request->id_, image.url());
}
}
void EchoNestArtistInfo::BiographiesFinished() {
RequestPtr request = ReplyFinished(qobject_cast<QNetworkReply*>(sender()));
foreach (const Echonest::Biography& bio, request->artist_->biographies()) {
QTextEdit* editor = new QTextEdit;
editor->setHtml(bio.text());
emit InfoReady(request->id_, tr("Biography from %1").arg(bio.site()), editor);
}
}

View File

@ -0,0 +1,49 @@
/* This file is part of Clementine.
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ECHONESTARTISTINFO_H
#define ECHONESTARTISTINFO_H
#include "artistinfoprovider.h"
#include <boost/shared_ptr.hpp>
class QNetworkReply;
class EchoNestArtistInfo : public ArtistInfoProvider {
Q_OBJECT
public:
EchoNestArtistInfo(QObject* parent = 0);
void FetchInfo(int id, const QString& artist);
private slots:
void BiographiesFinished();
void ImagesFinished();
private:
struct Request;
typedef boost::shared_ptr<Request> RequestPtr;
void ConnectReply(RequestPtr request, QNetworkReply* reply, const char* slot);
RequestPtr ReplyFinished(QNetworkReply* reply);
private:
QList<RequestPtr> requests_;
};
#endif // ECHONESTARTISTINFO_H

View File

@ -312,6 +312,10 @@ msgstr ""
msgid "Behavior"
msgstr ""
#, qt-format
msgid "Biography from %1"
msgstr ""
msgid "Bit rate"
msgstr "معدل البت"

View File

@ -313,6 +313,10 @@ msgstr ""
msgid "Behavior"
msgstr ""
#, qt-format
msgid "Biography from %1"
msgstr ""
msgid "Bit rate"
msgstr ""

View File

@ -322,6 +322,10 @@ msgstr "Blau Bàsic"
msgid "Behavior"
msgstr "Comportament"
#, qt-format
msgid "Biography from %1"
msgstr ""
msgid "Bit rate"
msgstr "Taxa de bits"

View File

@ -314,6 +314,10 @@ msgstr "Jednoduchá modrá"
msgid "Behavior"
msgstr "Chování"
#, qt-format
msgid "Biography from %1"
msgstr ""
msgid "Bit rate"
msgstr "Datový tok"

View File

@ -314,6 +314,10 @@ msgstr "Basal blå"
msgid "Behavior"
msgstr "Adfærd"
#, qt-format
msgid "Biography from %1"
msgstr ""
msgid "Bit rate"
msgstr "Bitrate"

View File

@ -320,6 +320,10 @@ msgstr "Standardblau"
msgid "Behavior"
msgstr "Verhalten"
#, qt-format
msgid "Biography from %1"
msgstr ""
msgid "Bit rate"
msgstr "Bitrate"

View File

@ -321,6 +321,10 @@ msgstr "Βασικό μπλε"
msgid "Behavior"
msgstr "Συμπεριφορά"
#, qt-format
msgid "Biography from %1"
msgstr ""
msgid "Bit rate"
msgstr "Ρυθμός bit"

View File

@ -312,6 +312,10 @@ msgstr "Basic Blue"
msgid "Behavior"
msgstr "Behaviour"
#, qt-format
msgid "Biography from %1"
msgstr ""
msgid "Bit rate"
msgstr "Bit rate"

View File

@ -312,6 +312,10 @@ msgstr "Basic Blue"
msgid "Behavior"
msgstr "Behaviour"
#, qt-format
msgid "Biography from %1"
msgstr ""
msgid "Bit rate"
msgstr "Bit rate"

View File

@ -322,6 +322,10 @@ msgstr "Azul básico"
msgid "Behavior"
msgstr "Comportamiento"
#, qt-format
msgid "Biography from %1"
msgstr ""
msgid "Bit rate"
msgstr "Tasa de bits"

View File

@ -313,6 +313,10 @@ msgstr ""
msgid "Behavior"
msgstr ""
#, qt-format
msgid "Biography from %1"
msgstr ""
msgid "Bit rate"
msgstr "Bittivirta"

View File

@ -325,6 +325,10 @@ msgstr "Bleu standard"
msgid "Behavior"
msgstr "Comportement"
#, qt-format
msgid "Biography from %1"
msgstr ""
msgid "Bit rate"
msgstr "Débit"

View File

@ -313,6 +313,10 @@ msgstr "Azul básico"
msgid "Behavior"
msgstr "Comportamento"
#, qt-format
msgid "Biography from %1"
msgstr ""
msgid "Bit rate"
msgstr "Taxa de bits"

View File

@ -318,6 +318,10 @@ msgstr "Egyszerű kék"
msgid "Behavior"
msgstr "Viselkedés"
#, qt-format
msgid "Biography from %1"
msgstr ""
msgid "Bit rate"
msgstr "Bitráta"

View File

@ -325,6 +325,10 @@ msgstr "Blu di base"
msgid "Behavior"
msgstr "Comportamento"
#, qt-format
msgid "Biography from %1"
msgstr ""
msgid "Bit rate"
msgstr "Bitrate"

View File

@ -312,6 +312,10 @@ msgstr ""
msgid "Behavior"
msgstr ""
#, qt-format
msgid "Biography from %1"
msgstr ""
msgid "Bit rate"
msgstr ""

View File

@ -313,6 +313,10 @@ msgstr ""
msgid "Behavior"
msgstr ""
#, qt-format
msgid "Biography from %1"
msgstr ""
msgid "Bit rate"
msgstr ""

View File

@ -313,6 +313,10 @@ msgstr "Blå"
msgid "Behavior"
msgstr ""
#, qt-format
msgid "Biography from %1"
msgstr ""
msgid "Bit rate"
msgstr "Bitrate"

View File

@ -321,6 +321,10 @@ msgstr "Basic Blue"
msgid "Behavior"
msgstr "Gedrag"
#, qt-format
msgid "Biography from %1"
msgstr ""
msgid "Bit rate"
msgstr "Bitsnelheid"

View File

@ -312,6 +312,10 @@ msgstr "Blau estandard"
msgid "Behavior"
msgstr "Compòrtament"
#, qt-format
msgid "Biography from %1"
msgstr ""
msgid "Bit rate"
msgstr "Debit binari"

View File

@ -321,6 +321,10 @@ msgstr "Prosty niebieski"
msgid "Behavior"
msgstr "Tryb"
#, qt-format
msgid "Biography from %1"
msgstr ""
msgid "Bit rate"
msgstr "Bitrate"

View File

@ -321,6 +321,10 @@ msgstr "Azul básico"
msgid "Behavior"
msgstr "Comportamento"
#, qt-format
msgid "Biography from %1"
msgstr ""
msgid "Bit rate"
msgstr "Taxa de \"bits\""

View File

@ -318,6 +318,10 @@ msgstr "Azul básico"
msgid "Behavior"
msgstr "Comportamento"
#, qt-format
msgid "Biography from %1"
msgstr ""
msgid "Bit rate"
msgstr "Taxa de bits"

View File

@ -312,6 +312,10 @@ msgstr ""
msgid "Behavior"
msgstr "Comportament"
#, qt-format
msgid "Biography from %1"
msgstr ""
msgid "Bit rate"
msgstr "Rată de biți"

View File

@ -316,6 +316,10 @@ msgstr "Стандартно голубой"
msgid "Behavior"
msgstr "Поведение"
#, qt-format
msgid "Biography from %1"
msgstr ""
msgid "Bit rate"
msgstr "Битрейт"

View File

@ -318,6 +318,10 @@ msgstr "Základná modrá"
msgid "Behavior"
msgstr "Správanie"
#, qt-format
msgid "Biography from %1"
msgstr ""
msgid "Bit rate"
msgstr "Bit rate"

View File

@ -317,6 +317,10 @@ msgstr "Preprosta modra"
msgid "Behavior"
msgstr "Obnašanje"
#, qt-format
msgid "Biography from %1"
msgstr ""
msgid "Bit rate"
msgstr "Bitna hitrost"

View File

@ -313,6 +313,10 @@ msgstr "Основно плаво"
msgid "Behavior"
msgstr "Понашање"
#, qt-format
msgid "Biography from %1"
msgstr ""
msgid "Bit rate"
msgstr "Битски проток"

View File

@ -313,6 +313,10 @@ msgstr "Basblå"
msgid "Behavior"
msgstr "Beteende"
#, qt-format
msgid "Biography from %1"
msgstr ""
msgid "Bit rate"
msgstr "Bithastighet"

View File

@ -317,6 +317,10 @@ msgstr "Temel Mavi"
msgid "Behavior"
msgstr "Davranış"
#, qt-format
msgid "Biography from %1"
msgstr ""
msgid "Bit rate"
msgstr "Bit oranı"

View File

@ -303,6 +303,10 @@ msgstr ""
msgid "Behavior"
msgstr ""
#, qt-format
msgid "Biography from %1"
msgstr ""
msgid "Bit rate"
msgstr ""

View File

@ -317,6 +317,10 @@ msgstr "Стандартний синій"
msgid "Behavior"
msgstr "Поведінка"
#, qt-format
msgid "Biography from %1"
msgstr ""
msgid "Bit rate"
msgstr "Бітова швидкість"

View File

@ -312,6 +312,10 @@ msgstr ""
msgid "Behavior"
msgstr ""
#, qt-format
msgid "Biography from %1"
msgstr ""
msgid "Bit rate"
msgstr "比特率"

View File

@ -317,6 +317,10 @@ msgstr ""
msgid "Behavior"
msgstr "行為"
#, qt-format
msgid "Biography from %1"
msgstr ""
msgid "Bit rate"
msgstr "位元率"

View File

@ -54,6 +54,7 @@
#include "radio/radioview.h"
#include "radio/radioviewcontainer.h"
#include "radio/savedradio.h"
#include "songinfo/artistinfoview.h"
#include "songinfo/lyricfetcher.h"
#include "songinfo/lyricview.h"
#include "transcoder/transcodedialog.h"
@ -142,6 +143,7 @@ MainWindow::MainWindow(NetworkAccessManager* network, Engine::Type engine, QWidg
radio_view_(new RadioViewContainer(this)),
device_view_(new DeviceView(this)),
lyric_view_(new LyricView(this)),
artist_info_view_(new ArtistInfoView(this)),
settings_dialog_(NULL),
cover_manager_(NULL),
equalizer_(new Equalizer),
@ -179,14 +181,14 @@ MainWindow::MainWindow(NetworkAccessManager* network, Engine::Type engine, QWidg
ui_->volume->setValue(player_->GetVolume());
// Add tabs to the fancy tab widget
AddFancyTab(library_view_, IconLoader::Load("folder-sound"), tr("Library"));
AddFancyTab(file_view_, IconLoader::Load("document-open"), tr("Files"));
AddFancyTab(radio_view_, QIcon(":last.fm/icon_radio.png"), tr("Internet"));
AddFancyTab(device_view_, IconLoader::Load("multimedia-player-ipod-mini-blue"), tr("Devices"));
ui_->tabs->addTab(library_view_, IconLoader::Load("folder-sound"), tr("Library"));
ui_->tabs->addTab(file_view_, IconLoader::Load("document-open"), tr("Files"));
ui_->tabs->addTab(radio_view_, QIcon(":last.fm/icon_radio.png"), tr("Internet"));
ui_->tabs->addTab(device_view_, IconLoader::Load("multimedia-player-ipod-mini-blue"), tr("Devices"));
ui_->tabs->addSpacer();
AddFancyTab(lyric_view_, IconLoader::Load("view-media-lyrics"), tr("Lyrics"));
AddFancyTab(new QWidget, IconLoader::Load("view-media-lyrics"), tr("Song info"));
AddFancyTab(new QWidget, IconLoader::Load("view-media-lyrics"), tr("Artist info"));
ui_->tabs->addTab(lyric_view_, IconLoader::Load("view-media-lyrics"), tr("Lyrics"));
ui_->tabs->addTab(new QWidget, IconLoader::Load("view-media-lyrics"), tr("Song info"));
ui_->tabs->addTab(artist_info_view_, IconLoader::Load("view-media-lyrics"), tr("Artist info"));
ui_->tabs->statusBar()->hide();
ui_->tabs->setBackgroundPixmap(QPixmap(":/sidebar_background.png"));
@ -491,6 +493,7 @@ MainWindow::MainWindow(NetworkAccessManager* network, Engine::Type engine, QWidg
// Lyrics
lyric_view_->set_network(network);
ConnectInfoView(lyric_view_);
ConnectInfoView(artist_info_view_);
// Analyzer
ui_->analyzer->SetEngine(player_->GetEngine());
@ -1579,10 +1582,6 @@ void MainWindow::ShowVisualisations() {
#endif // ENABLE_VISUALISATIONS
}
void MainWindow::AddFancyTab(QWidget* widget, const QIcon& icon, const QString& label) {
ui_->tabs->addTab(widget, icon, label);
}
void MainWindow::ConnectInfoView(SongInfoBase* view) {
connect(playlists_, SIGNAL(CurrentSongChanged(Song)), view, SLOT(SongChanged(Song)));
connect(player_, SIGNAL(PlaylistFinished()), view, SLOT(SongFinished()));

View File

@ -33,6 +33,7 @@
class About;
class AddStreamDialog;
class AlbumCoverManager;
class ArtistInfoView;
class CommandlineOptions;
class Database;
class DeviceManager;
@ -196,7 +197,6 @@ class MainWindow : public QMainWindow, public PlatformInterface {
void AddLibrarySongsToPlaylist(bool clear_first, const SongList& songs);
void AddDeviceSongsToPlaylist(bool clear_first, const SongList& songs);
void AddUrls(bool play_now, const QList<QUrl>& urls);
void AddFancyTab(QWidget* widget, const QIcon& icon, const QString& label);
void ConnectInfoView(SongInfoBase* view);
private:
@ -225,6 +225,7 @@ class MainWindow : public QMainWindow, public PlatformInterface {
RadioViewContainer* radio_view_;
DeviceView* device_view_;
LyricView* lyric_view_;
ArtistInfoView* artist_info_view_;
boost::scoped_ptr<SettingsDialog> settings_dialog_;
boost::scoped_ptr<AddStreamDialog> add_stream_dialog_;