From 69d1450b5c27341b9a6b6382916864b5208fc977 Mon Sep 17 00:00:00 2001 From: Casey Link Date: Tue, 10 Apr 2012 18:11:58 -0500 Subject: [PATCH] Implement New Releases info plugin Heavily based off existing charts info plugin, refactoring and consolidating can be done later. --- src/libtomahawk/CMakeLists.txt | 1 + .../infoplugins/generic/newreleasesplugin.cpp | 343 ++++++++++++++++++ .../infoplugins/generic/newreleasesplugin.h | 100 +++++ src/libtomahawk/infosystem/infosystem.h | 5 +- .../infosystem/infosystemworker.cpp | 6 +- 5 files changed, 452 insertions(+), 3 deletions(-) create mode 100644 src/libtomahawk/infosystem/infoplugins/generic/newreleasesplugin.cpp create mode 100644 src/libtomahawk/infosystem/infoplugins/generic/newreleasesplugin.h diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index 797f2acb1..a12425e5c 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -251,6 +251,7 @@ set( libSources infosystem/infoplugins/generic/echonestplugin.cpp infosystem/infoplugins/generic/chartsplugin.cpp + infosystem/infoplugins/generic/newreleasesplugin.cpp infosystem/infoplugins/generic/spotifyPlugin.cpp infosystem/infoplugins/generic/hypemPlugin.cpp infosystem/infoplugins/generic/musixmatchplugin.cpp diff --git a/src/libtomahawk/infosystem/infoplugins/generic/newreleasesplugin.cpp b/src/libtomahawk/infosystem/infoplugins/generic/newreleasesplugin.cpp new file mode 100644 index 000000000..d0b2df69e --- /dev/null +++ b/src/libtomahawk/infosystem/infoplugins/generic/newreleasesplugin.cpp @@ -0,0 +1,343 @@ +#include "newreleasesplugin.h" + +#include +#include +#include +#include + +#include "album.h" +#include "chartsplugin_data_p.h" +#include "typedefs.h" +#include "audio/audioengine.h" +#include "tomahawksettings.h" +#include "utils/tomahawkutils.h" +#include "utils/logger.h" + +#include +#include + +#define CHART_URL "http://charts.tomahawk-player.org/" +//#define CHART_URL "http://localhost:8080/" + +using namespace Tomahawk::InfoSystem; + +NewReleasesPlugin::NewReleasesPlugin() + : InfoPlugin() + , m_nrFetchJobs ( 0 ) +{ + m_nrVersion = "0"; + m_supportedGetTypes << InfoNewReleaseCapabilities << InfoNewRelease; +} + +NewReleasesPlugin::~NewReleasesPlugin() +{ + tDebug ( LOGVERBOSE ) << Q_FUNC_INFO; +} + +void NewReleasesPlugin::dataError ( InfoRequestData requestData ) +{ + emit info ( requestData, QVariant() ); + return; +} + +void NewReleasesPlugin::getInfo ( InfoRequestData requestData ) +{ +//qDebug() << Q_FUNC_INFO << requestData.caller; + //qDebug() << Q_FUNC_INFO << requestData.customData; + + InfoStringHash hash = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >(); + bool foundSource = false; + + switch ( requestData.type ) { + case InfoNewRelease: + /// We need something to check if the request is actually ment to go to this plugin + if ( !hash.contains ( "nr_source" ) ) { + tDebug ( LOGVERBOSE ) << Q_FUNC_INFO << "Hash did not contain required param!"; + dataError ( requestData ); + break; + } else { + foreach ( QString resource, m_nrSources ) { + if ( resource == hash["nr_source"] ) { + foundSource = true; + } + } + + if ( !foundSource ) { + dataError ( requestData ); + break; + } + + } + fetchNRFromCache ( requestData ); + break; + + case InfoNewReleaseCapabilities: + fetchNRCapabilitiesFromCache ( requestData ); + break; + default: + dataError ( requestData ); + } +} + +void NewReleasesPlugin::fetchNRFromCache ( 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 ( "nr_id" ) && !hash.contains ( "nr_source" ) ) { + tDebug ( LOGVERBOSE ) << Q_FUNC_INFO << "Hash did not contain required params!"; + dataError ( requestData ); + return; + + } + /// Set the criterias for current chart + criteria["nr_id"] = hash["nr_id"]; + criteria["nr_source"] = hash["nr_source"]; + + emit getCachedInfo ( criteria, 86400000, requestData ); +} + +void NewReleasesPlugin::fetchNRCapabilitiesFromCache ( InfoRequestData requestData ) +{ + if ( !requestData.input.canConvert< Tomahawk::InfoSystem::InfoStringHash >() ) { + tDebug ( LOGVERBOSE ) << Q_FUNC_INFO << "Could not convert requestData to InfoStringHash!"; + dataError ( requestData ); + return; + } + + Tomahawk::InfoSystem::InfoStringHash criteria; + criteria[ "InfoNewReleaseCapabilities" ] = "newreleasesplugin"; + criteria[ "InfoNewReleaseVersion" ] = m_nrVersion; + emit getCachedInfo ( criteria, 864000000, requestData ); +} + +void NewReleasesPlugin::notInCacheSlot ( InfoStringHash criteria, InfoRequestData requestData ) +{ + switch ( requestData.type ) { + case InfoNewRelease: { + tDebug ( LOGVERBOSE ) << Q_FUNC_INFO << "InfoNewRelease not in cache! Fetching..."; + fetchNR ( requestData, criteria["nr_source"], criteria["nr_id"] ); + return; + + } + + case InfoNewReleaseCapabilities: { + tDebug ( LOGVERBOSE ) << Q_FUNC_INFO << "InfoChartCapabilities not in cache! Fetching..."; + fetchNRSourcesList(); + m_cachedRequests.append ( requestData ); + + 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 NewReleasesPlugin::fetchNRSourcesList() +{ + QUrl url = QUrl ( QString ( CHART_URL "newreleases" ) ); + QNetworkReply* reply = TomahawkUtils::nam()->get ( QNetworkRequest ( url ) ); + + tDebug() << "fetching:" << url; + connect ( reply, SIGNAL ( finished() ), SLOT ( nrSourcesList() ) ); + +} + +void NewReleasesPlugin::nrSourcesList() +{ + tDebug ( LOGVERBOSE ) << "Got newreleases sources list"; + QNetworkReply* reply = qobject_cast ( sender() ); + + if ( reply->error() == QNetworkReply::NoError ) { + QJson::Parser p; + bool ok; + const QVariantMap res = p.parse ( reply, &ok ).toMap(); + const QVariantList sources = res.value ( "sources" ).toList(); + + if ( !ok ) { + tLog() << "Failed to parse sources" << p.errorString() << "On line" << p.errorLine(); + return; + } + + m_nrSources.clear(); + foreach ( const QVariant &source, sources ) { + m_nrSources << source.toString(); + } + + fetchAllNRSources(); + } +} + +void NewReleasesPlugin::fetchAllNRSources() +{ + if ( !m_nrSources.isEmpty() && m_allNRsMap.isEmpty() ) { + tDebug ( LOGVERBOSE ) << Q_FUNC_INFO << "InfoNewRelease fetching source data"; + foreach ( QString source, m_nrSources ) { + QUrl url = QUrl ( QString ( CHART_URL "newreleases/%1" ).arg ( source ) ); + QNetworkReply* reply = TomahawkUtils::nam()->get ( QNetworkRequest ( url ) ); + reply->setProperty ( "nr_source", source ); + + tDebug() << "fetching:" << url; + connect ( reply, SIGNAL ( finished() ), SLOT ( nrList() ) ); + + m_nrFetchJobs++; + } + } +} + +void NewReleasesPlugin::fetchNR ( InfoRequestData requestData, const QString& source, const QString& nr_id ) +{ + /// Fetch the chart, we need source and id + QUrl url = QUrl ( QString ( CHART_URL "newreleases/%1/%2" ).arg ( source ).arg ( nr_id ) ); + tDebug ( LOGVERBOSE ) << Q_FUNC_INFO << "fetching: " << url; + + QNetworkReply* reply = TomahawkUtils::nam()->get ( QNetworkRequest ( url ) ); + reply->setProperty ( "requestData", QVariant::fromValue< Tomahawk::InfoSystem::InfoRequestData > ( requestData ) ); + + connect ( reply, SIGNAL ( finished() ), SLOT ( nrReturned() ) ); +} + +void NewReleasesPlugin::nrList() +{ + tDebug ( LOGVERBOSE ) << "Got newreleases list result"; + QNetworkReply* reply = qobject_cast ( sender() ); + + if ( reply->error() == QNetworkReply::NoError ) { + QJson::Parser p; + bool ok; + const QVariantMap res = p.parse ( reply, &ok ).toMap(); + + if ( !ok ) { + tLog() << "Failed to parse resources" << p.errorString() << "On line" << p.errorLine(); + + return; + } + + /// Got types, append! + const QString source = reply->property ( "nr_source" ).toString(); + + // We'll populate newreleases with the data from the server + QVariantMap newreleases; + QString nrName; + + // Building: + // [Source] - New Release + QList< InfoStringHash > albumNRs; + + foreach ( const QVariant &nrObj, res.values() ) { + if ( !nrObj.toMap().isEmpty() ) { + const QVariantMap nrMap = nrObj.toMap(); + const QString type = nrMap.value ( "type" ).toString(); + + InfoStringHash nr; + nr["id"] = nrMap.value ( "id" ).toString(); + nr["label"] = nrMap.value ( "name" ).toString(); + nr["date"] = nrMap.value ( "date" ).toString(); + + if ( type == "Album" ) { + nr[ "type" ] = "album"; + albumNRs.append ( nr ); + } else { + tLog() << "Unknown newrelease type " << type; + continue; + } + + } + } + if ( !albumNRs.isEmpty() ) + newreleases.insert ( tr ( "Albums" ), QVariant::fromValue< QList< Tomahawk::InfoSystem::InfoStringHash > > ( albumNRs ) ); + + /// @note For displaying purposes, upper the first letter + /// @note Remeber to lower it when fetching this! + nrName = source; + nrName[0] = nrName[0].toUpper(); + + tDebug ( LOGVERBOSE ) << Q_FUNC_INFO << "ADDING newrelease TO NRS:" << nrName; + QVariantMap defaultMap = m_allNRsMap.value ( "defaults" ).value< QVariantMap >(); + m_allNRsMap.insert ( nrName, QVariant::fromValue< QVariantMap > ( newreleases ) ); + + } else { + tLog() << "Error fetching charts:" << reply->errorString(); + } + + m_nrFetchJobs--; + if ( !m_cachedRequests.isEmpty() && m_nrFetchJobs == 0 ) { + foreach ( InfoRequestData request, m_cachedRequests ) { + emit info ( request, m_allNRsMap ); + // update cache + Tomahawk::InfoSystem::InfoStringHash criteria; + criteria[ "InfoNewReleaseCapabilities" ] = "newreleasesplugin"; + criteria[ "InfoNewReleaseVersion" ] = m_nrVersion; + emit updateCache ( criteria, 864000000, request.type, m_allNRsMap ); + } + m_cachedRequests.clear(); + } +} + +void NewReleasesPlugin::nrReturned() +{ + /// Chart request returned something! Woho + QNetworkReply* reply = qobject_cast ( sender() ); + 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! + QVariantList albumList = res.value ( "list" ).toList(); + QList< Tomahawk::InfoSystem::InfoStringHash > newreleases; + + foreach( const QVariant & albumObj, albumList ) { + QVariantMap albumMap = albumObj.toMap(); + if(!albumMap.isEmpty()) { + const QString album = albumMap.value("album").toString(); + const QString artist = albumMap.value("artist").toString(); + const QString date = albumMap.value("date").toString(); + + Tomahawk::InfoSystem::InfoStringHash pair; + pair["artist"] = artist; + pair["album"] = album; + newreleases.append( pair ); + } + } + + tDebug() << "NewReleasesPlugin:" << "\tgot " << newreleases.size() << " albums"; + returnedData[ "albums" ] = QVariant::fromValue< QList< Tomahawk::InfoSystem::InfoStringHash > >( newreleases ); + returnedData[ "type" ] = "albums"; + Tomahawk::InfoSystem::InfoRequestData requestData = reply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >(); + + emit info( requestData, returnedData ); + // update cache + Tomahawk::InfoSystem::InfoStringHash criteria; + Tomahawk::InfoSystem::InfoStringHash origData = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >(); + criteria[ "nr_id" ] = origData[ "nr_id" ]; + criteria[ "nr_source" ] = origData[ "nr_source" ]; + emit updateCache( criteria, 86400000, requestData.type, returnedData ); + } else + tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Network error in fetching newrelease:" << reply->url().toString(); +} + + + + + + + + diff --git a/src/libtomahawk/infosystem/infoplugins/generic/newreleasesplugin.h b/src/libtomahawk/infosystem/infoplugins/generic/newreleasesplugin.h new file mode 100644 index 000000000..de17b8fca --- /dev/null +++ b/src/libtomahawk/infosystem/infoplugins/generic/newreleasesplugin.h @@ -0,0 +1,100 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2012, Casey Link + * + * 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 NEWRELEASESPLUGIN_H +#define NEWRELEASESPLUGIN_H + +#include "infosystem/infosystem.h" +#include "infosystem/infosystemworker.h" +#include +#include + +class QNetworkReply; + +namespace Tomahawk +{ + +namespace InfoSystem +{ + +class NewReleasesPlugin : public InfoPlugin +{ + Q_OBJECT + +public: + NewReleasesPlugin(); + virtual ~NewReleasesPlugin(); + +protected slots: + virtual void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData ); + virtual void notInCacheSlot( Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData ); + + virtual void pushInfo( Tomahawk::InfoSystem::InfoPushData pushData ) + { + Q_UNUSED( pushData ); + } + + /** + * Parses a QNetworkReply of a list of newreleases sources. + */ + void nrSourcesList(); + + /** + * Parses a QNetworkReply of a list of newreleases from a particular source + */ + void nrList(); + + /** + * Parses a QNetworkReply for the newreleases data for a particular newrelease + */ + void nrReturned(); + +private: + /** + * Fetch list of newlreeases sources (e.g., rovi) + * Populates the m_nrSources member. + */ + void fetchNRSourcesList(); + /** + * Requests newrelease list for each source in m_chartSources + */ + void fetchAllNRSources(); + /** + * Fetches a specific newrelease from a particular source. + * Updates the cache. + */ + void fetchNR( Tomahawk::InfoSystem::InfoRequestData requestData, const QString& source, const QString& nr_id ); + void fetchNRFromCache( Tomahawk::InfoSystem::InfoRequestData requestData ); + void fetchNRCapabilitiesFromCache( Tomahawk::InfoSystem::InfoRequestData requestData ); + void dataError( Tomahawk::InfoSystem::InfoRequestData requestData ); + + QStringList m_nrSources; + QString m_nrVersion; + QList< InfoStringHash > m_newreleases; + //ChartType m_chartType; + QVariantMap m_allNRsMap; + uint m_nrFetchJobs; + QList< InfoRequestData > m_cachedRequests; + QHash< QString, QString > m_cachedCountries; + QWeakPointer< QNetworkAccessManager > m_nam; +}; + +} +} + +#endif // NEWRELEASESPLUGIN_H diff --git a/src/libtomahawk/infosystem/infosystem.h b/src/libtomahawk/infosystem/infosystem.h index c59b6d62e..bb0716525 100644 --- a/src/libtomahawk/infosystem/infosystem.h +++ b/src/libtomahawk/infosystem/infosystem.h @@ -112,6 +112,9 @@ enum InfoType { // as items are saved in cache, mark them here to not change the */ InfoChart = 51, + InfoNewReleaseCapabilities = 52, + InfoNewRelease = 53, + InfoMiscTopHotttness = 60, InfoMiscTopTerms = 61, @@ -195,7 +198,7 @@ struct InfoPushData { , pushFlags( pflags ) , infoPair( Tomahawk::InfoSystem::PushInfoPair( QVariantMap(), QVariant() ) ) {} - + }; diff --git a/src/libtomahawk/infosystem/infosystemworker.cpp b/src/libtomahawk/infosystem/infosystemworker.cpp index a59bdd4ad..cdefc1095 100644 --- a/src/libtomahawk/infosystem/infosystemworker.cpp +++ b/src/libtomahawk/infosystem/infosystemworker.cpp @@ -28,6 +28,7 @@ #include "infoplugins/generic/echonestplugin.h" #include "infoplugins/generic/musixmatchplugin.h" #include "infoplugins/generic/chartsplugin.h" +#include "infoplugins/generic/newreleasesplugin.h" #include "infoplugins/generic/spotifyPlugin.h" #include "infoplugins/generic/musicbrainzPlugin.h" #include "infoplugins/generic/hypemPlugin.h" @@ -86,6 +87,7 @@ InfoSystemWorker::init( Tomahawk::InfoSystem::InfoSystemCache* cache ) addInfoPlugin( InfoPluginPtr( new MusixMatchPlugin() ) ); addInfoPlugin( InfoPluginPtr( new MusicBrainzPlugin() ) ); addInfoPlugin( InfoPluginPtr( new ChartsPlugin() ) ); + addInfoPlugin( InfoPluginPtr( new NewReleasesPlugin() ) ); addInfoPlugin( InfoPluginPtr( new RoviPlugin() ) ); addInfoPlugin( InfoPluginPtr( new SpotifyPlugin() ) ); addInfoPlugin( InfoPluginPtr( new hypemPlugin() ) ); @@ -274,7 +276,7 @@ void InfoSystemWorker::pushInfo( Tomahawk::InfoSystem::InfoPushData pushData ) { tDebug() << Q_FUNC_INFO << "type is " << pushData.type; - + if ( pushData.pushFlags != PushNoFlag ) { if ( pushData.pushFlags & PushShortUrlFlag ) @@ -334,7 +336,7 @@ InfoSystemWorker::shortLinkReady( QUrl longUrl, QUrl shortUrl, QVariant callback m_shortLinksWaiting--; if ( !m_shortLinksWaiting ) disconnect( GlobalActionManager::instance(), SIGNAL( shortLinkReady( QUrl, QUrl, QVariant ) ) ); - + if ( !callbackObj.isValid() ) { tDebug() << Q_FUNC_INFO << "callback object was not valid, cannot continue";