From 660a7cd0591dbd3baca4b1c58a12977feb57c268 Mon Sep 17 00:00:00 2001
From: Leo Franchi <lfranchi@kde.org>
Date: Sun, 23 Oct 2011 15:38:12 -0400
Subject: [PATCH] Add rovi infoplugin for album tracks

---
 src/libtomahawk/CMakeLists.txt                |   2 +
 .../infoplugins/generic/RoviPlugin.cpp        | 193 ++++++++++++++++++
 .../infoplugins/generic/RoviPlugin.h          |  67 ++++++
 .../infosystem/infosystemworker.cpp           |   7 +-
 src/libtomahawk/playlist/treemodel.cpp        |   7 +-
 src/libtomahawk/playlist/treemodel.h          |   1 +
 6 files changed, 274 insertions(+), 3 deletions(-)
 create mode 100644 src/libtomahawk/infosystem/infoplugins/generic/RoviPlugin.cpp
 create mode 100644 src/libtomahawk/infosystem/infoplugins/generic/RoviPlugin.h

diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt
index 209c721a7..9ab439ce9 100644
--- a/src/libtomahawk/CMakeLists.txt
+++ b/src/libtomahawk/CMakeLists.txt
@@ -113,6 +113,7 @@ set( libSources
     infosystem/infoplugins/generic/chartsplugin.cpp
     infosystem/infoplugins/generic/musixmatchplugin.cpp
     infosystem/infoplugins/generic/musicbrainzPlugin.cpp
+    infosystem/infoplugins/generic/RoviPlugin.cpp
 
     playlist/treemodel.cpp
     playlist/treeproxymodel.cpp
@@ -342,6 +343,7 @@ set( libHeaders
     infosystem/infoplugins/generic/chartsplugin.h
     infosystem/infoplugins/generic/musixmatchplugin.h
     infosystem/infoplugins/generic/musicbrainzPlugin.h
+    infosystem/infoplugins/generic/RoviPlugin.h
 
     network/bufferiodevice.h
     network/msgprocessor.h
diff --git a/src/libtomahawk/infosystem/infoplugins/generic/RoviPlugin.cpp b/src/libtomahawk/infosystem/infoplugins/generic/RoviPlugin.cpp
new file mode 100644
index 000000000..d4ce5950a
--- /dev/null
+++ b/src/libtomahawk/infosystem/infoplugins/generic/RoviPlugin.cpp
@@ -0,0 +1,193 @@
+/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
+ *
+ *   Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
+ *
+ *   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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "RoviPlugin.h"
+
+#include "utils/logger.h"
+
+#include <QDateTime>
+#include <QNetworkReply>
+#include <parser.h>
+
+using namespace Tomahawk::InfoSystem;
+
+static QString
+md5( const QByteArray& src )
+{
+    QByteArray const digest = QCryptographicHash::hash( src, QCryptographicHash::Md5 );
+    return QString::fromLatin1( digest.toHex() ).rightJustified( 32, '0' );
+}
+
+RoviPlugin::RoviPlugin()
+    : InfoPlugin()
+{
+    m_supportedGetTypes << InfoAlbumSongs;
+
+    /*
+     *    Your API Key is 7jxr9zggt45h6rg2n4ss3mrj
+     *    Your secret is XUnYutaAW6
+     */
+    m_apiKey = "7jxr9zggt45h6rg2n4ss3mrj";
+    m_secret = "XUnYutaAW6";
+}
+
+RoviPlugin::~RoviPlugin()
+{
+
+}
+
+
+
+void
+RoviPlugin::namChangedSlot( QNetworkAccessManager* nam )
+{
+    if ( !nam )
+        return;
+
+    m_nam = nam;
+}
+
+
+void
+RoviPlugin::getInfo( uint requestId, Tomahawk::InfoSystem::InfoRequestData requestData )
+{
+    if ( !requestData.input.canConvert< Tomahawk::InfoSystem::InfoStringHash >() )
+    {
+        emit info( requestId, requestData, QVariant() );
+        return;
+    }
+    InfoStringHash hash = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >();
+    if ( !hash.contains( "artist" ) || !hash.contains( "album" ) )
+    {
+        emit info( requestId, requestData, QVariant() );
+        return;
+    }
+
+    Tomahawk::InfoSystem::InfoStringHash criteria;
+    criteria["album"] = hash["album"];
+
+    emit getCachedInfo( requestId, criteria, 2419200000, requestData );
+}
+
+void
+RoviPlugin::notInCacheSlot( uint requestId, Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData )
+{
+    switch ( requestData.type )
+    {
+        case InfoAlbumSongs:
+        {
+            QUrl baseUrl = QUrl( "http://api.rovicorp.com/data/v1/album/tracks" );
+            baseUrl.addQueryItem( "album", criteria[ "album" ] );
+
+            QNetworkReply* reply = makeRequest( baseUrl );
+
+            reply->setProperty( "requestId", requestId );
+            reply->setProperty( "requestData", QVariant::fromValue< Tomahawk::InfoSystem::InfoRequestData >( requestData ) );
+            connect( reply, SIGNAL( finished() ), this, SLOT( albumLookupFinished() ) );
+            connect( reply, SIGNAL( error( QNetworkReply::NetworkError ) ), this, SLOT( albumLookupError( QNetworkReply::NetworkError ) ) );
+            break;
+        }
+        default:
+        {
+            Q_ASSERT( false );
+            break;
+        }
+    }
+}
+
+void
+RoviPlugin::albumLookupError( QNetworkReply::NetworkError error )
+{
+    if ( error == QNetworkReply::NoError )
+        return;
+
+    QNetworkReply* reply = qobject_cast<QNetworkReply*>( sender() );
+    Q_ASSERT( reply );
+
+    Tomahawk::InfoSystem::InfoRequestData requestData = reply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >();
+    int requestId = reply->property( "requestId" ).toUInt();
+
+    emit info( requestId, requestData, QVariant() );
+
+}
+
+void
+RoviPlugin::albumLookupFinished()
+{
+    QNetworkReply* reply = qobject_cast<QNetworkReply*>( sender() );
+    Q_ASSERT( reply );
+
+    if ( reply->error() != QNetworkReply::NoError )
+        return;
+
+    Tomahawk::InfoSystem::InfoRequestData requestData = reply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >();
+    int requestId = reply->property( "requestId" ).toUInt();
+
+    QByteArray data = reply->readAll();
+    qDebug() << "data:" << data;
+    QJson::Parser p;
+    bool ok;
+    QVariantMap result = p.parse( data, &ok ).toMap();
+
+    if ( !ok || result.isEmpty() || !result.contains( "tracks" ) )
+    {
+        tLog() << "Error parsing JSON from Rovi!" << p.errorString() << result;
+        emit info( requestId, requestData, QVariant() );
+    }
+
+    tDebug() << "Got Rovi results:" << result[ "tracks" ];
+    QVariantList tracks = result[ "tracks" ].toList();
+    QStringList trackNameList;
+    foreach ( const QVariant& track, tracks )
+    {
+        const QVariantMap trackData = track.toMap();
+        if ( trackData.contains( "title" ) )
+            trackNameList << trackData[ "title" ].toString();
+    }
+    tDebug() << "FOUND TRACK LIST FROM ROVI:" << trackNameList;
+
+    QVariantMap returnedData;
+    returnedData["tracks"] = trackNameList;
+
+    emit info( requestId, requestData, returnedData );
+
+    Tomahawk::InfoSystem::InfoStringHash criteria;
+    criteria["artist"] = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash>()["artist"];
+
+    emit updateCache( criteria, 0, requestData.type, returnedData );
+}
+
+
+QNetworkReply*
+RoviPlugin::makeRequest( QUrl url )
+{
+    url.addQueryItem( "apikey", m_apiKey );
+    url.addEncodedQueryItem( "sig", generateSig() );
+
+    qDebug() << "url:" << url.toString();
+    return m_nam->get( QNetworkRequest( url ) );
+}
+
+
+QByteArray
+RoviPlugin::generateSig() const
+{
+    QByteArray raw = m_apiKey + m_secret + QString::number( QDateTime::currentMSecsSinceEpoch() / 1000 ).toLatin1();
+    return md5( raw ).toLatin1();
+
+}
diff --git a/src/libtomahawk/infosystem/infoplugins/generic/RoviPlugin.h b/src/libtomahawk/infosystem/infoplugins/generic/RoviPlugin.h
new file mode 100644
index 000000000..0bc2e9e8c
--- /dev/null
+++ b/src/libtomahawk/infosystem/infoplugins/generic/RoviPlugin.h
@@ -0,0 +1,67 @@
+/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
+ *
+ *   Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
+ *
+ *   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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ROVIPLUGIN_H
+#define ROVIPLUGIN_H
+
+#include "infosystem/infosystem.h"
+
+#include <QNetworkReply>
+
+class QNetworkAccessManager;
+
+namespace Tomahawk
+{
+
+namespace InfoSystem
+{
+
+class RoviPlugin : public InfoPlugin
+{
+    Q_OBJECT
+public:
+    RoviPlugin();
+    virtual ~RoviPlugin();
+
+protected:
+    virtual void namChangedSlot( QNetworkAccessManager* nam );
+    virtual void notInCacheSlot( uint requestId, Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData );
+
+    virtual void pushInfo( QString, Tomahawk::InfoSystem::InfoType, QVariant )
+    {}
+
+    virtual void getInfo( uint requestId, Tomahawk::InfoSystem::InfoRequestData requestData );
+
+private slots:
+    void albumLookupFinished();
+    void albumLookupError( QNetworkReply::NetworkError );
+private:
+    QNetworkReply* makeRequest( QUrl url );
+    QByteArray generateSig() const;
+
+    QNetworkAccessManager* m_nam;
+
+    QByteArray m_apiKey;
+    QByteArray m_secret;
+};
+
+}
+
+}
+
+#endif // ROVIPLUGIN_H
diff --git a/src/libtomahawk/infosystem/infosystemworker.cpp b/src/libtomahawk/infosystem/infosystemworker.cpp
index 9ae11951c..965a21581 100644
--- a/src/libtomahawk/infosystem/infosystemworker.cpp
+++ b/src/libtomahawk/infosystem/infosystemworker.cpp
@@ -40,6 +40,7 @@
 #endif
 
 #include "lastfm/NetworkAccessManager"
+#include "infoplugins/generic/RoviPlugin.h"
 
 namespace Tomahawk
 {
@@ -92,7 +93,9 @@ InfoSystemWorker::init( QWeakPointer< Tomahawk::InfoSystem::InfoSystemCache> cac
     InfoPluginPtr sptr( new ChartsPlugin() );
     m_plugins.append( sptr );
     registerInfoTypes( sptr, sptr.data()->supportedGetTypes(), sptr.data()->supportedPushTypes() );
-
+    InfoPluginPtr roviptr( new RoviPlugin() );
+    m_plugins.append( roviptr );
+    registerInfoTypes( roviptr, roviptr.data()->supportedGetTypes(), roviptr.data()->supportedPushTypes() );
 
     #ifdef Q_WS_MAC
     InfoPluginPtr admptr( new AdiumPlugin() );
@@ -105,7 +108,7 @@ InfoSystemWorker::init( QWeakPointer< Tomahawk::InfoSystem::InfoSystemCache> cac
     registerInfoTypes( fdonotifyptr, fdonotifyptr.data()->supportedGetTypes(), fdonotifyptr.data()->supportedPushTypes() );
     InfoPluginPtr mprisptr( new MprisPlugin() );
     m_plugins.append( mprisptr );
-    registerInfoTypes( mprisptr, mprisptr.data()->supportedGetTypes(), mprisptr.data()->supportedPushTypes() );    
+    registerInfoTypes( mprisptr, mprisptr.data()->supportedGetTypes(), mprisptr.data()->supportedPushTypes() );
     #endif
 
     Q_FOREACH( InfoPluginPtr plugin, m_plugins )
diff --git a/src/libtomahawk/playlist/treemodel.cpp b/src/libtomahawk/playlist/treemodel.cpp
index 8dd336ea5..14cc9e06f 100644
--- a/src/libtomahawk/playlist/treemodel.cpp
+++ b/src/libtomahawk/playlist/treemodel.cpp
@@ -629,12 +629,13 @@ TreeModel::addTracks( const album_ptr& album, const QModelIndex& parent )
         artistInfo["artist"] = album->artist()->name();
         artistInfo["album"] = album->name();
 
+        m_receivedInfoData.remove( artistInfo );
         Tomahawk::InfoSystem::InfoRequestData requestData;
         requestData.caller = m_infoId;
         requestData.customData["rows"] = QVariant( rows );
         requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( artistInfo );
         requestData.type = Tomahawk::InfoSystem::InfoAlbumSongs;
-        Tomahawk::InfoSystem::InfoSystem::instance()->getInfo( requestData );
+        Tomahawk::InfoSystem::InfoSystem::instance()->getInfo( requestData, 0, true );
     }
     else
         Q_ASSERT( false );
@@ -845,6 +846,10 @@ TreeModel::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QV
 
         case Tomahawk::InfoSystem::InfoAlbumSongs:
         {
+            if ( m_receivedInfoData.contains( requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >() ) )
+                break;
+            m_receivedInfoData.insert( requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >() );
+
             QVariantMap returnedData = output.value< QVariantMap >();
             QStringList tracks = returnedData[ "tracks" ].toStringList();
             QList<query_ptr> ql;
diff --git a/src/libtomahawk/playlist/treemodel.h b/src/libtomahawk/playlist/treemodel.h
index af4aa6bf0..0c22511cc 100644
--- a/src/libtomahawk/playlist/treemodel.h
+++ b/src/libtomahawk/playlist/treemodel.h
@@ -171,6 +171,7 @@ private:
 
     Tomahawk::collection_ptr m_collection;
     QHash<qlonglong, QPersistentModelIndex> m_coverHash;
+    QSet<Tomahawk::InfoSystem::InfoStringHash> m_receivedInfoData;
 };
 
 #endif // ALBUMMODEL_H