PageRenderTime 382ms CodeModel.GetById 91ms app.highlight 129ms RepoModel.GetById 113ms app.codeStats 0ms

/src/libtomahawk/database/DatabaseCommand_Resolve.cpp

http://github.com/tomahawk-player/tomahawk
C++ | 286 lines | 210 code | 47 blank | 29 comment | 20 complexity | 7f6196af203ad219f2e731df0d4b1ae2 MD5 | raw file
  1/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
  2 *
  3 *   Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
  4 *
  5 *   Tomahawk is free software: you can redistribute it and/or modify
  6 *   it under the terms of the GNU General Public License as published by
  7 *   the Free Software Foundation, either version 3 of the License, or
  8 *   (at your option) any later version.
  9 *
 10 *   Tomahawk is distributed in the hope that it will be useful,
 11 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 12 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 13 *   GNU General Public License for more details.
 14 *
 15 *   You should have received a copy of the GNU General Public License
 16 *   along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
 17 */
 18
 19#include "DatabaseCommand_Resolve.h"
 20
 21#include "utils/Logger.h"
 22
 23#include "Album.h"
 24#include "Artist.h"
 25#include "Pipeline.h"
 26#include "PlaylistEntry.h"
 27#include "SourceList.h"
 28#include "Track.h"
 29
 30using namespace Tomahawk;
 31
 32
 33DatabaseCommand_Resolve::DatabaseCommand_Resolve( const query_ptr& query )
 34    : DatabaseCommand()
 35    , m_query( query )
 36{
 37    // FIXME: We need to run tests of this DbCmd without a Pipeline
 38    // Q_ASSERT( Pipeline::instance()->isRunning() );
 39}
 40
 41
 42DatabaseCommand_Resolve::~DatabaseCommand_Resolve()
 43{
 44}
 45
 46
 47void
 48DatabaseCommand_Resolve::exec( DatabaseImpl* lib )
 49{
 50    /*
 51     *        Resolving is a 2 stage process.
 52     *        1) find list of trk/art/alb IDs that are reasonable matches to the metadata given
 53     *        2) find files in database by permitted sources and calculate score, ignoring
 54     *           results that are less than MINSCORE
 55     */
 56
 57    if ( !m_query->resultHint().isEmpty() )
 58    {
 59        tDebug() << "Using result-hint to speed up resolving:" << m_query->resultHint();
 60
 61        Tomahawk::result_ptr result = lib->resultFromHint( m_query );
 62        if ( result && ( !result->resolvedByCollection() || result->resolvedByCollection()->isOnline() ) )
 63        {
 64            QList<Tomahawk::result_ptr> res;
 65            res << result;
 66            emit results( m_query->id(), res );
 67            return;
 68        }
 69    }
 70
 71    if ( m_query->isFullTextQuery() )
 72        fullTextResolve( lib );
 73    else
 74        resolve( lib );
 75}
 76
 77
 78void
 79DatabaseCommand_Resolve::resolve( DatabaseImpl* lib )
 80{
 81    QList<Tomahawk::result_ptr> res;
 82
 83    // STEP 1
 84    QList< QPair<int, float> > tracks = lib->search( m_query );
 85
 86    if ( tracks.isEmpty() )
 87    {
 88        qDebug() << "No candidates found in first pass, aborting resolve" << m_query->queryTrack()->toString();
 89        emit results( m_query->id(), res );
 90        return;
 91    }
 92
 93    // STEP 2
 94    TomahawkSqlQuery files_query = lib->newquery();
 95
 96    QStringList trksl;
 97    for ( int k = 0; k < tracks.count(); k++ )
 98        trksl.append( QString::number( tracks.at( k ).first ) );
 99
100    QString trksToken = QString( "file_join.track IN (%1)" ).arg( trksl.join( "," ) );
101
102    QString sql = QString( "SELECT "
103                            "url, mtime, size, md5, mimetype, duration, bitrate, "  //0
104                            "file_join.artist, file_join.album, file_join.track, "  //7
105                            "file_join.composer, file_join.discnumber, "            //10
106                            "artist.name as artname, "                              //12
107                            "album.name as albname, "                               //13
108                            "track.name as trkname, "                               //14
109                            "composer.name as cmpname, "                            //15
110                            "file.source, "                                         //16
111                            "file_join.albumpos, "                                  //17
112                            "artist.id as artid, "                                  //18
113                            "album.id as albid, "                                   //19
114                            "composer.id as cmpid, "                                //20
115                            "albumArtist.id as albumartistid, "                     //21
116                            "albumArtist.name as albumartistname "                  //22
117                            "FROM file, file_join, artist, track "
118                            "LEFT JOIN album ON album.id = file_join.album "
119                            "LEFT JOIN artist AS composer ON composer.id = file_join.composer "
120                            "LEFT JOIN artist AS albumArtist ON albumArtist.id = album.artist "
121                            "WHERE "
122                            "artist.id = file_join.artist AND "
123                            "track.id = file_join.track AND "
124                            "file.id = file_join.file AND "
125                            "(%1)" )
126         .arg( trksToken );
127
128    files_query.prepare( sql );
129    files_query.exec();
130
131    while ( files_query.next() )
132    {
133        QString url = files_query.value( 0 ).toString();
134        source_ptr s = SourceList::instance()->get( files_query.value( 16 ).toUInt() );
135        if ( !s )
136        {
137            tDebug() << "Could not find source" << files_query.value( 16 ).toUInt();
138            continue;
139        }
140        if ( !s->isLocal() )
141            url = QString( "servent://%1\t%2" ).arg( s->nodeId() ).arg( url );
142
143        Tomahawk::result_ptr result = Tomahawk::Result::getCached( url );
144        if ( result )
145        {
146            tDebug( LOGVERBOSE ) << "Result already cached:" << result->toString();
147            res << result;
148            continue;
149        }
150
151        track_ptr track = Track::get( files_query.value( 9 ).toUInt(), files_query.value( 12 ).toString(), files_query.value( 14 ).toString(),
152                                      files_query.value( 13 ).toString(), files_query.value( 22 ).toString(), files_query.value( 5 ).toUInt(),
153                                      files_query.value( 15 ).toString(), files_query.value( 17 ).toUInt(), files_query.value( 11 ).toUInt() );
154        if ( !track )
155            continue;
156        track->loadAttributes();
157
158        result = Result::get( url, track );
159        if ( !result )
160            continue;
161
162        result->setModificationTime( files_query.value( 1 ).toUInt() );
163        result->setSize( files_query.value( 2 ).toUInt() );
164        result->setMimetype( files_query.value( 4 ).toString() );
165        result->setBitrate( files_query.value( 6 ).toUInt() );
166        result->setRID( uuid() );
167        result->setResolvedByCollection( s->dbCollection() );
168
169        res << result;
170    }
171
172    emit results( m_query->id(), res );
173}
174
175
176void
177DatabaseCommand_Resolve::fullTextResolve( DatabaseImpl* lib )
178{
179    QList<Tomahawk::result_ptr> res;
180    typedef QPair<int, float> scorepair_t;
181
182    // STEP 1
183    QList< QPair<int, float> > trackPairs = lib->search( m_query );
184    QList< QPair<int, float> > albumPairs = lib->searchAlbum( m_query, 20 );
185
186    TomahawkSqlQuery query = lib->newquery();
187    query.prepare( "SELECT album.name, artist.id, artist.name FROM album, artist WHERE artist.id = album.artist AND album.id = ?" );
188
189    foreach ( const scorepair_t& albumPair, albumPairs )
190    {
191        query.bindValue( 0, albumPair.first );
192        query.exec();
193
194        QList<Tomahawk::album_ptr> albumList;
195        while ( query.next() )
196        {
197            Tomahawk::artist_ptr artist = Tomahawk::Artist::get( query.value( 1 ).toUInt(), query.value( 2 ).toString() );
198            Tomahawk::album_ptr album = Tomahawk::Album::get( albumPair.first, query.value( 0 ).toString(), artist );
199            albumList << album;
200        }
201
202        emit albums( m_query->id(), albumList );
203    }
204
205    if ( trackPairs.isEmpty() )
206    {
207        qDebug() << "No candidates found in first pass, aborting resolve" << m_query->fullTextQuery();
208        emit results( m_query->id(), res );
209        return;
210    }
211
212    // STEP 2
213    TomahawkSqlQuery files_query = lib->newquery();
214
215    QStringList trksl;
216    for ( int k = 0; k < trackPairs.count(); k++ )
217        trksl.append( QString::number( trackPairs.at( k ).first ) );
218
219    QString trksToken = QString( "file_join.track IN (%1)" ).arg( trksl.join( "," ) );
220    QString sql = QString( "SELECT "
221                            "url, mtime, size, md5, mimetype, duration, bitrate, "  //0
222                            "file_join.artist, file_join.album, file_join.track, "  //7
223                            "file_join.composer, file_join.discnumber, "            //10
224                            "artist.name as artname, "                              //12
225                            "album.name as albname, "                               //13
226                            "track.name as trkname, "                               //14
227                            "composer.name as cmpname, "                            //15
228                            "file.source, "                                         //16
229                            "file_join.albumpos, "                                  //17
230                            "artist.id as artid, "                                  //18
231                            "album.id as albid, "                                   //19
232                            "composer.id as cmpid, "                                //20
233                            "albumArtist.id as albumartistid, "                     //21
234                            "albumArtist.name as albumartistname "                  //22
235                            "FROM file, file_join, artist, track "
236                            "LEFT JOIN album ON album.id = file_join.album "
237                            "LEFT JOIN artist AS composer ON composer.id = file_join.composer "
238                            "LEFT JOIN artist AS albumArtist ON albumArtist.id = album.artist "
239                            "WHERE "
240                            "artist.id = file_join.artist AND "
241                            "track.id = file_join.track AND "
242                            "file.id = file_join.file AND "
243                            "%1" )
244                        .arg( !trksl.isEmpty() ? trksToken : QString( "0" ) );
245
246    files_query.prepare( sql );
247    files_query.exec();
248
249    while ( files_query.next() )
250    {
251        QString url = files_query.value( 0 ).toString();
252        source_ptr s = SourceList::instance()->get( files_query.value( 16 ).toUInt() );
253        if ( !s )
254        {
255            tDebug() << "Could not find source" << files_query.value( 16 ).toUInt();
256            continue;
257        }
258        if ( !s->isLocal() )
259            url = QString( "servent://%1\t%2" ).arg( s->nodeId() ).arg( url );
260
261        Tomahawk::result_ptr result = Tomahawk::Result::getCached( url );
262        if ( result )
263        {
264            tDebug( LOGVERBOSE ) << "Result already cached:" << result->toString();
265            res << result;
266            continue;
267        }
268
269        track_ptr track = Track::get( files_query.value( 9 ).toUInt(), files_query.value( 12 ).toString(), files_query.value( 14 ).toString(),
270                                      files_query.value( 13 ).toString(), files_query.value( 22 ).toString(), files_query.value( 5 ).toUInt(),
271                                      files_query.value( 15 ).toString(), files_query.value( 17 ).toUInt(), files_query.value( 11 ).toUInt() );
272        track->loadAttributes();
273
274        result = Result::get( url, track );
275        result->setModificationTime( files_query.value( 1 ).toUInt() );
276        result->setSize( files_query.value( 2 ).toUInt() );
277        result->setMimetype( files_query.value( 4 ).toString() );
278        result->setBitrate( files_query.value( 6 ).toUInt() );
279        result->setRID( uuid() );
280        result->setResolvedByCollection( s->dbCollection() );
281
282        res << result;
283    }
284
285    emit results( m_query->id(), res );
286}