1 /****************************************************************************************
2  * Copyright (c) 2010 Andrew Coder <andrew.coder@gmail.com>                             *                                                                                      *
3  * This program is free software; you can redistribute it and/or modify it under        *
4  * the terms of the GNU General Public License as published by the Free Software        *
5  * Foundation; either version 2 of the License, or (at your option) any later           *
6  * version.                                                                             *
7  *                                                                                      *
8  * This program is distributed in the hope that it will be useful, but WITHOUT ANY      *
9  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A      *
10  * PARTICULAR PURPOSE. See the GNU General Public License for more details.             *
11  *                                                                                      *
12  * You should have received a copy of the GNU General Public License along with         *
13  * this program.  If not, see <http://www.gnu.org/licenses/>.                           *
14  ****************************************************************************************/
15 
16 #include "Query.h"
17 
18 #include "Controller.h"
19 #include "core/meta/Meta.h"
20 #include "../PlaydarMeta.h"
21 #include "core/support/Debug.h"
22 
23 #include <QJsonArray>
24 #include <QJsonDocument>
25 #include <QJsonObject>
26 #include <QJsonParseError>
27 #include <QMap>
28 #include <QString>
29 #include <QUrl>
30 #include <QVariant>
31 #include <QVariantMap>
32 
33 #include <KIO/Job>
34 
35 
36 namespace Playdar
37 {
Query(const QString & qid,Playdar::Controller * controller,bool waitForSolution)38     Query::Query( const QString &qid,
39                   Playdar::Controller* controller,
40                   bool waitForSolution )
41     : m_controller( controller )
42     , m_waitForSolution( waitForSolution )
43     , m_qid( qid )
44     , m_artist( QString( "" ) )
45     , m_album( QString( "" ) )
46     , m_title( QString( "" ) )
47     , m_solved( false )
48     , m_receivedFirstResults( false )
49     , m_trackList( )
50     {
51         DEBUG_BLOCK
52 
53         if( m_waitForSolution )
54         {
55             m_receivedFirstResults = true;
56             m_controller->getResultsLongPoll( this );
57         }
58         else
59             m_controller->getResults( this );
60     }
61 
~Query()62     Query::~Query()
63     {
64         DEBUG_BLOCK
65 
66     }
67 
68     QString
qid() const69     Query::qid() const
70     {
71         DEBUG_BLOCK
72 
73         return m_qid;
74     }
75 
76     QString
artist() const77     Query::artist() const
78     {
79         DEBUG_BLOCK
80 
81         return m_artist;
82     }
83 
84     QString
album() const85     Query::album() const
86     {
87         DEBUG_BLOCK
88 
89         return m_album;
90     }
91 
92     QString
title() const93     Query::title() const
94     {
95         DEBUG_BLOCK
96 
97         return m_title;
98     }
99 
100     bool
isSolved() const101     Query::isSolved() const
102     {
103         DEBUG_BLOCK
104 
105         return m_solved;
106     }
107 
108     Meta::PlaydarTrackList
getTrackList() const109     Query::getTrackList() const
110     {
111         DEBUG_BLOCK
112 
113         return m_trackList;
114     }
115 
116     void
receiveResults(KJob * resultsJob)117     Query::receiveResults( KJob* resultsJob)
118     {
119         DEBUG_BLOCK
120 
121         if( resultsJob->error() != 0 ) {
122             debug() << "Error getting results from Playdar";
123             Q_EMIT playdarError( Playdar::Controller::ErrorState( 1 ) );
124             return;
125         }
126 
127         debug() << "Processing received JSON data...";
128         KIO::StoredTransferJob* storedResultsJob = static_cast<KIO::StoredTransferJob*>( resultsJob );
129 
130         QJsonParseError err;
131         auto doc = QJsonDocument::fromJson( storedResultsJob->data(), &err );
132 
133         if ( err.error != QJsonParseError::NoError )
134             debug() << "Error parsing JSON Data:" << err.errorString();
135 
136         if( !doc.isObject() )
137         {
138             debug() << "Parsed Json data is not an object";
139             return;
140         }
141 
142         auto object = doc.object();
143 
144         if( !object.contains( "results" ) )
145         {
146             debug() << "Expecting results in Playdar's response, received none";
147             Q_EMIT playdarError( Playdar::Controller::ErrorState( 6 ) );
148             return;
149         }
150         if( !object.contains( "qid" ) )
151         {
152             debug() << "Expected qid in Playdar's response, received none";
153             Q_EMIT playdarError( Playdar::Controller::ErrorState( 4 ) );
154             return;
155         }
156         if( object.value( "qid" ) != m_qid )
157         {
158             debug() << "A query received the wrong results from Playdar...";
159             Q_EMIT playdarError( Playdar::Controller::ErrorState( 5 ) );
160             return;
161         }
162 
163         m_artist = object.value( "artist" ).toString();
164         m_album = object.value( "album" ).toString();
165         m_title = object.value( "track" ).toString();
166 
167         for( const auto &resultVariant : object.value( "results" ).toArray() )
168         {
169             auto result = resultVariant.toObject();
170             Meta::PlaydarTrackPtr aTrack;
171             QUrl resultUrl( m_controller->urlForSid( result.value( "sid" ).toString() ) );
172 
173             QString trackSid = result.value( "sid" ).toString();
174             QString trackUrl = resultUrl.url();
175             QString trackTitle = result.value( "track" ).toString();
176             QString trackArtist = result.value( "artist" ).toString();
177             QString trackAlbum = result.value( "album" ).toString();
178             QString trackType = result.value( "mimetype" ).toString();
179             QString trackSource = result.value( "source" ).toString();
180             qint64 trackLengthInSeconds( result.value( "duration" ).toInt() );
181             aTrack = new Meta::PlaydarTrack
182             (
183                 trackSid,
184                 trackUrl,
185                 trackTitle,
186                 trackArtist,
187                 trackAlbum,
188                 trackType,
189                 result.value( "score" ).toDouble() * 100,
190                 ( trackLengthInSeconds * 1000 ), //convert s to ms
191                 result.value( "bitrate" ).toInt(),
192                 result.value( "size" ).toInt(),
193                 trackSource
194             );
195 
196             if( !m_solved && aTrack->score() >= 1.00 )
197             {
198                 m_solved = true;
199                 m_trackList.prepend( aTrack );
200                 Q_EMIT querySolved( aTrack );
201 
202                 if( m_waitForSolution )
203                 {
204                     Q_EMIT queryDone( this, m_trackList );
205                     return;
206                 }
207             }
208             else
209             {
210                 m_trackList.append( aTrack );
211             }
212             Q_EMIT newTrackAdded( aTrack );
213         }
214 
215         if( m_receivedFirstResults || m_solved )
216         {
217             m_receivedFirstResults = true;
218             Q_EMIT queryDone( this, m_trackList );
219         }
220         else
221         {
222             m_receivedFirstResults = true;
223             m_controller->getResultsLongPoll( this );
224         }
225     }
226 }
227