From f8d48cc9fcb4396a131178a2c287f32058f14419 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20Lindstr=C3=B6m?= Date: Fri, 28 Oct 2011 22:57:28 +0200 Subject: [PATCH] Adding Hypem and fix race in spotify(?) --- src/libtomahawk/CMakeLists.txt | 2 + .../infoplugins/generic/chartsplugin.cpp | 2 +- .../infoplugins/generic/hypemPlugin.cpp | 421 ++++++++++++++++++ .../infoplugins/generic/hypemPlugin.h | 93 ++++ .../infoplugins/generic/spotifyPlugin.cpp | 20 +- .../infoplugins/generic/spotifyPlugin.h | 4 +- .../infosystem/infosystemworker.cpp | 5 + 7 files changed, 543 insertions(+), 4 deletions(-) create mode 100644 src/libtomahawk/infosystem/infoplugins/generic/hypemPlugin.cpp create mode 100644 src/libtomahawk/infosystem/infoplugins/generic/hypemPlugin.h diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index 92e0bd1e8..a85ad861b 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -112,6 +112,7 @@ set( libSources infosystem/infoplugins/generic/lastfmplugin.cpp infosystem/infoplugins/generic/chartsplugin.cpp infosystem/infoplugins/generic/spotifyPlugin.cpp + infosystem/infoplugins/generic/hypemPlugin.cpp infosystem/infoplugins/generic/musixmatchplugin.cpp infosystem/infoplugins/generic/musicbrainzPlugin.cpp infosystem/infoplugins/generic/RoviPlugin.cpp @@ -340,6 +341,7 @@ set( libHeaders infosystem/infoplugins/generic/lastfmplugin.h infosystem/infoplugins/generic/chartsplugin.h infosystem/infoplugins/generic/spotifyPlugin.h + infosystem/infoplugins/generic/hypemPlugin.h infosystem/infoplugins/generic/musixmatchplugin.h infosystem/infoplugins/generic/musicbrainzPlugin.h infosystem/infoplugins/generic/RoviPlugin.h diff --git a/src/libtomahawk/infosystem/infoplugins/generic/chartsplugin.cpp b/src/libtomahawk/infosystem/infoplugins/generic/chartsplugin.cpp index a0fe25503..9185a1321 100644 --- a/src/libtomahawk/infosystem/infoplugins/generic/chartsplugin.cpp +++ b/src/libtomahawk/infosystem/infoplugins/generic/chartsplugin.cpp @@ -107,7 +107,7 @@ ChartsPlugin::getInfo( Tomahawk::InfoSystem::InfoRequestData requestData ) qDebug() << Q_FUNC_INFO << requestData.customData; InfoStringHash hash = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >(); - bool foundSource; + bool foundSource = false; switch ( requestData.type ) { diff --git a/src/libtomahawk/infosystem/infoplugins/generic/hypemPlugin.cpp b/src/libtomahawk/infosystem/infoplugins/generic/hypemPlugin.cpp new file mode 100644 index 000000000..b6b9a987b --- /dev/null +++ b/src/libtomahawk/infosystem/infoplugins/generic/hypemPlugin.cpp @@ -0,0 +1,421 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2010-2011, Hugo Lindström + * Copyright 2011, Leo Franchi + * + * Tomahawk 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. + * + * Tomahawk 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 Tomahawk. If not, see . + */ + +#include "hypemPlugin.h" + +#include +#include +#include +#include +#include +#include + +#include "album.h" +#include "typedefs.h" +#include "audio/audioengine.h" +#include "tomahawksettings.h" +#include "utils/tomahawkutils.h" +#include "utils/logger.h" + +#define HYPEM_URL "http://hypem.com/playlist/" +#define HYPEM_END_URL "json/1/data.js" +#include +#include + +using namespace Tomahawk::InfoSystem; + + +hypemPlugin::hypemPlugin() + : InfoPlugin() + , m_chartsFetchJobs( 0 ) +{ + + m_supportedGetTypes << InfoChart << InfoChartCapabilities; + m_types << "Artists" << "Tracks" << "Recent by Tag"; + + m_trackTypes << "Last 3 Days" + << "Last Week" + << "No Remixes" + << "On Twitter"; + + m_byTagTypes << "Dance" + << "Experimental" + << "Electronic" + << "Funk" + << "Hip-hop" + << "Indie" + << "Instrumental" + << "Post-punk" + << "Rock" + << "Singer-songwriter" + << "Alternative" + << "Pop" + << "Female" + << "Vocalist" + << "Folk" + << "Electro" + << "Lo-fi" + << "Psychedelic" + << "Rap" + << "British" + << "Ambient" + << "Dubstep" + << "House" + << "Chillwave" + << "Dreampop" + << "Shoegaze" + << "Chillout" + << "Soul" + << "French" + << "Acoustic" + << "Canadian" + << "60s" + << "80s" + << "Techno" + << "Punk" + << "New wave"; + chartTypes(); + +} + + + + +hypemPlugin::~hypemPlugin() +{ + qDebug() << Q_FUNC_INFO; +} + + +void +hypemPlugin::namChangedSlot( QNetworkAccessManager *nam ) +{ + tDebug() << "hypemPlugin: namChangedSLot"; + qDebug() << Q_FUNC_INFO; + if( !nam ) + return; + + m_nam = QWeakPointer< QNetworkAccessManager >( nam ); + + +} + + +void +hypemPlugin::dataError( Tomahawk::InfoSystem::InfoRequestData requestData ) +{ + emit info( requestData, QVariant() ); + return; +} + + +void +hypemPlugin::getInfo( Tomahawk::InfoSystem::InfoRequestData requestData ) +{ + qDebug() << Q_FUNC_INFO << requestData.caller; + qDebug() << Q_FUNC_INFO << requestData.customData; + + InfoStringHash hash = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >(); + + + switch ( requestData.type ) + { + + case InfoChart: + if ( !hash.contains( "chart_source" ) || hash["chart_source"] != "hypem" ) + { + dataError( requestData ); + break; + } + qDebug() << Q_FUNC_INFO << "InfoCHart req for" << hash["chart_source"]; + fetchChart( requestData ); + break; + + case InfoChartCapabilities: + fetchChartCapabilities( requestData ); + break; + default: + dataError( requestData ); + } +} + + +void +hypemPlugin::pushInfo( const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant input ) +{ + Q_UNUSED( caller ) + Q_UNUSED( type) + Q_UNUSED( input ) +} + + +void +hypemPlugin::fetchChart( Tomahawk::InfoSystem::InfoRequestData requestData ) +{ + + if ( !requestData.input.canConvert< Tomahawk::InfoSystem::InfoStringHash >() ) + { + dataError( requestData ); + return; + } + + InfoStringHash hash = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >(); + Tomahawk::InfoSystem::InfoStringHash criteria; + + /// Each request needs to contain both a id and source + if ( !hash.contains( "chart_id" ) && !hash.contains( "chart_source" ) ) + { + dataError( requestData ); + return; + + } + /// Set the criterias for current chart + criteria["chart_id"] = hash["chart_id"]; + criteria["chart_source"] = hash["chart_source"]; + + emit getCachedInfo( criteria, 0, requestData ); +} + +void +hypemPlugin::fetchChartCapabilities( Tomahawk::InfoSystem::InfoRequestData requestData ) +{ + if ( !requestData.input.canConvert< Tomahawk::InfoSystem::InfoStringHash >() ) + { + dataError( requestData ); + return; + } + + Tomahawk::InfoSystem::InfoStringHash criteria; + emit getCachedInfo( criteria, 0, requestData ); +} + +void +hypemPlugin::notInCacheSlot( QHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData ) +{ + if ( !m_nam.data() ) + { + tLog() << "Have a null QNAM, uh oh"; + emit info( requestData, QVariant() ); + return; + } + + + switch ( requestData.type ) + { + case InfoChart: + { + /// Fetch the chart, we need source and id + + QUrl url = QUrl( QString( HYPEM_URL "%1/%2" ).arg( criteria["chart_id"].toLower() ).arg(HYPEM_END_URL) ); + qDebug() << Q_FUNC_INFO << "Getting chart url" << url; + + QNetworkReply* reply = m_nam.data()->get( QNetworkRequest( url ) ); + reply->setProperty( "requestData", QVariant::fromValue< Tomahawk::InfoSystem::InfoRequestData >( requestData ) ); + connect( reply, SIGNAL( finished() ), SLOT( chartReturned() ) ); + return; + + + } + + case InfoChartCapabilities: + { + if ( m_chartsFetchJobs > 0 ) + { + qDebug() << Q_FUNC_INFO << "InfoChartCapabilities still fetching!"; + m_cachedRequests.append( requestData ); + return; + } + + emit info( requestData, m_allChartsMap ); + return; + } + + default: + { + tLog() << Q_FUNC_INFO << "Couldn't figure out what to do with this type of request after cache miss"; + emit info( requestData, QVariant() ); + return; + } + } +} + + +void +hypemPlugin::chartTypes() +{ + /// Get possible chart type for specifichypemPlugin: InfoChart types returned chart source + tDebug() << Q_FUNC_INFO << "Got hypem types"; + + QVariantMap charts; + + foreach(QVariant types, m_types ) + { + QList< InfoStringHash > chart_types; + QList< InfoStringHash > pop_charts; + InfoStringHash c; + + if(types.toString() != "Artists") + { + + if(types.toString() == "Tracks") + { + + foreach(QVariant trackType, m_trackTypes) + { + QString typeId; + if(trackType.toString() == "Last 3 Days") + typeId = "popular/3day"; + + if(trackType.toString() == "Last Week") + typeId = "popular/lastweek"; + + if(trackType.toString() == "No Remixes") + typeId = "popular/noremix"; + + if(trackType.toString() == "On Twitter") + typeId = "popular/twitter"; + + c[ "id" ] = typeId; + c[ "label" ] = trackType.toString(); + c[ "type" ] = "tracks"; + pop_charts.append( c ); + } + + chart_types.append( pop_charts ); + + } + else if(types.toString() == "Recent by Tag") + { + foreach(QVariant tagTypes, m_byTagTypes) + { + + c[ "id" ] = "tags/" + tagTypes.toString().toLower(); + c[ "label" ] = tagTypes.toString(); + c[ "type" ] = tagTypes.toString(); + chart_types.append( c ); + } + + } + + }else + { + InfoStringHash c; + c[ "id" ] = "popular/artists"; + c[ "label" ] = "Most Recent"; + c[ "type" ] = "artists"; + chart_types.append( c ); + } + + charts.insert( types.toString(), QVariant::fromValue >( chart_types ) ); + } + + + m_allChartsMap.insert( "Hypem", QVariant::fromValue( charts ) ); + qDebug() << "hypemPlugin:Chartstype: " << m_allChartsMap; + + +} + +void +hypemPlugin::chartReturned() +{ + + /// Chart request returned something! Woho + QNetworkReply* reply = qobject_cast( sender() ); + QString url = reply->url().toString(); + QVariantMap returnedData; + if ( reply->error() == QNetworkReply::NoError ) + { + QJson::Parser p; + bool ok; + QVariantMap res = p.parse( reply, &ok ).toMap(); + + if ( !ok ) + { + tLog() << "Failed to parse json from chart lookup:" << p.errorString() << "On line" << p.errorLine(); + return; + } + + /// SO we have a result, parse it! + QList< InfoStringHash > top_tracks; + QStringList top_artists; + + if( url.contains( "artists" ) ) + setChartType( Artist ); + else + setChartType( Track ); + + foreach(QVariant result, res ) + { + QString title, artist; + QVariantMap chartMap = result.toMap(); + + if ( !chartMap.isEmpty() ) + { + + title = chartMap.value( "title" ).toString(); + artist = chartMap.value( "artist" ).toString(); + + if( chartType() == Track ) + { + InfoStringHash pair; + pair["artist"] = artist; + pair["track"] = title; + top_tracks << pair; + + qDebug() << "HypemChart type is track"; + } + + + if( chartType() == Artist ) + { + + top_artists << artist; + qDebug() << "HypemChart type is artist"; + + } + } + } + + if( chartType() == Track ) + { + tDebug() << "HypemPlugin:" << "\tgot " << top_tracks.size() << " tracks"; + returnedData["tracks"] = QVariant::fromValue( top_tracks ); + returnedData["type"] = "tracks"; + } + + + + if( chartType() == Artist ) + { + tDebug() << "HypemPlugin:" << "\tgot " << top_artists.size() << " artists"; + returnedData["artists"] = top_artists; + returnedData["type"] = "artists"; + } + + Tomahawk::InfoSystem::InfoRequestData requestData = reply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >(); + + + emit info( requestData, returnedData ); + // TODO update cache + } + else + qDebug() << "Network error in fetching chart:" << reply->url().toString(); + +} diff --git a/src/libtomahawk/infosystem/infoplugins/generic/hypemPlugin.h b/src/libtomahawk/infosystem/infoplugins/generic/hypemPlugin.h new file mode 100644 index 000000000..a13c0299d --- /dev/null +++ b/src/libtomahawk/infosystem/infoplugins/generic/hypemPlugin.h @@ -0,0 +1,93 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2010-2011, Hugo Lindström + * + * Tomahawk 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. + * + * Tomahawk 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 Tomahawk. If not, see . + */ + +#ifndef hypemPlugin_H +#define hypemPlugin_H + +#include "infosystem/infosystem.h" +#include "infosystem/infosystemworker.h" +#include +#include + +class QNetworkReply; + +namespace Tomahawk +{ + +namespace InfoSystem +{ + +class hypemPlugin : public InfoPlugin +{ + Q_OBJECT + +public: + hypemPlugin(); + virtual ~hypemPlugin(); + + enum ChartType { + None = 0x00, + Track = 0x01, + Album = 0x02, + Artist = 0x04 + + }; + void setChartType( ChartType type ) { m_chartType = type; } + ChartType chartType() const { return m_chartType; } + +public slots: + void chartReturned(); + void chartTypes(); + void namChangedSlot( QNetworkAccessManager *nam ); + +protected slots: + virtual void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData ); + virtual void notInCacheSlot( Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData ); + + virtual void pushInfo( QString caller, Tomahawk::InfoSystem::InfoType type, QVariant data ); + +private: + void fetchChart( Tomahawk::InfoSystem::InfoRequestData requestData ); + void fetchChartCapabilities( Tomahawk::InfoSystem::InfoRequestData requestData ); + void dataError( Tomahawk::InfoSystem::InfoRequestData requestData ); + + QVariantList m_chartResources; + QList m_charts; + + + ChartType m_chartType; + QVariantMap m_allChartsMap; + QVariantList m_types; + QVariantList m_popularTypes; + QVariantList m_trackTypes; + QVariantList m_byTagTypes; + + + uint m_chartsFetchJobs; + QList< InfoRequestData > m_cachedRequests; + + QHash< QString, QString > m_cachedCountries; + + QWeakPointer< QNetworkAccessManager > m_nam; +}; + +} + +} + +#endif // hypemPlugin_H diff --git a/src/libtomahawk/infosystem/infoplugins/generic/spotifyPlugin.cpp b/src/libtomahawk/infosystem/infoplugins/generic/spotifyPlugin.cpp index 8965d6a94..c9549c81e 100644 --- a/src/libtomahawk/infosystem/infoplugins/generic/spotifyPlugin.cpp +++ b/src/libtomahawk/infosystem/infoplugins/generic/spotifyPlugin.cpp @@ -42,6 +42,7 @@ using namespace Tomahawk::InfoSystem; SpotifyPlugin::SpotifyPlugin() : InfoPlugin() + , m_chartsFetchJobs( 0 ) { m_supportedGetTypes << InfoChart << InfoChartCapabilities; @@ -72,6 +73,7 @@ SpotifyPlugin::namChangedSlot( QNetworkAccessManager *nam ) QNetworkReply* reply = m_nam.data()->get( QNetworkRequest( url ) ); tDebug() << Q_FUNC_INFO << "fetching:" << url; connect( reply, SIGNAL( finished() ), SLOT( chartTypes() ) ); + m_chartsFetchJobs++; } @@ -184,7 +186,13 @@ SpotifyPlugin::notInCacheSlot( Tomahawk::InfoSystem::InfoStringHash criteria, To } case InfoChartCapabilities: { - qDebug() << Q_FUNC_INFO << "EMITTING CHART" << m_allChartsMap; + if ( m_chartsFetchJobs > 0 ) + { + qDebug() << Q_FUNC_INFO << "InfoChartCapabilities still fetching!"; + m_cachedRequests.append( requestData ); + return; + } + emit info( requestData, m_allChartsMap ); return; } @@ -278,6 +286,16 @@ SpotifyPlugin::chartTypes() tLog() << Q_FUNC_INFO << "Error fetching charts:" << reply->errorString(); } + m_chartsFetchJobs--; + if ( !m_cachedRequests.isEmpty() && m_chartsFetchJobs == 0 ) + { + foreach ( InfoRequestData request, m_cachedRequests ) + { + emit info( request, m_allChartsMap ); + } + m_cachedRequests.clear(); + } + } void diff --git a/src/libtomahawk/infosystem/infoplugins/generic/spotifyPlugin.h b/src/libtomahawk/infosystem/infoplugins/generic/spotifyPlugin.h index 084da24ee..4a27d826c 100644 --- a/src/libtomahawk/infosystem/infoplugins/generic/spotifyPlugin.h +++ b/src/libtomahawk/infosystem/infoplugins/generic/spotifyPlugin.h @@ -68,8 +68,8 @@ private: ChartType m_chartType; QVariantMap m_allChartsMap; - - + uint m_chartsFetchJobs; + QList< InfoRequestData > m_cachedRequests; QWeakPointer< QNetworkAccessManager > m_nam; }; diff --git a/src/libtomahawk/infosystem/infosystemworker.cpp b/src/libtomahawk/infosystem/infosystemworker.cpp index 406fa1f01..726523bd6 100644 --- a/src/libtomahawk/infosystem/infosystemworker.cpp +++ b/src/libtomahawk/infosystem/infosystemworker.cpp @@ -29,6 +29,7 @@ #include "infoplugins/generic/spotifyPlugin.h" #include "infoplugins/generic/lastfmplugin.h" #include "infoplugins/generic/musicbrainzPlugin.h" +#include "infoplugins/generic/hypemPlugin.h" #include "utils/tomahawkutils.h" #include "utils/logger.h" @@ -99,6 +100,10 @@ InfoSystemWorker::init( QWeakPointer< Tomahawk::InfoSystem::InfoSystemCache> cac InfoPluginPtr spotptr( new SpotifyPlugin() ); m_plugins.append( spotptr ); registerInfoTypes( spotptr, spotptr.data()->supportedGetTypes(), spotptr.data()->supportedPushTypes() ); + InfoPluginPtr hypeptr( new hypemPlugin() ); + m_plugins.append( hypeptr ); + registerInfoTypes( hypeptr, hypeptr.data()->supportedGetTypes(), hypeptr.data()->supportedPushTypes() ); + #ifdef Q_WS_MAC InfoPluginPtr admptr( new AdiumPlugin() );