diff --git a/data/data.qrc b/data/data.qrc
index e7e5e42c6..bb65203f0 100644
--- a/data/data.qrc
+++ b/data/data.qrc
@@ -310,5 +310,6 @@
icons/22x22/mail-message.png
icons/32x32/mail-message.png
icons/48x48/mail-message.png
+ schema/schema-29.sql
diff --git a/data/schema/schema-29.sql b/data/schema/schema-29.sql
new file mode 100644
index 000000000..2f53528c5
--- /dev/null
+++ b/data/schema/schema-29.sql
@@ -0,0 +1,59 @@
+ALTER TABLE playlist_items ADD COLUMN albumartist TEXT;
+
+ALTER TABLE playlist_items ADD COLUMN composer TEXT;
+
+ALTER TABLE playlist_items ADD COLUMN track INTEGER;
+
+ALTER TABLE playlist_items ADD COLUMN disc INTEGER;
+
+ALTER TABLE playlist_items ADD COLUMN bpm REAL;
+
+ALTER TABLE playlist_items ADD COLUMN year INTEGER;
+
+ALTER TABLE playlist_items ADD COLUMN genre TEXT;
+
+ALTER TABLE playlist_items ADD COLUMN comment TEXT;
+
+ALTER TABLE playlist_items ADD COLUMN compilation INTEGER;
+
+ALTER TABLE playlist_items ADD COLUMN bitrate INTEGER;
+
+ALTER TABLE playlist_items ADD COLUMN samplerate INTEGER;
+
+ALTER TABLE playlist_items ADD COLUMN directory INTEGER;
+
+ALTER TABLE playlist_items ADD COLUMN filename TEXT;
+
+ALTER TABLE playlist_items ADD COLUMN mtime INTEGER;
+
+ALTER TABLE playlist_items ADD COLUMN ctime INTEGER;
+
+ALTER TABLE playlist_items ADD COLUMN filesize INTEGER;
+
+ALTER TABLE playlist_items ADD COLUMN sampler INTEGER NOT NULL DEFAULT 0;
+
+ALTER TABLE playlist_items ADD COLUMN art_automatic TEXT;
+
+ALTER TABLE playlist_items ADD COLUMN art_manual TEXT;
+
+ALTER TABLE playlist_items ADD COLUMN filetype INTEGER NOT NULL DEFAULT 0;
+
+ALTER TABLE playlist_items ADD COLUMN playcount INTEGER NOT NULL DEFAULT 0;
+
+ALTER TABLE playlist_items ADD COLUMN lastplayed INTEGER;
+
+ALTER TABLE playlist_items ADD COLUMN rating INTEGER;
+
+ALTER TABLE playlist_items ADD COLUMN forced_compilation_on INTEGER NOT NULL DEFAULT 0;
+
+ALTER TABLE playlist_items ADD COLUMN forced_compilation_off INTEGER NOT NULL DEFAULT 0;
+
+ALTER TABLE playlist_items ADD COLUMN effective_compilation NOT NULL DEFAULT 0;
+
+ALTER TABLE playlist_items ADD COLUMN skipcount INTEGER NOT NULL DEFAULT 0;
+
+ALTER TABLE playlist_items ADD COLUMN score INTEGER NOT NULL DEFAULT 0;
+
+UPDATE playlist_items SET filename = url;
+
+UPDATE schema_version SET version=29;
diff --git a/scripts/digitallyimported-radio/servicebase.py b/scripts/digitallyimported-radio/servicebase.py
index 9ec3947b1..246ade687 100644
--- a/scripts/digitallyimported-radio/servicebase.py
+++ b/scripts/digitallyimported-radio/servicebase.py
@@ -122,12 +122,15 @@ class DigitallyImportedServiceBase(clementine.RadioService):
self.root.removeRows(0, self.root.rowCount())
for stream in streams:
+ song = clementine.Song()
+ song.set_title(stream["name"])
+ song.set_artist(self.SERVICE_DESCRIPTION)
+ song.set_filename("digitallyimported://%s" % stream["key"])
+
item = QStandardItem(QIcon(":last.fm/icon_radio.png"), stream["name"])
item.setData(stream["description"], PyQt4.QtCore.Qt.ToolTipRole)
- item.setData("digitallyimported://%s" % stream["key"], clementine.RadioModel.Role_Url)
item.setData(clementine.RadioModel.PlayBehaviour_SingleItem, clementine.RadioModel.Role_PlayBehaviour)
- item.setData(stream["name"], clementine.RadioModel.Role_Title)
- item.setData(self.SERVICE_DESCRIPTION, clementine.RadioModel.Role_Artist)
+ item.setData(song, clementine.RadioModel.Role_SongMetadata)
self.root.appendRow(item)
def playlistitem_options(self):
diff --git a/src/core/database.cpp b/src/core/database.cpp
index f4fbfd6be..64d3369c2 100644
--- a/src/core/database.cpp
+++ b/src/core/database.cpp
@@ -32,7 +32,7 @@
#include
const char* Database::kDatabaseFilename = "clementine.db";
-const int Database::kSchemaVersion = 28;
+const int Database::kSchemaVersion = 29;
const char* Database::kMagicAllSongsTables = "%allsongstables";
int Database::sNextConnectionId = 1;
@@ -439,7 +439,7 @@ QSqlDatabase Database::Connect() {
" WHERE type='table'").arg(key), db);
if (!q.exec() || !q.next()) {
ScopedTransaction t(&db);
- ExecFromFile(attached_databases_[key].schema_, db);
+ ExecFromFile(attached_databases_[key].schema_, db, 0);
t.Commit();
}
}
@@ -508,25 +508,27 @@ void Database::UpdateDatabaseSchema(int version, QSqlDatabase &db) {
filename = QString(":/schema/schema-%1.sql").arg(version);
ScopedTransaction t(&db);
- ExecFromFile(filename, db);
+ ExecFromFile(filename, db, version - 1);
t.Commit();
}
-void Database::ExecFromFile(const QString &filename, QSqlDatabase &db) {
+void Database::ExecFromFile(const QString &filename, QSqlDatabase &db,
+ int schema_version) {
// Open and read the database schema
QFile schema_file(filename);
if (!schema_file.open(QIODevice::ReadOnly))
qFatal("Couldn't open schema file %s", filename.toUtf8().constData());
- ExecCommands(QString::fromUtf8(schema_file.readAll()), db);
+ ExecCommands(QString::fromUtf8(schema_file.readAll()), db, schema_version);
}
-void Database::ExecCommands(const QString &schema, QSqlDatabase &db) {
+void Database::ExecCommands(const QString& schema, QSqlDatabase& db,
+ int schema_version) {
// Run each command
QStringList commands(schema.split(";\n\n"));
// We don't want this list to reflect possible DB schema changes
// so we initialize it before executing any statements.
- QStringList tables = SongsTables(db);
+ QStringList tables = SongsTables(db, schema_version);
foreach (const QString& command, commands) {
// There are now lots of "songs" tables that need to have the same schema:
@@ -549,7 +551,7 @@ void Database::ExecCommands(const QString &schema, QSqlDatabase &db) {
}
}
-QStringList Database::SongsTables(QSqlDatabase& db) const {
+QStringList Database::SongsTables(QSqlDatabase& db, int schema_version) const {
QStringList ret;
// look for the tables in the main db
@@ -570,6 +572,11 @@ QStringList Database::SongsTables(QSqlDatabase& db) const {
}
}
+ if (schema_version > 29) {
+ // The playlist_items table became a songs table in version 29.
+ ret << "playlist_items";
+ }
+
return ret;
}
diff --git a/src/core/database.h b/src/core/database.h
index 1ab1c327f..1718291ab 100644
--- a/src/core/database.h
+++ b/src/core/database.h
@@ -54,8 +54,8 @@ class Database : public QObject {
QMutex* Mutex() { return &mutex_; }
void RecreateAttachedDb(const QString& database_name);
- void ExecFromFile(const QString& filename, QSqlDatabase &db);
- void ExecCommands(const QString& commands, QSqlDatabase &db);
+ void ExecFromFile(const QString& filename, QSqlDatabase &db, int schema_version);
+ void ExecCommands(const QString& commands, QSqlDatabase &db, int schema_version);
int startup_schema_version() const { return startup_schema_version_; }
int current_schema_version() const { return kSchemaVersion; }
@@ -67,7 +67,7 @@ class Database : public QObject {
void UpdateMainSchema(QSqlDatabase* db);
void UpdateDatabaseSchema(int version, QSqlDatabase& db);
- QStringList SongsTables(QSqlDatabase& db) const;
+ QStringList SongsTables(QSqlDatabase& db, int schema_version) const;
struct AttachedDatabase {
AttachedDatabase() {}
diff --git a/src/devices/devicedatabasebackend.cpp b/src/devices/devicedatabasebackend.cpp
index 9f2bbb6d8..1b452ee16 100644
--- a/src/devices/devicedatabasebackend.cpp
+++ b/src/devices/devicedatabasebackend.cpp
@@ -90,7 +90,7 @@ int DeviceDatabaseBackend::AddDevice(const Device& device) {
QString schema = QString::fromUtf8(schema_file.readAll());
schema.replace("%deviceid", QString::number(id));
- db_->ExecCommands(schema, db);
+ db_->ExecCommands(schema, db, 0);
t.Commit();
return id;
diff --git a/src/playlist/playlist.cpp b/src/playlist/playlist.cpp
index 6fb179b16..67b762ad5 100644
--- a/src/playlist/playlist.cpp
+++ b/src/playlist/playlist.cpp
@@ -935,9 +935,7 @@ void Playlist::InsertRadioStations(const RadioModel* model,
case RadioModel::PlayBehaviour_SingleItem:
playlist_items << shared_ptr(new RadioPlaylistItem(
model->ServiceForIndex(item),
- item.data(RadioModel::Role_Url).toUrl(),
- item.data(RadioModel::Role_Title).toString(),
- item.data(RadioModel::Role_Artist).toString()));
+ item.data(RadioModel::Role_SongMetadata).value()));
break;
case RadioModel::PlayBehaviour_UseSongLoader:
diff --git a/src/playlist/playlistbackend.cpp b/src/playlist/playlistbackend.cpp
index 8f8dc7bce..cfc0082c5 100644
--- a/src/playlist/playlistbackend.cpp
+++ b/src/playlist/playlistbackend.cpp
@@ -38,6 +38,8 @@ using smart_playlists::GeneratorPtr;
using boost::shared_ptr;
+const int PlaylistBackend::kSongTableJoins = 4;
+
PlaylistBackend::PlaylistBackend(QObject* parent)
: QObject(parent),
library_(NULL)
@@ -109,8 +111,8 @@ QFuture PlaylistBackend::GetPlaylistItems(int playlist) {
QString query = "SELECT songs.ROWID, " + Song::JoinSpec("songs") + ","
" magnatune_songs.ROWID, " + Song::JoinSpec("magnatune_songs") + ","
" jamendo_songs.ROWID, " + Song::JoinSpec("jamendo_songs") + ","
- " p.type, p.url, p.title, p.artist, p.album, p.length,"
- " p.radio_service, p.beginning, p.cue_path"
+ " p.ROWID, " + Song::JoinSpec("p") + ","
+ " p.type, p.radio_service"
" FROM playlist_items AS p"
" LEFT JOIN songs"
" ON p.library_id = songs.ROWID"
@@ -140,7 +142,7 @@ QFuture PlaylistBackend::GetPlaylistItems(int playlist) {
PlaylistItemPtr PlaylistBackend::NewSongFromQuery(const SqlRow& row, boost::shared_ptr state) {
// The song tables get joined first, plus one each for the song ROWIDs
- const int playlist_row = (Song::kColumns.count() + 1) * 3;
+ const int playlist_row = (Song::kColumns.count() + 1) * kSongTableJoins;
PlaylistItemPtr item(PlaylistItem::NewFromType(row.value(playlist_row).toString()));
if (item) {
@@ -219,9 +221,10 @@ void PlaylistBackend::SavePlaylist(int playlist, const PlaylistItemList& items,
QSqlQuery clear("DELETE FROM playlist_items WHERE playlist = :playlist", db);
QSqlQuery insert("INSERT INTO playlist_items"
- " (playlist, type, library_id, url, title, artist, album,"
- " length, radio_service, beginning, cue_path)"
- " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", db);
+ " (playlist, type, library_id, radio_service, " +
+ Song::kColumnSpec + ")"
+ " VALUES (:playlist, :type, :library_id, :radio_service, " +
+ Song::kBindSpec + ")", db);
QSqlQuery update("UPDATE playlists SET "
" last_played=:last_played,"
" dynamic_playlist_type=:dynamic_type,"
@@ -239,7 +242,7 @@ void PlaylistBackend::SavePlaylist(int playlist, const PlaylistItemList& items,
// Save the new ones
foreach (PlaylistItemPtr item, items) {
- insert.bindValue(0, playlist);
+ insert.bindValue(":playlist", playlist);
item->BindToQuery(&insert);
insert.exec();
diff --git a/src/playlist/playlistbackend.h b/src/playlist/playlistbackend.h
index ae3cd0e3b..0f3bea83b 100644
--- a/src/playlist/playlistbackend.h
+++ b/src/playlist/playlistbackend.h
@@ -50,6 +50,8 @@ class PlaylistBackend : public QObject {
typedef QList PlaylistList;
typedef QFuture PlaylistItemFuture;
+ static const int kSongTableJoins;
+
PlaylistList GetAllPlaylists();
Playlist GetPlaylist(int id);
PlaylistItemFuture GetPlaylistItems(int playlist);
diff --git a/src/playlist/playlistitem.cpp b/src/playlist/playlistitem.cpp
index e87c5c6ab..9742281d9 100644
--- a/src/playlist/playlistitem.cpp
+++ b/src/playlist/playlistitem.cpp
@@ -18,6 +18,7 @@
#include "playlistitem.h"
#include "songplaylistitem.h"
#include "core/logging.h"
+#include "core/song.h"
#include "library/library.h"
#include "library/libraryplaylistitem.h"
#include "radio/jamendoplaylistitem.h"
@@ -64,16 +65,11 @@ PlaylistItem* PlaylistItem::NewFromSongsTable(const QString& table, const Song&
}
void PlaylistItem::BindToQuery(QSqlQuery* query) const {
- query->bindValue(1, type());
- query->bindValue(2, DatabaseValue(Column_LibraryId));
- query->bindValue(3, DatabaseValue(Column_Url));
- query->bindValue(4, DatabaseValue(Column_Title));
- query->bindValue(5, DatabaseValue(Column_Artist));
- query->bindValue(6, DatabaseValue(Column_Album));
- query->bindValue(7, DatabaseValue(Column_Length));
- query->bindValue(8, DatabaseValue(Column_RadioService));
- query->bindValue(9, DatabaseValue(Column_Beginning));
- query->bindValue(10, DatabaseValue(Column_CuePath));
+ query->bindValue(":type", type());
+ query->bindValue(":library_id", DatabaseValue(Column_LibraryId));
+ query->bindValue(":radio_service", DatabaseValue(Column_RadioService));
+
+ DatabaseSongMetadata().BindToQuery(query);
}
void PlaylistItem::SetTemporaryMetadata(const Song& metadata) {
diff --git a/src/playlist/playlistitem.h b/src/playlist/playlistitem.h
index c2486e057..5d806334f 100644
--- a/src/playlist/playlistitem.h
+++ b/src/playlist/playlistitem.h
@@ -138,18 +138,12 @@ class PlaylistItem : public boost::enable_shared_from_this {
protected:
enum DatabaseColumn {
Column_LibraryId,
- Column_Url,
- Column_Title,
- Column_Artist,
- Column_Album,
- Column_Length,
Column_RadioService,
- Column_Beginning,
- Column_CuePath,
};
virtual QVariant DatabaseValue(DatabaseColumn) const {
return QVariant(QVariant::String); }
+ virtual Song DatabaseSongMetadata() const { return Song(); }
QString type_;
diff --git a/src/playlist/songplaylistitem.cpp b/src/playlist/songplaylistitem.cpp
index 7a9d4dfd7..e230b4642 100644
--- a/src/playlist/songplaylistitem.cpp
+++ b/src/playlist/songplaylistitem.cpp
@@ -15,6 +15,7 @@
along with Clementine. If not, see .
*/
+#include "playlistbackend.h"
#include "songplaylistitem.h"
#include "library/sqlrow.h"
@@ -35,55 +36,17 @@ SongPlaylistItem::SongPlaylistItem(const Song& song)
}
bool SongPlaylistItem::InitFromQuery(const SqlRow& query) {
- // The song tables get joined first, plus one each for the song ROWIDs
- const int row = (Song::kColumns.count() + 1) * 3;
-
- QString filename(query.value(row + 1).toString());
- QString title(query.value(row + 2).toString());
- QString artist(query.value(row + 3).toString());
- QString album(query.value(row + 4).toString());
- qint64 length(query.value(row + 5).toLongLong());
+ song_.InitFromQuery(query, (Song::kColumns.count() + 1) * 3);
if (type() == "Stream") {
- song_.set_filename(filename);
song_.set_filetype(Song::Type_Stream);
-
- song_.Init(title, artist, album, length);
} else {
- song_.InitFromFile(filename, -1);
-
- qint64 beginning(query.value(row + 7).toLongLong());
- QString cue_path(query.value(row + 8).toString());
-
- // If the song was part of a cuesheet then keep the title, artist etc. that
- // was loaded last time.
- if (!cue_path.isEmpty()) {
- song_.set_title(title);
- song_.set_artist(artist);
- song_.set_album(album);
- song_.set_length_nanosec(length);
- }
-
- song_.set_beginning_nanosec(beginning);
- song_.set_cue_path(cue_path);
+ song_.set_directory_id(-1);
}
return true;
}
-QVariant SongPlaylistItem::DatabaseValue(DatabaseColumn column) const {
- switch (column) {
- case Column_Url: return song_.filename();
- case Column_Title: return song_.title();
- case Column_Artist: return song_.artist();
- case Column_Album: return song_.album();
- case Column_Length: return song_.length_nanosec();
- case Column_Beginning: return song_.beginning_nanosec();
- case Column_CuePath: return song_.cue_path();
- default: return PlaylistItem::DatabaseValue(column);
- }
-}
-
QUrl SongPlaylistItem::Url() const {
return song_.url();
}
diff --git a/src/playlist/songplaylistitem.h b/src/playlist/songplaylistitem.h
index f5a5595a7..9ad0b42da 100644
--- a/src/playlist/songplaylistitem.h
+++ b/src/playlist/songplaylistitem.h
@@ -37,7 +37,7 @@ class SongPlaylistItem : public PlaylistItem {
QUrl Url() const;
protected:
- QVariant DatabaseValue(DatabaseColumn) const;
+ Song DatabaseSongMetadata() const { return song_; }
private:
Song song_;
diff --git a/src/radio/lastfmservice.cpp b/src/radio/lastfmservice.cpp
index 8493caf4a..d597e350d 100644
--- a/src/radio/lastfmservice.cpp
+++ b/src/radio/lastfmservice.cpp
@@ -234,9 +234,12 @@ void LastFMService::LazyPopulate(QStandardItem* parent) {
QStandardItem* LastFMService::CreateStationItem(
QStandardItem* parent, const QString& name, const QString& icon,
const QString& url, const QString& title) {
+ Song song;
+ song.set_filename(url);
+ song.set_title(title);
+
QStandardItem* ret = new QStandardItem(QIcon(icon), name);
- ret->setData(url, RadioModel::Role_Url);
- ret->setData(title, RadioModel::Role_Title);
+ ret->setData(QVariant::fromValue(song), RadioModel::Role_SongMetadata);
ret->setData(RadioModel::PlayBehaviour_SingleItem, RadioModel::Role_PlayBehaviour);
parent->appendRow(ret);
return ret;
@@ -606,9 +609,12 @@ void LastFMService::RefreshFriendsFinished() {
}
foreach (const lastfm::User& f, friends) {
+ Song song;
+ song.set_filename("lastfm://user/" + f.name() + "/library");
+ song.set_title(tr("Last.fm Library - %1").arg(f.name()));
+
QStandardItem* item = new QStandardItem(QIcon(":last.fm/icon_user.png"), f.name());
- item->setData(QUrl("lastfm://user/" + f.name() + "/library"), RadioModel::Role_Url);
- item->setData(tr("Last.fm Library - %1").arg(f.name()), RadioModel::Role_Title);
+ item->setData(QVariant::fromValue(song), RadioModel::Role_SongMetadata);
item->setData(true, RadioModel::Role_CanLazyLoad);
item->setData(Type_OtherUser, RadioModel::Role_Type);
item->setData(RadioModel::PlayBehaviour_SingleItem, RadioModel::Role_PlayBehaviour);
@@ -635,9 +641,12 @@ void LastFMService::RefreshNeighboursFinished() {
}
foreach (const lastfm::User& n, neighbours) {
+ Song song;
+ song.set_filename("lastfm://user/" + n.name() + "/library");
+ song.set_title(tr("Last.fm Library - %1").arg(n.name()));
+
QStandardItem* item = new QStandardItem(QIcon(":last.fm/user_purple.png"), n.name());
- item->setData(QUrl("lastfm://user/" + n.name() + "/library"), RadioModel::Role_Url);
- item->setData(tr("Last.fm Library - %1").arg(n.name()), RadioModel::Role_Title);
+ item->setData(QVariant::fromValue(song), RadioModel::Role_SongMetadata);
item->setData(true, RadioModel::Role_CanLazyLoad);
item->setData(Type_OtherUser, RadioModel::Role_Type);
item->setData(RadioModel::PlayBehaviour_SingleItem, RadioModel::Role_PlayBehaviour);
@@ -686,9 +695,12 @@ void LastFMService::AddArtistOrTag(const QString& name,
else
url_content = content;
+ Song song;
+ song.set_filename(url_pattern.arg(url_content));
+ song.set_title(title_pattern.arg(content));
+
QStandardItem* item = new QStandardItem(QIcon(icon), content);
- item->setData(url_pattern.arg(url_content), RadioModel::Role_Url);
- item->setData(title_pattern.arg(content), RadioModel::Role_Title);
+ item->setData(QVariant::fromValue(song), RadioModel::Role_SongMetadata);
item->setData(RadioModel::PlayBehaviour_SingleItem, RadioModel::Role_PlayBehaviour);
list->appendRow(item);
emit AddItemToPlaylist(item->index(), AddMode_Append);
@@ -728,9 +740,12 @@ void LastFMService::RestoreList(const QString& name,
else
url_content = content;
+ Song song;
+ song.set_filename(url_pattern.arg(url_content));
+ song.set_title(title_pattern.arg(content));
+
QStandardItem* item = new QStandardItem(icon, content);
- item->setData(url_pattern.arg(url_content), RadioModel::Role_Url);
- item->setData(title_pattern.arg(content), RadioModel::Role_Title);
+ item->setData(QVariant::fromValue(song), RadioModel::Role_SongMetadata);
item->setData(RadioModel::PlayBehaviour_SingleItem, RadioModel::Role_PlayBehaviour);
parent->appendRow(item);
}
@@ -845,22 +860,23 @@ PlaylistItemPtr LastFMService::PlaylistItemForUrl(const QUrl& url) {
// This is a bit of a hack, it's only used by the artist/song info tag
// widgets for tag radio and similar artists radio.
- PlaylistItemPtr ret;
-
if (url.scheme() != "lastfm")
- return ret;
+ return PlaylistItemPtr();
QStringList sections(url.path().split("/", QString::SkipEmptyParts));
+ Song song;
+ song.set_filename(url.toString());
+
if (sections.count() == 2 && url.host() == "artist" && sections[1] == "similarartists") {
- ret.reset(new RadioPlaylistItem(this, url,
- tr(kTitleArtist).arg(sections[0]), QString()));
+ song.set_title(tr(kTitleArtist).arg(sections[0]));
} else if (sections.count() == 1 && url.host() == "globaltags") {
- ret.reset(new RadioPlaylistItem(this, url,
- tr(kTitleTag).arg(sections[0]), QString()));
+ song.set_title(tr(kTitleTag).arg(sections[0]));
+ } else {
+ return PlaylistItemPtr();
}
- return ret;
+ return PlaylistItemPtr(new RadioPlaylistItem(this, song));
}
void LastFMService::ToggleScrobbling() {
diff --git a/src/radio/radiomodel.h b/src/radio/radiomodel.h
index 37aeaf9c3..f88b1eff5 100644
--- a/src/radio/radiomodel.h
+++ b/src/radio/radiomodel.h
@@ -54,14 +54,12 @@ public:
Role_PlayBehaviour,
// The URL of the media for this item. This is required if the
- // PlayBehaviour is set to something other than None. How the URL is
- // used depends on the PlayBehaviour.
+ // PlayBehaviour is set to PlayBehaviour_UseSongLoader.
Role_Url,
- // These fields are used to populate the playlist columns for this item
- // only when using PlayBehaviour_SingleItem. They are ignored otherwise
- Role_Title,
- Role_Artist,
+ // The metadata used in the item that is added to the playlist if the
+ // PlayBehaviour is set to PlayBehaviour_SingleItem. Ignored otherwise.
+ Role_SongMetadata,
// If this is set to true then the model will call the service's
// LazyPopulate method when this item is expanded. Use this if your item's
diff --git a/src/radio/radioplaylistitem.cpp b/src/radio/radioplaylistitem.cpp
index e893e3771..2c52c8338 100644
--- a/src/radio/radioplaylistitem.cpp
+++ b/src/radio/radioplaylistitem.cpp
@@ -20,6 +20,7 @@
#include "radiomodel.h"
#include "core/settingsprovider.h"
#include "library/sqlrow.h"
+#include "playlist/playlistbackend.h"
#include
#include
@@ -31,28 +32,24 @@ RadioPlaylistItem::RadioPlaylistItem(const QString& type)
{
}
-RadioPlaylistItem::RadioPlaylistItem(RadioService* service, const QUrl& url,
- const QString& title, const QString& artist)
+RadioPlaylistItem::RadioPlaylistItem(RadioService* service, const Song& metadata)
: PlaylistItem("Radio"),
- url_(url),
- title_(title),
- artist_(artist),
service_name_(service->name()),
- set_service_icon_(false)
+ set_service_icon_(false),
+ metadata_(metadata)
{
InitMetadata();
}
bool RadioPlaylistItem::InitFromQuery(const SqlRow& query) {
// The song tables gets joined first, plus one each for the song ROWIDs
- const int row = (Song::kColumns.count() + 1) * 3;
+ const int row = (Song::kColumns.count() + 1) * PlaylistBackend::kSongTableJoins;
- url_ = query.value(row + 1).toString();
- title_ = query.value(row + 2).toString();
- artist_ = query.value(row + 3).toString();
- service_name_ = query.value(row + 6).toString();
+ service_name_ = query.value(row + 1).toString();
+ metadata_.InitFromQuery(query, (Song::kColumns.count() + 1) * 3);
InitMetadata();
+
return true;
}
@@ -73,22 +70,16 @@ RadioService* RadioPlaylistItem::service() const {
QVariant RadioPlaylistItem::DatabaseValue(DatabaseColumn column) const {
switch (column) {
- case Column_Url: return url_.toString();
- case Column_Title: return title_;
- case Column_Artist: return artist_;
case Column_RadioService: return service_name_;
default: return PlaylistItem::DatabaseValue(column);
}
}
void RadioPlaylistItem::InitMetadata() {
- if (!title_.isEmpty())
- metadata_.set_title(title_);
- else
- metadata_.set_title(url_.toString());
-
- metadata_.set_artist(artist_);
+ if (metadata_.title().isEmpty())
+ metadata_.set_title(metadata_.filename());
metadata_.set_filetype(Song::Type_Stream);
+ metadata_.set_valid(true);
}
Song RadioPlaylistItem::Metadata() const {
@@ -106,18 +97,18 @@ PlaylistItem::SpecialLoadResult RadioPlaylistItem::StartLoading() {
RadioService* s = service();
if (!s)
return SpecialLoadResult();
- return s->StartLoading(url_);
+ return s->StartLoading(Url());
}
PlaylistItem::SpecialLoadResult RadioPlaylistItem::LoadNext() {
RadioService* s = service();
if (!s)
return SpecialLoadResult();
- return s->LoadNext(url_);
+ return s->LoadNext(Url());
}
QUrl RadioPlaylistItem::Url() const {
- return url_;
+ return QUrl(metadata_.filename());
}
PlaylistItem::Options RadioPlaylistItem::options() const {
diff --git a/src/radio/radioplaylistitem.h b/src/radio/radioplaylistitem.h
index ee2d36033..d264f1b1b 100644
--- a/src/radio/radioplaylistitem.h
+++ b/src/radio/radioplaylistitem.h
@@ -28,8 +28,7 @@ class RadioService;
class RadioPlaylistItem : public PlaylistItem {
public:
RadioPlaylistItem(const QString& type);
- RadioPlaylistItem(RadioService* service, const QUrl& url,
- const QString& title, const QString& artist);
+ RadioPlaylistItem(RadioService* service, const Song& metadata);
Options options() const;
@@ -44,15 +43,13 @@ class RadioPlaylistItem : public PlaylistItem {
protected:
QVariant DatabaseValue(DatabaseColumn) const;
+ Song DatabaseSongMetadata() const { return metadata_; }
private:
void InitMetadata();
RadioService* service() const;
private:
- QUrl url_;
- QString title_;
- QString artist_;
QString service_name_;
bool set_service_icon_;
diff --git a/src/radio/somafmservice.cpp b/src/radio/somafmservice.cpp
index 23b20d041..79bcdb407 100644
--- a/src/radio/somafmservice.cpp
+++ b/src/radio/somafmservice.cpp
@@ -158,28 +158,30 @@ void SomaFMService::RefreshChannelsFinished() {
}
void SomaFMService::ReadChannel(QXmlStreamReader& reader) {
- QStandardItem* item = new QStandardItem(QIcon(":last.fm/icon_radio.png"), QString());
- item->setData(RadioModel::PlayBehaviour_SingleItem, RadioModel::Role_PlayBehaviour);
+ Song song;
while (!reader.atEnd()) {
switch (reader.readNext()) {
case QXmlStreamReader::EndElement:
- if (item->data(RadioModel::Role_Url).toString().isNull()) {
- // Didn't find a URL
- delete item;
- } else {
+ if (!song.url().isEmpty()) {
+ QStandardItem* item = new QStandardItem(QIcon(":last.fm/icon_radio.png"), QString());
+ item->setText(song.title());
+
+ song.set_title("SomaFM " + song.title());
+ item->setData(QVariant::fromValue(song), RadioModel::Role_SongMetadata);
+ item->setData(RadioModel::PlayBehaviour_SingleItem, RadioModel::Role_PlayBehaviour);
+
root_->appendRow(item);
}
return;
case QXmlStreamReader::StartElement:
if (reader.name() == "title") {
- item->setText(reader.readElementText());
- item->setData("SomaFM " + item->text(), RadioModel::Role_Title);
+ song.set_title(reader.readElementText());
} else if (reader.name() == "dj") {
- item->setData(reader.readElementText(), RadioModel::Role_Artist);
+ song.set_artist(reader.readElementText());
} else if (reader.name() == "fastpls" && reader.attributes().value("format") == "mp3") {
- item->setData(reader.readElementText(), RadioModel::Role_Url);
+ song.set_filename(reader.readElementText());
} else {
ConsumeElement(reader);
}
@@ -189,8 +191,6 @@ void SomaFMService::ReadChannel(QXmlStreamReader& reader) {
break;
}
}
-
- delete item;
}
void SomaFMService::ConsumeElement(QXmlStreamReader& reader) {
diff --git a/src/radio/spotifyservice.cpp b/src/radio/spotifyservice.cpp
index db9b0de89..3ec4c2623 100644
--- a/src/radio/spotifyservice.cpp
+++ b/src/radio/spotifyservice.cpp
@@ -194,7 +194,7 @@ void SpotifyService::FillPlaylist(QStandardItem* item, const protobuf::LoadPlayl
QStandardItem* child = new QStandardItem(song.PrettyTitleWithArtist());
child->setData(Type_Track, RadioModel::Role_Type);
- child->setData(QVariant::fromValue(song), Role_Metadata);
+ child->setData(QVariant::fromValue(song), RadioModel::Role_SongMetadata);
child->setData(RadioModel::PlayBehaviour_SingleItem, RadioModel::Role_PlayBehaviour);
child->setData(QUrl(song.filename()), RadioModel::Role_Url);
diff --git a/src/radio/spotifyservice.h b/src/radio/spotifyservice.h
index 69be9224b..c81a03717 100644
--- a/src/radio/spotifyservice.h
+++ b/src/radio/spotifyservice.h
@@ -26,7 +26,6 @@ public:
enum Role {
Role_UserPlaylistIndex = RadioModel::RoleCount,
- Role_Metadata,
};
virtual QStandardItem* CreateRootItem();
diff --git a/src/scripting/python/radiomodel.sip b/src/scripting/python/radiomodel.sip
index 2bbbe605a..a901f5356 100644
--- a/src/scripting/python/radiomodel.sip
+++ b/src/scripting/python/radiomodel.sip
@@ -10,8 +10,7 @@ public:
Role_Type,
Role_PlayBehaviour,
Role_Url,
- Role_Title,
- Role_Artist,
+ Role_SongMetadata,
Role_CanLazyLoad,
Role_Service,
};