mirror of
https://github.com/clementine-player/Clementine
synced 2024-12-18 12:28:31 +01:00
Allow radio services (Spotify) to store whole songs in playlist items
This commit is contained in:
parent
8ba5e2c275
commit
3d6677fe6d
@ -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
59
data/schema/schema-29.sql
Normal 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;
|
@ -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):
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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() {}
|
||||
|
@ -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;
|
||||
|
@ -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:
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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_;
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ class SongPlaylistItem : public PlaylistItem {
|
||||
QUrl Url() const;
|
||||
|
||||
protected:
|
||||
QVariant DatabaseValue(DatabaseColumn) const;
|
||||
Song DatabaseSongMetadata() const { return song_; }
|
||||
|
||||
private:
|
||||
Song song_;
|
||||
|
@ -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() {
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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_;
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -26,7 +26,6 @@ public:
|
||||
|
||||
enum Role {
|
||||
Role_UserPlaylistIndex = RadioModel::RoleCount,
|
||||
Role_Metadata,
|
||||
};
|
||||
|
||||
virtual QStandardItem* CreateRootItem();
|
||||
|
@ -10,8 +10,7 @@ public:
|
||||
Role_Type,
|
||||
Role_PlayBehaviour,
|
||||
Role_Url,
|
||||
Role_Title,
|
||||
Role_Artist,
|
||||
Role_SongMetadata,
|
||||
Role_CanLazyLoad,
|
||||
Role_Service,
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user