Add tidal support

This commit is contained in:
Jonas Kvinge
2018-08-09 18:10:03 +02:00
parent 26062bd07b
commit 820124f9e1
74 changed files with 5420 additions and 273 deletions

View File

@@ -15,7 +15,7 @@
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*
*/
#include "config.h"
@@ -84,6 +84,11 @@
#include "songplaylistitem.h"
#include "tagreadermessages.pb.h"
#include "internet/internetmodel.h"
#include "internet/internetplaylistitem.h"
#include "internet/internetmimedata.h"
#include "internet/internetsongmimedata.h"
using std::placeholders::_1;
using std::placeholders::_2;
using std::shared_ptr;
@@ -153,7 +158,7 @@ Playlist::~Playlist() {
}
template <typename T>
void Playlist::InsertSongItems(const SongList &songs, int pos, bool play_now, bool enqueue) {
void Playlist::InsertSongItems(const SongList &songs, int pos, bool play_now, bool enqueue, bool enqueue_next) {
PlaylistItemList items;
@@ -161,7 +166,7 @@ void Playlist::InsertSongItems(const SongList &songs, int pos, bool play_now, bo
items << PlaylistItemPtr(new T(song));
}
InsertItems(items, pos, play_now, enqueue);
InsertItems(items, pos, play_now, enqueue, enqueue_next);
}
@@ -282,16 +287,15 @@ QVariant Playlist::data(const QModelIndex &index, int role) const {
case Column_AlbumArtist: return song.playlist_albumartist();
case Column_Composer: return song.composer();
case Column_Performer: return song.performer();
case Column_Grouping: return song.grouping();
case Column_Grouping: return song.grouping();
case Column_PlayCount: return song.playcount();
case Column_SkipCount: return song.skipcount();
case Column_LastPlayed: return song.lastplayed();
case Column_Samplerate: return song.samplerate();
case Column_Bitdepth: return song.bitdepth();
case Column_Bitrate: return song.bitrate();
case Column_SamplerateBitdepth: return song.SampleRateBitDepthToText();
case Column_Bitdepth: return song.bitdepth();
case Column_Bitrate: return song.bitrate();
case Column_Filename: return song.url();
case Column_BaseFilename: return song.basefilename();
@@ -304,7 +308,7 @@ QVariant Playlist::data(const QModelIndex &index, int role) const {
if (role == Qt::DisplayRole) return song.comment().simplified();
return song.comment();
//case Column_Source: return item->Url();
case Column_Source: return item->Url();
}
@@ -323,9 +327,7 @@ QVariant Playlist::data(const QModelIndex &index, int role) const {
if (items_[index.row()]->HasCurrentForegroundColor()) {
return QBrush(items_[index.row()]->GetCurrentForegroundColor());
}
//if (index.row() < dynamic_history_length()) {
//return QBrush(kDynamicHistoryColor);
//}
return QVariant();
case Qt::BackgroundRole:
@@ -562,7 +564,7 @@ int Playlist::previous_row(bool ignore_repeat_track) const {
void Playlist::set_current_row(int i, bool is_stopping) {
QModelIndex old_current_item_index = current_item_index_;
//ClearStreamMetadata();
ClearStreamMetadata();
current_item_index_ = QPersistentModelIndex(index(i, 0, QModelIndex()));
@@ -636,6 +638,7 @@ bool Playlist::dropMimeData(const QMimeData *data, Qt::DropAction action, int ro
bool play_now = false;
bool enqueue_now = false;
bool enqueue_next_now = false;
if (const MimeData *mime_data = qobject_cast<const MimeData*>(data)) {
if (mime_data->clear_first_) {
@@ -643,6 +646,7 @@ bool Playlist::dropMimeData(const QMimeData *data, Qt::DropAction action, int ro
}
play_now = mime_data->play_now_;
enqueue_now = mime_data->enqueue_now_;
enqueue_next_now = mime_data->enqueue_next_now_;
}
if (const SongMimeData *song_data = qobject_cast<const SongMimeData*>(data)) {
@@ -651,11 +655,13 @@ bool Playlist::dropMimeData(const QMimeData *data, Qt::DropAction action, int ro
if (song_data->backend && song_data->backend->songs_table() == SCollection::kSongsTable)
InsertSongItems<CollectionPlaylistItem>(song_data->songs, row, play_now, enqueue_now);
else
InsertSongItems<SongPlaylistItem>(song_data->songs, row, play_now, enqueue_now);
InsertSongItems<SongPlaylistItem>(song_data->songs, row, play_now, enqueue_now, enqueue_next_now);
}
else if (const PlaylistItemMimeData *item_data = qobject_cast<const PlaylistItemMimeData*>(data)) {
InsertItems(item_data->items_, row, play_now, enqueue_now);
InsertItems(item_data->items_, row, play_now, enqueue_now, enqueue_next_now);
}
else if (const InternetSongMimeData* internet_song_data = qobject_cast<const InternetSongMimeData*>(data)) {
InsertInternetItems(internet_song_data->service, internet_song_data->songs, row, play_now, enqueue_now, enqueue_next_now);
}
else if (data->hasFormat(kRowsMimetype)) {
// Dragged from the playlist
@@ -719,7 +725,7 @@ bool Playlist::dropMimeData(const QMimeData *data, Qt::DropAction action, int ro
}
void Playlist::InsertUrls(const QList<QUrl> &urls, int pos, bool play_now, bool enqueue) {
void Playlist::InsertUrls(const QList<QUrl> &urls, int pos, bool play_now, bool enqueue, bool enqueue_next) {
SongLoaderInserter *inserter = new SongLoaderInserter(task_manager_, collection_, backend_->app()->player());
connect(inserter, SIGNAL(Error(QString)), SIGNAL(Error(QString)));
@@ -832,7 +838,7 @@ void Playlist::MoveItemsWithoutUndo(int start, const QList<int> &dest_rows) {
}
void Playlist::InsertItems(const PlaylistItemList &itemsIn, int pos, bool play_now, bool enqueue) {
void Playlist::InsertItems(const PlaylistItemList &itemsIn, int pos, bool play_now, bool enqueue, bool enqueue_next) {
if (itemsIn.isEmpty())
return;
@@ -932,25 +938,37 @@ void Playlist::InsertItemsWithoutUndo(const PlaylistItemList &items, int pos, bo
}
void Playlist::InsertCollectionItems(const SongList &songs, int pos, bool play_now, bool enqueue) {
InsertSongItems<CollectionPlaylistItem>(songs, pos, play_now, enqueue);
void Playlist::InsertCollectionItems(const SongList &songs, int pos, bool play_now, bool enqueue, bool enqueue_next) {
InsertSongItems<CollectionPlaylistItem>(songs, pos, play_now, enqueue, enqueue_next);
}
void Playlist::InsertSongs(const SongList &songs, int pos, bool play_now, bool enqueue) {
InsertSongItems<SongPlaylistItem>(songs, pos, play_now, enqueue);
void Playlist::InsertSongs(const SongList &songs, int pos, bool play_now, bool enqueue, bool enqueue_next) {
InsertSongItems<SongPlaylistItem>(songs, pos, play_now, enqueue, enqueue_next);
}
void Playlist::InsertSongsOrCollectionItems(const SongList &songs, int pos, bool play_now, bool enqueue) {
void Playlist::InsertSongsOrCollectionItems(const SongList &songs, int pos, bool play_now, bool enqueue, bool enqueue_next) {
PlaylistItemList items;
for (const Song &song : songs) {
if (song.is_collection_song()) {
items << PlaylistItemPtr(new CollectionPlaylistItem(song));
} else {
}
else {
items << PlaylistItemPtr(new SongPlaylistItem(song));
}
}
InsertItems(items, pos, play_now, enqueue);
InsertItems(items, pos, play_now, enqueue, enqueue_next);
}
void Playlist::InsertInternetItems(InternetService *service, const SongList &songs, int pos, bool play_now, bool enqueue, bool enqueue_next) {
PlaylistItemList playlist_items;
for (const Song &song : songs) {
playlist_items << shared_ptr<PlaylistItem>(new InternetPlaylistItem(service, song));
}
InsertItems(playlist_items, pos, play_now, enqueue, enqueue_next);
}
@@ -973,8 +991,10 @@ void Playlist::UpdateItems(const SongList &songs) {
PlaylistItemPtr &item = items_[i];
if (item->Metadata().url() == song.url() &&
(item->Metadata().filetype() == Song::Type_Unknown ||
// Stream may change and may need to be updated too
item->Metadata().filetype() == Song::Type_Stream ||
// And CD tracks as well (tags are loaded in a second step)
item->Metadata().filetype() == Song::Type_Cdda)) {
item->Metadata().filetype() == Song::Type_CDDA)) {
PlaylistItemPtr new_item;
if (song.is_collection_song()) {
new_item = PlaylistItemPtr(new CollectionPlaylistItem(song));
@@ -1069,9 +1089,7 @@ bool Playlist::CompareItems(int column, Qt::SortOrder order, shared_ptr<Playlist
case Column_Bitrate: cmp(bitrate);
case Column_Samplerate: cmp(samplerate);
case Column_Bitdepth: cmp(bitdepth);
case Column_SamplerateBitdepth:
return QString::localeAwareCompare(a->Metadata().SampleRateBitDepthToText().toLower(), b->Metadata().SampleRateBitDepthToText().toLower()) < 0;
case Column_Bitdepth: cmp(bitdepth);
case Column_Filename:
return (QString::localeAwareCompare(a->Url().path().toLower(), b->Url().path().toLower()) < 0);
case Column_BaseFilename: cmp(basefilename);
@@ -1081,7 +1099,7 @@ bool Playlist::CompareItems(int column, Qt::SortOrder order, shared_ptr<Playlist
case Column_DateCreated: cmp(ctime);
case Column_Comment: strcmp(comment);
//case Column_Source: cmp(url);
case Column_Source: cmp(url);
}
#undef cmp
@@ -1126,7 +1144,6 @@ QString Playlist::column_name(Column column) {
case Column_Samplerate: return tr("Sample rate");
case Column_Bitdepth: return tr("Bit depth");
case Column_SamplerateBitdepth: return tr("Sample rate B");
case Column_Bitrate: return tr("Bitrate");
case Column_Filename: return tr("File name");
@@ -1137,7 +1154,7 @@ QString Playlist::column_name(Column column) {
case Column_DateCreated: return tr("Date created");
case Column_Comment: return tr("Comment");
//case Column_Source: return tr("Source");
case Column_Source: return tr("Source");
default: return QString();
}
return "";
@@ -1757,6 +1774,7 @@ void Playlist::InvalidateDeletedSongs() {
PlaylistItemPtr item = items_[row];
Song song = item->Metadata();
if (!song.is_stream()) {
bool exists = QFile::exists(song.url().toLocalFile());
if (!exists && !item->HasForegroundColor(kInvalidSongPriority)) {
@@ -1768,6 +1786,7 @@ void Playlist::InvalidateDeletedSongs() {
item->RemoveForegroundColor(kInvalidSongPriority);
invalidated_rows.append(row);
}
}
}
ReloadItems(invalidated_rows);