Allow radio services (Spotify) to store whole songs in playlist items

This commit is contained in:
David Sansome 2011-04-26 22:06:58 +00:00
parent 8ba5e2c275
commit 3d6677fe6d
21 changed files with 177 additions and 151 deletions

View File

@ -310,5 +310,6 @@
<file>icons/22x22/mail-message.png</file>
<file>icons/32x32/mail-message.png</file>
<file>icons/48x48/mail-message.png</file>
<file>schema/schema-29.sql</file>
</qresource>
</RCC>

59
data/schema/schema-29.sql Normal file
View File

@ -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;

View File

@ -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):

View File

@ -32,7 +32,7 @@
#include <QVariant>
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;
}

View File

@ -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() {}

View File

@ -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;

View File

@ -935,9 +935,7 @@ void Playlist::InsertRadioStations(const RadioModel* model,
case RadioModel::PlayBehaviour_SingleItem:
playlist_items << shared_ptr<PlaylistItem>(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<Song>()));
break;
case RadioModel::PlayBehaviour_UseSongLoader:

View File

@ -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<PlaylistItemPtr> 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<PlaylistItemPtr> PlaylistBackend::GetPlaylistItems(int playlist) {
PlaylistItemPtr PlaylistBackend::NewSongFromQuery(const SqlRow& row, boost::shared_ptr<NewSongFromQueryState> 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();

View File

@ -50,6 +50,8 @@ class PlaylistBackend : public QObject {
typedef QList<Playlist> PlaylistList;
typedef QFuture<PlaylistItemPtr> PlaylistItemFuture;
static const int kSongTableJoins;
PlaylistList GetAllPlaylists();
Playlist GetPlaylist(int id);
PlaylistItemFuture GetPlaylistItems(int playlist);

View File

@ -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) {

View File

@ -138,18 +138,12 @@ class PlaylistItem : public boost::enable_shared_from_this<PlaylistItem> {
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_;

View File

@ -15,6 +15,7 @@
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#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();
}

View File

@ -37,7 +37,7 @@ class SongPlaylistItem : public PlaylistItem {
QUrl Url() const;
protected:
QVariant DatabaseValue(DatabaseColumn) const;
Song DatabaseSongMetadata() const { return song_; }
private:
Song song_;

View File

@ -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() {

View File

@ -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

View File

@ -20,6 +20,7 @@
#include "radiomodel.h"
#include "core/settingsprovider.h"
#include "library/sqlrow.h"
#include "playlist/playlistbackend.h"
#include <QSettings>
#include <QApplication>
@ -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 {

View File

@ -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_;

View File

@ -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) {

View File

@ -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);

View File

@ -26,7 +26,6 @@ public:
enum Role {
Role_UserPlaylistIndex = RadioModel::RoleCount,
Role_Metadata,
};
virtual QStandardItem* CreateRootItem();

View File

@ -10,8 +10,7 @@ public:
Role_Type,
Role_PlayBehaviour,
Role_Url,
Role_Title,
Role_Artist,
Role_SongMetadata,
Role_CanLazyLoad,
Role_Service,
};