mpviewplugins/mpdetailsviewplugin/src/mpquerymanager.cpp
changeset 35 fdb31ab341af
child 32 c163ef0b758d
equal deleted inserted replaced
34:2c5162224003 35:fdb31ab341af
       
     1 /*
       
     2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available 
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description: Music Player Query Manager.
       
    15 *
       
    16 */
       
    17 
       
    18 #include "mpquerymanager.h"
       
    19 #include <QDebug>
       
    20 #include <QObject>
       
    21 #include <QNetworkAccessManager>
       
    22 #include <QNetworkDiskCache>
       
    23 #include <QNetworkProxyFactory>
       
    24 #include <qmobilityglobal.h>
       
    25 #include <qnetworksession.h>
       
    26 #include <QDomElement>
       
    27 #include <QList>
       
    28 #include <QFile>
       
    29 #include <QUrl>
       
    30 #include <QSslError>
       
    31 #include <QDir>
       
    32 #include <QCoreApplication>
       
    33 
       
    34 #include "mpdetailssharedialog.h"
       
    35 #include "mptrace.h"
       
    36 
       
    37 const int KRecommendationCount = 2;
       
    38 
       
    39 MpQueryManager::MpQueryManager()
       
    40                                
       
    41 {
       
    42     TX_ENTRY
       
    43 
       
    44     QString privatePathQt( QCoreApplication::applicationDirPath() );
       
    45     TX_LOG_ARGS( "Private path: " << privatePathQt );
       
    46     QDir dir( privatePathQt );
       
    47     QString newDir = "detailsview";
       
    48     bool res = dir.mkdir( newDir );
       
    49     TX_LOG_ARGS( "New dir creation result: " << res);
       
    50 
       
    51     // We're not handling a negative result for directory creation here,
       
    52     // instead it will be escalated in DownloadFinished() method.
       
    53     privatePathQt = privatePathQt + "/detailsview";
       
    54     QString albumArt1( privatePathQt + "/albumOne.png" );
       
    55     QString albumArt2( privatePathQt + "/albumTwo.png" );
       
    56     mRecommendationAlbumArtsName << albumArt1 << albumArt2;
       
    57     TX_LOG_ARGS( "recommendation album art names: " << mRecommendationAlbumArtsName );
       
    58 
       
    59     mManager = new QNetworkAccessManager( this );
       
    60       
       
    61     mDownloadManager = new QNetworkAccessManager( this );
       
    62     connect( mDownloadManager, SIGNAL( finished( QNetworkReply * ) ), this, SLOT( DownloadFinished( QNetworkReply * ) ) );
       
    63      
       
    64     TX_EXIT
       
    65 }
       
    66 
       
    67 MpQueryManager::~MpQueryManager()
       
    68 {
       
    69     TX_ENTRY
       
    70     if ( mManager ) {
       
    71        mManager->deleteLater();
       
    72      }
       
    73     if ( mDownloadManager ) {
       
    74        mDownloadManager->deleteLater();
       
    75     }
       
    76     TX_EXIT
       
    77 }
       
    78 
       
    79 
       
    80 void MpQueryManager::clearNetworkReplies()
       
    81 {
       
    82     disconnect( mManager, SIGNAL( finished( QNetworkReply * ) ), this, SLOT( retrieveInformationFinished( QNetworkReply * ) ) );     
       
    83     TX_ENTRY_ARGS( "Reply count = " << mReplys.count() );    
       
    84     for ( int i = 0; i < mReplys.count(); i++ ) {
       
    85         QNetworkReply *reply = mReplys.at( i );
       
    86         disconnect( reply, SIGNAL( error( QNetworkReply::NetworkError ) ), this, SLOT( retrieveInformationNetworkError( QNetworkReply::NetworkError ) ) );        
       
    87         if ( reply != NULL ) {
       
    88             reply->close();
       
    89             reply->deleteLater();
       
    90             reply = NULL;
       
    91         }   
       
    92     }
       
    93     mReplys.clear();
       
    94     TX_EXIT
       
    95 }
       
    96 
       
    97 
       
    98 void MpQueryManager::queryLocalMusicStore(QString artist,QString album,QString title)
       
    99 {
       
   100     TX_ENTRY
       
   101     mArtist=artist;
       
   102     mAlbum=album;
       
   103     mTitle=title;
       
   104     // TODO: country information handling, MCC
       
   105     QString queryURI("http://api.music.ovi.com/1.0/ru/?");
       
   106     constructRequest( queryURI );
       
   107     TX_LOG_ARGS( "queryURI : " << queryURI );
       
   108     retrieveInformation( queryURI );
       
   109     TX_EXIT    
       
   110 }
       
   111     
       
   112 void MpQueryManager::queryInspireMeItems(QString artist,QString album,QString title)
       
   113 {
       
   114     TX_ENTRY    
       
   115     mArtist=artist;
       
   116     mAlbum=album;
       
   117     mTitle=title;
       
   118     // start querying inspire me items
       
   119     QString queryRecommendation("http://api.music.ovi.com/1.0/gb/releases/recommend/?");
       
   120     constructRequest( queryRecommendation );
       
   121     TX_LOG_ARGS( "queryRecommendation : " << queryRecommendation );
       
   122     retrieveInformation( queryRecommendation );
       
   123     TX_EXIT
       
   124 }
       
   125 
       
   126 void MpQueryManager::clearRecommendations()
       
   127 {
       
   128     TX_ENTRY    
       
   129     mDownloadedAlbumArts = 0;
       
   130     mAlbumArtsReadyCount = 0;
       
   131     for ( int i = 0; i < KRecommendationCount; i++ ) {
       
   132        mRecommendationSongs.clear();
       
   133        mRecommendationArtists.clear();
       
   134        mRecommendationAlbumArtsLink.clear();
       
   135        mRecommendationAlbumArtsMap.clear();      
       
   136        QFile file( mRecommendationAlbumArtsName.at( i ) );        
       
   137        if ( file.exists() ) {
       
   138            if ( file.remove() ) {
       
   139                TX_LOG_ARGS( "File removed - " << file.fileName() );
       
   140            }
       
   141            else {
       
   142                TX_LOG_ARGS( "Cannot remove file - " << file.fileName() );
       
   143            }
       
   144        } else {
       
   145            TX_LOG_ARGS( "File doesn't exist - " << file.fileName() );
       
   146        }
       
   147     }
       
   148     TX_EXIT    
       
   149 }
       
   150 
       
   151 /*!
       
   152  Return recommendation songs
       
   153  */
       
   154 QStringList MpQueryManager::recommendationSongs()
       
   155 {
       
   156     TX_LOG  
       
   157     return mRecommendationSongs;
       
   158 }
       
   159 
       
   160 /*!
       
   161  Return recommendation artists
       
   162  */
       
   163 QStringList MpQueryManager::recommendationArtists()
       
   164 {
       
   165     TX_LOG  
       
   166     return mRecommendationArtists;
       
   167 }
       
   168 
       
   169 /*!
       
   170  Return recommendation album arts links
       
   171  */
       
   172 QStringList MpQueryManager::recommendationAlbumArtsLink()
       
   173 {
       
   174     TX_LOG  
       
   175     return mRecommendationAlbumArtsLink;
       
   176 }
       
   177 
       
   178 /*!
       
   179  Return map of name and pixmap
       
   180  */
       
   181 QMap<QString, QPixmap>  MpQueryManager::recommendationAlbumArtsMap()
       
   182 {
       
   183     TX_LOG  
       
   184     return mRecommendationAlbumArtsMap;
       
   185 }
       
   186 
       
   187 /*!
       
   188  Return the number of ready album arts
       
   189  */
       
   190 int &MpQueryManager::albumArtsReadyCount()
       
   191 {
       
   192     TX_LOG  
       
   193     return mAlbumArtsReadyCount;
       
   194 }
       
   195 
       
   196 /*!
       
   197  Insert one uri & pixmap item into map
       
   198  */
       
   199 void MpQueryManager::insertMapItem( const QString &uri, const QPixmap &pixmap )
       
   200 {
       
   201     TX_ENTRY_ARGS( "Map Item URI: " << uri );
       
   202     mRecommendationAlbumArtsMap.insert( uri, pixmap );
       
   203     TX_EXIT
       
   204 }
       
   205 
       
   206 /*!
       
   207  Slot to call when getting response
       
   208  */
       
   209 void MpQueryManager::retrieveInformationFinished( QNetworkReply* reply )
       
   210 {
       
   211     TX_ENTRY
       
   212     QString errorStr;
       
   213     int errorLine;
       
   214     int errorColumn;
       
   215     bool parsingSuccess;
       
   216     
       
   217     if ( reply->error() == QNetworkReply::NoError )
       
   218     {
       
   219         parsingSuccess = mDomDocument.setContent( reply, true, &errorStr, &errorLine, &errorColumn );
       
   220         if ( parsingSuccess ) {
       
   221             handleParsedXML();  //CodeScanner throws a warning mis-interpreting the trailing 'L' to be a leaving function.
       
   222         } else {
       
   223             // TODO: agree on error handling            
       
   224             TX_LOG_ARGS( "XML parsing error" );
       
   225         }
       
   226     }
       
   227     else
       
   228     {
       
   229         // TODO: agree on error handling
       
   230         TX_LOG_ARGS( "Network error in retrieving Information" );
       
   231         emit networkError();
       
   232     }
       
   233     TX_EXIT
       
   234 }
       
   235 
       
   236 /*!
       
   237  Slot to call when there is network error
       
   238  */
       
   239 void MpQueryManager::retrieveInformationNetworkError( QNetworkReply::NetworkError error )
       
   240 {
       
   241     Q_UNUSED(error);
       
   242     TX_ENTRY_ARGS( "Network error for retrieving Information" << error);
       
   243     TX_EXIT
       
   244 }
       
   245 
       
   246 /*!
       
   247  Slot to call when there is ssl error
       
   248  */
       
   249 void MpQueryManager::retrieveInformationSslErrors( const QList<QSslError> &/*error*/ )
       
   250 {   
       
   251     // TODO: agree on error handling
       
   252     TX_ENTRY_ARGS( "SSL error for retrieving Information" );
       
   253     TX_EXIT
       
   254 }
       
   255 
       
   256 /*!
       
   257  Slot to call when downloading finished
       
   258  */
       
   259 void MpQueryManager::DownloadFinished( QNetworkReply* reply )
       
   260 {
       
   261     TX_ENTRY_ARGS( "mDownloadedAlbumArts = " << mDownloadedAlbumArts );
       
   262     if ( reply->error() == QNetworkReply::NoError )
       
   263         {
       
   264         QString fileName = mRecommendationAlbumArtsName.at( mDownloadedAlbumArts );
       
   265         QByteArray imageData = reply->readAll();
       
   266         bool ret = writeImageToFile( imageData, fileName );
       
   267 
       
   268         // If file writing went OK, emit a signal with the real filename
       
   269         // If it failed, use empty filename (since file was removed in any case)
       
   270         if ( ret )
       
   271             {
       
   272             emit setAlbumArt( mRecommendationAlbumArtsLink.at( mDownloadedAlbumArts),
       
   273                                  mRecommendationAlbumArtsName.at( mDownloadedAlbumArts ) );
       
   274             }
       
   275         else
       
   276             {
       
   277             emit setAlbumArt( mRecommendationAlbumArtsLink.at( mDownloadedAlbumArts), "" );
       
   278             }
       
   279         }
       
   280     else
       
   281     {
       
   282         TX_LOG_ARGS( "Downloading album art failed!" );
       
   283         emit networkError();
       
   284     }
       
   285     
       
   286     mDownloadedAlbumArts++;
       
   287     TX_EXIT
       
   288 }
       
   289 
       
   290 /*!
       
   291  Write the image data to a file with the given filename.
       
   292  If writing operation fails for any reason (e.g. OOD),
       
   293  returns false, otherwise true.
       
   294  */
       
   295 bool MpQueryManager::writeImageToFile(const QByteArray &aImageData, const QString &aImageFileName )
       
   296     {
       
   297     bool ret( false );
       
   298     TX_ENTRY_ARGS( "imagefile: " << aImageFileName );
       
   299     if ( aImageFileName.isEmpty() )
       
   300         {
       
   301         TX_LOG_ARGS( "Only store two album arts" );
       
   302         }
       
   303     else
       
   304         {
       
   305         QFile file( aImageFileName );
       
   306 
       
   307         if ( !file.open( QIODevice::ReadWrite ) )
       
   308             {
       
   309             TX_LOG_ARGS( "Unable to open file" );
       
   310             }
       
   311         else
       
   312             {
       
   313             qint64 writtenBytes = file.write( aImageData );
       
   314 
       
   315             // Verify file write status
       
   316             if ( writtenBytes < aImageData.size() )
       
   317                 {
       
   318                 // If write succeeded only partially, or completely failed,
       
   319                 // remove the file from filesystem to remove risk of corruption
       
   320                 TX_LOG_ARGS( "Wrote only " << writtenBytes << " bytes, aborting operation!" );
       
   321                 file.close();
       
   322                 QFile::remove( mRecommendationAlbumArtsName.at( mDownloadedAlbumArts ) );
       
   323                 }
       
   324             else
       
   325                 {
       
   326                 // If write fully succeeded, flush contents
       
   327                 TX_LOG_ARGS( "Wrote all the bytes (" << writtenBytes << "), flushing and closing!");
       
   328                 file.flush();
       
   329                 file.close();
       
   330                 ret = true;
       
   331                 }
       
   332             }
       
   333         }
       
   334     TX_LOG_ARGS( "Returning with value: " << ret );
       
   335     TX_EXIT
       
   336     return ret;
       
   337     }
       
   338 
       
   339 /*!
       
   340  Get Atom response from Ovi server based on query
       
   341  */
       
   342 void MpQueryManager::retrieveInformation( const QString &urlEncoded )
       
   343 {
       
   344     TX_ENTRY_ARGS( "urlEconded = " << urlEncoded)
       
   345     connect( mManager, SIGNAL( finished( QNetworkReply * ) ), this, SLOT( retrieveInformationFinished( QNetworkReply * ) ) );    
       
   346     QNetworkReply *reply = mManager->get( QNetworkRequest( QUrl( urlEncoded ) ) );
       
   347     mReplys.append( reply );
       
   348     
       
   349     connect( reply, SIGNAL( error( QNetworkReply::NetworkError ) ), this, SLOT( retrieveInformationNetworkError( QNetworkReply::NetworkError ) ) );
       
   350     connect( reply, SIGNAL( sslErrors( QList<QSslError> ) ), this, SLOT( retrieveInformationSslErrors( QList<QSslError> ) ) );
       
   351     TX_EXIT
       
   352 }
       
   353 
       
   354 
       
   355 /*!
       
   356  Find the most suitable link based on Atom response from Ovi music server
       
   357  */
       
   358 void MpQueryManager::handleParsedXML()
       
   359 {
       
   360     TX_ENTRY
       
   361     QDomElement rootElement = mDomDocument.documentElement();
       
   362     
       
   363     if ( rootElement.attribute( "type" ) == "search" ) {
       
   364         TX_LOG_ARGS( "URI response" )
       
   365         QString result;
       
   366         QDomElement entry = rootElement.firstChildElement( "entry" );
       
   367         while ( !entry.isNull() )
       
   368         {
       
   369             if ( entry.attribute( "type" ) == "musictrack" ) {
       
   370                 QDomElement link = entry.firstChildElement( "link" );
       
   371                 while ( !link.isNull() )
       
   372                 {
       
   373                     if ( link.attribute( "rel" ) == "alternate"
       
   374                         && link.attribute( "type" ) == "text/html" ) {
       
   375                         result = link.attribute( "href" );
       
   376                     }
       
   377                     link = link.nextSiblingElement( "link" );
       
   378                 }
       
   379             }
       
   380             entry = entry.nextSiblingElement( "entry" );
       
   381         }
       
   382 		// Signal that the url was received. Might be empty string.
       
   383 		emit searchUrlRetrieved( result );
       
   384     } else if ( rootElement.attribute( "type" ) == "recommendedTracks" ) {
       
   385         TX_LOG_ARGS( "Recommendation response" )
       
   386         QDomElement entry = rootElement.firstChildElement( "entry" );
       
   387         QNetworkReply *reply;
       
   388         int count = 0;
       
   389         while ( !entry.isNull() && count < KRecommendationCount )
       
   390         {
       
   391             if ( entry.attribute( "type" ) == "musictrack" ) {
       
   392                 QDomElement link = entry.firstChildElement( "link" );
       
   393                 while ( !link.isNull() )
       
   394                 {
       
   395                     if ( link.attribute( "title" ) == "albumart100" ) {
       
   396                         mRecommendationAlbumArtsLink.append( link.attribute( "href" ) );
       
   397                         break;
       
   398                     } else {
       
   399                         link = link.nextSiblingElement( "link" );
       
   400                     }                    
       
   401                 }
       
   402                 QDomElement metadata = entry.firstChildElement( "metadata" );
       
   403                 mRecommendationSongs.append( metadata.firstChildElement( "name" ).text() );
       
   404                 mRecommendationArtists.append( metadata.firstChildElement( "primaryartist" ).text() );
       
   405                 count++;
       
   406             }
       
   407             entry = entry.nextSiblingElement( "entry" );
       
   408         }          
       
   409         
       
   410         for (int i = 0; i < KRecommendationCount; i++ ) {
       
   411             TX_LOG_ARGS( "song name: " << mRecommendationSongs.at(i) );
       
   412             TX_LOG_ARGS( "Artist name: " << mRecommendationArtists.at(i) );
       
   413             TX_LOG_ARGS( "Album art link: " << mRecommendationAlbumArtsLink.at(i) );
       
   414             
       
   415             if ( mRecommendationAlbumArtsLink.at( i ).contains( "http", Qt::CaseInsensitive ) ) {
       
   416                 reply = mDownloadManager->get( QNetworkRequest( QUrl( mRecommendationAlbumArtsLink.at(i) ) ) );
       
   417                 mReplys.append( reply );
       
   418                 connect( reply, SIGNAL( error( QNetworkReply::NetworkError ) ), this, SLOT( retrieveInformationNetworkError( QNetworkReply::NetworkError ) ) );
       
   419                 connect( reply, SIGNAL( sslErrors( QList<QSslError> ) ), this, SLOT( retrieveInformationSslErrors( QList<QSslError> ) ) );
       
   420             }             
       
   421         }
       
   422     } else {
       
   423         TX_LOG_ARGS( "Not supported response" )
       
   424     }
       
   425     TX_EXIT
       
   426 }
       
   427 
       
   428 /*!
       
   429  Construct the query for fetching URI & recommendations
       
   430  */
       
   431 void MpQueryManager::constructRequest( QString &uri )
       
   432 {
       
   433     TX_ENTRY_ARGS( "uri =" << uri)
       
   434     
       
   435     QStringList keys;
       
   436     keys << "artist" << "albumtitle" << "tracktitle" << "orderby";
       
   437     
       
   438     // TODO: need to clarify which crition to use for sort, currently hard code to "relevancy"
       
   439     // order can be relevancy, alltimedownloads, streetreleasedate, sortname, recentdownloads
       
   440     QStringList values;
       
   441     values << mArtist << mAlbum << mTitle << QString("relevancy");
       
   442     TX_LOG_ARGS( "Artist: " << mArtist ); 
       
   443     TX_LOG_ARGS( "Album: " << mAlbum );
       
   444     TX_LOG_ARGS( "Title: " << mTitle );
       
   445     
       
   446     uri += keyValues( keys, values );
       
   447 
       
   448     QUrl url(uri);
       
   449     uri = url.toEncoded();
       
   450     TX_EXIT
       
   451 }
       
   452 
       
   453 /*!
       
   454  Make a key & value pair string for querying
       
   455  */
       
   456 QString MpQueryManager::keyValues( QStringList keys, QStringList values ) const
       
   457 {
       
   458     TX_ENTRY
       
   459     QString str;
       
   460     if ( keys.length() != values.length() ) {
       
   461         TX_LOG_ARGS( "Error: keys length is not equal to values length" ); 
       
   462     } else {
       
   463         for ( int i = 0; i < keys.length(); i++ ) {
       
   464             QString tValue = values.at( i );
       
   465             if ( 0 != tValue.length() )
       
   466             {
       
   467                 str += keys.at( i ) + "=" + values.at( i ) + "&";
       
   468             }
       
   469         }
       
   470     }
       
   471     TX_EXIT
       
   472     return str.left( str.length() - 1 );
       
   473 }
       
   474