/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. #include "DatabaseCommand_Resolve.h"
  19. #include "utils/Logger.h"
  20. #include "Album.h"
  21. #include "Artist.h"
  22. #include "Pipeline.h"
  23. #include "PlaylistEntry.h"
  24. #include "SourceList.h"
  25. #include "Track.h"
  26. using namespace Tomahawk;
  27. DatabaseCommand_Resolve::DatabaseCommand_Resolve( const query_ptr& query )
  28. : DatabaseCommand()
  29. , m_query( query )
  30. {
  31. // FIXME: We need to run tests of this DbCmd without a Pipeline
  32. // Q_ASSERT( Pipeline::instance()->isRunning() );
  33. }
  34. DatabaseCommand_Resolve::~DatabaseCommand_Resolve()
  35. {
  36. }
  37. void
  38. DatabaseCommand_Resolve::exec( DatabaseImpl* lib )
  39. {
  40. /*
  41. * Resolving is a 2 stage process.
  42. * 1) find list of trk/art/alb IDs that are reasonable matches to the metadata given
  43. * 2) find files in database by permitted sources and calculate score, ignoring
  44. * results that are less than MINSCORE
  45. */
  46. if ( !m_query->resultHint().isEmpty() )
  47. {
  48. tDebug() << "Using result-hint to speed up resolving:" << m_query->resultHint();
  49. Tomahawk::result_ptr result = lib->resultFromHint( m_query );
  50. if ( result && ( !result->resolvedByCollection() || result->resolvedByCollection()->isOnline() ) )
  51. {
  52. QList<Tomahawk::result_ptr> res;
  53. res << result;
  54. emit results( m_query->id(), res );
  55. return;
  56. }
  57. }
  58. if ( m_query->isFullTextQuery() )
  59. fullTextResolve( lib );
  60. else
  61. resolve( lib );
  62. }
  63. void
  64. DatabaseCommand_Resolve::resolve( DatabaseImpl* lib )
  65. {
  66. QList<Tomahawk::result_ptr> res;
  67. // STEP 1
  68. QList< QPair<int, float> > tracks = lib->search( m_query );
  69. if ( tracks.isEmpty() )
  70. {
  71. qDebug() << "No candidates found in first pass, aborting resolve" << m_query->queryTrack()->toString();
  72. emit results( m_query->id(), res );
  73. return;
  74. }
  75. // STEP 2
  76. TomahawkSqlQuery files_query = lib->newquery();
  77. QStringList trksl;
  78. for ( int k = 0; k < tracks.count(); k++ )
  79. trksl.append( QString::number( tracks.at( k ).first ) );
  80. QString trksToken = QString( "file_join.track IN (%1)" ).arg( trksl.join( "," ) );
  81. QString sql = QString( "SELECT "
  82. "url, mtime, size, md5, mimetype, duration, bitrate, " //0
  83. "file_join.artist, file_join.album, file_join.track, " //7
  84. "file_join.composer, file_join.discnumber, " //10
  85. "artist.name as artname, " //12
  86. "album.name as albname, " //13
  87. "track.name as trkname, " //14
  88. "composer.name as cmpname, " //15
  89. "file.source, " //16
  90. "file_join.albumpos, " //17
  91. "artist.id as artid, " //18
  92. "album.id as albid, " //19
  93. "composer.id as cmpid, " //20
  94. "albumArtist.id as albumartistid, " //21
  95. "albumArtist.name as albumartistname " //22
  96. "FROM file, file_join, artist, track "
  97. "LEFT JOIN album ON album.id = file_join.album "
  98. "LEFT JOIN artist AS composer ON composer.id = file_join.composer "
  99. "LEFT JOIN artist AS albumArtist ON albumArtist.id = album.artist "
  100. "WHERE "
  101. "artist.id = file_join.artist AND "
  102. "track.id = file_join.track AND "
  103. "file.id = file_join.file AND "
  104. "(%1)" )
  105. .arg( trksToken );
  106. files_query.prepare( sql );
  107. files_query.exec();
  108. while ( files_query.next() )
  109. {
  110. QString url = files_query.value( 0 ).toString();
  111. source_ptr s = SourceList::instance()->get( files_query.value( 16 ).toUInt() );
  112. if ( !s )
  113. {
  114. tDebug() << "Could not find source" << files_query.value( 16 ).toUInt();
  115. continue;
  116. }
  117. if ( !s->isLocal() )
  118. url = QString( "servent://%1\t%2" ).arg( s->nodeId() ).arg( url );
  119. Tomahawk::result_ptr result = Tomahawk::Result::getCached( url );
  120. if ( result )
  121. {
  122. tDebug( LOGVERBOSE ) << "Result already cached:" << result->toString();
  123. res << result;
  124. continue;
  125. }
  126. track_ptr track = Track::get( files_query.value( 9 ).toUInt(), files_query.value( 12 ).toString(), files_query.value( 14 ).toString(),
  127. files_query.value( 13 ).toString(), files_query.value( 22 ).toString(), files_query.value( 5 ).toUInt(),
  128. files_query.value( 15 ).toString(), files_query.value( 17 ).toUInt(), files_query.value( 11 ).toUInt() );
  129. if ( !track )
  130. continue;
  131. track->loadAttributes();
  132. result = Result::get( url, track );
  133. if ( !result )
  134. continue;
  135. result->setModificationTime( files_query.value( 1 ).toUInt() );
  136. result->setSize( files_query.value( 2 ).toUInt() );
  137. result->setMimetype( files_query.value( 4 ).toString() );
  138. result->setBitrate( files_query.value( 6 ).toUInt() );
  139. result->setRID( uuid() );
  140. result->setResolvedByCollection( s->dbCollection() );
  141. res << result;
  142. }
  143. emit results( m_query->id(), res );
  144. }
  145. void
  146. DatabaseCommand_Resolve::fullTextResolve( DatabaseImpl* lib )
  147. {
  148. QList<Tomahawk::result_ptr> res;
  149. typedef QPair<int, float> scorepair_t;
  150. // STEP 1
  151. QList< QPair<int, float> > trackPairs = lib->search( m_query );
  152. QList< QPair<int, float> > albumPairs = lib->searchAlbum( m_query, 20 );
  153. TomahawkSqlQuery query = lib->newquery();
  154. query.prepare( "SELECT album.name, artist.id, artist.name FROM album, artist WHERE artist.id = album.artist AND album.id = ?" );
  155. foreach ( const scorepair_t& albumPair, albumPairs )
  156. {
  157. query.bindValue( 0, albumPair.first );
  158. query.exec();
  159. QList<Tomahawk::album_ptr> albumList;
  160. while ( query.next() )
  161. {
  162. Tomahawk::artist_ptr artist = Tomahawk::Artist::get( query.value( 1 ).toUInt(), query.value( 2 ).toString() );
  163. Tomahawk::album_ptr album = Tomahawk::Album::get( albumPair.first, query.value( 0 ).toString(), artist );
  164. albumList << album;
  165. }
  166. emit albums( m_query->id(), albumList );
  167. }
  168. if ( trackPairs.isEmpty() )
  169. {
  170. qDebug() << "No candidates found in first pass, aborting resolve" << m_query->fullTextQuery();
  171. emit results( m_query->id(), res );
  172. return;
  173. }
  174. // STEP 2
  175. TomahawkSqlQuery files_query = lib->newquery();
  176. QStringList trksl;
  177. for ( int k = 0; k < trackPairs.count(); k++ )
  178. trksl.append( QString::number( trackPairs.at( k ).first ) );
  179. QString trksToken = QString( "file_join.track IN (%1)" ).arg( trksl.join( "," ) );
  180. QString sql = QString( "SELECT "
  181. "url, mtime, size, md5, mimetype, duration, bitrate, " //0
  182. "file_join.artist, file_join.album, file_join.track, " //7
  183. "file_join.composer, file_join.discnumber, " //10
  184. "artist.name as artname, " //12
  185. "album.name as albname, " //13
  186. "track.name as trkname, " //14
  187. "composer.name as cmpname, " //15
  188. "file.source, " //16
  189. "file_join.albumpos, " //17
  190. "artist.id as artid, " //18
  191. "album.id as albid, " //19
  192. "composer.id as cmpid, " //20
  193. "albumArtist.id as albumartistid, " //21
  194. "albumArtist.name as albumartistname " //22
  195. "FROM file, file_join, artist, track "
  196. "LEFT JOIN album ON album.id = file_join.album "
  197. "LEFT JOIN artist AS composer ON composer.id = file_join.composer "
  198. "LEFT JOIN artist AS albumArtist ON albumArtist.id = album.artist "
  199. "WHERE "
  200. "artist.id = file_join.artist AND "
  201. "track.id = file_join.track AND "
  202. "file.id = file_join.file AND "
  203. "%1" )
  204. .arg( !trksl.isEmpty() ? trksToken : QString( "0" ) );
  205. files_query.prepare( sql );
  206. files_query.exec();
  207. while ( files_query.next() )
  208. {
  209. QString url = files_query.value( 0 ).toString();
  210. source_ptr s = SourceList::instance()->get( files_query.value( 16 ).toUInt() );
  211. if ( !s )
  212. {
  213. tDebug() << "Could not find source" << files_query.value( 16 ).toUInt();
  214. continue;
  215. }
  216. if ( !s->isLocal() )
  217. url = QString( "servent://%1\t%2" ).arg( s->nodeId() ).arg( url );
  218. Tomahawk::result_ptr result = Tomahawk::Result::getCached( url );
  219. if ( result )
  220. {
  221. tDebug( LOGVERBOSE ) << "Result already cached:" << result->toString();
  222. res << result;
  223. continue;
  224. }
  225. track_ptr track = Track::get( files_query.value( 9 ).toUInt(), files_query.value( 12 ).toString(), files_query.value( 14 ).toString(),
  226. files_query.value( 13 ).toString(), files_query.value( 22 ).toString(), files_query.value( 5 ).toUInt(),
  227. files_query.value( 15 ).toString(), files_query.value( 17 ).toUInt(), files_query.value( 11 ).toUInt() );
  228. track->loadAttributes();
  229. result = Result::get( url, track );
  230. result->setModificationTime( files_query.value( 1 ).toUInt() );
  231. result->setSize( files_query.value( 2 ).toUInt() );
  232. result->setMimetype( files_query.value( 4 ).toString() );
  233. result->setBitrate( files_query.value( 6 ).toUInt() );
  234. result->setRID( uuid() );
  235. result->setResolvedByCollection( s->dbCollection() );
  236. res << result;
  237. }
  238. emit results( m_query->id(), res );
  239. }