/src/libtomahawk/utils/ItunesParser.cpp

http://github.com/tomahawk-player/tomahawk · C++ · 207 lines · 147 code · 34 blank · 26 comment · 19 complexity · e7ba7cc8402d19de1a481ea57ee7b927 MD5 · raw file

  1. /* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
  2. *
  3. * Written by Hugo Lindström <hugolm84@gmail.com>
  4. * But based on Leo Franchi's work from spotifyParser
  5. * Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
  6. * Copyright 2010-2014, Christian Muehlhaeuser <muesli@tomahawk-player.org>
  7. *
  8. * Tomahawk is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation, either version 3 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * Tomahawk is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
  20. */
  21. #include "ItunesParser.h"
  22. #include "jobview/JobStatusView.h"
  23. #include "jobview/JobStatusModel.h"
  24. #include "jobview/ErrorStatusMessage.h"
  25. #include "utils/Json.h"
  26. #include "utils/NetworkReply.h"
  27. #include "utils/TomahawkUtils.h"
  28. #include "utils/Logger.h"
  29. #include "utils/NetworkAccessManager.h"
  30. #include "Query.h"
  31. #include "SourceList.h"
  32. #include <QNetworkAccessManager>
  33. #include <QRegExp>
  34. using namespace Tomahawk;
  35. QPixmap* ItunesParser::s_pixmap = 0;
  36. ItunesParser::ItunesParser( const QStringList& urls, QObject* parent )
  37. : QObject ( parent )
  38. , m_single( false )
  39. {
  40. foreach ( const QString& url, urls )
  41. {
  42. lookupItunesUri( url );
  43. }
  44. }
  45. ItunesParser::ItunesParser( const QString& Url, QObject* parent )
  46. : QObject ( parent )
  47. , m_single( true )
  48. {
  49. lookupItunesUri( Url );
  50. }
  51. ItunesParser::~ItunesParser()
  52. {
  53. }
  54. void
  55. ItunesParser::lookupItunesUri( const QString& link )
  56. {
  57. // Itunes uri parsing, using regex
  58. // (\d+)(?:\?i=*)(\d+) = AlbumId and trackId
  59. // (\d+)(?:\s*) = id
  60. QRegExp rxAlbumTrack( "(\\d+)(?:\\?i=*)(\\d+)" );
  61. QRegExp rxId( "(\\d+)(?:\\s*)" );
  62. QString id, trackId;
  63. // Doing a parse on regex in 2 stages,
  64. // first, look if we have both album and track id
  65. int pos = rxAlbumTrack.indexIn( link );
  66. if ( pos > -1 )
  67. {
  68. id = rxAlbumTrack.cap( 1 );
  69. trackId = rxAlbumTrack.cap( 2 );
  70. }
  71. else
  72. {
  73. // Second, if we dont have trackId, check for just Id
  74. int pos = rxId.indexIn( link );
  75. if ( pos > -1 )
  76. {
  77. id = rxId.cap( 1 );
  78. }
  79. else
  80. return;
  81. }
  82. QUrl url;
  83. DropJob::DropType type;
  84. if ( link.contains( "artist" ) )
  85. {
  86. type = DropJob::Artist;
  87. url = QUrl( QString( "http://ax.phobos.apple.com.edgesuite.net/WebObjects/MZStoreServices.woa/wa/wsLookup?id=%1&entity=song&limit=30" ).arg( id ) );
  88. }
  89. else
  90. {
  91. type = ( trackId.isEmpty() ? DropJob::Album : DropJob::Track );
  92. url = QUrl( QString( "http://ax.phobos.apple.com.edgesuite.net/WebObjects/MZStoreServices.woa/wa/wsLookup?id=%1&entity=song" ).arg( ( trackId.isEmpty() ? id : trackId ) ) );
  93. }
  94. NetworkReply* reply = new NetworkReply( Tomahawk::Utils::nam()->get( QNetworkRequest( url ) ) );
  95. connect( reply, SIGNAL( finished() ), SLOT( itunesResponseLookupFinished() ) );
  96. DropJobNotifier* j = new DropJobNotifier( pixmap(), QString( "Itunes" ), type, reply );
  97. JobStatusView::instance()->model()->addJob( j );
  98. m_queries.insert( reply );
  99. }
  100. void
  101. ItunesParser::itunesResponseLookupFinished()
  102. {
  103. NetworkReply* r = qobject_cast< NetworkReply* >( sender() );
  104. Q_ASSERT( r );
  105. r->deleteLater();
  106. m_queries.remove( r );
  107. if ( r->reply()->error() == QNetworkReply::NoError )
  108. {
  109. bool ok;
  110. QByteArray jsonData = r->reply()->readAll();
  111. QVariantMap res = TomahawkUtils::parseJson( jsonData, &ok ).toMap();
  112. if ( !ok )
  113. {
  114. tLog() << "Failed to parse json from itunes track lookup:" << jsonData;
  115. checkTrackFinished();
  116. return;
  117. }
  118. else if ( !res.contains( "results" ) )
  119. {
  120. tLog() << "No 'results' item in the itunes track lookup result... not doing anything";
  121. checkTrackFinished();
  122. return;
  123. }
  124. QVariantList itunesResponse = res.value( "results" ).toList();
  125. foreach ( QVariant itune, itunesResponse )
  126. {
  127. QString title, artist, album;
  128. QVariantMap ituneMap = itune.toMap();
  129. if ( ituneMap.value( "wrapperType" ).toString().contains( "track" ) )
  130. {
  131. title = ituneMap.value( "trackName" ).toString();
  132. artist = ituneMap.value( "artistName" ).toString();
  133. album = ituneMap.value( "collectionName" ).toString();
  134. if ( title.isEmpty() && artist.isEmpty() ) // don't have enough...
  135. {
  136. tLog() << "Didn't get an artist and track name from itunes, not enough to build a query on. Aborting" << title << artist << album;
  137. }
  138. else
  139. {
  140. Tomahawk::query_ptr q = Tomahawk::Query::get( artist, title, album, uuid(), true );
  141. if ( q.isNull() )
  142. continue;
  143. m_tracks << q;
  144. }
  145. }
  146. }
  147. }
  148. else
  149. {
  150. JobStatusView::instance()->model()->addJob( new ErrorStatusMessage( tr( "Error fetching iTunes information from the network!" ) ) );
  151. tLog() << "Error in network request to Itunes for track decoding:" << r->reply()->errorString();
  152. }
  153. checkTrackFinished();
  154. }
  155. void
  156. ItunesParser::checkTrackFinished()
  157. {
  158. if ( m_queries.isEmpty() ) // we're done
  159. {
  160. if ( m_single && !m_tracks.isEmpty() )
  161. emit track( m_tracks.first() );
  162. else if ( !m_single && !m_tracks.isEmpty() )
  163. emit tracks( m_tracks );
  164. deleteLater();
  165. }
  166. }
  167. QPixmap
  168. ItunesParser::pixmap() const
  169. {
  170. if ( !s_pixmap )
  171. s_pixmap = new QPixmap( RESPATH "images/itunes.png" );
  172. return *s_pixmap;
  173. }