PageRenderTime 183ms CodeModel.GetById 40ms app.highlight 116ms RepoModel.GetById 15ms app.codeStats 0ms

/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
 22#include "ItunesParser.h"
 23
 24#include "jobview/JobStatusView.h"
 25#include "jobview/JobStatusModel.h"
 26#include "jobview/ErrorStatusMessage.h"
 27#include "utils/Json.h"
 28#include "utils/NetworkReply.h"
 29#include "utils/TomahawkUtils.h"
 30#include "utils/Logger.h"
 31#include "utils/NetworkAccessManager.h"
 32
 33#include "Query.h"
 34#include "SourceList.h"
 35
 36#include <QNetworkAccessManager>
 37#include <QRegExp>
 38
 39
 40using namespace Tomahawk;
 41
 42QPixmap* ItunesParser::s_pixmap = 0;
 43
 44
 45ItunesParser::ItunesParser( const QStringList& urls, QObject* parent )
 46    : QObject ( parent )
 47    , m_single( false )
 48{
 49    foreach ( const QString& url, urls )
 50    {
 51        lookupItunesUri( url );
 52    }
 53}
 54
 55
 56ItunesParser::ItunesParser( const QString& Url, QObject* parent )
 57    : QObject ( parent )
 58    , m_single( true )
 59{
 60    lookupItunesUri( Url );
 61}
 62
 63
 64ItunesParser::~ItunesParser()
 65{
 66}
 67
 68
 69void
 70ItunesParser::lookupItunesUri( const QString& link )
 71{
 72    // Itunes uri parsing, using regex
 73    // (\d+)(?:\?i=*)(\d+) = AlbumId and trackId
 74    // (\d+)(?:\s*) = id
 75    QRegExp rxAlbumTrack( "(\\d+)(?:\\?i=*)(\\d+)" );
 76    QRegExp rxId( "(\\d+)(?:\\s*)" );
 77    QString id, trackId;
 78
 79    // Doing a parse on regex in 2 stages,
 80    // first, look if we have both album and track id
 81    int pos = rxAlbumTrack.indexIn( link );
 82    if ( pos > -1 )
 83    {
 84        id = rxAlbumTrack.cap( 1 );
 85        trackId = rxAlbumTrack.cap( 2 );
 86    }
 87    else
 88    {
 89        // Second, if we dont have trackId, check for just Id
 90        int pos = rxId.indexIn( link );
 91        if ( pos > -1 )
 92        {
 93            id = rxId.cap( 1 );
 94        }
 95        else
 96            return;
 97    }
 98
 99    QUrl url;
100    DropJob::DropType type;
101    if ( link.contains( "artist" ) )
102    {
103        type = DropJob::Artist;
104        url = QUrl( QString( "http://ax.phobos.apple.com.edgesuite.net/WebObjects/MZStoreServices.woa/wa/wsLookup?id=%1&entity=song&limit=30" ).arg( id ) );
105    }
106    else
107    {
108        type = ( trackId.isEmpty() ? DropJob::Album : DropJob::Track );
109        url = QUrl( QString( "http://ax.phobos.apple.com.edgesuite.net/WebObjects/MZStoreServices.woa/wa/wsLookup?id=%1&entity=song" ).arg( ( trackId.isEmpty() ? id : trackId ) ) );
110    }
111
112    NetworkReply* reply = new NetworkReply( Tomahawk::Utils::nam()->get( QNetworkRequest( url ) ) );
113    connect( reply, SIGNAL( finished() ), SLOT( itunesResponseLookupFinished() ) );
114
115    DropJobNotifier* j = new DropJobNotifier( pixmap(), QString( "Itunes" ), type, reply );
116    JobStatusView::instance()->model()->addJob( j );
117
118    m_queries.insert( reply );
119}
120
121
122void
123ItunesParser::itunesResponseLookupFinished()
124{
125    NetworkReply* r = qobject_cast< NetworkReply* >( sender() );
126    Q_ASSERT( r );
127    r->deleteLater();
128    m_queries.remove( r );
129
130    if ( r->reply()->error() == QNetworkReply::NoError )
131    {
132        bool ok;
133        QByteArray jsonData = r->reply()->readAll();
134        QVariantMap res = TomahawkUtils::parseJson( jsonData, &ok ).toMap();
135
136        if ( !ok )
137        {
138            tLog() << "Failed to parse json from itunes track lookup:" << jsonData;
139            checkTrackFinished();
140            return;
141        }
142        else if ( !res.contains( "results" ) )
143        {
144            tLog() << "No 'results' item in the itunes track lookup result... not doing anything";
145            checkTrackFinished();
146            return;
147        }
148        QVariantList itunesResponse = res.value( "results" ).toList();
149
150        foreach ( QVariant itune, itunesResponse )
151        {
152            QString title, artist, album;
153            QVariantMap ituneMap = itune.toMap();
154
155            if ( ituneMap.value( "wrapperType" ).toString().contains( "track" ) )
156            {
157                title = ituneMap.value( "trackName" ).toString();
158                artist = ituneMap.value( "artistName" ).toString();
159                album = ituneMap.value( "collectionName" ).toString();
160                if ( title.isEmpty() && artist.isEmpty() ) // don't have enough...
161                {
162                    tLog() << "Didn't get an artist and track name from itunes, not enough to build a query on. Aborting" << title << artist << album;
163                }
164                else
165                {
166                    Tomahawk::query_ptr q = Tomahawk::Query::get( artist, title, album, uuid(), true );
167                    if ( q.isNull() )
168                        continue;
169
170                    m_tracks << q;
171                }
172            }
173        }
174    }
175    else
176    {
177        JobStatusView::instance()->model()->addJob( new ErrorStatusMessage( tr( "Error fetching iTunes information from the network!" ) ) );
178        tLog() << "Error in network request to Itunes for track decoding:" << r->reply()->errorString();
179    }
180
181    checkTrackFinished();
182}
183
184
185void
186ItunesParser::checkTrackFinished()
187{
188    if ( m_queries.isEmpty() ) // we're done
189    {
190        if ( m_single && !m_tracks.isEmpty() )
191            emit track( m_tracks.first() );
192        else if ( !m_single && !m_tracks.isEmpty() )
193            emit tracks( m_tracks );
194
195        deleteLater();
196    }
197}
198
199
200QPixmap
201ItunesParser::pixmap() const
202{
203    if ( !s_pixmap )
204        s_pixmap = new QPixmap( RESPATH "images/itunes.png" );
205
206    return *s_pixmap;
207}