From 42e4c4a8dbf6b21c9a2c0a96f38cdff07134bdca Mon Sep 17 00:00:00 2001 From: David Sansome Date: Sun, 17 Oct 2010 17:50:20 +0000 Subject: [PATCH] Add a skipcount field to the database, and read the last played time into Song objects. (still not used in the GUI yet). --- data/data.qrc | 1 + data/schema/device-schema.sql | 4 +++- data/schema/schema-18.sql | 4 ++++ src/core/database.cpp | 32 ++++++++++++++++++++++++++++---- src/core/database.h | 2 ++ src/core/song.cpp | 16 +++++++++++++--- src/core/song.h | 6 ++++++ 7 files changed, 57 insertions(+), 8 deletions(-) create mode 100644 data/schema/schema-18.sql diff --git a/data/data.qrc b/data/data.qrc index caffdb6fd..41f47825e 100644 --- a/data/data.qrc +++ b/data/data.qrc @@ -278,5 +278,6 @@ icons/22x22/rating.png icons/32x32/rating.png icons/48x48/rating.png + schema/schema-18.sql diff --git a/data/schema/device-schema.sql b/data/schema/device-schema.sql index e368a4c93..7e5f11f93 100644 --- a/data/schema/device-schema.sql +++ b/data/schema/device-schema.sql @@ -45,7 +45,9 @@ CREATE TABLE device_%deviceid_songs ( rating INTEGER, forced_compilation_on INTEGER NOT NULL DEFAULT 0, forced_compilation_off INTEGER NOT NULL DEFAULT 0, - effective_compilation NOT NULL DEFAULT 0 + effective_compilation NOT NULL DEFAULT 0, + + skipcount INTEGER NOT NULL DEFAULT 0 ); CREATE INDEX idx_device_%deviceid_songs_album ON device_%deviceid_songs (album); diff --git a/data/schema/schema-18.sql b/data/schema/schema-18.sql new file mode 100644 index 000000000..b3a2d6683 --- /dev/null +++ b/data/schema/schema-18.sql @@ -0,0 +1,4 @@ +ALTER TABLE %allsongstables ADD COLUMN skipcount INTEGER NOT NULL DEFAULT 0; + +UPDATE schema_version SET version=18; + diff --git a/src/core/database.cpp b/src/core/database.cpp index 3d80929b6..b7e52aa2d 100644 --- a/src/core/database.cpp +++ b/src/core/database.cpp @@ -29,7 +29,8 @@ #include const char* Database::kDatabaseFilename = "clementine.db"; -const int Database::kSchemaVersion = 17; +const int Database::kSchemaVersion = 18; +const char* Database::kMagicAllSongsTables = "%allsongstables"; int Database::sNextConnectionId = 1; QMutex Database::sNextConnectionIdMutex; @@ -447,12 +448,35 @@ void Database::ExecCommands(const QString &schema, QSqlDatabase &db) { // Run each command QStringList commands(schema.split(";\n\n")); foreach (const QString& command, commands) { - QSqlQuery query(db.exec(command)); - if (CheckErrors(query.lastError())) - qFatal("Unable to update music library database"); + // There are now lots of "songs" tables that need to have the same schema: + // songs, magnatune_songs, and device_*_songs. We allow a magic value + // in the schema files to update all songs tables at once. + if (command.contains(kMagicAllSongsTables)) { + foreach (const QString& table, SongsTables(db)) { + qDebug() << "Updating" << table << "for" << kMagicAllSongsTables; + QString new_command(command); + new_command.replace(kMagicAllSongsTables, table); + QSqlQuery query(db.exec(new_command)); + if (CheckErrors(query.lastError())) + qFatal("Unable to update music library database"); + } + } else { + QSqlQuery query(db.exec(command)); + if (CheckErrors(query.lastError())) + qFatal("Unable to update music library database"); + } } } +QStringList Database::SongsTables(QSqlDatabase& db) const { + QStringList ret; + foreach (const QString& table, db.tables()) { + if (table == "songs" || table.endsWith("_songs")) + ret << table; + } + return ret; +} + bool Database::CheckErrors(const QSqlError& error) { if (error.isValid()) { qDebug() << error; diff --git a/src/core/database.h b/src/core/database.h index 39aadf1d6..0f73552f5 100644 --- a/src/core/database.h +++ b/src/core/database.h @@ -43,6 +43,7 @@ class Database : public QObject { static const int kSchemaVersion; static const char* kDatabaseFilename; + static const char* kMagicAllSongsTables; void Stop() {} @@ -58,6 +59,7 @@ class Database : public QObject { private: void UpdateDatabaseSchema(int version, QSqlDatabase& db); + QStringList SongsTables(QSqlDatabase& db) const; QString directory_; QMutex connect_mutex_; diff --git a/src/core/song.cpp b/src/core/song.cpp index 2a9610e36..4af39cf35 100644 --- a/src/core/song.cpp +++ b/src/core/song.cpp @@ -89,7 +89,7 @@ const QStringList Song::kColumns = QStringList() << "mtime" << "ctime" << "filesize" << "sampler" << "art_automatic" << "art_manual" << "filetype" << "playcount" << "lastplayed" << "rating" << "forced_compilation_on" << "forced_compilation_off" - << "effective_compilation"; + << "effective_compilation" << "skipcount"; const QString Song::kColumnSpec = Song::kColumns.join(", "); const QString Song::kBindSpec = Prepend(":", Song::kColumns).join(", "); @@ -151,6 +151,8 @@ Song::Private::Private() forced_compilation_off_(false), rating_(-1.0), playcount_(0), + skipcount_(0), + lastplayed_(-1), length_(-1), bitrate_(-1), samplerate_(-1), @@ -459,7 +461,7 @@ void Song::InitFromQuery(const SqlRow& q, int col) { d->filetype_ = FileType(q.value(col + 24).toInt()); d->playcount_ = q.value(col + 25).isNull() ? 0 : q.value(col + 25).toInt(); - // lastplayed = 26 + d->lastplayed_ = toint(col + 26); d->rating_ = tofloat(col + 27); d->forced_compilation_on_ = q.value(col + 28).toBool(); @@ -467,6 +469,8 @@ void Song::InitFromQuery(const SqlRow& q, int col) { // effective_compilation = 30 + d->skipcount_ = q.value(col + 31).isNull() ? 0 : q.value(col + 31).toInt(); + #undef tostr #undef toint #undef tofloat @@ -508,6 +512,8 @@ void Song::InitFromLastFM(const lastfm::Track& track) { d->filetype_ = track->type2 ? Type_Mpeg : Type_Mp4; d->rating_ = float(track->rating) / 100; // 100 = 20 * 5 stars d->playcount_ = track->playcount; + d->skipcount_ = track->skipcount; + d->lastplayed_ = track->time_played; d->filename_ = QString::fromLocal8Bit(track->ipod_path); d->filename_.replace(':', '/'); @@ -538,6 +544,8 @@ void Song::InitFromLastFM(const lastfm::Track& track) { track->mediatype = 1; // Audio track->rating = d->rating_ * 100; // 100 = 20 * 5 stars track->playcount = d->playcount_; + track->skipcount = d->skipcount_; + track->time_played = d->lastplayed_; } #endif @@ -905,7 +913,7 @@ void Song::BindToQuery(QSqlQuery *query) const { query->bindValue(":filetype", d->filetype_); query->bindValue(":playcount", d->playcount_); - query->bindValue(":lastplayed", -1); // TODO + query->bindValue(":lastplayed", intval(d->lastplayed_)); query->bindValue(":rating", intval(d->rating_)); query->bindValue(":forced_compilation_on", d->forced_compilation_on_ ? 1 : 0); @@ -913,6 +921,8 @@ void Song::BindToQuery(QSqlQuery *query) const { query->bindValue(":effective_compilation", is_compilation() ? 1 : 0); + query->bindValue(":skipcount", d->skipcount_); + #undef intval #undef notnullintval } diff --git a/src/core/song.h b/src/core/song.h index 159d42906..79c2e8f1a 100644 --- a/src/core/song.h +++ b/src/core/song.h @@ -159,6 +159,8 @@ class Song { } float rating() const { return d->rating_; } int playcount() const { return d->playcount_; } + int skipcount() const { return d->skipcount_; } + int lastplayed() const { return d->lastplayed_; } int length() const { return d->length_; } int bitrate() const { return d->bitrate_; } @@ -217,6 +219,8 @@ class Song { void set_forced_compilation_off(bool v) { d->forced_compilation_off_ = v; } void set_rating(float v) { d->rating_ = v; } void set_playcount(int v) { d->playcount_ = v; } + void set_skipcount(int v) { d->skipcount_ = v; } + void set_lastplayed(int v) { d->lastplayed_ = v; } // Setters that should only be used by tests void set_filename(const QString& v) { d->filename_ = v; } @@ -260,6 +264,8 @@ class Song { float rating_; int playcount_; + int skipcount_; + int lastplayed_; int length_; int bitrate_;