PageRenderTime 35ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/thirdparty/liblastfm2/src/fingerprint/Collection.cpp

http://github.com/tomahawk-player/tomahawk
C++ | 267 lines | 182 code | 55 blank | 30 comment | 12 complexity | e438e40cfb10ad4708afcf70c38e6092 MD5 | raw file
Possible License(s): LGPL-2.1, BSD-3-Clause, GPL-3.0, GPL-2.0
  1. /*
  2. Copyright 2009 Last.fm Ltd.
  3. - Primarily authored by Max Howell, Jono Cole and Doug Mansell
  4. This file is part of liblastfm.
  5. liblastfm 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. liblastfm is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with liblastfm. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. #include "Collection.h"
  17. #include "../core/misc.h"
  18. #include <QCoreApplication>
  19. #include <QFileInfo>
  20. #include <QMutexLocker>
  21. #include <QSqlQuery>
  22. #include <QSqlError>
  23. #include <QStringList>
  24. #include <QVariant>
  25. static const int k_collectionDbVersion = 1;
  26. // Singleton instance needs to be initialised
  27. Collection* Collection::s_instance = NULL;
  28. Collection::Collection()
  29. {
  30. m_db = QSqlDatabase::addDatabase( "QSQLITE", "collection" );
  31. m_db.setDatabaseName( lastfm::dir::runtimeData().filePath( "collection.db" ) );
  32. if (!m_db.open()) {
  33. qDebug() << m_db.lastError();
  34. return;
  35. }
  36. if (!m_db.isValid()) {
  37. qWarning() << "collection.db connection is not valid";
  38. return;
  39. }
  40. if (!m_db.tables().contains( "files" ))
  41. {
  42. qDebug() << "Creating Collection database";
  43. query( "CREATE TABLE artists ("
  44. "id INTEGER PRIMARY KEY AUTOINCREMENT,"
  45. "serverUid INTEGER,"
  46. "lcName TEXT NOT NULL,"
  47. "displayName TEXT NOT NULL );" );
  48. query( "CREATE TABLE albums ("
  49. "id INTEGER PRIMARY KEY AUTOINCREMENT,"
  50. "serverUid INTEGER,"
  51. "lcName TEXT NOT NULL,"
  52. "displayName TEXT NOT NULL,"
  53. "primaryArtist INTEGER NOT NULL );" );
  54. query( "CREATE UNIQUE INDEX album_names_idx ON albums ( primaryArtist, lcName );" );
  55. query( "CREATE TABLE tracks ("
  56. "id INTEGER PRIMARY KEY AUTOINCREMENT,"
  57. "lcName TEXT NOT NULL,"
  58. "displayName TEXT NOT NULL,"
  59. "primaryArtist INTEGER NOT NULL,"
  60. "primaryAlbum INTEGER );" );
  61. query( "CREATE UNIQUE INDEX track_names_idx ON tracks ( primaryArtist, lcName );" );
  62. query( "CREATE TABLE files ("
  63. "id INTEGER PRIMARY KEY AUTOINCREMENT,"
  64. "uri TEXT NOT NULL,"
  65. "track INTEGER NOT NULL,"
  66. "bitrate INTEGER,"
  67. "samplerate INTEGER,"
  68. "duration INTEGER,"
  69. "filesize INTEGER,"
  70. "source INTEGER,"
  71. "modificationDate INTEGER,"
  72. "lastPlayDate INTEGER,"
  73. "playCounter INTEGER,"
  74. "mbId VARCHAR( 36 ),"
  75. "fpId INTEGER );" );
  76. query( "CREATE UNIQUE INDEX files_uri_idx ON files ( uri );" );
  77. query( "CREATE INDEX files_track_idx ON files ( track );" );
  78. query( "CREATE INDEX files_fpId_idx ON files ( fpId );" );
  79. query( "CREATE INDEX files_source_idx ON files ( source );" );
  80. query( "CREATE TABLE sources ("
  81. "id INTEGER PRIMARY KEY AUTOINCREMENT,"
  82. "name TEXT UNIQUE,"
  83. "available INTEGER,"
  84. "host TEXT,"
  85. "cost INTEGER );" );
  86. query( "CREATE TABLE genres ("
  87. "id INTEGER PRIMARY KEY AUTOINCREMENT,"
  88. "name TEXT UNIQUE );" );
  89. query( "CREATE TABLE labels ("
  90. "id INTEGER PRIMARY KEY AUTOINCREMENT,"
  91. "serverUid INTEGER UNIQUE,"
  92. "name TEXT );" );
  93. }
  94. int const v = version();
  95. if ( v < k_collectionDbVersion )
  96. {
  97. qDebug() << "Upgrading Collection::db from" << v << "to" << k_collectionDbVersion;
  98. /**********************************************
  99. * README!!!!!!! *
  100. * Ensure you use v < x *
  101. * Ensure you do upgrades in ascending order! *
  102. **********************************************/
  103. if ( v < 1 )
  104. {
  105. // Norman discovered that he stored some fpId's wrong prior to 17th December 2007
  106. // So we have to wipe the fpIds for databases without the metadata table
  107. // we didn't store version information before that, which was a bad decision wasn't it?
  108. // this will trigger refingerprinting of every track
  109. query( "UPDATE files SET fpId = NULL;" );
  110. query( "CREATE TABLE metadata ("
  111. "key TEXT UNIQUE NOT NULL,"
  112. "value TEXT );" );
  113. query( "INSERT INTO metadata (key, value) VALUES ('version', '1');" );
  114. }
  115. // do last, update DB version number
  116. query( "UPDATE metadata set key='version', value='"
  117. + QString::number( k_collectionDbVersion ) + "';" );
  118. }
  119. }
  120. Collection& //static
  121. Collection::instance()
  122. {
  123. static QMutex mutex;
  124. QMutexLocker locker( &mutex );
  125. if ( !s_instance )
  126. {
  127. s_instance = new Collection;
  128. qAddPostRoutine(destroy);
  129. }
  130. return *s_instance;
  131. }
  132. void //static
  133. Collection::destroy()
  134. {
  135. delete s_instance;
  136. QSqlDatabase::removeDatabase( "collection" );
  137. }
  138. int
  139. Collection::version() const
  140. {
  141. QSqlQuery sql( m_db );
  142. sql.exec( "SELECT value FROM metadata WHERE key='version';" );
  143. if ( sql.next() )
  144. {
  145. return sql.value( 0 ).toInt();
  146. }
  147. return 0;
  148. }
  149. bool
  150. Collection::query( const QString& queryToken )
  151. {
  152. QSqlQuery query( m_db );
  153. query.exec( queryToken );
  154. if ( query.lastError().isValid() )
  155. {
  156. qDebug() << "SQL query failed:" << query.lastQuery() << endl
  157. << "SQL error was:" << query.lastError().databaseText() << endl
  158. << "SQL error type:" << query.lastError().type();
  159. return false;
  160. }
  161. return true;
  162. }
  163. QString
  164. Collection::fileURI( const QString& filePath )
  165. {
  166. QString prefix( "file:/" );
  167. #ifdef WIN32
  168. prefix = "file://";
  169. #endif
  170. return prefix + QFileInfo( filePath ).absoluteFilePath();
  171. }
  172. QString
  173. Collection::getFingerprintId( const QString& filePath )
  174. {
  175. QSqlQuery query( m_db );
  176. query.prepare( "SELECT fpId FROM files WHERE uri = :uri" );
  177. query.bindValue( ":uri", fileURI( filePath ) );
  178. query.exec();
  179. if ( query.lastError().isValid() )
  180. {
  181. qDebug() << "SQL query failed:" << query.lastQuery() << endl
  182. << "SQL error was:" << query.lastError().databaseText() << endl
  183. << "SQL error type:" << query.lastError().type();
  184. }
  185. else if (query.next())
  186. return query.value( 0 ).toString();
  187. return "";
  188. }
  189. bool
  190. Collection::setFingerprintId( const QString& filePath, QString fpId )
  191. {
  192. bool isNumeric;
  193. int intFpId = fpId.toInt( &isNumeric );
  194. Q_ASSERT( isNumeric );
  195. QSqlQuery query( m_db );
  196. query.prepare( "REPLACE INTO files ( uri, track, fpId ) VALUES ( :uri, 0, :fpId )" );
  197. query.bindValue( ":uri", fileURI( filePath ) );
  198. query.bindValue( ":fpId", intFpId );
  199. query.exec();
  200. if ( query.lastError().isValid() )
  201. {
  202. qDebug() << "SQL query failed:" << query.lastQuery() << endl
  203. << "SQL error was:" << query.lastError().databaseText() << endl
  204. << "SQL error type:" << query.lastError().type();
  205. return false;
  206. }
  207. return true;
  208. }