diff --git a/data/data.qrc b/data/data.qrc
index f447b5c36..94180a664 100644
--- a/data/data.qrc
+++ b/data/data.qrc
@@ -5,6 +5,7 @@
schema/schema-2.sql
schema/schema-3.sql
schema/schema-4.sql
+ schema/schema-5.sql
schema/device-schema.sql
style/strawberry.css
html/playing-tooltip-plain.html
diff --git a/data/schema/device-schema.sql b/data/schema/device-schema.sql
index 09594d074..855597329 100644
--- a/data/schema/device-schema.sql
+++ b/data/schema/device-schema.sql
@@ -27,6 +27,10 @@ CREATE TABLE device_%deviceid_songs (
comment TEXT NOT NULL,
lyrics TEXT NOT NULL,
+ artist_id INTEGER NOT NULL DEFAULT -1;
+ album_id INTEGER NOT NULL DEFAULT -1;
+ song_id INTEGER NOT NULL DEFAULT -1;
+
beginning INTEGER NOT NULL DEFAULT 0,
length INTEGER NOT NULL DEFAULT 0,
@@ -38,9 +42,9 @@ CREATE TABLE device_%deviceid_songs (
directory_id INTEGER NOT NULL,
filename TEXT NOT NULL,
filetype INTEGER NOT NULL DEFAULT 0,
- filesize INTEGER NOT NULL,
- mtime INTEGER NOT NULL,
- ctime INTEGER NOT NULL,
+ filesize INTEGER NOT NULL DEFAULT 0,
+ mtime INTEGER NOT NULL DEFAULT 0,
+ ctime INTEGER NOT NULL DEFAULT 0,
unavailable INTEGER DEFAULT 0,
playcount INTEGER NOT NULL DEFAULT 0,
diff --git a/data/schema/schema-5.sql b/data/schema/schema-5.sql
new file mode 100644
index 000000000..4575a1c65
--- /dev/null
+++ b/data/schema/schema-5.sql
@@ -0,0 +1,31 @@
+ALTER TABLE songs ADD COLUMN artist_id INTEGER NOT NULL DEFAULT -1;
+
+ALTER TABLE songs ADD COLUMN album_id INTEGER NOT NULL DEFAULT -1;
+
+ALTER TABLE songs ADD COLUMN song_id INTEGER NOT NULL DEFAULT -1;
+
+ALTER TABLE tidal_artists_songs ADD COLUMN artist_id INTEGER NOT NULL DEFAULT -1;
+
+ALTER TABLE tidal_artists_songs ADD COLUMN album_id INTEGER NOT NULL DEFAULT -1;
+
+ALTER TABLE tidal_artists_songs ADD COLUMN song_id INTEGER NOT NULL DEFAULT -1;
+
+ALTER TABLE tidal_albums_songs ADD COLUMN artist_id INTEGER NOT NULL DEFAULT -1;
+
+ALTER TABLE tidal_albums_songs ADD COLUMN album_id INTEGER NOT NULL DEFAULT -1;
+
+ALTER TABLE tidal_albums_songs ADD COLUMN song_id INTEGER NOT NULL DEFAULT -1;
+
+ALTER TABLE tidal_songs ADD COLUMN artist_id INTEGER NOT NULL DEFAULT -1;
+
+ALTER TABLE tidal_songs ADD COLUMN album_id INTEGER NOT NULL DEFAULT -1;
+
+ALTER TABLE tidal_songs ADD COLUMN song_id INTEGER NOT NULL DEFAULT -1;
+
+ALTER TABLE playlist_items ADD COLUMN artist_id INTEGER NOT NULL DEFAULT -1;
+
+ALTER TABLE playlist_items ADD COLUMN album_id INTEGER NOT NULL DEFAULT -1;
+
+ALTER TABLE playlist_items ADD COLUMN song_id INTEGER NOT NULL DEFAULT -1;
+
+UPDATE schema_version SET version=5;
diff --git a/data/schema/schema.sql b/data/schema/schema.sql
index d2a2db337..29a5e172e 100644
--- a/data/schema/schema.sql
+++ b/data/schema/schema.sql
@@ -4,7 +4,7 @@ CREATE TABLE IF NOT EXISTS schema_version (
DELETE FROM schema_version;
-INSERT INTO schema_version (version) VALUES (4);
+INSERT INTO schema_version (version) VALUES (5);
CREATE TABLE IF NOT EXISTS directories (
path TEXT NOT NULL,
@@ -35,6 +35,10 @@ CREATE TABLE IF NOT EXISTS songs (
comment TEXT NOT NULL,
lyrics TEXT NOT NULL,
+ artist_id INTEGER NOT NULL DEFAULT -1;
+ album_id INTEGER NOT NULL DEFAULT -1;
+ song_id INTEGER NOT NULL DEFAULT -1;
+
beginning INTEGER NOT NULL DEFAULT 0,
length INTEGER NOT NULL DEFAULT 0,
@@ -88,6 +92,10 @@ CREATE TABLE IF NOT EXISTS tidal_artists_songs (
comment TEXT NOT NULL,
lyrics TEXT NOT NULL,
+ artist_id INTEGER NOT NULL DEFAULT -1;
+ album_id INTEGER NOT NULL DEFAULT -1;
+ song_id INTEGER NOT NULL DEFAULT -1;
+
beginning INTEGER NOT NULL DEFAULT 0,
length INTEGER NOT NULL DEFAULT 0,
@@ -141,6 +149,10 @@ CREATE TABLE IF NOT EXISTS tidal_albums_songs (
comment TEXT NOT NULL,
lyrics TEXT NOT NULL,
+ artist_id INTEGER NOT NULL DEFAULT -1;
+ album_id INTEGER NOT NULL DEFAULT -1;
+ song_id INTEGER NOT NULL DEFAULT -1;
+
beginning INTEGER NOT NULL DEFAULT 0,
length INTEGER NOT NULL DEFAULT 0,
@@ -194,6 +206,10 @@ CREATE TABLE IF NOT EXISTS tidal_songs (
comment TEXT NOT NULL,
lyrics TEXT NOT NULL,
+ artist_id INTEGER NOT NULL DEFAULT -1;
+ album_id INTEGER NOT NULL DEFAULT -1;
+ song_id INTEGER NOT NULL DEFAULT -1;
+
beginning INTEGER NOT NULL DEFAULT 0,
length INTEGER NOT NULL DEFAULT 0,
@@ -263,6 +279,10 @@ CREATE TABLE IF NOT EXISTS playlist_items (
comment TEXT NOT NULL,
lyrics TEXT NOT NULL,
+ artist_id INTEGER NOT NULL DEFAULT -1;
+ album_id INTEGER NOT NULL DEFAULT -1;
+ song_id INTEGER NOT NULL DEFAULT -1;
+
beginning INTEGER NOT NULL DEFAULT 0,
length INTEGER NOT NULL DEFAULT 0,
diff --git a/src/core/database.cpp b/src/core/database.cpp
index 2981fb4f6..3c2c8dd23 100644
--- a/src/core/database.cpp
+++ b/src/core/database.cpp
@@ -52,7 +52,7 @@
#include "scopedtransaction.h"
const char *Database::kDatabaseFilename = "strawberry.db";
-const int Database::kSchemaVersion = 4;
+const int Database::kSchemaVersion = 5;
const char *Database::kMagicAllSongsTables = "%allsongstables";
int Database::sNextConnectionId = 1;
diff --git a/src/core/song.cpp b/src/core/song.cpp
index 1aa8f31d9..eacdd026e 100644
--- a/src/core/song.cpp
+++ b/src/core/song.cpp
@@ -89,6 +89,10 @@ const QStringList Song::kColumns = QStringList() << "title"
<< "comment"
<< "lyrics"
+ << "artist_id"
+ << "album_id"
+ << "song_id"
+
<< "beginning"
<< "length"
@@ -155,7 +159,6 @@ struct Song::Private : public QSharedData {
bool valid_;
int id_;
- int album_id_; // A unique album ID
QString title_;
QString album_;
@@ -173,6 +176,10 @@ struct Song::Private : public QSharedData {
QString comment_;
QString lyrics_;
+ int artist_id_;
+ int album_id_;
+ int song_id_;
+
qint64 beginning_;
qint64 end_;
@@ -215,15 +222,20 @@ struct Song::Private : public QSharedData {
Song::Private::Private(Song::Source source)
: valid_(false),
id_(-1),
- album_id_(-1),
+
track_(-1),
disc_(-1),
year_(-1),
originalyear_(-1),
compilation_(false),
+ artist_id_(-1),
+ album_id_(-1),
+ song_id_(-1),
+
beginning_(0),
end_(-1),
+
bitrate_(-1),
samplerate_(-1),
bitdepth_(-1),
@@ -261,60 +273,53 @@ Song &Song::operator=(const Song &other) {
bool Song::is_valid() const { return d->valid_; }
bool Song::is_unavailable() const { return d->unavailable_; }
int Song::id() const { return d->id_; }
+
+int Song::artist_id() const { return d->artist_id_; }
+int Song::album_id() const { return d->album_id_; }
+int Song::song_id() const { return d->song_id_; }
+
const QString &Song::title() const { return d->title_; }
const QString &Song::album() const { return d->album_; }
-const QString &Song::effective_album() const {
- // This value is useful for singles, which are one-track albums on their own.
- return d->album_.isEmpty() ? d->title_ : d->album_;
-}
+// This value is useful for singles, which are one-track albums on their own.
+const QString &Song::effective_album() const { return d->album_.isEmpty() ? d->title_ : d->album_; }
const QString &Song::artist() const { return d->artist_; }
const QString &Song::albumartist() const { return d->albumartist_; }
const QString &Song::effective_albumartist() const { return d->albumartist_.isEmpty() ? d->artist_ : d->albumartist_; }
const QString &Song::playlist_albumartist() const { return is_compilation() ? d->albumartist_ : effective_albumartist(); }
-const QString &Song::composer() const { return d->composer_; }
-const QString &Song::performer() const { return d->performer_; }
-const QString &Song::grouping() const { return d->grouping_; }
int Song::track() const { return d->track_; }
int Song::disc() const { return d->disc_; }
int Song::year() const { return d->year_; }
int Song::originalyear() const { return d->originalyear_; }
-int Song::effective_originalyear() const {
- return d->originalyear_ < 0 ? d->year_ : d->originalyear_;
-}
+int Song::effective_originalyear() const { return d->originalyear_ < 0 ? d->year_ : d->originalyear_; }
const QString &Song::genre() const { return d->genre_; }
+bool Song::is_compilation() const { return (d->compilation_ || d->compilation_detected_ || d->compilation_on_) && ! d->compilation_off_; }
+const QString &Song::composer() const { return d->composer_; }
+const QString &Song::performer() const { return d->performer_; }
+const QString &Song::grouping() const { return d->grouping_; }
const QString &Song::comment() const { return d->comment_; }
const QString &Song::lyrics() const { return d->lyrics_; }
-bool Song::is_compilation() const {
- return (d->compilation_ || d->compilation_detected_ || d->compilation_on_) && ! d->compilation_off_;
-}
-int Song::playcount() const { return d->playcount_; }
-int Song::skipcount() const { return d->skipcount_; }
-int Song::lastplayed() const { return d->lastplayed_; }
-const QString &Song::cue_path() const { return d->cue_path_; }
-bool Song::has_cue() const { return !d->cue_path_.isEmpty(); }
-int Song::album_id() const { return d->album_id_; }
+
qint64 Song::beginning_nanosec() const { return d->beginning_; }
qint64 Song::end_nanosec() const { return d->end_; }
qint64 Song::length_nanosec() const { return d->end_ - d->beginning_; }
+
int Song::bitrate() const { return d->bitrate_; }
int Song::samplerate() const { return d->samplerate_; }
int Song::bitdepth() const { return d->bitdepth_; }
+
Song::Source Song::source() const { return d->source_; }
int Song::directory_id() const { return d->directory_id_; }
const QUrl &Song::url() const { return d->url_; }
const QString &Song::basefilename() const { return d->basefilename_; }
+Song::FileType Song::filetype() const { return d->filetype_; }
+int Song::filesize() const { return d->filesize_; }
uint Song::mtime() const { return d->mtime_; }
uint Song::ctime() const { return d->ctime_; }
-int Song::filesize() const { return d->filesize_; }
-Song::FileType Song::filetype() const { return d->filetype_; }
-bool Song::is_stream() const { return d->source_ == Source_Stream || d->source_ == Source_Tidal; }
-bool Song::is_cdda() const { return d->source_ == Source_CDDA; }
-bool Song::is_collection_song() const {
- return !is_cdda() && !is_stream() && id() != -1;
-}
-bool Song::is_metadata_good() const {
- return !d->title_.isEmpty() && !d->album_.isEmpty() && !d->artist_.isEmpty() && !d->url_.isEmpty() && d->end_ > 0;
-}
+
+int Song::playcount() const { return d->playcount_; }
+int Song::skipcount() const { return d->skipcount_; }
+int Song::lastplayed() const { return d->lastplayed_; }
+
const QString &Song::art_automatic() const { return d->art_automatic_; }
const QString &Song::art_manual() const { return d->art_manual_; }
bool Song::has_manually_unset_cover() const { return d->art_manual_ == kManuallyUnsetCover; }
@@ -322,12 +327,24 @@ void Song::manually_unset_cover() { d->art_manual_ = kManuallyUnsetCover; }
bool Song::has_embedded_cover() const { return d->art_automatic_ == kEmbeddedCover; }
void Song::set_embedded_cover() { d->art_automatic_ = kEmbeddedCover; }
const QImage &Song::image() const { return d->image_; }
+
+const QString &Song::cue_path() const { return d->cue_path_; }
+bool Song::has_cue() const { return !d->cue_path_.isEmpty(); }
+
+bool Song::is_collection_song() const { return !is_cdda() && !is_stream() && id() != -1; }
+bool Song::is_metadata_good() const { return !d->title_.isEmpty() && !d->album_.isEmpty() && !d->artist_.isEmpty() && !d->url_.isEmpty() && d->end_ > 0; }
+bool Song::is_stream() const { return d->source_ == Source_Stream || d->source_ == Source_Tidal; }
+bool Song::is_cdda() const { return d->source_ == Source_CDDA; }
+
const QString &Song::error() const { return d->error_; }
void Song::set_id(int id) { d->id_ = id; }
-void Song::set_album_id(int v) { d->album_id_ = v; }
void Song::set_valid(bool v) { d->valid_ = v; }
+void Song::set_artist_id(int v) { d->artist_id_ = v; }
+void Song::set_album_id(int v) { d->album_id_ = v; }
+void Song::set_song_id(int v) { d->song_id_ = v; }
+
void Song::set_title(const QString &v) { d->title_ = v; }
void Song::set_album(const QString &v) { d->album_ = v; }
void Song::set_artist(const QString &v) { d->artist_ = v; }
@@ -674,6 +691,7 @@ void Song::ToProtobuf(pb::tagreader::SongMetadata *pb) const {
pb->set_suspicious_tags(d->suspicious_tags_);
pb->set_art_automatic(DataCommaSizeFromQString(d->art_automatic_));
pb->set_filetype(static_cast(d->filetype_));
+
}
#define tostr(n) (q.value(n).isNull() ? QString::null : q.value(n).toString())
@@ -744,6 +762,16 @@ void Song::InitFromQuery(const SqlRow &q, bool reliable_metadata, int col) {
d->comment_ = tostr(x);
}
+ else if (Song::kColumns.value(i) == "artist_id") {
+ d->artist_id_ = toint(x);
+ }
+ else if (Song::kColumns.value(i) == "album_id") {
+ d->album_id_ = toint(x);
+ }
+ else if (Song::kColumns.value(i) == "song_id") {
+ d->song_id_ = toint(x);
+ }
+
else if (Song::kColumns.value(i) == "beginning") {
d->beginning_ = q.value(x).isNull() ? 0 : q.value(x).toLongLong();
}
@@ -1093,6 +1121,10 @@ void Song::BindToQuery(QSqlQuery *query) const {
query->bindValue(":comment", strval(d->comment_));
query->bindValue(":lyrics", strval(d->lyrics_));
+ query->bindValue(":artist_id", intval(d->artist_id_));
+ query->bindValue(":album_id", intval(d->album_id_));
+ query->bindValue(":song_id", intval(d->song_id_));
+
query->bindValue(":beginning", d->beginning_);
query->bindValue(":length", intval(length_nanosec()));
@@ -1221,17 +1253,20 @@ bool Song::IsMetadataEqual(const Song &other) const {
d->album_ == other.d->album_ &&
d->artist_ == other.d->artist_ &&
d->albumartist_ == other.d->albumartist_ &&
- d->composer_ == other.d->composer_ &&
- d->performer_ == other.d->performer_ &&
- d->grouping_ == other.d->grouping_ &&
d->track_ == other.d->track_ &&
d->disc_ == other.d->disc_ &&
d->year_ == other.d->year_ &&
d->originalyear_ == other.d->originalyear_ &&
d->genre_ == other.d->genre_ &&
+ d->compilation_ == other.d->compilation_ &&
+ d->composer_ == other.d->composer_ &&
+ d->performer_ == other.d->performer_ &&
+ d->grouping_ == other.d->grouping_ &&
d->comment_ == other.d->comment_ &&
d->lyrics_ == other.d->lyrics_ &&
- d->compilation_ == other.d->compilation_ &&
+ d->artist_id_ == other.d->artist_id_ &&
+ d->album_id_ == other.d->album_id_ &&
+ d->song_id_ == other.d->song_id_ &&
d->beginning_ == other.d->beginning_ &&
length_nanosec() == other.length_nanosec() &&
d->bitrate_ == other.d->bitrate_ &&
diff --git a/src/core/song.h b/src/core/song.h
index d2cb23c5e..656cef12d 100644
--- a/src/core/song.h
+++ b/src/core/song.h
@@ -197,10 +197,9 @@ class Song {
const QString &comment() const;
const QString &lyrics() const;
- int playcount() const;
- int skipcount() const;
- int lastplayed() const;
+ int artist_id() const;
int album_id() const;
+ int song_id() const;
qint64 beginning_nanosec() const;
qint64 end_nanosec() const;
@@ -219,6 +218,10 @@ class Song {
uint mtime() const;
uint ctime() const;
+ int playcount() const;
+ int skipcount() const;
+ int lastplayed() const;
+
const QString &art_automatic() const;
const QString &art_manual() const;
@@ -265,7 +268,6 @@ class Song {
bool IsEditable() const;
void set_id(int id);
- void set_album_id(int v);
void set_valid(bool v);
void set_title(const QString &v);
@@ -285,6 +287,10 @@ class Song {
void set_comment(const QString &v);
void set_lyrics(const QString &v);
+ void set_artist_id(int v);
+ void set_album_id(int v);
+ void set_song_id(int v);
+
void set_beginning_nanosec(qint64 v);
void set_end_nanosec(qint64 v);
void set_length_nanosec(qint64 v);