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